3 # Copyright © 2012,2019-2020 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");
24 use Getopt::Long qw(:config gnu_getopt);
27 use lib "$FindBin::Bin";
30 my ($quiet, $binary, $ignore_errors, $download);
35 Copyright © 2019 Nick Bowler
36 License GPLv3+: GNU General Public License version 3 or any later version.
37 This is free software: you are free to change and redistribute it.
38 There is NO WARRANTY, to the extent permitted by law.
43 my $fh = $_[1] // *STDERR;
45 print $fh "Usage: $0 [options] [command ...]\n";
46 print "Try $0 --help for more information.\n" unless (@_ > 0);
52 This is "mpdexec": a tool to send simple commands to MPD.
55 -h, --host=HOST Connect to the MPD server on HOST, overriding defaults.
56 -p, --port=PORT Connect to the MPD server on PORT, overriding defaults.
57 -q, --quiet Do not output any response messages. Only errors (on
58 standard error) or binary data (if enabled) are output.
60 Output raw binary response data, which is normally not
61 written. If FILE is specified, the data is written there.
62 Otherwise, --quiet is automatically enabled and the data
63 goes to standard output.
64 --download Enable automatic sequencing of albumart commands; if this
65 option is specified, albumart commands without offsets will
66 be expanded into multiple commands in order to download the
68 --ignore-errors In batch mode, continue submitting commands after errors.
69 -V, --version Print a version message and then exit.
70 -H, --help Print this message and then exit.
72 Report bugs to <nbowler\@draconx.ca>.
77 'host|h=s' => \$MPD::host,
78 'port|p=s' => \$MPD::port,
81 'no-quiet' => sub { $quiet = 0; },
82 'binary|b:s' => \$binary,
83 'no-binary' => sub { $binary = undef; },
85 'download' => \$download,
86 'no-download' => sub { $download = 0; },
88 'ignore-errors' => \$ignore_errors,
89 'no-ignore-errors' => sub { $ignore_errors = 0; },
91 'V|version' => sub { print_version(); exit },
92 'H|help' => sub { print_help(); exit },
93 ) or do { print_usage; exit 1 };
95 my $binfile = *STDOUT;
98 open(my $fh, ">", $binary) or die "failed to open $binary: $!";
102 $quiet = 1 if (defined($binary) && $binary eq "");
104 my $sock = MPD::connect(binmode => ":raw");
112 return 0 unless ($count);
113 my $rc = $sock->read($buf, $count) or die "$!";
114 if (defined($binary)) {
115 $binfile->write($buf) or die "$!";
124 # special case for "albumart"; if no offset is specified
125 # (invalid command) we synthesize a sequence of albumart
126 # commands to retrieve the entire file.
127 if ($download && $_[0] eq "albumart" && @_ == 2) {
132 print $sock encode('UTF-8', join(' ', @_), Encode::FB_QUIET), $/;
134 $_ = decode('UTF_8', $_, Encode::FB_QUIET);
137 last unless ($downloadseq);
138 print $sock encode('UTF-8',
140 Encode::FB_QUIET), $/;
144 if (/^binary: ([0-9]+)$/) {
145 print unless ($quiet);
149 $downloadseq = 0 unless ($1);
150 $_[$downloadseq] += $1;
155 last if ($ignore_errors);
158 print unless ($quiet);
164 mpd_exec(map { MPD::escape($_) } @ARGV)
172 print $sock "close\n";