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.
23 #include <gmpc/plugin.h>
24 #include <gmpc/gmpc_easy_download.h>
25 #include <gmpc/misc.h>
26 #include <libmpd/libmpd-internal.h>
28 #include <libxml/xmlreader.h>
29 #include <libxml/tree.h>
30 #include "magnatune.h"
32 static void magnatune_cleanup_xml();
33 static sqlite3
*magnatune_sqlhandle
= NULL
;
34 GMutex
*mt_db_lock
= NULL
;
37 int magnatune_end_download();
40 "", "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
41 "Grunge", "Hip-Hop", "Jazz", "Metal ", "New Age ", "Oldies ", "Other ",
42 "Pop ", "R&B ", "Rap ", "Reggae ", "Rock ", "Techno ", "Industrial ",
43 "Alternative ", "Ska ", "Death Metal ", "Pranks ", "Soundtrack ", "Euro-Techno ", "Ambient ",
44 "Trip-Hop ", "Vocal ", "Jazz+Funk ", "Fusion ", "Trance ", "Classical ", "Instrumental ",
45 "Acid ", "House ", "Game ", "Sound Clip ", "Gospel ", "Noise ", "Alternative Rock ",
46 "Bass ", "Soul ", "Punk ", "Space ", "Meditative ", "Instrumental Pop ", "Instrumental Rock ",
47 "Ethnic ", "Gothic ", "Darkwave ", "Techno-Industrial ", "Electronic ", "Pop-Folk ", "Eurodance ",
48 "Dream ", "Southern Rock ", "Comedy ", "Cult ", "Gangsta ", "Top 40 ", "Christian Rap ",
49 "Pop/Funk ", "Jungle ", "Native US ", "Cabaret ", "New Wave ", "Psychadelic ", "Rave ",
50 "Showtunes ", "Trailer ", "Lo-Fi ", "Tribal ", "Acid Punk ", "Acid Jazz ", "Polka ",
51 "Retro ", "Musical ", "Rock & Roll ", "Hard Rock ", "Folk ", "Folk-Rock ", "National Folk ",
52 "Swing ", "Fast Fusion ", "Bebob ", "Latin ", "Revival ", "Celtic ", "Bluegrass ",
53 "Avantgarde ", "Gothic Rock ", "Progressive Rock ", "Psychedelic Rock ", "Symphonic Rock ", "Slow Rock ", "Big Band ",
54 "Chorus ", "Easy Listening ", "Acoustic ", "Humour ", "Speech ", "Chanson ", "Opera ",
55 "Chamber Music ", "Sonata ", "Symphony ", "Booty Bass ", "Primus ", "Porn Groove ", "Satire",
56 "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad",
57 "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "Acapella", "Euro-House",
58 "Dance Hall", "Goa", "Drum & Bass", "Club\"House", "Hardcore", "Terror", "Indie",
59 "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal",
60 "Crossover", "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime",
61 "JPop", "Synthpop", "Unknown", NULL
65 void magnatune_db_destroy(void)
69 g_mutex_lock(mt_db_lock
);
70 g_mutex_unlock(mt_db_lock
);
71 g_mutex_free(mt_db_lock
);
73 if(magnatune_sqlhandle
)
75 sqlite3_close(magnatune_sqlhandle
);
76 magnatune_sqlhandle
= NULL
;
80 /* run this before using the other fucntions */
81 void magnatune_db_init()
83 mt_db_lock
= g_mutex_new();
86 void magnatune_db_open()
90 g_mutex_lock(mt_db_lock
);
95 if(magnatune_sqlhandle
)
97 sqlite3_close(magnatune_sqlhandle
);
98 magnatune_sqlhandle
= NULL
;
102 path
= gmpc_get_user_path("magnatune.sqlite3");
103 sqlite3_open(path
, &(magnatune_sqlhandle
));
106 g_mutex_unlock(mt_db_lock
);
109 gboolean
magnatune_db_has_data()
114 MpdData
* magnatune_db_get_genre_list()
116 MpdData
*list
= NULL
;
121 g_mutex_lock(mt_db_lock
);
122 char *query
= sqlite3_mprintf("SELECT genre from 'genres' group by genre");
125 int r
= sqlite3_prepare_v2(magnatune_sqlhandle
, query
, -1, &stmt
, &tail
);
127 while((r
= sqlite3_step(stmt
)) == SQLITE_ROW
)
129 list
= mpd_new_data_struct_append(list
);
130 list
->type
= MPD_DATA_TYPE_TAG
;
131 list
->tag_type
= MPD_TAG_ITEM_GENRE
;
132 list
->tag
= g_strdup(sqlite3_column_text(stmt
,0));
134 sqlite3_finalize(stmt
);
137 g_mutex_unlock(mt_db_lock
);
138 return misc_mpddata_remove_duplicate_songs(list
);
141 void magnatune_db_download_xml_thread(gpointer data
)
144 xmlTextReaderPtr reader
= NULL
;
146 gmpc_easy_download_struct
*dld
= data
;
148 g_mutex_lock(mt_db_lock
);
150 path
= gmpc_get_user_path("magnatune.sqlite3");
151 if(magnatune_sqlhandle
)
153 sqlite3_close(magnatune_sqlhandle
);
154 magnatune_sqlhandle
= NULL
;
156 if(gmpc_easy_download("http://he3.magnatune.com/info/sqlite_magnatune.db", dld
))
158 g_file_set_contents(path
, dld
->data
, dld
->size
, NULL
);
159 gmpc_easy_download_clean(dld
);
161 /* open the db if it is closed */
162 if(!magnatune_sqlhandle
) {
165 int retv
= sqlite3_open(path
, &(magnatune_sqlhandle
));
166 if(retv
!= SQLITE_OK
)
169 g_mutex_unlock(mt_db_lock
);
174 sqlite3_exec(magnatune_sqlhandle
, "CREATE INDEX songsAlbumname ON songs(albumname);", NULL
, NULL
, &error
);
175 if(error
)printf("%i: %s",__LINE__
, error
);
176 sqlite3_exec(magnatune_sqlhandle
, "CREATE INDEX genresAlbumname ON genres(albumname);", NULL
, NULL
, &error
);
177 if(error
)printf("%i: %s",__LINE__
, error
);
178 sqlite3_exec(magnatune_sqlhandle
, "CREATE INDEX songsAlbumname ON songs(albumname);", NULL
, NULL
, &error
);
179 if(error
)printf("%i: %s",__LINE__
, error
);
180 sqlite3_exec(magnatune_sqlhandle
, "CREATE INDEX artistsAlbumname ON artists(albumname);", NULL
, NULL
, &error
);
181 if(error
)printf("%i: %s",__LINE__
, error
);
183 g_mutex_unlock(mt_db_lock
);
185 g_idle_add(magnatune_end_download
, NULL
);
188 void magnatune_db_download_xml(ProgressCallback cb
, gpointer data
)
190 gmpc_easy_download_struct
*dld
= g_malloc0(sizeof(*dld
));
191 dld
->callback_data
= data
;
196 g_thread_create((GThreadFunc
)magnatune_db_download_xml_thread
, dld
,FALSE
, NULL
);
200 MpdData
* magnatune_db_get_artist_list(char *wanted_genre
)
202 MpdData
*list
= NULL
;
205 /** check if there is data */
206 g_mutex_lock(mt_db_lock
);
207 char *query
= sqlite3_mprintf("SELECT albumname from 'genres' WHERE genre=%Q", wanted_genre
);
210 int r
= sqlite3_prepare_v2(magnatune_sqlhandle
, query
, -1, &stmt
, &tail
);
212 while((r
= sqlite3_step(stmt
)) == SQLITE_ROW
)
216 char *query2
= sqlite3_mprintf("SELECT artist from 'albums' WHERE albumname=%Q", sqlite3_column_text(stmt
,0));
217 printf("%s\n", sqlite3_column_text(stmt
, 0));
218 int r2
= sqlite3_prepare_v2(magnatune_sqlhandle
, query2
, -1, &stmt2
, &tail2
);
220 while((r2
= sqlite3_step(stmt2
)) == SQLITE_ROW
)
222 printf("a:%s\n", sqlite3_column_text(stmt2
, 0));
223 list
= mpd_new_data_struct_append(list
);
224 list
->type
= MPD_DATA_TYPE_TAG
;
225 list
->tag_type
= MPD_TAG_ITEM_ARTIST
;
226 list
->tag
= g_strdup(sqlite3_column_text(stmt2
,0));
229 sqlite3_finalize(stmt2
);
230 sqlite3_free(query2
);
232 sqlite3_finalize(stmt
);
235 g_mutex_unlock(mt_db_lock
);
236 return misc_mpddata_remove_duplicate_songs(list
);
239 MpdData
*magnatune_db_get_album_list(char *wanted_genre
,char *wanted_artist
)
241 MpdData
*list
= NULL
;
244 /** check if there is data */
245 g_mutex_lock(mt_db_lock
);
247 char *query
= sqlite3_mprintf("SELECT albumname from 'albums' WHERE artist=%Q",wanted_artist
);
250 int r
= sqlite3_prepare_v2(magnatune_sqlhandle
, query
, -1, &stmt
, &tail
);
252 while((r
= sqlite3_step(stmt
)) == SQLITE_ROW
)
256 char *query2
= sqlite3_mprintf("SELECT albumname from 'genres' WHERE albumname=%Q AND genre=%Q", sqlite3_column_text(stmt
,0),wanted_genre
);
257 printf("%s\n", sqlite3_column_text(stmt
, 0));
258 int r2
= sqlite3_prepare_v2(magnatune_sqlhandle
, query2
, -1, &stmt2
, &tail2
);
260 while((r2
= sqlite3_step(stmt2
)) == SQLITE_ROW
)
262 printf("a:%s\n", sqlite3_column_text(stmt2
, 0));
263 list
= mpd_new_data_struct_append(list
);
264 list
->type
= MPD_DATA_TYPE_TAG
;
265 list
->tag_type
= MPD_TAG_ITEM_ALBUM
;
266 list
->tag
= g_strdup(sqlite3_column_text(stmt2
,0));
269 sqlite3_finalize(stmt2
);
270 sqlite3_free(query2
);
272 sqlite3_finalize(stmt
);
275 g_mutex_unlock(mt_db_lock
);
276 return mpd_data_get_first(list
);
279 static char *__magnatune_get_artist_name(const char *album
)
285 const char *query
= NULL
;
286 if(!album
) return NULL
;
287 query
= sqlite3_mprintf("SELECT artist from 'albums' WHERE albumname=%Q limit 1",album
);
288 r
=sqlite3_prepare_v2(magnatune_sqlhandle
, query
, -1, &stmt
, &tail
);
290 if((r
= sqlite3_step(stmt
)) == SQLITE_ROW
)
292 retv
= g_strdup(sqlite3_column_text(stmt
, 0));
294 sqlite3_finalize(stmt
);
299 static char *__magnatune_get_genre_name(const char *album
)
305 const char *query
= NULL
;
306 if(!album
) return NULL
;
307 query
= sqlite3_mprintf("SELECT genre from 'genres' WHERE albumname=%Q",album
);
308 r
=sqlite3_prepare_v2(magnatune_sqlhandle
, query
, -1, &stmt
, &tail
);
310 while((r
= sqlite3_step(stmt
)) == SQLITE_ROW
)
312 gchar
*temp
= sqlite3_column_text(stmt
, 0);
316 retv
= g_strconcat(t
, ", ",temp
, NULL
);
319 else retv
= g_strdup(temp
);
321 sqlite3_finalize(stmt
);
326 static MpdData
*__magnatune_get_data_album(const char *album
, gboolean exact
)
328 MpdData
*list
= NULL
;
335 query
= sqlite3_mprintf("SELECT songs.albumname,duration,number,desc,mp3 from 'songs' "
336 "WHERE songs.albumname=%Q",album
);
338 query
= sqlite3_mprintf("SELECT songs.albumname,duration,number,desc,mp3 from 'songs' "
339 "WHERE songs.albumname LIKE '%%%%%q%%%%'",album
);
341 r
=sqlite3_prepare_v2(magnatune_sqlhandle
, query
, -1, &stmt
, &tail
);
343 while((r
= sqlite3_step(stmt
)) == SQLITE_ROW
)
345 gchar
*temp
= g_uri_escape_string(sqlite3_column_text(stmt
,4), NULL
, TRUE
);
346 list
= mpd_new_data_struct_append(list
);
347 list
->type
= MPD_DATA_TYPE_SONG
;
348 list
->song
= mpd_newSong();
349 list
->song
->album
= g_strdup(sqlite3_column_text(stmt
,0));
350 list
->song
->artist
= __magnatune_get_artist_name(list
->song
->album
);
351 list
->song
->genre
= __magnatune_get_genre_name(list
->song
->album
);
352 list
->song
->title
= g_strdup(sqlite3_column_text(stmt
,3));
353 list
->song
->track
= g_strdup(sqlite3_column_text(stmt
,2));
354 list
->song
->time
= sqlite3_column_int(stmt
,1);
355 list
->song
->file
= g_strdup_printf("http://he3.magnatune.com/all/%s",temp
);
358 sqlite3_finalize(stmt
);
363 static gchar
** __magnatune_get_albums(const char *genre
, const char *artist
, gboolean exact
)
370 const char *query
= NULL
;
372 if(genre
&& !artist
) {
374 query
= sqlite3_mprintf("SELECT albumname FROM 'genres' WHERE genre=%Q", genre
);
376 query
= sqlite3_mprintf("SELECT albumname FROM 'genres' WHERE genre LIKE '%%%%%q%%%%'", genre
);
378 else if (artist
&& !genre
) {
380 query
= sqlite3_mprintf("SELECT albumname FROM 'albums' WHERE artist=%Q", artist
);
382 query
= sqlite3_mprintf("SELECT albumname FROM 'albums' WHERE artist LIKE '%%%%%q%%%%'", artist
);
384 else if (artist
&& genre
) {
386 query
= sqlite3_mprintf("SELECT genres.albumname FROM 'albums' JOIN 'genres' on albums.albumname = genres.albumname WHERE albums.artist=%Q AND genres.genre=%Q", artist
,genre
);
388 query
= sqlite3_mprintf("SELECT genres.albumname FROM 'albums' JOIN 'genres' on albums.albumname = genres.albumname WHERE albums.artist LIKE '%%%%%q%%%%' AND genres.genre LIKE '%%%%%q%%%%'", artist
,genre
);
391 printf("qeury: %s\n", query
);
393 r
=sqlite3_prepare_v2(magnatune_sqlhandle
, query
, -1, &stmt
, &tail
);
395 while((r
= sqlite3_step(stmt
)) == SQLITE_ROW
)
398 retv
= g_realloc(retv
, (items
+1)*sizeof(*retv
));
400 retv
[items
-1] = g_strdup(sqlite3_column_text(stmt
, 0));
402 sqlite3_finalize(stmt
);
408 MpdData
* magnatune_db_get_song_list(const char *wanted_genre
,const char *wanted_artist
, const char *wanted_album
, gboolean exact
)
410 MpdData
*data
= NULL
;
415 if(!wanted_genre
&& !wanted_artist
&& !wanted_album
) return NULL
;
417 g_mutex_lock(mt_db_lock
);
418 if(wanted_album
) /* album seems to be unique */
420 data
= __magnatune_get_data_album(wanted_album
, exact
);
424 char **albums
= __magnatune_get_albums(wanted_genre
, wanted_artist
, exact
);
428 for(i
=0; albums
[i
];i
++)
430 MpdData
*data2
= __magnatune_get_data_album(albums
[i
], exact
);
431 data
= mpd_data_concatenate(data
, data2
);
437 g_mutex_unlock(mt_db_lock
);
438 return mpd_data_get_first(data
);
441 MpdData
* magnatune_db_search_title(const gchar
*title
)
444 MpdData
*list
= NULL
;
449 query
= sqlite3_mprintf("SELECT songs.albumname,duration,number,desc,mp3 from 'songs' "
450 "WHERE songs.desc LIKE '%%%%%q%%%%'",title
);
451 r
=sqlite3_prepare_v2(magnatune_sqlhandle
, query
, -1, &stmt
, &tail
);
453 while((r
= sqlite3_step(stmt
)) == SQLITE_ROW
)
455 gchar
*temp
= g_uri_escape_string(sqlite3_column_text(stmt
,4), NULL
, TRUE
);
456 list
= mpd_new_data_struct_append(list
);
457 list
->type
= MPD_DATA_TYPE_SONG
;
458 list
->song
= mpd_newSong();
459 list
->song
->album
= g_strdup(sqlite3_column_text(stmt
,0));
460 list
->song
->artist
= __magnatune_get_artist_name(list
->song
->album
);
461 list
->song
->genre
= __magnatune_get_genre_name(list
->song
->album
);
462 list
->song
->title
= g_strdup(sqlite3_column_text(stmt
,3));
463 list
->song
->track
= g_strdup(sqlite3_column_text(stmt
,2));
464 list
->song
->time
= sqlite3_column_int(stmt
,1);
465 list
->song
->file
= g_strdup_printf("http://he3.magnatune.com/all/%s",temp
);
468 sqlite3_finalize(stmt
);
476 gchar
*magnatune_get_artist_image(const gchar
*wanted_artist
)
482 gchar
*magnatune_get_album_url(const gchar
*wanted_artist
, const gchar
*wanted_album
)
487 gchar
*magnatune_get_album_image(const gchar
*wanted_artist
, const gchar
*wanted_album
)
490 char *artist
= __magnatune_process_string(wanted_artist
);
491 char *album
= __magnatune_process_string(wanted_album
);
492 gchar
*artist_enc
= g_uri_escape_string(artist
, NULL
, TRUE
);
493 gchar
*album_enc
= g_uri_escape_string(album
, NULL
, TRUE
);
494 retv
= g_strdup_printf("http://he3.magnatune.com/music/%s/%s/cover_600.jpg",artist_enc
, album_enc
);
495 printf("album url: %s\n", retv
);