From 62da95988941912a0ac85e7577ab6fd66b44de2f Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Tue, 31 Mar 2026 21:51:10 -0700 Subject: [PATCH] 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. --- core/spotify_client.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/core/spotify_client.py b/core/spotify_client.py index 13b98b88..3603e324 100644 --- a/core/spotify_client.py +++ b/core/spotify_client.py @@ -1307,6 +1307,18 @@ class SpotifyClient: @rate_limited 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""" + # 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(): try: albums = [] @@ -1324,11 +1336,13 @@ class SpotifyClient: logger.info(f"Retrieved {len(albums)} albums for artist {artist_id}") - # Cache individual albums opportunistically (skip if full data already cached) - cache = get_metadata_cache() - 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) + # Cache the full artist albums result + if raw_items: + cache.store_entity('spotify', 'artist', cache_key, raw_items) + # Also cache individual albums opportunistically + 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 @@ -1339,7 +1353,7 @@ class SpotifyClient: # Fallback - only if ID is numeric (non-Spotify format) 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) else: logger.debug(f"Cannot use fallback for Spotify artist ID: {artist_id}")