initial (and working?) version of history tracking plugin

This commit is contained in:
Brian S. Stephan 2021-05-05 08:03:56 -05:00
parent b3b8f832a2
commit e43807fb27
2 changed files with 143 additions and 0 deletions

1
history/__init__.py Normal file
View File

@ -0,0 +1 @@
"""Track IRC channel history and report on it for users."""

142
history/ircplugin.py Normal file
View File

@ -0,0 +1,142 @@
"""Monitor and playback IRC stuff."""
import logging
import irc.client
from ircbot.lib import Plugin, most_specific_message
logger = logging.getLogger(__name__)
class History(Plugin):
"""Watch the history of IRC channels and try to track what users may have missed."""
what_missed_regex = r'what did I miss\?$'
def start(self):
"""Set up the handlers."""
logger.debug("%s starting up", __name__)
self.connection.add_global_handler('pubmsg', self.handle_chatter, 50)
self.connection.add_global_handler('join', self.handle_join, 50)
self.connection.add_global_handler('part', self.handle_part, 50)
self.connection.add_global_handler('quit', self.handle_quit, 50)
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], self.what_missed_regex,
self.handle_what_missed, 60)
self.channel_history = {}
self.channel_participants = {}
self.channel_leave_points = {}
super(History, self).start()
def stop(self):
"""Tear down handlers."""
logger.debug("%s shutting down", __name__)
self.connection.remove_global_handler('pubmsg', self.handle_chatter)
self.connection.remove_global_handler('join', self.handle_join)
self.connection.remove_global_handler('part', self.handle_part)
self.connection.remove_global_handler('quit', self.handle_quit)
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_what_missed)
super(History, self).stop()
def handle_chatter(self, connection, event):
"""Track IRC chatter."""
what = event.arguments[0]
where = event.target
who = irc.client.NickMask(event.source).nick
logger.debug("tracking message for %s: (%s,%s)", where, who, what)
history = self.channel_history.setdefault(where, [])
history.append((who, what))
logger.debug("history for %s: %s", where, history)
# for when we maybe don't see a join, if they talked in the channel, add them to it
self._add_channel_participant(where, who)
def handle_join(self, connection, event):
"""Track who is entitled to see channel history."""
where = event.target
who = irc.client.NickMask(event.source).nick
logger.debug("%s joined %s", who, where)
self._add_channel_participant(where, who)
def handle_part(self, connection, event):
"""Note when people leave IRC channels."""
where = event.target
who = irc.client.NickMask(event.source).nick
logger.debug("%s left %s", who, where)
# if they parted the channel, they must have been in it, so note their point in history
self._add_channel_leave_point(where, who)
self._remove_channel_participant(where, who)
def handle_quit(self, connection, event):
"""Note when people leave IRC."""
who = irc.client.NickMask(event.source).nick
logger.debug("%s disconnected", who)
# find all channels the quitter was in, save their leave points
for channel in self.channel_participants.keys():
self._add_channel_leave_point(channel, who)
self._remove_channel_participant(channel, who)
def handle_what_missed(self, connection, event, match):
"""Tell the user what they missed."""
who = irc.client.NickMask(event.source).nick
if event.in_privmsg or event.addressed:
logger.debug("<%s> %s is asking for an update", who, most_specific_message(event))
if event.in_privmsg:
total_history = []
for channel in self.channel_leave_points.keys():
logger.debug("checking history slice for %s", channel)
total_history += self._missed_slice(channel, who)
logger.debug("total history so far: %s", total_history)
logger.debug("final missed history: %s", total_history)
self._send_history(who, total_history)
return 'NO MORE'
else:
where = event.target
history = self._missed_slice(where, who)
self._send_history(who, history)
return 'NO MORE'
def _send_history(self, who, history):
"""Reply to who with missed history."""
for line in history:
self.bot.privmsg(who, f"<{line[0]}> {line[1]}")
def _add_channel_leave_point(self, where, who):
"""Note that the given who left the channel at the current history point."""
leave_points = self.channel_leave_points.setdefault(where, {})
leave_points[who] = len(self.channel_history.setdefault(where, [])) - 1
logger.debug("leave points for %s: %s", where, leave_points)
def _add_channel_participant(self, where, who):
"""Add a who to the list of people who are/were in a channel."""
participants = self.channel_participants.setdefault(where, set())
participants.add(who)
logger.debug("participants for %s: %s", where, participants)
def _missed_slice(self, where, who):
"""Get the lines in where since who last left."""
leave_points = self.channel_leave_points.setdefault(where, {})
if leave_points.get(who) is not None:
leave_point = leave_points.get(who) + 1
history = self.channel_history.setdefault(where, [])
missed_history = history[leave_point:]
logger.debug("in %s, %s missed: %s", where, who, missed_history)
return missed_history
return []
def _remove_channel_participant(self, where, who):
"""Remove the specified who from the where channel's participants list."""
participants = self.channel_participants.setdefault(where, set())
participants.remove(who)
logger.debug("participants for %s: %s", where, participants)
plugin = History