From 1e8607f616b72699248478a173582a1e793402f6 Mon Sep 17 00:00:00 2001 From: dave Date: Sat, 11 Oct 2014 23:47:35 -0700 Subject: [PATCH] Added remind module --- data/config/Remind.yml | 2 + pyircbot/modules/Remind.py | 263 +++++++++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 data/config/Remind.yml create mode 100644 pyircbot/modules/Remind.py diff --git a/data/config/Remind.yml b/data/config/Remind.yml new file mode 100644 index 0000000..4e8f421 --- /dev/null +++ b/data/config/Remind.yml @@ -0,0 +1,2 @@ +mytimezone: US/Pacific +precision: 5 \ No newline at end of file diff --git a/pyircbot/modules/Remind.py b/pyircbot/modules/Remind.py new file mode 100644 index 0000000..bb31c3d --- /dev/null +++ b/pyircbot/modules/Remind.py @@ -0,0 +1,263 @@ +""" +.. module:: Remind + :synopsis: A module to support reminders + +.. moduleauthor:: Dave Pedu + +""" + +from modulebase import ModuleBase,ModuleHook +from datetime import datetime,timedelta +from threading import Thread +from time import sleep +import re +import pytz + +class Remind(ModuleBase): + def __init__(self, bot, moduleName): + ModuleBase.__init__(self, bot, moduleName); + + self.db = None + serviceProviders = self.bot.getmodulesbyservice("sqlite") + if len(serviceProviders)==0: + self.log.error("Remind: Could not find a valid sqlite service provider") + else: + self.log.info("Remind: Selecting sqlite service provider: %s" % serviceProviders[0]) + self.db = serviceProviders[0].opendb("remind.db") + + if not self.db.tableExists("reminders"): + self.log.info("Remind: Creating table: reminders") + c = self.db.query("""CREATE TABLE IF NOT EXISTS `reminders` ( + `id` INTEGER PRIMARY KEY, + `sender` varchar(64), + `senderch` varchar(64), + `when` timestamp, + `message` varchar(2048) + ) ;""") + c.close() + + self.hooks=[ModuleHook("PRIVMSG", self.remindin),ModuleHook("PRIVMSG", self.remindat)] + + self.disabled = False + + # Start monitor thread + self.t = Thread(target=self.monitor_thread) + self.t.daemon=True + self.t.start() + + + def monitor_thread(self): + while True: + sleep(self.config["precision"]) + if self.disabled: + break + self.monitor() + + def monitor(self): + remindPeople = self.db.query("SELECT * FROM `reminders` WHERE `when` < ?", (datetime.now(),)) + reminders = remindPeople.fetchall() + remindPeople.close() + + byrecip = {} + + for reminder in reminders: + if not reminder["sender"] in byrecip: + byrecip[reminder["sender"]]=[] + + byrecip[reminder["sender"]].append(reminder) + + reminders_bych = {} + + for recip in byrecip: + reminders_pm = [] + + for reminder in byrecip[recip]: + if reminder["senderch"]=="": + reminders_pm.append(reminder) + else: + if not reminder["senderch"] in reminders_bych: + reminders_bych[reminder["senderch"]] = [] + reminders_bych[reminder["senderch"]].append(reminder) + self.sendReminders(reminders_pm, recip, recip) + + for channel in reminders_bych: + channelpms_bysender = {} + + for chreminder in reminders_bych[channel]: + if not chreminder["sender"] in channelpms_bysender: + channelpms_bysender[chreminder["sender"]]=[] + channelpms_bysender[chreminder["sender"]].append(chreminder) + + for recip in channelpms_bysender: + self.sendReminders(channelpms_bysender[recip], channel, recip) + + # Delete now that it's sent + for item in reminders: + self.db.query("DELETE FROM `reminders` WHERE `id`=?", (item["id"],)).close() + + def sendReminders(self, reminders, target, nick): + " Send a set of reminders of the same recipient, to them. Collapse down into one message." + reminder_str = [] + for reminder in reminders: + reminder_str.append(reminder["message"]) + reminder_str = ", ".join(reminder_str) + if len(reminder_str)>0: + self.bot.act_PRIVMSG(target, "%s: Reminder: %s" % (nick, reminder_str)) + + def ondisable(self): + self.disabled = True + + def remindat(self, args, prefix, trailing): + prefixObj = self.bot.decodePrefix(prefix) + + replyTo = prefixObj.nick if not "#" in args[0] else args[0] + + # Lots of code borrowed from https://github.com/embolalia/willie/blob/master/willie/modules/remind.py + cmd = self.bot.messageHasCommand(".at", trailing, True) + if cmd: + regex = re.compile(r'(\d+):(\d+)(?::(\d+))?([^\s\d]+)? (.*)') + match = regex.match(cmd.args_str) + + try: + hour, minute, second, tz, message = match.groups() + message = message.strip() + + assert not message == "" + + hour = int(hour) + minute = int(minute) + if not second == None: + second = int(second) + + except: + self.bot.act_PRIVMSG(replyTo, "%s: .at - Remind at a time. Example: .at 20:45EST Do your homework!", prefixObj.nick) + return + + now = datetime.now() + + remindAt = datetime.now().replace(hour=hour).replace(minute=minute).replace(microsecond=0) + + if second == None: + remindAt = remindAt.replace(second=0) + else: + remindAt = remindAt.replace(second=second) + + # if there was timezone, adjust for it + if not tz == None: + try: + theirzone = pytz.timezone(Remind.translateZoneStr(tz)) + except: + self.bot.act_PRIVMSG(replyTo, "%s: I don't recognize the timezone '%s'." % (prefixObj.nick, tz)) + return + theirtime = theirzone.localize(remindAt, is_dst=Remind.is_dst(theirzone)) + remindAt = theirtime.astimezone(pytz.timezone(self.config["mytimezone"])).replace(tzinfo=None) + + # Advance it a day if the time would have been earlier today + while remindAt