h3x.se spotify remote

API/Protocol

Servify API/Protocol
Short description of the currently available commands to Servify.


Servify message specification
         +---------------------------+
Header   | Version (int32)           | <- 4 bytes, big endian
         | Version (char)            | <- 4 bytes
         | Length of Payload (int32) | <- 4 bytes, big endian
         +---------------------------+
Payload  | Json message              |
         +---------------------------+

*/

/**

Payload
Json
base64-encoded binary data fields
utf-8          textual data

*/

/* =============================================================================
 * Commands
/* =============================================================================

/* -------- Play -------- */
{
	"commandType": "playTrack",
	"trackNo": 0
}

/* -------- Stop -------- */
{
	"commandType": "stopPlayback"
}

/* -------- Play Next Track -------- */
{
	"commandType": "nextTrack"
}

/* -------- Play Previous Track -------- */
{
	"commandType": "previousTrack"
}

/* -------- Pause Playback -------- */
{"commandType": "togglePause"}

/* -------- Pong -------- */
{
	"commandType": "pong"
}

/* -------- List Users Playlists -------- */
{
	"commandType": "listPlaylists"
}




/* -------- Browse Playlist -------- */

{
	"commandType": "browsePlaylist",
	"spotifyURI": "sdkfj23fmwlk23df"
}

/* -------- Browse Artist -------- */
{
	"commandType": "browseArtist",
	"spotifyURI": "sdkfj23fmwlk23df"
}

/* -------- Browse Album -------- */
{
	"commandType": "browseAlbum",
	"spotifyURI": "sdkfj23fmwlk23df"
}

/* -------- Enqueue track/album/playlist to PlayQueue -------- */ 
{
	"commandType": "enqueue",
	"spotifyURI": "sdkfj23fmwlk23df",
	"spotifyURIs":
	[
		"sdkfj23fmwlk23df",
		"sdkfj23fmwlk23df",
		"sdkfj23fmwlk23df"
	]
}

/* -------- StarTrack -------- */ 
{
	"commandType": "starTrack",
	"spotifyURI": "sdkfj23fmwlk23df",
	"onOff": true
}

/* -------- Dequeue track from PlayQueue -------- */
{
	"commandType": "dequeue",
	"trackNo": 0
}

/* -------- Dequeue All tracks from PlayQueue -------- */
{
	"commandType": "dequeueAll"
}

/* -------- Toggle Shuffle -------- */
{
	"commandType": "toggleShuffle"
}

/* -------- Toggle Repeat -------- */
{
	"commandType": "toggleRepeat"
}

/* -------- Volume -------- */
{
	"commandType": "volume",
	"value": 72.3
}

/* -------- Seek -------- */
{
	"commandType": "seek",
	"value": 72.3
}

/* -------- Search -------- */
{
	"commandType": "search",
	"searchString": "Alban"
}

/* -------- Toggle Mute -------- */
{
	"commandType": "toggleMute"
}

/* -------- Artwork Request -------- */
{
	"commandType": "artworkRequest",
	"artworkType": "all"|"coverArt"|"artistPhoto",
	"size": "small"|"medium"|"large",
	"spotifyURI":"sdkfj23fmwlk23df",
	"spotifyURIs":
	[
		"sdkfj23fmwlk23df",
		"sdkfj23fmwlk23df",
		"sdkfj23fmwlk23df"
	]
}


##
## Playlist manipulation
##

/* -------- AddTrackToPlaylist -------- */
{
	"commandType": "addTrackToPlaylist",
	"tracks":
	[
		"sdkfj23fmwlk23df",
		"sdkfj23fmwlk23df",
		"sdkfj23fmwlk23df"
	],
	"playlistURI": "sdkfj23fmwlk23df"
}


/* =============================================================================
 * Common types
/* =============================================================================

/* ======== Artist ======== */
{
	"name": "Dan Cooper",
	"spotifyURI": "dasjflaksdfj"
	"albums":
	[
		#albumStub#,
		#albumStub#
	]
}

/* ======== ArtistStub ======== */
{
	"name": "Dan Cooper",
	"spotifyURI": "dasjflaksdfj"
}


/* ======== Track ======== */
{
	"name": "track1",
	"duration": 210,
	"artist": "Dan Cooper",
	"album": "The Album"
	"popularity": 65,
	"spotifyURI": "dasjflaksdfj"
}

/* ======== Album ======== */
// type: album, single, compilation, unknown
{
	"name": "My album",
	"year": "1985",
	"spotifyURI": "dasjflaksdfj",
	"albumType":"single",
	"artists":
	[
		#artistStub#,
		#artistStub#
	],
	"tracks":
	[
		#track#,
		#track#,
		#track#,
		#track#,
	]
}

/* ======== Album Stub ======== */
// type: album, single, compilation, unknown
{
	"name": "My album",
	"year": "1985",
	"spotifyURI": "dasjflaksdfj",
	"albumType":"single",
	"artists":
	[
		#artistStub#,
		#artistStub#,
	]
}


