Stream Spotify From Python

Spotify is probably one of my favorite companies that leverage Data Science. As you can read from their website, “Speed is a big focus for Spotify. Python fits well into this mindset, as it gets us big wins in speed of development”. I was over at a friends last weekend and he has an Amazon Echo that allows you to stream music on voice command for $200. Thus the idea for this blog post. If I knew how to access my Spotify Premium account from Python, maybe I could have my own Echo with a $5 Raspberry Pi Zero?

Speed of development

“To-market speed” is key with the Python programming language. This blog post is a prime example. Yesterday I knew nothing about the Python package PySpotify, but about four hours later I was ready for today’s post.

Spotify Stream – The Objectives

0. Make sure you have a Spotify Premium account -- it doesnt work for free accounts
1. Follow these references to create a Spotify Developer account/ make a new app and get the binaries
ref = get keys -- https://pyspotify.mopidy.com/en/latest/quickstart/#application-keys
2. Get PySpotify installed with AlsaSink as well
ref = install -- https://pyspotify.mopidy.com/en/latest/installation/
3. Start developing and if you need to read some documentation
ref = https://media.readthedocs.org/pdf/pyspotify/v2.x-develop/pyspotify.pdf
4. You are only limited by your imagination

For now we’re going to call it a success if we can login to our account, search for The Beatles’ Blackbird, and play Blackbird. First we use the login feature already available with the PySpotify package Spotify.Session(). Assuming that a file called spotify_appkey.key exists in the present folder (this is the binary you should have downloaded from Spotify), Spotify.Session() should take care of the heavy lifting.

We use the Threading module to make sure Python doesn’t step on itself while performing the actions. We also use event listeners to “listen” for a good connection and the end of the tracks we play. AlsaSink is used on Linux for Python to access the speakers on the computer. Logged_in.wait() is what we’ve been hoping for. If you see either of the print statements from the try/except portion of the above code, you have successfully logged into Spotify from Python.

How Do You Find an Artist?

We’re searching for The Beatles’ song Blackbird. In order to play the song, we need to know Spotify’s identification number for that track – they call it a URI. There are different formats for URIs depending on what you would like to do:

spotify:album:yyyyyyyyy

spotify:artist:zzzzzzzzzz

spotify:track:rrrrrrrrrrr

there are more I’m sure

From our perspective, we want to search for spotify:artist then try to find spotify:track.

def getURI(searchTerm):
"""input any search term and I'll find it for you and returns trackNames and trackURIs to use"""
try:
search = session.search(searchTerm)
print search.load()
#(search.artist_total, search.album_total, search.track_total, track.playlist_total)
print search.artists[0].load().name #get first result
#eventually will go and get cover art at the same time
#getCover(theAlbumURI)
print len(search.tracks) #the total number of tracks
print [a.load() for a in search.tracks] #if you leave "name" off, you get the uris
trackNames = [a.load().name for a in search.tracks] #make the list of all the track names
trackURIs = [a.load() for a in search.tracks] #make a list with all the track URIs
return trackNames,trackURIs
#lets play blackbird - which is 1 location
except:
print "sorry, I couldn't find ",searchTerm," for you..."

Now Go Get the Track

Now that we can search for any given artist, we now pass the resulting lists to another function that plays the track. One key to this process is the use of the Track(u’spotify:track:blahblahblah’) object. PySpotify allows you to load the track object directly into the session.player.load() method. Now we’re in business.

def playTrack(trackURI):
"""play any track with any given trackURI"""
#####main function to play something
#this is only needed if you dont use Track(u'xxxx')
# Play a single track
#track_uri = 'spotify:track:'+trackURI
#track_uri = trackURI
#track = session.get_track(track_uri).load()
#play a track using the info provided by Spotify themselves
session.player.load(trackURI)
session.player.play()
# Wait for playback to complete or Ctrl+C
try:
while not end_of_track.wait(0.1):
pass
#after exiting loop, logout
session.logout()
session.forget_me()
print "logged you out properly...I think"
except:
session.logout()
session.forget_me()
print "Shit went wrong, I'm logging out..."

What Is Next?

In the near future we will review implementing our code on a Raspberry Pi and expanding with other needed functions as we go. Maybe we want to play a specific song when motion is detected or if a house doorbell is rung. The possibilities are endless!

-j

Full Code

