From 4d3c17b2df116ab9d067fd1e307041ec57dfcb4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Mon, 27 Jul 2026 14:59:08 +0000 Subject: [PATCH] =?UTF-8?q?music=20indexer:=20cache-format=20version=20?= =?UTF-8?q?=E2=86=92=20full=20rebuild=20for=20posters/lyrics=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Videos/tracks indexed before posters+lyrics existed were skipped by the per-album `v` check (unchanged v → skip), so their posters/ and lyrics/ never generated — a plain reindex couldn't fix it. Add CACHE_VERSION (now 2). The `v` skip is only trusted when the on-disk manifest is already at the current format; an older version forces a one-time FULL rebuild that regenerates every album (incl. the new posters/lyrics), then writes version:2 so subsequent builds skip normally. Verified: old-cache rebuild regenerates the poster, next build skips (no loop). Deploy = restart officer-music, then one reindex (a full rebuild, slower than an incremental — one time only). Co-Authored-By: Claude Opus 4.8 --- src/servers/sidecar/music/indexer.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/servers/sidecar/music/indexer.ts b/src/servers/sidecar/music/indexer.ts index 63b7ad5f..e53a64d4 100644 --- a/src/servers/sidecar/music/indexer.ts +++ b/src/servers/sidecar/music/indexer.ts @@ -34,6 +34,11 @@ const COVER_FILES = ['folder.jpg', 'cover.jpg', 'folder.png', 'cover.png']; const DISCO_FILE = '_discography.md'; const TRACK_CONCURRENCY = 6; const COVER_MAX_PX = 600; +// Cache-format version. Bump when the build produces NEW per-album outputs (so far: v2 added video +// posters + lyrics). A manifest written by an older CACHE_VERSION forces a one-time FULL rebuild — the +// per-album `v` skip only applies once the cache is already at the current format. +// v1 → initial (meta + cover) v2 → + posters/ + lyrics/ +const CACHE_VERSION = 2; // ── Types (meta.json matches the app's IndexMeta/IndexTrack) ── @@ -445,7 +450,7 @@ export async function buildMusicIndex(): Promise { console.log('[music] resync started'); const prev = await loadManifest(); - const next: Manifest = { version: 1, generatedAt: status.startedAt!, albums: {} }; + const next: Manifest = { version: CACHE_VERSION, generatedAt: status.startedAt!, albums: {} }; try { await mkdir(CACHE_ROOT, { recursive: true }); @@ -584,7 +589,10 @@ async function walk(dirAbs: string, prev: Manifest, next: Manifest): Promise f !== null); const outputsExist = expected.every((f) => existsSync(join(cacheDir, f))); - if (prev.albums[rel]?.v === v && outputsExist) { + // Only trust the per-album `v` skip once the cache is already at the current format — an older + // CACHE_VERSION means new outputs (posters/lyrics) may be missing, so rebuild every folder once. + const formatCurrent = prev.version === CACHE_VERSION; + if (formatCurrent && prev.albums[rel]?.v === v && outputsExist) { status.albumsSkipped += 1; } else { await mkdir(cacheDir, { recursive: true });