Make downloading the db not block the whole damn interface.
[gmpc-magnatune.git] / src / magnatune.c
blob403c3a9dbf892a81d926273dc146fcdbdc14dbd1
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;
17 /**
18 * Makes a copy with all &#<id>; decoded
20 static char * url_decode(const char *string)
22 char *retv = NULL;
23 if(string && string[0] != '\0')
25 int i;
26 const gchar *a = string;
27 gchar *b;
28 b = retv= g_malloc0((strlen(string)+1)*sizeof(char));
29 while(*a){
30 if(*a == '&'){
31 const char *c = a;
32 while(*c != ';')c++;
33 /* skip &# */
34 a+=2;
35 *b= (char)atoi(a);
36 a = c;
38 else
39 *b = *a;
40 b++;
41 a++;
44 return retv;
47 void magnatune_db_destroy(void)
49 if(mt_db_lock)
51 g_mutex_lock(mt_db_lock);
52 g_mutex_unlock(mt_db_lock);
53 g_mutex_free(mt_db_lock);
55 if(magnatune_xmldoc)
57 axl_doc_free(magnatune_xmldoc);
58 axl_end();
59 magnatune_xmldoc = NULL;
63 /* run this before using the other fucntions */
64 void magnatune_db_init()
66 mt_db_lock = g_mutex_new();
67 axl_init();
70 void magnatune_db_open()
72 gchar *path = gmpc_get_user_path("magnatune.xml");
74 g_mutex_lock(mt_db_lock);
75 /**
76 * if the db doesn't exists exit
78 if(!g_file_test(path, G_FILE_TEST_EXISTS))
80 g_free(path);
81 g_mutex_unlock(mt_db_lock);
82 return;
84 /**
85 * if open close it
87 if(magnatune_xmldoc)
89 axl_doc_free(magnatune_xmldoc);
90 magnatune_xmldoc = NULL;
92 magnatune_xmldoc = axl_doc_parse_from_file(path, NULL);
94 g_mutex_unlock(mt_db_lock);
95 g_free(path);
98 gboolean magnatune_db_has_data()
100 gboolean data = FALSE;
101 g_mutex_lock(mt_db_lock);
102 data = (magnatune_xmldoc != NULL)? TRUE:FALSE;
103 g_mutex_unlock(mt_db_lock);
104 return data;
107 MpdData * magnatune_db_get_genre_list()
109 MpdData *list = NULL;
110 axlNode *root;
111 axlNode *cur;
112 /** check if there is data */
113 g_mutex_lock(mt_db_lock);
114 if(magnatune_xmldoc == NULL)
116 g_mutex_unlock(mt_db_lock);
117 return NULL;
120 root = axl_doc_get_root(magnatune_xmldoc);
121 cur = axl_node_get_first_child(root);
122 while(cur != NULL)
124 axlNode *cur2;
125 if(NODE_CMP_NAME(cur, "Album"))
127 const char *genre = NULL;
128 cur2 = axl_node_get_first_child(cur);
129 while(cur2 != NULL)
131 if(NODE_CMP_NAME(cur2, "magnatunegenres"))
133 gchar **tokens = NULL;
134 genre = axl_node_get_content(cur2,NULL);
135 if(genre)
137 int i =0;
138 tokens = g_strsplit(genre,",",0);
139 for(i=0; tokens[i];i++)
141 list = mpd_new_data_struct_append(list);
142 list->type = MPD_DATA_TYPE_TAG;
143 list->tag_type = MPD_TAG_ITEM_GENRE;
144 list->tag = url_decode(tokens[i]);
146 g_strfreev (tokens);
149 cur2 = axl_node_get_next(cur2);
153 cur = axl_node_get_next(cur);
155 g_mutex_unlock(mt_db_lock);
156 return misc_mpddata_remove_duplicate_songs(list);
159 gchar *magnatune_db_get_value(const char *artist, const char *album, int type)
161 gchar *retval = NULL;
162 axlNode *root;
163 axlNode *cur;
164 /** check if there is data */
165 g_mutex_lock(mt_db_lock);
166 if(magnatune_xmldoc == NULL || !artist )
168 g_mutex_unlock(mt_db_lock);
169 return NULL;
172 root = axl_doc_get_root(magnatune_xmldoc);
173 cur = axl_node_get_first_child(root);
174 while(cur != NULL && !retval)
176 axlNode *cur2;
177 if(NODE_CMP_NAME(cur, "Album"))
179 const char *gartist = NULL;
180 const char *galbum = NULL;
181 const char *gvalue = NULL;
182 cur2 = axl_node_get_first_child(cur);
183 while(cur2 != NULL && !retval)
185 if(!gartist && NODE_CMP_NAME(cur2, "artist"))
187 gartist = axl_node_get_content(cur2,NULL);
189 else if(!galbum && NODE_CMP_NAME(cur2, "albumname"))
191 galbum= axl_node_get_content(cur2,NULL);
193 else if(!gvalue && NODE_CMP_NAME(cur2, ((type== META_ARTIST_ART)?"artistphoto":"cover_small")))
195 gvalue= axl_node_get_content(cur2,NULL);
197 cur2 = axl_node_get_next(cur2);
199 if(gvalue && artist && !strncmp(gartist, artist,strlen(artist)))
201 if(type == META_ARTIST_ART)
203 retval = url_decode(gvalue);
205 else if(galbum && !strcmp(galbum, album)){
206 retval = url_decode(gvalue);
211 cur = axl_node_get_next(cur);
214 g_mutex_unlock(mt_db_lock);
215 return retval;
218 * This removes duplicate/unused fields from every Track entry,
219 * This remove around 1/2 the file size
220 * NOT THREAD SAFE, USE INTERNALLY
222 static void magnatune_cleanup_xml()
224 axlNode *root;
225 axlNode *cur;
226 if(!magnatune_xmldoc)
227 return;
228 root = axl_doc_get_root(magnatune_xmldoc);
229 cur = axl_node_get_first_child(root);
230 while(cur != NULL)
232 axlNode *cur2;
233 if(NODE_CMP_NAME(cur, "Album"))
235 cur2 = axl_node_get_first_child(cur);
236 while(cur2 != NULL)
238 if(NODE_CMP_NAME(cur2, "Track"))
240 axlNode *cur3 = axl_node_get_first_child(cur2) ;
241 while(cur3) {
242 if(NODE_CMP_NAME(cur3, "albumname") ||
243 NODE_CMP_NAME(cur3, "artist") ||
244 NODE_CMP_NAME(cur3, "artistdesc") ||
245 NODE_CMP_NAME(cur3, "home") ||
246 NODE_CMP_NAME (cur3, "artistphoto") ||
247 NODE_CMP_NAME (cur3, "mp3lofi") ||
248 NODE_CMP_NAME (cur3, "albumsku") ||
249 NODE_CMP_NAME (cur3, "mp3genre") ||
250 NODE_CMP_NAME (cur3, "magnatunegenres") ||
251 NODE_CMP_NAME (cur3, "license") ||
252 NODE_CMP_NAME (cur3, "album_notes") ||
253 NODE_CMP_NAME (cur3, "launchdate") ||
254 NODE_CMP_NAME (cur3, "buy") ||
255 NODE_CMP_NAME (cur3, "moods") )
258 axl_node_remove(cur3,TRUE);
260 cur3 = axl_node_get_first_child(cur2) ;
261 } else {
262 cur3 = axl_node_get_next(cur3);
265 cur2 = axl_node_get_next(cur2);
267 else if(NODE_CMP_NAME(cur2, "album_notes") ||
268 NODE_CMP_NAME (cur2, "buy") ||
269 NODE_CMP_NAME (cur2, "launchdate"))
271 axl_node_remove(cur2,TRUE);
272 cur2 = axl_node_get_first_child(cur);
273 } else {
274 cur2 = axl_node_get_next(cur2);
278 cur = axl_node_get_next(cur);
283 void magnatune_db_download_xml_thread(gpointer data)
285 gmpc_easy_download_struct *dld = data;
287 g_mutex_lock(mt_db_lock);
289 if(magnatune_xmldoc)
291 axl_doc_free(magnatune_xmldoc);
293 magnatune_xmldoc = NULL;
295 g_mutex_unlock(mt_db_lock);
296 if(gmpc_easy_download("http://www.magnatune.com/info/album_info.xml", dld))
298 g_mutex_lock(mt_db_lock);
299 gchar *path = NULL;
300 magnatune_xmldoc = axl_doc_parse(dld->data, dld->size, NULL);
301 magnatune_cleanup_xml();
302 path = gmpc_get_user_path("magnatune.xml");
303 axl_doc_dump_to_file(magnatune_xmldoc, path);
304 g_free(path);
305 g_mutex_unlock(mt_db_lock);
307 else
309 g_mutex_lock(mt_db_lock);
310 /* update */
311 gchar *path = gmpc_get_user_path("magnatune.xml");
312 if(g_file_test(path, G_FILE_TEST_EXISTS))
314 magnatune_xmldoc = axl_doc_parse_from_file(path, NULL);
316 g_free(path);
317 g_mutex_unlock(mt_db_lock);
320 * cleanup
322 gmpc_easy_download_clean(dld);
323 g_free(dld);
326 gdk_threads_enter();
327 magnatune_end_download();
328 gdk_threads_leave();
330 void magnatune_db_download_xml(ProgressCallback cb, gpointer data )
332 gmpc_easy_download_struct *dld = g_malloc0(sizeof(*dld));
333 dld->callback_data = data;
334 dld->callback = cb;
335 dld->max_size = -1;
336 dld->data = NULL;
337 dld->size = 0;
338 g_thread_create(magnatune_db_download_xml_thread, dld,FALSE, NULL);
342 MpdData * magnatune_db_get_artist_list(char *wanted_genre)
344 MpdData *list = NULL;
345 axlNode *root;
346 axlNode *cur;
347 /** check if there is data */
348 g_mutex_lock(mt_db_lock);
349 if(magnatune_xmldoc == NULL || wanted_genre == NULL)
351 g_mutex_unlock(mt_db_lock);
352 return NULL;
355 root = axl_doc_get_root(magnatune_xmldoc);
356 cur = axl_node_get_first_child(root);
357 while(cur != NULL)
359 axlNode *cur2;
360 if(NODE_CMP_NAME(cur, "Album"))
362 const char *genre = NULL;
363 const char *artist = NULL;
364 cur2 = axl_node_get_first_child(cur);
365 while(cur2 != NULL)
367 if(NODE_CMP_NAME(cur2, "magnatunegenres"))
369 genre = axl_node_get_content(cur2,NULL);
371 else if(NODE_CMP_NAME(cur2, "artist"))
373 artist = axl_node_get_content(cur2,NULL);
375 cur2 = axl_node_get_next(cur2);
377 if(genre && artist && strstr(genre, wanted_genre))
379 list = mpd_new_data_struct_append(list);
380 list->type = MPD_DATA_TYPE_TAG;
381 list->tag_type = MPD_TAG_ITEM_ARTIST;
382 list->tag = url_decode(artist);
387 cur = axl_node_get_next(cur);
389 g_mutex_unlock(mt_db_lock);
390 return misc_mpddata_remove_duplicate_songs(list);
393 MpdData *magnatune_db_get_album_list(char *wanted_genre,char *wanted_artist)
395 MpdData *list = NULL;
396 axlNode *root;
397 axlNode *cur;
398 /** check if there is data */
399 g_mutex_lock(mt_db_lock);
400 if(magnatune_xmldoc == NULL || wanted_genre == NULL || wanted_artist == NULL)
402 g_mutex_unlock(mt_db_lock);
403 return NULL;
406 root = axl_doc_get_root(magnatune_xmldoc);
407 cur = axl_node_get_first_child(root);
408 while(cur != NULL)
410 axlNode *cur2;
411 if(NODE_CMP_NAME(cur, "Album"))
413 const char *genre = NULL;
414 const char *album = NULL;
415 const char *artist = NULL;
416 cur2 = axl_node_get_first_child(cur);
417 while(cur2 != NULL)
419 if(NODE_CMP_NAME(cur2, "magnatunegenres"))
421 genre = axl_node_get_content(cur2,NULL);
423 else if(NODE_CMP_NAME(cur2, "artist"))
425 artist = axl_node_get_content(cur2,NULL);
427 else if(NODE_CMP_NAME(cur2, "albumname"))
429 album = axl_node_get_content(cur2,NULL);
431 cur2 = axl_node_get_next(cur2);
433 if(genre && artist&&album && strstr(genre, wanted_genre) && !strcmp(artist, wanted_artist))
435 list = mpd_new_data_struct_append(list);
436 list->type = MPD_DATA_TYPE_TAG;
437 list->tag_type = MPD_TAG_ITEM_ALBUM;
438 list->tag = url_decode(album);
441 cur = axl_node_get_next(cur);
443 g_mutex_unlock(mt_db_lock);
444 return mpd_data_get_first(list);
448 GList * magnatune_db_get_url_list(const char *wanted_genre,const char *wanted_artist, const char *wanted_album)
450 GList *list = NULL;
451 axlNode *root;
452 axlNode *cur;
453 /** check if there is data */
454 g_mutex_lock(mt_db_lock);
455 if(magnatune_xmldoc == NULL || wanted_genre == NULL)
457 g_mutex_unlock(mt_db_lock);
458 return NULL;
461 root = axl_doc_get_root(magnatune_xmldoc);
462 cur = axl_node_get_first_child(root);
463 while(cur != NULL)
465 axlNode *cur2;
466 if(NODE_CMP_NAME(cur, "Album"))
468 const char *genre = NULL;
469 const char *album = NULL;
470 const char *artist = NULL;
471 gboolean add_urls = FALSE;
472 axlNode *tracks;
473 cur2 = axl_node_get_first_child(cur);
474 while(cur2 != NULL)
476 if(NODE_CMP_NAME(cur2, "magnatunegenres"))
478 genre = axl_node_get_content(cur2,NULL);
480 else if(NODE_CMP_NAME(cur2, "artist"))
482 artist = axl_node_get_content(cur2,NULL);
484 else if(NODE_CMP_NAME(cur2, "albumname"))
486 album = axl_node_get_content(cur2,NULL);
488 cur2 = axl_node_get_next(cur2);
490 if(genre && strstr(genre, wanted_genre))
492 if(wanted_artist && wanted_album) {
493 if(!strcmp(wanted_artist,artist) && !strcmp(wanted_album, album)) {
494 add_urls = TRUE;
496 }else if(wanted_artist) {
497 if(!strcmp(wanted_artist, artist)) {
498 add_urls = TRUE;
500 } else {
501 add_urls = TRUE;
504 if(add_urls)
506 cur2 = axl_node_get_first_child(cur);
507 while(cur2)
509 if (NODE_CMP_NAME(cur2, "Track"))
511 tracks = axl_node_get_first_child(cur2);
512 while(tracks)
514 if (NODE_CMP_NAME(tracks, "url"))
516 const char *url = axl_node_get_content(tracks,NULL);
517 list = g_list_append(list, url_decode(url));
519 tracks = axl_node_get_next(tracks);
522 cur2 = axl_node_get_next(cur2);
526 cur = axl_node_get_next(cur);
528 g_mutex_unlock(mt_db_lock);
529 return list;
534 MpdData* magnatune_db_get_song_list(const char *wanted_genre,const char *wanted_artist, const char *wanted_album)
536 MpdData *data = NULL;
537 axlNode * root;
538 axlNode * cur;
539 /** check if there is data */
540 g_mutex_lock(mt_db_lock);
541 if(magnatune_xmldoc == NULL || wanted_genre == NULL)
543 g_mutex_unlock(mt_db_lock);
544 return NULL;
547 root = axl_doc_get_root(magnatune_xmldoc);
548 cur = axl_node_get_first_child(root);
549 while(cur != NULL)
551 axlNode * cur2;
552 if(NODE_CMP_NAME(cur, (const char *)"Album"))
554 const char *year = NULL;
555 const char *temp = NULL;
556 const char *genre = NULL;
557 const char *album = NULL;
558 const char *artist = NULL;
560 gboolean add_urls = FALSE;
561 axlNode * tracks;
562 cur2 = axl_node_get_first_child(cur);
563 while(cur2 != NULL)
565 if(NODE_CMP_NAME(cur2, (const char *)"magnatunegenres"))
567 genre = axl_node_get_content(cur2,NULL);
569 else if(NODE_CMP_NAME(cur2, (const char *)"artist"))
571 artist = axl_node_get_content(cur2,NULL);
573 else if(NODE_CMP_NAME(cur2, (const char *)"albumname"))
575 album = axl_node_get_content(cur2,NULL);
578 cur2 = axl_node_get_next(cur2);
580 if(genre && strstr(genre, wanted_genre))
582 if(wanted_artist && wanted_album) {
583 if(!strcmp(wanted_artist,artist) && !strcmp(wanted_album, album)) {
584 add_urls = TRUE;
586 }else if(wanted_artist) {
587 if(!strcmp(wanted_artist, artist)) {
588 add_urls = TRUE;
590 } else {
591 add_urls = TRUE;
595 if(add_urls)
597 cur2 = axl_node_get_first_child(cur);
598 while(cur2)
600 if (NODE_CMP_NAME(cur2, (const char *)"Track"))
602 const char *tn = NULL;
603 int stime = 0;
604 const char *url= NULL;
605 const char *name = NULL;
607 tracks = axl_node_get_first_child(cur2);
610 while(tracks)
612 if (NODE_CMP_NAME(tracks, (const char *)"url")&& !url)
614 url= axl_node_get_content(tracks,NULL);
616 else if (NODE_CMP_NAME(tracks, (const char *)"trackname")&& !name)
618 name = axl_node_get_content(tracks,NULL);
621 else if (NODE_CMP_NAME(tracks, (const char *)"tracknum")&& !tn)
623 tn = axl_node_get_content(tracks,NULL);
625 else if (NODE_CMP_NAME(tracks, "seconds")&& !stime)
627 const char *eurl = axl_node_get_content(tracks, NULL);
628 stime = atoi(eurl);
630 else if (NODE_CMP_NAME(tracks, (const char *)"year")&& !year)
632 year = axl_node_get_content(tracks,NULL);
634 tracks = axl_node_get_next(tracks);
637 if(url){
638 data = (MpdData *)mpd_new_data_struct_append((MpdData *)data);
639 data->type = MPD_DATA_TYPE_SONG;
640 data->song = mpd_newSong();
641 data->song->file = url_decode(url);
642 data->song->title = url_decode(name);
643 data->song->album = url_decode(album);
644 data->song->artist = url_decode(artist);
645 data->song->genre = url_decode(genre);
646 data->song->date = url_decode(year);
647 data->song->track = url_decode(tn);
648 data->song->time = stime;
651 cur2 = axl_node_get_next(cur2);
655 cur = axl_node_get_next(cur);
657 g_mutex_unlock(mt_db_lock);
658 return data;