def get_playlist_info(sp: spotipy.client.Spotify, playlist_uri: str) -> Tuple[str, list, list, list]: """ Extract track names and URIs from a playlist :param sp: spotify client object :param playlist_uri: playlist uri :return: playlist name, track names, artist names, song uris """ # Initialize vars offset = 0 tracks, uris, names, artists = [], [], [], [] # Get playlist id and name from URI playlist_id = playlist_uri.split(':')[2] playlist_name = sp.playlist(playlist_id)['name'] # Get all tracks in given playlist (max limit is 100 at a time --> use offset) while True: results = sp.playlist_items(playlist_id, offset=offset) tracks += results['items'] if results['next'] is not None: offset += 100 else: break # Get track metadata for track in tracks: names.append(track['track']['name']) artists.append(track['track']['artists'][0]['name']) uris.append(track['track']['uri']) return playlist_name, names, artists, uris
def get_playlist_tracks(spotify: spotipy.client.Spotify, playlist_id: str) -> list: """ This function takes an authenticated Spotify client, and a playlist ID, and returns a list of song details of every song in the playlist Parameters required: Authenticated Spotify Client, and playlist ID or URL Return Data: List of song details in the playlist """ # Get first 100 or lesser songs' details results = spotify.playlist_items(playlist_id) # Check if there are more songs for which details need to be obtained tracks = results["items"] while results["next"]: # Get next 100 songs' details, and append to the list of results already obtained results = spotify.next(results) tracks.extend(results["items"]) # Create new list to hold track IDs track_id = {} # Extract each track detail from the extracted information, and append to track_id list track_id["IDs"] = [] track_id["Name"] = [] track_id["Artist"] = [] track_id["Popularity"] = [] for i in tracks: # Looping through all tracks if i["track"]["id"] != None: track_id["IDs"].append( "spotify:track:" + i["track"]["id"] ) # Get ID of song track_id["Name"].append(i["track"]["name"]) # Get Name of song track_id["Artist"].append( i["track"]["artists"][0]["name"] ) # Get main Artist of song track_id["Popularity"].append( i["track"]["popularity"] ) # Get popularity of songs # Return all track IDs return track_id
def search_spotify(sp: spotipy.client.Spotify, artist: str, track: str): track_id = None artists = None name = None popularity = None results = sp.search(q=f"artist:{artist} track:{track} NOT Live", type='track', limit=1) if results['tracks']['total'] == 0: artist = clean_string(artist) results = sp.search(q=f"artist:{artist} track:{track} NOT Live", type='track', limit=1) if results['tracks']['total'] == 0: artist = artist.split(' ') if len(artist) > 1: artist = artist[0] + ' ' + artist[1] results = sp.search( q=f"artist:{artist} track:{track} NOT Live", type='track', limit=1) if results['tracks']['total'] != 0: track_id = results['tracks']['items'][0]['id'] artists = results['tracks']['items'][0]['artists'] name = results['tracks']['items'][0]['name'] popularity = results['tracks']['items'][0]['popularity'] return track_id, artists, name, popularity
def current_playlist_tracks(sp: spotipy.client.Spotify, playlist_id: str): playlist_cont = [] # Getting current songs in playlist to add to list for no duplicates results = sp.playlist_tracks(playlist_id=playlist_id) while len(playlist_cont) < results['total']: for tracks in results['items']: playlist_cont.append(tracks['track']['id']) results = sp.playlist_tracks(playlist_id=playlist_id, offset=len(playlist_cont)) return playlist_cont
def clear_playlist(sp: spotipy.client.Spotify, playlist_id: str): playlist_cont = current_playlist_tracks() with open( f'playlist_cont_{dt.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.txt', 'w') as f: for track_id in playlist_cont: f.write(f"{track_id}\n") sp.user_playlist_remove_all_occurrences_of_tracks( user=username, playlist_id=playlist_id, tracks=[track_id]) return 0
def download(self, sp: spotipy.client.Spotify, playlist_id: str) -> None: page_size = 100 offset = 0 fields = ','.join([ 'items.track.name', 'items.track.artists.name', 'items.added_by.id', 'items.added_at', ]) while True: rsp = sp.playlist_items( playlist_id, limit=page_size, offset=offset, fields=fields, additional_types=['track'] ) if not rsp['items']: break self.__items += [ PlaylistItem(s['track']['name'], s['added_at'], s['added_by']['id'], s['track']['artists']) for s in rsp['items'] if s['track'] ] offset += page_size
def get_audio_features(sp: spotipy.client.Spotify, track_uri: str): track_uri = sp._get_id("track", track_uri) os.makedirs("audio_features", exist_ok=True) filename = f"audio_features/{track_uri}" try: with open(filename, "r") as f: contents = f.read() data = json.loads(contents) except FileNotFoundError: features = sp.audio_features([track_uri]) data = features[0] with open(filename, "w") as f: contents = json.dumps(data, indent=4) f.write(contents) return data
def prep_songs(song_ids: list, spotify: spotipy.client.Spotify) -> pd.DataFrame: """ Songs passed with IDs cannot directly be used in the model. This function preps the song for the ML model Parameters Required: List of song ids (from client), authenticated spotify client Return Data: Pandas DataFrame of song details, for which classes can now be predicted """ prep_set = [] curr_number = 0 tracks = [] # Get all details of every song passed # Can only do 50 at a time, else throws an error of too many ids passed while curr_number <= len(song_ids): # Checking if it is empty if song_ids[curr_number : curr_number + 50]: tracks.extend( spotify.tracks(song_ids[curr_number : curr_number + 50])["tracks"] ) curr_number += 50 else: break # Getting audio features of all songs passed features = get_audio_features(spotify, song_ids) # Combining obtained data into single dictionary for i in range(len(features)): temp_song = features[i] temp_song["Popularity"] = tracks[i]["popularity"] temp_song["Name"] = tracks[i]["name"] temp_song["Artist"] = tracks[i]["artists"][0]["name"] # Adding dictionary to list containing all processed songs prep_set.append(temp_song) # Converting list of dictionaries to a pandas dataframe pred_data = pd.DataFrame(prep_set) # Returning Dataframe return pred_data
def get_tracks_artist_info(sp: spotipy.client.Spotify, pl_uri: str) -> List[List[Dict]]: artists_info = list() # Start retrieving tracks from the beginning of the playlist offset = 0 pl_length = get_pl_length(sp, pl_uri) # Playlist track retrieval only fetches 100 tracks at a time, hence\ # the loop to keep retrieving until we reach the end of the playlist while offset != pl_length: # Get the next batch of tracks pl_tracks = sp.playlist_tracks(pl_uri, offset=offset, fields="items.track") # Get the list with the info about the artists of each track from the\ # latest batch and append it to the running list [ artists_info.append(pl_item["track"]["artists"]) for pl_item in pl_tracks["items"] ] # Update the offset offset += len(pl_tracks["items"]) return artists_info
def get_track_info(sp: spotipy.client.Spotify, track_uri: str): track_uri = sp._get_id("track", track_uri) filename = f"track_info/{track_uri}" with open(filename, "r") as f: contents = f.read() track = json.loads(contents) return track
def save_track_info(sp: spotipy.client.Spotify, track): track_uri = sp._get_id("track", track["uri"]) os.makedirs("track_info", exist_ok=True) filename = f"track_info/{track_uri}" with open(filename, "w") as f: contents = json.dumps(track, indent=4) f.write(contents)
def failure_command_signal(client: spotipy.client.Spotify): current_volume = client.current_playback()['device']['volume_percent'] client.volume(int(current_volume * 1 / 2)) time.sleep(0.5) client.volume(int(current_volume * 1 / 5)) time.sleep(0.5) client.volume(current_volume)
def get_audio_features(spotify: spotipy.client.Spotify, track_ids: list) -> list: """ This function gets the following features of a spotify song, hundred songs at a time: ["acousticness", "danceability", "durationms", "energy", "instrumentalness", "key", "liveness", "loudness", "mode", "speechiness"\ , "tempo", "timesignature", "valence"] Getting more than 100 songs will result in a bad request error Parameters Required: Authenticated Spotify Client, and list of song IDs Return Data: List of dictionary containing song features """ # Getting features featurelst = [] count = 0 while count <= len(track_ids): # Get 100 songs' features at a time. Getting any more will result in bad result error featurelst.extend(spotify.audio_features(track_ids[count : count + 100])) count = count + 100 return featurelst
def get_features_for_playlist(sp: spotipy.client.Spotify, uri: str) -> pd.DataFrame: """ Extract features from each track in a playlist :param sp: spotify client object :param uri: playlist uri :return: playlist with audio features of each song """ # Get all track metadata from given playlist playlist_name, names, artists, uris = get_playlist_info(sp, uri) # Set column names and empty dataframe column_names = [ 'name', 'artist', 'track_URI', 'acousticness', 'danceability', 'energy', 'instrumentalness', 'liveness', 'loudness', 'speechiness', 'tempo', 'valence', 'playlist' ] df = pd.DataFrame(columns=column_names) # Iterate through each track to get audio features and save data into dataframe for name, artist, track_uri in zip(names, artists, uris): # Access audio features for given track URI via spotipy audio_features = sp.audio_features(track_uri) # Get relevant audio features feature_subset = [ audio_features[0][col] for col in column_names if col not in ["name", "artist", "track_URI", "playlist"] ] # Compose a row of the dataframe by flattening the list of audio features row = [name, artist, track_uri, *feature_subset, playlist_name] df.loc[len(df.index)] = row return df
def _get_playlist_from_spotify( spotify: spotipy.client.Spotify, spotify_playlist_id: SpotifyPlaylistId) -> PlayList: return spotify.playlist(spotify_playlist_id)
def get_pl_length(sp: spotipy.client.Spotify, pl_uri: str) -> int: return sp.playlist_tracks(pl_uri, offset=0, fields="total")["total"]
def add_track(sp: spotipy.client.Spotify, username: str, playlist_id: str, track_id: list): sp.user_playlist_add_tracks(user=username, playlist_id=playlist_id, tracks=track_id) return 0
def successful_command_signal(client: spotipy.client.Spotify): current_volume = client.current_playback()['device']['volume_percent'] client.volume(int(current_volume * 3 / 4)) time.sleep(0.6) client.volume(current_volume)