# -*- coding: utf-8 -*- ## gajim/music_track_listener.py ## ## Copyright (C) 2006 Gustavo Carneiro ## Nikos Kouremenos ## Copyright (C) 2006-2014 Yann Leboulanger ## Copyright (C) 2008 Jean-Marie Traissard ## Jonathan Schleifer ## Stephan Erb ## ## This file is part of Gajim. ## ## Gajim is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published ## by the Free Software Foundation; version 3 only. ## ## Gajim is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Gajim. If not, see . ## import logging from gi.repository import GObject from gi.repository import Gio, GLib log = logging.getLogger('gajim.music_track_listener') def _get_music_players(): players = [ 'org.mpris.MediaPlayer2.audacious', 'org.mpris.MediaPlayer2.bmp', 'org.mpris.MediaPlayer2.clementine', 'org.mpris.MediaPlayer2.GnomeMusic', 'org.mpris.MediaPlayer2.quodlibet', 'org.mpris.MediaPlayer2.rhythmbox', 'org.mpris.MediaPlayer2.vlc', 'org.mpris.MediaPlayer2.xmms2' ] return players class MusicTrackInfo(object): __slots__ = ['title', 'album', 'artist', 'duration', 'track_number', 'paused'] class MusicTrackListener(GObject.GObject): __gsignals__ = { 'music-track-changed': (GObject.SignalFlags.RUN_LAST, None, (object,)), } _instance = None @classmethod def get(cls): if cls._instance is None: cls._instance = cls() return cls._instance def __init__(self): super(MusicTrackListener, self).__init__() self.con = {} players = _get_music_players() for name in players: Gio.bus_watch_name( Gio.BusType.SESSION, name, Gio.BusNameWatcherFlags.NONE, self._appeared, self._vanished) def _appeared(self, connection, name, name_owner, *user_data): '''Set up a listener for music player signals''' log.info('%s appeared', name) self.con[name] = connection.signal_subscribe( name, 'org.freedesktop.DBus.Properties', 'PropertiesChanged', '/org/mpris/MediaPlayer2', None, Gio.DBusSignalFlags.NONE, self._signal_received, name) info = self.get_playing_track(name) if info is not None: self.emit('music-track-changed', info) def _vanished(self, connection, name, *user_data): log.info('%s vanished', name) if name in self.con: connection.signal_unsubscribe( self.con[name]) self.con.pop(name) self.emit('music-track-changed', None) def _signal_received(self, connection, sender_name, object_path, interface_name, signal_name, parameters, *user_data): '''Signal handler for PropertiesChanged event''' if 'PlaybackStatus' not in parameters[1]: return log.info('Signal received: %s - %s', interface_name, parameters) info = self.get_playing_track(user_data[0]) self.emit('music-track-changed', info) def _properties_extract(self, properties): meta = properties.get('Metadata') if meta is None or not meta: return None info = MusicTrackInfo() info.title = meta.get('xesam:title') info.album = meta.get('xesam:album') artist = meta.get('xesam:artist') if artist is not None and len(artist): info.artist = artist[0] else: info.artist = None info.duration = float(meta.get('mpris:length', 0)) info.track_number = meta.get('xesam:trackNumber', 0) status = properties.get('PlaybackStatus') info.paused = status is not None and status == 'Paused' return info def get_playing_track(self, name): '''Return a MusicTrackInfo for the currently playing song, or None if no song is playing''' proxy = Gio.DBusProxy.new_for_bus_sync( Gio.BusType.SESSION, Gio.DBusProxyFlags.NONE, None, name, '/org/mpris/MediaPlayer2', 'org.freedesktop.DBus.Properties', None) try: result = proxy.call_sync( "GetAll", GLib.Variant('(s)', ('org.mpris.MediaPlayer2.Player',)), Gio.DBusCallFlags.NONE, -1, None) except GLib.Error as e: if e.domain == 'g-dbus-error-quark': log.debug("Could not enable music listener: %s", e.message) return None else: raise else: info = self._properties_extract(result[0]) return info # here we test :) if __name__ == '__main__': def music_track_change_cb(listener, music_track_info): if music_track_info is None or music_track_info.paused: print('Stop!') else: print(music_track_info.title) listener = MusicTrackListener.get() listener.connect('music-track-changed', music_track_change_cb) GObject.MainLoop().run()