diff --git a/.cvsignore b/.cvsignore
index 6ff345a..f9177d4 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1 +1 @@
-rhythmbox-0.11.4.tar.bz2
+rhythmbox-0.11.5.tar.bz2
diff --git a/gsd-media-player-api.patch b/gsd-media-player-api.patch
deleted file mode 100644
index b0c71e7..0000000
--- a/gsd-media-player-api.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-Index: plugins/mmkeys/rb-mmkeys-plugin.c
-===================================================================
---- plugins/mmkeys/rb-mmkeys-plugin.c (revision 5546)
-+++ plugins/mmkeys/rb-mmkeys-plugin.c (working copy)
-@@ -295,9 +295,9 @@
- GError *error = NULL;
-
- plugin->proxy = dbus_g_proxy_new_for_name (bus,
-- "org.gnome.SettingsDaemon",
-- "/org/gnome/SettingsDaemon",
-- "org.gnome.SettingsDaemon");
-+ "org.gnome.SettingsDaemon",
-+ "/org/gnome/SettingsDaemon/MediaKeys",
-+ "org.gnome.SettingsDaemon.MediaKeys");
- if (plugin->proxy != NULL) {
- dbus_g_proxy_call (plugin->proxy,
- "GrabMediaPlayerKeys", &error,
-@@ -308,7 +308,7 @@
- if (error == NULL) {
- GtkWindow *window;
-
-- rb_debug ("created dbus proxy for org.gnome.SettingsDaemon; grabbing keys");
-+ rb_debug ("created dbus proxy for org.gnome.SettingsDaemon.MediaKeys; grabbing keys");
- dbus_g_object_register_marshaller (rb_marshal_VOID__STRING_STRING,
- G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
-
-@@ -336,7 +336,7 @@
- /* settings daemon dbus service doesn't exist.
- * just silently fail.
- */
-- rb_debug ("org.gnome.SettingsDaemon dbus service not found");
-+ rb_debug ("org.gnome.SettingsDaemon.MediaKeys dbus service not found");
- g_error_free (error);
- } else {
- g_warning ("Unable to grab media player keys: %s", error->message);
diff --git a/rb-activate-generic-players-from-uri.patch b/rb-activate-generic-players-from-uri.patch
deleted file mode 100644
index 8f5465a..0000000
--- a/rb-activate-generic-players-from-uri.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-Index: sources/rb-removable-media-source.c
-===================================================================
---- sources/rb-removable-media-source.c (revision 5601)
-+++ sources/rb-removable-media-source.c (working copy)
-@@ -62,6 +62,8 @@
- static void impl_paste (RBSource *source, GList *entries);
- #endif
- static gboolean impl_receive_drag (RBSource *asource, GtkSelectionData *data);
-+static guint impl_want_uri (RBSource *source, const char *uri);
-+static gboolean impl_uri_is_source (RBSource *source, const char *uri);
-
- typedef struct
- {
-@@ -102,6 +104,8 @@
- source_class->impl_delete = NULL;
- source_class->impl_get_config_widget = NULL;
- source_class->impl_show_popup = (RBSourceFeatureFunc) rb_false_function;
-+ source_class->impl_want_uri = impl_want_uri;
-+ source_class->impl_uri_is_source = impl_uri_is_source;
-
- browser_source_class->impl_get_paned_key = NULL;
- browser_source_class->impl_has_drop_support = (RBBrowserSourceFeatureFunc) rb_false_function;
-@@ -367,6 +371,50 @@
-
- #endif
-
-+static guint
-+impl_want_uri (RBSource *source, const char *uri)
-+{
-+ GnomeVFSVolume *volume;
-+ char *activation_uri;
-+ int retval, len;
-+
-+ retval = 0;
-+
-+ /* A default version for use with the audio players
-+ * that use mass storage */
-+ if (g_str_has_prefix (uri, "file://") == FALSE)
-+ return 0;
-+
-+ g_object_get (G_OBJECT (source),
-+ "volume", &volume,
-+ NULL);
-+ if (volume == NULL)
-+ return 0;
-+
-+ activation_uri = gnome_vfs_volume_get_activation_uri (volume);
-+ if (activation_uri == NULL)
-+ return 0;
-+
-+ len = strlen (uri);
-+ if (uri[len - 1] == '/') {
-+ if (strncmp (uri, activation_uri, len - 1) == 0)
-+ retval = 100;
-+ } else if (strcmp (uri, activation_uri) == 0)
-+ retval = 100;
-+
-+ g_free (activation_uri);
-+
-+ return retval;
-+}
-+
-+static gboolean
-+impl_uri_is_source (RBSource *source, const char *uri)
-+{
-+ if (impl_want_uri (source, uri) == 100)
-+ return TRUE;
-+ return FALSE;
-+}
-+
- static RhythmDB *
- get_db_for_source (RBSource *source)
- {
-Index: shell/rb-shell.c
-===================================================================
---- shell/rb-shell.c (revision 5601)
-+++ shell/rb-shell.c (working copy)
-@@ -3327,6 +3327,14 @@
- uri, error))
- return FALSE;
- }
-+ } else if (result == TOTEM_PL_PARSER_RESULT_IGNORED && rb_uri_is_local (uri)) {
-+ /* That happens for directories */
-+ playlist_source = rb_shell_guess_source_for_uri (shell, uri);
-+ if (playlist_source == NULL || rb_source_want_uri (playlist_source, uri) < 100) {
-+ rb_debug ("%s is a directory, but doesn't have a source, adding as a dir", uri);
-+ if (!rb_shell_add_uri (shell, uri, NULL, NULL, error))
-+ return FALSE;
-+ }
- } else {
- rb_debug ("%s didn't parse as a playlist", uri);
- if (!rb_shell_add_uri (shell, uri, NULL, NULL, error))
diff --git a/rb-automake-warning.patch b/rb-automake-warning.patch
deleted file mode 100644
index 76ef5a0..0000000
--- a/rb-automake-warning.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-Index: podcast/Makefile.am
-===================================================================
---- podcast/Makefile.am (revision 5561)
-+++ podcast/Makefile.am (working copy)
-@@ -55,8 +55,7 @@
- librhythmbox_itms_detection_plugin_la_LDFLAGS = \
- -avoid-version \
- -export-symbols $(srcdir)/plugin.symbols \
-- -module \
-- $(AM_LDFLAGS)
-+ -module
-
- endif
-
diff --git a/rb-ipod-save-artwork.patch b/rb-ipod-save-artwork.patch
deleted file mode 100644
index 7363eee..0000000
--- a/rb-ipod-save-artwork.patch
+++ /dev/null
@@ -1,204 +0,0 @@
---- trunk/plugins/ipod/rb-ipod-source.c 2008/01/01 14:11:29 5526
-+++ trunk/plugins/ipod/rb-ipod-source.c 2008/01/02 12:08:13 5527
-@@ -48,15 +48,11 @@
- #include "rhythmdb.h"
- #include "rb-cut-and-paste-code.h"
-
--static GObject *rb_ipod_source_constructor (GType type,
-+static GObject *rb_ipod_source_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_properties);
- static void rb_ipod_source_dispose (GObject *object);
-
--static GObject *rb_ipod_source_constructor (GType type, guint n_construct_properties,
-- GObjectConstructParam *construct_properties);
--static void rb_ipod_source_dispose (GObject *object);
--
- static gboolean impl_show_popup (RBSource *source);
- static void impl_move_to_trash (RBSource *asource);
- static void rb_ipod_load_songs (RBiPodSource *source);
-@@ -82,6 +78,11 @@
- const gchar *extension);
- static gchar* ipod_path_from_unix_path (const gchar *mount_point,
- const gchar *unix_path);
-+static gboolean rb_ipod_song_artwork_add_cb (RhythmDB *db,
-+ RhythmDBEntry *entry,
-+ const gchar *property_name,
-+ const GValue *metadata,
-+ RBiPodSource *isource);
- #endif
- static RhythmDB *get_db_for_source (RBiPodSource *source);
-
-@@ -108,6 +109,13 @@
- GQueue *offline_plays;
- } RBiPodSourcePrivate;
-
-+#ifdef ENABLE_IPOD_WRITING
-+typedef struct {
-+ RBiPodSourcePrivate *priv;
-+ GdkPixbuf *pixbuf;
-+} RBiPodSongArtworkAddData;
-+#endif
-+
- RB_PLUGIN_DEFINE_TYPE(RBiPodSource,
- rb_ipod_source,
- RB_TYPE_REMOVABLE_MEDIA_SOURCE)
-@@ -186,6 +194,15 @@
-
- rb_ipod_load_songs (source);
-
-+#ifdef ENABLE_IPOD_WRITING
-+ RhythmDB *db = get_db_for_source (RB_IPOD_SOURCE (source));
-+ g_signal_connect_object (db,
-+ "entry-extra-metadata-notify::rb:coverArt",
-+ G_CALLBACK (rb_ipod_song_artwork_add_cb),
-+ RB_IPOD_SOURCE(source), 0);
-+ g_object_unref (G_OBJECT (db));
-+#endif
-+
- return G_OBJECT (source);
- }
-
-@@ -1140,6 +1157,82 @@
- g_hash_table_remove (priv->artwork_request_map, entry);
- }
-
-+static gboolean
-+rb_add_artwork_whole_album_cb (GtkTreeModel *query_model,
-+ GtkTreePath *path,
-+ GtkTreeIter *iter,
-+ RBiPodSongArtworkAddData *artwork_data)
-+{
-+ RhythmDBEntry *entry;
-+ Itdb_Track *song;
-+
-+ entry = rhythmdb_query_model_iter_to_entry (RHYTHMDB_QUERY_MODEL (query_model), iter);
-+
-+ song = g_hash_table_lookup (artwork_data->priv->entry_map, entry);
-+
-+ if (song->has_artwork == 0x01) {
-+ return FALSE;
-+ }
-+
-+ rb_ipod_db_set_thumbnail (artwork_data->priv->ipod_db, song, artwork_data->pixbuf);
-+
-+ return FALSE;
-+}
-+
-+static gboolean
-+rb_ipod_song_artwork_add_cb (RhythmDB *db,
-+ RhythmDBEntry *entry,
-+ const gchar *property_name,
-+ const GValue *metadata,
-+ RBiPodSource *isource)
-+{
-+ RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (isource);
-+ Itdb_Device *device;
-+ Itdb_Track *song;
-+ GdkPixbuf *pixbuf;
-+ GtkTreeModel *query_model;
-+ RBiPodSongArtworkAddData artwork_data;
-+
-+ if (metadata == NULL) {
-+ return FALSE;
-+ }
-+
-+ if (G_VALUE_HOLDS (metadata, GDK_TYPE_PIXBUF) == FALSE) {
-+ return FALSE;
-+ }
-+
-+ song = g_hash_table_lookup (priv->entry_map, entry);
-+ if (song == NULL) {
-+ return FALSE;
-+ }
-+
-+ device = rb_ipod_db_get_device (priv->ipod_db);
-+ if (device == NULL || itdb_device_supports_artwork (device) == FALSE) {
-+ return FALSE;
-+ }
-+
-+ pixbuf = GDK_PIXBUF (g_value_get_object (metadata));
-+
-+ query_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
-+
-+ rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (query_model),
-+ RHYTHMDB_QUERY_PROP_EQUALS,
-+ RHYTHMDB_PROP_ARTIST, song->artist,
-+ RHYTHMDB_QUERY_PROP_EQUALS,
-+ RHYTHMDB_PROP_ALBUM, song->album,
-+ RHYTHMDB_QUERY_END);
-+
-+ artwork_data.priv = priv;
-+ artwork_data.pixbuf = pixbuf;
-+
-+ gtk_tree_model_foreach (query_model,
-+ (GtkTreeModelForeachFunc) rb_add_artwork_whole_album_cb,
-+ &artwork_data);
-+
-+ g_object_unref(query_model);
-+ return FALSE;
-+}
-+
- static void
- request_artwork (RBiPodSource *isource,
- RhythmDBEntry *entry,
---- trunk/plugins/ipod/rb-ipod-source.c 2008/01/02 12:08:13 5527
-+++ trunk/plugins/ipod/rb-ipod-source.c 2008/01/02 13:34:52 5528
-@@ -1169,7 +1169,8 @@
- entry = rhythmdb_query_model_iter_to_entry (RHYTHMDB_QUERY_MODEL (query_model), iter);
-
- song = g_hash_table_lookup (artwork_data->priv->entry_map, entry);
--
-+ g_return_val_if_fail (song != NULL, FALSE);
-+
- if (song->has_artwork == 0x01) {
- return FALSE;
- }
-@@ -1192,7 +1193,8 @@
- GdkPixbuf *pixbuf;
- GtkTreeModel *query_model;
- RBiPodSongArtworkAddData artwork_data;
--
-+ RhythmDBEntryType entry_type;
-+
- if (metadata == NULL) {
- return FALSE;
- }
-@@ -1210,12 +1212,16 @@
- if (device == NULL || itdb_device_supports_artwork (device) == FALSE) {
- return FALSE;
- }
--
-+
-+ g_object_get (G_OBJECT (isource), "entry-type", &entry_type, NULL);
-+
- pixbuf = GDK_PIXBUF (g_value_get_object (metadata));
-
- query_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
-
- rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (query_model),
-+ RHYTHMDB_QUERY_PROP_EQUALS,
-+ RHYTHMDB_PROP_ENTRY_ID, entry_type,
- RHYTHMDB_QUERY_PROP_EQUALS,
- RHYTHMDB_PROP_ARTIST, song->artist,
- RHYTHMDB_QUERY_PROP_EQUALS,
-@@ -1228,7 +1234,7 @@
- gtk_tree_model_foreach (query_model,
- (GtkTreeModelForeachFunc) rb_add_artwork_whole_album_cb,
- &artwork_data);
--
-+ g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
- g_object_unref(query_model);
- return FALSE;
- }
---- trunk/plugins/ipod/rb-ipod-source.c 2008/02/02 19:24:40 5558
-+++ trunk/plugins/ipod/rb-ipod-source.c 2008/02/14 14:11:22 5579
-@@ -1233,7 +1233,7 @@
-
- rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (query_model),
- RHYTHMDB_QUERY_PROP_EQUALS,
-- RHYTHMDB_PROP_ENTRY_ID, entry_type,
-+ RHYTHMDB_PROP_TYPE, entry_type,
- RHYTHMDB_QUERY_PROP_EQUALS,
- RHYTHMDB_PROP_ARTIST, song->artist,
- RHYTHMDB_QUERY_PROP_EQUALS,
diff --git a/rhythmbox-0.11.4-bigger-pane.patch b/rhythmbox-0.11.4-bigger-pane.patch
deleted file mode 100644
index a1bf22b..0000000
--- a/rhythmbox-0.11.4-bigger-pane.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-Index: data/rhythmbox.schemas
-===================================================================
---- data/rhythmbox.schemas (revision 5614)
-+++ data/rhythmbox.schemas (working copy)
-@@ -106,7 +106,7 @@
- /apps/rhythmbox/state/paned_position
- rhythmbox
- int
-- 88
-+ 160
-
- Position of main window pane
- Position of main window pane.
-@@ -117,7 +117,7 @@
- /apps/rhythmbox/state/window_width
- rhythmbox
- int
-- 600
-+ 800
-
- Main window width
- Main window width.
-@@ -155,7 +155,7 @@
- /apps/rhythmbox/state/window_height
- rhythmbox
- int
-- 600
-+ 550
-
- Main window height
- Main window height.
diff --git a/rhythmbox-0.11.4-updated-upnp.patch b/rhythmbox-0.11.4-updated-upnp.patch
deleted file mode 100644
index 80ab074..0000000
--- a/rhythmbox-0.11.4-updated-upnp.patch
+++ /dev/null
@@ -1,1618 +0,0 @@
-diff -uprN rhythmbox-0.11.4.old/plugins/coherence/coherence.rb-plugin.desktop.in rhythmbox-0.11.4/plugins/coherence/coherence.rb-plugin.desktop.in
---- rhythmbox-0.11.4.old/plugins/coherence/coherence.rb-plugin.desktop.in 2007-07-08 11:12:43.000000000 +0100
-+++ rhythmbox-0.11.4/plugins/coherence/coherence.rb-plugin.desktop.in 2008-03-13 16:55:54.000000000 +0000
-@@ -2,8 +2,8 @@
- Loader=python
- Module=upnp_coherence
- IAge=1
--_Name=UPnP sharing support
--_Description=Adds support for playing media from, and sending media to UPnP/DLNA network devices
--Authors=James Livingston
--Copyright=Copyright © 2007 James Livingston
--Website=http://www.rhythmbox.org/
-+_Name=DLNA/UPnP sharing and control support
-+_Description=Adds support for playing media from and sending media to DLNA/UPnP network devices, and enables Rhythmbox to be controlled by a DLNA/UPnP ControlPoint
-+Authors=James Livingston , Frank Scholz
-+Copyright=Copyright © 2007,2008 James Livingston & Frank Scholz
-+Website=http://www.rhythmbox.org/ - https://coherence.beebits.net
-diff -uprN rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/__init__.py rhythmbox-0.11.4/plugins/coherence/upnp_coherence/__init__.py
---- rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/__init__.py 2007-12-17 09:26:53.000000000 +0000
-+++ rhythmbox-0.11.4/plugins/coherence/upnp_coherence/__init__.py 2008-02-21 14:50:19.000000000 +0000
-@@ -1,140 +1,164 @@
- import rhythmdb, rb
- import gobject, gtk
-+
- import louie
-+
-+from coherence import log
-+
- # For the icon
- import os.path, urllib, gnomevfs, gtk.gdk
-
-+class CoherencePlugin(rb.Plugin,log.Loggable):
-+
-+ logCategory = 'rb_coherence_plugin'
-
--class CoherencePlugin(rb.Plugin):
-- def __init__(self):
-- rb.Plugin.__init__(self)
--
-- def activate(self, shell):
-- from twisted.internet import gtk2reactor
-- try:
-- gtk2reactor.install()
-- except AssertionError, e:
-- # sometimes it's already installed
-- print e
--
-- self.coherence = self.get_coherence()
-- if self.coherence is None:
-- print "Coherence is not installed or too old, aborting"
-- return
--
-- print "coherence UPnP plugin activated"
-- self.shell = shell
-- self.sources = {}
--
-- # watch for media servers
-- louie.connect(self.detected_media_server,
-- 'Coherence.UPnP.ControlPoint.MediaServer.detected',
-- louie.Any)
-- louie.connect(self.removed_media_server,
-- 'Coherence.UPnP.ControlPoint.MediaServer.removed',
-- louie.Any)
--
-- # Set up our icon
-- face_path = os.path.join(os.path.expanduser('~'), ".face")
-- if os.path.exists(face_path):
-- url = "file://" + urllib.pathname2url(face_path)
--
-- if url:
-- mimetype = gnomevfs.get_mime_type(url)
-- pixbuf = gtk.gdk.pixbuf_new_from_file(face_path)
-- width = "%s" % pixbuf.get_width()
-- height = "%s" % pixbuf.get_height()
-- depth = '24'
-- the_icon = {
-- 'url':url,
-- 'mimetype':mimetype,
-- 'width':width,
-- 'height':height,
-- 'depth':depth
-- }
--
-- # create our own media server
-- from coherence.upnp.devices.media_server import MediaServer
-- from MediaStore import MediaStore
-- if the_icon:
-- server = MediaServer(self.coherence, MediaStore, no_thread_needed=True, db=self.shell.props.db, plugin=self, icon=the_icon)
-- else:
-- server = MediaServer(self.coherence, MediaStore, no_thread_needed=True, db=self.shell.props.db, plugin=self)
--
-- def deactivate(self, shell):
-- print "coherence UPnP plugin deactivated"
-- if self.coherence is None:
-- return
--
-- self.coherence.shutdown()
--
-- louie.disconnect(self.detected_media_server,
-- 'Coherence.UPnP.ControlPoint.MediaServer.detected',
-- louie.Any)
-- louie.disconnect(self.removed_media_server,
-- 'Coherence.UPnP.ControlPoint.MediaServer.removed',
-- louie.Any)
--
-- del self.shell
-- del self.coherence
--
-- for usn, source in self.sources.iteritems():
-- source.delete_thyself()
-- del self.sources
--
-- # uninstall twisted reactor? probably not, since other thigngs may have used it
--
--
-- def get_coherence (self):
-- coherence_instance = None
-- required_version = (0, 3, 2)
--
-- try:
-- from coherence.base import Coherence
-- from coherence import __version_info__
-- except ImportError, e:
-- print "Coherence not found"
-- return None
--
-- if __version_info__ < required_version:
-- required = '.'.join([str(i) for i in required_version])
-- found = '.'.join([str(i) for i in __version_info__])
-- print "Coherence %s required. %s found. Please upgrade" % (required, found)
-- return None
--
-- coherence_config = {
-- #'logmode': 'info',
-- 'controlpoint': 'yes',
-- 'plugins':{}
-- }
-- coherence_instance = Coherence(coherence_config)
--
-- return coherence_instance
--
--
-- def removed_media_server(self, usn):
-- print "upnp server went away %s" % usn
-- if self.sources.has_key(usn):
-- self.sources[usn].delete_thyself()
-- del self.sources[usn]
--
-- def detected_media_server(self, client, usn):
-- print "found upnp server %s (%s)" % (client.device.get_friendly_name(), usn)
--
-- db = self.shell.props.db
-- group = rb.rb_source_group_get_by_name ("shared")
-- entry_type = db.entry_register_type("CoherenceUpnp:" + usn)
--
-- from UpnpSource import UpnpSource
-- source = gobject.new (UpnpSource,
-- shell=self.shell,
-- entry_type=entry_type,
-- source_group=group,
-- plugin=self,
-- client=client,
-- usn=usn)
-+ def __init__(self):
-+ rb.Plugin.__init__(self)
-
-- self.sources[usn] = source
-+ def activate(self, shell):
-+ from twisted.internet import gtk2reactor
-+ try:
-+ gtk2reactor.install()
-+ except AssertionError, e:
-+ # sometimes it's already installed
-+ print e
-+
-+ self.coherence = self.get_coherence()
-+ if self.coherence is None:
-+ print "Coherence is not installed or too old, aborting"
-+ return
-+
-+ print "coherence UPnP plugin activated"
-+ self.shell = shell
-+ self.sources = {}
-+
-+ # Set up our icon
-+ the_icon = None
-+ face_path = os.path.join(os.path.expanduser('~'), ".face")
-+ if os.path.exists(face_path):
-+ url = "file://" + urllib.pathname2url(face_path)
-+ mimetype = gnomevfs.get_mime_type(url)
-+ pixbuf = gtk.gdk.pixbuf_new_from_file(face_path)
-+ width = "%s" % pixbuf.get_width()
-+ height = "%s" % pixbuf.get_height()
-+ depth = '24'
-+ the_icon = {
-+ 'url':url,
-+ 'mimetype':mimetype,
-+ 'width':width,
-+ 'height':height,
-+ 'depth':depth
-+ }
-+ else:
-+ the_icon = None
-+
-+ # create our own media server
-+ from coherence.upnp.devices.media_server import MediaServer
-+ from MediaStore import MediaStore
-+ if the_icon:
-+ server = MediaServer(self.coherence, MediaStore, no_thread_needed=True, db=self.shell.props.db, plugin=self, icon=the_icon)
-+ else:
-+ server = MediaServer(self.coherence, MediaStore, no_thread_needed=True, db=self.shell.props.db, plugin=self)
-+
-+ self.uuid = str(server.uuid)
-+
-+ if self.coherence_version >= (0,5,2):
-+ # create our own media renderer
-+ # but only if we have a matching Coherence package installed
-+ from coherence.upnp.devices.media_renderer import MediaRenderer
-+ from MediaPlayer import RhythmboxPlayer
-+ if the_icon:
-+ MediaRenderer(self.coherence, RhythmboxPlayer, no_thread_needed=True, shell=self.shell, icon=the_icon)
-+ else:
-+ MediaRenderer(self.coherence, RhythmboxPlayer, no_thread_needed=True, shell=self.shell)
-+
-+ # watch for media servers
-+ louie.connect(self.detected_media_server,
-+ 'Coherence.UPnP.ControlPoint.MediaServer.detected',
-+ louie.Any)
-+ louie.connect(self.removed_media_server,
-+ 'Coherence.UPnP.ControlPoint.MediaServer.removed',
-+ louie.Any)
-+
-+
-+ def deactivate(self, shell):
-+ print "coherence UPnP plugin deactivated"
-+ if self.coherence is None:
-+ return
-+
-+ self.coherence.shutdown()
-+
-+ louie.disconnect(self.detected_media_server,
-+ 'Coherence.UPnP.ControlPoint.MediaServer.detected',
-+ louie.Any)
-+ louie.disconnect(self.removed_media_server,
-+ 'Coherence.UPnP.ControlPoint.MediaServer.removed',
-+ louie.Any)
-+
-+ del self.shell
-+ del self.coherence
-+
-+ for usn, source in self.sources.iteritems():
-+ source.delete_thyself()
-+ del self.sources
-+
-+ # uninstall twisted reactor? probably not, since other thigngs may have used it
-+
-+
-+ def get_coherence (self):
-+ coherence_instance = None
-+ required_version = (0, 3, 2)
-+
-+ try:
-+ from coherence.base import Coherence
-+ from coherence import __version_info__
-+ except ImportError, e:
-+ print "Coherence not found"
-+ return None
-+
-+ if __version_info__ < required_version:
-+ required = '.'.join([str(i) for i in required_version])
-+ found = '.'.join([str(i) for i in __version_info__])
-+ print "Coherence %s required. %s found. Please upgrade" % (required, found)
-+ return None
-+
-+ self.coherence_version = __version_info__
-+
-+ coherence_config = {
-+ #'logmode': 'info',
-+ 'controlpoint': 'yes',
-+ 'plugins': {},
-+ }
-+ coherence_instance = Coherence(coherence_config)
-+
-+ return coherence_instance
-+
-+ def removed_media_server(self, usn):
-+ print "upnp server went away %s" % usn
-+ if self.sources.has_key(usn):
-+ self.sources[usn].delete_thyself()
-+ del self.sources[usn]
-+
-+ def detected_media_server(self, client, usn):
-+ print "found upnp server %s (%s)" % (client.device.get_friendly_name(), usn)
-+ self.warning("found upnp server %s (%s)" % (client.device.get_friendly_name(), usn))
-+ if client.device.get_id() == self.uuid:
-+ """ don't react on our own MediaServer"""
-+ return
-+
-+ db = self.shell.props.db
-+ group = rb.rb_source_group_get_by_name ("shared")
-+ entry_type = db.entry_register_type("CoherenceUpnp:" + client.device.get_id()[5:])
-+
-+ from UpnpSource import UpnpSource
-+ source = gobject.new (UpnpSource,
-+ shell=self.shell,
-+ entry_type=entry_type,
-+ source_group=group,
-+ plugin=self,
-+ client=client,
-+ usn=usn)
-
-- self.shell.append_source (source, None)
-+ self.sources[usn] = source
-
-+ self.shell.append_source (source, None)
-diff -uprN rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/Makefile.am rhythmbox-0.11.4/plugins/coherence/upnp_coherence/Makefile.am
---- rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/Makefile.am 2007-07-13 08:58:49.000000000 +0100
-+++ rhythmbox-0.11.4/plugins/coherence/upnp_coherence/Makefile.am 2008-02-05 12:35:57.000000000 +0000
-@@ -4,4 +4,5 @@ plugindir = $(PLUGINDIR)/upnp_coherence
- plugin_PYTHON = \
- UpnpSource.py \
- MediaStore.py \
-+ MediaPlayer.py \
- __init__.py
-diff -uprN rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/MediaPlayer.py rhythmbox-0.11.4/plugins/coherence/upnp_coherence/MediaPlayer.py
---- rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/MediaPlayer.py 1970-01-01 01:00:00.000000000 +0100
-+++ rhythmbox-0.11.4/plugins/coherence/upnp_coherence/MediaPlayer.py 2008-02-05 12:35:57.000000000 +0000
-@@ -0,0 +1,437 @@
-+# Licensed under the MIT license
-+# http://opensource.org/licenses/mit-license.php
-+
-+# Copyright 2008, Frank Scholz
-+
-+import urllib
-+
-+import rhythmdb
-+
-+from coherence.upnp.core.soap_service import errorCode
-+from coherence.upnp.core import DIDLLite
-+
-+import louie
-+
-+from coherence.extern.simple_plugin import Plugin
-+
-+from coherence import log
-+
-+TRACK_COUNT = 1000000
-+
-+class RhythmboxPlayer(log.Loggable):
-+
-+ """ a backend to the Rhythmbox
-+
-+ """
-+ logCategory = 'rb_media_renderer'
-+
-+ implements = ['MediaRenderer']
-+ vendor_value_defaults = {'RenderingControl': {'A_ARG_TYPE_Channel':'Master'}}
-+ vendor_range_defaults = {'RenderingControl': {'Volume': {'maximum':100}}}
-+
-+ def __init__(self, device, **kwargs):
-+ self.warning("__init__ RhythmboxPlayer %r", kwargs)
-+ self.shell = kwargs['shell']
-+ self.server = device
-+
-+ self.player = None
-+ self.metadata = None
-+ self.host = '127.0.0.1'
-+ self.name = "Rhythmbox on %s" % self.server.coherence.hostname
-+
-+ self.player = self.shell.get_player()
-+ self.player.connect ('playing-song-changed',
-+ self.playing_song_changed),
-+ self.player.connect ('playing-changed',
-+ self.playing_changed)
-+ self.player.connect ('elapsed-changed',
-+ self.elapsed_changed)
-+ self.player.connect("notify::volume", self.volume_changed)
-+ louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)
-+
-+ self.playing = False
-+ self.state = None
-+ self.duration = None
-+ self.volume = 1.0
-+ self.muted_volume = None
-+ self.view = []
-+ self.tags = {}
-+
-+ def __repr__(self):
-+ return str(self.__class__).split('.')[-1]
-+
-+ def volume_changed(self, player, parameter):
-+ self.volume = self.player.props.volume
-+ self.warning('volume_changed to %r', self.volume)
-+ if self.volume > 0:
-+ rcs_id = self.server.connection_manager_server.lookup_rcs_id(self.current_connection_id)
-+ self.server.rendering_control_server.set_variable(rcs_id, 'Volume', self.volume*100)
-+
-+ def playing_song_changed(self, player, entry):
-+ self.warning("playing_song_changed %r", entry)
-+ if self.server != None:
-+ connection_id = self.server.connection_manager_server.lookup_avt_id(self.current_connection_id)
-+ if entry == None:
-+ self.update('STOPPED')
-+ self.playing = False
-+ #self.entry = None
-+ self.metadata = None
-+ self.duration = None
-+ else:
-+ self.id = self.shell.props.db.entry_get (entry, rhythmdb.PROP_ENTRY_ID)
-+ bitrate = self.shell.props.db.entry_get(entry, rhythmdb.PROP_BITRATE) * 1024 / 8
-+ # Duration is in HH:MM:SS format
-+ seconds = self.shell.props.db.entry_get(entry, rhythmdb.PROP_DURATION)
-+ hours = seconds / 3600
-+ seconds = seconds - hours * 3600
-+ minutes = seconds / 60
-+ seconds = seconds - minutes * 60
-+ self.duration = "%02d:%02d:%02d" % (hours, minutes, seconds)
-+
-+ mimetype = self.shell.props.db.entry_get(entry, rhythmdb.PROP_MIMETYPE)
-+ # This isn't a real mime-type
-+ if mimetype == "application/x-id3":
-+ mimetype = "audio/mpeg"
-+ size = self.shell.props.db.entry_get(entry, rhythmdb.PROP_FILE_SIZE)
-+
-+ # create item
-+ item = DIDLLite.MusicTrack(self.id + TRACK_COUNT)
-+ item.album = self.shell.props.db.entry_get(entry, rhythmdb.PROP_ALBUM)
-+ item.artist = self.shell.props.db.entry_get(entry, rhythmdb.PROP_ARTIST)
-+ item.genre = self.shell.props.db.entry_get(entry, rhythmdb.PROP_GENRE)
-+ item.originalTrackNumber = str(self.shell.props.db.entry_get (entry, rhythmdb.PROP_TRACK_NUMBER))
-+ item.title = self.shell.props.db.entry_get(entry, rhythmdb.PROP_TITLE) # much nicer if it was entry.title
-+
-+ item.res = []
-+
-+ uri = self.shell.props.db.entry_get(entry, rhythmdb.PROP_LOCATION)
-+ if uri.startswith("file://"):
-+ location = unicode(urllib.unquote(uri[len("file://"):]))
-+
-+ # add a fake resource for the moment
-+ res = DIDLLite.Resource(location, 'http-get:*:%s:*' % mimetype)
-+ if size > 0:
-+ res.size = size
-+ if self.duration > 0:
-+ res.duration = self.duration
-+ if bitrate > 0:
-+ res.bitrate = str(bitrate)
-+ item.res.append(res)
-+
-+ elt = DIDLLite.DIDLElement()
-+ elt.addItem(item)
-+ self.metadata = elt.toString()
-+ self.entry = entry
-+ if self.server != None:
-+ self.server.av_transport_server.set_variable(connection_id, 'AVTransportURIMetaData',self.metadata)
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackMetaData',self.metadata)
-+ self.warning("playing_song_changed %r", self.metadata)
-+ if self.server != None:
-+ self.server.av_transport_server.set_variable(connection_id, 'RelativeTimePosition', '00:00:00')
-+ self.server.av_transport_server.set_variable(connection_id, 'AbsoluteTimePosition', '00:00:00')
-+
-+ def playing_changed(self, player, state):
-+ self.warning("playing_changed", state)
-+ if state is True:
-+ transport_state = 'PLAYING'
-+ else:
-+ if self.playing is False:
-+ transport_state = 'STOPPED'
-+ else:
-+ transport_state = 'PAUSED_PLAYBACK'
-+ self.update(transport_state)
-+ try:
-+ position = player.get_playing_time()
-+ except:
-+ position = None
-+ try:
-+ duration = player.get_playing_song_duration()
-+ except:
-+ duration = None
-+ self.update_position(position,duration)
-+ self.warning("playing_changed %r %r ", position, duration)
-+
-+ def elapsed_changed(self, player, time):
-+ self.warning("elapsed_changed %r %r", player, time)
-+ try:
-+ duration = player.get_playing_song_duration()
-+ except:
-+ duration = None
-+ self.update_position(time,duration)
-+
-+ def update(self, state):
-+
-+ self.warning("update %r", state)
-+
-+ if state in ('STOPPED','READY'):
-+ transport_state = 'STOPPED'
-+ if state == 'PLAYING':
-+ transport_state = 'PLAYING'
-+ if state == 'PAUSED_PLAYBACK':
-+ transport_state = 'PAUSED_PLAYBACK'
-+
-+ if self.state != transport_state:
-+ self.state = transport_state
-+ if self.server != None:
-+ connection_id = self.server.connection_manager_server.lookup_avt_id(self.current_connection_id)
-+ self.server.av_transport_server.set_variable(connection_id,
-+ 'TransportState',
-+ transport_state)
-+
-+
-+ def update_position(self, position,duration):
-+ self.warning("update_position %r %r", position,duration)
-+
-+ if self.server != None:
-+ connection_id = self.server.connection_manager_server.lookup_avt_id(self.current_connection_id)
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTrack', 0)
-+
-+ if position is not None:
-+ m,s = divmod( position, 60)
-+ h,m = divmod(m,60)
-+ if self.server != None:
-+ self.server.av_transport_server.set_variable(connection_id, 'RelativeTimePosition', '%02d:%02d:%02d' % (h,m,s))
-+ self.server.av_transport_server.set_variable(connection_id, 'AbsoluteTimePosition', '%02d:%02d:%02d' % (h,m,s))
-+
-+ if duration <= 0:
-+ duration = None
-+
-+ if duration is not None:
-+ m,s = divmod( duration, 60)
-+ h,m = divmod(m,60)
-+
-+ if self.server != None:
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackDuration', '%02d:%02d:%02d' % (h,m,s))
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentMediaDuration', '%02d:%02d:%02d' % (h,m,s))
-+
-+ if self.duration is None:
-+ if self.metadata is not None:
-+ self.warning("update_position %r", self.metadata)
-+ elt = DIDLLite.DIDLElement.fromString(self.metadata)
-+ for item in elt:
-+ for res in item.findall('res'):
-+ res.attrib['duration'] = "%d:%02d:%02d" % (h,m,s)
-+ self.metadata = elt.toString()
-+
-+ if self.server != None:
-+ self.server.av_transport_server.set_variable(connection_id, 'AVTransportURIMetaData',self.metadata)
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackMetaData',self.metadata)
-+
-+ self.duration = duration
-+
-+ def load( self, uri, metadata):
-+ self.warning("player load %r %r", uri, metadata)
-+ #self.shell.load_uri(uri,play=False)
-+ self.duration = None
-+ self.metadata = metadata
-+ self.tags = {}
-+
-+ if len(self.metadata)>0:
-+ elt = DIDLLite.DIDLElement.fromString(self.metadata)
-+ if elt.numItems() == 1:
-+ item = elt.getItems()[0]
-+
-+ self.entry = self.shell.props.db.entry_lookup_by_location(uri)
-+ self.warning("check for entry %r %r", self.entry, item.server_uuid)
-+ if self.entry == None:
-+ if item.server_uuid is not None:
-+ entry_type = self.shell.props.db.entry_register_type("CoherenceUpnp:" + item.server_uuid)
-+ self.entry = self.shell.props.db.entry_new(entry_type, uri)
-+ self.warning("create new entry %r", self.entry)
-+ else:
-+ self.shell.load_uri(uri,play=False)
-+ self.entry = self.shell.props.db.entry_lookup_by_location(uri)
-+ self.warning("load and check for entry %r", self.entry)
-+
-+
-+ duration = None
-+ size = None
-+ bitrate = None
-+ for res in item.res:
-+ if res.data == uri:
-+ duration = res.duration
-+ size = res.size
-+ bitrate = res.bitrate
-+ break
-+
-+ self.shell.props.db.set(self.entry, rhythmdb.PROP_TITLE, item.title)
-+ try:
-+ if item.artist is not None:
-+ self.shell.props.db.set(self.entry, rhythmdb.PROP_ARTIST, item.artist)
-+ except AttributeError:
-+ pass
-+ try:
-+ if item.album is not None:
-+ self.shell.props.db.set(self.entry, rhythmdb.PROP_ALBUM, item.album)
-+ except AttributeError:
-+ pass
-+
-+ try:
-+ self.info("%r %r", item.title,item.originalTrackNumber)
-+ if item.originalTrackNumber is not None:
-+ self.shell.props.db.set(self.entry, rhythmdb.PROP_TRACK_NUMBER, int(item.originalTrackNumber))
-+ except AttributeError:
-+ pass
-+
-+ if duration is not None:
-+ h,m,s = duration.split(':')
-+ seconds = int(h)*3600 + int(m)*60 + int(s)
-+ self.info("%r %r:%r:%r %r", duration, h, m , s, seconds)
-+ self.shell.props.db.set(self.entry, rhythmdb.PROP_DURATION, seconds)
-+
-+ if size is not None:
-+ self.shell.props.db.set(self.entry, rhythmdb.PROP_FILE_SIZE,int(size))
-+
-+ else:
-+ self.shell.load_uri(uri,play=False)
-+ self.entry = self.shell.props.db.entry_lookup_by_location(uri)
-+
-+ self.playing = False
-+
-+ connection_id = self.server.connection_manager_server.lookup_avt_id(self.current_connection_id)
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTransportActions','Play,Stop,Pause')
-+ self.server.av_transport_server.set_variable(connection_id, 'NumberOfTracks',1)
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackURI',uri)
-+ self.server.av_transport_server.set_variable(connection_id, 'AVTransportURI',uri)
-+ self.server.av_transport_server.set_variable(connection_id, 'AVTransportURIMetaData',metadata)
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackURI',uri)
-+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackMetaData',metadata)
-+
-+ def start(self, uri):
-+ self.load(uri)
-+ self.play()
-+
-+ def stop(self):
-+ self.warning("player stop")
-+
-+ self.player.stop()
-+ self.playing = False
-+ #self.server.av_transport_server.set_variable( \
-+ # self.server.connection_manager_server.lookup_avt_id(self.current_connection_id),\
-+ # 'TransportState', 'STOPPED')
-+
-+ def play(self):
-+ self.warning("player play")
-+
-+ if self.playing == False:
-+ self.player.play_entry(self.entry)
-+ self.playing = True
-+ else:
-+ self.player.playpause()
-+ #self.server.av_transport_server.set_variable( \
-+ # self.server.connection_manager_server.lookup_avt_id(self.current_connection_id),\
-+ # 'TransportState', 'PLAYING')
-+
-+ def pause(self):
-+ self.player.pause()
-+ #self.server.av_transport_server.set_variable( \
-+ # self.server.connection_manager_server.lookup_avt_id(self.current_connection_id),\
-+ # 'TransportState', 'PAUSED_PLAYBACK')
-+
-+ def seek(self, location):
-+ """
-+ @param location: simple number = time to seek to, in seconds
-+ +nL = relative seek forward n seconds
-+ -nL = relative seek backwards n seconds
-+ """
-+
-+ def mute(self):
-+ self.muted_volume = self.volume
-+ self.player.set_volume(0)
-+ rcs_id = self.server.connection_manager_server.lookup_rcs_id(self.current_connection_id)
-+ self.server.rendering_control_server.set_variable(rcs_id, 'Mute', 'True')
-+
-+ def unmute(self):
-+ if self.muted_volume is not None:
-+ self.player.set_volume(self.muted_volume)
-+ self.muted_volume = None
-+ self.player.set_mute(False)
-+ rcs_id = self.server.connection_manager_server.lookup_rcs_id(self.current_connection_id)
-+ self.server.rendering_control_server.set_variable(rcs_id, 'Mute', 'False')
-+
-+ def get_mute(self):
-+ return self.player.get_mute()
-+
-+ def get_volume(self):
-+ self.volume = self.player.get_volume()
-+ self.warning("get_volume %r", self.volume)
-+ return self.volume * 100
-+
-+ def set_volume(self, volume):
-+ self.warning("set_volume %r", volume)
-+ volume = int(volume)
-+ if volume < 0:
-+ volume=0
-+ if volume > 100:
-+ volume=100
-+
-+ self.player.set_volume(float(volume/100.0))
-+
-+ def upnp_init(self):
-+ self.current_connection_id = None
-+ self.server.connection_manager_server.set_variable(0, 'SinkProtocolInfo',
-+ ['internal:%s:*:*' % self.host,
-+ 'http-get:*:audio/mpeg:*'],
-+ default=True)
-+ self.server.av_transport_server.set_variable(0, 'TransportState', 'NO_MEDIA_PRESENT', default=True)
-+ self.server.av_transport_server.set_variable(0, 'TransportStatus', 'OK', default=True)
-+ self.server.av_transport_server.set_variable(0, 'CurrentPlayMode', 'NORMAL', default=True)
-+ self.server.av_transport_server.set_variable(0, 'CurrentTransportActions', '', default=True)
-+ self.server.rendering_control_server.set_variable(0, 'Volume', self.get_volume())
-+ self.server.rendering_control_server.set_variable(0, 'Mute', self.get_mute())
-+
-+ def upnp_Play(self, *args, **kwargs):
-+ InstanceID = int(kwargs['InstanceID'])
-+ Speed = int(kwargs['Speed'])
-+ self.play()
-+ return {}
-+
-+ def upnp_Pause(self, *args, **kwargs):
-+ InstanceID = int(kwargs['InstanceID'])
-+ self.pause()
-+ return {}
-+
-+ def upnp_Stop(self, *args, **kwargs):
-+ InstanceID = int(kwargs['InstanceID'])
-+ self.stop()
-+ return {}
-+
-+ def upnp_SetAVTransportURI(self, *args, **kwargs):
-+ InstanceID = int(kwargs['InstanceID'])
-+ CurrentURI = kwargs['CurrentURI']
-+ CurrentURIMetaData = kwargs['CurrentURIMetaData']
-+ local_protocol_infos=self.server.connection_manager_server.get_variable('SinkProtocolInfo').value.split(',')
-+ #print '>>>', local_protocol_infos
-+ if len(CurrentURIMetaData)==0:
-+ self.load(CurrentURI,CurrentURIMetaData)
-+ else:
-+ elt = DIDLLite.DIDLElement.fromString(CurrentURIMetaData)
-+ #import pdb; pdb.set_trace()
-+ if elt.numItems() == 1:
-+ item = elt.getItems()[0]
-+ res = item.res.get_matching(local_protocol_infos, protocol_type='internal')
-+ if len(res) == 0:
-+ res = item.res.get_matching(local_protocol_infos)
-+ if len(res) > 0:
-+ res = res[0]
-+ remote_protocol,remote_network,remote_content_format,_ = res.protocolInfo.split(':')
-+ self.load(res.data,CurrentURIMetaData)
-+ return {}
-+ return failure.Failure(errorCode(714))
-+
-+ def upnp_SetMute(self, *args, **kwargs):
-+ InstanceID = int(kwargs['InstanceID'])
-+ Channel = kwargs['Channel']
-+ DesiredMute = kwargs['DesiredMute']
-+ if DesiredMute in ['TRUE', 'True', 'true', '1','Yes','yes']:
-+ self.mute()
-+ else:
-+ self.unmute()
-+ return {}
-+
-+ def upnp_SetVolume(self, *args, **kwargs):
-+ InstanceID = int(kwargs['InstanceID'])
-+ Channel = kwargs['Channel']
-+ DesiredVolume = int(kwargs['DesiredVolume'])
-+ self.set_volume(DesiredVolume)
-+ return {}
-diff -uprN rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/MediaStore.py rhythmbox-0.11.4/plugins/coherence/upnp_coherence/MediaStore.py
---- rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/MediaStore.py 2007-10-02 14:48:59.000000000 +0100
-+++ rhythmbox-0.11.4/plugins/coherence/upnp_coherence/MediaStore.py 2008-02-05 12:35:57.000000000 +0000
-@@ -1,10 +1,12 @@
- # Copyright 2007, James Livingston
-+# Copyright 2007, Frank Scholz
-
- import rhythmdb
- import louie
- import urllib
- from coherence.upnp.core import DIDLLite
-
-+from coherence import log
-
- ROOT_CONTAINER_ID = 0
- AUDIO_CONTAINER = 10
-@@ -12,12 +14,16 @@ AUDIO_ALL_CONTAINER_ID = 11
- AUDIO_ARTIST_CONTAINER_ID = 12
- AUDIO_ALBUM_CONTAINER_ID = 13
-
--CONTAINER_COUNT = 1000
-+CONTAINER_COUNT = 10000
-
-+TRACK_COUNT = 1000000
-+
-+# most of this class is from Coherence, originally under the MIT licence
-+
-+class Container(log.Loggable):
-+
-+ logCategory = 'rb_media_store'
-
--# this class is from Coherence, originally under the MIT licence
--# Copyright 2007, Frank Scholz
--class Container(object):
- def __init__(self, id, parent_id, name, children_callback=None):
- self.id = id
- self.parent_id = parent_id
-@@ -25,11 +31,11 @@ class Container(object):
- self.mimetype = 'directory'
- self.item = DIDLLite.Container(id, parent_id,self.name)
- self.update_id = 0
-+ self.item.childCount = 0
- if children_callback != None:
- self.children = children_callback
- else:
- self.children = []
-- self.item.childCount = self.get_child_count()
-
- def add_child(self, child):
- self.children.append(child)
-@@ -40,18 +46,22 @@ class Container(object):
- children = self.children()
- else:
- children = self.children
-+
-+ self.info("Container get_children %r (%r,%r)", children, start, request_count)
- if request_count == 0:
- return children[start:]
- else:
- return children[start:request_count]
-
- def get_child_count(self):
-+
- if callable(self.children):
- return len(self.children())
- else:
- return len(self.children)
-
- def get_item(self):
-+ self.item.childCount = self.get_child_count()
- return self.item
-
- def get_name(self):
-@@ -61,160 +71,349 @@ class Container(object):
- return self.id
-
-
--class Track:
-- def __init__(self, store, id):
-- self.id = id
-- self.store = store
--
-- def get_children(self, start=0, request_count=0):
-- return []
--
-- def get_child_count(self):
-- return 0
--
-- def get_item(self):
-- host = ""
--
-- # load common values
-- entry = self.store.db.entry_lookup_by_id (self.id)
-- # Bitrate is in bytes/second, not kilobits/second
-- bitrate = self.store.db.entry_get (entry, rhythmdb.PROP_BITRATE) * 1024 / 8
-- # Duration is in HH:MM:SS format
-- seconds = self.store.db.entry_get (entry, rhythmdb.PROP_DURATION)
-- hours = seconds / 3600
-- seconds = seconds - hours * 3600
-- minutes = seconds / 60
-- seconds = seconds - minutes * 60
-- duration = ("%02d:%02d:%02d") % (hours, minutes, seconds)
--
-- location = self.store.db.entry_get (entry, rhythmdb.PROP_LOCATION)
-- if location.startswith("file://"):
-- location = unicode(urllib.url2pathname(location)[len("file://"):])
-- else:
-- location = None
-- mimetype = self.store.db.entry_get (entry, rhythmdb.PROP_MIMETYPE)
-- # This isn't a real mime-type
-- if mimetype == "application/x-id3":
-- mimetype = "audio/mpeg"
-- size = self.store.db.entry_get (entry, rhythmdb.PROP_FILE_SIZE)
--
-- # create item
-- item = DIDLLite.MusicTrack(self.id + CONTAINER_COUNT)
-- item.album = self.store.db.entry_get (entry, rhythmdb.PROP_ALBUM)
-- #item.albumArtURI = ## can we somehow store art in the upnp share??
-- item.artist = self.store.db.entry_get (entry, rhythmdb.PROP_ARTIST)
-- #item.date =
-- item.genre = self.store.db.entry_get (entry, rhythmdb.PROP_GENRE)
-- item.originalTrackNumber = str(self.store.db.entry_get (entry, rhythmdb.PROP_TRACK_NUMBER))
-- item.title = self.store.db.entry_get (entry, rhythmdb.PROP_TITLE) # much nicer if it was entry.title
-- item.res = []
--
-- # add internal resource
-- #res = DIDLLite.Resource(location, 'internal:%s:%s:*' % (host, mimetype))
-- #res.size = size
-- #res.duration = duration
-- #res.bitrate = bitrate
-- #item.res.append(res)
--
-- # add http resource
-- res = DIDLLite.Resource(self.get_url(), 'http-get:*:%s:*' % mimetype)
-- if size > 0:
-- res.size = size
-- if duration > 0:
-- res.duration = str(duration)
-- if bitrate > 0:
-- res.bitrate = str(bitrate)
-- item.res.append(res)
--
-- return item
--
-- def get_id(self):
-- return self.id
--
-- def get_name(self):
-- entry = self.store.db.entry_lookup_by_id (self.id)
-- return self.store.db.entry_get (entry, rhythmdb.PROP_TITLE)
--
-- def get_url(self):
-- return self.store.urlbase + str(self.id + CONTAINER_COUNT)
--
-- def get_path(self):
-- entry = self.store.db.entry_lookup_by_id (self.id)
-- uri = self.store.db.entry_get (entry, rhythmdb.PROP_LOCATION)
-- if uri.startswith("file://"):
-- return unicode(urllib.url2pathname(uri)[len("file://"):])
-- else:
-- return None
--
--class MediaStore:
-- implements = ['MediaServer']
--
-- def __init__(self, server, **kwargs):
-- print "creating UPnP MediaStore"
-- self.server = server
-- self.db = kwargs['db']
-- self.plugin = kwargs['plugin']
--
-- self.urlbase = kwargs.get('urlbase','')
-- if( len(self.urlbase) > 0 and self.urlbase[len(self.urlbase)-1] != '/'):
-- self.urlbase += '/'
--
-- self.name = self.server.coherence.hostname
--
-- self.containers = {}
-- self.containers[ROOT_CONTAINER_ID] = \
-- Container( ROOT_CONTAINER_ID,-1, self.server.coherence.hostname)
--
-- self.containers[AUDIO_ALL_CONTAINER_ID] = \
-- Container( AUDIO_ALL_CONTAINER_ID,ROOT_CONTAINER_ID, 'All tracks',
-- children_callback=self.children_tracks)
-- self.containers[ROOT_CONTAINER_ID].add_child(self.containers[AUDIO_ALL_CONTAINER_ID])
--
-- #self.containers[AUDIO_ALBUM_CONTAINER_ID] = \
-- # Container( AUDIO_ALBUM_CONTAINER_ID,ROOT_CONTAINER_ID, 'Albums',
-- # children_callback=self.children_albums)
-- #self.containers[ROOT_CONTAINER_ID].add_child(self.containers[AUDIO_ALBUM_CONTAINER_ID])
--
-- #self.containers[AUDIO_ARTIST_CONTAINER_ID] = \
-- # Container( AUDIO_ARTIST_CONTAINER_ID,ROOT_CONTAINER_ID, 'Artists',
-- # children_callback=self.children_artists)
-- #self.containers[ROOT_CONTAINER_ID].add_child(self.containers[AUDIO_ARTIST_CONTAINER_ID])
--
-- louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)
--
-- def get_by_id(self,id):
-- print "getting resource id " + str(id)
-- if id.startswith('artist_all_tracks_'):
-- return self.containers[id]
--
-- id = int(id)
-- if id < 1000:
-- item = self.containers[id]
-- else:
-- item = Track(self, (id - CONTAINER_COUNT))
--
-- return item
--
-- def upnp_init(self):
-- if self.server:
-- self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo', [
-- #'internal:%s:*:*' % self.name,
-- 'http-get:*:audio/mpeg:*',
-- ])
--
-- def children_tracks(self):
-- tracks = []
--
-- def track_cb (entry):
-- id = self.db.entry_get (entry, rhythmdb.PROP_ENTRY_ID)
-- tracks.append(Track(self, id))
-- self.db.entry_foreach_by_type (self.db.entry_type_get_by_name('song'), track_cb)
-+class Album(log.Loggable):
-+
-+ logCategory = 'rb_media_store'
-+
-+ def __init__(self, store, title, id):
-+ self.id = id
-+ self.title = title
-+ self.store = store
-+
-+ query = self.store.db.query_new()
-+ self.store.db.query_append(query,[rhythmdb.QUERY_PROP_EQUALS, rhythmdb.PROP_TYPE, self.store.db.entry_type_get_by_name('song')],
-+ [rhythmdb.QUERY_PROP_EQUALS, rhythmdb.PROP_ALBUM, self.title])
-+ self.tracks_per_album_query = self.store.db.query_model_new(query)
-+ #self.tracks_per_album_query.set_sort_order(rhythmdb.rhythmdb_query_model_track_sort_func)
-+ self.store.db.do_full_query_async_parsed(self.tracks_per_album_query, query)
-+
-+ def get_children(self,start=0,request_count=0):
-+ children = []
-+
-+ def track_sort(x,y):
-+ entry = self.store.db.entry_lookup_by_id (x.id)
-+ x_track = self.store.db.entry_get (entry, rhythmdb.PROP_TRACK_NUMBER)
-+ entry = self.store.db.entry_lookup_by_id (y.id)
-+ y_track = self.store.db.entry_get (entry, rhythmdb.PROP_TRACK_NUMBER)
-+ return cmp(x_track,y_track)
-+
-+ def collate (model, path, iter):
-+ self.info("Album get_children %r %r %r" %(model, path, iter))
-+ id = model.get(iter, 0)[0]
-+ children.append(Track(self.store,id))
-+
-+ self.tracks_per_album_query.foreach(collate)
-+
-+ children.sort(cmp=track_sort)
-+
-+ if request_count == 0:
-+ return children[start:]
-+ else:
-+ return children[start:request_count]
-+
-+ def get_child_count(self):
-+ return len(self.get_children())
-+
-+ def get_item(self):
-+ item = DIDLLite.MusicAlbum(self.id, AUDIO_ALBUM_CONTAINER_ID, self.title)
-+ return item
-+
-+ def get_id(self):
-+ return self.id
-+
-+ def get_name(self):
-+ return self.title
-+
-+ def get_cover(self):
-+ return self.cover
-+
-+
-+class Artist(log.Loggable):
-+
-+ logCategory = 'rb_media_store'
-+
-+ def __init__(self, store, name, id):
-+ self.id = id
-+ self.name = name
-+ self.store = store
-+
-+ query = self.store.db.query_new()
-+ self.store.db.query_append(query,[rhythmdb.QUERY_PROP_EQUALS, rhythmdb.PROP_TYPE, self.store.db.entry_type_get_by_name('song')],
-+ [rhythmdb.QUERY_PROP_EQUALS, rhythmdb.PROP_ARTIST, self.name])
-+ qm = self.store.db.query_model_new(query)
-+ self.store.db.do_full_query_async_parsed(qm, query)
-+
-+ self.albums_per_artist_query = self.store.db.property_model_new(rhythmdb.PROP_ALBUM)
-+ self.albums_per_artist_query.props.query_model = qm
-+
-+ def get_children(self,start=0,request_count=0):
-+ children = []
-+
-+ def collate (model, path, iter):
-+ name = model.get(iter, 0)[0]
-+ priority = model.get(iter, 1)[0]
-+ self.info("get_children collate %r %r", name, priority)
-+ if priority is False:
-+ try:
-+ album = self.store.albums[name]
-+ children.append(album)
-+ except:
-+ self.warning("hmm, a new album %r, that shouldn't happen", name)
-+
-+ self.albums_per_artist_query.foreach(collate)
-+
-+ if request_count == 0:
-+ return children[start:]
-+ else:
-+ return children[start:request_count]
-+
-+ def get_child_count(self):
-+ return len(self.get_children())
-+
-+ def get_item(self):
-+ item = DIDLLite.MusicArtist(self.id, AUDIO_ARTIST_CONTAINER_ID, self.name)
-+ return item
-+
-+ def get_id(self):
-+ return self.id
-+
-+ def get_name(self):
-+ return self.name
-+
-+
-+class Track(log.Loggable):
-+
-+ logCategory = 'rb_media_store'
-+
-+ def __init__(self, store, id):
-+ self.store = store
-+ if type(id) == int:
-+ self.id = id
-+ else:
-+ self.id = self.store.db.entry_get (id, rhythmdb.PROP_ENTRY_ID)
-+
-+ def get_children(self, start=0, request_count=0):
-+ return []
-+
-+ def get_child_count(self):
-+ return 0
-+
-+ def get_item(self):
-+
-+ self.info("Track get_item %r" %(self.id))
-+
-+ host = ""
-+
-+ # load common values
-+ entry = self.store.db.entry_lookup_by_id(self.id)
-+ # Bitrate is in bytes/second, not kilobits/second
-+ bitrate = self.store.db.entry_get(entry, rhythmdb.PROP_BITRATE) * 1024 / 8
-+ # Duration is in HH:MM:SS format
-+ seconds = self.store.db.entry_get(entry, rhythmdb.PROP_DURATION)
-+ hours = seconds / 3600
-+ seconds = seconds - hours * 3600
-+ minutes = seconds / 60
-+ seconds = seconds - minutes * 60
-+ duration = ("%02d:%02d:%02d") % (hours, minutes, seconds)
-+
-+ location = self.get_path(entry)
-+ mimetype = self.store.db.entry_get(entry, rhythmdb.PROP_MIMETYPE)
-+ # This isn't a real mime-type
-+ if mimetype == "application/x-id3":
-+ mimetype = "audio/mpeg"
-+ size = self.store.db.entry_get(entry, rhythmdb.PROP_FILE_SIZE)
-+
-+ # create item
-+ item = DIDLLite.MusicTrack(self.id + TRACK_COUNT)
-+ item.album = self.store.db.entry_get(entry, rhythmdb.PROP_ALBUM)
-+ item.artist = self.store.db.entry_get(entry, rhythmdb.PROP_ARTIST)
-+ #item.date =
-+ item.genre = self.store.db.entry_get(entry, rhythmdb.PROP_GENRE)
-+ item.originalTrackNumber = str(self.store.db.entry_get (entry, rhythmdb.PROP_TRACK_NUMBER))
-+ item.title = self.store.db.entry_get(entry, rhythmdb.PROP_TITLE) # much nicer if it was entry.title
-+
-+ #cover = self.store.db.entry_request_extra_metadata(entry, "rb:coverArt")
-+ #self.warning("cover for %r is %r", item.title, cover)
-+ #item.albumArtURI = ## can we somehow store art in the upnp share??
-+
-+ # add internal resource
-+ #res = DIDLLite.Resource(location, 'internal:%s:%s:*' % (host, mimetype))
-+ #res.size = size
-+ #res.duration = duration
-+ #res.bitrate = bitrate
-+ #item.res.append(res)
-+
-+ # add http resource
-+ res = DIDLLite.Resource(self.get_url(), 'http-get:*:%s:*' % mimetype)
-+ if size > 0:
-+ res.size = size
-+ if duration > 0:
-+ res.duration = str(duration)
-+ if bitrate > 0:
-+ res.bitrate = str(bitrate)
-+ item.res.append(res)
-+
-+ return item
-+
-+ def get_id(self):
-+ return self.id
-+
-+ def get_name(self):
-+ entry = self.store.db.entry_lookup_by_id (self.id)
-+ return self.store.db.entry_get(entry, rhythmdb.PROP_TITLE)
-+
-+ def get_url(self):
-+ return self.store.urlbase + str(self.id + TRACK_COUNT)
-+
-+ def get_path(self, entry = None):
-+ if entry is None:
-+ entry = self.store.db.entry_lookup_by_id (self.id)
-+ uri = self.store.db.entry_get(entry, rhythmdb.PROP_LOCATION)
-+ self.warning("Track get_path uri = %r", uri)
-+ location = None
-+ if uri.startswith("file://"):
-+ location = unicode(urllib.unquote(uri[len("file://"):]))
-+ self.warning("Track get_path location = %r", location)
-+
-+ return location
-+
-+class MediaStore(log.Loggable):
-+
-+ logCategory = 'rb_media_store'
-+ implements = ['MediaServer']
-+
-+ def __init__(self, server, **kwargs):
-+ print "creating UPnP MediaStore"
-+ self.server = server
-+ self.db = kwargs['db']
-+ self.plugin = kwargs['plugin']
-
-- return tracks
-+ self.update_id = 0
-+
-+ self.next_id = CONTAINER_COUNT
-+ self.albums = None
-+ self.artists = None
-+ self.tracks = None
-+
-+ self.urlbase = kwargs.get('urlbase','')
-+ if( len(self.urlbase) > 0 and self.urlbase[len(self.urlbase)-1] != '/'):
-+ self.urlbase += '/'
-+
-+ self.name = "Rhythmbox on %s" % self.server.coherence.hostname
-+
-+ query = self.db.query_new()
-+ self.info(query)
-+ self.db.query_append(query, [rhythmdb.QUERY_PROP_EQUALS, rhythmdb.PROP_TYPE, self.db.entry_type_get_by_name('song')])
-+ qm = self.db.query_model_new(query)
-+ self.db.do_full_query_async_parsed(qm, query)
-+
-+ self.album_query = self.db.property_model_new(rhythmdb.PROP_ALBUM)
-+ self.album_query.props.query_model = qm
-+
-+ self.artist_query = self.db.property_model_new(rhythmdb.PROP_ARTIST)
-+ self.artist_query.props.query_model = qm
-+
-+ self.containers = {}
-+ self.containers[ROOT_CONTAINER_ID] = \
-+ Container( ROOT_CONTAINER_ID,-1, "Rhythmbox on %s" % self.server.coherence.hostname)
-+
-+ self.containers[AUDIO_ALL_CONTAINER_ID] = \
-+ Container( AUDIO_ALL_CONTAINER_ID,ROOT_CONTAINER_ID, 'All tracks',
-+ children_callback=self.children_tracks)
-+ self.containers[ROOT_CONTAINER_ID].add_child(self.containers[AUDIO_ALL_CONTAINER_ID])
-+
-+ self.containers[AUDIO_ALBUM_CONTAINER_ID] = \
-+ Container( AUDIO_ALBUM_CONTAINER_ID,ROOT_CONTAINER_ID, 'Albums',
-+ children_callback=self.children_albums)
-+ self.containers[ROOT_CONTAINER_ID].add_child(self.containers[AUDIO_ALBUM_CONTAINER_ID])
-+
-+ self.containers[AUDIO_ARTIST_CONTAINER_ID] = \
-+ Container( AUDIO_ARTIST_CONTAINER_ID,ROOT_CONTAINER_ID, 'Artists',
-+ children_callback=self.children_artists)
-+ self.containers[ROOT_CONTAINER_ID].add_child(self.containers[AUDIO_ARTIST_CONTAINER_ID])
-+
-+ louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)
-+
-+ def get_by_id(self,id):
-+
-+ self.info("looking for id %r", id)
-+ id = int(id)
-+ if id < TRACK_COUNT:
-+ item = self.containers[id]
-+ else:
-+ item = Track(self, (id - TRACK_COUNT))
-
-- def children_albums(self):
-- return []
-+ return item
-
-- def children_artists(self):
-- return []
-+ def get_next_container_id(self):
-+ ret = self.next_id
-+ self.next_id += 1
-+ return ret
-+
-+ def upnp_init(self):
-+ if self.server:
-+ self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo', [
-+ #'internal:%s:*:*' % self.name,
-+ 'http-get:*:audio/mpeg:*',
-+ ])
-+
-+ def children_tracks(self):
-+ tracks = []
-+
-+ def track_cb (entry):
-+ if self.db.entry_get (entry, rhythmdb.PROP_HIDDEN):
-+ return
-+ id = self.db.entry_get (entry, rhythmdb.PROP_ENTRY_ID)
-+ track = Track(self, id)
-+ tracks.append(track)
-+
-+ self.db.entry_foreach_by_type (self.db.entry_type_get_by_name('song'), track_cb)
-+ return tracks
-+
-+ def children_albums(self):
-+ albums = {}
-+
-+ self.info('children_albums')
-+
-+ def album_sort(x,y):
-+ r = cmp(x.title,y.title)
-+ self.info("sort %r - %r = %r", x.title, y.title, r)
-+ return r
-+
-+ def collate (model, path, iter):
-+ name = model.get(iter, 0)[0]
-+ priority = model.get(iter, 1)[0]
-+ self.info("children_albums collate %r %r", name, priority)
-+ if priority is False:
-+ id = self.get_next_container_id()
-+ album = Album(self, name, id)
-+ self.containers[id] = album
-+ albums[name] = album
-+
-+ if self.albums is None:
-+ self.album_query.foreach(collate)
-+ self.albums = albums
-+
-+ albums = self.albums.values() #.sort(cmp=album_sort)
-+ albums.sort(cmp=album_sort)
-+ return albums
-+
-+ def children_artists(self,killbug=False):
-+ artists = []
-+
-+ self.info('children_artists')
-+
-+ def collate (model, path, iter):
-+ name = model.get(iter, 0)[0]
-+ priority = model.get(iter, 1)[0]
-+ if priority is False:
-+ id = self.get_next_container_id()
-+ artist = Artist(self,name, id)
-+ self.containers[id] = artist
-+ artists.append(artist)
-+
-+ if self.artists is None:
-+ self.artist_query.foreach(collate)
-+ self.artists = artists
-
-+ return self.artists
-diff -uprN rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/UpnpSource.py rhythmbox-0.11.4/plugins/coherence/upnp_coherence/UpnpSource.py
---- rhythmbox-0.11.4.old/plugins/coherence/upnp_coherence/UpnpSource.py 2007-07-24 12:54:04.000000000 +0100
-+++ rhythmbox-0.11.4/plugins/coherence/upnp_coherence/UpnpSource.py 2008-02-05 12:35:57.000000000 +0000
-@@ -1,101 +1,177 @@
-+# Copyright 2007, James Livingston
-+# Copyright 2007, Frank Scholz
-+
- import rb, rhythmdb
- import gobject, gtk
-
--class UpnpSource(rb.BrowserSource):
-- __gproperties__ = {
-- 'plugin': (rb.Plugin, 'plugin', 'plugin', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
-- 'client': (gobject.TYPE_PYOBJECT, 'client', 'client', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
-- 'usn': (gobject.TYPE_PYOBJECT, 'usn', 'usn', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
-- }
--
-- def __init__(self):
-- rb.BrowserSource.__init__(self)
-- self.__db = None
-- self.__activated = False
--
--
-- def do_set_property(self, property, value):
-- if property.name == 'plugin':
-- self.__plugin = value
-- elif property.name == 'client':
-- self.__client = value
-- self.props.name = self.__client.device.get_friendly_name()
-- elif property.name == 'usn':
-- self.__usn = value
-- else:
-- raise AttributeError, 'unknown property %s' % property.name
--
--
-- def do_impl_activate(self):
-- if not self.__activated:
-- print "activating upnp source"
-- self.__activated = True
--
-- shell = self.get_property('shell')
-- self.__db = shell.get_property('db')
-- self.__entry_type = self.get_property('entry-type')
--
-- # load upnp db
-- self.load_db(0)
-- self.__client.content_directory.subscribe_for_variable('ContainerUpdateIDs', self.state_variable_change)
-- self.__client.content_directory.subscribe_for_variable('SystemUpdateID', self.state_variable_change)
--
--
-- def load_db(self, id):
-- d = self.__client.content_directory.browse(id, browse_flag='BrowseDirectChildren', backward_compatibility=False)
-- d.addCallback(self.process_media_server_browse, self.__usn)
--
--
-- def state_variable_change(self, variable, usn):
-- print "%s changed from %s to %s" % (variable.name, variable.old_value, variable.value)
-- if variable.old_value == '':
-- return
--
-- if variable.name == 'SystemUpdateID':
-- self.load_db(0)
-- elif variable.name == 'ContainerUpdateIDs':
-- changes = variable.value.split(',')
-- while len(changes) > 1:
-- container = changes.pop(0).strip()
-- update_id = changes.pop(0).strip()
-- if container in self.container_watch:
-- print "we have a change in %s, container needs a reload" % container
-- self.load_db(container)
--
--
-- def process_media_server_browse(self, results, usn):
-- for k,v in results.iteritems():
-- if k == 'items':
-- for id, values in v.iteritems():
-- if values['upnp_class'].startswith('object.container'):
-- self.load_db(id)
-- if values['upnp_class'].startswith('object.item.audioItem'):
-- # (url, [method, something which is in asterix, format, semicolon delimited key=value map of something])
-- resources = [(k, v.split(':')) for (k, v) in values['resources'].iteritems()]
-- # break data into map
-- for r in resources:
-- if r[1][3] is not '*':
-- r[1][3] = dict([v.split('=') for v in r[1][3].split(';')])
-- else:
-- r[1][3] = dict()
--
-- url = None
-- for r in resources:
-- if r[1][3].has_key('DLNA.ORG_CI') and r[1][3]['DLNA.ORG_CI'] is not '1':
-- url = r[0]
-- break
--
-- if url is None:
-- # use transcoded format, since we can't find a normal one
-- url = resources[0][0]
--
-- entry = self.__db.entry_lookup_by_location (url)
-- if entry == None:
-- entry = self.__db.entry_new(self.__entry_type, url)
--
-- self.__db.set(entry, rhythmdb.PROP_TITLE, values['title'])
--
-- self.__db.commit()
-+from coherence import __version_info__ as coherence_version
-
--gobject.type_register(UpnpSource)
-+from coherence import log
-+
-+class UpnpSource(rb.BrowserSource,log.Loggable):
-+
-+ logCategory = 'rb_media_store'
-
-+ __gproperties__ = {
-+ 'plugin': (rb.Plugin, 'plugin', 'plugin', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
-+ 'client': (gobject.TYPE_PYOBJECT, 'client', 'client', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
-+ 'usn': (gobject.TYPE_PYOBJECT, 'usn', 'usn', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
-+ }
-+
-+ def __init__(self):
-+ rb.BrowserSource.__init__(self)
-+ self.__db = None
-+ self.__activated = False
-+ self.container_watch = []
-+ if coherence_version < (0,5,1):
-+ self.process_media_server_browse = self.old_process_media_server_browse
-+ else:
-+ self.process_media_server_browse = self.new_process_media_server_browse
-+
-+ def do_set_property(self, property, value):
-+ if property.name == 'plugin':
-+ self.__plugin = value
-+ elif property.name == 'client':
-+ self.__client = value
-+ self.props.name = self.__client.device.get_friendly_name()
-+ elif property.name == 'usn':
-+ self.__usn = value
-+ else:
-+ raise AttributeError, 'unknown property %s' % property.name
-+
-+
-+ def do_impl_activate(self):
-+ if not self.__activated:
-+ print "activating upnp source"
-+ self.__activated = True
-+
-+ shell = self.get_property('shell')
-+ self.__db = shell.get_property('db')
-+ self.__entry_type = self.get_property('entry-type')
-+
-+ # load upnp db
-+ self.load_db(0)
-+ self.__client.content_directory.subscribe_for_variable('ContainerUpdateIDs', self.state_variable_change)
-+ self.__client.content_directory.subscribe_for_variable('SystemUpdateID', self.state_variable_change)
-+
-+
-+ def load_db(self, id):
-+ if coherence_version < (0,5,1):
-+ d = self.__client.content_directory.browse(id, browse_flag='BrowseDirectChildren', backward_compatibility=False)
-+ else:
-+ d = self.__client.content_directory.browse(id, browse_flag='BrowseDirectChildren', process_result=False, backward_compatibility=False)
-+ d.addCallback(self.process_media_server_browse, self.__usn)
-+
-+
-+ def state_variable_change(self, variable, usn=None):
-+ print "%s changed from %s to %s" % (variable.name, variable.old_value, variable.value)
-+ if variable.old_value == '':
-+ return
-+
-+ if variable.name == 'SystemUpdateID':
-+ self.load_db(0)
-+ elif variable.name == 'ContainerUpdateIDs':
-+ changes = variable.value.split(',')
-+ while len(changes) > 1:
-+ container = changes.pop(0).strip()
-+ update_id = changes.pop(0).strip()
-+ if container in self.container_watch:
-+ print "we have a change in %s, container needs a reload" % container
-+ self.load_db(container)
-+
-+
-+ def new_process_media_server_browse(self, results, usn):
-+ for item in results:
-+ self.info("process_media_server_browse %r %r", item.id, item)
-+ if item.upnp_class.startswith('object.container'):
-+ self.load_db(item.id)
-+ if item.upnp_class.startswith('object.item.audioItem'):
-+
-+ url = None
-+ duration = None
-+ size = None
-+ bitrate = None
-+
-+ for res in item.res:
-+ remote_protocol,remote_network,remote_content_format,remote_flags = res.protocolInfo.split(':')
-+ self.info("%r %r %r %r",remote_protocol,remote_network,remote_content_format,remote_flags)
-+ if remote_protocol == 'http-get':
-+ url = res.data
-+ duration = res.duration
-+ size = res.size
-+ bitrate = res.bitrate
-+ break
-+
-+ if url is not None:
-+ self.info("url %r %r",url,item.title)
-+
-+ entry = self.__db.entry_lookup_by_location (url)
-+ if entry == None:
-+ entry = self.__db.entry_new(self.__entry_type, url)
-+
-+ self.__db.set(entry, rhythmdb.PROP_TITLE, item.title)
-+ try:
-+ if item.artist is not None:
-+ self.__db.set(entry, rhythmdb.PROP_ARTIST, item.artist)
-+ except AttributeError:
-+ pass
-+ try:
-+ if item.album is not None:
-+ self.__db.set(entry, rhythmdb.PROP_ALBUM, item.album)
-+ except AttributeError:
-+ pass
-+
-+ try:
-+ self.info("%r %r", item.title,item.originalTrackNumber)
-+ if item.originalTrackNumber is not None:
-+ self.__db.set(entry, rhythmdb.PROP_TRACK_NUMBER, int(item.originalTrackNumber))
-+ except AttributeError:
-+ pass
-+
-+ if duration is not None:
-+ h,m,s = duration.split(':')
-+ seconds = int(h)*3600 + int(m)*60 + int(s)
-+ self.info("%r %r:%r:%r %r", duration, h, m , s, seconds)
-+ self.__db.set(entry, rhythmdb.PROP_DURATION, seconds)
-+
-+ if size is not None:
-+ self.__db.set(entry, rhythmdb.PROP_FILE_SIZE,int(size))
-+
-+ self.__db.commit()
-+
-+
-+ def old_process_media_server_browse(self, results, usn):
-+ for k,v in results.iteritems():
-+ if k == 'items':
-+ for id, values in v.iteritems():
-+ if values['upnp_class'].startswith('object.container'):
-+ self.load_db(id)
-+ if values['upnp_class'].startswith('object.item.audioItem'):
-+ # (url, [method, something which is in asterix, format, semicolon delimited key=value map of something])
-+ resources = [(k, v.split(':')) for (k, v) in values['resources'].iteritems()]
-+ # break data into map
-+ for r in resources:
-+ if r[1][3] is not '*':
-+ r[1][3] = dict([v.split('=') for v in r[1][3].split(';')])
-+ else:
-+ r[1][3] = dict()
-+
-+ url = None
-+ for r in resources:
-+ if r[1][3].has_key('DLNA.ORG_CI') and r[1][3]['DLNA.ORG_CI'] is not '1':
-+ url = r[0]
-+ break
-+
-+ if url is None:
-+ # use transcoded format, since we can't find a normal one
-+ url = resources[0][0]
-+
-+ entry = self.__db.entry_lookup_by_location (url)
-+ if entry == None:
-+ entry = self.__db.entry_new(self.__entry_type, url)
-+
-+ self.__db.set(entry, rhythmdb.PROP_TITLE, values['title'])
-+
-+ self.__db.commit()
-+
-+gobject.type_register(UpnpSource)
diff --git a/rhythmbox.spec b/rhythmbox.spec
index 8da495a..04f9376 100644
--- a/rhythmbox.spec
+++ b/rhythmbox.spec
@@ -2,8 +2,8 @@
Name: rhythmbox
Summary: Music Management Application
-Version: 0.11.4
-Release: 13%{?dist}
+Version: 0.11.5
+Release: 1%{?dist}
License: GPLv2+ and GFDL+
Group: Applications/Multimedia
URL: http://www.gnome.org/projects/rhythmbox/
@@ -55,27 +55,6 @@ ExcludeArch: s390 s390x
Patch0: rb-disable-power-plugin-by-default.patch
# http://bugzilla.gnome.org/show_bug.cgi?id=499208
Patch1: rhythmbox-0.11.3-force-python-thread-init.patch
-# http://bugzilla.gnome.org/show_bug.cgi?id=510323
-Patch2: x-content.patch
-# http://bugzilla.gnome.org/show_bug.cgi?id=509701
-Patch3: soup24.patch
-# http://bugzilla.gnome.org/show_bug.cgi?id=510406
-Patch4: gsd-media-player-api.patch
-
-Patch5: rb-automake-warning.patch
-
-# http://bugzilla.gnome.org/show_bug.cgi?id=519737
-Patch6: rb-activate-generic-players-from-uri.patch
-
-# http://bugzilla.gnome.org/show_bug.cgi?id=493996
-Patch7: rb-ipod-save-artwork.patch
-
-# https://bugzilla.redhat.com/show_bug.cgi?id=437066
-Patch8: rhythmbox-0.11.4-bigger-pane.patch
-
-# http://bugzilla.gnome.org/show_bug.cgi?id=512870
-# https://bugzilla.redhat.com/show_bug.cgi?id=436112
-Patch9: rhythmbox-0.11.4-updated-upnp.patch
%description
Rhythmbox is an integrated music management application based on the powerful
@@ -106,14 +85,6 @@ UPnP/DLNA network devices.
%patch0 -p0 -b .dont-disable-suspend
%patch1 -p1 -b .python-threading
-%patch2 -p1 -b .x-content
-%patch3 -p1 -b .soup24
-%patch4 -p0 -b .gsd
-%patch5 -p0 -b .automake
-%patch6 -p0 -b .player-activate
-%patch7 -p1 -b .ipod-artwork
-%patch8 -p0 -b .bigger-pane
-%patch9 -p1 -b .updated-upnp
%build
autoconf
@@ -231,6 +202,10 @@ fi
%{_libdir}/rhythmbox/plugins/upnp_coherence
%changelog
+* Mon Mar 17 2008 - Bastien Nocera - 0.11.5-1
+- Update to 0.11.5
+- Remove outdated patches
+
* Thu Mar 13 2008 - Bastien Nocera - 0.11.4-13
- Big update of the UPNP plugin, with MediaRenderer support
- Add patch to make the pane window bigger by default (#437066)
diff --git a/soup24.patch b/soup24.patch
deleted file mode 100644
index d257f63..0000000
--- a/soup24.patch
+++ /dev/null
@@ -1,1743 +0,0 @@
-diff -urN rhythmbox-0.11.4/configure.ac rhythmbox-0.11.4.new/configure.ac
---- rhythmbox-0.11.4/configure.ac 2007-12-20 11:56:44.000000000 +0000
-+++ rhythmbox-0.11.4.new/configure.ac 2008-02-06 00:57:27.000000000 +0000
-@@ -441,18 +441,25 @@
- dnl Check for libsoup, needed for DAAP and audioscrobbler
- if test "x$enable_daap" = "xyes" || test "x$enable_audioscrobbler" != "xno"; then
- PKG_CHECK_MODULES(SOUP, \
-- libsoup-2.2,
-- have_libsoup=yes,
-- have_libsoup=no)
-- if test x"$have_libsoup" = "xno"; then
-+ libsoup-2.4,
-+ have_libsoup24=yes,
-+ have_libsoup24=no)
-+ if test x"$have_libsoup24" = "xno"; then
- PKG_CHECK_MODULES(SOUP,
-- libsoup-2.4,
-- have_libsoup=yes,
-- have_libsoup=no)
-+ libsoup-2.2,
-+ have_libsoup22=yes,
-+ have_libsoup22=no)
- fi
-- if test x"$have_libsoup" = "xyes"; then
-+ if test x"$have_libsoup24" = "xyes" || test x"$have_libsoup22" = "xyes"; then
-+ have_libsoup=yes
- AC_DEFINE(HAVE_LIBSOUP, 1, [Define if libsoup support is enabled])
- fi
-+ if test x"$have_libsoup24" = "xyes"; then
-+ AC_DEFINE(HAVE_LIBSOUP_2_4, 1, [Define if libsoup 2.4 support is enabled])
-+ fi
-+ if test x"$have_libsoup22" = "xyes"; then
-+ AC_DEFINE(HAVE_LIBSOUP_2_2, 1, [Define if libsoup 2.2 support is enabled])
-+ fi
- fi
-
- AM_CONDITIONAL(USE_LIBSOUP, test x"$have_libsoup" = "xyes")
-@@ -513,27 +520,9 @@
-
-
-
--AC_PATH_X
--
--if test x"$x_includes" != x"NONE" && test -n "$x_includes" ; then
-- CFLAGS=$CFLAGS -I`echo $x_includes | sed -e "s/:/ -I/g"`
--fi
--if test x"$x_libraries" != x"NONE" && test -n "$x_libraries" ; then
-- LIBS=-L`echo $x_libraries | sed -e "s/:/ -L/g"`
--fi
--
--have_xidle=no
--AC_COMPILE_IFELSE([
-- #include
--int main(int argc,char **argv) {
-- return 0;
--}
--], have_xidle=yes)
--AC_MSG_CHECKING(for XIDLE extension)
--AC_MSG_RESULT($have_xidle)
--if test x"$have_xidle" = "xyes" ; then
-- AC_DEFINE(HAVE_XIDLE_EXTENSION, 1, [defined if you have X11/extensions/xidle.h])
--fi
-+AC_PATH_XTRA
-+CFLAGS="$CFLAGS $X_CFLAGS"
-+#LIBS=$X_LIBS
-
- dnl Multimedia keys
- have_xfree=no
-@@ -1167,7 +1156,11 @@
- AC_MSG_NOTICE([ CD burning support disabled])
- fi
- if test x"$enable_daap" = xyes; then
-- AC_MSG_NOTICE([** DAAP (music sharing) support is enabled])
-+ if test x"$have_libsoup24" = "xyes"; then
-+ AC_MSG_NOTICE([** DAAP (music sharing) support is enabled (using libsoup 2.4)])
-+ elif test x"$have_libsoup22" = "xyes"; then
-+ AC_MSG_NOTICE([** DAAP (music sharing) support is enabled (using libsoup 2.2)])
-+ fi
- else
- AC_MSG_NOTICE([ DAAP (music sharing) support is disabled])
- fi
-@@ -1197,7 +1190,11 @@
- AC_MSG_NOTICE([ gnome-keyring support disabled])
- fi
- if test x"$enable_audioscrobbler" != xno; then
-- AC_MSG_NOTICE([** Audioscrobbler support enabled])
-+ if test x"$have_libsoup24" = "xyes"; then
-+ AC_MSG_NOTICE([** Audioscrobbler support enabled (using libsoup 2.4)])
-+ elif test x"$have_libsoup22" = "xyes"; then
-+ AC_MSG_NOTICE([** Audioscrobbler support enabled (using libsoup 2.2)])
-+ fi
- else
- AC_MSG_NOTICE([ Audioscrobbler support disabled])
- fi
-diff -urN rhythmbox-0.11.4/lib/Makefile.am rhythmbox-0.11.4.new/lib/Makefile.am
---- rhythmbox-0.11.4/lib/Makefile.am 2007-08-01 09:04:11.000000000 +0100
-+++ rhythmbox-0.11.4.new/lib/Makefile.am 2008-02-06 00:57:27.000000000 +0000
-@@ -34,7 +34,8 @@
- rb-string-value-map.c \
- rb-string-value-map.h \
- rb-async-queue-watch.c \
-- rb-async-queue-watch.h
-+ rb-async-queue-watch.h \
-+ rb-soup-compat.h
-
- if WITH_INTERNAL_GSEQUENCE
- librb_la_SOURCES += gsequence.c gsequence.h
-diff -urN rhythmbox-0.11.4/lib/rb-proxy-config.c rhythmbox-0.11.4.new/lib/rb-proxy-config.c
---- rhythmbox-0.11.4/lib/rb-proxy-config.c 2007-06-03 02:55:02.000000000 +0100
-+++ rhythmbox-0.11.4.new/lib/rb-proxy-config.c 2008-02-06 00:57:27.000000000 +0000
-@@ -231,7 +231,28 @@
- }
- }
-
--#if defined(HAVE_LIBSOUP)
-+#if defined(HAVE_LIBSOUP_2_4)
-+SoupURI *
-+rb_proxy_config_get_libsoup_uri (RBProxyConfig *config)
-+{
-+ SoupURI *uri = NULL;
-+
-+ if (!config->enabled)
-+ return NULL;
-+
-+ uri = soup_uri_new (NULL);
-+ soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
-+ soup_uri_set_host (uri, config->host);
-+ soup_uri_set_port (uri, config->port);
-+
-+ if (config->auth_enabled) {
-+ soup_uri_set_user (uri, config->username);
-+ soup_uri_set_password (uri, config->password);
-+ }
-+
-+ return uri;
-+}
-+#elif defined(HAVE_LIBSOUP_2_2)
- SoupUri *
- rb_proxy_config_get_libsoup_uri (RBProxyConfig *config)
- {
-diff -urN rhythmbox-0.11.4/lib/rb-proxy-config.h rhythmbox-0.11.4.new/lib/rb-proxy-config.h
---- rhythmbox-0.11.4/lib/rb-proxy-config.h 2007-06-03 02:55:02.000000000 +0100
-+++ rhythmbox-0.11.4.new/lib/rb-proxy-config.h 2008-02-06 00:57:27.000000000 +0000
-@@ -24,8 +24,8 @@
- #include
-
- #if defined(HAVE_LIBSOUP)
-+#include "rb-soup-compat.h"
- #include
--#include
- #endif
-
- G_BEGIN_DECLS
-@@ -65,9 +65,7 @@
-
- RBProxyConfig * rb_proxy_config_new (void);
-
--#if defined(HAVE_LIBSOUP)
--SoupUri * rb_proxy_config_get_libsoup_uri (RBProxyConfig *config);
--#endif
-+SoupURI * rb_proxy_config_get_libsoup_uri (RBProxyConfig *config);
-
- #endif /* RB_PROXY_CONFIG_H */
-
-diff -urN rhythmbox-0.11.4/lib/rb-soup-compat.h rhythmbox-0.11.4.new/lib/rb-soup-compat.h
---- rhythmbox-0.11.4/lib/rb-soup-compat.h 1970-01-01 01:00:00.000000000 +0100
-+++ rhythmbox-0.11.4.new/lib/rb-soup-compat.h 2008-02-06 00:57:27.000000000 +0000
-@@ -0,0 +1,59 @@
-+/*
-+ * Copyright (C) 2008 Jonathan Matthew
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-+ * 02110-1301 USA
-+ */
-+
-+#ifndef RB_SOUP_COMPAT_H
-+#define RB_SOUP_COMPAT_H
-+
-+#include
-+
-+/* compatibility junk for libsoup 2.2.
-+ * not intended to obviate the need for #ifdefs in code, but
-+ * should remove a lot of the trivial ones and make it easier
-+ * to drop libsoup 2.2
-+ */
-+#if defined(HAVE_LIBSOUP_2_2)
-+
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+
-+typedef SoupUri SoupURI;
-+typedef SoupMessageCallbackFn SoupSessionCallback;
-+typedef SoupServerContext SoupClientContext;
-+
-+#define SOUP_MEMORY_TAKE SOUP_BUFFER_SYSTEM_OWNED
-+#define SOUP_MEMORY_TEMPORARY SOUP_BUFFER_USER_OWNED
-+
-+#define soup_message_headers_append soup_message_add_header
-+#define soup_message_headers_get soup_message_get_header
-+
-+#define soup_client_context_get_host soup_server_context_get_client_host
-+
-+#endif /* HAVE_LIBSOUP_2_2 */
-+
-+#endif /* RB_SOUP_COMPAT_H */
-+
-diff -urN rhythmbox-0.11.4/plugins/audioscrobbler/rb-audioscrobbler.c rhythmbox-0.11.4.new/plugins/audioscrobbler/rb-audioscrobbler.c
---- rhythmbox-0.11.4/plugins/audioscrobbler/rb-audioscrobbler.c 2007-12-17 09:26:53.000000000 +0000
-+++ rhythmbox-0.11.4.new/plugins/audioscrobbler/rb-audioscrobbler.c 2008-02-06 00:59:48.000000000 +0000
-@@ -24,6 +24,8 @@
-
- #define __EXTENSIONS__
-
-+#include "config.h"
-+
- #include
-
- #include
-@@ -35,10 +37,9 @@
- #include
- #include
-
-+#include "rb-soup-compat.h"
- #include
--#include
-
--#include "config.h"
- #include "eel-gconf-extensions.h"
- #include "rb-audioscrobbler.h"
- #include "rb-debug.h"
-@@ -193,14 +194,20 @@
-
- static gchar * mkmd5 (char *string);
- static void rb_audioscrobbler_parse_response (RBAudioscrobbler *audioscrobbler, SoupMessage *msg);
--static void rb_audioscrobbler_perform (RBAudioscrobbler *audioscrobbler,
-- char *url,
-- char *post_data,
-- SoupMessageCallbackFn response_handler);
-+
- static void rb_audioscrobbler_do_handshake (RBAudioscrobbler *audioscrobbler);
--static void rb_audioscrobbler_do_handshake_cb (SoupMessage *msg, gpointer user_data);
- static void rb_audioscrobbler_submit_queue (RBAudioscrobbler *audioscrobbler);
-+static void rb_audioscrobbler_perform (RBAudioscrobbler *audioscrobbler,
-+ char *url,
-+ char *post_data,
-+ SoupSessionCallback response_handler);
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void rb_audioscrobbler_do_handshake_cb (SoupSession *session, SoupMessage *msg, gpointer user_data);
-+static void rb_audioscrobbler_submit_queue_cb (SoupSession *session, SoupMessage *msg, gpointer user_data);
-+#else
-+static void rb_audioscrobbler_do_handshake_cb (SoupMessage *msg, gpointer user_data);
- static void rb_audioscrobbler_submit_queue_cb (SoupMessage *msg, gpointer user_data);
-+#endif
-
- static void rb_audioscrobbler_import_settings (RBAudioscrobbler *audioscrobbler);
- static void rb_audioscrobbler_preferences_sync (RBAudioscrobbler *audioscrobbler);
-@@ -688,18 +695,31 @@
- static void
- rb_audioscrobbler_parse_response (RBAudioscrobbler *audioscrobbler, SoupMessage *msg)
- {
-+ gboolean successful;
- rb_debug ("Parsing response, status=%d", msg->status_code);
--
-- if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) && (msg->response).body != NULL) {
-- gchar *body;
-+
-+ successful = FALSE;
-+#if defined(HAVE_LIBSOUP_2_4)
-+ if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) && msg->response_body->length != 0)
-+ successful = TRUE;
-+#else
-+ if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) && (msg->response).body != NULL)
-+ successful = TRUE;
-+#endif
-+ if (successful) {
- gchar **breaks;
-+ int i;
-+#if defined(HAVE_LIBSOUP_2_2)
-+ gchar *body;
-
- body = g_malloc0 ((msg->response).length + 1);
- memcpy (body, (msg->response).body, (msg->response).length);
-
- g_strstrip (body);
- breaks = g_strsplit (body, "\n", 4);
-- int i;
-+#else
-+ breaks = g_strsplit (msg->response_body->data, "\n", 4);
-+#endif
-
- g_free (audioscrobbler->priv->status_msg);
- audioscrobbler->priv->status = STATUS_OK;
-@@ -771,10 +791,12 @@
- audioscrobbler->priv->submit_next = time(NULL) + audioscrobbler->priv->submit_interval;
-
- g_strfreev (breaks);
-+#if defined(HAVE_LIBSOUP_2_2)
- g_free (body);
-+#endif
- } else {
- audioscrobbler->priv->status = REQUEST_FAILED;
-- audioscrobbler->priv->status_msg = g_strdup (soup_status_get_phrase (msg->status_code));
-+ audioscrobbler->priv->status_msg = g_strdup (msg->reason_phrase);
- }
- }
-
-@@ -793,24 +815,25 @@
- rb_audioscrobbler_perform (RBAudioscrobbler *audioscrobbler,
- char *url,
- char *post_data,
-- SoupMessageCallbackFn response_handler)
-+ SoupSessionCallback response_handler)
- {
- SoupMessage *msg;
-
- msg = soup_message_new (post_data == NULL ? "GET" : "POST", url);
-+ soup_message_headers_append (msg->request_headers, "User-Agent", "Rhythmbox/" VERSION);
-
- if (post_data != NULL) {
- rb_debug ("Submitting to Audioscrobbler: %s", post_data);
- soup_message_set_request (msg,
- "application/x-www-form-urlencoded",
-- SOUP_BUFFER_SYSTEM_OWNED,
-+ SOUP_MEMORY_TAKE,
- post_data,
- strlen (post_data));
- }
-
- /* create soup session, if we haven't got one yet */
- if (!audioscrobbler->priv->soup_session) {
-- SoupUri *uri;
-+ SoupURI *uri;
-
- uri = rb_proxy_config_get_libsoup_uri (audioscrobbler->priv->proxy_config);
- audioscrobbler->priv->soup_session = soup_session_async_new_with_options (
-@@ -891,8 +914,13 @@
- }
-
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+rb_audioscrobbler_do_handshake_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
-+#else
- static void
- rb_audioscrobbler_do_handshake_cb (SoupMessage *msg, gpointer user_data)
-+#endif
- {
- RBAudioscrobbler *audioscrobbler = RB_AUDIOSCROBBLER(user_data);
-
-@@ -1049,8 +1077,13 @@
- }
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+rb_audioscrobbler_submit_queue_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
-+#else
- static void
- rb_audioscrobbler_submit_queue_cb (SoupMessage *msg, gpointer user_data)
-+#endif
- {
- RBAudioscrobbler *audioscrobbler = RB_AUDIOSCROBBLER (user_data);
-
-@@ -1232,7 +1265,7 @@
- rb_audioscrobbler_proxy_config_changed_cb (RBProxyConfig *config,
- RBAudioscrobbler *audioscrobbler)
- {
-- SoupUri *uri;
-+ SoupURI *uri;
-
- if (audioscrobbler->priv->soup_session) {
- uri = rb_proxy_config_get_libsoup_uri (config);
-diff -urN rhythmbox-0.11.4/plugins/audioscrobbler/rb-lastfm-gst-src.c rhythmbox-0.11.4.new/plugins/audioscrobbler/rb-lastfm-gst-src.c
---- rhythmbox-0.11.4/plugins/audioscrobbler/rb-lastfm-gst-src.c 2007-06-19 12:38:41.000000000 +0100
-+++ rhythmbox-0.11.4.new/plugins/audioscrobbler/rb-lastfm-gst-src.c 2008-02-06 00:57:27.000000000 +0000
-@@ -25,7 +25,6 @@
-
- #include "rb-debug.h"
-
--#include
- #include
-
- #define RB_TYPE_LASTFM_SRC (rb_lastfm_src_get_type())
-diff -urN rhythmbox-0.11.4/plugins/audioscrobbler/rb-lastfm-source.c rhythmbox-0.11.4.new/plugins/audioscrobbler/rb-lastfm-source.c
---- rhythmbox-0.11.4/plugins/audioscrobbler/rb-lastfm-source.c 2007-12-04 03:05:39.000000000 +0000
-+++ rhythmbox-0.11.4.new/plugins/audioscrobbler/rb-lastfm-source.c 2008-02-06 01:01:13.000000000 +0000
-@@ -42,8 +42,8 @@
-
- #include
-
-+#include "rb-soup-compat.h"
- #include
--#include
-
- #include "md5.h"
-
-@@ -100,8 +100,12 @@
- static void rb_lastfm_perform (RBLastfmSource *lastfm,
- const char *url,
- char *post_data, /* this takes ownership */
-- SoupMessageCallbackFn response_handler);
-+ SoupSessionCallback response_handler);
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void rb_lastfm_message_cb (SoupSession *session, SoupMessage *req, gpointer user_data);
-+#else
- static void rb_lastfm_message_cb (SoupMessage *req, gpointer user_data);
-+#endif
- static void rb_lastfm_change_station (RBLastfmSource *source, const char *station);
-
- static void rb_lastfm_proxy_config_changed_cb (RBProxyConfig *config,
-@@ -724,30 +728,29 @@
- rb_lastfm_perform (RBLastfmSource *source,
- const char *url,
- char *post_data,
-- SoupMessageCallbackFn response_handler)
-+ SoupSessionCallback response_handler)
- {
- SoupMessage *msg;
- msg = soup_message_new ("GET", url);
-+ soup_message_headers_append (msg->request_headers, "User-Agent", "Rhythmbox/" VERSION);
-
- if (msg == NULL)
- return;
-
-- soup_message_set_http_version (msg, SOUP_HTTP_1_1);
--
- rb_debug ("Last.fm communicating with %s", url);
-
- if (post_data != NULL) {
- rb_debug ("POST data: %s", post_data);
- soup_message_set_request (msg,
- "application/x-www-form-urlencoded",
-- SOUP_BUFFER_SYSTEM_OWNED,
-+ SOUP_MEMORY_TAKE,
- post_data,
- strlen (post_data));
- }
-
- /* create soup session, if we haven't got one yet */
- if (!source->priv->soup_session) {
-- SoupUri *uri;
-+ SoupURI *uri;
-
- uri = rb_proxy_config_get_libsoup_uri (source->priv->proxy_config);
- source->priv->soup_session = soup_session_async_new_with_options (
-@@ -759,27 +762,45 @@
-
- soup_session_queue_message (source->priv->soup_session,
- msg,
-- (SoupMessageCallbackFn) response_handler,
-+ response_handler,
- source);
- source->priv->status = COMMUNICATING;
- rb_source_notify_status_changed (RB_SOURCE(source));
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+rb_lastfm_message_cb (SoupSession *session, SoupMessage *req, gpointer user_data)
-+#else
- static void
- rb_lastfm_message_cb (SoupMessage *req, gpointer user_data)
-+#endif
- {
- RBLastfmSource *source = RB_LASTFM_SOURCE (user_data);
-- char *body;
- char **pieces;
- int i;
-+ const char *body;
-+
-+#if defined(HAVE_LIBSOUP_2_2)
-+ char *free_body;
-
- if ((req->response).body == NULL) {
- rb_debug ("Lastfm: Server failed to respond");
- return;
- }
-
-- body = g_malloc0 ((req->response).length + 1);
-- memcpy (body, (req->response).body, (req->response).length);
-+ free_body = g_malloc0 ((req->response).length + 1);
-+ memcpy (free_body, (req->response).body, (req->response).length);
-+ g_strstrip (free_body);
-+
-+ body = free_body;
-+#else
-+ if (req->response_body->length == 0) {
-+ rb_debug ("Lastfm: Server failed to respond");
-+ return;
-+ }
-+ body = req->response_body->data;
-+#endif
-
- rb_debug ("response body: %s", body);
-
-@@ -787,7 +808,6 @@
- source->priv->status = NO_ARTIST;
- }
-
-- g_strstrip (body);
- pieces = g_strsplit (body, "\n", 0);
- for (i = 0; pieces[i] != NULL; i++) {
- gchar **values = g_strsplit (pieces[i], "=", 2);
-@@ -856,10 +876,14 @@
- rhythmdb_commit (source->priv->db);
-
- }
-+
-+ g_strfreev (values);
- }
-
- g_strfreev (pieces);
-- g_free (body);
-+#if defined(HAVE_LIBSOUP_2_2)
-+ g_free (free_body);
-+#endif
-
- /* doesn't work yet
- if (source->priv->pending_entry) {
-@@ -898,7 +922,7 @@
- rb_lastfm_proxy_config_changed_cb (RBProxyConfig *config,
- RBLastfmSource *source)
- {
-- SoupUri *uri;
-+ SoupURI *uri;
-
- if (source->priv->soup_session) {
- uri = rb_proxy_config_get_libsoup_uri (config);
-@@ -1163,10 +1187,16 @@
- g_free(title);
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+rb_lastfm_source_metadata_cb (SoupSession *session, SoupMessage *req, RBLastfmSource *source)
-+#else
- static void
- rb_lastfm_source_metadata_cb (SoupMessage *req, RBLastfmSource *source)
-+#endif
- {
-- char *body;
-+ const char *body;
-+ char *free_body;
- char **pieces;
- int p;
- RhythmDBEntry *entry;
-@@ -1179,10 +1209,16 @@
- }
-
- rb_debug ("got response to metadata request");
-- body = g_malloc0 ((req->response).length + 1);
-- memcpy (body, (req->response).body, (req->response).length);
-+#if defined(HAVE_LIBSOUP_2_4)
-+ body = req->response_body->data;
-+ free_body = NULL;
-+#else
-+ free_body = g_malloc0 ((req->response).length + 1);
-+ memcpy (free_body, (req->response).body, (req->response).length);
-+ g_strstrip (free_body);
-+ body = free_body;
-+#endif
-
-- g_strstrip (body);
- pieces = g_strsplit (body, "\n", 0);
- found_cover = FALSE;
-
-@@ -1238,7 +1274,9 @@
- }
-
- g_strfreev (pieces);
-- g_free (body);
-+#if defined(HAVE_LIBSOUP_2_2)
-+ g_free (free_body);
-+#endif
-
- if (found_cover == FALSE) {
- GValue v = {0,};
-@@ -1271,7 +1309,7 @@
- source->priv->base_url,
- source->priv->base_path,
- source->priv->session);
-- rb_lastfm_perform (source, uri, NULL, (SoupMessageCallbackFn) rb_lastfm_source_metadata_cb);
-+ rb_lastfm_perform (source, uri, NULL, (SoupSessionCallback) rb_lastfm_source_metadata_cb);
- g_free (uri);
-
- /* re-enable actions */
-diff -urN rhythmbox-0.11.4/plugins/daap/rb-daap-connection.c rhythmbox-0.11.4.new/plugins/daap/rb-daap-connection.c
---- rhythmbox-0.11.4/plugins/daap/rb-daap-connection.c 2007-11-22 08:23:50.000000000 +0000
-+++ rhythmbox-0.11.4.new/plugins/daap/rb-daap-connection.c 2008-02-06 00:57:27.000000000 +0000
-@@ -33,10 +33,8 @@
- #include
- #include
-
-+#include "rb-soup-compat.h"
- #include
--#include
--#include
--#include
-
- #include "rb-daap-hash.h"
- #include "rb-daap-connection.h"
-@@ -84,7 +82,7 @@
- gboolean is_connecting;
-
- SoupSession *session;
-- SoupUri *base_uri;
-+ SoupURI *base_uri;
- gchar *daap_base_uri;
-
- gdouble daap_version;
-@@ -329,7 +327,7 @@
- {
- RBDAAPConnectionPrivate *priv = connection->priv;
- SoupMessage *message = NULL;
-- SoupUri *uri = NULL;
-+ SoupURI *uri = NULL;
-
- uri = soup_uri_new_with_base (priv->base_uri, path);
- if (uri == NULL) {
-@@ -337,14 +335,13 @@
- }
-
- message = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
-- soup_message_set_http_version (message, SOUP_HTTP_1_1);
-
-- soup_message_add_header (message->request_headers, "Client-DAAP-Version", "3.0");
-- soup_message_add_header (message->request_headers, "Accept-Language", "en-us, en;q=5.0");
-+ soup_message_headers_append (message->request_headers, "Client-DAAP-Version", "3.0");
-+ soup_message_headers_append (message->request_headers, "Accept-Language", "en-us, en;q=5.0");
- #ifdef HAVE_LIBZ
-- soup_message_add_header (message->request_headers, "Accept-Encoding", "gzip");
-+ soup_message_headers_append (message->request_headers, "Accept-Encoding", "gzip");
- #endif
-- soup_message_add_header (message->request_headers, "Client-DAAP-Access-Index", "2");
-+ soup_message_headers_append (message->request_headers, "Client-DAAP-Access-Index", "2");
-
- if (priv->password_protected) {
- char *h;
-@@ -352,13 +349,17 @@
- char *token;
-
- user_pass = g_strdup_printf ("%s:%s", priv->username, priv->password);
-+#if defined(HAVE_LIBSOUP_2_4)
-+ token = g_base64_encode ((guchar *)user_pass, strlen (user_pass));
-+#else
- token = soup_base64_encode (user_pass, strlen (user_pass));
-+#endif
- h = g_strdup_printf ("Basic %s", token);
-
- g_free (token);
- g_free (user_pass);
-
-- soup_message_add_header (message->request_headers, "Authorization", h);
-+ soup_message_headers_append (message->request_headers, "Authorization", h);
- g_free (h);
- }
-
-@@ -372,10 +373,10 @@
-
- rb_daap_hash_generate ((short)floor (version), (const guchar*)no_daap_path, 2, (guchar*)hash, req_id);
-
-- soup_message_add_header (message->request_headers, "Client-DAAP-Validation", hash);
-+ soup_message_headers_append (message->request_headers, "Client-DAAP-Validation", hash);
- }
- if (send_close) {
-- soup_message_add_header (message->request_headers, "Connection", "close");
-+ soup_message_headers_append (message->request_headers, "Connection", "close");
- }
-
- soup_uri_free (uri);
-@@ -425,16 +426,22 @@
- {
- RBDAAPConnectionPrivate *priv;
- GNode *structure;
-- char *response;
-+ char *new_response = NULL;
-+ const char *response;
- const char *encoding_header;
- char *message_path;
- int response_length;
-
- priv = data->connection->priv;
- structure = NULL;
-- response = data->message->response.body;
- encoding_header = NULL;
-+#if defined(HAVE_LIBSOUP_2_4)
-+ response = data->message->response_body->data;
-+ response_length = data->message->response_body->length;
-+#else
-+ response = data->message->response.body;
- response_length = data->message->response.length;
-+#endif
-
- message_path = soup_uri_to_string (soup_message_get_uri (data->message), FALSE);
-
-@@ -444,13 +451,12 @@
- data->message->reason_phrase);
-
- if (data->message->response_headers) {
-- encoding_header = soup_message_get_header (data->message->response_headers, "Content-Encoding");
-+ encoding_header = soup_message_headers_get (data->message->response_headers, "Content-Encoding");
- }
-
- if (SOUP_STATUS_IS_SUCCESSFUL (data->status) && encoding_header && strcmp (encoding_header, "gzip") == 0) {
- #ifdef HAVE_LIBZ
- z_stream stream;
-- char *new_response;
- unsigned int factor = 4;
- unsigned int unc_size = response_length * factor;
-
-@@ -575,19 +581,23 @@
- rb_daap_structure_destroy (structure);
- }
-
-- if (response != data->message->response.body) {
-- g_free (response);
-- }
--
-+ g_free (new_response);
- g_free (message_path);
- g_object_unref (G_OBJECT (data->connection));
- g_object_unref (G_OBJECT (data->message));
- g_free (data);
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+http_response_handler (SoupSession *session,
-+ SoupMessage *message,
-+ RBDAAPConnection *connection)
-+#else
- static void
- http_response_handler (SoupMessage *message,
- RBDAAPConnection *connection)
-+#endif
- {
- DAAPResponseData *data;
- int response_length;
-@@ -599,7 +609,11 @@
-
- data = g_new0 (DAAPResponseData, 1);
- data->status = message->status_code;
-+#if defined(HAVE_LIBSOUP_2_4)
-+ response_length = message->response_body->length;
-+#else
- response_length = message->response.length;
-+#endif
-
- g_object_ref (G_OBJECT (connection));
- data->connection = connection;
-@@ -655,7 +669,7 @@
- priv->use_response_handler_thread = use_thread;
- priv->response_handler = handler;
- soup_session_queue_message (priv->session, message,
-- (SoupMessageCallbackFn) http_response_handler,
-+ (SoupSessionCallback) http_response_handler,
- connection);
- rb_debug ("Queued message for http://%s:%d/%s",
- priv->base_uri->host,
-@@ -1662,7 +1676,11 @@
- char *token;
-
- user_pass = g_strdup_printf ("%s:%s", priv->username, priv->password);
-+#if defined(HAVE_LIBSOUP_2_4)
-+ token = g_base64_encode ((guchar *)user_pass, strlen (user_pass));
-+#else
- token = soup_base64_encode (user_pass, strlen (user_pass));
-+#endif
- g_string_append_printf (headers, "Authentication: Basic %s\r\n", token);
- g_free (token);
- g_free (user_pass);
-diff -urN rhythmbox-0.11.4/plugins/daap/rb-daap-plugin.c rhythmbox-0.11.4.new/plugins/daap/rb-daap-plugin.c
---- rhythmbox-0.11.4/plugins/daap/rb-daap-plugin.c 2007-09-03 08:24:09.000000000 +0100
-+++ rhythmbox-0.11.4.new/plugins/daap/rb-daap-plugin.c 2008-02-06 00:57:27.000000000 +0000
-@@ -29,8 +29,8 @@
- #include
- #include
-
-+#include "rb-soup-compat.h"
- #include
--#include
-
- #include "rb-daap-plugin.h"
- #include "rb-debug.h"
-@@ -647,6 +647,9 @@
- g_free (host);
-
- soup_address_resolve_async (addr,
-+#if defined(HAVE_LIBSOUP_2_4)
-+ NULL, NULL,
-+#endif
- (SoupAddressCallback) new_daap_share_resolve_cb,
- data);
- }
-diff -urN rhythmbox-0.11.4/plugins/daap/rb-daap-share.c rhythmbox-0.11.4.new/plugins/daap/rb-daap-share.c
---- rhythmbox-0.11.4/plugins/daap/rb-daap-share.c 2007-11-08 13:09:20.000000000 +0000
-+++ rhythmbox-0.11.4.new/plugins/daap/rb-daap-share.c 2008-02-06 00:57:27.000000000 +0000
-@@ -27,13 +27,9 @@
-
- #include
- #include
-+
-+#include "rb-soup-compat.h"
- #include
--#include
--#include
--#include
--#include
--#include
--#include
- #include
-
- #include "rb-daap-share.h"
-@@ -513,20 +509,22 @@
- static void
- message_add_standard_headers (SoupMessage *message)
- {
-+#if defined(HAVE_LIBSOUP_2_2)
- gchar *s;
- time_t t;
- struct tm *tm;
-
-- soup_message_add_header (message->response_headers, "DAAP-Server", "Rhythmbox " VERSION);
--
-- soup_message_add_header (message->response_headers, "Content-Type", "application/x-dmap-tagged");
--
- t = time (NULL);
- tm = gmtime (&t);
- s = g_new (gchar, 100);
- strftime (s, 100, "%a, %d %b %Y %T GMT", tm);
-- soup_message_add_header (message->response_headers, "Date", s);
-+ soup_message_headers_append (message->response_headers, "Date", s);
- g_free (s);
-+#endif
-+
-+ soup_message_headers_append (message->response_headers, "DAAP-Server", "Rhythmbox " VERSION);
-+
-+ soup_message_headers_append (message->response_headers, "Content-Type", "application/x-dmap-tagged");
- }
-
- static void
-@@ -543,14 +541,15 @@
- return;
- }
-
-- message->response.owner = SOUP_BUFFER_SYSTEM_OWNED;
-- message->response.length = length;
-- message->response.body = resp;
-+ soup_message_set_response (message, "application/x-dmap-tagged", SOUP_MEMORY_TAKE, resp, length);
-+
-+#if defined(HAVE_LIBSOUP_2_2)
-+ soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message), SOUP_TRANSFER_CONTENT_LENGTH);
-+#endif
-
- message_add_standard_headers (message);
-
- soup_message_set_status (message, SOUP_STATUS_OK);
-- soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message), SOUP_TRANSFER_CONTENT_LENGTH);
- }
-
- #define DMAP_STATUS_OK 200
-@@ -559,10 +558,20 @@
- #define DAAP_VERSION 3.0
- #define DMAP_TIMEOUT 1800
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+server_info_cb (SoupServer *server,
-+ SoupMessage *message,
-+ const char *path,
-+ GHashTable *query,
-+ SoupClientContext *context,
-+ RBDAAPShare *share)
-+#else
- static void
- server_info_cb (RBDAAPShare *share,
- SoupServerContext *context,
- SoupMessage *message)
-+#endif
- {
- /* MSRV server info response
- * MSTT status
-@@ -619,10 +628,20 @@
- rb_daap_structure_destroy (msrv);
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+content_codes_cb (SoupServer *server,
-+ SoupMessage *message,
-+ const char *path,
-+ GHashTable *query,
-+ SoupClientContext *context,
-+ RBDAAPShare *share)
-+#else
- static void
- content_codes_cb (RBDAAPShare *share,
- SoupServerContext *context,
- SoupMessage *message)
-+#endif
- {
- /* MCCR content codes response
- * MSTT status
-@@ -656,6 +675,48 @@
- rb_daap_structure_destroy (mccr);
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static gboolean
-+get_session_id (GHashTable *query,
-+ guint32 *id)
-+{
-+ char *session_id_str;
-+ guint32 session_id;
-+
-+ session_id_str = g_hash_table_lookup (query, "session-id");
-+ if (session_id_str == NULL) {
-+ rb_debug ("session id not found");
-+ return FALSE;
-+ }
-+
-+ session_id = (guint32) strtoul (session_id_str, NULL, 10);
-+ if (id != NULL) {
-+ *id = session_id;
-+ }
-+ return TRUE;
-+}
-+
-+static gboolean
-+get_revision_number (GHashTable *query,
-+ guint *number)
-+{
-+ char *revision_number_str;
-+ guint revision_number;
-+
-+ revision_number_str = g_hash_table_lookup (query, "revision-number");
-+ if (revision_number_str == NULL) {
-+ rb_debug ("client asked for an update without a revision number?!?");
-+ return FALSE;
-+ }
-+
-+ revision_number = strtoul (revision_number_str, NULL, 10);
-+ if (number != NULL) {
-+ *number = revision_number;
-+ }
-+ return TRUE;
-+}
-+
-+#else
- static gboolean
- message_get_session_id (SoupMessage *message,
- guint32 *id)
-@@ -729,11 +790,13 @@
-
- return TRUE;
- }
-+#endif
-
- static gboolean
- session_id_validate (RBDAAPShare *share,
-- SoupServerContext *context,
-+ SoupClientContext *context,
- SoupMessage *message,
-+ GHashTable *query, /* NULL w/ libsoup 2.2 */
- guint32 *id)
- {
- guint32 session_id;
-@@ -745,7 +808,11 @@
- *id = 0;
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+ res = get_session_id (query, &session_id);
-+#else
- res = message_get_session_id (message, &session_id);
-+#endif
- if (! res) {
- rb_debug ("Validation failed: Unable to parse session id from message");
- return FALSE;
-@@ -758,7 +825,7 @@
- return FALSE;
- }
-
-- remote_address = soup_server_context_get_client_host (context);
-+ remote_address = soup_client_context_get_host (context);
- rb_debug ("Validating session id %u from %s matches %s",
- session_id, remote_address, addr);
- if (remote_address == NULL || strcmp (addr, remote_address) != 0) {
-@@ -775,7 +842,7 @@
-
- static guint32
- session_id_generate (RBDAAPShare *share,
-- SoupServerContext *context)
-+ SoupClientContext *context)
- {
- guint32 id;
-
-@@ -786,7 +853,7 @@
-
- static guint32
- session_id_create (RBDAAPShare *share,
-- SoupServerContext *context)
-+ SoupClientContext *context)
- {
- guint32 id;
- const char *addr;
-@@ -802,7 +869,7 @@
- } while (addr != NULL);
-
- /* store session id and remote address */
-- remote_address = g_strdup (soup_server_context_get_client_host (context));
-+ remote_address = g_strdup (soup_client_context_get_host (context));
- g_hash_table_insert (share->priv->session_ids, GUINT_TO_POINTER (id), remote_address);
-
- return id;
-@@ -810,16 +877,26 @@
-
- static void
- session_id_remove (RBDAAPShare *share,
-- SoupServerContext *context,
-+ SoupClientContext *context,
- guint32 id)
- {
- g_hash_table_remove (share->priv->session_ids, GUINT_TO_POINTER (id));
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
- static void
--login_cb (RBDAAPShare *share,
-+login_cb (SoupServer *server,
-+ SoupMessage *message,
-+ const char *path,
-+ GHashTable *query,
-+ SoupClientContext *context,
-+ RBDAAPShare *share)
-+#else
-+static void
-+login_cb (RBDAAPShare *share,
- SoupServerContext *context,
-- SoupMessage *message)
-+ SoupMessage *message)
-+#endif
- {
- /* MLOG login response
- * MSTT status
-@@ -840,15 +917,28 @@
- rb_daap_structure_destroy (mlog);
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+logout_cb (SoupServer *server,
-+ SoupMessage *message,
-+ const char *path,
-+ GHashTable *query,
-+ SoupClientContext *context,
-+ RBDAAPShare *share)
-+#else
- static void
- logout_cb (RBDAAPShare *share,
- SoupServerContext *context,
- SoupMessage *message)
-+#endif
- {
- int status;
- guint32 id;
-+#if defined(HAVE_LIBSOUP_2_2)
-+ GHashTable *query = NULL;
-+#endif
-
-- if (session_id_validate (share, context, message, &id)) {
-+ if (session_id_validate (share, context, message, query, &id)) {
- rb_debug ("Handling logout session id %u", id);
- session_id_remove (share, context, id);
-
-@@ -858,18 +948,34 @@
- }
-
- soup_message_set_status (message, status);
-+#if defined(HAVE_LIBSOUP_2_2)
- soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message), SOUP_TRANSFER_CONTENT_LENGTH);
-+#endif
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+update_cb (SoupServer *server,
-+ SoupMessage *message,
-+ const char *path,
-+ GHashTable *query,
-+ SoupClientContext *context,
-+ RBDAAPShare *share)
-+#else
- static void
- update_cb (RBDAAPShare *share,
- SoupServerContext *context,
- SoupMessage *message)
-+#endif
- {
- guint revision_number;
- gboolean res;
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+ res = get_revision_number (query, &revision_number);
-+#else
- res = message_get_revision_number (message, &revision_number);
-+#endif
-
- if (res && revision_number != share->priv->revision_number) {
- /* MUPD update response
-@@ -885,8 +991,15 @@
- message_set_from_rb_daap_structure (message, mupd);
- rb_daap_structure_destroy (mupd);
- } else {
-+ /* FIXME: This seems like a bug. It just leaks the
-+ * message (and socket) without ever replying.
-+ */
- g_object_ref (message);
-+#if defined(HAVE_LIBSOUP_2_4)
-+ soup_server_pause_message (server, message);
-+#else
- soup_message_io_pause (message);
-+#endif
- }
- }
-
-@@ -1148,14 +1261,47 @@
- }
-
- static bitwise
-+parse_meta_str (const char *attrs)
-+{
-+ gchar **attrsv;
-+ guint i;
-+ bitwise bits = 0;
-+
-+ attrsv = g_strsplit (attrs, ",", -1);
-+
-+ for (i = 0; attrsv[i]; i++) {
-+ guint j;
-+
-+ for (j = 0; j < G_N_ELEMENTS (meta_data_map); j++) {
-+ if (strcmp (meta_data_map[j].tag, attrsv[i]) == 0) {
-+ bits |= (((bitwise) 1) << meta_data_map[j].md);
-+ }
-+ }
-+ }
-+
-+ g_strfreev (attrsv);
-+
-+ return bits;
-+}
-+
-+#if defined(HAVE_LIBSOUP_2_4)
-+static bitwise
-+parse_meta (GHashTable *query)
-+{
-+ const gchar *attrs;
-+
-+ attrs = g_hash_table_lookup (query, "meta");
-+ return parse_meta_str (attrs);
-+}
-+
-+#else
-+static bitwise
- parse_meta (const gchar *s)
- {
-+ bitwise bits;
- gchar *start_of_attrs;
- gchar *end_of_attrs;
- gchar *attrs;
-- gchar **attrsv;
-- guint i;
-- bitwise bits = 0;
-
- start_of_attrs = strstr (s, "meta=");
- if (start_of_attrs == NULL) {
-@@ -1170,23 +1316,12 @@
- attrs = g_strdup (start_of_attrs);
- }
-
-- attrsv = g_strsplit (attrs,",",-1);
--
-- for (i = 0; attrsv[i]; i++) {
-- guint j;
--
-- for (j = 0; j < G_N_ELEMENTS (meta_data_map); j++) {
-- if (strcmp (meta_data_map[j].tag, attrsv[i]) == 0) {
-- bits |= (((bitwise) 1) << meta_data_map[j].md);
-- }
-- }
-- }
--
-+ bits = parse_meta_str (attrs);
- g_free (attrs);
-- g_strfreev (attrsv);
-
- return bits;
- }
-+#endif
-
- static void
- write_next_chunk (SoupMessage *message, GnomeVFSHandle *handle)
-@@ -1197,10 +1332,18 @@
-
- result = gnome_vfs_read (handle, chunk, DAAP_SHARE_CHUNK_SIZE, &read_size);
- if (result == GNOME_VFS_OK && read_size > 0) {
-+#if defined(HAVE_LIBSOUP_2_4)
-+ soup_message_body_append (message->response_body, SOUP_MEMORY_TAKE, chunk, read_size);
-+#else
- soup_message_add_chunk (message, SOUP_BUFFER_SYSTEM_OWNED, chunk, read_size);
-+#endif
- } else {
- g_free (chunk);
-+#if defined(HAVE_LIBSOUP_2_4)
-+ soup_message_body_complete (message->response_body);
-+#else
- soup_message_add_final_chunk (message);
-+#endif
- }
- }
-
-@@ -1238,7 +1381,11 @@
- file_size -= offset;
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+ soup_message_headers_set_encoding (message->response_headers, SOUP_ENCODING_CHUNKED);
-+#else
- soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message), SOUP_TRANSFER_CHUNKED);
-+#endif
-
- g_signal_connect (message, "wrote_chunk", G_CALLBACK (write_next_chunk), handle);
- g_signal_connect (message, "finished", G_CALLBACK (chunked_message_finished), handle);
-@@ -1268,11 +1415,14 @@
- g_warning ("Unable to map file %s: %s", path, error->message);
- soup_message_set_status (message, SOUP_STATUS_INTERNAL_SERVER_ERROR);
- } else {
-- message->response.owner = SOUP_BUFFER_USER_OWNED;
-- message->response.length = file_size;
-- message->response.body = g_mapped_file_get_contents (mapped_file) + offset;
-+ soup_message_set_response (message, "application/x-dmap-tagged",
-+ SOUP_MEMORY_TEMPORARY,
-+ g_mapped_file_get_contents (mapped_file) + offset,
-+ file_size);
-+#if defined(HAVE_LIBSOUP_2_2)
- soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message),
- SOUP_TRANSFER_CONTENT_LENGTH);
-+#endif
-
- g_signal_connect (message,
- "finished",
-@@ -1283,22 +1433,40 @@
- }
- #endif
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+static void
-+databases_cb (SoupServer *server,
-+ SoupMessage *message,
-+ const char *path,
-+ GHashTable *query,
-+ SoupClientContext *context,
-+ RBDAAPShare *share)
-+
-+#else
- static void
- databases_cb (RBDAAPShare *share,
- SoupServerContext *context,
- SoupMessage *message)
-+#endif
- {
-- gchar *path;
-- gchar *rest_of_path;
-+ const char *rest_of_path;
- /*guint revision_number;*/
-+#if defined(HAVE_LIBSOUP_2_2)
-+ GHashTable *query = NULL;
-+ gchar *path;
-+#endif
-
-- if (! session_id_validate (share, context, message, NULL)) {
-+ if (! session_id_validate (share, context, message, query, NULL)) {
- soup_message_set_status (message, SOUP_STATUS_FORBIDDEN);
-+#if defined(HAVE_LIBSOUP_2_2)
- soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message), SOUP_TRANSFER_CONTENT_LENGTH);
-+#endif
- return;
- }
-
-+#if defined(HAVE_LIBSOUP_2_2)
- path = soup_uri_to_string (soup_message_get_uri (message), TRUE);
-+#endif
-
- rest_of_path = strchr (path + 1, '/');
-
-@@ -1335,7 +1503,11 @@
-
- message_set_from_rb_daap_structure (message, avdb);
- rb_daap_structure_destroy (avdb);
-+#if defined(HAVE_LIBSOUP_2_4)
-+ } else if (g_ascii_strcasecmp ("/1/items", rest_of_path) == 0) {
-+#else
- } else if (g_ascii_strncasecmp ("/1/items?", rest_of_path, 9) == 0) {
-+#endif
- /* ADBS database songs
- * MSTT status
- * MUTY update type
-@@ -1351,7 +1523,11 @@
- gint32 num_songs = rhythmdb_entry_count_by_type (share->priv->db, share->priv->entry_type);
- struct MLCL_Bits mb = {NULL,0};
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+ mb.bits = parse_meta (query);
-+#else
- mb.bits = parse_meta (rest_of_path);
-+#endif
-
- adbs = rb_daap_structure_add (NULL, RB_DAAP_CC_ADBS);
- rb_daap_structure_add (adbs, RB_DAAP_CC_MSTT, (gint32) DMAP_STATUS_OK);
-@@ -1365,7 +1541,11 @@
- message_set_from_rb_daap_structure (message, adbs);
- rb_daap_structure_destroy (adbs);
- adbs = NULL;
-+#if defined(HAVE_LIBSOUP_2_4)
-+ } else if (g_ascii_strcasecmp ("/1/containers", rest_of_path) == 0) {
-+#else
- } else if (g_ascii_strncasecmp ("/1/containers?", rest_of_path, 14) == 0) {
-+#endif
- /* APLY database playlists
- * MSTT status
- * MUTY update type
-@@ -1402,6 +1582,7 @@
-
- message_set_from_rb_daap_structure (message, aply);
- rb_daap_structure_destroy (aply);
-+
- } else if (g_ascii_strncasecmp ("/1/containers/", rest_of_path, 14) == 0) {
- /* APSO playlist songs
- * MSTT status
-@@ -1420,7 +1601,11 @@
- struct MLCL_Bits mb = {NULL,0};
- gint pl_id = atoi (rest_of_path + 14);
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+ mb.bits = parse_meta (query);
-+#else
- mb.bits = parse_meta (rest_of_path);
-+#endif
-
- apso = rb_daap_structure_add (NULL, RB_DAAP_CC_APSO);
- rb_daap_structure_add (apso, RB_DAAP_CC_MSTT, (gint32) DMAP_STATUS_OK);
-@@ -1447,9 +1632,11 @@
- _find_by_id);
- if (idl == NULL) {
- soup_message_set_status (message, SOUP_STATUS_NOT_FOUND);
-+#if defined(HAVE_LIBSOUP_2_2)
- soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message),
- SOUP_TRANSFER_CONTENT_LENGTH);
- soup_message_set_response (message, "text/plain", SOUP_BUFFER_USER_OWNED, "", 0);
-+#endif
- goto out;
- }
- id = (RBPlaylistID *)idl->data;
-@@ -1470,7 +1657,7 @@
- rb_daap_structure_destroy (apso);
- } else if (g_ascii_strncasecmp ("/1/items/", rest_of_path, 9) == 0) {
- /* just the file :) */
-- gchar *id_str;
-+ const gchar *id_str;
- gint id;
- RhythmDBEntry *entry;
- const gchar *location;
-@@ -1486,9 +1673,9 @@
- file_size = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE);
-
- message_add_standard_headers (message);
-- soup_message_add_header (message->response_headers, "Accept-Ranges", "bytes");
-+ soup_message_headers_append (message->response_headers, "Accept-Ranges", "bytes");
-
-- range_header = soup_message_get_header (message->request_headers, "Range");
-+ range_header = soup_message_headers_get (message->request_headers, "Range");
- if (range_header) {
- const gchar *s;
- gchar *content_range;
-@@ -1497,7 +1684,7 @@
- offset = atoll (s);
-
- content_range = g_strdup_printf ("bytes %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, offset, file_size, file_size);
-- soup_message_add_header (message->response_headers, "Content-Range", content_range);
-+ soup_message_headers_append (message->response_headers, "Content-Range", content_range);
- g_free (content_range);
-
- soup_message_set_status (message, SOUP_STATUS_PARTIAL_CONTENT);
-@@ -1522,9 +1709,92 @@
- }
-
- out:
-+#if defined(HAVE_LIBSOUP_2_2)
- g_free (path);
-+#else
-+ ;
-+#endif
-+}
-+
-+static void
-+db_entry_added_cb (RhythmDB *db,
-+ RhythmDBEntry *entry,
-+ RBDAAPShare *share)
-+{
-+ /* TODO: update our db version number? */
-+}
-+
-+static void
-+add_db_entry (RhythmDBEntry *entry,
-+ RBDAAPShare *share)
-+{
-+ db_entry_added_cb (share->priv->db, entry, share);
-+}
-+
-+static void
-+db_entry_deleted_cb (RhythmDB *db,
-+ RhythmDBEntry *entry,
-+ RBDAAPShare *share)
-+{
-+ /* TODO: update our db version number? */
-+}
-+
-+static void
-+db_entry_changed_cb (RhythmDB *db,
-+ RhythmDBEntry *entry,
-+ GSList *changes,
-+ RBDAAPShare *share)
-+{
-+ if (rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN)) {
-+ db_entry_deleted_cb (db, entry, share);
-+ } else {
-+ db_entry_added_cb (db, entry, share);
-+ }
-+}
-+
-+#if defined(HAVE_LIBSOUP_2_4)
-+
-+static gboolean
-+soup_auth_filter (SoupAuthDomain *auth_domain,
-+ SoupMessage *msg,
-+ gpointer user_data)
-+{
-+ const char *path;
-+
-+ path = soup_message_get_uri (msg)->path;
-+ if (g_str_has_prefix (path, "/databases/")) {
-+ /* Subdirectories of /databases don't actually require
-+ * authentication
-+ */
-+ return FALSE;
-+ } else {
-+ /* Everything else in auth_domain's paths, including
-+ * /databases itself, does require auth.
-+ */
-+ return TRUE;
-+ }
- }
-
-+static gboolean
-+soup_auth_callback (SoupAuthDomain *auth_domain,
-+ SoupMessage *msg,
-+ const char *username,
-+ gpointer password,
-+ RBDAAPShare *share)
-+{
-+ gboolean allowed;
-+ const char *path;
-+
-+ path = soup_message_get_uri (msg)->path;
-+ rb_debug ("Auth request for %s, user %s", path, username);
-+
-+ allowed = !strcmp (password, share->priv->password);
-+ rb_debug ("Auth request: %s", allowed ? "ALLOWED" : "DENIED");
-+
-+ return allowed;
-+}
-+
-+#else
- typedef void (* DAAPPathFunction) (RBDAAPShare *share,
- SoupServerContext *context,
- SoupMessage *message);
-@@ -1567,42 +1837,6 @@
- g_free (path);
- }
-
--static void
--db_entry_added_cb (RhythmDB *db,
-- RhythmDBEntry *entry,
-- RBDAAPShare *share)
--{
-- /* TODO: update our db version number? */
--}
--
--static void
--add_db_entry (RhythmDBEntry *entry,
-- RBDAAPShare *share)
--{
-- db_entry_added_cb (share->priv->db, entry, share);
--}
--
--static void
--db_entry_deleted_cb (RhythmDB *db,
-- RhythmDBEntry *entry,
-- RBDAAPShare *share)
--{
-- /* TODO: update our db version number? */
--}
--
--static void
--db_entry_changed_cb (RhythmDB *db,
-- RhythmDBEntry *entry,
-- GSList *changes,
-- RBDAAPShare *share)
--{
-- if (rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN)) {
-- db_entry_deleted_cb (db, entry, share);
-- } else {
-- db_entry_added_cb (db, entry, share);
-- }
--}
--
- static gboolean
- soup_auth_callback (SoupServerAuthContext *auth_ctx,
- SoupServerAuth *auth,
-@@ -1642,12 +1876,14 @@
- return allowed;
- }
-
-+#endif
-+
-+
- static gboolean
- rb_daap_share_server_start (RBDAAPShare *share)
- {
- int port = STANDARD_DAAP_PORT;
- gboolean password_required;
-- SoupServerAuthContext auth_ctx = { 0 };
-
- share->priv->server = soup_server_new (SOUP_SERVER_PORT, port, NULL);
- if (share->priv->server == NULL) {
-@@ -1666,6 +1902,22 @@
- password_required = (share->priv->auth_method != RB_DAAP_SHARE_AUTH_METHOD_NONE);
-
- if (password_required) {
-+#if defined(HAVE_LIBSOUP_2_4)
-+ SoupAuthDomain *auth_domain;
-+
-+ auth_domain = soup_auth_domain_basic_new (SOUP_AUTH_DOMAIN_REALM, "Music Sharing",
-+ SOUP_AUTH_DOMAIN_ADD_PATH, "/login",
-+ SOUP_AUTH_DOMAIN_ADD_PATH, "/update",
-+ SOUP_AUTH_DOMAIN_ADD_PATH, "/database",
-+ SOUP_AUTH_DOMAIN_FILTER, soup_auth_filter,
-+ NULL);
-+ soup_auth_domain_basic_set_auth_callback (auth_domain,
-+ (SoupAuthDomainBasicAuthCallback)soup_auth_callback,
-+ g_object_ref (share),
-+ g_object_unref);
-+ soup_server_add_auth_domain (share->priv->server, auth_domain);
-+#else
-+ SoupServerAuthContext auth_ctx = { 0 };
- auth_ctx.types = SOUP_AUTH_TYPE_BASIC;
- auth_ctx.callback = (SoupServerAuthCallbackFn)soup_auth_callback;
- auth_ctx.user_data = share;
-@@ -1689,14 +1941,36 @@
- (SoupServerCallbackFn)server_cb,
- NULL,
- share);
-+#endif
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+ soup_server_add_handler (share->priv->server, "/server-info",
-+ (SoupServerCallback) server_info_cb,
-+ share, NULL);
-+ soup_server_add_handler (share->priv->server, "/content-codes",
-+ (SoupServerCallback) content_codes_cb,
-+ share, NULL);
-+ soup_server_add_handler (share->priv->server, "/login",
-+ (SoupServerCallback) login_cb,
-+ share, NULL);
-+ soup_server_add_handler (share->priv->server, "/logout",
-+ (SoupServerCallback) logout_cb,
-+ share, NULL);
-+ soup_server_add_handler (share->priv->server, "/update",
-+ (SoupServerCallback) update_cb,
-+ share, NULL);
-+ soup_server_add_handler (share->priv->server, "/databases",
-+ (SoupServerCallback) databases_cb,
-+ share, NULL);
-+#else
- soup_server_add_handler (share->priv->server,
- NULL,
- NULL,
- (SoupServerCallbackFn)server_cb,
- NULL,
- share);
-+#endif
- soup_server_run_async (share->priv->server);
-
- /* using direct since there is no g_uint_hash or g_uint_equal */
-diff -urN rhythmbox-0.11.4/plugins/daap/rb-daap-src.c rhythmbox-0.11.4.new/plugins/daap/rb-daap-src.c
---- rhythmbox-0.11.4/plugins/daap/rb-daap-src.c 2007-06-17 12:56:21.000000000 +0100
-+++ rhythmbox-0.11.4.new/plugins/daap/rb-daap-src.c 2008-02-06 00:57:27.000000000 +0000
-@@ -34,8 +34,8 @@
- #include
- #include
-
--#include
--#include
-+#include "rb-soup-compat.h"
-+#include
-
- #include
- #include
-@@ -432,7 +432,12 @@
- gchar *host;
- guint port;
- gchar *path;
-+#if defined(HAVE_LIBSOUP_2_4)
-+ SoupMessageHeaders *header_table;
-+#else
- GHashTable *header_table;
-+ char *dup_headers;
-+#endif
- gchar *request;
- gchar *response;
- gchar *end_headers;
-@@ -441,7 +446,6 @@
- guint http_status;
- gchar *http_status_phrase = NULL;
- gboolean parse_result;
-- char *dup_headers;
-
- if (src->buffer_base) {
- g_free (src->buffer_base);
-@@ -536,6 +540,15 @@
- return FALSE;
- }
-
-+#if defined(HAVE_LIBSOUP_2_4)
-+ header_table = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
-+ parse_result = soup_headers_parse_response (response,
-+ ((end_headers+2) - response),
-+ header_table,
-+ NULL,
-+ &http_status,
-+ &http_status_phrase);
-+#else
- /* for compatibility with older versions of libsoup, we may need to retry
- * the soup_headers_parse_response call with slightly different arguments.
- * since this function modifies the string passed in, we need to copy it
-@@ -567,28 +580,42 @@
- &http_status,
- &http_status_phrase);
- }
-+#endif
-
- if (parse_result) {
- if (http_status == 200 || http_status == 206) {
-+ const char *enc_str = NULL;
-+ const char *len_str = NULL;
-+#if defined(HAVE_LIBSOUP_2_4)
-+ enc_str = soup_message_headers_get (header_table, "Transfer-Encoding");
-+ len_str = soup_message_headers_get (header_table, "Content-Length");
-+#else
- GSList *val;
--
- val = g_hash_table_lookup (header_table, "Transfer-Encoding");
- if (val) {
-- if (g_strcasecmp ((gchar *)val->data, "chunked") == 0) {
-+ enc_str = ((const char *)val->data);
-+ }
-+ val = g_hash_table_lookup (header_table, "Content-Length");
-+ if (val) {
-+ len_str = ((const char *)val->data);
-+ }
-+#endif
-+
-+ if (enc_str) {
-+ if (g_strcasecmp (enc_str, "chunked") == 0) {
- src->chunked = TRUE;
- } else {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-- ("Unknown HTTP transfer encoding \"%s\"", val->data));
-+ ("Unknown HTTP transfer encoding \"%s\"", enc_str));
- }
- } else {
- src->chunked = FALSE;
-- val = g_hash_table_lookup (header_table, "Content-Length");
-- if (val) {
-+ if (len_str) {
- char *e;
-- src->size = strtoul ((char *)val->data, &e, 10);
-- if (e == val->data) {
-+ src->size = strtoul (len_str, &e, 10);
-+ if (e == len_str) {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-- ("Couldn't read HTTP content length \"%s\"", val->data));
-+ ("Couldn't read HTTP content length \"%s\"", len_str));
- ok = FALSE;
- }
- } else {
-@@ -609,8 +636,13 @@
- ok = FALSE;
- }
- g_free (http_status_phrase);
-+
-+#if defined(HAVE_LIBSOUP_2_4)
-+ soup_message_headers_free (header_table);
-+#else
- soup_message_clear_headers (header_table);
- g_hash_table_destroy (header_table);
-+#endif
-
- end_headers += 4;
-
diff --git a/sources b/sources
index 0c59fa6..f6259df 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-240f5c9c7986d9feb9d4dfe4f795f1b9 rhythmbox-0.11.4.tar.bz2
+967440dd984ec724e7e7992d5bd57bbd rhythmbox-0.11.5.tar.bz2
diff --git a/x-content.patch b/x-content.patch
deleted file mode 100644
index c3193e5..0000000
--- a/x-content.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -up rhythmbox-0.11.4/data/rhythmbox.desktop.in.in.x-content rhythmbox-0.11.4/data/rhythmbox.desktop.in.in
---- rhythmbox-0.11.4/data/rhythmbox.desktop.in.in.x-content 2008-01-18 00:33:33.000000000 -0500
-+++ rhythmbox-0.11.4/data/rhythmbox.desktop.in.in 2008-01-18 00:34:27.000000000 -0500
-@@ -8,7 +8,7 @@ Type=Application
- Icon=rhythmbox
- X-GNOME-DocPath=rhythmbox/rhythmbox.xml
- Categories=GNOME;GTK;AudioVideo;
--MimeType=application/x-ogg;application/ogg;audio/x-scpls;audio/x-mp3;audio/x-mpeg;audio/mpeg;audio/x-mpegurl;application/x-flac;
-+MimeType=application/x-ogg;application/ogg;audio/x-scpls;audio/x-mp3;audio/x-mpeg;audio/mpeg;audio/x-mpegurl;application/x-flac;x-content/audio-cdda;x-content/audio-dvd;x-content/audio-player;
- StartupNotify=true
- X-GNOME-Bugzilla-Bugzilla=GNOME
- X-GNOME-Bugzilla-Product=rhythmbox