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