mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
Spotify: gracefully handle 403 from deprecated audio-features API
Add a dedicated AudioFeaturesUnavailableError and track audio-features availability with an audio_features_available flag. If the audio-features endpoint returns HTTP 403, raise the new error, log a warning once, and disable further audio-features requests for the session. The plugin now skips attempting audio-features lookups when disabled (avoiding repeated failed calls and potential rate-limit issues). Also update changelog to document the behavior.
This commit is contained in:
parent
9608ec0925
commit
0d11e19ecf
2 changed files with 40 additions and 6 deletions
|
|
@ -77,6 +77,11 @@ class APIError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class AudioFeaturesUnavailableError(Exception):
|
||||
"""Raised when the audio features API returns 403 (deprecated/unavailable)."""
|
||||
pass
|
||||
|
||||
|
||||
class SpotifyPlugin(
|
||||
SearchApiMetadataSourcePlugin[
|
||||
Union[SearchResponseAlbums, SearchResponseTracks]
|
||||
|
|
@ -140,6 +145,7 @@ class SpotifyPlugin(
|
|||
self.config["client_id"].redact = True
|
||||
self.config["client_secret"].redact = True
|
||||
|
||||
self.audio_features_available = True # Track if audio features API is available
|
||||
self.setup()
|
||||
|
||||
def setup(self):
|
||||
|
|
@ -246,6 +252,16 @@ class SpotifyPlugin(
|
|||
f"API Error: {e.response.status_code}\n"
|
||||
f"URL: {url}\nparams: {params}"
|
||||
)
|
||||
elif e.response.status_code == 403:
|
||||
# Check if this is the audio features endpoint
|
||||
if self.audio_features_url in url:
|
||||
raise AudioFeaturesUnavailableError(
|
||||
"Audio features API returned 403 (deprecated or unavailable)"
|
||||
)
|
||||
raise APIError(
|
||||
f"API Error: {e.response.status_code}\n"
|
||||
f"URL: {url}\nparams: {params}"
|
||||
)
|
||||
elif e.response.status_code == 429:
|
||||
seconds = e.response.headers.get(
|
||||
"Retry-After", DEFAULT_WAITING_TIME
|
||||
|
|
@ -691,13 +707,18 @@ class SpotifyPlugin(
|
|||
item["isrc"] = isrc
|
||||
item["ean"] = ean
|
||||
item["upc"] = upc
|
||||
audio_features = self.track_audio_features(spotify_track_id)
|
||||
if audio_features is None:
|
||||
self._log.info("No audio features found for: {}", item)
|
||||
|
||||
if self.audio_features_available:
|
||||
audio_features = self.track_audio_features(spotify_track_id)
|
||||
if audio_features is None:
|
||||
self._log.info("No audio features found for: {}", item)
|
||||
else:
|
||||
for feature, value in audio_features.items():
|
||||
if feature in self.spotify_audio_features:
|
||||
item[self.spotify_audio_features[feature]] = value
|
||||
else:
|
||||
for feature, value in audio_features.items():
|
||||
if feature in self.spotify_audio_features:
|
||||
item[self.spotify_audio_features[feature]] = value
|
||||
self._log.debug("Audio features API unavailable, skipping")
|
||||
|
||||
item["spotify_updated"] = time.time()
|
||||
item.store()
|
||||
if write:
|
||||
|
|
@ -726,6 +747,13 @@ class SpotifyPlugin(
|
|||
return self._handle_response(
|
||||
"get", f"{self.audio_features_url}{track_id}"
|
||||
)
|
||||
except AudioFeaturesUnavailableError as e:
|
||||
self._log.warning(
|
||||
"Audio features API is unavailable (403 error). "
|
||||
"Skipping audio features for remaining tracks."
|
||||
)
|
||||
self.audio_features_available = False
|
||||
return None
|
||||
except APIError as e:
|
||||
self._log.debug("Spotify API error: {}", e)
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ New features:
|
|||
|
||||
Bug fixes:
|
||||
|
||||
- :doc:`/plugins/spotify`: The plugin now gracefully handles audio-features API
|
||||
deprecation (HTTP 403 errors). When a 403 error is encountered from the
|
||||
audio-features endpoint, the plugin logs a warning once and skips audio
|
||||
features for all remaining tracks in the session, avoiding unnecessary API
|
||||
calls and rate limit exhaustion.
|
||||
|
||||
For packagers:
|
||||
|
||||
Other changes:
|
||||
|
|
|
|||
Loading…
Reference in a new issue