Problem with adding songs of certain artist to spotify playlist using spotipy

67 Views Asked by At

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.

1

There are 1 best solutions below

0
On BEST ANSWER

Artist ID

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']

Artist's Top Tracks

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.

Filter search results

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.