Remove the gdk_thread_enter stuff from the plugin, and put thread unsafe in idle...
[gmpc-magnatune.git] / src / magnatune.c
blob8e7857c948f3ca7304248749962ef53b5b16c607
1 #include <stdio.h>
2 #include <string.h>
3 #include <gtk/gtk.h>
4 #include <axl/axl.h>
5 #include <gmpc/plugin.h>
6 #include <gmpc/gmpc_easy_download.h>
7 #include <gmpc/misc.h>
8 #include <libmpd/libmpd-internal.h>
9 #include "magnatune.h"
11 static void magnatune_cleanup_xml();
12 static axlDoc *magnatune_xmldoc = NULL;
13 GMutex *mt_db_lock = NULL;
15 /* hack fix this */
16 int magnatune_end_download();
18 /**
19 * Makes a copy with all &#<id>; decoded
21 static char * url_decode(const char *string)
23 char *retv = NULL;
24 if(string && string[0] != '\0')
26 int i;
27 const gchar *a = string;
28 gchar *b;
29 b = retv= g_malloc0((strlen(string)+1)*sizeof(char));
30 while(*a){
31 if(*a == '&'){
32 const char *c = a;
33 while(*c != ';')c++;
34 /* skip &# */
35 a+=2;
36 *b= (char)atoi(a);
37 a = c;
39 else
40 *b = *a;
41 b++;
42 a++;
45 return retv;
48 void magnatune_db_destroy(void)
50 if(mt_db_lock)
52 g_mutex_lock(mt_db_lock);
53 g_mutex_unlock(mt_db_lock);
54 g_mutex_free(mt_db_lock);
56 if(magnatune_xmldoc)
58 axl_doc_free(magnatune_xmldoc);
59 axl_end();
60 magnatune_xmldoc = NULL;
64 /* run this before using the other fucntions */
65 void magnatune_db_init()
67 mt_db_lock = g_mutex_new();
68 axl_init();
71 void magnatune_db_open()
73 gchar *path = gmpc_get_user_path("magnatune.xml");
75 g_mutex_lock(mt_db_lock);
76 /**
77 * if the db doesn't exists exit
79 if(!g_file_test(path, G_FILE_TEST_EXISTS))
81 g_free(path);
82 g_mutex_unlock(mt_db_lock);
83 return;
85 /**
86 * if open close it
88 if(magnatune_xmldoc)
90 axl_doc_free(magnatune_xmldoc);
91 magnatune_xmldoc = NULL;
93 magnatune_xmldoc = axl_doc_parse_from_file(path, NULL);
95 g_mutex_unlock(mt_db_lock);
96 g_free(path);
99 gboolean magnatune_db_has_data()
101 gboolean data = FALSE;
102 g_mutex_lock(mt_db_lock);
103 data = (magnatune_xmldoc != NULL)? TRUE:FALSE;
104 g_mutex_unlock(mt_db_lock);
105 return data;
108 MpdData * magnatune_db_get_genre_list()
110 MpdData *list = NULL;
111 axlNode *root;
112 axlNode *cur;
113 /** check if there is data */
114 g_mutex_lock(mt_db_lock);
115 if(magnatune_xmldoc == NULL)
117 g_mutex_unlock(mt_db_lock);
118 return NULL;
121 root = axl_doc_get_root(magnatune_xmldoc);
122 cur = axl_node_get_first_child(root);
123 while(cur != NULL)
125 axlNode *cur2;
126 if(NODE_CMP_NAME(cur, "Album"))
128 const char *genre = NULL;
129 cur2 = axl_node_get_first_child(cur);
130 while(cur2 != NULL)
132 if(NODE_CMP_NAME(cur2, "magnatunegenres"))
134 gchar **tokens = NULL;
135 genre = axl_node_get_content(cur2,NULL);
136 if(genre)
138 int i =0;
139 tokens = g_strsplit(genre,",",0);
140 for(i=0; tokens[i];i++)
142 list = mpd_new_data_struct_append(list);
143 list->type = MPD_DATA_TYPE_TAG;
144 list->tag_type = MPD_TAG_ITEM_GENRE;
145 list->tag = url_decode(tokens[i]);
147 g_strfreev (tokens);
150 cur2 = axl_node_get_next(cur2);
154 cur = axl_node_get_next(cur);
156 g_mutex_unlock(mt_db_lock);
157 return misc_mpddata_remove_duplicate_songs(list);
160 gchar *magnatune_db_get_value(const char *artist, const char *album, int type)
162 gchar *retval = NULL;
163 axlNode *root;
164 axlNode *cur;
165 /** check if there is data */
166 g_mutex_lock(mt_db_lock);
167 if(magnatune_xmldoc == NULL || !artist )
169 g_mutex_unlock(mt_db_lock);
170 return NULL;
173 root = axl_doc_get_root(magnatune_xmldoc);
174 cur = axl_node_get_first_child(root);
175 while(cur != NULL && !retval)
177 axlNode *cur2;
178 if(NODE_CMP_NAME(cur, "Album"))
180 const char *gartist = NULL;
181 const char *galbum = NULL;
182 const char *gvalue = NULL;
183 cur2 = axl_node_get_first_child(cur);
184 while(cur2 != NULL && !retval)
186 if(!gartist && NODE_CMP_NAME(cur2, "artist"))
188 gartist = axl_node_get_content(cur2,NULL);
190 else if(!galbum && NODE_CMP_NAME(cur2, "albumname"))
192 galbum= axl_node_get_content(cur2,NULL);
194 else if(!gvalue && NODE_CMP_NAME(cur2, ((type== META_ARTIST_ART)?"artistphoto":"cover_small")))
196 gvalue= axl_node_get_content(cur2,NULL);
198 cur2 = axl_node_get_next(cur2);
200 if(gvalue && artist && !strncmp(gartist, artist,strlen(artist)))
202 if(type == META_ARTIST_ART)
204 retval = url_decode(gvalue);
206 else if(galbum && !strcmp(galbum, album)){
207 retval = url_decode(gvalue);
212 cur = axl_node_get_next(cur);
215 g_mutex_unlock(mt_db_lock);
216 return retval;
219 * This removes duplicate/unused fields from every Track entry,
220 * This remove around 1/2 the file size
221 * NOT THREAD SAFE, USE INTERNALLY
223 static void magnatune_cleanup_xml()
225 axlNode *root;
226 axlNode *cur;
227 if(!magnatune_xmldoc)
228 return;
229 root = axl_doc_get_root(magnatune_xmldoc);
230 cur = axl_node_get_first_child(root);
231 while(cur != NULL)
233 axlNode *cur2;
234 if(NODE_CMP_NAME(cur, "Album"))
236 cur2 = axl_node_get_first_child(cur);
237 while(cur2 != NULL)
239 if(NODE_CMP_NAME(cur2, "Track"))
241 axlNode *cur3 = axl_node_get_first_child(cur2) ;
242 while(cur3) {
243 if(NODE_CMP_NAME(cur3, "albumname") ||
244 NODE_CMP_NAME(cur3, "artist") ||
245 NODE_CMP_NAME(cur3, "artistdesc") ||
246 NODE_CMP_NAME(cur3, "home") ||
247 NODE_CMP_NAME (cur3, "artistphoto") ||
248 NODE_CMP_NAME (cur3, "mp3lofi") ||
249 NODE_CMP_NAME (cur3, "albumsku") ||
250 NODE_CMP_NAME (cur3, "mp3genre") ||
251 NODE_CMP_NAME (cur3, "magnatunegenres") ||
252 NODE_CMP_NAME (cur3, "license") ||
253 NODE_CMP_NAME (cur3, "album_notes") ||
254 NODE_CMP_NAME (cur3, "launchdate") ||
255 NODE_CMP_NAME (cur3, "buy") ||
256 NODE_CMP_NAME (cur3, "moods") )
259 axl_node_remove(cur3,TRUE);
261 cur3 = axl_node_get_first_child(cur2) ;
262 } else {
263 cur3 = axl_node_get_next(cur3);
266 cur2 = axl_node_get_next(cur2);
268 else if(NODE_CMP_NAME(cur2, "album_notes") ||
269 NODE_CMP_NAME (cur2, "buy") ||
270 NODE_CMP_NAME (cur2, "launchdate"))
272 axl_node_remove(cur2,TRUE);
273 cur2 = axl_node_get_first_child(cur);
274 } else {
275 cur2 = axl_node_get_next(cur2);
279 cur = axl_node_get_next(cur);
284 void magnatune_db_download_xml_thread(gpointer data)
286 gmpc_easy_download_struct *dld = data;
288 g_mutex_lock(mt_db_lock);
290 if(magnatune_xmldoc)
292 axl_doc_free(magnatune_xmldoc);
294 magnatune_xmldoc = NULL;
296 g_mutex_unlock(mt_db_lock);
297 if(gmpc_easy_download("http://www.magnatune.com/info/album_info.xml", dld))
299 g_mutex_lock(mt_db_lock);
300 gchar *path = NULL;
301 magnatune_xmldoc = axl_doc_parse(dld->data, dld->size, NULL);
302 magnatune_cleanup_xml();
303 path = gmpc_get_user_path("magnatune.xml");
304 axl_doc_dump_to_file(magnatune_xmldoc, path);
305 g_free(path);
306 g_mutex_unlock(mt_db_lock);
308 else
310 g_mutex_lock(mt_db_lock);
311 /* update */
312 gchar *path = gmpc_get_user_path("magnatune.xml");
313 if(g_file_test(path, G_FILE_TEST_EXISTS))
315 magnatune_xmldoc = axl_doc_parse_from_file(path, NULL);
317 g_free(path);
318 g_mutex_unlock(mt_db_lock);
321 * cleanup
323 gmpc_easy_download_clean(dld);
324 g_free(dld);
328 g_idle_add(magnatune_end_download, NULL);
331 void magnatune_db_download_xml(ProgressCallback cb, gpointer data )
333 gmpc_easy_download_struct *dld = g_malloc0(sizeof(*dld));
334 dld->callback_data = data;
335 dld->callback = cb;
336 dld->max_size = -1;
337 dld->data = NULL;
338 dld->size = 0;
339 g_thread_create(magnatune_db_download_xml_thread, dld,FALSE, NULL);
343 MpdData * magnatune_db_get_artist_list(char *wanted_genre)
345 MpdData *list = NULL;
346 axlNode *root;
347 axlNode *cur;
348 /** check if there is data */
349 g_mutex_lock(mt_db_lock);
350 if(magnatune_xmldoc == NULL || wanted_genre == NULL)
352 g_mutex_unlock(mt_db_lock);
353 return NULL;
356 root = axl_doc_get_root(magnatune_xmldoc);
357 cur = axl_node_get_first_child(root);
358 while(cur != NULL)
360 axlNode *cur2;
361 if(NODE_CMP_NAME(cur, "Album"))
363 const char *genre = NULL;
364 const char *artist = NULL;
365 cur2 = axl_node_get_first_child(cur);
366 while(cur2 != NULL)
368 if(NODE_CMP_NAME(cur2, "magnatunegenres"))
370 genre = axl_node_get_content(cur2,NULL);
372 else if(NODE_CMP_NAME(cur2, "artist"))
374 artist = axl_node_get_content(cur2,NULL);
376 cur2 = axl_node_get_next(cur2);
378 if(genre && artist && strstr(genre, wanted_genre))
380 list = mpd_new_data_struct_append(list);
381 list->type = MPD_DATA_TYPE_TAG;
382 list->tag_type = MPD_TAG_ITEM_ARTIST;
383 list->tag = url_decode(artist);
388 cur = axl_node_get_next(cur);
390 g_mutex_unlock(mt_db_lock);
391 return misc_mpddata_remove_duplicate_songs(list);
394 MpdData *magnatune_db_get_album_list(char *wanted_genre,char *wanted_artist)
396 MpdData *list = NULL;
397 axlNode *root;
398 axlNode *cur;
399 /** check if there is data */
400 g_mutex_lock(mt_db_lock);
401 if(magnatune_xmldoc == NULL || wanted_genre == NULL || wanted_artist == NULL)
403 g_mutex_unlock(mt_db_lock);
404 return NULL;
407 root = axl_doc_get_root(magnatune_xmldoc);
408 cur = axl_node_get_first_child(root);
409 while(cur != NULL)
411 axlNode *cur2;
412 if(NODE_CMP_NAME(cur, "Album"))
414 const char *genre = NULL;
415 const char *album = NULL;
416 const char *artist = NULL;
417 cur2 = axl_node_get_first_child(cur);
418 while(cur2 != NULL)
420 if(NODE_CMP_NAME(cur2, "magnatunegenres"))
422 genre = axl_node_get_content(cur2,NULL);
424 else if(NODE_CMP_NAME(cur2, "artist"))
426 artist = axl_node_get_content(cur2,NULL);
428 else if(NODE_CMP_NAME(cur2, "albumname"))
430 album = axl_node_get_content(cur2,NULL);
432 cur2 = axl_node_get_next(cur2);
434 if(genre && artist&&album && strstr(genre, wanted_genre) && !strcmp(artist, wanted_artist))
436 list = mpd_new_data_struct_append(list);
437 list->type = MPD_DATA_TYPE_TAG;
438 list->tag_type = MPD_TAG_ITEM_ALBUM;
439 list->tag = url_decode(album);
442 cur = axl_node_get_next(cur);
444 g_mutex_unlock(mt_db_lock);
445 return mpd_data_get_first(list);
449 GList * magnatune_db_get_url_list(const char *wanted_genre,const char *wanted_artist, const char *wanted_album)
451 GList *list = NULL;
452 axlNode *root;
453 axlNode *cur;
454 /** check if there is data */
455 g_mutex_lock(mt_db_lock);
456 if(magnatune_xmldoc == NULL || wanted_genre == NULL)
458 g_mutex_unlock(mt_db_lock);
459 return NULL;
462 root = axl_doc_get_root(magnatune_xmldoc);
463 cur = axl_node_get_first_child(root);
464 while(cur != NULL)
466 axlNode *cur2;
467 if(NODE_CMP_NAME(cur, "Album"))
469 const char *genre = NULL;
470 const char *album = NULL;
471 const char *artist = NULL;
472 gboolean add_urls = FALSE;
473 axlNode *tracks;
474 cur2 = axl_node_get_first_child(cur);
475 while(cur2 != NULL)
477 if(NODE_CMP_NAME(cur2, "magnatunegenres"))
479 genre = axl_node_get_content(cur2,NULL);
481 else if(NODE_CMP_NAME(cur2, "artist"))
483 artist = axl_node_get_content(cur2,NULL);
485 else if(NODE_CMP_NAME(cur2, "albumname"))
487 album = axl_node_get_content(cur2,NULL);
489 cur2 = axl_node_get_next(cur2);
491 if(genre && strstr(genre, wanted_genre))
493 if(wanted_artist && wanted_album) {
494 if(!strcmp(wanted_artist,artist) && !strcmp(wanted_album, album)) {
495 add_urls = TRUE;
497 }else if(wanted_artist) {
498 if(!strcmp(wanted_artist, artist)) {
499 add_urls = TRUE;
501 } else {
502 add_urls = TRUE;
505 if(add_urls)
507 cur2 = axl_node_get_first_child(cur);
508 while(cur2)
510 if (NODE_CMP_NAME(cur2, "Track"))
512 tracks = axl_node_get_first_child(cur2);
513 while(tracks)
515 if (NODE_CMP_NAME(tracks, "url"))
517 const char *url = axl_node_get_content(tracks,NULL);
518 list = g_list_append(list, url_decode(url));
520 tracks = axl_node_get_next(tracks);
523 cur2 = axl_node_get_next(cur2);
527 cur = axl_node_get_next(cur);
529 g_mutex_unlock(mt_db_lock);
530 return list;
535 MpdData* magnatune_db_get_song_list(const char *wanted_genre,const char *wanted_artist, const char *wanted_album)
537 MpdData *data = NULL;
538 axlNode * root;
539 axlNode * cur;
540 /** check if there is data */
541 g_mutex_lock(mt_db_lock);
542 if(magnatune_xmldoc == NULL || wanted_genre == NULL)
544 g_mutex_unlock(mt_db_lock);
545 return NULL;
548 root = axl_doc_get_root(magnatune_xmldoc);
549 cur = axl_node_get_first_child(root);
550 while(cur != NULL)
552 axlNode * cur2;
553 if(NODE_CMP_NAME(cur, (const char *)"Album"))
555 const char *year = NULL;
556 const char *temp = NULL;
557 const char *genre = NULL;
558 const char *album = NULL;
559 const char *artist = NULL;
561 gboolean add_urls = FALSE;
562 axlNode * tracks;
563 cur2 = axl_node_get_first_child(cur);
564 while(cur2 != NULL)
566 if(NODE_CMP_NAME(cur2, (const char *)"magnatunegenres"))
568 genre = axl_node_get_content(cur2,NULL);
570 else if(NODE_CMP_NAME(cur2, (const char *)"artist"))
572 artist = axl_node_get_content(cur2,NULL);
574 else if(NODE_CMP_NAME(cur2, (const char *)"albumname"))
576 album = axl_node_get_content(cur2,NULL);
579 cur2 = axl_node_get_next(cur2);
581 if(genre && strstr(genre, wanted_genre))
583 if(wanted_artist && wanted_album) {
584 if(!strcmp(wanted_artist,artist) && !strcmp(wanted_album, album)) {
585 add_urls = TRUE;
587 }else if(wanted_artist) {
588 if(!strcmp(wanted_artist, artist)) {
589 add_urls = TRUE;
591 } else {
592 add_urls = TRUE;
596 if(add_urls)
598 cur2 = axl_node_get_first_child(cur);
599 while(cur2)
601 if (NODE_CMP_NAME(cur2, (const char *)"Track"))
603 const char *tn = NULL;
604 int stime = 0;
605 const char *url= NULL;
606 const char *name = NULL;
608 tracks = axl_node_get_first_child(cur2);
611 while(tracks)
613 if (NODE_CMP_NAME(tracks, (const char *)"url")&& !url)
615 url= axl_node_get_content(tracks,NULL);
617 else if (NODE_CMP_NAME(tracks, (const char *)"trackname")&& !name)
619 name = axl_node_get_content(tracks,NULL);
622 else if (NODE_CMP_NAME(tracks, (const char *)"tracknum")&& !tn)
624 tn = axl_node_get_content(tracks,NULL);
626 else if (NODE_CMP_NAME(tracks, "seconds")&& !stime)
628 const char *eurl = axl_node_get_content(tracks, NULL);
629 stime = atoi(eurl);
631 else if (NODE_CMP_NAME(tracks, (const char *)"year")&& !year)
633 year = axl_node_get_content(tracks,NULL);
635 tracks = axl_node_get_next(tracks);
638 if(url){
639 data = (MpdData *)mpd_new_data_struct_append((MpdData *)data);
640 data->type = MPD_DATA_TYPE_SONG;
641 data->song = mpd_newSong();
642 data->song->file = url_decode(url);
643 data->song->title = url_decode(name);
644 data->song->album = url_decode(album);
645 data->song->artist = url_decode(artist);
646 data->song->genre = url_decode(genre);
647 data->song->date = url_decode(year);
648 data->song->track = url_decode(tn);
649 data->song->time = stime;
652 cur2 = axl_node_get_next(cur2);
656 cur = axl_node_get_next(cur);
658 g_mutex_unlock(mt_db_lock);
659 return data;