close

Day 11: Get musical by building a Spotify application

So, you have recently heard about the new Spotify Platform? The new app platform built around everyone’s favourite subscription based audio service. As with all new platforms, developers can’t wait to take Spotify apps for a spin.

Before you touch any code it is probably advisable to actually download the Spotify preview itself. You can download the preview from here. Once you have downloaded the preview with the new Spotify App Finder. You will want to register yourself as a developer. This allows you to install local apps. To register as a developer you need to fill out a simple form.

But what if you want to start developing Spotify apps before they give you developer access? Well that is relatively simple. The Spotify platform is built on top of Chromium. Which as you probably know by now uses the WebKit rendering engine, which means you can test your apps visually just using Google Chrome.

OK, so now you have developer access or at least a vague development environment. Now you want to know what features you can use with the new Spotify apps. To begin with let’s discuss the features of the rendering engine.

From speaking to other developers the HTML5 features that they most hoped for in Spotify are WebSockets, Canvas, Audio API. The good news is that both WebSockets and Canvas are supported. However the bad news is that the Audio API is not supported and as it happens neither is the audio element itself. This unfortunately means that the ONLY audio you can play through your app HAS to go through Spotify itself.

Although the Audio API isn’t supported. Spotify developers have been working on providing audio data access from within apps. I was luckily enough to see a sneek peak at Music Hack Day London recently, where one of the devs showed off a simple levels visualiser. He told me that he will try and get it into the stable build as soon as he can and the product manager was also keen to enable this feature. So fingers crossed it will arrive in the coming months.

For a full list of HTML5 feature support, check out Spotify’s official page within their developer build of the app.

Another annoying thing about the current Spotify App API is that you don’t have any access to the current user. You have access to the current track being played and the ability to create playlists, but there is no way to obtain any information about the current user.

So what can you get from the API? Check out their docs for more info.

One major thing to bear in mind is that Spotify is a global app. But their tracks are not global, so for any kind of track usage you need to check to make sure the user CAN actually play the track that you want to specify.

There are two APIs that Spotify provider for you to use, the Apps API, and their Metadata API. The Apps API is for information mainly about the spotify player and app itself. Where as the Metadata API is for searching and retreiving data about particular artist or tracks.

For this demo, my app will also use the Echo Nest API. We will find out what the currently playing track is, and then cross reference with Echo Nest to find similar tracks. Once we have found the similar tracks the user will then be able to click on them to play them in spotify.

What is Echo Nest?

The Echo Nest knows more about music content and consumers than anyone. Their platform opens up this dynamic music data to any developer through their easy-to-use, real-time API. They provide information about tens of millions of songs and millions of artists.

Spotify uses Echo Nest to power their own radio.

So let’s crack on and make a simple app

Let’s start with where to create this project.

On a mac, you need to create a new folder in your users home directory, called Spotify (~/Spotify) [NB: it is case sensitive].

On Windows it is My DocumentsSpotify

Inside this folder, create a folder for your project. In the folder you NEED 2 files, index.html & manifest.json

1

For sake of ease I am also using jquery in this demo.

The manifest.json file consists of a json object containing data about the app.

{
"BundleType": "Application",
"AppIcon": {
"18x18": "icon.png"
},
"AppName": {
"en": "Suggestify"
},
"SupportedLanguages": [
"en"
],
"RequiredPermissions": [
"http://*.echonest.com",
"http://*.spotify.com",
]
}

One huge point to note in the manifest file, is the RequiredPermissions array. This array contains all the external domains that your app needs to access via AJAX etc.

An annoying bug with Spotify right now, is that if you change your manifest file, you also need to change the directory of the app.

In your index.html you have a standard html body structure.

There are 2 default css files provided by Spotify for native UI elements:

sp://import/css/adam.css – Dark theme
sp://import/css/eve.css – Light theme

The <head> of my index.html looks like this:

<title>Suggestify</title>
<link rel="stylesheet" href="sp://import/css/adam.css">
<script type="text/javascript" src="jquery.min.js"></script>

Then in the <body> my only html is an unordered list of id results this is a list for me to dynamically insert list items containing links to suggested songs.

Now my index.html looks like this:

