################################ # Google Module # ################################ # Author: Max Kanat-Alexander # Uses the Net::Google module to query Google for keywords. # Note that Net::Google requires SOAP::Lite. package BotModules::Google; use vars qw(@ISA); @ISA = qw(BotModules); use Net::Google; use constant SEPARATOR => ' -- '; 1; sub Help { my $self = shift; my ($event) = @_; return { '' => q{Queries Google for specified search terms. Note that you} . q{ have to specify your Google API Key (the 'googleApiKey'} . q{ var) before using any commands. To get a Google API Key,} . q{ see: http://www.google.com/apis/ and go to "Create an} . q{ Account."}, 'google' => q{Searches google for the specified terms.} . q{Syntax: 'google '}, }; } # RegisterConfig - Called when initialised, should call registerVariables sub RegisterConfig { my $self = shift; $self->SUPER::RegisterConfig(@_); $self->registerVariables( # [ name, save?, settable? ] ['maxResults', 1, 1, 10], ['maxInChannel', 1, 1, 1], # XXX - Not yet implemented. #['backoffTime', 1, 1, 120], ['googleApiKey', 1, 1, ''], ['safeSearch', 1, 1, 1], # Note that maxLineLength will not be respected if the URL # alone is longer than maxLineLength. ['maxLineLength', 1, 1, 256] ); } sub Told { my $self = shift; my ($event, $message) = @_; # We take anything that occurs at the end of the line, # because Google will ignore punctuation anyway. if ($message =~ /^(\s*google\s+)(.+)$/osi) { my $terms = $2; my @searchResults = $self->doSearch($terms); if (!@searchResults) { $self->say($event, "Nothing found."); # XXX - We could use $google->spell here to make suggestions. } # If we are in a channel, and not a /msg elsif ($event->{'channel'}) { splice(@searchResults, $self->{'maxInChannel'}); } # We're in a /msg else { unshift(@searchResults, scalar(@searchResults) . " results found: "); } foreach my $result (@searchResults) { $self->say($event, $event->{'from'} . ': ' . $result); } } else { return $self->SUPER::Told(@_); } return 0; # we've dealt with it, no need to do anything else. } # Performs the actual Google search and returns the # result as an array of lines to say. sub doSearch { my $self = shift; my ($terms) = @_; my $google = Net::Google->new(key => $self->{'googleApiKey'}); my $search = $google->search(safe => $self->{'safeSearch'}, filter => $self->{'safeSearch'}, max_results => $self->{'maxResults'}); $search->query($terms); my $results = $search->results(); my @searchLines = (); foreach my $result (@$results) { my $title = $result->title(); # The Google API puts tags into the title if the search # terms appear in the title. $title =~ s|||g; $title = $self->unescapeXML($title); my $url = $result->URL(); my $line_size = (length($title) + length($result) + length(SEPARATOR)); if ($line_size > $self->{'maxLineLength'} ) { # The 3 is for the '...' my $new_title_size = ($line_size - $self->{'maxLineLength'}) - 3; my $title = substr($title, 0, $new_title_size) . '...'; } my $resultLine = $title . SEPARATOR . $url; push(@searchLines, $resultLine); } return @searchLines; }