[totem] plugins: Re-indent Python files and fix whitespace issues



commit e9e33d203d7f162e147f3cb9ed603fead24bc62a
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sun Mar 27 10:59:39 2011 +0100

    plugins: Re-indent Python files and fix whitespace issues
    
    Nothing is changed in this commit apart from whitespace and line wrapping,
    as complained about by pylint.
    
    See: http://www.python.org/dev/peps/pep-0008/
    
    Helps: bgo#645739

 src/plugins/coherence_upnp/coherence_upnp.py |  141 +++--
 src/plugins/dbus-service/dbus-service.py     |  554 +++++++++--------
 src/plugins/iplayer/iplayer.py               |  446 +++++++------
 src/plugins/iplayer/iplayer2.py              |  891 ++++++++++++++------------
 src/plugins/iplayer/listparser.py            |   93 ++--
 src/plugins/jamendo/jamendo.py               |  564 +++++++++--------
 src/plugins/opensubtitles/hash.py            |   78 ++--
 src/plugins/opensubtitles/opensubtitles.py   |  808 ++++++++++++-----------
 src/plugins/pythonconsole/pythonconsole.py   |  203 ++++---
 src/plugins/sample-python/sample-python.py   |   18 +-
 10 files changed, 2010 insertions(+), 1786 deletions(-)
---
diff --git a/src/plugins/coherence_upnp/coherence_upnp.py b/src/plugins/coherence_upnp/coherence_upnp.py
index d785830..8863e19 100644
--- a/src/plugins/coherence_upnp/coherence_upnp.py
+++ b/src/plugins/coherence_upnp/coherence_upnp.py
@@ -10,102 +10,109 @@ from gi.repository import Gtk
 from gi.repository import Totem
 
 from coherence.ui.av_widgets import TreeWidget
-from coherence.ui.av_widgets import UDN_COLUMN,UPNP_CLASS_COLUMN,SERVICE_COLUMN
+from coherence.ui.av_widgets import UDN_COLUMN, UPNP_CLASS_COLUMN
+from coherence.ui.av_widgets import SERVICE_COLUMN
 
-gettext.textdomain("totem")
+gettext.textdomain ("totem")
 
 D_ = gettext.dgettext
 _ = gettext.gettext
 
-class UPnPClient(gobject.GObject, Peas.Activatable):
+class UPnPClient (gobject.GObject, Peas.Activatable):
     __gtype_name__ = 'UPnPClient'
 
-    object = gobject.property(type = gobject.GObject)
+    object = gobject.property (type = gobject.GObject)
 
     def __init__ (self):
         self.totem_object = None
-        self.ui = TreeWidget()
-        self.ui.window.set_shadow_type(gtk.SHADOW_IN)
+        self.ui = TreeWidget ()
+        self.ui.window.set_shadow_type (gtk.SHADOW_IN)
         self.ui.cb_item_right_click = self.button_pressed
-        self.ui.window.show_all()
-        selection = self.ui.treeview.get_selection()
-        selection.set_mode(gtk.SELECTION_MULTIPLE)
+        self.ui.window.show_all ()
+        selection = self.ui.treeview.get_selection ()
+        selection.set_mode (gtk.SELECTION_MULTIPLE)
 
-    def button_pressed(self, widget, event):
+    def button_pressed (self, widget, event):
         if event.button == 3:
-            x = int(event.x)
-            y = int(event.y)
+            x = int (event.x)
+            y = int (event.y)
             try:
-                row_path,column,_,_ = self.ui.treeview.get_path_at_pos(x, y)
-                selection = self.ui.treeview.get_selection()
-                if not selection.path_is_selected(row_path):
-                    self.ui.treeview.set_cursor(row_path,column,False)
+                row_path, column, _, _ = self.ui.treeview.get_path_at_pos (x, y)
+                selection = self.ui.treeview.get_selection ()
+                if not selection.path_is_selected (row_path):
+                    self.ui.treeview.set_cursor (row_path, column, False)
                 print "button_pressed", row_path, (row_path[0],)
-                iter = self.ui.store.get_iter((row_path[0],))
-                udn, = self.ui.store.get(iter,UDN_COLUMN)
-                iter = self.ui.store.get_iter(row_path)
-                upnp_class,url = self.ui.store.get(iter,UPNP_CLASS_COLUMN,SERVICE_COLUMN)
+                iter = self.ui.store.get_iter ((row_path[0],))
+                udn, = self.ui.store.get (iter, UDN_COLUMN)
+                iter = self.ui.store.get_iter (row_path)
+                upnp_class, url = self.ui.store.get (iter, UPNP_CLASS_COLUMN,
+                                                     SERVICE_COLUMN)
                 print udn, upnp_class, url
-                if(not upnp_class.startswith('object.container') and
-                   not upnp_class == 'root'):
-                    self.create_item_context(has_delete=self.ui.device_has_action(udn,'ContentDirectory','DestroyObject'))
-                    self.context.popup(None,None,None,event.button,event.time)
+                if (not upnp_class.startswith ('object.container') and
+                    not upnp_class == 'root'):
+                    has_delete = self.ui.device_has_action (udn,
+                                                            'ContentDirectory',
+                                                            'DestroyObject')
+                    self.create_item_context (has_delete = has_delete)
+                    self.context.popup (None, None, None, event.button,
+                                        event.time)
                     return 1
             except TypeError:
                 pass
             return 1
 
-    def create_item_context(self,has_delete=False):
+    def create_item_context (self, has_delete = False):
         """ create context menu for right click in treeview item"""
 
-        def action(menu, text):
-            selection = self.ui.treeview.get_selection()
-            model, selected_rows = selection.get_selected_rows()
+        def action (menu, text):
+            selection = self.ui.treeview.get_selection ()
+            model, selected_rows = selection.get_selected_rows ()
             if text == 'item.delete':
                 for row_path in selected_rows:
-                    self.ui.destroy_object(row_path)
+                    self.ui.destroy_object (row_path)
                 return
-            if(len(selected_rows) > 0 and
-               text ==' item.play'):
-                row_path = selected_rows.pop(0)
-                iter = self.ui.store.get_iter(row_path)
-                url, = self.ui.store.get(iter,SERVICE_COLUMN)
-                self.totem_object.action_remote(totem.REMOTE_COMMAND_REPLACE,url)
-                self.totem_object.action_remote(totem.REMOTE_COMMAND_PLAY,url)
+            if (len (selected_rows) > 0 and text ==' item.play'):
+                row_path = selected_rows.pop (0)
+                iter = self.ui.store.get_iter (row_path)
+                url, = self.ui.store.get (iter, SERVICE_COLUMN)
+                self.totem_object.action_remote (totem.REMOTE_COMMAND_REPLACE,
+                                                 url)
+                self.totem_object.action_remote (totem.REMOTE_COMMAND_PLAY, url)
             for row_path in selected_rows:
-                iter = self.ui.store.get_iter(row_path)
-                url, = self.ui.store.get(iter,SERVICE_COLUMN)
-                self.totem_object.action_remote(totem.REMOTE_COMMAND_ENQUEUE,url)
-                self.totem_object.action_remote(totem.REMOTE_COMMAND_PLAY,url)
-
-        if not hasattr(self, 'context_no_delete'):
-            self.context_no_delete = gtk.Menu()
+                iter = self.ui.store.get_iter (row_path)
+                url, = self.ui.store.get (iter, SERVICE_COLUMN)
+                self.totem_object.action_remote (totem.REMOTE_COMMAND_ENQUEUE,
+                                                 url)
+                self.totem_object.action_remote (totem.REMOTE_COMMAND_PLAY, url)
+
+        if not hasattr (self, 'context_no_delete'):
+            self.context_no_delete = gtk.Menu ()
             # Translators: this refers to a media file
-            play_menu = gtk.MenuItem(_(u"Play"))
-            play_menu.connect("activate", action, 'item.play')
+            play_menu = gtk.MenuItem (_(u"Play"))
+            play_menu.connect ("activate", action, 'item.play')
             # Translators: this refers to a media file
-            enqueue_menu = gtk.MenuItem(_(u"Enqueue"))
-            enqueue_menu.connect("activate", action, 'item.enqueue')
-            self.context_no_delete.append(play_menu)
-            self.context_no_delete.append(enqueue_menu)
-            self.context_no_delete.show_all()
-
-        if not hasattr(self, 'context_with_delete'):
-            self.context_with_delete = gtk.Menu()
+            enqueue_menu = gtk.MenuItem (_(u"Enqueue"))
+            enqueue_menu.connect ("activate", action, 'item.enqueue')
+            self.context_no_delete.append (play_menu)
+            self.context_no_delete.append (enqueue_menu)
+            self.context_no_delete.show_all ()
+
+        if not hasattr (self, 'context_with_delete'):
+            self.context_with_delete = gtk.Menu ()
             # Translators: this refers to a media file
-            play_menu = gtk.MenuItem(_(u"Play"))
-            play_menu.connect("activate", action, 'item.play')
+            play_menu = gtk.MenuItem (_(u"Play"))
+            play_menu.connect ("activate", action, 'item.play')
             # Translators: this refers to a media file
-            enqueue_menu = gtk.MenuItem(_(u"Enqueue"))
-            enqueue_menu.connect("activate", action, 'item.enqueue')
-            self.context_with_delete.append(play_menu)
-            self.context_with_delete.append(enqueue_menu)
-            self.context_with_delete.append(gtk.SeparatorMenuItem())
+            enqueue_menu = gtk.MenuItem (_(u"Enqueue"))
+            enqueue_menu.connect ("activate", action, 'item.enqueue')
+            self.context_with_delete.append (play_menu)
+            self.context_with_delete.append (enqueue_menu)
+            self.context_with_delete.append (gtk.SeparatorMenuItem ())
             # Translators: this refers to a media file
-            menu = gtk.MenuItem(_(u"Delete"))
-            menu.connect("activate", action, 'item.delete')
-            self.context_with_delete.append(menu)
-            self.context_with_delete.show_all()
+            menu = gtk.MenuItem (_(u"Delete"))
+            menu.connect ("activate", action, 'item.delete')
+            self.context_with_delete.append (menu)
+            self.context_with_delete.show_all ()
 
         if has_delete:
             self.context = self.context_with_delete
@@ -114,9 +121,11 @@ class UPnPClient(gobject.GObject, Peas.Activatable):
 
     def do_activate (self):
         self.totem_object = self.object
-        self.totem_object.add_sidebar_page ("upnp-coherence", _(u"Coherence DLNA/UPnP Client"), self.ui.window)
+        self.totem_object.add_sidebar_page ("upnp-coherence",
+                                            _(u"Coherence DLNA/UPnP Client"),
+                                            self.ui.window)
 
-        def load_and_play(url):
+        def load_and_play (url):
             self.totem_object.add_to_playlist_and_play (url, '', True)
 
         self.ui.cb_item_dbl_click = load_and_play
diff --git a/src/plugins/dbus-service/dbus-service.py b/src/plugins/dbus-service/dbus-service.py
index 7d96ffa..69a83c9 100644
--- a/src/plugins/dbus-service/dbus-service.py
+++ b/src/plugins/dbus-service/dbus-service.py
@@ -27,265 +27,307 @@ from gi.repository import Totem
 import dbus, dbus.service
 from dbus.mainloop.glib import DBusGMainLoop
 
-class dbusservice(gobject.GObject, Peas.Activatable):
-	__gtype_name__ = 'dbusservice'
+class dbusservice (gobject.GObject, Peas.Activatable):
+    __gtype_name__ = 'dbusservice'
 
-	object = gobject.property(type = gobject.GObject)
+    object = gobject.property (type = gobject.GObject)
 
-	def do_activate(self):
-		DBusGMainLoop(set_as_default = True)
+    def do_activate (self):
+        DBusGMainLoop (set_as_default = True)
 
-		name = dbus.service.BusName ('org.mpris.Totem', bus = dbus.SessionBus ())
-		self.root = Root (name, self.object)
-		self.player = Player (name, self.object)
-		self.track_list = TrackList (name, self.object)
+        name = dbus.service.BusName ('org.mpris.Totem',
+                                     bus = dbus.SessionBus ())
+        self.root = Root (name, self.object)
+        self.player = Player (name, self.object)
+        self.track_list = TrackList (name, self.object)
 
-	def do_deactivate(self):
-		self.root.disconnect() # ensure we don't leak our paths on the bus
-		self.player.disconnect()
-		self.track_list.disconnect()
+    def do_deactivate (self):
+        self.root.disconnect () # ensure we don't leak our paths on the bus
+        self.player.disconnect ()
+        self.track_list.disconnect ()
 
 class Root (dbus.service.Object):
-	def __init__(self, name, totem):
-		dbus.service.Object.__init__ (self, name, '/')
-		self.totem = totem
-
-	def disconnect(self):
-		self.remove_from_connection(None, None)
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='s')
-	def Identity(self):
-		return self.totem.get_version()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='')
-	def Quit(self):
-		self.totem.action_exit()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='(qq)')
-	def MprisVersion(self):
-		return dbus.Struct((dbus.UInt16(1), dbus.UInt16(0)), signature='(qq)')
-
-class Player(dbus.service.Object):
-	def __init__(self, name, totem):
-		dbus.service.Object.__init__(self, name, '/Player')
-		self.totem = totem
-
-		self.null_metadata = {"year" : "", "tracknumber" : "", "location" : "",
-			"title" : "", "album" : "", "time" : "", "genre" : "", "artist" : ""}
-		self.old_metadata = self.null_metadata.copy()
-		self.current_metadata = self.null_metadata.copy()
-		self.old_caps = 64 # at startup, we can only support a playlist
-		self.old_status = (2, 0, 0, 0) # startup state
-
-		totem.connect("metadata-updated", self.do_update_metadata)
-		totem.connect("notify::playing", self.do_notify)
-		totem.connect("notify::seekable", self.do_notify)
-		totem.connect("notify::current-mrl", self.do_notify)
-
-	def do_update_metadata(self, totem, artist, title, album, num):
-		self.current_metadata = self.null_metadata.copy()
-		if title:
-			self.current_metadata["title"] = title
-		if artist:
-			self.current_metadata["artist"] = artist
-		if album:
-			self.current_metadata["album"] = album
-		if num:
-			self.current_metadata["tracknumber"] = num
-
-		if totem.is_playing():
-			self.track_change(self.current_metadata)
-
-	def do_notify(self, totem, status):
-		if totem.is_playing():
-			self.track_change(self.current_metadata)
-		else:
-			self.track_change(self.null_metadata)
-
-		status = self.calculate_status()
-		if status != self.old_status:
-			self.status_change(status)
-
-		caps = self.calculate_caps()
-		if caps != self.old_caps:
-			self.caps_change(caps)
-
-	def calculate_status(self):
-		if self.totem.is_playing():
-			playing_status = 0
-		elif self.totem.is_paused():
-			playing_status = 1
-		else:
-			playing_status = 2
-
-		if self.totem.action_remote_get_setting(Totem.RemoteSetting.SHUFFLE):
-			shuffle_status = 1
-		else:
-			shuffle_status = 0
-
-		if self.totem.action_remote_get_setting(Totem.RemoteSetting.REPEAT):
-			repeat_status = 1
-		else:
-			repeat_status = 0
-
-		return (
-			dbus.Int32(playing_status), # 0 = Playing, 1 = Paused, 2 = Stopped
-			dbus.Int32(self.totem.action_remote_get_setting(Totem.RemoteSetting.SHUFFLE)), # 0 = Playing linearly , 1 = Playing randomly
-			dbus.Int32(0), # 0 = Go to the next element once the current has finished playing , 1 = Repeat the current element 
-			dbus.Int32(self.totem.action_remote_get_setting(Totem.RemoteSetting.REPEAT)) # 0 = Stop playing once the last element has been played, 1 = Never give up playing 
-		)
-
-	def calculate_caps(self):
-		caps = 64 # we can always have a playlist
-		playlist_length = self.totem.get_playlist_length()
-		playlist_pos = self.totem.get_playlist_pos()
-
-		if playlist_pos < playlist_length - 1:
-			caps |= 1 << 0 # go next
-		if playlist_pos > 0:
-			caps |= 1 << 1 # go previous
-		if playlist_length > 0:
-			caps |= 1 << 2 # pause
-			caps |= 1 << 3 # play
-		if self.totem.is_seekable():
-			caps |= 1 << 4 # seek
-		if self.current_metadata != self.null_metadata:
-			caps |= 1 << 5 # get metadata
-
-		return caps
-
-	def track_change(self, metadata):
-		if self.old_metadata != metadata:
-			self.old_metadata = metadata.copy()
-			self.TrackChange(metadata)
-
-	def status_change(self, status):
-		if self.old_status != status:
-			self.old_status = status
-			self.StatusChange(status)
-
-	def caps_change(self, caps):
-		if self.old_caps != caps:
-			self.old_caps = caps
-			self.CapsChange(caps)
-
-	def disconnect(self):
-		self.TrackChange(self.null_metadata)
-		self.remove_from_connection(None, None)
-
-	@dbus.service.signal(dbus_interface = "org.freedesktop.MediaPlayer", signature='a{sv}')
-	def TrackChange(self, metadata):
-		pass
-
-	@dbus.service.signal(dbus_interface = "org.freedesktop.MediaPlayer", signature='(iiii)')
-	def StatusChange(self, status):
-		pass
-
-	@dbus.service.signal(dbus_interface = "org.freedesktop.MediaPlayer", signature='i')
-	def CapsChange(self, caps):
-		pass
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='')
-	def Next(self):
-		self.totem.action_next()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='')
-	def Prev(self):
-		self.totem.action_previous()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='')
-	def Pause(self):
-		self.totem.action_play_pause()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='')
-	def Stop(self):
-		self.totem.action_stop()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='')
-	def Play(self):
-		# If playing : rewind to the beginning of current track, else : start playing. 
-		if self.totem.is_playing():
-			self.totem.action_seek_time(0, False)
-		else:
-			self.totem.action_play()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='b', out_signature='')
-	def Repeat(self, value):
-		pass # we don't support repeating individual tracks
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='(iiii)')
-	def GetStatus(self):
-		status = self.calculate_status()
-		self.old_status = status
-		return dbus.Struct(status, signature='(iiii)')
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='a{sv}')
-	def GetMetadata(self):
-		return self.current_metadata
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='i')
-	def GetCaps(self):
-		caps = self.calculate_caps()
-		self.old_caps = caps
-		return caps
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='i', out_signature='')
-	def VolumeSet(self, volume):
-		self.totem.action_volume(volume / 100.0)
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='i')
-	def VolumeGet(self):
-		return dbus.Int32(self.totem.get_volume() * 100)
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='i', out_signature='')
-	def PositionSet(self, position):
-		self.totem.action_seek_time(position, False)
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='i')
-	def PositionGet(self):
-		return dbus.Int32(self.totem.props.current_time)
-
-class TrackList(dbus.service.Object):
-	def __init__(self, name, totem):
-		dbus.service.Object.__init__(self, name, '/TrackList')
-		self.totem = totem
-
-	def disconnect(self):
-		self.remove_from_connection(None, None)
-
-	@dbus.service.signal(dbus_interface = "org.freedesktop.MediaPlayer", signature='i')
-	def TrackListChange(self, length):
-		# TODO: we can't implement this until TotemPlaylist is exposed in the Python API
-		pass
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='i', out_signature='a{sv}')
-	def GetMetadata(self, pos):
-		# Since the API doesn't currently exist in Totem to get the rest of the metadata, we can only return the title
-		return { "title" : self.totem.get_title_at_playlist_pos(pos) }
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='i')
-	def GetCurrentTrack(self):
-		return self.totem.get_playlist_pos()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='', out_signature='i')
-	def GetLength(self):
-		return self.totem.get_playlist_length()
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='sb', out_signature='i')
-	def AddTrack(self, uri, play_immediately):
-		# We can't currently support !play_immediately
-		self.totem.add_to_playlist_and_play(str(uri), '', True)
-		return 0
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='i', out_signature='')
-	def DelTrack(self, pos):
-		# TODO: we need TotemPlaylist exposed by the Python API for this
-		pass
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='b', out_signature='')
-	def SetLoop(self, loop):
-		self.totem.action_remote_set_setting(Totem.RemoteSetting.REPEAT, loop)
-
-	@dbus.service.method(dbus_interface='org.freedesktop.MediaPlayer', in_signature='b', out_signature='')
-	def SetRandom(self, random):
-		self.totem.action_remote_set_setting(Totem.RemoteSetting.SHUFFLE, random)
+    def __init__ (self, name, totem):
+        dbus.service.Object.__init__ (self, name, '/')
+        self.totem = totem
+
+    def disconnect (self):
+        self.remove_from_connection (None, None)
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = 's')
+    def Identity (self):
+        return self.totem.get_version ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = '')
+    def Quit (self):
+        self.totem.action_exit ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = '(qq)')
+    def MprisVersion (self):
+        return dbus.Struct ((dbus.UInt16 (1), dbus.UInt16 (0)),
+                            signature = '(qq)')
+
+class Player (dbus.service.Object):
+    def __init__ (self, name, totem):
+        dbus.service.Object.__init__ (self, name, '/Player')
+        self.totem = totem
+
+        self.null_metadata = {
+            "year" : "", "tracknumber" : "", "location" : "",
+            "title" : "", "album" : "", "time" : "", "genre" : "",
+            "artist" : ""
+        }
+        self.old_metadata = self.null_metadata.copy ()
+        self.current_metadata = self.null_metadata.copy ()
+        self.old_caps = 64 # at startup, we can only support a playlist
+        self.old_status = (2, 0, 0, 0) # startup state
+
+        totem.connect ("metadata-updated", self.do_update_metadata)
+        totem.connect ("notify::playing", self.do_notify)
+        totem.connect ("notify::seekable", self.do_notify)
+        totem.connect ("notify::current-mrl", self.do_notify)
+
+    def do_update_metadata (self, totem, artist, title, album, num):
+        self.current_metadata = self.null_metadata.copy ()
+        if title:
+            self.current_metadata["title"] = title
+        if artist:
+            self.current_metadata["artist"] = artist
+        if album:
+            self.current_metadata["album"] = album
+        if num:
+            self.current_metadata["tracknumber"] = num
+
+        if totem.is_playing ():
+            self.track_change (self.current_metadata)
+
+    def do_notify (self, totem, status):
+        if totem.is_playing ():
+            self.track_change (self.current_metadata)
+        else:
+            self.track_change (self.null_metadata)
+
+        status = self.calculate_status ()
+        if status != self.old_status:
+            self.status_change (status)
+
+        caps = self.calculate_caps ()
+        if caps != self.old_caps:
+            self.caps_change (caps)
+
+    def calculate_status (self):
+        if self.totem.is_playing ():
+            playing_status = 0
+        elif self.totem.is_paused ():
+            playing_status = 1
+        else:
+            playing_status = 2
+
+        if self.totem.action_remote_get_setting (Totem.RemoteSetting.SHUFFLE):
+            shuffle_status = 1
+        else:
+            shuffle_status = 0
+
+        if self.totem.action_remote_get_setting (Totem.RemoteSetting.REPEAT):
+            repeat_status = 1
+        else:
+            repeat_status = 0
+
+        return (
+            # 0 = Playing, 1 = Paused, 2 = Stopped
+            dbus.Int32 (playing_status),
+            # 0 = Playing linearly , 1 = Playing randomly
+            dbus.Int32 (shuffle_status),
+            # 0 = Go to the next element once the current has finished playing,
+            # 1 = Repeat the current element
+            dbus.Int32 (0),
+            # 0 = Stop playing once the last element has been played,
+            # 1 = Never give up playing
+            dbus.Int32 (repeat_status)
+        )
+
+    def calculate_caps (self):
+        caps = 64 # we can always have a playlist
+        playlist_length = self.totem.get_playlist_length ()
+        playlist_pos = self.totem.get_playlist_pos ()
+
+        if playlist_pos < playlist_length - 1:
+            caps |= 1 << 0 # go next
+        if playlist_pos > 0:
+            caps |= 1 << 1 # go previous
+        if playlist_length > 0:
+            caps |= 1 << 2 # pause
+            caps |= 1 << 3 # play
+        if self.totem.is_seekable ():
+            caps |= 1 << 4 # seek
+        if self.current_metadata != self.null_metadata:
+            caps |= 1 << 5 # get metadata
+
+        return caps
+
+    def track_change (self, metadata):
+        if self.old_metadata != metadata:
+            self.old_metadata = metadata.copy ()
+            self.TrackChange (metadata)
+
+    def status_change (self, status):
+        if self.old_status != status:
+            self.old_status = status
+            self.StatusChange (status)
+
+    def caps_change (self, caps):
+        if self.old_caps != caps:
+            self.old_caps = caps
+            self.CapsChange (caps)
+
+    def disconnect (self):
+        self.TrackChange (self.null_metadata)
+        self.remove_from_connection (None, None)
+
+    @dbus.service.signal (dbus_interface = "org.freedesktop.MediaPlayer",
+                          signature = 'a{sv}')
+    def TrackChange (self, metadata):
+        pass
+
+    @dbus.service.signal (dbus_interface = "org.freedesktop.MediaPlayer",
+                          signature = '(iiii)')
+    def StatusChange (self, status):
+        pass
+
+    @dbus.service.signal (dbus_interface = "org.freedesktop.MediaPlayer",
+                          signature = 'i')
+    def CapsChange (self, caps):
+        pass
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = '')
+    def Next (self):
+        self.totem.action_next ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = '')
+    def Prev (self):
+        self.totem.action_previous ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = '')
+    def Pause (self):
+        self.totem.action_play_pause ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = '')
+    def Stop (self):
+        self.totem.action_stop ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = '')
+    def Play (self):
+        # If playing : rewind to the beginning of current track,
+        # else : start playing.
+        if self.totem.is_playing ():
+            self.totem.action_seek_time (0, False)
+        else:
+            self.totem.action_play ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = 'b', out_signature = '')
+    def Repeat (self, value):
+        pass # we don't support repeating individual tracks
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = '(iiii)')
+    def GetStatus (self):
+        status = self.calculate_status ()
+        self.old_status = status
+        return dbus.Struct (status, signature = '(iiii)')
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = 'a{sv}')
+    def GetMetadata (self):
+        return self.current_metadata
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = 'i')
+    def GetCaps (self):
+        caps = self.calculate_caps ()
+        self.old_caps = caps
+        return caps
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = 'i', out_signature = '')
+    def VolumeSet (self, volume):
+        self.totem.action_volume (volume / 100.0)
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = 'i')
+    def VolumeGet (self):
+        return dbus.Int32 (self.totem.get_volume () * 100)
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = 'i', out_signature = '')
+    def PositionSet (self, position):
+        self.totem.action_seek_time (position, False)
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = 'i')
+    def PositionGet (self):
+        return dbus.Int32 (self.totem.props.current_time)
+
+class TrackList (dbus.service.Object):
+    def __init__ (self, name, totem):
+        dbus.service.Object.__init__ (self, name, '/TrackList')
+        self.totem = totem
+
+    def disconnect (self):
+        self.remove_from_connection (None, None)
+
+    @dbus.service.signal (dbus_interface = "org.freedesktop.MediaPlayer",
+                          signature = 'i')
+    def TrackListChange (self, length):
+        # TODO: we can't implement this until TotemPlaylist is exposed in the
+        # Python API
+        pass
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = 'i', out_signature = 'a{sv}')
+    def GetMetadata (self, pos):
+        # Since the API doesn't currently exist in Totem to get the rest of the
+        # metadata, we can only return the title
+        return { "title" : self.totem.get_title_at_playlist_pos (pos) }
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = 'i')
+    def GetCurrentTrack (self):
+        return self.totem.get_playlist_pos ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = '', out_signature = 'i')
+    def GetLength (self):
+        return self.totem.get_playlist_length ()
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = 'sb', out_signature = 'i')
+    def AddTrack (self, uri, play_immediately):
+        # We can't currently support !play_immediately
+        self.totem.add_to_playlist_and_play (str (uri), '', True)
+        return 0
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = 'i', out_signature = '')
+    def DelTrack (self, pos):
+        # TODO: we need TotemPlaylist exposed by the Python API for this
+        pass
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = 'b', out_signature = '')
+    def SetLoop (self, loop):
+        self.totem.action_remote_set_setting (Totem.RemoteSetting.REPEAT, loop)
+
+    @dbus.service.method (dbus_interface='org.freedesktop.MediaPlayer',
+                          in_signature = 'b', out_signature = '')
+    def SetRandom (self, random):
+        self.totem.action_remote_set_setting (Totem.RemoteSetting.SHUFFLE,
+                                              random)
diff --git a/src/plugins/iplayer/iplayer.py b/src/plugins/iplayer/iplayer.py
index 26baea0..848664a 100644
--- a/src/plugins/iplayer/iplayer.py
+++ b/src/plugins/iplayer/iplayer.py
@@ -8,226 +8,254 @@ from gi.repository import Totem
 import iplayer2
 import threading
 
