XML Client API
From MtdWiki
mt-daapd makes much of its information available as xml over http. This makes writing client application that interface with it much easier. Below is an overview of the different information that can be obtained from mt-daapd, and the expected response.
Note that all of these xml files are standalone, and have no DTD. For the most part, they are a direct analog to the dmap blocks that iTunes natively works with, so the API matches very closely that of iTunes.
These can all be called using regular http requests to the port that mt-daapd is configured to listen on. Also, since mt-daapd doesn't use session id's, any of these can be called using curl or wget. For example, to see server info, you could use the following curl command:
curl -o out.xml "http://server.ip.address:port/server-info?output=xml"
and you will get an output file called out.xml described in the server info section. The "output=xml" is the best format for client use, as it does not have any linefeeds or extraneous spaces, which helps obviate certain mozilla features (bugs?) regarding text nodes in the DOM. Sadly, though, that format is unpleasant for actually viewing xml data, so when browsing using curl or wget, I use "output=readable" which generates the indented and readable xml files you see below.
| Table of contents |
|
|
Common Notes
Many of these functions have things in common. Particularly some of the response fields and the way that custom metainfo can be specified.
Common Result Fields
dmap.status
Every response has a dmap.status result. This is presumably like the HTTP status code. Currently, this is always 200, as any kind of error will generate a HTTP error. For example, a bad request, or a request to an invalid database id will return a HTTP 500 error, rather than a HTTP 200 error and a dmap.status of 500.
This behavior will likely change in the future, so clients should probably check for both HTTP errors as well as dmap.status other than 200.
dmap.specifiedtotalcount, dmap.returnedcount
iTunes has the ability to "page" through results using indexes. For example, a memory-constrained device could page through the library ten results at a time by using the index argument. Currently mt-daapd doesn't support index, but will before a 0.3.0 release.
In any event, one would suppose (?) that dmap.specifiedtotal count would reflect the total number of results that the query could return, while dmap.returnedcount reflects the actual number of results returned due to constraints of the index argument. In the example of paging through the database of items 10 items at a time, dmap.specifiedtotalcount might be 5000, while dmap.returnedcount would be 10.
This is somewhat hypothetical.
Querying
The main query for retrieving items from the database is the items request. This returns all items in the database. You can filter that list by using queries. A query is specified by passing a variable called "query" with a valid query string. A valid query string consists of one or more expressions linked together by AND or OR specifiers. A valid expression is basically an iTunes fieldname, followed by an comparison operator, followed by a value, all enclosed in a single quote.
| specifier | SQL field | type |
|---|---|---|
| dmap.itemname | title | string |
| dmap.itemid | id | int |
| daap.songalbum | album | string |
| daap.songartist | artist | string |
| daap.songbitrate | bitrate | int |
| daap.songcomment | comment | string |
| daap.songcompilation | compilation | int (0 or 1) |
| daap.songcomposer | composer | string |
| daap.songdatakind | data_kind | int |
| daap.songdataurl | url | string |
| daap.songdateadded | time_added | int (unix epoch) |
| daap.songdatemodified | time_modified | int (unix epoch) |
| daap.songdescription | description | string |
| daap.songdisccount | total_discs | int |
| daap.songdiscnumber | disc | int |
| daap.songformat | type | string |
| daap.songgenre | genre | string |
| daap.songsamplerate | samplerate | int |
| daap.songsize | file_size | int |
| daap.songstoptime | song_length | int (milliseconds) |
| daap.songtrackcount | total_tracks | int |
| daap.songtracknumber | track | int |
| daap.songyear | year | int |
| operator | meaning |
|---|---|
| + | greater than (int only) |
| - | less than (int only) |
| : | equal |
The sense of the operators can be reversed with a leading "!". So "!-" is "greater than or equal". "!:" is "not equal". You can't negate string equality though. (why not?)
You can OR two expresions with a comma (,), and AND two expressions with a plus (+).
GET /databases/1/items?output=xml&query='daap.songartist:Morrissey'
This would return all songs performed by Morrissey.
GET /databases/1/items?output=xml&query='daap.songartist:Morrissey','daap.songartist:The Smiths'
This would return all songs performed by The Smiths or by Morrissey.
GET /databases/1/items?output=xml&query='daap.songformat:mp3'+'daap.songbitrate+128'
This would get all mp3s with a bitrate higher than 128Kb.
Leading and trailing wildcards (*) are allowed for strings, as well. So:
GET /databases/1/items?output=xml&query='daap.songgenre:*rock*'
would match a genres "Acid Rock", or "Rock and Roll", or "Sprocket", assuming you had songs tagged with a genre of "Sprocket".
There really is no reason there can't be more query fields, these are just the ones that are implemented. If you want/need another one, just post in the forums and let me know. I can add whatever you need for a client.
WARNINGS
- String matches are case sensitive
- Wildcard string matches are NOT case sensitive
This sort of makes sense, since with wildcard matches you are searching, so you might want to match string. That behavior is controlled by the underlying database (sqlite), so it's really out of my control.
iTunes-Compatible Requests
First, the functions that are iTunes compatible.
Server Info
- path
- /server-info
- required arguments
- output=xml
- example
- GET /server-info?output=xml
- supports meta
- No
- supports query
- No
The server info request gives information about the mt-daapd server, including what capabilities it has, what version it is, and what extensions of daap it supports. The result looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <dmap.serverinforesponse> <dmap.status>200</dmap.status> <dmap.protocolversion>2.0.0</dmap.protocolversion> <daap.protocolversion>3.0.0</daap.protocolversion> <dmap.timeoutinterval>1800</dmap.timeoutinterval> <dmap.itemname>svr-test</dmap.itemname> <dmap.authenticationmethod>0</dmap.authenticationmethod> <dmap.supportsextensions>0</dmap.supportsextensions> <dmap.supportsindex>0</dmap.supportsindex> <dmap.supportsbrowse>0</dmap.supportsbrowse> <dmap.supportsquery>0</dmap.supportsquery> <dmap.supportsupdate>0</dmap.supportsupdate> <dmap.databasescount>1</dmap.databasescount> </dmap.serverinforesponse>
Note that the "supports" values are all zero. The fact that they are there at all indicates it supports that particular extension. If it did not support browse, then there wouldn't be a "supportsbrowse" at all.
Notice also that there is a "databasescount" value. It appears that daap generally supports the idea of more than one database, but that isn't implemented in the iTunes client, so mt-daapd doesn't implement it either.
Containers
- path
- /databases/<dbid>/containers
- required arguments
- output=xml
- supports meta
- Yes
- supports query
- No
- custom meta fields
- org.mt-daapd.playlist-type
- org.mt-daapd.smart-playlist-spec
This enumerates all containers (playlists) for a particular database. Again, note that iTunes (and mt-daapd) only support one database, so the dbid MUST be 1.
Example:
GET /databases/1/containers?output=xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.databaseplaylists> <dmap.status>200</dmap.status> <dmap.updatetype>0</dmap.updatetype> <dmap.specifiedtotalcount>2</dmap.specifiedtotalcount> <dmap.returnedcount>2</dmap.returnedcount> <dmap.listing> <dmap.listingitem> <dmap.itemid>1</dmap.itemid> <dmap.itemcount>5946</dmap.itemcount> <com.apple.itunes.smart-playlist>1</com.apple.itunes.smart-playlist> <dmap.itemname>Library</dmap.itemname> </dmap.listingitem> <dmap.listingitem> <dmap.itemid>2</dmap.itemid> <dmap.itemcount>265</dmap.itemcount> <dmap.itemname>80s Glam Rock</dmap.itemname> </dmap.listingitem> </dmap.listing> </daap.databaseplaylists>
The custom meta fields are used to retrieve infomation about the mt-daapd playlists. org.mt-daapd.playlist-type retrieves what kind of playlist a specific playlist is.
- 0 - Static playlist, updated via the web interface
- 1 - Smart playlists (SQL query)
- 2 - Static playlist, from a m3u file (can't be edited from the web interface)
- 3 - Static playlist, from iTunes XML file (can't be edited from the web interface)
org.mt-daapd.smart-playlist-spec is the actual SQL query for a smart playlist.
Example:
GET /database/1/containers?output=xml&meta=dmap.itemid,dmap.itemname,org.mt-daapd.playlist-type,org.mt-daapd.smart-playlist-spec
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.databaseplaylists> <dmap.status>200</dmap.status> <dmap.updatetype>0</dmap.updatetype> <dmap.specifiedtotalcount>2</dmap.specifiedtotalcount> <dmap.returnedcount>2</dmap.returnedcount> <dmap.listing> <dmap.listingitem> <dmap.itemid>1</dmap.itemid> <dmap.itemcount>5946</dmap.itemcount> <com.apple.itunes.smart-playlist>1</com.apple.itunes.smart-playlist> <dmap.itemname>Library</dmap.itemname> </dmap.listingitem> <dmap.listingitem> <dmap.itemid>23</dmap.itemid> <dmap.itemcount>0</dmap.itemcount> <dmap.itemname>Fave!</dmap.itemname> <org.mt-daapd.smart-playlist-spec>rating > 79</org.mt-daapd.smart-playlist-spec> <org.mt-daapd.playlist-type>1</org.mt-daapd.playlist-type> </dmap.listingitem> </dmap.listing> </daap.databaseplaylists>
Items
- path
- /databases/<dbid>/items
- required arguments
- output=xml
- supports meta
- Yes
- supports query
- Yes
This returns song data for every song in the database. If no meta is specified, a full set of iTunes-compatible metainfo is returned. Custom metainfo will not be returned unless a meta is specified.
Example:
GET /databases/1/items?output=xml
<daap.databasesongs> <dmap.status>200</dmap.status> <dmap.updatetype>0</dmap.updatetype> <dmap.specifiedtotalcount>5946</dmap.specifiedtotalcount> <dmap.returnedcount>5946</dmap.returnedcount> <dmap.listing> <dmap.listingitem> <dmap.itemkind>2</dmap.itemkind> <daap.songdatakind>0</daap.songdatakind> <daap.songalbum>10,000 Maniacs MTV Unplugged</daap.songalbum> <daap.songartist>10,000 Maniacs</daap.songartist> <daap.songbitrate>192</daap.songbitrate> <daap.songdateadded>1114741647</daap.songdateadded> <daap.songdatemodified>1114741647</daap.songdatemodified> <daap.songgenre>Pop 1980's</daap.songgenre> <dmap.itemid>1</dmap.itemid> <daap.songformat>mp3</daap.songformat> <daap.songdescription>MPEG audio file</daap.songdescription> <dmap.itemname>These Are Days</dmap.itemname> <daap.songsamplerate>44100</daap.songsamplerate> <daap.songsize>7214148</daap.songsize> <daap.songtime>293485</daap.songtime> <daap.songtrackcount>14</daap.songtrackcount> <daap.songtracknumber>1</daap.songtracknumber> <daap.songuserrating>60</daap.songuserrating> <daap.songyear>2000</daap.songyear> <daap.songcodectype>1836082535</daap.songcodectype> <dmap.containeritemid>1</dmap.containeritemid> </dmap.listingitem> </dmap.listing> </daap.databasesongs>
This function does support queries. See the section on queries for more information.
Container Items
- path
- /databases/<dbid>/containers/<cid>/items
- required arguments
- output=xml
- supports meta
- Yes (But don't bother)
- supports query
- Yes
This function is much like the above function, but shows what items are in each playlist. If you look at the output of the containers query, you will see that the "Library" container is just a container like any other. It is always container id 1, but it's just a container. So the difference between /databases/1/items and /databases/1/containers/1/items is that the default meta for container item queries is dmap.itemkind,dmap.itemid,dmap.containeritemid.
Basically, then, you would just use a default meta for container items, and use the itemid to lookup against the full info you already obtained from the item list.
Or, if you didn't want to pull the whole database, you could just pull container lists, then lookup the full detail for a particular song when you need it. For example, if you wanted to pull the full song info for song id 15, you could pull it with a query:
GET /databases/1/items?output=xml&query='dmap.itemid:15'
And that would get you full details for just that song.
If you wanted to, you could do queries on playlist items, but I'm not sure why you would want to. Any valid query term will work.
Example:
GET /databases/1/containers/26/items?output=xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.playlistsongs> <dmap.status>200</dmap.status> <dmap.updatetype>0</dmap.updatetype> <dmap.specifiedtotalcount>1</dmap.specifiedtotalcount> <dmap.returnedcount>1</dmap.returnedcount> <dmap.listing> <dmap.listingitem> <dmap.itemkind>2</dmap.itemkind> <dmap.itemid>1903</dmap.itemid> <dmap.itemname>Watermark</dmap.itemname> <dmap.containeritemid>1903</dmap.containeritemid> </dmap.listingitem> </dmap.listing> </daap.playlistsongs>
Browse Extensions
Browse extensions allow you to browse by genre, artist, album, or composer. Basically, this gives you a distinct list of every genre, artist, album, or composer. They are almost identical, except in the name of the container format.
it's possible to add other browse extensions. If you leave a message in the forum asking for another browse field, I could implement it.
Also, note that all of these browse arguments support queries. So if you wanted a list of all albums by a particular artist, for example, you could execute the following query:
GET /databases/1/browse/albums?output=xml&query='daap.songartist:Morrissey'
Would give you all the albums by Morrissey:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.databasebrowse> <dmap.status>200</dmap.status> <dmap.specifiedtotalcount>7</dmap.specifiedtotalcount> <dmap.returnedcount>7</dmap.returnedcount> <daap.browsealbumlisting> <dmap.listingitem>Just Say Anything</dmap.listingitem> <dmap.listingitem>Bona Drag</dmap.listingitem> <dmap.listingitem>Kill Uncle</dmap.listingitem> <dmap.listingitem>Our Frank</dmap.listingitem> <dmap.listingitem>Viva Hate</dmap.listingitem> <dmap.listingitem>World Of Morrissey</dmap.listingitem> <dmap.listingitem>Your Arsenal</dmap.listingitem> </daap.browsealbumlisting> </daap.databasebrowse>
Browse by Genre
- path
- /databases/<dbid>/browse/genres
- required arguments
- output=xml
- supports meta
- No
- supports query
- Yes
- custom meta fields
- No
Example:
GET /databases/<dbid>/browse/genres?output=xml
<daap.databasebrowse> <dmap.status>200</dmap.status> <dmap.specifiedtotalcount>98</dmap.specifiedtotalcount> <dmap.returnedcount>98</dmap.returnedcount> <daap.browsegenrelisting> <dmap.listingitem>Pop 1980's</dmap.listingitem> <dmap.listingitem>Pop 1990's</dmap.listingitem> <dmap.listingitem>Satire</dmap.listingitem> <dmap.listingitem>Dance</dmap.listingitem> <dmap.listingitem>Glam Rock</dmap.listingitem> <dmap.listingitem>Other</dmap.listingitem> </daap.browsegenrelisting> </daap.databasebrowse>
Browse by Artist
- path
- /databases/<dbid>/browse/artists
- required arguments
- output=xml
- supports meta
- No
- supports query
- Yes
- custom meta fields
- No
Example:
GET /databases/1/browse/artists?output=xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.databasebrowse> <dmap.status>200</dmap.status> <dmap.specifiedtotalcount>638</dmap.specifiedtotalcount> <dmap.returnedcount>638</dmap.returnedcount> <daap.browseartistlisting> <dmap.listingitem>10,000 Maniacs</dmap.listingitem> <dmap.listingitem>311</dmap.listingitem> <dmap.listingitem>"Weird Al" Yankovic</dmap.listingitem> <dmap.listingitem>A Split-Second</dmap.listingitem> <dmap.listingitem>ABBA</dmap.listingitem> <dmap.listingitem>Aerosmith</dmap.listingitem> <dmap.listingitem>Air</dmap.listingitem> </daap.browseartistlisting> </daap.databasebrowse>
Yeah, that's right... ABBA, baby!
GET /databases/1/items?output=xml&query='dmap.songartist:ABBA'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.databasesongs> <dmap.status>200</dmap.status> <dmap.updatetype>0</dmap.updatetype> <dmap.specifiedtotalcount>1</dmap.specifiedtotalcount> <dmap.returnedcount>1</dmap.returnedcount> <dmap.listing> <dmap.listingitem> <dmap.itemkind>2</dmap.itemkind> <daap.songdatakind>0</daap.songdatakind> <daap.songalbum>Greatest Hits, Volume 2</daap.songalbum> <daap.songartist>ABBA</daap.songartist> <daap.songbitrate>128</daap.songbitrate> <daap.songdateadded>1114741668</daap.songdateadded> <daap.songdatemodified>1114741668</daap.songdatemodified> <daap.songgenre>Pop 1980's</daap.songgenre> <dmap.itemid>67</dmap.itemid> <daap.songformat>mp3</daap.songformat> <daap.songdescription>MPEG audio file</daap.songdescription> <dmap.itemname>Dancing Queen</dmap.itemname> <daap.songsamplerate>44100</daap.songsamplerate> <daap.songsize>3684453</daap.songsize> <daap.songtime>230269</daap.songtime> <daap.songtracknumber>8</daap.songtracknumber> <daap.songuserrating>80</daap.songuserrating> <daap.songcodectype>1836082535</daap.songcodectype> <dmap.containeritemid>67</dmap.containeritemid> </dmap.listingitem> </dmap.listing> </daap.databasesongs>
If for no other reason that it ticks my friends off when I make their ringtone "dancing queen"...
Browse by Album
- path
- /databases/<dbid>/browse/albums
- required arguments
- output=xml
- supports meta
- No
- supports query
- Yes
- custom meta fields
- No
Example:
GET /databases/1/browse/albums?output=xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.databasebrowse> <dmap.status>200</dmap.status> <dmap.specifiedtotalcount>651</dmap.specifiedtotalcount> <dmap.returnedcount>651</dmap.returnedcount> <daap.browsealbumlisting> <dmap.listingitem>10,000 Maniacs MTV Unplugged</dmap.listingitem> <dmap.listingitem>From Chaos</dmap.listingitem> <dmap.listingitem>Off The Deep End</dmap.listingitem> <dmap.listingitem>...From the Inside</dmap.listingitem> <dmap.listingitem>Firewalker</dmap.listingitem> <dmap.listingitem>Flesh and Fire (1991 Remixes)</dmap.listingitem> <dmap.listingitem>Kiss of Fury</dmap.listingitem> </daap.browsealbumlisting> </daap.databasebrowse>
Note that is is pretty useless by itself. The only reason I could even think of using this is by using a query term to restrict it so you could see albums by a particular artist. See the example above.
Browse by Composer
- path
- /databases/<dbid>/browse/composers
- required arguments
- output=xml
- supports meta
- No
- supports query
- Yes
- custom meta fields
- No
Example:
GET /databases/1/browse/composers?output=xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.databasebrowse> <dmap.status>200</dmap.status> <dmap.specifiedtotalcount>93</dmap.specifiedtotalcount> <dmap.returnedcount>93</dmap.returnedcount> <daap.browsecomposerlisting> <dmap.listingitem></dmap.listingitem> <dmap.listingitem> </dmap.listingitem> <dmap.listingitem>Antonio Vivaldi</dmap.listingitem> <dmap.listingitem>Hayden</dmap.listingitem> </daap.browsecomposerlisting> </daap.databasebrowse>
Index Extensions
These are not yet implemented
mt-daapd extensions
The previous functions are all standard iTunes functions. There have been functions added to allow an xml-rpc client to remotely control mt-daapd. These are documented below.
Again, if you need a new function, or want a way to expose some functionality remotely, leave a message in the forums, and I will work with you on implementing it.
Add Playlist
- path
- /databases/<dbid>/containers/add
- required arguments
- output=xml,org.mt-daapd.playlist-type
- dmap.itemname
- optional arguments
- org.mt-daapd.smart-playlist-spec
- supports meta
- No
- supports query
- No
- custom meta fields
- No
org.mt-daapd.playlist-type must be set to one of the two valid playlists types listed above:
- Type 0 - Static playlist
- Type 1 - Smart playlist
If org.mt-daapd.playlist-type 1 is specified, then org.mt-daapd.smart-playlist-spec must be specified. org.mt-daapd.smart-playlist-spec must be a valid "where" clause on the songs database.
Example:
GET /databases/1/containers/add?output=xml&org.mt-daapd.playlist-type=0&dmap.itemname=test%20playlist
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <org.mt-daapd.addplaylist> <dmap.status>200</dmap.status> <dmap.itemid>64</dmap.itemid> </org.mt-daapd.addplaylist>
Status 200 means it succeeded, and itemid 64 is the new playlist item id. This could be used to add items later.
Add Playlist Item
- path
- /databases/<dbid>/containers/<playlistid>/items/add
- required arguments
- output=xml
- dmap.itemid=<songid>[,<songid>,<songid>]
- supports meta
- No
- supports query
- No
- custom meta fields
- No
I could be convinced that for symmetry with delete playlist item, this should really be /databases/<dbid>/containers/<playlistid>/add. You can try to convince me on the forum if you think it should be changed.
Let's add a song to the playlist created above. From before, we learned that ABBA's Dancing Queen was ID 67 in my database (but #1 in my heart), so let's add that song to the database.
Example:
GET /databases/1/containers/64/items/add?output=xml&dmap.itemid=67
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <org.mt-daapd.addplaylistitem> <dmap.status>200</dmap.status> </org.mt-daapd.addplaylistitem>
Now a container list should show it:
GET /databases/1/containers/64/items?output=xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <daap.playlistsongs> <dmap.status>200</dmap.status> <dmap.updatetype>0</dmap.updatetype> <dmap.specifiedtotalcount>1</dmap.specifiedtotalcount> <dmap.returnedcount>1</dmap.returnedcount> <dmap.listing> <dmap.listingitem> <dmap.itemkind>2</dmap.itemkind> <dmap.itemid>67</dmap.itemid> <dmap.itemname>Dancing Queen</dmap.itemname> <dmap.containeritemid>67</dmap.containeritemid> </dmap.listingitem> </dmap.listing> </daap.playlistsongs>
Sure enough.
Delete Playlist
- path
- /databases/<dbid>/containers/del
- required arguments
- output=xml
- dmap.itemid=<playlistid>
- supports meta
- No
- supports query
- No
- custom meta fields
- No
dmap.itemid is the itemid of the playlist to delete.
Example:
GET /databases/1/containers/del?output=xml&dmap.itemid=64
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <org.mt-daapd.delplaylist> <dmap.status>200</dmap.status> </org.mt-daapd.delplaylist>
In the case of a static playlist, this will delete all associated items, as well.
Delete Playlist Item
- path
- /databases/<dbid>/containers/<playlistid>/del
- required arguments
- output=xml
- dmap.itemid=<songid>
- supports meta
- No
- supports query
- Yes
- custom meta fields
- No
dmap.itemid is the song id to delete from the specified playlist.
Example:
GET /databases/1/containers/64/del?output=xml&dmap.itemid=67
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <org.mt-daapd.delplaylistitem> <dmap.status>200</dmap.status> </org.mt-daapd.delplaylistitem>
Deleted successfully
Edit Playlist
- path
- /databases/<dbid>/containers/edit
- required arguments
- output=xml
- dmap.itemid
- dmap.itemname
- optional arguments
- org.mt-daapd.smart-playlist-spec
- supports meta
- No
- supports query
- No
- custom meta fields
- No
If the playlist specified by dmap.itemid is a smart playlist, then mt-daapd.smart-playlist-spec must be specified.
Example:
GET /databases/1/containers/edit?output=xml&dmap.itemid=3&dmap.itemname=new%name&org.mt-daapd.smart-playlist-spec=artist%3D%22Morrissey%22
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <org.mt-daapd.editplaylist> <dmap.status>200</dmap.status> </org.mt-daapd.editplaylist>
Status 200 means it succeeded.
