1 /* gmpc-magnatune (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.
24 #include <gmpc/plugin.h>
25 #include <gmpc/gmpc_easy_download.h>
26 #include <gmpc/misc.h>
27 #include <libmpd/libmpd-internal.h>
28 #include "magnatune.h"
30 static void magnatune_cleanup_xml();
31 static axlDoc
*magnatune_xmldoc
= NULL
;
32 GMutex
*mt_db_lock
= NULL
;
35 int magnatune_end_download();
38 * Makes a copy with all &#<id>; decoded
40 static char * url_decode(const char *string
)
43 if(string
&& string
[0] != '\0')
46 const gchar
*a
= string
;
48 b
= retv
= g_malloc0((strlen(string
)+1)*sizeof(char));
67 void magnatune_db_destroy(void)
71 g_mutex_lock(mt_db_lock
);
72 g_mutex_unlock(mt_db_lock
);
73 g_mutex_free(mt_db_lock
);
77 axl_doc_free(magnatune_xmldoc
);
79 magnatune_xmldoc
= NULL
;
83 /* run this before using the other fucntions */
84 void magnatune_db_init()
86 mt_db_lock
= g_mutex_new();
90 void magnatune_db_open()
92 gchar
*path
= gmpc_get_user_path("magnatune.xml");
94 g_mutex_lock(mt_db_lock
);
96 * if the db doesn't exists exit
98 if(!g_file_test(path
, G_FILE_TEST_EXISTS
))
101 g_mutex_unlock(mt_db_lock
);
109 axl_doc_free(magnatune_xmldoc
);
110 magnatune_xmldoc
= NULL
;
112 magnatune_xmldoc
= axl_doc_parse_from_file(path
, NULL
);
114 g_mutex_unlock(mt_db_lock
);
118 gboolean
magnatune_db_has_data()
120 gboolean data
= FALSE
;
121 g_mutex_lock(mt_db_lock
);
122 data
= (magnatune_xmldoc
!= NULL
)? TRUE
:FALSE
;
123 g_mutex_unlock(mt_db_lock
);
127 MpdData
* magnatune_db_get_genre_list()
129 MpdData
*list
= NULL
;
132 /** check if there is data */
133 g_mutex_lock(mt_db_lock
);
134 if(magnatune_xmldoc
== NULL
)
136 g_mutex_unlock(mt_db_lock
);
140 root
= axl_doc_get_root(magnatune_xmldoc
);
141 cur
= axl_node_get_first_child(root
);
145 if(NODE_CMP_NAME(cur
, "Album"))
147 const char *genre
= NULL
;
148 cur2
= axl_node_get_first_child(cur
);
151 if(NODE_CMP_NAME(cur2
, "magnatunegenres"))
153 gchar
**tokens
= NULL
;
154 genre
= axl_node_get_content(cur2
,NULL
);
158 tokens
= g_strsplit(genre
,",",0);
159 for(i
=0; tokens
[i
];i
++)
161 list
= mpd_new_data_struct_append(list
);
162 list
->type
= MPD_DATA_TYPE_TAG
;
163 list
->tag_type
= MPD_TAG_ITEM_GENRE
;
164 list
->tag
= url_decode(tokens
[i
]);
169 cur2
= axl_node_get_next(cur2
);
173 cur
= axl_node_get_next(cur
);
175 g_mutex_unlock(mt_db_lock
);
176 return misc_mpddata_remove_duplicate_songs(list
);
179 gchar
*magnatune_db_get_value(const char *artist
, const char *album
, int type
)
181 gchar
*retval
= NULL
;
184 /** check if there is data */
185 g_mutex_lock(mt_db_lock
);
186 if(magnatune_xmldoc
== NULL
|| !artist
)
188 g_mutex_unlock(mt_db_lock
);
192 root
= axl_doc_get_root(magnatune_xmldoc
);
193 cur
= axl_node_get_first_child(root
);
194 while(cur
!= NULL
&& !retval
)
197 if(NODE_CMP_NAME(cur
, "Album"))
199 const char *gartist
= NULL
;
200 const char *galbum
= NULL
;
201 const char *gvalue
= NULL
;
202 cur2
= axl_node_get_first_child(cur
);
203 while(cur2
!= NULL
&& !retval
)
205 if(!gartist
&& NODE_CMP_NAME(cur2
, "artist"))
207 gartist
= axl_node_get_content(cur2
,NULL
);
209 else if(!galbum
&& NODE_CMP_NAME(cur2
, "albumname"))
211 galbum
= axl_node_get_content(cur2
,NULL
);
213 else if(!gvalue
&& NODE_CMP_NAME(cur2
, ((type
== META_ARTIST_ART
)?"artistphoto":"cover_small")))
215 gvalue
= axl_node_get_content(cur2
,NULL
);
217 cur2
= axl_node_get_next(cur2
);
219 if(gvalue
&& artist
&& !strncmp(gartist
, artist
,strlen(artist
)))
221 if(type
== META_ARTIST_ART
)
223 retval
= url_decode(gvalue
);
225 else if(galbum
&& !strcmp(galbum
, album
)){
226 retval
= url_decode(gvalue
);
231 cur
= axl_node_get_next(cur
);
234 g_mutex_unlock(mt_db_lock
);
238 * This removes duplicate/unused fields from every Track entry,
239 * This remove around 1/2 the file size
240 * NOT THREAD SAFE, USE INTERNALLY
242 static void magnatune_cleanup_xml()
246 if(!magnatune_xmldoc
)
248 root
= axl_doc_get_root(magnatune_xmldoc
);
249 cur
= axl_node_get_first_child(root
);
253 if(NODE_CMP_NAME(cur
, "Album"))
255 cur2
= axl_node_get_first_child(cur
);
258 if(NODE_CMP_NAME(cur2
, "Track"))
260 axlNode
*cur3
= axl_node_get_first_child(cur2
) ;
262 if(NODE_CMP_NAME(cur3
, "albumname") ||
263 NODE_CMP_NAME(cur3
, "artist") ||
264 NODE_CMP_NAME(cur3
, "artistdesc") ||
265 NODE_CMP_NAME(cur3
, "home") ||
266 NODE_CMP_NAME (cur3
, "artistphoto") ||
267 NODE_CMP_NAME (cur3
, "mp3lofi") ||
268 NODE_CMP_NAME (cur3
, "albumsku") ||
269 NODE_CMP_NAME (cur3
, "mp3genre") ||
270 NODE_CMP_NAME (cur3
, "magnatunegenres") ||
271 NODE_CMP_NAME (cur3
, "license") ||
272 NODE_CMP_NAME (cur3
, "album_notes") ||
273 NODE_CMP_NAME (cur3
, "launchdate") ||
274 NODE_CMP_NAME (cur3
, "buy") ||
275 NODE_CMP_NAME (cur3
, "moods") )
278 axl_node_remove(cur3
,TRUE
);
280 cur3
= axl_node_get_first_child(cur2
) ;
282 cur3
= axl_node_get_next(cur3
);
285 cur2
= axl_node_get_next(cur2
);
287 else if(NODE_CMP_NAME(cur2
, "album_notes") ||
288 NODE_CMP_NAME (cur2
, "buy") ||
289 NODE_CMP_NAME (cur2
, "launchdate"))
291 axl_node_remove(cur2
,TRUE
);
292 cur2
= axl_node_get_first_child(cur
);
294 cur2
= axl_node_get_next(cur2
);
298 cur
= axl_node_get_next(cur
);
303 void magnatune_db_download_xml_thread(gpointer data
)
305 gmpc_easy_download_struct
*dld
= data
;
307 g_mutex_lock(mt_db_lock
);
311 axl_doc_free(magnatune_xmldoc
);
313 magnatune_xmldoc
= NULL
;
315 g_mutex_unlock(mt_db_lock
);
316 if(gmpc_easy_download("http://www.magnatune.com/info/album_info.xml", dld
))
318 g_mutex_lock(mt_db_lock
);
320 magnatune_xmldoc
= axl_doc_parse(dld
->data
, dld
->size
, NULL
);
321 magnatune_cleanup_xml();
322 path
= gmpc_get_user_path("magnatune.xml");
323 axl_doc_dump_to_file(magnatune_xmldoc
, path
);
325 g_mutex_unlock(mt_db_lock
);
329 g_mutex_lock(mt_db_lock
);
331 gchar
*path
= gmpc_get_user_path("magnatune.xml");
332 if(g_file_test(path
, G_FILE_TEST_EXISTS
))
334 magnatune_xmldoc
= axl_doc_parse_from_file(path
, NULL
);
337 g_mutex_unlock(mt_db_lock
);
342 gmpc_easy_download_clean(dld
);
347 g_idle_add(magnatune_end_download
, NULL
);
350 void magnatune_db_download_xml(ProgressCallback cb
, gpointer data
)
352 gmpc_easy_download_struct
*dld
= g_malloc0(sizeof(*dld
));
353 dld
->callback_data
= data
;
358 g_thread_create((GThreadFunc
)magnatune_db_download_xml_thread
, dld
,FALSE
, NULL
);
362 MpdData
* magnatune_db_get_artist_list(char *wanted_genre
)
364 MpdData
*list
= NULL
;
367 /** check if there is data */
368 g_mutex_lock(mt_db_lock
);
369 if(magnatune_xmldoc
== NULL
|| wanted_genre
== NULL
)
371 g_mutex_unlock(mt_db_lock
);
375 root
= axl_doc_get_root(magnatune_xmldoc
);
376 cur
= axl_node_get_first_child(root
);
380 if(NODE_CMP_NAME(cur
, "Album"))
382 const char *genre
= NULL
;
383 const char *artist
= NULL
;
384 cur2
= axl_node_get_first_child(cur
);
387 if(NODE_CMP_NAME(cur2
, "magnatunegenres"))
389 genre
= axl_node_get_content(cur2
,NULL
);
391 else if(NODE_CMP_NAME(cur2
, "artist"))
393 artist
= axl_node_get_content(cur2
,NULL
);
395 cur2
= axl_node_get_next(cur2
);
397 if(genre
&& artist
&& strstr(genre
, wanted_genre
))
399 list
= mpd_new_data_struct_append(list
);
400 list
->type
= MPD_DATA_TYPE_TAG
;
401 list
->tag_type
= MPD_TAG_ITEM_ARTIST
;
402 list
->tag
= url_decode(artist
);
407 cur
= axl_node_get_next(cur
);
409 g_mutex_unlock(mt_db_lock
);
410 return misc_mpddata_remove_duplicate_songs(list
);
413 MpdData
*magnatune_db_get_album_list(char *wanted_genre
,char *wanted_artist
)
415 MpdData
*list
= NULL
;
418 /** check if there is data */
419 g_mutex_lock(mt_db_lock
);
420 if(magnatune_xmldoc
== NULL
|| wanted_genre
== NULL
|| wanted_artist
== NULL
)
422 g_mutex_unlock(mt_db_lock
);
426 root
= axl_doc_get_root(magnatune_xmldoc
);
427 cur
= axl_node_get_first_child(root
);
431 if(NODE_CMP_NAME(cur
, "Album"))
433 const char *genre
= NULL
;
434 const char *album
= NULL
;
435 const char *artist
= NULL
;
436 cur2
= axl_node_get_first_child(cur
);
439 if(NODE_CMP_NAME(cur2
, "magnatunegenres"))
441 genre
= axl_node_get_content(cur2
,NULL
);
443 else if(NODE_CMP_NAME(cur2
, "artist"))
445 artist
= axl_node_get_content(cur2
,NULL
);
447 else if(NODE_CMP_NAME(cur2
, "albumname"))
449 album
= axl_node_get_content(cur2
,NULL
);
451 cur2
= axl_node_get_next(cur2
);
453 if(genre
&& artist
&&album
&& strstr(genre
, wanted_genre
) && !strcmp(artist
, wanted_artist
))
455 list
= mpd_new_data_struct_append(list
);
456 list
->type
= MPD_DATA_TYPE_TAG
;
457 list
->tag_type
= MPD_TAG_ITEM_ALBUM
;
458 list
->tag
= url_decode(album
);
461 cur
= axl_node_get_next(cur
);
463 g_mutex_unlock(mt_db_lock
);
464 return mpd_data_get_first(list
);
468 GList
* magnatune_db_get_url_list(const char *wanted_genre
,const char *wanted_artist
, const char *wanted_album
)
473 /** check if there is data */
474 g_mutex_lock(mt_db_lock
);
475 if(magnatune_xmldoc
== NULL
|| wanted_genre
== NULL
)
477 g_mutex_unlock(mt_db_lock
);
481 root
= axl_doc_get_root(magnatune_xmldoc
);
482 cur
= axl_node_get_first_child(root
);
486 if(NODE_CMP_NAME(cur
, "Album"))
488 const char *genre
= NULL
;
489 const char *album
= NULL
;
490 const char *artist
= NULL
;
491 gboolean add_urls
= FALSE
;
493 cur2
= axl_node_get_first_child(cur
);
496 if(NODE_CMP_NAME(cur2
, "magnatunegenres"))
498 genre
= axl_node_get_content(cur2
,NULL
);
500 else if(NODE_CMP_NAME(cur2
, "artist"))
502 artist
= axl_node_get_content(cur2
,NULL
);
504 else if(NODE_CMP_NAME(cur2
, "albumname"))
506 album
= axl_node_get_content(cur2
,NULL
);
508 cur2
= axl_node_get_next(cur2
);
510 if(genre
&& strstr(genre
, wanted_genre
))
512 if(wanted_artist
&& wanted_album
) {
513 if(!strcmp(wanted_artist
,artist
) && !strcmp(wanted_album
, album
)) {
516 }else if(wanted_artist
) {
517 if(!strcmp(wanted_artist
, artist
)) {
526 cur2
= axl_node_get_first_child(cur
);
529 if (NODE_CMP_NAME(cur2
, "Track"))
531 tracks
= axl_node_get_first_child(cur2
);
534 if (NODE_CMP_NAME(tracks
, "url"))
536 const char *url
= axl_node_get_content(tracks
,NULL
);
537 list
= g_list_append(list
, url_decode(url
));
539 tracks
= axl_node_get_next(tracks
);
542 cur2
= axl_node_get_next(cur2
);
546 cur
= axl_node_get_next(cur
);
548 g_mutex_unlock(mt_db_lock
);
552 static int custcmp(const gchar
*hay
, const gchar
*needle
)
555 gchar
*sa1
= g_utf8_casefold(needle
, -1);
556 gchar
*sa
= g_utf8_normalize(sa1
,-1,G_NORMALIZE_ALL_COMPOSE
);
557 gchar
*sb1
= g_utf8_casefold(hay
, -1);
558 gchar
*sb
= g_utf8_normalize(sb1
,-1,G_NORMALIZE_ALL_COMPOSE
);
559 retv
= (strstr(sb
, sa
) == NULL
);
560 g_free(sa1
);g_free(sa
);
561 g_free(sb1
);g_free(sb
);
565 MpdData
* magnatune_db_get_song_list(const char *wanted_genre
,const char *wanted_artist
, const char *wanted_album
, gboolean exact
)
567 MpdData
*data
= NULL
;
570 int (*cmpfunc
)(const char *hay
, const char *needle
);
577 /** check if there is data */
578 g_mutex_lock(mt_db_lock
);
579 if(magnatune_xmldoc
== NULL
)
581 g_mutex_unlock(mt_db_lock
);
585 root
= axl_doc_get_root(magnatune_xmldoc
);
586 cur
= axl_node_get_first_child(root
);
590 if(NODE_CMP_NAME(cur
, (const char *)"Album"))
592 const char *year
= NULL
;
593 const char *temp
= NULL
;
594 const char *genre
= NULL
;
595 const char *album
= NULL
;
596 const char *artist
= NULL
;
598 gboolean add_urls
= FALSE
;
600 cur2
= axl_node_get_first_child(cur
);
603 if(NODE_CMP_NAME(cur2
, (const char *)"magnatunegenres"))
605 genre
= axl_node_get_content(cur2
,NULL
);
607 else if(NODE_CMP_NAME(cur2
, (const char *)"artist"))
609 artist
= axl_node_get_content(cur2
,NULL
);
611 else if(NODE_CMP_NAME(cur2
, (const char *)"albumname"))
613 album
= axl_node_get_content(cur2
,NULL
);
616 cur2
= axl_node_get_next(cur2
);
619 if(wanted_genre
&& add_urls
) {
624 gchar
**str
= g_strsplit(genre
, ",", 0);
625 for(i
=0; str
&& str
[i
];i
++)
627 if(cmpfunc(str
[i
], wanted_genre
) == 0) add_urls
= TRUE
;
629 if(str
)g_strfreev(str
);
632 if(wanted_album
&& add_urls
) {
633 add_urls
= (album
&& cmpfunc(album
, wanted_album
) == 0);
635 if(wanted_artist
&& add_urls
) {
636 add_urls
= (artist
&& cmpfunc(artist
, wanted_artist
) == 0);
641 cur2
= axl_node_get_first_child(cur
);
644 if (NODE_CMP_NAME(cur2
, (const char *)"Track"))
646 const char *tn
= NULL
;
648 const char *url
= NULL
;
649 const char *name
= NULL
;
651 tracks
= axl_node_get_first_child(cur2
);
656 if (NODE_CMP_NAME(tracks
, (const char *)"url")&& !url
)
658 url
= axl_node_get_content(tracks
,NULL
);
660 else if (NODE_CMP_NAME(tracks
, (const char *)"trackname")&& !name
)
662 name
= axl_node_get_content(tracks
,NULL
);
665 else if (NODE_CMP_NAME(tracks
, (const char *)"tracknum")&& !tn
)
667 tn
= axl_node_get_content(tracks
,NULL
);
669 else if (NODE_CMP_NAME(tracks
, "seconds")&& !stime
)
671 const char *eurl
= axl_node_get_content(tracks
, NULL
);
674 else if (NODE_CMP_NAME(tracks
, (const char *)"year")&& !year
)
676 year
= axl_node_get_content(tracks
,NULL
);
678 tracks
= axl_node_get_next(tracks
);
682 data
= (MpdData
*)mpd_new_data_struct_append((MpdData
*)data
);
683 data
->type
= MPD_DATA_TYPE_SONG
;
684 data
->song
= mpd_newSong();
685 data
->song
->file
= url_decode(url
);
686 data
->song
->title
= url_decode(name
);
687 data
->song
->album
= url_decode(album
);
688 data
->song
->artist
= url_decode(artist
);
689 data
->song
->genre
= url_decode(genre
);
690 data
->song
->date
= url_decode(year
);
691 data
->song
->track
= url_decode(tn
);
692 data
->song
->time
= stime
;
695 cur2
= axl_node_get_next(cur2
);
699 cur
= axl_node_get_next(cur
);
701 g_mutex_unlock(mt_db_lock
);