2
* sj-metadata-musicbrainz4.c
3
* Copyright (C) 2008 Ross Burton <ross@burtonini.com>
4
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
5
* Copyright (C) 2011 Christophe Fergeau <cfergeau@redhat.com>
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Library General Public
9
* License as published by the Free Software Foundation; either
10
* version 2 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Library General Public License for more details.
17
* You should have received a copy of the GNU Library General Public
18
* License along with this library; if not, write to the
19
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
* Boston, MA 02111-1307, USA.
25
#endif /* HAVE_CONFIG_H */
30
#include <glib-object.h>
31
#include <gconf/gconf-client.h>
32
#include <discid/discid.h>
33
#include <musicbrainz4/mb4_c.h>
35
#include "sj-metadata-musicbrainz4.h"
36
#include "sj-structures.h"
39
#define GET(field, function, obj) { \
40
function (obj, buffer, sizeof (buffer)); \
43
if (*buffer == '\0') \
46
field = g_strdup (buffer); \
49
#define GCONF_MUSICBRAINZ_SERVER "/apps/sound-juicer/musicbrainz_server"
50
#define GCONF_PROXY_USE_PROXY "/system/http_proxy/use_http_proxy"
51
#define GCONF_PROXY_HOST "/system/http_proxy/host"
52
#define GCONF_PROXY_PORT "/system/http_proxy/port"
53
#define GCONF_PROXY_USE_AUTHENTICATION "/system/http_proxy/use_authentication"
54
#define GCONF_PROXY_USERNAME "/system/http_proxy/authentication_user"
55
#define GCONF_PROXY_PASSWORD "/system/http_proxy/authentication_password"
56
#define SJ_MUSICBRAINZ_USER_AGENT "libjuicer-"VERSION
65
} SjMetadataMusicbrainz4Private;
67
#define GET_PRIVATE(o) \
68
(G_TYPE_INSTANCE_GET_PRIVATE ((o), SJ_TYPE_METADATA_MUSICBRAINZ4, SjMetadataMusicbrainz4Private))
78
static void metadata_interface_init (gpointer g_iface, gpointer iface_data);
80
G_DEFINE_TYPE_WITH_CODE (SjMetadataMusicbrainz4,
81
sj_metadata_musicbrainz4,
83
G_IMPLEMENT_INTERFACE (SJ_TYPE_METADATA,
84
metadata_interface_init));
92
sj_mb4_album_details_dump (AlbumDetails *details)
95
g_print ("Country: %s\n", details->country);
97
g_print ("Type: %s\n", details->type);
98
if (details->lyrics_url)
99
g_print ("Lyrics URL: %s\n", details->lyrics_url);
102
#define sj_mb4_album_details_dump(...)
106
get_artist_list (Mb4ArtistCredit credit)
108
Mb4NameCreditList name_list;
111
char buffer[512]; /* for the GET macro */
116
name_list = mb4_artistcredit_get_namecreditlist (credit);
117
if (name_list == NULL) {
122
for (i = 0; i < mb4_namecredit_list_size (name_list); i++) {
123
Mb4NameCredit name_credit;
125
ArtistDetails *details;
127
name_credit = mb4_namecredit_list_item (name_list, i);
128
details = g_new0 (ArtistDetails, 1);
129
GET (details->joinphrase, mb4_namecredit_get_joinphrase, name_credit);
130
artists = g_list_prepend (artists, details);
131
artist = mb4_namecredit_get_artist (name_credit);
133
g_warning ("no Mb4Artist associated with Mb4NameCredit, falling back to Mb4NameCredit::name");
134
GET (details->name, mb4_namecredit_get_name, name_credit);
138
GET (details->id, mb4_artist_get_id, artist);
139
GET (details->name, mb4_artist_get_name, artist);
140
GET (details->sortname, mb4_artist_get_sortname, artist);
141
GET (details->disambiguation, mb4_artist_get_disambiguation, artist);
142
GET (details->gender, mb4_artist_get_gender, artist);
143
GET (details->country, mb4_artist_get_country, artist);
146
return g_list_reverse(artists);
150
get_artist_info (GList *artists, char **name, char **sortname, char **id)
152
GString *artist_name;
154
unsigned int artist_count;
156
artist_name = g_string_new (NULL);
158
for (it = artists; it != NULL; it = it->next) {
159
ArtistDetails *details = (ArtistDetails *)it->data;
161
g_string_append (artist_name, details->name);
162
if (details->joinphrase != NULL)
163
g_string_append (artist_name, details->joinphrase);
166
if (artist_count != 1) {
167
g_warning ("multiple artists");
168
if (sortname != NULL)
173
ArtistDetails *details = (ArtistDetails *)artists->data;
174
if (sortname != NULL)
175
*sortname = g_strdup (details->sortname);
177
*id = g_strdup (details->id);
181
*name = artist_name->str;
183
g_string_free (artist_name, FALSE);
188
fill_relations (Mb4RelationList relations, AlbumDetails *album)
192
for (i = 0; i < mb4_relation_list_size (relations); i++) {
193
Mb4Relation relation;
194
char buffer[512]; /* for the GET() macro */
197
relation = mb4_relation_list_item (relations, i);
198
if (relation == NULL)
201
GET (type, mb4_relation_get_type, relation);
205
if (g_str_equal (type, "wikipedia")) {
206
char *wikipedia = NULL;
207
GET (wikipedia, mb4_relation_get_target, relation);
208
if (wikipedia != NULL) {
209
g_free (album->wikipedia);
210
album->wikipedia = wikipedia;
212
} else if (g_str_equal (type, "discogs")) {
213
char *discogs = NULL;
214
GET (discogs, mb4_relation_get_target, relation);
215
if (discogs != NULL) {
216
g_free (album->discogs);
217
album->discogs = discogs;
219
} else if (g_str_equal (type, "lyrics")) {
221
GET (lyrics, mb4_relation_get_target, relation);
222
if (lyrics != NULL) {
223
g_free (album->lyrics_url);
224
album->lyrics_url = lyrics;
232
fill_tracks_from_medium (Mb4Medium medium, AlbumDetails *album)
234
Mb4TrackList track_list;
237
char buffer[512]; /* for the GET() macro */
239
track_list = mb4_medium_get_tracklist (medium);
243
album->number = mb4_track_list_size (track_list);
247
for (i = 0; i < mb4_track_list_size (track_list); i++) {
249
Mb4ArtistCredit credit;
250
Mb4Recording recording;
253
mbt = mb4_track_list_item (track_list, i);
257
track = g_new0 (TrackDetails, 1);
259
track->album = album;
261
track->number = mb4_track_get_position (mbt);
262
recording = mb4_track_get_recording (mbt);
263
if (recording != NULL) {
264
GET (track->title, mb4_recording_get_title, recording);
265
GET (track->track_id, mb4_recording_get_id, recording);
266
track->duration = mb4_recording_get_length (recording) / 1000;
267
credit = mb4_recording_get_artistcredit (recording);
269
GET (track->title, mb4_track_get_title, mbt);
270
track->duration = mb4_track_get_length (mbt) / 1000;
271
credit = mb4_track_get_artistcredit (mbt);
276
artists = get_artist_list (credit);
278
get_artist_info (artists, &track->artist,
279
&track->artist_sortname,
282
track->artists = artists;
284
if (track->artist == NULL)
285
track->artist = g_strdup (album->artist);
286
if (track->artist_sortname == NULL)
287
track->artist_sortname = g_strdup (album->artist_sortname);
288
if (track->artist_id == NULL)
289
track->artist_id = g_strdup (album->artist_id);
291
tracks = g_list_prepend (tracks, track);
293
album->tracks = g_list_reverse (tracks);
296
static AlbumDetails *
297
make_album_from_release (Mb4ReleaseGroup group,
302
Mb4ArtistCredit credit;
305
char buffer[512]; /* for the GET macro */
308
g_return_val_if_fail (medium != NULL, NULL);
310
album = g_new0 (AlbumDetails, 1);
312
GET (album->album_id, mb4_release_get_id, release);
313
GET (album->title, mb4_medium_get_title, medium);
314
if (album->title == NULL)
315
GET (album->title, mb4_release_get_title, release);
317
credit = mb4_release_get_artistcredit (release);
319
artists = get_artist_list (credit);
321
get_artist_info (artists, &album->artist,
322
&album->artist_sortname,
325
album->artists = artists;
327
GET (date, mb4_release_get_date, release);
328
album->release_date = sj_metadata_helper_scan_date (date);
331
GET (album->asin, mb4_release_get_asin, release);
332
GET (album->country, mb4_release_get_country, release);
334
GET (album->type, mb4_releasegroup_get_type, group);
335
if (g_str_has_suffix (album->type, "Spokenword")
336
|| g_str_has_suffix (album->type, "Interview")
337
|| g_str_has_suffix (album->type, "Audiobook")) {
338
album->is_spoken_word = TRUE;
340
fill_relations (mb4_releasegroup_get_relationlist(group), album);
343
album->disc_number = mb4_medium_get_position (medium);
344
fill_tracks_from_medium (medium, album);
345
fill_relations (mb4_release_get_relationlist (release), album);
347
sj_mb4_album_details_dump (album);
355
mb4_list_albums (SjMetadata *metadata, char **url, GError **error)
357
SjMetadataMusicbrainz4Private *priv;
358
GList *albums = NULL;
359
Mb4ReleaseList releases;
361
const char *discid = NULL;
364
g_return_val_if_fail (SJ_IS_METADATA_MUSICBRAINZ4 (metadata), NULL);
366
priv = GET_PRIVATE (metadata);
368
if (sj_metadata_helper_check_media (priv->cdrom, error) == FALSE) {
372
priv->disc = discid_new ();
373
if (priv->disc == NULL)
375
if (discid_read (priv->disc, priv->cdrom) == 0)
379
*url = g_strdup (discid_get_submission_url (priv->disc));
381
if (g_getenv("MUSICBRAINZ_FORCE_DISC_ID")) {
382
discid = g_getenv("MUSICBRAINZ_FORCE_DISC_ID");
384
discid = discid_get_id (priv->disc);
387
releases = mb4_query_lookup_discid(priv->mb, discid);
389
if (releases == NULL) {
393
if (mb4_release_list_size (releases) == 0) {
397
for (i = 0; i < mb4_release_list_size (releases); i++) {
400
release = mb4_release_list_item (releases, i);
402
char *releaseid = NULL;
403
Mb4Release full_release;
406
GET(releaseid, mb4_release_get_id, release);
408
full_release = mb4_query_lookup_release (priv->mb, releaseid);
412
Mb4Metadata metadata = NULL;
413
Mb4ReleaseGroup group;
416
group = mb4_release_get_releasegroup (full_release);
418
/* The release-group information we can extract from the
419
* lookup_release query doesn't have the url relations for the
420
* release-group, so run a separate query to get these urls
422
char *releasegroupid = NULL;
423
char *params_names[] = { "inc" };
424
char *params_values[] = { "artists url-rels" };
426
GET (releasegroupid, mb4_releasegroup_get_id, group);
427
metadata = mb4_query_query (priv->mb, "release-group", releasegroupid, "",
428
1, params_names, params_values);
429
g_free (releasegroupid);
432
if (metadata && mb4_metadata_get_releasegroup (metadata))
433
group = mb4_metadata_get_releasegroup (metadata);
435
media = mb4_release_media_matching_discid (full_release, discid);
436
for (j = 0; j < mb4_medium_list_size (media); j++) {
438
medium = mb4_medium_list_item (media, j);
440
album = make_album_from_release (group, full_release, medium);
441
album->metadata_source = SOURCE_MUSICBRAINZ;
442
albums = g_list_append (albums, album);
445
mb4_metadata_delete (metadata);
446
mb4_medium_list_delete (media);
447
mb4_release_delete (full_release);
451
mb4_release_list_delete (releases);
460
metadata_interface_init (gpointer g_iface, gpointer iface_data)
462
SjMetadataClass *klass = (SjMetadataClass*)g_iface;
464
klass->list_albums = mb4_list_albums;
468
sj_metadata_musicbrainz4_init (SjMetadataMusicbrainz4 *self)
470
GConfClient *gconf_client;
473
SjMetadataMusicbrainz4Private *priv;
475
priv = GET_PRIVATE (self);
477
gconf_client = gconf_client_get_default ();
479
server_name = gconf_client_get_string (gconf_client, GCONF_MUSICBRAINZ_SERVER, NULL);
481
if (server_name && (*server_name == '\0')) {
482
g_free (server_name);
486
priv->mb = mb4_query_new (SJ_MUSICBRAINZ_USER_AGENT, server_name, 0);
487
g_free (server_name);
490
/* Set the HTTP proxy */
491
if (gconf_client_get_bool (gconf_client, GCONF_PROXY_USE_PROXY, NULL)) {
495
proxy_host = gconf_client_get_string (gconf_client, GCONF_PROXY_HOST, NULL);
496
mb4_query_set_proxyhost (priv->mb, proxy_host);
499
port = gconf_client_get_int (gconf_client, GCONF_PROXY_PORT, NULL);
500
mb4_query_set_proxyport (priv->mb, port);
502
if (gconf_client_get_bool (gconf_client, GCONF_PROXY_USE_AUTHENTICATION, NULL)) {
503
char *username, *password;
505
username = gconf_client_get_string (gconf_client, GCONF_PROXY_USERNAME, NULL);
506
mb4_query_set_proxyusername (priv->mb, username);
509
password = gconf_client_get_string (gconf_client, GCONF_PROXY_PASSWORD, NULL);
510
mb4_query_set_proxypassword (priv->mb, password);
515
g_object_unref (gconf_client);
519
sj_metadata_musicbrainz4_get_property (GObject *object, guint property_id,
520
GValue *value, GParamSpec *pspec)
522
SjMetadataMusicbrainz4Private *priv = GET_PRIVATE (object);
525
switch (property_id) {
527
g_value_set_string (value, priv->cdrom);
529
case PROP_PROXY_HOST:
530
g_value_set_string (value, priv->http_proxy);
532
case PROP_PROXY_PORT:
533
g_value_set_int (value, priv->http_proxy_port);
536
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
541
sj_metadata_musicbrainz4_set_property (GObject *object, guint property_id,
542
const GValue *value, GParamSpec *pspec)
544
SjMetadataMusicbrainz4Private *priv = GET_PRIVATE (object);
547
switch (property_id) {
550
g_free (priv->cdrom);
551
priv->cdrom = g_value_dup_string (value);
553
case PROP_PROXY_HOST:
554
if (priv->http_proxy) {
555
g_free (priv->http_proxy);
557
priv->http_proxy = g_value_dup_string (value);
558
/* TODO: check this unsets the proxy if NULL, or should we pass "" ? */
559
mb4_query_set_proxyhost (priv->mb, priv->http_proxy);
561
case PROP_PROXY_PORT:
562
priv->http_proxy_port = g_value_get_int (value);
563
mb4_query_set_proxyport (priv->mb, priv->http_proxy_port);
566
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
571
sj_metadata_musicbrainz4_finalize (GObject *object)
573
SjMetadataMusicbrainz4Private *priv;
575
priv = GET_PRIVATE (object);
577
if (priv->mb != NULL) {
578
mb4_query_delete (priv->mb);
581
if (priv->disc != NULL) {
582
discid_free (priv->disc);
585
g_free (priv->cdrom);
587
G_OBJECT_CLASS (sj_metadata_musicbrainz4_parent_class)->finalize (object);
591
sj_metadata_musicbrainz4_class_init (SjMetadataMusicbrainz4Class *class)
593
GObjectClass *object_class = (GObjectClass*)class;
595
g_type_class_add_private (class, sizeof (SjMetadataMusicbrainz4Private));
597
object_class->get_property = sj_metadata_musicbrainz4_get_property;
598
object_class->set_property = sj_metadata_musicbrainz4_set_property;
599
object_class->finalize = sj_metadata_musicbrainz4_finalize;
601
g_object_class_override_property (object_class, PROP_DEVICE, "device");
602
g_object_class_override_property (object_class, PROP_PROXY_HOST, "proxy-host");
603
g_object_class_override_property (object_class, PROP_PROXY_PORT, "proxy-port");
612
sj_metadata_musicbrainz4_new (void)
614
return g_object_new (SJ_TYPE_METADATA_MUSICBRAINZ4, NULL);