######################Stream Using PYSPOTIFY##########################
###MUST HAVE A SPOTIFY PREMIUM ACCOUNT!!!!
#!/usr/bin/env python
"""
This is an example of playing music from Spotify using pyspotify.
The example use the :class:`spotify.AlsaSink`, and will thus only work on
systems with an ALSA sound subsystem, which means most Linux systems.
0. Make sure you have a Spotify Premium account -- it doesnt work for free accounts
1. Follow these references to create a Spotify Developer account/ make a new app and get the binaries
ref = get keys -- https://pyspotify.mopidy.com/en/latest/quickstart/#application-keys
2. Get PySpotify installed with AlsaSink as well
ref = install -- https://pyspotify.mopidy.com/en/latest/installation/
3. Start developing and if you need to read some documentation
ref = https://media.readthedocs.org/pdf/pyspotify/v2.x-develop/pyspotify.pdf
4. You are only limited by your imagination
"""
from __future__ import unicode_literals
import sys
import threading
import spotify
from spotify import sink
def on_connection_state_updated(session):
"""create a function that listens for the login status"""
if session.connection.state is spotify.ConnectionState.LOGGED_IN:
logged_in.set()
def on_end_of_track(self):
"""listens to see if its the end of the track"""
end_of_track.set()
def getPlaylist(playlistName):
"""gets the uris from a playlistName you want to search for"""
print "You have ",len(session.playlist_container)," playlists on your account"
i = 0
#print all the playlist names
for ea in session.playlist_container:
print session.playlist_container[i].load().name
#you can comment this out, just making sure to logout properly
session.logout()
session.forget_me()
def playTrack(trackURI):
"""play any track with any given trackURI"""
#####main function to play something
#this is only needed if you dont use Track(u'xxxx')
# Play a single track
#track_uri = 'spotify:track:'+trackURI
#track_uri = trackURI
#track = session.get_track(track_uri).load()
#play a track using the info provided by Spotify themselves
session.player.load(trackURI)
session.player.play()
# Wait for playback to complete or Ctrl+C
try:
while not end_of_track.wait(0.1):
pass
#after exiting loop, logout
session.logout()
session.forget_me()
print "logged you out properly...I think"
except:
session.logout()
session.forget_me()
print "Shit went wrong, I'm logging out..."
def getAlbum(albumURI):
"""get the album information -- right now only works if you know the album URI"""
try:
album_uri = 'spotify:album:'+albumURI
album = session.get_album(album_uri)
album.load()
except:
print "Sorry, couldn't load the album info..."
print "The Album name is: ",album.name()
print "The Artist name is: ",album.artist.load().name
#now we can browse the album
browser = album.browse()
#now we can get all the albums tracks
return browser.tracks
def getCover(trackURI):
"""get the cover and show it -- loads the values but doesnt display it for you"""
try:
cover_uri = 'spotify:album:'+trackURI
cover = session.get_album(cover_uri)
cover.load()
except:
print "Sorry, couldn't load the cover info..."
def getURI(searchTerm):
"""input any search term and I'll find it for you and returns trackNames and trackURIs to use"""
try:
search = session.search(searchTerm)
print search.load()
#(search.artist_total, search.album_total, search.track_total, track.playlist_total)
print search.artists[0].load().name #get first result
#eventually will go and get cover art at the same time
#getCover(theAlbumURI)
print len(search.tracks) #the total number of tracks
print [a.load() for a in search.tracks] #if you leave "name" off, you get the uris
trackNames = [a.load().name for a in search.tracks] #make the list of all the track names
trackURIs = [a.load() for a in search.tracks] #make a list with all the track URIs
return trackNames,trackURIs
#lets play blackbird - which is 1 location
except:
print "sorry, I couldn't find ",searchTerm," for you..."
# Assuming a spotify_appkey.key in the current dir
session = spotify.Session()
# Process events in the background
loop = spotify.EventLoop(session)
loop.start()
# Connect an audio sink - alsaSink is used on unix systems
audio = spotify.AlsaSink(session)
# Events for coordination
logged_in = threading.Event()
end_of_track = threading.Event()
# Register event listeners
session.on(spotify.SessionEvent.CONNECTION_STATE_UPDATED, on_connection_state_updated)
session.on(spotify.SessionEvent.END_OF_TRACK, on_end_of_track)
# Assuming a previous login, we may want to logout, especially if remember_me=True previously
session.logout() #clear out any priors just in case
session.forget_me()
try:
session.relogin()
print "I re-logged you in good Sir..."
except:
session.login(username="YOUR USERNAME",password="YOUR PASSWORD",remember_me=False)
print "You have\'t been here in a bit..."
#login and wait for the end of the track
logged_in.wait()
##use this to print out what playlists you have
#getPlaylist(trackURI)
##get the cover info - this one is still in progress
#getCover(someTrackURIthatYouHave)
#loop through the tracks for the Beatles and Play them all....
trackNames,trackURIs = getURI("The Beatles")
#for every trackName and trackURI in the found lists
for trackName,trackURI in zip(trackNames,trackURIs):
#ask if we should play that song
answer = str(raw_input("Play "+trackName+" now?(Y,N)>"))
#if yes, then stream it
if answer != "N":
print "Playing ",trackName," ..."
playTrack(trackURI)
else:
pass
#make sure you log out
session.logout()
session.forget_me()