From b0f5f5741b234174958ade58a6e884df8b6b00e4 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 4 May 2020 23:01:06 -0400 Subject: [PATCH] Factor out MPD connection code. Instead of having three different copies of the MPD connection code in the perl scripts, let's put it all in one place. Now mpdreload is no longer the only script that supports UNIX socket connections. --- MPDHacks.pm | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mpdexec.pl | 19 +++----------- mpdmenu.pl | 25 ++++-------------- mpdreload.pl | 24 +++--------------- 4 files changed, 82 insertions(+), 57 deletions(-) diff --git a/MPDHacks.pm b/MPDHacks.pm index 2c76c2f..94c0acc 100644 --- a/MPDHacks.pm +++ b/MPDHacks.pm @@ -13,10 +13,81 @@ use strict; 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 { diff --git a/mpdexec.pl b/mpdexec.pl index 8147f1d..496c558 100755 --- a/mpdexec.pl +++ b/mpdexec.pl @@ -20,7 +20,6 @@ decode_argv(Encode::FB_CROAK); binmode(STDOUT, ":utf8"); binmode(STDIN, ":utf8"); -use IO::Socket::INET6; use Getopt::Long qw(:config gnu_getopt); @@ -28,8 +27,6 @@ use FindBin; use lib "$FindBin::Bin"; use MPDHacks; -my $host = $ENV{MPD_HOST} // "localhost"; -my $port = $ENV{MPD_PORT} // 6600; my ($quiet, $binary, $ignore_errors, $download); sub print_version { @@ -77,8 +74,8 @@ EOF } GetOptions( - 'host|h=s' => \$host, - 'port|p=s' => \$port, + 'host|h=s' => \$MPD::host, + 'port|p=s' => \$MPD::port, 'quiet|q' => \$quiet, 'no-quiet' => sub { $quiet = 0; }, @@ -104,17 +101,7 @@ if ($binary) { } $quiet = 1 if (defined($binary) && $binary eq ""); -my $sock = new IO::Socket::INET6( - PeerAddr => $host, - PeerPort => $port, - Proto => 'tcp', -) or die "failed to connect to MPD: $!"; -#binmode($sock, ":utf8"); -binmode($sock); - -if (!(<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/)) { - die "MPD failed to announce version: $!"; -} +my $sock = MPD::connect(binmode => ":raw"); sub read_binary { my ($count) = @_; diff --git a/mpdmenu.pl b/mpdmenu.pl index 3a84f78..4916d2a 100755 --- a/mpdmenu.pl +++ b/mpdmenu.pl @@ -18,7 +18,6 @@ use Encode::Locale qw(decode_argv); decode_argv(Encode::FB_CROAK); binmode(STDOUT, ":utf8"); -use IO::Socket::INET6; use Getopt::Long qw(:config gnu_getopt); use Scalar::Util qw(reftype); use List::Util qw(any max); @@ -36,8 +35,6 @@ use constant { my $SELF = "$FindBin::Bin/$FindBin::Script"; my $MUSIC = $ENV{MUSIC} // "/srv/music"; -my $host = $ENV{MPD_HOST} // "localhost"; -my $port = $ENV{MPD_PORT} // "6600"; my $sock; my ($albumid, $trackid); @@ -488,8 +485,8 @@ EOF } GetOptions( - 'host|h=s' => \$host, - 'port|p=s' => \$port, + 'host|h=s' => \$MPD::host, + 'port|p=s' => \$MPD::port, 'menu|m=s' => \$menu, 'artist-id=s' => sub { $artistids{$_[1]} = 1; $mode = "artist"; }, @@ -509,21 +506,9 @@ unless (defined $menu) { $topmenu //= $menu; # Connect to MPD. -$sock = new IO::Socket::INET6( - PeerAddr => $host, - PeerPort => $port, - Proto => 'tcp', - Timeout => 2 -) or die("could not open socket: $!.\n"); -binmode($sock, ":utf8"); - -die("could not connect to MPD: $!.\n") - if (!(<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/)); - -die("MPD version $1.$2.$3 insufficient.\n") - if ( ($1 < MPD_MJR_MIN) - || ($1 == MPD_MJR_MIN && $2 < MPD_MNR_MIN) - || ($1 == MPD_MJR_MIN && $2 == MPD_MNR_MIN && $3 < MPD_REV_MIN)); +$sock = MPD::connect(); +die("MPD version $MPD::major.$MPD::minor.$MPD::revision insufficient.") + unless MPD::min_version(MPD_MJR_MIN, MPD_MNR_MIN, MPD_REV_MIN); if ($mode eq "top") { my %current; diff --git a/mpdreload.pl b/mpdreload.pl index fcbbcc3..ba822ae 100755 --- a/mpdreload.pl +++ b/mpdreload.pl @@ -17,8 +17,6 @@ use Encode::Locale qw(decode_argv); decode_argv(Encode::FB_CROAK); binmode(STDOUT, ":utf8"); -use IO::Socket::INET6; -use IO::Socket::UNIX; use Getopt::Long qw(:config gnu_getopt); @@ -26,8 +24,6 @@ use FindBin; use lib "$FindBin::Bin"; use MPDHacks; -my $host = $ENV{MPD_HOST} // "localhost"; -my $port = $ENV{MPD_PORT} // 6600; my $sock; # Submit a command to the MPD server; each argument to this function @@ -124,8 +120,8 @@ EOF } GetOptions( - 'host|h=s' => \$host, - 'port|p=s' => \$port, + 'host|h=s' => \$MPD::host, + 'port|p=s' => \$MPD::port, 'V|version' => sub { print_version(); exit }, 'H|help' => sub { print_help(); exit }, @@ -138,21 +134,7 @@ if (@ARGV != 1) { print_usage(); exit 1 }; -# Connect to MPD. -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'); -} -$sock or die "failed to connect to MPD: $!"; -binmode($sock, ":utf8"); - -if (!(<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/)) { - die "MPD failed to announce version: $!"; -} +$sock = MPD::connect(); # Retrieve the current play queue and target play queue. my $current = get_tracks_in_play_queue(); -- 2.43.0