Canonical findings: add artist image (guarded, schema-safe)
Findings now carry artist_thumb_url alongside album_thumb_url (same key the track-repair findings use, so the findings UI already renders it). Fetched via a guarded _lookup_artist_thumb() — checks the artists table has a thumb_url column first and swallows any error — rather than adding ar.thumb_url to the shared load_album_and_tracks SELECT. The shared-loader approach was tried first and REVERTED: it crashed reorganize on schemas whose artists table has no thumb_url column (caught by 40 orchestrator tests). The lookup only runs for albums that actually resolve, so it adds no cost to the no-source-id short-circuit majority. Tests: orchestration test asserts artist_name + album_thumb_url + artist_thumb_url flow through. 47 canonical + 104 canonical/reorganize regression tests pass.
This commit is contained in:
parent
ec8091caad
commit
03d099fb1d
2 changed files with 54 additions and 0 deletions
|
|
@ -162,6 +162,28 @@ def default_fetch_tracklist(source: str, album_id: str) -> Optional[List[Dict[st
|
|||
return out or None
|
||||
|
||||
|
||||
def _lookup_artist_thumb(db, artist_id) -> Optional[str]:
|
||||
"""Best-effort artist thumb URL by id. Returns None on missing column / any
|
||||
error (the artists table doesn't have thumb_url in every schema)."""
|
||||
if not artist_id:
|
||||
return None
|
||||
conn = None
|
||||
try:
|
||||
conn = db._get_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("PRAGMA table_info(artists)")
|
||||
if 'thumb_url' not in {r[1] for r in cursor.fetchall()}:
|
||||
return None
|
||||
cursor.execute("SELECT thumb_url FROM artists WHERE id = ?", (str(artist_id),))
|
||||
row = cursor.fetchone()
|
||||
return (row[0] or None) if row else None
|
||||
except Exception:
|
||||
return None
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
|
||||
def resolve_and_store_canonical_for_album(
|
||||
db,
|
||||
album_id,
|
||||
|
|
@ -223,6 +245,12 @@ def resolve_and_store_canonical_for_album(
|
|||
result['artist_name'] = album_data.get('artist_name') or ''
|
||||
if album_data.get('thumb_url'):
|
||||
result['album_thumb_url'] = album_data['thumb_url']
|
||||
# Artist thumb via a guarded lookup (not the shared album loader — some
|
||||
# schemas have no artists.thumb_url column). Only runs for resolved
|
||||
# albums, so no cost on the no-source-id short-circuit majority.
|
||||
artist_thumb = _lookup_artist_thumb(db, album_data.get('artist_id'))
|
||||
if artist_thumb:
|
||||
result['artist_thumb_url'] = artist_thumb
|
||||
if store:
|
||||
db.set_album_canonical(album_id, result['source'], result['album_id'], result['score'])
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -70,6 +70,32 @@ def test_default_mode_prefers_active_source(tmp_path):
|
|||
assert out["source"] == "spotify" # active source preferred
|
||||
|
||||
|
||||
def test_result_includes_artist_and_album_context(tmp_path):
|
||||
db = MusicDatabase(str(tmp_path / "m.db"))
|
||||
conn = db._get_connection()
|
||||
cur = conn.cursor()
|
||||
cur.execute("INSERT INTO artists (id, name, thumb_url) VALUES ('art1', 'Imagine Dragons', 'http://artist.jpg')")
|
||||
cur.execute(
|
||||
"INSERT INTO albums (id, title, artist_id, thumb_url, spotify_album_id) "
|
||||
"VALUES ('alb1', 'Evolve', 'art1', 'http://album.jpg', 'sp1')"
|
||||
)
|
||||
for i in range(11):
|
||||
cur.execute(
|
||||
"INSERT INTO tracks (id, album_id, artist_id, title, track_number, duration) "
|
||||
"VALUES (?, 'alb1', 'art1', ?, ?, ?)",
|
||||
(f"t{i}", f"Song {i+1}", i + 1, 180_000 + i * 10_000),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
out = resolve_and_store_canonical_for_album(
|
||||
db, "alb1", fetch_tracklist=lambda s, a: STD, source_priority=["spotify"],
|
||||
)
|
||||
assert out["artist_name"] == "Imagine Dragons"
|
||||
assert out["album_thumb_url"] == "http://album.jpg"
|
||||
assert out["artist_thumb_url"] == "http://artist.jpg"
|
||||
|
||||
|
||||
def test_resolve_returns_none_when_album_has_no_source_ids(tmp_path):
|
||||
db = MusicDatabase(str(tmp_path / "m.db"))
|
||||
album_id = _seed(db, spotify=None, deezer=None)
|
||||
|
|
|
|||
Loading…
Reference in a new issue