3 # Copyright © 2012,2019 Nick Bowler
5 # Send commands to MPD. Each command-line argument is quoted as necessary
6 # so it appears as a single argument at the protocol level. The result is
7 # printed to standard output.
9 # License GPLv3+: GNU General Public License version 3 or any later version.
10 # This is free software: you are free to change and redistribute it.
11 # There is NO WARRANTY, to the extent permitted by law.
17 use Encode qw(decode encode);
18 use Encode::Locale qw(decode_argv);
19 decode_argv(Encode::FB_CROAK);
21 binmode(STDOUT, ":utf8");
22 binmode(STDIN, ":utf8");
23 use IO::Socket::INET6;
25 use Getopt::Long qw(:config gnu_getopt);
27 my $host = $ENV{MPD_HOST} // "localhost";
28 my $port = $ENV{MPD_PORT} // 6600;
29 my ($quiet, $binary, $ignore_errors, $download);
34 Copyright © 2019 Nick Bowler
35 License GPLv3+: GNU General Public License version 3 or any later version.
36 This is free software: you are free to change and redistribute it.
37 There is NO WARRANTY, to the extent permitted by law.
42 my $fh = $_[1] // *STDERR;
44 print $fh "Usage: $0 [options] [command ...]\n";
45 print "Try $0 --help for more information.\n" unless (@_ > 0);
51 This is "mpdexec": a tool to send simple commands to MPD.
54 -h, --host=HOST Connect to the MPD server on HOST, overriding defaults.
55 -p, --port=PORT Connect to the MPD server on PORT, overriding defaults.
56 -q, --quiet Do not output any response messages. Only errors (on
57 standard error) or binary data (if enabled) are output.
59 Output raw binary response data, which is normally not
60 written. If FILE is specified, the data is written there.
61 Otherwise, --quiet is automatically enabled and the data
62 goes to standard output.
63 --download Enable automatic sequencing of albumart commands; if this
64 option is specified, albumart commands without offsets will
65 be expanded into multiple commands in order to download the
67 --ignore-errors In batch mode, continue submitting commands after errors.
68 -V, --version Print a version message and then exit.
69 -H, --help Print this message and then exit.
71 Report bugs to <nbowler\@draconx.ca>.
80 'no-quiet' => sub { $quiet = 0; },
81 'binary|b:s' => \$binary,
82 'no-binary' => sub { $binary = undef; },
84 'download' => \$download,
85 'no-download' => sub { $download = 0; },
87 'ignore-errors' => \$ignore_errors,
88 'no-ignore-errors' => sub { $ignore_errors = 0; },
90 'V|version' => sub { print_version(); exit },
91 'H|help' => sub { print_help(); exit },
92 ) or do { print_usage; exit 1 };
94 my $binfile = *STDOUT;
97 open(my $fh, ">", $binary) or die "failed to open $binary: $!";
101 $quiet = 1 if (defined($binary) && $binary eq "");
103 my $sock = new IO::Socket::INET6(
107 ) or die "failed to connect to MPD: $!";
108 #binmode($sock, ":utf8");
111 if (!(<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/)) {
112 die "MPD failed to announce version: $!";
118 # No way to encode literal newlines in the protocol, so we convert
119 # any newlines in the arguments into a space, which can help with
136 return 0 unless ($count);
137 my $rc = $sock->read($buf, $count) or die "$!";
138 if (defined($binary)) {
139 $binfile->write($buf) or die "$!";
148 # special case for "albumart"; if no offset is specified
149 # (invalid command) we synthesize a sequence of albumart
150 # commands to retrieve the entire file.
151 if ($download && $_[0] eq "albumart" && @_ == 2) {
156 print $sock encode('UTF-8', join(' ', @_), Encode::FB_QUIET), $/;
158 $_ = decode('UTF_8', $_, Encode::FB_QUIET);
161 last unless ($downloadseq);
162 print $sock encode('UTF-8',
164 Encode::FB_QUIET), $/;
168 if (/^binary: ([0-9]+)$/) {
169 print unless ($quiet);
173 $downloadseq = 0 unless ($1);
174 $_[$downloadseq] += $1;
179 last if ($ignore_errors);
182 print unless ($quiet);
188 mpd_exec(map { mpd_escape($_) } @ARGV)
196 print $sock "close\n";