Search code examples
curlcommand-line-interfacespotifybearer-tokenplaylist

New method required for adding tracks to a Spotify Playlist (from Windows command line)


on Windows 10... Just this March (and for years prior) I was able to add items to my Spotify playlists using successive curl commands from the command line as follows (sans carriage returns). It was cool because I could add any number of tracks to a playlist from a simple script file (bat) (... albeit, with some included pauses and some escape characters)

curl -X "POST" "https://api.spotify.com/v1/playlists/my-playlist-id/tracks? uris=spotify%3Atrack%3A0P7DoyGrr4Wp9w5TotEtUC" 
-H "Accept: application/json" 
-H "Content-Type: application/json" 
-H "Content-length: 0" 
-H "Authorization: **Bearer bearer-id-obtained-by-requesting-token-from-spotify-api-demo-web-page-with-necessary-scopes**" 

That once-familiar web interface (image below) for obtaining tokens isn't there now but it appears I can successfully obtain a token (?Bearer?) as follows... no problem:

REMOVED: this question isn't really about what I have tried (which failed).  

What I'd really like to understand is how to reproduce the very simple interface that once existed at developer.spotify.com under CONSOLE (as in the attached image). Understand the following...

Below is an image of how easy it had been to get an appropriate token in the old interface. One would click GET TOKEN and this would display choices of your desired scope(s). Select scopes as desired and it would take you back to the page with the GET TOKEN button, but with a usable Bearer token filled in. That token would be valid for the next hour. Then you would need a new one. Which was fine.

With that token I could execute any number of curl commands in CLI for adding items to a playlist.

From suggested reading this sounds like the "implicit grant flow". I get that it's not recommended... which is probably why Spotify removed that Console interface. But I want to reproduce it.

Everything I read seems to imply I now need my own web server to do that (albeit localhost)... all of which makes some sense, since I HAD previously been doing this on Spotify's. And I suppose I can do that (PITA). I have operated web servers and developed database apps on them.

It's the details of what code to place on that web server that have me baffled. About three layers deep in the overview kindly pointed to in Bench Vue's reply there is this. Scope is mentioned once in the example. Is it perhaps as simple as modifying "var scope" to list (instead) the scopes required for adding tracks to playlists?

P.S. Take it easy on this retired 70-year old who only USED TO do cool, complex things on web servers, and has forgotten much.

    localStorage.setItem(stateKey, state);
    var scope = 'user-read-private user-read-email';

    var url = 'https://accounts.spotify.com/authorize';
    url += '?response_type=token';
    url += '&client_id=' + encodeURIComponent(client_id);
    url += '&scope=' + encodeURIComponent(scope);
    url += '&redirect_uri=' + encodeURIComponent(redirect_uri);
    url += '&state=' + encodeURIComponent(state);

[Previous web interface] (https://i.sstatic.net/zAQTB.png)


Solution

  • From you and me comments communication was limited So I would like to explain in here.

    This is demo overview how to success to add a track(song) into playlist?

    The left side is Client Credentials Flow method

    The right side is Authorization Code Flow method

    Only the right side is possible to add. The left side can't do it.

    enter image description here

    Client Credentials Flow

    I will explain the left first.

    I will use this track

    https://open.spotify.com/track/4YCnTYbq3oL1Lqpyxg33CU
    

    enter image description here

    I will use this playlist (hide playlist id due to private)

    enter image description here

    #1 Curl

    From Terminal

    Set environment variables with credential

    CLIENT_ID='<your client id>'
    CLIENT_SECRET='<your client secret>'
    PLAYLIST_ID='<your playlist id>'
    TRACK_ID='4YCnTYbq3oL1Lqpyxg33CU'
    CLIENT_ID_SECRET=$(echo -n $CLIENT_ID:$CLIENT_SECRET | base64 -w 0)
    

    #2 Get Access Token

    ACCESS_TOKEN=$(curl --location --request POST 'https://accounts.spotify.com/api/token' \
    --header 'Authorization: Basic '$CLIENT_ID_SECRET \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'grant_type=client_credentials' --data-urlencode 'scope=playlist-modify-private,playlist-modify-public'| jq -r '.access_token')
    echo 'ACCESS_TOKEN = '$ACCESS_TOKEN
    

    Will be display Access Token like this

    enter image description here

    #3 Add a track into the playlist

    curl --location 'https://api.spotify.com/v1/playlists/'$PLAYLIST_ID'/tracks' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer '$ACCESS_TOKEN \
    --data '{
        "uris": [
            "spotify:track:4YCnTYbq3oL1Lqpyxg33CU"
        ]
    }'
    

    Will be shows error (403) like this

    enter image description here

    So this method can't add a track due to Client credentials Flow not allowing to add a song.

    Authorization Code Flow

    Save get-token.js

    const express = require("express")
    const axios = require('axios')
    const cors = require("cors");
    
    const app = express()
    app.use(cors())
    
    CLIENT_ID = "<your client id>"
    CLIENT_SECRET = "<your client secret>"
    PORT = 3000 // it is located in Spotify dashboard's Redirect URIs, my port is 3000
    REDIRECT_URI = `http://localhost:${PORT}/callback` // my case is 'http://localhost:3000/callback'
    SCOPE = [
        'playlist-modify-public',
        'playlist-modify-private'
    ]
    const PLAY_LIST_ID = 'your playlist ID' // your playlist ID
    
    const getToken = async (code) => {
        try {
            const resp = await axios.post(
                url = 'https://accounts.spotify.com/api/token',
                data = new URLSearchParams({
                    'grant_type': 'authorization_code',
                    'redirect_uri': REDIRECT_URI,
                    'code': code
                }),
                config = {
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    auth: {
                        username: CLIENT_ID,
                        password: CLIENT_SECRET
                    }
                })
            return Promise.resolve(resp.data.access_token);
        } catch (err) {
            console.error(err)
            return Promise.reject(err)
        }
    }
    
    app.get("/login", (request, response) => {
        const redirect_url = `https://accounts.spotify.com/authorize?response_type=code&client_id=${CLIENT_ID}&scope=${SCOPE}&state=123456&redirect_uri=${REDIRECT_URI}&prompt=consent`
        response.redirect(redirect_url);
    })
    
    app.get("/callback", async (request, response) => {
        const code = request.query["code"]
        getToken(code)
            .then(access_token => {
                return response.send({'access_token': access_token});
            })
            .catch(error => {
                console.log(error.message);
            })
    })
    
    app.listen(PORT, () => {
        console.log(`Listening on :${PORT}`)
    })
    

    install dependencies

    npm install express axios cors
    

    enter image description here

    Run express server

    node get-token.js
    

    enter image description here

    #4 Get Token

    Open the Browser and login with this URL

    http://localhost:3000/login
    

    The browser login then turns into redirect and shows access token Copy only the value of the token into the clipboard.

    enter image description here

    ACCESS_TOKEN1="Paste access token from Browser in here"
    

    enter image description here

    #5/#6 Add track with the new token

    curl --location 'https://api.spotify.com/v1/playlists/'$PLAYLIST_ID'/tracks' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer '$ACCESS_TOKEN1 \
    --data '{
        "uris": [
            "spotify:track:4YCnTYbq3oL1Lqpyxg33CU"
        ]
    }'
    

    enter image description here

    enter image description here

    Conclusion

    From this demo, the authorization code flow can add a song by curl.

    even if the client credentials flow cannot.

    I have no experience implicit flow so I have no idea it can do or cannot.