From: phantomjinx <pha...@us...> - 2012-06-01 08:18:28
|
commit 0ca1e68ddd703d6b30de2888c67119b97d55d0c7 Author: phantomjinx <p.g...@ph...> Date: Fri May 25 09:57:55 2012 +0100 Update and fix sjcd plugin * Update sjcd plugin to reflect latest developements in sound juicer including use of musicbrainz 4 * sj_extracting.c * Avoid segfaulting if a track value is empty. Happen to have a CD that failed to return any track names for an album - maybe a bug in the sound juicer musicbrainz 4 code configure.ac | 50 ++- plugins/sjcd/data/Makefile.am | 1 + plugins/sjcd/libjuicer/Makefile.am | 13 +- plugins/sjcd/libjuicer/sj-metadata-getter.c | 6 + plugins/sjcd/libjuicer/sj-metadata-musicbrainz4.c | 621 +++++++++++++++++++++ plugins/sjcd/libjuicer/sj-metadata-musicbrainz4.h | 56 ++ plugins/sjcd/libjuicer/sj-structures.c | 22 + plugins/sjcd/libjuicer/sj-structures.h | 25 + plugins/sjcd/sj-extracting.c | 15 + plugins/sjcd/sj-main.c | 23 +- po/POTFILES.in | 1 + 11 files changed, 796 insertions(+), 37 deletions(-) --- diff --git a/configure.ac b/configure.ac index 779f3dd..ed37002 100644 --- a/configure.ac +++ b/configure.ac @@ -105,6 +105,7 @@ PKG_CHECK_MODULES(BRASERO, libbrasero-media3 >= 3.0, [have_brasero="yes"], [have dnl musicbrainz 3 is deprecated so may not be included. However required by sound juicer dnl will probably need replacing faily soon PKG_CHECK_MODULES(MUSICBRAINZ3, libmusicbrainz3 >= 3.0.2, [have_mb3="yes"], [have_mb3="no"]) +PKG_CHECK_MODULES(MUSICBRAINZ4, libmusicbrainz4 >= 4.0.0, [have_mb4="yes"], [have_mb4="no"]) GTK_CLEANLINESS_FLAGS="-DG_DISABLE_SINGLE_INCLUDES -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES -DGTK_DISABLE_SINGLE_INCLUDES -DGSEAL_ENABLE" @@ -189,7 +190,7 @@ dnl Check for libcurl dnl ------------------------------------------------------------- AC_ARG_WITH(curl, AS_HELP_STRING([--without-curl],[Disable coverart download support])) if test "x$with_curl" != "xno" -a "x$have_curl" = "xno"; then - AC_MSG_ERROR([curl support explicitly requested but curl couldn't be found]) + AC_MSG_ERROR([curl support explicitly requested but curl could not be found]) fi AM_CONDITIONAL(HAVE_CURL, test "x$have_curl" = "xyes") @@ -287,7 +288,7 @@ dnl Checks for filetype_ogg plugin dnl ------------------------------------------------------------- AC_ARG_WITH(ogg, AS_HELP_STRING([--without-ogg],[Disable Ogg/Vorbis support])) if test "x$with_ogg" != "xno" -a "x$have_vorbis" = "xno"; then - AC_MSG_ERROR([Ogg/Vorbis support explicitly requested but ogg/vorbis libs couldn't be found]) + AC_MSG_ERROR([Ogg/Vorbis support explicitly requested but ogg/vorbis libs could not be found]) fi AM_CONDITIONAL(HAVE_PLUGIN_FILETYPE_OGG, test "x$have_vorbis" = "xyes") if test "x$have_vorbis" = "xyes"; then @@ -299,7 +300,7 @@ dnl Checks for filetype_flac plugin dnl ------------------------------------------------------------- AC_ARG_WITH(flac, AS_HELP_STRING([--without-flac],[Disable FLAC support])) if test "xwith_flac" = "xyes" -a "x$have_flac" = "xno"; then - AC_MSG_ERROR([FLAC support explicitly requested but flac libs couldn't be found]) + AC_MSG_ERROR([FLAC support explicitly requested but flac libs could not be found]) fi AM_CONDITIONAL(HAVE_PLUGIN_FILETYPE_FLAC, test "x$have_flac" = "xyes") if test "x$have_flac" = "xyes"; then @@ -357,23 +358,42 @@ if test "$user_disabled_sjcd" = 1; then else AC_MSG_RESULT(no) AC_MSG_CHECKING(sjcd plugin dependencies) - if test "x$have_gstreamer" = "xyes" -a "x$have_brasero" = "xyes" -a "x$have_mb3" = "xyes"; then - AC_MSG_RESULT(yes) - have_sjcd="yes" + if test "x$have_gstreamer" = "xyes" -a "x$have_brasero" = "xyes"; then + if test "x$have_mb3" = "xyes" -o "x$have_mb4" = "xyes"; then + + AC_MSG_RESULT(yes) + have_sjcd="yes" - dnl Checks for components of gstreamer - AM_GST_ELEMENT_CHECK(vorbisenc,,AC_MSG_WARN([The 'vorbisenc' element was not found. This will cause encoding to Ogg Vorbis to fail.])) - AM_GST_ELEMENT_CHECK(flacenc,,AC_MSG_WARN([The 'flacenc' element was not found. This will cause encoding to FLAC to fail.])) - AM_GST_ELEMENT_CHECK(wavenc,,AC_MSG_WARN([The 'wavenc' element was not found. This will cause encoding to Wave to fail.])) - AM_GST_ELEMENT_CHECK(giosink,,AC_MSG_WARN([The 'giosink' element was not found. This will cause Sound Juicer to fail at runtime.])) + dnl Checks for components of gstreamer + AM_GST_ELEMENT_CHECK(vorbisenc,,AC_MSG_WARN([The 'vorbisenc' element was not found. This will cause encoding to Ogg Vorbis to fail.])) + AM_GST_ELEMENT_CHECK(flacenc,,AC_MSG_WARN([The 'flacenc' element was not found. This will cause encoding to FLAC to fail.])) + AM_GST_ELEMENT_CHECK(wavenc,,AC_MSG_WARN([The 'wavenc' element was not found. This will cause encoding to Wave to fail.])) + AM_GST_ELEMENT_CHECK(giosink,,AC_MSG_WARN([The 'giosink' element was not found. This will cause Sound Juicer to fail at runtime.])) - AC_DEFINE([HAVE_MUSICBRAINZ3], 1, [Whether libmusicbrainz3 is available]) - else - AC_MSG_RESULT(no) + if test "x$have_mb4" = "xyes"; then + AC_DEFINE([HAVE_MUSICBRAINZ4], 1, [Whether libmusicbrainz4 is available]) + elif test "x$have_mb3" = "xyes"; then + dnl fallback to musicbrainz 3 + AC_DEFINE([HAVE_MUSICBRAINZ3], 1, [Whether libmusicbrainz3 is available]) + fi + + else + AC_MSG_RESULT(no) + fi fi fi -AM_CONDITIONAL(HAVE_MUSICBRAINZ3, [test "x$have_mb3" = "xyes"]) +if test "x$have_mb4" = "xyes"; then + AM_CONDITIONAL(HAVE_MUSICBRAINZ4, true) + dnl do not need musicbrainz 3 + AM_CONDITIONAL(HAVE_MUSICBRAINZ3, false) +elif test "xhave_mb3" = "xyes"; then + AM_CONDITIONAL(HAVE_MUSICBRAINZ4, false) + AM_CONDITIONAL(HAVE_MUSICBRAINZ3, true) +else + AM_CONDITIONAL(HAVE_MUSICBRAINZ4, false) + AM_CONDITIONAL(HAVE_MUSICBRAINZ3, false) +fi AM_CONDITIONAL(HAVE_PLUGIN_SJCD, [test "x$have_sjcd" = "xyes"]) if test "x$have_sjcd" = "xyes"; then AC_DEFINE(HAVE_PLUGIN_SJCD, 1, [Define if you have sound juicer support]) diff --git a/plugins/sjcd/data/Makefile.am b/plugins/sjcd/data/Makefile.am index 5f2a768..3040511 100644 --- a/plugins/sjcd/data/Makefile.am +++ b/plugins/sjcd/data/Makefile.am @@ -1,5 +1,6 @@ profilesdir = $(pkgdatadir)/data profiles_DATA = rhythmbox.gep +dist_profiles_DATA = rhythmbox.gep # gsettings_SCHEMAS is a list of all the schemas you want to install schema_in_files = org.gtkpod.sjcd.gschema.xml.in diff --git a/plugins/sjcd/libjuicer/Makefile.am b/plugins/sjcd/libjuicer/Makefile.am index dceb8fa..7854e15 100644 --- a/plugins/sjcd/libjuicer/Makefile.am +++ b/plugins/sjcd/libjuicer/Makefile.am @@ -25,13 +25,11 @@ libjuicer_la_CPPFLAGS = \ libjuicer_la_CFLAGS = \ $(WARN_CFLAGS) \ $(SOUND_JUICER_CFLAGS) \ - $(MUSICBRAINZ3_CFLAGS) \ $(GSTREAMER_CFLAGS) \ $(AM_CFLAGS) libjuicer_la_LIBADD = \ $(SOUND_JUICER_LIBS) \ - $(MUSICBRAINZ3_LIBS) \ $(GSTREAMER_LIBS) libjuicer_la_LDFLAGS = \ @@ -42,8 +40,19 @@ if HAVE_MUSICBRAINZ3 libjuicer_la_SOURCES += \ sj-metadata-musicbrainz3.h \ sj-metadata-musicbrainz3.c +libjuicer_la_LIBADD += $(MUSICBRAINZ3_LIBS) +libjuicer_la_CFLAGS += $(MUSICBRAINZ3_CFLAGS) endif +if HAVE_MUSICBRAINZ4 +libjuicer_la_SOURCES += \ + sj-metadata-musicbrainz4.h \ + sj-metadata-musicbrainz4.c +libjuicer_la_LIBADD += $(MUSICBRAINZ4_LIBS) +libjuicer_la_CFLAGS += $(MUSICBRAINZ4_CFLAGS) +endif + + # # Build the GValue marshals # diff --git a/plugins/sjcd/libjuicer/sj-metadata-getter.c b/plugins/sjcd/libjuicer/sj-metadata-getter.c index 1aff2f5..11002fa 100644 --- a/plugins/sjcd/libjuicer/sj-metadata-getter.c +++ b/plugins/sjcd/libjuicer/sj-metadata-getter.c @@ -26,6 +26,9 @@ #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 */ @@ -175,6 +178,9 @@ 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 */ diff --git a/plugins/sjcd/libjuicer/sj-metadata-musicbrainz4.c b/plugins/sjcd/libjuicer/sj-metadata-musicbrainz4.c new file mode 100644 index 0000000..3af7558 --- /dev/null +++ b/plugins/sjcd/libjuicer/sj-metadata-musicbrainz4.c @@ -0,0 +1,621 @@ +/* + * sj-metadata-musicbrainz4.c + * Copyright (C) 2008 Ross Burton <ro...@bu...> + * Copyright (C) 2008 Bastien Nocera <ha...@ha...> + * Copyright (C) 2011 Christophe Fergeau <cfe...@re...> + * + * 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 <gio/gio.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); \ +} + +#if 0 +#define SJ_SETTINGS_MUSICBRAINZ_SERVER "/apps/sound-juicer/musicbrainz_server" +#endif +#define SJ_SETTINGS_PROXY_USE_PROXY "enabled" +#define SJ_SETTINGS_PROXY_HOST "host" +#define SJ_SETTINGS_PROXY_PORT "port" +#define SJ_SETTINGS_PROXY_USE_AUTHENTICATION "use-authentication" +#define SJ_SETTINGS_PROXY_USERNAME "authentication-user" +#define SJ_SETTINGS_PROXY_PASSWORD "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) +{ + GSettings *settings; + + SjMetadataMusicbrainz4Private *priv; + + priv = GET_PRIVATE (self); + + settings = g_settings_new ("org.gnome.system.proxy.http"); + +#if 0 + gchar *server_name; + + server_name = g_settings_get_string (settings, SJ_SETTINGS_MUSICBRAINZ_SERVER); + + 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); +#endif + + priv->mb = mb4_query_new (SJ_MUSICBRAINZ_USER_AGENT, NULL, 0); + + /* Set the HTTP proxy */ + if (g_settings_get_boolean (settings, SJ_SETTINGS_PROXY_USE_PROXY)) { + char *proxy_host; + int port; + + proxy_host = g_settings_get_string (settings, SJ_SETTINGS_PROXY_HOST); + mb4_query_set_proxyhost (priv->mb, proxy_host); + g_free (proxy_host); + + port = g_settings_get_int (settings, SJ_SETTINGS_PROXY_PORT); + mb4_query_set_proxyport (priv->mb, port); + + if (g_settings_get_boolean (settings, SJ_SETTINGS_PROXY_USE_AUTHENTICATION)) { + char *username, *password; + + username = g_settings_get_string (settings, SJ_SETTINGS_PROXY_USERNAME); + mb4_query_set_proxyusername (priv->mb, username); + g_free (username); + + password = g_settings_get_string (settings, SJ_SETTINGS_PROXY_PASSWORD); + mb4_query_set_proxypassword (priv->mb, password); + g_free (password); + } + } + + g_object_unref (settings); +} + +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/sjcd/libjuicer/sj-metadata-musicbrainz4.h b/plugins/sjcd/libjuicer/sj-metadata-musicbrainz4.h new file mode 100644 index 0000000..5a73e9b --- /dev/null +++ b/plugins/sjcd/libjuicer/sj-metadata-musicbrainz4.h @@ -0,0 +1,56 @@ +/* + * sj-metadata-musicbrainz4.h + * Copyright (C) 2008 Ross Burton <ro...@bu...> + * Copyright (C) 2008 Bastien Nocera <ha...@ha...> + * + * 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/sjcd/libjuicer/sj-structures.c b/plugins/sjcd/libjuicer/sj-structures.c index 3d23ce6..b4577d4 100644 --- a/plugins/sjcd/libjuicer/sj-structures.c +++ b/plugins/sjcd/libjuicer/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/sjcd/libjuicer/sj-structures.h b/plugins/sjcd/libjuicer/sj-structures.h index 07ccc60..46d67e9 100644 --- a/plugins/sjcd/libjuicer/sj-structures.h +++ b/plugins/sjcd/libjuicer/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 diff --git a/plugins/sjcd/sj-extracting.c b/plugins/sjcd/sj-extracting.c index be1d6fa..a9604fe 100644 --- a/plugins/sjcd/sj-extracting.c +++ b/plugins/sjcd/sj-extracting.c @@ -50,6 +50,8 @@ #include "sj-genres.h" #include "egg-play-preview.h" +#define UNKNOWN_TAG_VALUE "???" + typedef struct { int seconds; struct timeval time; @@ -899,6 +901,11 @@ sanitize_path (const char* str, const char* filesystem_type) gchar *res = NULL; gchar *s; + if (str == NULL) { + /* Not a lot we can do other than return an empty string */ + return g_strdup_printf(UNKNOWN_TAG_VALUE); + } + /* Skip leading periods, otherwise files disappear... */ while (*str == '.') str++; @@ -1050,10 +1057,18 @@ filepath_parse_pattern (const char* pattern, const TrackDetails *track) switch (*++p) { case 't': string = sanitize_path (track->title, filesystem_type); + if (g_strcmp0(string, UNKNOWN_TAG_VALUE) == 0) { + g_free(string); + string = g_strdup_printf ("%d", track->number); + } break; case 'T': tmp = g_utf8_strdown (track->title, -1); string = sanitize_path (tmp, filesystem_type); + if (g_strcmp0(string, UNKNOWN_TAG_VALUE) == 0) { + g_free(string); + string = g_strdup_printf ("%d", track->number); + } g_free(tmp); break; case 'a': diff --git a/plugins/sjcd/sj-main.c b/plugins/sjcd/sj-main.c index 8ad0cc8..484c6d0 100644 --- a/plugins/sjcd/sj-main.c +++ b/plugins/sjcd/sj-main.c @@ -237,7 +237,7 @@ set_info_bar_text_and_icon (GtkInfoBar *infobar, ally_target = gtk_widget_get_accessible (button); - hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); + hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); gtk_widget_show (hbox_content); image = gtk_image_new_from_stock (icon_stock_id, GTK_ICON_SIZE_DIALOG); @@ -245,7 +245,7 @@ set_info_bar_text_and_icon (GtkInfoBar *infobar, gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0); gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0); - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_widget_show (vbox); gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0); @@ -977,24 +977,7 @@ static void profile_changed_cb (GSettings *settings, gchar *key, gpointer user_d g_object_set (extractor, "profile", profile, NULL); if (profile == NULL || !sj_extractor_supports_profile(profile)) { - GtkWidget *dialog; - int response; - - dialog = gtk_message_dialog_new (GTK_WINDOW (gtkpod_app), - GTK_DIALOG_MODAL, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - _("The currently selected audio profile is not available on your installation.")); - gtk_dialog_add_button (GTK_DIALOG (dialog), "gtk-quit", GTK_RESPONSE_REJECT); - gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Change Profile"), GTK_RESPONSE_ACCEPT); - response = gtk_dialog_run (GTK_DIALOG (dialog)); - if (response == GTK_RESPONSE_ACCEPT) { - gtk_widget_destroy (dialog); - on_edit_preferences_cb (NULL, NULL); - } else { - /* Can't use gtk_main_quit here, we may be outside the main loop */ - return; - } + gtkpod_warning(_("sjcd plugin: the currently selected audio profile is not available on your installation.")); } if (profile != NULL) diff --git a/po/POTFILES.in b/po/POTFILES.in index 47b1dd8..af2c6ef 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -135,6 +135,7 @@ plugins/sjcd/libjuicer/sj-extractor.c plugins/sjcd/libjuicer/sj-metadata-getter.c plugins/sjcd/libjuicer/sj-metadata-gvfs.c plugins/sjcd/libjuicer/sj-metadata.c +plugins/sjcd/libjuicer/sj-metadata-musicbrainz4.c plugins/sjcd/plugin.c plugins/sjcd/sj-extracting.c plugins/sjcd/sj-genres.c |