# -*- coding: utf-8 -*- ## musictracklistener.py ## ## Copyright (C) 2006 Gustavo Carneiro ## Copyright (C) 2006 Nikos Kouremenos ## ## 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 gobject if __name__ == '__main__': # install _() func before importing dbus_support from common import i18n from common import dbus_support if dbus_support.supported: import dbus import dbus.glib class MusicTrackInfo(object): __slots__ = ['title', 'album', 'artist', 'duration', 'track_number', 'paused'] class MusicTrackListener(gobject.GObject): __gsignals__ = { 'music-track-changed': (gobject.SIGNAL_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._last_playing_music = None bus = dbus.SessionBus() ## Muine bus.add_signal_receiver(self._muine_music_track_change_cb, 'SongChanged', 'org.gnome.Muine.Player') bus.add_signal_receiver(self._player_name_owner_changed, 'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Muine') bus.add_signal_receiver(self._player_playing_changed_cb, 'StateChanged', 'org.gnome.Muine.Player') ## Rhythmbox bus.add_signal_receiver(self._rhythmbox_music_track_change_cb, 'playingUriChanged', 'org.gnome.Rhythmbox.Player') bus.add_signal_receiver(self._player_name_owner_changed, 'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Rhythmbox') bus.add_signal_receiver(self._player_playing_changed_cb, 'playingChanged', 'org.gnome.Rhythmbox.Player') bus.add_signal_receiver(self._player_playing_song_property_changed_cb, 'playingSongPropertyChanged', 'org.gnome.Rhythmbox.Player') ## Banshee banshee_bus = dbus.SessionBus() dubus = banshee_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/dbus') self.dubus_methods = dbus.Interface(dubus, 'org.freedesktop.DBus') self.current_banshee_title = '' self.banshee_paused_before = False self.banshee_is_here = False gobject.timeout_add(10000, self._check_if_banshee_bus) if self.dubus_methods.NameHasOwner('org.gnome.Banshee'): self._get_banshee_bus() self.banshee_is_here = True # Otherwise, it opens Banshee! self.banshee_props ={} gobject.timeout_add(1000, self._banshee_check_track_status) def _check_if_banshee_bus(self): if self.dubus_methods.NameHasOwner('org.gnome.Banshee'): self._get_banshee_bus() self.banshee_is_here = True else: self.banshee_is_here = False return True def _get_banshee_bus(self): bus = dbus.SessionBus() banshee = bus.get_object('org.gnome.Banshee', '/org/gnome/Banshee/Player') self.banshee_methods = dbus.Interface(banshee, 'org.gnome.Banshee.Core') def do_music_track_changed(self, info): if info is not None: self._last_playing_music = info def _player_name_owner_changed(self, name, old, new): if not new: self.emit('music-track-changed', None) def _player_playing_changed_cb(self, playing): if playing: self.emit('music-track-changed', self._last_playing_music) else: self.emit('music-track-changed', None) def _player_playing_song_property_changed_cb(self, a, b, c, d): if b == 'rb:stream-song-title': self.emit('music-track-changed', self._last_playing_music) def _muine_properties_extract(self, song_string): d = dict((x.strip() for x in s1.split(':', 1)) for s1 in \ song_string.split('\n')) info = MusicTrackInfo() info.title = d['title'] info.album = d['album'] info.artist = d['artist'] info.duration = int(d['duration']) info.track_number = int(d['track_number']) return info def _muine_music_track_change_cb(self, arg): info = self._muine_properties_extract(arg) self.emit('music-track-changed', info) def _rhythmbox_properties_extract(self, props): info = MusicTrackInfo() info.title = props['title'] info.album = props['album'] info.artist = props['artist'] info.duration = int(props['duration']) info.track_number = int(props['track-number']) return info def _rhythmbox_music_track_change_cb(self, uri): if not uri: return bus = dbus.SessionBus() rbshellobj = bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell') rbshell = dbus.Interface(rbshellobj, 'org.gnome.Rhythmbox.Shell') props = rbshell.getSongProperties(uri) info = self._rhythmbox_properties_extract(props) self.emit('music-track-changed', info) def _banshee_check_track_status(self): if self.dubus_methods.NameHasOwner('org.gnome.Banshee') and \ not hasattr(self, 'banshee_methods'): self._get_banshee_bus() if self.dubus_methods.NameHasOwner('org.gnome.Banshee') and self.banshee_is_here: try: self.banshee_props['title'] = self.banshee_methods.GetPlayingTitle() self.banshee_props['album'] = self.banshee_methods.GetPlayingAlbum() self.banshee_props['artist'] = self.banshee_methods.\ GetPlayingArtist() self.banshee_props['duration'] = \ self.banshee_methods.GetPlayingDuration() self.banshee_props['paused'] = self.banshee_methods.\ GetPlayingStatus() info = self._banshee_properties_extract(self.banshee_props) except dbus.DBusException, err: info = None for key in self.banshee_props.keys(): self.banshee_props[key] = '' self.banshee_is_here = False if self.current_banshee_title != self.banshee_props['title']: self.emit('music-track-changed', info) self.banshee_paused_before = False if self.banshee_props['paused'] == 0 and self.banshee_paused_before ==\ False: self.emit('music-track-changed', info) self.banshee_paused_before = True else: if self.banshee_paused_before and self.banshee_props['paused'] == 1: self.emit('music-track-changed', info) self.banshee_paused_before = False self.current_banshee_title = self.banshee_props['title'] return 1 def _banshee_music_track_change_cb(self, arg): info = self._banshee_properties_extract(arg) self.emit('music-track-changed', info) def _banshee_properties_extract(self, props): info = MusicTrackInfo() info.title = props['title'] info.album = props['album'] info.artist = props['artist'] info.duration = int(props['duration']) info.paused = props['paused'] return info def get_playing_track(self): '''Return a MusicTrackInfo for the currently playing song, or None if no song is playing''' bus = dbus.SessionBus() ## Check Muine playing track test = False if hasattr(bus, 'name_has_owner'): if bus.name_has_owner('org.gnome.Muine'): test = True elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(), 'org.gnome.Muine'): test = True if test: obj = bus.get_object('org.gnome.Muine', '/org/gnome/Muine/Player') player = dbus.Interface(obj, 'org.gnome.Muine.Player') if player.GetPlaying(): song_string = player.GetCurrentSong() song = self._muine_properties_extract(song_string) self._last_playing_music = song return song ## Check Rhythmbox playing song test = False if hasattr(bus, 'name_has_owner'): if bus.name_has_owner('org.gnome.Rhythmbox'): test = True elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(), 'org.gnome.Rhythmbox'): test = True if test: rbshellobj = bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell') player = dbus.Interface( bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Player'), 'org.gnome.Rhythmbox.Player') rbshell = dbus.Interface(rbshellobj, 'org.gnome.Rhythmbox.Shell') uri = player.getPlayingUri() if not uri: return None props = rbshell.getSongProperties(uri) info = self._rhythmbox_properties_extract(props) self._last_playing_music = info return info return None # here we test :) if __name__ == '__main__': def music_track_change_cb(listener, music_track_info): if music_track_info is None: print "Stop!" else: print music_track_info.title listener = MusicTrackListener.get() listener.connect('music-track-changed', music_track_change_cb) track = listener.get_playing_track() if track is None: print 'Now not playing anything' else: print 'Now playing: "%s" by %s' % (track.title, track.artist) gobject.MainLoop().run()