3 # Copyright © 2012,2019-2021 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 © 2021 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) = (@_, *STDERR);
45 print $fh "Usage: $0 [options] [command ...]\n";
46 print $fh "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 and readpicture
65 commands; if this option is specified, such commands
66 without offsets will be expanded into multiple commands
67 in order to download the entire file.
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 "$!";
121 my %downloadcmds = map { $_ => 1 } ( "albumart", "readpicture" );
125 # special case for "albumart" and "readpicture"; if no offset is
126 # specified (invalid command) we synthesize a sequence of albumart
127 # commands to retrieve the entire file.
128 if ($download && $downloadcmds{$_[0]} && @_ == 2) {
133 print $sock encode('UTF-8', join(' ', @_), Encode::FB_QUIET), $/;
135 $_ = decode('UTF_8', $_, Encode::FB_QUIET);
138 last unless ($downloadseq);
139 print $sock encode('UTF-8',
141 Encode::FB_QUIET), $/;
145 if (/^binary: ([0-9]+)$/) {
146 print unless ($quiet);
150 $downloadseq = 0 unless ($1);
151 $_[$downloadseq] += $1;
156 last if ($ignore_errors);
159 print unless ($quiet);
165 mpd_exec(map { MPD::escape($_) } @ARGV)
173 print $sock "close\n";