From 2c2c006f832cfa9b57ce4c70875c312c9aae78fe Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Wed, 18 Mar 2026 14:23:53 -0700 Subject: [PATCH] Fix wishlisted tracks showing 'Unknown Album' with no cover art Multiple code paths built wishlist album data as a bare string instead of a dict with images/album_type/total_tracks, causing wishlist entries to lose album name and artwork. Fixed in: Beatport fallback conversion, sync normalization, _ensure_spotify_track_format, and wishlist service track reconstruction. Now uses track name as album fallback and always includes required album dict keys. --- core/wishlist_service.py | 15 ++++++++------- web_server.py | 34 +++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/core/wishlist_service.py b/core/wishlist_service.py index a9acc4b8..b48e8ba5 100644 --- a/core/wishlist_service.py +++ b/core/wishlist_service.py @@ -290,14 +290,14 @@ class WishlistService: # Look for Spotify metadata in the result if hasattr(slskd_result, 'artist') and hasattr(slskd_result, 'title'): - # Reconstruct basic Spotify track structure + album_name = getattr(slskd_result, 'album', '') or getattr(slskd_result, 'title', 'Unknown Album') return { 'id': f"reconstructed_{hash(f'{slskd_result.artist}_{slskd_result.title}')}", 'name': getattr(slskd_result, 'title', 'Unknown Track'), 'artists': [{'name': getattr(slskd_result, 'artist', 'Unknown Artist')}], - 'album': {'name': getattr(slskd_result, 'album', 'Unknown Album')}, - 'duration_ms': 0, # Unknown - 'reconstructed': True # Mark as reconstructed data + 'album': {'name': album_name, 'images': [], 'album_type': 'single', 'total_tracks': 1}, + 'duration_ms': 0, + 'reconstructed': True } # If no Spotify data found, try to reconstruct from available info @@ -321,16 +321,17 @@ class WishlistService: if hasattr(spotify_track, 'title') and hasattr(spotify_track, 'artist') and not hasattr(spotify_track, 'id'): logger.info("DEBUG: Detected TrackResult object, converting...") # Handle TrackResult objects - these don't have Spotify IDs + album_name = getattr(spotify_track, 'album', '') or getattr(spotify_track, 'title', 'Unknown Album') result = { 'id': f"trackresult_{hash(f'{spotify_track.artist}_{spotify_track.title}')}", 'name': getattr(spotify_track, 'title', 'Unknown Track'), 'artists': [{'name': getattr(spotify_track, 'artist', 'Unknown Artist')}], - 'album': {'name': getattr(spotify_track, 'album', 'Unknown Album')}, - 'duration_ms': 0, # TrackResult doesn't have duration + 'album': {'name': album_name, 'images': [], 'album_type': 'single', 'total_tracks': 1}, + 'duration_ms': 0, 'preview_url': None, 'external_urls': {}, 'popularity': 0, - 'source': 'trackresult' # Mark as reconstructed from TrackResult + 'source': 'trackresult' } logger.info(f"DEBUG: TrackResult converted successfully: {result['name']} by {result['artists'][0]['name']}") return result diff --git a/web_server.py b/web_server.py index 2142ba19..2bce2b2a 100644 --- a/web_server.py +++ b/web_server.py @@ -20758,8 +20758,14 @@ def _ensure_spotify_track_format(track_info): album.setdefault('name', 'Unknown Album') else: album = { - 'name': str(album_data) if album_data else 'Unknown Album' + 'name': str(album_data) if album_data else track_info.get('name', 'Unknown Album'), + 'album_type': 'single', + 'total_tracks': 1, + 'release_date': '', } + album.setdefault('images', []) + album.setdefault('album_type', 'album') + album.setdefault('total_tracks', 0) # Build proper Spotify track structure spotify_track = { @@ -29494,12 +29500,22 @@ def _run_sync_task(playlist_id, playlist_name, tracks_json, automation_id=None): track_id = t.get('id', '') if track_id: normalized = dict(t) - # Normalize album to dict format + # Normalize album to dict format, preserving images and metadata raw_album = normalized.get('album', '') if isinstance(raw_album, str): - normalized['album'] = {'name': raw_album} if raw_album else {'name': 'Unknown Album'} + normalized['album'] = { + 'name': raw_album or normalized.get('name', 'Unknown Album'), + 'images': [], 'album_type': 'single', 'total_tracks': 1, 'release_date': '' + } elif not isinstance(raw_album, dict): - normalized['album'] = {'name': str(raw_album) if raw_album else 'Unknown Album'} + normalized['album'] = { + 'name': str(raw_album) if raw_album else normalized.get('name', 'Unknown Album'), + 'images': [], 'album_type': 'single', 'total_tracks': 1, 'release_date': '' + } + else: + # Dict — ensure required keys exist + raw_album.setdefault('name', 'Unknown Album') + raw_album.setdefault('images', []) # Normalize artists to list of dicts raw_artists = normalized.get('artists', []) if raw_artists and isinstance(raw_artists[0], str): @@ -38064,11 +38080,19 @@ def convert_beatport_results_to_spotify_tracks(discovery_results): }) elif result.get('spotify_track') and result.get('status_class') == 'found': # Build from individual fields (automatic discovery format) + album_val = result.get('spotify_album', '') + album_dict = album_val if isinstance(album_val, dict) else { + 'name': album_val or result.get('spotify_track', 'Unknown Album'), + 'album_type': 'single', + 'images': [], + 'release_date': '', + 'total_tracks': 1, + } spotify_tracks.append({ 'id': result.get('spotify_id', 'unknown'), 'name': result.get('spotify_track', 'Unknown Track'), 'artists': [result.get('spotify_artist', 'Unknown Artist')] if result.get('spotify_artist') else ['Unknown Artist'], - 'album': result.get('spotify_album', 'Unknown Album'), + 'album': album_dict, 'source': 'beatport' })