How Spotify changed the way I listen to music


java tech spring
6 minutes read

For quite some time I found myself waiting impatiently for the next Monday, and that’s not because of opportunity to rise early and go to University. That’s because the most amazing thing appears: a stunning music playlist freshly crafted for me by Spotify, music streaming service.

The playlist, called Discover Weekly, is a set of 30 songs picked magically just for me. It sounds pretty simple, right? As some might expect, there is some serious Data Science involved in the process of music recommendation at Spotify.

It is almost weird how good Discover Weekly is. In fact it’s so good it inspired me to write about it and make a small Java project concerning it (more on that later).

Golden age of music

Remember when you had that great collection of Compact Cassettes or CD’s at home and wanted to take all your music with you? Of course it wasn’t impossible, but hey, it was inconvenient. What streaming services did to music is comparable to what YouTube did to funny videos or what Reddit did to pictures with cute kittens - they just completely changed the game.

The idea of having all the music you want with you while not having it physically is just awesome. To get the difference, a very fancy device in the eighties - a discman(a CD player, kids) with one CD could provide you with around 20 tracks. Not bad, huh? Today, with a little combined help from your smartphone and Spotify, you have more than 30 million songs and around 200 000 more appear every day. You don’t just have an artist or an album with you. You have the Music with you.

Making music better with Data Science

Spotify launched its Discover Weekly playlist in July, 2015. Since then every user has the privilege of getting new mixtape tailored just for him every Monday, and while the company actually has human music experts making thousands of special playlists it would just be impossible for Spotify to hire all the people needed to make tens of millions of them. The music streaming service uses three tricks to do it:

Collaborative filtering

In geek speak: automatic predictions about one user preferences based on collected preferences from many others. Speaking human, it’s an extension of: “people who like that, also like this”. The assumption is that if Alice likes a song that Ben likes, then in theory Ben is more likely to enjoy one of Alice favorites instead of something that Charlie listens to. This is exactly what happens at Spotify. The company analyzes hundreds of millions of user playlists in order to find similarities and based on that it proposes new tracks. The whole trick to collaborative filtering is that it recommends new things based on similarity between users, not between items.

Natural language processing

There is a certain obstacle in the way of collaborative filtering functioning neatly. It is called a cold start and it happens every time Spotify welcomes a brand new song into its vast database. The service simply hasn’t gathered any data about this track since nobody listened to it yet and it fails to find any similarities or relationships concerning the fresh song. Now a different tool comes into play: Word2Vec, a natural language processor created by the brightest minds at Google. This technique enables encoding words into mathematical representation - a vector. Vectors with similar shape are just like words with similar meaning. All this makes it possible for Spotify to treat songs as words and based on that determine which tracks are similar to each other even if they have only few plays.

Outlier detection

Technically speaking, outlier is an observation which is so different from other observations that it arouses suspicion of being generated by a different mechanism. This method is widely used in finance sector to detect fraud. To give you an idea - purchasing behavior of a credit card owner usually changes dramatically when the card is stolen. At Spotify, outlier detection is used to determine if a certain user actions are a part of normal behavior. This way if John only listens to classical music of First Viennese School he won’t have hardcore death metal on his Discover Weekly playlist when his nephew Andrew puts Slipknot or Slayer few times. Clever, ain’t it?

Making cool things cooler

Even though it all looks sweet there is one very tiny flaw that I couldn’t resist improving for myself. Since Spotify serves you a brand new and shiny playlist every Monday, it actually replaces the content of your previous Discover Weekly collection and if you fail to save the tracks in some predefined playlist of yours, then it’s gone. There are existing solutions to this problem like Save Discover Weekly or Mixkeepr but I wanted to tackle this in my own way. I created an app in Java which with a single run archives all the tracks from Spotify’s Discover Weekly playlist in my own collection.

How it works

I used Spring Boot to create a fully-fledged server without tons of configuration. Java was the best fit, thanks to Spotify Web API Java Wrapper which includes helper functions to complete authorization process and manage playlist modifications.

First, I registered my app at Spotify Developers Site to get Client ID and Client Secret which will be needed to complete the process of authorization once your app will send a request to Spotify. I also had to specify redirectURI where I would receive incoming request from authorization server which in this case is just localhost. Using those variables I instantiate API:

final String clientId = "clientId";
final String clientSecret = "clientSecret";
final String redirectURI = "http://localhost:8080/callback/";
final Api api = Api.builder().clientId(clientId).clientSecret(clientSecret).redirectURI(redirectURI).build();

This will allow me to create an authorization URL to which I need to connect in order to log myself to Spotify. Note that I have to set the specific scopes if I want to make modifications to private playlists - in this case these are playlist-read-private and playlist-modify-private

/* Set the necessary scopes that the
application will need from the user */
final List<String> scopes = Arrays.asList("user-read-private",
"user-read-email", "playlist-read-private","playlist-modify-private");

/* Set a state. Used to prevent cross site request forgeries */
final String state = "someExpectedStateString";

String authorizeURL = api.createAuthorizeURL(scopes, state);
URL spotifyAuthorize = new URL(authorizeURL);

The app opens default web browser with the authorizeURL and I am able to log in with my credentials. After, Spotify redirects me to the redirectURI, along with an authorization code. Luckily, our app listens to any request at localhost and is able to retrieve this code. This is getting boring, isn’t it? One last step in authorization process (I promise) is to take this code and fire off another request with it in order to get the Holy Grail - Access Token.

final String codeToString = code.toString();
final SettableFuture <AuthorizationCodeCredentials> codeCredentials =
api.authorizationCodeGrant(codeToString).build().getAsync();

/* Add callbacks to handle success and failure */
Futures.addCallback(codeCredentials,
 new FutureCallback<AuthorizationCodeCredentials>() {

@Override
public void onSuccess(AuthorizationCodeCredentials codeCredentials) {
  api.setAccessToken(authorizationCodeCredentials.getAccessToken());
}
});

Aaaaand, I am in. Now I have full access to my Spotify account and can do all the stuff like looking up tracks, artists, creating a playlist or getting new releases. But what we are looking for is modifying existing playlist. From here on it is just magic - first I make a request to get list of tracks from Spotify’s Discover Weekly:

/* Getting tracks from Spotify's Weekly Playlist */
final PlaylistTracksRequest request = api
.getPlaylistTracks("spotify", "discoverWeeklyPlaylistID").build();
final List<String> tracksToAdd = new ArrayList<String>();
final Page<PlaylistTrack> page = request.get();
final List<PlaylistTrack> playlistTracks = page.getItems();

/* Creating List of tracks to add */
for (PlaylistTrack playlistTrack : playlistTracks) {
	tracksToAdd.add(playlistTrack.getTrack().getUri());
}

and then, I add all of those tracks to my previously defined playlist called Discover in which I will store all of my Discover Weekly tracks (and believe me this playlist already rocks!)

final User user = requestCurrentUser.get();
/* Adding tracks from Spotify's Weekly Playlist to mine */
final AddTrackToPlaylistRequest requestAddTracks = api
.addTracksToPlaylist(user.getId(), "myPlaylistID",
tracksToAdd).build();
requestAddTracks.get();

And that’s it! Now I have all of the tracks I want, where I want with just a single run of this amazing-magic-stunning app. One more thing I did is to check if any of the tracks from Discover Weekly that I want to add to my playlist already exist in my collection. If so, those tracks are not going to be added. This prevents duplicate items in the playlist.

To wrap it up, I generated executable .jar package with mvn clean install and set an alias in my console for a quick access spotifyDiscover='java -jar ~/spotify.jar'

The project is at my Github, come take a look.