rhythmbox r5879 - in trunk: . plugins/audiocd



Author: hadess
Date: Fri Sep  5 00:38:27 2008
New Revision: 5879
URL: http://svn.gnome.org/viewvc/rhythmbox?rev=5879&view=rev

Log:
2008-09-05  Bastien Nocera  <hadess hadess net>

	* configure.ac:
	* plugins/audiocd/Makefile.am:
	* plugins/audiocd/rb-audiocd-source.c (metadata_cb),
	(metadata_cancelled_cb), (rb_audiocd_load_metadata),
	(rb_audiocd_is_volume_audiocd):
	* plugins/audiocd/sj-*.[ch]:
	* plugins/audiocd/update-from-egg.sh: Update from sound-juicer
	trunk, adds CD-Text support via gvfs trunk, and Musicbrainz3
	(Closes: #550481)



Added:
   trunk/plugins/audiocd/sj-metadata-getter.c
   trunk/plugins/audiocd/sj-metadata-getter.h
   trunk/plugins/audiocd/sj-metadata-musicbrainz3.c
   trunk/plugins/audiocd/sj-metadata-musicbrainz3.h
   trunk/plugins/audiocd/update-from-egg.sh   (contents, props changed)
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/plugins/audiocd/Makefile.am
   trunk/plugins/audiocd/rb-audiocd-source.c
   trunk/plugins/audiocd/sj-error.c
   trunk/plugins/audiocd/sj-error.h
   trunk/plugins/audiocd/sj-metadata-musicbrainz.c
   trunk/plugins/audiocd/sj-metadata-musicbrainz.h
   trunk/plugins/audiocd/sj-metadata.c
   trunk/plugins/audiocd/sj-metadata.h
   trunk/plugins/audiocd/sj-structures.c
   trunk/plugins/audiocd/sj-structures.h

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Fri Sep  5 00:38:27 2008
@@ -438,10 +438,16 @@
 	RHYTHMBOX_CFLAGS="$RHYTHMBOX_CFLAGS $MUSICBRAINZ_CFLAGS"
 	RHYTHMBOX_LIBS="$RHYTHMBOX_LIBS $MUSICBRAINZ_LIBS"
 	AC_DEFINE(HAVE_MUSICBRAINZ, 1, [define if you have Musicbrainz])
+
+	PKG_CHECK_MODULES(MUSICBRAINZ3, libmusicbrainz3, [have_mb3=yes], [have_mb3=no])
+	AC_SUBST(MUSICBRAINZ3_CFLAGS)
+	AC_SUBST(MUSICBRAINZ3_LIBS)
+	if test "$have_mb3" = "yes" ; then
+		AC_DEFINE([HAVE_MUSICBRAINZ3], 1, [Whether libmusicbrainz3 is available])
+	fi
 fi
 AM_CONDITIONAL(HAVE_MUSICBRAINZ, test "x$enable_musicbrainz" = "xyes")
-
-
+AM_CONDITIONAL([HAVE_MUSICBRAINZ3], [test "x$have_mb3" = "xyes"])
 
 AC_PATH_XTRA
 CFLAGS="$CFLAGS $X_CFLAGS"

Modified: trunk/plugins/audiocd/Makefile.am
==============================================================================
--- trunk/plugins/audiocd/Makefile.am	(original)
+++ trunk/plugins/audiocd/Makefile.am	Fri Sep  5 00:38:27 2008
@@ -6,17 +6,19 @@
 	rb-audiocd-source.c				\
 	rb-audiocd-source.h
 
-libaudiocd_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) $(LIBNAUTILUS_BURN_LIBS) $(MUSICBRAINZ_LIBS)
+libaudiocd_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
 
 libaudiocd_la_LIBADD = \
 	$(top_builddir)/corelib/librhythmbox-core.la \
-	$(HAL_LIBS)                  \
 	$(TOTEM_PLPARSER_LIBS)       \
 	$(LIBNAUTILUS_BURN_LIBS)
 
 if HAVE_MUSICBRAINZ
 libaudiocd_la_LIBADD += $(MUSICBRAINZ_LIBS)
 endif
+if HAVE_MUSICBRAINZ3
+libaudiocd_la_LIBADD +=$(MUSICBRAINZ3_LIBS)
+endif
 
 libaudiocd_la_LIBADD += $(NULL)
 
@@ -41,9 +43,10 @@
 	-DSHARE_DIR=\"$(pkgdatadir)\"                   \
 	-DDATADIR=\""$(datadir)"\"			\
 	$(TOTEM_PLPARSER_CFLAGS)			\
-	$(HAL_CFLAGS)					\
 	$(RHYTHMBOX_CFLAGS)				\
+	$(MUSICBRAINZ_CFLAGS) $(MUSICBRAINZ3_CFLAGS)	\
 	$(LIBNAUTILUS_BURN_CFLAGS)			\
+	-DUSE_TOTEM_PL_PARSER				\
 	-D_XOPEN_SOURCE -D_BSD_SOURCE
 
 gladedir = $(plugindir)
@@ -60,16 +63,36 @@
 
 EXTRA_DIST = $(glade_DATA) $(uixml_DATA) $(plugin_in_files) sj-metadata-marshal.list
 
+SJ_FILES =									\
+	sj-error.c sj-error.h							\
+	sj-metadata.c sj-metadata.h						\
+	sj-metadata-gvfs.c sj-metadata-gvfs.h					\
+	sj-metadata-getter.c sj-metadata-getter.h				\
+	sj-metadata-musicbrainz3.c sj-metadata-musicbrainz3.h			\
+	sj-metadata-musicbrainz.c sj-metadata-musicbrainz.h			\
+	sj-structures.c sj-structures.h						\
+	sj-metadata-marshal.list
+
+EGGDIR=$(srcdir)/../../../sound-juicer/libjuicer
+regenerate-built-sources:
+	EGGFILES="$(SJ_FILES)" EGGDIR="$(EGGDIR)" $(srcdir)/update-from-egg.sh || true
+
 MARSHALFILES = 
 
 if HAVE_MUSICBRAINZ
-libaudiocd_la_SOURCES += \
-	sj-metadata.h sj-metadata.c \
-	sj-metadata-musicbrainz.h sj-metadata-musicbrainz.c \
-	sj-structures.h sj-structures.c \
-	sj-error.h sj-error.c \
+libaudiocd_la_SOURCES +=							\
+	sj-metadata.h sj-metadata.c						\
+	sj-metadata-getter.c sj-metadata-getter.h				\
+	sj-metadata-musicbrainz.h sj-metadata-musicbrainz.c			\
+	sj-metadata-gvfs.c sj-metadata-gvfs.h					\
+	sj-structures.h sj-structures.c						\
+	sj-error.h sj-error.c							\
 	$(MARSHALFILES)
 
+if HAVE_MUSICBRAINZ3
+libaudiocd_la_SOURCES += sj-metadata-musicbrainz3.c sj-metadata-musicbrainz3.h
+endif
+
 MARSHALFILES += sj-metadata-marshal.h sj-metadata-marshal.c
 
 sj-metadata-marshal.h: sj-metadata-marshal.list

Modified: trunk/plugins/audiocd/rb-audiocd-source.c
==============================================================================
--- trunk/plugins/audiocd/rb-audiocd-source.c	(original)
+++ trunk/plugins/audiocd/rb-audiocd-source.c	Fri Sep  5 00:38:27 2008
@@ -39,24 +39,19 @@
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 #include <gst/gst.h>
-/*#include <totem-disc.h>*/
 
 #include "rb-plugin.h"
 #include "rhythmdb.h"
 #include "eel-gconf-extensions.h"
+#include "rb-shell.h"
 #include "rb-audiocd-source.h"
 #include "rb-util.h"
 #include "rb-debug.h"
 #include "rb-dialog.h"
 #include "rb-glade-helpers.h"
 
-#ifdef HAVE_HAL
-#include <libhal.h>
-#include <dbus/dbus.h>
-#endif
-
 #ifdef HAVE_MUSICBRAINZ
-#include "sj-metadata-musicbrainz.h"
+#include "sj-metadata-getter.h"
 #include "sj-structures.h"
 #endif
 
@@ -86,7 +81,7 @@
 	GstElement *fakesink;
 
 #ifdef HAVE_MUSICBRAINZ
-	SjMetadata *metadata;
+	SjMetadataGetter *metadata;
 #endif
 } RBAudioCdSourcePrivate;
 
@@ -506,7 +501,7 @@
 
 
 static void
-metadata_cb (SjMetadata *metadata,
+metadata_cb (SjMetadataGetter *metadata,
 	     GList *albums,
 	     GError *error,
 	     RBAudioCdSource *source)
@@ -549,6 +544,13 @@
 	} else
 		album = (AlbumDetails *)albums->data;
 
+	if (album->metadata_source == SOURCE_FALLBACK) {
+		g_object_unref (metadata);
+		priv->metadata = NULL;
+		g_object_unref (db);
+		return;
+	}
+
 	g_object_set (G_OBJECT (source), "name", album->title, NULL);
 
 	while (album->tracks && cd_track) {
@@ -616,7 +618,7 @@
 }
 
 static void
-metadata_cancelled_cb (SjMetadata *metadata,
+metadata_cancelled_cb (SjMetadataGetter *metadata,
 		       GList *albums,
 		       GError *error,
 		       gpointer old_source)
@@ -633,12 +635,12 @@
 #ifdef HAVE_MUSICBRAINZ
 	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
 
-	priv->metadata = (SjMetadata*)sj_metadata_musicbrainz_new ();
-	sj_metadata_set_cdrom (priv->metadata, priv->device_path);
+	priv->metadata = sj_metadata_getter_new ();
+	sj_metadata_getter_set_cdrom (priv->metadata, priv->device_path);
 
 	g_signal_connect (G_OBJECT (priv->metadata), "metadata",
 			  G_CALLBACK (metadata_cb), source);
-	sj_metadata_list_albums (priv->metadata, NULL);
+	sj_metadata_getter_list_albums (priv->metadata, NULL);
 #endif
 }
 
@@ -720,178 +722,27 @@
 	g_object_unref (db);
 }
 
