]> git.draconx.ca Git - irssi-scripts.git/blob - mpdsplat.pl
Update mpdsplat to work with latest perl.
[irssi-scripts.git] / mpdsplat.pl
1 # Copyright © 2008, 2010, 2020 Nick Bowler
2 #
3 # License WTFPL2: Do What The Fuck You Want To Public License, version 2.
4 # This is free software: you are free to do what the fuck you want to.
5 # There is NO WARRANTY, to the extent permitted by law.
6 #
7 # MPDSplat helps you annoy your friends by posting your MPD status.  By
8 # posting to public channels, you can piss off a wider audience.
9
10 use strict;
11 use utf8;
12
13 use vars qw($VERSION %IRSSI);
14
15 use IO::Socket::INET6;
16 use IO::Socket::UNIX;
17
18 $VERSION = '1.0';
19 %IRSSI = (
20         authors     => 'Nick Bowler',
21         contact     => 'nbowler@draconx.ca',
22         name        => 'MPDSplat',
23         description => 'Annoy your friends with MPD status information.',
24         license     => 'WTFPL2',
25 );
26
27 # MPD Connection Settings
28 $ENV{"MPD_HOST"} //= "localhost";
29 $ENV{"MPD_PORT"} //= 6600;
30 Irssi::settings_add_str("mpd", "mpd_host", $ENV{"MPD_HOST"});
31 Irssi::settings_add_int("mpd", "mpd_port", $ENV{"MPD_PORT"});
32
33 # Open a connection to MPD.
34 sub mpd_open {
35         my $host = Irssi::settings_get_str("mpd_host");
36         my $port = Irssi::settings_get_int("mpd_port");
37         my $sock;
38
39         if ($host =~ /^[@\/]/) {
40                 $host =~ s/^@/\0/;
41                 $sock = new IO::Socket::UNIX(Type => SOCK_STREAM(),
42                                              Peer => $host)
43         } else {
44                 $sock = new IO::Socket::INET6(PeerAddr => $host,
45                                               PeerPort => $port,
46                                               Proto    => 'tcp',
47                                               Timeout  => 2)
48         }
49
50         unless ($sock) {
51                 print CLIENTERROR "failed to open MPD socket: $!";
52                 return;
53         }
54
55         binmode($sock, ":utf8");
56
57         # Grab the MPD version.
58         unless (<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/) {
59                 print CLIENTERROR "failed MPD handshake: $!";
60                 return;
61         }
62
63         return $sock;
64 }
65
66 sub mpd_currentsong {
67         my ($sock) = @_;
68         my %data;
69
70         # Get MPD status.
71         print $sock "status\n";
72         while (<$sock>) {
73                 last if (/^OK/);
74                 do { print CLIENTERROR "$_"; return undef } if (/^ACK/);
75
76                 if (/^(\w+): (.*)$/) {
77                         $data{$1} = $2;
78                 }
79         }
80         return %data if (!defined $data{"songid"});
81
82         # Get song info
83         print $sock "playlistid $data{songid}\n";
84         while (<$sock>) {
85                 last if (/^OK/);
86                 do { print CLIENTERROR "$_"; return undef } if (/^ACK/);
87
88                 if (/^(\w+): (.*)$/) {
89                         $data{$1} = $2;
90                 }
91         }
92
93         return %data;
94 }
95
96 sub mpd_close {
97         my ($sock) = @_;
98         print $sock "close\n";
99         close $sock;
100 }
101
102 sub fileformat {
103         ($_) = @_;
104
105         return "vorbis" if (/\.ogg$/);
106         return "flac"   if (/\.flac$/);
107         return "mp3"    if (/\.mp3$/);
108 }
109
110 sub cmd_current {
111         my ($data, $server, $witem) = @_;
112         my ($window, $local) = (Irssi::active_win());
113
114         my $sock = mpd_open() or return;
115         my %info = mpd_currentsong($sock) or return;
116         mpd_close($sock);
117
118         if ($info{'state'} eq "stop") {
119                 $window->print("MPD is currently stopped.");
120                 return;
121         }
122
123         my $text = "$info{Artist} – $info{Title}, "
124                  . "track $info{Track}"
125                  . ($info{Disc} > 1 ? ", disc $info{Disc} " : "")
126                  . " of “$info{Album}” "
127                  . "($info{bitrate}kbps " . fileformat($info{'file'}) . ")";
128
129         # If the active window is not a channel or query, display locally.
130         $local = 1 unless ($witem && ($witem->{type} eq "CHANNEL"
131                                    || $witem->{type} eq "QUERY"));
132
133         if ($local) {
134                 $window->print($text);
135         } elsif ($data) {
136                 $data =~ s/\s.*//;
137                 $witem->command("SAY $data: /me is listening to $text.");
138         } else {
139                 $witem->command("SAY /me is listening to $text.");
140         }
141 }
142 Irssi::command_bind('mpd', 'cmd_current');