diff options
Diffstat (limited to 'bot/seasons')
| -rw-r--r-- | bot/seasons/easter/april_fools_vids.py | 2 | ||||
| -rw-r--r-- | bot/seasons/easter/bunny_name_generator.py | 92 | ||||
| -rw-r--r-- | bot/seasons/easter/easter_riddle.py | 101 | ||||
| -rw-r--r-- | bot/seasons/easter/egg_facts.py | 62 | ||||
| -rw-r--r-- | bot/seasons/evergreen/issues.py | 53 |
5 files changed, 309 insertions, 1 deletions
diff --git a/bot/seasons/easter/april_fools_vids.py b/bot/seasons/easter/april_fools_vids.py index 9fbe87a0..d921d07c 100644 --- a/bot/seasons/easter/april_fools_vids.py +++ b/bot/seasons/easter/april_fools_vids.py @@ -19,7 +19,7 @@ class AprilFoolVideos(commands.Cog): @staticmethod def load_json(): """A function to load JSON data.""" - p = Path('bot/resources/easterapril_fools_vids.json') + p = Path('bot/resources/easter/april_fools_vids.json') with p.open() as json_file: all_vids = load(json_file) return all_vids diff --git a/bot/seasons/easter/bunny_name_generator.py b/bot/seasons/easter/bunny_name_generator.py new file mode 100644 index 00000000..76d5c478 --- /dev/null +++ b/bot/seasons/easter/bunny_name_generator.py @@ -0,0 +1,92 @@ +import json +import logging +import random +import re +from pathlib import Path + +from discord.ext import commands + +log = logging.getLogger(__name__) + +with Path("bot/resources/easter/bunny_names.json").open("r", encoding="utf8") as f: + BUNNY_NAMES = json.load(f) + + +class BunnyNameGenerator(commands.Cog): + """Generate a random bunny name, or bunnify your Discord username!""" + + def __init__(self, bot): + self.bot = bot + + def find_separators(self, displayname): + """Check if Discord name contains spaces so we can bunnify an individual word in the name.""" + new_name = re.split(r'[_.\s]', displayname) + if displayname not in new_name: + return new_name + + def find_vowels(self, displayname): + """ + Finds vowels in the user's display name. + + If the Discord name contains a vowel and the letter y, + it will match one or more of these patterns. + Only the most recently matched pattern will apply the changes. + """ + expressions = [ + (r'a.+y', 'patchy'), + (r'e.+y', 'ears'), + (r'i.+y', 'ditsy'), + (r'o.+y', 'oofy'), + (r'u.+y', 'uffy'), + ] + + for exp, vowel_sub in expressions: + new_name = re.sub(exp, vowel_sub, displayname) + if new_name != displayname: + return new_name + + def append_name(self, displayname): + """Adds a suffix to the end of the Discord name""" + extensions = ['foot', 'ear', 'nose', 'tail'] + suffix = random.choice(extensions) + appended_name = displayname + suffix + + return appended_name + + @commands.command() + async def bunnyname(self, ctx): + """Picks a random bunny name from a JSON file""" + await ctx.send(random.choice(BUNNY_NAMES["names"])) + + @commands.command() + async def bunnifyme(self, ctx): + """Gets your Discord username and bunnifies it""" + username = ctx.message.author.display_name + + # If name contains spaces or other separators, get the individual words to randomly bunnify + spaces_in_name = self.find_separators(username) + + # If name contains vowels, see if it matches any of the patterns in this function + # If there are matches, the bunnified name is returned. + vowels_in_name = self.find_vowels(username) + + # Default if the checks above return None + unmatched_name = self.append_name(username) + + if spaces_in_name is not None: + replacements = ['Cotton', 'Fluff', 'Floof' 'Bounce', 'Snuffle', 'Nibble', 'Cuddle', 'Velvetpaw', 'Carrot'] + word_to_replace = random.choice(spaces_in_name) + substitute = random.choice(replacements) + bunnified_name = username.replace(word_to_replace, substitute) + elif vowels_in_name is not None: + bunnified_name = vowels_in_name + elif unmatched_name: + bunnified_name = unmatched_name + + await ctx.send(bunnified_name) + + +def setup(bot): + """Bunny Name Generator Cog load.""" + bot.add_cog(BunnyNameGenerator(bot)) + log.info("BunnyNameGenerator cog loaded.") diff --git a/bot/seasons/easter/easter_riddle.py b/bot/seasons/easter/easter_riddle.py new file mode 100644 index 00000000..56555586 --- /dev/null +++ b/bot/seasons/easter/easter_riddle.py @@ -0,0 +1,101 @@ +import asyncio +import logging +import random +from json import load +from pathlib import Path + +import discord +from discord.ext import commands + +from bot.constants import Colours + +log = logging.getLogger(__name__) + +with Path("bot/resources/easter/easter_riddle.json").open("r", encoding="utf8") as f: + RIDDLE_QUESTIONS = load(f) + +TIMELIMIT = 10 + + +class EasterRiddle(commands.Cog): + """This cog contains the command for the Easter quiz!""" + + def __init__(self, bot): + self.bot = bot + self.winners = [] + self.correct = "" + self.current_channel = None + + @commands.command(aliases=["riddlemethis", "riddleme"]) + async def riddle(self, ctx): + """ + Gives a random riddle, then provides 2 hints at certain intervals before revealing the answer. + + The duration of the hint interval can be configured by changing the TIMELIMIT constant in this file. + """ + if self.current_channel: + return await ctx.send(f"A riddle is already being solved in {self.current_channel.mention}!") + + self.current_channel = ctx.message.channel + + random_question = random.choice(RIDDLE_QUESTIONS) + question = random_question["question"] + hints = random_question["riddles"] + self.correct = random_question["correct_answer"] + + description = f"You have {TIMELIMIT} seconds before the first hint." + + riddle_embed = discord.Embed(title=question, description=description, colour=Colours.pink) + + await ctx.send(embed=riddle_embed) + await asyncio.sleep(TIMELIMIT) + + hint_embed = discord.Embed( + title=f"Here's a hint: {hints[0]}!", + colour=Colours.pink + ) + + await ctx.send(embed=hint_embed) + await asyncio.sleep(TIMELIMIT) + + hint_embed = discord.Embed( + title=f"Here's a hint: {hints[1]}!", + colour=Colours.pink + ) + + await ctx.send(embed=hint_embed) + await asyncio.sleep(TIMELIMIT) + + if self.winners: + win_list = " ".join(self.winners) + content = f"Well done {win_list} for getting it right!" + else: + content = "Nobody got it right..." + + answer_embed = discord.Embed( + title=f"The answer is: {self.correct}!", + colour=Colours.pink + ) + + await ctx.send(content, embed=answer_embed) + + self.winners = [] + self.current_channel = None + + @commands.Cog.listener() + async def on_message(self, message): + """If a non-bot user enters a correct answer, their username gets added to self.winners""" + if self.current_channel != message.channel: + return + + if self.bot.user == message.author: + return + + if message.content.lower() == self.correct.lower(): + self.winners.append(message.author.mention) + + +def setup(bot): + """Easter Riddle Cog load.""" + bot.add_cog(EasterRiddle(bot)) + log.info("Easter Riddle bot loaded") diff --git a/bot/seasons/easter/egg_facts.py b/bot/seasons/easter/egg_facts.py new file mode 100644 index 00000000..ae08ccd4 --- /dev/null +++ b/bot/seasons/easter/egg_facts.py @@ -0,0 +1,62 @@ +import asyncio +import logging +import random +from json import load +from pathlib import Path + +import discord +from discord.ext import commands + +from bot.constants import Channels +from bot.constants import Colours + + +log = logging.getLogger(__name__) + + +class EasterFacts(commands.Cog): + """ + A cog contains a command that will return an easter egg fact when called. + + It also contains a background task which sends an easter egg fact in the event channel everyday. + """ + + def __init__(self, bot): + self.bot = bot + self.facts = self.load_json() + + @staticmethod + def load_json(): + """Load a list of easter egg facts from the resource JSON file.""" + p = Path("bot/resources/easter/easter_egg_facts.json") + with p.open(encoding="utf8") as f: + return load(f) + + async def send_egg_fact_daily(self): + """A background task that sends an easter egg fact in the event channel everyday.""" + channel = self.bot.get_channel(Channels.seasonalbot_chat) + while True: + embed = self.make_embed() + await channel.send(embed=embed) + await asyncio.sleep(24 * 60 * 60) + + @commands.command(name='eggfact', aliases=['fact']) + async def easter_facts(self, ctx): + """Get easter egg facts.""" + embed = self.make_embed() + await ctx.send(embed=embed) + + def make_embed(self): + """Makes a nice embed for the message to be sent.""" + return discord.Embed( + colour=Colours.soft_red, + title="Easter Egg Fact", + description=random.choice(self.facts) + ) + + +def setup(bot): + """Easter Egg facts cog load.""" + bot.loop.create_task(EasterFacts(bot).send_egg_fact_daily()) + bot.add_cog(EasterFacts(bot)) + log.info("EasterFacts cog loaded") diff --git a/bot/seasons/evergreen/issues.py b/bot/seasons/evergreen/issues.py new file mode 100644 index 00000000..2a31a2e1 --- /dev/null +++ b/bot/seasons/evergreen/issues.py @@ -0,0 +1,53 @@ +import logging + +import discord +from discord.ext import commands + +from bot.constants import Colours + +log = logging.getLogger(__name__) + + +class Issues(commands.Cog): + """Cog that allows users to retrieve issues from GitHub.""" + + def __init__(self, bot): + self.bot = bot + + @commands.command(aliases=("issues",)) + async def issue(self, ctx, number: int, repository: str = "seasonalbot", user: str = "python-discord"): + """Command to retrieve issues from a GitHub repository.""" + api_url = f"https://api.github.com/repos/{user}/{repository}/issues/{number}" + failed_status = { + 404: f"Issue #{number} doesn't exist in the repository {user}/{repository}.", + 403: f"Rate limit exceeded. Please wait a while before trying again!" + } + + async with self.bot.http_session.get(api_url) as r: + json_data = await r.json() + response_code = r.status + + if response_code in failed_status: + return await ctx.send(failed_status[response_code]) + + repo_url = f"https://github.com/{user}/{repository}" + issue_embed = discord.Embed(colour=Colours.bright_green) + issue_embed.add_field(name="Repository", value=f"[{user}/{repository}]({repo_url})", inline=False) + issue_embed.add_field(name="Issue Number", value=f"#{number}", inline=False) + issue_embed.add_field(name="Status", value=json_data["state"].title()) + issue_embed.add_field(name="Link", value=json_data["html_url"], inline=False) + + description = json_data["body"] + if len(description) > 1024: + placeholder = " [...]" + description = f"{description[:1024 - len(placeholder)]}{placeholder}" + + issue_embed.add_field(name="Description", value=description, inline=False) + + await ctx.send(embed=issue_embed) + + +def setup(bot): + """Github Issues Cog Load.""" + bot.add_cog(Issues(bot)) + log.info("Issues cog loaded") |