зеркало из https://github.com/mozilla/pjs.git
256 строки
9.4 KiB
Plaintext
256 строки
9.4 KiB
Plaintext
|
################################
|
||
|
# RDF Module #
|
||
|
################################
|
||
|
|
||
|
package BotModules::RDF;
|
||
|
use vars qw(@ISA);
|
||
|
@ISA = qw(BotModules);
|
||
|
1;
|
||
|
|
||
|
# RegisterConfig - Called when initialised, should call registerVariables
|
||
|
sub RegisterConfig {
|
||
|
my $self = shift;
|
||
|
$self->SUPER::RegisterConfig(@_);
|
||
|
$self->registerVariables(
|
||
|
# [ name, save?, settable? ]
|
||
|
['sites', 1, 1, {}],
|
||
|
['updateDelay', 1, 1, 600],
|
||
|
['preferredLineLength', 1, 1, 80],
|
||
|
['maxInChannel', 1, 1, 5],
|
||
|
['trimTitles', 1, 1, '0'],
|
||
|
['data', 0, 0, {}], # data -> uri -> (title, link, last, items -> uri)
|
||
|
['mutes', 1, 1, {}], # uri -> "channel channel channel"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
# Schedule - called when bot connects to a server, to install any schedulers
|
||
|
# use $self->schedule($event, $delay, $times, $data)
|
||
|
# where $times is 1 for a single event, -1 for recurring events,
|
||
|
# and a +ve number for an event that occurs that many times.
|
||
|
sub Schedule {
|
||
|
my $self = shift;
|
||
|
my ($event) = @_;
|
||
|
$self->schedule($event, \$self->{'updateDelay'}, -1, 'rdf');
|
||
|
$self->SUPER::Schedule($event);
|
||
|
}
|
||
|
|
||
|
sub Help {
|
||
|
my $self = shift;
|
||
|
my ($event) = @_;
|
||
|
my %commands;
|
||
|
if ($self->isAdmin($event)) {
|
||
|
$commands{''} = "The RDF module monitors various websites. Add new RDF channels to the 'sites' hash. Duplicates with different nicknames are fine. For example, \"vars $self->{'_name'} sites '+|slashdot|http://...'\" and \"vars $self->{'_name'} sites '+|/.|http://...'\" is fine.";
|
||
|
$commands{'mute'} = 'Disable reporting of a site in a channel. (Only does something if the given site exists.) Syntax: mute <site> in <channel>';
|
||
|
$commands{'unmute'} = 'Enable reporting of a site in a channel. By default, sites are reported in all channels that the module is active in. Syntax: unmute <site> in <channel>';
|
||
|
} else {
|
||
|
$commands{''} = 'The RDF module monitors various websites.';
|
||
|
}
|
||
|
foreach my $site (keys(%{$self->{'sites'}})) {
|
||
|
if ($self->{'data'}->{$self->{'sites'}->{$site}}) {
|
||
|
$commands{$site} = "Reports the headlines listed in $self->{'data'}->{$self->{'sites'}->{$site}}->{'title'}";
|
||
|
|
||
|
# -- #mozilla was here --
|
||
|
# <Hixie> anyway, $self->{'data'}->{$self->{'sites'}->{$site}}->{'title'} is
|
||
|
# another nice piece of perl (embedded in a quoted string in this case)
|
||
|
# <moogle> yeah, that's a bit more familiar
|
||
|
# <jag> Oooh, nice one
|
||
|
# <jag> Reminds me of Java, a bit :-)
|
||
|
# <jag> Without all the casting about from Object to Hashtable
|
||
|
# <Hixie> all this, BTW, is from the RDF module (the one that mozbot uses to
|
||
|
# report changes in mozillazine and so on)
|
||
|
# <moogle> I still tend to comment these things a bit just for maintainability
|
||
|
# by others who might not wish to do mental gymnastics :)
|
||
|
# <Hixie> :-)
|
||
|
|
||
|
} else {
|
||
|
$commands{$site} = "Reports the headlines listed in $self->{'sites'}->{$site}";
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return \%commands;
|
||
|
}
|
||
|
|
||
|
sub Told {
|
||
|
my $self = shift;
|
||
|
my ($event, $message) = @_;
|
||
|
foreach my $site (keys(%{$self->{'sites'}})) {
|
||
|
if ($message =~ /^\s*(\Q$site\E)\s*$/si) {
|
||
|
$self->GetSite($event, $1, 'request');
|
||
|
return 0; # dealt with it...
|
||
|
}
|
||
|
}
|
||
|
if ($self->isAdmin($event)) {
|
||
|
if ($message =~ /^\s*mute\s+(\S+?)\s+in\s+(\S+?)\s*$/osi) {
|
||
|
my $site = $1 eq 'RDF' ? '' : $self->{'sites'}->{$1};
|
||
|
my $siteName = $site eq '' ? 'all sites' : $site;
|
||
|
if (defined($site)) {
|
||
|
$self->{'mutes'}->{$site} .= " $2";
|
||
|
$self->saveConfig();
|
||
|
$self->say($event, "$event->{'from'}: RDF notifications for $siteName muted in channel $2.");
|
||
|
} else {
|
||
|
# can't say this, other modules might recognise it: $self->say($event, "$event->{'from'}: I don't know about any '$1' site...");
|
||
|
}
|
||
|
} elsif ($message =~ /^\s*unmute\s+(\S+?)\s+in\s+(\S+?)\s*$/osi) {
|
||
|
my $site = $1 eq 'RDF' ? '' : $self->{'sites'}->{$1};
|
||
|
my $siteName = $site eq '' ? 'all sites' : $site;
|
||
|
if (defined($site)) {
|
||
|
my %mutedChannels = map { lc($_) => 1 } split(/ /o, $self->{'mutes'}->{$site});
|
||
|
delete($mutedChannels{lc($2)}); # get rid of any mentions of that channel
|
||
|
$self->{'mutes'}->{$site} = join(' ', keys(%mutedChannels));
|
||
|
$self->saveConfig();
|
||
|
$self->say($event, "$event->{'from'}: RDF notifications for $siteName resumed in channel $2.");
|
||
|
} else {
|
||
|
# can't say this, other modules might recognise it: $self->say($event, "$event->{'from'}: I don't know about any '$1' site...");
|
||
|
}
|
||
|
} else {
|
||
|
return $self->SUPER::Told(@_);
|
||
|
}
|
||
|
} else {
|
||
|
return $self->SUPER::Told(@_);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
sub GetSite {
|
||
|
my $self = shift;
|
||
|
my ($event, $site, $intent) = @_;
|
||
|
if (defined($self->{'sites'}->{$site})) {
|
||
|
my $uri = $self->{'sites'}->{$site};
|
||
|
$self->getURI($event, $uri, $intent);
|
||
|
} else {
|
||
|
# XXX
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub GotURI {
|
||
|
my $self = shift;
|
||
|
my ($event, $uri, $output, $intent) = @_;
|
||
|
|
||
|
$self->{'data'}->{$uri}->{'ready'} = defined($self->{'data'}->{$uri});
|
||
|
|
||
|
if ($output) {
|
||
|
|
||
|
# last update stamp
|
||
|
$self->{'data'}->{$uri}->{'last'} = time();
|
||
|
|
||
|
# this, of course, is a disaster waiting to happen.
|
||
|
# for example, we don't cope with comments.
|
||
|
# someone write a real XML version of this pleeeeease... XXX
|
||
|
|
||
|
# get the juicy stuff out
|
||
|
my $channelpart = "";
|
||
|
if ($output =~ /<channel>(.*)<\/channel>/osi) {
|
||
|
$channelpart = $1;
|
||
|
}
|
||
|
|
||
|
# remove any image related stuff
|
||
|
$output =~ s/<image>.*<\/image>//gosi;
|
||
|
|
||
|
# get the channel title
|
||
|
$self->{'data'}->{$uri}->{'title'} = $uri;
|
||
|
if ($channelpart =~ /<title>\s*(.+?)\s*<\/title>/osi) {
|
||
|
$self->{'data'}->{$uri}->{'title'} = $self->unescapeXML($1);
|
||
|
$self->{'data'}->{$uri}->{'title'} =~ s/: News for nerds, stuff that matters//gosi if $self->{'trimTitles'};
|
||
|
}
|
||
|
|
||
|
# get the channel website
|
||
|
$self->{'data'}->{$uri}->{'link'} = $uri;
|
||
|
if ($channelpart =~ /<link>\s*(.+?)\s*<\/link>/osi) {
|
||
|
$self->{'data'}->{$uri}->{'link'} = $self->unescapeXML($1);
|
||
|
}
|
||
|
|
||
|
# get all the items
|
||
|
while ($output =~ /<item>.*?<title>\s*(.+?)\s*<\/title>.*?<\/item>/osig) {
|
||
|
unless (($1 =~ /^last update/osi) or (defined($self->{'data'}->{$uri}->{'items'}->{$self->unescapeXML($1)}))) {
|
||
|
$self->{'data'}->{$uri}->{'items'}->{$self->unescapeXML($1)} = $self->{'data'}->{$uri}->{'last'};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$self->ReportDiffs($event, $uri, $intent);
|
||
|
if ($intent eq 'request') {
|
||
|
$self->ReportAll($event, $uri);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if ($intent eq 'request') {
|
||
|
$self->say($event, "$event->{'from'}: Dude, the file was empty! ($uri)");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
sub Scheduled {
|
||
|
my $self = shift;
|
||
|
my ($event, @data) = @_;
|
||
|
if ($data[0] eq 'rdf') {
|
||
|
my %sites = map { $_ => 1 } values(%{$self->{'sites'}});
|
||
|
foreach (keys(%sites)) {
|
||
|
$self->getURI($event, $_, 'update');
|
||
|
}
|
||
|
} else {
|
||
|
$self->SUPER::Scheduled($event, @data);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub ReportDiffs {
|
||
|
my $self = shift;
|
||
|
my ($event, $uri, $request) = @_;
|
||
|
return unless $self->{'data'}->{$uri}->{'ready'};
|
||
|
my $last = $self->{'data'}->{$uri}->{'last'};
|
||
|
my @output;
|
||
|
foreach (keys(%{$self->{'data'}->{$uri}->{'items'}})) {
|
||
|
push(@output, $_) if ($self->{'data'}->{$uri}->{'items'}->{$_} == $last);
|
||
|
}
|
||
|
if (@output) {
|
||
|
|
||
|
@output = $self->prettyPrint($self->{'preferredLineLength'},
|
||
|
"Just appeared in $self->{'data'}->{$uri}->{'title'} - $self->{'data'}->{$uri}->{'link'} : ",
|
||
|
'', ' -- ', @output);
|
||
|
|
||
|
my %mutedChannels = ();
|
||
|
if (defined($self->{'mutes'}->{$uri})) {
|
||
|
%mutedChannels = map { lc($_) => 1 } split(/\s+/os, $self->{'mutes'}->{$uri});
|
||
|
}
|
||
|
if (defined($self->{'mutes'}->{''})) {
|
||
|
%mutedChannels = (%mutedChannels, map { lc($_) => 1 } split(/\s+/os, $self->{'mutes'}->{''}));
|
||
|
}
|
||
|
if ($request eq 'request') {
|
||
|
$mutedChannels{$event->{'channel'}} = 1;
|
||
|
}
|
||
|
foreach (@{$self->{'channels'}}) {
|
||
|
unless ($mutedChannels{$_}) {
|
||
|
local $event->{'target'} = $_;
|
||
|
foreach (@output) {
|
||
|
$self->say($event, $_);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub ReportAll {
|
||
|
my $self = shift;
|
||
|
my ($event, $uri) = @_;
|
||
|
my @output;
|
||
|
foreach (keys(%{$self->{'data'}->{$uri}->{'items'}})) {
|
||
|
push(@output, $_);
|
||
|
}
|
||
|
|
||
|
@output = $self->prettyPrint($self->{'preferredLineLength'},
|
||
|
"Items in $self->{'data'}->{$uri}->{'title'} - $self->{'data'}->{$uri}->{'link'}: ",
|
||
|
"$event->{'from'}: ", ' -- ', @output);
|
||
|
|
||
|
if (@output > $self->{'maxInChannel'}) {
|
||
|
foreach (@output) {
|
||
|
$self->directSay($event, $_);
|
||
|
}
|
||
|
$self->channelSay($event, "$event->{'from'}: /msg'ed");
|
||
|
} else {
|
||
|
foreach (@output) {
|
||
|
$self->say($event, $_);
|
||
|
}
|
||
|
}
|
||
|
}
|