Using D-Bus to control spotifyd

If MPRIS support is built into your version and enabled (--use-mpris cli flag / use_mpris = true in config), spotifyd exposes some interfaces via D-Bus through which it provides information and can be controlled.

Most of the time, you won't have to worry to much about the details, since tools like playerctl work out of the box with spotifyd. If you have some custom requirements or want to write custom scripts to control spotifyd, this section is for you.

Available Interfaces

Directly after startup, no interfaces will be available. Once we are connected to Spotify, spotifyd will request the name rs.spotifyd.instance$PID (where PID=$(pidof spotifyd)) and expose the interface rs.spotifyd.Controls.

As soon as we are the playback device (e.g. because we are selected from another client or the TransferPlayback method has been called), spotifyd will additionally expose the MPRIS interfaces and request the name org.mpris.MediaPlayer2.spotifyd.instance$PID.

Spotifyd Controls

The rs.spotifyd.Controls interface exposes a few useful controls that are available even if we're not the active playback device.

  • Method TransferPlayback: transfers Spotify playback to spotifyd
  • Method VolumeUp: increases player volume
  • Method VolumeDown: decreases player volume

Examples:

dest=rs.spotifyd.instance$(pidof spotifyd)
# increase volume
dbus-send --print-reply --dest=$dest /rs/spotifyd/Controls rs.spotifyd.Controls.VolumeUp
# become the active playback device
dbus-send --print-reply --dest=$dest /rs/spotifyd/Controls rs.spotifyd.Controls.TransferPlayback

MPRIS

The org.mpris.MediaPlayer2 and org.mpris.MediaPlayer2.Player interfaces from the MPRIS specification are implemented.

Example usage:

dest=org.mpris.MediaPlayer2.spotifyd.instance$(pidof spotifyd)
# Start playback of some Spotify URI
dbus-send --print-reply --dest=$dest /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.OpenUri string:spotify:track:4PTG3Z6ehGkBFwjybzWkR8
# Get metadata of the currently playing track
dbus-send --print-reply --dest=$dest /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata

Examples

Starting Playback without Client:

#!/bin/bash

# optionally, we can start `spotifyd` here
if ! pidof -q spotifyd
then
  spotifyd --use-mpris
fi

dest=rs.spotifyd.instance$(pidof spotifyd)

wait_for_name() {
  dst=$1
  counter=0

  # check if controls are available
  until [ $counter -gt 10 ] || (dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep -q "$dest")
  do
    sleep 0.3
    ((counter++))
  done

  if [ $counter -gt 10 ]
  then
    echo "waiting for spotifyd timed out" >&1
    exit 1
  fi
}

controls_name=rs.spotifyd.instance$(pidof spotifyd)
wait_for_name $controls_name
echo "Transferring Playback"
dbus-send --print-reply --dest=$controls_name /rs/spotifyd/Controls rs.spotifyd.Controls.TransferPlayback

# if URI is specified, start the playback there
if [ -n "$1" ]
then
  uri="$1"
  mpris_name=org.mpris.MediaPlayer2.spotifyd.instance$(pidof spotifyd)
  wait_for_name $mpris_name
  echo "Starting Playback of $uri"
  dbus-send --print-reply --dest=$mpris_name /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.OpenUri "string:$uri"
else
  echo "Hint: specify an argument to start playback of a specific Spotify URI"
fi

Sleep Timer:

#!/bin/bash

usage() {
  echo "Usage: $0 <timeout>" >&1
  exit 1
}

[ -n "$1" ] || usage

echo "Sleeping for $1 seconds"
sleep $1

dest=org.mpris.MediaPlayer2.spotifyd.instance$(pidof spotifyd)
dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep -q "$dest"

if [ "$?" = "0" ]
then
  dbus-send --print-reply --dest=$dest /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Stop
  # alternatively just pause:
  # dbus-send --print-reply --dest=$dest /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause
else
  echo "No active spotifyd playback."
fi