aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/holidays/holidayreact.py
diff options
context:
space:
mode:
authorGravatar Thurisatic <[email protected]>2023-01-16 01:21:06 -0500
committerGravatar Thurisatic <[email protected]>2023-01-16 01:21:06 -0500
commit8e8750601fe5b41c773cbc51838bec9b5638074c (patch)
treea7e2806ebeaa85f433781231a4d6b84e54d5d3c0 /bot/exts/holidays/holidayreact.py
parentDe-Halloween-ify reaction Cog: move file, rename internals (diff)
Add non-Christmas holiday reaction capabilities
Triggers for reactions are moved from a dict to to a 2-deep NamedTuple. This is cleaner for multiple reactions, and allows for additional parameters, such as months. Message case checking is altered from `.lower` to `re.IGNORECASE`. Not only does the regex flag short circuit, it doesn't modify the string in question
Diffstat (limited to 'bot/exts/holidays/holidayreact.py')
-rw-r--r--bot/exts/holidays/holidayreact.py107
1 files changed, 89 insertions, 18 deletions
diff --git a/bot/exts/holidays/holidayreact.py b/bot/exts/holidays/holidayreact.py
index f0905f03..535e22ec 100644
--- a/bot/exts/holidays/holidayreact.py
+++ b/bot/exts/holidays/holidayreact.py
@@ -1,25 +1,80 @@
import logging
+import random
import re
+from typing import NamedTuple
import discord
from discord.ext.commands import Cog
from bot.bot import Bot
from bot.constants import Month
+from bot.utils import resolve_current_month
from bot.utils.decorators import in_month
log = logging.getLogger(__name__)
-SPOOKY_TRIGGERS = {
- "spooky": (r"\bspo{2,}[k|p][i|y](er|est)?\b", "\U0001F47B"),
- "skeleton": (r"\bskeleton\b", "\U0001F480"),
- "doot": (r"\bdo{2,}t\b", "\U0001F480"),
- "pumpkin": (r"\bpumpkin\b", "\U0001F383"),
- "halloween": (r"\bhalloween\b", "\U0001F383"),
- "jack-o-lantern": (r"\bjack-o-lantern\b", "\U0001F383"),
- "danger": (r"\bdanger\b", "\U00002620"),
- "bat": (r"\bbat((wo)?m[ae]n|persons?|people|s)?\b", "\U0001F987"),
-}
+
+class Trigger(NamedTuple):
+ """Representation of regex trigger and corresponding reactions."""
+
+ regex: str
+ reaction: list[str]
+
+
+class Holiday(NamedTuple):
+ """Representation of reaction holidays."""
+
+ months: list[Month]
+ triggers: dict[str, Trigger]
+
+
+Valentines = Holiday([Month.FEBRUARY], {
+ "heart": Trigger(r"\blove|heart\b", ["\u2764\uFE0F"]),
+ }
+)
+Easter = Holiday([Month.APRIL], {
+ "bunny": Trigger(r"\beaster|bunny|rabbit\b", ["\U0001F430", "\U0001F407"]),
+ "egg": Trigger(r"\begg\b", ["\U0001F95A"]),
+ }
+)
+EarthDay = Holiday([Month.FEBRUARY], {
+ "earth": Trigger(r"\bearth|planet\b", ["\U0001F30E", "\U0001F30D", "\U0001F30F",]),
+ }
+)
+Pride = Holiday([Month.JUNE], {
+ "pride": Trigger(r"\bpride\b", ["\U0001F3F3\uFE0F\u200D\U0001F308"]),
+ }
+)
+Halloween = Holiday([Month.OCTOBER], {
+ "spooky": Trigger(r"\bspo{2,}[k|p][i|y](er|est)?\b", ["\U0001F47B"]),
+ "skeleton": Trigger(r"\bskeleton\b", ["\U0001F480"]),
+ "doot": Trigger(r"\bdo{2,}t\b", ["\U0001F480"]),
+ "pumpkin": Trigger(r"\bpumpkin\b", ["\U0001F383"]),
+ "halloween": Trigger(r"\bhalloween\b", ["\U0001F383"]),
+ "jack-o-lantern": Trigger(r"\bjack-o-lantern\b", ["\U0001F383"]),
+ "danger": Trigger(r"\bdanger\b", ["\U00002620"]),
+ "bat": Trigger(r"\bbat((wo)?m[ae]n|persons?|people|s)?\b", ["\U0001F987"]),
+ }
+)
+Hanukkah = Holiday([Month.NOVEMBER, Month.DECEMBER], {
+ "menorah": Trigger(r"\bc?haukkah|menorah\b", ["\U0001F54E"]),
+ }
+)
+Christmas = Holiday([Month.DECEMBER], {
+ "christmas tree": Trigger(r"\b(christ|x)mas|tree\b", ["\U0001F384"]),
+ "snowflake": Trigger(r"\b(snow ?)?flake(?! ?8)\b", ["\u2744\uFE0F"]),
+ "santa": Trigger(r"\bsanta\b", ["\U0001F385"]),
+ "snowman": Trigger(r"\bsnow(man|angel)\b", ["\u2603\uFE0F", "\u26C4"]),
+ "reindeer": Trigger(r"\breindeer|caribou|buck|stag\b", ["\U0001F98C"]),
+ }
+)
+HOLIDAYS_TO_REACT = [
+ Valentines, Easter, EarthDay, Pride, Halloween, Hanukkah, Christmas
+]
+# Type (or order) doesn't matter here - set is for de-duplication
+MONTHS_TO_REACT = set(
+ month for holiday in HOLIDAYS_TO_REACT for month in holiday.months
+)
class HolidayReact(Cog):
@@ -28,20 +83,36 @@ class HolidayReact(Cog):
def __init__(self, bot: Bot):
self.bot = bot
- @in_month(Month.OCTOBER)
+ @in_month(*MONTHS_TO_REACT)
@Cog.listener()
async def on_message(self, message: discord.Message) -> None:
"""Triggered when the bot sees a message in a holiday month."""
- for name, trigger in SPOOKY_TRIGGERS.items():
- trigger_test = re.search(trigger[0], message.content.lower())
+ # Check message for bot replies and/or command invocations
+ # Short circuit if they're found, logging is handled in _short_circuit_check
+ if await self._short_circuit_check(message):
+ return
+
+ for holiday in HOLIDAYS_TO_REACT:
+ await self._check_message(message, holiday)
+
+ async def _check_message(self, message: discord.Message, holiday: Holiday) -> None:
+ """
+ Checks if message is reactable.
+
+ First checks if month is valid (else return). Then attempts to
+ match regex triggers to message. Those that succeed result in
+ reactions applied to the message.
+ """
+ if resolve_current_month() not in holiday.months:
+ return
+
+ for name, trigger in holiday.triggers.items():
+ trigger_test = re.search(trigger.regex, message.content, flags=re.IGNORECASE)
if trigger_test:
- # Check message for bot replies and/or command invocations
- # Short circuit if they're found, logging is handled in _short_circuit_check
if await self._short_circuit_check(message):
return
- else:
- await message.add_reaction(trigger[1])
- log.info(f"Added {name!r} reaction to message ID: {message.id}")
+ await message.add_reaction(random.choice(trigger.reaction))
+ log.info(f"Added {name!r} reaction to message ID: {message.id}")
async def _short_circuit_check(self, message: discord.Message) -> bool:
"""