Use new Spotify /items endpoint with fallback
Add _get_playlist_items_page to call the new playlists/{id}/items endpoint (Feb 2026 API migration) and fall back to spotipy.playlist_items (old /tracks) on 403/404. Update _get_playlist_tracks and web_server.get_playlist_tracks to use the new helper to avoid 403 errors for Development Mode apps while preserving compatibility with Extended Quota Mode.
This commit is contained in:
parent
58df2ba33c
commit
2aa529f8e4
2 changed files with 29 additions and 7 deletions
|
|
@ -505,15 +505,37 @@ class SpotifyClient:
|
|||
logger.error(f"Error fetching saved tracks: {e}")
|
||||
return []
|
||||
|
||||
def _get_playlist_items_page(self, playlist_id: str, limit: int = 100, offset: int = 0) -> dict:
|
||||
"""Fetch playlist items using the /items endpoint (Feb 2026 Spotify API migration).
|
||||
|
||||
Spotipy's playlist_items() still uses the deprecated /tracks endpoint internally,
|
||||
which returns 403 for Development Mode apps after the Feb 2026 API changes.
|
||||
Tries the new /items endpoint first, falls back to spotipy's /tracks for
|
||||
Extended Quota Mode apps where /items may not be available yet.
|
||||
"""
|
||||
plid = self.sp._get_id("playlist", playlist_id)
|
||||
try:
|
||||
return self.sp._get(
|
||||
f"playlists/{plid}/items",
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
additional_types="track,episode"
|
||||
)
|
||||
except spotipy.SpotifyException as e:
|
||||
if e.http_status in (403, 404):
|
||||
# /items not available — fall back to old /tracks endpoint
|
||||
return self.sp.playlist_items(playlist_id, limit=limit, offset=offset)
|
||||
raise
|
||||
|
||||
@rate_limited
|
||||
def _get_playlist_tracks(self, playlist_id: str) -> List[Track]:
|
||||
if not self.is_spotify_authenticated():
|
||||
return []
|
||||
|
||||
|
||||
tracks = []
|
||||
|
||||
|
||||
try:
|
||||
results = self.sp.playlist_items(playlist_id, limit=100)
|
||||
results = self._get_playlist_items_page(playlist_id, limit=100)
|
||||
|
||||
while results:
|
||||
for item in results['items']:
|
||||
|
|
@ -522,11 +544,11 @@ class SpotifyClient:
|
|||
if track_data and track_data.get('id'):
|
||||
track = Track.from_spotify_track(track_data)
|
||||
tracks.append(track)
|
||||
|
||||
|
||||
results = self.sp.next(results) if results['next'] else None
|
||||
|
||||
|
||||
return tracks
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching playlist tracks: {e}")
|
||||
return []
|
||||
|
|
|
|||
|
|
@ -16396,7 +16396,7 @@ def get_playlist_tracks(playlist_id):
|
|||
|
||||
# Fetch all tracks with full album data
|
||||
tracks = []
|
||||
results = spotify_client.sp.playlist_items(playlist_id, limit=100)
|
||||
results = spotify_client._get_playlist_items_page(playlist_id, limit=100)
|
||||
|
||||
while results:
|
||||
for item in results['items']:
|
||||
|
|
|
|||
Loading…
Reference in a new issue