2 Copyright (C) 2006 by Jonas Kramer
3 Published under the terms of the GNU General Public License (GPL).
12 #include <sys/types.h>
24 #include "interface.h"
35 #include "recommend.h"
40 extern time_t pausetime
;
44 char * shellescape(const char *);
46 void interface(int interactive
) {
49 char customkey
[8] = { 0 }, * marked
= NULL
;
53 if((key
= fetchkey(1000000)) == -1)
58 while((ch
= fetchkey(100000)) != -1 && !strchr("ABCDEFGHMPQRSZojmk~", ch
));
64 puts(rate("L") ? "Loved." : "Sorry, failed.");
68 puts(rate("U") ? "Unloved." : "Sorry, failed.");
72 puts(rate("B") ? "Banned." : "Sorry, failed.");
75 kill(playfork
, SIGUSR1
);
83 if(haskey(& rc
, "delay-change")) {
84 delayquit
= !delayquit
;
86 fputs("Going to quit soon.\n", stderr
);
88 fputs("Delayed quit cancelled.\n", stderr
);
93 unlink(rcpath("session"));
98 const char * path
= rcpath("i-template");
99 if(path
&& !access(path
, R_OK
)) {
100 char ** template = slurp(path
);
101 if(template != NULL
) {
104 puts(meta(template[n
], M_COLORED
, & track
));
111 puts(meta("Track: \"%t\" (%T)", M_COLORED
, & track
));
112 puts(meta("Artist: \"%a\" (%A)", M_COLORED
, & track
));
113 puts(meta("Album: \"%l\" (%L)", M_COLORED
, & track
));
114 puts(meta("Station: %s", M_COLORED
, & track
));
120 radioprompt("radio url> ");
125 printf("Discovery mode %s.\n", enabled(DISCOVERY
) ? "enabled" : "disabled");
128 "%u track(s) left to play/skip until change comes into affect.\n",
135 printf(meta("Really ban all tracks by artist %a? [yN]", M_COLORED
, & track
));
137 if(fetchkey(5000000) != 'y')
139 else if(autoban(value(& track
, "creator"))) {
140 printf("\n%s banned.\n", meta("%a", M_COLORED
, & track
));
148 "addTrackToUserPlaylist", "ss",
149 value(& track
, "creator"),
150 value(& track
, "title")
153 puts(result
? "Added to playlist." : "Sorry, failed.");
158 printf("%s RTP.\n", enabled(RTP
) ? "Enabled" : "Disabled");
163 station(meta("lastfm://artist/%a/fans", 0, & track
));
169 station(meta("lastfm://artist/%a/similarartists", 0, & track
));
178 if(playfork
&& currentStation
) {
179 puts("What number do you want to bookmark this stream as? [0-9]");
181 key
= fetchkey(5000000);
182 setmark(currentStation
, key
- 0x30);
189 kill(playfork
, SIGUSR1
);
201 kill(playfork
, SIGCONT
);
205 kill(playfork
, SIGSTOP
);
217 if(volume
< MAX_VOLUME
)
220 write(playpipe
, &key
, 1);
227 write(playpipe
, &key
, 1);
240 "a = add the track to the playlist | A = autoban artist\n"
241 "B = ban Track | d = discovery mode\n"
242 "E = manually expand playlist | f = fan Station\n"
243 "h = list bookmarks | H = bookmark current radio\n"
244 "i = current track information | l = love track\n"
245 "n = skip track | p = pause\n"
246 "P = enable/disable RTP | Q = quit\n"
247 "r = change radio station | R = recommend track/artist/album\n"
248 "S = stop | s = similiar artist\n"
249 "T = tag track/artist/album | u = show upcoming tracks in playlist\n"
250 "U = unlove track | + = increase volume\n"
251 "- = decrease volume\n",
266 if((marked
= getmark(key
- 0x30))) {
270 puts("Bookmark not defined.");
275 snprintf(customkey
, sizeof(customkey
), "key0x%02X", key
& 0xFF);
276 if(haskey(& rc
, customkey
))
277 run(meta(value(& rc
, customkey
), M_SHELLESC
, & track
));
282 int fetchkey(unsigned nsec
) {
287 FD_SET(fileno(stdin
), & fdset
);
289 tv
.tv_usec
= nsec
% 1000000;
290 tv
.tv_sec
= nsec
/ 1000000;
292 if(select(fileno(stdin
) + 1, & fdset
, NULL
, NULL
, & tv
) > 0) {
294 if(read(fileno(stdin
), & ch
, sizeof(char)) == sizeof(char))
302 #define remn (sizeof(string) - length - 1)
303 const char * meta(const char * fmt
, int flags
, struct hash
* track
) {
304 static char string
[4096];
305 unsigned length
= 0, x
= 0;
307 /* Switch off coloring when in batch mode */
314 memset(string
, 0, sizeof(string
));
316 while(fmt
[x
] && remn
> 0) {
318 string
[length
++] = fmt
[x
++];
321 string
[length
++] = fmt
[x
++];
324 const char * keys
[] = {
338 register unsigned i
= sizeof(keys
) / sizeof(char *);
340 /* Look for a track value with that format flag. */
342 if(fmt
[x
] == keys
[i
][0]) {
343 char * val
= strdup(value(track
, keys
[i
] + 1));
344 const char * color
= NULL
;
346 if(flags
& M_COLORED
) {
347 char colorkey
[64] = { 0 };
348 snprintf(colorkey
, sizeof(colorkey
), "%c-color", keys
[i
][0]);
349 color
= value(& rc
, colorkey
);
352 /* Strip leading spaces from end of color (Author: Ondrej Novy) */
353 char * color_st
= strdup(color
);
354 size_t len
= strlen(color_st
) - 1;
356 assert(color_st
!= NULL
);
358 while(isspace(color_st
[len
]) && len
> 0) {
362 length
+= snprintf(string
+ length
, remn
, "\x1B[%sm", color_st
);
367 if((flags
& M_RELAXPATH
) && val
) {
369 size_t l
= strlen(val
);
371 for(n
= 0; n
< l
; ++n
) {
377 if(flags
& M_SHELLESC
) {
378 char * escaped
= shellescape(val
);
383 length
= strlen(strncat(string
, val
? val
: "(unknown)", remn
));
388 length
= strlen(strncat(string
, "\x1B[0m", remn
));
404 void run(const char * cmd
) {
411 int rate(const char * rating
) {
412 if(playfork
&& rating
!= NULL
) {
415 set(& track
, "rating", rating
);
419 kill(playfork
, SIGUSR1
);
424 value(& track
, "creator"),
425 value(& track
, "title")
432 value(& track
, "creator"),
433 value(& track
, "title")
440 value(& track
, "creator"),
441 value(& track
, "title")
446 kill(playfork
, SIGUSR1
);
455 char * shellescape(const char * string
) {
457 unsigned length
= 0, n
, size
;
459 assert(string
!= NULL
);
461 size
= strlen(string
) * 2 + 1;
462 escaped
= malloc(size
);
463 memset(escaped
, 0, size
);
465 assert(string
!= NULL
);
467 for(n
= 0; n
< strlen(string
); ++n
) {
468 if(!isalnum(string
[n
]))
469 escaped
[length
++] = '\\';
471 escaped
[length
++] = string
[n
];