################################ # Google Module # ################################ # Original Author: Max Kanat-Alexander # Author: Stephen Lau # # stevel's notes: # The original version of this module used Net::Google which used the Google # SOAP API. I've updated it to use the REST::Google::Search module which # uses Google's AJAX API # # This API requires that you send a valid HTTP_REFERER, which you can set # with the REFERER constant below: package BotModules::Google; use vars qw(@ISA); @ISA = qw(BotModules); use REST::Google::Search; use constant SEPARATOR => ' -- '; use constant REFERER => 'http://www.mozilla.org/projects/mozbot/'; 1; sub Help { my $self = shift; my ($event) = @_; return { '' => q{Queries Google for specified search terms. }, 'google' => q{Searches google for the specified terms.} . q{Syntax: 'google '}, 'fight' => q{Google fight two terms.} . q{Syntax: 'fight vs. '} }; } # RegisterConfig - Called when initialised, should call registerVariables sub RegisterConfig { my $self = shift; $self->SUPER::RegisterConfig(@_); $self->registerVariables( # [ name, save?, settable? ] ['maxResults', 1, 1, 8], ['maxInChannel', 1, 1, 1], ['safeSearch', 1, 1, 1], ['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."); } # 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); } } elsif ($message =~ /^(\s*fight\s+)(.+)\s+vs\.\s+(.+)\s*$/osi) { my $term1 = $2; my $term2 = $3; my $results1 = $self->getNumResults($term1); my $results2 = $self->getNumResults($term2); if ($results1 > $results2) { $self->say($event, "$term1 beats $term2, $results1 to $results2!"); } elsif ($results2 > $results1) { $self->say($event, "$term2 beats $term1, $results2 to $results1!"); } else { $self->say($event, "It's a dead tie at $results1 results!"); } } else { return $self->SUPER::Told(@_); } return 0; # we've dealt with it, no need to do anything else. } sub getNumResults { my $self = shift; my ($terms) = @_; REST::Google::Search->http_referer(REFERER); my $res = REST::Google::Search->new( q => $terms, rsz => "large", ); if ($res->responseStatus != 200) { return 0; } my $data = $res->responseData; return $data->cursor->estimatedResultCount; } # Performs the actual Google search and returns the # result as an array of lines to say. sub doSearch { my $self = shift; my ($terms) = @_; my @searchLines = (); REST::Google::Search->http_referer(REFERER); my $res = REST::Google::Search->new( q => $terms, rsz => "large", ); if ($res->responseStatus != 200) { return @searchLines; } my $data = $res->responseData; my @results = $data->results; 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; }