Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
217 lines (175 sloc) 12.2 KB
(c) 2012 Stefan Wendler
Python based sound-cloud music server talking MPD protocol. This document describes
some of the implementation details of "pyscmpd".
Currently Supported MPD Commands
Command Supported MPD ver. Description
clearerror No Clears the current error message in status
currentsong Yes Displays the song info of the current song
idle No Waits until there is a noteworthy change in
one or more of MPD's subsystems.
status Yes Reports the current status of the player and the volume level.
stats No Displays statistics.
consume No 0.16 When consume is activated, each song played is
removed from play-list.
crossfade No Sets cross-fading between songs.
mixrampdb No Sets the threshold at which songs will be overlapped.
mixrampdelay No Additional time subtracted from the overlap calculated
by mixrampdb.
random No Sets random state.
repeat No Sets repeat state.
setvol Yes Sets volume.
single No When single is activated, playback is stopped after
current song.
replay_gain_mode No 0.16 Sets the replay gain mode.
replay_gain_status No 0.16 Prints replay gain options.
next Yes Plays next song in the play-list.
pause Yes Toggles pause/resumes playing.
play Yes Begins playing the play-list at song number.
playid Yes Begins playing the play-list at song with id.
previous Yes Plays previous song in the play-list.
seek No Seeks to position of song number.
seekid No Seeks to position of song with id.
seekcur No Seeks to the position within the current song.
stop Yes Stops playing.
add Yes Adds the file URI to the play-list.
addid Yes Adds a song to the play-list and returns the song id.
clear Yes Clears the current play-list
delete Yes (no ranges) Deletes a song from the play-list.
deleteid Yes Deletes a song from the play-list.
move Yes (no ranges) Moves the song in the play-list.
moveid Yes Moves the song in the play-list.
playlist No Displays the current play-list.
playlistfind No Finds songs in the current play-list with strict matching.
playlistid No Displays a list of songs in the play-list.
playlistinfo Yes (no ranges) Displays a list of all songs in the play-list.
playlistsearch No Searches case-sensitively for partial matches in the
current play-list.
plchanges Yes Displays changed songs currently in the play-list.
plchangesposid Yes As above but only returns positions and ids.
prio No Set the priority of the specified songs.
prioid No Same as above but uses ids.
shuffle No Shuffle the current play-list.
swap No Swap two songs.
swapid No As above but uses ids.
listplaylist Yes Lists the songs in the play-list.
listplaylistinfo Yes Lists the songs with meta-data in the play-list.
listplaylists Yes Prints a list of the play-list directory.
load Yes Loads the play-list into the current queue.
playlistadd Yes Adds track to a play-list.
playlistclear Yes Clears a play-list.
playlistdelete Yes Delete track from play-list.
playlistmove Yes Move song in play-list.
rename Yes Rename a play-list.
rm Yes Remove a play-list.
save Yes Save a play-list.
count No Counts the number of songs and their total playtime in the db.
find No Fins songs in the db.
findadd No Find songs in the db, add to play-list.
list No Lists all tags of the specified type.
listall No Lists all songs and directories in URI.
listallinfo No Same as above but lists full info.
lsinfo Yes Lists the contents of the directory URI.
search No Same as find but case insensitive
searchadd No Same as findadd but case insensitive
searchaddpl No Same as above but adds to named play-list.
update No Updates the music database.
rescan No Same as update, but also rescans unmodified files.
sticker No Pieces of information attached to existing MPD objects.
close No Closes the connection to MPD.
kill No Kills MPD.
password Yes Used for authentication with the server.
ping No Does nothing but return "OK".
disableoutput No Turns an output off.
enableoutput No Turns an output on.
outputs Yes Shows information about all outputs.
config No Dumps configuration values.
commands No Shows which commands the current user has access to.
notcommands Yes Shows which commands the current user does not have access to.
tagtypes No Shows a list of available song meta-data.
urlhandlers No Gets a list of available URL handlers.
decoders Yes Print a list of decoder plug-ins.
subscribe No Subscribe to a channel.
unsubscribe No Unsubscribe from a channel.
channels No Obtain a list of all channels.
readmessages No Reads messages for this client.
sendmessage No Send a message to the specified channel.
Tested Clients
The following table shows the general function blocks the "pyscmpd" server provides, and with
which clients they are tested, and what where the results so far.
Functionality Client Status
Basic song playing sonata Fully working
ncmpcpp 0.5.6 Fully working
Advanced song playing sonata Not working (not implemented in pyscmpd)
(seek, random etc.)
ncmpcpp 0.5.6 Not working (not implemented in pyscmpd)
Queue management sonata Fully working
(current play-list)
ncmpcpp 0.5.6 Fully working
Playlist management sonata Fully working
ncmpcpp 0.5.6 Fully working
Tagging sonata Not supported by sonata, not implemented in pyscmpd
ncmpcpp 0.5.6 Not working (not implemented in pyscmpd)
DB querying sonata Not working (not implemented in pyscmpd)
(search, find etc.)
ncmpcpp 0.5.6 Not working (not implemented in pyscmpd)
Client messaging sonata Not supported by sonata, not implemented in pyscmpd
ncmpcpp 0.5.6 Not supported by sonata, not implemented in pyscmpd
MPD Server Foundation
As a foundation for the core MPD protocol implementation, the [pympdserver]
( library is used.
This library provides a basic framwork for implementing commands served to clients through
the MPD protocol. In general one could provide its own implementation for commands outside
the library, but since the set of commands supported in general is defined within the library,
and the library does not provide all the commands needed e.g. by "ncmpcpp", the whole library
is inclueded as source in this project, and extended where needed.
MPD Version
I found no easy way to tell which MPD command was introduced with wich MPD version. Thus,
I just don't know which MPD version pyscmpd reassembles at the end. Thus, "MPD 0.13.0" is
returned as defined in the pympdserver library.
Song ID
Each resource (song or directory) needs to have an ID which is stable over time. This ID is passed
to the MPD clients. In general every resource on SoundCloud has a stable ID too. Thus, this ID
is used to be served to clients. However, "pyscmpd" inserts some artificial resources like "favorites",
"groups" etc. To distinguish this categories from SoundCloud songs, ID_OFFSET (= 100000000) is added
to each ID retrieved from SoundCloud.
moveId Workaround
MPD defines two commands for changing the position of a song in the current play-list.
* move: takes the from and to position for a song within the play-list
* moveId: takes the song ID and to tho position within the play-list
For some reason, "ncmpcpp" calls "moveId" but does not provide a song ID as first parameter
but a play-list position. To overcome this problem, it is checked if the provided song ID is
smaller than ID_OFFEST (= 100000000), and if so, "move" is called instead of "moveId".
Persistent Play-lists
The current play-list is persisted automatically whenever the daemon receives the TERM signal.
It is also possible to save the current play-list under a user defined name. However it is not
guarantied, that sound-cloud queries deliver the same results between two calls for the same
E.g. if you added some favorite group "A" which contains more then the maximum amount of users
the SoundCloud API is returning a more or less random set of users for that groups.
If now one adds some tracks lets say from user "U" to a play-list, and then comes back the other
day (starting the daemon freshly), it is very likely, that this time user "U" and its tracks are not
returned by the API query. Since MPD clients like ncmpcpp try to add songs from a user defined
play-list to the current play-list by using "addid" or "add" command, and supplying the path,
the daemon fails to find that track again from the query.
The workaround for this is, to put all tracks retrieved from a play-list to a track cache. Since
a track from a play-list contains all information needed to show it or play it, including its
former path, every time the "addid" or "add" command is called, the daemon first looks if it
finds the requested path in the cache. If so, the cached information is used instead of
querying it from SoundCloud.