-gettext.textdomain("totem")
+gettext.textdomain ("totem")
 
 D_ = gettext.dgettext
 _ = gettext.gettext
 
 class IplayerPlugin (gobject.GObject, Peas.Activatable):
-	__gtype_name__ = 'IplayerPlugin'
+    __gtype_name__ = 'IplayerPlugin'
 
-	object = gobject.property(type = gobject.GObject)
-
-	def __init__ (self):
-		self.debug = False
-		self.totem = None
-		self.programme_download_lock = threading.Lock ()
-
-	def do_activate (self):
-		self.totem = self.object
-		# Build the interface
-		builder = Totem.plugin_load_interface ("iplayer", "iplayer.ui", True, self.totem.get_main_window (), self)
-		container = builder.get_object ('iplayer_vbox')
-
-		self.tv_tree_store = builder.get_object ('iplayer_programme_store')
-		programme_list = builder.get_object ('iplayer_programme_list')
-		programme_list.connect ('row-expanded', self._row_expanded_cb)
-		programme_list.connect ('row-activated', self._row_activated_cb)
-
-		container.show_all ()
-
-		self.tv = iplayer2.feed ('tv')
-
-		# Add the interface to Totem's sidebar
-		self.totem.add_sidebar_page ("iplayer", _(u"BBC iPlayer"), container)
-
-		# Get the channel category listings
-		self.populate_channel_list (self.tv, self.tv_tree_store)
-
-	def do_deactivate (self):
-		self.totem.remove_sidebar_page ("iplayer")
-
-	def populate_channel_list (self, feed, tree_store):
-		if self.debug:
-			print "Populating channel listâ?¦"
-
-		# Add all the channels as top-level rows in the tree store
-		channels = feed.channels ()
-		for channel_id, title in channels.items ():
-			parent_iter = tree_store.append (None, (title, channel_id, None))
-
-		# Add the channels' categories in a thread, since they each require a network request
-		parent_path = tree_store.get_path (parent_iter)
-		thread = PopulateChannelsThread (self, parent_path, feed, tree_store)
-		thread.start ()
-
-	def _populate_channel_list_cb (self, tree_store, parent_path, values):
-		# Callback from PopulateChannelsThread to add stuff to the tree store
-		if values == None:
-			self.totem.action_error (_(u'Error listing channel categories'), _(u'There was an unknown error getting the list of television channels available on BBC iPlayer.'))
-			return False
-
-		parent_iter = tree_store.get_iter (parent_path)
-		category_iter = tree_store.append (parent_iter, values)
-
-		# Append a dummy child row so that the expander's visible; we can
-		# then queue off the expander to load the programme listing for this category
-		tree_store.append (category_iter, [_(u'Loadingâ?¦'), None, None])
-
-		return False
-
-	def _row_expanded_cb (self, tree_view, row_iter, path):
-		tree_model = tree_view.get_model ()
-
-		if self.debug:
-			print "_row_expanded_cb called."
-
-		# We only care about the category level (level 1), and only when
-		# it has the "Loading..." placeholder child row
-		if get_iter_level (tree_model, row_iter) != 1 or tree_model.iter_n_children (row_iter) != 1:
-			return
-
-		# Populate it with programmes asynchronously
-		self.populate_programme_list (self.tv, tree_model, row_iter)
-
-	def _row_activated_cb (self, tree_view, path, view_column):
-		tree_store = tree_view.get_model ()
-		tree_iter = tree_store.get_iter (path)
-		if tree_iter == None:
-			return
-
-		mrl = tree_store.get_value (tree_iter, 2)
-
-		# Only allow programme rows to be activated, not channel or category rows
-		if mrl == None:
-			return
-
-		# Add the programme to the playlist and play it
-		self.totem.add_to_playlist_and_play (mrl, tree_store.get_value (tree_iter, 0), True)
-
-	def populate_programme_list (self, feed, tree_store, category_iter):
-		if self.debug:
-			print "Populating programme listâ?¦"
-
-		category_path = tree_store.get_path (category_iter)
-		thread = PopulateProgrammesThread (self, feed, tree_store, category_path)
-		thread.start ()
-
-	def _populate_programme_list_cb (self, tree_store, category_path, values, remove_placeholder):
-		# Callback from PopulateProgrammesThread to add stuff to the tree store
-		if values == None:
-			# Translators: the "programme feed" is the list of TV shows available to watch online
-			self.totem.action_error (_(u'Error getting programme feed'), _(u'There was an error getting the list of programmes for this channel and category combination.'))
-			return False
-
-		category_iter = tree_store.get_iter (category_path)
-		if category_iter != None:
-			tree_store.append (category_iter, values)
-
-		# Remove the placeholder row
-		children = tree_store.iter_children (category_iter)
-		if remove_placeholder and children != None:
-			tree_store.remove (children)
-
-		return False
+    object = gobject.property (type = gobject.GObject)
+
+    def __init__ (self):
+        self.debug = False
+        self.totem = None
+        self.programme_download_lock = threading.Lock ()
+
+    def do_activate (self):
+        self.totem = self.object
+        # Build the interface
+        builder = Totem.plugin_load_interface ("iplayer", "iplayer.ui", True,
+                                               self.totem.get_main_window (),
+                                               self)
+        container = builder.get_object ('iplayer_vbox')
+
+        self.tv_tree_store = builder.get_object ('iplayer_programme_store')
+        programme_list = builder.get_object ('iplayer_programme_list')
+        programme_list.connect ('row-expanded', self._row_expanded_cb)
+        programme_list.connect ('row-activated', self._row_activated_cb)
+
+        container.show_all ()
+
+        self.tv = iplayer2.feed ('tv')
+
+        # Add the interface to Totem's sidebar
+        self.totem.add_sidebar_page ("iplayer", _(u"BBC iPlayer"), container)
+
+        # Get the channel category listings
+        self.populate_channel_list (self.tv, self.tv_tree_store)
+
+    def do_deactivate (self):
+        self.totem.remove_sidebar_page ("iplayer")
+
+    def populate_channel_list (self, feed, tree_store):
+        if self.debug:
+            print "Populating channel listâ?¦"
+
+        # Add all the channels as top-level rows in the tree store
+        channels = feed.channels ()
+        for channel_id, title in channels.items ():
+            parent_iter = tree_store.append (None, (title, channel_id, None))
+
+        # Add the channels' categories in a thread, since they each require a
+        # network request
+        parent_path = tree_store.get_path (parent_iter)
+        thread = PopulateChannelsThread (self, parent_path, feed, tree_store)
+        thread.start ()
+
+    def _populate_channel_list_cb (self, tree_store, parent_path, values):
+        # Callback from PopulateChannelsThread to add stuff to the tree store
+        if values == None:
+            self.totem.action_error (_(u'Error listing channel categories'),
+                                     _(u'There was an unknown error getting '\
+                                        'the list of television channels '\
+                                        'available on BBC iPlayer.'))
+            return False
+
+        parent_iter = tree_store.get_iter (parent_path)
+        category_iter = tree_store.append (parent_iter, values)
+
+        # Append a dummy child row so that the expander's visible; we can
+        # then queue off the expander to load the programme listing for this
+        # category
+        tree_store.append (category_iter, [_(u'Loadingâ?¦'), None, None])
+
+        return False
+
+    def _row_expanded_cb (self, tree_view, row_iter, path):
+        tree_model = tree_view.get_model ()
+
+        if self.debug:
+            print "_row_expanded_cb called."
+
+        # We only care about the category level (level 1), and only when
+        # it has the "Loading..." placeholder child row
+        if (get_iter_level (tree_model, row_iter) != 1 or
+            tree_model.iter_n_children (row_iter) != 1):
+            return
+
+        # Populate it with programmes asynchronously
+        self.populate_programme_list (self.tv, tree_model, row_iter)
+
+    def _row_activated_cb (self, tree_view, path, view_column):
+        tree_store = tree_view.get_model ()
+        tree_iter = tree_store.get_iter (path)
+        if tree_iter == None:
+            return
+
+        mrl = tree_store.get_value (tree_iter, 2)
+
+        # Only allow programme rows to be activated, not channel or category
+        # rows
+        if mrl == None:
+            return
+
+        # Add the programme to the playlist and play it
+        title = tree_store.get_value (tree_iter, 0)
+        self.totem.add_to_playlist_and_play (mrl, title, True)
+
+    def populate_programme_list (self, feed, tree_store, category_iter):
+        if self.debug:
+            print "Populating programme listâ?¦"
+
+        category_path = tree_store.get_path (category_iter)
+        thread = PopulateProgrammesThread (self, feed, tree_store,
+                                           category_path)
+        thread.start ()
+
+    def _populate_programme_list_cb (self, tree_store, category_path, values,
+                                     remove_placeholder):
+        # Callback from PopulateProgrammesThread to add stuff to the tree store
+        if values == None:
+            # Translators: the "programme feed" is the list of TV shows
+            # available to watch online
+            self.totem.action_error (_(u'Error getting programme feed'),
+                                     _(u'There was an error getting the list '\
+                                        'of programmes for this channel and '\
+                                        'category combination.'))
+            return False
+
+        category_iter = tree_store.get_iter (category_path)
+        if category_iter != None:
+            tree_store.append (category_iter, values)
+
+        # Remove the placeholder row
+        children = tree_store.iter_children (category_iter)
+        if remove_placeholder and children != None:
+            tree_store.remove (children)
+
+        return False
 
 def get_iter_level (tree_model, tree_iter):
-	i = 0;
-	while True:
-		tree_iter = tree_model.iter_parent (tree_iter)
-		if tree_iter == None:
-			break
-		i += 1
-	return i
+    i = 0
+    while True:
+        tree_iter = tree_model.iter_parent (tree_iter)
+        if tree_iter == None:
+            break
+        i += 1
+    return i
 
 def category_name_to_id (category_name):
-	return category_name.lower ().replace (' ', '_').replace ('&', 'and')
+    return category_name.lower ().replace (' ', '_').replace ('&', 'and')
 
 class PopulateChannelsThread (threading.Thread):
-	# Class to populate the channel list from the Internet
-	def __init__ (self, plugin, parent_path, feed, tree_model):
-		self.plugin = plugin
-		self.feed = feed
-		self.tree_model = tree_model
-		threading.Thread.__init__ (self)
-
-	def run (self):
-		shown_error = False
-		tree_iter = self.tree_model.get_iter_first ()
-		while (tree_iter != None):
-			channel_id = self.tree_model.get_value (tree_iter, 1)
-			parent_path = self.tree_model.get_path (tree_iter)
-
-			try:
-				# Add this channel's categories as sub-rows
-				# We have to pass a path because the model could theoretically be modified
-				# while the idle function is waiting in the queue, invalidating an iter
-				for name, count in self.feed.get (channel_id).categories ():
-					category_id = category_name_to_id (name)
-					gobject.idle_add (self.plugin._populate_channel_list_cb, self.tree_model, parent_path, [name, category_id, None])
-			except:
-				# Only show the error once, rather than for each channel (it gets a bit grating)
-				if not shown_error:
-					gobject.idle_add (self.plugin._populate_channel_list_cb, self.tree_model, parent_path, None)
-					shown_error = True
-
-			tree_iter = self.tree_model.iter_next (tree_iter)
+    # Class to populate the channel list from the Internet
+    def __init__ (self, plugin, parent_path, feed, tree_model):
+        self.plugin = plugin
+        self.feed = feed
+        self.tree_model = tree_model
+        threading.Thread.__init__ (self)
+
+    def run (self):
+        shown_error = False
+        tree_iter = self.tree_model.get_iter_first ()
+        while (tree_iter != None):
+            channel_id = self.tree_model.get_value (tree_iter, 1)
+            parent_path = self.tree_model.get_path (tree_iter)
+
+            try:
+                # Add this channel's categories as sub-rows
+                # We have to pass a path because the model could theoretically
+                # be modified while the idle function is waiting in the queue,
+                # invalidating an iter
+                for name, count in self.feed.get (channel_id).categories ():
+                    category_id = category_name_to_id (name)
+                    gobject.idle_add (self.plugin._populate_channel_list_cb,
+                                      self.tree_model, parent_path,
+                                      [name, category_id, None])
+            except:
+                # Only show the error once, rather than for each channel
+                # (it gets a bit grating)
+                if not shown_error:
+                    gobject.idle_add (self.plugin._populate_channel_list_cb,
+                                      self.tree_model, parent_path, None)
+                    shown_error = True
+
+            tree_iter = self.tree_model.iter_next (tree_iter)
 
 class PopulateProgrammesThread (threading.Thread):
-	# Class to populate the programme list for a channel/category combination from the Internet
-	def __init__ (self, plugin, feed, tree_model, category_path):
-		self.plugin = plugin
-		self.feed = feed
-		self.tree_model = tree_model
-		self.category_path = category_path
-		threading.Thread.__init__ (self)
-
-	def run (self):
-		self.plugin.programme_download_lock.acquire ()
-
-		category_iter = self.tree_model.get_iter (self.category_path)
-		if category_iter == None:
-			gobject.idle_add (self.plugin._populate_programme_list_cb, self.tree_model, self.category_path, None, False)
-			self.plugin.programme_download_lock.release ()
-			return
-
-		category_id = self.tree_model.get_value (category_iter, 1)
-		parent_iter = self.tree_model.iter_parent (category_iter)
-		channel_id = self.tree_model.get_value (parent_iter, 1)
-
-		# Retrieve the programmes and return them
-		feed = self.feed.get (channel_id).get (category_id)
-		if feed == None:
-			gobject.idle_add (self.plugin._populate_programme_list_cb, self.tree_model, self.category_path, None, False)
-			self.plugin.programme_download_lock.release ()
-			return
-
-		# Get the programmes
-		try:
-			programmes = feed.list ()
-		except:
-			gobject.idle_add (self.plugin._populate_programme_list_cb, self.tree_model, self.category_path, None, False)
-			self.plugin.programme_download_lock.release ()
-			return
-
-		# Add the programmes to the tree store
-		remove_placeholder = True
-		for programme in programmes:
-			programme_item = programme.programme
-
-			# Get the media, which gives the stream URI.
-			# We go for mobile quality, since the higher-quality streams are RTMP-only
-			# which isn't currently supported by GStreamer or xine
-			# TODO: Use higher-quality streams once http://bugzilla.gnome.org/show_bug.cgi?id=566604 is fixed
-			media = programme_item.get_media_for ('mobile')
-			if media == None:
-				# Not worth displaying an error in the interface for this
-				print "Programme has no HTTP streams"
-				continue
-
-			gobject.idle_add (self.plugin._populate_programme_list_cb, self.tree_model, self.category_path,
-					  [programme.get_title (), programme.get_summary (), media.url],
-					  remove_placeholder)
-			remove_placeholder = False
-
-		self.plugin.programme_download_lock.release ()
+    # Class to populate the programme list for a channel/category combination
+    # from the Internet
+    def __init__ (self, plugin, feed, tree_model, category_path):
+        self.plugin = plugin
+        self.feed = feed
+        self.tree_model = tree_model
+        self.category_path = category_path
+        threading.Thread.__init__ (self)
+
+    def run (self):
+        self.plugin.programme_download_lock.acquire ()
+
+        category_iter = self.tree_model.get_iter (self.category_path)
+        if category_iter == None:
+            gobject.idle_add (self.plugin._populate_programme_list_cb,
+                              self.tree_model, self.category_path, None, False)
+            self.plugin.programme_download_lock.release ()
+            return
+
+        category_id = self.tree_model.get_value (category_iter, 1)
+        parent_iter = self.tree_model.iter_parent (category_iter)
+        channel_id = self.tree_model.get_value (parent_iter, 1)
+
+        # Retrieve the programmes and return them
+        feed = self.feed.get (channel_id).get (category_id)
+        if feed == None:
+            gobject.idle_add (self.plugin._populate_programme_list_cb,
+                              self.tree_model, self.category_path, None, False)
+            self.plugin.programme_download_lock.release ()
+            return
+
+        # Get the programmes
+        try:
+            programmes = feed.list ()
+        except:
+            gobject.idle_add (self.plugin._populate_programme_list_cb,
+                              self.tree_model, self.category_path, None, False)
+            self.plugin.programme_download_lock.release ()
+            return
+
+        # Add the programmes to the tree store
+        remove_placeholder = True
+        for programme in programmes:
+            programme_item = programme.programme
+
+            # Get the media, which gives the stream URI.
+            # We go for mobile quality, since the higher-quality streams are
+            # RTMP-only which isn't currently supported by GStreamer or xine
+            # TODO: Use higher-quality streams once
+            # http://bugzilla.gnome.org/show_bug.cgi?id=566604 is fixed
+            media = programme_item.get_media_for ('mobile')
+            if media == None:
+                # Not worth displaying an error in the interface for this
+                print "Programme has no HTTP streams"
+                continue
+
+            gobject.idle_add (self.plugin._populate_programme_list_cb,
+                              self.tree_model, self.category_path,
+                              [programme.get_title (), programme.get_summary (),
+                               media.url],
+                              remove_placeholder)
+            remove_placeholder = False
+
+        self.plugin.programme_download_lock.release ()
diff --git a/src/plugins/iplayer/iplayer2.py b/src/plugins/iplayer/iplayer2.py
index 6c5f3b4..665b070 100644
--- a/src/plugins/iplayer/iplayer2.py
+++ b/src/plugins/iplayer/iplayer2.py
@@ -16,15 +16,15 @@ import feedparser
 import listparser
 from BeautifulSoup import BeautifulStoneSoup
 
-gettext.textdomain("totem")
+gettext.textdomain ("totem")
 
 D_ = gettext.dgettext
 _ = gettext.gettext
 
-IMG_DIR = os.path.join(os.getcwd(), 'resources', 'media')
+IMG_DIR = os.path.join (os.getcwd (), 'resources', 'media')
 
 #try:
-#    logging.basicConfig(
+#    logging.basicConfig (
 #        filename='iplayer2.log',
 #        filemode='w',
 #        format='%(asctime)s %(levelname)4s %(message)s',
@@ -32,36 +32,36 @@ IMG_DIR = os.path.join(os.getcwd(), 'resources', 'media')
 #    )
 #except IOError:
 #    #print "iplayer2 logging to stdout"
-#    logging.basicConfig(
+#    logging.basicConfig (
 #        stream=sys.stdout,
 #        level=logging.DEBUG,
 #        format='iplayer2.py: %(asctime)s %(levelname)4s %(message)s',
 #    )
 # me want 2.5!!!
-def any(iterable):
-     for element in iterable:
-         if element:
-             return True
-     return False
+def any (iterable):
+    for element in iterable:
+        if element:
+            return True
+    return False
 
 
 # http://colinm.org/blog/on-demand-loading-of-flickr-photo-metadata
 # returns immediately for all previously-called functions
-def call_once(fn):
+def call_once (fn):
     called_by = {}
-    def result(self):
+    def result (self):
         if self in called_by:
             return
         called_by[self] = True
-        fn(self)
+        fn (self)
     return result
 
 # runs loader before decorated function
-def loaded_by(loader):
-    def decorator(fn):
-        def result(self, *args, **kwargs):
-            loader(self)
-            return fn(self, *args, **kwargs)
+def loaded_by (loader):
+    def decorator (fn):
+        def result (self, *args, **kwargs):
+            loader (self)
+            return fn (self, *args, **kwargs)
         return result
     return decorator
 
@@ -77,7 +77,7 @@ channels_tv_list = [
     ('bbc_hd', 'BBC HD'),
     ('bbc_alba', 'BBC Alba'),
 ]
