トラックリスト データ設計書
最終更新: 2026-11-07
1. 概要
releases.json にアルバム収録曲・シングルカップリングのトラックリストを追加するためのデータ設計。
プレイリスト機能(#336)において楽曲とリリースを紐付ける trackId の参照先を確立することが本設計の主目的である。
2. 背景・目的
現行の releases.json はリリースのメタ情報(タイトル・日付・フォーマット)のみを保持しており、収録曲情報がない。
| 目的 | 詳細 |
|---|---|
| プレイリスト楽曲の参照先確立 | PlaylistEntry.trackId が指す Track エンティティを定義する |
| リリース詳細画面の収録曲表示 | トラック番号・曲名・ディスク番号を画面に表示できるようにする |
| MusicBrainz API との整合 | 取得可能なフィールドを洗い出し、スキーマに反映する |
3. MusicBrainz API フィールドマッピング
取得エンドポイント: https://musicbrainz.org/ws/2/release/{mbid}?inc=recordings&fmt=json
レスポンス構造(関連部分)
{
"media": [
{
"position": 1,
"format": "CD",
"tracks": [
{
"id": "...",
"number": "1",
"title": "愛の種",
"length": 214000,
"recording": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
]
}
]
}
フィールド対応表
| MusicBrainz フィールド | 本設計フィールド | 説明 |
|---|---|---|
media[].tracks[].recording.id |
Track.id |
MusicBrainz recording UUID(楽曲の安定識別子) |
media[].tracks[].id |
Track.mbTrackId |
MusicBrainz track UUID(リリース上の出現位置) |
media[].tracks[].number |
Track.trackNumber |
ディスク内でのトラック番号(数値化) |
media[].position |
Track.discNumber |
ディスク番号(1始まり) |
media[].tracks[].title |
Track.title |
収録曲タイトル |
media[].tracks[].length |
Track.length |
曲の長さ(ミリ秒) |
Track.idに recording UUID を採用する理由 同一楽曲がシングルとアルバムに重複収録される場合、track UUID はリリースごとに異なるが recording UUID は同一となる。PlaylistEntry.trackIdからの参照は recording UUID の方が安定しており、クロスリリース参照(「このシングル曲はどのアルバムにも収録されている」等)が可能になる。
4. 型定義
Track インターフェース(新規追加)
export interface Track {
/** MusicBrainz recording UUID(楽曲の安定識別子・PlaylistEntry.trackId の参照先) */
id: string;
/** MusicBrainz track UUID(このリリース上の出現位置の識別子)。手動登録リリースでは省略可 */
mbTrackId?: string;
/** ディスク内でのトラック番号(1始まり) */
trackNumber: number;
/** ディスク番号(1始まり。シングル等の1枚組は省略可) */
discNumber?: number;
/** 収録曲タイトル */
title: string;
/** 曲の長さ(ミリ秒。MusicBrainz に未登録の場合は省略可) */
length?: number;
/** 外部リンク(YouTube MV・YouTube Music・YouTube Shorts 等)。sync-discography により自動付与。未取得時は省略 */
links?: ExternalLink[];
/** MusicBrainz artist-credit の全要素を結合句つきで連結した名義(例: `MIMI feat. モーニング娘。`)。sync-discography で自動設定 */
artist?: string;
/** 主体のいずれかが広義のユニット(ユニットまたは音楽グループ)に解決できた場合の広義のユニット ID(units.json または groups.json の id と一致)。sync-discography で自動設定 */
unitId?: string;
/** MusicBrainz artist-credit の主体のうち先頭のアーティストの MBID。sync-discography で自動設定 */
artistMbid?: string;
}
名義(artist-credit)の解釈
MusicBrainz の artist-credit は、アーティスト・クレジット表記名(name)・次の要素との結合句(joinphrase)の並びで1つの名義を表す。たとえば MIMI feat. モーニング娘。 は、MIMI(結合句 feat.)と モーニング娘。 の2要素で1つの名義である。sync-discography は結合句を読み取り、名義・主体・客演を次のとおり扱う(実装: lib/musicbrainz.ts)。
| 用語 | 定義 |
|---|---|
| 名義 | 全要素のクレジット表記名(省略時はアーティスト名)を、結合句を挟んで先頭から連結した文字列。Track.artist に保存する |
| 客演 | 結合句が単語 feat・featuring・ft を含む(ピリオドの有無・大文字小文字・前後の空白は区別しない)箇所より後ろに並ぶアーティスト |
| 主体 | 客演でないアーティスト。with・×・&・と・+・/ 等の結合句で並ぶ連名は、全員を主体とする。ただし、連続して並ぶ2人以上のアーティストが、ユニット名と一致する並びになっている場合は、その並びをまとめて1つの主体とする(後述) |
| 主体の先頭 | 客演でないアーティストのうち先頭のアーティスト。その MBID を Track.artistMbid に保存する(並びをまとめた主体があっても変わらない) |
ユニット名と一致する並びのまとめ方: 客演でないアーティストの並びを先頭から見ていき、各位置から始まる連続した2人以上のアーティストのクレジット表記名を、間の結合句ごと連結する(並びの最後のアーティストの後ろの結合句は含めない)。連結した文字列がユニット名(Unit.name)と一致すれば、その並びを1つの主体にまとめ、並びの次のアーティストから続きを見る。同じ位置から始まる並びが複数一致する場合は、長い並びを採る。比較は、連結した文字列とユニット名の両方に次の正規化をしてから行う。同じ名義でも曲によって表記が異なるため(例: 「仔犬ダンの物語 オリジナルサウンドトラック」の「がんばっちゃえ!」は +、「がんばっちゃえ! (Symphonic Version)」は +、No.5 の「がんばっちゃえ!」は ハロー!プロジェクト・キッズ+ と ! も全角)。
- Unicode の NFKC 正規化で、全角の英数字・記号(
!・+・?・&等)と全角スペースを半角にする - 空白(半角スペース)を取り除く
まとめた主体のクレジット表記名は、一致したユニット名とする(ユニットへの紐づけは ユニット一覧機能 データ設計書 §6)。ソロアーティストへの紐づけでは、まとめた主体を、並びを構成する各アーティストの MBID でも照合する(ソロアーティスト データ設計書 §6-2)。
| 名義の例 | 主体 | 客演 |
|---|---|---|
モーニング娘。 |
モーニング娘。 | なし |
モーニング娘。 & 平家みちよ |
モーニング娘。、平家みちよ | なし |
あややム with エコハムず |
あややム、エコハムず | なし |
MIMI feat. モーニング娘。 |
MIMI | モーニング娘。 |
モーニング娘。とハロー!プロジェクト・キッズ+後藤真希 |
モーニング娘。とハロー!プロジェクト・キッズ+後藤真希(ユニット名と一致する並び) | なし |
モーニング娘。とハロー!プロジェクト・キッズ+後藤真希 |
モーニング娘。とハロー!プロジェクト・キッズ+後藤真希(+ を + にして一致) |
なし |
モーニング娘。とハロー!プロジェクト・キッズ+後藤真希 |
モーニング娘。とハロー!プロジェクト・キッズ+後藤真希(!・+ を半角にして一致) |
なし |
高木ブーとモーニング娘。・ココナッツ娘。・藤本美貴・石井リカ |
高木ブーとモーニング娘。・ココナッツ娘。・藤本美貴・石井リカ(ユニット名と一致する並び) | なし |
高木ブーとモーニング娘。 |
高木ブー、モーニング娘。 | なし |
ユニット・ソロアーティストへの紐づけは主体で行う(ユニットは バッチ設計書 W2「ユニット照合」、ソロアーティストは ソロアーティスト データ設計書 §6-2)。連名の2番目以降を含む主体の全アーティストは、sync-discography の実行中にだけ保持し、Track には保存しない。
備考: 従来は結合句を読まずに先頭要素だけを artist・artistMbid として保存していたため、モーニング娘。が客演のみの名義(MIMI feat. モーニング娘。)が MIMI として保存され、モーニング娘。のリリースと区別できなかった(MorningStatusApp#1697)。
トラック単位の補正(data/inputs/track-corrections.json)
MusicBrainz は有志が登録しているデータで、このアプリにとっては収集の手段・ベースである。MusicBrainz の名義から決まるユニット(Track.unitId)が実態と異なるトラックは、補正ファイルで実態のユニットを指定する。手動登録リリース(data/inputs/manual-releases.json)と同じく、リポジトリで管理する JSON ファイルとし、いつ・何を・なぜ補正したかをコミットに残す。
{
"corrections": [
{
"trackId": "<Track.id(recording UUID。手動登録リリースのトラックは手動登録の ID)>",
"unitId": "<実態の広義のユニットの id(units.json または groups.json の id と一致)>",
"reason": "<補正の理由(例: CD のクレジットでは〜の名義)>"
}
]
}
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
trackId |
string |
✅ | 補正するトラックの Track.id。recording UUID は同じ録音を収録した全リリースで共通のため、補正は同じ録音を収録したすべてのリリースのトラックに当たる |
unitId |
string |
✅ | 実態の広義のユニットの id。units.json または groups.json に存在する id であること |
reason |
string |
✅ | 補正の理由。根拠にした資料(CD のクレジット等)を書く |
sync-discographyは、MusicBrainz からの取得と手動登録リリースのマージの後、ユニットの照合(ユニット一覧機能 データ設計書 §6)で、補正ファイルに登録したトラックは、照合の結果と既存のunitIdより優先して、補正ファイルのunitIdをTrack.unitIdにする。実行のたびに適用するため、保存済みのトラックにも当たり、REFETCH_RELEASE_IDS等で再取得しても補正は保たれるtrackIdに一致するトラックがない場合と、unitIdがunits.jsonにもgroups.jsonにも存在しない場合は、警告をログに出し、その補正を適用しない- 補正が必要なトラックは、
sync-discographyが出力する登録揺れの候補(バッチ設計書 W2)から見つける
トラックの保存先リリース(複数のリリースに載る曲)
同じ録音(Track.id。recording UUID)が複数のリリースに載る場合、Track はそのうち1つのリリースにだけ保存する。保存先は、リリースの形式(Release.format)の優先度が最も高いもの(single > album > ep > compilation > live > soundtrack > other)とする。シングルの曲が、ベスト盤やコレクションではなく、シングルの収録曲になるようにするため。
- 保存先にならなかったリリースは、収録曲のすべてが他のリリースに保存されることがあり、その場合は
Trackが0件のリリースとして保存される(ベスト盤・コレクション〈ハワイ限定盤を含む。いずれもcompilation〉、サウンドトラック〈soundtrack〉等)。欠落ではなく、削除の対象でもない - 取り込みルールで取り込まないと判定されるリリース(映像のみのライブ映像・映像作品。バッチ設計書 W2「MusicBrainz API」)とは原因が異なる。
Trackが0件のリリースは、MusicBrainz に収録曲があり、その曲が他のリリースに保存済みなら残す - 再取得(
REFETCH_RELEASE_IDS等)をしても、保存先は変わらないため、0件のままになる
リリース・トラックの除外(data/inputs/discography-exclusions.json)
MusicBrainz に登録されていても、このアプリの対象外とするリリース・トラックを、除外ファイルで指定する。トラック単位の補正と同じく、リポジトリで管理する JSON ファイルとし、いつ・何を・なぜ除外したかをコミットに残す。
{
"releases": [
{
"releaseId": "<Release.id(リリースグループ ID)>",
"title": "<リリース名(ファイルを読む人のための控え)>",
"reason": "<除外の理由(例: 歌なしの音源。MusicBrainz の注記で確認)>"
}
],
"tracks": [
{
"trackId": "<Track.id(recording UUID)>",
"title": "<曲名(ファイルを読む人のための控え)>",
"reason": "<除外の理由(例: モーニング娘。のメンバーではないアーティストの歌唱)>"
}
]
}
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
releases[].releaseId |
string |
✅ | 除外するリリースの Release.id |
tracks[].trackId |
string |
✅ | 除外するトラックの Track.id。recording UUID は同じ録音を収録した全リリースで共通のため、同じ録音を収録したすべてのリリースから除外する |
releases[].title・tracks[].title |
string |
✅ | リリース名・曲名。照合には使わない |
releases[].reason・tracks[].reason |
string |
✅ | 除外の理由。根拠にした資料を書く |
sync-discographyは、除外ファイルに登録したリリース・トラックを、取得したデータから外してから照合・保存する(バッチ設計書 W2「リリース・トラックの除外」)。実行のたびに適用するため、REFETCH_RELEASE_IDS等で再取得しても取り込まれない- 項目が欠けているものは、警告をログに出し、その除外を適用しない
- 除外ファイルに登録する前から保存されているリリース・トラックは、
sync-discographyでは消えない(保存は追加・更新だけのため)。一回限りのパッチで消す(バッチ設計書「一回限りパッチ一覧」) - 除外するかは、登録揺れの候補(バッチ設計書 W2)を確認して判断する。対象外とする例: 歌なしの音源(オルゴール等)のリリース、正規のリリースか確認できないリリース、モーニング娘。のメンバーではないアーティストの歌唱のトラック
ExternalLink 型(Track.links の要素)
ExternalLink は { type: ExternalLinkType; url: string } の形式で定義される(types/external-link.ts)。
ExternalLinkType 値 |
説明 | 付与元 |
|---|---|---|
youtube |
YouTube MV(曲詳細でインライン iframe 表示) | syncTrackLinks |
youtube-music |
YouTube Music(曲詳細の外部リンクセクションにボタン表示) | syncTrackLinks |
youtube-short |
YouTube Shorts(シングル曲のみ・Instrumental 除外・最大10件・曲詳細でインライン iframe 表示)(#774, #828) | syncTrackShortLinks |
spotify |
Spotify | 手動登録 |
apple-music |
Apple Music | 手動登録 |
line-music |
LINE MUSIC | 手動登録 |
recochoku |
レコチョク | 手動登録 |
mora |
mora | 手動登録 |
genius |
Genius(歌詞リンクセクション専用。曲詳細で「Genius で歌詞を見る」リンクとして表示) | syncGeniusLinks |
other |
その他外部リンク | 手動登録 |
Release インターフェース(tracks フィールド追加)
export interface Release {
id: string;
title: string;
releaseDate: string;
format: ReleaseFormat;
source: string;
sourceUrl: string;
/** トラックリスト(sync-discography による取得後に付与。未取得時は省略) */
tracks?: Track[];
}
tracksを省略可(optional)にすることで、既存データへの後方互換を維持する。
5. ER 図
→ docs/design/er-diagram.mdx を参照すること。
本設計で追加される Track エンティティの位置づけは ER 図の「v0.5.0 完成時点」セクションに記載。
Playlist / PlaylistEntry との関係は「v0.6.0 完成時点・全体」セクションに記載。
6. releases.json スキーマ変更
変更前
{
"releases": [
{
"id": "...",
"title": "LOVEマシーン",
"releaseDate": "1999-09-09",
"format": "single",
"source": "musicbrainz",
"sourceUrl": "https://musicbrainz.org/release/..."
}
]
}
変更後(tracks フィールド追加例)
{
"releases": [
{
"id": "fcd58b7d-77c0-37db-9334-5f50d92b09f1",
"title": "LOVEマシーン",
"releaseDate": "1999-09-09",
"format": "single",
"source": "musicbrainz",
"sourceUrl": "https://musicbrainz.org/release/fcd58b7d-77c0-37db-9334-5f50d92b09f1",
"tracks": [
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"mbTrackId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"trackNumber": 1,
"title": "LOVEマシーン",
"length": 273000
},
{
"id": "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz",
"mbTrackId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"trackNumber": 2,
"title": "ザ☆ピ〜ス!",
"length": 262000
}
]
}
]
}
7. PlaylistEntry への影響
playlists.json の各エントリには既に releaseId(任意)が存在する。
tracks の追加後、trackId を追加して楽曲を一意に特定できるようにする。
{
"memberId": "makino-maria",
"releaseId": "fcd58b7d-77c0-37db-9334-5f50d92b09f1",
"trackId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"songTitle": "LOVEマシーン",
"links": []
}
| フィールド | 必須 | 説明 |
|---|---|---|
memberId |
必須 | 選曲したメンバーの ID |
releaseId |
任意 | リリースが特定できる場合に付与 |
trackId |
任意 | Track.id(recording UUID)。収録曲が特定できる場合に付与 |
songTitle |
必須 | 表示用の楽曲タイトル(trackId が未設定でも表示に使用) |
links |
必須 | 外部リンク(YouTube 等) |
trackIdを任意とする理由:tracksデータが未取得のリリースや、プレイリスト上の楽曲が特定リリースに紐付かないケース(ライブ音源等)に対応するため。
8. マルチディスク対応方針
アルバム等の複数ディスク構成(CD1・CD2)は discNumber フィールドで区別する。
discNumberは省略可。省略時は1とみなすtrackNumberはディスク内での連番(1始まり)- ソート順:
discNumber ASC, trackNumber ASC
9. 既存データへの影響
| 対象 | 変更内容 | 後方互換 |
|---|---|---|
types/release.ts |
tracks?: Track[] フィールド追加 |
○ optional のため既存データは変更不要 |
releases.json |
tracks フィールドは sync-discography 実行後に付与 |
○ |
types/playlist.ts(実装済) |
trackId?: string フィールド追加 |
○ |
scripts/sync-discography.ts |
MusicBrainz recording API を呼び出してトラックリストを取得・保存 | - |
10. バージョン位置づけ
| バージョン | 機能 | 対応 Issue |
|---|---|---|
| v0.5.0 | トラックリスト管理機能(リリース収録曲) | #341(#338・#339・#340・#344) |
| v0.6.0 | プレイリスト管理機能 | #336(#328〜#335) |
v0.5.0 の完成をもってプレイリスト機能(v0.6.0)の前提基盤が整う。
11. 後続 Issue との関係
| Issue | 依存内容 |
|---|---|
#339 Release 型定義への tracks フィールド追加 |
本設計書の型定義に基づいて実装 |
#347 Release.youtubeUrl および ExternalLink 共通型の追加 |
本設計書の Release 拡張方針に基づいて実装(※ youtubeUrl はその後廃止され ExternalLink[] ベースに移行済) |
#340 sync-discography でのトラックリスト同期 |
MusicBrainz フィールドマッピング(§3)に基づいて実装 |
#350 sync-discography への YouTube MV URL 自動取得追加 |
Release.youtubeUrl フィールド(#347)に基づいて実装(現実装では Release.links を使用) |
| #344 リリース詳細画面の画面設計書の改訂 | 本設計のトラックリスト表示要件・YouTube MV リンク仕様を反映 |
| #348 リリース詳細画面への YouTube MV リンク追加 | #347・#344 完了後に実装 |
| #330 プレイリスト機能 型定義・基盤データファイルの追加 | PlaylistEntry.trackId の型定義(§7)に基づいて実装 |
改訂履歴
| 版 | 更新日 | 変更内容 |
|---|---|---|
| 1.13 | 2026-11-07 | 【実装時に追記(MorningStatusApp#1808)】Track 型の unitId と、§4 のトラック単位の補正の unitId の対応先を、units.json の id から、units.json または groups.json の id(広義のユニット)に変更(morning-status-blume#245、MorningStatusApp#1803) |
| 1.12 | 2026-10-10 | 【実装時に追記(MorningStatusApp#1731)】§4 に「トラックの保存先リリース(複数のリリースに載る曲)」を新設し、同じ録音が複数のリリースに載る場合は形式の優先度が最も高い1つのリリースにだけ保存すること、トラックが0件のリリースが生じることを追記(MorningStatusApp#1731) |
| 1.11 | 2026-10-06 | 【v11.3.6(MorningStatusApp#1711)】§4 に「リリース・トラックの除外(data/inputs/discography-exclusions.json)」を新設(MorningStatusApp#1711) |
| 1.10 | 2026-10-03 | 【v11.3.1(MorningStatusApp#1706)】§4「名義(artist-credit)の解釈」のユニット名との比較の正規化を、NFKC 正規化(全角の英数字・記号・スペースを半角にする)に広げ、No.5 の ! の例を追加。名義の例の「高木ブーとモーニング娘。・ココナッツ娘。・藤本美貴・石井リカ」を全体で1つのユニットとする形に改め、高木ブーとモーニング娘。 の例を追加。§4 に「トラック単位の補正(data/inputs/track-corrections.json)」を新設(MorningStatusApp#1706, morning-status-blume#178) |
| 1.9 | 2026-10-03 | 【v11.3.0(MorningStatusApp#1704)】§4「名義(artist-credit)の解釈」に、ユニット名と一致する連続したアーティストの並びを1つの主体にまとめる規則(空白と +・+ の表記ゆれの吸収、ソロアーティストへの紐づけでは並びを構成する各アーティストの MBID でも照合することを含む)と、その名義の例を追加(MorningStatusApp#1681, morning-status-blume#174) |
| 1.8 | 2026-10-02 | 【v11.2.1(MorningStatusApp#1697)】§4に「名義(artist-credit)の解釈」を追加し、Track.artist・unitId・artistMbid の定義を、結合句で解釈した名義・主体に合わせて更新(MorningStatusApp#1697, #1690, #1696) |
| 1.7 | 2026-05-28 | Track インターフェースから shortsRefetchRequested フィールドを削除(Neon スキーマ削除 #950) |
| 1.6 | 2026-05-10 | Track インターフェースに artist・unitId・artistMbid フィールドを追記(Neon スキーマ追加 #853 に合わせてドキュメントを実態と一致させる) |
| 1.5 | 2026-05-06 | youtube-short 取得上限を 3 → 10 件に拡大し Instrumental を除外対象に追加(#828)。syncTrackShortLinks に shortsRefetchRequested フラグ駆動の再取得ロジックを追加(#823) |
| 1.4 | 2026-05-06 | Track インターフェースに shortsRefetchRequested フラグを追加(#824) |
| 1.3 | 2026-05-06 | ExternalLinkType に youtube-short を追加し、付与元ごとの一覧表を §4 に整備(#774) |
| 1.2 | 2026-03-19 | PlaylistEntry.trackId 仕様を §7 に追加(PR #353 レビュー指摘) |
| 1.1 | 2026-03-19 | ExternalLink 型を使った Track.links 設計を §4 に追加(#362・#363) |
| 1.0 | 2026-03-03 | 初版作成(#338) |