Cover Art Filler: write cover.jpg to the RESOLVED folder, not the raw DB path (Sokhi — the actual bug)

THE bug behind "embeds art but never writes cover.jpgs": _fix_missing_cover_art
passed `details['album_folder']` (= dirname of the raw DB path, e.g. Jellyfin's
/data/music/...) as the target folder. That path doesn't exist inside the
SoulSync container — only the resolved /app/... path does. So apply_art_to_album_
files' `os.path.isdir(target_dir)` was False and the ENTIRE cover.jpg block was
silently skipped: embedding still worked (it uses the resolved paths) and the DB
thumb updated, but the sidecar was never written. Exactly Sokhi's symptom + the
"Cover art already present — database thumbnail updated" toast (cover_written
stayed False).

Fix:
- _fix_missing_cover_art: derive the folder from the RESOLVED file
  (os.path.dirname(resolved[0])), never the raw album_folder.
- apply_art_to_album_files: bulletproof it — if the passed folder doesn't exist,
  fall back to the real directory of the files instead of silently skipping.

Tests: a non-existent folder still writes cover.jpg to the real file dir. 1348
cover/art/repair tests pass.
This commit is contained in:
BoulderBadgeDad 2026-06-08 18:25:50 -07:00
parent 2f3ade8acb
commit 13dca2dea6
3 changed files with 37 additions and 3 deletions

View file

@ -198,8 +198,15 @@ def apply_art_to_album_files(
logger.warning("Could not embed art into %s: %s", fp, exc) logger.warning("Could not embed art into %s: %s", fp, exc)
result["failed"] += 1 result["failed"] += 1
target_dir = folder or (os.path.dirname(paths[0]) if paths else None) # Prefer the caller's folder, but if it doesn't actually exist (e.g. a raw
if target_dir and os.path.isdir(target_dir) and not folder_has_cover_sidecar(target_dir): # DB path that isn't mounted in this container), fall back to the real
# directory of the files we just wrote to — never silently skip the sidecar
# because a passed-in folder was wrong (Sokhi: cover.jpg never written).
target_dir = folder if (folder and os.path.isdir(folder)) else None
if not target_dir and paths:
cand = os.path.dirname(paths[0])
target_dir = cand if os.path.isdir(cand) else None
if target_dir and not folder_has_cover_sidecar(target_dir):
# Prefer the album's OWN embedded art for the cover.jpg sidecar: it's # Prefer the album's OWN embedded art for the cover.jpg sidecar: it's
# always present once the files are arted (we may have just embedded it), # always present once the files are arted (we may have just embedded it),
# needs no API call, and the sidecar matches the files exactly # needs no API call, and the sidecar matches the files exactly

View file

@ -1394,7 +1394,14 @@ class RepairWorker:
'album_name': album_title, 'album_image_url': artwork_url, 'album_name': album_title, 'album_image_url': artwork_url,
'musicbrainz_release_id': mbid, 'musicbrainz_release_id': mbid,
} }
folder = details.get('album_folder') or os.path.dirname(resolved[0]) # Use the RESOLVED file's directory — NOT details['album_folder'], which
# is the raw DB path (e.g. Jellyfin's /data/music) and frequently does
# NOT exist inside the SoulSync container (only the resolved /app/...
# path does). Passing the raw folder made os.path.isdir() fail in
# apply_art_to_album_files, silently skipping the cover.jpg write while
# embedding (which uses the resolved paths) still worked — Sokhi's
# "embeds art but never writes cover.jpgs".
folder = os.path.dirname(resolved[0])
art_result = apply_art_to_album_files(resolved, metadata, album_info, folder=folder) art_result = apply_art_to_album_files(resolved, metadata, album_info, folder=folder)
embedded = art_result.get('embedded', 0) embedded = art_result.get('embedded', 0)

View file

@ -314,3 +314,23 @@ def test_apply_skips_cover_when_sidecar_exists(tmp_path, monkeypatch):
aa.apply_art_to_album_files([str(f)], {}, {}, folder=str(tmp_path)) aa.apply_art_to_album_files([str(f)], {}, {}, folder=str(tmp_path))
assert (tmp_path / 'cover.jpg').read_bytes() == b'EXISTING' # untouched assert (tmp_path / 'cover.jpg').read_bytes() == b'EXISTING' # untouched
assert dl_called == [] assert dl_called == []
def test_apply_cover_falls_back_to_file_dir_when_folder_doesnt_exist(tmp_path, monkeypatch):
# The Sokhi bug: the caller passed the raw DB folder (e.g. Jellyfin's
# /data/music/...) which doesn't exist in the container, so the cover.jpg
# write was silently skipped. Now it falls back to the real directory of
# the files and writes there anyway.
real_dir = tmp_path / 'real'
real_dir.mkdir()
f = real_dir / '01.flac'; f.write_bytes(b'')
audio = SimpleNamespace(pictures=[SimpleNamespace(data=b'EMB')], tags=None, save=lambda: None)
monkeypatch.setattr(aa, 'get_mutagen_symbols', lambda: _fake_symbols(audio))
monkeypatch.setattr(aa, 'embed_album_art_metadata', lambda *a, **k: True)
monkeypatch.setattr(aa, 'download_cover_art', lambda *a, **k: None)
res = aa.apply_art_to_album_files([str(f)], {}, {},
folder='/data/music/does/not/exist/in/container')
assert (real_dir / 'cover.jpg').read_bytes() == b'EMB' # written to the REAL dir
assert res['cover_written'] is True