From ba01a6aee591787d4de59a0be25622b44d942e3d Mon Sep 17 00:00:00 2001 From: jonathan-huston <72905961+jonathan-huston@users.noreply.github.com> Date: Sun, 12 Jan 2025 06:47:10 -0800 Subject: [PATCH 1/2] Examples directory updates (#1055) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed scripts in examples directory that didn't work, deleted any redundant examples. * Added examples for methods related to audiobooks, shows and episodes * Updated changelog --------- Co-authored-by: Stéphane Bruckert --- CHANGELOG.md | 2 ++ examples/add_saved_episodes.py | 28 +++++++++++++++ examples/add_saved_shows.py | 28 +++++++++++++++ examples/check_show_is_saved.py | 31 +++++++++++++++++ examples/delete_saved_episodes.py | 28 +++++++++++++++ examples/follow_playlist.py | 21 +++++------- examples/get_audiobook_chapters_info.py | 29 ++++++++++++++++ examples/get_audiobooks_info.py | 29 ++++++++++++++++ examples/playlist_add_items.py | 12 ------- examples/read_a_playlist.py | 2 +- examples/remove_tracks_from_playlist.py | 4 +-- examples/replace_tracks_in_playlist.py | 2 +- examples/{tracks.py => show_artist_tracks.py} | 0 examples/show_tracks.py | 34 +++++++++++-------- examples/test.py | 11 ------ examples/unfollow_playlist.py | 6 ++-- examples/user_saved_episodes.py | 29 ++++++++++++++++ examples/user_saved_shows.py | 29 ++++++++++++++++ 18 files changed, 268 insertions(+), 57 deletions(-) create mode 100644 examples/add_saved_episodes.py create mode 100644 examples/add_saved_shows.py create mode 100644 examples/check_show_is_saved.py create mode 100644 examples/delete_saved_episodes.py create mode 100644 examples/get_audiobook_chapters_info.py create mode 100644 examples/get_audiobooks_info.py delete mode 100644 examples/playlist_add_items.py rename examples/{tracks.py => show_artist_tracks.py} (100%) delete mode 100644 examples/test.py create mode 100644 examples/user_saved_episodes.py create mode 100644 examples/user_saved_shows.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f2b422..9eb0f2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Add your changes below. ### Added +- Added examples for audiobooks, shows and episodes methods to examples directory ### Fixed +- Fixed scripts in examples directory that didn't run correctly ### Removed diff --git a/examples/add_saved_episodes.py b/examples/add_saved_episodes.py new file mode 100644 index 0000000..5acc177 --- /dev/null +++ b/examples/add_saved_episodes.py @@ -0,0 +1,28 @@ +""" +Add episodes to current user's library +Usage: add_saved_episodes.py -e episode_id episode_id ... +""" + +import argparse +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +scope = 'user-library-modify' + +def get_args(): + parser = argparse.ArgumentParser(description='Add episodes to library') + # Default args set to This American Life episodes 814 and 815 + parser.add_argument('-e', '--eids', nargs='+', + default=['6rxg9Lpt2ywNHFea8LxEBO', '7q8or6oYYRFQFYlA0remoy'], + help='Episode ids') + return parser.parse_args() + +def main(): + args = get_args() + print('Adding following episode ids to library: ' + str(args.eids)) + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) + sp.current_user_saved_episodes_add(episodes=args.eids) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/examples/add_saved_shows.py b/examples/add_saved_shows.py new file mode 100644 index 0000000..ef16258 --- /dev/null +++ b/examples/add_saved_shows.py @@ -0,0 +1,28 @@ +""" +Add shows to current user's library +Usage: add_saved_shows.py -s show_id show_id ... +""" + +import argparse +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +scope = 'user-library-modify' + +def get_args(): + parser = argparse.ArgumentParser(description='Add shows to library') + # Default args set to Radiolab and 99% invisible + parser.add_argument('-s', '--sids', nargs='+', + default=['2hmkzUtix0qTqvtpPcMzEL', '2VRS1IJCTn2Nlkg33ZVfkM'], + help='Show ids') + return parser.parse_args() + +def main(): + args = get_args() + print('Adding following show ids to library: ' + str(args.sids)) + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) + sp.current_user_saved_shows_add(shows=args.sids) + + +if __name__ == '__main__': + main() diff --git a/examples/check_show_is_saved.py b/examples/check_show_is_saved.py new file mode 100644 index 0000000..eeeb56d --- /dev/null +++ b/examples/check_show_is_saved.py @@ -0,0 +1,31 @@ +""" +Check if shows are saved in user's library +Usage: check_show_is_saved -s show_id show_id ... +""" + +import argparse +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +scope = 'user-library-read' + +def get_args(): + parser = argparse.ArgumentParser(description='Check that a show is saved') + # Default args set to Radiolab and 99% invisible + parser.add_argument('-s', '--sids', nargs='+', + default=['2hmkzUtix0qTqvtpPcMzEL', '2VRS1IJCTn2Nlkg33ZVfkM'], + help='Show ids') + return parser.parse_args() + +def main(): + args = get_args() + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) + results = sp.current_user_saved_episodes_contains(episodes=args.sids) + show_names = sp.shows(shows=args.sids) + # Print show names and if show is saved by current user + for i, show in enumerate(show_names['shows']): + print(show['name'] + ': ' + str(results[i])) + + +if __name__ == '__main__': + main() diff --git a/examples/delete_saved_episodes.py b/examples/delete_saved_episodes.py new file mode 100644 index 0000000..b62f4f0 --- /dev/null +++ b/examples/delete_saved_episodes.py @@ -0,0 +1,28 @@ +""" +Delete episodes from current user's library +Usage: delete_saved_episodes.py -e episode_id episode_id ... +""" + +import argparse +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +scope = 'user-library-modify' + +def get_args(): + parser = argparse.ArgumentParser(description='Delete episodes from library') + # Default args set to This American Life episodes 814 and 815 + parser.add_argument('-e', '--eids', nargs='+', + default=['6rxg9Lpt2ywNHFea8LxEBO', '7q8or6oYYRFQFYlA0remoy'], + help='Episode ids') + return parser.parse_args() + +def main(): + args = get_args() + print('Deleting following episode ids from library: ' + str(args.eids)) + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) + sp.current_user_saved_episodes_delete(episodes=args.eids) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/examples/follow_playlist.py b/examples/follow_playlist.py index 6973468..20f4c32 100644 --- a/examples/follow_playlist.py +++ b/examples/follow_playlist.py @@ -1,27 +1,22 @@ -import argparse +# Follow a playlist +import argparse import spotipy from spotipy.oauth2 import SpotifyOAuth +scope = 'playlist-modify-public' +sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) def get_args(): parser = argparse.ArgumentParser(description='Follows a playlist based on playlist ID') - parser.add_argument('-p', '--playlist', required=True, help='Playlist ID') - + # Default to Top 50 Global if no playlist is provided + parser.add_argument('-p', '--playlist', help='Playlist ID', nargs='?', default='37i9dQZEVXbMDoHDwVN2tF') return parser.parse_args() def main(): args = get_args() - - if args.playlist is None: - # Uses the Spotify Global Top 50 playlist - spotipy.Spotify(auth_manager=SpotifyOAuth()).current_user_follow_playlist( - '37i9dQZEVXbMDoHDwVN2tF') - - else: - spotipy.Spotify(auth_manager=SpotifyOAuth()).current_user_follow_playlist(args.playlist) - + sp.current_user_follow_playlist(args.playlist) if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/examples/get_audiobook_chapters_info.py b/examples/get_audiobook_chapters_info.py new file mode 100644 index 0000000..abbf37a --- /dev/null +++ b/examples/get_audiobook_chapters_info.py @@ -0,0 +1,29 @@ +""" +Print chapter titles and lengths for given audiobook +Usage: get_audiobooks_chapters_info.py -a audiobook_id +""" + +import argparse +import spotipy +from spotipy.oauth2 import SpotifyOAuth + + +def get_args(): + parser = argparse.ArgumentParser(description='Get chapter info for an audiobook') + # Default set to Dune + parser.add_argument('-a', '--audiobook', default='2h01INWMBvfpzNMpGFzhdF', help='Audiobook id') + return parser.parse_args() + + +def main(): + args = get_args() + print('Getting chapter info for follow audiobook id: ' + str(args.audiobook)) + sp = spotipy.Spotify(auth_manager=SpotifyOAuth()) + results = sp.get_audiobook_chapters(id=args.audiobook) + # Print chapter name and length + for item in results['items']: + print('Name: ' + item['name'] + ', length: ' + str(round(item['duration_ms']/60000,1)) + ' minutes') + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/examples/get_audiobooks_info.py b/examples/get_audiobooks_info.py new file mode 100644 index 0000000..72fe18d --- /dev/null +++ b/examples/get_audiobooks_info.py @@ -0,0 +1,29 @@ +""" +Print audiobook title and description for a list of audiobook ids +Usage: get_audiobooks_info.py -a audiobook_id audiobook_id ... +""" + +import argparse +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +def get_args(): + parser = argparse.ArgumentParser(description='Get information for a list of audiobooks') + # Defaults set to The Great Gatsby, The Chronicles of Narnia and Dune + parser.add_argument('-a', '--aids', nargs='+', + default=['6qjpt1CUHhKXiNoeNoU7nu', '1ezmXd68LbDtxebvygEQ2U', '2h01INWMBvfpzNMpGFzhdF'], + help='Audiobook ids') + return parser.parse_args() + +def main(): + args = get_args() + print('Getting info for follow audiobook ids: ' + str(args.aids) + '\n') + sp = spotipy.Spotify(auth_manager=SpotifyOAuth()) + results = sp.get_audiobooks(ids=args.aids) + # Print book title and description + for book in results['audiobooks']: + print('Title: ' + book['name'] + '\n' + book['description'] + '\n') + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/examples/playlist_add_items.py b/examples/playlist_add_items.py deleted file mode 100644 index 8d10c5b..0000000 --- a/examples/playlist_add_items.py +++ /dev/null @@ -1,12 +0,0 @@ -# Add a list of items (URI) to a playlist (URI) - -import spotipy -from spotipy.oauth2 import SpotifyOAuth - -sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id="YOUR_APP_CLIENT_ID", - client_secret="YOUR_APP_CLIENT_SECRET", - redirect_uri="YOUR_APP_REDIRECT_URI", - scope="playlist-modify-private" - )) - -sp.playlist_add_items('playlist_id', ['list_of_items']) diff --git a/examples/read_a_playlist.py b/examples/read_a_playlist.py index 06cad00..a6b5676 100644 --- a/examples/read_a_playlist.py +++ b/examples/read_a_playlist.py @@ -5,6 +5,6 @@ import json client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) -playlist_id = 'spotify:user:spotifycharts:playlist:37i9dQZEVXbJiZcmkrIHGU' +playlist_id = '37i9dQZEVXbJiZcmkrIHGU' results = sp.playlist(playlist_id) print(json.dumps(results, indent=4)) diff --git a/examples/remove_tracks_from_playlist.py b/examples/remove_tracks_from_playlist.py index 4e011eb..59625cc 100644 --- a/examples/remove_tracks_from_playlist.py +++ b/examples/remove_tracks_from_playlist.py @@ -7,8 +7,8 @@ from spotipy.oauth2 import SpotifyOAuth if len(sys.argv) > 2: - playlist_id = sys.argv[2] - track_ids = sys.argv[3:] + playlist_id = sys.argv[1] + track_ids = sys.argv[2:] else: print(f"Usage: {sys.argv[0]} playlist_id track_id ...") sys.exit() diff --git a/examples/replace_tracks_in_playlist.py b/examples/replace_tracks_in_playlist.py index 6c76b05..2a46d46 100644 --- a/examples/replace_tracks_in_playlist.py +++ b/examples/replace_tracks_in_playlist.py @@ -6,7 +6,7 @@ import sys import spotipy from spotipy.oauth2 import SpotifyOAuth -if len(sys.argv) > 3: +if len(sys.argv) > 2: playlist_id = sys.argv[1] track_ids = sys.argv[2:] else: diff --git a/examples/tracks.py b/examples/show_artist_tracks.py similarity index 100% rename from examples/tracks.py rename to examples/show_artist_tracks.py diff --git a/examples/show_tracks.py b/examples/show_tracks.py index efee1d2..9ea31ef 100644 --- a/examples/show_tracks.py +++ b/examples/show_tracks.py @@ -3,21 +3,25 @@ given a list of track IDs show the artist and track name ''' -from spotipy.oauth2 import SpotifyClientCredentials -import sys +from spotipy.oauth2 import SpotifyOAuth import spotipy +import argparse + + +def get_args(): + parser = argparse.ArgumentParser(description='Print artist and track name given a list of track IDs') + parser.add_argument('-u', '--uris', nargs='+', + required=True, help='Track ids') + return parser.parse_args() + + +def main(): + args = get_args() + sp = spotipy.Spotify(auth_manager=SpotifyOAuth()) + track_list = sp.tracks(args.uris) + for track in track_list['tracks']: + print(track['name'] + ' - ' + track['artists'][0]['name']) + if __name__ == '__main__': - max_tracks_per_call = 50 - if len(sys.argv) > 1: - file = open(sys.argv[1]) - else: - file = sys.stdin - tids = file.read().split() - - client_credentials_manager = SpotifyClientCredentials() - sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) - for start in range(0, len(tids), max_tracks_per_call): - results = sp.tracks(tids[start: start + max_tracks_per_call]) - for track in results['tracks']: - print(track['name'] + ' - ' + track['artists'][0]['name']) + main() diff --git a/examples/test.py b/examples/test.py deleted file mode 100644 index bffb19b..0000000 --- a/examples/test.py +++ /dev/null @@ -1,11 +0,0 @@ -import spotipy -from spotipy.oauth2 import SpotifyOAuth - -scope = "user-library-read" - -sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) - -results = sp.current_user_saved_tracks() -for idx, item in enumerate(results['items']): - track = item['track'] - print(idx, track['artists'][0]['name'], " – ", track['name']) diff --git a/examples/unfollow_playlist.py b/examples/unfollow_playlist.py index bf0466f..eebf216 100644 --- a/examples/unfollow_playlist.py +++ b/examples/unfollow_playlist.py @@ -4,6 +4,8 @@ import logging import spotipy from spotipy.oauth2 import SpotifyOAuth +scope = 'playlist-modify-public' + logger = logging.getLogger('examples.unfollow_playlist') logging.basicConfig(level='DEBUG') @@ -23,9 +25,9 @@ def get_args(): def main(): args = get_args() - sp = spotipy.Spotify(auth_manager=SpotifyOAuth()) + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) sp.current_user_unfollow_playlist(args.playlist) if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/examples/user_saved_episodes.py b/examples/user_saved_episodes.py new file mode 100644 index 0000000..4a10682 --- /dev/null +++ b/examples/user_saved_episodes.py @@ -0,0 +1,29 @@ +""" +List current user's saved episodes +Usage: user_saved_episodes -l -o +""" + +import argparse +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +scope = 'user-library-read' + +def get_args(): + parser = argparse.ArgumentParser(description='Show user\'s saved episodes') + parser.add_argument('-l', '--limit', default=20, help='Num of episodes to return') + parser.add_argument('-o', '--offset', default=0, help='Index of first show to return') + + return parser.parse_args() + +def main(): + args = get_args() + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) + results = sp.current_user_saved_episodes(limit=args.limit, offset=args.offset) + # Print episode names + for item in results['items']: + print(item['episode']['name']) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/examples/user_saved_shows.py b/examples/user_saved_shows.py new file mode 100644 index 0000000..ea60f4a --- /dev/null +++ b/examples/user_saved_shows.py @@ -0,0 +1,29 @@ +""" +List current user's saved shows +Usage: user_saved_shows -l -o +""" + +import argparse +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +scope = 'user-library-read' + +def get_args(): + parser = argparse.ArgumentParser(description='Show user\'s saved shows') + parser.add_argument('-l', '--limit', default=20, help='Num of shows to return') + parser.add_argument('-o', '--offset', default=0, help='Index of first show to return') + + return parser.parse_args() + +def main(): + args = get_args() + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) + results = sp.current_user_saved_shows(limit=args.limit, offset=args.offset) + # Print episode names + for item in results['items']: + print(item['show']['name']) + + +if __name__ == '__main__': + main() \ No newline at end of file From ca207e4f2d6e221e464e9d8ad5abc09a47ca0aeb Mon Sep 17 00:00:00 2001 From: Michael Rossetti Date: Sun, 12 Jan 2025 10:42:56 -0500 Subject: [PATCH 2/2] Update docs for `current_user_top_artists` (#1171) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update docs Add maximum value for limit parameter. See: https://developer.spotify.com/documentation/web-api/reference/get-users-top-artists-and-tracks * Update CHANGELOG.md --------- Co-authored-by: Stéphane Bruckert --- CHANGELOG.md | 1 + spotipy/client.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eb0f2d..e639413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Add your changes below. ### Fixed - Fixed scripts in examples directory that didn't run correctly +- Updated documentation for `Client.current_user_top_artists` to indicate maximum number of artists limit ### Removed diff --git a/spotipy/client.py b/spotipy/client.py index 9261f23..8978058 100644 --- a/spotipy/client.py +++ b/spotipy/client.py @@ -1497,7 +1497,7 @@ class Spotify: """ Get the current user's top artists Parameters: - - limit - the number of entities to return + - limit - the number of entities to return (max 50) - offset - the index of the first entity to return - time_range - Over what time frame are the affinities computed Valid-values: short_term, medium_term, long_term