You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.3 KiB

import random
from datetime import datetime, timedelta
from edmond.plugin import Plugin
from edmond.utils import proc
class SleepPlugin(Plugin):
"""Handle sleep state of the bot, snore a little bit."""
REQUIRED_CONFIGS = [
"commands",
"sleep_time",
"wakeup_time",
"snore",
"sleep_messages",
"wakeup_messages",
"snore_rate",
]
def __init__(self, bot):
super().__init__(bot)
def on_welcome(self, event):
self.set_runtime_value("awake", True)
def on_ping(self, event):
awake = self.get_runtime_value("awake")
in_sleep_hours = self.is_sleep_time(datetime.now())
if awake and in_sleep_hours:
self.fall_asleep()
elif not awake:
if not in_sleep_hours:
self.wake_up()
else:
# Maybe snore.
if proc(self.config["snore_rate"]):
for channel in self.bot.channels:
self.bot.say(channel, self.config["snore"])
def on_pubmsg(self, event):
if not self.should_handle_command(
event.arguments[0],
no_content=True,
exclude_conditions=["sleep"],
):
return False
# "sleep" command.
if self.command.ident == self.config["commands"][0]:
self.fall_asleep()
return True
# "wake up" command.
if self.command.ident == self.config["commands"][1]:
self.wake_up()
return True
return False
def fall_asleep(self):
if not self.get_runtime_value("awake"):
return
for channel in self.bot.channels:
self.bot.say(channel, random.choice(self.config["sleep_messages"]))
self.set_runtime_value("awake", False)
def wake_up(self):
if self.get_runtime_value("awake"):
return
self.set_runtime_value("awake", True)
for channel in self.bot.channels:
self.bot.say(
channel, random.choice(self.config["wakeup_messages"])
)
def is_sleep_time(self, now):
"""Return True if the bot should be sleeping by now.
The sleep range can span over 2 days (e.g. 23 to 7) or be contained in a
day (e.g. 0 to 8).
"""
sleep_time = self.config["sleep_time"]
wakeup_time = self.config["wakeup_time"]
current_hour = now.hour
# If we're before the sleep hour, check that we are not in the
# previous sleep range. Else just check today's range.
if current_hour < sleep_time:
ref_dt = now - timedelta(days=1)
else:
ref_dt = now
sleep_dt, wakeup_dt = self._get_sleep_range(
ref_dt, sleep_time, wakeup_time
)
return sleep_dt <= now < wakeup_dt
@staticmethod
def _get_sleep_range(now, sleep_time, wakeup_time):
"""Return the (start, end) datetime tuple using config values.
Properly accounts for a sleep range going around midnight.
"""
sleep_dt = now.replace(hour=sleep_time, minute=0, second=0)
wakeup_dt = now.replace(hour=wakeup_time, minute=0, second=0)
if wakeup_time < sleep_time:
wakeup_dt += timedelta(days=1)
return sleep_dt, wakeup_dt