use Exporter;
our ($VERSION, @ISA, @EXPORT);
+use IO::Socket::INET6;
+use IO::Socket::UNIX;
+
$VERSION = 0;
@ISA = qw(Exporter);
@EXPORT = qw();
+our $host = $ENV{MPD_HOST} // "localhost";
+our $port = $ENV{MPD_PORT} // 6600;
+our $sock;
+
+our ($major, $minor, $revision);
+
+# MPD::connect([ARGS])
+#
+# Connect to MPD based on the current settings of $MPD::host and $MPD::port.
+#
+# The following key-value arguments may optionally be specified:
+#
+# binmode => socket binmode, e.g., :utf8 or :raw. The default is :utf8.
+#
+# Text in the MPD protocol is always UTF-8 encoded but some
+# commands return raw binary data which can be easier to
+# handle in :raw mode.
+#
+# On failure, an error message is printed and undef is returned.
+sub connect {
+ my %args = @_;
+
+ if ($host =~ /^[@\/]/) {
+ $host =~ s/^@/\0/;
+ $sock = new IO::Socket::UNIX(Type => SOCK_STREAM(),
+ Peer => $host)
+ } else {
+ $sock = new IO::Socket::INET6(PeerAddr => $host,
+ PeerPort => $port,
+ Proto => 'tcp',
+ Timeout => 2)
+ }
+ die "MPD connection failed: $!\n" unless $sock;
+
+ binmode($sock, $args{binmode} // ":utf8");
+ unless (<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/) {
+ $sock->close();
+ die "MPD failed to announce version: $!\n";
+ }
+
+ ($major, $minor, $revision) = ($1, $2, $3);
+ return $sock;
+}
+
+# min_version(x, y, z)
+#
+# Returns true iff the MPD protocol version is at least x.y.z.
+sub min_version {
+ my ($maj, $min, $rev) = @_;
+
+ if (defined $maj) {
+ return 1 if $maj < $major;
+ return 0 if $maj > $major;
+ }
+
+ if (defined $min) {
+ return 1 if $min < $minor;
+ return 0 if $min > $minor;
+ }
+
+ if (defined $rev) {
+ return 1 if $rev < $revision;
+ return 0 if $rev > $revision;
+ }
+
+ return 1;
+}
+
# Returns the argument (or $_ if no arguments are supplied) quoted so that it
# can be presented as a single command argument to MPD at the protocol level.
sub escape {
return $s;
}
+# Submit a command to the MPD server; each argument to this function
+# is quoted and sent as a single argument to MPD.
+sub exec {
+ my $cmd = join(' ', map { MPD::escape } @_);
+
+ print $sock "$cmd\n";
+}
+
+# Submit a command to the MPD server and wait for it to complete.
+# Intended for simple cases where the command output is unneeded.
+sub run {
+ MPD::exec(@_);
+ while (<$sock>) {
+ last if (/^OK/);
+ die($_) if (/^ACK/);
+ }
+}
+
1;