From c336604b710c1191ed79cba518c57c92d1a52498 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sat, 4 Apr 2026 12:19:29 -0700 Subject: [PATCH] Fix hero slider + recommended modal returning 0 artists get_top_similar_artists now accepts require_source parameter to filter by source ID in SQL. Previously fetched 200 artists then post-filtered, but cycling logic (last_featured ASC) rotated artists without IDs to the front, causing all 200 to be filtered out. Both /api/discover/hero and /api/discover/similar-artists now pass require_source=active_source so only artists with valid IDs are returned. --- database/music_database.py | 18 ++++++++++++++---- web_server.py | 24 ++++++------------------ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/database/music_database.py b/database/music_database.py index 3e2e0eb8..9a68eaee 100644 --- a/database/music_database.py +++ b/database/music_database.py @@ -7260,13 +7260,23 @@ class MusicDatabase: logger.error(f"Error checking similar artists freshness: {e}") return False # Default to re-fetching on error - def get_top_similar_artists(self, limit: int = 50, profile_id: int = 1) -> List[SimilarArtist]: - """Get top similar artists excluding watchlist artists, with cycling support""" + def get_top_similar_artists(self, limit: int = 50, profile_id: int = 1, require_source: str = None) -> List[SimilarArtist]: + """Get top similar artists excluding watchlist artists, with cycling support. + require_source: if set ('spotify','itunes','deezer'), only returns artists with that source ID.""" try: with self._get_connection() as conn: cursor = conn.cursor() - cursor.execute(""" + # Build source filter + source_filter = '' + if require_source == 'spotify': + source_filter = "AND sa.similar_artist_spotify_id IS NOT NULL AND sa.similar_artist_spotify_id != ''" + elif require_source == 'itunes': + source_filter = "AND sa.similar_artist_itunes_id IS NOT NULL AND sa.similar_artist_itunes_id != ''" + elif require_source == 'deezer': + source_filter = "AND sa.similar_artist_deezer_id IS NOT NULL AND sa.similar_artist_deezer_id != ''" + + cursor.execute(f""" SELECT MAX(sa.id) as id, MAX(sa.source_artist_id) as source_artist_id, @@ -7287,7 +7297,7 @@ class MusicDatabase: OR (sa.similar_artist_deezer_id IS NOT NULL AND sa.similar_artist_deezer_id = wa.deezer_artist_id) OR LOWER(sa.similar_artist_name) = LOWER(wa.artist_name) ) AND wa.profile_id = ? - WHERE wa.id IS NULL AND sa.profile_id = ? + WHERE wa.id IS NULL AND sa.profile_id = ? {source_filter} GROUP BY sa.similar_artist_name ORDER BY CASE WHEN MAX(sa.last_featured) IS NULL THEN 0 ELSE 1 END, diff --git a/web_server.py b/web_server.py index 22ffa0cf..f269ce5c 100644 --- a/web_server.py +++ b/web_server.py @@ -39021,7 +39021,8 @@ def get_discover_hero(): # Get top similar artists (excluding watchlist, cycled by last_featured) # Fetch more than needed since strict source filtering may drop many pid = get_current_profile_id() - similar_artists = database.get_top_similar_artists(limit=200, profile_id=pid) + print(f"[Discover Hero] Profile ID: {pid}, Active source: {active_source}") + similar_artists = database.get_top_similar_artists(limit=200, profile_id=pid, require_source=active_source) # FALLBACK: If no similar artists exist, use watchlist artists for Hero section if not similar_artists: @@ -39067,15 +39068,8 @@ def get_discover_hero(): print(f"[Discover Hero] Returning {len(hero_artists)} watchlist artists as fallback") return jsonify({"success": True, "artists": hero_artists, "source": active_source, "fallback": "watchlist"}) - # Filter to artists that have the appropriate ID for the active source - valid_artists = [] - for artist in similar_artists: - if active_source == 'spotify' and artist.similar_artist_spotify_id: - valid_artists.append(artist) - elif active_source == 'deezer' and getattr(artist, 'similar_artist_deezer_id', None): - valid_artists.append(artist) - elif active_source == 'itunes' and artist.similar_artist_itunes_id: - valid_artists.append(artist) + # Artists are already filtered by source in SQL — no post-filter needed + valid_artists = list(similar_artists) # FALLBACK: If no valid artists for fallback source, try to resolve IDs on-the-fly if active_source in ('itunes', 'deezer') and not valid_artists: @@ -39198,20 +39192,14 @@ def get_discover_similar_artists(): database = get_database() active_source = _get_active_discovery_source() - similar_artists = database.get_top_similar_artists(limit=200, profile_id=get_current_profile_id()) + similar_artists = database.get_top_similar_artists(limit=200, profile_id=get_current_profile_id(), require_source=active_source) if not similar_artists: return jsonify({"success": True, "artists": [], "source": active_source, "count": 0}) - # Filter to artists with valid ID for active source (strict — no cross-source) + # Artists already filtered by source in SQL result_artists = [] for artist in similar_artists: - if active_source == 'spotify' and not artist.similar_artist_spotify_id: - continue - if active_source == 'deezer' and not getattr(artist, 'similar_artist_deezer_id', None) and not artist.similar_artist_itunes_id: - continue - if active_source == 'itunes' and not artist.similar_artist_itunes_id: - continue if active_source == 'spotify': artist_id = artist.similar_artist_spotify_id