summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-26 18:09:44 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-26 18:09:44 +0200
commit6fb948045b9c563ce591da289cdac1df6bed360c (patch)
tree1a783c4ed5dcf23bc65d6bb8825906473670d3aa /packages/meshbay-node/src
parent80cb6c4dc5f22336387f2ac74ef2cb85cf2cf7d4 (diff)
downloadmeshbay-6fb948045b9c563ce591da289cdac1df6bed360c.tar.gz
fix(music): stop sharing one folder's cover across unrelated tracks, and merge various-artists compilations into one album
Two real, confirmed bugs in a large flat music library: - enrich_audio.py's sibling-cover fallback assumed one folder is one release. A large flat "chart ranking" folder mixing dozens of unrelated artists carried several distinct WMP AlbumArt-cache guids (one per original album a track was ripped from), and the fallback picked whichever one WMP had copied to Folder.jpg — attaching one unrelated release's cover to every other track in the folder. Now refuses to pick a cover at all once 2+ distinct guids show up, rather than guess. - music-app.js's groupMusicEntries grouped by artist first, album second, so a various-artists compilation (many genuinely different per-track artists, one shared album tag, no album-artist tag at all — a real ~20-track soundtrack rip has exactly this shape) could never be recognized as one release: every track landed alone in its own artist's bucket and got folded into a singleton pile. Now detects an album key shared across 2+ distinct artist keys and merges those tracks into one compilation card under a "Various" heading instead. Both verified against real, previously-affected files and live in the browser: the shared wrong cover is gone, and the compilation renders as one card with all its tracks in order.
Diffstat (limited to 'packages/meshbay-node/src')
-rw-r--r--packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py17
1 files changed, 17 insertions, 0 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py b/packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py
index a93df51..4fa08ef 100644
--- a/packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py
+++ b/packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py
@@ -141,6 +141,18 @@ def _extract_cover(mf) -> bytes | None:
_COVER_STEM_RANK = ("cover", "folder", "front", "albumart")
_COVER_EXTS = (".jpg", ".jpeg", ".png")
+# Windows Media Player's per-folder thumbnail cache: one `AlbumArt_{guid}_*`
+# pair per *release* it ever cached art for in that folder, keyed by a GUID
+# tied to that release — never to a track. Real folder, real GUIDs (module
+# docstring's revision note): a ~500-track flat "chart ranking" rip mixing
+# dozens of unrelated artists carried seven distinct guids here, each an art
+# leftover from one different original album. `Folder.jpg`/`AlbumArtSmall.jpg`
+# are WMP's own copy of just *one* arbitrary one of those for the folder icon
+# — fine when a folder really is one release (one guid, or none), meaningless
+# once two or more show up: there is no way to tell which track it belongs to,
+# so no candidate in the folder can be trusted as "the" cover for any of them.
+_WMP_ALBUMART_GUID_RE = re.compile(r"^albumart_\{([0-9a-f-]{36})\}_(large|small)$", re.IGNORECASE)
+
def _find_sibling_cover(folder: Path) -> Path | None:
try:
@@ -151,6 +163,11 @@ def _find_sibling_cover(folder: Path) -> Path | None:
if not candidates:
return None
+ guids = {m.group(1).lower() for p in candidates
+ if (m := _WMP_ALBUMART_GUID_RE.match(p.stem))}
+ if len(guids) >= 2:
+ return None
+
def rank(p: Path) -> int:
stem = p.stem.lower()
for i, name in enumerate(_COVER_STEM_RANK):