#include #include #include #include #include #include #include #include static void lastfm_init(); static void lastfm_cover_art_pref_construct(GtkWidget *container); static void lastfm_cover_art_pref_destroy(GtkWidget *container); static int lastfm_fetch_cover_art(mpd_Song *song, GSourceFunc function); static int lastfm_fetch_cover_artist_art_path(mpd_Song *song, gchar **path); static int lastfm_fetch_cover_priority(void); static int lastfm_fetch_get_image(mpd_Song *song,MetaDataType type, char **path); static void lastfm_set_enabled(int enabled); static int lastfm_get_enabled(); static GtkWidget *wp_pref_vbox = NULL; gmpcMetaDataPlugin lf_cover = { lastfm_fetch_cover_priority, lastfm_fetch_get_image }; int plugin_api_version = PLUGIN_API_VERSION; gmpcPlugin plugin = { "Last FM Artist Image Fetcher", {0,15,0}, GMPC_PLUGIN_META_DATA, 0, NULL, /* path */ lastfm_init, /* init */ NULL, /* Destroy */ NULL, /* browser */ NULL, /* status changed */ NULL, /* connection changed */ NULL, /* preferences */ &lf_cover, /* Metadata */ lastfm_get_enabled, lastfm_set_enabled }; static int lastfm_get_enabled() { return cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "enable", TRUE); } static void lastfm_set_enabled(int enabled) { cfg_set_single_value_as_int(config, "cover-lastfm", "enable", enabled); } static void lastfm_init() { char *file = g_strdup_printf("%s/.covers/",g_get_home_dir()); if(!g_file_test(file,G_FILE_TEST_EXISTS)) { g_mkdir(file, 0755); } g_free(file); } static int lastfm_fetch_cover_priority(void){ return cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "priority", 80); } static int lastfm_fetch_get_image(mpd_Song *song,MetaDataType type, char **path) { int result = 0; if(song->artist == NULL ) { return META_DATA_UNAVAILABLE; } if(type == META_ARTIST_ART) { result = lastfm_fetch_cover_artist_art_path(song, path); if(result != META_DATA_AVAILABLE) { lastfm_fetch_cover_art(song, NULL); result = lastfm_fetch_cover_artist_art_path(song, path); } if(result == META_DATA_AVAILABLE) { return META_DATA_AVAILABLE; } } else if (type == META_ALBUM_ART && cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "fetch-album", FALSE)) { result = lastfm_fetch_cover_album_art_path(song, path); if(result != META_DATA_AVAILABLE) { lastfm_fetch_cover_album_art(song, NULL); result = lastfm_fetch_cover_album_art_path(song, path); } if(result == META_DATA_AVAILABLE) { return META_DATA_AVAILABLE; } } if(*path) g_free(*path); return META_DATA_UNAVAILABLE; } static char * __lastfm_art_process_string(char *name) { int i = 0; int j = 0; int depth = 0; int spaces = 0; char *result = NULL; int length = strlen(name); for(i=0; i= 'a' && name[i] <= 'z') && !(name[i] >= 'A' && name[i] <= 'Z') && !(name[i] >= '0' && name[i] <= '9')) { length+=2; } } /** allocate */ /** TODO do this somewhere else */ result = g_malloc0((length+1)*sizeof(char)); depth = 0; for(i=0; i < strlen(name);i++) { if(name[i] == '(' || name[i] == '[' || name[i] == '{') { depth++; } else if(name[i] == ')' || name[i] == ']' || name[i] == '}') { depth--; } else if(depth >0) { /* do nothing */ } else if(!(name[i] >= 'a' && name[i] <= 'z') && !(name[i] >= 'A' && name[i] <= 'Z') && !(name[i] >= '0' && name[i] <= '9')) { snprintf(&result[j],4,"%%%02X", name[i]); j+=3; } else { result[j] = name[i]; j++; } } return result; } static int lastfm_fetch_cover_artist_art_path(mpd_Song *song, gchar **path) { int i=0; char *url =NULL; char *artist = NULL; char *album = NULL; if(song == NULL || !cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "enable", TRUE)) return META_DATA_UNAVAILABLE; if(song->artist == NULL ) return META_DATA_UNAVAILABLE; artist = __lastfm_art_process_string(song->artist); url = g_strdup_printf("%s/.covers/%s.jpg", g_get_home_dir(), artist); if(g_file_test(url, G_FILE_TEST_EXISTS)) { *path = url; g_free(artist); return META_DATA_AVAILABLE; } g_free(artist); g_free(url); return META_DATA_FETCHING; } static char *__lastfm_art_xml_get_artist_image(char *data,int size) { char *retv = NULL; if(size == 0) return NULL; if(data[0] != '<') return NULL; xmlDocPtr doc = xmlParseMemory(data,size); if(doc) { xmlNodePtr root = xmlDocGetRootElement(doc); xmlNodePtr cur = root; for(;cur;cur = cur->next){ if(xmlStrEqual(cur->name, (xmlChar *)"similarartists")){ xmlChar *temp = xmlGetProp(cur, (const xmlChar *) "picture"); retv = g_strdup(temp); xmlFree(temp); /* one result is enough */ xmlFreeDoc(doc); xmlCleanupParser(); return retv; } } xmlFreeDoc(doc); xmlCleanupParser(); } return NULL; } static char *__lastfm_art_xml_get_album_image(char *data,int size, char *album) { char *retv = NULL; int is_album = FALSE; if(size == 0) return NULL; if(data[0] != '<') return NULL; gchar *url = NULL; xmlDocPtr doc = xmlParseMemory(data,size); if(doc) { xmlNodePtr root = xmlDocGetRootElement(doc); xmlNodePtr cur = root->xmlChildrenNode; for(;url && cur;cur = cur->next){ if(xmlStrEqual(cur->name, (xmlChar *)"album")){ xmlNodePtr cur2 = cur->xmlChildrenNode; is_album = FALSE; for(;cur2 && url;cur2 = cur2->next) { if(xmlStrEqual(cur2->name, (xmlChar *)"name")) { xmlChar *temp = xmlNodeGetContent(cur2); if(strcasecmp(temp, album) == 0) { is_album = TRUE; } } else if (xmlStrEqual(cur2->name, (xmlChar *)"coverart")) { xmlNodePtr cur3 = cur2->xmlChildrenNode; for(;cur3 && !url;cur3 = cur3->next) { if(xmlStrEqual(cur3->name, (xmlChar *)"large")) { xmlChar *temp = xmlNodeGetContent(cur3); url = g_strdup(temp); /* one result is enough */ } } } } } } xmlFreeDoc(doc); xmlCleanupParser(); if(is_album && url) { printf("album image found\n"); return url; } if(url) g_free(url); } return NULL; } int __lastfm_art_get_artist_image(char *nartist) { gmpc_easy_download_struct data= {NULL, 0,-1,NULL, NULL}; int found = 0; char furl[1024]; snprintf(furl,1024,"http://ws.audioscrobbler.com/1.0/artist/%s/similar.xml", nartist); /** So we don't do to much queries a second */ sleep(1); if(gmpc_easy_download(furl, &data)) { char *url = __lastfm_art_xml_get_artist_image(data.data, data.size); gmpc_easy_download_clean(&data); if(url && url[0] != '\0' && strstr(url, "noartist_") == NULL) { gmpc_easy_download(url, &data); if(data.size){ int i =0; FILE *fp = NULL; char *imgpath = NULL; imgpath = g_strdup_printf("%s/.covers/%s.jpg", g_get_home_dir(),nartist); fp = fopen(imgpath, "wb"); if(fp) { fwrite(data.data, sizeof(char), data.size,fp); fclose(fp); } g_free(imgpath); gmpc_easy_download_clean(&data); found = 1; } } if(url)g_free(url); } return found; } int __lastfm_art_get_album_image(char *nartist, char *nalbum,char *artist) { gmpc_easy_download_struct data= {NULL, 0,-1,NULL, NULL}; int found = 0; char furl[1024]; snprintf(furl,1024,"http://ws.audioscrobbler.com/1.0/artist/%s/topalbums.xml", nartist); /** So we don't do to much queries a second */ sleep(1); if(gmpc_easy_download(furl, &data)) { char *url = __lastfm_art_xml_get_album_image(data.data, data.size,artist); gmpc_easy_download_clean(&data); if(url && url[0] != '\0' && strstr(url, "noartist_") == NULL) { gmpc_easy_download(url, &data); if(data.size){ int i =0; FILE *fp = NULL; char *imgpath = NULL; imgpath = g_strdup_printf("%s/.covers/%s - %s.jpg", g_get_home_dir(),nartist,nalbum); fp = fopen(imgpath, "wb"); if(fp) { fwrite(data.data, sizeof(char), data.size,fp); fclose(fp); } g_free(imgpath); gmpc_easy_download_clean(&data); found = 1; } } if(url)g_free(url); } return found; } int lastfm_fetch_cover_album_art(mpd_Song *song, GSourceFunc function) { int retval; char *artist = __lastfm_art_process_string(song->artist); char *album = __lastfm_art_process_string(song->album); retval = __lastfm_art_get_album_image(artist,album, song->artist); g_free(artist); g_free(album); return retval; } int lastfm_fetch_cover_art(mpd_Song *song, GSourceFunc function) { int retval; char *artist = __lastfm_art_process_string(song->artist); retval = __lastfm_art_get_artist_image(artist); g_free(artist); return retval; } int lastfm_fetch_cover_album_art_path(mpd_Song *song, gchar **path) { int i=0; char *url =NULL; char *artist = NULL; char *album = NULL; if(song == NULL || !cfg_get_single_value_as_int_with_default(config, "cover-lastfm", "enable", TRUE)) return META_DATA_UNAVAILABLE; if(song->artist == NULL && song->album == NULL) return META_DATA_UNAVAILABLE; artist = __lastfm_art_process_string(song->artist); album = __lastfm_art_process_string(song->album); url = g_strdup_printf("%s/.covers/%s - %s.jpg", g_get_home_dir(), artist, album); g_free(artist); g_free(album); if(g_file_test(url, G_FILE_TEST_EXISTS)) { *path = url; return META_DATA_AVAILABLE; } g_free(url); return META_DATA_FETCHING; }