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 "argparse.h"
19 #include "defs.h"
20 #include "dbact.h"
21 #include "harpconfig.h"
22 #include "list.h"
23 #include "shuffle.h"
24 #include "player.h"
25 #include "insert.h"
26 #include "admin.h"
27 #include "util.h"
28 #include "harp.h"
29 #include "tree.h"
30 #include "edit_shell.h"
31 #include "edit.h"
32 
33 #if 0
34 static char subarglist[]={
35 	'p',	/*Playlist*/
36 	's',	/*Song*/
37 	'a',	/*Album*/
38 	'r',	/*Artist*/
39 	'g',	/*Genre*/
40 	0		/*Placeholder*/
41 };
42 #endif
43 
44 struct argument arglist[]={
45 	{'l',NULL,0},	/*List*/
46 	{'p',NULL,0},	/*Play*/
47 	{'s',NULL,0},	/*Shuffle*/
48 	{'i',NULL,0},	/*Insert*/
49 	{'e',NULL,0},	/*Merge*/
50 	{'E',NULL,0},	/*Merge*/
51 	{123,NULL,0},	/*Merge*/
52 	{'v',NULL,0},	/*Debug (verbose)*/
53 	{'t',NULL,0},	/*Type*/
54 	{'z',NULL,0},	/*Shuffle*/
55 	{'a',NULL,0},	/*Admin*/
56 	{'D',NULL,0},	/*Device*/
57 	{'r',NULL,0},	/*Repeat*/
58 	{0,  NULL,0}	/*Placeholder*/
59 };
60 
61 struct option longopts[]={
62 	{"list",2,NULL,'l'},
63 	{"play",1,NULL,'p'},
64 	{"shuffle",2,NULL,'s'},
65 	{"insert",2,NULL,'i'},
66 	{"edit-stdin",0,NULL,'e'},
67 	{"edit",1,NULL,'E'},
68 	{"old-edit",0,NULL,123},
69 	{"verbose",0,NULL,'v'},
70 	{"type",1,NULL,'t'},
71 	{"zshuffle",0,NULL,'z'},
72 	{"admin",0,NULL,'a'},
73 	{"device",2,NULL,'D'},
74 	{"repeat",0,NULL,'r'},
75 	{"version",0,NULL,200},
76 	{0,0,0,0}
77 };
78 
79 static unsigned int argSearch(int argc, char *argv[]);
80 
printVersion()81 static void printVersion(){
82 	printf("HARP %s  Copyright (C) 2009-2015 Christian Heckendorf\n",PACKAGE_VERSION);
83 	cleanExit();
84 	exit(1);
85 }
86 
printHelp()87 static void printHelp(){
88 	printf("Valid options are:\n\
89 	-t [s,p,r,a,g,t]\tType (song, playlist, artist, album, genre, tag)\n\
90 	-l [name, ID]\tList (requires -t)\n\
91 	-p [name, ID]\tPlay (requires -t)\n\
92 		-s [s,a,r]\tShuffle (requires -p)\n\
93 		-z\tSmart shuffle (requires -p)\n\
94 		-r [number of repeats]\tRepeat playlist (requires -p)\n\
95 		-D {device name}\tOutput to specified device (requires -p)\n\
96 	-i [file path, directory]\tInsert songs\n\
97 	-e\tEdit via script using stdin\n\
98 	-E {script}\tEdit via script using command line\n\
99 	--old-edit\tEdit via deprecated portal interface\n\
100 	-a\tAdmin\n\
101 	-v\tVerbose\n\
102 	--version\t Print version information\n");
103 	cleanExit();
104 	exit(1);
105 }
106 
genreToPlaylistSong(struct dbnode * cur)107 static void genreToPlaylistSong(struct dbnode *cur){
108 	if(!cur->dbi.row_count)return;
109 	char query[150],cb_query[150];
110 	static struct insert_tps_arg data={1,0,NULL};
111 	data.query=cb_query;
112 	sprintf(query,"SELECT Song.SongID FROM SongCategory NATURAL JOIN Song WHERE Active=1 AND CategoryID=%s",cur->dbi.row[0]);
113 	harp_sqlite3_exec(conn,query,batch_tempplaylistsong_insert_cb,&data,NULL);
114 }
115 
makeTempPlaylist(int * multilist,int multi)116 static void makeTempPlaylist(int *multilist, int multi){
117 	int mx;
118 	char query[250],cb_query[150];
119 	struct insert_tps_arg data={1,0,cb_query};
120 
121 	createTempPlaylistSong();
122 
123 	switch(*arglist[ATYPE].subarg){
124 		case 'p':
125 			for(mx=0;mx<multi;mx++){
126 				sprintf(query,"SELECT Song.SongID FROM PlaylistSong NATURAL JOIN Song WHERE Active=1 AND PlaylistID=%d ORDER BY \"Order\"",multilist[mx]);
127 				harp_sqlite3_exec(conn,query,batch_tempplaylistsong_insert_cb,&data,NULL);
128 			}
129 			break;
130 		case 's':
131 			for(mx=0;mx<multi;mx++){
132 				sprintf(query,"SELECT SongID FROM Song WHERE SongID=%d",multilist[mx]);
133 				harp_sqlite3_exec(conn,query,batch_tempplaylistsong_insert_cb,&data,NULL);
134 			}
135 			break;
136 		case 'a':
137 			for(mx=0;mx<multi;mx++){
138 				//sprintf(query,"SELECT Song.SongID FROM Album INNER JOIN Song USING(AlbumID) WHERE Active=1 AND Album.AlbumID=%d ORDER BY Track",multilist[mx]);
139 				sprintf(query,"SELECT SongID FROM Song WHERE Active=1 AND AlbumID=%d ORDER BY Track",multilist[mx]);
140 				harp_sqlite3_exec(conn,query,batch_tempplaylistsong_insert_cb,&data,NULL);
141 			}
142 			break;
143 		case 'r':
144 			for(mx=0;mx<multi;mx++){
145 				sprintf(query,"SELECT Song.SongID FROM AlbumArtist NATURAL JOIN Song WHERE Active=1 AND AlbumArtist.ArtistID=%d ORDER BY AlbumArtist.AlbumID,Track",multilist[mx]);
146 				harp_sqlite3_exec(conn,query,batch_tempplaylistsong_insert_cb,&data,NULL);
147 			}
148 			break;
149 		case 't':
150 			for(mx=0;mx<multi;mx++){
151 				sprintf(query,"SELECT Song.SongID FROM SongTag NATURAL JOIN Song WHERE Active=1 AND TagID=%d ORDER BY TagID,Track",multilist[mx]);
152 				harp_sqlite3_exec(conn,query,batch_tempplaylistsong_insert_cb,&data,NULL);
153 			}
154 			break;
155 		case 'g':
156 			for(mx=0;mx<multi;mx++){
157 				printGenreTree(multilist[mx],(void *)genreToPlaylistSong);
158 			}
159 			break;
160 	}
161 }
162 
doArgs(int argc,char * argv[])163 unsigned int doArgs(int argc,char *argv[]){
164 	int *multilist,id=0,multi=0;
165 	setDefaultConfig();
166 
167 	if(argSearch(argc,argv)==0){
168 		return 0;
169 	}
170 
171 	//list
172 	if(arglist[ALIST].active){
173 		if(!arglist[ALIST].subarg){
174 			listall();
175 			return 0;
176 		}
177 
178 		if(!(multilist=getMulti(arglist[ALIST].subarg,&multi)))return 1;
179 		if(multi<1 || *multilist<1)return 1;
180 		list(multilist,multi);
181 		free(multilist);
182 		return 0;
183 	}
184 	//play
185 	if(arglist[APLAY].active){
186 		if(!(multilist=getMulti(arglist[APLAY].subarg,&multi)))return 1;
187 		if(multi<1 || *multilist<1)return 1;
188 
189 		makeTempPlaylist(multilist,multi);
190 		id=0;
191 
192 		free(multilist);
193 
194 		if(arglist[AREPEAT].active && arglist[AREPEAT].subarg!=NULL)
195 			arglist[AREPEAT].active=strtol(arglist[AREPEAT].subarg,NULL,10);
196 
197 		if(arglist[ASHUFFLE].active || arglist[AZSHUFFLE].active){
198 			shuffle(id);
199 			id=0;
200 		}
201 		player(id);
202 		return 0;
203 	}
204 	//insert
205 	if(arglist[AINSERT].active){
206 		batchInsert(arglist[AINSERT].subarg);
207 		return 0;
208 	}
209 	//edit
210 	if(arglist[AEDIT].active){
211 		switch(arglist[AEDIT].active){
212 			case 1:
213 				editShell();
214 				break;
215 			case 2:
216 				editPortal();
217 				break;
218 		}
219 		return 0;
220 	}
221 	//admin
222 	if(arglist[AADMIN].active){
223 		adminPortal();
224 		return 0;
225 	}
226 	printHelp();
227 	return 0;
228 }
229 
argSearch(int argc,char * argv[])230 static unsigned int argSearch(int argc,char *argv[]){
231 	int opt,optindex;
232 	while((opt=getopt_long(argc,argv,"i::l::E:D::p:s::t:evzar::",longopts,&optindex))!=-1){
233 		switch(opt){
234 			//case 'e':arglist[AEDIT].active=1;arglist[AEDIT].subarg=optarg;break;
235 			case 123:arglist[AEDIT].active=2;break;
236 			case 'e':arglist[AEDIT].active=1;arglist[AEDIT].subarg=NULL;break;
237 			case 'E':arglist[AEDIT].active=1;arglist[AEDIT].subarg=optarg;break;
238 			case 'i':arglist[AINSERT].active=1;arglist[AINSERT].subarg=(argv[optind]&&argv[optind][0]!='-')?argv[optind]:optarg;break;
239 			case 'l':arglist[ALIST].active=1;arglist[ALIST].subarg=(argv[optind]&&argv[optind][0]!='-')?argv[optind]:optarg;break;
240 			case 'D':arglist[ADEVICE].active=1;arglist[ADEVICE].subarg=(argv[optind]&&argv[optind][0]!='-')?argv[optind]:optarg;break;
241 			case 'p':arglist[APLAY].active=1;arglist[APLAY].subarg=optarg;break;
242 			case 's':arglist[ASHUFFLE].active=1;arglist[AZSHUFFLE].active=0;arglist[ASHUFFLE].subarg=(argv[optind]&&argv[optind][0]!='-')?argv[optind]:optarg;break;
243 			case 't':arglist[ATYPE].active=1;arglist[ATYPE].subarg=optarg;break;
244 			case 'v':arglist[AVERBOSE].active++;break;
245 			case 'z':arglist[AZSHUFFLE].active=1;arglist[ASHUFFLE].active=0;break;
246 			case 'a':arglist[AADMIN].active=1;break;
247 			case 'r':arglist[AREPEAT].active=1;arglist[AREPEAT].subarg=(argv[optind]&&argv[optind][0]!='-')?argv[optind]:optarg;break;
248 			case 200:printVersion();break;
249 			case '?':
250 			default: printHelp();break;
251 		}
252 	}
253 	return 1;
254 }
255