A really good radio, and a really cool Python script
September 26, 2006
Recently, I discovered an online radio I really like: HardRadio, a webradio that streams heavy metal music 24 hours a day, and doesn’t make the mistake other “metal” radios do of streaming only extreme metal (the black and death variants). On HardRadio I get classics such as Motörhead, Black Label Society, Judas Priest…
It also streams in high quality Ogg Vorbis, which I find really great. Its only downside: it doesn’t stream the track titles in the stream. Not that it would stop a python programmer from writing his own applet to get the track data!
So, my theory is that HardRadio doesn’t stream titles because they’re corporate sellouts: they have licences to stream everything, and probably one of the conditions was “Make it hard for those evil pirates who eat babies to rip the stream to mp3’s”. Without stream titles, tools such as the excellent Streamripper have no idea when to chunk the stream into separate music files, rendering the rip cumbersome at best, useless at worst.
The problem is that we, the casual listener, don’t get titles either. How am I supposed to know that I’m listening to a really cool Judas Priest track, that I’d really like to buy, if only I knew what it was?
Turns out that HardRadio do provide track information on their website. It’s in a tiny Flash applet, in a frame that is loaded for all pages of the site. The page is this one this one[/link]. Notice that the flash applet is tiny, so the ticker is annoying to read, because it’s slow and tiny and you have to have a web browser open to know what you’re listening to.
You know what? Screw that. Let’s look at the page source and discover the URL of the flash applet. Then, let’s download it and run strings over it. Strings is a small unix utility that scans a binary file (such as a flash applet) and finds everything that looks like a string within, using some magic heuristic like “if it has at least 4 printable ascii characters, it’s a string!”. The result of running it on this flash applet is:
$ strings hardradioticker.swf
http://axl.hardradio.com/playnow.txt
_level0
Arial
song
... (some near-garbage here) ...
Aha, now this first string is interesting! Let’s see what is at http://axl.hardradio.com/playnow.txt .
song= Ride On by Viron
Yay, there’s our track information! The track data is periodically refreshed when needed, so what we need is an application that emulates the behaviour of the flash applet: periodically ping that file to get the current track, and display it somewhere.
For now, I took and heavily hacked the code from the KeyCounter project, to make myself a small taskbar icon which displays the current track in a tooltip.
#!/usr/bin/python
#
# HardRadio Ticker
#
# Periodically refresh the ticker information from HardRadio and place
# it in a tooltip. Easy consulting of the track info at your
# fingertips!
#
# Copyright (C) 2006 David Anderson <dave@natulte.net>
#
from sys import exit
import urllib2
import time
import pygtk
pygtk.require('2.0')
import gtk
import gobject
try:
import egg.trayicon
except:
print 'WARNING: python-gnome2-extras is missing'
exit(1)
# -------------------------------------------------------------------
# GktTrayIcon tray icon.
# -------------------------------------------------------------------
class TickerTray(object):
def __init__(self, url):
self.url = url
# create tray icon
self.icon = egg.trayicon.TrayIcon('HardRadio Ticker')
self.eventbox = gtk.EventBox()
self.eventbox.add(gtk.image_new_from_icon_name
('gnome-settings-keybindings',
gtk.ICON_SIZE_SMALL_TOOLBAR))
self.tips = gtk.Tooltips()
self.tips.set_tip(self.icon, 'No track')
self.icon.add(self.eventbox)
self.icon.show_all()
def update_track(self):
ticker_file = urllib2.urlopen(self.url)
track = ticker_file.read().split('= ')[1].strip()
ticker_file.close()
self.tips.set_tip(self.icon, (track))
return True
# -------------------------------------------------------------------
# Main loop
# -------------------------------------------------------------------
if __name__ == '__main__':
HARDRADIO_TICKER_URL = "http://axl.hardradio.com/playnow.txt"
trayicon = TickerTray(HARDRADIO_TICKER_URL)
gobject.timeout_add(5000, trayicon.update_track)
trayicon.update_track()
gtk.main()
Okay, so after writing this I discovered that Streamripper now supports ripping by sourcing track/artist info from third party scripts. But I didn’t want to rip, I just wanted an easy way to know what I’m listening to :-).