1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
|
10
|
|
11
|
|
12
|
|
13
|
|
14
|
|
15
|
|
16
|
|
17
|
|
18
|
|
19
|
|
20
|
#include <stdio.h>
|
21
|
#include <stdlib.h>
|
22
|
#include <string.h>
|
23
|
|
24
|
#include <glib.h>
|
25
|
|
26
|
#include <libaudcore/audstrings.h>
|
27
|
#include <libaudcore/drct.h>
|
28
|
#include <libaudcore/hook.h>
|
29
|
#include <libaudcore/i18n.h>
|
30
|
#include <libaudcore/interface.h>
|
31
|
#include <libaudcore/playlist.h>
|
32
|
#include <libaudcore/runtime.h>
|
33
|
#include <libaudcore/tuple.h>
|
34
|
|
35
|
#ifdef USE_DBUS
|
36
|
#include "aud-dbus.h"
|
37
|
#endif
|
38
|
|
39
|
#include "main.h"
|
40
|
#include "util.h"
|
41
|
bool jwt_norepeat = false;
|
42
|
bool resetEqState;
|
43
|
bool resetRepeatToOn;
|
44
|
int resetDefaultGain;
|
45
|
|
46
|
static struct {
|
47
|
int help, version;
|
48
|
int play, pause, play_pause, stop, fwd, rew;
|
49
|
int enqueue, enqueue_to_temp;
|
50
|
int mainwin, show_jump_box;
|
51
|
int headless, quit_after_play;
|
52
|
int verbose;
|
53
|
int qt;
|
54
|
int clearplaylist, newinstance, pauseismute, forcenoequalizer, forcenogainchg, deleteallplaylists;
|
55
|
} options;
|
56
|
|
57
|
static Index<PlaylistAddItem> filenames;
|
58
|
|
59
|
static const struct {
|
60
|
const char * long_arg;
|
61
|
char short_arg;
|
62
|
int * value;
|
63
|
const char * desc;
|
64
|
} arg_map[] = {
|
65
|
{"clear", 'c', & options.clearplaylist, N_("Clear Playlist")},
|
66
|
{"delete", 'D', & options.deleteallplaylists, N_("DELETE all playlists!")},
|
67
|
{"enqueue", 'e', & options.enqueue, N_("Add files to the playlist")},
|
68
|
{"enqueue-to-temp", 'E', & options.enqueue_to_temp, N_("Add files to a temporary playlist")},
|
69
|
{"fwd", 'f', & options.fwd, N_("Skip to next song")},
|
70
|
{"no-gain", 'g', & options.forcenogainchg, N_("Force No Gain Adjustment")},
|
71
|
{"help", 'h', & options.help, N_("Show command-line help")},
|
72
|
{"headless", 'H', & options.headless, N_("Start without a graphical interface")},
|
73
|
{"show-jump-box", 'j', & options.show_jump_box, N_("Display the jump-to-song window")},
|
74
|
{"show-main-window", 'm', & options.mainwin, N_("Display the main window")},
|
75
|
{"new", 'n', & options.newinstance, N_("New Instance")},
|
76
|
|
77
|
{"play", 'p', & options.play, N_("Start playback")},
|
78
|
{"pause-mute", 'P', & options.pauseismute, N_("Pause mutes instead of pausing")},
|
79
|
{"quit-after-play", 'q', & options.quit_after_play, N_("Quit on playback stop")},
|
80
|
#if defined(USE_QT) && defined(USE_GTK)
|
81
|
{"qt", 'Q', & options.qt, N_("Run in Qt mode")},
|
82
|
#endif
|
83
|
{"rew", 'r', & options.rew, N_("Skip to previous song")},
|
84
|
{"stop", 's', & options.stop, N_("Stop playback")},
|
85
|
{"play-pause", 't', & options.play_pause, N_("Pause if playing, play otherwise")},
|
86
|
{"pause", 'u', & options.pause, N_("Pause playback")},
|
87
|
{"version", 'v', & options.version, N_("Show version")},
|
88
|
{"verbose", 'V', & options.verbose, N_("Print debugging messages (may be used twice)")},
|
89
|
{"no-equalizer", 'z', & options.forcenoequalizer, N_("Force Equalizer Off")},
|
90
|
};
|
91
|
|
92
|
static bool parse_options (int argc, char * * argv)
|
93
|
{
|
94
|
char * cur = g_get_current_dir ();
|
95
|
bool success = true;
|
96
|
|
97
|
#ifdef _WIN32
|
98
|
Index<String> args = get_argv_utf8 ();
|
99
|
|
100
|
for (int n = 1; n < args.len (); n ++)
|
101
|
{
|
102
|
const char * arg = args[n];
|
103
|
#else
|
104
|
for (int n = 1; n < argc; n ++)
|
105
|
{
|
106
|
const char * arg = argv[n];
|
107
|
#endif
|
108
|
|
109
|
if (!(strcmp (arg, "-")))
|
110
|
{
|
111
|
char lnfromstdin[1000];
|
112
|
String uri;
|
113
|
|
114
|
while (fgets (lnfromstdin, 1000 , stdin) != NULL)
|
115
|
{
|
116
|
lnfromstdin[strlen(lnfromstdin)-1] = '\0';
|
117
|
if (strlen(lnfromstdin) > 1 && lnfromstdin[0] != '#')
|
118
|
{
|
119
|
if (strstr (lnfromstdin, "://"))
|
120
|
uri = String (lnfromstdin);
|
121
|
else if (g_path_is_absolute (lnfromstdin))
|
122
|
uri = String (filename_to_uri (lnfromstdin));
|
123
|
else
|
124
|
uri = String (filename_to_uri (filename_build ({cur, lnfromstdin})));
|
125
|
|
126
|
if (uri)
|
127
|
filenames.append (uri);
|
128
|
}
|
129
|
}
|
130
|
}
|
131
|
else if (arg[0] != '-')
|
132
|
{
|
133
|
String uri;
|
134
|
|
135
|
if (strstr (arg, "://"))
|
136
|
{
|
137
|
uri = String (arg);
|
138
|
if (strstr (arg, "://-."))
|
139
|
jwt_norepeat = true;
|
140
|
}
|
141
|
else if (g_path_is_absolute (arg))
|
142
|
uri = String (filename_to_uri (arg));
|
143
|
else
|
144
|
uri = String (filename_to_uri (filename_build ({cur, arg})));
|
145
|
|
146
|
if (uri)
|
147
|
filenames.append (uri);
|
148
|
}
|
149
|
else if (arg[1] == '-')
|
150
|
{
|
151
|
bool found = false;
|
152
|
|
153
|
for (auto & arg_info : arg_map)
|
154
|
{
|
155
|
if (! strcmp (arg + 2, arg_info.long_arg))
|
156
|
{
|
157
|
(* arg_info.value) ++;
|
158
|
found = true;
|
159
|
break;
|
160
|
}
|
161
|
}
|
162
|
|
163
|
if (! found)
|
164
|
{
|
165
|
fprintf (stderr, _("Unknown option: %s\n"), arg);
|
166
|
success = false;
|
167
|
goto OUT;
|
168
|
}
|
169
|
}
|
170
|
else
|
171
|
{
|
172
|
for (int c = 1; arg[c]; c ++)
|
173
|
{
|
174
|
bool found = false;
|
175
|
|
176
|
for (auto & arg_info : arg_map)
|
177
|
{
|
178
|
if (arg[c] == arg_info.short_arg)
|
179
|
{
|
180
|
(* arg_info.value) ++;
|
181
|
found = true;
|
182
|
break;
|
183
|
}
|
184
|
}
|
185
|
|
186
|
if (! found)
|
187
|
{
|
188
|
fprintf (stderr, _("Unknown option: -%c\n"), arg[c]);
|
189
|
success = false;
|
190
|
goto OUT;
|
191
|
}
|
192
|
}
|
193
|
}
|
194
|
}
|
195
|
|
196
|
aud_set_headless_mode (options.headless);
|
197
|
|
198
|
if (options.verbose >= 2)
|
199
|
audlog::set_stderr_level (audlog::Debug);
|
200
|
else if (options.verbose)
|
201
|
audlog::set_stderr_level (audlog::Info);
|
202
|
if (options.pauseismute)
|
203
|
aud_set_pausemute_mode (true);
|
204
|
else
|
205
|
aud_set_pausemute_mode (false);
|
206
|
if (options.qt)
|
207
|
aud_set_mainloop_type (MainloopType::Qt);
|
208
|
|
209
|
OUT:
|
210
|
g_free (cur);
|
211
|
return success;
|
212
|
}
|
213
|
|
214
|
static void print_help (void)
|
215
|
{
|
216
|
static const char pad[21] = " ";
|
217
|
|
218
|
fprintf (stderr, _("Usage: audacious [OPTION] ... [FILE] ...\n\n"));
|
219
|
|
220
|
for (auto & arg_info : arg_map)
|
221
|
fprintf (stderr, " -%c, --%s%.*s%s\n", arg_info.short_arg,
|
222
|
arg_info.long_arg, (int) (20 - strlen (arg_info.long_arg)), pad,
|
223
|
_(arg_info.desc));
|
224
|
|
225
|
fprintf (stderr, "\n");
|
226
|
}
|
227
|
|
228
|
#ifdef USE_DBUS
|
229
|
static void do_remote (void)
|
230
|
{
|
231
|
GDBusConnection * bus = nullptr;
|
232
|
ObjAudacious * obj = nullptr;
|
233
|
GError * error = nullptr;
|
234
|
|
235
|
#if ! GLIB_CHECK_VERSION (2, 36, 0)
|
236
|
g_type_init ();
|
237
|
#endif
|
238
|
|
239
|
|
240
|
if (options.newinstance || dbus_server_init () != StartupType::Client)
|
241
|
return;
|
242
|
|
243
|
if (! (bus = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr, & error)))
|
244
|
goto ERR;
|
245
|
|
246
|
if (! (obj = obj_audacious_proxy_new_sync (bus, (GDBusProxyFlags) 0,
|
247
|
"org.atheme.audacious", "/org/atheme/audacious", nullptr, & error)))
|
248
|
goto ERR;
|
249
|
|
250
|
AUDINFO ("Connected to remote session.\n");
|
251
|
|
252
|
|
253
|
if (! (filenames.len () || options.play || options.pause ||
|
254
|
options.play_pause || options.stop || options.rew || options.fwd ||
|
255
|
options.show_jump_box || options.mainwin))
|
256
|
options.mainwin = true;
|
257
|
|
258
|
if (filenames.len ())
|
259
|
{
|
260
|
Index<const char *> list;
|
261
|
|
262
|
for (auto & item : filenames)
|
263
|
list.append (item.filename);
|
264
|
|
265
|
list.append (nullptr);
|
266
|
|
267
|
if (options.enqueue_to_temp)
|
268
|
obj_audacious_call_open_list_to_temp_sync (obj, list.begin (), nullptr, nullptr);
|
269
|
else if (options.enqueue)
|
270
|
obj_audacious_call_add_list_sync (obj, list.begin (), nullptr, nullptr);
|
271
|
else
|
272
|
obj_audacious_call_open_list_sync (obj, list.begin (), nullptr, nullptr);
|
273
|
}
|
274
|
|
275
|
if (options.play)
|
276
|
obj_audacious_call_play_sync (obj, nullptr, nullptr);
|
277
|
if (options.pause)
|
278
|
obj_audacious_call_pause_sync (obj, nullptr, nullptr);
|
279
|
if (options.play_pause)
|
280
|
obj_audacious_call_play_pause_sync (obj, nullptr, nullptr);
|
281
|
if (options.stop)
|
282
|
obj_audacious_call_stop_sync (obj, nullptr, nullptr);
|
283
|
if (options.rew)
|
284
|
obj_audacious_call_reverse_sync (obj, nullptr, nullptr);
|
285
|
if (options.fwd)
|
286
|
obj_audacious_call_advance_sync (obj, nullptr, nullptr);
|
287
|
if (options.show_jump_box)
|
288
|
obj_audacious_call_show_jtf_box_sync (obj, true, nullptr, nullptr);
|
289
|
if (options.mainwin)
|
290
|
obj_audacious_call_show_main_win_sync (obj, true, nullptr, nullptr);
|
291
|
|
292
|
g_object_unref (obj);
|
293
|
|
294
|
exit (EXIT_SUCCESS);
|
295
|
|
296
|
ERR:
|
297
|
if (error)
|
298
|
{
|
299
|
AUDERR ("D-Bus error: %s\n", error->message);
|
300
|
g_error_free (error);
|
301
|
}
|
302
|
}
|
303
|
#endif
|
304
|
|
305
|
static void do_commands (void)
|
306
|
{
|
307
|
bool resume = aud_get_bool (nullptr, "resume_playback_on_startup");
|
308
|
|
309
|
if (options.deleteallplaylists)
|
310
|
{
|
311
|
const char *playlist_dir = aud_get_path(AudPath::PlaylistDir);
|
312
|
if (strstr(playlist_dir, "config")) {
|
313
|
AUDINFO("-D:DELETING ALL PLAYLISTS (DIR=%s)!", playlist_dir);
|
314
|
int i;
|
315
|
int playlist_count = aud_playlist_count();
|
316
|
for (i=playlist_count;i>=0;i--)
|
317
|
{
|
318
|
aud_playlist_delete(i);
|
319
|
}
|
320
|
}
|
321
|
}
|
322
|
else if (options.clearplaylist)
|
323
|
{
|
324
|
int playlist_count = aud_playlist_count();
|
325
|
if (playlist_count > 0)
|
326
|
aud_playlist_delete(playlist_count-1);
|
327
|
}
|
328
|
if (filenames.len ())
|
329
|
{
|
330
|
if (options.enqueue_to_temp)
|
331
|
{
|
332
|
aud_drct_pl_open_temp_list (std::move (filenames));
|
333
|
resume = false;
|
334
|
}
|
335
|
else if (options.enqueue)
|
336
|
aud_drct_pl_add_list (std::move (filenames), -1);
|
337
|
else
|
338
|
{
|
339
|
aud_drct_pl_open_list (std::move (filenames));
|
340
|
resume = false;
|
341
|
}
|
342
|
}
|
343
|
|
344
|
if (resume)
|
345
|
aud_resume ();
|
346
|
|
347
|
if (options.play_pause)
|
348
|
{
|
349
|
if (! aud_drct_get_playing ())
|
350
|
aud_drct_play ();
|
351
|
else if (aud_drct_get_paused ())
|
352
|
aud_drct_pause ();
|
353
|
}
|
354
|
if (options.play) aud_drct_play ();
|
355
|
if (options.pause) aud_drct_pause ();
|
356
|
|
357
|
if (options.show_jump_box && ! options.headless)
|
358
|
aud_ui_show_jump_to_song ();
|
359
|
if (options.mainwin && ! options.headless)
|
360
|
aud_ui_show (true);
|
361
|
if (options.forcenoequalizer)
|
362
|
{
|
363
|
resetEqState = aud_get_bool (nullptr, "equalizer_active");
|
364
|
aud_set_bool (nullptr, "equalizer_active", false);
|
365
|
}
|
366
|
if (jwt_norepeat)
|
367
|
{
|
368
|
resetRepeatToOn = aud_get_bool (nullptr, "repeat");
|
369
|
aud_set_bool (nullptr, "repeat", false);
|
370
|
}
|
371
|
if (options.forcenogainchg)
|
372
|
{
|
373
|
resetDefaultGain = aud_get_int (nullptr, "default_gain");
|
374
|
aud_set_int (nullptr, "default_gain", 0);
|
375
|
}
|
376
|
}
|
377
|
|
378
|
static void main_cleanup (void)
|
379
|
{
|
380
|
filenames.clear ();
|
381
|
aud_cleanup_paths ();
|
382
|
|
383
|
aud_leak_check ();
|
384
|
}
|
385
|
|
386
|
static bool check_should_quit (void)
|
387
|
{
|
388
|
return options.quit_after_play && ! aud_drct_get_playing () &&
|
389
|
! aud_playlist_add_in_progress (-1);
|
390
|
}
|
391
|
|
392
|
static void maybe_quit (void)
|
393
|
{
|
394
|
if (check_should_quit ())
|
395
|
aud_quit ();
|
396
|
}
|
397
|
|
398
|
int main (int argc, char * * argv)
|
399
|
{
|
400
|
atexit (main_cleanup);
|
401
|
|
402
|
#ifdef HAVE_SIGWAIT
|
403
|
signals_init_one ();
|
404
|
#endif
|
405
|
|
406
|
aud_init_paths ();
|
407
|
aud_init_i18n ();
|
408
|
|
409
|
if (! parse_options (argc, argv))
|
410
|
{
|
411
|
print_help ();
|
412
|
return EXIT_FAILURE;
|
413
|
}
|
414
|
|
415
|
if (options.help)
|
416
|
{
|
417
|
print_help ();
|
418
|
return EXIT_SUCCESS;
|
419
|
}
|
420
|
|
421
|
if (options.version)
|
422
|
{
|
423
|
printf ("%s %s (%s)\n", _("Audacious"), VERSION, BUILDSTAMP);
|
424
|
return EXIT_SUCCESS;
|
425
|
}
|
426
|
|
427
|
#if USE_DBUS
|
428
|
do_remote ();
|
429
|
#endif
|
430
|
|
431
|
AUDINFO ("No remote session; starting up.\n");
|
432
|
|
433
|
#ifdef HAVE_SIGWAIT
|
434
|
signals_init_two ();
|
435
|
#endif
|
436
|
|
437
|
aud_init ();
|
438
|
if (options.deleteallplaylists)
|
439
|
{
|
440
|
const char *playlist_dir = aud_get_path(AudPath::PlaylistDir);
|
441
|
if (strstr (playlist_dir, "config")) {
|
442
|
AUDINFO("-D:DELETING ALL PLAYLISTS (DIR=%s)!", playlist_dir);
|
443
|
int i;
|
444
|
int playlist_count = aud_playlist_count();
|
445
|
for (i=playlist_count;i>=0;i--)
|
446
|
{
|
447
|
aud_playlist_delete(i);
|
448
|
}
|
449
|
}
|
450
|
}
|
451
|
|
452
|
do_commands ();
|
453
|
|
454
|
if (check_should_quit ())
|
455
|
goto QUIT;
|
456
|
|
457
|
hook_associate ("playback stop", (HookFunction) maybe_quit, nullptr);
|
458
|
hook_associate ("playlist add complete", (HookFunction) maybe_quit, nullptr);
|
459
|
hook_associate ("quit", (HookFunction) aud_quit, nullptr);
|
460
|
|
461
|
aud_run ();
|
462
|
|
463
|
hook_dissociate ("playback stop", (HookFunction) maybe_quit);
|
464
|
hook_dissociate ("playlist add complete", (HookFunction) maybe_quit);
|
465
|
hook_dissociate ("quit", (HookFunction) aud_quit);
|
466
|
|
467
|
QUIT:
|
468
|
#ifdef USE_DBUS
|
469
|
dbus_server_cleanup ();
|
470
|
#endif
|
471
|
|
472
|
if (options.forcenoequalizer)
|
473
|
aud_set_bool (nullptr, "equalizer_active", resetEqState);
|
474
|
if (jwt_norepeat) {
|
475
|
aud_set_bool (nullptr, "repeat", resetRepeatToOn);
|
476
|
|
477
|
} if (options.forcenogainchg)
|
478
|
aud_set_int (nullptr, "default_gain", resetDefaultGain);
|
479
|
|
480
|
aud_cleanup ();
|
481
|
|
482
|
return EXIT_SUCCESS;
|
483
|
}
|