def get_track_features(track_id: str, sp: spotipy.Spotify): """get dict of track features""" if track_id is None: return None else: features = sp.audio_features([track_id]) return features
def get_song_features_from_query(query: str, sp: spotipy.Spotify) -> Dict[str, float]: all_features = { "danceability": 0.0, "energy": 0.0, "speechiness": 0.0, "acousticness": 0.0, "instrumentalness": 0.0, "liveness": 0.0, "valence": 0.0, "tempo": 0.0, } result = sp.search(query, type="track", limit=10) tracks = result["tracks"]["items"] numSongs = len(tracks) for song in tracks: track_features = sp.audio_features(song["uri"])[0] for feature in all_features: all_features[feature] = all_features[feature] + track_features[feature] for feature in all_features: all_features[feature] = all_features[feature] / numSongs return all_features
def add_audio_features(songs: List[Song], sp: spotipy.Spotify) -> List[Song]: if not songs: return [] annotated_songs = [] feature_list = [] for song in songs: if song["uri"] in feature_memo: features = feature_memo[song["uri"]] else: features = sp.audio_features(song["uri"])[0] feature_list.append(features) for song, features in zip(songs, feature_list): feel = { "energy": features["energy"], "dance": features["danceability"], "lyrics": features["speechiness"], "valence": features["valence"], } song["features"] = feel annotated_songs.append(song) return annotated_songs
def suggest_audio_features_tags(tracks): tags = [] token = sp_oauth.get_cached_token()['access_token'] sp = Spotify(token) track_ids = [t['track']['id'] for t in tracks][:min(len(tracks), 100)] audio_features = sp.audio_features(tracks=track_ids) if average_field(audio_features, 'danceability') > .75: tags.append(Tag.objects.get(name="Party", category=TAG_CATEGORY_MOOD)) avg_tempo = average_field(audio_features, 'tempo') if avg_tempo > 120 and avg_tempo < 150: tags.append(Tag.objects.get(name="Roadtrip", category=TAG_CATEGORY_MOOD)) avg_energy = average_field(audio_features, 'energy') avg_valence = average_field(audio_features, 'valence') # Refactor this bullshit mess # No magic numbers if avg_energy > .7 and avg_valence > .7: tags.append(Tag.objects.get(name="Upbeat", category=TAG_CATEGORY_MOOD)) elif avg_energy < .4 and avg_valence > .7: tags.append(Tag.objects.get(name="Relaxed", category=TAG_CATEGORY_MOOD)) elif avg_energy < .4 and avg_valence < .4: tags.append(Tag.objects.get(name="Melancholy", category=TAG_CATEGORY_MOOD)) elif avg_energy > .7 and avg_valence < .4: tags.append(Tag.objects.get(name="Angry", category=TAG_CATEGORY_MOOD)) return tags
def get_track_audio_features(sp_api: Spotify, base_track: dict): audio_features: dict = dict() try: track_id: str = base_track.get('id') res: list = sp_api.audio_features([track_id]) audio_features: dict = res[0] audio_features.pop('duration_ms', None) audio_features.pop('track_href', None) except Exception as e: logger.error(e) return audio_features
def newCreateVibe(self, playlistName, token): # find playlist spotifyObject = Spotify(auth=token) spotifyUser = spotifyObject.current_user() username = spotifyUser['id'] # find playlist playlistID = playlistName #create genre dictionary genreDict = {} # get songs from playlist playlistSongs = spotifyObject.user_playlist_tracks(user=username, playlist_id=playlistID) numberOfSongs = int(playlistSongs['total']) totalAdded = int(0) songObjectsList = [] songID_List = [] while (numberOfSongs > totalAdded): playlistSongs = spotifyObject.user_playlist_tracks(user=username, playlist_id=playlistID, offset=totalAdded) for i in range(0, len(playlistSongs['items'])): try: songURI = playlistSongs['items'][i]['track']['uri'] songID = playlistSongs['items'][i]['track']['id'] songID_List.append(songID) songFeatures = spotifyObject.audio_features(songURI) genreDict = self.genreVibe(spotifyObject=spotifyObject, songId=songID, genreDict=genreDict) songObj = [songFeatures[0]['acousticness'], songFeatures[0]['danceability'], songFeatures[0]['energy'], songFeatures[0]['instrumentalness'], songFeatures[0]['liveness'], songFeatures[0]['speechiness'], round(songFeatures[0]['tempo'] / 180, 6), songFeatures[0]['valence']] songObjectsList.append(songObj) except: print("song was removed from spotify sorry") totalAdded = totalAdded + 100 centroidsAndError = self.KMeansVibe(data=songObjectsList) centroidsAndError_GenreDict = [centroidsAndError, genreDict, songID_List] return centroidsAndError_GenreDict
def cache(album_descriptions: List[AlbumDescription], sp: spotipy.Spotify) -> None: """ Cache the results for the given album descriptions for fast lookup later. Calling this before using the spotify methods on a list of albums will improve performance. """ global search_memo global album_tracks_memo global feature_memo missed = [False, False, False] for title, artists in album_descriptions: q = query(title, artists) if q not in search_memo: missed[0] = True search_memo[q] = sp.search(query(title, artists), type="album", limit=50) album_id = find_album_id_from_search(search_memo[q], artists) if album_id is not None and album_id not in album_tracks_memo: missed[1] = True album_tracks_memo[album_id] = sp.album_tracks(album_id) if missed[0]: set_memo(search_memo, "search") if missed[1]: set_memo(album_tracks_memo, "tracks") songs = get_songs(album_descriptions, sp) for songs_chunk in util.chunks(iter(songs), 100): seenAllSongs = True song_links = [song["uri"] for song in songs_chunk] for link in song_links: if link not in feature_memo: seenAllSongs = False if not seenAllSongs: missed[2] = True feature_list = sp.audio_features(song_links) for uri, features in zip(song_links, feature_list): feature_memo[uri] = features if missed[2]: set_memo(feature_memo, "features")
def audio_features(): """Get the audio features for a Spotify track This function takes a request with a given track ID and returns a JSON object with the audio features and track identification Returns ------- json a json of the audio features and track identification to send to the back-end """ token = credentials.get_access_token() spotify = Spotify(auth=token) track_id = request.args.get('track_id', default='06w9JimcZu16KyO3WXR459', type=str) results = spotify.audio_features(track_id) return json.dumps(results)
def retrieve_audio_features(self, spotify: Spotify, features: List[str]) -> dict: """ call spotify api and retrieve audio features """ audio_features = spotify.audio_features(self.id)[0] rowdict = {'release_date': self.release_date, 'song_name': self.name} audio_features_dict = {} for col in features: try: rowdict[col] = audio_features[col] audio_features_dict[col] = audio_features[col] except KeyError as ke: print( f'Could not find {col} in returned audio features for {self.name}' ) continue self.audio_features = audio_features_dict return audio_features_dict
def newBuildPlaylist (self, playlistName, clustersAndError, token, newPlaylist, genreDict): # get user spotifyObject = Spotify(auth=token) spotifyUser = spotifyObject.current_user() username = spotifyUser['id'] # find playlist playlistID = playlistName # find playlist where we will add songs playlist_to_add_to = newPlaylist #vibe Genres vibeGenresTest = genreDict vibeGenres = [] for vibe in vibeGenresTest: vibeGenres.append(str(vibe)) songGenreDict = {} # get songs playlist = spotifyObject.user_playlist_tracks(user=username, playlist_id=playlistID) numberOfSongs = int(playlist['total']) totalAdded = int(0) songsToAdd = [] listOfAllSongsToAdd = [] while (numberOfSongs > totalAdded): playlist = spotifyObject.user_playlist_tracks(user=username, playlist_id=playlistID, offset=totalAdded) for i in range(0, len(playlist['items'])): try: songURI = playlist['items'][i]['track']['uri'] songId = playlist['items'][i]['track']['id'] songFeatures = spotifyObject.audio_features(songURI) #if song contains a genre that matches the inputted vibe if (self.songGenreInVibe(spotifyObject=spotifyObject, songId=songId, songGenreDict=songGenreDict, vibeGenreDict=vibeGenres) == True): song = [[songFeatures[0]['acousticness'], songFeatures[0]['danceability'], songFeatures[0]['energy'], songFeatures[0]['instrumentalness'], songFeatures[0]['liveness'], songFeatures[0]['speechiness'], round(songFeatures[0]['tempo'] / 180, 6), songFeatures[0]['valence']]] distArray = cdist(song, clustersAndError[0], 'euclidean') dist = min(distArray[0]) #is the min distance between song and cluster within average min distance if float(dist) < float(clustersAndError[1]): songsToAdd.append(songURI) if len(songsToAdd) == 100 or i == len(playlist['items']) - 1: listOfAllSongsToAdd.append(songsToAdd) songsToAdd = [] except: print("spotify does not have this song anymore. Sorry") totalAdded = totalAdded + 100 if (len(listOfAllSongsToAdd) < 1): #if there is less than 100 songs to add spotifyObject.user_playlist_add_tracks(user=username, playlist_id=playlist_to_add_to, tracks=songsToAdd) else: for songs in listOfAllSongsToAdd: spotifyObject.user_playlist_add_tracks(user=username, playlist_id=playlist_to_add_to, tracks=songs) time.sleep(5)
class SpotifyConnection(object): def __init__(self, user_data): self.user_name = user_data['user_name'] token = spotipy.util.prompt_for_user_token( self.user_name, scope='user-read-recently-played', client_id=user_data['client_id'], client_secret=user_data['client_secret'], redirect_uri=user_data['redirect_uri']) self.client = Spotify(auth=token) self.db = self.init_db() def init_db(self): return PostgreSQLConnection() def get_artist(self, artist_id): artist = self.db.session.query(Artist).get(artist_id) if artist: return artist else: artist_response = self.client.artist(artist_id) artist = Artist() artist.artist_id = artist_id artist.artist_data = artist_response self.db.save_instance(artist) print("> Artist {} was not in database.".format( artist.artist_data['name'])) return self.db.session.query(Artist).get(artist_id) def get_album(self, album_id): album = self.db.session.query(Album).get(album_id) if album: return album else: album_response = self.client.album(album_id) album = Album() album.album_data = album_response album.album_id = album_response['id'] # Artists for album_artist_response in album_response['artists']: album.artists.append( self.get_artist(album_artist_response['id'])) self.db.save_instance(album) print("> Album {} was not in database.".format( album.album_data['name'])) return self.db.session.query(Album).get(album_id) def get_track(self, track_id): track = self.db.session.query(Track).get(track_id) if track: return track else: response = self.client.track(track_id) track = Track() track.track_id = track_id track.track_data = response # Album track.album = self.get_album(response['album']['id']) # Artists for artist_response in response['artists']: track.artists.append(self.get_artist(artist_response['id'])) # Audio feature audio_feature_response = self.client.audio_features(track_id)[0] if audio_feature_response: # Some tracks do not have audio features track.audio_feature_data = audio_feature_response print("> Track {} was not in database.".format( track.track_data['name'])) self.db.save_instance(track) return self.db.session.query(Track).get(track_id) def get_play_from_played_at_utc_and_track_id(self, played_at_utc, track_id): played_at_utc = convert_played_at_from_response_to_datetime( played_at_utc) played_at_utc = set_timezone_to_datetime(played_at_utc, timezone='UTC') played_at_cet = convert_datetime_from_timezone_to_timezone( played_at_utc, from_tz_code='UTC', to_tz_code='CET') # Play play = Play() play.user_name = self.user_name play.played_at_utc_timestamp = played_at_utc.timestamp() * 1000 play.played_at_utc = played_at_utc play.played_at_cet = played_at_cet play.day = played_at_cet.day play.month = played_at_cet.month play.year = played_at_cet.year play.hour = played_at_cet.hour play.minute = played_at_cet.minute play.second = played_at_cet.second play.day_of_week = played_at_cet.weekday() play.week_of_year = played_at_cet.date().isocalendar()[1] # Track track = self.get_track(track_id) play.track = track play.track_id = track_id return play def _get_play_tuples_from_response(self, response): plays = [] for item in response['items']: play_tuple = (item['played_at'], item['track']['id']) plays.append(play_tuple) return plays def _get_play_tuples(self, limit=50, after=None): play_tuples = [] response = self.client._get('me/player/recently-played', after=after, limit=limit) play_tuples.extend(self._get_play_tuples_from_response(response)) while response and 'next' in response: response = self.client.next(response) if response: play_tuples.extend( self._get_play_tuples_from_response(response)) return play_tuples def extract_plays(self): print("* Extracting latest plays of {}.".format(self.user_name)) play_tuples = self._get_play_tuples() for played_at, track_id in play_tuples: play = self.get_play_from_played_at_utc_and_track_id( played_at, track_id) self.db.save_play(play)
# Get track information for chosen playlist (limited to 100 tracks per API call) output = [] for offset in range(0,1100,100): playlist = sp.user_playlist_tracks(user, playlist_uri, limit=100, offset=offset) output += playlist['items'] # Create output dictionary with track information, including audio features res = [] for item in output: row = {'artists':[]} for artist in item['track']['artists']: row['artists'].append(artist['name']) row['title'] = item['track']['name'] row['explicit'] = item['track']['explicit'] analysis = sp.audio_features([item['track']['uri']])[0] for key, value in analysis.items(): row[key] = value res.append(row) # Parse artist list into separate fields, clean titles res_cleaned = [] for track in res: row = {} for key,value in track.items(): if key == 'artists': row['num_artists'] = len(value) for i in range(0,len(value)): row['artist_{0}'.format(i+1)] = value[i] elif key == 'title': title = value
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): self.spotify = Spotify( client_credentials_manager=SpotifyClientCredentials()) self.spotify.trace = False def test_audio_analysis(self): result = self.spotify.audio_analysis(self.four_tracks[0]) assert ('beats' in result) def test_audio_features(self): results = self.spotify.audio_features(self.four_tracks) self.assertTrue(len(results) == len(self.four_tracks)) for track in results: assert ('speechiness' in track) def test_audio_features_with_bad_track(self): bad_tracks = [] bad_tracks = ['spotify:track:bad'] input = self.four_tracks + bad_tracks results = self.spotify.audio_features(input) self.assertTrue(len(results) == len(input)) for track in results[:-1]: if track is not None: assert ('speechiness' in track) self.assertTrue(results[-1] is None) def test_recommendations(self): results = self.spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50) self.assertTrue(len(results['tracks']) == 20)
class AuthTestSpotipy(unittest.TestCase): """ These tests require client authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' """ 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' creep_urn = 'spotify:track:3HfB5hBU0dmBt8T0iCmH42' creep_id = '3HfB5hBU0dmBt8T0iCmH42' creep_url = 'http://open.spotify.com/track/3HfB5hBU0dmBt8T0iCmH42' el_scorcho_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQJ' el_scorcho_bad_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQK' pinkerton_urn = 'spotify:album:04xe676vyiTeYNXw15o9jT' weezer_urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu' pablo_honey_urn = 'spotify:album:6AZv3m27uyRxi8KyJSfUxL' radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb' angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM' @classmethod def setUpClass(self): self.spotify = Spotify( client_credentials_manager=SpotifyClientCredentials()) self.spotify.trace = False def test_audio_analysis(self): result = self.spotify.audio_analysis(self.four_tracks[0]) assert ('beats' in result) def test_audio_features(self): results = self.spotify.audio_features(self.four_tracks) self.assertTrue(len(results) == len(self.four_tracks)) for track in results: assert ('speechiness' in track) def test_audio_features_with_bad_track(self): bad_tracks = ['spotify:track:bad'] input = self.four_tracks + bad_tracks results = self.spotify.audio_features(input) self.assertTrue(len(results) == len(input)) for track in results[:-1]: if track is not None: assert ('speechiness' in track) self.assertTrue(results[-1] is None) def test_recommendations(self): results = self.spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50) self.assertTrue(len(results['tracks']) == 20) def test_artist_urn(self): artist = self.spotify.artist(self.radiohead_urn) self.assertTrue(artist['name'] == 'Radiohead') def test_artists(self): results = self.spotify.artists([self.weezer_urn, self.radiohead_urn]) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 2) def test_album_urn(self): album = self.spotify.album(self.pinkerton_urn) self.assertTrue(album['name'] == 'Pinkerton') def test_album_tracks(self): results = self.spotify.album_tracks(self.pinkerton_urn) self.assertTrue(len(results['items']) == 10) def test_album_tracks_many(self): results = self.spotify.album_tracks(self.angeles_haydn_urn) tracks = results['items'] total, received = results['total'], len(tracks) while received < total: results = self.spotify.album_tracks(self.angeles_haydn_urn, offset=received) tracks.extend(results['items']) received = len(tracks) self.assertEqual(received, total) def test_albums(self): results = self.spotify.albums( [self.pinkerton_urn, self.pablo_honey_urn]) self.assertTrue('albums' in results) self.assertTrue(len(results['albums']) == 2) def test_track_urn(self): track = self.spotify.track(self.creep_urn) self.assertTrue(track['name'] == 'Creep') def test_track_id(self): track = self.spotify.track(self.creep_id) self.assertTrue(track['name'] == 'Creep') self.assertTrue(track['popularity'] > 0) def test_track_url(self): track = self.spotify.track(self.creep_url) self.assertTrue(track['name'] == 'Creep') def test_track_bad_urn(self): try: self.spotify.track(self.el_scorcho_bad_urn) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_tracks(self): results = self.spotify.tracks([self.creep_url, self.el_scorcho_urn]) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 2) def test_artist_top_tracks(self): results = self.spotify.artist_top_tracks(self.weezer_urn) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 10) def test_artist_related_artists(self): results = self.spotify.artist_related_artists(self.weezer_urn) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 20) for artist in results['artists']: if artist['name'] == 'Jimmy Eat World': found = True self.assertTrue(found) def test_artist_search(self): results = self.spotify.search(q='weezer', type='artist') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_search_with_market(self): results = self.spotify.search(q='weezer', type='artist', market='GB') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_albums(self): results = self.spotify.artist_albums(self.weezer_urn) self.assertTrue('items' in results) self.assertTrue(len(results['items']) > 0) found = False for album in results['items']: if album['name'] == 'Hurley': found = True self.assertTrue(found) def test_search_timeout(self): client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify( client_credentials_manager=client_credentials_manager, requests_timeout=.01) try: sp.search(q='my*', type='track') self.assertTrue(False, 'unexpected search timeout') except requests.exceptions.Timeout: self.assertTrue(True, 'expected search timeout') def test_album_search(self): results = self.spotify.search(q='weezer pinkerton', type='album') self.assertTrue('albums' in results) self.assertTrue(len(results['albums']['items']) > 0) self.assertTrue( results['albums']['items'][0]['name'].find('Pinkerton') >= 0) def test_track_search(self): results = self.spotify.search(q='el scorcho weezer', type='track') self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']['items']) > 0) self.assertTrue(results['tracks']['items'][0]['name'] == 'El Scorcho') def test_user(self): user = self.spotify.user(user='******') self.assertTrue(user['uri'] == 'spotify:user:plamere') def test_track_bad_id(self): try: self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_unauthenticated_post_fails(self): with self.assertRaises(SpotifyException) as cm: self.spotify.user_playlist_create("spotify", "Best hits of the 90s") self.assertTrue(cm.exception.http_status == 401 or cm.exception.http_status == 403) def test_custom_requests_session(self): sess = requests.Session() sess.headers["user-agent"] = "spotipy-test" with_custom_session = spotipy.Spotify( client_credentials_manager=SpotifyClientCredentials(), requests_session=sess) self.assertTrue( with_custom_session.user(user="******")["uri"] == "spotify:user:akx") sess.close() def test_force_no_requests_session(self): from requests import Session with_no_session = spotipy.Spotify( client_credentials_manager=SpotifyClientCredentials(), requests_session=False) self.assertFalse(isinstance(with_no_session._session, Session)) self.assertTrue( with_no_session.user(user="******")["uri"] == "spotify:user:akx")
class iSpotify(object): def __init__(self): self.token = None def connectSpotify(self, d_credentials, service_name): self.auth = oauth2.SpotifyClientCredentials( **d_credentials[service_name]) self.token = self.auth.get_access_token() self.tk_spot = Spotify(auth=self.token) def regenerateTokenIfExpired(self): self.token = self.auth.get_access_token() self.tk_spot = Spotify(auth=self.token) def getCategories(self, country='US', locale='en_US', limit=50, offset=0): self.regenerateTokenIfExpired() self.categories = dumps( self.tk_spot.categories(country='US', locale='en_US', limit=20, offset=offset)) def getCategoryNewReleases(self, cat_id, limit=50, country='US', offset=0): self.regenerateTokenIfExpired() self.category_new_releases = dumps( self.tk_spot.category_playlists(cat_id, limit=limit, country=country, offset=offset)) def getUserPlayList(self, user_id, limit=50, offset=0): self.regenerateTokenIfExpired() self.user_playlists = dumps( self.tk_spot.user_playlists(user_id, limit=limit, offset=offset)) def getPlaylistTracks(self, owner_id, playlist_id, limit=50, country='US', offset=0): self.regenerateTokenIfExpired() self.playlist_tracks = dumps( self.tk_spot.user_playlist_tracks(owner_id, playlist_id, limit=limit, market=country, offset=offset)) def getAlbums(self, album_id=[]): self.regenerateTokenIfExpired() self.albums = dumps(self.tk_spot.albums(album_id)) def getArtists(self, artist_id=[]): self.regenerateTokenIfExpired() self.artists = dumps(self.tk_spot.artists(artist_id)) def getAudioFeatures(self, track_id): self.regenerateTokenIfExpired() self.audio_features = dumps(self.tk_spot.audio_features(track_id)) def getAudioAnalysis(self, track_id): self.regenerateTokenIfExpired() self.audio_analysis = dumps(self.tk_spot.audio_analysis(track_id))
class SpotifyWrapper(object): def __init__(self, client_creds, albums): iprint("Setting up Spotify client") self.sp = Spotify(client_credentials_manager=SpotifyClientCredentials( *client_creds)) self.sp.trace = False # Sqpotify API endpoint limits self.MAX_ALBUMS = 20 self.MAX_AUDIO_FEATS = 100 self.MAX_SEARCH = 50 self.albums = albums self.table = [] def get_table(self): return self.table def get_albums_uris(self): iprint("Getting album URIs") failed_resp = 0 for album_ix, album in enumerate(self.albums): resp = self.sp.search(q="album:{} artist:{}".format(*album[1:3]), type="album", limit=self.MAX_SEARCH)["albums"] if resp["total"]: self.table.append(( album[10:] + (resp["items"][0]["uri"].replace("spotify:album:", ''), ))) sprint("Received response for: ", " by ".join(album[1:3])) else: self.table.append((album[10:] + (None, ))) failed_resp += 1 wprint("No response for: ", " by ".join(album[1:3])) if failed_resp: wprint("Responses received for {}/{} albums".format( len(self.table) - failed_resp, len(self.table))) else: iprint("Responses received for {}/{} albums".format( len(self.table) - failed_resp, len(self.table))) def get_tracklists_uris(self): tracklists = [] iprint("Getting tracks URIs") # increment by MAX_ALBUMS album IDs for album_ix in range(0, len(self.table), self.MAX_ALBUMS): resp = self.sp.albums([ album[-1] for album in self.table[album_ix:album_ix + self.MAX_ALBUMS] if album[-1] ]) # append all the responses tracklists.append(resp) sprint("Received {} tracks".format(len(resp["albums"]))) # flatten tracklist array tracklists = [item for ll in tracklists if ll for item in ll["albums"]] album_ix = 0 tracks_ix = 0 while album_ix < len(self.table): if self.table[album_ix][-1]: self.table[album_ix] = ( self.table[album_ix] + ( # comma joined URIs ",".join(tracks["uri"].replace("spotify:track:", '') for tracks in tracklists[tracks_ix]["tracks"] ["items"]), # percentage of explicit tracks np.mean( np.array([ tracks["explicit"] for tracks in tracklists[tracks_ix]["tracks"]["items"] ])))) tracks_ix += 1 else: self.table[album_ix] = self.table[album_ix] + (None, np.NaN) album_ix += 1 def __stats(self, feats): stats = [len(feats)] for attr, attr_type in FEATS: try: stats.append(np.mean(np.array([resp[attr] for resp in feats]))) stats.append( np.median(np.array([resp[attr] for resp in feats]))) if attr_type is not np.bool: stats.append( np.min( np.array([attr_type(resp[attr]) for resp in feats]))) stats.append( np.max( np.array([attr_type(resp[attr]) for resp in feats]))) except TypeError as e: eprint("Response error with {} {}".format(", ".join(feats), e)) return tuple(stats) def get_tracks_analysis(self): iprint("Getting audio analysis on tracks") track_uris = ",".join(i[-2] for i in self.table if i[-2]).split(",") feats = [] for uri_ix in range(0, len(track_uris), self.MAX_AUDIO_FEATS): feats.extend( self.sp.audio_features(track_uris[uri_ix:uri_ix + self.MAX_AUDIO_FEATS])) sprint("Audio features received for {} tracklists".format( len(feats))) uri_ix = 0 for album_ix in range(len(self.table)): album_uris = self.table[album_ix][-2] if album_uris: n_albums = album_uris.count(",") + 1 self.table[album_ix] = ( self.table[album_ix][2:] + self.__stats(feats[uri_ix:uri_ix + n_albums])) uri_ix += n_albums else: self.table[album_ix] = (self.table[album_ix][2:] + (np.NaN, ) * 51)
def get_audio_features(sp: Spotify, track_ids: List[str]) -> List[Dict[str, Any]]: """Returns audio features for tracks given their ID or URI""" return sp.audio_features(track_ids)
class AuthTestSpotipy(unittest.TestCase): """ These tests require client authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' """ 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' creep_urn = 'spotify:track:6b2oQwSGFkzsMtQruIWm2p' creep_id = '6b2oQwSGFkzsMtQruIWm2p' creep_url = 'http://open.spotify.com/track/6b2oQwSGFkzsMtQruIWm2p' el_scorcho_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQJ' el_scorcho_bad_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQK' pinkerton_urn = 'spotify:album:04xe676vyiTeYNXw15o9jT' weezer_urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu' pablo_honey_urn = 'spotify:album:6AZv3m27uyRxi8KyJSfUxL' radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb' angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM' heavyweight_urn = 'spotify:show:5c26B28vZMN8PG0Nppmn5G' heavyweight_id = '5c26B28vZMN8PG0Nppmn5G' heavyweight_url = 'https://open.spotify.com/show/5c26B28vZMN8PG0Nppmn5G' reply_all_urn = 'spotify:show:7gozmLqbcbr6PScMjc0Zl4' heavyweight_ep1_urn = 'spotify:episode:68kq3bNz6hEuq8NtdfwERG' heavyweight_ep1_id = '68kq3bNz6hEuq8NtdfwERG' heavyweight_ep1_url = 'https://open.spotify.com/episode/68kq3bNz6hEuq8NtdfwERG' reply_all_ep1_urn = 'spotify:episode:1KHjbpnmNpFmNTczQmTZlR' @classmethod def setUpClass(self): self.spotify = Spotify( client_credentials_manager=SpotifyClientCredentials()) self.spotify.trace = False def test_audio_analysis(self): result = self.spotify.audio_analysis(self.four_tracks[0]) assert ('beats' in result) def test_audio_features(self): results = self.spotify.audio_features(self.four_tracks) self.assertTrue(len(results) == len(self.four_tracks)) for track in results: assert ('speechiness' in track) def test_audio_features_with_bad_track(self): bad_tracks = ['spotify:track:bad'] input = self.four_tracks + bad_tracks results = self.spotify.audio_features(input) self.assertTrue(len(results) == len(input)) for track in results[:-1]: if track is not None: assert ('speechiness' in track) self.assertTrue(results[-1] is None) def test_recommendations(self): results = self.spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50) self.assertTrue(len(results['tracks']) == 20) def test_artist_urn(self): artist = self.spotify.artist(self.radiohead_urn) self.assertTrue(artist['name'] == 'Radiohead') def test_artists(self): results = self.spotify.artists([self.weezer_urn, self.radiohead_urn]) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 2) def test_album_urn(self): album = self.spotify.album(self.pinkerton_urn) self.assertTrue(album['name'] == 'Pinkerton') def test_album_tracks(self): results = self.spotify.album_tracks(self.pinkerton_urn) self.assertTrue(len(results['items']) == 10) def test_album_tracks_many(self): results = self.spotify.album_tracks(self.angeles_haydn_urn) tracks = results['items'] total, received = results['total'], len(tracks) while received < total: results = self.spotify.album_tracks(self.angeles_haydn_urn, offset=received) tracks.extend(results['items']) received = len(tracks) self.assertEqual(received, total) def test_albums(self): results = self.spotify.albums( [self.pinkerton_urn, self.pablo_honey_urn]) self.assertTrue('albums' in results) self.assertTrue(len(results['albums']) == 2) def test_track_urn(self): track = self.spotify.track(self.creep_urn) self.assertTrue(track['name'] == 'Creep') def test_track_id(self): track = self.spotify.track(self.creep_id) self.assertTrue(track['name'] == 'Creep') self.assertTrue(track['popularity'] > 0) def test_track_url(self): track = self.spotify.track(self.creep_url) self.assertTrue(track['name'] == 'Creep') def test_track_bad_urn(self): try: self.spotify.track(self.el_scorcho_bad_urn) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_tracks(self): results = self.spotify.tracks([self.creep_url, self.el_scorcho_urn]) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 2) def test_artist_top_tracks(self): results = self.spotify.artist_top_tracks(self.weezer_urn) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 10) def test_artist_related_artists(self): results = self.spotify.artist_related_artists(self.weezer_urn) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 20) for artist in results['artists']: if artist['name'] == 'Jimmy Eat World': found = True self.assertTrue(found) def test_artist_search(self): results = self.spotify.search(q='weezer', type='artist') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_search_with_market(self): results = self.spotify.search(q='weezer', type='artist', market='GB') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_search_with_multiple_markets(self): total = 5 countries_list = ['GB', 'US', 'AU'] countries_tuple = ('GB', 'US', 'AU') results_multiple = self.spotify.search_markets(q='weezer', type='artist', markets=countries_list) results_all = self.spotify.search_markets(q='weezer', type='artist') results_tuple = self.spotify.search_markets(q='weezer', type='artist', markets=countries_tuple) results_limited = self.spotify.search_markets(q='weezer', limit=3, type='artist', markets=countries_list, total=total) self.assertTrue( all('artists' in results_multiple[country] for country in results_multiple)) self.assertTrue( all('artists' in results_all[country] for country in results_all)) self.assertTrue( all('artists' in results_tuple[country] for country in results_tuple)) self.assertTrue( all('artists' in results_limited[country] for country in results_limited)) self.assertTrue( all( len(results_multiple[country]['artists']['items']) > 0 for country in results_multiple)) self.assertTrue( all( len(results_all[country]['artists']['items']) > 0 for country in results_all)) self.assertTrue( all( len(results_tuple[country]['artists']['items']) > 0 for country in results_tuple)) self.assertTrue( all( len(results_limited[country]['artists']['items']) > 0 for country in results_limited)) self.assertTrue( all(results_multiple[country]['artists']['items'][0]['name'] == 'Weezer' for country in results_multiple)) self.assertTrue( all(results_all[country]['artists']['items'][0]['name'] == 'Weezer' for country in results_all)) self.assertTrue( all(results_tuple[country]['artists']['items'][0]['name'] == 'Weezer' for country in results_tuple)) self.assertTrue( all(results_limited[country]['artists']['items'][0]['name'] == 'Weezer' for country in results_limited)) total_limited_results = 0 for country in results_limited: total_limited_results += len( results_limited[country]['artists']['items']) self.assertTrue(total_limited_results <= total) def test_artist_albums(self): results = self.spotify.artist_albums(self.weezer_urn) self.assertTrue('items' in results) self.assertTrue(len(results['items']) > 0) found = False for album in results['items']: if album['name'] == 'Hurley': found = True self.assertTrue(found) def test_search_timeout(self): client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify( requests_timeout=0.01, client_credentials_manager=client_credentials_manager) # depending on the timing or bandwidth, this raises a timeout or connection error" self.assertRaises( (requests.exceptions.Timeout, requests.exceptions.ConnectionError), lambda: sp.search(q='my*', type='track')) def test_album_search(self): results = self.spotify.search(q='weezer pinkerton', type='album') self.assertTrue('albums' in results) self.assertTrue(len(results['albums']['items']) > 0) self.assertTrue( results['albums']['items'][0]['name'].find('Pinkerton') >= 0) def test_track_search(self): results = self.spotify.search(q='el scorcho weezer', type='track') self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']['items']) > 0) self.assertTrue(results['tracks']['items'][0]['name'] == 'El Scorcho') def test_user(self): user = self.spotify.user(user='******') self.assertTrue(user['uri'] == 'spotify:user:plamere') def test_track_bad_id(self): try: self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_show_urn(self): show = self.spotify.show(self.heavyweight_urn, market="US") self.assertTrue(show['name'] == 'Heavyweight') def test_show_id(self): show = self.spotify.show(self.heavyweight_id, market="US") self.assertTrue(show['name'] == 'Heavyweight') def test_show_url(self): show = self.spotify.show(self.heavyweight_url, market="US") self.assertTrue(show['name'] == 'Heavyweight') def test_show_bad_urn(self): with self.assertRaises(SpotifyException): self.spotify.show("bogus_urn", market="US") def test_shows(self): results = self.spotify.shows( [self.heavyweight_urn, self.reply_all_urn], market="US") self.assertTrue('shows' in results) self.assertTrue(len(results['shows']) == 2) def test_show_episodes(self): results = self.spotify.show_episodes(self.heavyweight_urn, market="US") self.assertTrue(len(results['items']) > 1) def test_show_episodes_many(self): results = self.spotify.show_episodes(self.reply_all_urn, market="US") episodes = results['items'] total, received = results['total'], len(episodes) while received < total: results = self.spotify.show_episodes(self.reply_all_urn, offset=received, market="US") episodes.extend(results['items']) received = len(episodes) self.assertEqual(received, total) def test_episode_urn(self): episode = self.spotify.episode(self.heavyweight_ep1_urn, market="US") self.assertTrue(episode['name'] == '#1 Buzz') def test_episode_id(self): episode = self.spotify.episode(self.heavyweight_ep1_id, market="US") self.assertTrue(episode['name'] == '#1 Buzz') def test_episode_url(self): episode = self.spotify.episode(self.heavyweight_ep1_url, market="US") self.assertTrue(episode['name'] == '#1 Buzz') def test_episode_bad_urn(self): with self.assertRaises(SpotifyException): self.spotify.episode("bogus_urn", market="US") def test_episodes(self): results = self.spotify.episodes( [self.heavyweight_ep1_urn, self.reply_all_ep1_urn], market="US") self.assertTrue('episodes' in results) self.assertTrue(len(results['episodes']) == 2) def test_unauthenticated_post_fails(self): with self.assertRaises(SpotifyException) as cm: self.spotify.user_playlist_create("spotify", "Best hits of the 90s") self.assertTrue(cm.exception.http_status == 401 or cm.exception.http_status == 403) def test_custom_requests_session(self): sess = requests.Session() sess.headers["user-agent"] = "spotipy-test" with_custom_session = spotipy.Spotify( client_credentials_manager=SpotifyClientCredentials(), requests_session=sess) self.assertTrue( with_custom_session.user(user="******")["uri"] == "spotify:user:akx") sess.close() def test_force_no_requests_session(self): with_no_session = spotipy.Spotify( client_credentials_manager=SpotifyClientCredentials(), requests_session=False) self.assertNotIsInstance(with_no_session._session, requests.Session) user = with_no_session.user(user="******") self.assertEqual(user["uri"], "spotify:user:akx")
def shuffle(self, playlistName, clustersAndError, token, shuffleTime, genreDict): # get user spotifyObject = Spotify(auth=token) spotifyUser = spotifyObject.current_user() username = spotifyUser['id'] # find playlist playlistID = playlistName #vibe Genres vibeGenresTest = genreDict vibeGenres = [] for vibe in vibeGenresTest: vibeGenres.append(str(vibe)) songGenreDict = {} # get songs playlist = spotifyObject.user_playlist_tracks(user=username, playlist_id=playlistID) numberOfSongs = int(playlist['total']) totalAdded = int(0) songsToAdd = [] while (numberOfSongs > totalAdded): playlist = spotifyObject.user_playlist_tracks(user=username, playlist_id=playlistID, offset=totalAdded) for i in range(0, len(playlist['items'])): try: songURI = playlist['items'][i]['track']['uri'] songId = playlist['items'][i]['track']['id'] songFeatures = spotifyObject.audio_features(songURI) if (self.songGenreInVibe(spotifyObject=spotifyObject, songId=songId, songGenreDict=songGenreDict, vibeGenreDict=vibeGenres) == True): song = [[songFeatures[0]['acousticness'], songFeatures[0]['danceability'], songFeatures[0]['energy'], songFeatures[0]['instrumentalness'], songFeatures[0]['liveness'], songFeatures[0]['speechiness'], round(songFeatures[0]['tempo'] / 180, 6), songFeatures[0]['valence']]] distArray = cdist(song, clustersAndError[0], 'euclidean') dist = min(distArray[0]) if float(dist) < float(clustersAndError[1]): if len(songsToAdd) < 2: songsToAdd.append(songURI) spotifyObject.add_to_queue(songURI) else: songsToAdd.append(songURI) except: print("spotify does not have this song anymore. Sorry") totalAdded = totalAdded + 100 numSongsToAdd = int(int(shuffleTime) / 2) songsAdded = 0 while songsAdded < numSongsToAdd or len(songsToAdd) == 0: try: addSong = random.choice(songsToAdd) spotifyObject.add_to_queue(addSong) songsToAdd.remove(addSong) songsAdded = songsAdded + 1 time.sleep(int(5)) except: print("song not added")