Issue
I am building a custom Spotify music player using Flask on the backend to handle calls to the Spotify API. It gets information from the currently playing track and populates the local webpage. I now need to poll the Spotify API (every 2 seconds or so) to check whether the song has changed and if so, update the webpage (hopefully with JavaScript so there is no need to refresh the page). I am not sure how do this with Flask or if there is a better method to go about it. I believe I can solve the issue by creating and calling an asynchronous function to do the polling, but if a change was identified I'm not sure where to go from there.
Here is the spotify view I have thus far. I am using the spotipy library inside custom auth and now_playing functions in a spotify.py file.
@app.route('/spotify')
def spotify():
# Get Spotify instance and authorization token
authData = dev.auth()
sp = authData[0]
token = authData[1]
current = dev.now_playing(sp, token)
# Assign individual track information to variable for sending to web page via Jinja
separator = ', '
return render_template('spotify.html',
artists = separator.join(current[0]),
song = current[1],
album = current[2],
cover_url = current[3],
year = current[4],
auth_tok = token
)
I have limited web development experience and this is my first time using Flask. I am using this project to learn more but have hit this roadblock.
Solution
Concept
A great way to poll APIs is to schedule requests in javascript then wait a certain amount of time (no more than 10-30 seconds) for the server to hold the request to see if the song changes then return the result. If the result is found earlier than 10-30 seconds, the server returns it early. The client sees the request as in progress, and can receive it in the entire window the server has it as long as the request does not time out (exceeds 30+ seconds or so). You can also just simply request the url every few seconds to check, but that uses a lot of system resources.
API Code
from flask import Flask, redirect
song = "" # global identifier
@app.route("/track", methods=["GET"])
def track():
for _ in range(10):
time.sleep(1)
global song # regrab the song value every iteration
current = dev.now_playing(sp, token) # get current song
if current[1] != song: # song changed
song = current[1]
return redirect("http://www.website.com/spotify", code=302) #essentially an automatic refresh by redirecting to itself, and will regrab the song data!
return {}, 200 # give the client SOMETHING so the request doesn't timeout and error
@app.route('/spotify')
def spotify():
global song
# Get Spotify instance and authorization token
authData = dev.auth()
sp = authData[0]
token = authData[1]
current = dev.now_playing(sp, token)
# Assign individual track information to variable for sending to web page via Jinja
separator = ', '
song = "" # assign the song value to whatever is sent to the client
return render_template('spotify.html',
artists = separator.join(current[0]),
song = current[1],
album = current[2],
cover_url = current[3],
year = current[4],
auth_tok = token
)
The code provided will take requests from a client, then check to see if the value global song
which represents the song when the client last refreshed the page is different than the current song the API is using. In the case it is, the server will send a redirect code so the client will redirect and essentially refresh the current page it is on, thus grabbing the song and information!
Javascript
The javascript code will use simple requests, and continuously grab the server data on the endpoint /track using GET. It can be found here or from simply researching by yourself javascript get requests. To continuously do requests, use the following code.
function stopFunction(){
clearInterval(myVar); // stop the timer
}
$(document).ready(function(){
myVar = setInterval("makeRequest()", 1000);
});
This is not a scaleable piece of code I provided but should work for private access and can be adapted conceptually into a scaleable endpoint.
Answered By - KMM
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.