Move to sqlite
[gmpc-magnatune.git] / src / magnatune.c
blob21f64c3cfad3d72e9f0e4b95fc2304d513d57b6d
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.
20 #include <stdio.h>
21 #include <string.h>
22 #include <gtk/gtk.h>
23 #include <gmpc/plugin.h>
24 #include <gmpc/gmpc_easy_download.h>
25 #include <gmpc/misc.h>
26 #include <libmpd/libmpd-internal.h>
27 #include <sqlite3.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;
36 /* hack fix this */
37 int magnatune_end_download();
38 char *GENRE_LIST[] =
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)
67 if(mt_db_lock)
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()
88 gchar *path = NULL;
90 g_mutex_lock(mt_db_lock);
92 /**
93 * if open close it
95 if(magnatune_sqlhandle)
97 sqlite3_close(magnatune_sqlhandle);
98 magnatune_sqlhandle = NULL;
101 g_free(path);
102 path = gmpc_get_user_path("magnatune.sqlite3");
103 sqlite3_open(path, &(magnatune_sqlhandle));
104 g_free(path);
106 g_mutex_unlock(mt_db_lock);
108 /* FIXME */
109 gboolean magnatune_db_has_data()
111 return TRUE;
114 MpdData * magnatune_db_get_genre_list()
116 MpdData *list = NULL;
117 xmlNodePtr **root;
118 xmlNodePtr **cur;
119 int i;
121 g_mutex_lock(mt_db_lock);
122 char *query = sqlite3_mprintf("SELECT genre from 'genres' group by genre");
123 sqlite3_stmt *stmt;
124 const char *tail;
125 int r = sqlite3_prepare_v2(magnatune_sqlhandle, query, -1, &stmt, &tail);
126 if(r ==SQLITE_OK) {
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);
136 sqlite3_free(query);
137 g_mutex_unlock(mt_db_lock);
138 return misc_mpddata_remove_duplicate_songs(list);
141 void magnatune_db_download_xml_thread(gpointer data)
143 gchar *error = NULL;
144 xmlTextReaderPtr reader = NULL;
145 gchar *path;
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)
168 /* Cleanup */
169 g_mutex_unlock(mt_db_lock);
170 return;
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);
182 g_free(dld);
183 g_mutex_unlock(mt_db_lock);
185 g_idle_add(magnatune_end_download, NULL);
186 g_free(path);
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;
192 dld->callback = cb;
193 dld->max_size = -1;
194 dld->data = NULL;
195 dld->size = 0;
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;
203 xmlNodePtr root;
204 xmlNodePtr cur;
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);
208 sqlite3_stmt *stmt;
209 const char *tail;
210 int r = sqlite3_prepare_v2(magnatune_sqlhandle, query, -1, &stmt, &tail);
211 if(r ==SQLITE_OK) {
212 while((r = sqlite3_step(stmt)) == SQLITE_ROW)
214 sqlite3_stmt *stmt2;
215 const char *tail2;
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);
219 if(r2 ==SQLITE_OK) {
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);
234 sqlite3_free(query);
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;
242 xmlNodePtr **root;
243 xmlNodePtr **cur;
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);
248 sqlite3_stmt *stmt;
249 const char *tail;
250 int r = sqlite3_prepare_v2(magnatune_sqlhandle, query, -1, &stmt, &tail);
251 if(r ==SQLITE_OK) {
252 while((r = sqlite3_step(stmt)) == SQLITE_ROW)
254 sqlite3_stmt *stmt2;
255 const char *tail2;
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);
259 if(r2 ==SQLITE_OK) {
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);
274 sqlite3_free(query);
275 g_mutex_unlock(mt_db_lock);
276 return mpd_data_get_first(list);
279 static char *__magnatune_get_artist_name(const char *album)
281 char *retv = NULL;
282 sqlite3_stmt *stmt;
283 const char *tail;
284 int r = 0;
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);
289 if(r ==SQLITE_OK) {
290 if((r = sqlite3_step(stmt)) == SQLITE_ROW)
292 retv = g_strdup(sqlite3_column_text(stmt, 0));
294 sqlite3_finalize(stmt);
296 sqlite3_free(query);
297 return retv;
299 static char *__magnatune_get_genre_name(const char *album)
301 char *retv = NULL;
302 sqlite3_stmt *stmt;
303 const char *tail;
304 int r = 0;
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);
309 if(r ==SQLITE_OK) {
310 while((r = sqlite3_step(stmt)) == SQLITE_ROW)
312 gchar *temp= sqlite3_column_text(stmt, 0);
313 if(retv)
315 gchar *t = retv;
316 retv = g_strconcat(t, ", ",temp, NULL);
317 g_free(t);
319 else retv = g_strdup(temp);
321 sqlite3_finalize(stmt);
323 sqlite3_free(query);
324 return retv;
326 static MpdData *__magnatune_get_data_album(const char *album, gboolean exact)
328 MpdData *list = NULL;
329 char *query = NULL;
330 sqlite3_stmt *stmt;
331 const char *tail;
332 int r = 0;
333 if(exact)
335 query = sqlite3_mprintf("SELECT songs.albumname,duration,number,desc,mp3 from 'songs' "
336 "WHERE songs.albumname=%Q",album);
337 }else{
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);
342 if(r ==SQLITE_OK) {
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);
356 g_free(temp);
358 sqlite3_finalize(stmt);
360 sqlite3_free(query);
361 return list;
363 static gchar ** __magnatune_get_albums(const char *genre, const char *artist, gboolean exact)
365 char **retv = NULL;
366 sqlite3_stmt *stmt;
367 const char *tail;
368 int items = 0;
369 int r = 0;
370 const char *query = NULL;
372 if(genre && !artist) {
373 if(exact)
374 query = sqlite3_mprintf("SELECT albumname FROM 'genres' WHERE genre=%Q", genre);
375 else
376 query = sqlite3_mprintf("SELECT albumname FROM 'genres' WHERE genre LIKE '%%%%%q%%%%'", genre);
378 else if (artist && !genre) {
379 if(exact)
380 query = sqlite3_mprintf("SELECT albumname FROM 'albums' WHERE artist=%Q", artist);
381 else
382 query = sqlite3_mprintf("SELECT albumname FROM 'albums' WHERE artist LIKE '%%%%%q%%%%'", artist);
384 else if (artist && genre) {
385 if(exact)
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);
387 else
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);
394 if(r ==SQLITE_OK) {
395 while((r = sqlite3_step(stmt)) == SQLITE_ROW)
397 items++;
398 retv = g_realloc(retv, (items+1)*sizeof(*retv));
399 retv[items] = NULL;
400 retv[items-1] = g_strdup(sqlite3_column_text(stmt, 0));
402 sqlite3_finalize(stmt);
404 sqlite3_free(query);
405 return retv;
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;
411 xmlNodePtr * root;
412 xmlNodePtr * cur;
413 char *query;
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);
422 else
424 char **albums = __magnatune_get_albums(wanted_genre, wanted_artist, exact);
425 if(albums)
427 int i;
428 for(i=0; albums[i];i++)
430 MpdData *data2 = __magnatune_get_data_album(albums[i], exact);
431 data = mpd_data_concatenate(data, data2);
433 g_strfreev(albums);
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;
445 char *query = NULL;
446 sqlite3_stmt *stmt;
447 const char *tail;
448 int r = 0;
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);
452 if(r ==SQLITE_OK) {
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);
466 g_free(temp);
468 sqlite3_finalize(stmt);
470 sqlite3_free(query);
471 return list;
476 gchar *magnatune_get_artist_image(const gchar *wanted_artist)
478 gchar *retv = NULL;
479 return retv;
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)
489 char *retv = NULL;
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);
496 g_free(artist);
497 g_free(album);
498 g_free(artist_enc);
499 g_free(album_enc);
500 return retv;