Remove printf and cleanup
[gmpc-coveramazon.git] / src / plugin.c
blob19790a991d56c09018089075368bebc3ad773b7e
1 #include <stdio.h>
2 #include <string.h>
3 #include <gtk/gtk.h>
4 #include <libxml/parser.h>
5 #include <libxml/tree.h>
6 #include <libmpd/debug_printf.h>
7 #include <gmpc/plugin.h>
8 #include <gmpc/gmpc_easy_download.h>
9 #include <config.h>
10 #define AMAZONKEY "14TC04B24356BPHXW1R2"
12 static char * host = "http://ecs.amazonaws.%s/onca/xml?Service=AWSECommerceService&Operation=ItemSearch&SearchIndex=Music&ResponseGroup=Images,EditorialReview&AWSAccessKeyId=%s&%s=%s&%s=%s";
14 static int fetch_cover_art(mpd_Song *song,int type, char **url);
16 #define ENDPOINTS 6
17 static char *endpoints[ENDPOINTS][2] =
19 {"com", "United States"},
20 {"co.uk", "United Kingdom"},
21 {"jp", "Japan"},
22 {"fr", "France"},
23 {"ca", "Canada"},
24 {"de", "Germany"}
27 static GtkWidget *wp_pref_vbox = NULL;
29 typedef struct amazon_song_info {
30 char *image_big;
31 char *image_medium;
32 char *image_small;
33 char *album_info;
35 }amazon_song_info;
37 /**
38 * Get Set enabled
40 static int amazon_get_enabled()
42 return cfg_get_single_value_as_int_with_default(config, "cover-amazon", "enable", TRUE);
44 static void amazon_set_enabled(int enabled)
46 cfg_set_single_value_as_int(config, "cover-amazon", "enable", enabled);
49 /**
50 * Get priority
52 static int fetch_cover_priority(){
53 return cfg_get_single_value_as_int_with_default(config, "cover-amazon", "priority", 80);
56 static int fetch_metadata(mpd_Song *song,MetaDataType type, char **path)
58 gchar *url = NULL;
60 if(song->artist == NULL || song->album == NULL)
62 return META_DATA_UNAVAILABLE;
64 if(type != META_ALBUM_ART && type != META_ALBUM_TXT) {
65 return META_DATA_UNAVAILABLE;
67 /* Always fetch it. */
68 fetch_cover_art(song,type, &url);
69 if(url){
70 *path = url;
71 return META_DATA_AVAILABLE;
74 g_free(url);
75 return META_DATA_UNAVAILABLE;
78 static amazon_song_info * amazon_song_info_new()
80 amazon_song_info *asi = g_malloc(sizeof(amazon_song_info));
81 asi->image_big = NULL;
82 asi->image_medium = NULL;
83 asi->image_small = NULL;
84 asi->album_info = NULL;
85 return asi;
87 static void amazon_song_info_free(amazon_song_info *asi)
89 if(asi->image_big != NULL) g_free(asi->image_big);
90 if(asi->image_medium != NULL) g_free(asi->image_medium);
91 if(asi->image_small != NULL) g_free(asi->image_small);
92 if(asi->album_info != NULL) g_free(asi->album_info);
93 g_free(asi);
94 return;
97 static xmlNodePtr get_first_node_by_name(xmlNodePtr xml, gchar *name) {
98 if(xml) {
99 xmlNodePtr c = xml->xmlChildrenNode;
100 for(;c;c=c->next) {
101 if(xmlStrEqual(c->name, (xmlChar *) name))
102 return c;
105 return NULL;
108 static amazon_song_info *__cover_art_xml_get_image(char *data,int size)
110 xmlDocPtr doc = xmlParseMemory(data,size);
111 if(doc)
113 xmlNodePtr root = xmlDocGetRootElement(doc);
114 xmlNodePtr cur = get_first_node_by_name(root, "Items");
115 amazon_song_info *asi = NULL;
116 if(cur) {
117 cur = get_first_node_by_name(cur, "Item");
118 if(cur) {
119 xmlNodePtr child = NULL;
120 asi = amazon_song_info_new();
121 if((child = get_first_node_by_name(cur, "LargeImage"))) {
122 xmlChar *temp = xmlNodeGetContent(get_first_node_by_name(child, "URL"));
123 /* copy it, so we can free it, and don't need xmlFree */
124 asi->image_big = g_strdup((char *)temp);
125 xmlFree(temp);
127 if((child = get_first_node_by_name(cur, "MediumImage"))){
128 xmlChar *temp = xmlNodeGetContent(get_first_node_by_name(child, "URL"));
129 asi->image_medium = g_strdup((char *)temp);
130 xmlFree(temp);
132 if((child = get_first_node_by_name(cur, "SmallImage"))){
133 xmlChar *temp = xmlNodeGetContent(get_first_node_by_name(child, "URL"));
134 asi->image_small = g_strdup((char *)temp);
135 xmlFree(temp);
138 if((child = get_first_node_by_name(cur, "EditorialReviews"))) {
139 child = get_first_node_by_name(child, "EditorialReview");
140 if(child) {
141 xmlChar *temp = xmlNodeGetContent(get_first_node_by_name(child, "Content")); /* ugy, lazy */
142 asi->album_info = g_strdup((char *)temp);
143 xmlFree(temp);
148 xmlFreeDoc(doc);
149 return asi;
151 xmlCleanupParser();
152 return NULL;
156 static int __fetch_metadata_amazon(char *sfield, char *nartist, char *stype,char *nalbum,int type, char **url)
159 gmpc_easy_download_struct data= {NULL, 0,-1, NULL, NULL};
160 int found = 0;
161 char furl[1024];
162 int endpoint = cfg_get_single_value_as_int_with_default(config, "cover-amazon", "location", 0);
163 char *endp = endpoints[endpoint][0];
165 debug_printf(DEBUG_INFO, "search-type: %s\n", stype);
166 snprintf(furl,1024, host,endp, AMAZONKEY,sfield, nartist, stype, nalbum);
167 if(gmpc_easy_download(furl, &data))
169 amazon_song_info *asi = __cover_art_xml_get_image(data.data, data.size);
170 gmpc_easy_download_clean(&data);
171 if(asi)
173 if(type&META_ALBUM_ART)
175 debug_printf(DEBUG_INFO, "Trying to fetch album art");
176 gmpc_easy_download(asi->image_big, &data);
177 if(data.size <= 900){
178 gmpc_easy_download_clean(&data);
179 gmpc_easy_download(asi->image_medium, &data);
180 if(data.size <= 900){
181 gmpc_easy_download_clean(&data);
182 gmpc_easy_download(asi->image_small, &data);
183 if(data.size <= 900)
185 gmpc_easy_download_clean(&data);
189 if(data.size){
190 FILE *fp = NULL;
191 gchar *imgpath = NULL;
192 gchar *filename = g_strdup_printf("%s-%s.jpg",nartist,nalbum);
193 imgpath = gmpc_get_covers_path(filename);
194 g_free(filename);
195 fp = fopen(imgpath, "wb");
196 if(fp)
198 fwrite(data.data, sizeof(char), data.size,fp);
199 *url = g_strdup(imgpath);
200 found = 1;
201 fclose(fp);
203 g_free(imgpath);
205 gmpc_easy_download_clean(&data);
209 else if(type&META_ALBUM_TXT)
211 debug_printf(DEBUG_INFO, "Trying to fetch album txt");
212 if(asi->album_info)
214 FILE *fp;
215 gchar *filename, *imgpath;
216 filename = g_strdup_printf("%s-%s.albuminfo",nartist,nalbum);
217 imgpath = gmpc_get_covers_path(filename);
218 g_free(filename);
219 fp = fopen(imgpath, "w");
220 if(fp)
222 int j=0,depth=0;;
223 *url = g_strdup(imgpath);
225 * Quick 'n Dirty html stripper
227 for(j=0; j < strlen(asi->album_info);j++)
229 if((asi->album_info)[j] == '<') depth++;
230 else if((asi->album_info)[j] == '>' && depth) depth--;
231 else if(depth == 0)
233 fputc((asi->album_info)[j],fp);
236 fclose(fp);
237 found = 1;
240 g_free(imgpath);
243 amazon_song_info_free(asi);
247 return found;
249 static int fetch_cover_art(mpd_Song *song,int type, char **url)
251 int retval=0;
252 gchar *artist = g_uri_escape_string(song->artist,NULL, TRUE);
253 gchar *album = g_uri_escape_string(song->album,NULL, TRUE);
255 retval = __fetch_metadata_amazon(
256 "Title",album,
257 "Artist", artist,
258 type,url);
259 if(!retval && song->performer)
261 gchar *performer = g_uri_escape_string(song->performer, NULL, TRUE);
262 retval = __fetch_metadata_amazon(
263 "Title",album,
264 "Performer", performer,
265 type,url);
266 g_free(performer);
269 g_free(artist);
270 g_free(album);
271 return retval;
275 * Preferences
278 static void amazon_cover_art_enable_toggle(GtkWidget *wid)
280 int kk = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wid));
281 amazon_set_enabled(kk);
283 static void amazon_cover_art_pref_destroy(GtkWidget *container)
285 gtk_container_remove(GTK_CONTAINER(container), wp_pref_vbox);
287 static void amazon_cover_art_pref_selection_changed(GtkWidget *box)
289 cfg_set_single_value_as_int(config, "cover-amazon", "location", gtk_combo_box_get_active(GTK_COMBO_BOX(box)));
292 static void amazon_cover_art_pref_construct(GtkWidget *container)
294 GtkWidget *enable_cg = gtk_check_button_new_with_mnemonic("_Enable amazon as cover art source");
295 GtkWidget *label = NULL;
296 GtkWidget *selection = NULL;
297 GtkWidget *hbox = NULL;
298 int i;
299 wp_pref_vbox = gtk_vbox_new(FALSE,6);
301 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_cg), amazon_get_enabled());
303 g_signal_connect(G_OBJECT(enable_cg), "toggled", G_CALLBACK(amazon_cover_art_enable_toggle), NULL);
304 gtk_box_pack_start(GTK_BOX(wp_pref_vbox), enable_cg, FALSE, FALSE, 0);
306 /* Location */
307 hbox = gtk_hbox_new(FALSE, 6);
308 label = gtk_label_new("Location:");
309 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE,0);
310 selection = gtk_combo_box_new_text();
311 for(i=0;i<ENDPOINTS;i++)
312 gtk_combo_box_append_text(GTK_COMBO_BOX(selection), endpoints[i][1]);
313 gtk_combo_box_set_active(GTK_COMBO_BOX(selection),cfg_get_single_value_as_int_with_default(config, "cover-amazon", "location", 0));
314 g_signal_connect(G_OBJECT(selection), "changed",G_CALLBACK(amazon_cover_art_pref_selection_changed), NULL);
316 gtk_box_pack_start(GTK_BOX(hbox), selection, TRUE,TRUE,0);
317 gtk_box_pack_start(GTK_BOX(wp_pref_vbox), hbox, FALSE, FALSE, 0);
319 gtk_container_add(GTK_CONTAINER(container), wp_pref_vbox);
320 gtk_widget_show_all(container);
323 gmpcPrefPlugin cam_pref = {
324 .construct = amazon_cover_art_pref_construct,
325 .destroy = amazon_cover_art_pref_destroy
328 gmpcMetaDataPlugin cam_cover = {
329 .get_priority = fetch_cover_priority,
330 .get_image = fetch_metadata
333 int plugin_api_version = PLUGIN_API_VERSION;
334 gmpcPlugin plugin = {
335 .name = "Amazon Cover Fetcher",
336 .version = {PLUGIN_MAJOR_VERSION,PLUGIN_MINOR_VERSION,PLUGIN_MICRO_VERSION},
337 .plugin_type = GMPC_PLUGIN_META_DATA,
338 .pref = &cam_pref,
339 .metadata = &cam_cover,
340 .get_enabled = amazon_get_enabled,
341 .set_enabled = amazon_set_enabled