-channels_tv = dict(channels_tv_list)
+channels_tv = dict (channels_tv_list)
 channels_national_radio_list = [
     ('bbc_radio_one', 'Radio 1'),
     ('bbc_1xtra', '1 Xtra'),
@@ -139,56 +139,64 @@ channels_local_radio_list = [
     ('bbc_radio_guernsey', 'BBC Guernsey'),
     ('bbc_radio_jersey', 'BBC Jersey')
 ]
+
+LOGO_URI = 'http://www.bbc.co.uk/englandcms/'
 channels_logos = {
-    'bbc_radio_cumbria': 'http://www.bbc.co.uk/englandcms/localradio/images/cumbria.gif',
-    'bbc_radio_newcastle': 'http://www.bbc.co.uk/englandcms/localradio/images/newcastle.gif',
-    'bbc_tees': 'http://www.bbc.co.uk/englandcms/localradio/images/tees.gif',
-    'bbc_radio_lancashire': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_lancs.gif',
-    'bbc_radio_merseyside': 'http://www.bbc.co.uk/englandcms/localradio/images/merseyside.gif',
-    'bbc_radio_manchester': os.path.join(IMG_DIR, 'bbc_local_radio.png'),
-    'bbc_radio_leeds': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_leeds.gif',
-    'bbc_radio_sheffield': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_sheffield.gif',
-    'bbc_radio_york': 'http://www.bbc.co.uk/englandcms/localradio/images/york.gif',
-    'bbc_radio_humberside': 'http://www.bbc.co.uk/radio/images/home/r-home-nation-regions.gif',
-    'bbc_radio_lincolnshire': 'http://www.bbc.co.uk/englandcms/localradio/images/lincs.gif',
-    'bbc_radio_nottingham': os.path.join(IMG_DIR, 'bbc_local_radio.png'),
-    'bbc_radio_leicester': 'http://www.bbc.co.uk/englandcms/localradio/images/leicester.gif',
-    'bbc_radio_derby': 'http://www.bbc.co.uk/englandcms/derby/images/rh_nav170_derby.gif',
-    'bbc_radio_stoke': 'http://www.bbc.co.uk/englandcms/localradio/images/stoke.gif',
-    'bbc_radio_shropshire': 'http://www.bbc.co.uk/englandcms/localradio/images/shropshire.gif',
-    'bbc_wm': os.path.join(IMG_DIR, 'bbc_local_radio.png'),
-    'bbc_radio_coventry_warwickshire': 'http://www.bbc.co.uk/englandcms/localradio/images/cov_warks.gif',
-    'bbc_radio_hereford_worcester': 'http://www.bbc.co.uk/englandcms/localradio/images/hereford_worcester.gif',
-    'bbc_radio_northampton': 'http://www.bbc.co.uk/englandcms/localradio/images/northampton.gif',
-    'bbc_three_counties_radio': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_3counties.gif',
-    'bbc_radio_cambridge': 'http://www.bbc.co.uk/englandcms/localradio/images/cambridgeshire.gif',
-    'bbc_radio_norfolk': 'http://www.bbc.co.uk/englandcms/localradio/images/norfolk.gif',
-    'bbc_radio_suffolk': 'http://www.bbc.co.uk/englandcms/localradio/images/suffolk.gif',
-    'bbc_radio_essex': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_essex.gif',
-    'bbc_london': os.path.join(IMG_DIR, 'bbc_local_radio.png'),
-    'bbc_radio_kent': 'http://www.bbc.co.uk/radio/images/home/r-home-nation-regions.gif',
-    'bbc_southern_counties_radio': os.path.join(IMG_DIR, 'bbc_local_radio.png'),
-    'bbc_radio_oxford': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_oxford.gif',
-    'bbc_radio_berkshire': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_berks.gif',
-    'bbc_radio_solent': 'http://www.bbc.co.uk/englandcms/localradio/images/solent.gif',
-    'bbc_radio_gloucestershire': 'http://www.bbc.co.uk/englandcms/localradio/images/gloucestershire.gif',
-    'bbc_radio_swindon': os.path.join(IMG_DIR, 'bbc_local_radio.png'),
-    'bbc_radio_wiltshire': os.path.join(IMG_DIR, 'bbc_local_radio.png'),
-    'bbc_radio_bristol': 'http://www.bbc.co.uk/englandcms/localradio/images/bristol.gif',
-    'bbc_radio_somerset_sound': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_somerset.gif',
-    'bbc_radio_devon': 'http://www.bbc.co.uk/englandcms/images/rh_nav170_devon.gif',
-    'bbc_radio_cornwall': 'http://www.bbc.co.uk/englandcms/localradio/images/cornwall.gif',
-    'bbc_radio_guernsey': 'http://www.bbc.co.uk/englandcms/localradio/images/guernsey.gif',
-    'bbc_radio_jersey': 'http://www.bbc.co.uk/englandcms/localradio/images/jersey.gif'
+    'bbc_radio_cumbria': LOGO_URI + 'localradio/images/cumbria.gif',
+    'bbc_radio_newcastle': LOGO_URI + 'localradio/images/newcastle.gif',
+    'bbc_tees': LOGO_URI + 'localradio/images/tees.gif',
+    'bbc_radio_lancashire': LOGO_URI + 'images/rh_nav170_lancs.gif',
+    'bbc_radio_merseyside': LOGO_URI + 'localradio/images/merseyside.gif',
+    'bbc_radio_manchester': os.path.join (IMG_DIR, 'bbc_local_radio.png'),
+    'bbc_radio_leeds': LOGO_URI + 'images/rh_nav170_leeds.gif',
+    'bbc_radio_sheffield': LOGO_URI + 'images/rh_nav170_sheffield.gif',
+    'bbc_radio_york': LOGO_URI + 'localradio/images/york.gif',
+    'bbc_radio_humberside': 'http://www.bbc.co.uk/radio/images/home/'\
+                            'r-home-nation-regions.gif',
+    'bbc_radio_lincolnshire': LOGO_URI + 'localradio/images/lincs.gif',
+    'bbc_radio_nottingham': os.path.join (IMG_DIR, 'bbc_local_radio.png'),
+    'bbc_radio_leicester': LOGO_URI + 'localradio/images/leicester.gif',
+    'bbc_radio_derby': LOGO_URI + 'derby/images/rh_nav170_derby.gif',
+    'bbc_radio_stoke': LOGO_URI + 'localradio/images/stoke.gif',
+    'bbc_radio_shropshire': LOGO_URI + 'localradio/images/shropshire.gif',
+    'bbc_wm': os.path.join (IMG_DIR, 'bbc_local_radio.png'),
+    'bbc_radio_coventry_warwickshire': LOGO_URI + 'localradio/images/'\
+                                                  'cov_warks.gif',
+    'bbc_radio_hereford_worcester': LOGO_URI + 'localradio/images/'\
+                                               'hereford_worcester.gif',
+    'bbc_radio_northampton': LOGO_URI + 'localradio/images/northampton.gif',
+    'bbc_three_counties_radio': LOGO_URI + 'images/rh_nav170_3counties.gif',
+    'bbc_radio_cambridge': LOGO_URI + 'localradio/images/cambridgeshire.gif',
+    'bbc_radio_norfolk': LOGO_URI + 'localradio/images/norfolk.gif',
+    'bbc_radio_suffolk': LOGO_URI + 'localradio/images/suffolk.gif',
+    'bbc_radio_essex': LOGO_URI + 'images/rh_nav170_essex.gif',
+    'bbc_london': os.path.join (IMG_DIR, 'bbc_local_radio.png'),
+    'bbc_radio_kent': 'http://www.bbc.co.uk/radio/images/home/'\
+                      'r-home-nation-regions.gif',
+    'bbc_southern_counties_radio': os.path.join (IMG_DIR,
+                                                 'bbc_local_radio.png'),
+    'bbc_radio_oxford': LOGO_URI + 'images/rh_nav170_oxford.gif',
+    'bbc_radio_berkshire': LOGO_URI + 'images/rh_nav170_berks.gif',
+    'bbc_radio_solent': LOGO_URI + 'localradio/images/solent.gif',
+    'bbc_radio_gloucestershire': LOGO_URI + 'localradio/images/'\
+                                            'gloucestershire.gif',
+    'bbc_radio_swindon': os.path.join (IMG_DIR, 'bbc_local_radio.png'),
+    'bbc_radio_wiltshire': os.path.join (IMG_DIR, 'bbc_local_radio.png'),
+    'bbc_radio_bristol': LOGO_URI + 'localradio/images/bristol.gif',
+    'bbc_radio_somerset_sound': LOGO_URI + 'images/rh_nav170_somerset.gif',
+    'bbc_radio_devon': LOGO_URI + 'images/rh_nav170_devon.gif',
+    'bbc_radio_cornwall': LOGO_URI + 'localradio/images/cornwall.gif',
+    'bbc_radio_guernsey': LOGO_URI + 'localradio/images/guernsey.gif',
+    'bbc_radio_jersey': LOGO_URI + 'localradio/images/jersey.gif'
 }
 
 
-channels_national_radio = dict(channels_national_radio_list)
-channels_local_radio = dict(channels_local_radio_list)
+channels_national_radio = dict (channels_national_radio_list)
+channels_local_radio = dict (channels_local_radio_list)
 channels_radio_list = channels_national_radio_list + channels_local_radio_list
-channels_radio = dict(channels_radio_list)
+channels_radio = dict (channels_radio_list)
 
-channels = dict(channels_tv_list + channels_radio_list)
+channels = dict (channels_tv_list + channels_radio_list)
 categories_list = [
     ('childrens', 'Children\'s'),
     ('comedy', 'Comedy'),
@@ -205,158 +213,171 @@ categories_list = [
     ('scotland', 'Scotland'),
     ('wales', 'Wales')
 ]
-categories = dict(categories_list)
-
-live_radio_stations = {'Radio 1': 'http://www.bbc.co.uk/radio1/wm_asx/aod/radio1_hi.asx',
-                       '1 Xtra':  'http://www.bbc.co.uk/1xtra/realmedia/1xtra_hi.asx',
-                       'Radio 2': 'http://www.bbc.co.uk/radio2/wm_asx/aod/radio2_hi.asx',
-                       'BBC 3': 'http://www.bbc.co.uk/radio3/wm_asx/aod/radio3_hi.asx',
-                       'BBC 4': 'http://www.bbc.co.uk/radio4/wm_asx/aod/radio4.asx',
-                       '5 Live':  'http://www.bbc.co.uk/fivelive/live/live.asx',
-                       '5 Live Sports Extra': 'http://www.bbc.co.uk/fivelive/live/live_sportsextra.asx',
-                       '6 Music': 'http://www.bbc.co.uk/6music/ram/6music_hi.asx',
-                       'BBC 7':   'http://www.bbc.co.uk/bbc7/realplayer/bbc7_hi.asx',
-                       'Asian Network': 'http://www.bbc.co.uk/asiannetwork/rams/asiannet_hi.asx',
-                       'Radio Scotland': 'http://www.bbc.co.uk/scotland/radioscotland/media/radioscotland.ram',
-                       'World Service': 'http://www.bbc.co.uk/worldservice/meta/tx/nb/live_eneuk_au_nb.asx',
-                       'BBC nan Gaidheal': 'http://www.bbc.co.uk/scotland/alba/media/live/radio_ng.ram',
-                       'BBC London': 'http://www.bbc.co.uk/england/realmedia/live/localradio/london.ram',
-                       'BBC Berkshire': 'http://www.bbc.co.uk/england/realmedia/live/localradio/radioberkshire.ram',
-                       'BBC Bristol': 'http://www.bbc.co.uk/england/realmedia/live/localradio/bristol.ram',
-                       'BBC Cambridgeshire': 'http://www.bbc.co.uk/england/realmedia/live/localradio/cambridgeshire.ram',
-                       'BBC Cornwall': 'http://www.bbc.co.uk/england/realmedia/live/localradio/cornwall.ram',
-                       'BBC Cumbria': 'http://www.bbc.co.uk/england/realmedia/live/localradio/cumbria.ram',
-                       'BBC Derby': 'http://www.bbc.co.uk/england/realmedia/live/localradio/derby.ram',
-                       'BBC Devon': 'http://www.bbc.co.uk/england/realmedia/live/localradio/devon.ram',
-                       'BBC Essex': 'http://www.bbc.co.uk/england/realmedia/live/localradio/essex.ram',
-                       'BBC Gloucestershire': 'http://www.bbc.co.uk/england/realmedia/live/localradio/gloucestershire.ram',
-                       'BBC Guernsey': 'http://www.bbc.co.uk/england/realmedia/live/localradio/guernsey.ram',
-                       'BBC Hereford/Worcester': 'http://www.bbc.co.uk/england/realmedia/live/localradio/herefordandworcester.ram',
-                       'BBC Humberside': 'http://www.bbc.co.uk/england/realmedia/live/localradio/humberside.ram',
-                       'BBC Jersey': 'http://www.bbc.co.uk/england/realmedia/live/localradio/jersey.ram',
-                       'BBC Kent': 'http://www.bbc.co.uk/england/realmedia/live/localradio/kent.ram',
-                       'BBC Lancashire': 'http://www.bbc.co.uk/england/realmedia/live/localradio/lancashire.ram',
-                       'BBC Leeds': 'http://www.bbc.co.uk/england/realmedia/live/localradio/leeds.ram',
-                       'BBC Leicester': 'http://www.bbc.co.uk/england/realmedia/live/localradio/leicester.ram',
-                       'BBC Lincolnshire': 'http://www.bbc.co.uk/england/realmedia/live/localradio/lincolnshire.ram',
-                       'BBC Manchester': 'http://www.bbc.co.uk/england/realmedia/live/localradio/manchester.ram',
-                       'BBC Merseyside': 'http://www.bbc.co.uk/england/realmedia/live/localradio/merseyside.ram',
-                       'BBC Newcastle': 'http://www.bbc.co.uk/england/realmedia/live/localradio/newcastle.ram',
-                       'BBC Norfolk': 'http://www.bbc.co.uk/england/realmedia/live/localradio/norfolk.ram',
-                       'BBC Northampton': 'http://www.bbc.co.uk/england/realmedia/live/localradio/northampton.ram',
-                       'BBC Nottingham': 'http://www.bbc.co.uk/england/realmedia/live/localradio/nottingham.ram',
-                       'BBC Oxford': 'http://www.bbc.co.uk/england/realmedia/live/localradio/radiooxford.ram',
-                       'BBC Sheffield': 'http://www.bbc.co.uk/england/realmedia/live/localradio/sheffield.ram',
-                       'BBC Shropshire': 'http://www.bbc.co.uk/england/realmedia/live/localradio/shropshire.ram',
-                       'BBC Solent': 'http://www.bbc.co.uk/england/realmedia/live/localradio/solent.ram',
-                       'BBC Somerset Sound': 'http://www.bbc.co.uk/england/realmedia/live/localradio/somerset.ram',
-                       'BBC Southern Counties Radio': 'http://www.bbc.co.uk/england/realmedia/live/localradio/southerncounties.ram',
-                       'BBC Stoke': 'http://www.bbc.co.uk/england/realmedia/live/localradio/stoke.ram',
-                       'BBC Suffolk': 'http://www.bbc.co.uk/england/realmedia/live/localradio/suffolk.ram',
-                       'BBC Swindon': 'http://www.bbc.co.uk/england/realmedia/live/localradio/swindon.ram',
-                       'BBC Three Counties Radio': 'http://www.bbc.co.uk/england/realmedia/live/localradio/threecounties.ram',
-                       'BBC Wiltshire': 'http://www.bbc.co.uk/england/realmedia/live/localradio/wiltshire.ram',
-                       'BBC York': 'http://www.bbc.co.uk/england/realmedia/live/localradio/york.ram',
-                       'BBC WM': 'http://www.bbc.co.uk/england/realmedia/live/localradio/wm.ram',
-                       'BBC Cymru': 'http://www.bbc.co.uk/cymru/live/rc-live.ram',
-                       'Radio Foyle': 'http://www.bbc.co.uk/northernireland/realmedia/rf-live.ram',
-                       'BBC Scotland': 'http://www.bbc.co.uk/scotland/radioscotland/media/radioscotland.ram',
-                       'BBC nan Gaidheal': 'http://www.bbc.co.uk/scotland/alba/media/live/radio_ng.ram',
-                       'BBC Ulster': 'http://www.bbc.co.uk/ni/realmedia/ru-live.ram',
-                       'BBC Wales': 'http://www.bbc.co.uk/wales/live/rwg2.ram',
-                       'BBC Tees': 'http://www.bbc.co.uk/england/realmedia/live/localradio/cleveland.ram',
-                       }
-live_webcams = {'Radio 1': 'http://www.bbc.co.uk/radio1/webcam/images/live/webcam.jpg',
-                '1 Xtra':  'http://www.bbc.co.uk/1xtra/webcam/live/1xtraa.jpg',
-                'Radio 2': 'http://www.bbc.co.uk/radio2/webcam/live/radio2.jpg',
-                '5 Live':  'http://www.bbc.co.uk/fivelive/inside/webcam/5Lwebcam1.jpg',
-                '6 Music': 'http://www.bbc.co.uk/6music/webcam/live/6music.jpg',
-                'Asian Network': 'http://www.bbc.co.uk/asiannetwork/webcams/birmingham.jpg'}
+categories = dict (categories_list)
+
+ENGLAND_RADIO_URI = 'http://www.bbc.co.uk/england/'
+live_radio_stations = {
+    'Radio 1': 'http://www.bbc.co.uk/radio1/wm_asx/aod/radio1_hi.asx',
+    '1 Xtra':  'http://www.bbc.co.uk/1xtra/realmedia/1xtra_hi.asx',
+    'Radio 2': 'http://www.bbc.co.uk/radio2/wm_asx/aod/radio2_hi.asx',
+    'BBC 3': 'http://www.bbc.co.uk/radio3/wm_asx/aod/radio3_hi.asx',
+    'BBC 4': 'http://www.bbc.co.uk/radio4/wm_asx/aod/radio4.asx',
+    '5 Live':  'http://www.bbc.co.uk/fivelive/live/live.asx',
+    '5 Live Sports Extra': 'http://www.bbc.co.uk/fivelive/live/'\
+                           'live_sportsextra.asx',
+    '6 Music': 'http://www.bbc.co.uk/6music/ram/6music_hi.asx',
+    'BBC 7':   'http://www.bbc.co.uk/bbc7/realplayer/bbc7_hi.asx',
+    'Asian Network': 'http://www.bbc.co.uk/asiannetwork/rams/asiannet_hi.asx',
+    'Radio Scotland': 'http://www.bbc.co.uk/scotland/radioscotland/media/'\
+                      'radioscotland.ram',
+    'World Service': 'http://www.bbc.co.uk/worldservice/meta/tx/nb/'\
+                     'live_eneuk_au_nb.asx',
+    'BBC nan Gaidheal': 'http://www.bbc.co.uk/scotland/alba/media/live/'\
+                        'radio_ng.ram',
+    'BBC London': ENGLAND_RADIO_URI + 'london.ram',
+    'BBC Berkshire': ENGLAND_RADIO_URI + 'radioberkshire.ram',
+    'BBC Bristol': ENGLAND_RADIO_URI + 'bristol.ram',
+    'BBC Cambridgeshire': ENGLAND_RADIO_URI + 'cambridgeshire.ram',
+    'BBC Cornwall': ENGLAND_RADIO_URI + 'cornwall.ram',
+    'BBC Cumbria': ENGLAND_RADIO_URI + 'cumbria.ram',
+    'BBC Derby': ENGLAND_RADIO_URI + 'derby.ram',
+    'BBC Devon': ENGLAND_RADIO_URI + 'devon.ram',
+    'BBC Essex': ENGLAND_RADIO_URI + 'essex.ram',
+    'BBC Gloucestershire': ENGLAND_RADIO_URI + 'gloucestershire.ram',
+    'BBC Guernsey': ENGLAND_RADIO_URI + 'guernsey.ram',
+    'BBC Hereford/Worcester': ENGLAND_RADIO_URI + 'herefordandworcester.ram',
+    'BBC Humberside': ENGLAND_RADIO_URI + 'humberside.ram',
+    'BBC Jersey': ENGLAND_RADIO_URI + 'jersey.ram',
+    'BBC Kent': ENGLAND_RADIO_URI + 'kent.ram',
+    'BBC Lancashire': ENGLAND_RADIO_URI + 'lancashire.ram',
+    'BBC Leeds': ENGLAND_RADIO_URI + 'leeds.ram',
+    'BBC Leicester': ENGLAND_RADIO_URI + 'leicester.ram',
+    'BBC Lincolnshire': ENGLAND_RADIO_URI + 'lincolnshire.ram',
+    'BBC Manchester': ENGLAND_RADIO_URI + 'manchester.ram',
+    'BBC Merseyside': ENGLAND_RADIO_URI + 'merseyside.ram',
+    'BBC Newcastle': ENGLAND_RADIO_URI + 'newcastle.ram',
+    'BBC Norfolk': ENGLAND_RADIO_URI + 'norfolk.ram',
+    'BBC Northampton': ENGLAND_RADIO_URI + 'northampton.ram',
+    'BBC Nottingham': ENGLAND_RADIO_URI + 'nottingham.ram',
+    'BBC Oxford': ENGLAND_RADIO_URI + 'radiooxford.ram',
+    'BBC Sheffield': ENGLAND_RADIO_URI + 'sheffield.ram',
+    'BBC Shropshire': ENGLAND_RADIO_URI + 'shropshire.ram',
+    'BBC Solent': ENGLAND_RADIO_URI + 'solent.ram',
+    'BBC Somerset Sound': ENGLAND_RADIO_URI + 'somerset.ram',
+    'BBC Southern Counties Radio': ENGLAND_RADIO_URI + 'southerncounties.ram',
+    'BBC Stoke': ENGLAND_RADIO_URI + 'stoke.ram',
+    'BBC Suffolk': ENGLAND_RADIO_URI + 'suffolk.ram',
+    'BBC Swindon': ENGLAND_RADIO_URI + 'swindon.ram',
+    'BBC Three Counties Radio': ENGLAND_RADIO_URI + 'threecounties.ram',
+    'BBC Wiltshire': ENGLAND_RADIO_URI + 'wiltshire.ram',
+    'BBC York': ENGLAND_RADIO_URI + 'york.ram',
+    'BBC WM': ENGLAND_RADIO_URI + 'wm.ram',
+    'BBC Cymru': 'http://www.bbc.co.uk/cymru/live/rc-live.ram',
+    'Radio Foyle': 'http://www.bbc.co.uk/northernireland/realmedia/rf-live.ram',
+    'BBC Scotland': 'http://www.bbc.co.uk/scotland/radioscotland/media/'\
+                    'radioscotland.ram',
+    'BBC nan Gaidheal': 'http://www.bbc.co.uk/scotland/alba/media/live/'\
+                        'radio_ng.ram',
+    'BBC Ulster': 'http://www.bbc.co.uk/ni/realmedia/ru-live.ram',
+    'BBC Wales': 'http://www.bbc.co.uk/wales/live/rwg2.ram',
+    'BBC Tees': ENGLAND_RADIO_URI + 'cleveland.ram',
+}
+
+live_webcams = {
+    'Radio 1': 'http://www.bbc.co.uk/radio1/webcam/images/live/webcam.jpg',
+    '1 Xtra':  'http://www.bbc.co.uk/1xtra/webcam/live/1xtraa.jpg',
+    'Radio 2': 'http://www.bbc.co.uk/radio2/webcam/live/radio2.jpg',
+    '5 Live':  'http://www.bbc.co.uk/fivelive/inside/webcam/5Lwebcam1.jpg',
+    '6 Music': 'http://www.bbc.co.uk/6music/webcam/live/6music.jpg',
+    'Asian Network': 'http://www.bbc.co.uk/asiannetwork/webcams/birmingham.jpg'
+}
 
 rss_cache = {}
 
 self_closing_tags = ['alternate', 'mediator']
 
-http = httplib2.Http()
+http = httplib2.Http ()
 
-re_selfclose = re.compile('<([a-zA-Z0-9]+)( ?.*)/>', re.M | re.S)
+re_selfclose = re.compile ('< ([a-zA-Z0-9]+) ( ?.*)/>', re.M | re.S)
 
-def fix_selfclosing(xml):
-    return re_selfclose.sub('<\\1\\2></\\1>', xml)
+def fix_selfclosing (xml):
+    return re_selfclose.sub ('<\\1\\2></\\1>', xml)
 
-def set_http_cache_dir(d):
-    fc = httplib2.FileCache(d)
+def set_http_cache_dir (d):
+    fc = httplib2.FileCache (d)
     http.cache = fc
 
-def set_http_cache(c):
+def set_http_cache (c):
     http.cache = c
 
-class NoItemsError(Exception):
-    def __init__(self, reason=None):
+class NoItemsError (Exception):
+    def __init__ (self, reason=None):
         self.reason = reason
 
-    def __str__(self):
+    def __str__ (self):
         reason = self.reason or _(u'<no reason given>')
         return _(u'Programme unavailable ("%s")') % (reason)
 
-class memoize(object):
-    def __init__(self, func):
+class memoize (object):
+    def __init__ (self, func):
         self.func = func
         self._cache = {}
-    def __call__(self, *args, **kwds):
+    def __call__ (self, *args, **kwds):
         key = args
         if kwds:
-            items = kwds.items()
-            items.sort()
-            key = key + tuple(items)
+            items = kwds.items ()
+            items.sort ()
+            key = key + tuple (items)
         if key in self._cache:
             return self._cache[key]
-        self._cache[key] = result = self.func(*args, **kwds)
+        self._cache[key] = result = self.func (*args, **kwds)
         return result
 
-def httpretrieve(url, filename):
-    _, data = http.request(url, 'GET')
-    f = open(filename, 'wb')
-    f.write(data)
-    f.close()
+def httpretrieve (url, filename):
+    _, data = http.request (url, 'GET')
+    f = open (filename, 'wb')
+    f.write (data)
+    f.close ()
 
-def httpget(url):
-    resp, data = http.request(url, 'GET')
+def httpget (url):
+    resp, data = http.request (url, 'GET')
     return data
 
-def parse_entry_id(entry_id):
+def parse_entry_id (entry_id):
     # tag:bbc.co.uk,2008:PIPS:b00808sc
-    r = re.compile('PIPS:([0-9a-z]{8})')
-    matches = r.findall(entry_id)
-    if not matches: return None
+    r = re.compile ('PIPS: ([0-9a-z]{8})')
+    matches = r.findall (entry_id)
+    if not matches:
+        return None
     return matches[0]
 
-class media(object):
-    def __init__(self, item, media_node):
+class media (object):
+    def __init__ (self, item, media_node):
         self.item = item
         self.href = None
         self.kind = None
         self.method = None
         self.width, self.height = None, None
-        self.read_media_node(media_node)
+        self.read_media_node (media_node)
 
     @property
-    def url(self):
+    def url (self):
         if self.connection_method == 'resolve':
-            #logging.info("Resolving URL %s", self.connection_href)
-            page = urllib2.urlopen(self.connection_href)
-            page.close()
-            url = page.geturl()
-            #logging.info("URL resolved to %s", url)
-            return page.geturl()
+            #logging.info ("Resolving URL %s", self.connection_href)
+            page = urllib2.urlopen (self.connection_href)
+            page.close ()
+            url = page.geturl ()
+            #logging.info ("URL resolved to %s", url)
+            return page.geturl ()
         else:
             return self.connection_href
 
     @property
-    def application(self):
+    def application (self):
         """
         The type of stream represented as a string.
-        i.e. 'captions', 'flashhigh', 'flashmed', 'flashwii', 'mobile', 'mp3' or 'real'
+        i.e. 'captions', 'flashhigh', 'flashmed', 'flashwii', 'mobile', 'mp3'
+        or 'real'
         """
         tep = {}
         tep['captions', 'application/ttaf+xml', None, 'http'] = 'captions'
@@ -367,28 +388,28 @@ class media(object):
         tep['audio', 'audio/mpeg', 'mp3', 'rtmp'] = 'mp3'
         tep['audio', 'audio/real', 'real', 'http'] = 'real'
         me = (self.kind, self.mimetype, self.encoding, self.connection_protocol)
-        return tep.get(me, None)
+        return tep.get (me, None)
 
-    def read_media_node(self, media, resolve=False):
+    def read_media_node (self, media, resolve=False):
         """
         Reads media info from a media XML node
         media: media node from BeautifulStoneSoup
         """
-        self.kind = media.get('kind')
-        self.mimetype = media.get('type')
-        self.encoding = media.get('encoding')
-        self.width, self.height = media.get('width'), media.get('height')
-        self.live = media.get('live') == 'true'
-
-        conn = media.find('connection')
-        self.connection_kind = conn.get('kind')
-        self.connection_live = conn.get('live') == 'true'
+        self.kind = media.get ('kind')
+        self.mimetype = media.get ('type')
+        self.encoding = media.get ('encoding')
+        self.width, self.height = media.get ('width'), media.get ('height')
+        self.live = media.get ('live') == 'true'
+
+        conn = media.find ('connection')
+        self.connection_kind = conn.get ('kind')
+        self.connection_live = conn.get ('live') == 'true'
         self.connection_protocol = None
         self.connection_href = None
         self.connection_method = None
 
         if self.connection_kind in ['http', 'sis']: # http
-            self.connection_href = conn.get('href')
+            self.connection_href = conn.get ('href')
             self.connection_protocol = 'http'
             if self.mimetype == 'video/mp4' and self.encoding == 'h264':
                 # iPhone, don't redirect or it goes to license failure page
@@ -399,35 +420,41 @@ class media(object):
                 self.connection_method = 'resolve'
         elif self.connection_kind in ['level3', 'akamai']: #rtmp
             self.connection_protocol = 'rtmp'
-            server = conn.get('server')
-            identifier = conn.get('identifier')
+            server = conn.get ('server')
+            identifier = conn.get ('identifier')
 
             if not self.connection_live:
-                #logging.error("No support for live streams!")
-                auth = conn.get('authstring')
-                params = dict(ip=server, server=server, auth=auth, identifier=identifier)
-                self.connection_href = "rtmp://%(ip)s:1935/ondemand?_fcs_vhost=%(server)s&auth=%(auth)s&aifp=v001&slist=%(identifier)s" % params
+                #logging.error ("No support for live streams!")
+                auth = conn.get ('authstring')
+                params = dict (ip=server, server=server, auth=auth,
+                               identifier=identifier)
+                self.connection_href = "rtmp://%(ip)s:1935/ondemand"\
+                                       "?_fcs_vhost=%(server)s&auth=%(auth)s"\
+                                       "&aifp=v001"\
+                                       "&slist=%(identifier)s" % params
         #else:
-        #    logging.error("connectionkind %s unknown", self.connection_kind)
+        #    logging.error ("connectionkind %s unknown", self.connection_kind)
 
         #if self.connection_protocol:
-        #    logging.info("conn protocol: %s - conn kind: %s - media type: %s - media encoding: %s" %
-        #                 (self.connection_protocol, self.connection_kind, self.mimetype, self.encoding))
-        #    logging.info("conn href: %s", self.connection_href)
+        #    logging.info ("conn protocol: %s - conn kind: %s - media type: "\
+        #                  "%s - media encoding: %s" %
+        #                 (self.connection_protocol, self.connection_kind,
+        #                  self.mimetype, self.encoding))
+        #    logging.info ("conn href: %s", self.connection_href)
 
     @property
-    def programme(self):
+    def programme (self):
         return self.item.programme
 
-class item(object):
+class item (object):
     """
-    Represents an iPlayer programme item. Most programmes consist of 2 such items,
-    (1) the ident, and (2) the actual programme. The item specifies the properties
-    of the media available, such as whether it's a radio/TV programme, if it's live,
-    signed, etc.
+    Represents an iPlayer programme item. Most programmes consist of 2 such
+    items, (1) the ident, and (2) the actual programme. The item specifies the
+    properties of the media available, such as whether it's a radio/TV
+    programme, if it's live, signed, etc.
     """
 
-    def __init__(self, programme, item_node):
+    def __init__ (self, programme, item_node):
         """
         programme: a programme object that represents the 'parent' of this item.
         item_node: an XML &lt;item&gt; node representing this item.
@@ -440,77 +467,80 @@ class item(object):
         self.alternate = None
         self.duration = ''
         self.medias = None
-        self.read_item_node(item_node)
+        self.read_item_node (item_node)
 
-    def read_item_node(self, node):
+    def read_item_node (self, node):
         """
         Reads the specified XML &lt;item&gt; node and sets this instance's
         properties.
         """
-        self.kind = node.get('kind')
-        self.identifier = node.get('identifier')
-        #logging.info('Found item: %s, %s', self.kind, self.identifier)
+        self.kind = node.get ('kind')
+        self.identifier = node.get ('identifier')
+        #logging.info ('Found item: %s, %s', self.kind, self.identifier)
         if self.kind in ['programme', 'radioProgramme']:
-            self.live = node.get('live') == 'true'
-            #self.title = node.get('title')
-            self.group = node.get('group')
-            self.duration = node.get('duration')
+            self.live = node.get ('live') == 'true'
+            #self.title = node.get ('title')
+            self.group = node.get ('group')
+            self.duration = node.get ('duration')
             #self.broadcast = node.broadcast
-            self.service = node.service and node.service.get('id')
-            self.masterbrand = node.masterbrand and node.masterbrand.get('id')
-            self.alternate = node.alternate and node.alternate.get('id')
+            self.service = node.service and node.service.get ('id')
+            self.masterbrand = node.masterbrand and node.masterbrand.get ('id')
+            self.alternate = node.alternate and node.alternate.get ('id')
             self.guidance = node.guidance
 
     @property
-    def is_radio(self):
+    def is_radio (self):
         """ True if this stream is a radio programme. """
         return self.kind == 'radioProgramme'
 
     @property
-    def is_tv(self):
+    def is_tv (self):
         """ True if this stream is a TV programme. """
         return self.kind == 'programme'
 
     @property
-    def is_ident(self):
+    def is_ident (self):
         """ True if this stream is an ident. """
         return self.kind == 'ident'
 
     @property
-    def is_programme(self):
+    def is_programme (self):
         """ True if this stream is a programme (TV or Radio). """
         return self.is_radio or self.is_tv
 
     @property
-    def is_live(self):
+    def is_live (self):
         """ True if this stream is being broadcast live. """
         return self.live
 
     @property
-    def is_signed(self):
+    def is_signed (self):
         """ True if this stream is 'signed' for the hard-of-hearing. """
         return self.alternate == 'signed'
 
     @property
-    def mediaselector_url(self):
-        return "http://www.bbc.co.uk/mediaselector/4/mtis/stream/%s"; % self.identifier
+    def mediaselector_url (self):
+        url = "http://www.bbc.co.uk/mediaselector/4/mtis/stream/%s";
+        return url % self.identifier
 
     @property
-    def media(self):
+    def media (self):
         """
         Returns a list of all the media available for this item.
         """
-        if self.medias: return self.medias
+        if self.medias:
+            return self.medias
         url = self.mediaselector_url
-        #logging.info("Stream XML URL: %s", str(url))
-        _, xml = http.request(url)
-        soup = BeautifulStoneSoup(xml, convertEntities = BeautifulStoneSoup.XML_ENTITIES)
-        medias = [media(self, m) for m in soup('media')]
-        #logging.info('Found media: %s', pformat(medias, indent=8))
+        #logging.info ("Stream XML URL: %s", str (url))
+        _, xml = http.request (url)
+        entities = BeautifulStoneSoup.XML_ENTITIES
+        soup = BeautifulStoneSoup (xml, convertEntities = entities)
+        medias = [media (self, m) for m in soup ('media')]
+        #logging.info ('Found media: %s', pformat (medias, indent=8))
         self.medias = medias
         return medias
 
-    def get_media_for(self, application):
+    def get_media_for (self, application):
         """
         Returns a media object for the given application type.
         """
@@ -519,155 +549,160 @@ class item(object):
             return None
         return medias[0]
 
-    def get_medias_for(self, applications):
+    def get_medias_for (self, applications):
         """
         Returns a dictionary of media objects for the given application types.
         """
         medias = [m for m in self.media if m.application in applications]
-        d = {}.fromkeys(applications)
+        d = {}.fromkeys (applications)
         for m in medias:
             d[m.application] = m
         return d
 
-class programme(object):
+class programme (object):
     """
-    Represents an individual iPlayer programme, as identified by an 8-letter PID,
-    and contains the programme title, subtitle, broadcast time and list of playlist
-    items (e.g. ident and then the actual programme.)
+    Represents an individual iPlayer programme, as identified by an 8-letter
+    PID, and contains the programme title, subtitle, broadcast time and list of
+    playlist items (e.g. ident and then the actual programme.)
     """
 
-    def __init__(self, pid):
+    def __init__ (self, pid):
         self.pid = pid
         self.meta = {}
         self._items = []
         self._related = []
 
     @call_once
-    def read_playlist(self):
-        #logging.info('Read playlist for %s...', self.pid)
-        self.parse_playlist(self.playlist)
+    def read_playlist (self):
+        #logging.info ('Read playlist for %s...', self.pid)
+        self.parse_playlist (self.playlist)
 
-    def get_playlist_xml(self):
+    def get_playlist_xml (self):
         """ Downloads and returns the XML for a PID from the iPlayer site. """
         try:
             url = self.playlist_url
-            #logging.info("Getting XML playlist at URL: %s", url)
-            r, xml = http.request(url, 'GET')
+            #logging.info ("Getting XML playlist at URL: %s", url)
+            r, xml = http.request (url, 'GET')
             return xml
         except SocketTimeoutError:
-            #logging.error("Timed out trying to download programme XML")
+            #logging.error ("Timed out trying to download programme XML")
             raise
 
-    def parse_playlist(self, xml):
-        #logging.info('Parsing playlist XML... %s', xml)
-        #xml.replace('<summary/>', '<summary></summary>')
-        #xml = fix_selfclosing(xml)
+    def parse_playlist (self, xml):
+        #logging.info ('Parsing playlist XML... %s', xml)
+        #xml.replace ('<summary/>', '<summary></summary>')
+        #xml = fix_selfclosing (xml)
 
-        soup = BeautifulStoneSoup(xml, selfClosingTags=self_closing_tags, convertEntities = BeautifulStoneSoup.XML_ENTITIES)
+        entities = BeautifulStoneSoup.XML_ENTITIES
+        soup = BeautifulStoneSoup (xml, selfClosingTags=self_closing_tags,
+                                   convertEntities = entities)
 
         self.meta = {}
         self._items = []
         self._related = []
 
-        #logging.info('  Found programme: %s', soup.playlist.title.string)
+        #logging.info ('  Found programme: %s', soup.playlist.title.string)
         self.meta['title'] = soup.playlist.title.string.encode ('utf-8')
         self.meta['summary'] = soup.playlist.summary.string.encode ('utf-8')
         self.meta['updated'] = soup.playlist.updated.string
 
         if soup.playlist.noitems:
-            #logging.info('No playlist items: %s', soup.playlist.noitems.get('reason'))
-            self.meta['reason'] = soup.playlist.noitems.get('reason')
+            #logging.info ('No playlist items: %s',
+            #              soup.playlist.noitems.get ('reason'))
+            self.meta['reason'] = soup.playlist.noitems.get ('reason')
 
-        self._items = [item(self, i) for i in soup('item')]
+        self._items = [item (self, i) for i in soup ('item')]
         #for i in self._items:
         #    print i, i.alternate , " ",
         #print
 
-        rId = re.compile('concept_pid:([a-z0-9]{8})')
-        for link in soup('relatedlink'):
+        rId = re.compile ('concept_pid: ([a-z0-9]{8})')
+        for link in soup ('relatedlink'):
             i = {}
             i['title'] = link.title.string
             #i['summary'] = item.summary # FIXME looks like a bug in BSS
-            i['pid'] = (rId.findall(link.id.string) or [None])[0]
-            i['programme'] = programme(i['pid'])
-            self._related.append(i)
+            i['pid'] = (rId.findall (link.id.string) or [None])[0]
+            i['programme'] = programme (i['pid'])
+            self._related.append (i)
 
-    def get_thumbnail(self, size='large', tvradio='tv'):
+    def get_thumbnail (self, size='large', tvradio='tv'):
         """
         Returns the URL of a thumbnail.
         size: '640x360'/'biggest'/'largest' or '512x288'/'big'/'large' or None
         """
+        url_format = "http://www.bbc.co.uk/iplayer/images/episode/%s_%d_%d.jpg";
+
         if size in ['640x360', '640x', 'x360', 'biggest', 'largest']:
-            return "http://www.bbc.co.uk/iplayer/images/episode/%s_640_360.jpg"; % (self.pid)
+            return url_format % (self.pid, 640, 360)
         elif size in ['512x288', '512x', 'x288', 'big', 'large']:
-            return "http://www.bbc.co.uk/iplayer/images/episode/%s_512_288.jpg"; % (self.pid)
+            return url_format % (self.pid, 512, 288)
         elif size in ['178x100', '178x', 'x100', 'small']:
-            return "http://www.bbc.co.uk/iplayer/images/episode/%s_178_100.jpg"; % (self.pid)
+            return url_format % (self.pid, 178, 100)
         elif size in ['150x84', '150x', 'x84', 'smallest']:
-            return "http://www.bbc.co.uk/iplayer/images/episode/%s_150_84.jpg"; % (self.pid)
+            return url_format % (self.pid, 150, 84)
         else:
-            return os.path.join(IMG_DIR, '%s.png' % tvradio)
+            return os.path.join (IMG_DIR, '%s.png' % tvradio)
 
 
-    def get_url(self):
+    def get_url (self):
         """
         Returns the programmes episode page.
         """
         return "http://www.bbc.co.uk/iplayer/episode/%s"; % (self.pid)
 
     @property
-    def playlist_url(self):
+    def playlist_url (self):
         return "http://www.bbc.co.uk/iplayer/playlist/%s"; % self.pid
 
     @property
-    def playlist(self):
-        return self.get_playlist_xml()
+    def playlist (self):
+        return self.get_playlist_xml ()
 
-    def get_updated(self):
+    def get_updated (self):
         return self.meta['updated']
 
-    @loaded_by(read_playlist)
-    def get_title(self):
+    @loaded_by (read_playlist)
+    def get_title (self):
         return self.meta['title']
 
-    @loaded_by(read_playlist)
-    def get_summary(self):
+    @loaded_by (read_playlist)
+    def get_summary (self):
         return self.meta['summary']
 
-    @loaded_by(read_playlist)
-    def get_related(self):
+    @loaded_by (read_playlist)
+    def get_related (self):
         return self._related
 
-    @loaded_by(read_playlist)
-    def get_items(self):
+    @loaded_by (read_playlist)
+    def get_items (self):
         if not self._items:
-            raise NoItemsError(self.meta['reason'])
+            raise NoItemsError (self.meta['reason'])
         return self._items
 
     @property
-    def programme(self):
+    def programme (self):
         for i in self.items:
             if i.is_programme:
                 return i
         return None
 
-    title = property(get_title)
-    summary = property(get_summary)
-    updated = property(get_updated)
-    thumbnail = property(get_thumbnail)
-    related = property(get_related)
-    items = property(get_items)
+    title = property (get_title)
+    summary = property (get_summary)
+    updated = property (get_updated)
+    thumbnail = property (get_thumbnail)
+    related = property (get_related)
+    items = property (get_items)
 
-#programme = memoize(programme)
+#programme = memoize (programme)
 
 
-class programme_simple(object):
+class programme_simple (object):
     """
-    Represents an individual iPlayer programme, as identified by an 8-letter PID,
-    and contains the programme pid, title, subtitle etc
+    Represents an individual iPlayer programme, as identified by an 8-letter
+    PID, and contains the programme pid, title, subtitle etc
     """
 
-    def __init__(self, pid, entry):
+    def __init__ (self, pid, entry):
         self.pid = pid
         self.meta = {}
         self.meta['title'] = entry.title
@@ -676,93 +711,96 @@ class programme_simple(object):
         self.categories = []
         for c in entry.categories:
             if c != 'TV':
-                self.categories.append(c.rstrip())
+                self.categories.append (c.rstrip ())
         self._items = []
         self._related = []
 
     @call_once
-    def read_playlist(self):
+    def read_playlist (self):
         pass
 
-    def get_playlist_xml(self):
+    def get_playlist_xml (self):
         pass
 
-    def parse_playlist(self, xml):
+    def parse_playlist (self, xml):
         pass
 
-    def get_thumbnail(self, size='large', tvradio='tv'):
+    def get_thumbnail (self, size='large', tvradio='tv'):
         """
         Returns the URL of a thumbnail.
         size: '640x360'/'biggest'/'largest' or '512x288'/'big'/'large' or None
         """
+        url_format = "http://www.bbc.co.uk/iplayer/images/episode/%s_%d_%d.jpg";
 
         if size in ['640x360', '640x', 'x360', 'biggest', 'largest']:
-            return "http://www.bbc.co.uk/iplayer/images/episode/%s_640_360.jpg"; % (self.pid)
+            return url_format % (self.pid, 640, 360)
         elif size in ['512x288', '512x', 'x288', 'big', 'large']:
-            return "http://www.bbc.co.uk/iplayer/images/episode/%s_512_288.jpg"; % (self.pid)
+            return url_format % (self.pid, 512, 288)
         elif size in ['178x100', '178x', 'x100', 'small']:
-            return "http://www.bbc.co.uk/iplayer/images/episode/%s_178_100.jpg"; % (self.pid)
+            return url_format % (self.pid, 178, 100)
         elif size in ['150x84', '150x', 'x84', 'smallest']:
-            return "http://www.bbc.co.uk/iplayer/images/episode/%s_150_84.jpg"; % (self.pid)
+            return url_format % (self.pid, 150, 84)
         else:
-            return os.path.join(IMG_DIR, '%s.png' % tvradio)
+            return os.path.join (IMG_DIR, '%s.png' % tvradio)
 
 
-    def get_url(self):
+    def get_url (self):
         """
         Returns the programmes episode page.
         """
         return "http://www.bbc.co.uk/iplayer/episode/%s"; % (self.pid)
 
     @property
-    def playlist_url(self):
+    def playlist_url (self):
         return "http://www.bbc.co.uk/iplayer/playlist/%s"; % self.pid
 
     @property
-    def playlist(self):
-        return self.get_playlist_xml()
+    def playlist (self):
+        return self.get_playlist_xml ()
 
-    def get_updated(self):
+    def get_updated (self):
         return self.meta['updated']
 
-    @loaded_by(read_playlist)
-    def get_title(self):
+    @loaded_by (read_playlist)
+    def get_title (self):
         return self.meta['title']
 
-    @loaded_by(read_playlist)
-    def get_summary(self):
+    @loaded_by (read_playlist)
+    def get_summary (self):
         return self.meta['summary']
 
-    @loaded_by(read_playlist)
-    def get_related(self):
+    @loaded_by (read_playlist)
+    def get_related (self):
         return self._related
 
-    @loaded_by(read_playlist)
-    def get_items(self):
+    @loaded_by (read_playlist)
+    def get_items (self):
         if not self._items:
-            raise NoItemsError(self.meta['reason'])
+            raise NoItemsError (self.meta['reason'])
         return self._items
 
     @property
-    def programme(self):
+    def programme (self):
         for i in self.items:
             if i.is_programme:
                 return i
         return None
 
-    title = property(get_title)
-    summary = property(get_summary)
-    updated = property(get_updated)
-    thumbnail = property(get_thumbnail)
-    related = property(get_related)
-    items = property(get_items)
+    title = property (get_title)
+    summary = property (get_summary)
+    updated = property (get_updated)
+    thumbnail = property (get_thumbnail)
+    related = property (get_related)
+    items = property (get_items)
 
 
-class feed(object):
-    def __init__(self, tvradio=None, channel=None, category=None, subcategory=None, atoz=None, searchterm=None):
+class feed (object):
+    def __init__ (self, tvradio = None, channel = None, category = None,
+                  subcategory = None, atoz = None, searchterm = None):
         """
         Creates a feed for the specified channel/category/whatever.
-        tvradio: type of channel - 'tv' or 'radio'. If a known channel is specified, use 'auto'.
+        tvradio: type of channel - 'tv' or 'radio'. If a known channel is
+                 specified, use 'auto'.
         channel: name of channel, e.g. 'bbc_one'
         category: category name, e.g. 'drama'
         subcategory: subcategory name, e.g. 'period_drama'
@@ -770,13 +808,15 @@ class feed(object):
         """
         if tvradio == 'auto':
             if not channel and not searchterm:
-                raise Exception, "Must specify channel or searchterm when using 'auto'"
+                raise Exception, "Must specify channel or searchterm when "\
+                                 "using 'auto'"
             elif channel in channels_tv:
                 self.tvradio = 'tv'
             elif channel in channels_radio:
                 self.tvradio = 'radio'
             else:
-                raise Exception, "TV channel '%s' not recognised." % self.channel
+                raise Exception, "TV channel '%s' not "\
+                                 "recognised." % self.channel
 
         elif tvradio in ['tv', 'radio']:
             self.tvradio = tvradio
@@ -788,12 +828,15 @@ class feed(object):
         self.atoz = atoz
         self.searchterm = searchterm
 
-    def create_url(self, listing):
+    def create_url (self, listing):
         """
         <channel>/['list'|'popular'|'highlights']
-        'categories'/<category>(/<subcategory>)(/['tv'/'radio'])/['list'|'popular'|'highlights']
+        'categories'/<category> (/<subcategory>) \
+            (/['tv'/'radio'])/['list'|'popular'|'highlights']
         """
-        assert listing in ['list', 'popular', 'highlights'], "Unknown listing type"
+        assert listing in ['list', 'popular', 'highlights'], "Unknown "\
+                                                             "listing type"
+
         if self.searchterm:
             path = ['search']
             if self.tvradio:
@@ -819,205 +862,219 @@ class feed(object):
             assert listing != 'list', "Can't list at tv/radio level'"
             path = [listing, self.tvradio]
 
-        return "http://feeds.bbc.co.uk/iplayer/"; + '/'.join(path)
+        return "http://feeds.bbc.co.uk/iplayer/"; + '/'.join (path)
 
-    def get_name(self, separator=' '):
+    def get_name (self, separator=' '):
         """
-        A readable title for this feed, e.g. 'BBC One' or 'TV Drama' or 'BBC One Drama'
-        separator: string to separate name parts with, defaults to ' '. Use None to return a list (e.g. ['TV', 'Drama']).
+        A readable title for this feed, e.g. 'BBC One' or 'TV Drama' or
+        'BBC One Drama'
+        separator: string to separate name parts with, defaults to ' '.
+                   Use None to return a list (e.g. ['TV', 'Drama']).
         """
         path = []
 
         # TODO: This is not i18n-friendly whatsoever
         # if got a channel, don't need tv/radio distinction
         if self.channel:
-            assert self.channel in channels_tv or self.channel in channels_radio, 'Unknown channel'
+            assert (self.channel in channels_tv or
+                    self.channel in channels_radio), 'Unknown channel'
             #print self.tvradio
             if self.tvradio == 'tv':
-                path.append(channels_tv.get(self.channel, '(TV)'))
+                path.append (channels_tv.get (self.channel, ' (TV)'))
             else:
-                path.append(channels_radio.get(self.channel, '(Radio)'))
+                path.append (channels_radio.get (self.channel, ' (Radio)'))
         elif self.tvradio:
             # no channel
             medium = 'TV'
-            if self.tvradio == 'radio': medium = 'Radio'
-            path.append(medium)
+            if self.tvradio == 'radio':
+                medium = 'Radio'
+            path.append (medium)
 
         if self.searchterm:
             path += ['Search results for %s' % self.searchterm]
 
         if self.category:
             assert self.category in categories, 'Unknown category'
-            path.append(categories.get(self.category, '(Category)'))
+            path.append (categories.get (self.category, ' (Category)'))
 
         if self.atoz:
-            path.append("beginning with %s" % self.atoz.upper())
+            path.append ("beginning with %s" % self.atoz.upper ())
 
         if separator != None:
-            return separator.join(path)
+            return separator.join (path)
         else:
             return path
 
-    def channels(self):
+    def channels (self):
         """
         Return a list of available channels.
         """
-        if self.channel: return None
-        if self.tvradio == 'tv': return channels_tv
-        if self.tvradio == 'radio': return channels_radio
+        if self.channel:
+            return None
+        if self.tvradio == 'tv':
+            return channels_tv
+        if self.tvradio == 'radio':
+            return channels_radio
         return None
 
-    def channels_feed(self):
+    def channels_feed (self):
         """
         Return a list of available channels as a list of feeds.
         """
         if self.channel:
-            #logging.warning("%s doesn\'t have any channels!", self.channel)
+            #logging.warning ("%s doesn\'t have any channels!", self.channel)
             return None
         if self.tvradio == 'tv':
-            return [feed('tv', channel=ch) for (ch, title) in channels_tv_list]
+            return [feed ('tv', channel = ch)
+                    for (ch, title) in channels_tv_list]
         if self.tvradio == 'radio':
-            return [feed('radio', channel=ch) for (ch, title) in channels_radio_list]
+            return [feed ('radio', channel = ch)
+                    for (ch, title) in channels_radio_list]
         return None
 
-    def subcategories(self):
-        raise NotImplementedError('Sub-categories not yet supported')
+    def subcategories (self):
+        raise NotImplementedError ('Sub-categories not yet supported')
 
     @classmethod
-    def is_atoz(self, letter):
+    def is_atoz (self, letter):
         """
-        Return False if specified letter is not a valid 'A to Z' directory entry.
-        Otherwise returns the directory name.
+        Return False if specified letter is not a valid 'A to Z' directory
+        entry. Otherwise returns the directory name.
 
-        >>> feed.is_atoz('a'), feed.is_atoz('z')
+        >>> feed.is_atoz ('a'), feed.is_atoz ('z')
         ('a', 'z')
-        >>> feed.is_atoz('0'), feed.is_atoz('9')
+        >>> feed.is_atoz ('0'), feed.is_atoz ('9')
         ('0-9', '0-9')
-        >>> feed.is_atoz('123'), feed.is_atoz('abc')
+        >>> feed.is_atoz ('123'), feed.is_atoz ('abc')
         (False, False)
-        >>> feed.is_atoz('big british castle'), feed.is_atoz('')
+        >>> feed.is_atoz ('big british castle'), feed.is_atoz ('')
         (False, False)
         """
-        l = letter.lower()
-        if len(l) != 1 and l != '0-9':
+        l = letter.lower ()
+        if len (l) != 1 and l != '0-9':
             return False
-        if l in '0123456789': l = "0-9"
+        if l in '0123456789':
+            l = "0-9"
         if l not in 'abcdefghijklmnopqrstuvwxyz0-9':
             return False
         return l
 
-    def sub(self, *args, **kwargs):
+    def sub (self, *args, **kwargs):
         """
         Clones this feed, altering the specified parameters.
 
-        >>> feed('tv').sub(channel='bbc_one').channel
+        >>> feed ('tv').sub (channel='bbc_one').channel
         'bbc_one'
-        >>> feed('tv', channel='bbc_one').sub(channel='bbc_two').channel
+        >>> feed ('tv', channel='bbc_one').sub (channel='bbc_two').channel
         'bbc_two'
-        >>> feed('tv', channel='bbc_one').sub(category='drama').category
+        >>> feed ('tv', channel='bbc_one').sub (category='drama').category
         'drama'
-        >>> feed('tv', channel='bbc_one').sub(channel=None).channel
+        >>> feed ('tv', channel='bbc_one').sub (channel=None).channel
         >>>
         """
-        d = self.__dict__.copy()
-        d.update(kwargs)
-        return feed(**d)
+        d = self.__dict__.copy ()
+        d.update (kwargs)
+        return feed (**d)
 
-    def get(self, subfeed):
+    def get (self, subfeed):
         """
         Returns a child/subfeed of this feed.
         child: can be channel/cat/subcat/letter, e.g. 'bbc_one'
         """
         if self.channel:
-            return self.sub(category=subfeed)
+            return self.sub (category = subfeed)
         elif self.category:
             # no children: TODO support subcategories
             return None
-        elif self.is_atoz(subfeed):
-            return self.sub(atoz=self.is_atoz(subfeed))
+        elif self.is_atoz (subfeed):
+            return self.sub (atoz=self.is_atoz (subfeed))
         else:
-            if subfeed in channels_tv: return feed('tv', channel=subfeed)
-            if subfeed in channels_radio: return feed('radio', channel=subfeed)
+            if subfeed in channels_tv:
+                return feed ('tv', channel = subfeed)
+            if subfeed in channels_radio:
+                return feed ('radio', channel = subfeed)
         # TODO handle properly oh pants
         return None
 
     @classmethod
-    def read_rss(self, url):
-        #logging.info('Read RSS: %s', url)
+    def read_rss (self, url):
+        #logging.info ('Read RSS: %s', url)
         if url not in rss_cache:
-            #logging.info('Feed URL not in cache, requesting...')
-            xml = httpget(url)
-            progs = listparser.parse(xml)
-            if not progs: return []
+            #logging.info ('Feed URL not in cache, requesting...')
+            xml = httpget (url)
+            progs = listparser.parse (xml)
+            if not progs:
+                return []
             d = []
             for entry in progs.entries:
-                pid = parse_entry_id(entry.id)
-                p = programme(pid)
-                d.append(p)
-            #logging.info('Found %d entries', len(d))
+                pid = parse_entry_id (entry.id)
+                p = programme (pid)
+                d.append (p)
+            #logging.info ('Found %d entries', len (d))
             rss_cache[url] = d
         #else:
-        #    logging.info('RSS found in cache')
+        #    logging.info ('RSS found in cache')
         return rss_cache[url]
 
-    def popular(self):
-        return self.read_rss(self.create_url('popular'))
+    def popular (self):
+        return self.read_rss (self.create_url ('popular'))
 
-    def highlights(self):
-        return self.read_rss(self.create_url('highlights'))
+    def highlights (self):
+        return self.read_rss (self.create_url ('highlights'))
 
-    def list(self):
-        return self.read_rss(self.create_url('list'))
+    def list (self):
+        return self.read_rss (self.create_url ('list'))
 
-    def categories(self):
+    def categories (self):
         # quick and dirty category extraction and count
-        xmlURL = self.create_url('list')
-        xml    = httpget(xmlURL)
-        cat    = re.findall( "<category .*term=\"(.*?)\"", xml )
+        xmlURL = self.create_url ('list')
+        xml = httpget (xmlURL)
+        cat = re.findall ("<category .*term=\" (.*?)\"", xml)
         categories = {}
         for c in cat:
             if c != 'TV':
-                if not categories.has_key(c): categories[c] = 0
+                if not categories.has_key (c):
+                    categories[c] = 0
                 categories[c] += 1
-        alist=[]
-        k = categories.keys()
-        k.sort()
+        alist = []
+        k = categories.keys ()
+        k.sort ()
         for c in k:
             n = categories[c]
-            c = c.replace('&amp;', '&')
-            c = c.replace('&gt;', '>')
-            c = c.replace('&lt;', '<')
-            alist.append((c, n))
+            c = c.replace ('&amp;', '&')
+            c = c.replace ('&gt;', '>')
+            c = c.replace ('&lt;', '<')
+            alist.append ( (c, n))
         return alist
 
     @property
-    def is_radio(self):
+    def is_radio (self):
         """ True if this feed is for radio. """
         return self.tvradio == 'radio'
 
     @property
-    def is_tv(self):
+    def is_tv (self):
         """ True if this feed is for tv. """
         return self.tvradio == 'tv'
 
-    name = property(get_name)
+    name = property (get_name)
 
 
-tv = feed('tv')
-radio = feed('radio')
+tv = feed ('tv')
+radio = feed ('radio')
 
-def test():
-    tv = feed('tv')
-    print tv.popular()
-    print tv.channels()
-    print tv.get('bbc_one')
-    print tv.get('bbc_one').list()
-    for c in tv.get('bbc_one').categories():
+def test ():
+    tv = feed ('tv')
+    print tv.popular ()
+    print tv.channels ()
+    print tv.get ('bbc_one')
+    print tv.get ('bbc_one').list ()
+    for c in tv.get ('bbc_one').categories ():
         print c
-    #print tv.get('bbc_one').channels()
-    #print tv.categories()
-    #print tv.get('drama').list()
-    #print tv.get('drama').get_subcategory('period').list()
+    #print tv.get ('bbc_one').channels ()
+    #print tv.categories ()
+    #print tv.get ('drama').list ()
+    #print tv.get ('drama').get_subcategory ('period').list ()
 
 if __name__ == '__main__':
-    test()
+    test ()
diff --git a/src/plugins/iplayer/listparser.py b/src/plugins/iplayer/listparser.py
index 526224a..b96f80c 100644
--- a/src/plugins/iplayer/listparser.py
+++ b/src/plugins/iplayer/listparser.py
@@ -4,49 +4,62 @@
 
 import re
 
-def xmlunescape(data):
-    data = data.replace('&amp;', '&')
-    data = data.replace('&gt;', '>')
-    data = data.replace('&lt;', '<')
+def xmlunescape (data):
+    data = data.replace ('&amp;', '&')
+    data = data.replace ('&gt;', '>')
+    data = data.replace ('&lt;', '<')
     return data
 
-class listentry(object):
-     def __init__(self, title=None, id=None, updated=None, summary=None, categories=None):
-         self.title      = title
-         self.id         = id
-         self.updated    = updated
-         self.summary    = summary
-         self.categories = categories
-
-class listentries(object):
-     def __init__(self):
-         self.entries = []
-                  
-def parse(xmlSource):  
+class listentry (object):
+    def __init__ (self, title = None, id = None, updated = None, summary = None,
+                  categories = None):
+        self.title = title
+        self.id = id
+        self.updated = updated
+        self.summary = summary
+        self.categories = categories
+
+class listentries (object):
+    def __init__ (self):
+        self.entries = []
+
+def parse (xmlSource):
     try:
-        encoding = re.findall( "<\?xml version=\"[^\"]*\" encoding=\"([^\"]*)\"\?>", xmlSource )[ 0 ]
-    except: return None
-    elist=listentries()
-    # gather all list entries 
-    entriesSrc = re.findall( "<entry>(.*?)</entry>", xmlSource, re.DOTALL)
-    datematch = re.compile(':\s+([0-9]+)/([0-9]+)/([0-9]{4})')
-    
+        regexp = "<\?xml version=\"[^\"]*\" encoding=\" ([^\"]*)\"\?>"
+        encoding = re.findall (regexp, xmlSource)[0]
+    except:
+        return None
+
+    elist = listentries ()
+    # gather all list entries
+    entriesSrc = re.findall ("<entry> (.*?)</entry>", xmlSource, re.DOTALL)
+    datematch = re.compile (':\s+ ([0-9]+)/ ([0-9]+)/ ([0-9]{4})')
+
     # enumerate thru the element list and gather info
     for entrySrc in entriesSrc:
-        entry={}
-        title   = re.findall( "<title[^>]*>(.*?)</title>", entrySrc, re.DOTALL )[0]
-        id      = re.findall( "<id[^>]*>(.*?)</id>", entrySrc, re.DOTALL )[0]
-        updated = re.findall( "<updated[^>]*>(.*?)</updated>", entrySrc, re.DOTALL )[0]
-        summary = re.findall( "<content[^>]*>(.*?)</content>", entrySrc, re.DOTALL )[0].splitlines()[-3]
-        categories = re.findall( "<category[^>]*term=\"(.*?)\"[^>]*>", entrySrc, re.DOTALL )
-
-        match = datematch.search(title)
+        entry = {}
+        title = re.findall ("<title[^>]*> (.*?)</title>",
+                            entrySrc, re.DOTALL)[0]
+        id = re.findall ("<id[^>]*> (.*?)</id>", entrySrc, re.DOTALL)[0]
+        updated = re.findall ("<updated[^>]*> (.*?)</updated>",
+                              entrySrc, re.DOTALL)[0]
+        summary = re.findall ("<content[^>]*> (.*?)</content>",
+                              entrySrc, re.DOTALL)[0].splitlines ()[-3]
+        categories = re.findall ("<category[^>]*term=\" (.*?)\"[^>]*>",
+                                 entrySrc, re.DOTALL)
+
+        match = datematch.search (title)
         if match:
-            # if the title contains a data at the end use that as the updated date YYYY-MM-DD
-            updated = "%s-%s-%s" % ( match.group(3), match.group(2), match.group(1)  )
-                    
-        e_categories=[]
-        for c in categories: e_categories.append(xmlunescape(c))        
-        elist.entries.append(listentry(xmlunescape(title), xmlunescape(id), xmlunescape(updated), xmlunescape(summary), e_categories))
-
-    return elist   
+            # if the title contains a data at the end use that as the updated
+            # date YYYY-MM-DD
+            updated = "%s-%s-%s" % (match.group (3), match.group (2),
+                                    match.group (1))
+
+        e_categories = []
+        for c in categories:
+            e_categories.append (xmlunescape (c))
+        elist.entries.append (listentry (xmlunescape (title), xmlunescape (id),
+                                         xmlunescape (updated),
+                                         xmlunescape (summary), e_categories))
+
+    return elist
diff --git a/src/plugins/jamendo/jamendo.py b/src/plugins/jamendo/jamendo.py
index 76e28a1..e27850b 100644
--- a/src/plugins/jamendo/jamendo.py
+++ b/src/plugins/jamendo/jamendo.py
@@ -14,7 +14,7 @@
 #
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
@@ -51,22 +51,22 @@ except ImportError:
     try:
         import simplejson as json
     except ImportError:
-        dlg = Gtk.MessageDialog(
+        dlg = Gtk.MessageDialog (
             message_type=Gtk.MessageType.ERROR,
             buttons=Gtk.ButtonsType.OK
         )
-        dlg.set_markup(_(u'You need to install the Python simplejson module.'))
-        dlg.run()
-        dlg.destroy()
+        dlg.set_markup (_(u'You need to install the Python simplejson module.'))
+        dlg.run ()
+        dlg.destroy ()
         raise
 
-socket.setdefaulttimeout(30)
-gobject.threads_init()
+socket.setdefaulttimeout (30)
+gobject.threads_init ()
 
-class JamendoPlugin(gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
+class JamendoPlugin (gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
     __gtype_name__ = 'JamendoPlugin'
 
-    object = gobject.property(type = gobject.GObject)
+    object = gobject.property (type = gobject.GObject)
 
     """
     Jamendo totem plugin GUI.
@@ -77,83 +77,97 @@ class JamendoPlugin(gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
     TAB_POPULAR     = 1
     TAB_LATEST      = 2
 
-    def __init__(self):
+    def __init__ (self):
         self.debug = True
         self.gstreamer_plugins_present = True
         self.totem = None
         self.settings = Gio.Settings.new ('org.gnome.totem.plugins.jamendo')
         self.settings.connect ('changed::format', self.on_format_changed)
-        self.settings.connect ('changed::num-per-page', self.on_num_per_page_changed)
+        self.settings.connect ('changed::num-per-page',
+                               self.on_num_per_page_changed)
 
-    def do_activate(self):
+    def do_activate (self):
         """
         Plugin activation.
         """
         self.totem = self.object
         # Initialise the interface
-        builder = Totem.plugin_load_interface ("jamendo", "jamendo.ui", True, self.totem.get_main_window (), self)
-        self.popup = builder.get_object('popup_menu')
-        container = builder.get_object('container')
-        self.notebook = builder.get_object('notebook')
-        self.search_entry = builder.get_object('search_entry')
-        self.search_combo = builder.get_object('search_combo')
-        self.search_combo.set_active(0)
-        self.album_button = builder.get_object('album_button')
-        self.previous_button = builder.get_object('previous_button')
-        self.next_button = builder.get_object('next_button')
+        builder = Totem.plugin_load_interface ("jamendo", "jamendo.ui", True,
+                                               self.totem.get_main_window (),
+                                               self)
+        self.popup = builder.get_object ('popup_menu')
+        container = builder.get_object ('container')
+        self.notebook = builder.get_object ('notebook')
+        self.search_entry = builder.get_object ('search_entry')
+        self.search_combo = builder.get_object ('search_combo')
+        self.search_combo.set_active (0)
+        self.album_button = builder.get_object ('album_button')
+        self.previous_button = builder.get_object ('previous_button')
+        self.next_button = builder.get_object ('next_button')
         self.progressbars = [
-            builder.get_object('results_progressbar'),
-            builder.get_object('popular_progressbar'),
-            builder.get_object('latest_progressbar'),
+            builder.get_object ('results_progressbar'),
+            builder.get_object ('popular_progressbar'),
+            builder.get_object ('latest_progressbar'),
         ]
         self.treeviews = [
-            builder.get_object('results_treeview'),
-            builder.get_object('popular_treeview'),
-            builder.get_object('latest_treeview'),
+            builder.get_object ('results_treeview'),
+            builder.get_object ('popular_treeview'),
+            builder.get_object ('latest_treeview'),
         ]
-        self.setup_treeviews()
+        self.setup_treeviews ()
 
         # Set up signals
-        builder.get_object('search_button').connect('clicked', self.on_search_button_clicked)
-        self.search_entry.connect('activate', self.on_search_entry_activate)
-        self.notebook.connect('switch-page', self.on_notebook_switch_page)
-        self.previous_button.connect('clicked', self.on_previous_button_clicked)
-        self.next_button.connect('clicked', self.on_next_button_clicked)
-        self.album_button.connect('clicked', self.on_album_button_clicked)
-        builder.get_object('add_to_playlist').connect('activate', self.on_add_to_playlist_activate)
-        builder.get_object('jamendo_album_page').connect('activate', self.on_open_jamendo_album_page_activate)
-
-        self.reset()
-        container.show_all()
-        self.totem.add_sidebar_page("jamendo", _(u"Jamendo"), container)
-
-    def do_deactivate(self):
+        search_button = builder.get_object ('search_button')
+        search_button.connect ('clicked', self.on_search_button_clicked)
+        self.search_entry.connect ('activate', self.on_search_entry_activate)
+        self.notebook.connect ('switch-page', self.on_notebook_switch_page)
+        self.previous_button.connect ('clicked',
+                                      self.on_previous_button_clicked)
+        self.next_button.connect ('clicked', self.on_next_button_clicked)
+        self.album_button.connect ('clicked', self.on_album_button_clicked)
+        add_to_playlist = builder.get_object ('add_to_playlist')
+        add_to_playlist.connect ('activate', self.on_add_to_playlist_activate)
+        album_page_button = builder.get_object ('jamendo_album_page')
+        album_page_button.connect ('activate',
+                                   self.on_open_jamendo_album_page_activate)
+
+        self.reset ()
+        container.show_all ()
+        self.totem.add_sidebar_page ("jamendo", _(u"Jamendo"), container)
+
+    def do_deactivate (self):
         """
         Plugin deactivation.
         """
-        self.totem.remove_sidebar_page("jamendo")
+        self.totem.remove_sidebar_page ("jamendo")
 
-    def do_create_configure_widget(self):
+    def do_create_configure_widget (self):
         """
         Plugin config widget.
-        This code must be independent from the rest of the plugin. FIXME: bgo#624073
+        This code must be independent from the rest of the plugin.
+        FIXME: bgo#624073
         """
-        builder = Totem.plugin_load_interface ('jamendo', 'jamendo.ui', True, None, self)
+        builder = Totem.plugin_load_interface ('jamendo', 'jamendo.ui', True,
+                                               None, self)
         config_widget = builder.get_object ('config_widget')
         config_widget.connect ('destroy', self.on_config_widget_destroy)
         format = self.settings.get_enum ('format')
         num_per_page = self.settings.get_value ('num-per-page').get_uint32 ()
 
-        # Set up the "format" combo box. We can't use g_settings_bind() here, as it won't automatically convert between enums and ints. To do so,
-        # we'd need to use g_settings_bind_with_mapping(), but that isn't introspectable. We have to handle the binding manually.
-        combo = builder.get_object('preferred_format_combo')
-        combo.set_active(format)
+        # Set up the "format" combo box. We can't use g_settings_bind () here,
+        # as it won't automatically convert between enums and ints. To do so,
+        # we'd need to use g_settings_bind_with_mapping (), but that isn't
+        # introspectable. We have to handle the binding manually.
+        combo = builder.get_object ('preferred_format_combo')
+        combo.set_active (format)
         combo.connect ('changed', self.on_format_combo_changed)
-        self.settings.connect ('changed::format', self.on_format_setting_changed, combo)
+        self.settings.connect ('changed::format',
+                               self.on_format_setting_changed, combo)
 
-        spinbutton = builder.get_object('album_num_spinbutton')
-        spinbutton.set_value(num_per_page)
-        self.settings.bind ('num-per-page', spinbutton, 'value', Gio.SettingsBindFlags.DEFAULT)
+        spinbutton = builder.get_object ('album_num_spinbutton')
+        spinbutton.set_value (num_per_page)
+        self.settings.bind ('num-per-page', spinbutton, 'value',
+                            Gio.SettingsBindFlags.DEFAULT)
 
         return config_widget
 
@@ -165,7 +179,8 @@ class JamendoPlugin(gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
 
     def on_format_setting_changed (self, settings, key, combo):
         """
-        Called for the "format" preference combo box when the corresponding GSettings value is changed.
+        Called for the "format" preference combo box when the corresponding
+        GSettings value is changed.
         """
         combo.set_active (self.settings.get_enum ('format'))
 
@@ -177,11 +192,11 @@ class JamendoPlugin(gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
 
     def on_config_widget_destroy (self, widget):
         try:
-            self.reset()
+            self.reset ()
         except:
             pass
 
-    def reset(self):
+    def reset (self):
         """
         XXX this will be refactored asap.
         """
@@ -202,295 +217,303 @@ class JamendoPlugin(gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
         }
         self.album_count = [0, 0, 0]
         for tv in self.treeviews:
-            tv.get_model().clear()
-        self._update_buttons_state()
+            tv.get_model ().clear ()
+        self._update_buttons_state ()
 
-    def setup_treeviews(self):
+    def setup_treeviews (self):
         """
         Setup the 3 treeview: result, popular and latest
         """
         self.current_treeview = self.treeviews[0]
         for w in self.treeviews:
             selection = w.get_selection ()
-            selection.set_mode(Gtk.SelectionMode.MULTIPLE)
+            selection.set_mode (Gtk.SelectionMode.MULTIPLE)
             selection.connect ('changed', self.on_treeview_selection_changed)
 
             # build pixbuf column
-            cell = Gtk.CellRendererPixbuf()
-            col = Gtk.TreeViewColumn(cell_renderer=cell, pixbuf=1)
+            cell = Gtk.CellRendererPixbuf ()
+            col = Gtk.TreeViewColumn (cell_renderer=cell, pixbuf=1)
 
-            w.append_column(col)
+            w.append_column (col)
 
             # build description column
-            cell = Gtk.CellRendererText()
-            cell.set_property('ellipsize', Pango.EllipsizeMode.END)
-            col = Gtk.TreeViewColumn(cell_renderer=cell, markup=2)
-            col.set_expand(True)
-            w.append_column(col)
+            cell = Gtk.CellRendererText ()
+            cell.set_property ('ellipsize', Pango.EllipsizeMode.END)
+            col = Gtk.TreeViewColumn (cell_renderer=cell, markup=2)
+            col.set_expand (True)
+            w.append_column (col)
 
             # duration column
-            cell = Gtk.CellRendererText()
-            cell.set_property('xalign', 1.0)
-            cell.set_property('size-points', 8)
-            col = Gtk.TreeViewColumn(cell_renderer=cell, markup=3)
-            col.set_alignment(1.0)
-            w.append_column(col)
+            cell = Gtk.CellRendererText ()
+            cell.set_property ('xalign', 1.0)
+            cell.set_property ('size-points', 8)
+            col = Gtk.TreeViewColumn (cell_renderer=cell, markup=3)
+            col.set_alignment (1.0)
+            w.append_column (col)
 
             # configure the treeview
-            w.set_show_expanders(False) # we manage internally expand/collapse
-            w.set_tooltip_column(4)     # set the tooltip column
+            w.set_show_expanders (False) # we manage internally expand/collapse
+            w.set_tooltip_column (4)     # set the tooltip column
 
             # Connect signals
-            w.connect("button-press-event", self.on_treeview_row_clicked)
-            w.connect("row-activated", self.on_treeview_row_activated)
+            w.connect ("button-press-event", self.on_treeview_row_clicked)
+            w.connect ("row-activated", self.on_treeview_row_activated)
 
 
-    def add_treeview_item(self, treeview, album):
-        if not isinstance(album['image'], GdkPixbuf.Pixbuf):
+    def add_treeview_item (self, treeview, album):
+        if not isinstance (album['image'], GdkPixbuf.Pixbuf):
             # album image pixbuf is not yet built
             try:
-                pb = GdkPixbuf.Pixbuf.new_from_file(album['image'])
-                os.unlink(album['image'])
+                pb = GdkPixbuf.Pixbuf.new_from_file (album['image'])
+                os.unlink (album['image'])
                 album['image'] = pb
             except:
                 # do not fail for this, just display a dummy pixbuf
-                album['image'] = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True,
-                    8, 1, 1)
+                album['image'] = GdkPixbuf.Pixbuf.new (GdkPixbuf.Colorspace.RGB,
+                                                       True, 8, 1, 1)
         # format title
-        title  = '<b>%s</b>\n' % self._format_str(album['name'])
-        title += _(u'Artist: %s') % self._format_str(album['artist_name'])
+        title  = '<b>%s</b>\n' % self._format_str (album['name'])
+        title += _(u'Artist: %s') % self._format_str (album['artist_name'])
         # format duration
-        dur = self._format_duration(album['duration'])
+        dur = self._format_duration (album['duration'])
         # format tooltip
         try:
-            # Translators: this is the release date of an album in Python strptime format
-            release = time.strptime(album['dates']['release'][0:10], _(u'%Y-%m-%d'))
-            # Translators: this is the release time of an album in Python strftime format
-            release = time.strftime(_(u'%x'), release)
+            # Translators: this is the release date of an album in Python
+            # strptime format
+            release = time.strptime (album['dates']['release'][0:10],
+                                     _(u'%Y-%m-%d'))
+            # Translators: this is the release time of an album in Python
+            # strftime format
+            release = time.strftime (_(u'%x'), release)
         except:
             release = ''
-        tip = '\n'.join([
-            '<b>%s</b>' % self._format_str(album['name']),
-            _(u'Artist: %s') % self._format_str(album['artist_name']),
-            _(u'Genre: %s') % self._format_str(album['genre']),
+        tip = '\n'.join ([
+            '<b>%s</b>' % self._format_str (album['name']),
+            _(u'Artist: %s') % self._format_str (album['artist_name']),
+            _(u'Genre: %s') % self._format_str (album['genre']),
             _(u'Released on: %s') % release,
-            _(u'License: %s') % self._format_str(album['license'][0]),
+            _(u'License: %s') % self._format_str (album['license'][0]),
         ])
         # append album row
-        parent = treeview.get_model().append(None,
+        parent = treeview.get_model ().append (None,
             [album, album['image'], title, dur, tip]
         )
 
         # append track rows
-        icon = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 1, 1)
-        for i, track in enumerate(album['tracks']):
+        icon = GdkPixbuf.Pixbuf.new (GdkPixbuf.Colorspace.RGB, True, 8, 1, 1)
+        for i, track in enumerate (album['tracks']):
             # track title
             # Translators: this is the title of a track in Python format
             # (first argument is the track number, second is the track title)
             tt = (u'<small>%s</small>' % _(u'%02d. %s')) % \
-                (i+1, self._format_str(track['name']))
+                (i+1, self._format_str (track['name']))
             # track duration
-            td = self._format_duration(track['duration'])
+            td = self._format_duration (track['duration'])
             # track tooltip
-            tip = '\n'.join([
-                '<b>%s</b>' %  self._format_str(track['name']),
-                _(u'Album: %s') % self._format_str(album['name']),
-                _(u'Artist: %s') % self._format_str(album['artist_name']),
+            tip = '\n'.join ([
+                '<b>%s</b>' %  self._format_str (track['name']),
+                _(u'Album: %s') % self._format_str (album['name']),
+                _(u'Artist: %s') % self._format_str (album['artist_name']),
                 _(u'Duration: %s') % td,
             ])
             # append track
-            treeview.get_model().append(parent, [track, icon, tt, td, tip])
+            treeview.get_model ().append (parent, [track, icon, tt, td, tip])
         # update current album count
-        pindex = self.treeviews.index(treeview)
+        pindex = self.treeviews.index (treeview)
         self.album_count[pindex] += 1
 
-    def add_album_to_playlist(self, mode, album):
+    def add_album_to_playlist (self, mode, album):
         """
         Add an album to the playlist, mode can be: replace, enqueue or
         enqueue_and_play.
         """
-        for i, track in enumerate(album['tracks']):
+        for i, track in enumerate (album['tracks']):
             if mode in ('replace', 'enqueue_and_play'):
                 if i == 0:
                     # play first track
-                    self.add_track_to_playlist(mode, track)
+                    self.add_track_to_playlist (mode, track)
                 else:
                     # and enqueue other tracks
-                    self.add_track_to_playlist('enqueue', track)
+                    self.add_track_to_playlist ('enqueue', track)
             else:
-                self.add_track_to_playlist('enqueue', track)
+                self.add_track_to_playlist ('enqueue', track)
 
-    def add_track_to_playlist(self, mode, t):
+    def add_track_to_playlist (self, mode, t):
         """
         Add a track to the playlist, mode can be: replace, enqueue or
         enqueue_and_play.
         """
         if mode == 'replace':
-            self.totem.action_remote(Totem.RemoteCommand.REPLACE, t['stream'].encode ('UTF-8'))
+            self.totem.action_remote (Totem.RemoteCommand.REPLACE,
+                                      t['stream'].encode ('UTF-8'))
         elif mode == 'enqueue':
-            self.totem.action_remote(Totem.RemoteCommand.ENQUEUE, t['stream'].encode ('UTF-8'))
+            self.totem.action_remote (Totem.RemoteCommand.ENQUEUE,
+                                      t['stream'].encode ('UTF-8'))
 
-    def fetch_albums(self, pn=1):
+    def fetch_albums (self, pn=1):
         """
         Initialize the fetch thread.
         """
-        tab_index = self.treeviews.index(self.current_treeview)
+        tab_index = self.treeviews.index (self.current_treeview)
         if tab_index == self.TAB_POPULAR:
             params = {'order': 'rating_desc'}
         elif tab_index == self.TAB_LATEST:
             params = {'order': 'date_desc'}
         else:
-            value = self.search_entry.get_text()
+            value = self.search_entry.get_text ()
             if not value:
                 return
-            prop = self.SEARCH_CRITERIA[self.search_combo.get_active()]
+            prop = self.SEARCH_CRITERIA[self.search_combo.get_active ()]
             params = {'order': 'date_desc', prop: value}
         params['pn'] = pn
-        self.current_treeview.get_model().clear()
-        self.previous_button.set_sensitive(False)
-        self.next_button.set_sensitive(False)
-        self.album_button.set_sensitive(False)
-        self.progressbars[tab_index].show()
-        self.progressbars[tab_index].set_fraction(0.0)
-        self.progressbars[tab_index].set_text(
+        self.current_treeview.get_model ().clear ()
+        self.previous_button.set_sensitive (False)
+        self.next_button.set_sensitive (False)
+        self.album_button.set_sensitive (False)
+        self.progressbars[tab_index].show ()
+        self.progressbars[tab_index].set_fraction (0.0)
+        self.progressbars[tab_index].set_text (
             _(u'Fetching albums, please waitâ?¦')
         )
         lcb = (self.on_fetch_albums_loop, self.current_treeview)
         dcb = (self.on_fetch_albums_done, self.current_treeview)
         ecb = (self.on_fetch_albums_error, self.current_treeview)
-        thread = JamendoService(params, lcb, dcb, ecb)
-        thread.start()
+        thread = JamendoService (params, lcb, dcb, ecb)
+        thread.start ()
         self.running_threads[tab_index] = True
 
-    def on_fetch_albums_loop(self, treeview, album):
+    def on_fetch_albums_loop (self, treeview, album):
         """
         Add an album item and its tracks to the current treeview.
         """
-        self.add_treeview_item(treeview, album)
+        self.add_treeview_item (treeview, album)
         # pulse progressbar
-        pindex = self.treeviews.index(treeview)
-        self.progressbars[pindex].set_fraction(
-            float(self.album_count[pindex]) / float(JamendoService.NUM_PER_PAGE)
+        pindex = self.treeviews.index (treeview)
+        album_count = self.album_count[pindex]
+        self.progressbars[pindex].set_fraction (
+            float (album_count) / float (JamendoService.NUM_PER_PAGE)
         )
 
-    def on_fetch_albums_done(self, treeview, albums, save_state=True):
+    def on_fetch_albums_done (self, treeview, albums, save_state=True):
         """
         Called when the thread finished fetching albums.
         """
-        pindex = self.treeviews.index(treeview)
-        model = treeview.get_model()
-        if save_state and len(albums):
-            self.pages[pindex].append(albums)
-            self.current_page[pindex] = len(self.pages[pindex])
-        self._update_buttons_state()
-        self.progressbars[pindex].set_fraction(0.0)
-        self.progressbars[pindex].hide()
+        pindex = self.treeviews.index (treeview)
+        model = treeview.get_model ()
+        if save_state and len (albums):
+            self.pages[pindex].append (albums)
+            self.current_page[pindex] = len (self.pages[pindex])
+        self._update_buttons_state ()
+        self.progressbars[pindex].set_fraction (0.0)
+        self.progressbars[pindex].hide ()
         self.album_count[pindex] = 0
         self.running_threads[pindex] = False
 
-    def on_fetch_albums_error(self, treeview, exc):
+    def on_fetch_albums_error (self, treeview, exc):
         """
         Called when an error occured in the thread.
         """
-        self.reset()
-        pindex = self.treeviews.index(treeview)
-        self.progressbars[pindex].set_fraction(0.0)
-        self.progressbars[pindex].hide()
+        self.reset ()
+        pindex = self.treeviews.index (treeview)
+        self.progressbars[pindex].set_fraction (0.0)
+        self.progressbars[pindex].hide ()
         self.running_threads[pindex] = False
 
-        # managing exceptions with urllib is a real PITA... :(
-        if hasattr(exc, 'reason'):
+        # managing exceptions with urllib is a real PITA... : (
+        if hasattr (exc, 'reason'):
             try:
                 reason = exc.reason[1]
             except:
                 try:
                     reason = exc.reason[0]
                 except:
-                    reason = str(exc)
-            reason = reason.capitalize()
+                    reason = str (exc)
+            reason = reason.capitalize ()
             msg = _(u'Failed to connect to Jamendo server.\n%s.') % reason
-        elif hasattr(exc, 'code'):
+        elif hasattr (exc, 'code'):
             msg = _(u'The Jamendo server returned code %s.') % exc.code
         else:
-            msg = str(exc)
+            msg = str (exc)
 
-        self.totem.action_error(_(u'An error occurred while fetching albums.'), msg)
+        self.totem.action_error (_(u'An error occurred while fetching albums.'),
+                                 msg)
 
-    def on_search_entry_activate(self, *args):
+    def on_search_entry_activate (self, *args):
         """
         Called when the user typed <enter> in the search entry.
         """
-        return self.on_search_button_clicked()
+        return self.on_search_button_clicked ()
 
-    def on_search_button_clicked(self, *args):
+    def on_search_button_clicked (self, *args):
         """
         Called when the user clicked on the search button.
         """
-        if not self.search_entry.get_text():
+        if not self.search_entry.get_text ():
             return
         if self.current_treeview != self.treeviews[self.TAB_RESULTS]:
             self.current_treeview = self.treeviews[self.TAB_RESULTS]
-            self.notebook.set_current_page(self.TAB_RESULTS)
+            self.notebook.set_current_page (self.TAB_RESULTS)
         else:
-            self.on_notebook_switch_page(new_search=True)
+            self.on_notebook_switch_page (new_search=True)
 
-    def on_notebook_switch_page(self, nb=None, tab=None, tab_num=0,
+    def on_notebook_switch_page (self, nb=None, tab=None, tab_num=0,
         new_search=False):
         """
         Called when the changed a notebook page.
         """
-        self.current_treeview = self.treeviews[int(tab_num)]
-        self._update_buttons_state()
-        model = self.current_treeview.get_model()
+        self.current_treeview = self.treeviews[int (tab_num)]
+        self._update_buttons_state ()
+        model = self.current_treeview.get_model ()
         # fetch popular and latest albums only once
-        if self.running_threads[int(tab_num)] == True or \
-           (not new_search and len(model)):
+        if self.running_threads[int (tab_num)] == True or \
+           (not new_search and len (model)):
             return
         if new_search:
             self.current_page[self.TAB_RESULTS] = 1
             self.pages[self.TAB_RESULTS] = []
             self.album_count[self.TAB_RESULTS] = 0
-            self._update_buttons_state()
-        model.clear()
-        self.fetch_albums()
+            self._update_buttons_state ()
+        model.clear ()
+        self.fetch_albums ()
 
-    def on_treeview_row_activated(self, tv, path, column):
+    def on_treeview_row_activated (self, tv, path, column):
         """
         Called when the user double-clicked on a treeview element.
         """
         try:
-            item = self._get_selection()[0] # first item selected
+            item = self._get_selection ()[0] # first item selected
         except:
             return
 
         if path.get_depth () == 1:
-            self.add_album_to_playlist('replace', item)
+            self.add_album_to_playlist ('replace', item)
         else:
-            self.add_track_to_playlist('replace', item)
+            self.add_track_to_playlist ('replace', item)
 
-    def on_treeview_row_clicked(self, tv, evt):
+    def on_treeview_row_clicked (self, tv, evt):
         """
         Called when the user clicked on a treeview element.
         """
         try:
             if evt.button == 3:
-                (path, _, _, _) = tv.get_path_at_pos(int(evt.x), int(evt.y))
-                sel  = tv.get_selection()
-                (_, rows) = sel.get_selected_rows()
+                (path, _, _, _) = tv.get_path_at_pos (int (evt.x), int (evt.y))
+                sel  = tv.get_selection ()
+                (_, rows) = sel.get_selected_rows ()
                 if path not in rows:
-                    sel.unselect_all()
-                    sel.select_path(path)
-                tv.grab_focus()
-                self.popup.popup_for_device(None, None, None, None, None, evt.button, evt.time)
+                    sel.unselect_all ()
+                    sel.select_path (path)
+                tv.grab_focus ()
+                self.popup.popup_for_device (None, None, None, None, None,
+                                             evt.button, evt.time)
                 return True
 
-            (event_x, event_y) = evt.get_coords()
-            (path, c, x, y) = tv.get_path_at_pos(int(event_x), int(event_y))
-            if (path.get_depth() == 1):
-                if tv.row_expanded(path):
-                    tv.collapse_row(path)
+            (event_x, event_y) = evt.get_coords ()
+            (path, c, x, y) = tv.get_path_at_pos (int (event_x), int (event_y))
+            if path.get_depth () == 1:
+                if tv.row_expanded (path):
+                    tv.collapse_row (path)
                 else:
-                    tv.expand_row(path, False)
+                    tv.expand_row (path, False)
         except:
             pass
 
@@ -498,77 +521,77 @@ class JamendoPlugin(gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
         (_, rows) = selection.get_selected_rows ()
         self.album_button.set_sensitive (len (rows) > 0)
 
-    def on_previous_button_clicked(self, *args):
+    def on_previous_button_clicked (self, *args):
         """
         Called when the user clicked the previous button.
         """
-        self._update_buttons_state()
-        model = self.current_treeview.get_model()
-        model.clear()
-        pindex = self.treeviews.index(self.current_treeview)
+        self._update_buttons_state ()
+        model = self.current_treeview.get_model ()
+        model.clear ()
+        pindex = self.treeviews.index (self.current_treeview)
         self.current_page[pindex] -= 1
         albums = self.pages[pindex][self.current_page[pindex]-1]
         for album in albums:
-            self.add_treeview_item(self.current_treeview, album)
-        self.on_fetch_albums_done(self.current_treeview, albums, False)
+            self.add_treeview_item (self.current_treeview, album)
+        self.on_fetch_albums_done (self.current_treeview, albums, False)
 
-    def on_next_button_clicked(self, *args):
+    def on_next_button_clicked (self, *args):
         """
         Called when the user clicked the next button.
         """
-        self._update_buttons_state()
-        model = self.current_treeview.get_model()
-        model.clear()
-        pindex = self.treeviews.index(self.current_treeview)
-        if self.current_page[pindex] == len(self.pages[pindex]):
-            self.fetch_albums(self.current_page[pindex]+1)
+        self._update_buttons_state ()
+        model = self.current_treeview.get_model ()
+        model.clear ()
+        pindex = self.treeviews.index (self.current_treeview)
+        if self.current_page[pindex] == len (self.pages[pindex]):
+            self.fetch_albums (self.current_page[pindex]+1)
         else:
             self.current_page[pindex] += 1
             albums = self.pages[pindex][self.current_page[pindex]-1]
             for album in albums:
-                self.add_treeview_item(self.current_treeview, album)
-            self.on_fetch_albums_done(self.current_treeview, albums, False)
+                self.add_treeview_item (self.current_treeview, album)
+            self.on_fetch_albums_done (self.current_treeview, albums, False)
 
-    def on_album_button_clicked(self, *args):
+    def on_album_button_clicked (self, *args):
         """
         Called when the user clicked on the album button.
         """
         try:
-            url = self._get_selection(True)[0]['url']
-            os.spawnlp(os.P_NOWAIT, "xdg-open", "xdg-open", url)
+            url = self._get_selection (True)[0]['url']
+            os.spawnlp (os.P_NOWAIT, "xdg-open", "xdg-open", url)
         except:
             pass
 
-    def on_add_to_playlist_activate(self, *args):
+    def on_add_to_playlist_activate (self, *args):
         """
         Called when the user clicked on the add to playlist button of the
         popup menu.
         """
-        items = self._get_selection()
+        items = self._get_selection ()
         for item in items:
             if 'tracks' in item:
                 # we have an album
-                self.add_album_to_playlist('enqueue', item)
+                self.add_album_to_playlist ('enqueue', item)
             else:
                 # we have a track
-                self.add_track_to_playlist('enqueue', item)
+                self.add_track_to_playlist ('enqueue', item)
 
-    def on_open_jamendo_album_page_activate(self, *args):
+    def on_open_jamendo_album_page_activate (self, *args):
         """
         Called when the user clicked on the jamendo album page button of the
         popup menu.
         """
-        return self.on_album_button_clicked()
+        return self.on_album_button_clicked ()
 
-    def _get_selection(self, root=False):
+    def _get_selection (self, root=False):
         """
         Shortcut method to retrieve the treeview items selected.
         """
         ret = []
-        sel = self.current_treeview.get_selection()
-        (model, rows) = sel.get_selected_rows()
+        sel = self.current_treeview.get_selection ()
+        (model, rows) = sel.get_selected_rows ()
         for row in rows:
-            it = model.get_iter(row)
+            it = model.get_iter (row)
 
             # Return the parent node if root == true
             if root:
@@ -576,28 +599,29 @@ class JamendoPlugin(gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
                 if parent_iter != None:
                     it = parent_iter
 
-            elt = model.get_value(it, 0)
+            elt = model.get_value (it, 0)
             if elt not in ret:
-                ret.append(elt)
+                ret.append (elt)
         return ret
 
-    def _update_buttons_state(self):
+    def _update_buttons_state (self):
         """
         Update the state of the previous and next buttons.
         """
-        sel = self.current_treeview.get_selection()
-        (model, rows) = sel.get_selected_rows()
+        sel = self.current_treeview.get_selection ()
+        (model, rows) = sel.get_selected_rows ()
         try:
-            it = model.get_iter(rows[0])
+            it = model.get_iter (rows[0])
         except:
             it = None
-        pindex = self.treeviews.index(self.current_treeview)
-        self.previous_button.set_sensitive(self.current_page[pindex] > 1)
-        self.next_button.set_sensitive(len(model)==JamendoService.NUM_PER_PAGE)
-        self.album_button.set_sensitive(it is not None)
+        pindex = self.treeviews.index (self.current_treeview)
+        self.previous_button.set_sensitive (self.current_page[pindex] > 1)
+        more_results = len (model) == JamendoService.NUM_PER_PAGE
+        self.next_button.set_sensitive (more_results)
+        self.album_button.set_sensitive (it is not None)
 
 
-    def _format_str(self, st, truncate=False):
+    def _format_str (self, st, truncate=False):
         """
         Escape entities for pango markup and force the string to utf-8.
         """
@@ -608,24 +632,24 @@ class JamendoPlugin(gobject.GObject, Peas.Activatable, PeasGtk.Configurable):
         except:
             return st
 
-    def _format_duration(self, secs):
+    def _format_duration (self, secs):
         """
         Format the given number of seconds to a human readable duration.
         """
         try:
-            secs = int(secs)
+            secs = int (secs)
             if secs >= 3600:
-                # Translators: time formatting (in Python strftime format) for the Jamendo plugin
-                # for times longer than an hour
-                return time.strftime(_(u'%H:%M:%S'), time.gmtime(secs))
-            # Translators: time formatting (in Python strftime format) for the Jamendo plugin
-            # for times shorter than an hour
-            return time.strftime(_(u'%M:%S'), time.gmtime(secs))
+                # Translators: time formatting (in Python strftime format) for
+                # the Jamendo plugin for times longer than an hour
+                return time.strftime (_(u'%H:%M:%S'), time.gmtime (secs))
+            # Translators: time formatting (in Python strftime format) for the
+            # Jamendo plugin for times shorter than an hour
+            return time.strftime (_(u'%M:%S'), time.gmtime (secs))
         except:
             return ''
 
 
-class JamendoService(threading.Thread):
+class JamendoService (threading.Thread):
     """
     Class that requests the jamendo REST service.
     """
@@ -634,54 +658,60 @@ class JamendoService(threading.Thread):
     AUDIO_FORMAT = 'ogg2'
     NUM_PER_PAGE = 10
 
-    def __init__(self, params, loop_cb, done_cb, error_cb):
+    def __init__ (self, params, loop_cb, done_cb, error_cb):
         self.params = params
         self.loop_cb = loop_cb
         self.done_cb = done_cb
         self.error_cb = error_cb
-        self.lock = threading.Lock()
-        threading.Thread.__init__(self)
+        self.lock = threading.Lock ()
+        threading.Thread.__init__ (self)
 
-    def run(self):
+    def run (self):
         url = '%s/id+name+duration+image+genre+dates+url+artist_id+' \
               'artist_name+artist_url/album/json/?n=%s&imagesize=50' % \
               (self.API_URL, self.NUM_PER_PAGE)
-        if len(self.params):
-            url += '&%s' % urllib.urlencode(self.params)
+        if len (self.params):
+            url += '&%s' % urllib.urlencode (self.params)
         try:
-            self.lock.acquire()
-            albums = json.loads(self._request(url))
+            self.lock.acquire ()
+            albums = json.loads (self._request (url))
             ret = []
-            for i, album in enumerate(albums):
-                fname, headers = urllib.urlretrieve(album['image'])
+            for i, album in enumerate (albums):
+                fname, headers = urllib.urlretrieve (album['image'])
                 album['image'] = fname
-                album['tracks'] = json.loads(self._request(
+                album['tracks'] = json.loads (self._request (
                     '%s/id+name+duration+stream/track/json/?album_id=%s'\
-                    '&order=numalbum_asc&streamencoding=%s' % (self.API_URL, album['id'], self.AUDIO_FORMAT)
+                    '&order=numalbum_asc'\
+                    '&streamencoding=%s' % (self.API_URL, album['id'],
+                                            self.AUDIO_FORMAT)
                 ))
-                album['license'] = json.loads(self._request(
+                album['license'] = json.loads (self._request (
                     '%s/name/license/json/album_license/?album_id=%s'\
                     % (self.API_URL, album['id'])
                 ))
-                # Translators: If Jamendo supports your language, replace "en" with the language code, enclosed
-                # in slashes, used to view pages in your language on the Jamendo website. e.g. For French, "en"
-                # would be translated to "fr", as Jamendo uses that in its URLs:
+                url = album['url']
+                # Translators: If Jamendo supports your language, replace "en"
+                # with the language code, enclosed in slashes, used to view
+                # pages in your language on the Jamendo website. e.g. For
+                # French, "en" would be translated to "fr", as Jamendo uses that
+                # in its URLs:
                 #  http://www.jamendo.com/fr/album/4818
                 # Compared to:
                 #  http://www.jamendo.com/en/album/4818
-                # If Jamendo doesn't support your language, *do not translate this string*!
-                album['url'] = album['url'].replace('/en/', '/' + _('en') + '/')
-                gobject.idle_add(self.loop_cb[0], self.loop_cb[1], album)
-            gobject.idle_add(self.done_cb[0], self.done_cb[1], albums)
+                # If Jamendo doesn't support your language, *do not translate
+                # this string*!
+                album['url'] = url.replace ('/en/', '/' + _('en') + '/')
+                gobject.idle_add (self.loop_cb[0], self.loop_cb[1], album)
+            gobject.idle_add (self.done_cb[0], self.done_cb[1], albums)
         except Exception as exc:
-            gobject.idle_add(self.error_cb[0], self.error_cb[1], exc)
+            gobject.idle_add (self.error_cb[0], self.error_cb[1], exc)
         finally:
-            self.lock.release()
-
-    def _request(self, url):
-        opener = urllib2.build_opener()
-        opener.addheaders = [('User-agent', 'Totem Jamendo plugin')]
-        handle = opener.open(url)
-        data = handle.read()
-        handle.close()
+            self.lock.release ()
+
+    def _request (self, url):
+        opener = urllib2.build_opener ()
+        opener.addheaders = [ ('User-agent', 'Totem Jamendo plugin')]
+        handle = opener.open (url)
+        data = handle.read ()
+        handle.close ()
         return data
diff --git a/src/plugins/opensubtitles/hash.py b/src/plugins/opensubtitles/hash.py
index 7e1189d..b8135b4 100644
--- a/src/plugins/opensubtitles/hash.py
+++ b/src/plugins/opensubtitles/hash.py
@@ -5,43 +5,43 @@ import gio
 SIZE_ERROR = -1
 SEEK_ERROR = -2
 
-def hashFile(name):
-       """ FIXME Need to handle exceptions !! """
-
- 
-       longlongformat = 'q'  # long long 
-       bytesize = struct.calcsize(longlongformat) 
-           
-       fp = gio.File(name) 
-           
-       filesize = fp.query_info('standard::size', 0).get_attribute_uint64('standard::size') 
-       
-       hash = filesize 
-          
-       if filesize < 65536 * 2: 
-              return SIZE_ERROR, 0
-
-       data = fp.read()                 
-       
-       if data.can_seek() != True:
-               return SEEK_ERROR, 0
-
-       for x in range(65536/bytesize):
-               buffer = data.read(bytesize)
-               (l_value,)= struct.unpack(longlongformat, buffer)  
-               hash += l_value 
-               hash = hash & 0xFFFFFFFFFFFFFFFF #to remain as 64bit number  
-               
-       if data.seek(max(0,filesize-65536),1) != True:
-               return SEEK_ERROR, 0
-
-       for x in range(65536/bytesize):
-               buffer = data.read(bytesize)
-               (l_value,)= struct.unpack(longlongformat, buffer)  
-               hash += l_value 
-               hash = hash & 0xFFFFFFFFFFFFFFFF 
-        
-       data.close() 
-       returnedhash =  "%016x" % hash 
-       return returnedhash, filesize 
+def hashFile (name):
+    """ FIXME Need to handle exceptions !! """
+
+    longlongformat = 'q' # long long
+    bytesize = struct.calcsize (longlongformat)
+
+    fp = gio.File (name)
+
+    file_info = fp.query_info ('standard::size', 0)
+    filesize = file_info.get_attribute_uint64 ('standard::size')
+
+    hash = filesize
+
+    if filesize < 65536 * 2:
+        return SIZE_ERROR, 0
+
+    data = fp.read ()
+
+    if data.can_seek () != True:
+        return SEEK_ERROR, 0
+
+    for x in range (65536/bytesize):
+        buffer = data.read (bytesize)
+        (l_value,) = struct.unpack (longlongformat, buffer)
+        hash += l_value
+        hash = hash & 0xFFFFFFFFFFFFFFFF #to remain as 64bit number
+
+    if data.seek (max (0, filesize-65536), 1) != True:
+        return SEEK_ERROR, 0
+
+    for x in range (65536/bytesize):
+        buffer = data.read (bytesize)
+        (l_value,) = struct.unpack (longlongformat, buffer)
+        hash += l_value
+        hash = hash & 0xFFFFFFFFFFFFFFFF
+
+    data.close ()
+    returnedhash = "%016x" % hash
+    return returnedhash, filesize
 
diff --git a/src/plugins/opensubtitles/opensubtitles.py b/src/plugins/opensubtitles/opensubtitles.py
index 1c4edb8..63281c4 100644
--- a/src/plugins/opensubtitles/opensubtitles.py
+++ b/src/plugins/opensubtitles/opensubtitles.py
@@ -7,7 +7,7 @@ from gi.repository import Gio
 from gi.repository import Pango
 from gi.repository import Totem
 import gobject
-gobject.threads_init()
+gobject.threads_init ()
 import xmlrpclib
 import threading
 import xdg.BaseDirectory
@@ -16,7 +16,7 @@ import gettext
 
 from hash import hashFile
 
-gettext.textdomain("totem")
+gettext.textdomain ("totem")
 
 D_ = gettext.dgettext
 _ = gettext.gettext
@@ -26,197 +26,201 @@ OK200 = '200 OK'
 TOTEM_REMOTE_COMMAND_REPLACE = 14
 
 SUBTITLES_EXT = [
-	"asc",
-	"txt",
-        "sub",
-        "srt",
-        "smi",
-        "ssa",
-        "ass",
+    "asc",
+    "txt",
+    "sub",
+    "srt",
+    "smi",
+    "ssa",
+    "ass",
 ]
 
-# Map of the language codes used by opensubtitles.org's API to their human-readable name
-LANGUAGES_STR = [(D_('iso_639_3', 'Albanian'), 'sq'),
-		 (D_('iso_639_3', 'Arabic'), 'ar'),
-		 (D_('iso_639_3', 'Armenian'), 'hy'),
-		 (D_('iso_639_3', 'Neo-Aramaic, Assyrian'), 'ay'),
-		 (D_('iso_639_3', 'Bosnian'), 'bs'),
-		 (_('Brasilian Portuguese'), 'pb'),
-		 (D_('iso_639_3', 'Bulgarian'), 'bg'),
-		 (D_('iso_639_3', 'Catalan'), 'ca'),
-		 (D_('iso_639_3', 'Chinese'), 'zh'),
-		 (D_('iso_639_3', 'Croatian'), 'hr'),
-		 (D_('iso_639_3', 'Czech'), 'cs'),
-		 (D_('iso_639_3', 'Danish'), 'da'),
-		 (D_('iso_639_3', 'Dutch'), 'nl'),
-		 (D_('iso_639_3', 'English'), 'en'),
-		 (D_('iso_639_3', 'Esperanto'), 'eo'),
-		 (D_('iso_639_3', 'Estonian'), 'et'),
-		 (D_('iso_639_3', 'Finnish'), 'fi'),
-		 (D_('iso_639_3', 'French'), 'fr'),
-		 (D_('iso_639_3', 'Galician'), 'gl'),
-		 (D_('iso_639_3', 'Georgian'), 'ka'),
-		 (D_('iso_639_3', 'German'), 'de'),
-		 (D_('iso_639_3', 'Greek, Modern (1453-)'), 'el'),
-		 (D_('iso_639_3', 'Hebrew'), 'he'),
-		 (D_('iso_639_3', 'Hindi'), 'hi'),
-		 (D_('iso_639_3', 'Hungarian'), 'hu'),
-		 (D_('iso_639_3', 'Icelandic'), 'is'),
-		 (D_('iso_639_3', 'Indonesian'), 'id'),
-		 (D_('iso_639_3', 'Italian'), 'it'),
-		 (D_('iso_639_3', 'Japanese'), 'ja'),
-		 (D_('iso_639_3', 'Kazakh'), 'kk'),
-		 (D_('iso_639_3', 'Korean'), 'ko'),
-		 (D_('iso_639_3', 'Latvian'), 'lv'),
-		 (D_('iso_639_3', 'Lithuanian'), 'lt'),
-		 (D_('iso_639_3', 'Luxembourgish'), 'lb'),
-		 (D_('iso_639_3', 'Macedonian'), 'mk'),
-		 (D_('iso_639_3', 'Malay (macrolanguage)'), 'ms'),
-		 (D_('iso_639_3', 'Norwegian'), 'no'),
-		 (D_('iso_639_3', 'Occitan (post 1500)'), 'oc'),
-		 (D_('iso_639_3', 'Persian'), 'fa'),
-		 (D_('iso_639_3', 'Polish'), 'pl'),
-		 (D_('iso_639_3', 'Portuguese'), 'pt'),
-		 (D_('iso_639_3', 'Romanian'), 'ro'),
-		 (D_('iso_639_3', 'Russian'), 'ru'),
-		 (D_('iso_639_3', 'Serbian'), 'sr'),
-		 (D_('iso_639_3', 'Slovak'), 'sk'),
-		 (D_('iso_639_3', 'Slovenian'), 'sl'),
-		 (D_('iso_639_3', 'Spanish'), 'es'),
-		 (D_('iso_639_3', 'Swedish'), 'sv'),
-		 (D_('iso_639_3', 'Thai'), 'th'),
-		 (D_('iso_639_3', 'Turkish'), 'tr'),
-		 (D_('iso_639_3', 'Ukrainian'), 'uk'),
-		 (D_('iso_639_3', 'Vietnamese'), 'vi'),]
+# Map of the language codes used by opensubtitles.org's API to their
+# human-readable name
+LANGUAGES_STR = [ (D_('iso_639_3', 'Albanian'), 'sq'),
+         (D_('iso_639_3', 'Arabic'), 'ar'),
+         (D_('iso_639_3', 'Armenian'), 'hy'),
+         (D_('iso_639_3', 'Neo-Aramaic, Assyrian'), 'ay'),
+         (D_('iso_639_3', 'Bosnian'), 'bs'),
+         (_('Brasilian Portuguese'), 'pb'),
+         (D_('iso_639_3', 'Bulgarian'), 'bg'),
+         (D_('iso_639_3', 'Catalan'), 'ca'),
+         (D_('iso_639_3', 'Chinese'), 'zh'),
+         (D_('iso_639_3', 'Croatian'), 'hr'),
+         (D_('iso_639_3', 'Czech'), 'cs'),
+         (D_('iso_639_3', 'Danish'), 'da'),
+         (D_('iso_639_3', 'Dutch'), 'nl'),
+         (D_('iso_639_3', 'English'), 'en'),
+         (D_('iso_639_3', 'Esperanto'), 'eo'),
+         (D_('iso_639_3', 'Estonian'), 'et'),
+         (D_('iso_639_3', 'Finnish'), 'fi'),
+         (D_('iso_639_3', 'French'), 'fr'),
+         (D_('iso_639_3', 'Galician'), 'gl'),
+         (D_('iso_639_3', 'Georgian'), 'ka'),
+         (D_('iso_639_3', 'German'), 'de'),
+         (D_('iso_639_3', 'Greek, Modern (1453-)'), 'el'),
+         (D_('iso_639_3', 'Hebrew'), 'he'),
+         (D_('iso_639_3', 'Hindi'), 'hi'),
+         (D_('iso_639_3', 'Hungarian'), 'hu'),
+         (D_('iso_639_3', 'Icelandic'), 'is'),
+         (D_('iso_639_3', 'Indonesian'), 'id'),
+         (D_('iso_639_3', 'Italian'), 'it'),
+         (D_('iso_639_3', 'Japanese'), 'ja'),
+         (D_('iso_639_3', 'Kazakh'), 'kk'),
+         (D_('iso_639_3', 'Korean'), 'ko'),
+         (D_('iso_639_3', 'Latvian'), 'lv'),
+         (D_('iso_639_3', 'Lithuanian'), 'lt'),
+         (D_('iso_639_3', 'Luxembourgish'), 'lb'),
+         (D_('iso_639_3', 'Macedonian'), 'mk'),
+         (D_('iso_639_3', 'Malay (macrolanguage)'), 'ms'),
+         (D_('iso_639_3', 'Norwegian'), 'no'),
+         (D_('iso_639_3', 'Occitan (post 1500)'), 'oc'),
+         (D_('iso_639_3', 'Persian'), 'fa'),
+         (D_('iso_639_3', 'Polish'), 'pl'),
+         (D_('iso_639_3', 'Portuguese'), 'pt'),
+         (D_('iso_639_3', 'Romanian'), 'ro'),
+         (D_('iso_639_3', 'Russian'), 'ru'),
+         (D_('iso_639_3', 'Serbian'), 'sr'),
+         (D_('iso_639_3', 'Slovak'), 'sk'),
+         (D_('iso_639_3', 'Slovenian'), 'sl'),
+         (D_('iso_639_3', 'Spanish'), 'es'),
+         (D_('iso_639_3', 'Swedish'), 'sv'),
+         (D_('iso_639_3', 'Thai'), 'th'),
+         (D_('iso_639_3', 'Turkish'), 'tr'),
+         (D_('iso_639_3', 'Ukrainian'), 'uk'),
+         (D_('iso_639_3', 'Vietnamese'), 'vi'),]
 
 # Map of ISO 639-1 language codes to the codes used by opensubtitles.org's API
-LANGUAGES =     {'sq':'alb',
-		 'ar':'ara',
-		 'hy':'arm',
-		 'ay':'ass',
-		 'bs':'bos',
-		 'pb':'pob',
-		 'bg':'bul',
-		 'ca':'cat',
-		 'zh':'chi',
-		 'hr':'hrv',
-		 'cs':'cze',
-		 'da':'dan',
-		 'nl':'dut',
-		 'en':'eng',
-		 'eo':'epo',
-		 'et':'est',
-		 'fi':'fin',
-		 'fr':'fre',
-		 'gl':'glg',
-		 'ka':'geo',
-		 'de':'ger',
-		 'el':'ell',
-		 'he':'heb',
-		 'hi':'hin',
-		 'hu':'hun',
-		 'is':'ice',
-		 'id':'ind',
-		 'it':'ita',
-		 'ja':'jpn',
-		 'kk':'kaz',
-		 'ko':'kor',
-		 'lv':'lav',
-		 'lt':'lit',
-		 'lb':'ltz',
-		 'mk':'mac',
-		 'ms':'may',
-		 'no':'nor',
-		 'oc':'oci',
-		 'fa':'per',
-		 'pl':'pol',
-		 'pt':'por',
-		 'ro':'rum',
-		 'ru':'rus',
-		 'sr':'scc',
-		 'sk':'slo',
-		 'sl':'slv',
-		 'es':'spa',
-		 'sv':'swe',
-		 'th':'tha',
-		 'tr':'tur',
-		 'uk':'ukr',
-		 'vi':'vie',}
-
-class SearchThread(threading.Thread):
+LANGUAGES = {'sq':'alb',
+         'ar':'ara',
+         'hy':'arm',
+         'ay':'ass',
+         'bs':'bos',
+         'pb':'pob',
+         'bg':'bul',
+         'ca':'cat',
+         'zh':'chi',
+         'hr':'hrv',
+         'cs':'cze',
+         'da':'dan',
+         'nl':'dut',
+         'en':'eng',
+         'eo':'epo',
+         'et':'est',
+         'fi':'fin',
+         'fr':'fre',
+         'gl':'glg',
+         'ka':'geo',
+         'de':'ger',
+         'el':'ell',
+         'he':'heb',
+         'hi':'hin',
+         'hu':'hun',
+         'is':'ice',
+         'id':'ind',
+         'it':'ita',
+         'ja':'jpn',
+         'kk':'kaz',
+         'ko':'kor',
+         'lv':'lav',
+         'lt':'lit',
+         'lb':'ltz',
+         'mk':'mac',
+         'ms':'may',
+         'no':'nor',
+         'oc':'oci',
+         'fa':'per',
+         'pl':'pol',
+         'pt':'por',
+         'ro':'rum',
+         'ru':'rus',
+         'sr':'scc',
+         'sk':'slo',
+         'sl':'slv',
+         'es':'spa',
+         'sv':'swe',
+         'th':'tha',
+         'tr':'tur',
+         'uk':'ukr',
+         'vi':'vie',}
+
+class SearchThread (threading.Thread):
     """
     This is the thread started when the dialog is searching for subtitles
     """
-    def __init__(self, model):
+    def __init__ (self, model):
         self.model = model
         self._done = False
-        self._lock = threading.Lock()
-        threading.Thread.__init__(self)
+        self._lock = threading.Lock ()
+        threading.Thread.__init__ (self)
 
-    def run(self):
-        self.model.lock.acquire(True)
-        self.model.results = self.model.os_search_subtitles()
-        self.model.lock.release()
+    def run (self):
+        self.model.lock.acquire (True)
+        self.model.results = self.model.os_search_subtitles ()
+        self.model.lock.release ()
         self._done = True
-	
+
     @property
-    def done(self):
+    def done (self):
         """ Thread-safe property to know whether the query is done or not """
-        self._lock.acquire(True)
+        self._lock.acquire (True)
         res = self._done
-        self._lock.release()
+        self._lock.release ()
         return res
 
-class DownloadThread(threading.Thread):
+class DownloadThread (threading.Thread):
     """
     This is the thread started when the dialog is downloading the subtitles.
     """
-    def __init__(self, model, subtitle_id):
+    def __init__ (self, model, subtitle_id):
         self.model = model
         self.subtitle_id = subtitle_id
         self._done = False
-        self._lock = threading.Lock()
-        threading.Thread.__init__(self)
+        self._lock = threading.Lock ()
+        threading.Thread.__init__ (self)
+
+    def run (self):
+        model = self.model
+
+        model.lock.acquire (True)
+        model.subtitles = model.os_download_subtitles (self.subtitle_id)
+        model.lock.release ()
 
-    def run(self):
-        self.model.lock.acquire(True)
-        self.model.subtitles = self.model.os_download_subtitles(self.subtitle_id)
-        self.model.lock.release()
         self._done = True
-    
+
     @property
-    def done(self):
+    def done (self):
         """ Thread-safe property to know whether the query is done or not """
-        self._lock.acquire(True)
+        self._lock.acquire (True)
         res = self._done
-        self._lock.release()
+        self._lock.release ()
         return res
 
 # OpenSubtitles.org API abstraction
 
-class OpenSubtitlesModel(object):
+class OpenSubtitlesModel (object):
     """
     This contains the logic of the opensubtitles service.
     """
-    def __init__(self, server):
+    def __init__ (self, server):
         self.server = server
         self.token = None
 
         try:
             import locale
-            self.lang = LANGUAGES[locale.getlocale()[0].split('_')[0]]
+            self.lang = LANGUAGES[locale.getlocale ()[0].split ('_')[0]]
         except:
             self.lang = 'eng'
         self.hash = None
         self.size = 0
 
-        self.lock = threading.Lock()
+        self.lock = threading.Lock ()
         self.results = []
         self.subtitles = ''
 
         self.message = ''
 
-    def os_login(self, username='', password=''):
+    def os_login (self, username='', password=''):
         """
         Logs into the opensubtitles web service and gets a valid token for
         the comming comunications. If we are already logged it only checks
@@ -230,17 +234,18 @@ class OpenSubtitlesModel(object):
         if self.token:
             # We have already logged-in before, check the connection
             try:
-                result = self.server.NoOperation(self.token)
+                result = self.server.NoOperation (self.token)
             except:
                 pass
             if result and result['status'] != OK200:
                 return True
         try:
-            result = self.server.LogIn(username, password, self.lang, USER_AGENT)
+            result = self.server.LogIn (username, password, self.lang,
+                                        USER_AGENT)
         except:
             pass
-        if result and result.get('status') == OK200:
-            self.token = result.get('token')
+        if result and result.get ('status') == OK200:
+            self.token = result.get ('token')
             if self.token:
                 return True
 
@@ -248,421 +253,448 @@ class OpenSubtitlesModel(object):
 
         return False
 
-    def os_search_subtitles(self):
+    def os_search_subtitles (self):
         """
 
         """
         self.message = ''
-        if self.os_login():
-            searchdata = {'sublanguageid': self.lang, 
-                          'moviehash'    : self.hash, 
-                          'moviebytesize': str(self.size)}
+        if self.os_login ():
+            searchdata = {'sublanguageid': self.lang,
+                          'moviehash'    : self.hash,
+                          'moviebytesize': str (self.size)}
             try:
-                result = self.server.SearchSubtitles(self.token, [searchdata])
+                result = self.server.SearchSubtitles (self.token, [searchdata])
             except xmlrpclib.ProtocolError:
                 self.message = _(u'Could not contact the OpenSubtitles website')
 
-            if result.get('data'):
+            if result.get ('data'):
                 return result['data']
             else:
                 self.message = _(u'No results found')
 
         return None
 
-    def os_download_subtitles(self, subtitleId):
+    def os_download_subtitles (self, subtitleId):
         """
         """
         self.message = ''
-        if self.os_login():
+        error_message = _(u'Could not contact the OpenSubtitles website')
+
+        if self.os_login ():
             try:
-                result = self.server.DownloadSubtitles(self.token, [subtitleId])
+                result = self.server.DownloadSubtitles (self.token,
+                                                        [subtitleId])
             except xmlrpclib.ProtocolError:
-                self.message = _(u'Could not contact the OpenSubtitles website')
+                self.message = error_message
 
-            if result and result.get('status') == OK200:
+            if result and result.get ('status') == OK200:
                 try:
                     subtitle64 = result['data'][0]['data']
                 except:
-                    self.message = _(u'Could not contact the OpenSubtitles website')
+                    self.message = error_message
                     return None
 
                 import StringIO, gzip, base64
-                subtitleDecoded = base64.decodestring(subtitle64)
-                subtitleGzipped = StringIO.StringIO(subtitleDecoded)
-                subtitleGzippedFile = gzip.GzipFile(fileobj=subtitleGzipped)
+                subtitleDecoded = base64.decodestring (subtitle64)
+                subtitleGzipped = StringIO.StringIO (subtitleDecoded)
+                subtitleGzippedFile = gzip.GzipFile (fileobj=subtitleGzipped)
 
-                return subtitleGzippedFile.read()
+                return subtitleGzippedFile.read ()
 
         return None
 
-class OpenSubtitles(gobject.GObject, Peas.Activatable):
+class OpenSubtitles (gobject.GObject, Peas.Activatable):
     __gtype_name__ = 'OpenSubtitles'
 
-    object = gobject.property(type = gobject.GObject)
+    object = gobject.property (type = gobject.GObject)
 
-    def __init__(self):
+    def __init__ (self):
         self.dialog = None
         self.totem = None
-        self.settings = Gio.Settings.new ('org.gnome.totem.plugins.opensubtitles')
+        schema = 'org.gnome.totem.plugins.opensubtitles'
+        self.settings = Gio.Settings.new (schema)
 
     # totem.Plugin methods
 
-    def do_activate(self):
+    def do_activate (self):
         """
         Called when the plugin is activated.
-        Here the sidebar page is initialized(set up the treeview, connect 
+        Here the sidebar page is initialized (set up the treeview, connect
         the callbacks, ...) and added to totem.
         """
         self.totem = self.object
-	self.filename = None
+        self.filename = None
 
-        self.manager = self.totem.get_ui_manager()
-        self.os_append_menu()
+        self.manager = self.totem.get_ui_manager ()
+        self.os_append_menu ()
 
-        self.totem.connect('file-opened', self.on_totem__file_opened)
-        self.totem.connect('file-closed', self.on_totem__file_closed)
+        self.totem.connect ('file-opened', self.on_totem__file_opened)
+        self.totem.connect ('file-closed', self.on_totem__file_closed)
 
-	# Obtain the ServerProxy and init the model
-        server = xmlrpclib.Server('http://api.opensubtitles.org/xml-rpc')
-        self.model = OpenSubtitlesModel(server)
+        # Obtain the ServerProxy and init the model
+        server = xmlrpclib.Server ('http://api.opensubtitles.org/xml-rpc')
+        self.model = OpenSubtitlesModel (server)
 
-    def do_deactivate(self):
+    def do_deactivate (self):
         if self.dialog:
-            self.dialog.destroy()
-	    self.dialog = None
-	
-        self.os_delete_menu()
+            self.dialog.destroy ()
+        self.dialog = None
+
+        self.os_delete_menu ()
 
     # UI related code
 
-    def os_build_dialog(self, action):
-        builder = Totem.plugin_load_interface ("opensubtitles", "opensubtitles.ui", True, self.totem.get_main_window (), self)
+    def os_build_dialog (self, action):
+        builder = Totem.plugin_load_interface ("opensubtitles",
+                                               "opensubtitles.ui", True,
+                                               self.totem.get_main_window (),
+                                               self)
 
         # Obtain all the widgets we need to initialize
-        combobox =       builder.get_object('language_combobox')
-        languages =      builder.get_object('language_model')
-        self.progress =  builder.get_object('progress_bar')
-        self.treeview =  builder.get_object('subtitle_treeview')
-        self.liststore = builder.get_object('subtitle_model')
-        self.dialog =    builder.get_object('subtitles_dialog')
-	self.find_button = builder.get_object('find_button')
-	self.apply_button = builder.get_object('apply_button')
-	self.close_button = builder.get_object('close_button')
+        combobox = builder.get_object ('language_combobox')
+        languages = builder.get_object ('language_model')
+        self.progress = builder.get_object ('progress_bar')
+        self.treeview = builder.get_object ('subtitle_treeview')
+        self.liststore = builder.get_object ('subtitle_model')
+        self.dialog = builder.get_object ('subtitles_dialog')
+        self.find_button = builder.get_object ('find_button')
+        self.apply_button = builder.get_object ('apply_button')
+        self.close_button = builder.get_object ('close_button')
 
         # Set up and populate the languages combobox
-        renderer = Gtk.CellRendererText()
+        renderer = Gtk.CellRendererText ()
         sorted_languages = Gtk.TreeModelSort (model = languages)
-        sorted_languages.set_sort_column_id(0, Gtk.SortType.ASCENDING)
-        combobox.set_model(sorted_languages)
-        combobox.pack_start(renderer, True)
-        combobox.add_attribute(renderer, 'text', 0)
+        sorted_languages.set_sort_column_id (0, Gtk.SortType.ASCENDING)
+        combobox.set_model (sorted_languages)
+        combobox.pack_start (renderer, True)
+        combobox.add_attribute (renderer, 'text', 0)
 
         lang = self.settings.get_string ('language')
         if lang is not None:
             self.model.lang = lang
 
         for lang in LANGUAGES_STR:
-            it = languages.append(lang)
+            it = languages.append (lang)
             if LANGUAGES[lang[1]] == self.model.lang:
-                (success, parentit) = sorted_languages.convert_child_iter_to_iter (it)
+                (success,
+                 parentit) = sorted_languages.convert_child_iter_to_iter (it)
                 if success:
                     combobox.set_active_iter (parentit)
 
-        # Set up the results treeview 
-        renderer = Gtk.CellRendererText()
-        self.treeview.set_model(self.liststore)
-        self.treeview.set_headers_visible(False)
-        renderer.set_property('ellipsize', Pango.EllipsizeMode.END)
-        column = Gtk.TreeViewColumn(_(u"Subtitles"), renderer, text=0)
-        column.set_resizable(True)
-        column.set_expand(True)
-        self.treeview.append_column(column)
-	# translators comment:
-	# This is the file-type of the subtitle file detected
-        column = Gtk.TreeViewColumn(_(u"Format"), renderer, text=1)
-        column.set_resizable(False)
-        self.treeview.append_column(column)
-	# translators comment:
-	# This is a rating of the quality of the subtitle
-        column = Gtk.TreeViewColumn(_(u"Rating"), renderer, text=2)
-        column.set_resizable(False)
-        self.treeview.append_column(column)
-
-	self.apply_button.set_sensitive(False)
-
-        self.apply_button.connect('clicked', self.on_apply_clicked)
-        self.find_button.connect('clicked', self.on_find_clicked)
-        self.close_button.connect('clicked', self.on_close_clicked)
-
-	# Set up signals
-
-        combobox_changed_id = combobox.connect('changed', self.on_combobox__changed)
-	self.dialog.connect ('delete-event', self.dialog.hide_on_delete)
-	self.dialog.set_transient_for (self.totem.get_main_window())
-	self.dialog.set_position (Gtk.WindowPosition.CENTER_ON_PARENT)
-
-	# Connect the callbacks
-	self.dialog.connect ('key-press-event', self.on_window__key_press_event)
-        self.treeview.get_selection().connect('changed', self.on_treeview__row_change)
-        self.treeview.connect('row-activated', self.on_treeview__row_activate)
-
-    def os_show_dialog(self, action):
+        # Set up the results treeview
+        renderer = Gtk.CellRendererText ()
+        self.treeview.set_model (self.liststore)
+        self.treeview.set_headers_visible (False)
+        renderer.set_property ('ellipsize', Pango.EllipsizeMode.END)
+        column = Gtk.TreeViewColumn (_(u"Subtitles"), renderer, text=0)
+        column.set_resizable (True)
+        column.set_expand (True)
+        self.treeview.append_column (column)
+        # translators comment:
+        # This is the file-type of the subtitle file detected
+        column = Gtk.TreeViewColumn (_(u"Format"), renderer, text=1)
+        column.set_resizable (False)
+        self.treeview.append_column (column)
+        # translators comment:
+        # This is a rating of the quality of the subtitle
+        column = Gtk.TreeViewColumn (_(u"Rating"), renderer, text=2)
+        column.set_resizable (False)
+        self.treeview.append_column (column)
+
+        self.apply_button.set_sensitive (False)
+
+        self.apply_button.connect ('clicked', self.on_apply_clicked)
+        self.find_button.connect ('clicked', self.on_find_clicked)
+        self.close_button.connect ('clicked', self.on_close_clicked)
+
+        # Set up signals
+
+        combobox_changed_id = combobox.connect ('changed',
+                                                self.on_combobox__changed)
+        self.dialog.connect ('delete-event', self.dialog.hide_on_delete)
+        self.dialog.set_transient_for (self.totem.get_main_window ())
+        self.dialog.set_position (Gtk.WindowPosition.CENTER_ON_PARENT)
+
+        # Connect the callbacks
+        self.dialog.connect ('key-press-event', self.on_window__key_press_event)
+        self.treeview.get_selection ().connect ('changed',
+                                                self.on_treeview__row_change)
+        self.treeview.connect ('row-activated', self.on_treeview__row_activate)
+
+    def os_show_dialog (self, action):
         if not self.dialog:
-            self.os_build_dialog(action)
+            self.os_build_dialog (action)
 
-        filename = self.totem.get_current_mrl()
+        filename = self.totem.get_current_mrl ()
         if not self.model.results or filename != self.filename:
             self.filename = filename
 
-        self.dialog.show_all()
+        self.dialog.show_all ()
 
-	self.progress.set_fraction(0.0)
+        self.progress.set_fraction (0.0)
 
-    def os_append_menu(self):
+    def os_append_menu (self):
         """
         """
-	
-        self.os_action_group = Gtk.ActionGroup(name='OpenSubtitles')
 
-        self.action = Gtk.Action(name='opensubtitles',
+        self.os_action_group = Gtk.ActionGroup (name='OpenSubtitles')
+
+        tooltip_text = _(u"Download movie subtitles from OpenSubtitles")
+        self.action = Gtk.Action (name='opensubtitles',
                                  label=_(u'_Download Movie Subtitlesâ?¦'),
-                                 tooltip=_(u"Download movie subtitles from OpenSubtitles"),
+                                 tooltip=tooltip_text,
                                  stock_id=None)
 
-        self.os_action_group.add_action(self.action)
+        self.os_action_group.add_action (self.action)
 
-        self.manager.insert_action_group(self.os_action_group, 0)
+        self.manager.insert_action_group (self.os_action_group, 0)
 
-        self.menu_id = self.manager.new_merge_id()
-        self.manager.add_ui(self.menu_id,
-                             '/tmw-menubar/view/subtitles/subtitle-download-placeholder',
+        self.menu_id = self.manager.new_merge_id ()
+        path = '/tmw-menubar/view/subtitles/subtitle-download-placeholder'
+        self.manager.add_ui (self.menu_id,
+                             path,
                              'opensubtitles',
                              'opensubtitles',
                              Gtk.UIManagerItemType.MENUITEM,
                              False
                             )
-        self.action.set_visible(True)
+        self.action.set_visible (True)
 
-        self.manager.ensure_update()
+        self.manager.ensure_update ()
 
-        self.action.connect('activate', self.os_show_dialog)
+        self.action.connect ('activate', self.os_show_dialog)
 
-        self.action.set_sensitive(self.totem.is_playing() and
-				  self.os_check_allowed_scheme() and
-                                  not self.os_check_is_audio())
+        self.action.set_sensitive (self.totem.is_playing () and
+                  self.os_check_allowed_scheme () and
+                                  not self.os_check_is_audio ())
 
-    def os_check_allowed_scheme(self):
-        scheme = Gio.file_new_for_uri(self.totem.get_current_mrl()).get_uri_scheme()
-        if scheme == 'dvd' or scheme == 'http' or scheme == 'dvb' or scheme == 'vcd':
+    def os_check_allowed_scheme (self):
+        current_file = Gio.file_new_for_uri (self.totem.get_current_mrl ())
+        scheme = current_file.get_uri_scheme ()
+
+        if (scheme == 'dvd' or scheme == 'http' or
+            scheme == 'dvb' or scheme == 'vcd'):
             return False
+
         return True
 
-    def os_check_is_audio(self):
+    def os_check_is_audio (self):
         # FIXME need to use something else here
-        # I think we must use video widget metadata but I don't found a way 
-	# to get this info from python
-        filename = self.totem.get_current_mrl()
-        if Gio.content_type_guess(filename, '')[0].split('/')[0] == 'audio':
+        # I think we must use video widget metadata but I don't found a way
+        # to get this info from python
+        filename = self.totem.get_current_mrl ()
+        if Gio.content_type_guess (filename, '')[0].split ('/')[0] == 'audio':
             return True
         return False
 
-    def os_delete_menu(self):
-        self.manager.remove_action_group(self.os_action_group)
-        self.manager.remove_ui(self.menu_id)
+    def os_delete_menu (self):
+        self.manager.remove_action_group (self.os_action_group)
+        self.manager.remove_ui (self.menu_id)
 
-    def os_get_results(self):
+    def os_get_results (self):
         """
         """
-        self.liststore.clear()
-	self.treeview.set_headers_visible(False)
+        self.liststore.clear ()
+        self.treeview.set_headers_visible (False)
         self.model.results = []
-        self.apply_button.set_sensitive(False)
-	self.find_button.set_sensitive(False)        
+        self.apply_button.set_sensitive (False)
+        self.find_button.set_sensitive (False)
 
-        self.dialog.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
+        cursor = Gdk.Cursor.new (Gdk.CursorType.WATCH)
+        self.dialog.get_window ().set_cursor (cursor)
 
-        thread = SearchThread(self.model)
-        thread.start()
-        gobject.idle_add(self.os_populate_treeview)
+        thread = SearchThread (self.model)
+        thread.start ()
+        gobject.idle_add (self.os_populate_treeview)
 
-        self.progress.set_text(_(u'Searching subtitlesâ?¦'))
-        gobject.timeout_add(350, self.os_progress_bar_increment, thread)
+        self.progress.set_text (_(u'Searching subtitlesâ?¦'))
+        gobject.timeout_add (350, self.os_progress_bar_increment, thread)
 
-    def os_populate_treeview(self):
+    def os_populate_treeview (self):
         """
         """
-        if self.model.lock.acquire(False) == False:
+        if self.model.lock.acquire (False) == False:
             return True
 
         if self.model.results:
-            self.apply_button.set_sensitive(True)
+            self.apply_button.set_sensitive (True)
             for subData in self.model.results:
-		if not SUBTITLES_EXT.count(subData['SubFormat']):
-			continue
-                self.liststore.append([subData['SubFileName'], subData['SubFormat'], subData['SubRating'], subData['IDSubtitleFile'],])
-	        self.treeview.set_headers_visible(True)
+                if not SUBTITLES_EXT.count (subData['SubFormat']):
+                    continue
+                self.liststore.append ([subData['SubFileName'],
+                                        subData['SubFormat'],
+                                        subData['SubRating'],
+                                        subData['IDSubtitleFile'],])
+                self.treeview.set_headers_visible (True)
         else:
-            self.apply_button.set_sensitive(False)
+            self.apply_button.set_sensitive (False)
 
-        self.model.lock.release()
+        self.model.lock.release ()
 
-        self.dialog.get_window().set_cursor(None)
+        self.dialog.get_window ().set_cursor (None)
 
         return False
 
-    def os_save_selected_subtitle(self, filename=None):
+    def os_save_selected_subtitle (self, filename=None):
         """
         """
-        self.dialog.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
+        cursor = Gdk.Cursor.new (Gdk.CursorType.WATCH)
+        self.dialog.get_window ().set_cursor (cursor)
 
-        model, rows = self.treeview.get_selection().get_selected_rows()
+        model, rows = self.treeview.get_selection ().get_selected_rows ()
         if rows:
-            iter = model.get_iter(rows[0])
-            subtitle_id = model.get_value(iter, 3)
-            subtitle_format = model.get_value(iter, 1)
+            iter = model.get_iter (rows[0])
+            subtitle_id = model.get_value (iter, 3)
+            subtitle_format = model.get_value (iter, 1)
 
             gfile = None
 
             if not filename:
-                directory = Gio.file_new_for_path(xdg.BaseDirectory.xdg_cache_home + sep + 'totem' + sep + 'subtitles' + sep) 
-                if not directory.query_exists(None):
-                    if not path.exists (xdg.BaseDirectory.xdg_cache_home + sep + 'totem' + sep):
-                        mkdir (xdg.BaseDirectory.xdg_cache_home + sep + 'totem' + sep)
-                    if not path.exists (xdg.BaseDirectory.xdg_cache_home + sep + 'totem' + sep + 'subtitles' + sep):
-                        mkdir (xdg.BaseDirectory.xdg_cache_home + sep + 'totem' + sep + 'subtitles' + sep)
-                    # FIXME: We can't use this function until we depend on GLib (PyGObject) 2.18
-                    # directory.make_directory_with_parents()
-
-                file = Gio.file_new_for_path(self.filename)
-                movie_name = file.get_basename().rpartition('.')[0]
-                filename = directory.get_uri() + sep + movie_name + '.' + subtitle_format
+                bpath = xdg.BaseDirectory.xdg_cache_home + sep
+                bpath += 'totem' + sep
+
+                directory = Gio.file_new_for_path (bpath + 'subtitles' + sep)
+
+                if not directory.query_exists (None):
+                    if not path.exists (bpath):
+                        mkdir (bpath)
+                    if not path.exists (bpath + 'subtitles' + sep):
+                        mkdir (bpath + 'subtitles' + sep)
+                    # FIXME: We can't use this function until we depend on
+                    # GLib (PyGObject) 2.18
+                    # directory.make_directory_with_parents ()
+
+                file = Gio.file_new_for_path (self.filename)
+                movie_name = file.get_basename ().rpartition ('.')[0]
+
+                filename = directory.get_uri () + sep
+                filename += movie_name + '.' + subtitle_format
 
             self.model.subtitles = ''
 
-            thread = DownloadThread(self.model, subtitle_id)
-            thread.start()
-            gobject.idle_add(self.os_save_subtitles, filename)
+            thread = DownloadThread (self.model, subtitle_id)
+            thread.start ()
+            gobject.idle_add (self.os_save_subtitles, filename)
 
-            self.progress.set_text(_(u'Downloading the subtitlesâ?¦'))
-            gobject.timeout_add(350, self.os_progress_bar_increment, thread)
+            self.progress.set_text (_(u'Downloading the subtitlesâ?¦'))
+            gobject.timeout_add (350, self.os_progress_bar_increment, thread)
         else:
             #warn user!
             pass
 
-    def os_save_subtitles(self, filename):
-        if self.model.lock.acquire(False) == False:
+    def os_save_subtitles (self, filename):
+        if self.model.lock.acquire (False) == False:
             return True
 
         if self.model.subtitles:
-            # Delete all previous cached subtitle for this file 
+            # Delete all previous cached subtitle for this file
             for ext in SUBTITLES_EXT:
-		fp = Gio.file_new_for_path(filename[:-3] + ext)
-		if fp.query_exists(None):
-                    fp.delete(None)
+                fp = Gio.file_new_for_path (filename[:-3] + ext)
+                if fp.query_exists (None):
+                    fp.delete (None)
 
             fp = Gio.file_new_for_uri (filename)
             suburi = fp.get_uri ()
 
-            subFile  = fp.replace('', False)
-            subFile.write(self.model.subtitles)
-            subFile.close()
+            subFile = fp.replace ('', False)
+            subFile.write (self.model.subtitles)
+            subFile.close ()
 
-        self.model.lock.release()
+        self.model.lock.release ()
 
-        self.dialog.get_window().set_cursor(None)
+        self.dialog.get_window ().set_cursor (None)
         self.on_close_clicked (None)
 
         if suburi:
-            self.totem.set_current_subtitle(suburi)
+            self.totem.set_current_subtitle (suburi)
 
         return False
 
-    def os_progress_bar_increment(self, thread):
-
+    def os_progress_bar_increment (self, thread):
         if not thread.done:
-            self.progress.pulse()
+            self.progress.pulse ()
             return True
 
         if self.model.message:
-            self.progress.set_text(self.model.message)
+            self.progress.set_text (self.model.message)
         else:
-            self.progress.set_text('')
-	
-	self.progress.set_fraction(0.0)
-	self.find_button.set_sensitive(True)
-        self.apply_button.set_sensitive(False)
-        self.treeview.set_sensitive(True)
+            self.progress.set_text ('')
+
+        self.progress.set_fraction (0.0)
+        self.find_button.set_sensitive (True)
+        self.apply_button.set_sensitive (False)
+        self.treeview.set_sensitive (True)
         return False
 
-    def os_download_and_apply(self):
-        self.apply_button.set_sensitive(False)
-        self.find_button.set_sensitive(False)
-        self.action.set_sensitive(False)
-        self.treeview.set_sensitive(False)
-        self.os_save_selected_subtitle()
+    def os_download_and_apply (self):
+        self.apply_button.set_sensitive (False)
+        self.find_button.set_sensitive (False)
+        self.action.set_sensitive (False)
+        self.treeview.set_sensitive (False)
+        self.os_save_selected_subtitle ()
 
     # Callbacks
 
-    def on_window__key_press_event(self, widget, event):
+    def on_window__key_press_event (self, widget, event):
         if event.keyval == Gdk.KEY_Escape:
-            self.dialog.destroy()
+            self.dialog.destroy ()
             self.dialog = None
             return True
         return False
 
-    def on_treeview__row_change(self, selection):
-        if selection.count_selected_rows() > 0:
-            self.apply_button.set_sensitive(True)
+    def on_treeview__row_change (self, selection):
+        if selection.count_selected_rows () > 0:
+            self.apply_button.set_sensitive (True)
         else:
-            self.apply_button.set_sensitive(False)
+            self.apply_button.set_sensitive (False)
 
-    def on_treeview__row_activate(self, path, column, data):
-	self.os_download_and_apply()
+    def on_treeview__row_activate (self, path, column, data):
+        self.os_download_and_apply ()
 
-    def on_totem__file_opened(self, totem, filename):
+    def on_totem__file_opened (self, totem, filename):
         """
         """
         # Check if allows subtitles
-	if self.os_check_allowed_scheme() and not self.os_check_is_audio():
-            self.action.set_sensitive(True)
-	    if self.dialog:
-	    	self.find_button.set_sensitive(True)
-		self.filename = self.totem.get_current_mrl()
-		self.liststore.clear()
-	        self.treeview.set_headers_visible(False)
-	    	self.apply_button.set_sensitive(False)
-		self.results = [] 
-	else:
-            self.action.set_sensitive(False)
-	    if self.dialog and self.dialog.is_active():
-                self.liststore.clear()
-	        self.treeview.set_headers_visible(False)
-	    	self.apply_button.set_sensitive(False)
-	    	self.find_button.set_sensitive(False)
-
-    def on_totem__file_closed(self, totem):
-        self.action.set_sensitive(False)
+        if self.os_check_allowed_scheme () and not self.os_check_is_audio ():
+            self.action.set_sensitive (True)
+            if self.dialog:
+                self.find_button.set_sensitive (True)
+                self.filename = self.totem.get_current_mrl ()
+                self.liststore.clear ()
+                self.treeview.set_headers_visible (False)
+                self.apply_button.set_sensitive (False)
+                self.results = []
+        else:
+            self.action.set_sensitive (False)
+            if self.dialog and self.dialog.is_active ():
+                self.liststore.clear ()
+                self.treeview.set_headers_visible (False)
+                self.apply_button.set_sensitive (False)
+                self.find_button.set_sensitive (False)
+
+    def on_totem__file_closed (self, totem):
+        self.action.set_sensitive (False)
         if self.dialog:
-	    self.apply_button.set_sensitive(False)
-	    self.find_button.set_sensitive(False)
+            self.apply_button.set_sensitive (False)
+            self.find_button.set_sensitive (False)
 
-    def on_combobox__changed(self, combobox):
-        iter = combobox.get_active_iter()
-        self.model.lang = LANGUAGES[combobox.get_model().get_value(iter, 1)]
-        self.settings.set_string('language', self.model.lang)
+    def on_combobox__changed (self, combobox):
+        iter = combobox.get_active_iter ()
+        self.model.lang = LANGUAGES[combobox.get_model ().get_value (iter, 1)]
+        self.settings.set_string ('language', self.model.lang)
 
-    def on_close_clicked(self, data):
-        self.dialog.destroy()
+    def on_close_clicked (self, data):
+        self.dialog.destroy ()
         self.dialog = None
 
-    def on_apply_clicked(self, data):
-	self.os_download_and_apply()
+    def on_apply_clicked (self, data):
+        self.os_download_and_apply ()
 
-    def on_find_clicked(self, data):
-        self.apply_button.set_sensitive(False)
-        self.find_button.set_sensitive(False)
-        self.filename = self.totem.get_current_mrl()
-        self.model.hash , self.model.size = hashFile(self.filename)
+    def on_find_clicked (self, data):
+        self.apply_button.set_sensitive (False)
+        self.find_button.set_sensitive (False)
+        self.filename = self.totem.get_current_mrl ()
+        self.model.hash , self.model.size = hashFile (self.filename)
 
-        self.os_get_results()
+        self.os_get_results ()
 
diff --git a/src/plugins/pythonconsole/pythonconsole.py b/src/plugins/pythonconsole/pythonconsole.py
index 6e6b286..a16244e 100644
--- a/src/plugins/pythonconsole/pythonconsole.py
+++ b/src/plugins/pythonconsole/pythonconsole.py
@@ -8,7 +8,7 @@
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 2, 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
@@ -18,7 +18,8 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-# Parts from "Interactive Python-GTK Console" (stolen from epiphany's console.py)
+# Parts from "Interactive Python-GTK Console" (stolen from epiphany's
+# console.py)
 #     Copyright (C), 1998 James Henstridge <james daa com au>
 #     Copyright (C), 2005 Adam Hooper <adamh densi com>
 # Bits from gedit Python Console Plugin
@@ -42,13 +43,13 @@ from gi.repository import Totem
 from gi.repository import Gio
 import gobject
 try:
-	import rpdb2
-	have_rpdb2 = True
+    import rpdb2
+    have_rpdb2 = True
 except:
-	have_rpdb2 = False
+    have_rpdb2 = False
 
 import gettext
-gettext.textdomain("totem")
+gettext.textdomain ("totem")
 
 D_ = gettext.dgettext
 _ = gettext.gettext
@@ -66,92 +67,104 @@ ui_str = """
 </ui>
 """
 
-class PythonConsolePlugin(gobject.GObject, Peas.Activatable):
-	__gtype_name__ = 'PythonConsolePlugin'
-
-	object = gobject.property(type = gobject.GObject)
-
-	def __init__(self):
-		self.totem = None
-		self.window = None
-	
-	def do_activate(self):
-		self.totem = self.object
-
-		data = dict()
-		manager = self.totem.get_ui_manager()
-
-		data['action_group'] = Gtk.ActionGroup(name = 'Python')
-		
-		action = Gtk.Action(name = 'Python', label = 'Python', tooltip = _(u'Python Console Menu'), stock_id = None)
-		data['action_group'].add_action(action)
-
-		action = Gtk.Action(name = 'PythonConsole', label = _(u'_Python Console'),
-		                    tooltip = _(u"Show Totem's Python console"),
-		                    stock_id = 'gnome-mime-text-x-python')
-		action.connect('activate', self.show_console)
-		data['action_group'].add_action(action)
-
-		action = Gtk.Action(name = 'PythonDebugger', label = _(u'Python Debugger'),
-				    tooltip = _(u"Enable remote Python debugging with rpdb2"), stock_id = None)
-		if have_rpdb2:
-			action.connect('activate', self.enable_debugging)
-		else:
-			action.set_visible(False)
-		data['action_group'].add_action(action)
-				
-		manager.insert_action_group(data['action_group'], 0)
-		data['ui_id'] = manager.add_ui_from_string(ui_str)
-		manager.ensure_update()
-		
-		self.totem.set_data('PythonConsolePluginInfo', data)
-	
-	def show_console(self, action):
-		if not self.window:
-			console = PythonConsole(namespace = {'__builtins__' : __builtins__,
-			                                     'Totem' : Totem,
-			                                     'totem_object' : self.totem},
-			                                     destroy_cb = self.destroy_console)
-
-			console.set_size_request(600, 400)
-			console.eval('print "%s" %% totem_object' % _(u"You can access the Totem.Object through " \
-				     "\'totem_object\' :\\n%s"), False)
-
-			self.window = Gtk.Window()
-			self.window.set_title(_(u'Totem Python Console'))
-			self.window.add(console)
-			self.window.connect('destroy', self.destroy_console)
-			self.window.show_all()
-		else:
-			self.window.show_all()
-			self.window.grab_focus()
-
-	def enable_debugging(self, action):
-		msg = _(u"After you press OK, Totem will wait until you connect to it with winpdb or rpdb2. If you have not set a debugger password in DConf, it will use the default password ('totem').")
-		dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.INFO, Gtk.ButtonsType.OK_CANCEL, msg)
-		if dialog.run() == Gtk.ResponseType.OK:
-			settings = Gio.Settings.new ('org.gnome.totem.plugins.pythonconsole')
-			password = settings.get_string('rpdb2-password') or "totem"
-			def start_debugger(password):
-				rpdb2.start_embedded_debugger(password)
-				return False
-
-			gobject.idle_add(start_debugger, password)
-		dialog.destroy()
-
-	def destroy_console(self, *args):
-		self.window.destroy()
-		self.window = None
-
-	def do_deactivate(self):
-		data = self.totem.get_data('PythonConsolePluginInfo')
-
-		manager = self.totem.get_ui_manager()
-		manager.remove_ui(data['ui_id'])
-		manager.remove_action_group(data['action_group'])
-		manager.ensure_update()
-
-		self.totem.set_data('PythonConsolePluginInfo', None)
-		
-		if self.window is not None:
-			self.window.destroy()
+class PythonConsolePlugin (gobject.GObject, Peas.Activatable):
+    __gtype_name__ = 'PythonConsolePlugin'
+
+    object = gobject.property (type = gobject.GObject)
+
+    def __init__ (self):
+        self.totem = None
+        self.window = None
+
+    def do_activate (self):
+        self.totem = self.object
+
+        data = dict ()
+        manager = self.totem.get_ui_manager ()
+
+        data['action_group'] = Gtk.ActionGroup (name = 'Python')
+
+        action = Gtk.Action (name = 'Python', label = 'Python',
+                             tooltip = _(u'Python Console Menu'),
+                             stock_id = None)
+        data['action_group'].add_action (action)
+
+        action = Gtk.Action (name = 'PythonConsole',
+                             label = _(u'_Python Console'),
+                             tooltip = _(u"Show Totem's Python console"),
+                             stock_id = 'gnome-mime-text-x-python')
+        action.connect ('activate', self.show_console)
+        data['action_group'].add_action (action)
+
+        action = Gtk.Action (name = 'PythonDebugger',
+                             label = _(u'Python Debugger'),
+                             tooltip = _(u"Enable remote Python debugging "\
+                                          "with rpdb2"),
+                             stock_id = None)
+        if have_rpdb2:
+            action.connect ('activate', self.enable_debugging)
+        else:
+            action.set_visible (False)
+        data['action_group'].add_action (action)
+
+        manager.insert_action_group (data['action_group'], 0)
+        data['ui_id'] = manager.add_ui_from_string (ui_str)
+        manager.ensure_update ()
+
+        self.totem.set_data ('PythonConsolePluginInfo', data)
+
+    def show_console (self, action):
+        if not self.window:
+            console = PythonConsole (namespace = {
+                '__builtins__' : __builtins__,
+                'Totem' : Totem,
+                'totem_object' : self.totem
+            }, destroy_cb = self.destroy_console)
+
+            console.set_size_request (600, 400)
+            console.eval ('print "%s" %% totem_object' % _(u"You can access "\
+                "the Totem.Object through \'totem_object\' :\\n%s"), False)
+
+            self.window = Gtk.Window ()
+            self.window.set_title (_(u'Totem Python Console'))
+            self.window.add (console)
+            self.window.connect ('destroy', self.destroy_console)
+            self.window.show_all ()
+        else:
+            self.window.show_all ()
+            self.window.grab_focus ()
+
+    def enable_debugging (self, action):
+        msg = _(u"After you press OK, Totem will wait until you connect to it "\
+                 "with winpdb or rpdb2. If you have not set a debugger "\
+                 "password in DConf, it will use the default password "\
+                 "('totem').")
+        dialog = Gtk.MessageDialog (None, 0, Gtk.MessageType.INFO,
+                                    Gtk.ButtonsType.OK_CANCEL, msg)
+        if dialog.run () == Gtk.ResponseType.OK:
+            schema = 'org.gnome.totem.plugins.pythonconsole'
+            settings = Gio.Settings.new (schema)
+            password = settings.get_string ('rpdb2-password') or "totem"
+            def start_debugger (password):
+                rpdb2.start_embedded_debugger (password)
+                return False
+
+            gobject.idle_add (start_debugger, password)
+        dialog.destroy ()
+
+    def destroy_console (self, *args):
+        self.window.destroy ()
+        self.window = None
+
+    def do_deactivate (self):
+        data = self.totem.get_data ('PythonConsolePluginInfo')
+
+        manager = self.totem.get_ui_manager ()
+        manager.remove_ui (data['ui_id'])
+        manager.remove_action_group (data['action_group'])
+        manager.ensure_update ()
+
+        self.totem.set_data ('PythonConsolePluginInfo', None)
+
+        if self.window is not None:
+            self.window.destroy ()
diff --git a/src/plugins/sample-python/sample-python.py b/src/plugins/sample-python/sample-python.py
index 3956cf8..025c13d 100644
--- a/src/plugins/sample-python/sample-python.py
+++ b/src/plugins/sample-python/sample-python.py
@@ -4,14 +4,14 @@ import gobject
 from gi.repository import Peas
 from gi.repository import Totem
 
-class SamplePython(gobject.GObject, Peas.Activatable):
-	__gtype_name__ = 'SamplePython'
+class SamplePython (gobject.GObject, Peas.Activatable):
+    __gtype_name__ = 'SamplePython'
 
-	object = gobject.property(type = gobject.GObject)
+    object = gobject.property (type = gobject.GObject)
 
-	def do_activate(self):
-		print "Activating sample Python plugin"
-		self.object.action_fullscreen_toggle()
-	
-	def do_deactivate(self):
-		print "Deactivating sample Python plugin"
+    def do_activate (self):
+        print "Activating sample Python plugin"
+        self.object.action_fullscreen_toggle ()
+
+    def do_deactivate (self):
+        print "Deactivating sample Python plugin"



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]