# anidb.pl: irssi AniDB anime database script. # # Copyright (C) 2006 Tristan Willy # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License version 2 # as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. use strict; use DBI; use Text::ParseWords; use anidb; use vars qw($VERSION %IRSSI); use Irssi; $VERSION = '0.11'; %IRSSI = ( 'authors' => 'Tristan Willy', 'contact' => 'tristan.willy at gmail.com', 'name' => 'AniDB', 'description' => 'AniDB in-channel query & report.', 'license' => 'GPL v2' ); Irssi::settings_add_str($IRSSI{'name'}, 'anidb_channels', ''); Irssi::settings_add_str($IRSSI{'name'}, 'anidb_path', ''); my (%anidb_active_chans, $path); load_globals(); Irssi::signal_add('event privmsg', 'irc_privmsg'); Irssi::signal_add('setup changed', 'load_globals'); sub load_globals { map { $anidb_active_chans{uc($_)} = 1 } quotewords(',', 0, Irssi::settings_get_str('anidb_channels')); $path = Irssi::settings_get_str('anidb_path'); if(not -d $path){ Irssi::print("Warning: anidb_path ($path) is not a directory."); } } sub irc_privmsg { my ($server, $data, $from, $address) = @_; my ($to, $message) = split(/\s+:/, $data, 2); my ($me, $target) = ($server->{'nick'}, find_target($to, $from)); # Check if it was for the channel we joined... if(uc($to) eq uc($me) or $anidb_active_chans{uc($to)}){ if($message =~ /^[^!]*!anidb\s+(.+)/i){ trigger_anidb($server, $target, $to, $from, $address, $1); } } return 1; } sub trigger_anidb { my ($server, $target, $to, $from, $address, $query) = @_; my $anidb = new anidb('Database' => 'pikabot') or do { $server->command("msg $target \x0311AniDB: Error pulling up anidb module."); return; }; # compress spaces $query =~ s/\s+/ /g; $query =~ s/^\s+//; $query =~ s/\s+$//; if($query =~ /^help\s*$/i or length($query) == 0){ $server->command("msg $target \x0311`!anidb' usage: " . "!anidb ID: or !anidb "); return 1; } # If the query matches a number or specific ID, then run against that. # If not, then the user is searching with a title rather than an ID. my $anime; if($query =~ /^(ID:)?(\d+)/i){ $anime = $anidb->anime_query($2); } else { Irssi::print("anidb: running query `$query'."); my @titles = $anidb->title_query($query); # Check if there are any or too many results if($#titles < 0){ $server->command("msg $target AniDB: No Results"); $anidb->close(); return; } if($#titles > 10){ $server->command("msg $target AniDB: Too many hits. Please be more specific."); $anidb->close(); return; } # The anidb module can return multiple titles with the same id. Merge these # titles together. my %mergeset; map { if(defined $mergeset{$_->{id}}){ $mergeset{$_->{id}} .= ", $_->{title}"; } else { $mergeset{$_->{id}} .= $_->{title}; } } @titles; @titles = (); map { push @titles, { 'id' => $_, 'title' => $mergeset{$_} }; } keys %mergeset; # Sort the title set so the highest id is first @titles = sort { $b->{id} <=> $a->{id} } @titles; # More than one result means we should print out all the title maches # This will also break up results into multiple messages should a few # titles exceed the maximum message length limit. # Note: titles are printed in descending id number. if($#titles > 0){ my $header = "\x0313AniDB Title Results:\x0311"; my $msgbuff = $header; foreach my $title (@titles){ my $prevstate = $msgbuff; my $item; $item .= " ID:$title->{id} [\x0312 $title->{title}\x0311 ]"; if(length($msgbuff . $item) > 384){ # prevent overflow $server->command("msg $target $prevstate"); $msgbuff = $header . $item; } else { $msgbuff .= $item; } } $server->command("msg $target $msgbuff"); } # run against the first title match if(not defined $titles[0]->{id}){ Irssi::print "$IRSSI{name}: Error: anidb->title_query seems to be ok, but we got a undefined aid."; $anidb->close(); return; } else { $anime = $anidb->anime_query($titles[0]->{id}); } } if(not defined $anime){ Irssi::print "$IRSSI{name}: anidb->anime_query returned a undefined result."; $server->command("msg $target AniDB: Internal error. Try again at a later time."); $anidb->close(); return; } # Print out requested anime info my @msgpieces = (); push @msgpieces, "\x0305{ID:$anime->{aid}} "; map { push @msgpieces, "\x0313<$_> " } @{$anime->{titles}}; push @msgpieces, "\x0311Genre: [ @{$anime->{genres}} ] " if $#{$anime->{genres}} >= 0; push @msgpieces, "\x0311#Eps: [ $anime->{numeps} ] " if defined $anime->{numeps}; push @msgpieces, "\x0311Rating: [ $anime->{rating} ] " if defined $anime->{rating}; push @msgpieces, "\x0311URL: [ $anime->{url} ] " if defined $anime->{url}; push @msgpieces, "\x0311AniDB: [ \x0312http://anidb.info/a$anime->{aid}\x0311 ]"; my $msgbuff; while($#msgpieces >= 0){ if(length ($msgbuff . $msgpieces[0]) > 384){ $server->command("msg $target $msgbuff"); $msgbuff = shift @msgpieces; } else { $msgbuff .= shift @msgpieces; } } $server->command("msg $target $msgbuff"); $anidb->close(); } sub find_target { my ($to, $from) = @_; if($to =~ /^#/){ return $to; # from a channel } return $from; # from a private message }