|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
1 |
/* |
|
c3e3fb0a
»
|
jkramer |
2009-01-28 |
Updated copyright notes for... |
2 |
Copyright (C) 2006-2009 by Jonas Kramer |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
3 |
Published under the terms of the GNU General Public License (GPL). |
| |
4 |
*/ |
| |
5 |
|
| |
6 |
#define _GNU_SOURCE |
| |
7 |
|
| |
8 |
|
| |
9 |
#include <stdio.h> |
| |
10 |
#include <stdlib.h> |
| |
11 |
#include <string.h> |
| |
12 |
#include <unistd.h> |
| |
13 |
#include <fcntl.h> |
| |
14 |
#include <signal.h> |
| |
15 |
#include <sys/wait.h> |
| |
16 |
#include <time.h> |
|
50aa9f76
»
|
jkr |
2008-04-14 |
* 2008-04-14, jkramer |
17 |
#include <sys/types.h> |
| |
18 |
#include <sys/stat.h> |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
19 |
|
|
3272c802
»
|
jkr |
2008-04-06 |
* " is now converted t... |
20 |
#include <dirent.h> |
| |
21 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
22 |
#include "hash.h" |
| |
23 |
#include "service.h" |
| |
24 |
#include "interface.h" |
| |
25 |
#include "settings.h" |
| |
26 |
#include "autoban.h" |
| |
27 |
#include "sckif.h" |
| |
28 |
#include "playlist.h" |
| |
29 |
#include "submit.h" |
|
4277526e
»
|
jkr |
2008-04-05 |
Now using readline instead ... |
30 |
#include "readline.h" |
|
e79f83e1
»
|
jkramer |
2008-10-07 |
Prompt for radio URI on sta... |
31 |
#include "radio.h" |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
32 |
|
| |
33 |
#include "globals.h" |
| |
34 |
|
| |
35 |
#ifndef PATH_MAX |
| |
36 |
#define PATH_MAX 4096 |
| |
37 |
#endif |
| |
38 |
|
|
6b4a0ec0
»
|
chneukirchen |
2008-08-01 |
Patches for NetBSD |
39 |
#ifdef __NetBSD__ |
| |
40 |
# ifndef WCONTINUED |
| |
41 |
# define WCONTINUED 0 /* not available on NetBSD */ |
| |
42 |
# endif |
| |
43 |
# ifndef WIFCONTINUED |
| |
44 |
# define WIFCONTINUED(x) ((x) == 0x13) /* SIGCONT */ |
| |
45 |
# endif |
| |
46 |
#endif |
| |
47 |
|
|
1b427c1b
»
|
jkramer |
2009-02-28 |
Redefine some constants if ... |
48 |
#if !defined(WCONTINUED) || !defined(WIFCONTINUED) |
| |
49 |
# undef WCONTINUED |
| |
50 |
# define WCONTINUED 0 |
| |
51 |
# undef WIFCONTINUED |
| |
52 |
# define WIFCONTINUED(wstat) (0) |
| |
53 |
#endif |
| |
54 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
55 |
unsigned flags = RTP; |
| |
56 |
time_t changeTime = 0, pausetime = 0; |
|
0c9f393d
»
|
jkr |
2008-04-06 |
Added option "delay-change"... |
57 |
char * nextstation = NULL; |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
58 |
|
|
28290572
»
|
jkramer |
2009-01-13 |
Added delayed quit ('q', wo... |
59 |
int batch = 0, error = 0, delayquit = 0; |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
60 |
|
| |
61 |
static void cleanup(void); |
| |
62 |
static void forcequit(int); |
| |
63 |
static void help(const char *, int); |
|
5533132e
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
64 |
static void playsig(int); |
|
f151e238
»
|
jkramer |
2008-07-06 |
Fixed pause timer for "paus... |
65 |
static void stopsig(int); |
|
67dabd84
»
|
jkramer |
2008-09-25 |
Removing now-playing file a... |
66 |
static void unlinknp(void); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
67 |
|
|
7a1b18df
»
|
jkramer |
2008-05-20 |
Fixed cleanup of UNIX socket. |
68 |
pid_t ppid = 0; |
| |
69 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
70 |
int main(int argc, char ** argv) { |
| |
71 |
int option, nerror = 0, background = 0, haveSocket = 0; |
| |
72 |
time_t pauselength = 0; |
| |
73 |
char * proxy; |
| |
74 |
opterr = 0; |
|
33dfd4b8
»
|
jkramer |
2008-05-24 |
Automatically creating ~/.s... |
75 |
|
| |
76 |
/* Create directories. */ |
| |
77 |
makercd(); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
78 |
|
| |
79 |
/* Load settings from ~/.shell-fm/shell-fm.rc. */ |
| |
80 |
settings(rcpath("shell-fm.rc"), !0); |
| |
81 |
|
|
0d2777f7
»
|
jkr |
2008-04-12 |
* 2008-04-12, jkramer |
82 |
/* Enable discovery by default if it is set in configuration. */ |
| |
83 |
if(haskey(& rc, "discovery")) |
| |
84 |
enable(DISCOVERY); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
85 |
|
|
4dd0d1c5
»
|
jkramer |
2009-05-05 |
"daemon" in the configurati... |
86 |
/* If "daemon" is set in the configuration, enable daemon mode by default. */ |
| |
87 |
if(haskey(& rc, "daemon")) |
| |
88 |
background = !0; |
| |
89 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
90 |
/* Get proxy environment variable. */ |
| |
91 |
if((proxy = getenv("http_proxy")) != NULL) |
| |
92 |
set(& rc, "proxy", proxy); |
| |
93 |
|
| |
94 |
|
| |
95 |
/* Parse through command line options. */ |
| |
96 |
while(-1 != (option = getopt(argc, argv, ":dbhi:p:D:y:"))) |
| |
97 |
switch(option) { |
| |
98 |
case 'd': /* Daemonize. */ |
|
4dd0d1c5
»
|
jkramer |
2009-05-05 |
"daemon" in the configurati... |
99 |
background = !background; |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
100 |
break; |
| |
101 |
|
| |
102 |
case 'i': /* IP to bind network interface to. */ |
| |
103 |
set(& rc, "bind", optarg); |
| |
104 |
break; |
| |
105 |
|
| |
106 |
case 'p': /* Port to listen on. */ |
| |
107 |
if(atoi(optarg)) |
| |
108 |
set(& rc, "port", optarg); |
| |
109 |
else { |
| |
110 |
fputs("Invalid port.\n", stderr); |
| |
111 |
++nerror; |
| |
112 |
} |
| |
113 |
break; |
|
b8b5b890
»
|
jkr |
2008-02-02 |
- added two missing option... |
114 |
|
| |
115 |
case 'b': /* Batch mode */ |
| |
116 |
batch = !0; |
| |
117 |
break; |
| |
118 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
119 |
case 'D': /* Path to audio device file. */ |
| |
120 |
set(& rc, "device", optarg); |
| |
121 |
break; |
| |
122 |
|
| |
123 |
case 'y': /* Proxy address. */ |
| |
124 |
set(& rc, "proxy", optarg); |
| |
125 |
break; |
| |
126 |
|
| |
127 |
case 'h': /* Print help text and exit. */ |
| |
128 |
help(argv[0], 0); |
| |
129 |
break; |
| |
130 |
|
| |
131 |
case ':': |
| |
132 |
fprintf(stderr, "Missing argument for option -%c.\n\n", optopt); |
| |
133 |
++nerror; |
| |
134 |
break; |
| |
135 |
|
| |
136 |
case '?': |
| |
137 |
default: |
| |
138 |
fprintf(stderr, "Unknown option -%c.\n", optopt); |
| |
139 |
++nerror; |
| |
140 |
break; |
| |
141 |
} |
| |
142 |
|
| |
143 |
/* The next argument, if present, is the lastfm:// URL we want to play. */ |
| |
144 |
if(optind > 0 && optind < argc && argv[optind]) { |
| |
145 |
const char * station = argv[optind]; |
| |
146 |
|
|
3eca42a8
»
|
jkramer |
2009-05-05 |
Don't require lastfm:// sch... |
147 |
set(& rc, "default-radio", station); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
148 |
} |
| |
149 |
|
| |
150 |
|
| |
151 |
if(nerror) |
| |
152 |
help(argv[0], EXIT_FAILURE); |
| |
153 |
|
|
64a23344
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
154 |
#ifndef LIBAO |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
155 |
if(!haskey(& rc, "device")) |
| |
156 |
set(& rc, "device", "/dev/audio"); |
| |
157 |
#endif |
| |
158 |
|
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
159 |
if(!background) { |
|
b25261cc
»
|
jkramer |
2009-02-04 |
Updated year in copyright n... |
160 |
puts("Shell.FM v" PACKAGE_VERSION ", (C) 2006-2009 by Jonas Kramer"); |
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
161 |
puts("Published under the terms of the GNU General Public License (GPL)."); |
| |
162 |
|
|
1b427c1b
»
|
jkramer |
2009-02-28 |
Redefine some constants if ... |
163 |
#ifndef TUXBOX |
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
164 |
puts("\nPress ? for help.\n"); |
|
1b427c1b
»
|
jkramer |
2009-02-28 |
Redefine some constants if ... |
165 |
#else |
| |
166 |
puts("Compiled for the use with Shell.FM Wrapper.\n"); |
| |
167 |
#endif |
| |
168 |
fflush(stdout); |
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
169 |
} |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
170 |
|
| |
171 |
|
| |
172 |
/* Open a port so Shell.FM can be controlled over network. */ |
| |
173 |
if(haskey(& rc, "bind")) { |
| |
174 |
int port = 54311; |
| |
175 |
|
| |
176 |
if(haskey(& rc, "port")) |
| |
177 |
port = atoi(value(& rc, "port")); |
| |
178 |
|
|
19b3a40e
»
|
jkramer |
2008-05-20 |
Added support for UNIX sock... |
179 |
if(tcpsock(value(& rc, "bind"), (unsigned short) port)) |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
180 |
haveSocket = !0; |
| |
181 |
} |
| |
182 |
|
| |
183 |
|
|
19b3a40e
»
|
jkramer |
2008-05-20 |
Added support for UNIX sock... |
184 |
/* Open a UNIX socket for local "remote" control. */ |
| |
185 |
if(haskey(& rc, "unix") && unixsock(value(& rc, "unix"))) |
| |
186 |
haveSocket = !0; |
| |
187 |
|
| |
188 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
189 |
/* We can't daemonize if there's no possibility left to control Shell.FM. */ |
| |
190 |
if(background && !haveSocket) { |
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
191 |
fputs("Can't daemonize without control socket.\n", stderr); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
192 |
exit(EXIT_FAILURE); |
| |
193 |
} |
| |
194 |
|
| |
195 |
|
| |
196 |
/* Ask for username/password if they weren't specified in the .rc file. */ |
| |
197 |
if(!haskey(& rc, "password")) { |
| |
198 |
char * password; |
| |
199 |
|
| |
200 |
if(!haskey(& rc, "username")) { |
| |
201 |
char username[256] = { 0 }; |
|
4277526e
»
|
jkr |
2008-04-05 |
Now using readline instead ... |
202 |
|
| |
203 |
struct prompt prompt = { |
| |
204 |
.prompt = "Login: ", |
| |
205 |
.line = getenv("USER"), .history = NULL, .callback = NULL, |
| |
206 |
}; |
| |
207 |
|
| |
208 |
strncpy(username, readline(& prompt), 255); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
209 |
|
| |
210 |
set(& rc, "username", username); |
| |
211 |
} |
| |
212 |
|
| |
213 |
if(!(password = getpass("Password: "))) |
| |
214 |
exit(EXIT_FAILURE); |
| |
215 |
|
| |
216 |
set(& rc, "password", password); |
| |
217 |
} |
| |
218 |
|
| |
219 |
|
| |
220 |
memset(& data, 0, sizeof(struct hash)); |
| |
221 |
memset(& track, 0, sizeof(struct hash)); |
| |
222 |
memset(& playlist, 0, sizeof(struct playlist)); |
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
223 |
|
| |
224 |
/* Fork to background. */ |
| |
225 |
if(background) { |
|
f7a365e9
»
|
be1 |
2008-09-21 |
Fixed daemonizing issue: tr... |
226 |
int null; |
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
227 |
pid_t pid = fork(); |
|
f7a365e9
»
|
be1 |
2008-09-21 |
Fixed daemonizing issue: tr... |
228 |
|
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
229 |
if(pid == -1) { |
| |
230 |
fputs("Failed to daemonize.\n", stderr); |
| |
231 |
exit(EXIT_FAILURE); |
| |
232 |
} else if(pid) { |
| |
233 |
exit(EXIT_SUCCESS); |
| |
234 |
} |
|
f7a365e9
»
|
be1 |
2008-09-21 |
Fixed daemonizing issue: tr... |
235 |
|
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
236 |
enable(QUIET); |
|
f7a365e9
»
|
be1 |
2008-09-21 |
Fixed daemonizing issue: tr... |
237 |
|
| |
238 |
/* Detach from TTY */ |
| |
239 |
setsid(); |
| |
240 |
pid = fork(); |
| |
241 |
|
| |
242 |
if(pid > 0) |
| |
243 |
exit(EXIT_SUCCESS); |
| |
244 |
|
| |
245 |
/* Close stdin out and err */ |
| |
246 |
close(0); |
| |
247 |
close(1); |
| |
248 |
close(2); |
| |
249 |
|
| |
250 |
/* Redirect stdin and out to /dev/null */ |
| |
251 |
null = open("/dev/null", O_RDWR); |
| |
252 |
dup(null); |
| |
253 |
dup(null); |
|
0a0080cc
»
|
jkramer |
2008-05-20 |
Removed the HTTP indicator ... |
254 |
} |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
255 |
|
|
7a1b18df
»
|
jkramer |
2008-05-20 |
Fixed cleanup of UNIX socket. |
256 |
ppid = getpid(); |
| |
257 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
258 |
atexit(cleanup); |
| |
259 |
loadqueue(!0); |
| |
260 |
|
| |
261 |
/* Set up signal handlers for communication with the playback process. */ |
| |
262 |
signal(SIGINT, forcequit); |
| |
263 |
|
|
41a0adb8
»
|
jkramer |
2008-09-20 |
'stop' in daemon mode now s... |
264 |
/* SIGUSR2 from playfork means it detected an error. */ |
|
5533132e
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
265 |
signal(SIGUSR2, playsig); |
| |
266 |
|
|
f151e238
»
|
jkramer |
2008-07-06 |
Fixed pause timer for "paus... |
267 |
/* Catch SIGTSTP to set pausetime when user suspends us with ^Z. */ |
| |
268 |
signal(SIGTSTP, stopsig); |
| |
269 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
270 |
|
| |
271 |
/* Authenticate to the Last.FM server. */ |
| |
272 |
if(!authenticate(value(& rc, "username"), value(& rc, "password"))) |
| |
273 |
exit(EXIT_FAILURE); |
| |
274 |
|
| |
275 |
/* Store session key for use by external tools. */ |
| |
276 |
if(haskey(& data, "session")) { |
| |
277 |
FILE * fd = fopen(rcpath("session"), "w"); |
| |
278 |
if(fd) { |
| |
279 |
fprintf(fd, "%s\n", value(& data, "session")); |
| |
280 |
fclose(fd); |
| |
281 |
} |
| |
282 |
} |
| |
283 |
|
| |
284 |
|
| |
285 |
/* Play default radio, if specified. */ |
| |
286 |
if(haskey(& rc, "default-radio")) |
| |
287 |
station(value(& rc, "default-radio")); |
|
67a50eac
»
|
jkramer |
2009-03-12 |
Don't prompt for stream URL... |
288 |
else if(!background) |
|
e79f83e1
»
|
jkramer |
2008-10-07 |
Prompt for radio URI on sta... |
289 |
radioprompt("radio url> "); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
290 |
|
| |
291 |
/* The main loop. */ |
| |
292 |
while(!0) { |
| |
293 |
pid_t child; |
| |
294 |
int status, playnext = 0; |
| |
295 |
|
| |
296 |
/* Check if anything died (submissions fork or playback fork). */ |
| |
297 |
while((child = waitpid(-1, & status, WNOHANG | WUNTRACED | WCONTINUED)) > 0) { |
| |
298 |
if(child == subfork) |
| |
299 |
subdead(WEXITSTATUS(status)); |
| |
300 |
else if(child == playfork) { |
|
f151e238
»
|
jkramer |
2008-07-06 |
Fixed pause timer for "paus... |
301 |
if(WIFSTOPPED(status)) { |
| |
302 |
/* time(& pausetime); */ |
| |
303 |
} |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
304 |
else { |
|
f151e238
»
|
jkramer |
2008-07-06 |
Fixed pause timer for "paus... |
305 |
if(WIFCONTINUED(status)) { |
| |
306 |
signal(SIGTSTP, stopsig); |
| |
307 |
if(pausetime != 0) { |
| |
308 |
pauselength += time(NULL) - pausetime; |
| |
309 |
} |
| |
310 |
} |
| |
311 |
else { |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
312 |
playnext = !0; |
|
67dabd84
»
|
jkramer |
2008-09-25 |
Removing now-playing file a... |
313 |
unlinknp(); |
|
28290572
»
|
jkramer |
2009-01-13 |
Added delayed quit ('q', wo... |
314 |
|
| |
315 |
if(delayquit) { |
| |
316 |
unlink(rcpath("session")); |
| |
317 |
exit(EXIT_SUCCESS); |
| |
318 |
} |
|
f151e238
»
|
jkramer |
2008-07-06 |
Fixed pause timer for "paus... |
319 |
} |
|
41a0adb8
»
|
jkramer |
2008-09-20 |
'stop' in daemon mode now s... |
320 |
pausetime = 0; |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
321 |
} |
| |
322 |
} |
| |
323 |
} |
| |
324 |
|
| |
325 |
/* |
| |
326 |
Check if the playback process died. If so, submit the data |
| |
327 |
of the last played track. Then check if there are tracks left |
| |
328 |
in the playlist; if not, try to refresh the list and stop the |
| |
329 |
stream if there are no new tracks to fetch. |
| |
330 |
Also handle user stopping the stream here. We need to check for |
| |
331 |
playnext != 0 before handling enabled(STOPPED) anyway, otherwise |
| |
332 |
playfork would still be running. |
| |
333 |
*/ |
| |
334 |
if(playnext) { |
|
08750ee5
»
|
jkr |
2008-04-02 |
* 2008-04-02, jkramer |
335 |
playfork = 0; |
| |
336 |
|
| |
337 |
if(enabled(RTP)) { |
| |
338 |
unsigned duration, played, minimum; |
| |
339 |
|
|
859f319b
»
|
jkramer |
2009-02-06 |
Using seconds for duration ... |
340 |
duration = atoi(value(& track, "duration")); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
341 |
played = time(NULL) - changeTime - pauselength; |
| |
342 |
|
|
08750ee5
»
|
jkr |
2008-04-02 |
* 2008-04-02, jkramer |
343 |
/* Allow user to specify minimum playback length (min. 50%). */ |
| |
344 |
if(haskey(& rc, "minimum")) { |
| |
345 |
unsigned percent = atoi(value(& rc, "minimum")); |
| |
346 |
if(percent < 50) |
| |
347 |
percent = 50; |
| |
348 |
minimum = duration * percent / 100; |
| |
349 |
} |
| |
350 |
else { |
| |
351 |
minimum = duration / 2; |
| |
352 |
} |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
353 |
|
|
08750ee5
»
|
jkr |
2008-04-02 |
* 2008-04-02, jkramer |
354 |
if(duration >= 30 && (played >= 240 || played > minimum)) |
| |
355 |
enqueue(& track); |
| |
356 |
} |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
357 |
|
| |
358 |
submit(value(& rc, "username"), value(& rc, "password")); |
| |
359 |
|
| |
360 |
/* Check if the user stopped the stream. */ |
|
5533132e
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
361 |
if(enabled(STOPPED) || error) { |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
362 |
freelist(& playlist); |
| |
363 |
empty(& track); |
|
5533132e
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
364 |
|
| |
365 |
if(error) { |
| |
366 |
fputs("Playback stopped with an error.\n", stderr); |
| |
367 |
error = 0; |
| |
368 |
} |
| |
369 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
370 |
disable(STOPPED); |
|
41a0adb8
»
|
jkramer |
2008-09-20 |
'stop' in daemon mode now s... |
371 |
disable(CHANGED); |
|
5533132e
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
372 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
373 |
continue; |
| |
374 |
} |
| |
375 |
|
| |
376 |
shift(& playlist); |
| |
377 |
} |
| |
378 |
|
| |
379 |
|
| |
380 |
if(playnext || enabled(CHANGED)) { |
|
0c9f393d
»
|
jkr |
2008-04-06 |
Added option "delay-change"... |
381 |
if(nextstation != NULL) { |
| |
382 |
playnext = 0; |
| |
383 |
disable(CHANGED); |
| |
384 |
|
|
fa0d6c73
»
|
jkramer |
2009-03-11 |
Fixed a seg. fault when a d... |
385 |
if(!station(nextstation)) |
| |
386 |
enable(STOPPED); |
|
0c9f393d
»
|
jkr |
2008-04-06 |
Added option "delay-change"... |
387 |
|
| |
388 |
free(nextstation); |
| |
389 |
nextstation = NULL; |
| |
390 |
} |
| |
391 |
|
|
fa0d6c73
»
|
jkramer |
2009-03-11 |
Fixed a seg. fault when a d... |
392 |
if(!enabled(STOPPED) && !playlist.left) { |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
393 |
expand(& playlist); |
| |
394 |
if(!playlist.left) { |
| |
395 |
puts("No tracks left."); |
| |
396 |
playnext = 0; |
| |
397 |
disable(CHANGED); |
| |
398 |
continue; |
| |
399 |
} |
| |
400 |
} |
| |
401 |
|
| |
402 |
if(!playfork) { |
|
980ed52d
»
|
jkramer |
2009-01-13 |
Added "gap" option for slee... |
403 |
/* |
| |
404 |
If there was a track played before, and there is a gap |
| |
405 |
configured, wait that many seconds before playing the next |
| |
406 |
track. |
| |
407 |
*/ |
|
6192d6d4
»
|
jkramer |
2009-02-06 |
Fixed interrupt detection a... |
408 |
if(playnext && !enabled(INTERRUPTED) && haskey(& rc, "gap")) { |
|
980ed52d
»
|
jkramer |
2009-01-13 |
Added "gap" option for slee... |
409 |
int gap = atoi(value(& rc, "gap")); |
| |
410 |
|
| |
411 |
if(gap > 0) |
| |
412 |
sleep(gap); |
| |
413 |
} |
| |
414 |
|
|
c4e6e528
»
|
jkramer |
2009-02-05 |
No gap when track was skipp... |
415 |
disable(INTERRUPTED); |
| |
416 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
417 |
if(play(& playlist)) { |
| |
418 |
time(& changeTime); |
|
08750ee5
»
|
jkr |
2008-04-02 |
* 2008-04-02, jkramer |
419 |
pauselength = 0; |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
420 |
|
| |
421 |
set(& track, "stationURL", currentStation); |
| |
422 |
|
| |
423 |
/* Print what's currently played. (Ondrej Novy) */ |
| |
424 |
if(!background) { |
| |
425 |
if(enabled(CHANGED) && playlist.left > 0) { |
|
42fa7071
»
|
csabahenk |
2008-12-25 |
fix dumping files when the ... |
426 |
puts(meta("Receiving %s.", M_COLORED, & track)); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
427 |
disable(CHANGED); |
| |
428 |
} |
| |
429 |
|
| |
430 |
if(haskey(& rc, "title-format")) |
|
42fa7071
»
|
csabahenk |
2008-12-25 |
fix dumping files when the ... |
431 |
printf("%s\n", meta(value(& rc, "title-format"), M_COLORED, & track)); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
432 |
else |
|
42fa7071
»
|
csabahenk |
2008-12-25 |
fix dumping files when the ... |
433 |
printf("%s\n", meta("Now playing \"%t\" by %a.", M_COLORED, & track)); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
434 |
} |
| |
435 |
|
| |
436 |
|
| |
437 |
/* Write track data into a file. */ |
| |
438 |
if(haskey(& rc, "np-file") && haskey(& rc, "np-file-format")) { |
| |
439 |
signed np; |
| |
440 |
const char |
| |
441 |
* file = value(& rc, "np-file"), |
| |
442 |
* fmt = value(& rc, "np-file-format"); |
| |
443 |
|
| |
444 |
unlink(file); |
| |
445 |
if(-1 != (np = open(file, O_WRONLY | O_CREAT, 0644))) { |
|
0d2777f7
»
|
jkr |
2008-04-12 |
* 2008-04-12, jkramer |
446 |
const char * output = meta(fmt, 0, & track); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
447 |
if(output) |
| |
448 |
write(np, output, strlen(output)); |
| |
449 |
close(np); |
| |
450 |
} |
| |
451 |
} |
| |
452 |
|
| |
453 |
|
|
852cb631
»
|
jkramer |
2008-09-12 |
Added "screen-format" optio... |
454 |
if(haskey(& rc, "screen-format")) { |
| |
455 |
const char * term = getenv("TERM"); |
| |
456 |
if(term != NULL && !strncmp(term, "screen", 6)) { |
| |
457 |
const char * output = |
| |
458 |
meta(value(& rc, "screen-format"), 0, & track); |
| |
459 |
printf("\x1Bk%s\x1B\\", output); |
| |
460 |
} |
| |
461 |
} |
| |
462 |
|
| |
463 |
|
|
ee51ddb4
»
|
jkramer |
2008-09-12 |
When "term-format" is set t... |
464 |
if(haskey(& rc, "term-format")) { |
| |
465 |
const char * output = |
| |
466 |
meta(value(& rc, "term-format"), 0, & track); |
| |
467 |
printf("\x1B]2;%s\a", output); |
| |
468 |
} |
| |
469 |
|
| |
470 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
471 |
/* Run a command with our track data. */ |
| |
472 |
if(haskey(& rc, "np-cmd")) |
|
0865b83d
»
|
pioto |
2009-02-13 |
Shell-escape metadata befor... |
473 |
run(meta(value(& rc, "np-cmd"), M_SHELLESC, & track)); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
474 |
} else |
| |
475 |
changeTime = 0; |
| |
476 |
} |
| |
477 |
|
| |
478 |
if(banned(value(& track, "creator"))) { |
|
42fa7071
»
|
csabahenk |
2008-12-25 |
fix dumping files when the ... |
479 |
puts(meta("%a is banned.", M_COLORED, & track)); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
480 |
rate("B"); |
| |
481 |
fflush(stdout); |
| |
482 |
} |
| |
483 |
} |
| |
484 |
|
| |
485 |
playnext = 0; |
| |
486 |
|
| |
487 |
if(playfork && changeTime && haskey(& track, "duration") && !pausetime) { |
| |
488 |
unsigned duration; |
| |
489 |
signed remain; |
| |
490 |
char remstr[32]; |
| |
491 |
|
|
859f319b
»
|
jkramer |
2009-02-06 |
Using seconds for duration ... |
492 |
duration = atoi(value(& track, "duration")); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
493 |
|
| |
494 |
remain = (changeTime + duration) - time(NULL) + pauselength; |
| |
495 |
|
| |
496 |
snprintf(remstr, sizeof(remstr), "%d", remain); |
| |
497 |
set(& track, "remain", remstr); |
| |
498 |
|
| |
499 |
if(!background) { |
|
72bff1f2
»
|
jkramer |
2008-04-25 |
Applied another patch from ... |
500 |
printf( |
| |
501 |
"%c%02d:%02d%c", |
| |
502 |
remain < 0 ? '-' : ' ', |
| |
503 |
(remain >= 0) ? (remain / 60) : (-remain / 60), |
| |
504 |
(remain >= 0) ? (remain % 60) : (-remain % 60), |
| |
505 |
batch ? '\n' : '\r' |
| |
506 |
); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
507 |
fflush(stdout); |
| |
508 |
} |
| |
509 |
} |
| |
510 |
|
| |
511 |
interface(!background); |
| |
512 |
if(haveSocket) |
|
19b3a40e
»
|
jkramer |
2008-05-20 |
Added support for UNIX sock... |
513 |
sckif(background ? 2 : 0, -1); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
514 |
} |
| |
515 |
|
| |
516 |
return 0; |
| |
517 |
} |
| |
518 |
|
| |
519 |
|
| |
520 |
static void help(const char * argv0, int errorCode) { |
| |
521 |
fprintf(stderr, |
|
b25261cc
»
|
jkramer |
2009-02-04 |
Updated year in copyright n... |
522 |
"Shell.FM v" PACKAGE_VERSION ", (C) 2006-2009 by Jonas Kramer\n" |
|
8bd32e16
»
|
jkr |
2008-02-02 |
- fixed Makefile |
523 |
"Published under the terms of the GNU General Public License (GPL).\n" |
| |
524 |
"\n" |
| |
525 |
"%s [options] [lastfm://url]\n" |
| |
526 |
"\n" |
| |
527 |
" -d daemon mode.\n" |
| |
528 |
" -i address to listen on.\n" |
| |
529 |
" -p port to listen on.\n" |
| |
530 |
" -b batch mode.\n" |
| |
531 |
" -D device to play on.\n" |
| |
532 |
" -y proxy url to connect through.\n" |
| |
533 |
" -h this help.\n", |
| |
534 |
argv0 |
| |
535 |
); |
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
536 |
|
| |
537 |
exit(errorCode); |
| |
538 |
} |
| |
539 |
|
| |
540 |
|
| |
541 |
static void cleanup(void) { |
| |
542 |
canon(!0); |
| |
543 |
rmsckif(); |
| |
544 |
|
|
7a1b18df
»
|
jkramer |
2008-05-20 |
Fixed cleanup of UNIX socket. |
545 |
if(haskey(& rc, "unix") && getpid() == ppid) |
|
19b3a40e
»
|
jkramer |
2008-05-20 |
Added support for UNIX sock... |
546 |
unlink(value(& rc, "unix")); |
| |
547 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
548 |
empty(& data); |
| |
549 |
empty(& rc); |
| |
550 |
empty(& track); |
| |
551 |
|
| |
552 |
freelist(& playlist); |
| |
553 |
|
| |
554 |
if(currentStation) { |
| |
555 |
free(currentStation); |
| |
556 |
currentStation = NULL; |
| |
557 |
} |
| |
558 |
|
| |
559 |
if(subfork) |
| |
560 |
waitpid(subfork, NULL, 0); |
| |
561 |
|
| |
562 |
dumpqueue(!0); |
| |
563 |
|
|
3272c802
»
|
jkr |
2008-04-06 |
* " is now converted t... |
564 |
/* Clean cache. */ |
| |
565 |
if(!access(rcpath("cache"), R_OK | W_OK | X_OK)) { |
| |
566 |
const char * cache = rcpath("cache"); |
| |
567 |
DIR * directory = opendir(cache); |
| |
568 |
|
| |
569 |
if(directory != NULL) { |
|
7a1b18df
»
|
jkramer |
2008-05-20 |
Fixed cleanup of UNIX socket. |
570 |
time_t expiry = 24 * 60 * 60; /* Expiration after 24h. */ |
|
3272c802
»
|
jkr |
2008-04-06 |
* " is now converted t... |
571 |
struct dirent * entry; |
| |
572 |
struct stat status; |
| |
573 |
char path[PATH_MAX]; |
| |
574 |
|
| |
575 |
if(haskey(& rc, "expiry")) |
| |
576 |
expiry = atoi(value(& rc, "expiry")); |
| |
577 |
|
| |
578 |
while((entry = readdir(directory)) != NULL) { |
| |
579 |
snprintf(path, sizeof(path), "%s/%s", cache, entry->d_name); |
| |
580 |
|
| |
581 |
if(!stat(path, & status)) { |
| |
582 |
if(status.st_mtime < (time(NULL) - expiry)) { |
| |
583 |
unlink(path); |
| |
584 |
} |
| |
585 |
} |
| |
586 |
} |
| |
587 |
|
| |
588 |
closedir(directory); |
| |
589 |
} |
| |
590 |
} |
| |
591 |
|
|
cfd9a613
»
|
jkr |
2008-02-02 |
Removed autoconf branch. |
592 |
if(playfork) |
| |
593 |
kill(playfork, SIGUSR1); |
| |
594 |
} |
| |
595 |
|
| |
596 |
|
| |
597 |
static void forcequit(int sig) { |
| |
598 |
if(sig == SIGINT) { |
| |
599 |
fputs("Try to press Q next time you want to quit.\n", stderr); |
| |
600 |
exit(-1); |
| |
601 |
} |
| |
602 |
} |
|
5533132e
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
603 |
|
| |
604 |
|
| |
605 |
static void playsig(int sig) { |
|
c4e6e528
»
|
jkramer |
2009-02-05 |
No gap when track was skipp... |
606 |
if(sig == SIGUSR2) { |
|
5533132e
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
607 |
error = !0; |
|
c4e6e528
»
|
jkramer |
2009-02-05 |
No gap when track was skipp... |
608 |
enable(INTERRUPTED); |
| |
609 |
} |
|
5533132e
»
|
jkr |
2008-04-10 |
* 2008-04-10, jkramer |
610 |
} |
|
f151e238
»
|
jkramer |
2008-07-06 |
Fixed pause timer for "paus... |
611 |
|
| |
612 |
|
| |
613 |
static void stopsig(int sig) { |
| |
614 |
if(sig == SIGTSTP) { |
| |
615 |
time(& pausetime); |
| |
616 |
|
| |
617 |
signal(SIGTSTP, SIG_DFL); |
| |
618 |
raise(SIGTSTP); |
| |
619 |
} |
| |
620 |
} |
|
67dabd84
»
|
jkramer |
2008-09-25 |
Removing now-playing file a... |
621 |
|
| |
622 |
static void unlinknp(void) { |
| |
623 |
/* Remove now-playing file. */ |
| |
624 |
if(haskey(& rc, "np-file")) { |
| |
625 |
const char * np = value(& rc, "np-file"); |
| |
626 |
if(np != NULL) |
| |
627 |
unlink(np); |
| |
628 |
} |
| |
629 |
} |