root/branches/gajim_0.11.1/src/music_track_listener.py

Revision 8841, 8.5 kB (checked in by asterix, 13 months ago)

don't crash when we close rhythmbox while Gajim is running. fixes #3442

Line 
1# -*- coding: utf-8 -*-
2##      musictracklistener.py
3##
4## Copyright (C) 2006 Gustavo Carneiro <gjcarneiro@gmail.com>
5## Copyright (C) 2006 Nikos Kouremenos <kourem@gmail.com>
6##
7## This program is free software; you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published
9## by the Free Software Foundation; version 2 only.
10##
11## This program is distributed in the hope that it will be useful,
12## but WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14## GNU General Public License for more details.
15##
16import gobject
17if __name__ == '__main__':
18        # install _() func before importing dbus_support
19        from common import i18n
20
21from common import dbus_support
22if dbus_support.supported:
23        import dbus
24        import dbus.glib
25
26class MusicTrackInfo(object):
27        __slots__ = ['title', 'album', 'artist', 'duration', 'track_number',
28                'paused']
29
30
31class 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                ## Muine
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                ## Rhythmbox
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                ## Banshee
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                # Otherwise, it opens Banshee!
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                ## 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                        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# here we test :)
248if __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()
Note: See TracBrowser for help on using the browser.