Skip to content

MPRIS player control in the odio API

The MPRIS backend auto-discovers every MPRIS-compatible player (Spotify, VLC, Firefox, MPD, Kodi, Bluetooth devices) and exposes unified playback controls. Players appear and disappear in real time — no configuration needed.

GET /players

Returns all active players with their current state: playback status, track metadata, volume, shuffle, loop mode, position, and whether the player exposes a tracklist.

POST /players/{player}/play
POST /players/{player}/pause
POST /players/{player}/play_pause
POST /players/{player}/stop
POST /players/{player}/next
POST /players/{player}/previous
POST /players/{player}/seek
{ "offset": 1000000 }
POST /players/{player}/position
{ "track_id": "...", "position": 0 }
POST /players/{player}/volume
{ "volume": 0.5 }
POST /players/{player}/loop
{ "loop": "None|Track|Playlist" }
POST /players/{player}/shuffle
{ "shuffle": true }

Since odio-api v0.16.0, players implementing the MPRIS TrackList interface expose their queue. /players reports tracklist_supported per player, and the routes below answer 404 on players that don’t implement the interface.

TrackList is optional in the MPRIS spec, and most players skip it — a player advertises it through the HasTrackList root property, which is what tracklist_supported mirrors.

PlayerTracklist
MPD via mpd2mpris 0.13.0+The MPD queue, editable when the server allows queue edits
VLCIts playlist, always editable
Bluetooth devices via BlueZ mpris-proxyOnly when the connected phone or laptop exposes a browsable now-playing list over AVRCP
spotifydNot implemented, HasTrackList is hardcoded to false
Shairport SyncNot implemented, the property isn’t exposed at all
GET /players/{player}/tracklist
{
"can_edit_tracks": true,
"tracks": [
{ "track_id": "/org/mpris/MediaPlayer2/Track/42", "metadata": { "xesam:title": "..." } }
]
}

The list is served from the player cache, kept live by the TrackListReplaced, TrackAdded, TrackRemoved and TrackMetadataChanged D-Bus signals.

POST /players/{player}/tracklist/goto/{trackid}
POST /players/{player}/tracklist/remove/{trackid}
POST /players/{player}/tracklist/add
{ "uri": "file:///media/USB/album/01.flac", "after_track": "", "set_as_current": false }

{trackid} is either the last segment of the track’s object path (42) or the full %2F-encoded path. uri must be absolute and its scheme must be one the player declares in SupportedUriSchemes, otherwise the request is rejected with 400. An empty after_track appends, NoTrack prepends.

add and remove require can_edit_tracks and answer 403 otherwise. goto is not an edit operation per the spec, so it works on read-only tracklists too.

EventTrigger
player.updatedPlayback state, volume, or metadata change
player.addedNew player appeared
player.removedPlayer closed
player.positionPeriodic position tick
player.tracklist.updatedQueue replaced, or a track added, removed, or its metadata changed

The backend listens on D-Bus for org.mpris.MediaPlayer2 interfaces. Player state is cached and invalidated via D-Bus signals, with a heartbeat for accurate position tracking.