[rhythmbox] Patch to replace DAAP-related code with libdmapsharing



commit ef580491b70233cbcb17416b8fadcdda3ac89829
Author: W. Michael Petullo <mike flyn org>
Date:   Sat May 29 13:04:18 2010 -0500

    Patch to replace DAAP-related code with libdmapsharing
    
    This patch requires libdmapsharing 1.9.0.20. Receiving playlists as a
    client, receiving songs as a client, serving songs, serving playlists
    and password-protected shares have survived basic testing. This
    patch integrates with the new artist and album sort order code in
    libdmapsharing.
    Signed-off-by: W. Michael Petullo <mike flyn org>

 configure.ac                                       |   48 +-
 plugins/Makefile.am                                |    2 +-
 plugins/daap/Makefile.am                           |   54 +-
 plugins/daap/rb-daap-connection.c                  | 1894 --------------------
 plugins/daap/rb-daap-connection.h                  |  120 --
 plugins/daap/rb-daap-container-record.c            |  183 ++
 plugins/daap/rb-daap-container-record.h            |   75 +
 plugins/daap/rb-daap-hash.c                        |  518 ------
 plugins/daap/rb-daap-mdns-avahi.c                  |  122 --
 plugins/daap/rb-daap-mdns-avahi.h                  |   40 -
 plugins/daap/rb-daap-mdns-browser-avahi.c          |  405 -----
 plugins/daap/rb-daap-mdns-browser.h                |   91 -
 plugins/daap/rb-daap-mdns-publisher-avahi.c        |  423 -----
 plugins/daap/rb-daap-mdns-publisher.h              |   98 -
 plugins/daap/rb-daap-plugin.c                      |   86 +-
 .../{rb-daap-hash.h => rb-daap-record-factory.c}   |   61 +-
 plugins/daap/rb-daap-record-factory.h              |   67 +
 plugins/daap/rb-daap-record.c                      |  412 +++++
 plugins/daap/rb-daap-record.h                      |   72 +
 plugins/daap/rb-daap-share.c                       | 1785 ------------------
 plugins/daap/rb-daap-share.h                       |   68 -
 plugins/daap/rb-daap-sharing.c                     |   19 +-
 plugins/daap/rb-daap-source.c                      |   80 +-
 plugins/daap/rb-daap-source.h                      |   23 +-
 plugins/daap/rb-daap-src.c                         |   35 +-
 plugins/daap/rb-daap-structure.c                   |  751 --------
 plugins/daap/rb-daap-structure.h                   |  204 ---
 plugins/daap/rb-dmap-container-db-adapter.c        |  193 ++
 plugins/daap/rb-dmap-container-db-adapter.h        |   64 +
 plugins/daap/rb-rhythmdb-dmap-db-adapter.c         |  275 +++
 plugins/daap/rb-rhythmdb-dmap-db-adapter.h         |   61 +
 .../daap/rb-rhythmdb-query-model-dmap-db-adapter.c |  156 ++
 .../daap/rb-rhythmdb-query-model-dmap-db-adapter.h |   61 +
 33 files changed, 1874 insertions(+), 6672 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 37a6c25..f807236 100644
