diff options
Diffstat (limited to 'bot/exts/holidays')
| -rw-r--r-- | bot/exts/holidays/valentines/__init__.py | 0 | ||||
| -rw-r--r-- | bot/exts/holidays/valentines/be_my_valentine.py | 192 | ||||
| -rw-r--r-- | bot/exts/holidays/valentines/lovecalculator.py | 99 | ||||
| -rw-r--r-- | bot/exts/holidays/valentines/movie_generator.py | 67 | ||||
| -rw-r--r-- | bot/exts/holidays/valentines/myvalenstate.py | 82 | ||||
| -rw-r--r-- | bot/exts/holidays/valentines/pickuplines.py | 41 | ||||
| -rw-r--r-- | bot/exts/holidays/valentines/savethedate.py | 38 | ||||
| -rw-r--r-- | bot/exts/holidays/valentines/valentine_zodiac.py | 146 | ||||
| -rw-r--r-- | bot/exts/holidays/valentines/whoisvalentine.py | 49 |
9 files changed, 714 insertions, 0 deletions
diff --git a/bot/exts/holidays/valentines/__init__.py b/bot/exts/holidays/valentines/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/bot/exts/holidays/valentines/__init__.py diff --git a/bot/exts/holidays/valentines/be_my_valentine.py b/bot/exts/holidays/valentines/be_my_valentine.py new file mode 100644 index 00000000..4d454c3a --- /dev/null +++ b/bot/exts/holidays/valentines/be_my_valentine.py @@ -0,0 +1,192 @@ +import logging +import random +from json import loads +from pathlib import Path + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Channels, Colours, Lovefest, Month +from bot.utils.decorators import in_month +from bot.utils.extensions import invoke_help_command + +log = logging.getLogger(__name__) + +HEART_EMOJIS = [":heart:", ":gift_heart:", ":revolving_hearts:", ":sparkling_heart:", ":two_hearts:"] + + +class BeMyValentine(commands.Cog): + """A cog that sends Valentines to other users!""" + + def __init__(self, bot: Bot): + self.bot = bot + self.valentines = self.load_json() + + @staticmethod + def load_json() -> dict: + """Load Valentines messages from the static resources.""" + p = Path("bot/resources/holidays/valentines/bemyvalentine_valentines.json") + return loads(p.read_text("utf8")) + + @in_month(Month.FEBRUARY) + @commands.group(name="lovefest") + async def lovefest_role(self, ctx: commands.Context) -> None: + """ + Subscribe or unsubscribe from the lovefest role. + + The lovefest role makes you eligible to receive anonymous valentines from other users. + + 1) use the command \".lovefest sub\" to get the lovefest role. + 2) use the command \".lovefest unsub\" to get rid of the lovefest role. + """ + if not ctx.invoked_subcommand: + await invoke_help_command(ctx) + + @lovefest_role.command(name="sub") + async def add_role(self, ctx: commands.Context) -> None: + """Adds the lovefest role.""" + user = ctx.author + role = ctx.guild.get_role(Lovefest.role_id) + if role not in ctx.author.roles: + await user.add_roles(role) + await ctx.send("The Lovefest role has been added !") + else: + await ctx.send("You already have the role !") + + @lovefest_role.command(name="unsub") + async def remove_role(self, ctx: commands.Context) -> None: + """Removes the lovefest role.""" + user = ctx.author + role = ctx.guild.get_role(Lovefest.role_id) + if role not in ctx.author.roles: + await ctx.send("You dont have the lovefest role.") + else: + await user.remove_roles(role) + await ctx.send("The lovefest role has been successfully removed!") + + @commands.cooldown(1, 1800, commands.BucketType.user) + @commands.group(name="bemyvalentine", invoke_without_command=True) + async def send_valentine( + self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None + ) -> None: + """ + Send a valentine to a specified user with the lovefest role. + + syntax: .bemyvalentine [user] [p/poem/c/compliment/or you can type your own valentine message] + (optional) + + example: .bemyvalentine Iceman#6508 p (sends a poem to Iceman) + example: .bemyvalentine Iceman Hey I love you, wanna hang around ? (sends the custom message to Iceman) + NOTE : AVOID TAGGING THE USER MOST OF THE TIMES.JUST TRIM THE '@' when using this command. + """ + if ctx.guild is None: + # This command should only be used in the server + raise commands.UserInputError("You are supposed to use this command in the server.") + + if Lovefest.role_id not in [role.id for role in user.roles]: + raise commands.UserInputError( + f"You cannot send a valentine to {user} as they do not have the lovefest role!" + ) + + if user == ctx.author: + # Well a user can't valentine himself/herself. + raise commands.UserInputError("Come on, you can't send a valentine to yourself :expressionless:") + + emoji_1, emoji_2 = self.random_emoji() + channel = self.bot.get_channel(Channels.community_bot_commands) + valentine, title = self.valentine_check(valentine_type) + + embed = discord.Embed( + title=f"{emoji_1} {title} {user.display_name} {emoji_2}", + description=f"{valentine} \n **{emoji_2}From {ctx.author}{emoji_1}**", + color=Colours.pink + ) + await channel.send(user.mention, embed=embed) + + @commands.cooldown(1, 1800, commands.BucketType.user) + @send_valentine.command(name="secret") + async def anonymous( + self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None + ) -> None: + """ + Send an anonymous Valentine via DM to to a specified user with the lovefest role. + + syntax : .bemyvalentine secret [user] [p/poem/c/compliment/or you can type your own valentine message] + (optional) + + example : .bemyvalentine secret Iceman#6508 p (sends a poem to Iceman in DM making you anonymous) + example : .bemyvalentine secret Iceman#6508 Hey I love you, wanna hang around ? (sends the custom message to + Iceman in DM making you anonymous) + """ + if Lovefest.role_id not in [role.id for role in user.roles]: + await ctx.message.delete() + raise commands.UserInputError( + f"You cannot send a valentine to {user} as they do not have the lovefest role!" + ) + + if user == ctx.author: + # Well a user cant valentine himself/herself. + raise commands.UserInputError("Come on, you can't send a valentine to yourself :expressionless:") + + emoji_1, emoji_2 = self.random_emoji() + valentine, title = self.valentine_check(valentine_type) + + embed = discord.Embed( + title=f"{emoji_1}{title} {user.display_name}{emoji_2}", + description=f"{valentine} \n **{emoji_2}From anonymous{emoji_1}**", + color=Colours.pink + ) + await ctx.message.delete() + try: + await user.send(embed=embed) + except discord.Forbidden: + raise commands.UserInputError(f"{user} has DMs disabled, so I couldn't send the message. Sorry!") + else: + await ctx.author.send(f"Your message has been sent to {user}") + + def valentine_check(self, valentine_type: str) -> tuple[str, str]: + """Return the appropriate Valentine type & title based on the invoking user's input.""" + if valentine_type is None: + return self.random_valentine() + + elif valentine_type.lower() in ["p", "poem"]: + return self.valentine_poem(), "A poem dedicated to" + + elif valentine_type.lower() in ["c", "compliment"]: + return self.valentine_compliment(), "A compliment for" + + else: + # in this case, the user decides to type his own valentine. + return valentine_type, "A message for" + + @staticmethod + def random_emoji() -> tuple[str, str]: + """Return two random emoji from the module-defined constants.""" + emoji_1 = random.choice(HEART_EMOJIS) + emoji_2 = random.choice(HEART_EMOJIS) + return emoji_1, emoji_2 + + def random_valentine(self) -> tuple[str, str]: + """Grabs a random poem or a compliment (any message).""" + valentine_poem = random.choice(self.valentines["valentine_poems"]) + valentine_compliment = random.choice(self.valentines["valentine_compliments"]) + random_valentine = random.choice([valentine_compliment, valentine_poem]) + if random_valentine == valentine_poem: + title = "A poem dedicated to" + else: + title = "A compliment for " + return random_valentine, title + + def valentine_poem(self) -> str: + """Grabs a random poem.""" + return random.choice(self.valentines["valentine_poems"]) + + def valentine_compliment(self) -> str: + """Grabs a random compliment.""" + return random.choice(self.valentines["valentine_compliments"]) + + +def setup(bot: Bot) -> None: + """Load the Be my Valentine Cog.""" + bot.add_cog(BeMyValentine(bot)) diff --git a/bot/exts/holidays/valentines/lovecalculator.py b/bot/exts/holidays/valentines/lovecalculator.py new file mode 100644 index 00000000..3999db2b --- /dev/null +++ b/bot/exts/holidays/valentines/lovecalculator.py @@ -0,0 +1,99 @@ +import bisect +import hashlib +import json +import logging +import random +from pathlib import Path +from typing import Coroutine, Optional + +import discord +from discord import Member +from discord.ext import commands +from discord.ext.commands import BadArgument, Cog, clean_content + +from bot.bot import Bot +from bot.constants import Channels, Client, Lovefest, Month +from bot.utils.decorators import in_month + +log = logging.getLogger(__name__) + +LOVE_DATA = json.loads(Path("bot/resources/holidays/valentines/love_matches.json").read_text("utf8")) +LOVE_DATA = sorted((int(key), value) for key, value in LOVE_DATA.items()) + + +class LoveCalculator(Cog): + """A cog for calculating the love between two people.""" + + @in_month(Month.FEBRUARY) + @commands.command(aliases=("love_calculator", "love_calc")) + @commands.cooldown(rate=1, per=5, type=commands.BucketType.user) + async def love(self, ctx: commands.Context, who: Member, whom: Optional[Member] = None) -> None: + """ + Tells you how much the two love each other. + + This command requires at least one member as input, if two are given love will be calculated between + those two users, if only one is given, the second member is asusmed to be the invoker. + Members are converted from: + - User ID + - Mention + - name#discrim + - name + - nickname + + Any two arguments will always yield the same result, regardless of the order of arguments: + Running .love @joe#6000 @chrisjl#2655 will always yield the same result. + Running .love @chrisjl#2655 @joe#6000 will yield the same result as before. + """ + if ( + Lovefest.role_id not in [role.id for role in who.roles] + or (whom is not None and Lovefest.role_id not in [role.id for role in whom.roles]) + ): + raise BadArgument( + "This command can only be ran against members with the lovefest role! " + "This role be can assigned by running " + f"`{Client.prefix}lovefest sub` in <#{Channels.community_bot_commands}>." + ) + + if whom is None: + whom = ctx.author + + def normalize(arg: Member) -> Coroutine: + # This has to be done manually to be applied to usernames + return clean_content(escape_markdown=True).convert(ctx, str(arg)) + + # Sort to ensure same result for same input, regardless of order + who, whom = sorted([await normalize(arg) for arg in (who, whom)]) + + # Hash inputs to guarantee consistent results (hashing algorithm choice arbitrary) + # + # hashlib is used over the builtin hash() to guarantee same result over multiple runtimes + m = hashlib.sha256(who.encode() + whom.encode()) + # Mod 101 for [0, 100] + love_percent = sum(m.digest()) % 101 + + # We need the -1 due to how bisect returns the point + # see the documentation for further detail + # https://docs.python.org/3/library/bisect.html#bisect.bisect + index = bisect.bisect(LOVE_DATA, (love_percent,)) - 1 + # We already have the nearest "fit" love level + # We only need the dict, so we can ditch the first element + _, data = LOVE_DATA[index] + + status = random.choice(data["titles"]) + embed = discord.Embed( + title=status, + description=f"{who} \N{HEAVY BLACK HEART} {whom} scored {love_percent}%!\n\u200b", + color=discord.Color.dark_magenta() + ) + embed.add_field( + name="A letter from Dr. Love:", + value=data["text"] + ) + embed.set_footer(text=f"You can unsubscribe from lovefest by using {Client.prefix}lovefest unsub") + + await ctx.send(embed=embed) + + +def setup(bot: Bot) -> None: + """Load the Love calculator Cog.""" + bot.add_cog(LoveCalculator()) diff --git a/bot/exts/holidays/valentines/movie_generator.py b/bot/exts/holidays/valentines/movie_generator.py new file mode 100644 index 00000000..d2dc8213 --- /dev/null +++ b/bot/exts/holidays/valentines/movie_generator.py @@ -0,0 +1,67 @@ +import logging +import random +from os import environ + +import discord +from discord.ext import commands + +from bot.bot import Bot + +TMDB_API_KEY = environ.get("TMDB_API_KEY") + +log = logging.getLogger(__name__) + + +class RomanceMovieFinder(commands.Cog): + """A Cog that returns a random romance movie suggestion to a user.""" + + def __init__(self, bot: Bot): + self.bot = bot + + @commands.command(name="romancemovie") + async def romance_movie(self, ctx: commands.Context) -> None: + """Randomly selects a romance movie and displays information about it.""" + # Selecting a random int to parse it to the page parameter + random_page = random.randint(0, 20) + # TMDB api params + params = { + "api_key": TMDB_API_KEY, + "language": "en-US", + "sort_by": "popularity.desc", + "include_adult": "false", + "include_video": "false", + "page": random_page, + "with_genres": "10749" + } + # The api request url + request_url = "https://api.themoviedb.org/3/discover/movie" + async with self.bot.http_session.get(request_url, params=params) as resp: + # Trying to load the json file returned from the api + try: + data = await resp.json() + # Selecting random result from results object in the json file + selected_movie = random.choice(data["results"]) + + embed = discord.Embed( + title=f":sparkling_heart: {selected_movie['title']} :sparkling_heart:", + description=selected_movie["overview"], + ) + embed.set_image(url=f"http://image.tmdb.org/t/p/w200/{selected_movie['poster_path']}") + embed.add_field(name="Release date :clock1:", value=selected_movie["release_date"]) + embed.add_field(name="Rating :star2:", value=selected_movie["vote_average"]) + embed.set_footer(text="This product uses the TMDb API but is not endorsed or certified by TMDb.") + embed.set_thumbnail(url="https://i.imgur.com/LtFtC8H.png") + await ctx.send(embed=embed) + except KeyError: + warning_message = ( + "A KeyError was raised while fetching information on the movie. The API service" + " could be unavailable or the API key could be set incorrectly." + ) + embed = discord.Embed(title=warning_message) + log.warning(warning_message) + await ctx.send(embed=embed) + + +def setup(bot: Bot) -> None: + """Load the Romance movie Cog.""" + bot.add_cog(RomanceMovieFinder(bot)) diff --git a/bot/exts/holidays/valentines/myvalenstate.py b/bot/exts/holidays/valentines/myvalenstate.py new file mode 100644 index 00000000..4b547d9b --- /dev/null +++ b/bot/exts/holidays/valentines/myvalenstate.py @@ -0,0 +1,82 @@ +import collections +import json +import logging +from pathlib import Path +from random import choice + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours + +log = logging.getLogger(__name__) + +STATES = json.loads(Path("bot/resources/holidays/valentines/valenstates.json").read_text("utf8")) + + +class MyValenstate(commands.Cog): + """A Cog to find your most likely Valentine's vacation destination.""" + + def levenshtein(self, source: str, goal: str) -> int: + """Calculates the Levenshtein Distance between source and goal.""" + if len(source) < len(goal): + return self.levenshtein(goal, source) + if len(source) == 0: + return len(goal) + if len(goal) == 0: + return len(source) + + pre_row = list(range(0, len(source) + 1)) + for i, source_c in enumerate(source): + cur_row = [i + 1] + for j, goal_c in enumerate(goal): + if source_c != goal_c: + cur_row.append(min(pre_row[j], pre_row[j + 1], cur_row[j]) + 1) + else: + cur_row.append(min(pre_row[j], pre_row[j + 1], cur_row[j])) + pre_row = cur_row + return pre_row[-1] + + @commands.command() + async def myvalenstate(self, ctx: commands.Context, *, name: str = None) -> None: + """Find the vacation spot(s) with the most matching characters to the invoking user.""" + eq_chars = collections.defaultdict(int) + if name is None: + author = ctx.author.name.lower().replace(" ", "") + else: + author = name.lower().replace(" ", "") + + for state in STATES.keys(): + lower_state = state.lower().replace(" ", "") + eq_chars[state] = self.levenshtein(author, lower_state) + + matches = [x for x, y in eq_chars.items() if y == min(eq_chars.values())] + valenstate = choice(matches) + matches.remove(valenstate) + + embed_title = "But there are more!" + if len(matches) > 1: + leftovers = f"{', '.join(matches[:-2])}, and {matches[-1]}" + embed_text = f"You have {len(matches)} more matches, these being {leftovers}." + elif len(matches) == 1: + embed_title = "But there's another one!" + embed_text = f"You have another match, this being {matches[0]}." + else: + embed_title = "You have a true match!" + embed_text = "This state is your true Valenstate! There are no states that would suit" \ + " you better" + + embed = discord.Embed( + title=f"Your Valenstate is {valenstate} \u2764", + description=STATES[valenstate]["text"], + colour=Colours.pink + ) + embed.add_field(name=embed_title, value=embed_text) + embed.set_image(url=STATES[valenstate]["flag"]) + await ctx.send(embed=embed) + + +def setup(bot: Bot) -> None: + """Load the Valenstate Cog.""" + bot.add_cog(MyValenstate()) diff --git a/bot/exts/holidays/valentines/pickuplines.py b/bot/exts/holidays/valentines/pickuplines.py new file mode 100644 index 00000000..bc4b88c6 --- /dev/null +++ b/bot/exts/holidays/valentines/pickuplines.py @@ -0,0 +1,41 @@ +import logging +import random +from json import loads +from pathlib import Path + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours + +log = logging.getLogger(__name__) + +PICKUP_LINES = loads(Path("bot/resources/holidays/valentines/pickup_lines.json").read_text("utf8")) + + +class PickupLine(commands.Cog): + """A cog that gives random cheesy pickup lines.""" + + @commands.command() + async def pickupline(self, ctx: commands.Context) -> None: + """ + Gives you a random pickup line. + + Note that most of them are very cheesy. + """ + random_line = random.choice(PICKUP_LINES["lines"]) + embed = discord.Embed( + title=":cheese: Your pickup line :cheese:", + description=random_line["line"], + color=Colours.pink + ) + embed.set_thumbnail( + url=random_line.get("image", PICKUP_LINES["placeholder"]) + ) + await ctx.send(embed=embed) + + +def setup(bot: Bot) -> None: + """Load the Pickup lines Cog.""" + bot.add_cog(PickupLine()) diff --git a/bot/exts/holidays/valentines/savethedate.py b/bot/exts/holidays/valentines/savethedate.py new file mode 100644 index 00000000..3638c1ef --- /dev/null +++ b/bot/exts/holidays/valentines/savethedate.py @@ -0,0 +1,38 @@ +import logging +import random +from json import loads +from pathlib import Path + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours + +log = logging.getLogger(__name__) + +HEART_EMOJIS = [":heart:", ":gift_heart:", ":revolving_hearts:", ":sparkling_heart:", ":two_hearts:"] + +VALENTINES_DATES = loads(Path("bot/resources/holidays/valentines/date_ideas.json").read_text("utf8")) + + +class SaveTheDate(commands.Cog): + """A cog that gives random suggestion for a Valentine's date.""" + + @commands.command() + async def savethedate(self, ctx: commands.Context) -> None: + """Gives you ideas for what to do on a date with your valentine.""" + random_date = random.choice(VALENTINES_DATES["ideas"]) + emoji_1 = random.choice(HEART_EMOJIS) + emoji_2 = random.choice(HEART_EMOJIS) + embed = discord.Embed( + title=f"{emoji_1}{random_date['name']}{emoji_2}", + description=f"{random_date['description']}", + colour=Colours.pink + ) + await ctx.send(embed=embed) + + +def setup(bot: Bot) -> None: + """Load the Save the date Cog.""" + bot.add_cog(SaveTheDate()) diff --git a/bot/exts/holidays/valentines/valentine_zodiac.py b/bot/exts/holidays/valentines/valentine_zodiac.py new file mode 100644 index 00000000..d1b3a630 --- /dev/null +++ b/bot/exts/holidays/valentines/valentine_zodiac.py @@ -0,0 +1,146 @@ +import calendar +import json +import logging +import random +from datetime import datetime +from pathlib import Path +from typing import Union + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours + +log = logging.getLogger(__name__) + +LETTER_EMOJI = ":love_letter:" +HEART_EMOJIS = [":heart:", ":gift_heart:", ":revolving_hearts:", ":sparkling_heart:", ":two_hearts:"] + + +class ValentineZodiac(commands.Cog): + """A Cog that returns a counter compatible zodiac sign to the given user's zodiac sign.""" + + def __init__(self): + self.zodiacs, self.zodiac_fact = self.load_comp_json() + + @staticmethod + def load_comp_json() -> tuple[dict, dict]: + """Load zodiac compatibility from static JSON resource.""" + explanation_file = Path("bot/resources/holidays/valentines/zodiac_explanation.json") + compatibility_file = Path("bot/resources/holidays/valentines/zodiac_compatibility.json") + + zodiac_fact = json.loads(explanation_file.read_text("utf8")) + + for zodiac_data in zodiac_fact.values(): + zodiac_data["start_at"] = datetime.fromisoformat(zodiac_data["start_at"]) + zodiac_data["end_at"] = datetime.fromisoformat(zodiac_data["end_at"]) + + zodiacs = json.loads(compatibility_file.read_text("utf8")) + + return zodiacs, zodiac_fact + + def generate_invalidname_embed(self, zodiac: str) -> discord.Embed: + """Returns error embed.""" + embed = discord.Embed() + embed.color = Colours.soft_red + error_msg = f"**{zodiac}** is not a valid zodiac sign, here is the list of valid zodiac signs.\n" + names = list(self.zodiac_fact) + middle_index = len(names) // 2 + first_half_names = ", ".join(names[:middle_index]) + second_half_names = ", ".join(names[middle_index:]) + embed.description = error_msg + first_half_names + ",\n" + second_half_names + log.info("Invalid zodiac name provided.") + return embed + + def zodiac_build_embed(self, zodiac: str) -> discord.Embed: + """Gives informative zodiac embed.""" + zodiac = zodiac.capitalize() + embed = discord.Embed() + embed.color = Colours.pink + if zodiac in self.zodiac_fact: + log.trace("Making zodiac embed.") + embed.title = f"__{zodiac}__" + embed.description = self.zodiac_fact[zodiac]["About"] + embed.add_field(name="__Motto__", value=self.zodiac_fact[zodiac]["Motto"], inline=False) + embed.add_field(name="__Strengths__", value=self.zodiac_fact[zodiac]["Strengths"], inline=False) + embed.add_field(name="__Weaknesses__", value=self.zodiac_fact[zodiac]["Weaknesses"], inline=False) + embed.add_field(name="__Full form__", value=self.zodiac_fact[zodiac]["full_form"], inline=False) + embed.set_thumbnail(url=self.zodiac_fact[zodiac]["url"]) + else: + embed = self.generate_invalidname_embed(zodiac) + log.trace("Successfully created zodiac information embed.") + return embed + + def zodiac_date_verifier(self, query_date: datetime) -> str: + """Returns zodiac sign by checking date.""" + for zodiac_name, zodiac_data in self.zodiac_fact.items(): + if zodiac_data["start_at"].date() <= query_date.date() <= zodiac_data["end_at"].date(): + log.trace("Zodiac name sent.") + return zodiac_name + + @commands.group(name="zodiac", invoke_without_command=True) + async def zodiac(self, ctx: commands.Context, zodiac_sign: str) -> None: + """Provides information about zodiac sign by taking zodiac sign name as input.""" + final_embed = self.zodiac_build_embed(zodiac_sign) + await ctx.send(embed=final_embed) + log.trace("Embed successfully sent.") + + @zodiac.command(name="date") + async def date_and_month(self, ctx: commands.Context, date: int, month: Union[int, str]) -> None: + """Provides information about zodiac sign by taking month and date as input.""" + if isinstance(month, str): + month = month.capitalize() + try: + month = list(calendar.month_abbr).index(month[:3]) + log.trace("Valid month name entered by user") + except ValueError: + log.info("Invalid month name entered by user") + await ctx.send(f"Sorry, but `{month}` is not a valid month name.") + return + if (month == 1 and 1 <= date <= 19) or (month == 12 and 22 <= date <= 31): + zodiac = "capricorn" + final_embed = self.zodiac_build_embed(zodiac) + else: + try: + zodiac_sign_based_on_date = self.zodiac_date_verifier(datetime(2020, month, date)) + log.trace("zodiac sign based on month and date received.") + except ValueError as e: + final_embed = discord.Embed() + final_embed.color = Colours.soft_red + final_embed.description = f"Zodiac sign could not be found because.\n```\n{e}\n```" + log.info(f"Error in 'zodiac date' command:\n{e}.") + else: + final_embed = self.zodiac_build_embed(zodiac_sign_based_on_date) + + await ctx.send(embed=final_embed) + log.trace("Embed from date successfully sent.") + + @zodiac.command(name="partnerzodiac", aliases=("partner",)) + async def partner_zodiac(self, ctx: commands.Context, zodiac_sign: str) -> None: + """Provides a random counter compatible zodiac sign to the given user's zodiac sign.""" + embed = discord.Embed() + embed.color = Colours.pink + zodiac_check = self.zodiacs.get(zodiac_sign.capitalize()) + if zodiac_check: + compatible_zodiac = random.choice(self.zodiacs[zodiac_sign.capitalize()]) + emoji1 = random.choice(HEART_EMOJIS) + emoji2 = random.choice(HEART_EMOJIS) + embed.title = "Zodiac Compatibility" + embed.description = ( + f"{zodiac_sign.capitalize()}{emoji1}{compatible_zodiac['Zodiac']}\n" + f"{emoji2}Compatibility meter : {compatible_zodiac['compatibility_score']}{emoji2}" + ) + embed.add_field( + name=f"A letter from Dr.Zodiac {LETTER_EMOJI}", + value=compatible_zodiac["description"] + ) + else: + embed = self.generate_invalidname_embed(zodiac_sign) + await ctx.send(embed=embed) + log.trace("Embed from date successfully sent.") + + +def setup(bot: Bot) -> None: + """Load the Valentine zodiac Cog.""" + bot.add_cog(ValentineZodiac()) diff --git a/bot/exts/holidays/valentines/whoisvalentine.py b/bot/exts/holidays/valentines/whoisvalentine.py new file mode 100644 index 00000000..67e46aa4 --- /dev/null +++ b/bot/exts/holidays/valentines/whoisvalentine.py @@ -0,0 +1,49 @@ +import json +import logging +from pathlib import Path +from random import choice + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours + +log = logging.getLogger(__name__) + +FACTS = json.loads(Path("bot/resources/holidays/valentines/valentine_facts.json").read_text("utf8")) + + +class ValentineFacts(commands.Cog): + """A Cog for displaying facts about Saint Valentine.""" + + @commands.command(aliases=("whoisvalentine", "saint_valentine")) + async def who_is_valentine(self, ctx: commands.Context) -> None: + """Displays info about Saint Valentine.""" + embed = discord.Embed( + title="Who is Saint Valentine?", + description=FACTS["whois"], + color=Colours.pink + ) + embed.set_thumbnail( + url="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Saint_Valentine_-_" + "facial_reconstruction.jpg/1024px-Saint_Valentine_-_facial_reconstruction.jpg" + ) + + await ctx.send(embed=embed) + + @commands.command() + async def valentine_fact(self, ctx: commands.Context) -> None: + """Shows a random fact about Valentine's Day.""" + embed = discord.Embed( + title=choice(FACTS["titles"]), + description=choice(FACTS["text"]), + color=Colours.pink + ) + + await ctx.send(embed=embed) + + +def setup(bot: Bot) -> None: + """Load the Who is Valentine Cog.""" + bot.add_cog(ValentineFacts()) |