use DisOrder;
use File::FcntlLock;
+use Getopt::Long qw{:config gnu_compat bundling
+ require_order no_getopt_compat};
use POSIX qw{:errno_h :fcntl_h};
###--------------------------------------------------------------------------
lockdir => "$ENV{HOME}/.disorder/",
mixer => "Master,0");
+(my $PROG = $0) =~ s:^.*/::;
my $TITLE = "DisOrder";
my $VARIANT = "default";
if (-l $C{config} && (my $t = readlink $C{config}) =~ /^passwd\.(.*)$/)
return \%st;
}
+my $CONF = undef;
+
+sub configured_connection (;$) {
+ my ($quietp) = @_;
+ $CONF //= load_config $C{config};
+ return connect_to_server %$CONF, $quietp // 0;
+}
+
sub get_state () {
- my $sk = connect_to_server $C{config};
+ my $sk = configured_connection;
send_command0 $sk, "log";
my $st = get_state0 $sk;
close $sk;
return sprintf "%d:%02d", int $n/60, $n%60;
}
-sub format_now_playing (\%) {
- my ($info) = @_;
- exists $info->{track} or return "Nothing.";
- my $r = "$info->{artist}: ‘$info->{title}’";
- $r .= ", from ‘$info->{album}’" if $info->{album};
- exists $info->{sofar} && exists $info->{length} and
- $r .= sprintf " (%s/%s)",
- fmt_duration $info->{sofar}, fmt_duration $info->{length};
- $r .= "\n(chosen by $info->{submitter})" if exists $info->{submitter};
- return $r;
-}
-
sub get_now_playing ($) {
my ($sk) = @_;
my $r = send_command $sk, "playing";
return \%info;
}
+sub format_now_playing (;\%) {
+ my ($info) = @_;
+ unless (defined $info) {
+ my $sk = configured_connection;
+ $info = get_now_playing $sk;
+ close $sk;
+ }
+ exists $info->{track} or return "Nothing.";
+ my $r = "$info->{artist}: ‘$info->{title}’";
+ $r .= ", from ‘$info->{album}’" if $info->{album};
+ exists $info->{sofar} && exists $info->{length} and
+ $r .= sprintf " (%s/%s)",
+ fmt_duration $info->{sofar}, fmt_duration $info->{length};
+ $r .= "\n(chosen by $info->{submitter})" if exists $info->{submitter};
+ return $r;
+}
+
sub watch_and_notify0 ($) {
my ($now_playing) = @_;
- my $sk = connect_to_server $C{config}, 1;
- my $sk_log = connect_to_server $C{config}, 1;
+ my $sk = configured_connection 1;
+ my $sk_log = configured_connection 1;
send_command0 $sk_log, "log";
my $st = get_state0 $sk_log;
my $buffer = "";
my @lines = ();
my $rdin = ""; vec($rdin, (fileno $sk_log), 1) = 1;
+ my $loss;
WATCH: for (;;) {
for my $line (@lines) {
my @f = split_fields $line;
if ($f[1] eq "state") {
my $msg = undef;
- if ($f[2] eq "disable_random") { $msg = "Random play disabled"; }
- elsif ($f[2] eq "enable_random") { $msg = "Random play enabled"; }
- elsif ($f[2] eq "disable_play") { $msg = "Playing disabled"; }
- elsif ($f[2] eq "enable_play") { $msg = "Playing enabled"; }
- elsif ($f[2] eq "pause") { $msg = "Paused"; }
- elsif ($f[2] eq "resume") { $msg = "Playing"; }
+ if ($f[2] eq "disable_random")
+ { $st->{random} = 0; $msg = "Random play disabled"; }
+ elsif ($f[2] eq "enable_random")
+ { $st->{random} = 1; $msg = "Random play enabled"; }
+ elsif ($f[2] eq "disable_play")
+ { $st->{play} = 0; $msg = "Playing disabled"; }
+ elsif ($f[2] eq "enable_play")
+ { $st->{play} = 1; $msg = "Playing enabled"; }
+ elsif ($f[2] eq "pause")
+ { $st->{pause} = 1; $msg = "Paused"; }
+ elsif ($f[2] eq "resume")
+ { $st->{pause} = 0; $msg = "Playing"; }
notify "$TITLE state", $msg if defined $msg;
} elsif ($f[1] eq "playing") {
my %info;
$info{track} = $f[2];
decode_track_name $sk, %info;
notify "$TITLE: Scratched by $f[3]", format_now_playing %info;
+ } elsif ($f[1] eq "completed" && !$st->{play}) {
+ notify "$TITLE state", "Stopped";
}
}
- last WATCH unless $sk_log;
- select my $rdout = $rdin, undef, undef, undef;
- READ: for (;;) {
- my ($b, $n);
- eval { $n = sysread $sk_log, $b, 4096; };
- if ($@ && $@->errno == EAGAIN) { last READ; }
- elsif ($@) { die $@; }
- elsif (!$n) { close $sk_log; $sk_log = undef; }
- else { $buffer .= $b; }
- }
+ if (!$sk_log) { $loss = "EOF from server"; last WATCH; }
+ my $nfd = select my $rdout = $rdin, undef, undef, 60;
+ if (!$nfd) {
+ eval { print $sk_log "."; flush $sk_log; };
+ if ($@) { $loss = "error from write: " . $@->errno; last WATCH; }
+ @lines = ();
+ } else {
+ READ: for (;;) {
+ my ($b, $n);
+ eval { $n = sysread $sk_log, $b, 4096; };
+ if ($@ && $@->errno == EAGAIN) { last READ; }
+ elsif ($@) { $loss = "error from read: " . $@->errno; last WATCH; }
+ elsif (!$n) { close $sk_log; $sk_log = undef; last READ; }
+ else { $buffer .= $b; }
+ }
- @lines = split /\n/, $buffer, -1;
- $buffer = pop @lines;
+ @lines = split /\n/, $buffer, -1;
+ $buffer = pop @lines;
+ }
}
- notify "$TITLE state", "Lost connection";
+ notify "$TITLE state", "Lost connection: $loss";
close $sk;
close $sk_log if defined $sk_log;
sub { run_discard_output "amixer", "sset", $C{mixer}, "5\%-"; };
$OP{"scratch"} = sub {
- my $sk = connect_to_server $C{config};
+ my $sk = configured_connection;
send_command $sk, "scratch";
close $sk;
};
$OP{"enable/disable"} = sub {
my $st = get_state;
- my $sk = connect_to_server $C{config};
+ my $sk = configured_connection;
if ($st->{play}) { send_command $sk, "disable"; }
else { send_command $sk, "enable"; }
close $sk;
$OP{"play/pause"} = sub {
my $st = get_state;
- my $sk = connect_to_server $C{config};
+ my $sk = configured_connection;
if (!$st->{play}) {
send_command $sk, "enable";
if ($st->{pause}) { send_command $sk, "resume"; }
};
$OP{"now-playing"} = sub {
- my $sk = connect_to_server $C{config};
+ my $sk = configured_connection;
my $info = get_now_playing $sk;
close $sk;
print format_now_playing %$info;
};
$OP{"notify-now-playing"} = sub {
- my $sk = connect_to_server $C{config};
+ my $sk = configured_connection;
my $info = get_now_playing $sk;
close $sk;
notify "$TITLE: Now playing", format_now_playing %$info;
###--------------------------------------------------------------------------
### Main program.
-if (@ARGV != 1) { print STDERR "usage: $0 OP\n"; exit 2; }
+sub usage (\*) {
+ my ($fh) = @_;
+ print $fh "usage: $PROG [-u CONFIG] COMMAND\n";
+}
+
+sub help () {
+ usage *STDOUT;
+ print <<EOF;
+
+Command-line options:
+ -h, --help Show this help text
+ -u, --user-config Set user configuration file
+
+Commands:
+ volume-up
+ volume-down
+ scratch
+ enable/disable
+ play/pause
+ watch
+ now-playing
+ notify-now-playing
+ next-config
+EOF
+}
+
+my $bad = 0;
+GetOptions
+ "h|help" => sub { help; exit 0; },
+ "u|user-config=s" => \$C{config}
+ or $bad = 1;
+@ARGV == 1 or $bad = 1;
+if ($bad) { usage *STDERR; exit 2; }
my $op = $ARGV[0];
if (!exists $OP{$op}) { print STDERR "$0: unknown op `$op'\n"; exit 2; }
$OP{$op}();