--- a/configure.ac
+++ b/configure.ac
@@ -250,11 +250,6 @@ PKG_CHECK_MODULES(GSTREAMER_0_10, \
 RHYTHMBOX_CFLAGS="$RHYTHMBOX_CFLAGS $GSTREAMER_0_10_CFLAGS"
 RHYTHMBOX_LIBS="$RHYTHMBOX_LIBS $GSTREAMER_0_10_LIBS -lgstinterfaces-0.10"
 
-dnl DAAP (iTunes Music Shares)
-AC_ARG_ENABLE(daap,
-	      AC_HELP_STRING([--disable-daap],
-			     [Disable Digital Audio Access Protocol (music sharing) in rhythmbox]))
-
 AC_ARG_WITH(mdns,
    AC_HELP_STRING([--with-mdns=auto|avahi],
    [Select the mDNS/DNS-SD implementation to use (default auto)]),,
@@ -327,22 +322,6 @@ if test x$enable_libnotify = xyes ; then
     AC_SUBST(NOTIFY_LIBS)
 fi
 
-dnl daap support
-if test "x$enable_daap" != "xno"; then
-	if test x"$have_mdns" = xno; then
-		if test "x$enable_daap" = "xyes"; then
-			AC_MSG_ERROR([DAAP support explicitly requested, but no mDNS implementation found.  Install Avahi])
-		fi
-		enable_daap=no
-	else
-		AC_DEFINE(WITH_DAAP_SUPPORT, 1, [Define if DAAP should be enabled])
-		enable_daap="yes"
-		AC_SUBST(MDNS_CFLAGS)
-		AC_SUBST(MDNS_LIBS)
-	fi
-fi
-AM_CONDITIONAL(USE_DAAP, test "x$enable_daap" != "xno")
-
 AC_CHECK_LIB(z, uncompress)
 
 dnl check for libgstcdda, needed to list the audio tracks
@@ -797,6 +776,31 @@ AC_ARG_VAR([MOZILLA_PLUGINDIR],[Where to install the browser plugin to])
 
 AM_CONDITIONAL([ENABLE_BROWSER_PLUGIN], test x$enable_browser_plugin = xyes)
 
+
+dnl ================================================================
+dnl Use libdmapsharing for DAAP?
+dnl ================================================================
+AC_ARG_ENABLE(daap,
+              AC_HELP_STRING([--disable-daap],
+                             [Disable DAAP support]),,
+              enable_daap=auto)
+if test "x$enable_daap" != "xno"; then
+	PKG_CHECK_MODULES(DMAPSHARING, libdmapsharing-1.9 >= 1.9.0.20,
+			  have_libdmapsharing=yes,
+			  have_libdmapsharing=no)
+	if test "x$have_libdmapsharing" = "xno" -a "x$enable_daap" = "xyes"; then
+		AC_MSG_ERROR([DAAP support explicitly requested, but libdmapsharing couldn't be found])
+	fi
+	if test x"$have_libdmapsharing" = "xyes"; then
+		AC_DEFINE(HAVE_LIBDMAPSHARING, 1, [Define if libdmapsharing support is enabled])
+	fi
+fi
+
+AM_CONDITIONAL(USE_LIBDMAPSHARING, test x"$have_libdmapsharing" = "xyes")
+
+AC_SUBST(DMAPSHARING_CFLAGS)
+AC_SUBST(DMAPSHARING_LIBS)
+
 dnl ================================================================
 dnl end-game
 dnl ================================================================
@@ -941,7 +945,7 @@ elif test x"$have_libnautilus_burn" != xno; then
 else
 	AC_MSG_NOTICE([   CD burning support disabled])
 fi
-if test x"$enable_daap" = xyes; then
+if test x"$have_libdmapsharing" = xyes; then
 	AC_MSG_NOTICE([** DAAP (music sharing) support is enabled])
 else
 	AC_MSG_NOTICE([   DAAP (music sharing) support is disabled])
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index dd7732e..55755f5 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -46,7 +46,7 @@ SUBDIRS += cd-recorder
 endif # HAVE_NAUTILUS_BURN
 endif # HAVE_LIBBRASERO_MEDIA
 
-if USE_DAAP
+if USE_LIBDMAPSHARING
 SUBDIRS += daap
 endif
 
diff --git a/plugins/daap/Makefile.am b/plugins/daap/Makefile.am
index dfc1058..a22f866 100644
--- a/plugins/daap/Makefile.am
+++ b/plugins/daap/Makefile.am
@@ -4,39 +4,37 @@ plugindir = $(PLUGINDIR)/daap
 plugin_LTLIBRARIES = libdaap.la
 
 libdaap_la_SOURCES = \
-	rb-daap-plugin.c			\
-	rb-daap-plugin.h			\
-	rb-daap-source.c			\
-	rb-daap-source.h			\
-	rb-daap-sharing.c			\
-	rb-daap-sharing.h			\
-	rb-daap-share.c				\
-	rb-daap-share.h				\
-	rb-daap-structure.c			\
-	rb-daap-structure.h 			\
-	rb-daap-mdns-publisher.h		\
-	rb-daap-mdns-browser.h			\
-	rb-daap-connection.c			\
-	rb-daap-connection.h			\
-	rb-daap-hash.c				\
-	rb-daap-hash.h				\
-	rb-daap-src.c				\
-	rb-daap-src.h				\
-	rb-daap-dialog.c			\
-	rb-daap-dialog.h			\
-	rb-daap-mdns-avahi.c			\
-	rb-daap-mdns-avahi.h			\
-	rb-daap-mdns-publisher-avahi.c		\
-	rb-daap-mdns-browser-avahi.c		\
+	rb-daap-container-record.c		  \
+	rb-daap-container-record.h		  \
+	rb-daap-plugin.c			  \
+	rb-daap-plugin.h			  \
+	rb-daap-record.c			  \
+	rb-daap-record.h			  \
+	rb-daap-record-factory.c		  \
+	rb-daap-record-factory.h		  \
+	rb-daap-sharing.c			  \
+	rb-daap-sharing.h			  \
+	rb-daap-source.c			  \
+	rb-daap-source.h			  \
+	rb-daap-src.c				  \
+	rb-daap-src.h				  \
+	rb-dmap-container-db-adapter.c		  \
+	rb-dmap-container-db-adapter.h		  \
+	rb-daap-dialog.c			  \
+	rb-daap-dialog.h			  \
+	rb-rhythmdb-dmap-db-adapter.c             \
+	rb-rhythmdb-dmap-db-adapter.h             \
+	rb-rhythmdb-query-model-dmap-db-adapter.c \
+	rb-rhythmdb-query-model-dmap-db-adapter.h \
 	$(NULL)
 
 libdaap_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
 libdaap_la_LIBTOOLFLAGS = --tag=disable-static
 libdaap_la_LIBADD = 					\
 	$(top_builddir)/shell/librhythmbox-core.la	\
+	$(DMAPSHARING_LIBS)                             \
 	$(DBUS_LIBS)					\
-	$(RHYTHMBOX_LIBS)				\
-	$(MDNS_LIBS)
+	$(RHYTHMBOX_LIBS)
 
 INCLUDES = 						\
         -DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
@@ -59,7 +57,7 @@ INCLUDES = 						\
 	-DPIXMAP_DIR=\""$(datadir)/pixmaps"\"		\
 	-DSHARE_DIR=\"$(pkgdatadir)\"                   \
 	-DDATADIR=\""$(datadir)"\"			\
-	$(MDNS_CFLAGS)					\
+	$(DMAPSHARING_CFLAGS)				\
 	$(RHYTHMBOX_CFLAGS)				\
 	$(DBUS_CFLAGS)					\
 	-D_XOPEN_SOURCE -D_BSD_SOURCE
@@ -88,7 +86,7 @@ plugin_DATA = 			\
 	$(NULL)
 
 EXTRA_DIST = 			\
-	$(gtkbuilder_DATA)		\
+	$(gtkbuilder_DATA)	\
 	$(uixml_DATA)		\
 	$(plugin_in_files)	\
 	$(NULL)
diff --git a/plugins/daap/rb-daap-container-record.c b/plugins/daap/rb-daap-container-record.c
new file mode 100644
index 0000000..843f915
--- /dev/null
+++ b/plugins/daap/rb-daap-container-record.c
@@ -0,0 +1,183 @@
+/*
+ *  Container / playlist database record class for DAAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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.
+ *
+ */
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include "rhythmdb-query-model.h"
+#include "rb-daap-container-record.h"
+#include "rb-rhythmdb-query-model-dmap-db-adapter.h"
+
+enum {
+        PROP_0,
+	PROP_NAME
+};
+
+struct RBDAAPContainerRecordPrivate {
+	char *name;
+	RBPlaylistSource *source;
+};
+
+static void rb_daap_container_record_finalize (GObject *object);
+
+static void
+rb_daap_container_record_set_property (GObject *object,
+				guint prop_id,
+				const GValue *value,
+				GParamSpec *pspec)
+{
+	RBDAAPContainerRecord *record = RB_DAAP_CONTAINER_RECORD (object);
+
+	switch (prop_id) {
+		case PROP_NAME:
+			g_free (record->priv->name);
+			record->priv->name = g_value_dup_string (value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+rb_daap_container_record_get_property (GObject *object,
+				guint prop_id,
+				GValue *value,
+				GParamSpec *pspec)
+{
+	RBDAAPContainerRecord *record = RB_DAAP_CONTAINER_RECORD (object);
+
+	switch (prop_id) {
+		case PROP_NAME:
+			g_value_set_string (value, record->priv->name);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+guint
+rb_daap_container_record_get_id (DMAPContainerRecord *record)
+{
+	return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (RB_DAAP_CONTAINER_RECORD (record)->priv->source), "daap_id"));
+}
+
+void
+rb_daap_container_record_add_entry (DMAPContainerRecord *container_record,
+                                       DMAPRecord *record, gint id)
+{
+	g_error ("Unimplemented");
+}
+
+guint64
+rb_daap_container_record_get_entry_count (DMAPContainerRecord *record)
+{
+	RhythmDBQueryModel *model;
+	guint64 count;
+	g_object_get (RB_DAAP_CONTAINER_RECORD (record)->priv->source,
+		     "base-query-model",
+		     &model,
+		      NULL);
+	count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL);
+	g_object_unref (model);
+	return count;
+}
+
+const DMAPDb *
+rb_daap_container_record_get_entries (DMAPContainerRecord *record)
+{
+	RhythmDBQueryModel *model;
+	g_object_get (RB_DAAP_CONTAINER_RECORD (record)->priv->source,
+		     "base-query-model",
+		     &model,
+		      NULL);
+	return DMAP_DB (rb_rhythmdb_query_model_dmap_db_adapter_new (model));
+}
+
+static void
+rb_daap_container_record_init (RBDAAPContainerRecord *record)
+{
+	record->priv = RB_DAAP_CONTAINER_RECORD_GET_PRIVATE (record);
+}
+
+static void
+rb_daap_container_record_class_init (RBDAAPContainerRecordClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (RBDAAPContainerRecordPrivate));
+
+	gobject_class->set_property = rb_daap_container_record_set_property;
+	gobject_class->get_property = rb_daap_container_record_get_property;
+	gobject_class->finalize     = rb_daap_container_record_finalize;
+
+	g_object_class_override_property (gobject_class, PROP_NAME, "name");
+}
+
+static void
+rb_daap_container_record_daap_iface_init (gpointer iface, gpointer data)
+{
+	DMAPContainerRecordInterface *dmap_container_record = iface;
+
+	g_assert (G_TYPE_FROM_INTERFACE (dmap_container_record) == TYPE_DMAP_CONTAINER_RECORD);
+
+	dmap_container_record->get_id = rb_daap_container_record_get_id;
+	dmap_container_record->add_entry = rb_daap_container_record_add_entry;
+	dmap_container_record->get_entry_count = rb_daap_container_record_get_entry_count;
+	dmap_container_record->get_entries = rb_daap_container_record_get_entries;
+}
+
+G_DEFINE_TYPE_WITH_CODE (RBDAAPContainerRecord, rb_daap_container_record, G_TYPE_OBJECT, 
+			 G_IMPLEMENT_INTERFACE (TYPE_DMAP_CONTAINER_RECORD, rb_daap_container_record_daap_iface_init))
+
+static void rb_daap_container_record_finalize (GObject *object)
+{
+	RBDAAPContainerRecord *record = RB_DAAP_CONTAINER_RECORD (object);
+
+        g_free (record->priv->name);
+
+	G_OBJECT_CLASS (rb_daap_container_record_parent_class)->finalize (object);
+}
+
+RBDAAPContainerRecord *
+rb_daap_container_record_new (char *name, RBPlaylistSource *source)
+{
+	RBDAAPContainerRecord *record;
+
+	record = g_object_new (RB_TYPE_DAAP_CONTAINER_RECORD, NULL);
+
+	record->priv->source = source;
+	record->priv->name = name;
+
+	return record;
+}
diff --git a/plugins/daap/rb-daap-container-record.h b/plugins/daap/rb-daap-container-record.h
new file mode 100644
index 0000000..b52d9b7
--- /dev/null
+++ b/plugins/daap/rb-daap-container-record.h
@@ -0,0 +1,75 @@
+/*
+ *  Container / playlist database record class for DAAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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_DAAP_CONTAINER_RECORD
+#define __RB_DAAP_CONTAINER_RECORD
+
+#include <libdmapsharing/dmap.h>
+
+#include "rb-playlist-source.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DAAP_CONTAINER_RECORD         (rb_daap_container_record_get_type ())
+#define RB_DAAP_CONTAINER_RECORD(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DAAP_CONTAINER_RECORD, RBDAAPContainerRecord))
+#define RB_DAAP_CONTAINER_RECORD_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DAAP_CONTAINER_RECORD, RBDAAPContainerRecordClass))
+#define RB_IS_DAAP_CONTAINER_RECORD(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DAAP_CONTAINER_RECORD))
+#define RB_IS_DAAP_CONTAINER_RECORD_CLASS (k) (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DAAP_CONTAINER_RECORD_CLASS))
+#define RB_DAAP_CONTAINER_RECORD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DAAP_CONTAINER_RECORD, RBDAAPContainerRecordClass))
+#define RB_DAAP_CONTAINER_RECORD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_CONTAINER_RECORD, RBDAAPContainerRecordPrivate))
+
+typedef struct RBDAAPContainerRecordPrivate RBDAAPContainerRecordPrivate;
+
+typedef struct {
+	GObject parent;
+	RBDAAPContainerRecordPrivate *priv;
+} RBDAAPContainerRecord;
+
+typedef struct {
+	GObjectClass parent;
+} RBDAAPContainerRecordClass;
+
+GType rb_daap_container_record_get_type (void);
+
+guint         rb_daap_container_record_get_id          (DMAPContainerRecord *record);
+
+void	      rb_daap_container_record_add_entry       (DMAPContainerRecord *container_record,
+							DMAPRecord *record,
+							gint id);
+
+guint64       rb_daap_container_record_get_entry_count (DMAPContainerRecord *record);
+
+const DMAPDb *rb_daap_container_record_get_entries     (DMAPContainerRecord *record);
+
+RBDAAPContainerRecord *rb_daap_container_record_new (char *name,
+						     RBPlaylistSource *model);
+
+#endif /* __RB_DAAP_CONTAINER_RECORD */
+
+G_END_DECLS
diff --git a/plugins/daap/rb-daap-plugin.c b/plugins/daap/rb-daap-plugin.c
index f14f809..c03afe0 100644
--- a/plugins/daap/rb-daap-plugin.c
+++ b/plugins/daap/rb-daap-plugin.c
@@ -53,7 +53,7 @@
 #include "rb-daap-src.h"
 #include "rb-uri-dialog.h"
 
-#include "rb-daap-mdns-browser.h"
+#include <libdmapsharing/dmap.h>
 
 /* preferences */
 #define CONF_DAAP_PREFIX  	CONF_PREFIX "/plugins/daap"
@@ -74,7 +74,7 @@ struct RBDaapPluginPrivate
 	GtkActionGroup *daap_action_group;
 	guint daap_ui_merge_id;
 
-	RBDaapMdnsBrowser *mdns_browser;
+	DMAPMdnsBrowser *mdns_browser;
 
 	GHashTable *source_lookup;
 
@@ -113,6 +113,10 @@ static void enable_browsing_changed_cb (GConfClient *client,
 					guint cnxn_id,
 					GConfEntry *entry,
 					RBDaapPlugin *plugin);
+static void libdmapsharing_debug (const char *domain,
+				  GLogLevelFlags level,
+				  const char *message,
+				  gpointer data);
 
 gboolean rb_daap_add_source (RBDaapPlugin *plugin, gchar *service_name, gchar *host, unsigned int port, GError **error);
 gboolean rb_daap_remove_source (RBDaapPlugin *plugin, gchar *service_name, GError **error);
@@ -223,6 +227,11 @@ impl_activate (RBPlugin *bplugin,
 	plugin->priv->shutdown = FALSE;
 	plugin->priv->shell = g_object_ref (shell);
 
+	g_log_set_handler ("libdmapsharing",
+			    G_LOG_LEVEL_MASK,
+			    libdmapsharing_debug,
+			    NULL);
+
 	value = gconf_client_get_without_default (client,
 						  CONF_ENABLE_BROWSING, NULL);
 	if (value != NULL) {
@@ -458,33 +467,33 @@ find_source_by_service_name (RBDaapPlugin *plugin,
 }
 
 static void
-mdns_service_added (RBDaapMdnsBrowser *browser,
-		    const char        *service_name,
-		    const char        *name,
-		    const char        *host,
-		    guint              port,
-		    gboolean           password_protected,
-		    RBDaapPlugin      *plugin)
+mdns_service_added (DMAPMdnsBrowser *browser,
+		    DMAPMdnsBrowserService *service,
+		    RBDaapPlugin	*plugin)
 {
 	RBSource *source;
 
 	rb_debug ("New service: %s name=%s host=%s port=%u password=%d",
-		   service_name, name, host, port, password_protected);
+		   service->service_name,
+		   service->name,
+		   service->host,
+		   service->port,
+		   service->password_protected);
 
 	GDK_THREADS_ENTER ();
 
-	source = find_source_by_service_name (plugin, service_name);
+	source = find_source_by_service_name (plugin, service->service_name);
 
 	if (source == NULL) {
-		source = rb_daap_source_new (plugin->priv->shell, RB_PLUGIN (plugin), service_name, name, host, port, password_protected);
-		g_hash_table_insert (plugin->priv->source_lookup, g_strdup (service_name), source);
+		source = rb_daap_source_new (plugin->priv->shell, RB_PLUGIN (plugin), service->service_name, service->name, service->host, service->port, service->password_protected);
+		g_hash_table_insert (plugin->priv->source_lookup, g_strdup (service->service_name), source);
 		rb_shell_append_source (plugin->priv->shell, source, NULL);
 	} else {
 		g_object_set (G_OBJECT (source),
-			      "name", name,
-			      "host", host,
-			      "port", port,
-			      "password-protected", password_protected,
+			      "name", service->name,
+			      "host", service->host,
+			      "port", service->port,
+			      "password-protected", service->password_protected,
 			      NULL);
 	}
 
@@ -492,7 +501,7 @@ mdns_service_added (RBDaapMdnsBrowser *browser,
 }
 
 static void
-mdns_service_removed (RBDaapMdnsBrowser *browser,
+mdns_service_removed (DMAPMdnsBrowser *browser,
 		      const char        *service_name,
 		      RBDaapPlugin	*plugin)
 {
@@ -533,7 +542,7 @@ start_browsing (RBDaapPlugin *plugin)
 		return;
 	}
 
-	plugin->priv->mdns_browser = rb_daap_mdns_browser_new ();
+	plugin->priv->mdns_browser = dmap_mdns_browser_new (DMAP_MDNS_BROWSER_SERVICE_TYPE_DAAP);
 	if (plugin->priv->mdns_browser == NULL) {
 		g_warning ("Unable to start mDNS browsing");
 		return;
@@ -551,7 +560,7 @@ start_browsing (RBDaapPlugin *plugin)
 				 0);
 
 	error = NULL;
-	rb_daap_mdns_browser_start (plugin->priv->mdns_browser, &error);
+	dmap_mdns_browser_start (plugin->priv->mdns_browser, &error);
 	if (error != NULL) {
 		g_warning ("Unable to start mDNS browsing: %s", error->message);
 		g_error_free (error);
@@ -581,7 +590,7 @@ stop_browsing (RBDaapPlugin *plugin)
 	g_signal_handlers_disconnect_by_func (plugin->priv->mdns_browser, mdns_service_removed, plugin);
 
 	error = NULL;
-	rb_daap_mdns_browser_stop (plugin->priv->mdns_browser, &error);
+	dmap_mdns_browser_stop (plugin->priv->mdns_browser, &error);
 	if (error != NULL) {
 		g_warning ("Unable to stop mDNS browsing: %s", error->message);
 		g_error_free (error);
@@ -606,6 +615,19 @@ enable_browsing_changed_cb (GConfClient *client,
 	}
 }
 
+static void
+libdmapsharing_debug (const char *domain,
+		      GLogLevelFlags level,
+		      const char *message,
+		      gpointer data)
+{
+	if ((level & G_LOG_LEVEL_DEBUG) != 0) {
+		rb_debug ("%s", message);
+	} else {
+		g_log_default_handler (domain, level, message, data);
+	}
+}
+
 /* daap share connect/disconnect commands */
 
 static void
@@ -627,6 +649,7 @@ new_daap_share_location_added_cb (RBURIDialog *dialog,
 	char *host;
 	char *p;
 	int port = 3689;
+	DMAPMdnsBrowserService service;
 
 	host = g_strdup (location);
 	p = strrchr (host, ':');
@@ -636,12 +659,12 @@ new_daap_share_location_added_cb (RBURIDialog *dialog,
 	}
 
 	rb_debug ("adding manually specified DAAP share at %s", location);
+	service.name = (char *) location;
+	service.host = (char *) location;
+	service.port = port;
+	service.password_protected = FALSE;
 	mdns_service_added (NULL,
-			    g_strdup (location),
-			    g_strdup (location),
-			    g_strdup (host),
-			    port,
-			    FALSE,
+			    &service,
 			    plugin);
 
 	g_free (host);
@@ -900,6 +923,7 @@ impl_create_configure_dialog (RBPlugin *bplugin)
 gboolean
 rb_daap_add_source (RBDaapPlugin *plugin, gchar *service_name, gchar *host, unsigned int port, GError **error)
 {
+	DMAPMdnsBrowserService service;
 
 	if (plugin->priv->shutdown)
 		return FALSE;
@@ -907,12 +931,12 @@ rb_daap_add_source (RBDaapPlugin *plugin, gchar *service_name, gchar *host, unsi
 	rb_debug ("Add DAAP source %s (%s:%d)", service_name, host, port);
 
 	rb_debug ("adding manually specified DAAP share at %s", service_name);
+	service.name = service_name;
+	service.host = host;
+	service.port = port;
+	service.password_protected = FALSE;
 	mdns_service_added (NULL,
-			    g_strdup (service_name),
-			    g_strdup (service_name),
-			    g_strdup (host),
-			    port,
-			    FALSE,
+			    &service,
 			    plugin);
 
 	return TRUE;
diff --git a/plugins/daap/rb-daap-hash.h b/plugins/daap/rb-daap-record-factory.c
similarity index 50%
rename from plugins/daap/rb-daap-hash.h
rename to plugins/daap/rb-daap-record-factory.c
index e6c25ad..be750e4 100644
--- a/plugins/daap/rb-daap-hash.h
+++ b/plugins/daap/rb-daap-record-factory.c
@@ -1,8 +1,7 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+/*
+ *  RBDAAPRecord factory class
  *
- *  Header for DAAP (iTunes Music Sharing) hashing, connection
- *
- *  Copyright (C) 2004-2005 Charles Schmidt <cschmidt2 emich edu>
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
  *
  *  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
@@ -28,19 +27,51 @@
  *
  */
 
-#ifndef __RB_DAAP_HASH_H
-#define __RB_DAAP_HASH_H
+#include "rhythmdb.h"
+#include "rb-daap-record-factory.h"
+#include "rb-daap-record.h"
+
+DMAPRecord *
+rb_daap_record_factory_create  (DMAPRecordFactory *factory,
+				gpointer user_data)
+{
+	DAAPRecord *record;
+
+	record = DAAP_RECORD (rb_daap_record_new ((RhythmDBEntry *) user_data));
+
+	return (DMAP_RECORD (record));
+}
+
+static void
+rb_daap_record_factory_init (RBDAAPRecordFactory *factory)
+{
+}
+
+static void
+rb_daap_record_factory_class_init (RBDAAPRecordFactoryClass *klass)
+{
+}
+
+static void
+rb_daap_record_factory_interface_init (gpointer iface, gpointer data)
+{
+	DMAPRecordFactoryInterface *factory = iface;
+
+	g_assert (G_TYPE_FROM_INTERFACE (factory) == TYPE_DMAP_RECORD_FACTORY);
 
-#include <glib.h>
+	factory->create = rb_daap_record_factory_create;
+}
 
-G_BEGIN_DECLS
+G_DEFINE_TYPE_WITH_CODE (RBDAAPRecordFactory, rb_daap_record_factory, G_TYPE_OBJECT, 
+			 G_IMPLEMENT_INTERFACE (TYPE_DMAP_RECORD_FACTORY,
+					        rb_daap_record_factory_interface_init))
 
-void rb_daap_hash_generate (short         version_major,
-			    const guchar *url,
-			    guchar        hash_select,
-			    guchar       *out,
-			    gint          request_id);
+RBDAAPRecordFactory *
+rb_daap_record_factory_new (void)
+{
+	RBDAAPRecordFactory *factory;
 
-G_END_DECLS
+	factory = RB_DAAP_RECORD_FACTORY (g_object_new (RB_TYPE_DAAP_RECORD_FACTORY, NULL));
 
-#endif /* __RB_DAAP_HASH_H */
+	return factory;
+}
diff --git a/plugins/daap/rb-daap-record-factory.h b/plugins/daap/rb-daap-record-factory.h
new file mode 100644
index 0000000..3bb9961
--- /dev/null
+++ b/plugins/daap/rb-daap-record-factory.h
@@ -0,0 +1,67 @@
+/*
+ *  RBDAAPRecord factory class
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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_DAAP_RECORD_FACTORY
+#define __RB_DAAP_RECORD_FACTORY
+
+#include <libdmapsharing/dmap.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DAAP_RECORD_FACTORY         (rb_daap_record_factory_get_type ())
+#define RB_DAAP_RECORD_FACTORY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), \
+				               RB_TYPE_DAAP_RECORD_FACTORY, RBDAAPRecordFactory))
+#define RB_DAAP_RECORD_FACTORY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), \
+				               RB_TYPE_DAAP_RECORD_FACTORY, RBDAAPRecordFactoryClass))
+#define RB_IS_DAAP_RECORD_FACTORY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
+				               RB_TYPE_DAAP_RECORD_FACTORY))
+#define RB_IS_DAAP_RECORD_FACTORY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), \
+				               RB_TYPE_DAAP_RECORD_FACTORY_CLASS))
+#define RB_DAAP_RECORD_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), \
+				               RB_TYPE_DAAP_RECORD_FACTORY, RBDAAPRecordFactoryClass))
+
+typedef struct RBDAAPRecordFactoryPrivate RBDAAPRecordFactoryPrivate;
+
+typedef struct {
+	GObject parent;
+} RBDAAPRecordFactory;
+
+typedef struct {
+	GObjectClass parent;
+} RBDAAPRecordFactoryClass;
+
+GType                  rb_daap_record_factory_get_type (void);
+
+RBDAAPRecordFactory *rb_daap_record_factory_new      (void);
+
+DMAPRecord            *rb_daap_record_factory_create   (DMAPRecordFactory *factory, gpointer user_data);
+
+#endif /* __RB_DAAP_RECORD_FACTORY */
+
+G_END_DECLS
diff --git a/plugins/daap/rb-daap-record.c b/plugins/daap/rb-daap-record.c
new file mode 100644
index 0000000..e995b90
--- /dev/null
+++ b/plugins/daap/rb-daap-record.c
@@ -0,0 +1,412 @@
+/*
+ *  Database record class for DAAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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.
+ *
+ */
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "rhythmdb.h"
+#include "rb-daap-record.h"
+
+struct RBDAAPRecordPrivate {
+	guint64 filesize;
+	char *location;
+	char *format;	 /* Format, possibly after transcoding. */
+	char *real_format;
+	char *title;
+	char *album;
+	char *artist;
+	char *genre;
+	gboolean has_video;
+	gint rating;
+	int duration;
+	int track;
+	int year;
+	int firstseen;
+	int mtime;
+	int disc;
+	int bitrate;
+	char *sort_artist;
+	char *sort_album;
+};
+
+enum {
+	PROP_0,
+	PROP_LOCATION,
+	PROP_TITLE,
+	PROP_RATING,
+	PROP_FILESIZE,
+	PROP_ALBUM,
+	PROP_ARTIST,
+	PROP_GENRE,
+	PROP_FORMAT,
+	PROP_DURATION,
+	PROP_TRACK,
+	PROP_YEAR,
+	PROP_FIRSTSEEN,
+	PROP_MTIME,
+	PROP_DISC,
+	PROP_BITRATE,
+	PROP_HAS_VIDEO,
+	PROP_REAL_FORMAT,
+	PROP_ARTIST_SORT_NAME,
+	PROP_ALBUM_SORT_NAME
+};
+
+static void rb_daap_record_finalize (GObject *object);
+
+static void
+rb_daap_record_set_property (GObject *object,
+				guint prop_id,
+				const GValue *value,
+				GParamSpec *pspec)
+{
+	RBDAAPRecord *record = RB_DAAP_RECORD (object);
+
+	switch (prop_id) {
+		case PROP_LOCATION:
+			g_free (record->priv->location);
+			record->priv->location = g_value_dup_string (value);
+			break;
+		case PROP_TITLE:
+			g_free (record->priv->title);
+			record->priv->title = g_value_dup_string (value);
+			break;
+		case PROP_ALBUM:
+			g_free (record->priv->album);
+			record->priv->album = g_value_dup_string (value);
+			break;
+		case PROP_ARTIST:
+			g_free (record->priv->artist);
+			record->priv->artist = g_value_dup_string (value);
+			break;
+		case PROP_GENRE:
+			g_free (record->priv->genre);
+			record->priv->genre = g_value_dup_string (value);
+			break;
+		case PROP_FORMAT:
+			g_free (record->priv->format);
+			record->priv->format = g_value_dup_string (value);
+			break;
+		case PROP_RATING:
+			record->priv->rating = g_value_get_int (value);
+			break;
+		case PROP_FILESIZE:
+			record->priv->filesize = g_value_get_uint64 (value);
+			break;
+		case PROP_DURATION:
+			record->priv->duration = g_value_get_int (value);
+			break;
+		case PROP_TRACK:
+			record->priv->track = g_value_get_int (value);
+			break;
+		case PROP_YEAR:
+			record->priv->year = g_value_get_int (value);
+			break;
+		case PROP_FIRSTSEEN:
+			record->priv->firstseen = g_value_get_int (value);
+			break;
+		case PROP_MTIME:
+			record->priv->mtime = g_value_get_int (value);
+			break;
+		case PROP_DISC:
+			record->priv->disc = g_value_get_int (value);
+			break;
+		case PROP_BITRATE:
+			record->priv->bitrate = g_value_get_int (value);
+			break;
+		case PROP_HAS_VIDEO:
+			record->priv->has_video = g_value_get_boolean (value);
+			break;
+		case PROP_REAL_FORMAT:
+			g_free (record->priv->real_format);
+			record->priv->real_format = g_value_dup_string (value);
+			break;
+		case PROP_ARTIST_SORT_NAME:
+			g_free (record->priv->sort_artist);
+			record->priv->sort_artist = g_value_dup_string (value);
+			break;
+		case PROP_ALBUM_SORT_NAME:
+			g_free (record->priv->sort_album);
+			record->priv->sort_album = g_value_dup_string (value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+rb_daap_record_get_property (GObject *object,
+				guint prop_id,
+				GValue *value,
+				GParamSpec *pspec)
+{
+	RBDAAPRecord *record = RB_DAAP_RECORD (object);
+
+	switch (prop_id) {
+		case PROP_LOCATION:
+			g_value_set_string (value, record->priv->location);
+			break;
+		case PROP_TITLE:
+			g_value_set_string (value, record->priv->title);
+			break;
+		case PROP_ALBUM:
+			g_value_set_string (value, record->priv->album);
+			break;
+		case PROP_ARTIST:
+			g_value_set_string (value, record->priv->artist);
+			break;
+		case PROP_GENRE:
+			g_value_set_string (value, record->priv->genre);
+			break;
+		case PROP_FORMAT:
+			g_value_set_string (value, record->priv->format);
+			break;
+		case PROP_RATING:
+			g_value_set_int (value, record->priv->rating);
+			break;
+		case PROP_FILESIZE:
+			g_value_set_uint64 (value, record->priv->filesize);
+			break;
+		case PROP_DURATION:
+			g_value_set_int (value, record->priv->duration);
+			break;
+		case PROP_TRACK:
+			g_value_set_int (value, record->priv->track);
+			break;
+		case PROP_YEAR:
+			g_value_set_int (value, record->priv->year);
+			break;
+		case PROP_FIRSTSEEN:
+			g_value_set_int (value, record->priv->firstseen);
+			break;
+		case PROP_MTIME:
+			g_value_set_int (value, record->priv->mtime);
+			break;
+		case PROP_DISC:
+			g_value_set_int (value, record->priv->disc);
+			break;
+		case PROP_BITRATE:
+			g_value_set_int (value, record->priv->bitrate);
+			break;
+		case PROP_HAS_VIDEO:
+			g_value_set_boolean (value, record->priv->has_video);
+			break;
+		case PROP_REAL_FORMAT:
+			g_value_set_string (value, record->priv->real_format);
+			break;
+		case PROP_ARTIST_SORT_NAME:
+			g_value_set_string (value, record->priv->sort_artist);
+			break;
+		case PROP_ALBUM_SORT_NAME:
+			g_value_set_string (value, record->priv->sort_album);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+gboolean
+rb_daap_record_itunes_compat (DAAPRecord *record)
+{
+	const gchar *format = RB_DAAP_RECORD (record)->priv->real_format;
+
+	if (! strcmp (format, "mp3"))
+		return TRUE;
+	else
+		return FALSE;
+}
+
+GInputStream *
+rb_daap_record_read (DAAPRecord *record, GError **error)
+{
+	GFile *file;
+	GInputStream *fnval = NULL;
+
+	file = g_file_new_for_uri (RB_DAAP_RECORD (record)->priv->location);
+	fnval = G_INPUT_STREAM (g_file_read (file, NULL, error));
+
+	g_object_unref (file);
+
+	return fnval;
+}
+
+static void
+rb_daap_record_init (RBDAAPRecord *record)
+{
+	record->priv = RB_DAAP_RECORD_GET_PRIVATE (record);
+}
+
+static void
+rb_daap_record_class_init (RBDAAPRecordClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (RBDAAPRecordPrivate));
+
+	gobject_class->set_property = rb_daap_record_set_property;	
+	gobject_class->get_property = rb_daap_record_get_property;	
+	gobject_class->finalize     = rb_daap_record_finalize;	
+
+	g_object_class_override_property (gobject_class, PROP_LOCATION, "location");
+	g_object_class_override_property (gobject_class, PROP_TITLE, "title");
+	g_object_class_override_property (gobject_class, PROP_ALBUM, "daap.songalbum");
+	g_object_class_override_property (gobject_class, PROP_ARTIST, "daap.songartist");
+	g_object_class_override_property (gobject_class, PROP_GENRE, "daap.songgenre");
+	g_object_class_override_property (gobject_class, PROP_FORMAT, "format");
+	g_object_class_override_property (gobject_class, PROP_RATING, "rating");
+	g_object_class_override_property (gobject_class, PROP_FILESIZE, "filesize");
+	g_object_class_override_property (gobject_class, PROP_DURATION, "duration");
+	g_object_class_override_property (gobject_class, PROP_TRACK, "track");
+	g_object_class_override_property (gobject_class, PROP_YEAR, "year");
+	g_object_class_override_property (gobject_class, PROP_FIRSTSEEN, "firstseen");
+	g_object_class_override_property (gobject_class, PROP_MTIME, "mtime");
+	g_object_class_override_property (gobject_class, PROP_DISC, "disc");
+	g_object_class_override_property (gobject_class, PROP_BITRATE, "bitrate");
+	g_object_class_override_property (gobject_class, PROP_HAS_VIDEO, "has-video");
+	g_object_class_override_property (gobject_class, PROP_ARTIST_SORT_NAME, "sort_artist");
+	g_object_class_override_property (gobject_class, PROP_ALBUM_SORT_NAME, "sort_album");
+
+	g_object_class_install_property (gobject_class, PROP_REAL_FORMAT,
+	                        g_param_spec_string ("real-format",
+			     "Real format of song data",
+			     "Real format of song data",
+			       NULL,
+			    G_PARAM_READWRITE));
+}
+
+static void
+rb_daap_record_daap_iface_init (gpointer iface, gpointer data)
+{
+	DAAPRecordInterface *daap_record = iface;
+
+	g_assert (G_TYPE_FROM_INTERFACE (daap_record) == TYPE_DAAP_RECORD);
+
+	daap_record->itunes_compat = rb_daap_record_itunes_compat;
+	daap_record->read = rb_daap_record_read;
+}
+
+static void
+rb_daap_record_dmap_iface_init (gpointer iface, gpointer data)
+{
+	DMAPRecordInterface *dmap_record = iface;
+
+	g_assert (G_TYPE_FROM_INTERFACE (dmap_record) == TYPE_DMAP_RECORD);
+}
+
+G_DEFINE_TYPE_WITH_CODE (RBDAAPRecord, rb_daap_record, G_TYPE_OBJECT, 
+			 G_IMPLEMENT_INTERFACE (TYPE_DAAP_RECORD, rb_daap_record_daap_iface_init)
+			 G_IMPLEMENT_INTERFACE (TYPE_DMAP_RECORD, rb_daap_record_dmap_iface_init))
+
+static void rb_daap_record_finalize (GObject *object)
+{
+	RBDAAPRecord *record = RB_DAAP_RECORD (object);
+
+        g_free (record->priv->location);
+	g_free (record->priv->title);
+	g_free (record->priv->format);
+	g_free (record->priv->album);
+	g_free (record->priv->artist);
+	g_free (record->priv->genre);
+	g_free (record->priv->real_format);
+
+	G_OBJECT_CLASS (rb_daap_record_parent_class)->finalize (object);
+}
+
+RBDAAPRecord *rb_daap_record_new (RhythmDBEntry *entry)
+{
+	RBDAAPRecord *record = NULL;
+	record = RB_DAAP_RECORD (g_object_new (RB_TYPE_DAAP_RECORD, NULL));
+
+	/* When browsing, entry will be NULL because we will pull
+	 * the metadata from the DAAP query. When sharing, entry will
+	 * point to an existing entry from the Rhythmbox DB.
+	 */
+	if (entry) {
+		gchar *ext;
+
+		record->priv->filesize = rhythmdb_entry_get_uint64 
+						(entry, RHYTHMDB_PROP_FILE_SIZE);
+
+		record->priv->location = rhythmdb_entry_dup_string
+						(entry, RHYTHMDB_PROP_LOCATION);
+
+		record->priv->title    = rhythmdb_entry_dup_string
+						(entry, RHYTHMDB_PROP_TITLE);
+
+		record->priv->artist   = rhythmdb_entry_dup_string
+						(entry, RHYTHMDB_PROP_ARTIST);
+
+		record->priv->album    = rhythmdb_entry_dup_string
+						(entry, RHYTHMDB_PROP_ALBUM);
+
+		record->priv->genre    = rhythmdb_entry_dup_string
+						(entry, RHYTHMDB_PROP_GENRE);
+
+		/* FIXME: Support transcoding: */
+		/* FIXME: we should use RHYTHMDB_PROP_MIMETYPE instead */
+		ext = strrchr (record->priv->location, '.');
+		if (ext == NULL) {
+			ext = "mp3";
+		} else {
+			ext++;
+		}
+		record->priv->real_format = g_strdup (ext);
+		record->priv->format = g_strdup (record->priv->real_format);
+
+		record->priv->track    = rhythmdb_entry_get_ulong
+						(entry, RHYTHMDB_PROP_TRACK_NUMBER);
+
+		record->priv->duration = rhythmdb_entry_get_ulong
+						(entry, RHYTHMDB_PROP_DURATION);
+
+		record->priv->rating   = (gint) rhythmdb_entry_get_double
+						(entry, RHYTHMDB_PROP_RATING);
+
+		record->priv->year     = rhythmdb_entry_get_ulong
+						(entry, RHYTHMDB_PROP_YEAR);
+
+		record->priv->firstseen = rhythmdb_entry_get_ulong
+						(entry, RHYTHMDB_PROP_FIRST_SEEN);
+
+		record->priv->mtime     = rhythmdb_entry_get_ulong
+						(entry, RHYTHMDB_PROP_MTIME);
+
+		record->priv->disc      = rhythmdb_entry_get_ulong
+						(entry, RHYTHMDB_PROP_DISC_NUMBER);
+
+		record->priv->bitrate   = rhythmdb_entry_get_ulong
+						(entry, RHYTHMDB_PROP_BITRATE);
+	}
+
+	return record;
+}
diff --git a/plugins/daap/rb-daap-record.h b/plugins/daap/rb-daap-record.h
new file mode 100644
index 0000000..0a1edd0
--- /dev/null
+++ b/plugins/daap/rb-daap-record.h
@@ -0,0 +1,72 @@
+/*
+ *  Database record class for DAAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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_DAAP_RECORD
+#define __RB_DAAP_RECORD
+
+#include <libdmapsharing/dmap.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DAAP_RECORD         (rb_daap_record_get_type ())
+#define RB_DAAP_RECORD(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DAAP_RECORD, RBDAAPRecord))
+#define RB_DAAP_RECORD_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DAAP_RECORD, RBDAAPRecordClass))
+#define RB_IS_DAAP_RECORD(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DAAP_RECORD))
+#define RB_IS_DAAP_RECORD_CLASS (k) (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DAAP_RECORD_CLASS))
+#define RB_DAAP_RECORD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DAAP_RECORD, RBDAAPRecordClass))
+#define RB_DAAP_RECORD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_RECORD, RBDAAPRecordPrivate))
+
+typedef struct RBDAAPRecordPrivate RBDAAPRecordPrivate;
+
+typedef struct {
+	GObject parent;
+	RBDAAPRecordPrivate *priv;
+} RBDAAPRecord;
+
+typedef struct {
+	GObjectClass parent;
+} RBDAAPRecordClass;
+
+GType rb_daap_record_get_type (void);
+
+RBDAAPRecord *rb_daap_record_new (RhythmDBEntry *entry);
+
+gint          rb_daap_record_get_id          (DAAPRecord *record);
+
+gboolean      rb_daap_record_itunes_compat   (DAAPRecord *record);
+
+void          rb_daap_record_set_transcode_format (DAAPRecord *record,
+						      const gint format);
+
+GInputStream *rb_daap_record_read            (DAAPRecord *record,
+						 GError **err);
+
+#endif /* __RB_DAAP_RECORD */
+
+G_END_DECLS
diff --git a/plugins/daap/rb-daap-sharing.c b/plugins/daap/rb-daap-sharing.c
index a5f43bb..4b446fa 100644
--- a/plugins/daap/rb-daap-sharing.c
+++ b/plugins/daap/rb-daap-sharing.c
@@ -36,14 +36,17 @@
 #include <glib/gprintf.h>
 
 #include "rb-daap-sharing.h"
-#include "rb-daap-share.h"
+#include "rb-rhythmdb-dmap-db-adapter.h"
+#include "rb-dmap-container-db-adapter.h"
 #include "rb-debug.h"
 #include "rb-dialog.h"
 #include "rb-playlist-manager.h"
 #include "eel-gconf-extensions.h"
 #include "rb-preferences.h"
 
-static RBDAAPShare *share = NULL;
+#include <libdmapsharing/dmap.h>
+
+static DAAPShare *share = NULL;
 static guint enable_sharing_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 static guint require_password_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 static guint share_name_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
@@ -65,7 +68,9 @@ rb_daap_sharing_default_share_name ()
 static void
 create_share (RBShell *shell)
 {
-	RhythmDB *db;
+	RhythmDB *rdb;
+	DMAPDb *db;
+	DMAPContainerDb *container_db;
 	RBPlaylistManager *playlist_manager;
 	char *name;
 	char *password;
@@ -81,8 +86,10 @@ create_share (RBShell *shell)
 	}
 
 	g_object_get (shell,
-		      "db", &db,
+		      "db", &rdb,
 		      "playlist-manager", &playlist_manager, NULL);
+	db = DMAP_DB (rb_rhythmdb_dmap_db_adapter_new (rdb, RHYTHMDB_ENTRY_TYPE_SONG));
+	container_db = DMAP_CONTAINER_DB (rb_dmap_container_db_adapter_new (playlist_manager));
 
 	require_password = eel_gconf_get_boolean (CONF_DAAP_REQUIRE_PASSWORD);
 	if (require_password) {
@@ -91,9 +98,11 @@ create_share (RBShell *shell)
 		password = NULL;
 	}
 
-	share = rb_daap_share_new (name, password, db, RHYTHMDB_ENTRY_TYPE_SONG, playlist_manager);
+	share = daap_share_new (name, password, db, container_db, NULL);
 
 	g_object_unref (db);
+	g_object_unref (container_db);
+	g_object_unref (rdb);
 	g_object_unref (playlist_manager);
 
 	g_free (name);
diff --git a/plugins/daap/rb-daap-source.c b/plugins/daap/rb-daap-source.c
index 5e59e0a..9ec42af 100644
--- a/plugins/daap/rb-daap-source.c
+++ b/plugins/daap/rb-daap-source.c
@@ -50,14 +50,16 @@
 #include "rb-dialog.h"
 #include "rb-preferences.h"
 #include "rb-daap-src.h"
+#include "rb-daap-record-factory.h"
+#include "rb-rhythmdb-dmap-db-adapter.h"
 
-#include "rb-daap-connection.h"
-#include "rb-daap-mdns-browser.h"
 #include "rb-daap-dialog.h"
 #include "rb-daap-plugin.h"
 
 #include "rb-static-playlist-source.h"
 
+#include <libdmapsharing/dmap.h>
+
 static void rb_daap_source_dispose (GObject *object);
 static void rb_daap_source_set_property  (GObject *object,
 					  guint prop_id,
@@ -392,7 +394,7 @@ ask_password (RBDAAPSource *source, const char *name, const char *keyring)
 }
 
 static char *
-connection_auth_cb (RBDAAPConnection *connection,
+connection_auth_cb (DMAPConnection   *connection,
 		    const char       *name,
 		    RBDAAPSource     *source)
 {
@@ -440,8 +442,8 @@ connection_auth_cb (RBDAAPConnection *connection,
 }
 
 static void
-connection_connecting_cb (RBDAAPConnection     *connection,
-			  RBDAAPConnectionState state,
+connection_connecting_cb (DMAPConnection       *connection,
+			  DMAPConnectionState   state,
 			  float		        progress,
 			  RBDAAPSource         *source)
 {
@@ -452,20 +454,20 @@ connection_connecting_cb (RBDAAPConnection     *connection,
 	rb_debug ("DAAP connection status: %d/%f", state, progress);
 
 	switch (state) {
-	case DAAP_GET_INFO:
-	case DAAP_GET_PASSWORD:
-	case DAAP_LOGIN:
+	case DMAP_GET_INFO:
+	case DMAP_GET_PASSWORD:
+	case DMAP_LOGIN:
 		source->priv->connection_status = _("Connecting to music share");
 		break;
-	case DAAP_GET_REVISION_NUMBER:
-	case DAAP_GET_DB_INFO:
-	case DAAP_GET_SONGS:
-	case DAAP_GET_PLAYLISTS:
-	case DAAP_GET_PLAYLIST_ENTRIES:
+	case DMAP_GET_REVISION_NUMBER:
+	case DMAP_GET_DB_INFO:
+	case DMAP_GET_SONGS:
+	case DMAP_GET_PLAYLISTS:
+	case DMAP_GET_PLAYLIST_ENTRIES:
 		source->priv->connection_status = _("Retrieving songs from music share");
 		break;
-	case DAAP_LOGOUT:
-	case DAAP_DONE:
+	case DMAP_LOGOUT:
+	case DMAP_DONE:
 		source->priv->connection_status = NULL;
 		break;
 	}
@@ -474,7 +476,7 @@ connection_connecting_cb (RBDAAPConnection     *connection,
 
 	rb_source_notify_status_changed (RB_SOURCE (source));
 
-	is_connected = rb_daap_connection_is_connected (connection);
+	is_connected = dmap_connection_is_connected (DMAP_CONNECTION (connection));
 
 	g_object_get (source, "plugin", &plugin, NULL);
 	g_assert (plugin != NULL);
@@ -491,7 +493,7 @@ connection_connecting_cb (RBDAAPConnection     *connection,
 }
 
 static void
-connection_disconnected_cb (RBDAAPConnection *connection,
+connection_disconnected_cb (DMAPConnection   *connection,
 			    RBDAAPSource     *source)
 {
 	GdkPixbuf *icon;
@@ -527,13 +529,13 @@ release_connection (RBDAAPSource *daap_source)
 }
 
 static void
-_add_location_to_playlist (RBRefString *uri, RBStaticPlaylistSource *source)
+_add_location_to_playlist (const char *uri, RBStaticPlaylistSource *source)
 {
-	rb_static_playlist_source_add_location (source, rb_refstring_get (uri), -1);
+	rb_static_playlist_source_add_location (source, uri, -1);
 }
 
 static void
-rb_daap_source_connection_cb (RBDAAPConnection *connection,
+rb_daap_source_connection_cb (DMAPConnection   *connection,
 			      gboolean          result,
 			      const char       *reason,
 			      RBSource         *source)
@@ -564,9 +566,9 @@ rb_daap_source_connection_cb (RBDAAPConnection *connection,
 		      "shell", &shell,
 		      "entry-type", &entry_type,
 		      NULL);
-	playlists = rb_daap_connection_get_playlists (RB_DAAP_CONNECTION (daap_source->priv->connection));
+	playlists = dmap_connection_get_playlists (DMAP_CONNECTION (daap_source->priv->connection));
 	for (l = playlists; l != NULL; l = g_slist_next (l)) {
-		RBDAAPPlaylist *playlist = l->data;
+		DMAPPlaylist *playlist = l->data;
 		RBSource *playlist_source;
 		char *sorting_name;
 
@@ -591,7 +593,9 @@ rb_daap_source_activate (RBSource *source)
 {
 	RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
 	RBShell *shell = NULL;
-	RhythmDB *db = NULL;
+	DMAPRecordFactory *factory;
+	RhythmDB *rdb = NULL;
+	DMAPDb *db = NULL;
 	char *name = NULL;
 	RhythmDBEntryType type;
 
@@ -601,17 +605,20 @@ rb_daap_source_activate (RBSource *source)
 
 	g_object_get (daap_source,
 		      "shell", &shell,
-		      "entry-type", &type,
 		      "name", &name,
+		      "entry-type", &type,
 		      NULL);
-	g_object_get (shell, "db", &db, NULL);
+	g_object_get (shell, "db", &rdb, NULL);
+	db = DMAP_DB (rb_rhythmdb_dmap_db_adapter_new (rdb, type));
+
+	factory = DMAP_RECORD_FACTORY (rb_daap_record_factory_new ());
 
-	daap_source->priv->connection = rb_daap_connection_new (name,
+	daap_source->priv->connection = dmap_connection_new (name,
 								daap_source->priv->host,
 								daap_source->priv->port,
 								daap_source->priv->password_protected,
 								db,
-								type);
+								factory);
         g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, type);
 	g_object_add_weak_pointer (G_OBJECT (daap_source->priv->connection), (gpointer *)&daap_source->priv->connection);
 
@@ -630,16 +637,16 @@ rb_daap_source_activate (RBSource *source)
                           G_CALLBACK (connection_disconnected_cb),
 			  source);
 
-	rb_daap_connection_connect (RB_DAAP_CONNECTION (daap_source->priv->connection),
-				    (RBDAAPConnectionCallback) rb_daap_source_connection_cb,
+	dmap_connection_connect (DMAP_CONNECTION (daap_source->priv->connection),
+				    (DMAPConnectionCallback) rb_daap_source_connection_cb,
 				    source);
 
-	g_object_unref (G_OBJECT (db));
+	g_object_unref (G_OBJECT (rdb));
 	g_object_unref (G_OBJECT (shell));
 }
 
 static void
-rb_daap_source_disconnect_cb (RBDAAPConnection *connection,
+rb_daap_source_disconnect_cb (DMAPConnection   *connection,
 			      gboolean          result,
 			      const char       *reason,
 			      RBSource         *source)
@@ -704,8 +711,8 @@ rb_daap_source_disconnect (RBDAAPSource *daap_source)
 
 	/* keep the source alive until the disconnect completes */
 	g_object_ref (daap_source);
-	rb_daap_connection_disconnect (daap_source->priv->connection,
-				       (RBDAAPConnectionCallback) rb_daap_source_disconnect_cb,
+	dmap_connection_disconnect (daap_source->priv->connection,
+				       (DMAPConnectionCallback) rb_daap_source_disconnect_cb,
 				       daap_source);
 
 	/* wait until disconnected */
@@ -726,7 +733,7 @@ rb_daap_source_show_popup (RBSource *source)
 	return TRUE;
 }
 
-GstStructure *
+SoupMessageHeaders *
 rb_daap_source_get_headers (RBDAAPSource *source,
 			    const char *uri)
 {
@@ -735,7 +742,7 @@ rb_daap_source_get_headers (RBDAAPSource *source,
 		return NULL;
 	}
 
-	return rb_daap_connection_get_headers (source->priv->connection, uri);
+	return dmap_connection_get_headers (source->priv->connection, uri);
 }
 
 static char *
@@ -765,7 +772,7 @@ rb_daap_source_get_status (RBSource *source,
 		*progress_text = NULL;
 	}
 	if (progress != NULL) {
-		*progress = 0.0;
+		*progress = 1.0;
 	}
 
 	if (daap_source->priv->connection_status != NULL) {
@@ -795,4 +802,3 @@ rb_daap_source_get_playback_uri (RhythmDBEntry *entry, gpointer data)
 
 	return g_strdup (location);
 }
-
diff --git a/plugins/daap/rb-daap-source.h b/plugins/daap/rb-daap-source.h
index 3e92ab1..667d984 100644
--- a/plugins/daap/rb-daap-source.h
+++ b/plugins/daap/rb-daap-source.h
@@ -35,6 +35,7 @@
 #include "rb-plugin.h"
 
 #include <gst/gst.h>
+#include <libsoup/soup.h>
 
 G_BEGIN_DECLS
 
@@ -57,20 +58,20 @@ typedef struct {
 	RBBrowserSourceClass parent;
 } RBDAAPSourceClass;
 
-GType 		rb_daap_source_get_type 	(void);
+GType			rb_daap_source_get_type		(void);
 
-RBSource *	rb_daap_source_new 		(RBShell *shell,
-						 RBPlugin *plugin,
-						 const char *service_name,
-						 const char *name,
-						 const char *host,
-						 guint port,
-						 gboolean password_protected);
+RBSource *		rb_daap_source_new 		(RBShell *shell,
+							 RBPlugin *plugin,
+							 const char *service_name,
+							 const char *name,
+							 const char *host,
+							 guint port,
+							 gboolean password_protected);
 
-void 		rb_daap_source_disconnect 	(RBDAAPSource *daap_source);
+void			rb_daap_source_disconnect 	(RBDAAPSource *daap_source);
 
-GstStructure *	rb_daap_source_get_headers 	(RBDAAPSource *source,
-						 const gchar *uri);
+SoupMessageHeaders *	rb_daap_source_get_headers	(RBDAAPSource *source,
+							 const gchar *uri);
 
 G_END_DECLS
 
diff --git a/plugins/daap/rb-daap-src.c b/plugins/daap/rb-daap-src.c
index 60f66af..a23d634 100644
--- a/plugins/daap/rb-daap-src.c
+++ b/plugins/daap/rb-daap-src.c
@@ -241,6 +241,27 @@ rb_daap_src_get_property (GObject *object,
 	}
 }
 
+static void
+rb_daap_src_set_header (const char *name, const char *value, gpointer headers)
+{
+	gst_structure_set (headers, name, G_TYPE_STRING, value, NULL);
+}
+
+static GstStructure *
+rb_daap_src_soup_message_headers_to_gst_structure (SoupMessageHeaders *headers)
+{
+	GstStructure *gst_headers = gst_structure_new ("extra-headers", NULL);
+
+	if (gst_headers == NULL)
+		return gst_headers;
+
+	soup_message_headers_foreach (headers,
+				      rb_daap_src_set_header,
+				      gst_headers);
+
+	return gst_headers;
+}
+
 GstStateChangeReturn
 rb_daap_src_change_state (GstElement *element, GstStateChange transition)
 {
@@ -251,7 +272,8 @@ rb_daap_src_change_state (GstElement *element, GstStateChange transition)
 		{
 			const char *http = "http";
 			char *httpuri;
-			GstStructure *headers;
+			SoupMessageHeaders *headers;
+			GstStructure *gst_headers;
 			RBDAAPSource *source;
 
 			/* Retrieve extra headers for the HTTP connection. */
@@ -267,8 +289,15 @@ rb_daap_src_change_state (GstElement *element, GstStateChange transition)
 				return GST_STATE_CHANGE_FAILURE;
 			}
 
-			g_object_set (src->souphttpsrc, "extra-headers", headers, NULL);
-			gst_structure_free (headers);
+			gst_headers = rb_daap_src_soup_message_headers_to_gst_structure
+					(headers);
+			if (gst_headers == NULL) {
+				return GST_STATE_CHANGE_FAILURE;
+			}
+			soup_message_headers_free (headers);
+
+			g_object_set (src->souphttpsrc, "extra-headers", gst_headers, NULL);
+			gst_structure_free (gst_headers);
 
 			/* Set daap://... URI as http:// on souphttpsrc to ready connection. */
 			httpuri = g_strdup (src->daap_uri);
diff --git a/plugins/daap/rb-dmap-container-db-adapter.c b/plugins/daap/rb-dmap-container-db-adapter.c
new file mode 100644
index 0000000..0f3e640
--- /dev/null
+++ b/plugins/daap/rb-dmap-container-db-adapter.c
@@ -0,0 +1,193 @@
+/*
+ *  Container / Playlist database adapter class for DMAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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.
+ *
+ */
+
+#include "rb-playlist-manager.h"
+#include "rb-playlist-source.h"
+#include "rb-dmap-container-db-adapter.h"
+#include "rb-daap-container-record.h"
+
+#include <libdmapsharing/dmap.h>
+
+static guint next_playlist_id = 2;
+
+struct RBDMAPContainerDbAdapterPrivate {
+	RBPlaylistManager *playlist_manager;
+};
+
+typedef struct ForeachAdapterData {
+	gpointer data;
+	GHFunc func;
+} ForeachAdapterData;
+
+static guint find_by_id (gconstpointer a, gconstpointer b)
+{
+	return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (a), "daap_id")) != GPOINTER_TO_UINT (b);
+
+}
+
+static DMAPContainerRecord *
+rb_dmap_container_db_adapter_lookup_by_id (DMAPContainerDb *db, guint id)
+{
+	gchar *name;
+	GList *playlists;
+	DMAPContainerRecord *fnval = NULL;
+
+	playlists = rb_playlist_manager_get_playlists (RB_DMAP_CONTAINER_DB_ADAPTER (db)->priv->playlist_manager);
+
+	if (playlists != NULL && playlists->data != NULL) {
+		GList *result;
+		result = g_list_find_custom (playlists, GINT_TO_POINTER (id), (GCompareFunc) find_by_id);
+		if (result != NULL && result->data != NULL) {
+			RBPlaylistSource *source;
+			source = RB_PLAYLIST_SOURCE (result->data);
+			g_object_get (source, "name", &name, NULL);
+			fnval = DMAP_CONTAINER_RECORD (rb_daap_container_record_new (name, source));
+		}
+	}
+
+	g_list_free (playlists);
+
+	return fnval;
+}
+
+static void
+foreach_adapter (RBPlaylistSource *entry, gpointer data)
+{
+	gchar *name;
+	DMAPContainerRecord *record;
+	ForeachAdapterData *foreach_adapter_data;
+
+	foreach_adapter_data = data;
+	g_object_get (entry, "name", &name, NULL);
+	record = DMAP_CONTAINER_RECORD (rb_daap_container_record_new (name, entry));
+
+	foreach_adapter_data->func (GINT_TO_POINTER (rb_daap_container_record_get_id (record)),
+				    record,
+				    foreach_adapter_data->data);
+
+	g_object_unref (record);
+}
+
+static void
+rb_dmap_container_db_adapter_foreach	(DMAPContainerDb *db,
+					 GHFunc func,
+				         gpointer data)
+{
+	ForeachAdapterData *foreach_adapter_data;
+	GList *playlists;
+
+	playlists = rb_playlist_manager_get_playlists (RB_DMAP_CONTAINER_DB_ADAPTER (db)->priv->playlist_manager);
+
+	foreach_adapter_data = g_new (ForeachAdapterData, 1);
+	foreach_adapter_data->data = data;
+	foreach_adapter_data->func = func;
+	g_list_foreach (playlists, (GFunc) foreach_adapter, foreach_adapter_data);
+
+	g_list_free (playlists);
+	g_free (foreach_adapter_data);
+}
+
+static gint64
+rb_dmap_container_db_adapter_count (DMAPContainerDb *db)
+{
+	gint64 count = 0;
+	GList *playlists = rb_playlist_manager_get_playlists (
+		RB_DMAP_CONTAINER_DB_ADAPTER (db)->priv->playlist_manager);
+	count = g_list_length (playlists);
+	g_list_free (playlists);
+	return count;
+}
+
+static void
+rb_dmap_container_db_adapter_init (RBDMAPContainerDbAdapter *db)
+{
+	db->priv = RB_DMAP_CONTAINER_DB_ADAPTER_GET_PRIVATE (db);
+}
+
+static void
+rb_dmap_container_db_adapter_class_init (RBDMAPContainerDbAdapterClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (RBDMAPContainerDbAdapterPrivate));
+}
+
+static void
+rb_dmap_container_db_adapter_interface_init (gpointer iface, gpointer data)
+{
+	DMAPContainerDbInterface *dmap_db = iface;
+
+	g_assert (G_TYPE_FROM_INTERFACE (dmap_db) == TYPE_DMAP_CONTAINER_DB);
+
+	dmap_db->lookup_by_id = rb_dmap_container_db_adapter_lookup_by_id;
+	dmap_db->foreach = rb_dmap_container_db_adapter_foreach;
+	dmap_db->count = rb_dmap_container_db_adapter_count;
+}
+
+G_DEFINE_TYPE_WITH_CODE (RBDMAPContainerDbAdapter, rb_dmap_container_db_adapter, G_TYPE_OBJECT, 
+			 G_IMPLEMENT_INTERFACE (TYPE_DMAP_CONTAINER_DB, rb_dmap_container_db_adapter_interface_init))
+
+static void
+assign_id (RBPlaylistManager *mgr,
+	   RBSource *source)
+{
+	if (g_object_get_data (G_OBJECT (source), "daap_id") == NULL)
+		g_object_set_data (G_OBJECT (source), "daap_id", GUINT_TO_POINTER (next_playlist_id++));
+}
+
+RBDMAPContainerDbAdapter *
+rb_dmap_container_db_adapter_new (RBPlaylistManager *playlist_manager)
+{
+	RBDMAPContainerDbAdapter *db;
+	GList *playlists;
+	
+	playlists = rb_playlist_manager_get_playlists (playlist_manager);
+
+	/* These IDs are DAAP-specific, so they are not a part of the
+	 * general-purpose RBPlaylistSource class:
+	 */
+	if (playlists != NULL && playlists->data != NULL) {
+		g_list_foreach (playlists, (GFunc) assign_id, NULL);
+	}
+	
+	g_signal_connect (G_OBJECT (playlist_manager),
+			 "playlist_created",
+			  G_CALLBACK (assign_id),
+			  NULL);
+	
+	g_signal_connect (G_OBJECT (playlist_manager),
+			 "playlist_added",
+			  G_CALLBACK (assign_id),
+			  NULL);
+
+	db = RB_DMAP_CONTAINER_DB_ADAPTER (g_object_new (RB_TYPE_DMAP_CONTAINER_DB_ADAPTER,
+					       NULL));
+
+	db->priv->playlist_manager = playlist_manager;
+
+	return db;
+}
diff --git a/plugins/daap/rb-dmap-container-db-adapter.h b/plugins/daap/rb-dmap-container-db-adapter.h
new file mode 100644
index 0000000..160c80c
--- /dev/null
+++ b/plugins/daap/rb-dmap-container-db-adapter.h
@@ -0,0 +1,64 @@
+/*
+ *  Container / playlist database adapter class for DMAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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_DMAP_CONTAINER_DB_ADAPTER
+#define __RB_DMAP_CONTAINER_DB_ADAPTER
+
+#include <libdmapsharing/dmap.h>
+
+#include "rb-playlist-manager.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DMAP_CONTAINER_DB_ADAPTER         (rb_dmap_container_db_adapter_get_type ())
+#define RB_DMAP_CONTAINER_DB_ADAPTER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DMAP_CONTAINER_DB_ADAPTER, RBDMAPContainerDbAdapter))
+#define RB_DMAP_CONTAINER_DB_ADAPTER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DMAP_CONTAINER_DB_ADAPTER, RBDMAPContainerDbAdapterClass))
+#define RB_IS_DMAP_CONTAINER_DB_ADAPTER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DMAP_CONTAINER_DB_ADAPTER))
+#define RB_IS_DMAP_CONTAINER_DB_ADAPTER_CLASS (k) (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DMAP_CONTAINER_DB_ADAPTER_CLASS))
+#define RB_DMAP_CONTAINER_DB_ADAPTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DMAP_CONTAINER_DB_ADAPTER, RBDMAPContainerDbAdapterClass))
+#define RB_DMAP_CONTAINER_DB_ADAPTER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DMAP_CONTAINER_DB_ADAPTER, RBDMAPContainerDbAdapterPrivate))
+
+typedef struct RBDMAPContainerDbAdapterPrivate RBDMAPContainerDbAdapterPrivate;
+
+typedef struct {
+	GObject parent;
+	RBDMAPContainerDbAdapterPrivate *priv;
+} RBDMAPContainerDbAdapter;
+
+typedef struct {
+	GObjectClass parent;
+} RBDMAPContainerDbAdapterClass;
+
+RBDMAPContainerDbAdapter *rb_dmap_container_db_adapter_new (
+				RBPlaylistManager *playlist_manager);
+GType rb_dmap_container_db_adapter_get_type (void);
+
+#endif /* _RB_DMAP_CONTAINER_DB_ADAPTER */
+
+G_END_DECLS
diff --git a/plugins/daap/rb-rhythmdb-dmap-db-adapter.c b/plugins/daap/rb-rhythmdb-dmap-db-adapter.c
new file mode 100644
index 0000000..b4370ce
--- /dev/null
+++ b/plugins/daap/rb-rhythmdb-dmap-db-adapter.c
@@ -0,0 +1,275 @@
+/*
+ *  Database adapter class for DMAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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.
+ *
+ */
+
+#include "rhythmdb.h"
+#include "rb-rhythmdb-dmap-db-adapter.h"
+#include "rb-daap-record.h"
+
+#include <glib/gi18n.h>
+#include <libdmapsharing/dmap.h>
+
+struct RBRhythmDBDMAPDbAdapterPrivate {
+	RhythmDB *db;
+	RhythmDBEntryType type;
+};
+
+typedef struct ForeachAdapterData {
+	gpointer data;
+	GHFunc func;
+} ForeachAdapterData;
+
+static DMAPRecord *
+rb_rhythmdb_dmap_db_adapter_lookup_by_id (const DMAPDb *db, guint id)
+{
+	RhythmDBEntry *entry;
+
+	g_assert (RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db != NULL);
+
+	entry = rhythmdb_entry_lookup_by_id (
+			RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db,
+			id);
+
+	return DMAP_RECORD (rb_daap_record_new (entry));
+}
+
+static void
+foreach_adapter (RhythmDBEntry *entry, gpointer data)
+{
+	ulong id;
+	DMAPRecord *record;
+	ForeachAdapterData *foreach_adapter_data;
+	
+	id = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_ENTRY_ID);
+	foreach_adapter_data = data;
+	record = DMAP_RECORD (rb_daap_record_new (entry));
+
+	foreach_adapter_data->func (GUINT_TO_POINTER (id),
+				    record,
+				    foreach_adapter_data->data);
+
+	g_object_unref (record);
+}
+
+static void
+rb_rhythmdb_dmap_db_adapter_foreach	(const DMAPDb *db,
+					 GHFunc func,
+				         gpointer data)
+{
+	ForeachAdapterData *foreach_adapter_data;
+
+	g_assert (RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db != NULL);
+
+	foreach_adapter_data = g_new (ForeachAdapterData, 1);
+	foreach_adapter_data->data = data;
+	foreach_adapter_data->func = func;
+
+	rhythmdb_entry_foreach_by_type (RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db,
+					RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->type,
+				       (GFunc) foreach_adapter,
+				        foreach_adapter_data);
+
+	g_free (foreach_adapter_data);
+}
+
+static gint64
+rb_rhythmdb_dmap_db_adapter_count (const DMAPDb *db)
+{
+	g_assert (RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db != NULL);
+	return rhythmdb_entry_count_by_type (
+			RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db,
+			RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->type);
+}
+
+static void
+entry_set_string_prop (RhythmDB        *db,
+                       RhythmDBEntry   *entry,
+                       RhythmDBPropType propid,
+                       const char      *str)
+{
+        GValue value = {0,};
+        const gchar *tmp;
+
+        if (str == NULL || *str == '\0' || !g_utf8_validate (str, -1, NULL)) {
+                tmp = _("Unknown");
+        } else {
+                tmp = str;
+        }
+
+        g_value_init (&value, G_TYPE_STRING);
+        g_value_set_string (&value, tmp);
+        rhythmdb_entry_set (RHYTHMDB (db), entry, propid, &value);
+        g_value_unset (&value);
+}
+
+static guint
+rb_rhythmdb_dmap_db_adapter_add (DMAPDb *db, DMAPRecord *record)
+{
+	gchar *uri = NULL;
+	const gchar *title = NULL;
+	const gchar *album = NULL;
+	const gchar *artist = NULL;
+	const gchar *format = NULL;
+	const gchar *genre = NULL;
+	gint length = 0;
+	gint track = 0;
+	gint disc = 0;
+	gint year = 0;
+	gint filesize = 0;
+	gint bitrate = 0;
+	GValue value = { 0, };
+	RhythmDBEntry *entry = NULL;
+	RBRhythmDBDMAPDbAdapterPrivate *priv = RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv;
+
+	g_assert (priv->db != NULL);
+
+	g_object_get (record,
+		     "location", &uri,
+		     "year", &year,
+                     "track", &track,
+                     "disc", &disc,
+                     "bitrate", &bitrate,
+                     "duration", &length,
+                     "filesize", &filesize,
+		     "format", &format,
+                     "title", &title,
+                     "daap.songalbum", &album,
+                     "daap.songartist", &artist,
+                     "daap.songgenre", &genre,
+		      NULL);
+
+	entry = rhythmdb_entry_new (priv->db, priv->type, uri);
+
+	if (entry == NULL) {
+		g_warning ("cannot create entry for daap track %s", uri);
+		return FALSE;
+	}
+
+	/* year */
+	if (year != 0) {
+		GDate date;
+		gulong julian;
+
+		/* create dummy date with given year */
+		g_date_set_dmy (&date, 1, G_DATE_JANUARY, year);
+		julian = g_date_get_julian (&date);
+
+		g_value_init (&value, G_TYPE_ULONG);
+		g_value_set_ulong (&value,julian);
+		rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_DATE, &value);
+		g_value_unset (&value);
+	}
+
+	/* track number */
+	g_value_init (&value, G_TYPE_ULONG);
+	g_value_set_ulong (&value,(gulong)track);
+	rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_TRACK_NUMBER, &value);
+	g_value_unset (&value);
+
+	/* disc number */
+	g_value_init (&value, G_TYPE_ULONG);
+	g_value_set_ulong (&value,(gulong)disc);
+	rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_DISC_NUMBER, &value);
+	g_value_unset (&value);
+
+	/* bitrate */
+	g_value_init (&value, G_TYPE_ULONG);
+	g_value_set_ulong (&value,(gulong)bitrate);
+	rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_BITRATE, &value);
+	g_value_unset (&value);
+
+	/* length */
+	g_value_init (&value, G_TYPE_ULONG);
+	g_value_set_ulong (&value,(gulong)length);
+	rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_DURATION, &value);
+	g_value_unset (&value);
+
+	/* file size */
+	g_value_init (&value, G_TYPE_UINT64);
+	g_value_set_uint64(&value,(gint64)filesize);
+	rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_FILE_SIZE, &value);
+	g_value_unset (&value);
+
+	/* title */
+	entry_set_string_prop (priv->db, entry, RHYTHMDB_PROP_TITLE, title);
+
+	/* album */
+	entry_set_string_prop (priv->db, entry, RHYTHMDB_PROP_ALBUM, album);
+
+	/* artist */
+	entry_set_string_prop (priv->db, entry, RHYTHMDB_PROP_ARTIST, artist);
+
+	/* genre */
+	entry_set_string_prop (priv->db, entry, RHYTHMDB_PROP_GENRE, genre);
+
+	rhythmdb_commit (priv->db);
+
+	return rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_ENTRY_ID);
+}
+
+static void
+rb_rhythmdb_dmap_db_adapter_init (RBRhythmDBDMAPDbAdapter *db)
+{
+	db->priv = RB_RHYTHMDB_DMAP_DB_ADAPTER_GET_PRIVATE (db);
+}
+
+static void
+rb_rhythmdb_dmap_db_adapter_class_init (RBRhythmDBDMAPDbAdapterClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (RBRhythmDBDMAPDbAdapterPrivate));
+}
+
+static void
+rb_rhythmdb_dmap_db_adapter_interface_init (gpointer iface, gpointer data)
+{
+	DMAPDbInterface *dmap_db = iface;
+
+	g_assert (G_TYPE_FROM_INTERFACE (dmap_db) == TYPE_DMAP_DB);
+
+	dmap_db->add = rb_rhythmdb_dmap_db_adapter_add;
+	dmap_db->lookup_by_id = rb_rhythmdb_dmap_db_adapter_lookup_by_id;
+	dmap_db->foreach = rb_rhythmdb_dmap_db_adapter_foreach;
+	dmap_db->count = rb_rhythmdb_dmap_db_adapter_count;
+}
+
+G_DEFINE_TYPE_WITH_CODE (RBRhythmDBDMAPDbAdapter, rb_rhythmdb_dmap_db_adapter, G_TYPE_OBJECT, 
+			 G_IMPLEMENT_INTERFACE (TYPE_DMAP_DB, rb_rhythmdb_dmap_db_adapter_interface_init))
+
+RBRhythmDBDMAPDbAdapter *
+rb_rhythmdb_dmap_db_adapter_new (RhythmDB *rdb, RhythmDBEntryType type)
+{
+	RBRhythmDBDMAPDbAdapter *db;
+
+	db = RB_RHYTHMDB_DMAP_DB_ADAPTER (g_object_new (RB_TYPE_DMAP_DB_ADAPTER,
+					       NULL));
+
+	db->priv->db = rdb;
+	db->priv->type = type;
+
+	return db;
+}
diff --git a/plugins/daap/rb-rhythmdb-dmap-db-adapter.h b/plugins/daap/rb-rhythmdb-dmap-db-adapter.h
new file mode 100644
index 0000000..536718d
--- /dev/null
+++ b/plugins/daap/rb-rhythmdb-dmap-db-adapter.h
@@ -0,0 +1,61 @@
+/*
+ *  Database adapter class for DMAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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_RHYTHMDB_DMAP_DB_ADAPTER
+#define __RB_RHYTHMDB_DMAP_DB_ADAPTER
+
+#include <libdmapsharing/dmap.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DMAP_DB_ADAPTER         (rb_rhythmdb_dmap_db_adapter_get_type ())
+#define RB_RHYTHMDB_DMAP_DB_ADAPTER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DMAP_DB_ADAPTER, RBRhythmDBDMAPDbAdapter))
+#define RB_RHYTHMDB_DMAP_DB_ADAPTER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DMAP_DB_ADAPTER, RBRhythmDBDMAPDbAdapterClass))
+#define RB_IS_DMAP_DB_ADAPTER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DMAP_DB_ADAPTER))
+#define RB_IS_DMAP_DB_ADAPTER_CLASS (k) (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DMAP_DB_ADAPTER_CLASS))
+#define RB_RHYTHMDB_DMAP_DB_ADAPTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DMAP_DB_ADAPTER, RBRhythmDBDMAPDbAdapterClass))
+#define RB_RHYTHMDB_DMAP_DB_ADAPTER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DMAP_DB_ADAPTER, RBRhythmDBDMAPDbAdapterPrivate))
+
+typedef struct RBRhythmDBDMAPDbAdapterPrivate RBRhythmDBDMAPDbAdapterPrivate;
+
+typedef struct {
+	GObject parent;
+	RBRhythmDBDMAPDbAdapterPrivate *priv;
+} RBRhythmDBDMAPDbAdapter;
+
+typedef struct {
+	GObjectClass parent;
+} RBRhythmDBDMAPDbAdapterClass;
+
+RBRhythmDBDMAPDbAdapter *rb_rhythmdb_dmap_db_adapter_new (RhythmDB *db, RhythmDBEntryType type);
+GType rb_rhythmdb_dmap_db_adapter_get_type (void);
+
+#endif /* _RB_RHYTHMDB_DMAP_DB_ADAPTER */
+
+G_END_DECLS
diff --git a/plugins/daap/rb-rhythmdb-query-model-dmap-db-adapter.c b/plugins/daap/rb-rhythmdb-query-model-dmap-db-adapter.c
new file mode 100644
index 0000000..9607a39
--- /dev/null
+++ b/plugins/daap/rb-rhythmdb-query-model-dmap-db-adapter.c
@@ -0,0 +1,156 @@
+/*
+ *  Database adapter class for DMAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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.
+ *
+ */
+
+#include "rhythmdb-query-model.h"
+#include "rb-rhythmdb-query-model-dmap-db-adapter.h"
+#include "rb-daap-record.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <libdmapsharing/dmap.h>
+
+struct RBRhythmDBQueryModelDMAPDbAdapterPrivate {
+	RhythmDBQueryModel *model;
+};
+
+typedef struct ForeachAdapterData {
+	gpointer data;
+	GHFunc func;
+} ForeachAdapterData;
+
+static DMAPRecord *
+rb_rhythmdb_query_model_dmap_db_adapter_lookup_by_id (const DMAPDb *db,
+						      guint id)
+{
+	g_error ("Not implemented");
+	return NULL;
+}
+
+static gboolean
+foreach_adapter (GtkTreeModel *model,
+		 GtkTreePath *path,
+		 GtkTreeIter *iter,
+		 gpointer data)
+{
+	ulong id;
+	DMAPRecord *record;
+	RhythmDBEntry *entry;
+	ForeachAdapterData *foreach_adapter_data;
+
+	gtk_tree_model_get (model, iter, 0, &entry, -1);
+	
+	id = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_ENTRY_ID);
+	foreach_adapter_data = data;
+	record = DMAP_RECORD (rb_daap_record_new (entry));
+
+	foreach_adapter_data->func (GUINT_TO_POINTER (id),
+				    record,
+				    foreach_adapter_data->data);
+
+	g_object_unref (record);
+	rhythmdb_entry_unref (entry);
+
+	return FALSE;
+}
+
+static void
+rb_rhythmdb_query_model_dmap_db_adapter_foreach	(const DMAPDb *db,
+					 GHFunc func,
+				         gpointer data)
+{
+	ForeachAdapterData *foreach_adapter_data;
+
+	g_assert (RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER (db)->priv->model != NULL);
+
+	foreach_adapter_data = g_new (ForeachAdapterData, 1);
+	foreach_adapter_data->data = data;
+	foreach_adapter_data->func = func;
+
+	gtk_tree_model_foreach (GTK_TREE_MODEL (RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER (db)->priv->model),
+			       (GtkTreeModelForeachFunc) foreach_adapter,
+				foreach_adapter_data);
+
+	g_free (foreach_adapter_data);
+}
+
+static gint64
+rb_rhythmdb_query_model_dmap_db_adapter_count (const DMAPDb *db)
+{
+	g_assert (RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER (db)->priv->model != NULL); 
+	return gtk_tree_model_iter_n_children (
+		GTK_TREE_MODEL (RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER (db)->priv->model), NULL);
+}
+
+static guint
+rb_rhythmdb_query_model_dmap_db_adapter_add (DMAPDb *db, DMAPRecord *record)
+{
+	g_error ("Not implemented");
+	return 0;
+}
+
+static void
+rb_rhythmdb_query_model_dmap_db_adapter_init (RBRhythmDBQueryModelDMAPDbAdapter *db)
+{
+	db->priv = RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER_GET_PRIVATE (db);
+}
+
+static void
+rb_rhythmdb_query_model_dmap_db_adapter_class_init (RBRhythmDBQueryModelDMAPDbAdapterClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (RBRhythmDBQueryModelDMAPDbAdapterPrivate));
+}
+
+static void
+rb_rhythmdb_query_model_dmap_db_adapter_interface_init (gpointer iface, gpointer data)
+{
+	DMAPDbInterface *dmap_db = iface;
+
+	g_assert (G_TYPE_FROM_INTERFACE (dmap_db) == TYPE_DMAP_DB);
+
+	dmap_db->add = rb_rhythmdb_query_model_dmap_db_adapter_add;
+	dmap_db->lookup_by_id = rb_rhythmdb_query_model_dmap_db_adapter_lookup_by_id;
+	dmap_db->foreach = rb_rhythmdb_query_model_dmap_db_adapter_foreach;
+	dmap_db->count = rb_rhythmdb_query_model_dmap_db_adapter_count;
+}
+
+G_DEFINE_TYPE_WITH_CODE (RBRhythmDBQueryModelDMAPDbAdapter, rb_rhythmdb_query_model_dmap_db_adapter, G_TYPE_OBJECT, 
+			 G_IMPLEMENT_INTERFACE (TYPE_DMAP_DB, rb_rhythmdb_query_model_dmap_db_adapter_interface_init))
+
+RBRhythmDBQueryModelDMAPDbAdapter *
+rb_rhythmdb_query_model_dmap_db_adapter_new (RhythmDBQueryModel *model)
+{
+	RBRhythmDBQueryModelDMAPDbAdapter *db;
+
+	db = RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER (g_object_new (RB_TYPE_DMAP_DB_ADAPTER,
+					       NULL));
+
+	db->priv->model = model;
+
+	return db;
+}
diff --git a/plugins/daap/rb-rhythmdb-query-model-dmap-db-adapter.h b/plugins/daap/rb-rhythmdb-query-model-dmap-db-adapter.h
new file mode 100644
index 0000000..d35147a
--- /dev/null
+++ b/plugins/daap/rb-rhythmdb-query-model-dmap-db-adapter.h
@@ -0,0 +1,61 @@
+/*
+ *  Database adapter class for DMAP sharing
+ *
+ *  Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER
+#define __RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER
+
+#include <libdmapsharing/dmap.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DMAP_DB_ADAPTER         (rb_rhythmdb_query_model_dmap_db_adapter_get_type ())
+#define RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DMAP_DB_ADAPTER, RBRhythmDBQueryModelDMAPDbAdapter))
+#define RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DMAP_DB_ADAPTER, RBRhythmDBQueryModelDMAPDbAdapterClass))
+#define RB_IS_DMAP_DB_ADAPTER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DMAP_DB_ADAPTER))
+#define RB_IS_DMAP_DB_ADAPTER_CLASS (k) (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DMAP_DB_ADAPTER_CLASS))
+#define RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DMAP_DB_ADAPTER, RBRhythmDBQueryModelDMAPDbAdapterClass))
+#define RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DMAP_DB_ADAPTER, RBRhythmDBQueryModelDMAPDbAdapterPrivate))
+
+typedef struct RBRhythmDBQueryModelDMAPDbAdapterPrivate RBRhythmDBQueryModelDMAPDbAdapterPrivate;
+
+typedef struct {
+	GObject parent;
+	RBRhythmDBQueryModelDMAPDbAdapterPrivate *priv;
+} RBRhythmDBQueryModelDMAPDbAdapter;
+
+typedef struct {
+	GObjectClass parent;
+} RBRhythmDBQueryModelDMAPDbAdapterClass;
+
+RBRhythmDBQueryModelDMAPDbAdapter *rb_rhythmdb_query_model_dmap_db_adapter_new (RhythmDBQueryModel *db);
+GType rb_rhythmdb_query_model_dmap_db_adapter_get_type (void);
+
+#endif /* _RB_RHYTHMDB_QUERY_MODEL_DMAP_DB_ADAPTER */
+
+G_END_DECLS



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