Raise artist discography limit from 50 to 200 with Deezer pagination
Deezer and iTunes defaulted to 50 albums max, silently truncating large discographies. Deezer now paginates (100 per page) up to 200. iTunes raised to 200 (single call). All callers in web_server.py updated to use the new defaults instead of hardcoding limit=50. Also adds diagnostic logging for allow_duplicates album comparison to help debug inconsistent singles behavior.
This commit is contained in:
parent
b4cf8b4cc1
commit
0edd8f5c81
4 changed files with 39 additions and 25 deletions
|
|
@ -635,26 +635,37 @@ class DeezerClient:
|
|||
'_raw_data': artist_data
|
||||
}
|
||||
|
||||
def get_artist_albums_list(self, artist_id: str, album_type: str = 'album,single', limit: int = 50) -> List[Album]:
|
||||
def get_artist_albums_list(self, artist_id: str, album_type: str = 'album,single', limit: int = 200) -> List[Album]:
|
||||
"""Get albums by artist ID — returns Album dataclass list (metadata source interface).
|
||||
|
||||
Matches iTunesClient.get_artist_albums() interface."""
|
||||
data = self._api_get(f'artist/{artist_id}/albums', {'limit': min(limit, 100)})
|
||||
if not data or 'data' not in data:
|
||||
return []
|
||||
|
||||
Matches iTunesClient.get_artist_albums() interface.
|
||||
Paginates through all results up to the requested limit."""
|
||||
albums = []
|
||||
all_raw = []
|
||||
requested_types = [t.strip() for t in album_type.split(',')]
|
||||
offset = 0
|
||||
page_size = 100 # Deezer API max per request
|
||||
|
||||
for album_data in data['data']:
|
||||
album = Album.from_deezer_album(album_data)
|
||||
while offset < limit:
|
||||
fetch_limit = min(page_size, limit - offset)
|
||||
data = self._api_get(f'artist/{artist_id}/albums', {'limit': fetch_limit, 'index': offset})
|
||||
if not data or 'data' not in data or len(data['data']) == 0:
|
||||
break
|
||||
|
||||
if album_type != 'album,single':
|
||||
if album.album_type not in requested_types:
|
||||
if not (album.album_type == 'ep' and 'single' in requested_types):
|
||||
continue
|
||||
for album_data in data['data']:
|
||||
all_raw.append(album_data)
|
||||
album = Album.from_deezer_album(album_data)
|
||||
|
||||
albums.append(album)
|
||||
if album_type != 'album,single':
|
||||
if album.album_type not in requested_types:
|
||||
if not (album.album_type == 'ep' and 'single' in requested_types):
|
||||
continue
|
||||
|
||||
albums.append(album)
|
||||
|
||||
if len(data['data']) < fetch_limit:
|
||||
break # Last page
|
||||
offset += len(data['data'])
|
||||
|
||||
cache = get_metadata_cache()
|
||||
# Deezer's /artist/{id}/albums endpoint doesn't include artist info on each album.
|
||||
|
|
@ -663,7 +674,7 @@ class DeezerClient:
|
|||
if albums and albums[0].artists:
|
||||
artist_stub = {'id': int(artist_id) if artist_id.isdigit() else 0, 'name': albums[0].artists[0]}
|
||||
entries = []
|
||||
for ad in data['data']:
|
||||
for ad in all_raw:
|
||||
if ad.get('id'):
|
||||
if artist_stub and not ad.get('artist'):
|
||||
ad['artist'] = artist_stub
|
||||
|
|
|
|||
|
|
@ -991,7 +991,7 @@ class iTunesClient:
|
|||
|
||||
return None
|
||||
|
||||
def get_artist_albums(self, artist_id: str, album_type: str = 'album,single', limit: int = 50) -> List[Album]:
|
||||
def get_artist_albums(self, artist_id: str, album_type: str = 'album,single', limit: int = 200) -> List[Album]:
|
||||
"""
|
||||
Get albums by artist ID
|
||||
|
||||
|
|
|
|||
|
|
@ -1542,10 +1542,13 @@ class WatchlistScanner:
|
|||
from difflib import SequenceMatcher
|
||||
album_sim = SequenceMatcher(None, album_name.lower(), lib_album.lower()).ratio()
|
||||
if album_sim < 0.85:
|
||||
logger.debug(f"Track found but different album (allow_duplicates=True): '{original_title}' — library: '{lib_album}', wanted: '{album_name}'")
|
||||
logger.info(f"[AllowDup] Different album — allowing: '{original_title}' (wanted: '{album_name}', library: '{lib_album}', sim: {album_sim:.2f})")
|
||||
continue # Different album — allow it
|
||||
else:
|
||||
logger.info(f"[AllowDup] Same album — skipping: '{original_title}' (wanted: '{album_name}', library: '{lib_album}', sim: {album_sim:.2f})")
|
||||
else:
|
||||
# No album info in library — can't compare, allow it
|
||||
logger.info(f"[AllowDup] No album info in library — allowing: '{original_title}'")
|
||||
continue
|
||||
logger.debug(f"Track found in library: '{original_title}' by '{artist_name}' (confidence: {confidence:.2f})")
|
||||
return False # Track exists in library
|
||||
|
|
|
|||
|
|
@ -10458,17 +10458,17 @@ def get_artist_discography(artist_id):
|
|||
active_source = 'spotify'
|
||||
elif source_override == 'itunes':
|
||||
itunes_cl = _get_itunes_client()
|
||||
albums = itunes_cl.get_artist_albums(artist_id, album_type='album,single', limit=50)
|
||||
albums = itunes_cl.get_artist_albums(artist_id, album_type='album,single')
|
||||
if albums:
|
||||
active_source = 'itunes'
|
||||
elif source_override == 'deezer':
|
||||
deezer_cl = _get_deezer_client()
|
||||
albums = deezer_cl.get_artist_albums(artist_id, album_type='album,single', limit=50)
|
||||
albums = deezer_cl.get_artist_albums(artist_id, album_type='album,single')
|
||||
if albums:
|
||||
active_source = 'deezer'
|
||||
elif source_override == 'discogs':
|
||||
discogs_cl = _get_discogs_client()
|
||||
albums = discogs_cl.get_artist_albums(artist_id, album_type='album,single', limit=50)
|
||||
albums = discogs_cl.get_artist_albums(artist_id, album_type='album,single')
|
||||
if albums:
|
||||
active_source = 'discogs'
|
||||
elif source_override == 'hydrabase':
|
||||
|
|
@ -10479,7 +10479,7 @@ def get_artist_discography(artist_id):
|
|||
hb_cl = _get_itunes_client()
|
||||
else:
|
||||
hb_cl = spotify_client
|
||||
albums = hb_cl.get_artist_albums(artist_id, album_type='album,single', limit=50)
|
||||
albums = hb_cl.get_artist_albums(artist_id, album_type='album,single')
|
||||
if albums:
|
||||
active_source = plugin or 'hydrabase'
|
||||
|
||||
|
|
@ -10506,7 +10506,7 @@ def get_artist_discography(artist_id):
|
|||
search_artists = cl.search_artists(artist_name, limit=5)
|
||||
if search_artists:
|
||||
best = next((a for a in search_artists if a.name.lower() == artist_name.lower()), search_artists[0])
|
||||
albums = cl.get_artist_albums(best.id, album_type='album,single', limit=50)
|
||||
albums = cl.get_artist_albums(best.id, album_type='album,single')
|
||||
if albums:
|
||||
active_source = source_override
|
||||
|
||||
|
|
@ -10544,7 +10544,7 @@ def get_artist_discography(artist_id):
|
|||
try:
|
||||
if is_numeric_id:
|
||||
# It's a numeric ID (iTunes/Deezer), use directly
|
||||
albums = fallback_client.get_artist_albums(artist_id, album_type='album,single', limit=50)
|
||||
albums = fallback_client.get_artist_albums(artist_id, album_type='album,single')
|
||||
if albums:
|
||||
active_source = fallback_source
|
||||
print(f"Got {len(albums)} albums from {fallback_source} (direct ID)")
|
||||
|
|
@ -10563,7 +10563,7 @@ def get_artist_discography(artist_id):
|
|||
best_match = fallback_artists[0]
|
||||
|
||||
print(f"Found {fallback_source} artist: {best_match.name} (ID: {best_match.id})")
|
||||
albums = fallback_client.get_artist_albums(best_match.id, album_type='album,single', limit=50)
|
||||
albums = fallback_client.get_artist_albums(best_match.id, album_type='album,single')
|
||||
if albums:
|
||||
active_source = fallback_source
|
||||
print(f"Got {len(albums)} albums from {fallback_source} (name search)")
|
||||
|
|
@ -48064,7 +48064,7 @@ def playlist_explorer_build_tree():
|
|||
try:
|
||||
# skip_cache only supported by spotify_client — other clients don't cache this call
|
||||
_skip = {'skip_cache': True} if hasattr(active_client, 'sp') else {}
|
||||
all_albums = active_client.get_artist_albums(artist_id, album_type='album,single', limit=50, **_skip)
|
||||
all_albums = active_client.get_artist_albums(artist_id, album_type='album,single', **_skip)
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': f'Album fetch failed: {e}'}
|
||||
|
||||
|
|
@ -49269,7 +49269,7 @@ def get_spotify_artist_discography(artist_name):
|
|||
print(f"Found Spotify artist: {artist.name} (ID: {spotify_artist_id}, confidence: {highest_score:.3f})")
|
||||
|
||||
# Get all albums (albums, singles, and compilations)
|
||||
all_albums = spotify_client.get_artist_albums(spotify_artist_id, album_type='album,single,compilation', limit=50)
|
||||
all_albums = spotify_client.get_artist_albums(spotify_artist_id, album_type='album,single,compilation')
|
||||
|
||||
if not all_albums:
|
||||
return {
|
||||
|
|
|
|||
Loading…
Reference in a new issue