def get_target_playlist(date: dt, client: spotipy.Spotify, user: str) -> str: """ ASSUMPTIONS: a user has no duplicate playlist names In the case that a user has a duplicate playlist name, the script will modify the one 'lower' in the user's playlist library Solution: no intuitive workaround """ # december of 2019 looks for playlist "winter 2020" target_playlist_name = get_current_season(date) + " " + str( date.year if date.month != 12 else date.year + 1) chunk, offset = 50, 0 all_playlists = {} # Case 1: Playlist is cached and playlist is current season # Good, use it # Case 2: Playlist is cached but playlist is out of season # Make a new playlist and cache it # Case 3: Playlist isnt cached # Look for it playlist_id = "" try: playlist_id = database.get_field(user, "last_playlist") # case 1 if playlist_id != '' and client.playlist( playlist_id)["name"] == target_playlist_name: return playlist_id # case 2 else: resp = client.user_playlist_create( client.me()['id'], target_playlist_name, public=False, description= 'AUTOMATED PLAYLIST - https://github.com/turrence/spotify-new-music-sorter' ) return resp['id'] except KeyError as e: # case 3: do nothing, it's not cached, hopefully this is rare pass while True: playlist_info = client.current_user_playlists(chunk, offset) for item in playlist_info['items']: all_playlists[item['name']] = item['id'] if len(all_playlists) >= playlist_info['total']: break else: offset += chunk if target_playlist_name not in all_playlists: resp = client.user_playlist_create( client.me()['id'], target_playlist_name, public=False, description= 'AUTOMATED PLAYLIST - https://github.com/turrence/spotify-new-music-sorter' ) return resp['id'] else: return all_playlists[target_playlist_name]
def update_playlist(client: spotipy.Spotify, user: str): target_playlist = get_target_playlist(dt.now(tz=tz.utc), client, user) # in utc last_updated = get_newest_date_in_playlist(target_playlist, client) songs_to_be_added = get_unadded_songs(last_updated, client) database.update_user(client.me()['id'], "last_playlist", target_playlist) if len(songs_to_be_added) < 1: # print("No songs to be added for", client.me()['id']) pass else: timestamp = dt.now(tz=tz.utc).strftime('%Y-%m-%d %H:%M:%S') # print(timestamp + ": Adding " + str(len(songs_to_be_added)) + " songs for", client.me()['id']) database.update_user(client.me()['id'], "last_update", timestamp) database.increment_field(client.me()['id'], "update_count") # we can only add 100 songs at a time, place all the songs in a queue # and dequeue into a chunk 100 songs at a time chunk = [] while songs_to_be_added: chunk.append(songs_to_be_added.popleft()) if (len(chunk) == 100): client.user_playlist_add_tracks(client.me()['id'], target_playlist, chunk) chunk.clear() # if the chunk isn't completely filled then add the rest of the songs if (len(chunk) > 0): client.user_playlist_add_tracks(client.me()['id'], target_playlist, chunk)
def index(request): if not request.session.get('uuid'): request.session['uuid'] = str(uuid.uuid4()) auth_manager = SpotifyOAuth( scope='user-read-currently-playing', cache_path=session_cache_path(request.session), show_dialog=True) if request.method == 'GET': if request.GET.get("code"): # Step 3. Being redirected from Spotify auth page request.session['token_info'] = auth_manager.get_access_token( request.GET.get("code")) return redirect(index) if not auth_manager.get_cached_token(): auth_url = auth_manager.get_authorize_url() return HttpResponse(f'<h2><a href="{auth_url}">Sign in</a></h2>') if auth_manager.is_token_expired(request.session.get('token_info')): request.session['token_info'] = auth_manager.refresh_access_token( request.session.get('token_info')) spotify = Spotify(auth_manager=auth_manager) request.session['username'] = spotify.me()['id'] request.session['token'] = auth_manager.get_cached_token() return redirect(visview, request.session.get('username'))
def _login( ): # The login button (also called for auto-login if user was logged in last time) global username global spoofy global logged_in global playlists username_submit.state(["disabled"]) if logged_in: # Logged in logging out print("logging out") username = None playlist_list.delete(0, playlist_list.size() - 1) playlists = [] os.remove("lastuser") logged_in = False else: # Logged out loggin in spoofy = Spotify(auth=authorize(username)) user_id = spoofy.me()["id"] # Get who we are logged in as if username != user_id: username = user_id with open("lastuser", "w") as f: f.write(username) logged_in = True set_login_state() username_submit.state(["!disabled"])
def main() -> None: scope = "user-read-recently-played " \ "playlist-modify-public " \ "playlist-modify-private " \ "user-read-currently-playing " \ "user-library-modify " \ "playlist-read-private " \ "user-library-read" spotify_credentials = SpotifyOAuth( client_id=os.environ.get('SPOTIFY_WEEKLY_SAVER_CLIENT_ID'), client_secret=os.environ.get('SPOTIFY_WEEKLY_SAVER_CLIENT_SECRET'), redirect_uri="http://localhost:8000/", scope=scope, ) spotify_instance = Spotify(auth_manager=spotify_credentials) spotify_handler = SpotifyHandler(spotify_instance=spotify_instance, ) try: user_id = spotify_instance.me().get('id') except SpotifyOauthError: spotify_instance = Spotify( auth=spotify_handler.refresh_access_token(spotify_credentials), ) user_id = spotify_instance.me().get('id') # get Discover Weekly playlist and its creation date dwp, created_at = spotify_handler.get_discover_weekly_playlist() # create new dwp name new_dwp_name = f"{dwp['name']} - {created_at.split('T')[0]}" # get tracks from the main dwp print('Getting tracks from your Discover Weekly Playlist...') tracks = [track['track']['id'] for track in dwp['tracks']['items']] # create new playlist print('Creating new playlist...') new_dwp = archive_discover_weekly_playlist(spotify_instance, spotify_handler, user_id, new_dwp_name) # add tracks from the main dwp to the new one print('Saving tracks...') spotify_instance.playlist_add_items(new_dwp['id'], items=tracks)
def connect(self, response_code, redirect_uri): try: token_response = self.auth_api(redirect_uri).get_access_token(response_code) self.token = token_response['access_token'] sp = Spotify(auth=self.token) self.username = sp.me()['id'] self.state = self.CONNECTED except SpotifyOauthError: self.state = self.FAILED self.repository.save(self)
class SpotifyController(BaseController): @classmethod def app_information(cls, session_id): return [{ "appId": cls.app_id(), "displayName": "Spotify", "iconUrl": "", "isIdleScreen": False, "launchedFromCloud": False, "namespaces": [ { "name": "urn:x-cast:com.spotify.chromecast.secure.v1" }, ], "sessionId": session_id, "statusText": "Spotify", "transportId": session_id }] @classmethod def app_id(cls): return APP_SPOTIFY def __init__(self): super().__init__(APP_NAMESPACE) self._spotify = None def get_reply(self, message): message_type = message.data.get("type", "") if message_type == "setCredentials": token = message.data.get("credentials", "") logger.debug("received spotify token %s", token) self._spotify = Spotify(auth=token) user = self._spotify.me() no_value = "[n/a]" email = user.get("email", no_value) name = user.get("display_name", no_value) country = user.get("country", no_value) birthday = user.get("birthdate", no_value) logger.info("%s (%s from %s, born %s) launched spotify", email, name, country, birthday) return super().get_reply(message)
def create_and_populate_playlist(playlist_name: str, track_ids: list, sp: Spotify): """ Creates and populates a spotify playlist for a user @param playlist_name: name of the playlist @param track_ids: a list of song id's @param sp: Spotify object authenticated by a user to be used with the API queries. @return: """ try: playlist = sp.user_playlist_create(sp.me()['id'], playlist_name, public=True, description='generated by ' 'FindSimilarArtists') playlist_id = playlist['uri'] sp.user_playlist_add_tracks(sp.me()['id'], playlist_id, track_ids) return playlist_id except SpotifyException as e: print(e) return None except Exception as e: print(e) return None
async def callback_for_spotify( code: str, spotipy_oauth: SpotifyOAuth = Depends(get_spotipy_oauth), db: Session = Depends(get_db)): """ Callback for spotify api Redirects to /dashboard on frontend Creates user if not exsists Returns pait of jwt tokens in cookies """ # auth_creds = requests.post( # 'https://accounts.spotify.com/api/token', # data={"grant_type": "authorization_code", "code": code, # "redirect_uri": os.getenv('REDIRECT_URL')}, # headers={ # "Authorization": # f"Basic YjMyMzcwNDExZTcwNGE1NzkxNDRlNTVmYjY3OTgyY2U6YmMwNzljOTllMjIzNDMxNWJjZjMxY2Y2NzE2ZTI3YmY="}).json() auth_creds = spotipy_oauth.get_access_token(code=code, check_cache=False) spotify_client = Spotify(auth=auth_creds["access_token"]) spotify_user = spotify_client.me() db_user = user_crud.get_user(db, spotify_id=spotify_user['id']) UserSchema = UserCreate if not db_user else UserUpdate if spotify_user and auth_creds: image = spotify_user['images'] user = UserSchema(email=spotify_user['email'], name=spotify_user['display_name'], image_url=image[0]['url'] if len(image) else '', spotify_id=spotify_user['id'], access_token=auth_creds['access_token'], refresh_token=auth_creds['refresh_token'], token_expires=datetime.now().timestamp() + float(auth_creds['expires_in'])) if db_user: user_crud.update_user(db, spotify_user['id'], cast(UserUpdate, user)) else: user_crud.create_user(db, cast(UserCreate, user)) frontend_url = os.getenv('FRONTEND_URL') if not spotify_user and not auth_creds: return RedirectResponse(url=f"{frontend_url}", status_code=500) access_token = create_access_token( data=TokenData(spotify_id=spotify_user['id'], spotify_expires=user.token_expires - 600).dict(), expires_delta=ACCESS_TOKEN_EXPIRE_MINUTES) return RedirectResponse(url=f"{frontend_url}/token?token={access_token}")
def auth(request): if not request.session.get('uuid'): request.session['uuid'] = str(uuid.uuid4()) auth_manager = SpotifyOAuth( scope='user-read-currently-playing user-top-read', cache_path=session_cache_path(request.session), show_dialog=True) if request.GET.get('code'): auth_manager.get_access_token(request.GET.get('code')) return redirect('index') if not auth_manager.get_cached_token(): auth_url = auth_manager.get_authorize_url() return Response({"auth_url": auth_url}) spotify = Spotify(auth_manager=auth_manager) return Response({"name": spotify.me()["display_name"]})
def callback(request): spotify_oauth = SpotifyOAuth( settings.SPOTIPY_CLIENT_ID, settings.SPOTIPY_CLIENT_SECRET, settings.SPOTIPY_REDIRECT_URI, scope='user-read-email playlist-modify-public user-follow-modify') oauth_token = request.GET.get('code') access_token = spotify_oauth.get_access_token(oauth_token) spotify = Spotify(auth=access_token.get('access_token')) me = spotify.me() # Check spotify session current_user = None user = None try: current_user = SpotifySession.objects.get(username=me['id']) user = current_user.user user.backend = 'django.contrib.auth.backends.ModelBackend' except: current_user = SpotifySession(username=me.get('id')) # Create this current_user.access_token = access_token.get('access_token') current_user.refresh_token = access_token.get('refresh_token') current_user.expires_in = access_token.get('expires_in') password = get_random_string(length=32) user = User.objects.create_user(me['id'], me['email'], password) user.backend = 'django.contrib.auth.backends.ModelBackend' user.save() current_user.user = user current_user.save() if user is not None: if user.is_active: login(request, user) return HttpResponseRedirect('/dashboard')
class AuthTestSpotipy(unittest.TestCase): """ These tests require user authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_USERNAME' 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' 'SPOTIPY_REDIRECT_URI' """ playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx" playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI" four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB", "4VrWlk8IQxevMvERoX08iC", "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"] two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB"] other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa", "spotify:track:29xKs5BAHlmlX1u4gzQAbJ", "spotify:track:1PB7gRWcvefzu7t3LJLUlf"] album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU", "spotify:album:6RTzC0rDbvagTSJLlY7AKl"] bad_id = 'BAD_ID' @classmethod def setUpClass(self): if sys.version_info >= (3, 2): # >= Python3.2 only warnings.filterwarnings( "ignore", category=ResourceWarning, # noqa message="unclosed.*<ssl.SSLSocket.*>") missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV)) if missing: raise Exception( ('Please set the client credentials for the test application' ' using the following environment variables: {}').format( CCEV.values())) self.username = os.getenv(CCEV['client_username']) self.scope = ( 'playlist-modify-public ' 'user-library-read ' 'user-follow-read ' 'user-library-modify ' 'user-read-private ' 'user-top-read ' 'user-follow-modify ' 'user-read-recently-played ' 'ugc-image-upload' ) self.token = prompt_for_user_token(self.username, scope=self.scope) self.spotify = Spotify(auth=self.token) # Helper def get_or_create_spotify_playlist(self, playlist_name): playlists = self.spotify.user_playlists(self.username) while playlists: for item in playlists['items']: if item['name'] == playlist_name: return item playlists = self.spotify.next(playlists) return self.spotify.user_playlist_create( self.username, playlist_name) # Helper def get_as_base64(self, url): import base64 return base64.b64encode(requests.get(url).content).decode("utf-8") def test_track_bad_id(self): try: self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_basic_user_profile(self): user = self.spotify.user(self.username) self.assertTrue(user['id'] == self.username.lower()) def test_current_user(self): user = self.spotify.current_user() self.assertTrue(user['id'] == self.username.lower()) def test_me(self): user = self.spotify.me() self.assertTrue(user['id'] == self.username.lower()) def test_user_playlists(self): playlists = self.spotify.user_playlists(self.username, limit=5) self.assertTrue('items' in playlists) self.assertTrue(len(playlists['items']) == 5) def test_user_playlist_tracks(self): playlists = self.spotify.user_playlists(self.username, limit=5) self.assertTrue('items' in playlists) for playlist in playlists['items']: user = playlist['owner']['id'] pid = playlist['id'] results = self.spotify.user_playlist_tracks(user, pid) self.assertTrue(len(results['items']) >= 0) def test_current_user_saved_albums(self): # List albums = self.spotify.current_user_saved_albums() self.assertTrue(len(albums['items']) > 1) # Add self.spotify.current_user_saved_albums_add(self.album_ids) # Contains self.assertTrue( self.spotify.current_user_saved_albums_contains( self.album_ids) == [ True, True]) # Remove self.spotify.current_user_saved_albums_delete(self.album_ids) albums = self.spotify.current_user_saved_albums() self.assertTrue(len(albums['items']) > 1) def test_current_user_playlists(self): playlists = self.spotify.current_user_playlists(limit=10) self.assertTrue('items' in playlists) self.assertTrue(len(playlists['items']) == 10) def test_user_playlist_follow(self): self.spotify.user_playlist_follow_playlist( 'plamere', '4erXB04MxwRAVqcUEpu30O') follows = self.spotify.user_playlist_is_following( 'plamere', '4erXB04MxwRAVqcUEpu30O', [ self.spotify.current_user()['id']]) self.assertTrue(len(follows) == 1, 'proper follows length') self.assertTrue(follows[0], 'is following') self.spotify.user_playlist_unfollow( 'plamere', '4erXB04MxwRAVqcUEpu30O') follows = self.spotify.user_playlist_is_following( 'plamere', '4erXB04MxwRAVqcUEpu30O', [ self.spotify.current_user()['id']]) self.assertTrue(len(follows) == 1, 'proper follows length') self.assertFalse(follows[0], 'is no longer following') def test_current_user_saved_tracks(self): tracks = self.spotify.current_user_saved_tracks() self.assertTrue(len(tracks['items']) > 0) def test_current_user_save_and_unsave_tracks(self): tracks = self.spotify.current_user_saved_tracks() total = tracks['total'] self.spotify.current_user_saved_tracks_add(self.four_tracks) tracks = self.spotify.current_user_saved_tracks() new_total = tracks['total'] self.assertTrue(new_total - total == len(self.four_tracks)) tracks = self.spotify.current_user_saved_tracks_delete( self.four_tracks) tracks = self.spotify.current_user_saved_tracks() new_total = tracks['total'] self.assertTrue(new_total == total) def test_categories(self): response = self.spotify.categories() self.assertTrue(len(response['categories']) > 0) def test_category_playlists(self): response = self.spotify.categories() for cat in response['categories']['items']: cat_id = cat['id'] response = self.spotify.category_playlists(category_id=cat_id) if len(response['playlists']["items"]) > 0: break self.assertTrue(True) def test_new_releases(self): response = self.spotify.new_releases() self.assertTrue(len(response['albums']) > 0) def test_featured_releases(self): response = self.spotify.featured_playlists() self.assertTrue(len(response['playlists']) > 0) def test_current_user_follows(self): response = self.spotify.current_user_followed_artists() artists = response['artists'] self.assertTrue(len(artists['items']) > 0) def test_current_user_top_tracks(self): response = self.spotify.current_user_top_tracks() items = response['items'] self.assertTrue(len(items) > 0) def test_current_user_top_artists(self): response = self.spotify.current_user_top_artists() items = response['items'] self.assertTrue(len(items) > 0) def test_current_user_recently_played(self): # No cursor res = self.spotify.current_user_recently_played() self.assertTrue(len(res['items']) <= 50) played_at = res['items'][0]['played_at'] # Using `before` gives tracks played before res = self.spotify.current_user_recently_played( before=res['cursors']['after']) self.assertTrue(len(res['items']) <= 50) self.assertTrue(res['items'][0]['played_at'] < played_at) played_at = res['items'][0]['played_at'] # Using `after` gives tracks played after res = self.spotify.current_user_recently_played( after=res['cursors']['before']) self.assertTrue(len(res['items']) <= 50) self.assertTrue(res['items'][0]['played_at'] > played_at) def test_user_playlist_ops(self): sp = self.spotify # create empty playlist playlist = self.get_or_create_spotify_playlist( 'spotipy-testing-playlist-1') playlist_id = playlist['id'] # remove all tracks from it sp.user_playlist_replace_tracks( self.username, playlist_id, []) playlist = sp.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 0) self.assertTrue(len(playlist['tracks']['items']) == 0) # add tracks to it sp.user_playlist_add_tracks( self.username, playlist_id, self.four_tracks) playlist = sp.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 4) self.assertTrue(len(playlist['tracks']['items']) == 4) # remove two tracks from it sp.user_playlist_remove_all_occurrences_of_tracks(self.username, playlist_id, self.two_tracks) playlist = sp.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 2) self.assertTrue(len(playlist['tracks']['items']) == 2) # replace with 3 other tracks sp.user_playlist_replace_tracks(self.username, playlist_id, self.other_tracks) playlist = sp.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 3) self.assertTrue(len(playlist['tracks']['items']) == 3) def test_playlist(self): # New playlist ID pl = self.spotify.playlist(self.playlist_new_id) self.assertTrue(pl["tracks"]["total"] > 0) # Old playlist ID pl = self.spotify.playlist(self.playlist) self.assertTrue(pl["tracks"]["total"] > 0) def test_playlist_tracks(self): # New playlist ID pl = self.spotify.playlist_tracks(self.playlist_new_id, limit=2) self.assertTrue(len(pl["items"]) == 2) self.assertTrue(pl["total"] > 0) # Old playlist ID pl = self.spotify.playlist_tracks(self.playlist, limit=2) self.assertTrue(len(pl["items"]) == 2) self.assertTrue(pl["total"] > 0) def test_playlist_upload_cover_image(self): pl1 = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1') plid = pl1['uri'] old_b64 = pl1['images'][0]['url'] # Upload random dog image r = requests.get('https://dog.ceo/api/breeds/image/random') dog_base64 = self.get_as_base64(r.json()['message']) self.spotify.playlist_upload_cover_image(plid, dog_base64) # Image must be different pl1 = self.spotify.playlist(plid) new_b64 = self.get_as_base64(pl1['images'][0]['url']) self.assertTrue(old_b64 != new_b64) def test_playlist_cover_image(self): pl = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1') plid = pl['uri'] res = self.spotify.playlist_cover_image(plid) self.assertTrue(len(res) > 0) first_image = res[0] self.assertTrue('width' in first_image) self.assertTrue('height' in first_image) self.assertTrue('url' in first_image) def test_user_follows_and_unfollows_artist(self): # Initially follows 1 artist res = self.spotify.current_user_followed_artists() self.assertTrue(res['artists']['total'] == 1) # Follow 2 more artists artists = ["6DPYiyq5kWVQS4RGwxzPC7", "0NbfKEOTQCcwd6o7wSDOHI"] self.spotify.user_follow_artists(artists) res = self.spotify.current_user_followed_artists() self.assertTrue(res['artists']['total'] == 3) # Unfollow these 2 artists self.spotify.user_unfollow_artists(artists) res = self.spotify.current_user_followed_artists() self.assertTrue(res['artists']['total'] == 1) def test_user_follows_and_unfollows_user(self): # TODO improve after implementing `me/following/contains` users = ["11111204", "xlqeojt6n7on0j7coh9go8ifd"] # Follow 2 more users self.spotify.user_follow_users(users) # Unfollow these 2 users self.spotify.user_unfollow_users(users) def test_deprecated_starred(self): pl = self.spotify.user_playlist(self.username) self.assertTrue(pl["tracks"] is None) self.assertTrue(pl["owner"] is None) def test_deprecated_user_playlist(self): # Test without user due to change from # https://developer.spotify.com/community/news/2018/06/12/changes-to-playlist-uris/ pl = self.spotify.user_playlist(None, self.playlist) self.assertTrue(pl["tracks"]["total"] > 0) def test_deprecated_user_playlis(self): # Test without user due to change from # https://developer.spotify.com/community/news/2018/06/12/changes-to-playlist-uris/ pl = self.spotify.user_playlist_tracks(None, self.playlist, limit=2) self.assertTrue(len(pl["items"]) == 2) self.assertTrue(pl["total"] > 0)
def create_playlist(session: spotipy.Spotify, name: str): playlist_all_data = session.user_playlist_create( session.me()['id'], name) # print(playlist_all_data) return playlist_all_data['id']
class AuthTestSpotipy(unittest.TestCase): """ These tests require user authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_USERNAME' 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' 'SPOTIPY_REDIRECT_URI' """ playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx" four_tracks = [ "spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB", "4VrWlk8IQxevMvERoX08iC", "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf" ] two_tracks = [ "spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB" ] other_tracks = [ "spotify:track:2wySlB6vMzCbQrRnNGOYKa", "spotify:track:29xKs5BAHlmlX1u4gzQAbJ", "spotify:track:1PB7gRWcvefzu7t3LJLUlf" ] bad_id = 'BAD_ID' @classmethod def setUpClass(self): missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV)) if missing: raise Exception( 'Please set the client credentials for the test application using the following environment variables: {}' .format(CCEV.values())) self.username = os.getenv(CCEV['client_username']) self.scope = ('playlist-modify-public ' 'user-library-read ' 'user-follow-read ' 'user-library-modify ' 'user-read-private ' 'user-top-read') self.token = prompt_for_user_token(self.username, scope=self.scope) self.spotify = Spotify(auth=self.token) def test_track_bad_id(self): try: track = self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_basic_user_profile(self): user = self.spotify.user(self.username) self.assertTrue(user['id'] == self.username.lower()) def test_current_user(self): user = self.spotify.current_user() self.assertTrue(user['id'] == self.username.lower()) def test_me(self): user = self.spotify.me() self.assertTrue(user['id'] == self.username.lower()) def test_user_playlists(self): playlists = self.spotify.user_playlists(self.username, limit=5) self.assertTrue('items' in playlists) self.assertTrue(len(playlists['items']) == 5) def test_user_playlist_tracks(self): playlists = self.spotify.user_playlists(self.username, limit=5) self.assertTrue('items' in playlists) for playlist in playlists['items']: user = playlist['owner']['id'] pid = playlist['id'] results = self.spotify.user_playlist_tracks(user, pid) self.assertTrue(len(results['items']) >= 0) def user_playlist_tracks(self, user, playlist_id=None, fields=None, limit=100, offset=0): # known API issue currently causes this test to fail # the issue is that the API doesn't currently respect the # limit paramter self.assertTrue(len(playlists['items']) == 5) def test_current_user_saved_tracks(self): tracks = self.spotify.current_user_saved_tracks() self.assertTrue(len(tracks['items']) > 0) def test_current_user_saved_albums(self): albums = self.spotify.current_user_saved_albums() self.assertTrue(len(albums['items']) > 0) def test_current_user_playlists(self): playlists = self.spotify.current_user_playlists(limit=10) self.assertTrue('items' in playlists) self.assertTrue(len(playlists['items']) == 10) def test_user_playlist_follow(self): self.spotify.user_playlist_follow_playlist('plamere', '4erXB04MxwRAVqcUEpu30O') follows = self.spotify.user_playlist_is_following( 'plamere', '4erXB04MxwRAVqcUEpu30O', [self.spotify.current_user()['id']]) self.assertTrue(len(follows) == 1, 'proper follows length') self.assertTrue(follows[0], 'is following') self.spotify.user_playlist_unfollow('plamere', '4erXB04MxwRAVqcUEpu30O') follows = self.spotify.user_playlist_is_following( 'plamere', '4erXB04MxwRAVqcUEpu30O', [self.spotify.current_user()['id']]) self.assertTrue(len(follows) == 1, 'proper follows length') self.assertFalse(follows[0], 'is no longer following') def test_current_user_save_and_unsave_tracks(self): tracks = self.spotify.current_user_saved_tracks() total = tracks['total'] self.spotify.current_user_saved_tracks_add(self.four_tracks) tracks = self.spotify.current_user_saved_tracks() new_total = tracks['total'] self.assertTrue(new_total - total == len(self.four_tracks)) tracks = self.spotify.current_user_saved_tracks_delete( self.four_tracks) tracks = self.spotify.current_user_saved_tracks() new_total = tracks['total'] self.assertTrue(new_total == total) def test_categories(self): response = self.spotify.categories() self.assertTrue(len(response['categories']) > 0) def test_category_playlists(self): response = self.spotify.categories() for cat in response['categories']['items']: cat_id = cat['id'] response = self.spotify.category_playlists(category_id=cat_id) if len(response['playlists']["items"]) > 0: break self.assertTrue(True) def test_new_releases(self): response = self.spotify.new_releases() self.assertTrue(len(response['albums']) > 0) def test_featured_releases(self): response = self.spotify.featured_playlists() self.assertTrue(len(response['playlists']) > 0) def test_current_user_follows(self): response = self.spotify.current_user_followed_artists() artists = response['artists'] self.assertTrue(len(artists['items']) > 0) def test_current_user_top_tracks(self): response = self.spotify.current_user_top_tracks() items = response['items'] self.assertTrue(len(items) > 0) def test_current_user_top_artists(self): response = self.spotify.current_user_top_artists() items = response['items'] self.assertTrue(len(items) > 0) def get_or_create_spotify_playlist(self, playlist_name): playlists = self.spotify.user_playlists(self.username) while playlists: for item in playlists['items']: if item['name'] == playlist_name: return item['id'] playlists = self.spotify.next(playlists) playlist = self.spotify.user_playlist_create(self.username, playlist_name) playlist_id = playlist['uri'] return playlist_id def test_user_playlist_ops(self): # create empty playlist playlist_id = self.get_or_create_spotify_playlist( 'spotipy-testing-playlist-1') # remove all tracks from it self.spotify.user_playlist_replace_tracks(self.username, playlist_id, []) playlist = self.spotify.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 0) self.assertTrue(len(playlist['tracks']['items']) == 0) # add tracks to it self.spotify.user_playlist_add_tracks(self.username, playlist_id, self.four_tracks) playlist = self.spotify.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 4) self.assertTrue(len(playlist['tracks']['items']) == 4) # remove two tracks from it self.spotify.user_playlist_remove_all_occurrences_of_tracks( self.username, playlist_id, self.two_tracks) playlist = self.spotify.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 2) self.assertTrue(len(playlist['tracks']['items']) == 2) # replace with 3 other tracks self.spotify.user_playlist_replace_tracks(self.username, playlist_id, self.other_tracks) playlist = self.spotify.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 3) self.assertTrue(len(playlist['tracks']['items']) == 3)
def backup_all_playlists(sp: spotipy.Spotify, file=None): all_playlists = [] all_tracks = get_track_index() playlists_offset = 0 while True: playlists = sp.current_user_playlists(limit=50, offset=playlists_offset) for playlist in playlists['items']: current_list = { 'name': playlist['name'], 'collaborative': playlist['collaborative'], 'public': playlist['public'], 'uri': playlist['uri'], 'owner_id': playlist['owner']['id'], 'tracks': [] } tracks_offset = 0 while True: playlist_tracks = sp.user_playlist_tracks( user=current_list['owner_id'], playlist_id=playlist['id'], fields='items(is_local,track(uri,id,name,artists.name,' 'album.name)),next', limit=100, offset=tracks_offset) for playlist_item in playlist_tracks['items']: track = playlist_item['track'] track_id = track['id'] # Local tracks doesn't have a Spotify ID, so we'll use its Spotify URI as an ID instead if playlist_item['is_local']: track_id = track['uri'] current_list['tracks'].append(track_id) if track_id not in all_tracks: print('Adding new track {} to track index'.format( track['name'])) all_tracks[track_id] = { 'name': track['name'], 'artists': [artist['name'] for artist in track['artists']], 'album': track['album']['name'], } if playlist_tracks['next'] is None: break tracks_offset += 100 print('List {} has {} tracks'.format(current_list['name'], len(current_list['tracks']))) all_playlists.append(current_list) if playlists['next'] is None: break playlists_offset += 50 print('Total num lists: {}'.format(len(all_playlists))) print('Total num unique tracks: {}'.format(len(all_tracks))) def json_dump_compact(obj, fp): json.dump(obj=obj, fp=fp, separators=(',', ':')) if file is None: user_id = sp.me()['id'] with open( 'spotify_backup_{}_{}.json'.format( user_id, datetime.now().strftime('%Y-%m-%d_%H%M')), 'w') as file: json_dump_compact(all_playlists, file) else: json_dump_compact(all_playlists, file) with open('spotify_track_index.json', 'w') as track_index_file: json_dump_compact(all_tracks, track_index_file)
class AuthTestSpotipy(unittest.TestCase): """ These tests require user authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_USERNAME' 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' 'SPOTIPY_REDIRECT_URI' """ playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx" playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI" four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB", "4VrWlk8IQxevMvERoX08iC", "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"] two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB"] other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa", "spotify:track:29xKs5BAHlmlX1u4gzQAbJ", "spotify:track:1PB7gRWcvefzu7t3LJLUlf"] album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU", "spotify:album:6RTzC0rDbvagTSJLlY7AKl"] bad_id = 'BAD_ID' @classmethod def setUpClass(self): missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV)) if missing: raise Exception( ('Please set the client credentials for the test application' ' using the following environment variables: {}').format( CCEV.values())) self.username = os.getenv(CCEV['client_username']) self.scope = ( 'playlist-modify-public ' 'user-library-read ' 'user-follow-read ' 'user-library-modify ' 'user-read-private ' 'user-top-read ' 'user-follow-modify' ) self.token = prompt_for_user_token(self.username, scope=self.scope) self.spotify = Spotify(auth=self.token) def test_track_bad_id(self): try: self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_basic_user_profile(self): user = self.spotify.user(self.username) self.assertTrue(user['id'] == self.username.lower()) def test_current_user(self): user = self.spotify.current_user() self.assertTrue(user['id'] == self.username.lower()) def test_me(self): user = self.spotify.me() self.assertTrue(user['id'] == self.username.lower()) def test_user_playlists(self): playlists = self.spotify.user_playlists(self.username, limit=5) self.assertTrue('items' in playlists) self.assertTrue(len(playlists['items']) == 5) def test_user_playlist_tracks(self): playlists = self.spotify.user_playlists(self.username, limit=5) self.assertTrue('items' in playlists) for playlist in playlists['items']: user = playlist['owner']['id'] pid = playlist['id'] results = self.spotify.user_playlist_tracks(user, pid) self.assertTrue(len(results['items']) >= 0) # known API issue currently causes this test to fail # the issue is that the API doesn't currently respect the # limit parameter # def user_playlist_tracks(self, user, playlist_id=None, fields=None, # limit=100, offset=0): # self.assertTrue(len(playlists['items']) == 5) def test_current_user_saved_albums(self): # List albums = self.spotify.current_user_saved_albums() self.assertTrue(len(albums['items']) == 1) # Add self.spotify.current_user_saved_albums_add(self.album_ids) # Contains self.assertTrue( self.spotify.current_user_saved_albums_contains( self.album_ids) == [ True, True]) # Remove self.spotify.current_user_saved_albums_delete(self.album_ids) albums = self.spotify.current_user_saved_albums() self.assertTrue(len(albums['items']) == 1) def test_current_user_playlists(self): playlists = self.spotify.current_user_playlists(limit=10) self.assertTrue('items' in playlists) self.assertTrue(len(playlists['items']) == 10) def test_user_playlist_follow(self): self.spotify.user_playlist_follow_playlist( 'plamere', '4erXB04MxwRAVqcUEpu30O') follows = self.spotify.user_playlist_is_following( 'plamere', '4erXB04MxwRAVqcUEpu30O', [ self.spotify.current_user()['id']]) self.assertTrue(len(follows) == 1, 'proper follows length') self.assertTrue(follows[0], 'is following') self.spotify.user_playlist_unfollow( 'plamere', '4erXB04MxwRAVqcUEpu30O') follows = self.spotify.user_playlist_is_following( 'plamere', '4erXB04MxwRAVqcUEpu30O', [ self.spotify.current_user()['id']]) self.assertTrue(len(follows) == 1, 'proper follows length') self.assertFalse(follows[0], 'is no longer following') def test_current_user_saved_tracks(self): tracks = self.spotify.current_user_saved_tracks() self.assertTrue(len(tracks['items']) > 0) def test_current_user_save_and_unsave_tracks(self): tracks = self.spotify.current_user_saved_tracks() total = tracks['total'] self.spotify.current_user_saved_tracks_add(self.four_tracks) tracks = self.spotify.current_user_saved_tracks() new_total = tracks['total'] self.assertTrue(new_total - total == len(self.four_tracks)) tracks = self.spotify.current_user_saved_tracks_delete( self.four_tracks) tracks = self.spotify.current_user_saved_tracks() new_total = tracks['total'] self.assertTrue(new_total == total) def test_categories(self): response = self.spotify.categories() self.assertTrue(len(response['categories']) > 0) def test_category_playlists(self): response = self.spotify.categories() for cat in response['categories']['items']: cat_id = cat['id'] response = self.spotify.category_playlists(category_id=cat_id) if len(response['playlists']["items"]) > 0: break self.assertTrue(True) def test_new_releases(self): response = self.spotify.new_releases() self.assertTrue(len(response['albums']) > 0) def test_featured_releases(self): response = self.spotify.featured_playlists() self.assertTrue(len(response['playlists']) > 0) def test_current_user_follows(self): response = self.spotify.current_user_followed_artists() artists = response['artists'] self.assertTrue(len(artists['items']) > 0) def test_current_user_top_tracks(self): response = self.spotify.current_user_top_tracks() items = response['items'] self.assertTrue(len(items) > 0) def test_current_user_top_artists(self): response = self.spotify.current_user_top_artists() items = response['items'] self.assertTrue(len(items) > 0) def get_or_create_spotify_playlist(self, playlist_name): playlists = self.spotify.user_playlists(self.username) while playlists: for item in playlists['items']: if item['name'] == playlist_name: return item['id'] playlists = self.spotify.next(playlists) playlist = self.spotify.user_playlist_create( self.username, playlist_name) playlist_id = playlist['uri'] return playlist_id def test_user_playlist_ops(self): sp = self.spotify # create empty playlist playlist_id = self.get_or_create_spotify_playlist( 'spotipy-testing-playlist-1') # remove all tracks from it sp.user_playlist_replace_tracks( self.username, playlist_id, []) playlist = sp.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 0) self.assertTrue(len(playlist['tracks']['items']) == 0) # add tracks to it sp.user_playlist_add_tracks( self.username, playlist_id, self.four_tracks) playlist = sp.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 4) self.assertTrue(len(playlist['tracks']['items']) == 4) # remove two tracks from it sp.user_playlist_remove_all_occurrences_of_tracks(self.username, playlist_id, self.two_tracks) playlist = sp.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 2) self.assertTrue(len(playlist['tracks']['items']) == 2) # replace with 3 other tracks sp.user_playlist_replace_tracks(self.username, playlist_id, self.other_tracks) playlist = sp.user_playlist(self.username, playlist_id) self.assertTrue(playlist['tracks']['total'] == 3) self.assertTrue(len(playlist['tracks']['items']) == 3) def test_playlist(self): # New playlist ID pl = self.spotify.playlist(self.playlist_new_id) self.assertTrue(pl["tracks"]["total"] > 0) # Old playlist ID pl = self.spotify.playlist(self.playlist) self.assertTrue(pl["tracks"]["total"] > 0) def test_user_follows_and_unfollows_artist(self): # Initially follows 1 artist res = self.spotify.current_user_followed_artists() self.assertTrue(res['artists']['total'] == 1) # Follow 2 more artists artists = ["6DPYiyq5kWVQS4RGwxzPC7", "0NbfKEOTQCcwd6o7wSDOHI"] self.spotify.user_follow_artists(artists) res = self.spotify.current_user_followed_artists() self.assertTrue(res['artists']['total'] == 3) # Unfollow these 2 artists self.spotify.user_unfollow_artists(artists) res = self.spotify.current_user_followed_artists() self.assertTrue(res['artists']['total'] == 1) def test_user_follows_and_unfollows_user(self): # TODO improve after implementing `me/following/contains` users = ["11111204", "xlqeojt6n7on0j7coh9go8ifd"] # Follow 2 more users self.spotify.user_follow_users(users) # Unfollow these 2 users self.spotify.user_unfollow_users(users)