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: 37
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!

toothpick
Posts: 3
Joined: Mon Mar 12, 2018 1:08 am

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

Post by toothpick » Mon Mar 12, 2018 1:22 am

Hey there, I have been searching online for a function that does exactly what your script does and decided to spend some time trying to go through your post. After following your tutorial (fairly straightforward, thank you for that) I have the Python Script added to EventGhost with your script pasted and edited to have my user variables.

When I trigger the script, either through testing or keyboard shortcut I receive an error I don't know how to fix:

Code: Select all

   Traceback (most recent call last):
       Python script "3", line 36, in <module>
          trackInfo = requests.get("https://api.spotify.com/v1/me/player/currently-playing", headers={"Authorization": "Bearer " + accessToken})
   TypeError: cannot concatenate 'str' and 'NoneType' objects     
If you have any idea why this might be happening I would love to know. I'm not sure if this script is up to date with Spotify's coding conventions or whatever, but I imagine any recent changes to Spotify's Web API could complicate things and require an update of your work.

My knowledge of Python is fairly limited but I'm a quick learner, thanks for bearing with me

User avatar
yokel22
Experienced User
Posts: 208
Joined: Thu Feb 05, 2015 5:56 pm
Location: U.S. - Kansas city

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

Post by yokel22 » Thu Mar 15, 2018 4:31 pm

I don't use spotify, so i can't really test this, but i believe the error is because the WebServer persistent variable 'spotify token' isn't being set. Give this a shot.

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>"
##

### Set persistent variable, yokel edit.  
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 == 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 + "\"."

toothpick
Posts: 3
Joined: Mon Mar 12, 2018 1:08 am

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

Post by toothpick » Fri Mar 23, 2018 6:56 pm

Thanks for the reply yokel.

I used your script and got this error:

Code: Select all

 Traceback (most recent call last):
	Python script "4", line 55, in <module>
             trackID=i['item']['id']
 KeyError: 'item'
I went ahead and printed i after it was initialized with the song data to see what I was working with and got this:

Code: Select all

 {u'error': {u'status': 401, u'message': u'Permissions missing'}}
Any ideas?

User avatar
yokel22
Experienced User
Posts: 208
Joined: Thu Feb 05, 2015 5:56 pm
Location: U.S. - Kansas city

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

Post by yokel22 » Sat Mar 24, 2018 12:31 am

Likely something wrong with the api token. It's not returning data because you don't have the proper permission. Something in the token setup is off. I don't think they've made an changes to the api since this was posted. Have you seen this post viewtopic.php?f=10&t=9894? It's further work that has been done to this script. It was working last time i tested it. It should take care of all the tokken stuff for you.

toothpick
Posts: 3
Joined: Mon Mar 12, 2018 1:08 am

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

Post by toothpick » Sat Mar 24, 2018 1:13 am

yokel22 wrote:
Sat Mar 24, 2018 12:31 am
[...] Have you seen this post [...]
I haven't! I followed that and got it working. Thanks so much, you're a godsend!

User avatar
yokel22
Experienced User
Posts: 208
Joined: Thu Feb 05, 2015 5:56 pm
Location: U.S. - Kansas city

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

Post by yokel22 » Sat Mar 24, 2018 10:16 am

Good deal.

Post Reply