set transient for roster windows to error / warning dialogs. Fixes #6942
[gajim.git] / src / music_track_listener.py
blob4d0df3bf848511cf4aee33a2307a91b02585fd81
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-2010 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>
11 ## This file is part of Gajim.
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.
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.
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/>.
26 import gobject
27 if __name__ == '__main__':
28 # install _() func before importing dbus_support
29 from common import i18n
31 from common import dbus_support
32 if dbus_support.supported:
33 import dbus
34 import dbus.glib
36 class MusicTrackInfo(object):
37 __slots__ = ['title', 'album', 'artist', 'duration', 'track_number',
38 'paused']
40 class MusicTrackListener(gobject.GObject):
41 __gsignals__ = {
42 'music-track-changed': (gobject.SIGNAL_RUN_LAST, None, (object,)),
45 _instance = None
46 @classmethod
47 def get(cls):
48 if cls._instance is None:
49 cls._instance = cls()
50 return cls._instance
52 def __init__(self):
53 super(MusicTrackListener, self).__init__()
54 self._last_playing_music = None
56 bus = dbus.SessionBus()
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')
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')
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')
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')
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')
101 def _player_name_owner_changed(self, name, old, new):
102 if not new:
103 self.emit('music-track-changed', None)
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)
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)
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
123 def _mpris_playing_changed_cb(self, playing):
124 if type(playing) is dbus.Struct:
125 if playing[0]:
126 self.emit('music-track-changed', None)
127 else:
128 self.emit('music-track-changed', self._last_playing_music)
129 else: # Workaround for e.g. Audacious
130 if playing:
131 self.emit('music-track-changed', None)
132 else:
133 self.emit('music-track-changed', self._last_playing_music)
135 def _mpris_music_track_change_cb(self, arg):
136 self._last_playing_music = self._mpris_properties_extract(arg)
137 self.emit('music-track-changed', self._last_playing_music)
139 def _muine_properties_extract(self, song_string):
140 d = dict((x.strip() for x in s1.split(':', 1)) for s1 in \
141 song_string.split('\n'))
142 info = MusicTrackInfo()
143 info.title = d['title']
144 info.album = d['album']
145 info.artist = d['artist']
146 info.duration = int(d['duration'])
147 info.track_number = int(d['track_number'])
148 return info
150 def _muine_music_track_change_cb(self, arg):
151 info = self._muine_properties_extract(arg)
152 self.emit('music-track-changed', info)
154 def _rhythmbox_playing_changed_cb(self, playing):
155 if playing:
156 info = self.get_playing_track()
157 self.emit('music-track-changed', info)
158 else:
159 self.emit('music-track-changed', None)
161 def _rhythmbox_properties_extract(self, props):
162 info = MusicTrackInfo()
163 info.title = props.get('title', None)
164 info.album = props.get('album', None)
165 info.artist = props.get('artist', None)
166 info.duration = int(props.get('duration', 0))
167 info.track_number = int(props.get('track-number', 0))
168 return info
170 def _banshee_state_changed_cb(self, state):
171 if state == 'playing':
172 bus = dbus.SessionBus()
173 banshee = bus.get_object('org.bansheeproject.Banshee',
174 '/org/bansheeproject/Banshee/PlayerEngine')
175 currentTrack = banshee.GetCurrentTrack()
176 self._last_playing_music = self._banshee_properties_extract(
177 currentTrack)
178 self.emit('music-track-changed', self._last_playing_music)
179 elif state == 'paused':
180 self.emit('music-track-changed', None)
182 def _banshee_properties_extract(self, props):
183 info = MusicTrackInfo()
184 info.title = props.get('name', None)
185 info.album = props.get('album', None)
186 info.artist = props.get('artist', None)
187 info.duration = int(props.get('length', 0))
188 return info
190 def _quodlibet_state_change_cb(self, state=None):
191 info = self.get_playing_track()
192 if info:
193 self.emit('music-track-changed', info)
194 else:
195 self.emit('music-track-changed', None)
197 def _quodlibet_properties_extract(self, props):
198 info = MusicTrackInfo()
199 info.title = props.get('title', None)
200 info.album = props.get('album', None)
201 info.artist = props.get('artist', None)
202 info.duration = int(props.get('~#length', 0))
203 return info
205 def get_playing_track(self):
206 '''Return a MusicTrackInfo for the currently playing
207 song, or None if no song is playing'''
209 bus = dbus.SessionBus()
211 ## Check Muine playing track
212 test = False
213 if hasattr(bus, 'name_has_owner'):
214 if bus.name_has_owner('org.gnome.Muine'):
215 test = True
216 elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(),
217 'org.gnome.Muine'):
218 test = True
219 if test:
220 obj = bus.get_object('org.gnome.Muine', '/org/gnome/Muine/Player')
221 player = dbus.Interface(obj, 'org.gnome.Muine.Player')
222 if player.GetPlaying():
223 song_string = player.GetCurrentSong()
224 song = self._muine_properties_extract(song_string)
225 self._last_playing_music = song
226 return song
228 ## Check Rhythmbox playing song
229 test = False
230 if hasattr(bus, 'name_has_owner'):
231 if bus.name_has_owner('org.gnome.Rhythmbox'):
232 test = True
233 elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(),
234 'org.gnome.Rhythmbox'):
235 test = True
236 if test:
237 rbshellobj = bus.get_object('org.gnome.Rhythmbox',
238 '/org/gnome/Rhythmbox/Shell')
239 player = dbus.Interface(
240 bus.get_object('org.gnome.Rhythmbox',
241 '/org/gnome/Rhythmbox/Player'), 'org.gnome.Rhythmbox.Player')
242 rbshell = dbus.Interface(rbshellobj, 'org.gnome.Rhythmbox.Shell')
243 try:
244 uri = player.getPlayingUri()
245 except dbus.DBusException:
246 uri = None
247 if not uri:
248 return None
249 props = rbshell.getSongProperties(uri)
250 info = self._rhythmbox_properties_extract(props)
251 self._last_playing_music = info
252 return info
254 ## Check Banshee playing track
255 test = False
256 if hasattr(bus, 'name_has_owner'):
257 if bus.name_has_owner('org.bansheeproject.Banshee'):
258 test = True
259 elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(),
260 'org.bansheeproject.Banshee'):
261 test = True
262 if test:
263 banshee = bus.get_object('org.bansheeproject.Banshee',
264 '/org/bansheeproject/Banshee/PlayerEngine')
265 currentTrack = banshee.GetCurrentTrack()
266 if currentTrack:
267 song = self._banshee_properties_extract(currentTrack)
268 self._last_playing_music = song
269 return song
271 ## Check Quod Libet playing track
272 test = False
273 if hasattr(bus, 'name_has_owner'):
274 if bus.name_has_owner('net.sacredchao.QuodLibet'):
275 test = True
276 elif dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(),
277 'net.sacredchao.QuodLibet'):
278 test = True
279 if test:
280 quodlibet = bus.get_object('net.sacredchao.QuodLibet',
281 '/net/sacredchao/QuodLibet')
282 if quodlibet.IsPlaying():
283 currentTrack = quodlibet.CurrentSong()
284 song = self._quodlibet_properties_extract(currentTrack)
285 self._last_playing_music = song
286 return song
288 return None
290 # here we test :)
291 if __name__ == '__main__':
292 def music_track_change_cb(listener, music_track_info):
293 if music_track_info is None:
294 print 'Stop!'
295 else:
296 print music_track_info.title
297 listener = MusicTrackListener.get()
298 listener.connect('music-track-changed', music_track_change_cb)
299 track = listener.get_playing_track()
300 if track is None:
301 print 'Now not playing anything'
302 else:
303 print 'Now playing: "%s" by %s' % (track.title, track.artist)
304 gobject.MainLoop().run()