Modify version string to post-release version 0.20.95
[gmpc-last.fm.git] / src / plugin.c
blobd22110ed2d273d48e92fab4720277d1500d312be
1 /* gmpc-last.fm (GMPC plugin)
2 * Copyright (C) 2006-2009 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpcwiki.sarine.nl/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <stdio.h>
21 #include <string.h>
23 #include <config.h>
24 #include <glib.h>
25 #include <glib/gi18n-lib.h>
26 #include <glib/gstdio.h>
27 #include <gtk/gtk.h>
28 #include <libxml/parser.h>
29 #include <libxml/tree.h>
30 #include <gmpc/plugin.h>
31 #include <gmpc/gmpc_easy_download.h>
32 #include <gmpc/metadata.h>
34 #define LASTFM_API_KEY "ec1cdd08d574e93fa6ef9ad861ae795a"
35 #define LASTFM_API_ROOT "http://ws.audioscrobbler.com/2.0/"
36 gmpcPlugin plugin;
38 typedef struct Query {
39 MetaDataType type;
40 void (*callback)(GList *list, gpointer data);
41 gpointer user_data;
42 }Query;
44 static int lastfm_get_enabled()
46 return cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "enable", TRUE);
48 static void lastfm_set_enabled(int enabled)
50 cfg_set_single_value_as_int(config, "cover-lastfm", "enable", enabled);
53 static int lastfm_fetch_cover_priority(void){
54 return cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "priority", 80);
56 static void lastfm_fetch_cover_priority_set(int priority){
57 cfg_set_single_value_as_int(config, "cover-lastfm", "priority", priority);
60 static xmlNodePtr get_first_node_by_name(xmlNodePtr xml, gchar *name) {
61 if(name == NULL) return NULL;
62 if(xml) {
63 xmlNodePtr c = xml->xmlChildrenNode;
64 for(;c;c=c->next) {
65 if(c->name && xmlStrEqual(c->name, (xmlChar *) name))
66 return c;
69 return NULL;
72 static GList *__lastfm_art_xml_get_artist_image(const char *data, gint size, MetaDataType mtype)
74 GList *list = NULL;
75 xmlDocPtr doc;
76 if(size <= 0 || data == NULL || data[0] != '<')
77 return NULL;
79 doc = xmlParseMemory(data,size);
80 if(doc)
82 xmlNodePtr root = xmlDocGetRootElement(doc);
83 if(root)
85 /* loop through all albums */
86 xmlNodePtr cur = get_first_node_by_name(root,"images");
87 if(cur)
89 xmlNodePtr cur2 = cur->xmlChildrenNode;
90 for(;cur2;cur2 = cur2->next)
92 if(cur2->name)
94 if (xmlStrEqual(cur2->name, (xmlChar *)"image"))
96 xmlNodePtr cur3 = cur2->xmlChildrenNode;
97 for(;cur3;cur3 = cur3->next)
99 if(xmlStrEqual(cur3->name, (xmlChar *)"sizes"))
101 xmlNodePtr cur4 = cur3->xmlChildrenNode;
102 for(;cur4;cur4 = cur4->next)
104 if(xmlStrEqual(cur4->name, (xmlChar *)"size"))
106 xmlChar *temp = xmlGetProp(cur4, (xmlChar *)"name");
107 if(temp)
110 * We want large image, but if that is not available, get the medium one
112 if(xmlStrEqual(temp, (xmlChar *)"original"))
114 xmlChar *xurl = xmlNodeGetContent(cur4);
115 if(xurl){
116 if(strstr((char *)xurl, "noartist") == NULL){
117 MetaData *mtd = meta_data_new();
118 mtd->type = mtype;
119 mtd->plugin_name = plugin.name;
120 mtd->content_type = META_DATA_CONTENT_URI;
121 mtd->content = g_strdup((char *)xurl); mtd->size = 0;
122 list =g_list_prepend(list, mtd);
124 xmlFree(xurl);
126 }/*else if(xmlStrEqual(temp, (xmlChar *)"large") || xmlStrEqual(temp, (xmlChar *)"extralarge"))
128 xmlChar *xurl = xmlNodeGetContent(cur2);
129 if(xurl)
131 if(strstr((char *)xurl, "noartist") == NULL){
132 MetaData *mtd = meta_data_new();
133 mtd->type = mtype;
134 mtd->plugin_name = plugin.name;
135 mtd->content_type = META_DATA_CONTENT_URI;
136 mtd->content = g_strdup((char *)xurl); mtd->size = 0;
137 list =g_list_prepend(list, mtd);
139 xmlFree(xurl);
142 xmlFree(temp);
153 xmlFreeDoc(doc);
155 return g_list_reverse(list);
157 static GList* __lastfm_art_xml_get_image(const char* data, gint size, char* type, MetaDataType mtype)
159 GList *list = NULL;
160 xmlDocPtr doc;
161 if(size <= 0 || data == NULL || data[0] != '<')
162 return NULL;
164 doc = xmlParseMemory(data,size);
165 if(doc)
167 xmlNodePtr root = xmlDocGetRootElement(doc);
168 if(root)
170 /* loop through all albums */
171 xmlNodePtr cur = get_first_node_by_name(root,type);
172 if(cur)
174 xmlNodePtr cur2 = cur->xmlChildrenNode;
175 for(;cur2;cur2 = cur2->next)
177 if(cur2->name)
179 if (xmlStrEqual(cur2->name, (xmlChar *)"image"))
182 xmlChar *temp = xmlGetProp(cur2, (xmlChar *)"size");
183 if(temp)
186 * We want large image, but if that is not available, get the medium one
188 if(xmlStrEqual(temp, (xmlChar *)"medium"))
190 xmlChar *xurl = xmlNodeGetContent(cur2);
191 if(xurl){
192 if(strstr((char *)xurl, "noartist") == NULL){
193 MetaData *mtd = meta_data_new();
194 mtd->type = mtype;
195 mtd->plugin_name = plugin.name;
196 mtd->content_type = META_DATA_CONTENT_URI;
197 mtd->content = g_strdup((char *)xurl); mtd->size = 0;
198 list =g_list_append(list, mtd);
200 xmlFree(xurl);
202 }else if(xmlStrEqual(temp, (xmlChar *)"large") || xmlStrEqual(temp, (xmlChar *)"extralarge"))
204 xmlChar *xurl = xmlNodeGetContent(cur2);
205 if(xurl)
207 if(strstr((char *)xurl, "noartist") == NULL){
208 MetaData *mtd = meta_data_new();
209 mtd->type = mtype;
210 mtd->plugin_name = plugin.name;
211 mtd->content_type = META_DATA_CONTENT_URI;
212 mtd->content = g_strdup((char *)xurl); mtd->size = 0;
213 list =g_list_prepend(list, mtd);
215 xmlFree(xurl);
218 xmlFree(temp);
225 xmlFreeDoc(doc);
227 return list;
230 /* get similar genres */
231 static MetaData* __lastfm_art_xml_get_genre_similar(const gchar* l_data, gint l_size)
233 if(l_size <= 0 || l_data == NULL || l_data[0] != '<')
234 return NULL;
236 MetaData* mtd = NULL;
237 xmlDocPtr doc = xmlParseMemory(l_data, l_size);
238 if(doc != NULL)
240 xmlNodePtr root = xmlDocGetRootElement(doc);
241 xmlNodePtr cur = get_first_node_by_name(root, "similartags");
242 if(cur != NULL)
244 xmlNodePtr cur2 = cur->xmlChildrenNode;
245 for(; cur2 != NULL; cur2 = cur2->next)
247 if(xmlStrEqual(cur2->name, (xmlChar*) "tag"))
249 xmlNodePtr cur3 = cur2->xmlChildrenNode;
250 for(; cur3 != NULL; cur3 = cur3->next)
252 if(xmlStrEqual(cur3->name, (xmlChar*) "name"))
254 xmlChar* temp = xmlNodeGetContent(cur3);
255 if(temp)
257 if(!mtd)
259 mtd = meta_data_new();
260 mtd->type = META_GENRE_SIMILAR;
261 mtd->plugin_name = plugin.name;
262 mtd->content_type = META_DATA_CONTENT_TEXT_LIST;
263 mtd->size = 0;
265 mtd->size++;
266 mtd->content = g_list_prepend((GList*) mtd->content, g_strdup((char *)temp));
267 xmlFree(temp);
268 break;
274 if(mtd != NULL)
275 mtd->content = g_list_reverse((GList*) mtd->content); /* to have the match-order */
277 xmlFreeDoc(doc);
280 return mtd;
284 * Get 20 artists
286 static MetaData* __lastfm_art_xml_get_artist_similar(const gchar* data, gint size)
288 if(size <= 0 || data == NULL || data[0] != '<')
289 return NULL;
291 MetaData *mtd = NULL;
292 xmlDocPtr doc = xmlParseMemory(data,size);
293 if(doc)
295 xmlNodePtr root = xmlDocGetRootElement(doc);
296 xmlNodePtr cur = get_first_node_by_name(root, "similarartists");
297 if(cur)
299 xmlNodePtr cur2 = cur->xmlChildrenNode;
300 for(;cur2;cur2=cur2->next)
302 if(xmlStrEqual(cur2->name, (xmlChar *)"artist"))
304 xmlNodePtr cur3 = cur2->xmlChildrenNode;
305 for(;cur3;cur3=cur3->next)
307 if(xmlStrEqual(cur3->name, (xmlChar *)"name"))
309 xmlChar *temp = xmlNodeGetContent(cur3);
310 if(temp)
312 if(!mtd) {
313 mtd = meta_data_new();
314 mtd->type = META_ARTIST_SIMILAR;
315 mtd->plugin_name = plugin.name;
316 mtd->content_type = META_DATA_CONTENT_TEXT_LIST;
317 mtd->size = 0;
319 mtd->size++;
320 mtd->content = g_list_prepend((GList*) mtd->content, g_strdup((char *)temp));
321 xmlFree(temp);
327 if(mtd != NULL)
328 mtd->content = g_list_reverse((GList*) mtd->content);
330 xmlFreeDoc(doc);
333 return mtd;
337 * Get 20Songs
339 static MetaData* __lastfm_art_xml_get_song_similar(const gchar* data, gint size)
341 if(size <= 0 || data == NULL || data[0] != '<')
342 return NULL;
344 MetaData *mtd = NULL;
345 xmlDocPtr doc = xmlParseMemory(data,size);
346 if(doc)
348 xmlNodePtr root = xmlDocGetRootElement(doc);
349 xmlNodePtr cur = get_first_node_by_name(root, "similartracks");
350 if(cur)
352 xmlNodePtr cur2 = cur->xmlChildrenNode;
353 for(;cur2;cur2=cur2->next)
355 if(xmlStrEqual(cur2->name, (xmlChar *)"track"))
357 xmlNodePtr cur3 = cur2->xmlChildrenNode;
358 xmlChar *artist = NULL;
359 xmlChar *title = NULL;
360 for(;cur3;cur3=cur3->next)
362 if(xmlStrEqual(cur3->name, (xmlChar *)"name"))
364 xmlChar *temp = xmlNodeGetContent(cur3);
365 title = temp;
367 else if (xmlStrEqual(cur3->name, (xmlChar *)"artist"))
369 xmlNodePtr cur4 = get_first_node_by_name(cur3, "name");
370 if(cur4){
371 xmlChar *temp = xmlNodeGetContent(cur4);
372 artist = temp;
376 if(artist && title) {
377 if(!mtd) {
378 mtd = meta_data_new();
379 mtd->type = META_SONG_SIMILAR;
380 mtd->plugin_name = plugin.name;
381 mtd->content_type = META_DATA_CONTENT_TEXT_LIST;
382 mtd->size = 0;
384 mtd->size++;
385 mtd->content = g_list_prepend((GList*) mtd->content, g_strdup_printf("%s::%s", artist, title));
387 if(artist) xmlFree(artist);
388 if(title) xmlFree(title);
391 if(mtd != NULL)
392 mtd->content = g_list_reverse((GList*) mtd->content);
394 xmlFreeDoc(doc);
397 return mtd;
401 /**
402 * Get album image
405 * Get artist info
409 static gchar* __lastfm_art_xml_get_artist_bio(const gchar* data , gint size)
411 xmlDocPtr doc = xmlParseMemory(data,size);
412 gchar* info=NULL;
413 if(doc)
415 xmlNodePtr root = xmlDocGetRootElement(doc);
416 xmlNodePtr bio = get_first_node_by_name(get_first_node_by_name(get_first_node_by_name(root,"artist"),"bio"),"content");
417 if(bio)
419 xmlChar *temp = xmlNodeGetContent(bio);
420 info = g_strdup((gchar*) temp);
421 xmlFree(temp);
424 xmlFreeDoc(doc);
426 return info;
431 * Preferences
433 static void pref_destroy(GtkWidget *con)
435 GtkWidget *child = gtk_bin_get_child(GTK_BIN(con));
436 if(child) {
437 gtk_container_remove(GTK_CONTAINER(con), child);
441 static void pref_enable_fetch(GtkWidget *con, gpointer data)
443 MetaDataType type = GPOINTER_TO_INT(data);
444 int state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(con));
445 switch(type) {
446 case META_ARTIST_ART:
447 cfg_set_single_value_as_int(config, "cover-lastfm", "fetch-art-artist",state);
448 break;
449 case META_ALBUM_ART:
450 cfg_set_single_value_as_int(config, "cover-lastfm", "fetch-art-album",state);
451 break;
452 case META_ARTIST_SIMILAR:
453 cfg_set_single_value_as_int(config, "cover-lastfm", "fetch-similar-artist",state);
454 break;
455 case META_SONG_SIMILAR:
456 cfg_set_single_value_as_int(config, "cover-lastfm", "fetch-similar-song",state);
457 break;
458 case META_GENRE_SIMILAR:
459 cfg_set_single_value_as_int(config, "cover-lastfm", "fetch-similar-genre", state);
460 break;
461 case META_ARTIST_TXT:
462 cfg_set_single_value_as_int(config, "cover-lastfm", "fetch-biography-artist",state);
463 break;
464 default:
465 break;
470 static void pref_construct(GtkWidget *con)
472 GtkWidget *frame,*vbox;
473 GtkWidget *a_a_ck, *a_b_ck, *a_s_ck,*c_a_ck, *s_s_ck, *s_g_ck;
476 * Enable/Disable checkbox
478 frame = gtk_frame_new("");
479 gtk_label_set_markup(GTK_LABEL(gtk_frame_get_label_widget(GTK_FRAME(frame))), "<b>Fetch</b>");
480 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
481 vbox = gtk_vbox_new(FALSE,6);
482 gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
483 gtk_container_add(GTK_CONTAINER(frame), vbox);
485 /* Fetch artist art */
486 a_a_ck = gtk_check_button_new_with_label(_("Artist images"));
487 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a_a_ck),
488 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-art-artist", TRUE));
489 gtk_box_pack_start(GTK_BOX(vbox), a_a_ck, FALSE, TRUE, 0);
490 g_signal_connect(G_OBJECT(a_a_ck), "toggled", G_CALLBACK(pref_enable_fetch), GINT_TO_POINTER(META_ARTIST_ART));
492 /* Fetch artist text*/
493 a_b_ck = gtk_check_button_new_with_label(_("Artist biography"));
494 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a_b_ck),
495 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-biography-artist", TRUE));
496 gtk_box_pack_start(GTK_BOX(vbox), a_b_ck, FALSE, TRUE, 0);
497 g_signal_connect(G_OBJECT(a_b_ck), "toggled", G_CALLBACK(pref_enable_fetch), GINT_TO_POINTER(META_ARTIST_TXT));
499 /* Fetch similar artists */
500 a_s_ck = gtk_check_button_new_with_label(_("Similar artists"));
501 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a_s_ck),
502 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-similar-artist", TRUE));
503 gtk_box_pack_start(GTK_BOX(vbox), a_s_ck, FALSE, TRUE, 0);
504 g_signal_connect(G_OBJECT(a_s_ck), "toggled", G_CALLBACK(pref_enable_fetch), GINT_TO_POINTER(META_ARTIST_SIMILAR));
506 /* Fetch artist art */
507 c_a_ck = gtk_check_button_new_with_label(_("Album cover"));
508 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(c_a_ck),
509 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-art-album", TRUE));
510 gtk_box_pack_start(GTK_BOX(vbox), c_a_ck, FALSE, TRUE, 0);
511 g_signal_connect(G_OBJECT(c_a_ck), "toggled", G_CALLBACK(pref_enable_fetch), GINT_TO_POINTER(META_ALBUM_ART));
513 /* Fetch similar songs */
514 s_s_ck = gtk_check_button_new_with_label(_("Similar songs"));
515 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(s_s_ck),
516 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-similar-song", TRUE));
517 gtk_box_pack_start(GTK_BOX(vbox), s_s_ck, FALSE, TRUE, 0);
518 g_signal_connect(G_OBJECT(s_s_ck), "toggled", G_CALLBACK(pref_enable_fetch), GINT_TO_POINTER(META_SONG_SIMILAR));
520 /* Fetch similar genre */
521 s_g_ck = gtk_check_button_new_with_label(_("Similar genres"));
522 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(s_g_ck),
523 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-similar-genre", TRUE));
524 gtk_box_pack_start(GTK_BOX(vbox), s_g_ck, FALSE, TRUE, 0);
525 g_signal_connect(G_OBJECT(s_g_ck), "toggled", G_CALLBACK(pref_enable_fetch), GINT_TO_POINTER(META_GENRE_SIMILAR));
528 if(!lastfm_get_enabled()) {
529 gtk_widget_set_sensitive(GTK_WIDGET(vbox), FALSE);
532 gtk_widget_show_all(frame);
533 gtk_container_add(GTK_CONTAINER(con), frame);
536 * Similarsong
538 static void similar_song_callback(const GEADAsyncHandler *handle, GEADStatus status, gpointer user_data)
540 Query *q = (Query *)user_data;
541 GList *list = NULL;
542 if(status == GEAD_PROGRESS) return;
543 if(status == GEAD_DONE)
545 goffset size=0;
546 const char *data = gmpc_easy_handler_get_data(handle, &size);
547 MetaData *mtd = __lastfm_art_xml_get_song_similar((char *)data,(gint)size);
548 if(mtd) {
549 list = g_list_append(list, mtd);
552 q->callback(list, q->user_data);
553 g_slice_free(Query, q);
556 * Similar artist
558 static void similar_artist_callback(const GEADAsyncHandler *handle, GEADStatus status, gpointer user_data)
560 Query *q = (Query *)user_data;
561 GList *list = NULL;
562 if(status == GEAD_PROGRESS) return;
563 if(status == GEAD_DONE)
565 goffset size=0;
566 const gchar* data = gmpc_easy_handler_get_data(handle, &size);
567 MetaData *mtd = __lastfm_art_xml_get_artist_similar(data, size);
568 if(mtd){
569 list = g_list_append(list, mtd);
572 q->callback(list, q->user_data);
573 g_slice_free(Query, q);
576 * Similar genre
578 static void similar_genre_callback(const GEADAsyncHandler *handle, GEADStatus status, gpointer user_data)
580 if(status == GEAD_PROGRESS)
581 return;
583 Query* q = (Query*) user_data;
584 GList* list = NULL;
585 if(status == GEAD_DONE)
587 goffset size = 0;
588 const gchar* data = gmpc_easy_handler_get_data(handle, &size);
589 MetaData* mtd = __lastfm_art_xml_get_genre_similar(data, size);
590 if(mtd)
591 list = g_list_append(list, mtd);
593 q->callback(list, q->user_data);
594 g_slice_free(Query, q);
596 /****
597 * Get biograpy new style
600 static void biography_callback(const GEADAsyncHandler *handle, GEADStatus status, gpointer user_data)
602 Query *q = (Query *)user_data;
603 GList *list = NULL;
604 if(status == GEAD_PROGRESS) return;
605 if(status == GEAD_DONE)
607 goffset size=0;
608 const gchar *data = gmpc_easy_handler_get_data(handle, &size);
609 char* url = __lastfm_art_xml_get_artist_bio(data, size);
610 /* strip html */
611 if(url)
613 int i=0;
614 int j=0,depth=0;;
615 for(j=0; j < strlen(url);j++)
617 if(url[j] == '<') depth++;
618 else if(url[j] == '>' && depth) depth--;
619 else if(depth == 0)
621 /* Quick and dirty html unescape*/
622 if(strncasecmp(&url[j], "&lt;", 4) == 0){
623 url[i] = url[j];
624 i++;
625 j+=3;
626 }else if (strncasecmp(&url[j], "&gt;", 4) == 0){
627 url[i] = url[j];
628 i++;
629 j+=3;
630 }else if (strncasecmp(&url[j], "&quot;", 6) == 0){
631 url[i] = url[j];
632 i++;
633 j+=5;
634 }else if (strncasecmp(&url[j], "&amp;", 5) == 0){
635 url[i] = url[j];
636 i++;
637 j+=4;
639 else{
640 url[i] = url[j];
641 i++;
645 url[i] = '\0';
646 if(i > 0){
647 MetaData *mtd = meta_data_new();
648 mtd->type = META_ARTIST_TXT;
649 mtd->plugin_name = plugin.name;
650 mtd->content_type = META_DATA_CONTENT_TEXT;
651 mtd->content = url;
652 mtd->size = i;
653 list = g_list_append(list, mtd);
655 else g_free(url);
659 q->callback(list, q->user_data);
660 g_slice_free(Query, q);
662 /****
663 * Get album images new style
666 static void album_image_callback(const GEADAsyncHandler *handle, GEADStatus status, gpointer user_data)
668 Query *q = (Query *)user_data;
669 GList *list = NULL;
670 if(status == GEAD_PROGRESS) return;
671 if(status == GEAD_DONE)
673 goffset size=0;
674 const gchar* data = gmpc_easy_handler_get_data(handle, &size);
675 list = __lastfm_art_xml_get_image(data, size, "album", META_ALBUM_ART);
677 q->callback(list, q->user_data);
678 g_slice_free(Query, q);
681 * Get artist image new style
683 static void artist_image_callback(const GEADAsyncHandler *handle, GEADStatus status, gpointer user_data)
685 Query *q = (Query *)user_data;
686 GList *list = NULL;
687 if(status == GEAD_PROGRESS) return;
688 if(status == GEAD_DONE)
690 goffset size=0;
691 const gchar* data = gmpc_easy_handler_get_data(handle, &size);
692 list = __lastfm_art_xml_get_artist_image(data, size, META_ARTIST_ART);
695 q->callback(list, q->user_data);
696 g_slice_free(Query, q);
699 static void lastfm_fetch_get_uris(mpd_Song *song, MetaDataType type, void (*callback)(GList *list, gpointer data), gpointer user_data)
701 g_debug("Query last.fm api v2");
702 if(song->artist != NULL && type == META_ARTIST_ART &&
703 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-art-artist", TRUE))
705 char furl[1024];
706 gchar *artist = gmpc_easy_download_uri_escape(song->artist);
707 Query *q = g_slice_new0(Query);
709 q->callback = callback;
710 q->user_data = user_data;
711 snprintf(furl,1024,LASTFM_API_ROOT"?method=artist.getImages&artist=%s&api_key=%s", artist,LASTFM_API_KEY);
712 g_debug("url: '%s'", furl);
713 gmpc_easy_async_downloader(furl, artist_image_callback, q);
714 g_free(artist);
715 return;
717 else if (song->artist != NULL && song->album != NULL && type == META_ALBUM_ART &&
718 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-art-album", TRUE))
720 char furl[1024];
721 gchar *artist = gmpc_easy_download_uri_escape(song->artist);
722 gchar *album = gmpc_easy_download_uri_escape(song->album);
723 Query *q = g_slice_new0(Query);
725 q->callback = callback;
726 q->user_data = user_data;
727 snprintf(furl,1024,LASTFM_API_ROOT"?method=album.getinfo&artist=%s&album=%s&api_key=%s", artist,album,LASTFM_API_KEY);
728 g_debug("url: '%s'", furl);
729 gmpc_easy_async_downloader(furl, album_image_callback, q);
730 g_free(artist);
731 g_free(album);
732 return;
735 /* Fetch artist info */
736 else if (song->artist != NULL && type == META_ARTIST_TXT &&
737 cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-biography-artist", TRUE))
740 char furl[1024];
741 gchar *artist = gmpc_easy_download_uri_escape(song->artist);
742 Query *q = g_slice_new0(Query);
744 q->callback = callback;
745 q->user_data = user_data;
746 snprintf(furl,1024, LASTFM_API_ROOT"?method=artist.getinfo&artist=%s&api_key=%s", artist,LASTFM_API_KEY);
747 g_debug("url: '%s'", furl);
748 gmpc_easy_async_downloader(furl, biography_callback, q);
749 g_free(artist);
751 return;
753 else if (song->artist != NULL && type == META_ARTIST_SIMILAR
754 && cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-similar-artist", TRUE))
756 char furl[1024];
757 char *artist = gmpc_easy_download_uri_escape(song->artist);
758 Query *q = g_slice_new0(Query);
760 q->callback = callback;
761 q->user_data = user_data;
762 snprintf(furl,1024,LASTFM_API_ROOT"?method=artist.getsimilar&artist=%s&api_key=%s", artist,LASTFM_API_KEY);
763 g_debug("url: '%s'", furl);
764 g_free(artist);
765 gmpc_easy_async_downloader(furl, similar_artist_callback, q);
766 return;
768 else if (song->genre != NULL && type == META_GENRE_SIMILAR
769 && cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-similar-genre", TRUE))
771 Query *q = g_slice_new0(Query);
772 q->callback = callback;
773 q->user_data = user_data;
775 gchar* genre = gmpc_easy_download_uri_escape(song->genre);
776 gchar* furl = g_strdup_printf(LASTFM_API_ROOT"?method=tag.getsimilar&tag=%s&api_key=%s", genre, LASTFM_API_KEY);
777 g_debug("url: '%s'", furl);
778 gmpc_easy_async_downloader(furl, similar_genre_callback, q);
779 g_free(genre);
780 g_free(furl);
782 return;
783 }else if (song->title != NULL && song->artist != NULL && type == META_SONG_SIMILAR && cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-similar-song", TRUE))
786 char furl[1024];
787 char *artist = gmpc_easy_download_uri_escape(song->artist);
788 char *title = gmpc_easy_download_uri_escape(song->title);
789 Query *q = g_slice_new0(Query);
791 q->callback = callback;
792 q->user_data = user_data;
793 snprintf(furl,1024,LASTFM_API_ROOT"?method=track.getsimilar&artist=%s&track=%s&api_key=%s", artist,title,LASTFM_API_KEY);
794 g_debug("url: '%s'", furl);
795 g_free(artist);
796 gmpc_easy_async_downloader(furl, similar_song_callback, q);
797 return;
800 callback(NULL, user_data);
802 gmpcPrefPlugin pref = {
803 .construct = pref_construct,
804 .destroy = pref_destroy
808 * Metadata Plugin
810 gmpcMetaDataPlugin lf_cover = {
811 .get_priority = lastfm_fetch_cover_priority,
812 .set_priority = lastfm_fetch_cover_priority_set,
813 .get_metadata = lastfm_fetch_get_uris
816 int plugin_api_version = PLUGIN_API_VERSION;
817 static void lastfm_init(void)
819 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
820 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
822 static const gchar *lastfm_get_translation_domain(void)
824 return GETTEXT_PACKAGE;
826 gmpcPlugin plugin = {
827 .name = N_("Last FM metadata fetcher"),
828 .version = {PLUGIN_MAJOR_VERSION,PLUGIN_MINOR_VERSION,PLUGIN_MICRO_VERSION},
829 .plugin_type = GMPC_PLUGIN_META_DATA,
830 .init = lastfm_init,
831 .metadata = &lf_cover,
832 .pref = &pref,
833 .get_enabled = lastfm_get_enabled,
834 .set_enabled = lastfm_set_enabled,
835 .get_translation_domain = lastfm_get_translation_domain
838 /* vim:set ts=4 sw=4: */