All pastes #576746 Raw Edit

anidb.pl

public text v1 · immutable
·published 2007-06-19 16:30 UTC
rendered paste body
# anidb.pl: irssi AniDB anime database script.
#
# Copyright (C) 2006   Tristan Willy <tristan.willy at gmail.com>
#
# 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:<number> or !anidb <title>");
    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
}