In a previous post, I hacked this by getting the album artwork jpg from my amplifier. Unfortunately, upgrading to a new amp ‘improved’ its operating system and the artwork vanished, so I had to bite the bullet to get it straight from Spotify. This is far more painful than it needs to be and Spotify could do better (see footnote).
So, with a bit of help (actually a lot of help) from ChatGPT-4* and many rabbit holes explored, I’ve now got a call directly to the Spotify API of “now playing”.
To get going, set up a developer account in Spotify, create a new app and then get hold of
- Client ID
- Client secret
You must also set a Redirect URIs because Spotify requires you to use a web browser to authenticate: it’s not possible to do entirely on the command line (no, you can’t use CURL either, apparently).
This means you need to be able to put a web page somewhere that you can access. I decided to use one of my public web servers, so I can get the image from anywhere, not just at home, but you can use localhost.
Luckily there’s a Python library that does things. So, install python
pip install spotipy
Also, to use this we also need to add it to a Python virtual environment using this:
pip install virtualenv python3 -m venv myenv source myenv/bin/activate pip freeze > requirements.txt
And using source myenv/bin/activate to recall.
After many iterations (thanks ai), we get to a script:
get_spot.py
import spotipy from spotipy.oauth2 import SpotifyOAuth # Add your credentials here SPOTIPY_CLIENT_ID = 'your_spotify_client_id' SPOTIPY_CLIENT_SECRET = 'your_spotify_client_secret' SPOTIPY_REDIRECT_URI = 'your_redirect_uri' USERNAME = 'your_username' SCOPE = "user-read-currently-playing" # Create Spotify object with permissions oauth = SpotifyOAuth(client_id=SPOTIPY_CLIENT_ID, client_secret=SPOTIPY_CLIENT_SECRET, redirect_uri=SPOTIPY_REDIRECT_URI, username=USERNAME, scope=SCOPE, open_browser=False) token_info = oauth.get_cached_token() # Check if token needs to be refreshed if token_info and oauth.is_token_expired(token_info): token_info = oauth.refresh_access_token(token_info['refresh_token']) sp = spotipy.Spotify(auth_manager=oauth) # Get current playing current_playing = sp.current_user_playing_track() # Ensure that a track is playing if current_playing is not None: # Get the album art album_art = current_playing['item']['album']['images'][0]['url'] print(album_art) else: print("No track is currently playing.")
When you first run this, using
python get_spot.py
it’ll give you a URL to copy/paste into a browser so you can authenticate.
You need to have this as a web page at the RedirectURI
<div id="authorizationCode"></div> <script> function handleAuthorizationCode() { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const authorizationCode = urlParams.get('code'); const authorizationCodeDiv = document.getElementById('authorizationCode'); if (authorizationCode) { authorizationCodeDiv.innerHTML = `${authorizationCode}`; // Do something with the code (e.g., store it for later use) // You can also make a POST request to your server to exchange it for an access token } else { authorizationCodeDiv.innerHTML = 'No authorization code found in the URL.'; // Handle the case when the user denies permission or other errors } } handleAuthorizationCode(); </script>
Then access it, via <your URL>/<file>?code=<your_ClientID>
You need to copy the ‘return URL‘ (not the code it renders) that it generates and paste it back onto the command line prompt.
After you’ve done that, you can run it again and it’ll (hopefully) give you a URL directly to the artwork on Spotify’s CDN, for example:
https://i.scdn.co/image/ab67616d0000b2737a9230e1ede602936d5056c8
We can then use THAT URL instead of the one I was getting from the amplifier in the previous post.
And, finally, we want to cron this as we did with the local example from last time.
spot.sh (this time, on the server)
#!/bin/bash folder='/{path}/spotify' cd $folder # Activate the virtual environment and get the album art URL source $folder/myenv/bin/activate albumart=$(python $folder/get.py) # Check if the Python script executed successfully if [ $? -ne 0 ]; then echo "Error: Failed to execute the Python script." echo "empty" > status.flag exit 1 fi # Download the album art, or exit with an error message if curl fails if ! curl -o nowtmp.jpg $albumart; then echo "Failed to download album art" echo "empty" > status.flag exit 1 fi # Move the temporary image to 'now.jpg' mv nowtmp.jpg now.jpg file now.jpg | awk '{print $2}' > status.flag # Compute the MD5 checksums of the current and live images current_checksum=$(md5sum now.jpg | awk '{print $1}') live_checksum=$(md5sum live.jpg | awk '{print $1}') # If the checksums differ, update the live image if [ "$current_checksum" != "$live_checksum" ]; then cp now.jpg live.jpg fi
Then, on the pi, we can do this:
up-spot.sh
#!/bin/bash cd /{path}/hcm server=`curl -k https://{server}/{folder}/status.flag` echo server $server if [ "$server" = "JPEG" ]; then if [ `cat status.flag` = "no" ]; then echo "yes" > status.flag cp album-cover-live-safe.html album-cover.html ./refresh.sh fi else if [ `cat status.flag` = "yes" ]; then echo "no" > status.flag cp clock-analogue.html album-cover.html ./refresh.sh fi fi
and put that into cron on the pi with:
* * * * * /{path}/up-spot.sh > /dev/null 2>&1
and then
test-refresh.sh becomes
#!/bin/bash cd /{local path} hifi=`cat hifi.ip` albumart="https://{server}/{path}/live.jpg" nowtmp="nowtmp.jpg" curl -k $albumart > $nowtmp wait if [ -f "$nowtmp" ]; then # echo `date` "file exists: " `du -sk $nowtmp` "and" `md5sum $nowtmp` >> log mv nowtmp.jpg now.jpg # do as a step in case latency leads to partial download tests x=`md5sum now.jpg | awk '{print $1}'` y=`md5sum live.jpg | awk '{print $1}'` if [ "$x" != "$y" ] ; then # echo "updating" `date` $x $y >> log cp now.jpg live.jpg ./refresh.sh fi fi
See the previous post for more on other bits of script and cron.
* I started with “write a shell script to get the ‘now playing’ album art from my spotify account”
Footnote
As an aside, I found that this nice chap has done a *really simple* integration where you just authorise his app and it tells you what’s playing. Unfortunately, it’s not generating the images (just the titles) and I didn’t want to rely on a 3rd party service [hint: Spotify, just make it this easy, good grief!]