music indexer: add disc number to each track (from ID3 TPOS)
ffprobe surfaces ID3 TPOS as the `disc` tag ("n" or "n/total"); parse the leading
number → IndexTrack.disc?: number in meta.json (undefined when absent/unparseable),
alongside `track`. Verified on Pink Floyd - The Wall (Disc 1 → 1, Disc 2 → 2).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import { homedir } from 'node:os';
|
||||
// (relative to the Music root):
|
||||
//
|
||||
// DATA_PATH/music/cache/<rel>/meta.json { path, cover?, tracks: [{ file, title, artist, albumArtist,
|
||||
// album, track, year, durationSec, lyrics?:'lrc'|'txt' }],
|
||||
// album, track, disc?, year, durationSec, lyrics?:'lrc'|'txt' }],
|
||||
// videos?: [{ file, title, durationSec, width, height, poster? }],
|
||||
// images?: [{ file }] } (phone IndexMeta schema)
|
||||
// DATA_PATH/music/cache/<rel>/cover.jpg compressed (<=600px, jpeg q5)
|
||||
@@ -89,6 +89,7 @@ export type IndexTrack = {
|
||||
albumArtist?: string;
|
||||
album?: string;
|
||||
track?: string;
|
||||
disc?: number; // disc / part-of-set number, from ID3 TPOS (the `disc` tag "n" or "n/total")
|
||||
year?: string;
|
||||
durationSec?: number;
|
||||
lyrics?: 'lrc' | 'txt'; // available lyrics format ('lrc' = synced/timestamped); text via /lyrics. Absent = none.
|
||||
@@ -344,6 +345,8 @@ async function ffprobeTrack(absPath: string, file: string): Promise<{ track: Ind
|
||||
for (const [k, val] of Object.entries(fmt.tags ?? {})) tags[k.toLowerCase()] = val;
|
||||
const durNum = fmt.duration ? Math.round(parseFloat(fmt.duration)) : undefined;
|
||||
const yearMatch = tags.date?.match(/\d{4}/);
|
||||
// Disc / part-of-set from ID3 TPOS (ffprobe surfaces it as `disc`, "n" or "n/total").
|
||||
const discNum = tags.disc ? parseInt(tags.disc.split('/')[0]!.trim(), 10) : NaN;
|
||||
// Embedded lyrics: USLT/foobar keys — `lyrics`, `lyrics-<lang>`, `unsyncedlyrics`.
|
||||
let lyricsText: string | undefined;
|
||||
for (const [k, val] of Object.entries(tags)) {
|
||||
@@ -360,6 +363,7 @@ async function ffprobeTrack(absPath: string, file: string): Promise<{ track: Ind
|
||||
albumArtist: tags.album_artist || tags.albumartist || undefined,
|
||||
album: tags.album || undefined,
|
||||
track: tags.track || undefined,
|
||||
disc: Number.isFinite(discNum) ? discNum : undefined,
|
||||
year: yearMatch ? yearMatch[0] : undefined,
|
||||
durationSec: Number.isFinite(durNum) ? durNum : undefined,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user