1 /*
2 * Copyright (C) 2009-2015 Christian Heckendorf <heckendorfc@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <regex.h>
19 #include "insert.h"
20 #include "defs.h"
21 #include "dbact.h"
22 #include "util.h"
23 #include "plugins/plugin.h"
24
25 //static int verifySong(const int sid);
26 static int insertSong(const char *arg, struct musicInfo *mi);
27
db_insert_safe(char * str,char * data,const size_t size)28 static void db_insert_safe(char *str, char *data, const size_t size){
29 if(!*data){
30 strcpy(str,"Unknown");
31 return;
32 }
33 db_clean(str,data,size);
34 strcpy(data,str);
35 db_safe(str,data,size);
36 if(!*str)strcpy(str,"Unknown");
37 }
38
getArtist(const char * arg)39 int getArtist(const char *arg){
40 char query[301];
41 struct dbitem dbi;
42 dbiInit(&dbi);
43
44 sprintf(query,"SELECT COUNT(ArtistID), ArtistID FROM Artist WHERE Name=\'%s\'",arg);
45 debug(3,query);
46 doQuery(query,&dbi);
47 fetch_row(&dbi);
48 if(strtol(dbi.row[0],NULL,10)==0){//create artist
49 dbiClean(&dbi);
50 sprintf(query,"INSERT INTO Artist (Name) VALUES (\'%s\')",arg);
51 debug(3,query);
52 if(harp_sqlite3_exec(conn,query,NULL,NULL,NULL)!=SQLITE_OK)
53 return -1;
54 return sqlite3_last_insert_rowid(conn);
55 }
56 int id=(int)strtol(dbi.row[1],NULL,10);
57 dbiClean(&dbi);
58 return id;
59 }
60
getAlbum(const char * arg,const int id)61 int getAlbum(const char *arg, const int id){
62 char query[401];
63 struct dbitem dbi;
64 dbiInit(&dbi);
65
66 sprintf(query,"SELECT COUNT(Album.AlbumID), Album.AlbumID FROM Album,AlbumArtist WHERE Album.Title=\'%s\' AND Album.AlbumID = AlbumArtist.AlbumID AND AlbumArtist.ArtistID=%d",arg,id);
67 debug(3,query);
68 doQuery(query,&dbi);
69 fetch_row(&dbi);
70 if(strtol(dbi.row[0],NULL,10)==0){//create album
71 dbiClean(&dbi);
72 sprintf(query,"INSERT INTO Album (Title) VALUES (\'%s\')",arg);
73 debug(3,query);
74 if(harp_sqlite3_exec(conn,query,NULL,NULL,NULL)!=SQLITE_OK)
75 return -1;
76 sprintf(query,"INSERT INTO AlbumArtist (ArtistID,AlbumID) VALUES (%d,%d)",id,(int)sqlite3_last_insert_rowid(conn));
77 debug(3,query);
78 if(harp_sqlite3_exec(conn,query,NULL,NULL,NULL)!=SQLITE_OK)
79 return -1;
80 return sqlite3_last_insert_rowid(conn);
81 }
82 int newid=(int)strtol(dbi.row[1],NULL,10);
83 dbiClean(&dbi);
84 return newid;
85 }
86
getSong(const char * arg,const char * loc,const int id)87 int getSong(const char *arg, const char *loc, const int id){
88 char query[401];
89 struct dbitem dbi;
90 dbiInit(&dbi);
91
92 sprintf(query,"SELECT COUNT(Song.SongID), Song.SongID FROM Song, Album WHERE Song.Location=\'%s\' AND Song.AlbumID = Album.AlbumID AND Album.AlbumID=%d",loc,id);
93 debug(3,query);
94 doQuery(query,&dbi);
95 fetch_row(&dbi);
96 if(strtol(dbi.row[0],NULL,10)==0){//create song
97 dbiClean(&dbi);
98 sprintf(query,"INSERT INTO Song (Title,Location,AlbumID,TypeID) VALUES (\'%s\',\'%s\',%d,%d)",arg,loc,id,-1);
99 debug(3,query);
100 if(harp_sqlite3_exec(conn,query,NULL,NULL,NULL)!=SQLITE_OK)
101 return -1;
102 return sqlite3_last_insert_rowid(conn);
103 }
104 int newid=(int)strtol(dbi.row[1],NULL,10);
105 dbiClean(&dbi);
106 return newid;
107 }
108
getPlaylist(const char * arg)109 int getPlaylist(const char *arg){
110 char query[401];
111 struct dbitem dbi;
112 dbiInit(&dbi);
113
114 sprintf(query,"SELECT COUNT(Playlist.PlaylistID), Playlist.PlaylistID FROM Playlist WHERE Playlist.Title=\'%s\'",arg);
115 debug(3,query);
116 doQuery(query,&dbi);
117 fetch_row(&dbi);
118 if(strtol(dbi.row[0],NULL,10)==0){//create playlist
119 dbiClean(&dbi);
120 sprintf(query,"INSERT INTO Playlist (Title) VALUES ('%s')",arg);
121 debug(3,query);
122 if(harp_sqlite3_exec(conn,query,NULL,NULL,NULL)!=SQLITE_OK)
123 return -1;
124 return sqlite3_last_insert_rowid(conn);
125 }
126 int newid=(int)strtol(dbi.row[1],NULL,10);
127 dbiClean(&dbi);
128 return newid;
129 }
130
getPlaylistSong(const int sid,const int pid)131 int getPlaylistSong(const int sid, const int pid){
132 char query[201];
133 struct dbitem dbi;
134 dbiInit(&dbi);
135
136 sprintf(query,"SELECT COUNT(PlaylistSong.PlaylistSongID), PlaylistSong.PlaylistSongID FROM PlaylistSong WHERE PlaylistSong.PlaylistID=%d AND PlaylistSong.SongID=%d",pid,sid);
137 debug(3,query);
138 doQuery(query,&dbi);
139 fetch_row(&dbi);
140 if(strtol(dbi.row[0],NULL,10)==0){//create playlistsong
141 sprintf(query,"SELECT \"Order\" FROM PlaylistSong WHERE PlaylistID=%d ORDER BY \"Order\" DESC LIMIT 1",pid);
142 debug(3,query);
143 doQuery(query,&dbi);
144 int order;
145 if(fetch_row(&dbi))
146 order=(int)strtol(dbi.row[0],NULL,10)+1;
147 else
148 order=1;
149
150 dbiClean(&dbi);
151 sprintf(query,"INSERT INTO PlaylistSong(SongID,PlaylistID,\"Order\") VALUES(%d,%d,%d)",sid,pid,order);
152 debug(3,query);
153 if(harp_sqlite3_exec(conn,query,NULL,NULL,NULL)!=SQLITE_OK)
154 return -1;
155 return sqlite3_last_insert_rowid(conn);
156 }
157 int newid=(int)strtol(dbi.row[1],NULL,10);
158 dbiClean(&dbi);
159 return newid;
160 }
161
getCategory(const char * arg)162 int getCategory(const char *arg){
163 char query[401];
164 struct dbitem dbi;
165 dbiInit(&dbi);
166
167 sprintf(query,"SELECT COUNT(CategoryID), CategoryID FROM Category WHERE Name=\'%s\'",arg);
168 debug(3,query);
169 doQuery(query,&dbi);
170 fetch_row(&dbi);
171 if(strtol(dbi.row[0],NULL,10)==0){//create playlist
172 dbiClean(&dbi);
173 sprintf(query,"INSERT INTO Category (Name) VALUES ('%s')",arg);
174 debug(3,query);
175 if(harp_sqlite3_exec(conn,query,NULL,NULL,NULL)!=SQLITE_OK)
176 return -1;
177 return sqlite3_last_insert_rowid(conn);
178 }
179 int newid=(int)strtol(dbi.row[1],NULL,10);
180 dbiClean(&dbi);
181 return newid;
182 }
183
getSongCategory(const int sid,const int cid)184 int getSongCategory(const int sid, const int cid){
185 char query[201];
186 struct dbitem dbi;
187 dbiInit(&dbi);
188
189 sprintf(query,"SELECT COUNT(SongCatID), SongCatID FROM SongCategory WHERE CategoryID=%d AND SongID=%d",cid,sid);
190 debug(3,query);
191 doQuery(query,&dbi);
192 fetch_row(&dbi);
193 if(strtol(dbi.row[0],NULL,10)==0){//create songcategory
194 dbiClean(&dbi);
195 sprintf(query,"INSERT INTO SongCategory(SongID,CategoryID) VALUES(%d,%d)",sid,cid);
196 debug(3,query);
197 if(harp_sqlite3_exec(conn,query,NULL,NULL,NULL)!=SQLITE_OK)
198 return -1;
199 return sqlite3_last_insert_rowid(conn);
200 }
201 int newid=(int)strtol(dbi.row[1],NULL,10);
202 dbiClean(&dbi);
203 return newid;
204 }
205
206 /*
207 static int verifySong(const int sid){
208 char query[201];
209 char ans[4];
210 struct dbitem dbi;
211 dbiInit(&dbi);
212
213 sprintf(query,"SELECT Song.Title,Song.Location FROM Song WHERE Song.SongID=%d",sid);
214 printf("%s\n",query);
215 doQuery(query,&dbi);
216 if(fetch_row(&dbi)){
217 printf("%s located at: %s.\nIs this correct?[y] ",dbi.row[0],dbi.row[1]);
218 dbiClean(&dbi);
219 if(!fgets(ans,sizeof(ans),stdin))return -1;
220 if(*ans=='y' || *ans=='\n')
221 return sid;
222 else
223 return -1;
224 }
225 else
226 fprintf(stderr,"That song doesn't exist\n");
227 dbiClean(&dbi);
228 return -1;
229 }
230 */
231
getMusicInfo(struct musicInfo * mi)232 static struct musicInfo *getMusicInfo(struct musicInfo *mi){
233 static struct musicInfo *hold;
234 if(mi)
235 hold=mi;
236 return hold;
237 }
238
239 #ifdef HAVE_FTW_H
240 #include <ftw.h>
useFile(const char * fpath,const struct stat * sb,int typeflag)241 int useFile(const char *fpath, const struct stat *sb, int typeflag) {
242 if(typeflag==FTW_F)
243 if(insertSong(fpath,NULL)<0)
244 return -1; /* error */
245 return 0; /* continue */
246 }
247
directoryInsert(const char * arg)248 static int directoryInsert(const char *arg){
249 if(ftw(arg,&useFile,1)){
250 fprintf(stderr,"FTW Err\n");
251 return 0;
252 }
253 return 1;
254 }
255 #else
directoryInsert(const char * arg)256 static int directoryInsert(const char *arg){
257 return insertSong(arg,NULL);
258 }
259 #endif
260
batchInsert(char * arg)261 int batchInsert(char *arg){
262 struct musicInfo mi;
263
264 if(!(mi.title=malloc((MI_TITLE_SIZE*2+1)*sizeof(char))) ||
265 !(mi.track=malloc(((MI_TRACK_SIZE*2)+1)*sizeof(char))) ||
266 !(mi.artist=malloc(((MI_ARTIST_SIZE*2)+1)*sizeof(char))) ||
267 !(mi.album=malloc(((MI_ALBUM_SIZE*2)+1)*sizeof(char))) ||
268 !(mi.year=malloc(((MI_YEAR_SIZE*2)+1)*sizeof(char))))
269 return 0;
270 getMusicInfo(&mi);
271
272 if(arg){//single argv insert
273 if(isURL(arg))
274 (void)insertSong(arg,&mi);
275 else
276 directoryInsert(expand(arg));
277 }
278 else{//batch insert
279 char temp[250];
280 while(printf("File Location: ") && fgets(temp,sizeof(temp),stdin) && *temp!='\n'){
281 expand(temp);
282 (void)insertSong(temp,&mi);
283 }
284 }
285 miFree(&mi);
286 return 1;
287 }
288
metadataInsert(struct insert_data * data)289 int metadataInsert(struct insert_data *data){
290 FILE *ffd=NULL;
291 struct pluginitem *pi_ptr=NULL;
292
293 //while((pi_ptr=findPluginByID(plugin_head,findPluginIDByType(data->fmt)))){
294 if(data->fmt<PLUGIN_NULL && (pi_ptr=plugin_head[data->fmt])){
295 if((ffd=pi_ptr->modopen(data->path,"rb"))!=NULL){
296 debug(1,data->path);
297 pi_ptr->modmeta(ffd,data->mi);
298 pi_ptr->modclose(ffd);
299 }
300 }
301 if(ffd==NULL)
302 fprintf(stderr,"Can't open file\n");
303 if(!pi_ptr){
304 return -1; // Fatal error
305 }
306 return 1;
307 }
308
setInsertData(struct musicInfo * mi,char * str,int start,int end,int id)309 void setInsertData(struct musicInfo *mi, char *str, int start, int end, int id){
310 int len=end-start;
311 char *ptr;
312
313 switch(id){
314 case MI_ARTIST:
315 ptr=mi->artist;
316 break;
317 case MI_ALBUM:
318 ptr=mi->album;
319 break;
320 case MI_TITLE:
321 ptr=mi->title;
322 break;
323 case MI_TRACK:
324 ptr=mi->track;
325 break;
326 case MI_YEAR:
327 ptr=mi->year;
328 break;
329 default:
330 ptr=NULL;
331 }
332 if(ptr)
333 memcpy(ptr,str+start,len);
334 }
335
filepathInsert(struct insert_data * data)336 int filepathInsert(struct insert_data *data){
337 char *ptr=(char*)data->path;
338 const size_t nrm=9;
339 int **ko=insertconf.keyorder;
340 regex_t *preg=insertconf.pattern;
341 regmatch_t rmatch[nrm];
342 int i,j;
343 int rret;
344
345 for(i=0;ko[i];i++){
346 rret=regexec(preg+i,ptr,nrm,rmatch,0);
347 if(rret==0){
348 for(j=0;ko[i][j]<MI_NULL && j<nrm-1;j++){
349 setInsertData(data->mi,ptr,rmatch[j+1].rm_so,rmatch[j+1].rm_eo,ko[i][j]);
350 }
351 return 1;
352 }
353 else if(rret==REG_NOMATCH){
354 }
355 else{
356 debug(1,"Regex match error!");
357 }
358 }
359
360 debug(1,"No regex matches.");
361 return 1;
362 }
363
insertSong(const char * arg,struct musicInfo * mi)364 static int insertSong(const char *arg, struct musicInfo *mi){
365 struct dbitem dbi;
366 char query[350];
367 char dbfilename[250];
368 char tempname[401];
369 unsigned int songid=0,artistid,albumid;
370 int fmt;
371 int x;
372 struct insert_data data;
373
374 //data.plugin_head=getPluginList(NULL);
375
376 if(!mi)mi=getMusicInfo(NULL);
377 miClean(mi);
378
379 db_safe(dbfilename,arg,250);
380 debug(1,arg);
381
382 dbiInit(&dbi);
383 //chack for dupicate
384 sprintf(query,"SELECT SongID FROM Song WHERE Location='%s' LIMIT 1",dbfilename);
385 harp_sqlite3_exec(conn,query,uint_return_cb,&songid,NULL);
386 if(songid){
387 debug(1,"Duplicate entry -- skipping");
388 return 0;
389 }
390
391 debug(1,"Finding file type");
392 if((fmt=fileFormat(plugin_head,arg))>=PLUGIN_NULL){
393 if(fmt==PLUGIN_NULL)
394 fprintf(stderr,"Unknown file type\n");
395 return 0;
396 }
397
398 data.fmt=fmt;
399 data.query=query;
400 data.mi=mi;
401 data.dbi=&dbi;
402 data.path=arg;
403
404 if(insertconf.first_cb){
405 x=insertconf.first_cb(&data);
406 if(x<0)
407 return -1;
408 if(!x && insertconf.second_cb)
409 insertconf.second_cb(&data);
410 }
411 dbiClean(&dbi);
412
413 db_insert_safe(tempname,mi->artist,MI_ARTIST_SIZE);
414 strcpy(mi->artist,tempname);
415 if((artistid=getArtist(mi->artist))==-1){
416 fprintf(stderr,"Error inserting artist: %s\n",mi->artist);
417 return 0;
418 }
419
420 db_insert_safe(tempname,mi->album,MI_ALBUM_SIZE);
421 strcpy(mi->album,tempname);
422 if((albumid=getAlbum(mi->album,artistid))==-1){
423 fprintf(stderr,"Error inserting album: %s\n",mi->album);
424 return 0;
425 }
426 if(strcmp(mi->album,"Unknown") && *mi->year){
427 sprintf(query,"UPDATE Album SET \"Date\"=%s WHERE AlbumID=%d",mi->year,albumid);
428 debug(3,query);
429 harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
430 }
431
432 if(!*mi->title){
433 strcpy(tempname,getFilename((char *)arg));
434 db_insert_safe(mi->title,tempname,MI_TITLE_SIZE);
435 }
436 else{
437 db_insert_safe(tempname,mi->title,MI_TITLE_SIZE);
438 strcpy(mi->title,tempname);
439 }
440 if((songid=getSong(mi->title,dbfilename,albumid))==-1){
441 fprintf(stderr,"Error inserting song: %s\n",mi->title);
442 return 0;
443 }
444
445 // This prints escaped strings. Is it worth fixing?
446 printf("%s | %s | %s \n",mi->title,mi->album,mi->artist);
447
448 sprintf(query,"UPDATE Song SET Track=%d, Length=%d, Rating=3, TypeID=%d WHERE SongID=%d",(int)strtol(mi->track,NULL,10),mi->length,fmt,songid);
449 debug(3,query);
450 harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
451
452 getPlaylistSong(songid,getPlaylist("Library"));
453 getSongCategory(songid,1); // Unknown
454 debug(1,"Song inserted into Library");
455 printf("\n");
456 return 1;
457 }
458