commit 0ca1e68ddd703d6b30de2888c67119b97d55d0c7 Author: phantomjinx <p.g.richard...@phantomjinx.co.uk> 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 <r...@burtonini.com> + * Copyright (C) 2008 Bastien Nocera <had...@hadess.net> + * Copyright (C) 2011 Christophe Fergeau <cferg...@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 <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 <r...@burtonini.com> + * Copyright (C) 2008 Bastien Nocera <had...@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/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 ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ gtkpod-cvs2 mailing list gtkpod-cvs2@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2