Cache get_artist_albums to reduce Spotify API rate limiting
get_artist_albums was making fresh API calls on every invocation with no cache check, despite being one of the most called methods (discography views, completion badges, watchlist scans). The method already cached individual albums opportunistically but never checked for a cached result before hitting the API. Now follows the same check-then-fetch-then-cache pattern used by get_album_tracks and get_artist. Cache key includes album_type param so different queries (album,single vs compilation) are cached separately.
This commit is contained in:
parent
87f17a1318
commit
62da959889
1 changed files with 20 additions and 6 deletions
|
|
@ -1307,6 +1307,18 @@ class SpotifyClient:
|
||||||
@rate_limited
|
@rate_limited
|
||||||
def get_artist_albums(self, artist_id: str, album_type: str = 'album,single', limit: int = 10) -> List[Album]:
|
def get_artist_albums(self, artist_id: str, album_type: str = 'album,single', limit: int = 10) -> List[Album]:
|
||||||
"""Get albums by artist ID - falls back to iTunes if Spotify not authenticated"""
|
"""Get albums by artist ID - falls back to iTunes if Spotify not authenticated"""
|
||||||
|
# Check cache first — keyed by artist_id + album_type
|
||||||
|
cache = get_metadata_cache()
|
||||||
|
fallback_src = self._fallback_source
|
||||||
|
source = fallback_src if self._is_itunes_id(artist_id) else 'spotify'
|
||||||
|
cache_key = f"{artist_id}_albums_{album_type.replace(',', '_')}"
|
||||||
|
cached = cache.get_entity(source, 'artist', cache_key)
|
||||||
|
if cached:
|
||||||
|
try:
|
||||||
|
return [Album.from_spotify_album(ad) for ad in cached]
|
||||||
|
except Exception:
|
||||||
|
pass # Cache data incompatible, re-fetch
|
||||||
|
|
||||||
if self.is_spotify_authenticated():
|
if self.is_spotify_authenticated():
|
||||||
try:
|
try:
|
||||||
albums = []
|
albums = []
|
||||||
|
|
@ -1324,11 +1336,13 @@ class SpotifyClient:
|
||||||
|
|
||||||
logger.info(f"Retrieved {len(albums)} albums for artist {artist_id}")
|
logger.info(f"Retrieved {len(albums)} albums for artist {artist_id}")
|
||||||
|
|
||||||
# Cache individual albums opportunistically (skip if full data already cached)
|
# Cache the full artist albums result
|
||||||
cache = get_metadata_cache()
|
if raw_items:
|
||||||
entries = [(ad.get('id'), ad) for ad in raw_items if ad.get('id')]
|
cache.store_entity('spotify', 'artist', cache_key, raw_items)
|
||||||
if entries:
|
# Also cache individual albums opportunistically
|
||||||
cache.store_entities_bulk('spotify', 'album', entries, skip_if_exists=True)
|
entries = [(ad.get('id'), ad) for ad in raw_items if ad.get('id')]
|
||||||
|
if entries:
|
||||||
|
cache.store_entities_bulk('spotify', 'album', entries, skip_if_exists=True)
|
||||||
|
|
||||||
return albums
|
return albums
|
||||||
|
|
||||||
|
|
@ -1339,7 +1353,7 @@ class SpotifyClient:
|
||||||
|
|
||||||
# Fallback - only if ID is numeric (non-Spotify format)
|
# Fallback - only if ID is numeric (non-Spotify format)
|
||||||
if self._is_itunes_id(artist_id):
|
if self._is_itunes_id(artist_id):
|
||||||
logger.debug(f"Using {self._fallback_source} fallback for artist albums: {artist_id}")
|
logger.debug(f"Using {fallback_src} fallback for artist albums: {artist_id}")
|
||||||
return self._fallback.get_artist_albums(artist_id, album_type, limit)
|
return self._fallback.get_artist_albums(artist_id, album_type, limit)
|
||||||
else:
|
else:
|
||||||
logger.debug(f"Cannot use fallback for Spotify artist ID: {artist_id}")
|
logger.debug(f"Cannot use fallback for Spotify artist ID: {artist_id}")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue