diff options
author | Bastien Nocera <hadess@hadess.net> | 2008-09-03 18:47:17 +0000 |
---|---|---|
committer | Bastien Nocera <hadess@src.gnome.org> | 2008-09-03 18:47:17 +0000 |
commit | 1b3f6985ff6eb5eb58274f4a57a781617feec463 (patch) | |
tree | d33e580fee68853ed4c34a8462aae0f0568551d4 /libjuicer | |
parent | a24b08ed586873b21e905119dfab018aed9b3c0e (diff) |
Check for libmusicbrainz3, and require libcdio
2008-09-03 Bastien Nocera <hadess@hadess.net>
* configure.in: Check for libmusicbrainz3, and require libcdio
* libjuicer/Makefile.am:
* libjuicer/sj-metadata-getter.c:
* libjuicer/sj-metadata-getter.h: Add a helper object to gather
data from different metadata backends, with fallback support. The
threading is now in the helper object, and not in the metadata
backends themselves. The backends don't have signals anymore,
and are synchronous.
* libjuicer/sj-metadata-cdtext.c (cdtext_list_albums),
(sj_metadata_cdtext_finalize):
* libjuicer/sj-metadata-musicbrainz.c (mb_list_albums),
(metadata_interface_init):
* libjuicer/sj-metadata.c (sj_metadata_base_init),
(sj_metadata_list_albums):
* libjuicer/sj-metadata.h:
* libjuicer/sj-structures.h:
* src/sj-main.c (metadata_cb), (reread_cd), (set_device),
(http_proxy_setup), (main):
* tests/mb-test.c (source_to_str), (metadata_cb), (main):
Change for the above
* libjuicer/sj-metadata-musicbrainz3.c:
* libjuicer/sj-metadata-musicbrainz3.h: Add libmusicbrainz3 support
(Closes: #516447)
2008-09-03 Bastien Nocera <hadess@hadess.net>
* POTFILES.in: upd
svn path=/trunk/; revision=2279
Diffstat (limited to 'libjuicer')
-rw-r--r-- | libjuicer/Makefile.am | 22 | ||||
-rw-r--r-- | libjuicer/sj-metadata-cdtext.c | 47 | ||||
-rw-r--r-- | libjuicer/sj-metadata-getter.c | 251 | ||||
-rw-r--r-- | libjuicer/sj-metadata-getter.h | 62 | ||||
-rw-r--r-- | libjuicer/sj-metadata-musicbrainz.c | 111 | ||||
-rw-r--r-- | libjuicer/sj-metadata-musicbrainz3.c | 451 | ||||
-rw-r--r-- | libjuicer/sj-metadata-musicbrainz3.h | 55 | ||||
-rw-r--r-- | libjuicer/sj-metadata.c | 24 | ||||
-rw-r--r-- | libjuicer/sj-metadata.h | 9 | ||||
-rw-r--r-- | libjuicer/sj-structures.h | 3 |
10 files changed, 872 insertions, 163 deletions
diff --git a/libjuicer/Makefile.am b/libjuicer/Makefile.am index 6519f28..7a26447 100644 --- a/libjuicer/Makefile.am +++ b/libjuicer/Makefile.am @@ -12,6 +12,10 @@ libjuicer_la_SOURCES = \ sj-metadata.c \ sj-metadata-musicbrainz.h \ sj-metadata-musicbrainz.c \ + sj-metadata-cdtext.h \ + sj-metadata-cdtext.c \ + sj-metadata-getter.c \ + sj-metadata-getter.h \ sj-util.h sj-util.c libjuicer_la_CPPFLAGS = \ @@ -21,33 +25,31 @@ libjuicer_la_CPPFLAGS = \ libjuicer_la_CFLAGS = \ $(WARN_CFLAGS) \ $(MUSICBRAINZ_CFLAGS) \ + $(MUSICBRAINZ3_CFLAGS) \ $(GSTREAMER_CFLAGS) \ $(MEDIA_PROFILES_CFLAGS) \ $(BURN_CFLAGS) \ $(UI_CFLAGS) \ + $(CDIO_CFLAGS) \ $(AM_CFLAGS) libjuicer_la_LIBADD = \ $(MUSICBRAINZ_LIBS) \ + $(MUSICBRAINZ3_LIBS) \ $(MEDIA_PROFILES_LIBS) \ $(GSTREAMER_LIBS) \ $(BURN_LIBS) \ - $(UI_LIBS) + $(UI_LIBS) \ + $(CDIO_LIBS) libjuicer_la_LDFLAGS = \ -export-dynamic \ $(AM_LDFLAGS) -if HAVE_CDIO +if HAVE_MB3 libjuicer_la_SOURCES += \ - sj-metadata-cdtext.h \ - sj-metadata-cdtext.c - -libjuicer_la_CFLAGS += \ - $(CDIO_CFLAGS) - -libjuicer_la_LDFLAGS += \ - $(CDIO_LIBS) + sj-metadata-musicbrainz3.h \ + sj-metadata-musicbrainz3.c endif # diff --git a/libjuicer/sj-metadata-cdtext.c b/libjuicer/sj-metadata-cdtext.c index dde7343..5796e69 100644 --- a/libjuicer/sj-metadata-cdtext.c +++ b/libjuicer/sj-metadata-cdtext.c @@ -40,7 +40,6 @@ struct SjMetadataCdtextPrivate { char *cdrom; GList *albums; - GError *error; }; #define GET_PRIVATE(o) \ @@ -64,35 +63,25 @@ G_DEFINE_TYPE_WITH_CODE (SjMetadataCdtext, sj_metadata_cdtext, * Private methods */ -static gboolean -fire_signal_idle (SjMetadataCdtext *m) +static GList * +cdtext_list_albums (SjMetadata *metadata, char **url, GError **error) { - g_return_val_if_fail (SJ_IS_METADATA_CDTEXT (m), FALSE); - g_signal_emit_by_name (G_OBJECT (m), "metadata", m->priv->albums, m->priv->error); - return FALSE; -} - -static void -cdtext_list_albums (SjMetadata *metadata, GError **error) -{ - /* TODO: put in a thread */ SjMetadataCdtextPrivate *priv; AlbumDetails *album; CdIo *cdio; track_t cdtrack, last_cdtrack; const cdtext_t *cdtext; - g_return_if_fail (SJ_IS_METADATA_CDTEXT (metadata)); + g_return_val_if_fail (SJ_IS_METADATA_CDTEXT (metadata), NULL); priv = SJ_METADATA_CDTEXT (metadata)->priv; cdio = cdio_open (priv->cdrom, DRIVER_UNKNOWN); if (!cdio) { g_warning ("Cannot open CD"); - priv->error = g_error_new (SJ_ERROR, SJ_ERROR_INTERNAL_ERROR, _("Cannot read CD")); + g_set_error (error, SJ_ERROR, SJ_ERROR_INTERNAL_ERROR, _("Cannot read CD")); priv->albums = NULL; - g_idle_add ((GSourceFunc)fire_signal_idle, metadata); - return; + return NULL; } #if 0 @@ -120,7 +109,8 @@ cdtext_list_albums (SjMetadata *metadata, GError **error) track->title = g_strdup (cdtext_get (CDTEXT_TITLE, cdtext)); track->artist = g_strdup (cdtext_get (CDTEXT_PERFORMER, cdtext)); } else { - g_print ("No CD-TEXT for track %u\n", cdtrack); + track->title = g_strdup_printf (_("Track %d"), cdtrack); + track->artist = g_strdup (_("Unknown Artist")); } track->duration = cdio_get_track_sec_count (cdio, cdtrack) / CDIO_CD_FRAMES_PER_SEC; @@ -130,15 +120,24 @@ cdtext_list_albums (SjMetadata *metadata, GError **error) /* TODO: why can't I do this first? */ cdtext = cdio_get_cdtext(cdio, 0); - album->title = g_strdup (cdtext_get (CDTEXT_TITLE, cdtext)); - album->artist = g_strdup (cdtext_get (CDTEXT_PERFORMER, cdtext)); - album->genre = g_strdup (cdtext_get (CDTEXT_GENRE, cdtext)); + if (cdtext) { + album->title = g_strdup (cdtext_get (CDTEXT_TITLE, cdtext)); + album->artist = g_strdup (cdtext_get (CDTEXT_PERFORMER, cdtext)); + album->genre = g_strdup (cdtext_get (CDTEXT_GENRE, cdtext)); + + album->metadata_source = SOURCE_CDTEXT; + } else { + album->artist = g_strdup (_("Unknown Artist")); + album->title = g_strdup (_("Unknown Title")); + album->genre = g_strdup (""); + + album->metadata_source = SOURCE_FALLBACK; + } - album->metadata_source = SOURCE_CDTEXT; - priv->error = NULL; priv->albums = g_list_append (NULL, album); - g_idle_add ((GSourceFunc)fire_signal_idle, metadata); + + return priv->albums; } @@ -198,8 +197,6 @@ sj_metadata_cdtext_finalize (GObject *object) SjMetadataCdtextPrivate *priv = SJ_METADATA_CDTEXT (object)->priv; g_free (priv->cdrom); g_list_deep_free (priv->albums, (GFunc)album_details_free); - if (priv->error) - g_error_free (priv->error); } static void diff --git a/libjuicer/sj-metadata-getter.c b/libjuicer/sj-metadata-getter.c new file mode 100644 index 0000000..6c08f46 --- /dev/null +++ b/libjuicer/sj-metadata-getter.c @@ -0,0 +1,251 @@ +/* + * 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_MB3 +#include "sj-metadata-musicbrainz3.h" +#endif /* HAVE_MB3 */ +#include "sj-metadata-musicbrainz.h" +#include "sj-metadata-cdtext.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); + + if (priv->cdrom) + g_free (priv->cdrom); + 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_MB3 + SJ_TYPE_METADATA_MUSICBRAINZ3, +#endif /* HAVE_MB3 */ + SJ_TYPE_METADATA_MUSICBRAINZ, + SJ_TYPE_METADATA_CDTEXT, + }; + + 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; +} + diff --git a/libjuicer/sj-metadata-getter.h b/libjuicer/sj-metadata-getter.h new file mode 100644 index 0000000..05b93a4 --- /dev/null +++ b/libjuicer/sj-metadata-getter.h @@ -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 */ diff --git a/libjuicer/sj-metadata-musicbrainz.c b/libjuicer/sj-metadata-musicbrainz.c index b78d8a5..c221ae4 100644 --- a/libjuicer/sj-metadata-musicbrainz.c +++ b/libjuicer/sj-metadata-musicbrainz.c @@ -55,9 +55,7 @@ struct SjMetadataMusicbrainzPrivate { char *http_proxy; int http_proxy_port; char *cdrom; - /* TODO: remove and use an async queue? */ GList *albums; - GError *error; GRegex *disc_regex; }; @@ -94,54 +92,6 @@ 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; - } - - 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; -} - /** * Virtual methods */ @@ -324,8 +274,8 @@ convert_encoding(char **str) g_free (iso8859); } -static gpointer -lookup_cd (SjMetadata *metadata) +static GList * +mb_list_albums (SjMetadata *metadata, char **url, GError **error) { /** The size of the buffer used in MusicBrainz lookups */ SjMetadataMusicbrainzPrivate *priv; @@ -338,12 +288,10 @@ lookup_cd (SjMetadata *metadata) NautilusBurnDriveMonitor *monitor; NautilusBurnDrive *drive; - /* 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 */ if (! nautilus_burn_initialized ()) { nautilus_burn_init (); @@ -367,21 +315,24 @@ lookup_cd (SjMetadata *metadata) msg = g_strdup_printf (_("Device '%s' could not be opened. Check the access permissions on the device."), priv->cdrom); err = SJ_ERROR_CD_PERMISSION_ERROR; } - priv->error = g_error_new (SJ_ERROR, err, _("Cannot read CD: %s"), msg); + g_set_error (error, SJ_ERROR, err, _("Cannot read CD: %s"), msg); g_free (msg); 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++) { @@ -467,9 +418,8 @@ lookup_cd (SjMetadata *metadata) 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++) { @@ -561,45 +511,9 @@ lookup_cd (SjMetadata *metadata) } } - priv->albums = albums; - g_idle_add ((GSourceFunc)fire_signal_idle, metadata); return albums; } -static void -mb_list_albums (SjMetadata *metadata, GError **error) -{ - GThread *thread; - - g_return_if_fail (SJ_IS_METADATA_MUSICBRAINZ (metadata)); - - 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; - } -} - -static char * -mb_get_submit_url (SjMetadata *metadata) -{ - SjMetadataMusicbrainzPrivate *priv; - char url[1025]; - - g_return_val_if_fail (metadata != NULL, NULL); - - priv = SJ_METADATA_MUSICBRAINZ (metadata)->priv; - - if (mb_GetWebSubmitURL(priv->mb, url, 1024)) { - return g_strdup(url); - } else { - return NULL; - } -} - - /* * GObject methods */ @@ -609,7 +523,6 @@ metadata_interface_init (gpointer g_iface, gpointer iface_data) { SjMetadataClass *klass = (SjMetadataClass*)g_iface; klass->list_albums = mb_list_albums; - klass->get_submit_url = mb_get_submit_url; } static void diff --git a/libjuicer/sj-metadata-musicbrainz3.c b/libjuicer/sj-metadata-musicbrainz3.c new file mode 100644 index 0000000..f59dbb0 --- /dev/null +++ b/libjuicer/sj-metadata-musicbrainz3.c @@ -0,0 +1,451 @@ +/* + * sj-metadata-musicbrainz3.c + * Copyright (C) 2008 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <glib.h> +#include <glib-object.h> +#include <glib/gi18n.h> +#include <gconf/gconf-client.h> +#include <nautilus-burn.h> +#include <musicbrainz3/mb_c.h> + +#include "sj-metadata-musicbrainz3.h" +#include "sj-metadata-cdtext.h" +#include "sj-structures.h" +#include "sj-error.h" + +#define GET(field, function, obj) function (obj, buffer, sizeof (buffer)); if (field) g_free (field); 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; + GRegex *disc_regex; + GMatchInfo *info; + 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); + disc_regex = g_regex_new (".+( \\(disc (\\d+).*)", 0, 0, NULL); + + 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) { + s = g_strndup (album->title, pos); + g_free (album->title); + album->title = s; + } + + s = g_match_info_fetch (info, 2); + album->disc_number = atoi (s); + g_free (s); + } + + g_match_info_free (info); + g_regex_unref (disc_regex); + + 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; + int matched, year=1, month=1, day=1; + + event = mb_release_get_release_event (release, 1); + GET (date, mb_release_event_get_date, event); + matched = sscanf(date, "%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); + 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 < 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; + NautilusBurnMediaType type; + NautilusBurnDriveMonitor *monitor; + NautilusBurnDrive *drive; + + g_return_val_if_fail (SJ_IS_METADATA_MUSICBRAINZ3 (metadata), FALSE); + + priv = GET_PRIVATE (metadata); + + if (! nautilus_burn_initialized ()) { + nautilus_burn_init (); + } + monitor = nautilus_burn_get_drive_monitor (); + drive = nautilus_burn_drive_monitor_get_drive_for_device (monitor, priv->cdrom); + if (drive == NULL) { + return NULL; + } + 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 (priv->cdrom, W_OK) == 0) { + msg = g_strdup_printf (_("Device '%s' does not contain any media"), priv->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."), priv->cdrom); + err = SJ_ERROR_CD_PERMISSION_ERROR; + } + g_set_error (error, SJ_ERROR, err, _("Cannot read CD: %s"), msg); + g_free (msg); + + 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); + } + + 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); + + 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); +} diff --git a/libjuicer/sj-metadata-musicbrainz3.h b/libjuicer/sj-metadata-musicbrainz3.h new file mode 100644 index 0000000..1d4684b --- /dev/null +++ b/libjuicer/sj-metadata-musicbrainz3.h @@ -0,0 +1,55 @@ +/* + * sj-metadata-musicbrainz3.h + * Copyright (C) 2008 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. + */ + +#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 */ diff --git a/libjuicer/sj-metadata.c b/libjuicer/sj-metadata.c index 4772e7d..6e96223 100644 --- a/libjuicer/sj-metadata.c +++ b/libjuicer/sj-metadata.c @@ -27,21 +27,11 @@ enum { LAST_SIGNAL }; -static int signals[LAST_SIGNAL] = { 0 }; - static void sj_metadata_base_init (gpointer g_iface) { static gboolean initialized = FALSE; if (!initialized) { - signals[METADATA] = g_signal_new ("metadata", - G_TYPE_FROM_CLASS (g_iface), - 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, @@ -106,17 +96,9 @@ sj_metadata_set_proxy_port (SjMetadata *metadata, const int 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) -{ - if (SJ_METADATA_GET_CLASS (metadata)->get_submit_url) - return SJ_METADATA_GET_CLASS (metadata)->get_submit_url (metadata); - else - return NULL; -} diff --git a/libjuicer/sj-metadata.h b/libjuicer/sj-metadata.h index 1e153bb..acb4330 100644 --- a/libjuicer/sj-metadata.h +++ b/libjuicer/sj-metadata.h @@ -40,20 +40,15 @@ struct _SjMetadataClass { GTypeInterface g_iface; - /* Signals */ - void (*metadata) (SjMetadata *md, GList *albums, GError *error); - /* Virtual Table */ - 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); 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); G_END_DECLS diff --git a/libjuicer/sj-structures.h b/libjuicer/sj-structures.h index 840aa92..284d524 100644 --- a/libjuicer/sj-structures.h +++ b/libjuicer/sj-structures.h @@ -35,7 +35,8 @@ enum _MetadataSource { SOURCE_UNKNOWN = 0, SOURCE_CDTEXT, SOURCE_FREEDB, - SOURCE_MUSICBRAINZ + SOURCE_MUSICBRAINZ, + SOURCE_FALLBACK }; struct _TrackDetails { |