1 # -*- coding: utf-8 -*-
2 ## src/music_track_listener.py
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/>.
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
:
36 class MusicTrackInfo(object):
37 __slots__
= ['title', 'album', 'artist', 'duration', 'track_number',
40 class MusicTrackListener(gobject
.GObject
):
42 'music-track-changed': (gobject
.SIGNAL_RUN_LAST
, None, (object,)),
48 if cls
._instance
is None:
53 super(MusicTrackListener
, self
).__init
__()
54 self
._last
_playing
_music
= None
56 bus
= dbus
.SessionBus()
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')
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')
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')
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')
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
):
103 self
.emit('music-track-changed', None)
105 def _player_playing_changed_cb(self
, playing
):
107 self
.emit('music-track-changed', self
._last
_playing
_music
)
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))
123 def _mpris_playing_changed_cb(self
, playing
):
124 if type(playing
) is dbus
.Struct
:
126 self
.emit('music-track-changed', None)
128 self
.emit('music-track-changed', self
._last
_playing
_music
)
129 else: # Workaround for e.g. Audacious
131 self
.emit('music-track-changed', None)
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'])
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
):
156 info
= self
.get_playing_track()
157 self
.emit('music-track-changed', info
)
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))
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
(
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))
190 def _quodlibet_state_change_cb(self
, state
=None):
191 info
= self
.get_playing_track()
193 self
.emit('music-track-changed', info
)
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))
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
213 if hasattr(bus
, 'name_has_owner'):
214 if bus
.name_has_owner('org.gnome.Muine'):
216 elif dbus
.dbus_bindings
.bus_name_has_owner(bus
.get_connection(),
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
228 ## Check Rhythmbox playing song
230 if hasattr(bus
, 'name_has_owner'):
231 if bus
.name_has_owner('org.gnome.Rhythmbox'):
233 elif dbus
.dbus_bindings
.bus_name_has_owner(bus
.get_connection(),
234 'org.gnome.Rhythmbox'):
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')
244 uri
= player
.getPlayingUri()
245 except dbus
.DBusException
:
249 props
= rbshell
.getSongProperties(uri
)
250 info
= self
._rhythmbox
_properties
_extract
(props
)
251 self
._last
_playing
_music
= info
254 ## Check Banshee playing track
256 if hasattr(bus
, 'name_has_owner'):
257 if bus
.name_has_owner('org.bansheeproject.Banshee'):
259 elif dbus
.dbus_bindings
.bus_name_has_owner(bus
.get_connection(),
260 'org.bansheeproject.Banshee'):
263 banshee
= bus
.get_object('org.bansheeproject.Banshee',
264 '/org/bansheeproject/Banshee/PlayerEngine')
265 currentTrack
= banshee
.GetCurrentTrack()
267 song
= self
._banshee
_properties
_extract
(currentTrack
)
268 self
._last
_playing
_music
= song
271 ## Check Quod Libet playing track
273 if hasattr(bus
, 'name_has_owner'):
274 if bus
.name_has_owner('net.sacredchao.QuodLibet'):
276 elif dbus
.dbus_bindings
.bus_name_has_owner(bus
.get_connection(),
277 'net.sacredchao.QuodLibet'):
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
291 if __name__
== '__main__':
292 def music_track_change_cb(listener
, music_track_info
):
293 if music_track_info
is None:
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()
301 print 'Now not playing anything'
303 print 'Now playing: "%s" by %s' % (track
.title
, track
.artist
)
304 gobject
.MainLoop().run()