-#if  0
-gboolean
-rb_audiocd_is_volume_audiocd (GVolume *volume)
-{
-	char *device_path;
-
-	device_path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
-	if (device_path != NULL) {
-		gboolean result;
-		TotemDiscMediaType media_type;
-		GError *error = NULL;
-
-		/* should we do any kind of checking before we make this call? */
-		media_type = totem_cd_detect_type (device_path, &error);
-		if (error != NULL) {
-			rb_debug ("error detecting if volume is an audio CD: %s", error->message);
-			g_error_free (error);
-			result = FALSE;
-		} else if (media_type == MEDIA_TYPE_CDDA) {
-			rb_debug ("totem-disc says this is an audio CD");
-			result = TRUE;
-		} else {
-			rb_debug ("totem-disc says this is not an audio CD");
-			result = FALSE;
-		}
-
-		g_free (device_path);
-		return result;
-	} else {
-		rb_debug ("couldn't get device path");
-		return FALSE;
-	}
-}
-#endif
-
-
-#ifdef HAVE_HAL
-
-/* copied this stuff from the generic player plugin,
- * so it should probably go somewhere common.
- */
-
-static void
-free_dbus_error (const char *what, DBusError *error)
-{
-	if (dbus_error_is_set (error)) {
-		rb_debug ("%s: dbus error: %s", what, error->message);
-		dbus_error_free (error);
-	}
-}
-
-static LibHalContext *
-get_hal_context (void)
-{
-	LibHalContext *ctx = NULL;
-	DBusConnection *conn = NULL;
-	DBusError error;
-	gboolean result = FALSE;
-
-	dbus_error_init (&error);
-	ctx = libhal_ctx_new ();
-	if (ctx == NULL)
-		return NULL;
-
-	conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
-	if (conn != NULL && !dbus_error_is_set (&error)) {
-		libhal_ctx_set_dbus_connection (ctx, conn);
-		if (libhal_ctx_init (ctx, &error))
-			result = TRUE;
-	}
-
-	if (dbus_error_is_set (&error)) {
-		free_dbus_error ("setting up hal context", &error);
-		result = FALSE;
-	}
-
-	if (!result) {
-		libhal_ctx_free (ctx);
-		ctx = NULL;
-	}
-	return ctx;
-}
-
-static void
-cleanup_hal_context (LibHalContext *ctx)
-{
-	DBusError error;
-	if (ctx == NULL)
-		return;
-
-	dbus_error_init (&error);
-	libhal_ctx_shutdown (ctx, &error);
-	libhal_ctx_free (ctx);
-	free_dbus_error ("cleaning up hal context", &error);
-}
-
-#endif
-
 gboolean
 rb_audiocd_is_volume_audiocd (GVolume *volume)
 {
 	GMount *mount;
-#ifdef HAVE_HAL
-	LibHalContext *ctx;
-	char *udi;
-	char *device_path;
-
-	/* get device path for debug purposes */
-	device_path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
-	if (device_path == NULL) {
-		device_path = g_strdup ("unknown device");
-	}
-
-	/* look at HAL properties to see if it's an audio CD */
-	udi = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_HAL_UDI);
-	if (udi != NULL) {
-		ctx = get_hal_context ();
-		if (ctx != NULL) {
-			gboolean result = FALSE;
-			DBusError error;
-			dbus_error_init (&error);
-
-			/* check if it's a disc at all */
-			if (libhal_device_query_capability (ctx, udi, "volume.disc", &error) &&
-			    !dbus_error_is_set (&error)) {
-				/* check it's a CD with audio; maybe check it's not blank? */
-				dbus_bool_t is_audio;
-
-				is_audio = libhal_device_get_property_bool (ctx, udi, "volume.disc.has_audio", &error);
-				if (dbus_error_is_set (&error)) {
-					free_dbus_error ("checking if disc has audio", &error);
-					is_audio = FALSE;
-				}
-
-				if (is_audio) {
-					rb_debug ("disc in %s is an audio CD", device_path);
-					result = TRUE;
-				} else {
-					rb_debug ("disc %s is not an audio CD", device_path);
-				}
-				
-			} else if (dbus_error_is_set (&error)) {
-				free_dbus_error ("checking volume type", &error);
-			} else {
-				rb_debug ("volume in %s is not a disc", device_path);
-			}
-
-			cleanup_hal_context (ctx);
-			return result;
-		}
-	}
-	g_free (device_path);
-	rb_debug ("HAL couldn't tell us if this is an audio CD or not");
-#endif
 
 	/* if it's mounted, we can check the mount root URI scheme */
 	mount = g_volume_get_mount (volume);
 	if (mount != NULL) {
-		GFile *mount_root;
-		char *uri_scheme;
 		gboolean result = FALSE;
+		char **types;
+		guint i;
 
-		mount_root = g_mount_get_root (mount);
-		if (mount_root != NULL) {
-			uri_scheme = g_file_get_uri_scheme (mount_root);
-			rb_debug ("URI scheme of mounted volume is %s", uri_scheme);
-			result = (strcmp (uri_scheme, "cdda") == 0);
-
-			g_free (uri_scheme);
-			g_object_unref (mount_root);
+		types = g_mount_guess_content_type_sync (mount, FALSE, NULL, NULL);
+		for (i = 0; types[i] != NULL; i++) {
+			if (g_str_equal (types[i], "x-content/audio-cdda") != FALSE) {
+				result = TRUE;
+				break;
+			}
 		}
 
+		g_strfreev (types);
 		g_object_unref (mount);
 		return result;
 	}

Modified: trunk/plugins/audiocd/sj-error.c
==============================================================================
--- trunk/plugins/audiocd/sj-error.c	(original)
+++ trunk/plugins/audiocd/sj-error.c	Fri Sep  5 00:38:27 2008
@@ -3,28 +3,21 @@
  *
  * Sound Juicer - sj-error.c
  *
- * 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 library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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 grants 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,
+ * This library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
  *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+
  * Authors: Ross Burton <ross burtonini com>
  */
 

Modified: trunk/plugins/audiocd/sj-error.h
==============================================================================
--- trunk/plugins/audiocd/sj-error.h	(original)
+++ trunk/plugins/audiocd/sj-error.h	Fri Sep  5 00:38:27 2008
@@ -3,27 +3,20 @@
  *
  * Sound Juicer - sj-error.h
  *
- * 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 library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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 grants 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,
+ * This library 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.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
  *
  * Authors: Ross Burton <ross burtonini com>
  */

Added: trunk/plugins/audiocd/sj-metadata-getter.c
==============================================================================
--- (empty file)
+++ trunk/plugins/audiocd/sj-metadata-getter.c	Fri Sep  5 00:38:27 2008
@@ -0,0 +1,263 @@
+/*
+ * sj-metadata.c
+ * Copyright (C) 2003 Ross Burton <ross burtonini com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include "sj-metadata-getter.h"
+#include "sj-metadata-marshal.h"
+#include "sj-metadata.h"
+#ifdef HAVE_MUSICBRAINZ3
+#include "sj-metadata-musicbrainz3.h"
+#endif /* HAVE_MUSICBRAINZ3 */
+#include "sj-metadata-musicbrainz.h"
+#ifdef HAVE_LIBCDIO
+#include "sj-metadata-cdtext.h"
+#endif /* HAVE_LIBCDIO */
+#include "sj-metadata-gvfs.h"
+#include "sj-error.h"
+
+enum {
+  METADATA,
+  LAST_SIGNAL
+};
+
+struct SjMetadataGetterPrivate {
+  char *url;
+  char *cdrom;
+  char *proxy_host;
+  int proxy_port;
+};
+
+struct SjMetadataGetterSignal {
+  SjMetadataGetter *mdg;
+  SjMetadata *metadata;
+  GList *albums;
+  GError *error;
+};
+
+typedef struct SjMetadataGetterPrivate SjMetadataGetterPrivate;
+typedef struct SjMetadataGetterSignal SjMetadataGetterSignal;
+
+static int signals[LAST_SIGNAL] = { 0 };
+
+static void sj_metadata_getter_finalize (GObject *object);
+static void sj_metadata_getter_init (SjMetadataGetter *mdg);
+
+G_DEFINE_TYPE(SjMetadataGetter, sj_metadata_getter, G_TYPE_OBJECT);
+
+#define GETTER_PRIVATE(o)                                            \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), SJ_TYPE_METADATA_GETTER, SjMetadataGetterPrivate))
+
+static void
+sj_metadata_getter_class_init (SjMetadataGetterClass *klass)
+{
+  GObjectClass *object_class;
+  object_class = (GObjectClass *)klass;
+
+  g_type_class_add_private (klass, sizeof (SjMetadataGetterPrivate));
+
+  object_class->finalize = sj_metadata_getter_finalize;
+
+  /* Properties */
+  signals[METADATA] = g_signal_new ("metadata",
+				    G_TYPE_FROM_CLASS (object_class),
+				    G_SIGNAL_RUN_LAST,
+				    G_STRUCT_OFFSET (SjMetadataGetterClass, metadata),
+				    NULL, NULL,
+				    metadata_marshal_VOID__POINTER_POINTER,
+				    G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+}
+
+static void
+sj_metadata_getter_finalize (GObject *object)
+{
+  SjMetadataGetterPrivate *priv = GETTER_PRIVATE (object);
+  
+  g_free (priv->url);
+  g_free (priv->cdrom);
+  g_free (priv->proxy_host);
+
+  G_OBJECT_CLASS (sj_metadata_getter_parent_class)->finalize (object);
+}
+
+static void
+sj_metadata_getter_init (SjMetadataGetter *mdg)
+{
+}
+
+SjMetadataGetter *
+sj_metadata_getter_new (void)
+{
+  return SJ_METADATA_GETTER (g_object_new (SJ_TYPE_METADATA_GETTER, NULL));
+}
+
+void
+sj_metadata_getter_set_cdrom (SjMetadataGetter *mdg, const char* device)
+{
+  SjMetadataGetterPrivate *priv;
+
+  priv = GETTER_PRIVATE (mdg);
+
+  g_free (priv->cdrom);
+
+#if defined (sun) && defined (__SVR4)
+  if (g_str_has_prefix (device, "/dev/dsk/")) {
+    priv->cdrom = g_strdup_printf ("/dev/rdsk/%s", device + strlen ("/dev/dsk/"));
+    return;
+  }
+#endif
+  priv->cdrom = g_strdup (device);
+}
+
+void
+sj_metadata_getter_set_proxy (SjMetadataGetter *mdg, const char* proxy)
+{
+  SjMetadataGetterPrivate *priv;
+
+  priv = GETTER_PRIVATE (mdg);
+
+  if (priv->proxy_host)
+    g_free (priv->proxy_host);
+  priv->proxy_host = g_strdup (proxy);
+}
+
+void
+sj_metadata_getter_set_proxy_port (SjMetadataGetter *mdg, const int proxy_port)
+{
+  SjMetadataGetterPrivate *priv;
+
+  priv = GETTER_PRIVATE (mdg);
+
+  priv->proxy_port = proxy_port;
+}
+
+static gboolean
+fire_signal_idle (SjMetadataGetterSignal *signal)
+{
+  g_signal_emit_by_name (G_OBJECT (signal->mdg), "metadata",
+  			 signal->albums, signal->error);
+
+  /* This will kill the albums, as
+   * those belong to the metadata backend */
+  if (signal->metadata)
+    g_object_unref (signal->metadata);
+  if (signal->error != NULL)
+    g_error_free (signal->error);
+  g_free (signal);
+
+  return FALSE;
+}
+
+static gpointer
+lookup_cd (SjMetadataGetter *mdg)
+{
+  SjMetadata *metadata;
+  guint i;
+  SjMetadataGetterPrivate *priv;
+  GError *error = NULL;
+  gboolean found = FALSE;
+  GType types[] = {
+#ifdef HAVE_MUSICBRAINZ3
+    SJ_TYPE_METADATA_MUSICBRAINZ3,
+#endif /* HAVE_MUSICBRAINZ3 */
+    SJ_TYPE_METADATA_MUSICBRAINZ,
+#ifdef HAVE_LIBCDIO
+    SJ_TYPE_METADATA_CDTEXT,
+#endif /* HAVE_LIBCDIO */
+    SJ_TYPE_METADATA_GVFS
+  };
+
+  priv = GETTER_PRIVATE (mdg);
+
+  g_free (priv->url);
+  priv->url = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS (types); i++) {
+    GList *albums;
+
+    metadata = g_object_new (types[i],
+    			     "device", priv->cdrom,
+    			     "proxy-host", priv->proxy_host,
+    			     "proxy-port", priv->proxy_port,
+    			     NULL);
+    if (priv->url == NULL)
+      albums = sj_metadata_list_albums (metadata, &priv->url, &error);
+    else
+      albums = sj_metadata_list_albums (metadata, NULL, &error);
+
+    if (albums != NULL) {
+      SjMetadataGetterSignal *signal;
+
+      signal = g_new0 (SjMetadataGetterSignal, 1);
+      signal->albums = albums;
+      signal->mdg = mdg;
+      signal->metadata = metadata;
+      g_idle_add ((GSourceFunc)fire_signal_idle, signal);
+      break;
+    }
+
+    g_object_unref (metadata);
+
+    if (error != NULL) {
+      SjMetadataGetterSignal *signal;
+
+      g_assert (found == FALSE);
+
+      signal = g_new0 (SjMetadataGetterSignal, 1);
+      signal->error = error;
+      signal->mdg = mdg;
+      g_idle_add ((GSourceFunc)fire_signal_idle, signal);
+      break;
+    }
+  }
+
+  return NULL;
+}
+
+gboolean
+sj_metadata_getter_list_albums (SjMetadataGetter *mdg, GError **error)
+{
+  GThread *thread;
+
+  thread = g_thread_create ((GThreadFunc)lookup_cd, mdg, TRUE, error);
+  if (thread == NULL) {
+    g_set_error (error,
+                 SJ_ERROR, SJ_ERROR_INTERNAL_ERROR,
+                 _("Could not create CD lookup thread"));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+char *
+sj_metadata_getter_get_submit_url (SjMetadataGetter *mdg)
+{
+  SjMetadataGetterPrivate *priv;
+
+  priv = GETTER_PRIVATE (mdg);
+
+  if (priv->url)
+    return g_strdup (priv->url);
+  return NULL;
+}
+

Added: trunk/plugins/audiocd/sj-metadata-getter.h
==============================================================================
--- (empty file)
+++ trunk/plugins/audiocd/sj-metadata-getter.h	Fri Sep  5 00:38:27 2008
@@ -0,0 +1,62 @@
+/*
+ * sj-metadata-getter.h
+ * Copyright (C) 2008 Bastien Nocera
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SJ_METADATA_GETTER_H
+#define SJ_METADATA_GETTER_H
+
+#include <glib-object.h>
+#include <glib/gerror.h>
+
+G_BEGIN_DECLS
+
+#define SJ_TYPE_METADATA_GETTER            (sj_metadata_getter_get_type ())
+#define SJ_METADATA_GETTER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SJ_TYPE_METADATA_GETTER, SjMetadataGetter))
+#define SJ_METADATA_GETTER_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), SJ_TYPE_METADATA_GETTER, SjMetadataGetterClass))
+#define SJ_IS_METADATA_GETTER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SJ_TYPE_METADATA_GETTER))
+#define SJ_IS_METADATA_GETTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), SJ_TYPE_METADATA_GETTER))
+#define SJ_METADATA_GETTER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), SJ_TYPE_METADATA_GETTER, SjMetadataGetterClass))
+
+struct _SjMetadataGetter
+{
+  GObject parent;
+};
+
+typedef struct _SjMetadataGetter SjMetadataGetter;
+typedef struct _SjMetadataGetterClass SjMetadataGetterClass;
+
+struct _SjMetadataGetterClass
+{
+  GObjectClass parent;
+
+  /* Signals */
+  void         (*metadata) (SjMetadataGetter *mdg, GList *albums, GError *error);
+};
+
+GType sj_metadata_getter_get_type (void);
+SjMetadataGetter *sj_metadata_getter_new (void);
+void sj_metadata_getter_set_cdrom (SjMetadataGetter *mdg, const char* device);
+void sj_metadata_getter_set_proxy (SjMetadataGetter *mdg, const char* proxy);
+void sj_metadata_getter_set_proxy_port (SjMetadataGetter *mdg, const int proxy_port);
+gboolean sj_metadata_getter_list_albums (SjMetadataGetter *mdg, GError **error);
+char *sj_metadata_getter_get_submit_url (SjMetadataGetter *mdg);
+
+G_END_DECLS
+
+#endif /* SJ_METADATA_GETTER_H */

Modified: trunk/plugins/audiocd/sj-metadata-musicbrainz.c
==============================================================================
--- trunk/plugins/audiocd/sj-metadata-musicbrainz.c	(original)
+++ trunk/plugins/audiocd/sj-metadata-musicbrainz.c	Fri Sep  5 00:38:27 2008
@@ -7,14 +7,6 @@
  * 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 grants 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 library 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
@@ -31,7 +23,6 @@
 #endif /* HAVE_CONFIG_H */
 
 #include <string.h>
-#include <stdio.h>
 #include <glib-object.h>
 #include <glib/gi18n.h>
 #include <glib/gerror.h>
@@ -42,32 +33,11 @@
 #include <musicbrainz/queries.h>
 #include <musicbrainz/mb_c.h>
 #include <stdlib.h>
-#include <unistd.h>
-
-#include <totem-disc.h>
 
 #include "sj-metadata-musicbrainz.h"
 #include "sj-structures.h"
 #include "sj-error.h"
 
-struct SjMetadataMusicbrainzPrivate {
-  GError *construct_error;
-  musicbrainz_t mb;
-  char *http_proxy;
-  int http_proxy_port;
-  char *cdrom;
-  /* TODO: remove and use an async queue or something l33t */
-  GList *albums;
-  GError *error;
-};
-
-static GError* mb_get_new_error (SjMetadata *metadata);
-static void mb_set_cdrom (SjMetadata *metadata, const char* device);
-static void mb_set_proxy (SjMetadata *metadata, const char* proxy);
-static void mb_set_proxy_port (SjMetadata *metadata, const int port);
-static void mb_list_albums (SjMetadata *metadata, GError **error);
-static char *mb_get_submit_url (SjMetadata *metadata);
-
 #define GCONF_MUSICBRAINZ_SERVER "/apps/sound-juicer/musicbrainz_server"
 #define GCONF_PROXY_USE_PROXY "/system/http_proxy/use_http_proxy"
 #define GCONF_PROXY_HOST "/system/http_proxy/host"
@@ -76,256 +46,52 @@
 #define GCONF_PROXY_USERNAME "/system/http_proxy/authentication_user"
 #define GCONF_PROXY_PASSWORD "/system/http_proxy/authentication_password"
 
-/**
- * GObject methods
- */
-
-static GObjectClass *parent_class = NULL;
-
-static void
-sj_metadata_musicbrainz_finalize (GObject *object)
-{
-  SjMetadataMusicbrainzPrivate *priv;
-  g_return_if_fail (object != NULL);
-  priv = SJ_METADATA_MUSICBRAINZ (object)->priv;
-
-  g_free (priv->http_proxy);
-  g_free (priv->cdrom);
-  mb_Delete (priv->mb);
-  g_free (priv);
-
-  parent_class->finalize (object);
-}
-
-static void
-sj_metadata_musicbrainz_instance_init (GTypeInstance *instance, gpointer g_class)
-{
-  GConfClient *gconf_client;
-  char *server_name = NULL;
-  SjMetadataMusicbrainz *self = (SjMetadataMusicbrainz*)instance;
-  self->priv = g_new0 (SjMetadataMusicbrainzPrivate, 1);
-  self->priv->construct_error = NULL;
-  self->priv->mb = mb_New ();
-  /* TODO: something. :/ */
-  if (!self->priv->mb) {
-    g_set_error (&self->priv->construct_error,
-                 SJ_ERROR, SJ_ERROR_CD_LOOKUP_ERROR,
-                 _("Cannot create MusicBrainz client"));
-    return;
-  }
-  mb_UseUTF8 (self->priv->mb, TRUE);
-
-  gconf_client = gconf_client_get_default ();
-  server_name = gconf_client_get_string (gconf_client, GCONF_MUSICBRAINZ_SERVER, NULL);
-  if (server_name) {
-    g_strstrip (server_name);
-  }
-  if (server_name && strcmp (server_name, "") != 0) {
-    mb_SetServer (self->priv->mb, server_name, 80);
-    g_free (server_name);
-  }
-  
-  /* Set the HTTP proxy */
-  if (gconf_client_get_bool (gconf_client, GCONF_PROXY_USE_PROXY, NULL)) {
-    char *proxy_host = gconf_client_get_string (gconf_client, GCONF_PROXY_HOST, NULL);
-    mb_SetProxy (self->priv->mb, proxy_host,
-                 gconf_client_get_int (gconf_client, GCONF_PROXY_PORT, NULL));
-    g_free (proxy_host);
-    if (gconf_client_get_bool (gconf_client, GCONF_PROXY_USE_AUTHENTICATION, NULL)) {
-#if HAVE_MB_SETPROXYCREDS
-      char *username = gconf_client_get_string (gconf_client, GCONF_PROXY_USERNAME, NULL);
-      char *password = gconf_client_get_string (gconf_client, GCONF_PROXY_PASSWORD, NULL);
-      mb_SetProxyCreds (self->priv->mb, username, password);
-      g_free (username);
-      g_free (password);
-#else
-      g_warning ("mb_SetProxyCreds() not found, no proxy authorisation possible.");
-#endif
-    }
-  }
 
-  g_object_unref (gconf_client);
+struct SjMetadataMusicbrainzPrivate {
+  musicbrainz_t mb;
+  char *http_proxy;
+  int http_proxy_port;
+  char *cdrom;
+  GList *albums;
+};
 
-  if (g_getenv("MUSICBRAINZ_DEBUG")) {
-    mb_SetDebug (self->priv->mb, TRUE);
-  }
-}
+#define GET_PRIVATE(o)  \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), SJ_TYPE_METADATA_MUSICBRAINZ, SjMetadataMusicbrainzPrivate))
 
-static void
-metadata_interface_init (gpointer g_iface, gpointer iface_data)
-{
-  SjMetadataClass *klass = (SjMetadataClass*)g_iface;
-  klass->get_new_error = mb_get_new_error;
-  klass->set_cdrom = mb_set_cdrom;
-  klass->set_proxy = mb_set_proxy;
-  klass->set_proxy_port = mb_set_proxy_port;
-  klass->list_albums = mb_list_albums;
-  klass->get_submit_url = mb_get_submit_url;
-}
+enum {
+  PROP_0,
+  PROP_DEVICE,
+  PROP_USE_PROXY,
+  PROP_PROXY_HOST,
+  PROP_PROXY_PORT,
+};
 
-static void
-sj_metadata_musicbrainz_class_init (SjMetadataMusicbrainzClass *class)
-{
-  GObjectClass *object_class;
-  parent_class = g_type_class_peek_parent (class);
-  object_class = (GObjectClass*) class;
-  object_class->finalize = sj_metadata_musicbrainz_finalize;
-}
+static void metadata_interface_init (gpointer g_iface, gpointer iface_data);
 
-GType
-sj_metadata_musicbrainz_get_type (void)
-{
-  static GType type = 0;
-  if (type == 0) {
-    static const GTypeInfo info = {
-      sizeof (SjMetadataMusicbrainzClass),
-      NULL,
-      NULL,
-      (GClassInitFunc)sj_metadata_musicbrainz_class_init,
-      NULL,
-      NULL,
-      sizeof (SjMetadataMusicbrainz),
-      0,
-      sj_metadata_musicbrainz_instance_init,
-      NULL
-    };
-    static const GInterfaceInfo metadata_i_info = {
-      (GInterfaceInitFunc) metadata_interface_init,
-      NULL, NULL
-    };
-    type = g_type_register_static (G_TYPE_OBJECT, "SjMetadataMusicBrainzClass", &info, 0);
-    g_type_add_interface_static (type, SJ_TYPE_METADATA, &metadata_i_info);
-  }
-  return type;
-}
+G_DEFINE_TYPE_WITH_CODE (SjMetadataMusicbrainz,
+                         sj_metadata_musicbrainz,
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (SJ_TYPE_METADATA,
+                                                metadata_interface_init));
 
-GObject *
-sj_metadata_musicbrainz_new (void)
-{
-  return g_object_new (sj_metadata_musicbrainz_get_type (), NULL);
-}
 
-/**
+/*
  * Private methods
  */
 
-#define BYTES_PER_SECTOR 2352
-#define BYTES_PER_SECOND (44100 / 8) / 16 / 2
-
 static int
 get_duration_from_sectors (int sectors)
 {
-  return (sectors * BYTES_PER_SECTOR / BYTES_PER_SECOND);
-}
-
-static GList*
-get_offline_track_listing(SjMetadata *metadata, GError **error)
-{
-  SjMetadataMusicbrainzPrivate *priv;
-  GList* list = NULL;
-  AlbumDetails *album;
-  TrackDetails *track;
-  int num_tracks, i;
-
-  g_return_val_if_fail (metadata != NULL, NULL);
-  priv = SJ_METADATA_MUSICBRAINZ (metadata)->priv;
-
-  if (!mb_Query (priv->mb, MBQ_GetCDTOC)) {
-    char message[255];
-    mb_GetQueryError (priv->mb, message, 255);
-    g_set_error (error,
-                 SJ_ERROR, SJ_ERROR_CD_LOOKUP_ERROR,
-                 _("Cannot read CD: %s"), message);
-    return NULL;
-  }
+#define BYTES_PER_SECTOR 2352
+#define BYTES_PER_SECOND (44100 / 8) / 16 / 2
   
-  num_tracks = mb_GetResultInt (priv->mb, MBE_TOCGetLastTrack);
-
-  album = g_new0 (AlbumDetails, 1);
-  album->artist = g_strdup (_("Unknown Artist"));
-  album->title = g_strdup (_("Unknown Title"));
-  album->genre = NULL;
-  for (i = 1; i <= num_tracks; i++) {
-    track = g_new0 (TrackDetails, 1);
-    track->album = album;
-    track->number = i;
-    track->title = g_strdup_printf (_("Track %d"), i);
-    track->artist = g_strdup (album->artist);
-    track->duration = get_duration_from_sectors (mb_GetResultInt1 (priv->mb, MBE_TOCGetTrackNumSectors, i+1));
-    album->tracks = g_list_append (album->tracks, track);
-    album->number++;
-  }
-  return g_list_append (list, album);
-}
-
-static gboolean
-fire_signal_idle (SjMetadataMusicbrainz *m)
-{
-  g_return_val_if_fail (SJ_IS_METADATA_MUSICBRAINZ (m), FALSE);
-  g_signal_emit_by_name (G_OBJECT (m), "metadata", m->priv->albums, m->priv->error);
-  return FALSE;
+  return (sectors * BYTES_PER_SECTOR / BYTES_PER_SECOND);
 }
 
 /**
  * Virtual methods
  */
 
-static GError*
-mb_get_new_error (SjMetadata *metadata)
-{
-  GError *error = NULL;
-  if (metadata == NULL || SJ_METADATA_MUSICBRAINZ (metadata)->priv == NULL) {
-    g_set_error (&error,
-                 SJ_ERROR, SJ_ERROR_INTERNAL_ERROR,
-                 _("MusicBrainz metadata object is not valid. This is bad, check your console for errors."));
-    return error;
-  }
-  return SJ_METADATA_MUSICBRAINZ (metadata)->priv->construct_error;
-}
-
-static void
-mb_set_cdrom (SjMetadata *metadata, const char* device)
-{
-  SjMetadataMusicbrainzPrivate *priv;
-  g_return_if_fail (metadata != NULL);
-  g_return_if_fail (device != NULL);
-  priv = SJ_METADATA_MUSICBRAINZ (metadata)->priv;
-
-  if (priv->cdrom) {
-    g_free (priv->cdrom);
-  }
-  priv->cdrom = g_strdup (device);
-  mb_SetDevice (priv->mb, priv->cdrom);
-}
-
-static void
-mb_set_proxy (SjMetadata *metadata, const char* proxy)
-{
-  SjMetadataMusicbrainzPrivate *priv;
-  g_return_if_fail (metadata != NULL);
-  priv = SJ_METADATA_MUSICBRAINZ (metadata)->priv;
-
-  if (proxy == NULL) {
-    proxy = "";
-  }
-  if (priv->http_proxy) {
-    g_free (priv->http_proxy);
-  }
-  priv->http_proxy = g_strdup (proxy);
-  mb_SetProxy (priv->mb, priv->http_proxy, priv->http_proxy_port);
-}
-
-static void
-mb_set_proxy_port (SjMetadata *metadata, const int port)
-{
-  SjMetadataMusicbrainzPrivate *priv;
-  g_return_if_fail (metadata != NULL);
-  priv = SJ_METADATA_MUSICBRAINZ (metadata)->priv;
-
-  priv->http_proxy_port = port;
-  mb_SetProxy (priv->mb, priv->http_proxy, priv->http_proxy_port);
-}
-
 /* Data imported from FreeDB is horrendeous for compilations,
  * Try to split the 'Various' artist */
 static void
@@ -333,7 +99,7 @@
 {
   char *slash, **split;
 
-  if (g_ascii_strncasecmp (MBI_VARIOUS_ARTIST_ID, track->album->artist_id, 64) != 0 && track->album->artist_id[0] != '\0' && track->artist_id[0] != '\0') {
+  if (g_ascii_strncasecmp (track->album->album_id, "freedb:", 7) != 0 && track->album->artist_id[0] != '\0' && track->artist_id[0] != '\0') {
     track->title = g_strdup (data);
     return;
   }
@@ -382,7 +148,7 @@
   g_free (rdf);
 }
 
-/*
+/**
  * Load into the MusicBrainz object the RDF from the specified cache file if it
  * exists and is valid then return TRUE, otherwise return FALSE.
  */
@@ -425,7 +191,7 @@
 }
 #endif
 
-/*
+/**
  * Fill the MusicBrainz object with RDF.  Basically get the CD Index and check
  * the local cache, if that fails then lookup the data online.
  */
@@ -476,8 +242,36 @@
   g_free (cdindex);
 }
 
-static gpointer
-lookup_cd (SjMetadata *metadata)
+/*
+ * Magic character set encoding to try and repair brain-dead FreeDB encoding,
+ * converting it to the current locale's encoding (which is likely to be the
+ * intended encoding).
+ */
+static void
+convert_encoding(char **str)
+{
+  char *iso8859;
+  char *converted;
+
+  if (str == NULL || *str == NULL)
+    return;
+
+  iso8859 = g_convert (*str, -1, "ISO-8859-1", "UTF-8", NULL, NULL, NULL);
+
+  if (iso8859) {
+    converted = g_locale_to_utf8 (iso8859, -1, NULL, NULL, NULL);
+
+    if (converted) {
+      g_free (*str);
+      *str = converted;
+    }
+  }
+
+  g_free (iso8859);
+}
+
+static GList *
+mb_list_albums (SjMetadata *metadata, char **url, GError **error)
 {
   /** The size of the buffer used in MusicBrainz lookups */
   SjMetadataMusicbrainzPrivate *priv;
@@ -485,43 +279,41 @@
   GList *al, *tl;
   char data[256];
   int num_albums, i, j;
-  TotemDiscMediaType type;
-  GError *totem_error = NULL;
 
-  /* TODO: fire error signal */
   g_return_val_if_fail (metadata != NULL, NULL);
   g_return_val_if_fail (SJ_IS_METADATA_MUSICBRAINZ (metadata), NULL);
   priv = SJ_METADATA_MUSICBRAINZ (metadata)->priv;
   g_return_val_if_fail (priv->cdrom != NULL, NULL);
-  priv->error = NULL; /* TODO: hack */
 
-  type = totem_cd_detect_type (priv->cdrom, &totem_error);
-
-  if (totem_error != NULL) {
-    priv->error = g_error_new (SJ_ERROR, SJ_ERROR_CD_NO_MEDIA, _("Cannot read CD: %s"), totem_error->message);
-    g_error_free (totem_error);
+  if (sj_metadata_helper_check_media (priv->cdrom, error) == FALSE) {
     priv->albums = NULL;
-    g_idle_add ((GSourceFunc)fire_signal_idle, metadata);
     return NULL;
   }
 
   get_rdf (metadata);
 
+  if (url != NULL) {
+    mb_GetWebSubmitURL(priv->mb, data, sizeof(data));
+    *url = g_strdup(data);
+  }
+
   num_albums = mb_GetResultInt(priv->mb, MBE_GetNumAlbums);
   if (num_albums < 1) {
-    priv->albums = get_offline_track_listing (metadata, &(priv->error));
-    g_idle_add ((GSourceFunc)fire_signal_idle, metadata);
-    return priv->albums;
+    priv->albums = NULL;
+    return NULL;
   }
 
   for (i = 1; i <= num_albums; i++) {
     int num_tracks;
     AlbumDetails *album;
+    gboolean from_freedb = FALSE;
 
     mb_Select1(priv->mb, MBS_SelectAlbum, i);
     album = g_new0 (AlbumDetails, 1);
 
     if (mb_GetResultData(priv->mb, MBE_AlbumGetAlbumId, data, sizeof (data))) {
+      from_freedb = strstr(data, "freedb:") == data;
+
       mb_GetIDFromURL (priv->mb, data, data, sizeof (data));
       album->album_id = g_strdup (data);
     }
@@ -529,37 +321,43 @@
     if (mb_GetResultData (priv->mb, MBE_AlbumGetAlbumArtistId, data, sizeof (data))) {
       mb_GetIDFromURL (priv->mb, data, data, sizeof (data));
       album->artist_id = g_strdup (data);
-      if (g_ascii_strncasecmp (MBI_VARIOUS_ARTIST_ID, data, 64) == 0) {
-        album->artist = g_strdup (_("Various"));
+
+      if (mb_GetResultData (priv->mb, MBE_AlbumGetAlbumArtistName, data, sizeof (data))) {
+        album->artist = g_strdup (data);
       } else {
-        if (*data && mb_GetResultData1(priv->mb, MBE_AlbumGetArtistName, data, sizeof (data), 1)) {
-          album->artist = g_strdup (data);
+        if (g_ascii_strcasecmp (MBI_VARIOUS_ARTIST_ID, album->artist_id) == 0) {
+          album->artist = g_strdup (_("Various"));
         } else {
           album->artist = g_strdup (_("Unknown Artist"));
         }
-        if (*data && mb_GetResultData1(priv->mb, MBE_AlbumGetArtistSortName, data, sizeof (data), 1)) {
-          album->artist_sortname = g_strdup (data);
-        }
+      }
+      if (mb_GetResultData(priv->mb, MBE_AlbumGetAlbumArtistSortName, data, sizeof (data))) {
+        album->artist_sortname = g_strdup (data);
       }
     }
 
     if (mb_GetResultData(priv->mb, MBE_AlbumGetAlbumName, data, sizeof (data))) {
-      album->title = g_strdup (data);
+      char *new_title;
+      new_title = sj_metadata_helper_scan_disc_number (data, &album->disc_number);
+      if (new_title)
+        album->title = new_title;
+      else
+        album->title = g_strdup (data);
     } else {
       album->title = g_strdup (_("Unknown Title"));
     }
 
+    if (mb_GetResultData(priv->mb, MBE_AlbumGetAmazonAsin, data, sizeof (data))) {
+      album->asin = g_strdup (data);
+    }
+
     {
       int num_releases;
       num_releases = mb_GetResultInt (priv->mb, MBE_AlbumGetNumReleaseDates);
       if (num_releases > 0) {
         mb_Select1(priv->mb, MBS_SelectReleaseDate, 1);
         if (mb_GetResultData(priv->mb, MBE_ReleaseGetDate, data, sizeof (data))) {
-          int matched, year=1, month=1, day=1;
-          matched = sscanf(data, "%u-%u-%u", &year, &month, &day);
-          if (matched >= 1) {
-            album->release_date = g_date_new_dmy ((day == 0) ? 1 : day, (month == 0) ? 1 : month, year);
-          }
+          album->release_date = sj_metadata_helper_scan_date (data);
         }
         mb_Select(priv->mb, MBS_Back);
       }
@@ -572,9 +370,8 @@
       g_free (album->title);
       g_free (album);
       g_warning (_("Incomplete metadata for this CD"));
-      priv->albums = get_offline_track_listing (metadata, &(priv->error));
-      g_idle_add ((GSourceFunc)fire_signal_idle, metadata);
-      return priv->albums;
+      priv->albums = NULL;
+      return NULL;
     }
 
     for (j = 1; j <= num_tracks; j++) {
@@ -601,6 +398,8 @@
         } else {
           track->title = g_strdup (data);
         }
+      } else {
+        track->title = g_strdup (_("[Untitled]"));
       }
 
       if (track->artist == NULL && mb_GetResultData1(priv->mb, MBE_AlbumGetArtistName, data, sizeof (data), j)) {
@@ -614,11 +413,29 @@
       if (mb_GetResultData1(priv->mb, MBE_AlbumGetTrackDuration, data, sizeof (data), j)) {
         track->duration = atoi (data) / 1000;
       }
+
+      if (from_freedb) {
+        convert_encoding(&track->title);
+        convert_encoding(&track->artist);
+        convert_encoding(&track->artist_sortname);
+      }
       
       album->tracks = g_list_append (album->tracks, track);
       album->number++;
     }
 
+    if (from_freedb) {
+      convert_encoding(&album->title);
+      convert_encoding(&album->artist);
+      convert_encoding(&album->artist_sortname);
+    }
+
+    if (from_freedb) {
+      album->metadata_source = SOURCE_FREEDB;
+    } else {
+      album->metadata_source = SOURCE_MUSICBRAINZ;
+    }
+
     albums = g_list_append (albums, album);
 
     mb_Select (priv->mb, MBS_Rewind);
@@ -646,40 +463,157 @@
     }
   }
 
-  priv->albums = albums;
-  g_idle_add ((GSourceFunc)fire_signal_idle, metadata);
   return albums;
 }
 
+/*
+ * GObject methods
+ */
+
+static void
+metadata_interface_init (gpointer g_iface, gpointer iface_data)
+{
+  SjMetadataClass *klass = (SjMetadataClass*)g_iface;
+  klass->list_albums = mb_list_albums;
+}
+
 static void
-mb_list_albums (SjMetadata *metadata, GError **error)
+sj_metadata_musicbrainz_init (SjMetadataMusicbrainz *self)
 {
-  GThread *thread;
+  GConfClient *gconf_client;
+  char *server_name = NULL;
 
-  g_return_if_fail (SJ_IS_METADATA_MUSICBRAINZ (metadata));
+  self->priv = GET_PRIVATE (self);
+  self->priv->mb = mb_New ();
+  mb_UseUTF8 (self->priv->mb, TRUE);
 
-  thread = g_thread_create ((GThreadFunc)lookup_cd, metadata, TRUE, error);
-  if (thread == NULL) {
-    g_set_error (error,
-                 SJ_ERROR, SJ_ERROR_INTERNAL_ERROR,
-                 _("Could not create CD lookup thread"));
-    return;
+  gconf_client = gconf_client_get_default ();
+  server_name = gconf_client_get_string (gconf_client, GCONF_MUSICBRAINZ_SERVER, NULL);
+  if (server_name) {
+    g_strstrip (server_name);
+  }
+  if (server_name && strcmp (server_name, "") != 0) {
+    mb_SetServer (self->priv->mb, server_name, 80);
+    g_free (server_name);
+  }
+  
+  /* Set the HTTP proxy */
+  if (gconf_client_get_bool (gconf_client, GCONF_PROXY_USE_PROXY, NULL)) {
+    char *proxy_host = gconf_client_get_string (gconf_client, GCONF_PROXY_HOST, NULL);
+    mb_SetProxy (self->priv->mb, proxy_host,
+                 gconf_client_get_int (gconf_client, GCONF_PROXY_PORT, NULL));
+    g_free (proxy_host);
+    if (gconf_client_get_bool (gconf_client, GCONF_PROXY_USE_AUTHENTICATION, NULL)) {
+#if HAVE_MB_SETPROXYCREDS
+      char *username = gconf_client_get_string (gconf_client, GCONF_PROXY_USERNAME, NULL);
+      char *password = gconf_client_get_string (gconf_client, GCONF_PROXY_PASSWORD, NULL);
+      mb_SetProxyCreds (self->priv->mb, username, password);
+      g_free (username);
+      g_free (password);
+#else
+      g_warning ("mb_SetProxyCreds() not found, no proxy authorisation possible.");
+#endif
+    }
+  }
+
+  g_object_unref (gconf_client);
+
+  if (g_getenv("MUSICBRAINZ_DEBUG")) {
+    mb_SetDebug (self->priv->mb, TRUE);
   }
 }
 
-static char *
-mb_get_submit_url (SjMetadata *metadata)
+static void
+sj_metadata_musicbrainz_get_property (GObject *object, guint property_id,
+                                      GValue *value, GParamSpec *pspec)
+{
+  SjMetadataMusicbrainzPrivate *priv = SJ_METADATA_MUSICBRAINZ (object)->priv;
+  g_assert (priv);
+
+  switch (property_id) {
+  case PROP_DEVICE:
+    g_value_set_string (value, priv->cdrom);
+    break;
+  case PROP_PROXY_HOST:
+    g_value_set_string (value, priv->http_proxy);
+    break;
+  case PROP_PROXY_PORT:
+    g_value_set_int (value, priv->http_proxy_port);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+sj_metadata_musicbrainz_set_property (GObject *object, guint property_id,
+                                      const GValue *value, GParamSpec *pspec)
+{
+  SjMetadataMusicbrainzPrivate *priv = SJ_METADATA_MUSICBRAINZ (object)->priv;
+  g_assert (priv);
+
+  switch (property_id) {
+  case PROP_DEVICE:
+    if (priv->cdrom)
+      g_free (priv->cdrom);
+    priv->cdrom = g_value_dup_string (value);
+    if (priv->cdrom)
+      mb_SetDevice (priv->mb, priv->cdrom);
+    break;
+  case PROP_PROXY_HOST:
+    if (priv->http_proxy) {
+      g_free (priv->http_proxy);
+    }
+    priv->http_proxy = g_value_dup_string (value);
+    /* TODO: check this unsets the proxy if NULL, or should we pass "" ? */
+    mb_SetProxy (priv->mb, priv->http_proxy, priv->http_proxy_port);
+    break;
+  case PROP_PROXY_PORT:
+    priv->http_proxy_port = g_value_get_int (value);
+    mb_SetProxy (priv->mb, priv->http_proxy, priv->http_proxy_port);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+sj_metadata_musicbrainz_finalize (GObject *object)
 {
   SjMetadataMusicbrainzPrivate *priv;
-  char url[1025];
+  
+  priv = SJ_METADATA_MUSICBRAINZ (object)->priv;
 
-  g_return_val_if_fail (metadata != NULL, NULL);
+  g_free (priv->http_proxy);
+  g_free (priv->cdrom);
+  mb_Delete (priv->mb);
 
-  priv = SJ_METADATA_MUSICBRAINZ (metadata)->priv;
+  G_OBJECT_CLASS (sj_metadata_musicbrainz_parent_class)->finalize (object);
+}
 
-  if (mb_GetWebSubmitURL(priv->mb, url, 1024)) {
-    return g_strdup(url);
-  } else {
-    return NULL;
-  }
+static void
+sj_metadata_musicbrainz_class_init (SjMetadataMusicbrainzClass *class)
+{
+  GObjectClass *object_class = (GObjectClass*)class;
+
+  g_type_class_add_private (class, sizeof (SjMetadataMusicbrainzPrivate));
+
+  object_class->get_property = sj_metadata_musicbrainz_get_property;
+  object_class->set_property = sj_metadata_musicbrainz_set_property;
+  object_class->finalize = sj_metadata_musicbrainz_finalize;
+
+  g_object_class_override_property (object_class, PROP_DEVICE, "device");
+  g_object_class_override_property (object_class, PROP_PROXY_HOST, "proxy-host");
+  g_object_class_override_property (object_class, PROP_PROXY_PORT, "proxy-port");
+}
+
+
+/*
+ * Public methods.
+ */
+
+GObject *
+sj_metadata_musicbrainz_new (void)
+{
+  return g_object_new (SJ_TYPE_METADATA_MUSICBRAINZ, NULL);
 }

Modified: trunk/plugins/audiocd/sj-metadata-musicbrainz.h
==============================================================================
--- trunk/plugins/audiocd/sj-metadata-musicbrainz.h	(original)
+++ trunk/plugins/audiocd/sj-metadata-musicbrainz.h	Fri Sep  5 00:38:27 2008
@@ -7,14 +7,6 @@
  * 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 grants 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 library 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
@@ -34,7 +26,7 @@
 
 G_BEGIN_DECLS
 
-#define SJ_TYPE_METADATA_MUSICBRAINZ            (sj_metadata_get_type ())
+#define SJ_TYPE_METADATA_MUSICBRAINZ            (sj_metadata_musicbrainz_get_type ())
 #define SJ_METADATA_MUSICBRAINZ(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SJ_TYPE_METADATA_MUSICBRAINZ, SjMetadataMusicbrainz))
 #define SJ_METADATA_MUSICBRAINZ_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), SJ_TYPE_METADATA_MUSICBRAINZ, SjMetadataMusicbrainzClass))
 #define SJ_IS_METADATA_MUSICBRAINZ(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SJ_TYPE_METADATA_MUSICBRAINZ))

Added: trunk/plugins/audiocd/sj-metadata-musicbrainz3.c
==============================================================================
--- (empty file)
+++ trunk/plugins/audiocd/sj-metadata-musicbrainz3.c	Fri Sep  5 00:38:27 2008
@@ -0,0 +1,425 @@
+/*
+ * sj-metadata-musicbrainz3.c
+ * Copyright (C) 2008 Ross Burton <ross burtonini com>
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <gconf/gconf-client.h>
+#include <musicbrainz3/mb_c.h>
+
+#include "sj-metadata-musicbrainz3.h"
+#include "sj-structures.h"
+#include "sj-error.h"
+
+#define GET(field, function, obj) {						\
+	function (obj, buffer, sizeof (buffer));				\
+	if (field)								\
+		g_free (field);							\
+	if (*buffer == '\0')							\
+		field = NULL;							\
+	else									\
+		field = g_strdup (buffer);					\
+}
+
+#define GCONF_PROXY_USE_PROXY "/system/http_proxy/use_http_proxy"
+#define GCONF_PROXY_HOST "/system/http_proxy/host"
+#define GCONF_PROXY_PORT "/system/http_proxy/port"
+#define GCONF_PROXY_USE_AUTHENTICATION "/system/http_proxy/use_authentication"
+#define GCONF_PROXY_USERNAME "/system/http_proxy/authentication_user"
+#define GCONF_PROXY_PASSWORD "/system/http_proxy/authentication_password"
+
+typedef struct {
+  MbWebService mb;
+  MbDisc disc;
+  char *cdrom;
+  GList *albums;
+  /* Proxy */
+  char *http_proxy;
+  int http_proxy_port;
+} SjMetadataMusicbrainz3Private;
+
+#define GET_PRIVATE(o)  \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), SJ_TYPE_METADATA_MUSICBRAINZ3, SjMetadataMusicbrainz3Private))
+
+enum {
+  PROP_0,
+  PROP_DEVICE,
+  PROP_USE_PROXY,
+  PROP_PROXY_HOST,
+  PROP_PROXY_PORT,
+};
+
+static void metadata_interface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (SjMetadataMusicbrainz3,
+                         sj_metadata_musicbrainz3,
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (SJ_TYPE_METADATA,
+                                                metadata_interface_init));
+
+
+/*
+ * Private methods
+ */
+
+static AlbumDetails *
+make_album_from_release (MbRelease *release)
+{
+  AlbumDetails *album;
+  char buffer[512];
+  MbArtist artist;
+  char *new_title;
+  int i;
+
+  g_assert (release);
+
+  album = g_new0 (AlbumDetails, 1);
+
+   /* Some versions of libmusicbrainz3 seem to forget the trailing .html in the URL */
+  GET (album->album_id, mb_release_get_id, release);
+  if (album->album_id && g_str_has_suffix (album->album_id, ".html") == FALSE) {
+    char *tmp;
+    tmp = g_strdup_printf ("%s.html", album->album_id);
+    g_free (album->album_id);
+    album->album_id = tmp;
+  }
+
+  GET (album->title, mb_release_get_title, release);
+  new_title = sj_metadata_helper_scan_disc_number (album->title, &album->disc_number);
+  if (new_title) {
+    g_free (album->title);
+    album->title = new_title;
+  }
+
+  artist = mb_release_get_artist (release);
+  GET (album->artist_id, mb_artist_get_id, artist);
+  GET (album->artist, mb_artist_get_name, artist);
+  GET (album->artist_sortname, mb_artist_get_sortname, artist);
+
+  if (mb_release_get_num_release_events (release) >= 1) {
+    MbReleaseEvent event;
+    char *date = NULL;
+
+    event = mb_release_get_release_event (release, 0);
+    GET (date, mb_release_event_get_date, event);
+    album->release_date = sj_metadata_helper_scan_date (date);
+    g_free (date);
+  }
+
+  album->number = mb_release_get_num_tracks (release);
+  GET (album->asin, mb_release_get_asin, release);
+
+  for (i = 0; i < mb_release_get_num_relations (release); i++) {
+    MbRelation relation;
+    char *type = NULL;
+
+    relation = mb_release_get_relation (release, i);
+    GET(type, mb_relation_get_type, relation);
+    if (type && g_str_equal (type, "http://musicbrainz.org/ns/rel-1.0#Wikipedia";)) {
+      GET (album->wikipedia, mb_relation_get_target_id, relation);
+    } else if (type && g_str_equal (type, "http://musicbrainz.org/ns/rel-1.0#Discogs";)) {
+      GET (album->discogs, mb_relation_get_target_id, relation);
+      continue;
+    }
+    g_free (type);
+  }
+
+  for (i = 0; i < mb_release_get_num_types (release); i++) {
+    mb_release_get_type (release, i, buffer, sizeof(buffer));
+
+    if (g_str_has_suffix (buffer, "#Spokenword")
+    	|| g_str_has_suffix (buffer, "#Interview")
+    	|| g_str_has_suffix (buffer, "#Audiobook")) {
+      album->is_spoken_word = TRUE;
+      break;
+    }
+  }
+
+  for (i = 0; i < album->number; i++) {
+    MbTrack mbt;
+    TrackDetails *track;
+
+    mbt = mb_release_get_track (release, i);
+    track = g_new0 (TrackDetails, 1);
+
+    track->album = album;
+
+    track->number = i + 1;
+    GET (track->track_id, mb_track_get_id, mbt);
+
+    GET (track->title, mb_track_get_title, mbt);
+    track->duration = mb_track_get_duration (mbt) / 1000;
+
+    artist = mb_release_get_artist (release);
+    GET (track->artist_id, mb_artist_get_id, artist);
+    GET (track->artist, mb_artist_get_name, artist);
+    GET (track->artist_sortname, mb_artist_get_sortname, artist);
+
+    album->tracks = g_list_append (album->tracks, track);
+  }
+
+  return album;
+}
+
+static void
+fill_empty_durations (MbDisc *disc, AlbumDetails *album)
+{
+  if (disc == NULL)
+    return;
+}
+
+static MbReleaseIncludes
+get_release_includes (void)
+{
+    MbReleaseIncludes includes;
+
+    includes = mb_release_includes_new ();
+    includes = mb_release_includes_artist (includes);
+    includes = mb_release_includes_tracks (includes);
+    includes = mb_artist_includes_release_events (includes);
+    includes = mb_track_includes_url_relations (includes);
+
+    return includes;
+}
+
+/**
+ * Virtual methods
+ */
+
+static GList *
+mb_list_albums (SjMetadata *metadata, char **url, GError **error)
+{
+  SjMetadataMusicbrainz3Private *priv;
+  MbQuery query;
+  MbReleaseFilter filter;
+  MbResultList results;
+  MbRelease release;
+  char *id = NULL;
+  char buffer[512];
+  int i;
+  g_return_val_if_fail (SJ_IS_METADATA_MUSICBRAINZ3 (metadata), FALSE);
+
+  priv = GET_PRIVATE (metadata);
+
+  if (sj_metadata_helper_check_media (priv->cdrom, error) == FALSE) {
+    priv->albums = NULL;
+    return NULL;
+  }
+
+  priv->disc = mb_read_disc (priv->cdrom);
+  if (url != NULL) {
+    mb_get_submission_url (priv->disc, NULL, 0, buffer, sizeof (buffer));
+    *url = g_strdup (buffer);
+  }
+
+  if (g_getenv("MUSICBRAINZ_FORCE_DISC_ID")) {
+    id = g_strdup (g_getenv("MUSICBRAINZ_FORCE_DISC_ID"));
+  } else {
+    GET(id, mb_disc_get_id, priv->disc);
+  }
+
+  query = mb_query_new (priv->mb, "sound-juicer");
+  filter = mb_release_filter_new ();
+  filter = mb_release_filter_disc_id (filter, id);
+  results = mb_query_get_releases (query, filter);
+  mb_release_filter_free (filter);
+  g_free (id);
+
+  if (mb_result_list_get_size (results) == 0) {
+    mb_result_list_free (results);
+    mb_query_free (query);
+    return NULL;
+  }
+
+  for (i = 0; i < mb_result_list_get_size (results); i++) {
+    AlbumDetails *album;
+    MbReleaseIncludes includes;
+    char buffer[512];
+
+    release = mb_result_list_get_release (results, i);
+    mb_release_get_id (release, buffer, sizeof (buffer));
+    includes = get_release_includes ();
+    release = mb_query_get_release_by_id (query, buffer, includes);
+    mb_release_includes_free (includes);
+
+    album = make_album_from_release (release);
+    album->metadata_source = SOURCE_MUSICBRAINZ;
+    fill_empty_durations (priv->disc, album);
+    priv->albums = g_list_append (priv->albums, album);
+    mb_release_free (release);
+  }
+  mb_result_list_free (results);
+  mb_query_free (query);
+
+  return priv->albums;
+}
+
+/*
+ * GObject methods
+ */
+
+static void
+metadata_interface_init (gpointer g_iface, gpointer iface_data)
+{
+  SjMetadataClass *klass = (SjMetadataClass*)g_iface;
+
+  klass->list_albums = mb_list_albums;
+}
+
+static void
+sj_metadata_musicbrainz3_init (SjMetadataMusicbrainz3 *self)
+{
+  GConfClient *gconf_client;
+  SjMetadataMusicbrainz3Private *priv;
+
+  priv = GET_PRIVATE (self);
+
+  priv->mb = mb_webservice_new();
+
+  gconf_client = gconf_client_get_default ();
+
+  /* Set the HTTP proxy */
+  if (gconf_client_get_bool (gconf_client, GCONF_PROXY_USE_PROXY, NULL)) {
+    char *proxy_host;
+    int port;
+
+    proxy_host = gconf_client_get_string (gconf_client, GCONF_PROXY_HOST, NULL);
+    mb_webservice_set_proxy_host (priv->mb, proxy_host);
+    g_free (proxy_host);
+
+    port = gconf_client_get_int (gconf_client, GCONF_PROXY_PORT, NULL);
+    mb_webservice_set_proxy_port (priv->mb, port);
+
+    if (gconf_client_get_bool (gconf_client, GCONF_PROXY_USE_AUTHENTICATION, NULL)) {
+      char *username, *password;
+
+      username = gconf_client_get_string (gconf_client, GCONF_PROXY_USERNAME, NULL);
+      mb_webservice_set_proxy_username (priv->mb, username);
+      g_free (username);
+
+      password = gconf_client_get_string (gconf_client, GCONF_PROXY_PASSWORD, NULL);
+      mb_webservice_set_proxy_password (priv->mb, password);
+      g_free (password);
+    }
+  }
+
+  g_object_unref (gconf_client);
+}
+
+static void
+sj_metadata_musicbrainz3_get_property (GObject *object, guint property_id,
+                                       GValue *value, GParamSpec *pspec)
+{
+  SjMetadataMusicbrainz3Private *priv = GET_PRIVATE (object);
+  g_assert (priv);
+
+  switch (property_id) {
+  case PROP_DEVICE:
+    g_value_set_string (value, priv->cdrom);
+    break;
+  case PROP_PROXY_HOST:
+    g_value_set_string (value, priv->http_proxy);
+    break;
+  case PROP_PROXY_PORT:
+    g_value_set_int (value, priv->http_proxy_port);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+sj_metadata_musicbrainz3_set_property (GObject *object, guint property_id,
+                                       const GValue *value, GParamSpec *pspec)
+{
+  SjMetadataMusicbrainz3Private *priv = GET_PRIVATE (object);
+  g_assert (priv);
+
+  switch (property_id) {
+  case PROP_DEVICE:
+    if (priv->cdrom)
+      g_free (priv->cdrom);
+    priv->cdrom = g_value_dup_string (value);
+    break;
+  case PROP_PROXY_HOST:
+    if (priv->http_proxy) {
+      g_free (priv->http_proxy);
+    }
+    priv->http_proxy = g_value_dup_string (value);
+    /* TODO: check this unsets the proxy if NULL, or should we pass "" ? */
+    mb_webservice_set_proxy_host (priv->mb, priv->http_proxy);
+    break;
+  case PROP_PROXY_PORT:
+    priv->http_proxy_port = g_value_get_int (value);
+    mb_webservice_set_proxy_port (priv->mb, priv->http_proxy_port);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+sj_metadata_musicbrainz3_finalize (GObject *object)
+{
+  SjMetadataMusicbrainz3Private *priv;
+  
+  priv = GET_PRIVATE (object);
+
+  if (priv->mb != NULL) {
+    mb_webservice_free (priv->mb);
+    priv->mb = NULL;
+  }
+  g_free (priv->cdrom);
+
+  G_OBJECT_CLASS (sj_metadata_musicbrainz3_parent_class)->finalize (object);
+}
+
+static void
+sj_metadata_musicbrainz3_class_init (SjMetadataMusicbrainz3Class *class)
+{
+  GObjectClass *object_class = (GObjectClass*)class;
+
+  g_type_class_add_private (class, sizeof (SjMetadataMusicbrainz3Private));
+
+  object_class->get_property = sj_metadata_musicbrainz3_get_property;
+  object_class->set_property = sj_metadata_musicbrainz3_set_property;
+  object_class->finalize = sj_metadata_musicbrainz3_finalize;
+
+  g_object_class_override_property (object_class, PROP_DEVICE, "device");
+  g_object_class_override_property (object_class, PROP_PROXY_HOST, "proxy-host");
+  g_object_class_override_property (object_class, PROP_PROXY_PORT, "proxy-port");
+}
+
+
+/*
+ * Public methods.
+ */
+
+GObject *
+sj_metadata_musicbrainz3_new (void)
+{
+  return g_object_new (SJ_TYPE_METADATA_MUSICBRAINZ3, NULL);
+}

Added: trunk/plugins/audiocd/sj-metadata-musicbrainz3.h
==============================================================================
--- (empty file)
+++ trunk/plugins/audiocd/sj-metadata-musicbrainz3.h	Fri Sep  5 00:38:27 2008
@@ -0,0 +1,56 @@
+/*
+ * sj-metadata-musicbrainz3.h
+ * Copyright (C) 2008 Ross Burton <ross burtonini com>
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SJ_METADATA_MUSICBRAINZ3_H
+#define SJ_METADATA_MUSICBRAINZ3_H
+
+#include <glib-object.h>
+#include "sj-metadata.h"
+
+G_BEGIN_DECLS
+
+#define SJ_TYPE_METADATA_MUSICBRAINZ3           (sj_metadata_musicbrainz3_get_type ())
+#define SJ_METADATA_MUSICBRAINZ3(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), SJ_TYPE_METADATA_MUSICBRAINZ3, SjMetadataMusicbrainz3))
+#define SJ_METADATA_MUSICBRAINZ3_CLASS(vtable)  (G_TYPE_CHECK_CLASS_CAST ((vtable), SJ_TYPE_METADATA_MUSICBRAINZ3, SjMetadataMusicbrainz3Class))
+#define SJ_IS_METADATA_MUSICBRAINZ3(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SJ_TYPE_METADATA_MUSICBRAINZ3))
+#define SJ_IS_METADATA_MUSICBRAINZ3_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), SJ_TYPE_METADATA_MUSICBRAINZ3))
+#define SJ_METADATA_MUSICBRAINZ3_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SJ_TYPE_METADATA_MUSICBRAINZ3, SjMetadataMusicbrainz3Class))
+
+typedef struct _SjMetadataMusicbrainz3 SjMetadataMusicbrainz3;
+typedef struct _SjMetadataMusicbrainz3Class SjMetadataMusicbrainz3Class;
+
+struct _SjMetadataMusicbrainz3
+{
+  GObject parent;
+};
+
+struct _SjMetadataMusicbrainz3Class
+{
+  GObjectClass parent;
+};
+
+GType sj_metadata_musicbrainz3_get_type (void);
+
+GObject *sj_metadata_musicbrainz3_new (void);
+
+G_END_DECLS
+
+#endif /* SJ_METADATA_MUSICBRAINZ3_H */

Modified: trunk/plugins/audiocd/sj-metadata.c
==============================================================================
--- trunk/plugins/audiocd/sj-metadata.c	(original)
+++ trunk/plugins/audiocd/sj-metadata.c	Fri Sep  5 00:38:27 2008
@@ -7,14 +7,6 @@
  * 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 grants 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 library 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
@@ -26,31 +18,50 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include "config.h"
-
 #include <glib-object.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef USE_TOTEM_PL_PARSER
+#include <unistd.h>
+#include <nautilus-burn.h>
+#else
+#include <totem-disc.h>
+#endif /* USE_TOTEM_PL_PARSER */
+
 #include "sj-metadata.h"
 #include "sj-metadata-marshal.h"
+#include "sj-error.h"
 
 enum {
   METADATA,
   LAST_SIGNAL
 };
 
-static int signals[LAST_SIGNAL] = { 0 };
-
 static void
-sj_metadata_base_init (gpointer g_class)
+sj_metadata_base_init (gpointer g_iface)
 {
   static gboolean initialized = FALSE;
   if (!initialized) {
-    signals[METADATA] = g_signal_new ("metadata",
-                                      G_TYPE_FROM_CLASS (g_class),
-                                      G_SIGNAL_RUN_LAST,
-                                      G_STRUCT_OFFSET (SjMetadataClass, metadata),
-                                      NULL, NULL,
-                                      metadata_marshal_VOID__POINTER_POINTER,
-                                      G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+    /* TODO: make these constructors */
+    /* TODO: add nice nick and blurb strings */
+    g_object_interface_install_property (g_iface,
+                                         g_param_spec_string ("device", "device", NULL, NULL,
+                                                              G_PARAM_READABLE|G_PARAM_WRITABLE|
+                                                              G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
+
+    g_object_interface_install_property (g_iface,
+                                         g_param_spec_string ("proxy-host", "proxy-host", NULL, NULL,
+                                                              G_PARAM_READABLE|G_PARAM_WRITABLE|
+                                                              G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
+
+    g_object_interface_install_property (g_iface,
+                                         g_param_spec_int ("proxy-port", "proxy-port", NULL,
+                                                           0, G_MAXINT, 0,
+                                                           G_PARAM_READABLE|G_PARAM_WRITABLE|
+                                                           G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
+
     initialized = TRUE;
   }
 }
@@ -79,49 +90,124 @@
   return type;
 }
 
-GError *
-sj_metadata_get_new_error (SjMetadata *metadata)
-{
-  return SJ_METADATA_GET_CLASS (metadata)->get_new_error (metadata);
-}
-
 void
 sj_metadata_set_cdrom (SjMetadata *metadata, const char* device)
 {
-#if defined (sun) && defined (__SVR4)
-  if (g_str_has_prefix (device, "/dev/dsk/")) {
-    char *raw_path = g_strdup_printf ("/dev/rdsk/%s", device + strlen ("/dev/dsk/"));
-    SJ_METADATA_GET_CLASS (metadata)->set_cdrom (metadata, raw_path);
-    g_free (raw_path);
-  }
-#else
-  SJ_METADATA_GET_CLASS (metadata)->set_cdrom (metadata, device);
-#endif
+  g_object_set (metadata, "device", device, NULL);
 }
 
 void
 sj_metadata_set_proxy (SjMetadata *metadata, const char* proxy)
 {
-  SJ_METADATA_GET_CLASS (metadata)->set_proxy (metadata, proxy);
+  g_object_set (metadata, "proxy-host", proxy, NULL);
 }
 
 void
 sj_metadata_set_proxy_port (SjMetadata *metadata, const int proxy_port)
 {
-  SJ_METADATA_GET_CLASS (metadata)->set_proxy_port (metadata, proxy_port);
+  g_object_set (metadata, "proxy-port", proxy_port, NULL);
 }
 
-void
-sj_metadata_list_albums (SjMetadata *metadata, GError **error)
+GList *
+sj_metadata_list_albums (SjMetadata *metadata, char **url, GError **error)
 {
-  SJ_METADATA_GET_CLASS (metadata)->list_albums (metadata, error);
+  return SJ_METADATA_GET_CLASS (metadata)->list_albums (metadata, url, error);
 }
 
 char *
-sj_metadata_get_submit_url (SjMetadata *metadata)
+sj_metadata_helper_scan_disc_number (const char *album_title, int *disc_number)
+{
+  GRegex *disc_regex;
+  GMatchInfo *info;
+  char *new_title;
+  int num;
+
+  disc_regex = g_regex_new (".+( \\(disc (\\d+).*)", 0, 0, NULL);
+  new_title = NULL;
+  *disc_number = 0;
+
+  if (g_regex_match (disc_regex, album_title, 0, &info)) {
+    int pos = 0;
+    char *s;
+
+    g_match_info_fetch_pos (info, 1, &pos, NULL);
+    if (pos) {
+      new_title = g_strndup (album_title, pos);
+    }
+
+    s = g_match_info_fetch (info, 2);
+    num = atoi (s);
+    *disc_number = num;
+    g_free (s);
+  }
+
+  g_match_info_free (info);
+  g_regex_unref (disc_regex);
+
+  return new_title;
+}
+
+GDate *
+sj_metadata_helper_scan_date (const char *date)
 {
-  if (SJ_METADATA_GET_CLASS (metadata)->get_submit_url)
-    return SJ_METADATA_GET_CLASS (metadata)->get_submit_url (metadata);
-  else
-    return NULL;
+  int matched, year=1, month=1, day=1;
+  matched = sscanf(date, "%u-%u-%u", &year, &month, &day);
+  if (matched >= 1) {
+    return g_date_new_dmy ((day == 0) ? 1 : day, (month == 0) ? 1 : month, year);
+  }
+
+  return NULL;
+}
+
+gboolean
+sj_metadata_helper_check_media (const char *cdrom, GError **error)
+{
+#ifndef USE_TOTEM_PL_PARSER
+  NautilusBurnMediaType type;
+  NautilusBurnDriveMonitor *monitor;
+  NautilusBurnDrive *drive;
+
+  if (! nautilus_burn_initialized ()) {
+    nautilus_burn_init ();
+  }
+  monitor = nautilus_burn_get_drive_monitor ();
+  drive = nautilus_burn_drive_monitor_get_drive_for_device (monitor, cdrom);
+  if (drive == NULL) {
+    return FALSE;
+  }
+  type = nautilus_burn_drive_get_media_type (drive);
+  nautilus_burn_drive_unref (drive);
+
+  if (type == NAUTILUS_BURN_MEDIA_TYPE_ERROR) {
+    char *msg;
+    SjError err;
+
+    if (access (cdrom, W_OK) == 0) {
+      msg = g_strdup_printf (_("Device '%s' does not contain any media"), cdrom);
+      err = SJ_ERROR_CD_NO_MEDIA;
+    } else {
+      msg = g_strdup_printf (_("Device '%s' could not be opened. Check the access permissions on the device."), cdrom);
+      err = SJ_ERROR_CD_PERMISSION_ERROR;
+    }
+    g_set_error (error, SJ_ERROR, err, _("Cannot read CD: %s"), msg);
+    g_free (msg);
+
+    return FALSE;
+  }
+#else
+  TotemDiscMediaType type;
+  GError *totem_error = NULL;
+
+  type = totem_cd_detect_type (cdrom, &totem_error);
+
+  if (totem_error != NULL) {
+    g_set_error (error, SJ_ERROR, SJ_ERROR_CD_NO_MEDIA, _("Cannot read CD: %s"), totem_error->message);
+    g_error_free (totem_error);
+
+    return FALSE;
+  }
+#endif /* !USE_TOTEM_PL_PARSER */
+
+  return TRUE;
 }
+

Modified: trunk/plugins/audiocd/sj-metadata.h
==============================================================================
--- trunk/plugins/audiocd/sj-metadata.h	(original)
+++ trunk/plugins/audiocd/sj-metadata.h	Fri Sep  5 00:38:27 2008
@@ -7,14 +7,6 @@
  * 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 grants 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 library 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
@@ -48,25 +40,19 @@
 {
   GTypeInterface g_iface;
 
-  /* Signals */
-  void         (*metadata) (SjMetadata *md, GList *albums, GError *error);
-
   /* Virtual Table */
-  GError* (*get_new_error) (SjMetadata *metadata);
-  void (*set_cdrom) (SjMetadata *metadata, const char* device);
-  void (*set_proxy) (SjMetadata *metadata, const char* proxy);
-  void (*set_proxy_port) (SjMetadata *metadata, int proxy_port);
-  void (*list_albums) (SjMetadata *metadata, GError **error);
-  char *(*get_submit_url) (SjMetadata *metadata);
+  GList * (*list_albums) (SjMetadata *metadata, char **url, GError **error);
 };
 
 GType sj_metadata_get_type (void);
-GError *sj_metadata_get_new_error (SjMetadata *metadata);
 void sj_metadata_set_cdrom (SjMetadata *metadata, const char* device);
 void sj_metadata_set_proxy (SjMetadata *metadata, const char* proxy);
 void sj_metadata_set_proxy_port (SjMetadata *metadata, const int proxy_port);
-void sj_metadata_list_albums (SjMetadata *metadata, GError **error);
-char *sj_metadata_get_submit_url (SjMetadata *metadata);
+GList * sj_metadata_list_albums (SjMetadata *metadata, char **url, GError **error);
+
+char * sj_metadata_helper_scan_disc_number (const char *album_title, int *disc_number);
+GDate * sj_metadata_helper_scan_date (const char *date);
+gboolean sj_metadata_helper_check_media (const char *cdrom, GError **error);
 
 G_END_DECLS
 

Modified: trunk/plugins/audiocd/sj-structures.c
==============================================================================
--- trunk/plugins/audiocd/sj-structures.c	(original)
+++ trunk/plugins/audiocd/sj-structures.c	Fri Sep  5 00:38:27 2008
@@ -3,33 +3,24 @@
  *
  * Sound Juicer - sj-structures.c
  *
- * 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 library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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 grants 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,
+ * This library 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.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.*
  *
  * Authors: Ross Burton <ross burtonini com>
  */
 
-#include "config.h"
-
 #include "sj-structures.h"
 #include <glib/gmessages.h>
 #include <glib/glist.h>
@@ -62,5 +53,8 @@
   g_list_foreach (album->tracks, (GFunc)track_details_free, NULL);
   g_list_free (album->tracks);
   g_free (album->artist_sortname);
+  g_free (album->asin);
+  g_free (album->discogs);
+  g_free (album->wikipedia);
   g_free (album);
 }

Modified: trunk/plugins/audiocd/sj-structures.h
==============================================================================
--- trunk/plugins/audiocd/sj-structures.h	(original)
+++ trunk/plugins/audiocd/sj-structures.h	Fri Sep  5 00:38:27 2008
@@ -3,27 +3,20 @@
  *
  * Sound Juicer - sj-structures.h
  *
- * 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 library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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 grants 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,
+ * This library 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.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
  *
  * Authors: Ross Burton <ross burtonini com>
  */
@@ -32,11 +25,20 @@
 #define SJ_STRUCTURES_H
 
 #include <glib/glist.h>
-#include <gtk/gtktreemodel.h>
+#include <glib/gdate.h>
+
+typedef enum _MetadataSource MetadataSource;
 
 typedef struct _AlbumDetails AlbumDetails;
 typedef struct _TrackDetails TrackDetails;
 
+enum _MetadataSource {
+  SOURCE_UNKNOWN = 0,
+  SOURCE_CDTEXT,
+  SOURCE_FREEDB,
+  SOURCE_MUSICBRAINZ,
+  SOURCE_FALLBACK
+};
 
 struct _TrackDetails {
   AlbumDetails *album;
@@ -47,7 +49,6 @@
   int duration; /* seconds */
   char* track_id;
   char* artist_id;
-  GtkTreeIter iter; /* Temporary iterator for internal use */
 };
 
 struct _AlbumDetails {
@@ -56,10 +57,16 @@
   char* artist_sortname;
   char *genre;
   int   number; /* number of tracks in the album */
+  int   disc_number;
   GList* tracks;
   GDate *release_date; /* MusicBrainz support multiple releases per album */
   char* album_id;
   char* artist_id;
+  char* asin;
+  char* discogs;
+  char* wikipedia;
+  MetadataSource metadata_source;
+  gboolean is_spoken_word;
 };
 
 void album_details_free(AlbumDetails *album);

Added: trunk/plugins/audiocd/update-from-egg.sh
==============================================================================
--- (empty file)
+++ trunk/plugins/audiocd/update-from-egg.sh	Fri Sep  5 00:38:27 2008
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+function die() {
+  echo $*
+  exit 1
+}
+
+if test -z "$EGGDIR"; then
+   echo "Must set EGGDIR"
+   exit 1
+fi
+
+if test -z "$EGGFILES"; then
+   echo "Must set EGGFILES"
+   exit 1
+fi
+
+for FILE in $EGGFILES; do
+  if cmp -s $EGGDIR/$FILE $FILE; then
+     echo "File $FILE is unchanged"
+  else
+     cp $EGGDIR/$FILE $FILE || die "Could not move $EGGDIR/$FILE to $FILE"
+     echo "Updated $FILE"
+  fi
+done



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