Blame


1 508e5f5f 2022-07-10 op #!/usr/bin/env perl
2 508e5f5f 2022-07-10 op #
3 508e5f5f 2022-07-10 op # Copyright (c) 2022 Omar Polo <op@omarpolo.com>
4 508e5f5f 2022-07-10 op #
5 508e5f5f 2022-07-10 op # Permission to use, copy, modify, and distribute this software for any
6 508e5f5f 2022-07-10 op # purpose with or without fee is hereby granted, provided that the above
7 508e5f5f 2022-07-10 op # copyright notice and this permission notice appear in all copies.
8 508e5f5f 2022-07-10 op #
9 508e5f5f 2022-07-10 op # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 508e5f5f 2022-07-10 op # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 508e5f5f 2022-07-10 op # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 508e5f5f 2022-07-10 op # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 508e5f5f 2022-07-10 op # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 508e5f5f 2022-07-10 op # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 508e5f5f 2022-07-10 op # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 508e5f5f 2022-07-10 op
17 508e5f5f 2022-07-10 op use strict;
18 508e5f5f 2022-07-10 op use warnings;
19 508e5f5f 2022-07-10 op use v5.12;
20 7945ad34 2023-07-02 op
21 7945ad34 2023-07-02 op use open ":std", ":encoding(UTF-8)";
22 7945ad34 2023-07-02 op use utf8;
23 508e5f5f 2022-07-10 op
24 508e5f5f 2022-07-10 op use Curses;
25 7945ad34 2023-07-02 op use POSIX qw(:sys_wait_h setlocale LC_ALL);
26 508e5f5f 2022-07-10 op use Text::CharWidth qw(mbswidth);
27 508e5f5f 2022-07-10 op use IO::Poll qw(POLLIN);
28 508e5f5f 2022-07-10 op use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);
29 508e5f5f 2022-07-10 op use Getopt::Long qw(:config bundling);
30 508e5f5f 2022-07-10 op use Pod::Usage;
31 508e5f5f 2022-07-10 op
32 3a0b3cb8 2022-07-10 op my $run = 1;
33 3a0b3cb8 2022-07-10 op
34 508e5f5f 2022-07-10 op my $pfile;
35 508e5f5f 2022-07-10 op my $trim = "";
36 508e5f5f 2022-07-10 op
37 508e5f5f 2022-07-10 op my $pair_n = 1;
38 508e5f5f 2022-07-10 op
39 508e5f5f 2022-07-10 op my @songs;
40 e9c1a558 2023-01-09 op my $current_song;
41 508e5f5f 2022-07-10 op my $playlist_cur;
42 508e5f5f 2022-07-10 op my $playlist_max;
43 508e5f5f 2022-07-10 op my $time_cur;
44 508e5f5f 2022-07-10 op my $time_dur;
45 508e5f5f 2022-07-10 op my $status;
46 63dcef30 2022-07-13 op my $mode;
47 508e5f5f 2022-07-10 op
48 508e5f5f 2022-07-10 op my $last_lines;
49 508e5f5f 2022-07-10 op
50 3c8ce7d5 2022-07-11 op sub round {
51 3c8ce7d5 2022-07-11 op return int(0.5 + shift);
52 3c8ce7d5 2022-07-11 op }
53 3c8ce7d5 2022-07-11 op
54 508e5f5f 2022-07-10 op sub max {
55 508e5f5f 2022-07-10 op my ($a, $b) = @_;
56 508e5f5f 2022-07-10 op return $a > $b ? $a : $b;
57 508e5f5f 2022-07-10 op }
58 508e5f5f 2022-07-10 op
59 508e5f5f 2022-07-10 op sub excerpt {
60 3c8ce7d5 2022-07-11 op my $lines = shift;
61 508e5f5f 2022-07-10 op my @tmp;
62 42426670 2022-07-11 op my ($n, $idx, $cur) = (0, 0, -1);
63 508e5f5f 2022-07-10 op
64 42426670 2022-07-11 op open (my $fh, "-|", "amused", "show", "-p");
65 508e5f5f 2022-07-10 op while (<$fh>) {
66 508e5f5f 2022-07-10 op chomp;
67 508e5f5f 2022-07-10 op s,$trim,,;
68 42426670 2022-07-11 op $tmp[$idx] = $_;
69 e9c1a558 2023-01-09 op
70 e9c1a558 2023-01-09 op if (m/^>/) {
71 e9c1a558 2023-01-09 op $cur = $n;
72 e9c1a558 2023-01-09 op $current_song = s/^> //r;
73 e9c1a558 2023-01-09 op }
74 e9c1a558 2023-01-09 op
75 42426670 2022-07-11 op $n++;
76 42426670 2022-07-11 op $idx = ++$idx % $lines;
77 42426670 2022-07-11 op
78 83438dc0 2022-07-13 op last if $cur != -1 && $n - $cur > int($lines/2) &&
79 42426670 2022-07-11 op $#tmp == $lines-1;
80 508e5f5f 2022-07-10 op }
81 508e5f5f 2022-07-10 op close($fh);
82 508e5f5f 2022-07-10 op
83 42426670 2022-07-11 op return ("Empty playlist.") unless @tmp;
84 508e5f5f 2022-07-10 op
85 42426670 2022-07-11 op # reorder the entries
86 42426670 2022-07-11 op my @r;
87 42426670 2022-07-11 op my $len = $#tmp + 1;
88 6045cf87 2022-07-13 op $idx = $idx % $len;
89 42426670 2022-07-11 op for (1..$len) {
90 42426670 2022-07-11 op push @r, $tmp[$idx];
91 42426670 2022-07-11 op $idx = ++$idx % $len;
92 42426670 2022-07-11 op }
93 42426670 2022-07-11 op return @r;
94 508e5f5f 2022-07-10 op }
95 508e5f5f 2022-07-10 op
96 508e5f5f 2022-07-10 op sub playlist_numbers {
97 508e5f5f 2022-07-10 op my ($cur, $tot, $found) = (0, 0, 0);
98 508e5f5f 2022-07-10 op open (my $fh, "-|", "amused", "show", "-p");
99 508e5f5f 2022-07-10 op while (<$fh>) {
100 508e5f5f 2022-07-10 op $tot++;
101 508e5f5f 2022-07-10 op $cur++ unless $found;
102 508e5f5f 2022-07-10 op $found = 1 if m/^>/;
103 508e5f5f 2022-07-10 op }
104 508e5f5f 2022-07-10 op close($fh);
105 508e5f5f 2022-07-10 op return ($cur, $tot);
106 508e5f5f 2022-07-10 op }
107 508e5f5f 2022-07-10 op
108 508e5f5f 2022-07-10 op sub status {
109 63dcef30 2022-07-13 op my ($pos, $dur, $mode);
110 508e5f5f 2022-07-10 op
111 508e5f5f 2022-07-10 op open (my $fh, "-|", "amused", "status", "-f",
112 63dcef30 2022-07-13 op "status,time:raw,mode:oneline");
113 e9c1a558 2023-01-09 op
114 e9c1a558 2023-01-09 op <$fh> =~ m/([a-z]+) (.*)/;
115 e9c1a558 2023-01-09 op my ($status, $current_song) = ($1, $2);
116 e9c1a558 2023-01-09 op
117 508e5f5f 2022-07-10 op while (<$fh>) {
118 508e5f5f 2022-07-10 op chomp;
119 508e5f5f 2022-07-10 op $pos = s/position //r if m/^position /;
120 508e5f5f 2022-07-10 op $dur = s/duration //r if m/^duration /;
121 63dcef30 2022-07-13 op $mode = $_ if m/^repeat/;
122 508e5f5f 2022-07-10 op }
123 508e5f5f 2022-07-10 op close($fh);
124 e9c1a558 2023-01-09 op return ($status, $current_song, $pos, $dur, $mode);
125 508e5f5f 2022-07-10 op }
126 508e5f5f 2022-07-10 op
127 508e5f5f 2022-07-10 op sub showtime {
128 508e5f5f 2022-07-10 op my $seconds = shift;
129 508e5f5f 2022-07-10 op my $str = "";
130 508e5f5f 2022-07-10 op
131 508e5f5f 2022-07-10 op if ($seconds > 3600) {
132 508e5f5f 2022-07-10 op my $hours = int($seconds / 3600);
133 508e5f5f 2022-07-10 op $seconds -= $hours * 3600;
134 86d7c366 2022-08-23 op $str = sprintf("%02d:", $hours);
135 508e5f5f 2022-07-10 op }
136 508e5f5f 2022-07-10 op
137 508e5f5f 2022-07-10 op my $minutes = int($seconds / 60);
138 508e5f5f 2022-07-10 op $seconds -= $minutes * 60;
139 508e5f5f 2022-07-10 op $str .= sprintf "%02d:%02d", $minutes, $seconds;
140 508e5f5f 2022-07-10 op return $str;
141 508e5f5f 2022-07-10 op }
142 508e5f5f 2022-07-10 op
143 508e5f5f 2022-07-10 op sub center {
144 508e5f5f 2022-07-10 op my ($str, $pstr) = @_;
145 508e5f5f 2022-07-10 op my $width = mbswidth($str);
146 508e5f5f 2022-07-10 op return $str if $width > $COLS;
147 1b135dc5 2022-07-26 op my $pre = round(($COLS - $width) / 2);
148 508e5f5f 2022-07-10 op my $lpad = $pstr x $pre;
149 1b135dc5 2022-07-26 op my $rpad = $pstr x ($COLS - $width - $pre);
150 508e5f5f 2022-07-10 op return ($lpad, $str, $rpad);
151 508e5f5f 2022-07-10 op }
152 508e5f5f 2022-07-10 op
153 508e5f5f 2022-07-10 op sub offsets {
154 508e5f5f 2022-07-10 op my ($y, $x, $cur, $max) = @_;
155 508e5f5f 2022-07-10 op my ($pre, $c, $post) = center(" $cur / $max ", '-');
156 508e5f5f 2022-07-10 op addstring $y, $x, "";
157 508e5f5f 2022-07-10 op
158 508e5f5f 2022-07-10 op my $p = COLOR_PAIR($pair_n);
159 508e5f5f 2022-07-10 op
160 508e5f5f 2022-07-10 op attron $p;
161 508e5f5f 2022-07-10 op addstring $pre;
162 508e5f5f 2022-07-10 op attroff $p;
163 508e5f5f 2022-07-10 op
164 508e5f5f 2022-07-10 op addstring $c;
165 508e5f5f 2022-07-10 op
166 508e5f5f 2022-07-10 op attron $p;
167 508e5f5f 2022-07-10 op addstring $post;
168 508e5f5f 2022-07-10 op attroff $p;
169 508e5f5f 2022-07-10 op }
170 508e5f5f 2022-07-10 op
171 508e5f5f 2022-07-10 op sub progress {
172 508e5f5f 2022-07-10 op my ($y, $x, $pos, $dur) = @_;
173 508e5f5f 2022-07-10 op
174 508e5f5f 2022-07-10 op my $pstr = showtime $pos;
175 508e5f5f 2022-07-10 op my $dstr = showtime $dur;
176 508e5f5f 2022-07-10 op
177 508e5f5f 2022-07-10 op my $len = $COLS - length($pstr) - length($dstr) - 4;
178 127f376a 2022-07-11 op return if $len <= 0 or $dur <= 0;
179 3c8ce7d5 2022-07-11 op my $filled = round($pos * $len / $dur);
180 508e5f5f 2022-07-10 op
181 508e5f5f 2022-07-10 op addstring $y, $x, "$pstr [";
182 508e5f5f 2022-07-10 op addstring "#" x $filled;
183 508e5f5f 2022-07-10 op addstring " " x max($len - $filled, 0);
184 508e5f5f 2022-07-10 op addstring "] $dstr";
185 508e5f5f 2022-07-10 op }
186 508e5f5f 2022-07-10 op
187 508e5f5f 2022-07-10 op sub show_status {
188 508e5f5f 2022-07-10 op my ($y, $x, $status) = @_;
189 508e5f5f 2022-07-10 op my ($pre, $c, $post) = center($status, ' ');
190 508e5f5f 2022-07-10 op addstring $y, $x, $pre;
191 508e5f5f 2022-07-10 op addstring $c;
192 508e5f5f 2022-07-10 op addstring $post;
193 508e5f5f 2022-07-10 op }
194 508e5f5f 2022-07-10 op
195 63dcef30 2022-07-13 op sub show_mode {
196 63dcef30 2022-07-13 op my ($y, $x, $mode) = @_;
197 63dcef30 2022-07-13 op my ($pre, $c, $post) = center($mode, ' ');
198 508e5f5f 2022-07-10 op addstring $y, $x, $pre;
199 508e5f5f 2022-07-10 op addstring $c;
200 508e5f5f 2022-07-10 op addstring $post;
201 508e5f5f 2022-07-10 op }
202 508e5f5f 2022-07-10 op
203 508e5f5f 2022-07-10 op sub render {
204 508e5f5f 2022-07-10 op erase;
205 508e5f5f 2022-07-10 op if ($LINES < 4 || $COLS < 20) {
206 508e5f5f 2022-07-10 op addstring "window too small";
207 508e5f5f 2022-07-10 op refresh;
208 508e5f5f 2022-07-10 op return;
209 508e5f5f 2022-07-10 op }
210 508e5f5f 2022-07-10 op
211 508e5f5f 2022-07-10 op my $song_pad = "";
212 508e5f5f 2022-07-10 op my $longest = 0;
213 508e5f5f 2022-07-10 op $longest = max $longest, length($_) foreach @songs;
214 508e5f5f 2022-07-10 op if ($longest < $COLS) {
215 508e5f5f 2022-07-10 op $song_pad = " " x (($COLS - $longest)/2);
216 508e5f5f 2022-07-10 op }
217 508e5f5f 2022-07-10 op
218 508e5f5f 2022-07-10 op my $line = 0;
219 508e5f5f 2022-07-10 op map {
220 508e5f5f 2022-07-10 op attron(A_BOLD) if m/^>/;
221 508e5f5f 2022-07-10 op addstring $line++, 0, $song_pad . $_;
222 508e5f5f 2022-07-10 op standend;
223 508e5f5f 2022-07-10 op } @songs;
224 508e5f5f 2022-07-10 op
225 508e5f5f 2022-07-10 op offsets $LINES - 4, 0, $playlist_cur, $playlist_max;
226 508e5f5f 2022-07-10 op progress $LINES - 3, 0, $time_cur, $time_dur;
227 e9c1a558 2023-01-09 op show_status $LINES - 2, 0, "$status $current_song";
228 63dcef30 2022-07-13 op show_mode $LINES - 1, 0, $mode;
229 508e5f5f 2022-07-10 op
230 508e5f5f 2022-07-10 op refresh;
231 508e5f5f 2022-07-10 op }
232 508e5f5f 2022-07-10 op
233 508e5f5f 2022-07-10 op sub getsongs {
234 508e5f5f 2022-07-10 op $last_lines = $LINES;
235 42426670 2022-07-11 op @songs = excerpt $LINES - 4;
236 508e5f5f 2022-07-10 op }
237 508e5f5f 2022-07-10 op
238 508e5f5f 2022-07-10 op sub getnums {
239 508e5f5f 2022-07-10 op ($playlist_cur, $playlist_max) = playlist_numbers;
240 508e5f5f 2022-07-10 op }
241 508e5f5f 2022-07-10 op
242 508e5f5f 2022-07-10 op sub save {
243 508e5f5f 2022-07-10 op return unless defined $pfile;
244 508e5f5f 2022-07-10 op
245 508e5f5f 2022-07-10 op open(my $fh, ">", $pfile);
246 508e5f5f 2022-07-10 op open(my $ph, "-|", "amused", "show", "-p");
247 508e5f5f 2022-07-10 op
248 508e5f5f 2022-07-10 op print $fh $_ while (<$ph>);
249 508e5f5f 2022-07-10 op }
250 508e5f5f 2022-07-10 op
251 508e5f5f 2022-07-10 op sub hevent {
252 508e5f5f 2022-07-10 op my $fh = shift;
253 508e5f5f 2022-07-10 op my $l = <$fh>;
254 508e5f5f 2022-07-10 op die "monitor quit" unless defined($l);
255 e9c1a558 2023-01-09 op
256 e9c1a558 2023-01-09 op $status = "playing" if $l =~ m/^play/;
257 e9c1a558 2023-01-09 op $status = "paused" if $l =~ m/^pause/;
258 e9c1a558 2023-01-09 op $status = "stopped" if $l =~ m/^stop/;
259 e9c1a558 2023-01-09 op
260 e9c1a558 2023-01-09 op ($time_cur, $time_dur) = ($1, $2) if $l =~ m/^seek (\d+) (\d+)/;
261 e9c1a558 2023-01-09 op
262 e9c1a558 2023-01-09 op $mode = $1 if $l =~ m/^mode (.*)/;
263 e9c1a558 2023-01-09 op
264 508e5f5f 2022-07-10 op getnums if $l =~ m/load|jump|next|prev/;
265 508e5f5f 2022-07-10 op getsongs if $l =~ m/load|jump|next|prev/;
266 508e5f5f 2022-07-10 op }
267 508e5f5f 2022-07-10 op
268 508e5f5f 2022-07-10 op sub hinput {
269 508e5f5f 2022-07-10 op my ($ch, $key) = getchar;
270 9c72efd4 2022-07-13 op if (defined $key) {
271 9c72efd4 2022-07-13 op if ($key == KEY_BACKSPACE) {
272 3fc73666 2022-07-26 op system "amused", "seek", "0";
273 9c72efd4 2022-07-13 op }
274 9c72efd4 2022-07-13 op } elsif (defined $ch) {
275 508e5f5f 2022-07-10 op if ($ch eq " ") {
276 508e5f5f 2022-07-10 op system "amused", "toggle";
277 508e5f5f 2022-07-10 op } elsif ($ch eq "<" or $ch eq "p") {
278 508e5f5f 2022-07-10 op system "amused", "prev";
279 508e5f5f 2022-07-10 op } elsif ($ch eq ">" or $ch eq "n") {
280 508e5f5f 2022-07-10 op system "amused", "next";
281 508e5f5f 2022-07-10 op } elsif ($ch eq ",") {
282 508e5f5f 2022-07-10 op system "amused", "seek", "-5";
283 508e5f5f 2022-07-10 op } elsif ($ch eq ".") {
284 508e5f5f 2022-07-10 op system "amused", "seek", "+5";
285 508e5f5f 2022-07-10 op } elsif ($ch eq "S") {
286 508e5f5f 2022-07-10 op system "amused show | sort -u | amused load";
287 508e5f5f 2022-07-10 op } elsif ($ch eq "R") {
288 508e5f5f 2022-07-10 op system "amused show | sort -R | amused load";
289 508e5f5f 2022-07-10 op } elsif ($ch eq "s") {
290 508e5f5f 2022-07-10 op save;
291 508e5f5f 2022-07-10 op } elsif ($ch eq "q") {
292 3a0b3cb8 2022-07-10 op $run = 0;
293 9c72efd4 2022-07-13 op } elsif ($ch eq "\cH") {
294 3fc73666 2022-07-26 op system "amused", "seek", "0"
295 508e5f5f 2022-07-10 op }
296 508e5f5f 2022-07-10 op }
297 508e5f5f 2022-07-10 op }
298 508e5f5f 2022-07-10 op
299 508e5f5f 2022-07-10 op GetOptions(
300 508e5f5f 2022-07-10 op "p:s" => \$pfile,
301 508e5f5f 2022-07-10 op "t:s" => \$trim,
302 508e5f5f 2022-07-10 op ) or pod2usage(1);
303 508e5f5f 2022-07-10 op
304 87abdf60 2022-07-12 op my $mpid = open(my $monitor, "-|", "amused", "monitor")
305 508e5f5f 2022-07-10 op or die "can't spawn amused monitor";
306 508e5f5f 2022-07-10 op
307 7945ad34 2023-07-02 op setlocale(LC_ALL, "");
308 508e5f5f 2022-07-10 op initscr;
309 508e5f5f 2022-07-10 op start_color;
310 508e5f5f 2022-07-10 op use_default_colors;
311 508e5f5f 2022-07-10 op init_pair $pair_n, 250, -1;
312 508e5f5f 2022-07-10 op
313 508e5f5f 2022-07-10 op timeout 1000;
314 508e5f5f 2022-07-10 op scrollok 0;
315 508e5f5f 2022-07-10 op curs_set 0;
316 9c72efd4 2022-07-13 op keypad 1;
317 508e5f5f 2022-07-10 op
318 508e5f5f 2022-07-10 op my $poll = IO::Poll->new();
319 508e5f5f 2022-07-10 op $poll->mask(\*STDIN => POLLIN);
320 508e5f5f 2022-07-10 op $poll->mask($monitor => POLLIN);
321 936bd534 2022-08-13 op
322 936bd534 2022-08-13 op if (`uname` =~ "OpenBSD") {
323 936bd534 2022-08-13 op use OpenBSD::Pledge;
324 936bd534 2022-08-13 op use OpenBSD::Unveil;
325 936bd534 2022-08-13 op
326 936bd534 2022-08-13 op my $prog = `which amused`;
327 936bd534 2022-08-13 op chomp $prog;
328 936bd534 2022-08-13 op
329 936bd534 2022-08-13 op unveil($prog, 'rx') or die "unveil $prog: $!";
330 936bd534 2022-08-13 op if (defined($pfile)) {
331 936bd534 2022-08-13 op unveil($pfile, 'wc') or die "unveil $pfile: $!";
332 936bd534 2022-08-13 op pledge qw(stdio wpath cpath tty proc exec) or die "pledge: $!";
333 936bd534 2022-08-13 op } else {
334 936bd534 2022-08-13 op pledge qw(stdio tty proc exec) or die "pledge: $!";
335 936bd534 2022-08-13 op }
336 936bd534 2022-08-13 op }
337 508e5f5f 2022-07-10 op
338 508e5f5f 2022-07-10 op getsongs;
339 508e5f5f 2022-07-10 op getnums;
340 e9c1a558 2023-01-09 op ($status, $current_song, $time_cur, $time_dur, $mode) = status;
341 508e5f5f 2022-07-10 op render;
342 508e5f5f 2022-07-10 op
343 3a0b3cb8 2022-07-10 op while ($run) {
344 e9c1a558 2023-01-09 op $poll->poll();
345 508e5f5f 2022-07-10 op hinput if $poll->events(\*STDIN) & POLLIN;
346 508e5f5f 2022-07-10 op hevent $monitor if $poll->events($monitor) & POLLIN;
347 508e5f5f 2022-07-10 op
348 508e5f5f 2022-07-10 op getsongs if $LINES != $last_lines;
349 508e5f5f 2022-07-10 op
350 508e5f5f 2022-07-10 op render;
351 508e5f5f 2022-07-10 op }
352 508e5f5f 2022-07-10 op
353 508e5f5f 2022-07-10 op endwin;
354 508e5f5f 2022-07-10 op save;
355 508e5f5f 2022-07-10 op
356 508e5f5f 2022-07-10 op kill 'INT', $mpid;
357 508e5f5f 2022-07-10 op wait;
358 508e5f5f 2022-07-10 op
359 508e5f5f 2022-07-10 op __END__
360 508e5f5f 2022-07-10 op
361 508e5f5f 2022-07-10 op =pod
362 508e5f5f 2022-07-10 op
363 508e5f5f 2022-07-10 op =head1 NAME
364 508e5f5f 2022-07-10 op
365 508e5f5f 2022-07-10 op amused-monitor - curses interface for amused(1)
366 508e5f5f 2022-07-10 op
367 508e5f5f 2022-07-10 op =head1 SYNOPSIS
368 508e5f5f 2022-07-10 op
369 508e5f5f 2022-07-10 op B<amused-monitor> [B<-p> I<playlist>] [B<-t> I<string>]
370 508e5f5f 2022-07-10 op
371 508e5f5f 2022-07-10 op =head1 DESCRIPTION
372 508e5f5f 2022-07-10 op
373 508e5f5f 2022-07-10 op amused-monitor is a simple curses interface for amused(1).
374 508e5f5f 2022-07-10 op
375 508e5f5f 2022-07-10 op The following options are available:
376 508e5f5f 2022-07-10 op
377 508e5f5f 2022-07-10 op =over 12
378 508e5f5f 2022-07-10 op
379 508e5f5f 2022-07-10 op =item B<-p> I<playlist>
380 508e5f5f 2022-07-10 op
381 508e5f5f 2022-07-10 op Save the current playling queue to the file I<playlist> upon exit or
382 508e5f5f 2022-07-10 op I<s> key.
383 508e5f5f 2022-07-10 op
384 508e5f5f 2022-07-10 op =item B<-t> I<string>
385 508e5f5f 2022-07-10 op
386 508e5f5f 2022-07-10 op Trim out the given I<string> from every song in the playlist view.
387 508e5f5f 2022-07-10 op
388 508e5f5f 2022-07-10 op =back
389 508e5f5f 2022-07-10 op
390 508e5f5f 2022-07-10 op The following key-bindings are available:
391 508e5f5f 2022-07-10 op
392 508e5f5f 2022-07-10 op =over 8
393 508e5f5f 2022-07-10 op
394 9c72efd4 2022-07-13 op =item backspace or C-h
395 9c72efd4 2022-07-13 op
396 9c72efd4 2022-07-13 op Seek back to the beginning of the track.
397 9c72efd4 2022-07-13 op
398 508e5f5f 2022-07-10 op =item space
399 508e5f5f 2022-07-10 op
400 508e5f5f 2022-07-10 op Toggle play/pause.
401 508e5f5f 2022-07-10 op
402 508e5f5f 2022-07-10 op =item < or p
403 508e5f5f 2022-07-10 op
404 508e5f5f 2022-07-10 op Play previous song.
405 508e5f5f 2022-07-10 op
406 508e5f5f 2022-07-10 op =item > or n
407 508e5f5f 2022-07-10 op
408 508e5f5f 2022-07-10 op Play next song.
409 508e5f5f 2022-07-10 op
410 508e5f5f 2022-07-10 op =item ,
411 508e5f5f 2022-07-10 op
412 508e5f5f 2022-07-10 op Seek backward by five seconds.
413 508e5f5f 2022-07-10 op
414 508e5f5f 2022-07-10 op =item .
415 508e5f5f 2022-07-10 op
416 508e5f5f 2022-07-10 op Seek forward by five seconds.
417 508e5f5f 2022-07-10 op
418 508e5f5f 2022-07-10 op =item R
419 508e5f5f 2022-07-10 op
420 508e5f5f 2022-07-10 op Randomize the playlist.
421 508e5f5f 2022-07-10 op
422 508e5f5f 2022-07-10 op =item S
423 508e5f5f 2022-07-10 op
424 508e5f5f 2022-07-10 op Sort the playlist.
425 508e5f5f 2022-07-10 op
426 508e5f5f 2022-07-10 op =item s
427 508e5f5f 2022-07-10 op
428 508e5f5f 2022-07-10 op Save the status to the file given with the B<-p> flag.
429 508e5f5f 2022-07-10 op
430 508e5f5f 2022-07-10 op =item q
431 508e5f5f 2022-07-10 op
432 508e5f5f 2022-07-10 op Quit.
433 508e5f5f 2022-07-10 op
434 508e5f5f 2022-07-10 op =back
435 508e5f5f 2022-07-10 op
436 508e5f5f 2022-07-10 op =head1 SEE ALSO
437 508e5f5f 2022-07-10 op
438 508e5f5f 2022-07-10 op amused(1)
439 508e5f5f 2022-07-10 op
440 508e5f5f 2022-07-10 op =cut