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