<!DOCTYPE html>
<html>
<head>
<title>Suggester</title>
<link rel="stylesheet" href="sp://import/css/adam.css">
<script type="text/javascript" src="jquery.min.js"></script>
</head>

<body>
<h1> Here's a generated track list from echo nest and the current track</h1>
<ul id="results"> </ul>

<script type="text/javascript">
// this is where we do something
</script>
</body>
</html>

To load the app into Spotify itself, via the UI, search for spotify:app:appNAME

2

Now we want to get access to the Spotify Apps API:

var sp = getSpotifyApi(1);

And we want access to the Spotify models

var m = sp.require('sp://import/scripts/api/models');

Now we want to find out what the current track is:

// get the track that is currently playing
function getCurrentlyPlaying() {
var currentTrack = m.player.track;

// if nothing currently playing
if (currentTrack == null) {
console.log("No track currently playing");
}

// winner we have a track
else {
var track = currentTrack;
var artist = track.artists[0].name;

// do something with this information
}
}

So, we know what the current track and artist is, we now need to fetch from EchoNest suggested tracks.

function fetchSuggestions(artist, size) {
var echoNestAPIKey = "GPQCPTGUIZ43M2FSV";
// find similar songs using echonest
var url = 'http://developer.echonest.com/api/v4/playlist/basic?api_key='+echoNestAPIKey+'&callback=?';

// in this demo I will only use artist-radio so that we don't need extra requests.
$.getJSON(url, {
artist: artist,
format: 'jsonp',
results: size,
type: 'artist-radio'
}, function(data) {
if (data.response && data.response.status.code === 0) {
$("#results").empty();

for (var i = 0; i < data.response.songs.length; i++) {

// we now have the echo nest song
var song = data.response.songs[i];

// fetch spotify tracks from these songs using their metadata api
// do something with this info

}
} else {
info("failed getting results");
}
});
}

So we now have the data for each suggested track, such as artist and track name. From this, we need to obtain a spotify track object from this information. Spotify has a Search model built into it’s API. We use that to find a spotify track.

// using artist name and song name, find the spotify track
function fetchSpotifyTrack(artist,song) {

// build the search query
var query = artist + " " + song;

// using the search model
var search = new m.Search(query,function(results) {

// spotify may return more than one possible track
for (var i= 0; i< results.results.length;i++) {

// get the actual track
var track = results.results[i].data;

// check that the artist name is the same
if (track.artists && track.artists[0].name === artist) {

// check that the track name is the same
if (track.name === song) {

// create a list element
var li = $("<li/>");

// don't forget not all songs are available everywhere
if (track.availableForPlayback) {

var a = $("<a href='"+track.href+"'/>");

a.html(artist + " - " + song);
// play it on click
a.click(function() {
playTrack(track);
return false;
});

li.append(a);

} else {

li.html(artist + " - " + song);

// NOT AVAILABLE show in red
li.css('color','#f00')
}

// add the list item
$("#results").append(li);

// we no longer want to loop
break;
}
}
}
});
}

So we now have suggested tracks, and spotify tracks, and we know if they can be played in the current country. The only left to do, is set them to play when clicked on.

// play a track in the player
function playTrack(track) {

// play the track from it's uri, here you can pass the whole track object, but it will switch to album view away from the app
m.player.play(track.uri);
}

Finally we need to piece it all together and get it to run each time the song changes, or on first load.

// when the track changes, we need to listen for an event
sp.trackPlayer.addEventListener("playerStateChanged", function (event) {
// if the event is actually a new song
if (event.data.curtrack) {
getCurrentlyPlaying();
}
});

// check on start
getCurrentlyPlaying();

We now have a very simple app that uses the Echo Nest API to list suggested tracks based on the current track played.

To view the source code and download this demo app, you can get it from my github account.

I have also extended this demo app to create a much nicer UI and a more fully featured version. This can be found on the “swanky” branch on github.

Points to note

  • If you change your manifest, you must restart Spotify itself, I have been informed they may be looking into an easier method but at the moment Spotify caches the manifest.
  • App MUST be located: ~/Spotify/{appname}
  • App launched by searching for: spotify:app:{appname}
  • To get access to the models available, you need to: sp.require(‘sp://import/scripts/api/models’);
  • The Apps API is currently in development and may change at any point