CurrentSong Plugins
currentSong plugins are actually sub-plugins.
Plugin: .../plugins_base/CurrentSong.py. The currentSong plugin. It's an interface between emesene and the players.
Player: .../plugins_base/currentSong/*.py. All the modules in currentSong directory that have the required structure and are included by currentSong/__init__.py
Base class: .../plugins_base/currentSong/CurrentSong.py. Provides some dummy methods (check, isPlaying, isRunning...) and the style parsing code. You could override all that methods, including the style parsing ones, but doing that would disable the style feature. See appendix A.
Building a basic player module
These are a few steps to write a basic player module. If your media player supports dbus, you could try using the higher-level interface described here.
First, import and subclass CurrentSong
import CurrentSong
class YourPlayer( CurrentSong.CurrentSong ):
def __init__( self ):
CurrentSong.CurrentSong.__init__( self )
Now, define the following methods:
check()
Return value: boolean
Called by the plugin periodically to update the current song information. Checks if the current song has changed, asking the player, and comparing the saved values with the new ones. If they've changed, sets (or calls an internal function to set) the song data in self.artist, self.title and self.album and returns True. You should return True only one time, only when the song changes and you can send different, new data.
getStatus()
Return value: tuple(bool, str)
This works like *plugins* check() funcion (not currentsong check!). Returns a tuple with two items to tell the init status. If the bool is True, everything is ok, and the str is ignored. Else, if the bool is False, something failed, and it should display an error message with the str to the user.
isRunning() / isPlaying()
Return value: boolean
Tell currentSong if the player is running/playing.
Dbus players
Since r686, there is a dbus base class that makes dbus currentsong plugins simpler. You have to change the header a bit
IFACE_NAME = 'org.example.iface.name'
IFACE_PATH = '/org/example/iface/path'
import CurrentSong
class YourPlayer( CurrentSong.DbusBase ):
def __init__( self ):
CurrentSong.DbusBase.__init__( self, IFACE_NAME, self.setInterface )
try: self.iface
except: self.iface = None
def setInterface( self ):
self.iface = self.bus.get_object( IFACE_NAME, IFACE_PATH )
DbusBase.__init__(): There are two optional parameters here, the interface name and a callback function. That function is called when the interface becomes available (the player starts). If init detects that it is already playing, calls it immediately. That try...except block sets the self.iface attribute to None to avoid AttributeErrors. The example setInterface() should work with most players, but you can do any init tasks there (for example)
Some useful variables/methods provided by DbusBase:
- self.module: the dbus module
- self.bus: dbus.SessionBus()
- self.root: org.freedesktop.DBus
- self.isNameActive(name): self.root.NameHasOwner(name)
Appendix A (?): Missing information
Consider this situation: Your player doesn't provide any standard way to get the title, and you've found a binary tmp file in ~/.X11/.X12/.X13/.X14/useless_stuff/your_player/weird_cache that sometimes, in offset 0xA5DF, contains the raw title ("jo's here - Arfenhouse") and sometimes contains the filename (~/pr0n/illegal_stuff/mp3/09_arfenhouse__LOLOLOLOLOL_(http___illeg.alt.orre.nt).flac.ogg.rar.exe).
In that situation, you don't have the exact artist/title/album data, so you could override the user style. But for that "raw title", I'd recommend you to try simple parsing with split: title, artist = rawtitle.split( " - ", 1 ). If that isn't possible, if the title format varies, or if you just have the filename, send it directly. Remember to remove the ~/pr0n/illegal_stuff/mp3/ part of the path.
Trying to get metadata from the filename
In the above example, we had the filename only when something failed. And is pretty obvious that the file hadn't enough meta tags. If you are in this situation, avoid retrieving that metadata.
But, if your player is lazy and just provides a filename, you could fetch that tags. But consider first:
- Performance
- Delay when updating
- "Non-blocking", using threads or some thing
- Modules availability
- (etc)
