Wait 10s and Add Error Handling

This can determine the difference between playing/not playing,
if the user token expired, and if we've been rate-limited.
This can be easily expanded in the future for various other exceptions.
This commit is contained in:
David Todd (c0de) 2018-01-30 14:27:29 -06:00
parent 7757235dbb
commit b75cf268e8
2 changed files with 75 additions and 30 deletions

View File

@ -4,7 +4,7 @@ This is a collection of experimentations with the Spotipy python library.
All of these scripts will request an auth token for a particular user (username arg) upon startup
From my experimentation so far, this will remmeber that the app was previously authorized for whatever "authorization scope" was approved by the user at the oauth screen
save_now_playing.py - This script will poll for the user's now playing track every minute and update a text file.
save_now_playing.py - This script will poll for the user's now playing track every 10s and update a text file
get_user_auth.py - "Hello World" from the docs, this shows how to authorize using env
show_all_playlist.py - Unlike the name suggests, I did not see all my playlists. This could be an auth scope issue however

View File

@ -3,11 +3,16 @@
# License: MIT
# Copyright (c) 2018 c0de <c0defox.es>
# Edit "set_env.sh" to configure your API key
# $ virtualenv venv
# $ ./set_env.sh
# $ pip install -r requirements.txt
import sys
import time
import spotipy
import spotipy.util as util
import time
import sys
import os
from spotipy.client import SpotifyException
start_time = time.time()
@ -20,35 +25,75 @@ else:
def get_now_playing(sp):
# This should be sp.currently_playing(), but somehow does not work...
# So I its return: https://github.com/plamere/spotipy/blob/master/spotipy/client.py#L899
# Get the currently playing track and artist
np = sp._get("me/player/currently-playing", market=None)
return "%s by: %s" % (np['item']['name'], np['item']['artists'][0]['name'])
# So I used its return: https://github.com/plamere/spotipy/blob/master/spotipy/client.py#L899
# Authorization Scope, can possibly be a dict?
scope = 'user-read-currently-playing'
try:
# Get the currently playing track and artist
np = sp._get("me/player/currently-playing", market=None)
# Take a look at the other goodies that gets returned here for future stuff
return "%s by: %s" % (np['item']['name'], np['item']['artists'][0]['name'])
except TypeError:
return "Nothing is playing"
# User Auth-Token - Achieved by running a webserver on localhost (might not be needed) as we just paste the URL here
token = util.prompt_for_user_token(username, scope)
def authorize_api(username, scope=None):
if not scope:
# Authorization Scope, can possibly be a dict?
scope = 'user-read-currently-playing'
if token:
# Authorize with the API
sp = spotipy.Spotify(auth=token)
print "[%.2fs] Authorizing %s with this auth scope: %s" % \
(time.time()-start_time, username, scope)
# User Auth-Token - Achieved by running a webserver on localhost (might not be needed) as we just paste the URL here
# The access token appears to expire around 2000ish seconds of use.
# Rerunning this and retrieving the callback url (with new token) will allow the script to continue
token = util.prompt_for_user_token(username, scope)
while True:
if token:
# Authorize with the API
return spotipy.Spotify(auth=token)
else:
print "[%.2fs] Unable to authorize %s - Did they approve the oauth login?" % \
(time.time()-start_time, username)
sys.exit()
sp = authorize_api(username)
# Main loop
while True:
try:
np = get_now_playing(sp)
except SpotifyException as e:
if e.http_status == '401' and e.code == '-1': # Unauthorized and Expired access token
print "[%.2fs] Access Token for %s Expired, reaquiring..." % \
(time.time()-start_time, username)
# Reauth and get the next now playing
sp = authorize_api(username)
continue
if e.http_status == '429': # Too Many Requests
# We're hitting the API too fast. The response should include a "Retry-After" Header
if e.headers and e.headers["Retry-After"]:
secs = float(e.headers["Retry-After"])
print "[%.2fs] Too Many API Requests, waiting %.1fs before continuing" % \
(time.time()-start_time, secs)
# Wait X Seconds before trying again
time.sleep(secs - (time.time() - start_time) % secs)
continue
else:
# Wait 30 secs
print "[%.2fs] Too Many API Requests and No Retry-After Header, \
waiting 30s before continuing" % (time.time()-start_time)
time.sleep(30.0 - (time.time() - start_time) % 30.0)
continue
else:
raise Exception(e)
try:
with open(outfile, 'w') as output:
output.write(np)
print "[%.2fs] %s" % (time.time()-start_time, np)
output.close()
except:
print "[%.2fs] Unable to open %s" % (time.time()-start_time, outfile)
sys.exit()
# Wait 1 minute before checking again
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
else:
print "Can't get a token for %s" % username
sys.exit()
try:
with open(outfile, 'w') as output:
output.write(np)
print "[%.2fs] %s" % (time.time()-start_time, np)
output.close()
except:
print "[%.2fs] Unable to open %s" % (time.time()-start_time, outfile)
sys.exit()
# Wait approximately 10s before checking again
time.sleep(10.0 - ((time.time() - start_time) % 10.0))