From 10294e18bca3bc4d13ab84707769a7bcca94a616 Mon Sep 17 00:00:00 2001 From: tonarec <23620541+tonarec@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:18:12 +0100 Subject: [PATCH] #1227 - Updated methods related to API changes - Updated /tracks endpoints to /items - Switching IDs to URIs for /me/library endpoint - Fixed playlist limit to 50 (according to API) - Added warnings for deprecated methods --- spotipy/client.py | 167 +++++++++++++++++++++++++++++++++------------- 1 file changed, 121 insertions(+), 46 deletions(-) diff --git a/spotipy/client.py b/spotipy/client.py index 92fe1da..42a0a1b 100644 --- a/spotipy/client.py +++ b/spotipy/client.py @@ -445,6 +445,11 @@ class Spotify: - country - limit the response to one particular country. """ + warnings.warn( + "You're using `artist_top_tracks(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) trid = self._get_id("artist", artist_id) return self._get("artists/" + trid + "/top-tracks", country=country) @@ -647,6 +652,11 @@ class Spotify: Parameters: - user - the id of the usr """ + warnings.warn( + "You're using `user(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) return self._get("users/" + user) def current_user_playlists(self, limit=50, offset=0): @@ -680,7 +690,7 @@ class Spotify: self, playlist_id, fields=None, - limit=100, + limit=50, offset=0, market=None, additional_types=("track",) @@ -712,7 +722,7 @@ class Spotify: self, playlist_id, fields=None, - limit=100, + limit=50, offset=0, market=None, additional_types=("track", "episode") @@ -730,7 +740,7 @@ class Spotify: """ plid = self._get_id("playlist", playlist_id) return self._get( - f"playlists/{plid}/tracks", + f"playlists/{plid}/items", limit=limit, offset=offset, fields=fields, @@ -826,6 +836,12 @@ class Spotify: - limit - the number of items to return - offset - the index of the first item to return """ + warnings.warn( + "You're using `user_playlists(...)`, " + "which is marked as deprecated by Spotify. Use " + "current_user_playlists(...) instead.", + DeprecationWarning, + ) return self._get( f"users/{user}/playlists", limit=limit, offset=offset ) @@ -840,6 +856,12 @@ class Spotify: - collaborative - is the created playlist collaborative - description - the description of the playlist """ + warnings.warn( + "You're using `user_playlist_create(...)`, " + "which is marked as deprecated by Spotify. Use " + "current_user_playlist_create(...) instead.", + DeprecationWarning, + ) data = { "name": name, "public": public, @@ -849,6 +871,24 @@ class Spotify: return self._post(f"users/{user}/playlists", payload=data) + def current_user_playlist_create(self, name, public=True, collaborative=False, description=""): + """ Creates a playlist for the current user + + Parameters: + - name - the name of the playlist + - public - is the created playlist public + - collaborative - is the created playlist collaborative + - description - the description of the playlist + """ + data = { + "name": name, + "public": public, + "collaborative": collaborative, + "description": description + } + + return self._post("me/playlists", payload=data) + def user_playlist_change_details( self, user, @@ -1171,7 +1211,7 @@ class Spotify: plid = self._get_id("playlist", playlist_id) ftracks = [self._get_uri("track", tid) for tid in items] return self._post( - f"playlists/{plid}/tracks", + f"playlists/{plid}/items", payload=ftracks, position=position, ) @@ -1187,7 +1227,7 @@ class Spotify: ftracks = [self._get_uri("track", tid) for tid in items] payload = {"uris": ftracks} return self._put( - f"playlists/{plid}/tracks", payload=payload + f"playlists/{plid}/items", payload=payload ) def playlist_reorder_items( @@ -1218,7 +1258,7 @@ class Spotify: if snapshot_id: payload["snapshot_id"] = snapshot_id return self._put( - f"playlists/{plid}/tracks", payload=payload + f"playlists/{plid}/items", payload=payload ) def playlist_remove_all_occurrences_of_items( @@ -1235,11 +1275,11 @@ class Spotify: plid = self._get_id("playlist", playlist_id) ftracks = [self._get_uri("track", tid) for tid in items] - payload = {"tracks": [{"uri": track} for track in ftracks]} + payload = {"items": [{"uri": track} for track in ftracks]} if snapshot_id: payload["snapshot_id"] = snapshot_id return self._delete( - f"playlists/{plid}/tracks", payload=payload + f"playlists/{plid}/items", payload=payload ) def playlist_remove_specific_occurrences_of_items( @@ -1266,11 +1306,11 @@ class Spotify: "positions": tr["positions"], } ) - payload = {"tracks": ftracks} + payload = {"items": ftracks} if snapshot_id: payload["snapshot_id"] = snapshot_id return self._delete( - f"playlists/{plid}/tracks", payload=payload + f"playlists/{plid}/items", payload=payload ) def current_user_follow_playlist(self, playlist_id, public=True): @@ -1281,10 +1321,7 @@ class Spotify: - playlist_id - the id of the playlist """ - return self._put( - f"playlists/{playlist_id}/followers", - payload={"public": public} - ) + return self._put("me/library?uris=" + self._get_uri("playlist", playlist_id)) def playlist_is_following( self, playlist_id, user_ids @@ -1298,8 +1335,27 @@ class Spotify: if they follow the playlist. Maximum: 5 ids. """ + warnings.warn( + "You're using `playlist_is_following(..., user_ids=...)`, " + "which is marked as deprecated by Spotify. Use ", + "current_user_follow_playlist(...) instead.", + DeprecationWarning, + ) + endpoint = f"playlists/{playlist_id}/followers/contains?ids={','.join(user_ids)}" return self._get(endpoint) + + def current_user_saved_items(self, uris): + """ + Check if the current user is following the given artists, users, or playlists + + Parameters: + - uris - a list of URIs to check for following status. Maximum: 40 ids. + + """ + valid_uris = [uri for uri in uris if self._is_uri(uri)] + endpoint = f"me/library/contains?uris={','.join(valid_uris)}" + return self._get(endpoint) def me(self): """ Get detailed profile information about the current user. @@ -1347,8 +1403,8 @@ class Spotify: - albums - a list of album URIs, URLs or IDs """ - alist = [self._get_id("album", a) for a in albums] - return self._put("me/albums?ids=" + ",".join(alist)) + alist = [self._get_uri("album", a) for a in albums] + return self._put("me/library?uris=" + ",".join(alist)) def current_user_saved_albums_delete(self, albums=[]): """ Remove one or more albums from the current user's @@ -1357,8 +1413,8 @@ class Spotify: Parameters: - albums - a list of album URIs, URLs or IDs """ - alist = [self._get_id("album", a) for a in albums] - return self._delete("me/albums/?ids=" + ",".join(alist)) + alist = [self._get_uri("album", a) for a in albums] + return self._delete("me/library?uris=" + ",".join(alist)) def current_user_saved_albums_contains(self, albums=[]): """ Check if one or more albums is already saved in @@ -1367,8 +1423,8 @@ class Spotify: Parameters: - albums - a list of album URIs, URLs or IDs """ - alist = [self._get_id("album", a) for a in albums] - return self._get("me/albums/contains?ids=" + ",".join(alist)) + alist = [self._get_uri("album", a) for a in albums] + return self._get("me/library/contains?uris=" + ",".join(alist)) def current_user_saved_tracks(self, limit=20, offset=0, market=None): """ Gets a list of the tracks saved in the current authorized user's @@ -1391,8 +1447,8 @@ class Spotify: """ tlist = [] if tracks is not None: - tlist = [self._get_id("track", t) for t in tracks] - return self._put("me/tracks/?ids=" + ",".join(tlist)) + tlist = [self._get_uri("track", t) for t in tracks] + return self._put("me/library?uris=" + ",".join(tlist)) def current_user_saved_tracks_delete(self, tracks=None): """ Remove one or more tracks from the current user's @@ -1403,8 +1459,8 @@ class Spotify: """ tlist = [] if tracks is not None: - tlist = [self._get_id("track", t) for t in tracks] - return self._delete("me/tracks/?ids=" + ",".join(tlist)) + tlist = [self._get_uri("track", t) for t in tracks] + return self._delete("me/library/?uris=" + ",".join(tlist)) def current_user_saved_tracks_contains(self, tracks=None): """ Check if one or more tracks is already saved in @@ -1415,8 +1471,8 @@ class Spotify: """ tlist = [] if tracks is not None: - tlist = [self._get_id("track", t) for t in tracks] - return self._get("me/tracks/contains?ids=" + ",".join(tlist)) + tlist = [self._get_uri("track", t) for t in tracks] + return self._get("me/library/contains?uris=" + ",".join(tlist)) def current_user_saved_episodes(self, limit=20, offset=0, market=None): """ Gets a list of the episodes saved in the current authorized user's @@ -1439,8 +1495,8 @@ class Spotify: """ elist = [] if episodes is not None: - elist = [self._get_id("episode", e) for e in episodes] - return self._put("me/episodes/?ids=" + ",".join(elist)) + elist = [self._get_uri("episode", e) for e in episodes] + return self._put("me/library?uris=" + ",".join(elist)) def current_user_saved_episodes_delete(self, episodes=None): """ Remove one or more episodes from the current user's @@ -1451,8 +1507,8 @@ class Spotify: """ elist = [] if episodes is not None: - elist = [self._get_id("episode", e) for e in episodes] - return self._delete("me/episodes/?ids=" + ",".join(elist)) + elist = [self._get_uri("episode", e) for e in episodes] + return self._delete("me/library?uris=" + ",".join(elist)) def current_user_saved_episodes_contains(self, episodes=None): """ Check if one or more episodes is already saved in @@ -1484,8 +1540,8 @@ class Spotify: Parameters: - shows - a list of show URIs, URLs or IDs """ - slist = [self._get_id("show", s) for s in shows] - return self._put("me/shows?ids=" + ",".join(slist)) + slist = [self._get_uri("show", s) for s in shows] + return self._put("me/library?uris=" + ",".join(slist)) def current_user_saved_shows_delete(self, shows=[]): """ Remove one or more shows from the current user's @@ -1494,8 +1550,8 @@ class Spotify: Parameters: - shows - a list of show URIs, URLs or IDs """ - slist = [self._get_id("show", s) for s in shows] - return self._delete("me/shows/?ids=" + ",".join(slist)) + slist = [self._get_uri("show", s) for s in shows] + return self._delete("me/library?uris=" + ",".join(slist)) def current_user_saved_shows_contains(self, shows=[]): """ Check if one or more shows is already saved in @@ -1504,8 +1560,8 @@ class Spotify: Parameters: - shows - a list of show URIs, URLs or IDs """ - slist = [self._get_id("show", s) for s in shows] - return self._get("me/shows/contains?ids=" + ",".join(slist)) + slist = [self._get_uri("show", s) for s in shows] + return self._get("me/library/contains?uris=" + ",".join(slist)) def current_user_followed_artists(self, limit=20, after=None): """ Gets a list of the artists followed by the current authorized user @@ -1528,11 +1584,11 @@ class Spotify: Parameters: - ids - a list of artist URIs, URLs or IDs """ - idlist = [] + ulist = [] if ids is not None: - idlist = [self._get_id("artist", i) for i in ids] + ulist = [self._get_uri("artist", i) for i in ids] return self._get( - "me/following/contains", ids=",".join(idlist), type="artist" + "me/library/contains", uris=",".join(ulist) ) def current_user_following_users(self, ids=None): @@ -1543,11 +1599,11 @@ class Spotify: Parameters: - ids - a list of user URIs, URLs or IDs """ - idlist = [] + ulist = [] if ids is not None: - idlist = [self._get_id("user", i) for i in ids] + ulist = [self._get_uri("user", i) for i in ids] return self._get( - "me/following/contains", ids=",".join(idlist), type="user" + "me/library/contains", uris=",".join(ulist) ) def current_user_top_artists( @@ -1604,28 +1660,32 @@ class Spotify: Parameters: - ids - a list of artist IDs """ - return self._put("me/following?type=artist&ids=" + ",".join(ids)) + alist = [self._get_uri("artist", a) for a in ids] + return self._put("me/library", uris=",".join(alist)) def user_follow_users(self, ids=[]): """ Follow one or more users Parameters: - ids - a list of user IDs """ - return self._put("me/following?type=user&ids=" + ",".join(ids)) + ulist = [self._get_uri("user", a) for a in ids] + return self._put("me/library", uris=",".join(ulist)) def user_unfollow_artists(self, ids=[]): """ Unfollow one or more artists Parameters: - ids - a list of artist IDs """ - return self._delete("me/following?type=artist&ids=" + ",".join(ids)) + alist = [self._get_uri("artist", a) for a in ids] + return self._delete("me/library", uris=",".join(alist)) def user_unfollow_users(self, ids=[]): """ Unfollow one or more users Parameters: - ids - a list of user IDs """ - return self._delete("me/following?type=user&ids=" + ",".join(ids)) + ulist = [self._get_uri("user", a) for a in ids] + return self._delete("me/library", uris=",".join(ulist)) def featured_playlists( self, locale=None, country=None, timestamp=None, limit=20, offset=0 @@ -1681,6 +1741,11 @@ class Spotify: (the first object). Use with limit to get the next set of items. """ + warnings.warn( + "You're using `new_release(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) return self._get( "browse/new-releases", country=country, limit=limit, offset=offset ) @@ -1696,6 +1761,11 @@ class Spotify: language code and an ISO 3166-1 alpha-2 country code, joined by an underscore. """ + warnings.warn( + "You're using `category(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) return self._get( "browse/categories/" + category_id, country=country, @@ -1718,6 +1788,11 @@ class Spotify: (the first object). Use with limit to get the next set of items. """ + warnings.warn( + "You're using `categories(...)`, " + "which is marked as deprecated by Spotify.", + DeprecationWarning, + ) return self._get( "browse/categories", country=country,