Backfill missing watchlist artist images during scan

Runs at scan start after ID backfill — zero API calls, all DB lookups:
1. Metadata cache artist image (any source)
2. Deezer direct URL from stored deezer_artist_id
3. Deezer ID from metadata cache by name (even if not on watchlist row)
4. Album art fallback (iTunes artists have no artist images)

Also fixes update path for artists with no external IDs — falls back
to direct row ID update instead of silently matching zero rows.
This commit is contained in:
Broque Thomas 2026-04-04 21:26:25 -07:00
parent 48a9de8861
commit 4439873542

View file

@ -37495,7 +37495,85 @@ def start_watchlist_scan():
import traceback
traceback.print_exc()
# Continue with scan even if backfilling fails
# IMAGE BACKFILL — fix watchlist artists with missing images
# Uses DB-only lookups (metadata cache + album art) — no API calls
try:
conn = database._get_connection()
cursor = conn.cursor()
cursor.execute("""
SELECT id, artist_name, spotify_artist_id, itunes_artist_id,
deezer_artist_id, discogs_artist_id
FROM watchlist_artists
WHERE profile_id = ? AND (image_url IS NULL OR image_url = '' OR image_url = 'None'
OR image_url NOT LIKE 'http%')
""", (scan_profile_id,))
imageless = cursor.fetchall()
if imageless:
print(f"🖼️ Backfilling images for {len(imageless)} watchlist artists...")
filled = 0
for row in imageless:
name = row['artist_name']
nn = name.lower().strip()
img = None
# 1. Check metadata cache for artist image
cursor.execute("""
SELECT image_url FROM metadata_cache_entities
WHERE entity_type = 'artist' AND name = ? COLLATE NOCASE
AND image_url IS NOT NULL AND image_url LIKE 'http%'
LIMIT 1
""", (name,))
cr = cursor.fetchone()
if cr:
img = cr['image_url']
# 2. Deezer direct URL (no API call needed)
if not img and row['deezer_artist_id']:
img = f"https://api.deezer.com/artist/{row['deezer_artist_id']}/image?size=big"
# 3. Deezer ID from cache (artist may have a Deezer match we haven't stored on watchlist)
if not img:
cursor.execute("""
SELECT entity_id FROM metadata_cache_entities
WHERE entity_type = 'artist' AND source = 'deezer'
AND name = ? COLLATE NOCASE LIMIT 1
""", (name,))
dz = cursor.fetchone()
if dz and dz['entity_id']:
img = f"https://api.deezer.com/artist/{dz['entity_id']}/image?size=big"
# 4. Album art fallback (iTunes artists have no artist images)
if not img:
cursor.execute("""
SELECT image_url FROM metadata_cache_entities
WHERE entity_type = 'album' AND image_url LIKE 'http%'
AND artist_name = ? COLLATE NOCASE LIMIT 1
""", (name,))
alb = cursor.fetchone()
if alb:
img = alb['image_url']
if img:
aid = (row['spotify_artist_id'] or row['itunes_artist_id']
or row['deezer_artist_id'] or row['discogs_artist_id'])
if aid:
database.update_watchlist_artist_image(aid, img)
else:
# No external IDs — update by internal row ID directly
cursor.execute("""
UPDATE watchlist_artists SET image_url = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
""", (img, row['id']))
conn.commit()
filled += 1
if filled:
print(f"🖼️ Backfilled {filled}/{len(imageless)} watchlist artist images")
except Exception as img_err:
print(f"⚠️ Image backfill error: {img_err}")
# Initialize detailed progress tracking
watchlist_scan_state.update({
'total_artists': len(watchlist_artists),