# Rhythmbox_Bonobo.py # Copyright (c) 2005 Alex Revo # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # TODO: # clean up code # poll for changes BROKEN = True DISABLED = True # Import the required system modules. try: import bonobo import CORBA BROKEN = False DISABLED = False except ImportError, error: print("*** ERROR ***") print("Unable to import required modules: %s" % error) print("This package requires:") print(" gnome-python >= 2.6.0") print(" pyorbit >= 2.0.0") print("*** ERROR ***") print("") except Exception, error: print("*** ERROR ***") print("Unknown error: %s" % error) print("*** ERROR ***") from Debug import Debug # Set constant values. EVENTSOURCE_IID = "OAFIID:Bonobo_Activation_EventSource" EVENTSOURCE_IDL = "IDL:Bonobo/EventSource:1.0" EVENT_REGISTER = "Bonobo/ObjectDirectory:activation:register" EVENT_UNREGISTER = "Bonobo/ObjectDirectory:activation:unregister" RHYTHMBOX_IID = "OAFIID:GNOME_Rhythmbox" RHYTHMBOX_IDL = "IDL:GNOME/Rhythmbox:1.0" RB_CHANGE_PLAYING = "Bonobo/Property:change:playing" RB_CHANGE_REPEAT = "Bonobo/Property:change:repeat" RB_CHANGE_SHUFFLE = "Bonobo/Property:change:shuffle" RB_CHANGE_SONG = "Bonobo/Property:change:song" BOOLEAN_IDL = "IDL:omg.org/CORBA/boolean:1.0" class Rhythmbox_Bonobo(Debug): def __init__(self, *args): # Initialise variables. self._rhythmbox = None self._rbProps = None self._rbSong = None self._running = False # Bonobo stuff self.e_reg = None self.e_unreg = None self.e_playing = None self.e_repeat = None self.e_shuffle = None self.e_song = None # Callbacks self._callbacks_song = [] self._callbacks_state = [] # Callback stuff: def add_callback_song(self, callback): if (callback not in self._callbacks_song): self.debug("Adding callback (song): %s::%s" % (callback.__module__, callback.__name__)) self._callbacks_song.append(callback) # Run callback immediately for good measure. self._run_callbacks([callback]) return(True) def add_callback_state(self, callback): if (callback not in self._callbacks_state): self.debug("Adding callback (state): %s::%s" % (callback.__module__, callback.__name__)) self._callbacks_state.append(callback) # Run callback immediately for good measure. self._run_callbacks([callback]) return(True) def clear_callbacks_song(self): self._callbacks_song = [] return(True) def clear_callbacks_state(self): self._callbacks_state = [] return(True) def _run_callbacks(self, list): for callback in list: if (callable(callback)): #self.debug("Running callback (%s::%s)" % (callback.__module__, callback.__name__)) try: if (callable(callback)): callback(self) except Exception, error: self.handle_exception(error) def song_change(self, obj_ref=None): self._run_callbacks(self._callbacks_song) def state_change(self, obj_ref=None): self._run_callbacks(self._callbacks_state) def cleanup(self): self.debug ("Removing Bonobo listeners (Registers)") try: if (self.e_reg): bonobo.event_source_client_remove_listener (self.event_source, self.e_reg) if (self.e_unreg): bonobo.event_source_client_remove_listener (self.event_source, self.e_unreg) if (self._rbProps): self._rbProps.unref() except: pass def cleanup_rb(self): self.debug ("Removing Bonobo listeners (Rhythmbox)") try: if (self.e_playing): bonobo.event_source_client_remove_listener (self._rbProps, self.e_playing) if (self.e_repeat): bonobo.event_source_client_remove_listener (self._rbProps, self.e_repeat) if (self.e_shuffle): bonobo.event_source_client_remove_listener (self._rbProps, self.e_shuffle) if (self.e_song): bonobo.event_source_client_remove_listener (self._rbProps, self.e_song) except: pass def disable(self): self.debug ("Disabling Rhythmbox_Bonobo...") DISABLED = True self.cleanup_rb() self.cleanup() def enable(self): if (BROKEN): DISABLED = True return(False) DISABLED = False # Set Bonobo listeners (register/unregister): # (appropriated from tune ) self.event_source = bonobo.get_object(EVENTSOURCE_IID, EVENTSOURCE_IDL) self.e_reg = bonobo.event_source_client_add_listener(self.event_source, self._bonobo_register, EVENT_REGISTER) self.e_unreg = bonobo.event_source_client_add_listener(self.event_source, self._bonobo_register, EVENT_UNREGISTER) # Get Rhythmbox's running state & update immediately. self._bonobo_register() return(True) def _bonobo_register(self, listener=None, event=None, value=None, error=None): #self.debug("Recieved register/unregister event") try: if ((bonobo.activation.query("(repo_ids.has('%s')) AND (_active == TRUE)" % RHYTHMBOX_IDL))): self._rhythmbox = bonobo.activation.activate_from_id(RHYTHMBOX_IID, 0, None) self._rbProps = self._rhythmbox.getPlayerProperties() if (not self._running): self.debug("Rhythmbox is running.") self._running = True self.refresh() # Add Bonobo listeners. # NOTE: shuffle/repeat/play-order don't notify (in Rhythmbox 0.8.x). self.cleanup_rb() self.debug("Adding Bonobo listeners...") self.e_playing = bonobo.event_source_client_add_listener(self._rbProps, self._bonobo_state_change, RB_CHANGE_PLAYING) self.e_repeat = bonobo.event_source_client_add_listener(self._rbProps, self._bonobo_state_change, RB_CHANGE_REPEAT) self.e_shuffle = bonobo.event_source_client_add_listener(self._rbProps, self._bonobo_state_change, RB_CHANGE_SHUFFLE) self.e_song = bonobo.event_source_client_add_listener(self._rbProps, self._bonobo_song_change, RB_CHANGE_SONG) else: if (self._running): self.debug("Rhythmbox is (probably) not running.") self._running = False self._rhythmbox = None self._rbProps.unref() self._rbSong = None self.cleanup_rb() self._bonobo_song_change() except CORBA.COMM_FAILURE: self._running = False except Exception, error: self.handle_exception(error) def _bonobo_state_change(self, listener=None, event=None, value=None, error=None): self.state_change() def _bonobo_song_change(self, listener=None, event=None, value=None, error=None): self.refresh() self.song_change() def refresh(self): try: if (self.is_active()): self._rbSong = self._rbProps.getValue("song").value() return(True) else: self._rbSong = None except CORBA.COMM_FAILURE: self._running = False except AttributeError: self._running = False except Exception, error: self._running = False self.handle_exception(error) return(False) def is_active(self): if (DISABLED or not self._running): return(False) return(True) def has_song_info(self): try: if (self._rbSong.artist): return(True) except: pass return(False) def __getitem__(self, key): ret_val = "None" if (self.is_active()): try: if (self.has_song_info()): if (key == "album"): ret_val = str(self._rbSong.album) if (key == "artist"): ret_val = str(self._rbSong.artist) if (key == "bitrate"): ret_val = int(self._rbSong.bitrate) if (key == "duration"): ret_val = int(self._rbSong.duration) if (key == "file_size"): ret_val = int(self._rbSong.filesize) if (key == "genre"): ret_val = str(self._rbSong.genre) if (key == "last_played"): ret_val = int(self._rbSong.last_played) if (key == "play_count"): ret_val = int(self._rbSong.play_count) if (key == "rating"): ret_val = int(self._rbSong.rating) if (key == "title"): ret_val = str(self._rbSong.title) if (key == "track_number"): ret_val = int(self._rbSong.track_number) if (key == "uri"): ret_val = str(self._rbSong.path) if (key == "elapsed_time"): ret_val = int(self._rhythmbox.getPlayingTime()) if (key == "playing"): ret_val = bool(self._rbProps.getValue("playing").value()) if (key == "repeat"): ret_val = bool(self._rbProps.getValue("repeat").value()) if (key == "shuffle"): ret_val = bool(self._rbProps.getValue("shuffle").value()) except CORBA.COMM_FAILURE: self._running = False except Exception, error: self.handle_exception(error) if (ret_val == "None"): # Return appropriate types depending on key. if (key == "album"): return("") if (key == "artist"): return("") if (key == "bitrate"): return(0) if (key == "duration"): return(0) if (key == "elapsed_time"): return(0) if (key == "file_size"): return(0) if (key == "genre"): return("") if (key == "last_played"): return(0) if (key == "play_count"): return(0) if (key == "playing"): return(False) if (key == "rating"): return(0) if (key == "repeat"): return(False) if (key == "shuffle"): return(False) if (key == "title"): return("") if (key == "track_number"): return(0) if (key == "uri"): return("") return("") else: return(ret_val) def __setitem__(self, key, value): if (not self.is_active()): return(None) try: if (self.has_song_info()): if (key == "elapsed_time"): self._rhythmbox.setPlayingTime(value) # Run callbacks self._bonobo_song_change() if (key == "rating"): if (value > 5): value = 5 if (value < 0): value = 0 self._rhythmbox.setRating(value) # Run callbacks self._bonobo_song_change() if (key == "playing"): self._rhythmbox.playPause() # No need to run callbacks here; Bonobo will notify us. if (key == "repeat"): new_val = CORBA.Any(CORBA.TypeCode(BOOLEAN_IDL), CORBA.FALSE) if (value): new_val = CORBA.Any(CORBA.TypeCode(BOOLEAN_IDL), CORBA.TRUE) self._rbProps.setValue("repeat", new_val) # Run callbacks self._bonobo_state_change() if (key == "shuffle"): new_val = CORBA.Any(CORBA.TypeCode(BOOLEAN_IDL), CORBA.FALSE) if (value): new_val = CORBA.Any(CORBA.TypeCode(BOOLEAN_IDL), CORBA.TRUE) self._rbProps.setValue("shuffle", new_val) # Run callbacks self._bonobo_state_change() except CORBA.COMM_FAILURE: self._running = False except Exception, error: self.handle_exception(error) def run_command(self, command, args=None): if (not self.is_active()): return(None) try: if (command == "NEXT"): self._rhythmbox.next() if (command == "PAUSE"): self._rhythmbox.pause() if (command == "PLAY"): self._rhythmbox.play() if (command == "PLAY_PAUSE"): self._rhythmbox.playPause() if (command == "PLAY_URI"): self._rhythmbox.handleFile(args) if (command == "PREVIOUS"): self._rhythmbox.previous() except Exception, error: self.handle_exception(error)