How to: Add the currently playing Spotify song to a specific playlist

If you have macros or EventGhost Configuration Tree items you wish to share this is the place to do it.
Post Reply
Septik
Posts: 33
Joined: Sun Feb 15, 2015 1:29 pm

How to: Add the currently playing Spotify song to a specific playlist

Post by Septik » Thu Oct 12, 2017 8:57 pm

Check out this post for initial discussion around this idea.

I have a master playlist in Spotify with close to 6000 songs. I pretty much add anything and everything I like to it. I use the following script, triggered by a keyboard shortcut, to check if the currently playing song exists in the playlist, and if not - add it. The script uses the Spotify Web Api, and therefore needs a few user variables. I'll present them and some ideas on how to obtain them below:

Client ID and Client Secret:
  1. Log in here and click "Create an app". Add any name and description, and copy the Client ID and Client Secret keys somewhere.
  2. In the Redirect URI section, add "http://localhost:8888/callback" (without quotation marks). You will need unless you have a refresh token already or other means of getting it.
Refresh token:
This is probably the hardest part, but also the easiest way I found to retrieve a refresh token.
  1. Follow this tutorial for setting up Node.js and creating an access and refresh token.
  2. If you followed the tutorial, you will have a file called index.html in "<project folder>\authorization_code\public". Open this in any text editor and find two lines that say contain "{{access_token}}" and "{{refresh_token}}". Both of these lines have a class tag. I can't remember the default value now, but I changed it to "clearfix". You will then be able to view both the access and the refresh token in full.
Playlist ID:
In Spotify, right click the playlist you want to use and click Share > Copy Spotify URI. The playlist ID is the string after "playlist:" in the text you just copied.

Now on to the script. You can view it on hastebin or below:

Code: Select all

import json
import base64
import requests
import sys

def getAccessToken(test):
    #USER VARIABLES
    refresh_token = "<your refresh token>"
    client_id = "<your client id>"
    client_secret = "<your client secret>"
    ##
    
    url = 'https://accounts.spotify.com/api/token'
    payload = {'grant_type': 'refresh_token', 'refresh_token': refresh_token}
    headers = {'Authorization': 'Basic ' + base64.standard_b64encode(client_id + ':' + client_secret)}

    r = requests.post(url, payload, headers=headers)
    json_string = r.content
    parsed_json = json.loads(json_string)

    newtoken = parsed_json['access_token']
    eg.plugins.Webserver.SetPersistentValue(u'spotify_token', str(newtoken), False, False)
    
    return

#Create OSD object
osd = eg.plugins.EventGhost.actions["ShowOSD"]()

#USER VARIABLES
username = "<your username>"
playlistID = "<ID of playlist you wish to use>"
##

accessToken = eg.plugins.Webserver.GetPersistentValue(u'spotify_token', False)

trackInfo = requests.get("https://api.spotify.com/v1/me/player/currently-playing", headers={"Authorization": "Bearer " + accessToken})

if trackInfo.status_code == 401:
    test = 5
    getAccessToken(test)
    accessToken = eg.plugins.Webserver.GetPersistentValue(u'spotify_token', False)
    trackInfo = requests.get("https://api.spotify.com/v1/me/player/currently-playing", headers={"Authorization": "Bearer " + accessToken})

if trackInfo.status_code == 204:
    print "No track info found!"
    osd("No track info found!", u'0;-16;0;0;0;700;0;0;0;0;3;2;1;34;Arial', (255, 255, 255), None, 3, (5, 37), 0, 3.0, True)
    sys.exit()

#Parse track info
i=trackInfo.json()
trackID=i['item']['id']
trackName=i['item']['name']
trackArtist=i['item']['album']['artists'][0]['name']
##

#Get playlist name
playlist = requests.get("https://api.spotify.com/v1/users/" + username + "/playlists/" + playlistID + "?fields=name", headers={"Authorization": "Bearer " + accessToken})
p = playlist.json()
pname = p['name']

#Get playlist contents
tracklist = requests.get("https://api.spotify.com/v1/users/" + username + "/playlists/" + playlistID + "/tracks?fields=items(track.id),total", headers={"Accept": "application/json", "Authorization": "Bearer " + accessToken + "\"" })
t = tracklist.json()
total = t['total']

osd("Checking for duplicates...", u'0;-16;0;0;0;700;0;0;0;0;3;2;1;34;Arial', (255, 255, 255), None, 3, (5, 37), 0, 3.0, True)
print "Checking for duplicates..."

#Check for duplicates
offset = 100
while (offset < total):
    tracklist = requests.get("https://api.spotify.com/v1/users/" + username + "/playlists/" + playlistID + "/tracks?fields=items(track.id),total&offset=" + str(offset), headers={"Accept": "application/json", "Authorization": "Bearer " + accessToken + "\"" })
    t = tracklist.json()
    for i, song in enumerate(t['items']):
        if song['track']['id'] == trackID:
            print "Duplicate found!"
            osd("Error: Duplicate found!", u'0;-16;0;0;0;700;0;0;0;0;3;2;1;34;Arial', (255, 255, 255), None, 3, (5, 37), 0, 5.0, True)
            sys.exit()
    offset +=100

print "No duplicates found."

#Add track to playlist
add = requests.post("https://api.spotify.com/v1/users/" + username + "/playlists/" + playlistID + "/tracks?uris=spotify%3Atrack%3A" + trackID, headers={"Accept": "application/json", "Authorization": "Bearer " + accessToken + "\"" })
##



#Exit with error if song couldn't be added to playlist
if add.status_code != 201:
    print ("POST ERROR: " + str(add.status_code) + " " + add.reason)
    osd("Error adding song to playlist! See log for more details.")
    sys.exit()
##

#Show OSD if everything went well
osd("\"" + trackArtist + " - " + trackName + "\" added to playlist \"" + pname + "\".", u'0;-16;0;0;0;700;0;0;0;0;3;2;1;34;Arial', (255, 255, 255), None, 3, (5, 37), 0, 5.0, True)
print "\"" + trackArtist + " - " + trackName + "\" added to playlist \"" + pname + "\"."
In EventGhost, just add an action EventGhost > Python Script where needed and paste this script. Paste your user variables under the two "USER VARIABLES" sections, and you should be good to go! Feel free to modify the script, but please share your work if you do so. Feedback and ideas for improvement are highly welcome.

Thanks for reading!

Post Reply