Fix album 404 on library page when Spotify is rate limited
_resolve_db_album_id was missing deezer_album_id from stored ID checks and hardcoded Spotify for the name-based search fallback. When Spotify was rate limited (common for new Navidrome users), no fallback was tried and the album returned 404. Now checks all stored IDs (spotify, deezer, itunes, discogs) in priority order matching the active metadata source, and falls back through all available sources for name-based search instead of only Spotify.
This commit is contained in:
parent
0380e88bb0
commit
abb08efe74
1 changed files with 37 additions and 26 deletions
|
|
@ -11353,19 +11353,20 @@ def get_artist_discography(artist_id):
|
|||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
def _resolve_db_album_id(album_id, artist_id=None):
|
||||
"""Resolve a database album ID to a real Spotify/iTunes album ID.
|
||||
"""Resolve a database album ID to a real external album ID.
|
||||
|
||||
When the artist detail page falls back to owned_releases (Spotify artist
|
||||
search failed), the album cards carry a database auto-increment ID.
|
||||
This helper looks up stored external IDs first, then falls back to an
|
||||
iTunes/Spotify search by album title + artist name.
|
||||
When the artist detail page falls back to owned_releases, the album cards
|
||||
carry a database ID. This helper looks up stored external IDs first, then
|
||||
falls back to a search by album title + artist name using the primary
|
||||
metadata source (with fallback to other sources).
|
||||
"""
|
||||
try:
|
||||
database = get_database()
|
||||
with database._get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
SELECT a.title, a.spotify_album_id, a.itunes_album_id, a.discogs_id, ar.name as artist_name
|
||||
SELECT a.title, a.spotify_album_id, a.itunes_album_id, a.discogs_id,
|
||||
a.deezer_album_id, ar.name as artist_name
|
||||
FROM albums a
|
||||
JOIN artists ar ON a.artist_id = ar.id
|
||||
WHERE a.id = ?
|
||||
|
|
@ -11374,32 +11375,42 @@ def _resolve_db_album_id(album_id, artist_id=None):
|
|||
if not row:
|
||||
return None
|
||||
|
||||
# Prefer stored external IDs — match the active fallback source
|
||||
# Prefer stored external IDs — match the active primary source first
|
||||
fallback = _get_metadata_fallback_source()
|
||||
if fallback == 'discogs' and row.get('discogs_id'):
|
||||
return row['discogs_id']
|
||||
if row['spotify_album_id']:
|
||||
return row['spotify_album_id']
|
||||
if row['itunes_album_id']:
|
||||
return row['itunes_album_id']
|
||||
if row.get('discogs_id'):
|
||||
return row['discogs_id']
|
||||
id_priority = {
|
||||
'spotify': [('spotify_album_id', None), ('deezer_album_id', None), ('itunes_album_id', None), ('discogs_id', None)],
|
||||
'deezer': [('deezer_album_id', None), ('spotify_album_id', None), ('itunes_album_id', None), ('discogs_id', None)],
|
||||
'itunes': [('itunes_album_id', None), ('spotify_album_id', None), ('deezer_album_id', None), ('discogs_id', None)],
|
||||
'discogs': [('discogs_id', None), ('spotify_album_id', None), ('deezer_album_id', None), ('itunes_album_id', None)],
|
||||
}
|
||||
for col, _ in id_priority.get(fallback, id_priority['spotify']):
|
||||
val = row[col] if col in row.keys() else None
|
||||
if val:
|
||||
return val
|
||||
|
||||
# No stored external ID — search by name
|
||||
# No stored external ID — search by name using primary source with fallback
|
||||
album_title = row['title']
|
||||
artist_name = row['artist_name']
|
||||
query = f"{artist_name} {album_title}"
|
||||
logger.debug("Searching for album by name: %s", query)
|
||||
results = spotify_client.search_albums(query, limit=5)
|
||||
if results:
|
||||
# Pick the best match (search already ranks by relevance)
|
||||
for album in results:
|
||||
if album.name.lower().strip() == album_title.lower().strip():
|
||||
logger.debug("Found exact album match: %s (id=%s)", album.name, album.id)
|
||||
return album.id
|
||||
# Fall back to first result if no exact title match
|
||||
logger.debug("No exact match, using best result: %s (id=%s)", results[0].name, results[0].id)
|
||||
return results[0].id
|
||||
|
||||
from core.metadata_service import get_source_priority, get_client_for_source
|
||||
for source in get_source_priority(fallback):
|
||||
try:
|
||||
client = get_client_for_source(source)
|
||||
if not client:
|
||||
continue
|
||||
results = client.search_albums(query, limit=5)
|
||||
if results:
|
||||
for album in results:
|
||||
if album.name.lower().strip() == album_title.lower().strip():
|
||||
logger.debug("Found exact album match via %s: %s (id=%s)", source, album.name, album.id)
|
||||
return album.id
|
||||
logger.debug("No exact match via %s, using best result: %s (id=%s)", source, results[0].name, results[0].id)
|
||||
return results[0].id
|
||||
except Exception as e:
|
||||
logger.debug("Album search via %s failed: %s", source, e)
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
logger.debug("Error resolving DB album ID %s: %s", album_id, e)
|
||||
|
|
|
|||
Loading…
Reference in a new issue