2018-01-19 18:04:38 -05:00
|
|
|
#!/usr/bin/env python3
|
2017-11-22 19:26:40 -05:00
|
|
|
"""
|
2018-01-19 18:04:38 -05:00
|
|
|
Reminds of things.
|
2017-11-22 19:26:40 -05:00
|
|
|
"""
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import time
|
2018-03-02 21:25:50 -05:00
|
|
|
import sqlite3
|
2017-11-22 19:26:40 -05:00
|
|
|
import threading
|
|
|
|
import collections
|
2018-03-02 21:25:50 -05:00
|
|
|
from datetime import datetime
|
2018-01-19 18:04:38 -05:00
|
|
|
|
|
|
|
import pytz
|
|
|
|
|
2017-11-22 19:26:40 -05:00
|
|
|
from module import commands, example, NOLIMIT
|
|
|
|
from tools.time import get_timezone, format_time
|
|
|
|
|
2018-03-02 21:25:50 -05:00
|
|
|
def init_database(bot):
|
|
|
|
"""
|
|
|
|
Initializes the 'remind' table in the bot's database. Does nothing if
|
|
|
|
the table already exists.
|
|
|
|
"""
|
|
|
|
con = bot.db.connect()
|
|
|
|
cur = con.cursor()
|
|
|
|
try:
|
|
|
|
cur.execute("SELECT * FROM remind").fetchone()
|
|
|
|
except sqlite3.OperationalError:
|
|
|
|
cur.execute("CREATE TABLE remind("
|
|
|
|
"unixtime INT DEFAULT (STRFTIME('%s', 'now')),"
|
|
|
|
"channel STRING,"
|
|
|
|
"nick STRING,"
|
|
|
|
"message STRING)")
|
|
|
|
con.commit()
|
|
|
|
con.close()
|
|
|
|
|
|
|
|
|
|
|
|
def load_database(bot):
|
|
|
|
"""
|
|
|
|
Loads all entries from the 'remind' table in the bot's database and
|
|
|
|
stores them in memory
|
|
|
|
"""
|
2017-11-22 19:26:40 -05:00
|
|
|
data = {}
|
2018-03-02 21:25:50 -05:00
|
|
|
con = bot.db.connect()
|
|
|
|
cur = con.cursor()
|
|
|
|
reminds = cur.execute("SELECT * FROM remind").fetchall()
|
|
|
|
con.close()
|
|
|
|
|
|
|
|
for remind in reminds:
|
|
|
|
unixtime, channel, nick, message = remind
|
|
|
|
reminder = (channel, nick, message)
|
|
|
|
try:
|
|
|
|
data[unixtime].append(reminder)
|
|
|
|
except KeyError:
|
|
|
|
data[unixtime] = [reminder]
|
2017-11-22 19:26:40 -05:00
|
|
|
return data
|
|
|
|
|
|
|
|
|
2018-03-02 21:25:50 -05:00
|
|
|
def insert_reminder(bot, unixtime, reminder):
|
|
|
|
"""
|
|
|
|
Inserts a new reminder into the 'remind' table in the bot's database.
|
|
|
|
reminder - a tuple containing (channel, nick, message)
|
|
|
|
"""
|
|
|
|
con = bot.db.connect()
|
|
|
|
cur = con.cursor()
|
|
|
|
cur.execute("INSERT INTO remind (unixtime, channel, nick, message) "
|
|
|
|
"VALUES(?,?,?,?)", (unixtime,) + reminder)
|
|
|
|
con.commit()
|
|
|
|
con.close()
|
|
|
|
|
|
|
|
|
|
|
|
def delete_reminder(bot, unixtime):
|
|
|
|
"""
|
|
|
|
Deletes a reminder from the 'remind' table in the bot's database, using
|
|
|
|
unixtime as the key.
|
|
|
|
"""
|
|
|
|
con = bot.db.connect()
|
|
|
|
cur = con.cursor()
|
|
|
|
cur.execute("DELETE FROM remind WHERE unixtime = ?", (unixtime,))
|
|
|
|
con.commit()
|
|
|
|
con.close()
|
2017-11-22 19:26:40 -05:00
|
|
|
|
|
|
|
|
|
|
|
def setup(bot):
|
2018-03-02 21:25:50 -05:00
|
|
|
init_database(bot)
|
|
|
|
bot.rdb = load_database(bot)
|
2017-11-22 19:26:40 -05:00
|
|
|
|
|
|
|
def monitor(bot):
|
2018-03-02 21:25:50 -05:00
|
|
|
time.sleep(10)
|
2017-11-22 19:26:40 -05:00
|
|
|
while True:
|
|
|
|
now = int(time.time())
|
|
|
|
unixtimes = [int(key) for key in bot.rdb]
|
|
|
|
oldtimes = [t for t in unixtimes if t <= now]
|
|
|
|
if oldtimes:
|
|
|
|
for oldtime in oldtimes:
|
|
|
|
for (channel, nick, message) in bot.rdb[oldtime]:
|
|
|
|
if message:
|
2018-01-18 23:43:27 -05:00
|
|
|
bot.say(nick + ': ' + message, channel)
|
2017-11-22 19:26:40 -05:00
|
|
|
else:
|
2018-01-18 23:43:27 -05:00
|
|
|
bot.say(nick + '!', channel)
|
2017-11-22 19:26:40 -05:00
|
|
|
del bot.rdb[oldtime]
|
2018-03-02 21:25:50 -05:00
|
|
|
delete_reminder(bot, oldtime)
|
2017-11-22 19:26:40 -05:00
|
|
|
time.sleep(2.5)
|
|
|
|
|
|
|
|
targs = (bot,)
|
|
|
|
t = threading.Thread(target=monitor, args=targs)
|
|
|
|
t.start()
|
|
|
|
|
|
|
|
scaling = collections.OrderedDict([
|
|
|
|
('years', 365.25 * 24 * 3600),
|
|
|
|
('year', 365.25 * 24 * 3600),
|
|
|
|
('yrs', 365.25 * 24 * 3600),
|
|
|
|
('y', 365.25 * 24 * 3600),
|
|
|
|
|
|
|
|
('months', 29.53059 * 24 * 3600),
|
|
|
|
('month', 29.53059 * 24 * 3600),
|
|
|
|
('mo', 29.53059 * 24 * 3600),
|
|
|
|
|
|
|
|
('weeks', 7 * 24 * 3600),
|
|
|
|
('week', 7 * 24 * 3600),
|
|
|
|
('wks', 7 * 24 * 3600),
|
|
|
|
('wk', 7 * 24 * 3600),
|
|
|
|
('w', 7 * 24 * 3600),
|
|
|
|
|
|
|
|
('days', 24 * 3600),
|
|
|
|
('day', 24 * 3600),
|
|
|
|
('d', 24 * 3600),
|
|
|
|
|
|
|
|
('hours', 3600),
|
|
|
|
('hour', 3600),
|
|
|
|
('hrs', 3600),
|
|
|
|
('hr', 3600),
|
|
|
|
('h', 3600),
|
|
|
|
|
|
|
|
('minutes', 60),
|
|
|
|
('minute', 60),
|
|
|
|
('mins', 60),
|
|
|
|
('min', 60),
|
|
|
|
('m', 60),
|
|
|
|
|
|
|
|
('seconds', 1),
|
|
|
|
('second', 1),
|
|
|
|
('secs', 1),
|
|
|
|
('sec', 1),
|
|
|
|
('s', 1),
|
|
|
|
])
|
|
|
|
|
|
|
|
periods = '|'.join(scaling.keys())
|
|
|
|
|
|
|
|
|
|
|
|
@commands('remind')
|
|
|
|
@example('.remind 3h45m Go to class')
|
|
|
|
def remind(bot, trigger):
|
|
|
|
"""Gives you a reminder in the given amount of time."""
|
|
|
|
if not trigger.group(2):
|
|
|
|
bot.say("Missing arguments for reminder command.")
|
|
|
|
return NOLIMIT
|
|
|
|
if trigger.group(3) and not trigger.group(4):
|
|
|
|
bot.say("No message given for reminder.")
|
|
|
|
return NOLIMIT
|
|
|
|
duration = 0
|
|
|
|
message = filter(None, re.split('(\d+(?:\.\d+)? ?(?:(?i)' + periods + ')) ?',
|
|
|
|
trigger.group(2))[1:])
|
|
|
|
reminder = ''
|
|
|
|
stop = False
|
|
|
|
for piece in message:
|
|
|
|
grp = re.match('(\d+(?:\.\d+)?) ?(.*) ?', piece)
|
|
|
|
if grp and not stop:
|
|
|
|
length = float(grp.group(1))
|
|
|
|
factor = scaling.get(grp.group(2).lower(), 60)
|
|
|
|
duration += length * factor
|
|
|
|
else:
|
|
|
|
reminder = reminder + piece
|
|
|
|
stop = True
|
|
|
|
if duration == 0:
|
|
|
|
return bot.reply("Sorry, didn't understand the input.")
|
|
|
|
|
|
|
|
if duration % 1:
|
|
|
|
duration = int(duration) + 1
|
|
|
|
else:
|
|
|
|
duration = int(duration)
|
|
|
|
timezone = get_timezone(
|
|
|
|
bot.db, bot.config, None, trigger.nick, trigger.sender)
|
|
|
|
create_reminder(bot, trigger, duration, reminder, timezone)
|
|
|
|
|
|
|
|
|
|
|
|
@commands('at')
|
|
|
|
@example('.at 13:47 Do your homework!')
|
|
|
|
def at(bot, trigger):
|
|
|
|
"""
|
|
|
|
Gives you a reminder at the given time. Takes hh:mm:ssTimezone
|
|
|
|
message. Timezone is any timezone Sopel takes elsewhere; the best choices
|
|
|
|
are those from the tzdb; a list of valid options is available at
|
|
|
|
http://sopel.chat/tz . The seconds and timezone are optional.
|
|
|
|
"""
|
|
|
|
if not trigger.group(2):
|
|
|
|
bot.say("No arguments given for reminder command.")
|
|
|
|
return NOLIMIT
|
|
|
|
if trigger.group(3) and not trigger.group(4):
|
|
|
|
bot.say("No message given for reminder.")
|
|
|
|
return NOLIMIT
|
|
|
|
regex = re.compile(r'(\d+):(\d+)(?::(\d+))?([^\s\d]+)? (.*)')
|
|
|
|
match = regex.match(trigger.group(2))
|
|
|
|
if not match:
|
|
|
|
bot.reply("Sorry, but I didn't understand your input.")
|
|
|
|
return NOLIMIT
|
|
|
|
hour, minute, second, tz, message = match.groups()
|
|
|
|
if not second:
|
|
|
|
second = '0'
|
|
|
|
|
|
|
|
if pytz:
|
|
|
|
timezone = get_timezone(bot.db, bot.config, tz,
|
|
|
|
trigger.nick, trigger.sender)
|
|
|
|
if not timezone:
|
|
|
|
timezone = 'UTC'
|
|
|
|
now = datetime.now(pytz.timezone(timezone))
|
|
|
|
at_time = datetime(now.year, now.month, now.day,
|
|
|
|
int(hour), int(minute), int(second),
|
|
|
|
tzinfo=now.tzinfo)
|
|
|
|
timediff = at_time - now
|
|
|
|
else:
|
|
|
|
if tz and tz.upper() != 'UTC':
|
|
|
|
bot.reply("I don't have timzeone support installed.")
|
|
|
|
return NOLIMIT
|
|
|
|
now = datetime.now()
|
|
|
|
at_time = datetime(now.year, now.month, now.day,
|
|
|
|
int(hour), int(minute), int(second))
|
|
|
|
timediff = at_time - now
|
|
|
|
|
|
|
|
duration = timediff.seconds
|
|
|
|
|
|
|
|
if duration < 0:
|
|
|
|
duration += 86400
|
|
|
|
create_reminder(bot, trigger, duration, message, 'UTC')
|
|
|
|
|
|
|
|
|
|
|
|
def create_reminder(bot, trigger, duration, message, tz):
|
|
|
|
t = int(time.time()) + duration
|
|
|
|
reminder = (trigger.sender, trigger.nick, message)
|
|
|
|
try:
|
|
|
|
bot.rdb[t].append(reminder)
|
|
|
|
except KeyError:
|
|
|
|
bot.rdb[t] = [reminder]
|
|
|
|
|
2018-03-02 21:25:50 -05:00
|
|
|
insert_reminder(bot, t, reminder)
|
2017-11-22 19:26:40 -05:00
|
|
|
|
|
|
|
if duration >= 60:
|
|
|
|
remind_at = datetime.utcfromtimestamp(t)
|
|
|
|
timef = format_time(bot.db, bot.config, tz, trigger.nick,
|
|
|
|
trigger.sender, remind_at)
|
|
|
|
|
|
|
|
bot.reply('Okay, will remind at %s' % timef)
|
|
|
|
else:
|
|
|
|
bot.reply('Okay, will remind in %s secs' % duration)
|