/* ======== Playlist ======== */
{
	"name": "My playlist",
	"creator": "username",
	"spotifyURI": "sdkfj23fmwlk23df",
	"tracks":
	[
		#track#,
		#track#,
		#track#,
		#track#
	]
}

/* ======== Playlist stub ======== */
{
	"name": "My playlist",
	"creator": "username",
	"spotifyURI": "sdkfj23fmwlk23df",
	"trackCount":34
}

/* =============================================================================
 * Messages
/* =============================================================================

/* -------- Hello -------- */
{
	"messageType": "hello",
	"severType": "Servify/C#",
	"serverVersion": "1.0",
	"messageVersion": "1.0"
}

/* -------- Ping -------- */
{
	"messageType": "ping"
}

/* -------- Volume -------- */
{
	"messageType": "volume",
	"volume": 89.5
}

/* -------- Alert -------- */
{
	"messageType": "alert",
	"type": "error" | "info" | "warning"
	"message": "This is an error message"
}

/* -------- Album -------- */
{
	"messageType": "album",
	"album": #album#
}

/* -------- Artist -------- */
{
	"messageType": "artist",
	"artist": #artist#
}

/* -------- Playback -------- */
{
	"messageType": "playback",
	"isPlaying": true,
	"track": #track#,
	"trackNo": 3
}

/* -------- Progress -------- */
{
	"messageType": "progress",
	"timeString": "03:22",
	"percentage": 25.63,
	"milliseconds": 2333
}

/* -------- Shuffle -------- */
{
	"messageType": "shuffle",
	"isShuffle": true
}

/* -------- Mute -------- */
{
	"messageType": "mute",
	"isMuted": true
}

/* -------- Repeat -------- */
{
	"messageType": "repeat",
	"isRepeat": true
}

/* -------- Play Queue -------- */
{
	"messageType": "playQueue",
	"tracks"
	[
		#track#,
		#track#,
		#track#,
		#track#
	]
}

/* -------- Artwork -------- */
{
	"messageType": "artwork",
	"type": "coverArt",
	"spotifyURI": "sdkfj23fmwlk23df",
	"spotifyURIs": 
	[
	    "sdkfj23fmwlk23df"
		"sdkfj23fmwlk23df"
		"sdkfj23fmwlk23df"
	],
	"size": "small",
	"imageData": <>
}

/* -------- List of Playlists -------- */
{
	"messageType": "listOfPlaylists",
	"playlists":
	[
		#playlist stub#,
		#playlist stub#,
		#playlist stub#
	]
}

/* -------- Playlist -------- */
{
	"messageType": "playlist",
	"playlist": #playlist object#
}


/* -------- SearchResult -------- */
{
	"messageType": "searchResult",
	"searchString": "Alban",
	"tracks":
	[
		#track,
		#track,
		#track,
		#track,
		#track,
		#track
	],
	"albums":
	[
		#albumStub,
		#albumStub,
		#albumStub,
		#albumStub
	],
	"artists":
	[
		#artist,
		#artist,
		#artist,
		#artist
	]
}

Comments () Trackbacks (0)
  1. I’m a bit impatient so until I get a chance to try this out…

    In order to use the API it’s an HTTP GET/POST request and response cycle using plain JSON? The payload doesn’t have to be bundled in any way?

    I could even use curl to communicate with Servify?

    This really looks good are you going to open the code or do you want to protect your IP?

    Where’s your donate button :)?

  2. Anthony, each request/response must have a header as described in the protocol document.

  3. Could you post a simple example, please? An example header and an example for say, getting all playlists. Oh, and please open the code for the servify/C#. No good reason for keeping it closed, eh?

  4. Ravi: a code (java) example of how to send messages to Servify:

    DataOutputStream dataStream = new DataOutputStream(socket.getOutputStream());
    dataStream.writeInt(1);
    dataStream.writeBytes(“H3X!”);
    dataStream.writeInt(payload.length());
    dataStream.writeBytes(payload);
    dataStream.flush();

    payload is a string such as:
    {“commandType”: “toggleShuffle”}

    See the API/Protocol stuff here on h3x.se for more info about different messages.

  5. Hello!

    Can we use this somehow to dump songs to hdd. And use other players to listen to it.

    Applian Media Catcher won’t work.

    Thanks

  6. Hi mate,

    Classic 4:30am mistake:
    ”HEX!” should be “H3X!”

    Hence the incorrect magic string. Feel free to delete my noise πŸ˜›

  7. Alex, good that you got it working.. and yes, classic mistake πŸ™‚

  8. Any plans on adding support for local files?

  9. Patrik, no. Not at this time.

  10. Hey..

    would i be able to use servify with jQuery?
    By doing something like an $.ajax call with the right headers defined?

    and if so how should the headers be?

  11. Hello I ahave just discovered you program and I am having trouble sending the header. This is what im sending, can you see anything wrong?

    Any help greatly appreciated.

    POST / HTTP/1.1
    HOST: 192.168.1.134:1337
    Content-Type: application/json
    1
    H3X!
    Content-Length: 30

    {“commandType”: “stopPlayback”}


Leave a comment

No trackbacks yet.