From f82c283c90beab6924eb0bc70e317beae17e4ad4 Mon Sep 17 00:00:00 2001 From: oliveraw Date: Sun, 4 Dec 2022 21:36:43 -0500 Subject: [PATCH 1/3] updated functionality of playlist_add_items() to accept only uris and urls (ids should not be allowed since 'track' or 'episode' cannot be inferred purely from the id) --- examples/add_tracks_to_playlist.py | 4 +-- spotipy/client.py | 34 +++++++++++++++++++++--- tests/integration/user_endpoints/test.py | 10 ++++++- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/examples/add_tracks_to_playlist.py b/examples/add_tracks_to_playlist.py index 28e6cf49..eaaa6637 100644 --- a/examples/add_tracks_to_playlist.py +++ b/examples/add_tracks_to_playlist.py @@ -11,7 +11,7 @@ def get_args(): parser = argparse.ArgumentParser(description='Adds track to user playlist') - parser.add_argument('-t', '--tids', action='append', + parser.add_argument('-u', '--uris', action='append', required=True, help='Track ids') parser.add_argument('-p', '--playlist', required=True, help='Playlist to add track to') @@ -22,7 +22,7 @@ def main(): args = get_args() sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) - sp.playlist_add_items(args.playlist, args.tids) + sp.playlist_add_items(args.playlist, args.uris) if __name__ == '__main__': diff --git a/spotipy/client.py b/spotipy/client.py index a0222328..2ca27ba3 100644 --- a/spotipy/client.py +++ b/spotipy/client.py @@ -846,8 +846,27 @@ def user_playlist_add_tracks( - tracks - a list of track URIs, URLs or IDs - position - the position to add the tracks """ + tracks = [self._get_uri("track", tid) for tid in tracks] return self.playlist_add_items(playlist_id, tracks, position) + def user_playlist_add_episodes( + self, user, playlist_id, episodes, position=None + ): + warnings.warn( + "You should use `playlist_add_items(playlist_id, episodes)` instead", + DeprecationWarning, + ) + """ Adds episodes to a playlist + + Parameters: + - user - the id of the user + - playlist_id - the id of the playlist + - episodes - a list of track URIs, URLs or IDs + - position - the position to add the episodes + """ + episodes = [self._get_uri("episode", tid) for tid in episodes] + return self.playlist_add_items(playlist_id, episodes, position) + def user_playlist_replace_tracks(self, user, playlist_id, tracks): """ Replace all tracks in a playlist for a user @@ -1026,20 +1045,20 @@ def current_user_unfollow_playlist(self, playlist_id): ) def playlist_add_items( - self, playlist_id, items, position=None + self, playlist_id, item_uris, position=None ): """ Adds tracks/episodes to a playlist Parameters: - playlist_id - the id of the playlist - - items - a list of track/episode URIs, URLs or IDs + - items - a list of track/episode URIs or URLs - position - the position to add the tracks """ plid = self._get_id("playlist", playlist_id) - ftracks = [self._get_uri("track", tid) for tid in items] + item_uris = [self._url_to_uri(item) if self._is_url(item) else item for item in item_uris] return self._post( "playlists/%s/tracks" % (plid), - payload=ftracks, + payload=item_uris, position=position, ) @@ -1945,6 +1964,13 @@ def _get_uri(self, type, id): def _is_uri(self, uri): return uri.startswith("spotify:") and len(uri.split(':')) == 3 + def _is_url(self, url): + return url.startswith("http") + + def _url_to_uri(self, url): + splitted = url.split("/") + return "spotify:" + splitted[-2] + ":" + splitted[-1] + def _search_multiple_markets(self, q, limit, offset, type, markets, total): if total and limit > total: limit = total diff --git a/tests/integration/user_endpoints/test.py b/tests/integration/user_endpoints/test.py index d2568499..ec035771 100644 --- a/tests/integration/user_endpoints/test.py +++ b/tests/integration/user_endpoints/test.py @@ -35,6 +35,14 @@ def setUpClass(cls): "spotify:episode:7cRcsGYYRUFo1OF3RgRzdx", ] + cls.tracks_and_episodes = [ + "spotify:track:3F5CgOj3wFlRv51JsHbxhe", + "http://open.spotify.com/track/5mCPDVBb16L4XQwDdbRUpz", + + "spotify:episode:7AY0yaj2k0W3obOSCfm6m4", + "https://open.spotify.com/episode/5AJB2BTp7RExSGpbQlIsXI" + ] + scope = ( 'playlist-modify-public ' 'user-library-read ' @@ -101,7 +109,7 @@ def test_current_user_follow_playlist(self): def test_playlist_replace_items(self): # add tracks to playlist self.spotify.playlist_add_items( - self.new_playlist['id'], self.four_tracks) + self.new_playlist['id'], self.tracks_and_episodes) playlist = self.spotify.playlist(self.new_playlist['id']) self.assertEqual(playlist['tracks']['total'], 4) self.assertEqual(len(playlist['tracks']['items']), 4) From ddac78e506c5e147dbbfed13e9527d629249f39b Mon Sep 17 00:00:00 2001 From: oliveraw Date: Sun, 4 Dec 2022 21:57:06 -0500 Subject: [PATCH 2/3] added a check to raise runtime error if any items in playlist_add_items() are not URIs or URLs --- spotipy/client.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spotipy/client.py b/spotipy/client.py index 2ca27ba3..65432954 100644 --- a/spotipy/client.py +++ b/spotipy/client.py @@ -1045,7 +1045,7 @@ def current_user_unfollow_playlist(self, playlist_id): ) def playlist_add_items( - self, playlist_id, item_uris, position=None + self, playlist_id, items, position=None ): """ Adds tracks/episodes to a playlist @@ -1054,11 +1054,14 @@ def playlist_add_items( - items - a list of track/episode URIs or URLs - position - the position to add the tracks """ + for item in items: + if not self._is_uri(item) and not self._is_url(item): + raise RuntimeError("playlist_add_items() only accepts URIs and URLs.") plid = self._get_id("playlist", playlist_id) - item_uris = [self._url_to_uri(item) if self._is_url(item) else item for item in item_uris] + items = [self._url_to_uri(item) if self._is_url(item) else item for item in items] return self._post( "playlists/%s/tracks" % (plid), - payload=item_uris, + payload=items, position=position, ) From 3d83f3f70c56a2c30c12c827a9c6701d1005fb51 Mon Sep 17 00:00:00 2001 From: oliveraw Date: Sun, 4 Dec 2022 22:00:01 -0500 Subject: [PATCH 3/3] modified change log --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26f9ed5c..5e16ab30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Pin Github Actions Runner to Ubuntu 20 for Py27 - Fixed potential error where `found` variable in `test_artist_related_artists` is undefined if for loop never evaluates to true - Fixed false positive test `test_new_releases` which looks up the wrong property of the JSON response object and always evaluates to true +- Fixed playlist_add_items() to accept only URIs and URLs and not IDs, since 'track' and 'episode' cannot be inferred from ID only ## [2.21.0] - 2022-09-26