| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | import gobject |
|---|
| 17 | if __name__ == '__main__': |
|---|
| 18 | |
|---|
| 19 | from common import i18n |
|---|
| 20 | |
|---|
| 21 | from common import dbus_support |
|---|
| 22 | if dbus_support.supported: |
|---|
| 23 | import dbus |
|---|
| 24 | import dbus.glib |
|---|
| 25 | |
|---|
| 26 | class MusicTrackInfo(object): |
|---|
| 27 | __slots__ = ['title', 'album', 'artist', 'duration', 'track_number', |
|---|
| 28 | 'paused'] |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | class MusicTrackListener(gobject.GObject): |
|---|
| 32 | __gsignals__ = { |
|---|
| 33 | 'music-track-changed': (gobject.SIGNAL_RUN_LAST, None, (object,)), |
|---|
| 34 | } |
|---|
| 35 | |
|---|
| 36 | _instance = None |
|---|
| 37 | @classmethod |
|---|
| 38 | def get(cls): |
|---|
| 39 | if cls._instance is None: |
|---|
| 40 | cls._instance = cls() |
|---|
| 41 | return cls._instance |
|---|
| 42 | |
|---|
| 43 | def __init__(self): |
|---|
| 44 | super(MusicTrackListener, self).__init__() |
|---|
| 45 | self._last_playing_music = None |
|---|
| 46 | |
|---|
| 47 | bus = dbus.SessionBus() |
|---|
| 48 | |
|---|
| 49 | |
|---|
| 50 | bus.add_signal_receiver(self._muine_music_track_change_cb, 'SongChanged', |
|---|
| 51 | 'org.gnome.Muine.Player') |
|---|
| 52 | bus.add_signal_receiver(self._player_name_owner_changed, |
|---|
| 53 | 'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Muine') |
|---|
| 54 | bus.add_signal_receiver(self._player_playing_changed_cb, 'StateChanged', |
|---|
| 55 | 'org.gnome.Muine.Player') |
|---|
| 56 | |
|---|
| 57 | |
|---|
| 58 | bus.add_signal_receiver(self._rhythmbox_music_track_change_cb, |
|---|
| 59 | 'playingUriChanged', 'org.gnome.Rhythmbox.Player') |
|---|
| 60 | bus.add_signal_receiver(self._player_name_owner_changed, |
|---|
| 61 | 'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Rhythmbox') |
|---|
| 62 | bus.add_signal_receiver(self._player_playing_changed_cb, |
|---|
| 63 | 'playingChanged', 'org.gnome.Rhythmbox.Player') |
|---|
| 64 | bus.add_signal_receiver(self._player_playing_song_property_changed_cb, |
|---|
| 65 | 'playingSongPropertyChanged', 'org.gnome.Rhythmbox.Player') |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | banshee_bus = dbus.SessionBus() |
|---|
| 69 | dubus = banshee_bus.get_object('org.freedesktop.DBus', |
|---|
| 70 | '/org/freedesktop/dbus') |
|---|
| 71 | self.dubus_methods = dbus.Interface(dubus, 'org.freedesktop.DBus') |
|---|
| 72 | self.current_banshee_title = '' |
|---|
| 73 | self.banshee_paused_before = False |
|---|
| 74 | self.banshee_is_here = False |
|---|
| 75 | gobject.timeout_add(10000, self._check_if_banshee_bus) |
|---|
| 76 | if self.dubus_methods.NameHasOwner('org.gnome.Banshee'): |
|---|
| 77 | self._get_banshee_bus() |
|---|
| 78 | self.banshee_is_here = True |
|---|
| 79 | |
|---|
| 80 | self.banshee_props ={} |
|---|
| 81 | gobject.timeout_add(1000, self._banshee_check_track_status) |
|---|
| 82 | |
|---|
| 83 | def _check_if_banshee_bus(self): |
|---|
| 84 | if self.dubus_methods.NameHasOwner('org.gnome.Banshee'): |
|---|
| 85 | self._get_banshee_bus() |
|---|
| 86 | self.banshee_is_here = True |
|---|
| 87 | else: |
|---|
| 88 | self.banshee_is_here = False |
|---|
| 89 | return True |
|---|
| 90 | |
|---|
| 91 | def _get_banshee_bus(self): |
|---|
| 92 | bus = dbus.SessionBus() |
|---|
| 93 | banshee = bus.get_object('org.gnome.Banshee', '/org/gnome/Banshee/Player') |
|---|
| 94 | self.banshee_methods = dbus.Interface(banshee, 'org.gnome.Banshee.Core') |
|---|
| 95 | |
|---|
| 96 | def do_music_track_changed(self, info): |
|---|
| 97 | if info is not None: |
|---|
| 98 | self._last_playing_music = info |
|---|
| 99 | |
|---|
| 100 | def _player_name_owner_changed(self, name, old, new): |
|---|
| 101 | if not new: |
|---|
| 102 | self.emit('music-track-changed', None) |
|---|
| 103 | |
|---|
| 104 | def _player_playing_changed_cb(self, playing): |
|---|
| 105 | if playing: |
|---|
| 106 | self.emit('music-track-changed', self._last_playing_music) |
|---|
| 107 | else: |
|---|
| 108 | self.emit('music-track-changed', None) |
|---|
| 109 | |
|---|
| 110 | def _player_playing_song_property_changed_cb(self, a, b, c, d): |
|---|
| 111 | if b == 'rb:stream-song-title': |
|---|
| 112 | self.emit('music-track-changed', self._last_playing_music) |
|---|
| 113 | |
|---|
| 114 | def _muine_properties_extract(self, song_string): |
|---|
| 115 | d = dict((x.strip() for x in s1.split(':', 1)) for s1 in \ |
|---|
| 116 | song_string.split('\n')) |
|---|
| 117 | info = MusicTrackInfo() |
|---|
| 118 | info.title = d['title'] |
|---|
| 119 | info.album = d['album'] |
|---|
| 120 | info.artist = d['artist'] |
|---|
| 121 | info.duration = int(d['duration']) |
|---|
| 122 | info.track_number = int(d['track_number']) |
|---|
| 123 | return info |
|---|
| 124 | |
|---|
| 125 | def _muine_music_track_change_cb(self, arg): |
|---|
| 126 | info = self._muine_properties_extract(arg) |
|---|
| 127 | self.emit('music-track-changed', info) |
|---|
| 128 | |
|---|
| 129 | def _rhythmbox_properties_extract(self, props): |
|---|
| 130 | info = MusicTrackInfo() |
|---|
| 131 | info.title = props['title'] |
|---|
| 132 | info.album = props['album'] |
|---|
| 133 | info.artist = props['artist'] |
|---|
| 134 | info.duration = int(props['duration']) |
|---|
| 135 | info.track_number = int(props['track-number']) |
|---|
| 136 | return info |
|---|
| 137 | |
|---|
| 138 | def _rhythmbox_music_track_change_cb(self, uri): |
|---|
| 139 | if not uri: |
|---|
| 140 | return |
|---|
| 141 | bus = dbus.SessionBus() |
|---|
| 142 | rbshellobj = bus.get_object('org.gnome.Rhythmbox', |
|---|
| 143 | '/org/gnome/Rhythmbox/Shell') |
|---|
| 144 | rbshell = dbus.Interface(rbshellobj, 'org.gnome.Rhythmbox.Shell') |
|---|
| 145 | props = rbshell.getSongProperties(uri) |
|---|
| 146 | info = self._rhythmbox_properties_extract(props) |
|---|
| 147 | self.emit('music-track-changed', info) |
|---|
| 148 | |
|---|
| 149 | def _banshee_check_track_status(self): |
|---|
| 150 | if self.dubus_methods.NameHasOwner('org.gnome.Banshee') and \ |
|---|
| 151 | not hasattr(self, 'banshee_methods'): |
|---|
| 152 | self._get_banshee_bus() |
|---|
| 153 | |
|---|
| 154 | if self.dubus_methods.NameHasOwner('org.gnome.Banshee') and self.banshee_is_here: |
|---|
| 155 | try: |
|---|
| 156 | self.banshee_props['title'] = self.banshee_methods.GetPlayingTitle() |
|---|
| 157 | self.banshee_props['album'] = self.banshee_methods.GetPlayingAlbum() |
|---|
| 158 | self.banshee_props['artist'] = self.banshee_methods.\ |
|---|
| 159 | GetPlayingArtist() |
|---|
| 160 | self.banshee_props['duration'] = \ |
|---|
| 161 | self.banshee_methods.GetPlayingDuration() |
|---|
| 162 | self.banshee_props['paused'] = self.banshee_methods.\ |
|---|
| 163 | GetPlayingStatus() |
|---|
| 164 | info = self._banshee_properties_extract(self.banshee_props) |
|---|
| 165 | except dbus.DBusException, err: |
|---|
| 166 | info = None |
|---|
| 167 | |
|---|
| 168 | for key in self.banshee_props.keys(): |
|---|
| 169 | self.banshee_props[key] = '' |
|---|
| 170 | self.banshee_is_here = False |
|---|
| 171 | |
|---|
| 172 | if self.current_banshee_title != self.banshee_props['title']: |
|---|
| 173 | self.emit('music-track-changed', info) |
|---|
| 174 | self.banshee_paused_before = False |
|---|
| 175 | if self.banshee_props['paused'] == 0 and self.banshee_paused_before ==\ |
|---|
| 176 | False: |
|---|
| 177 | self.emit('music-track-changed', info) |
|---|
| 178 | self.banshee_paused_before = True |
|---|
| 179 | else: |
|---|
| 180 | if self.banshee_paused_before and self.banshee_props['paused'] == 1: |
|---|
| 181 | self.emit('music-track-changed', info) |
|---|
| 182 | self.banshee_paused_before = False |
|---|
| 183 | self.current_banshee_title = self.banshee_props['title'] |
|---|
| 184 | return 1 |
|---|
| 185 | |
|---|
| 186 | def _banshee_music_track_change_cb(self, arg): |
|---|
| 187 | info = self._banshee_properties_extract(arg) |
|---|
| 188 | self.emit('music-track-changed', info) |
|---|
| 189 | |
|---|
| 190 | def _banshee_properties_extract(self, props): |
|---|
| 191 | info = MusicTrackInfo() |
|---|
| 192 | info.title = props['title'] |
|---|
| 193 | info.album = props['album'] |
|---|
| 194 | info.artist = props['artist'] |
|---|
| 195 | info.duration = int(props['duration']) |
|---|
| 196 | info.paused = props['paused'] |
|---|
| 197 | return info |
|---|
| 198 | |
|---|
| 199 | def get_playing_track(self): |
|---|
| 200 | '''Return a MusicTrackInfo for the currently playing |
|---|
| 201 | song, or None if no song is playing''' |
|---|
| 202 | |
|---|
| 203 | bus = dbus.SessionBus() |
|---|
| 204 | |
|---|
| 205 | |
|---|
| 206 | test = False |
|---|
| 207 | if hasattr(bus, 'name_has_owner'): |
|---|
| 208 | if bus.name_has_owner('org.gnome.Muine'): |
|---|
| 209 | test = True |
|---|
| 210 | elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(), |
|---|
| 211 | 'org.gnome.Muine'): |
|---|
| 212 | test = True |
|---|
| 213 | if test: |
|---|
| 214 | obj = bus.get_object('org.gnome.Muine', '/org/gnome/Muine/Player') |
|---|
| 215 | player = dbus.Interface(obj, 'org.gnome.Muine.Player') |
|---|
| 216 | if player.GetPlaying(): |
|---|
| 217 | song_string = player.GetCurrentSong() |
|---|
| 218 | song = self._muine_properties_extract(song_string) |
|---|
| 219 | self._last_playing_music = song |
|---|
| 220 | return song |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | test = False |
|---|
| 224 | if hasattr(bus, 'name_has_owner'): |
|---|
| 225 | if bus.name_has_owner('org.gnome.Rhythmbox'): |
|---|
| 226 | test = True |
|---|
| 227 | elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(), |
|---|
| 228 | 'org.gnome.Rhythmbox'): |
|---|
| 229 | test = True |
|---|
| 230 | if test: |
|---|
| 231 | rbshellobj = bus.get_object('org.gnome.Rhythmbox', |
|---|
| 232 | '/org/gnome/Rhythmbox/Shell') |
|---|
| 233 | player = dbus.Interface( |
|---|
| 234 | bus.get_object('org.gnome.Rhythmbox', |
|---|
| 235 | '/org/gnome/Rhythmbox/Player'), 'org.gnome.Rhythmbox.Player') |
|---|
| 236 | rbshell = dbus.Interface(rbshellobj, 'org.gnome.Rhythmbox.Shell') |
|---|
| 237 | uri = player.getPlayingUri() |
|---|
| 238 | if not uri: |
|---|
| 239 | return None |
|---|
| 240 | props = rbshell.getSongProperties(uri) |
|---|
| 241 | info = self._rhythmbox_properties_extract(props) |
|---|
| 242 | self._last_playing_music = info |
|---|
| 243 | return info |
|---|
| 244 | |
|---|
| 245 | return None |
|---|
| 246 | |
|---|
| 247 | |
|---|
| 248 | if __name__ == '__main__': |
|---|
| 249 | def music_track_change_cb(listener, music_track_info): |
|---|
| 250 | if music_track_info is None: |
|---|
| 251 | print "Stop!" |
|---|
| 252 | else: |
|---|
| 253 | print music_track_info.title |
|---|
| 254 | listener = MusicTrackListener.get() |
|---|
| 255 | listener.connect('music-track-changed', music_track_change_cb) |
|---|
| 256 | track = listener.get_playing_track() |
|---|
| 257 | if track is None: |
|---|
| 258 | print 'Now not playing anything' |
|---|
| 259 | else: |
|---|
| 260 | print 'Now playing: "%s" by %s' % (track.title, track.artist) |
|---|
| 261 | gobject.MainLoop().run() |
|---|