[rhythmbox] sync audiocd metadata code with sound-juicer



commit 8f84030e28573997ecaf28263a3d8f0895212a16
Author: Jonathan Matthew <jonathan d14n org>
Date:   Wed Mar 28 19:41:13 2012 +1000

    sync audiocd metadata code with sound-juicer
    
    Adds code to make use of libmusicbrainz4, which provides more
    album detail (that we don't use) and should deal with multi-disc
    albums properly.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=668395

 configure.ac                               |   19 +-
 plugins/audiocd/Makefile.am                |    8 +
 plugins/audiocd/sj-error.h                 |    3 +-
 plugins/audiocd/sj-metadata-getter.c       |   20 +-
 plugins/audiocd/sj-metadata-gvfs.c         |    4 +
 plugins/audiocd/sj-metadata-musicbrainz4.c |  615 ++++++++++++++++++++++++++++
 plugins/audiocd/sj-metadata-musicbrainz4.h |   56 +++
 plugins/audiocd/sj-metadata.c              |    9 +
 plugins/audiocd/sj-structures.c            |   22 +
 plugins/audiocd/sj-structures.h            |   25 ++
 10 files changed, 770 insertions(+), 11 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e8074a0..a469f1a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,6 +50,7 @@ GDK_PIXBUF_REQS=2.18.0
 GLIB_REQS=2.28.0
 LIBGPOD_REQS=0.6
 MUSICBRAINZ3_REQS=3.0.2
+MUSICBRAINZ4_REQS=4.0.0
 TOTEM_PLPARSER_REQS=2.32.1
 VALA_REQS=0.9.4
 AVAHI_REQS=0.6
@@ -347,13 +348,16 @@ AC_SUBST(GSTCDDA_CFLAGS)
 dnl check for MusicBrainz
 have_sj_metadata_getter=no
 AC_ARG_ENABLE(musicbrainz, AC_HELP_STRING([--disable-musicbrainz],
-				[don't build with MusicBrainz support]))
+				[build without MusicBrainz support]))
 if test x"$enable_musicbrainz" != "xno"; then
 	PKG_CHECK_MODULES(MUSICBRAINZ3, libmusicbrainz3 >= $MUSICBRAINZ3_REQS gconf-2.0, [have_musicbrainz3=yes], [have_musicbrainz3=no])
-
 	AC_SUBST(MUSICBRAINZ3_CFLAGS)
 	AC_SUBST(MUSICBRAINZ3_LIBS)
 
+	PKG_CHECK_MODULES(MUSICBRAINZ4, libmusicbrainz4 >= $MUSICBRAINZ4_REQS gconf-2.0, [have_musicbrainz4=yes], [have_musicbrainz4=no])
+	AC_SUBST(MUSICBRAINZ4_CFLAGS)
+	AC_SUBST(MUSICBRAINZ4_LIBS)
+
 	if test x"$have_musicbrainz3" = xyes; then
 		oldlibs=$LIBS
 		LIBS="$LIBS $MUSICBRAINZ3_LIBS"
@@ -362,14 +366,23 @@ if test x"$enable_musicbrainz" != "xno"; then
 
 		AC_DEFINE([HAVE_MUSICBRAINZ3], 1, [Whether libmusicbrainz3 is available])
 		have_sj_metadata_getter=yes
+	fi
+
+	if test x"$have_musicbrainz4" = xyes; then
+		AC_DEFINE([HAVE_MUSICBRAINZ4], 1, [Whether libmusicbrainz4 is available])
+		have_sj_metadata_getter=yes
+	fi
+
+	if test x"$have_sj_metadata_getter" = xyes; then
 		AC_DEFINE([HAVE_SJ_METADATA_GETTER], 1, [Whether to use the sound-juicer metadata getter code])
 	else
 		if test x"$enable_musicbrainz" = xyes; then
-			AC_MSG_ERROR([MusicBrainz requested, but neither libmusicbrainz nor libmusicbrainz3 are available])
+			AC_MSG_ERROR([MusicBrainz requested, but neither libmusicbrainz3 nor libmusicbrainz4 are available])
 		fi
 	fi
 fi
 AM_CONDITIONAL([HAVE_MUSICBRAINZ3], [test "x$have_musicbrainz3" = "xyes"])
+AM_CONDITIONAL([HAVE_MUSICBRAINZ4], [test "x$have_musicbrainz4" = "xyes"])
 AM_CONDITIONAL([HAVE_SJ_METADATA_GETTER], [test "x$have_sj_metadata_getter" = "xyes"])
 
 AC_PATH_XTRA
diff --git a/plugins/audiocd/Makefile.am b/plugins/audiocd/Makefile.am
index d9475f4..e757d2d 100644
--- a/plugins/audiocd/Makefile.am
+++ b/plugins/audiocd/Makefile.am
@@ -46,6 +46,10 @@ if HAVE_MUSICBRAINZ3
 libaudiocd_la_LIBADD +=$(MUSICBRAINZ3_LIBS)
 INCLUDES += $(MUSICBRAINZ3_CFLAGS)
 endif
+if HAVE_MUSICBRAINZ4
+libaudiocd_la_LIBADD +=$(MUSICBRAINZ4_LIBS)
+INCLUDES += $(MUSICBRAINZ4_CFLAGS)
+endif
 
 libaudiocd_la_LIBADD += $(NULL)
 
@@ -72,6 +76,7 @@ SJ_FILES =									\
 	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-musicbrainz4.c sj-metadata-musicbrainz4.h			\
 	sj-structures.c sj-structures.h						\
 	sj-metadata-marshal.list
 
@@ -93,6 +98,9 @@ libaudiocd_la_SOURCES +=							\
 if HAVE_MUSICBRAINZ3
 libaudiocd_la_SOURCES += sj-metadata-musicbrainz3.c sj-metadata-musicbrainz3.h
 endif
+if HAVE_MUSICBRAINZ4
+libaudiocd_la_SOURCES += sj-metadata-musicbrainz4.c sj-metadata-musicbrainz4.h
+endif
 
 MARSHALFILES += sj-metadata-marshal.h sj-metadata-marshal.c
 
diff --git a/plugins/audiocd/sj-error.h b/plugins/audiocd/sj-error.h
index d23e577..3d8e94e 100644
--- a/plugins/audiocd/sj-error.h
+++ b/plugins/audiocd/sj-error.h
@@ -32,7 +32,8 @@ typedef enum {
   SJ_ERROR_INTERNAL_ERROR,
   SJ_ERROR_CD_PERMISSION_ERROR,
   SJ_ERROR_CD_NO_MEDIA,
-  SJ_ERROR_CD_LOOKUP_ERROR
+  SJ_ERROR_CD_LOOKUP_ERROR,
+  SJ_ERROR_CD_BUSY
 } SjError;
 
 GQuark sj_error_quark (void) G_GNUC_CONST;
diff --git a/plugins/audiocd/sj-metadata-getter.c b/plugins/audiocd/sj-metadata-getter.c
index 191796f..cfc447d 100644
--- a/plugins/audiocd/sj-metadata-getter.c
+++ b/plugins/audiocd/sj-metadata-getter.c
@@ -26,12 +26,15 @@
 #include "sj-metadata-getter.h"
 #include "sj-metadata-marshal.h"
 #include "sj-metadata.h"
+#ifdef HAVE_MUSICBRAINZ4
+#include "sj-metadata-musicbrainz4.h"
+#endif /* HAVE_MUSICBRAINZ4 */
 #ifdef HAVE_MUSICBRAINZ3
 #include "sj-metadata-musicbrainz3.h"
 #endif /* HAVE_MUSICBRAINZ3 */
-#ifdef HAVE_LIBCDIO
-#include "sj-metadata-cdtext.h"
-#endif /* HAVE_LIBCDIO */
+#ifdef HAVE_MUSICBRAINZ
+#include "sj-metadata-musicbrainz.h"
+#endif /* HAVE_MUSICBRAINZ */
 #include "sj-metadata-gvfs.h"
 #include "sj-error.h"
 
@@ -119,7 +122,7 @@ sj_metadata_getter_set_cdrom (SjMetadataGetter *mdg, const char* device)
 
   g_free (priv->cdrom);
 
-#if defined (sun) && defined (__SVR4)
+#ifdef __sun
   if (g_str_has_prefix (device, "/dev/dsk/")) {
     priv->cdrom = g_strdup_printf ("/dev/rdsk/%s", device + strlen ("/dev/dsk/"));
     return;
@@ -175,12 +178,15 @@ lookup_cd (SjMetadataGetter *mdg)
   GError *error = NULL;
   gboolean found = FALSE;
   GType types[] = {
+#ifdef HAVE_MUSICBRAINZ4
+    SJ_TYPE_METADATA_MUSICBRAINZ4,
+#endif /* HAVE_MUSICBRAINZ4 */
 #ifdef HAVE_MUSICBRAINZ3
     SJ_TYPE_METADATA_MUSICBRAINZ3,
 #endif /* HAVE_MUSICBRAINZ3 */
-#ifdef HAVE_LIBCDIO
-    SJ_TYPE_METADATA_CDTEXT,
-#endif /* HAVE_LIBCDIO */
+#ifdef HAVE_MUSICBRAINZ
+    SJ_TYPE_METADATA_MUSICBRAINZ,
+#endif /* HAVE_MUSICBRAINZ */
     SJ_TYPE_METADATA_GVFS
   };
 
diff --git a/plugins/audiocd/sj-metadata-gvfs.c b/plugins/audiocd/sj-metadata-gvfs.c
index 5d31b10..0c05a80 100644
--- a/plugins/audiocd/sj-metadata-gvfs.c
+++ b/plugins/audiocd/sj-metadata-gvfs.c
@@ -63,7 +63,11 @@ device_to_cdda_uri (const char *device)
 {
   if (g_str_has_prefix (device, "/dev/") == FALSE)
     return NULL;
+#ifdef __sun
+  return g_strdup_printf ("cdda://%s", device + strlen ("/dev/rdsk/"));
+#else
   return g_strdup_printf ("cdda://%s", device + strlen ("/dev/"));
+#endif
 }
 
 static GList *
diff --git a/plugins/audiocd/sj-metadata-musicbrainz4.c b/plugins/audiocd/sj-metadata-musicbrainz4.c
new file mode 100644
index 0000000..573ef64
--- /dev/null
+++ b/plugins/audiocd/sj-metadata-musicbrainz4.c
@@ -0,0 +1,615 @@
+/*
+ * sj-metadata-musicbrainz4.c
+ * Copyright (C) 2008 Ross Burton <ross burtonini com>
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ * Copyright (C) 2011 Christophe Fergeau <cfergeau redhat 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.
+ */
+
+#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 <discid/discid.h>
+#include <musicbrainz4/mb4_c.h>
+
+#include "sj-metadata-musicbrainz4.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_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"
+#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"
+#define SJ_MUSICBRAINZ_USER_AGENT "libjuicer-"VERSION
+
+typedef struct {
+  Mb4Query mb;
+  DiscId *disc;
+  char *cdrom;
+  /* Proxy */
+  char *http_proxy;
+  int http_proxy_port;
+} SjMetadataMusicbrainz4Private;
+
+#define GET_PRIVATE(o)  \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), SJ_TYPE_METADATA_MUSICBRAINZ4, SjMetadataMusicbrainz4Private))
+
+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 (SjMetadataMusicbrainz4,
+                         sj_metadata_musicbrainz4,
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (SJ_TYPE_METADATA,
+                                                metadata_interface_init));
+
+
+/*
+ * Private methods
+ */
+#ifdef DUMP_DETAILS
+static void
+sj_mb4_album_details_dump (AlbumDetails *details)
+{
+  if (details->country)
+    g_print ("Country: %s\n", details->country);
+  if (details->type)
+    g_print ("Type: %s\n", details->type);
+  if (details->lyrics_url)
+    g_print ("Lyrics URL: %s\n", details->lyrics_url);
+}
+#else
+#define sj_mb4_album_details_dump(...)
+#endif
+
+static GList *
+get_artist_list (Mb4ArtistCredit credit)
+{
+  Mb4NameCreditList name_list;
+  GList *artists;
+  unsigned int i;
+  char buffer[512]; /* for the GET macro */
+
+  if (credit == NULL)
+    return NULL;
+
+  name_list = mb4_artistcredit_get_namecreditlist (credit);
+  if (name_list == NULL) {
+    return NULL;
+  }
+
+  artists = NULL;
+  for (i = 0; i < mb4_namecredit_list_size (name_list); i++) {
+    Mb4NameCredit name_credit;
+    Mb4Artist artist;
+    ArtistDetails *details;
+
+    name_credit = mb4_namecredit_list_item (name_list, i);
+    details = g_new0 (ArtistDetails, 1);
+    GET (details->joinphrase, mb4_namecredit_get_joinphrase, name_credit);
+    artists = g_list_prepend (artists, details);
+    artist = mb4_namecredit_get_artist (name_credit);
+    if (!artist) {
+      g_warning ("no Mb4Artist associated with Mb4NameCredit, falling back to Mb4NameCredit::name");
+      GET (details->name, mb4_namecredit_get_name, name_credit);
+      continue;
+    }
+
+    GET (details->id, mb4_artist_get_id, artist);
+    GET (details->name, mb4_artist_get_name, artist);
+    GET (details->sortname, mb4_artist_get_sortname, artist);
+    GET (details->disambiguation, mb4_artist_get_disambiguation, artist);
+    GET (details->gender, mb4_artist_get_gender, artist);
+    GET (details->country, mb4_artist_get_country, artist);
+  }
+
+  return g_list_reverse(artists);
+}
+
+static void
+get_artist_info (GList *artists, char **name, char **sortname, char **id)
+{
+  GString *artist_name;
+  GList *it;
+  unsigned int artist_count;
+
+  artist_name = g_string_new (NULL);
+  artist_count = 0;
+  for (it = artists; it != NULL; it = it->next) {
+    ArtistDetails *details = (ArtistDetails *)it->data;
+    artist_count++;
+    g_string_append (artist_name, details->name);
+    if (details->joinphrase != NULL)
+      g_string_append (artist_name, details->joinphrase);
+  }
+
+  if (artist_count != 1) {
+      g_warning ("multiple artists");
+      if (sortname != NULL)
+        *sortname = NULL;
+      if (id != NULL)
+        *id = NULL;
+  } else {
+      ArtistDetails *details = (ArtistDetails *)artists->data;
+      if (sortname != NULL)
+        *sortname = g_strdup (details->sortname);
+      if (id != NULL)
+        *id = g_strdup (details->id);
+  }
+
+  if (name != NULL)
+    *name = artist_name->str;
+
+  g_string_free (artist_name, FALSE);
+}
+
+
+static void
+fill_relations (Mb4RelationList relations, AlbumDetails *album)
+{
+  unsigned int i;
+
+  for (i = 0; i < mb4_relation_list_size (relations); i++) {
+    Mb4Relation relation;
+    char buffer[512]; /* for the GET() macro */
+    char *type = NULL;
+
+    relation = mb4_relation_list_item (relations, i);
+    if (relation == NULL)
+      continue;
+
+    GET (type, mb4_relation_get_type, relation);
+    if (type == NULL) {
+      continue;
+    }
+    if (g_str_equal (type, "wikipedia")) {
+      char *wikipedia = NULL;
+      GET (wikipedia, mb4_relation_get_target, relation);
+      if (wikipedia != NULL) {
+          g_free (album->wikipedia);
+          album->wikipedia = wikipedia;
+      }
+    } else if (g_str_equal (type, "discogs")) {
+      char *discogs = NULL;
+      GET (discogs, mb4_relation_get_target, relation);
+      if (discogs != NULL) {
+          g_free (album->discogs);
+          album->discogs = discogs;
+      }
+    } else if (g_str_equal (type, "lyrics")) {
+      char *lyrics = NULL;
+      GET (lyrics, mb4_relation_get_target, relation);
+      if (lyrics != NULL) {
+          g_free (album->lyrics_url);
+          album->lyrics_url = lyrics;
+      }
+    }
+    g_free (type);
+  }
+}
+
+static void
+fill_tracks_from_medium (Mb4Medium medium, AlbumDetails *album)
+{
+  Mb4TrackList track_list;
+  GList *tracks;
+  unsigned int i;
+  char buffer[512]; /* for the GET() macro */
+
+  track_list = mb4_medium_get_tracklist (medium);
+  if (!track_list)
+    return;
+
+  album->number = mb4_track_list_size (track_list);
+
+  tracks = NULL;
+
+  for (i = 0; i < mb4_track_list_size (track_list); i++) {
+    Mb4Track mbt;
+    Mb4ArtistCredit credit;
+    Mb4Recording recording;
+    TrackDetails *track;
+
+    mbt = mb4_track_list_item (track_list, i);
+    if (!mbt)
+      continue;
+
+    track = g_new0 (TrackDetails, 1);
+
+    track->album = album;
+
+    track->number = mb4_track_get_position (mbt);
+    recording = mb4_track_get_recording (mbt);
+    if (recording != NULL) {
+      GET (track->title, mb4_recording_get_title, recording);
+      GET (track->track_id, mb4_recording_get_id, recording);
+      track->duration = mb4_recording_get_length (recording) / 1000;
+      credit = mb4_recording_get_artistcredit (recording);
+    } else {
+      GET (track->title, mb4_track_get_title, mbt);
+      track->duration = mb4_track_get_length (mbt) / 1000;
+      credit = mb4_track_get_artistcredit (mbt);
+    }
+
+    if (credit) {
+      GList *artists;
+      artists = get_artist_list (credit);
+      if (artists) {
+        get_artist_info (artists, &track->artist,
+                         &track->artist_sortname,
+                         &track->artist_id);
+      }
+      track->artists = artists;
+    }
+    if (track->artist == NULL)
+      track->artist = g_strdup (album->artist);
+    if (track->artist_sortname == NULL)
+      track->artist_sortname = g_strdup (album->artist_sortname);
+    if (track->artist_id == NULL)
+      track->artist_id = g_strdup (album->artist_id);
+
+    tracks = g_list_prepend (tracks, track);
+  }
+  album->tracks = g_list_reverse (tracks);
+}
+
+static AlbumDetails *
+make_album_from_release (Mb4ReleaseGroup group,
+                         Mb4Release release,
+                         Mb4Medium medium)
+{
+  AlbumDetails *album;
+  Mb4ArtistCredit credit;
+  GList *artists;
+  char *date = NULL;
+  char buffer[512]; /* for the GET macro */
+
+  g_assert (release);
+  g_return_val_if_fail (medium != NULL, NULL);
+
+  album = g_new0 (AlbumDetails, 1);
+
+  GET (album->album_id, mb4_release_get_id, release);
+  GET (album->title, mb4_medium_get_title, medium);
+  if (album->title == NULL)
+    GET (album->title, mb4_release_get_title, release);
+
+  credit = mb4_release_get_artistcredit (release);
+
+  artists = get_artist_list (credit);
+  if (artists) {
+    get_artist_info (artists, &album->artist,
+                     &album->artist_sortname,
+                     &album->artist_id);
+  }
+  album->artists = artists;
+
+  GET (date, mb4_release_get_date, release);
+  album->release_date = sj_metadata_helper_scan_date (date);
+  g_free (date);
+
+  GET (album->asin, mb4_release_get_asin, release);
+  GET (album->country, mb4_release_get_country, release);
+  if (group) {
+    GET (album->type, mb4_releasegroup_get_type, group);
+    if (g_str_has_suffix (album->type, "Spokenword")
+        || g_str_has_suffix (album->type, "Interview")
+        || g_str_has_suffix (album->type, "Audiobook")) {
+      album->is_spoken_word = TRUE;
+    }
+    fill_relations (mb4_releasegroup_get_relationlist(group), album);
+  }
+
+  album->disc_number = mb4_medium_get_position (medium);
+  fill_tracks_from_medium (medium, album);
+  fill_relations (mb4_release_get_relationlist (release), album);
+
+  sj_mb4_album_details_dump (album);
+  return album;
+}
+
+/*
+ * Virtual methods
+ */
+static GList *
+mb4_list_albums (SjMetadata *metadata, char **url, GError **error)
+{
+  SjMetadataMusicbrainz4Private *priv;
+  GList *albums = NULL;
+  Mb4ReleaseList releases;
+  Mb4Release release;
+  const char *discid = NULL;
+  char buffer[1024];
+  int i;
+  g_return_val_if_fail (SJ_IS_METADATA_MUSICBRAINZ4 (metadata), NULL);
+
+  priv = GET_PRIVATE (metadata);
+
+  if (sj_metadata_helper_check_media (priv->cdrom, error) == FALSE) {
+    return NULL;
+  }
+
+  priv->disc = discid_new ();
+  if (priv->disc == NULL)
+    return NULL;
+  if (discid_read (priv->disc, priv->cdrom) == 0)
+    return NULL;
+
+  if (url != NULL)
+    *url = g_strdup (discid_get_submission_url (priv->disc));
+
+  if (g_getenv("MUSICBRAINZ_FORCE_DISC_ID")) {
+    discid = g_getenv("MUSICBRAINZ_FORCE_DISC_ID");
+  } else {
+    discid = discid_get_id (priv->disc);
+  }
+
+  releases = mb4_query_lookup_discid(priv->mb, discid);
+
+  if (releases == NULL) {
+    return NULL;
+  }
+
+  if (mb4_release_list_size (releases) == 0) {
+    return NULL;
+  }
+
+  for (i = 0; i < mb4_release_list_size (releases); i++) {
+    AlbumDetails *album;
+
+    release = mb4_release_list_item (releases, i);
+    if (release) {
+      char *releaseid = NULL;
+      Mb4Release full_release;
+
+      releaseid = NULL;
+      GET(releaseid, mb4_release_get_id, release);
+
+      full_release = mb4_query_lookup_release (priv->mb, releaseid);
+      g_free (releaseid);
+      if (full_release) {
+        Mb4MediumList media;
+        Mb4Metadata metadata = NULL;
+        Mb4ReleaseGroup group;
+        unsigned int j;
+
+        group = mb4_release_get_releasegroup (full_release);
+        if (group) {
+          /* The release-group information we can extract from the
+           * lookup_release query doesn't have the url relations for the
+           * release-group, so run a separate query to get these urls
+           */
+          char *releasegroupid = NULL;
+          char *params_names[] = { "inc" };
+          char *params_values[] = { "artists url-rels" };
+
+          GET (releasegroupid, mb4_releasegroup_get_id, group);
+          metadata = mb4_query_query (priv->mb, "release-group", releasegroupid, "",
+                                      1, params_names, params_values);
+          g_free (releasegroupid);
+        }
+
+        if (metadata && mb4_metadata_get_releasegroup (metadata))
+          group = mb4_metadata_get_releasegroup (metadata);
+
+        media = mb4_release_media_matching_discid (full_release, discid);
+        for (j = 0; j < mb4_medium_list_size (media); j++) {
+          Mb4Medium medium;
+          medium = mb4_medium_list_item (media, j);
+          if (medium) {
+            album = make_album_from_release (group, full_release, medium);
+            album->metadata_source = SOURCE_MUSICBRAINZ;
+            albums = g_list_append (albums, album);
+          }
+        }
+        mb4_metadata_delete (metadata);
+        mb4_medium_list_delete (media);
+        mb4_release_delete (full_release);
+      }
+    }
+  }
+  mb4_release_list_delete (releases);
+  return albums;
+}
+
+/*
+ * GObject methods
+ */
+
+static void
+metadata_interface_init (gpointer g_iface, gpointer iface_data)
+{
+  SjMetadataClass *klass = (SjMetadataClass*)g_iface;
+
+  klass->list_albums = mb4_list_albums;
+}
+
+static void
+sj_metadata_musicbrainz4_init (SjMetadataMusicbrainz4 *self)
+{
+  GConfClient *gconf_client;
+  gchar *server_name;
+
+  SjMetadataMusicbrainz4Private *priv;
+
+  priv = GET_PRIVATE (self);
+
+  gconf_client = gconf_client_get_default ();
+
+  server_name = gconf_client_get_string (gconf_client, GCONF_MUSICBRAINZ_SERVER, NULL);
+
+  if (server_name && (*server_name == '\0')) {
+    g_free (server_name);
+    server_name = NULL;
+  }
+
+  priv->mb = mb4_query_new (SJ_MUSICBRAINZ_USER_AGENT, server_name, 0);
+  g_free (server_name);
+
+
+  /* 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);
+    mb4_query_set_proxyhost (priv->mb, proxy_host);
+    g_free (proxy_host);
+
+    port = gconf_client_get_int (gconf_client, GCONF_PROXY_PORT, NULL);
+    mb4_query_set_proxyport (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);
+      mb4_query_set_proxyusername (priv->mb, username);
+      g_free (username);
+
+      password = gconf_client_get_string (gconf_client, GCONF_PROXY_PASSWORD, NULL);
+      mb4_query_set_proxypassword (priv->mb, password);
+      g_free (password);
+    }
+  }
+
+  g_object_unref (gconf_client);
+}
+
+static void
+sj_metadata_musicbrainz4_get_property (GObject *object, guint property_id,
+                                       GValue *value, GParamSpec *pspec)
+{
+  SjMetadataMusicbrainz4Private *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_musicbrainz4_set_property (GObject *object, guint property_id,
+                                       const GValue *value, GParamSpec *pspec)
+{
+  SjMetadataMusicbrainz4Private *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 "" ? */
+    mb4_query_set_proxyhost (priv->mb, priv->http_proxy);
+    break;
+  case PROP_PROXY_PORT:
+    priv->http_proxy_port = g_value_get_int (value);
+    mb4_query_set_proxyport (priv->mb, priv->http_proxy_port);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+sj_metadata_musicbrainz4_finalize (GObject *object)
+{
+  SjMetadataMusicbrainz4Private *priv;
+
+  priv = GET_PRIVATE (object);
+
+  if (priv->mb != NULL) {
+    mb4_query_delete (priv->mb);
+    priv->mb = NULL;
+  }
+  if (priv->disc != NULL) {
+      discid_free (priv->disc);
+      priv->disc = NULL;
+  }
+  g_free (priv->cdrom);
+
+  G_OBJECT_CLASS (sj_metadata_musicbrainz4_parent_class)->finalize (object);
+}
+
+static void
+sj_metadata_musicbrainz4_class_init (SjMetadataMusicbrainz4Class *class)
+{
+  GObjectClass *object_class = (GObjectClass*)class;
+
+  g_type_class_add_private (class, sizeof (SjMetadataMusicbrainz4Private));
+
+  object_class->get_property = sj_metadata_musicbrainz4_get_property;
+  object_class->set_property = sj_metadata_musicbrainz4_set_property;
+  object_class->finalize = sj_metadata_musicbrainz4_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_musicbrainz4_new (void)
+{
+  return g_object_new (SJ_TYPE_METADATA_MUSICBRAINZ4, NULL);
+}
diff --git a/plugins/audiocd/sj-metadata-musicbrainz4.h b/plugins/audiocd/sj-metadata-musicbrainz4.h
new file mode 100644
index 0000000..5a73e9b
--- /dev/null
+++ b/plugins/audiocd/sj-metadata-musicbrainz4.h
@@ -0,0 +1,56 @@
+/*
+ * sj-metadata-musicbrainz4.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_MUSICBRAINZ4_H
+#define SJ_METADATA_MUSICBRAINZ4_H
+
+#include <glib-object.h>
+#include "sj-metadata.h"
+
+G_BEGIN_DECLS
+
+#define SJ_TYPE_METADATA_MUSICBRAINZ4           (sj_metadata_musicbrainz4_get_type ())
+#define SJ_METADATA_MUSICBRAINZ4(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), SJ_TYPE_METADATA_MUSICBRAINZ4, SjMetadataMusicbrainz4))
+#define SJ_METADATA_MUSICBRAINZ4_CLASS(vtable)  (G_TYPE_CHECK_CLASS_CAST ((vtable), SJ_TYPE_METADATA_MUSICBRAINZ4, SjMetadataMusicbrainz4Class))
+#define SJ_IS_METADATA_MUSICBRAINZ4(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SJ_TYPE_METADATA_MUSICBRAINZ4))
+#define SJ_IS_METADATA_MUSICBRAINZ4_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), SJ_TYPE_METADATA_MUSICBRAINZ4))
+#define SJ_METADATA_MUSICBRAINZ4_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SJ_TYPE_METADATA_MUSICBRAINZ4, SjMetadataMusicbrainz4Class))
+
+typedef struct _SjMetadataMusicbrainz4 SjMetadataMusicbrainz4;
+typedef struct _SjMetadataMusicbrainz4Class SjMetadataMusicbrainz4Class;
+
+struct _SjMetadataMusicbrainz4
+{
+  GObject parent;
+};
+
+struct _SjMetadataMusicbrainz4Class
+{
+  GObjectClass parent;
+};
+
+GType sj_metadata_musicbrainz4_get_type (void);
+
+GObject *sj_metadata_musicbrainz4_new (void);
+
+G_END_DECLS
+
+#endif /* SJ_METADATA_MUSICBRAINZ4_H */
diff --git a/plugins/audiocd/sj-metadata.c b/plugins/audiocd/sj-metadata.c
index 797c9ff..ce25cf6 100644
--- a/plugins/audiocd/sj-metadata.c
+++ b/plugins/audiocd/sj-metadata.c
@@ -175,10 +175,19 @@ sj_metadata_helper_check_media (const char *cdrom, GError **error)
 
   /* This initialize the library if it isn't done yet */
   monitor = brasero_medium_monitor_get_default ();
+  if (brasero_medium_monitor_is_probing (monitor)) {
+      /* FIXME: would be nicer to only check if "cdrom" is being probed,
+       * but libbrasero doesn't seem to have an API for that
+       */
+      g_set_error (error, SJ_ERROR, SJ_ERROR_CD_BUSY, _("Cannot read CD: %s"),
+                   _("Devices haven't been all probed yet"));
+      return FALSE;
+  }
   drive = brasero_medium_monitor_get_drive (monitor, cdrom);
   if (drive == NULL) {
     return FALSE;
   }
+
   medium = brasero_drive_get_medium (drive);
   g_object_unref (drive);
 
diff --git a/plugins/audiocd/sj-structures.c b/plugins/audiocd/sj-structures.c
index 3d23ce6..b4577d4 100644
--- a/plugins/audiocd/sj-structures.c
+++ b/plugins/audiocd/sj-structures.c
@@ -35,6 +35,8 @@ void track_details_free(TrackDetails *track)
   g_free (track->track_id);
   g_free (track->artist_id);
   g_free (track->artist_sortname);
+  g_list_foreach (track->artists, (GFunc)artist_details_free, NULL);
+
   g_free (track);
 }
 
@@ -55,5 +57,25 @@ void album_details_free(AlbumDetails *album)
   g_free (album->asin);
   g_free (album->discogs);
   g_free (album->wikipedia);
+  g_free (album->lyrics_url);
+  g_free (album->country);
+  g_free (album->type);
+  g_list_foreach (album->artists, (GFunc)artist_details_free, NULL);
+
   g_free (album);
 }
+
+/*
+ * Free a ArtistDetails*
+ */
+void artist_details_free (ArtistDetails *artist)
+{
+  g_free (artist->id);
+  g_free (artist->name);
+  g_free (artist->sortname);
+  g_free (artist->disambiguation);
+  g_free (artist->gender);
+  g_free (artist->country);
+  g_free (artist->joinphrase);
+  g_free (artist);
+}
diff --git a/plugins/audiocd/sj-structures.h b/plugins/audiocd/sj-structures.h
index 07ccc60..46d67e9 100644
--- a/plugins/audiocd/sj-structures.h
+++ b/plugins/audiocd/sj-structures.h
@@ -29,6 +29,7 @@
 typedef enum _MetadataSource MetadataSource;
 
 typedef struct _AlbumDetails AlbumDetails;
+typedef struct _ArtistDetails ArtistDetails;
 typedef struct _TrackDetails TrackDetails;
 
 enum _MetadataSource {
@@ -48,6 +49,7 @@ struct _TrackDetails {
   int duration; /* seconds */
   char* track_id;
   char* artist_id;
+  GList *artists;
 };
 
 struct _AlbumDetails {
@@ -66,9 +68,32 @@ struct _AlbumDetails {
   char* wikipedia;
   MetadataSource metadata_source;
   gboolean is_spoken_word;
+
+  /* some of the new properties that we can get with the NGS musicbrainz
+   * API
+   */
+  char *type;
+  char *lyrics_url;
+  char *country;
+  GList *artists;
 };
 
+struct _ArtistDetails {
+  char *id;
+  char *name;
+  char *sortname;
+  char *disambiguation;
+  char *gender;
+  char *country;
+
+  /* doesn't belong in here, prevent sharing the artist structure between
+   * distinct ReleaseGroups - more convenient for now */
+  char *joinphrase;
+};
+
+
 void album_details_free(AlbumDetails *album);
+void artist_details_free(ArtistDetails *artist);
 void track_details_free(TrackDetails *track);
 
 #endif



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