/* * sj-metadata-musicbrainz3.c * Copyright (C) 2008 Ross Burton * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #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; /* 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; GList *albums = NULL; 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), NULL); priv = GET_PRIVATE (metadata); if (sj_metadata_helper_check_media (priv->cdrom, error) == FALSE) { 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 (results == NULL) { mb_query_free (query); return NULL; } 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); albums = g_list_append (albums, album); mb_release_free (release); } mb_result_list_free (results); mb_query_free (query); 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 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); }