I'm building basic spotipy
code that is creating playlist containing top songs of given artist. Code works for some artists, but e.g. for Adele it adds songs that aren't Adele's. Here is part of my code:
def get_songs_uris(self, top_artist_name, top_songs):
for i in range(len(top_songs)):
songs_data = self.sp.search(
q=f"artist: {top_artist_name}, track: {top_songs[i]}",
type="track", limit=1)
self.songs_URIs.append(songs_data["tracks"]["items"][0]["uri"])
return self.songs_URIs
Where top_artist_name="Adele"
and top_songs
is list of titles of most popular Adele's songs.
Code runs okay, but...
Playlist is created and all songs are added, but e.g. song "Someone Like You" have artist "Mason" instead of "Adele". Some other tracks are indeed Adele's, but not all.
An artist given may have more than meaning. It could be id
(e.g. 4dpARuHxo51G3z768sgnrY
) or uri
(spotify:artist:4dpARuHxo51G3z768sgnrY
). If not and we have only the name, we need to obtain one of those possibly via searching. I presume there should be some user interaction, because Spotify's search is somewhat unpredictable and not always reproducible.
# client = spotipy.Spotify(...)
# may raise SpotifyException
response = client.search(q="Adele", type="artist", limit=1)
artists = response['artists']['items']
# may raise IndexError
artist = artists[0]
# may raise KeyError
artist_id = artist['id']
artist_uri = artist['uri']
Spotify provides an endpoint for acquiring artist's top track (by country) and spotipy
has it implemented. Processing is somewhat straightforward:
country = 'PL'
# may raise SpotifyException
response = client.artist_top_tracks(artist_id, country)
tracks = response['tracks']
for track in tracks:
self.songs_URIs.append(track['uri']
But it's only 10 tracks per an artist and may not meet your needs.
Another idea is to try filtering search results of tracks by an artist. Here is a sample implementation of that idea:
offset = 0
limit = 50
artist_tracks = {} # name => uri
track_popularity = collections.defaultdict(lambda: -1) # name => popularity value
while offset < 1000:
try:
response = client.search(q="artist:Adele", type="track",
limit=50, offset=offset)
except SpotifyException:
break
try:
tracks = response['tracks']['items']
except (TypeError, KeyError):
break
for track in tracks:
# skip that tracks that do not relate to an artist we look for
if not any(artist_id == artist['id'] for artist in track['artists']):
continue
track_name = track['name']
if track_popularity[track_name] < track['popularity']:
track_popularity[track_name] = track['popularity']
artist_tracks[track_name] = track['uri']
offset += limit
Can apply further actions to the result collected:
data = [(track_popularity[title], title, artist_tracks[title])
for title in artist_tracks]
data.sort(key=lambda item: (-item[0], item[1]))
for popularity, title, uri in data[:5]:
print(f"{popularity}: {title} ({uri})")
Sample output:
86: Set Fire to the Rain (spotify:track:3di5hcvxxciiqwMH1jarhY)
86: Skyfall (spotify:track:6VObnIkLVruX4UVyxWhlqm)
84: Easy On Me (spotify:track:0gplL1WMoJ6iYaPgMCL0gX)
84: Love In The Dark (spotify:track:0DuWDLjriRPjDRoPgaCslY)
84: Rolling in the Deep (spotify:track:4OSBTYWVwsQhGLF9NHvIbR)
The result resembles a quick reference, however some tracks are missing due to a different Spotify's data. E.g. metadata of Ricsta - Be Divine feat. Adele doesn't hold any connection to Adele. But it could be not relevant to the top songs.