aboutsummaryrefslogtreecommitdiffstats
path: root/bot/seasons
diff options
context:
space:
mode:
Diffstat (limited to 'bot/seasons')
-rw-r--r--bot/seasons/easter/april_fools_vids.py2
-rw-r--r--bot/seasons/easter/bunny_name_generator.py92
-rw-r--r--bot/seasons/easter/easter_riddle.py101
-rw-r--r--bot/seasons/easter/egg_facts.py62
-rw-r--r--bot/seasons/evergreen/issues.py53
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")