spotipy-dev / spotipy

A light weight Python library for the Spotify Web API
http://spotipy.readthedocs.org
MIT License
5.02k stars 960 forks source link

Add Tracks to Playlist bug #1075

Closed cmiller11stats closed 3 months ago

cmiller11stats commented 8 months ago

Describe the bug The function 'playlist_add_items' no longer works for me. Full code output is below. Everything worked perfect yesterday and I made no changes to my code environment. Error message below just showed up today.

Your code import spotipy tracklist = [ '6YrEHf7hVlg401qkiKRJG9' ,'1WzAGniIlPgpsVrJb4Bl7L' ,'2XmYgBX5WTd8ZGwzdZNStZ' ] playlist_id = '6ayPApeknsvxahwtTRwPDG' spot.playlist_add_items(playlist_id=playlist_id, items=tracklist)

Expected behavior TrackIds provided are added to playlistId provided.

Output HTTP Error for POST to https://api.spotify.com/v1/playlists/6ayPApeknsvxahwtTRwPDG/tracks with Params: {'position': None} returned 400 due to No uris provided. Traceback (most recent call last): File "C:\Users\chris\PycharmProjects\Spotify Code.venv\Lib\site-packages\spotipy\client.py", line 271, in _internal_call response.raise_for_status() File "C:\Users\chris\PycharmProjects\Spotify Code.venv\Lib\site-packages\requests\models.py", line 1021, in raise_for_status raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.spotify.com/v1/playlists/6ayPApeknsvxahwtTRwPDG/tracks During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Program Files\JetBrains\PyCharm Community Edition 2023.3.2\plugins\python-ce\helpers\pydev\pydevconsole.py", line 364, in runcode coro = func() ^^^^^^ File "", line 1, in File "C:\Users\chris\PycharmProjects\Spotify Code.venv\Lib\site-packages\spotipy\client.py", line 1085, in playlist_add_items return self._post( ^^^^^^^^^^^ File "C:\Users\chris\PycharmProjects\Spotify Code.venv\Lib\site-packages\spotipy\client.py", line 328, in _post return self._internal_call("POST", url, payload, kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\chris\PycharmProjects\Spotify Code.venv\Lib\site-packages\spotipy\client.py", line 293, in _internal_call raise SpotifyException( spotipy.exceptions.SpotifyException: http status: 400, code:-1 - https://api.spotify.com/v1/playlists/6ayPApeknsvxahwtTRwPDG/tracks: No uris provided., reason: None

Environment:

Additional context NA

rollersteaam commented 8 months ago

I can also verify this is happening to me. Glad to see someone else has the issue.

The Cause

The issue is because the payload for playlist_add_items (and user_playlist_add_tracks, as it uses that function) is just a list of uris, but Spotify's official documentation (at least, as of the time of writing) expects a dict with a "uris" key.

Here's the erroneous code snippet from Spotipy:

    def playlist_add_items(
        self, playlist_id, items, position=None
    ):
        """ Adds tracks/episodes to a playlist

            Parameters:
                - playlist_id - the id of the playlist
                - items - a list of track/episode URIs or URLs
                - position - the position to add the tracks
        """
        plid = self._get_id("playlist", playlist_id)
        ftracks = [self._get_uri("track", tid) for tid in items]
        return self._post(
            "playlists/%s/tracks" % (plid),
            payload=ftracks,
            position=position,
        )

Seems like Spotify may have silently shut down this way of handling it? Very frustrating to diagnose this issue...

Workaround

As a temporary workaround if you're able to, use playlist_replace_items instead. That works for now.

For reference, playlist_replace_items implements this correctly, which is why it works:

    def playlist_replace_items(self, playlist_id, items):
        """ Replace all tracks/episodes in a playlist

            Parameters:
                - playlist_id - the id of the playlist
                - items - list of track/episode ids to comprise playlist
        """
        plid = self._get_id("playlist", playlist_id)
        ftracks = [self._get_uri("track", tid) for tid in items]
        payload = {"uris": ftracks}
        return self._put(
            "playlists/%s/tracks" % (plid), payload=payload
        )
lfg6000 commented 8 months ago

yep the spotify server appears to no longer accept items = ['spotify:track:6HG5MFydepB9F8DAP0ejDD', 'spotify:track:3yQ4dy23XekcMsdeaBXZR6']

you must now pass in items = {'uris': ['spotify:track:6HG5MFydepB9F8DAP0ejDD', 'spotify:track:3yQ4dy23XekcMsdeaBXZR6']} or items = {'uris': ['spotify:track:6HG5MFydepB9F8DAP0ejDD', 'spotify:track:3yQ4dy23XekcMsdeaBXZR6'], 'position': X }

a revised spoitipy - client.py - playlist_add_items() is needed where you just pass on the items param directly to spotify

def playlist_add_items(self, playlist_id, items, position=None):
    plid = self._get_id("playlist", playlist_id)
    return self._post("playlists/%s/tracks" % (plid), payload=items) 

where items = {'uris': ['spotify:track:6HG5MFydepB9F8DAP0ejDD', 'spotify:track:3yQ4dy23XekcMsdeaBXZR6']} the tracks are added as expected

wonder if spotify knows they broke spotipy?

here is the web app i built using spotipy: spotifyfinder.com (many thanks to all the folks who work spotipy) the web app allows you to search for dups across playlists and search across playlists for a track or artist, etc... the web app is free, open source, tracker free, ad free.

mitsuru-nashimoto commented 8 months ago

Does the success of playlist_replace_items over playlist_add_items indicate a bug in spotipy? Is there any plan to address this issue in future updates?

lfg6000 commented 8 months ago

it appears spotify reverted the change and spotipy playlist_add_items() is working again. spotify is once again accepting method = POST url = 'https://api.spotify.com/v1/playlists/1n2STXHae0Wg6ZV0OYwToy/tracks' payload = ['spotify:track:6HG5MFydepB9F8DAP0ejDD', 'spotify:track:3yQ4dy23XekcMsdeaBXZR6']

i suspect spotify will break it again because the spotify docs say the payload needs to be payload = {'uris': ['spotify:track:6HG5MFydepB9F8DAP0ejDD', 'spotify:track:3yQ4dy23XekcMsdeaBXZR6'], 'position': X }

stephanebruckert commented 3 months ago

Looks like this was a temporary issue on the API side, closing