Commit Diff


commit - /dev/null
commit + 06f09e349815cf018a2919a3f152cee136bb763c
blob - /dev/null
blob + ef03406c437f8341575b389e203d5fe70e999ea3 (mode 644)
--- /dev/null
+++ lib/Bot/BasicBot/Pluggable/Module/Wiki.pm
@@ -0,0 +1,268 @@
+package Bot::BasicBot::Pluggable::Module::Wiki;
+
+use warnings;
+use strict;
+use XML::RSS::Parser;
+use HTTP::Tiny;
+use Time::Piece;    # convert time string to epoch
+use Digest::MD5 qw(md5_hex);    # Store rss url as md5_hex
+use base qw(Bot::BasicBot::Pluggable::Module);
+
+our $VERSION = '0.02';
+
+
+sub help {
+	return "wiki [list]";
+}
+		
+sub init {
+    my $self = shift;
+	$self->{tick} = 0;
+	$self->{delay} = 60;
+	$self->{limit} = 5;
+	$self->{notify} = {
+		links=>{},
+		feeds=>{},
+	};
+    $self->config(
+        {
+            feeds                    => {},
+            user_delay               => 60,	# 5 min delay between checks
+#            user_init_headlines_seen => 1,
+#            user_debug               => 0,
+#            user_tmpdir              => File::Spec->tmpdir(),
+#            user_format              => 'RSS: %h <%u>'
+        }
+    );
+	#    $self->{feeds} = $self->get('feeds');
+}
+# Set feeds
+sub feeds {
+	my $self=shift;
+	my $feeds=shift;
+	for my $feed (keys %{$feeds}) {
+		$self->{feeds}->{$feed}={
+			   feed_id=>md5_hex($feed),
+			   channels=>$feeds->{$feed},
+		}
+	}
+}
+
+
+sub list_feeds {
+	my ($self,$channel) = @_;
+
+	my $reply;
+	for my $url (keys %{$self->{feeds}}) {
+		$reply .= "$url\n" ;
+		my $chan_str="";
+		for my $chan (@{$self->{feeds}->{$url}->{channels}}) {
+			$chan_str .= "$chan,";
+		}
+		chop($chan_str); #remove last coma
+		$reply .= "$chan_str\n";
+	}
+
+	$self->fetch_rss();
+	if ($reply) {
+		return $reply;
+	} else {
+		return 'No feeds to list';
+	}
+}
+
+sub parse_feed {
+	my $self = shift;
+	my $feed = shift;
+	my $feed_id = shift;
+	my $uriHash = shift;
+	my $rss = HTTP::Tiny->new->get($feed);
+	my $p = XML::RSS::Parser->new;
+	my $data = $p->parse_string($rss->{content});
+
+	if (not defined $data) {
+		print $p->errstr;
+		return 0; #failed to parse to return fail.
+	}
+	my $notify=$self->{notify};
+	my $dateFormat = qq|%a, %d %b %Y %T %Z|;
+	foreach my $i ( $data->query('//item') ) {
+		my $date = $i->query('pubDate');
+		my $tp = Time::Piece->strptime($date->text_content, $dateFormat);
+		my $epoch=$tp->epoch;
+		my $title = $i->query('title');
+		my $contributor = $i->query('dc:contributor');
+		my $link = $i->query('link');
+		my $link_id = md5_hex($link->text_content);
+		if (not exists $uriHash->{$link_id} or ($epoch > $uriHash->{$link_id})) {
+			$uriHash->{$link_id} = $epoch;
+			$notify->{links}->{$link_id}->{message} = $contributor->text_content." updated ".$title->text_content." on ".$date->text_content
+				."\n  ".$link->text_content."\n";
+			push (@{$notify->{feeds}->{$feed_id}},$link_id);
+		}
+	}
+}
+
+
+#	$self->{notify}->{
+#					links=>{
+#						$link_id=>{
+#								message=>
+#								channels=>{}
+#								}
+#					}
+#					feeds=>{
+#						$feed_id => [$link_ids]
+#					}
+#
+
+
+sub tick {
+	my $self=shift;
+	$self->{tick} += 1;
+	my $notify=$self->{notify};
+
+	# See if there are any nessages to send out.
+	# Limit notifications to $self->{limit}
+	my $count=0;
+	for my $link_id (keys %{$notify->{links}}) {
+		my $msg=$notify->{links}->{$link_id}->{message};
+		next if not length($msg);
+		for my $chan (keys %{$notify->{links}->{$link_id}->{channels}}) {
+			$self->tell( $chan, $msg);
+			$count++;
+		}
+		delete $notify->{links}->{$link_id};
+		return if ($count > $self->{limit});
+	}
+
+	# Increase the tick counter and return unless its time to check for updats
+	return if ($self->{tick} < $self->{delay});
+	$self->{tick} = 0;
+
+	$self->fetch_rss();
+}
+
+sub fetch_rss {
+	my $self = shift;
+	my $notify=$self->{notify};
+
+	# Check for updates to the feed 
+	my $uriHash = $self->get('uriHash') || {};
+	for my $feed (keys %{$self->{feeds}}) {
+		my $feed_id=$self->{feeds}->{$feed}->{feed_id};
+		# parse the feed
+		$self->parse_feed($feed,$feed_id,$uriHash);
+		# find all the link_ids parsed for this feed
+		for my $link_id (@{$notify->{feeds}->{$feed_id}}) {
+			# Add the list of channels for each feed to the notify channel list for each link_id
+			for my $chan (@{$self->{feeds}->{$feed}->{channels}}) {
+			$notify->{links}->{$link_id}->{channels}->{$chan}=1;
+			}
+		}
+	}
+
+	$self->set('uriHash', $uriHash);
+}
+
+
+sub told {
+	my ($self,$message) = @_;
+	# Only act if we are addressed
+	if ($message->{address}) {
+		my $body    = $message->{body};
+		my $channel = $message->{channel};
+
+		if ($channel eq 'msg') {
+			$channel = $message->{who};
+		}
+
+		my @cmds = split(' ',$body);
+		if ($cmds[0] eq '!wiki' or ($channel eq $message->{who} and $cmds[0] eq 'wiki')) {
+			my %actions = (
+					#				add    => sub { return $self->add_feed( $channel, @_ ) },
+				list   => sub { return $self->list_feeds($channel); },
+				#				remove => sub { return $self->remove_feed( $channel, @_ ) },
+			);
+			if (!defined($actions{$cmds[1]})) {
+				return $self->help();
+			}
+			my $reply = $actions{$cmds[1]}->(@cmds[2,-1]) ;
+			return $reply;
+		}
+	}
+}
+
+
+
+
+1; # End of Bot::BasicBot::Pluggable::Module::Wiki
+
+__END__
+
+=head1 NAME
+
+Bot::BasicBot::Pluggable::Module::Wiki - Update parser for pmWiki RSS feed
+
+=head1 VERSION
+
+Version 0.02
+
+=head1 SYNOPSIS
+
+    wiki list
+
+=head1 DESCRIPTION
+
+This module enables your bot to monitor various RSS feeds for new
+posts or updates to pmWiki pages. Currently configuration is done
+through variables you pass to the module from your bot.  Future versions
+will have the ability to add RSS feeds to monitor on a per channel bases.
+
+=head1 VARIABLES
+
+=head2 feeds
+
+A hash reference of rss feeds urls to monitor for changes containing an array of irc channels to publish updates to.
+Currently passed in from your bot's main loop like this:
+
+$bot->{wiki}->feeds = {
+	'https://wiki.ircnow.org/pmwiki.php?n=Site.AllRecentChanges&action=rss' => ['#planetofnix','#planetofnix-team'],
+}
+
+Future versions will have bot commands to add and modify the list.
+
+=head1 LIMITATIONS
+
+ This is still a work in progress. 
+
+=head1 TODO
+
+ This is still a work in progress. It's a working proof of concept with room for improvement.
+
+=head1 AUTHOR
+
+Izzy Blacklock, C<< <izzyb at planetofnix.com> >>
+
+=head1 BUGS
+
+Please report any bugs or feature requests to C<izzyb at planetofnix.com>.
+
+=head1 SUPPORT
+
+You can find documentation for this module with the perldoc command.
+
+    perldoc Bot::BasicBot::Pluggable::Module::Wiki
+
+
+=head1 SEE ALSO
+
+L<Bot::BasicBot::Pluggable>
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2023 Izzy Blacklock, all rights reserved.
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+