Rhythmbox nowplaying in irssi on a remote server

So, a few weeks ago i hacked together a quick nowplaying script for xchat, which communicated with rhythmbox on the same system using the python dbus bindings. I could probably have found a preexisting script, but i enjoy doing things for myself, and learned a bit about python and dbus in the process.

Now, that was all fine and dandy when i was using xchat on the same system, but as eveyone knows, the only true way to irc is via irssi in screen on a remote, always-connected system. And as such, when i subsequently got this linode, i switched to using irssi, and bemoaned the loss of my ability to annoy people by telling them what i was listening to.

Eventually i found a quick hack that pulls the song/artist name from your last.fm recently-played list, but this has some major drawback - for starters, you have to be signed upf or last.fm (not a bad thing in itself, but potentially an issue), and more notably, the list doesn’t update until you’re about halfway through the song. Naturally, i thought to myself “i can do better than this”.

And given that i have a webserver with whatever extensions/scripting languages/etc i want running on the same server as irssi, it actually turned out to be fairly straightforward, once i managed to pull together enough samples of rhythmbox python plugins that i could figure out what i was doing.

I’ll leave the serverside script as an exercise for the reader (wait, i don’t actually have any readers… oh well), as it’s fairly trivial, and just look at the local rhythmbox plugin part.

The basic structure of a plugin is outlined (in a rather convoluted fashion) on the live.gnome.org wiki, but basically the minimum you can get away with is two files, an __init__.py and a <pluginname>.rb-plugin description file. The description file is, again, trivial, so i’ll ignore it. The .py file is where the fun stuff happens:

import rhythmdb, rb
import urllib

class NPRemote (rb.Plugin):
	def __init__(self):
		rb.Plugin.__init__(self)

	def activate(self, shell):
		self.shell = shell
		self.player = shell.get_player()
		self.db = shell.get_property('db')
		self.songchanged_id = self.player.connect('playing-song-changed',
				self.song_changed)
		self.songpropchanged_id = self.player.connect('playing-song-property-changed',
				self.song_prop_changed)
		self.last_artist = ""
		self.last_song = ""

	def deactivate(self, shell):
		shell.disconnect(self.songchanged_id)
		shell.disconnect(self.songpropchanged_id)
		del self.shell

	def song_changed(self, player, entry):
		if (entry is not None):
			artist = self.db.entry_get(entry, rhythmdb.PROP_ARTIST)
			song   = self.db.entry_get(entry, rhythmdb.PROP_TITLE)
			album  = self.db.entry_get(entry, rhythmdb.PROP_ALBUM)

			if (artist is not None) and (song is not None):
				self.last_artist = artist
				self.last_song = song
				self.send_to_server(self.last_artist, self.last_song)

	def song_prop_changed(self, player, uri, prop, value, value_):
		# i'm not quite sure why the last arg seems to repeat itself, but it
		# always seems to be identical for the scenarios i'm covering, so i'll
		# ignore the second one...
		if (uri[:4] == "http" and prop == "rb:stream-song-title"):
			details = arg4.split('-')
			self.last_artist = details[0].strip()
			self.last_song = details[1].strip()
			self.send_to_server(self.last_artist, self.last_song)
		elif (uri[:6] == "lastfm"):
			if (prop == "rb:stream-song-artist"):
				self.last_artist = value
			elif (prop == "rb:stream-song-title"):
				self.last_song = value
				self.send_to_server(self.last_artist, self.last_song)

	def send_to_server(self, artist, song):
		enc_artist = urllib.quote_plus(artist)
		enc_song = urllib.quote_plus(song)

		# pointless callback, but seems to be necessary for loader.get_url()?
		def callback(data):
			pass

		loader = rb.Loader()
		loader.get_url(
			"http://something.example.net/whatever/nowplaying.foo?artist=" + enc_artist +
			"&song=" + enc_song,
			callback)

Of course, in your server-side script you need to do something with the artist/song name data the plugin provides - the easiest solution is just to write it out to a file which you can subsequently load into irssi with a simple alias, something along the lines of:

/alias np exec - -o echo "now playing: `cat /path/to/file/nowplaying.txt`"

Now, i’m not saying that this is the best way to do this (thanks to my not being able to find any documentation, other than the source itself, and the fact that i couldn’t be arsed heading to #rhythmbox to ask questions, i’m not even sure what some of the parameters to my song-property-changed signal handler are, hence the generic argX names…), but it seems to do the job nicely (at least, a hell of a lot better than the last.fm method i’d been using before), and can be adapted quite easily to support any remote server where you have the ability to run any kind of script (whether it be php, perl, ruby, python, etc), or with a bit more effort probably anything you have ssh or ftp access to, and it doesn’t even require that your web server be the same system that you run irssi on (just adapt the alias to use wget/curl/etc to grab the file rather than cating it directly from the local filesystem, as long as you ca put it in a web-accessible location).

update: now also handles last.fm streams

Tags: , ,

One Response to “Rhythmbox nowplaying in irssi on a remote server”

  1. Recent Faves Tagged With "irssi" : MyNetFaves Says:

    [...] public links >> irssi Rhythmbox nowplaying in irssi on a remote server First saved by aidi1016 | 2 days ago Twitter or This post had to come sooner or later First [...]

Leave a Reply