aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/seasons/evergreen/fun.py57
-rw-r--r--bot/utils/__init__.py56
2 files changed, 109 insertions, 4 deletions
diff --git a/bot/seasons/evergreen/fun.py b/bot/seasons/evergreen/fun.py
index ce3484f7..87077f36 100644
--- a/bot/seasons/evergreen/fun.py
+++ b/bot/seasons/evergreen/fun.py
@@ -2,20 +2,34 @@ import logging
import random
from discord.ext import commands
+from discord.ext.commands import Bot, Cog, Context, MessageConverter
+from bot import utils
from bot.constants import Emojis
log = logging.getLogger(__name__)
+UWU_WORDS = {
+ "fi": "fwi",
+ "l": "w",
+ "r": "w",
+ "th": "d",
+ "thing": "fing",
+ "tho": "fo",
+ "you're": "yuw'we",
+ "your": "yur",
+ "you": "yuw",
+}
-class Fun(commands.Cog):
+
+class Fun(Cog):
"""A collection of general commands for fun."""
- def __init__(self, bot):
+ def __init__(self, bot: Bot) -> None:
self.bot = bot
@commands.command()
- async def roll(self, ctx, num_rolls: int = 1):
+ async def roll(self, ctx: Context, num_rolls: int = 1) -> None:
"""Outputs a number of random dice emotes (up to 6)."""
output = ""
if num_rolls > 6:
@@ -27,8 +41,43 @@ class Fun(commands.Cog):
output += getattr(Emojis, terning, '')
await ctx.send(output)
+ @commands.command(name="uwu", aliases=("uwuwize", "uwuify",))
+ async def uwu_command(self, ctx: Context, *, text: str) -> None:
+ """Converts a given `text` into it's uwu equivalent."""
+ text = await Fun.get_discord_message(ctx, text)
+ converted = utils.replace_many(text, UWU_WORDS, ignore_case=True, match_case=True)
+ await ctx.send(f">>> {converted}")
+
+ @commands.command(name="randomcase", aliases=("rcase", "randomcaps", "rcaps",))
+ async def randomcase_command(self, ctx: Context, *, text: str) -> None:
+ """Randomly converts the casing of a given `text`."""
+ text = await Fun.get_discord_message(ctx, text)
+ converted = (
+ char.upper() if round(random.random()) else char.lower() for char in text
+ )
+ await ctx.send(f">>> {''.join(converted)}")
+
+ @staticmethod
+ async def get_discord_message(ctx: Context, text: str) -> str:
+ """
+ Attempts to convert a given `text` to a discord Message object, then return the contents.
+
+ Useful if the user enters a link or an id to a valid Discord message, because the contents
+ of the message get returned.
+
+ Returns `text` if the conversion fails.
+ """
+ try:
+ message = await MessageConverter().convert(ctx, text)
+ except commands.BadArgument:
+ log.debug(f"Input '{text:.20}...' is not a valid Discord Message")
+ else:
+ text = message.content
+ finally:
+ return text
+
-def setup(bot):
+def setup(bot) -> None:
"""Fun Cog load."""
bot.add_cog(Fun(bot))
log.info("Fun cog loaded")
diff --git a/bot/utils/__init__.py b/bot/utils/__init__.py
index 15c4b5db..3249a9cf 100644
--- a/bot/utils/__init__.py
+++ b/bot/utils/__init__.py
@@ -1,4 +1,6 @@
import asyncio
+import re
+import string
from typing import List
import discord
@@ -71,3 +73,57 @@ async def disambiguate(
return entries[index - 1]
except IndexError:
raise BadArgument('Invalid choice.')
+
+
+def replace_many(
+ sentence: str, replacements: dict, *, ignore_case: bool = False, match_case: bool = False
+) -> str:
+ """
+ Replaces multiple substrings in a string given a mapping of strings.
+
+ By default replaces long strings before short strings, and lowercase before uppercase.
+ Example:
+ var = replace_many("This is a sentence", {"is": "was", "This": "That"})
+ assert var == "That was a sentence"
+
+ If `ignore_case` is given, does a case insensitive match.
+ Example:
+ var = replace_many("THIS is a sentence", {"IS": "was", "tHiS": "That"}, ignore_case=True)
+ assert var == "That was a sentence"
+
+ If `match_case` is given, matches the case of the replacement with the replaced word.
+ Example:
+ var = replace_many(
+ "This IS a sentence", {"is": "was", "this": "that"}, ignore_case=True, match_case=True
+ )
+ assert var == "That WAS a sentence"
+ """
+ if ignore_case:
+ replacements = dict(
+ (word.lower(), replacement) for word, replacement in replacements.items()
+ )
+
+ words_to_replace = sorted(replacements, key=lambda s: (-len(s), s))
+
+ # Join and compile words to replace into a regex
+ pattern = "|".join(re.escape(word) for word in words_to_replace)
+ regex = re.compile(pattern, re.I if ignore_case else 0)
+
+ def _repl(match):
+ """Returns replacement depending on `ignore_case` and `match_case`"""
+ word = match.group(0)
+ replacement = replacements[word.lower() if ignore_case else word]
+
+ if not match_case:
+ return replacement
+
+ # Clean punctuation from word so string methods work
+ cleaned_word = word.translate(str.maketrans('', '', string.punctuation))
+ if cleaned_word.isupper():
+ return replacement.upper()
+ elif cleaned_word[0].isupper():
+ return replacement.capitalize()
+ else:
+ return replacement.lower()
+
+ return regex.sub(_repl, sentence)