root/trunk/src/music_track_listener.py

Revision 10698, 9.8 kB (checked in by asterix, 7 days ago)

use correct title from quodlibet. fixes #4510

Line 
1# -*- coding: utf-8 -*-
2## src/music_track_listener.py
3##
4## Copyright (C) 2006 Gustavo Carneiro <gjcarneiro AT gmail.com>
5##                    Nikos Kouremenos <kourem AT gmail.com>
6## Copyright (C) 2006-2008 Yann Leboulanger <asterix AT lagaule.org>
7## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org>
8##                    Jonathan Schleifer <js-gajim AT webkeks.org>
9##                    Stephan Erb <steve-e AT h3c.de>
10##
11## This file is part of Gajim.
12##
13## Gajim is free software; you can redistribute it and/or modify
14## it under the terms of the GNU General Public License as published
15## by the Free Software Foundation; version 3 only.
16##
17## Gajim is distributed in the hope that it will be useful,
18## but WITHOUT ANY WARRANTY; without even the implied warranty of
19## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20## GNU General Public License for more details.
21##
22## You should have received a copy of the GNU General Public License
23## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
24##
25
26import gobject
27if __name__ == '__main__':
28        # install _() func before importing dbus_support
29        from common import i18n
30
31from common import dbus_support
32if dbus_support.supported:
33        import dbus
34        import dbus.glib
35
36class MusicTrackInfo(object):
37        __slots__ = ['title', 'album', 'artist', 'duration', 'track_number',
38                'paused']
39
40class MusicTrackListener(gobject.GObject):
41        __gsignals__ = {
42                'music-track-changed': (gobject.SIGNAL_RUN_LAST, None, (object,)),
43        }
44
45        _instance = None
46        @classmethod
47        def get(cls):
48                if cls._instance is None:
49                        cls._instance = cls()
50                return cls._instance
51       
52        def __init__(self):
53                super(MusicTrackListener, self).__init__()
54                self._last_playing_music = None
55               
56                bus = dbus.SessionBus()
57
58                ## MPRIS
59                bus.add_signal_receiver(self._mpris_music_track_change_cb, 'TrackChange',
60                        'org.freedesktop.MediaPlayer')
61                bus.add_signal_receiver(self._mpris_playing_changed_cb, 'StatusChange',
62                        'org.freedesktop.MediaPlayer')
63                bus.add_signal_receiver(self._player_name_owner_changed,
64                        'NameOwnerChanged', 'org.freedesktop.DBus',
65                        arg0='org.freedesktop.MediaPlayer')
66
67                ## Muine
68                bus.add_signal_receiver(self._muine_music_track_change_cb, 'SongChanged',
69                        'org.gnome.Muine.Player')
70                bus.add_signal_receiver(self._player_name_owner_changed,
71                        'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Muine')
72                bus.add_signal_receiver(self._player_playing_changed_cb, 'StateChanged',
73                        'org.gnome.Muine.Player')
74
75                ## Rhythmbox
76                bus.add_signal_receiver(self._player_name_owner_changed,
77                        'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Rhythmbox')
78                bus.add_signal_receiver(self._rhythmbox_playing_changed_cb,
79                        'playingChanged', 'org.gnome.Rhythmbox.Player')
80                bus.add_signal_receiver(self._player_playing_song_property_changed_cb,
81                        'playingSongPropertyChanged', 'org.gnome.Rhythmbox.Player')
82
83                ## Banshee
84                bus.add_signal_receiver(self._banshee_state_changed_cb,
85                        'StateChanged', 'org.bansheeproject.Banshee.PlayerEngine')
86                bus.add_signal_receiver(self._player_name_owner_changed,
87                        'NameOwnerChanged', 'org.freedesktop.DBus',
88                        arg0='org.bansheeproject.Banshee')
89
90                ## Quod Libet
91                bus.add_signal_receiver(self._quodlibet_state_change_cb,
92                        'SongStarted', 'net.sacredchao.QuodLibet')
93                bus.add_signal_receiver(self._quodlibet_state_change_cb,
94                        'Paused', 'net.sacredchao.QuodLibet')
95                bus.add_signal_receiver(self._quodlibet_state_change_cb,
96                        'Unpaused', 'net.sacredchao.QuodLibet')
97                bus.add_signal_receiver(self._player_name_owner_changed,
98                        'NameOwnerChanged', 'org.freedesktop.DBus',
99                        arg0='net.sacredchao.QuodLibet')
100
101        def _player_name_owner_changed(self, name, old, new):
102                if not new:
103                        self.emit('music-track-changed', None)
104
105        def _player_playing_changed_cb(self, playing):
106                if playing:
107                        self.emit('music-track-changed', self._last_playing_music)
108                else:
109                        self.emit('music-track-changed', None)
110
111        def _player_playing_song_property_changed_cb(self, a, b, c, d):
112                if b == 'rb:stream-song-title':
113                        self.emit('music-track-changed', self._last_playing_music)
114
115        def _mpris_properties_extract(self, song):
116                info = MusicTrackInfo()
117                info.title = song.get('title', '')
118                info.album = song.get('album', '')
119                info.artist = song.get('artist', '')
120                info.duration = int(song.get('length', 0))
121                return info
122
123        def _mpris_playing_changed_cb(self, playing):
124                if playing == 0:
125                        self.emit('music-track-changed', self._last_playing_music)
126                else:
127                        self.emit('music-track-changed', None)
128
129        def _mpris_music_track_change_cb(self, arg):
130                self._last_playing_music = self._mpris_properties_extract(arg)
131                self.emit('music-track-changed', self._last_playing_music)
132
133        def _muine_properties_extract(self, song_string):
134                d = dict((x.strip() for x in  s1.split(':', 1)) for s1 in \
135                        song_string.split('\n'))
136                info = MusicTrackInfo()
137                info.title = d['title']
138                info.album = d['album']
139                info.artist = d['artist']
140                info.duration = int(d['duration'])
141                info.track_number = int(d['track_number'])
142                return info
143
144        def _muine_music_track_change_cb(self, arg):
145                info = self._muine_properties_extract(arg)
146                self.emit('music-track-changed', info)
147
148        def _rhythmbox_playing_changed_cb(self, playing):
149                if playing:
150                        info = self.get_playing_track()
151                        self.emit('music-track-changed', info)
152                else:
153                        self.emit('music-track-changed', None)
154
155        def _rhythmbox_properties_extract(self, props):
156                info = MusicTrackInfo()
157                info.title = props.get('title', None)
158                info.album = props.get('album', None)
159                info.artist = props.get('artist', None)
160                info.duration = int(props.get('duration', 0))
161                info.track_number = int(props.get('track-number', 0))
162                return info
163
164        def _banshee_state_changed_cb(self, state):
165                if state == 'playing':
166                        bus = dbus.SessionBus()
167                        banshee = bus.get_object('org.bansheeproject.Banshee',
168                                '/org/bansheeproject/Banshee/PlayerEngine')
169                        currentTrack = banshee.GetCurrentTrack()
170                        self._last_playing_music = self._banshee_properties_extract(
171                                currentTrack) 
172                        self.emit('music-track-changed', self._last_playing_music)
173                elif state == 'paused':
174                        self.emit('music-track-changed', None)
175
176        def _banshee_properties_extract(self, props):
177                info = MusicTrackInfo()
178                info.title = props.get('name', None)
179                info.album = props.get('album', None)
180                info.artist = props.get('artist', None)
181                info.duration = int(props.get('length', 0))
182                return info
183
184        def _quodlibet_state_change_cb(self, state=None):
185                info = self.get_playing_track()
186                if info:
187                        self.emit('music-track-changed', info)
188                else:
189                        self.emit('music-track-changed', None)
190
191        def _quodlibet_properties_extract(self, props):
192                info = MusicTrackInfo()
193                info.title = props.get('title', None)
194                info.album = props.get('album', None)
195                info.artist = props.get('artist', None)
196                info.duration = int(props.get('~#length', 0))
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                ## Check Muine playing track
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                ## Check Rhythmbox playing song
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                        try:
238                                uri = player.getPlayingUri()
239                        except dbus.DBusException:
240                                uri = None
241                        if not uri:
242                                return None
243                        props = rbshell.getSongProperties(uri)
244                        info = self._rhythmbox_properties_extract(props)
245                        self._last_playing_music = info
246                        return info
247
248                ## Check Banshee playing track
249                test = False
250                if hasattr(bus, 'name_has_owner'):
251                        if bus.name_has_owner('org.bansheeproject.Banshee'):
252                                test = True
253                elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(),
254                'org.bansheeproject.Banshee'):
255                        test = True
256                if test:
257                        banshee = bus.get_object('org.bansheeproject.Banshee',
258                                '/org/bansheeproject/Banshee/PlayerEngine')
259                        currentTrack = banshee.GetCurrentTrack()
260                        if currentTrack:
261                                song = self._banshee_properties_extract(currentTrack)
262                                self._last_playing_music = song
263                                return song
264
265                ## Check Quod Libet playing track
266                test = False
267                if hasattr(bus, 'name_has_owner'):
268                        if bus.name_has_owner('net.sacredchao.QuodLibet'):
269                                test = True
270                elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(),
271                'net.sacredchao.QuodLibet'):
272                        test = True
273                if test:
274                        quodlibet = bus.get_object('net.sacredchao.QuodLibet',
275                                '/net/sacredchao/QuodLibet')
276                        if quodlibet.IsPlaying():
277                                currentTrack = quodlibet.CurrentSong()
278                                song = self._quodlibet_properties_extract(currentTrack)
279                                self._last_playing_music = song
280                                return song
281
282                return None
283
284# here we test :)
285if __name__ == '__main__':
286        def music_track_change_cb(listener, music_track_info):
287                if music_track_info is None:
288                        print 'Stop!'
289                else:
290                        print music_track_info.title
291        listener = MusicTrackListener.get()
292        listener.connect('music-track-changed', music_track_change_cb)
293        track = listener.get_playing_track()
294        if track is None:
295                print 'Now not playing anything'
296        else:
297                print 'Now playing: "%s" by %s' % (track.title, track.artist)
298        gobject.MainLoop().run()
299
300# vim: se ts=3:
Note: See TracBrowser for help on using the browser.