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

209 Views Asked by At

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.stack.imgur.com/zAQTB.png)

1

There are 1 best solutions below

9
Bench Vue On BEST ANSWER

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.