Skip to content
Advertisement

How to connect to MediaPlayer2.Player PlaybackStatus signal using pygtk?

I actually want to display the information about the media or song currently being played with a window as a popup containing the artwork and the song name etc. I read about that a

PlaybackStatus

signal is emitted whenever a media is playing or stopped. How would i connect to that signal, well I read about dbus and came to know that it can be accessed using the org.freedesktop.DBus.Properties interface. I have recently started development with PyGtk so I don`t know how to do it?

Thanks.

Advertisement

Answer

Before doing this with Python I find it useful to experiment on the command line to see what the expected values are. This can be done with the busctl tool.

The media players are on the Session (or user) bus.

$ busctl --user list | grep -i MediaPlayer2
org.mpris.MediaPlayer2.firefox.instance62995  62995 GeckoMain       usera :1.99         user@1000.service -       -          

I can use the name of the service to find the objects in the D-Bus tree:

$ busctl --user tree org.mpris.MediaPlayer2.firefox.instance62995
└─/org
  └─/org/mpris
    └─/org/mpris/MediaPlayer2

With the name and the object path the object can be introspected

$ busctl --user introspect org.mpris.MediaPlayer2.firefox.instance62995 /org/mpris/MediaPlayer2
NAME                                TYPE      SIGNATURE RESULT/VALUE              >
org.freedesktop.DBus.Introspectable interface -         -                         >
.Introspect                         method    -         s                         >
org.freedesktop.DBus.Peer           interface -         -                         >
.GetMachineId                       method    -         s                         >
.Ping                               method    -         -                         >
org.freedesktop.DBus.Properties     interface -         -                         >
.Get                                method    ss        v                         >
.GetAll                             method    s         a{sv}                     >
.Set                                method    ssv       -                         >
.PropertiesChanged                  signal    sa{sv}as  -                         >
org.mpris.MediaPlayer2              interface -         -                         >
.Quit                               method    -         -                         >
.Raise                              method    -         -                         >
.CanQuit                            property  b         false                     >
.CanRaise                           property  b         true                      >
.DesktopEntry                       property  s         "firefox"                 >
.HasTrackList                       property  b         false                     >
.Identity                           property  s         "Mozilla Firefox"         >
.SupportedMimeTypes                 property  as        0                         >
.SupportedUriSchemes                property  as        0                         >
org.mpris.MediaPlayer2.Player       interface -         -                         >
.Next                               method    -         -                         >
.OpenUri                            method    s         -                         >
.Pause                              method    -         -                         >
.Play                               method    -         -                         >
.PlayPause                          method    -         -                         >
.Previous                           method    -         -                         >
.Seek                               method    x         -                         >
.SetPosition                        method    ox        -                         >
.Stop                               method    -         -                         >
.CanControl                         property  b         true                      >
.CanGoNext                          property  b         false                     >
.CanGoPrevious                      property  b         false                     >
.CanPause                           property  b         true                      >
.CanPlay                            property  b         true                      >
.CanSeek                            property  b         false                     >
.MaximumRate                        property  d         -                         >
.Metadata                           property  a{sv}     5 "mpris:trackid" o "/org/>
.MinimumRate                        property  d         -                         >
.PlaybackStatus                     property  s         "Paused"                  >
.Position                           property  x         -                         >
.Rate                               property  d         -                         >
.Volume                             property  d         -                         >
.Seeked                             signal    x         -                         >

As you want to use Gtk it would seem sensible to use the D-Bus binding from https://pygobject.readthedocs.io/en/latest/

It will mainly be the DBusProxy that will be required.

An example of a window with a couple of labels for playback status and artist information might look like the following:

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gio, Gtk


PLAYER_IFACE = 'org.mpris.MediaPlayer2.Player'


class MainApp(Gtk.Window):

    def __init__(self):
        super().__init__(title="Player Status")
        self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        self.add(self.box)
        self.lbl_status = Gtk.Label(label='Status Here')
        self.box.pack_start(self.lbl_status, True, True, 0)
        self.lbl_artist = Gtk.Label(label='Artist Here')
        self.box.pack_start(self.lbl_artist, True, True, 0)

    def update_label(self, proxy, changed_props, invalidated_props):
        props = changed_props.unpack()
        print(props)
        status = props.get('PlaybackStatus')
        artist = props.get('Metadata', {}).get('xesam:title')
        if status:
            self.lbl_status.set_text(status)
        if artist:
            self.lbl_artist.set_text(artist)


def find_player():
    """
    Find the first `org.mpris.MediaPlayer2` name in list
    """
    names = Gio.DBusProxy.new_for_bus_sync(
            bus_type=Gio.BusType.SESSION,
            flags=Gio.DBusProxyFlags.NONE,
            info=None,
            name='org.freedesktop.DBus',
            object_path='/org/freedesktop/DBus',
            interface_name='org.freedesktop.DBus',
            cancellable=None).ListNames()
    for name in names:
        if name.startswith('org.mpris.MediaPlayer2'):
            return name


def player_proxy(media_name):
    """
    Provide proxy for comfortable and pythonic method calls
    """
    return Gio.DBusProxy.new_for_bus_sync(
            bus_type=Gio.BusType.SESSION,
            flags=Gio.DBusProxyFlags.NONE,
            info=None,
            name=media_name,
            object_path='/org/mpris/MediaPlayer2',
            interface_name=PLAYER_IFACE,
            cancellable=None)


if __name__ == "__main__":
    print("running application")
    app = MainApp()

    player_name = find_player()
    player = player_proxy(player_name)
    # Connect signal to callback
    player.connect('g-properties-changed', app.update_label)

    app.show_all()
    Gtk.main()
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement