# Copyright © 2008, 2010, 2020 Nick Bowler
#
# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
# This is free software: you are free to do what the fuck you want to.
# There is NO WARRANTY, to the extent permitted by law.
#
# MPDSplat helps you annoy your friends by posting your MPD status.  By
# posting to public channels, you can piss off a wider audience.

use strict;
use utf8;

use vars qw($VERSION %IRSSI);

use IO::Socket::INET6;
use IO::Socket::UNIX;

$VERSION = '1.0';
%IRSSI = (
	authors     => 'Nick Bowler',
	contact     => 'nbowler@draconx.ca',
	name        => 'MPDSplat',
	description => 'Annoy your friends with MPD status information.',
	license     => 'WTFPL2',
);

# MPD Connection Settings
$ENV{"MPD_HOST"} //= "localhost";
$ENV{"MPD_PORT"} //= 6600;
Irssi::settings_add_str("mpd", "mpd_host", $ENV{"MPD_HOST"});
Irssi::settings_add_int("mpd", "mpd_port", $ENV{"MPD_PORT"});

# Open a connection to MPD.
sub mpd_open {
	my $host = Irssi::settings_get_str("mpd_host");
	my $port = Irssi::settings_get_int("mpd_port");
	my $sock;

        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)
        }

	unless ($sock) {
		print CLIENTERROR "failed to open MPD socket: $!";
		return;
	}

	binmode($sock, ":utf8");

	# Grab the MPD version.
	unless (<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/) {
		print CLIENTERROR "failed MPD handshake: $!";
		return;
	}

	return $sock;
}

sub mpd_currentsong {
	my ($sock) = @_;
	my %data;

	# Get MPD status.
	print $sock "status\n";
	while (<$sock>) {
		last if (/^OK/);
		do { print CLIENTERROR "$_"; return undef } if (/^ACK/);

		if (/^(\w+): (.*)$/) {
			$data{$1} = $2;
		}
	}
	return %data if (!defined $data{"songid"});

	# Get song info
	print $sock "playlistid $data{songid}\n";
	while (<$sock>) {
		last if (/^OK/);
		do { print CLIENTERROR "$_"; return undef } if (/^ACK/);

		if (/^(\w+): (.*)$/) {
			$data{$1} = $2;
		}
	}

	return %data;
}

sub mpd_close {
	my ($sock) = @_;
	print $sock "close\n";
	close $sock;
}

sub fileformat {
	($_) = @_;

	return "vorbis" if (/\.ogg$/);
	return "flac"   if (/\.flac$/);
	return "mp3"    if (/\.mp3$/);
}

sub cmd_current {
	my ($data, $server, $witem) = @_;
	my ($window, $local) = (Irssi::active_win());

	my $sock = mpd_open() or return;
	my %info = mpd_currentsong($sock) or return;
	mpd_close($sock);

	if ($info{'state'} eq "stop") {
		$window->print("MPD is currently stopped.");
		return;
	}

	my $text = "$info{Artist} – $info{Title}, "
	         . "track $info{Track}"
		 . ($info{Disc} > 1 ? ", disc $info{Disc} " : "")
                 . " of “$info{Album}” "
		 . "($info{bitrate}kbps " . fileformat($info{'file'}) . ")";

	# If the active window is not a channel or query, display locally.
	$local = 1 unless ($witem && ($witem->{type} eq "CHANNEL"
	                           || $witem->{type} eq "QUERY"));

	if ($local) {
		$window->print($text);
	} elsif ($data) {
		$data =~ s/\s.*//;
		$witem->command("SAY $data: /me is listening to $text.");
	} else {
		$witem->command("SAY /me is listening to $text.");
	}
}
Irssi::command_bind('mpd', 'cmd_current');
