diff options
Diffstat (limited to 'bot/exts')
| -rw-r--r-- | bot/exts/christmas/advent_of_code/_helpers.py | 8 | ||||
| -rw-r--r-- | bot/exts/evergreen/avatar_modification/_effects.py | 31 | ||||
| -rw-r--r-- | bot/exts/evergreen/avatar_modification/avatar_modify.py | 42 | ||||
| -rw-r--r-- | bot/exts/evergreen/help.py | 4 | ||||
| -rw-r--r-- | bot/exts/evergreen/snakes/_converter.py | 2 | ||||
| -rw-r--r-- | bot/exts/evergreen/trivia_quiz.py | 2 | ||||
| -rw-r--r-- | bot/exts/pride/pride_leader.py | 2 | ||||
| -rw-r--r-- | bot/exts/valentines/lovecalculator.py | 49 | 
8 files changed, 95 insertions, 45 deletions
| diff --git a/bot/exts/christmas/advent_of_code/_helpers.py b/bot/exts/christmas/advent_of_code/_helpers.py index 96de90c4..e26a17ca 100644 --- a/bot/exts/christmas/advent_of_code/_helpers.py +++ b/bot/exts/christmas/advent_of_code/_helpers.py @@ -67,7 +67,7 @@ class UnexpectedResponseStatus(aiohttp.ClientError):      """Raised when an unexpected redirect was detected.""" -class FetchingLeaderboardFailed(Exception): +class FetchingLeaderboardFailedError(Exception):      """Raised when one or more leaderboards could not be fetched at all.""" @@ -210,7 +210,7 @@ async def _fetch_leaderboard_data() -> typing.Dict[str, typing.Any]:              except UnexpectedRedirect:                  if cookies["session"] == AdventOfCode.fallback_session:                      log.error("It seems like the fallback cookie has expired!") -                    raise FetchingLeaderboardFailed from None +                    raise FetchingLeaderboardFailedError from None                  # If we're here, it means that the original session did not                  # work. Let's fall back to the fallback session. @@ -218,7 +218,7 @@ async def _fetch_leaderboard_data() -> typing.Dict[str, typing.Any]:                  continue              except aiohttp.ClientError:                  # Don't retry, something unexpected is wrong and it may not be the session. -                raise FetchingLeaderboardFailed from None +                raise FetchingLeaderboardFailedError from None              else:                  # Get the participants and store their current count.                  board_participants = raw_data["members"] @@ -227,7 +227,7 @@ async def _fetch_leaderboard_data() -> typing.Dict[str, typing.Any]:                  break          else:              log.error(f"reached 'unreachable' state while fetching board `{leaderboard.id}`.") -            raise FetchingLeaderboardFailed +            raise FetchingLeaderboardFailedError      log.info(f"Fetched leaderboard information for {len(participants)} participants")      return participants diff --git a/bot/exts/evergreen/avatar_modification/_effects.py b/bot/exts/evergreen/avatar_modification/_effects.py index b53b26f3..92244207 100644 --- a/bot/exts/evergreen/avatar_modification/_effects.py +++ b/bot/exts/evergreen/avatar_modification/_effects.py @@ -22,6 +22,7 @@ class PfpEffects:          """Applies the given effect to the image passed to it."""          im = Image.open(BytesIO(image_bytes))          im = im.convert("RGBA") +        im = im.resize((1024, 1024))          im = effect(im, *args)          bufferedio = BytesIO() @@ -74,7 +75,6 @@ class PfpEffects:      @staticmethod      def pridify_effect(image: Image.Image, pixels: int, flag: str) -> Image.Image:          """Applies the given pride effect to the given image.""" -        image = image.resize((1024, 1024))          image = PfpEffects.crop_avatar_circle(image)          ring = Image.open(Path(f"bot/resources/pride/flags/{flag}.png")).resize((1024, 1024)) @@ -97,6 +97,17 @@ class PfpEffects:          return image.quantize()      @staticmethod +    def flip_effect(image: Image.Image) -> Image.Image: +        """ +        Flips the image horizontally. + +        This is done by just using ImageOps.mirror(). +        """ +        image = ImageOps.mirror(image) + +        return image + +    @staticmethod      def easterify_effect(image: Image.Image, overlay_image: t.Optional[Image.Image] = None) -> Image.Image:          """          Applies the easter effect to the given image. @@ -272,16 +283,14 @@ class PfpEffects:          return new_image      @staticmethod -    def mosaic_effect(img_bytes: bytes, squares: int, file_name: str) -> discord.File: -        """Separate function run from an executor which turns an image into a mosaic.""" -        avatar = Image.open(BytesIO(img_bytes)) -        avatar = avatar.convert("RGBA").resize((1024, 1024)) +    def mosaic_effect(image: Image.Image, squares: int) -> Image.Image: +        """ +        Applies a mosaic effect to the given image. -        img_squares = PfpEffects.split_image(avatar, squares) +        The "squares" argument specifies the number of squares to split +        the image into. This should be a square number. +        """ +        img_squares = PfpEffects.split_image(image, squares)          new_img = PfpEffects.join_images(img_squares) -        bufferedio = BytesIO() -        new_img.save(bufferedio, format="PNG") -        bufferedio.seek(0) - -        return discord.File(bufferedio, filename=file_name) +        return new_img diff --git a/bot/exts/evergreen/avatar_modification/avatar_modify.py b/bot/exts/evergreen/avatar_modification/avatar_modify.py index bd324f67..7b4ae9c7 100644 --- a/bot/exts/evergreen/avatar_modification/avatar_modify.py +++ b/bot/exts/evergreen/avatar_modification/avatar_modify.py @@ -120,6 +120,43 @@ class AvatarModify(commands.Cog):          await ctx.send(embed=embed, file=file) +    @avatar_modify.command(name="reverse", root_aliases=("reverse",)) +    async def reverse(self, ctx: commands.Context, *, text: t.Optional[str]) -> None: +        """ +        Reverses the sent text. + +        If no text is provided, the user's profile picture will be reversed. +        """ +        if text: +            await ctx.send(f"> {text[::-1]}", allowed_mentions=discord.AllowedMentions.none()) +            return + +        async with ctx.typing(): +            user = await self._fetch_user(ctx.author.id) +            if not user: +                await ctx.send(f"{Emojis.cross_mark} Could not get user info.") +                return + +            image_bytes = await user.avatar_url_as(size=1024).read() +            filename = file_safe_name("reverse_avatar", ctx.author.display_name) + +            file = await in_executor( +                PfpEffects.apply_effect, +                image_bytes, +                PfpEffects.flip_effect, +                filename +            ) + +            embed = discord.Embed( +                title="Your reversed avatar.", +                description="Here is your reversed avatar. I think it is a spitting image of you." +            ) + +            embed.set_image(url=f"attachment://{filename}") +            embed.set_footer(text=f"Made by {ctx.author.display_name}.", icon_url=user.avatar_url) + +            await ctx.send(embed=embed, file=file) +      @avatar_modify.command(aliases=("easterify",), root_aliases=("easterify", "avatareasterify"))      async def avatareasterify(self, ctx: commands.Context, *colours: t.Union[discord.Colour, str]) -> None:          """ @@ -301,10 +338,11 @@ class AvatarModify(commands.Cog):              img_bytes = await user.avatar_url_as(size=1024).read()              file = await in_executor( -                PfpEffects.mosaic_effect, +                PfpEffects.apply_effect,                  img_bytes, +                PfpEffects.mosaic_effect, +                file_name,                  squares, -                file_name              )              if squares == 1: diff --git a/bot/exts/evergreen/help.py b/bot/exts/evergreen/help.py index 3c9ba4d2..bfb5db17 100644 --- a/bot/exts/evergreen/help.py +++ b/bot/exts/evergreen/help.py @@ -8,7 +8,7 @@ from typing import List, NamedTuple, Union  from discord import Colour, Embed, HTTPException, Message, Reaction, User  from discord.ext import commands  from discord.ext.commands import CheckFailure, Cog as DiscordCog, Command, Context -from fuzzywuzzy import fuzz, process +from rapidfuzz import process  from bot import constants  from bot.bot import Bot @@ -159,7 +159,7 @@ class HelpSession:          # Combine command and cog names          choices = list(self._bot.all_commands) + list(self._bot.cogs) -        result = process.extractBests(query, choices, scorer=fuzz.ratio, score_cutoff=90) +        result = process.extract(query, choices, score_cutoff=90)          raise HelpQueryNotFound(f'Query "{query}" not found.', dict(result)) diff --git a/bot/exts/evergreen/snakes/_converter.py b/bot/exts/evergreen/snakes/_converter.py index 26bde611..c8d1909b 100644 --- a/bot/exts/evergreen/snakes/_converter.py +++ b/bot/exts/evergreen/snakes/_converter.py @@ -5,7 +5,7 @@ from typing import Iterable, List  import discord  from discord.ext.commands import Context, Converter -from fuzzywuzzy import fuzz +from rapidfuzz import fuzz  from bot.exts.evergreen.snakes._utils import SNAKE_RESOURCES  from bot.utils import disambiguate diff --git a/bot/exts/evergreen/trivia_quiz.py b/bot/exts/evergreen/trivia_quiz.py index 28924aed..bc25cbf7 100644 --- a/bot/exts/evergreen/trivia_quiz.py +++ b/bot/exts/evergreen/trivia_quiz.py @@ -9,7 +9,7 @@ from typing import Callable, List, Optional  import discord  from discord.ext import commands -from fuzzywuzzy import fuzz +from rapidfuzz import fuzz  from bot.bot import Bot  from bot.constants import Colours, NEGATIVE_REPLIES, Roles diff --git a/bot/exts/pride/pride_leader.py b/bot/exts/pride/pride_leader.py index c3426ad1..8e88183b 100644 --- a/bot/exts/pride/pride_leader.py +++ b/bot/exts/pride/pride_leader.py @@ -6,7 +6,7 @@ from typing import Optional  import discord  from discord.ext import commands -from fuzzywuzzy import fuzz +from rapidfuzz import fuzz  from bot import bot  from bot import constants diff --git a/bot/exts/valentines/lovecalculator.py b/bot/exts/valentines/lovecalculator.py index b10b7bca..1cb10e64 100644 --- a/bot/exts/valentines/lovecalculator.py +++ b/bot/exts/valentines/lovecalculator.py @@ -4,7 +4,7 @@ import json  import logging  import random  from pathlib import Path -from typing import Coroutine, Union +from typing import Coroutine, Optional  import discord  from discord import Member @@ -12,6 +12,8 @@ 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__) @@ -22,45 +24,45 @@ 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: Union[Member, str], whom: Union[Member, str] = None) -> None: +    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 accepts users or arbitrary strings as arguments. -        Users are converted from: +        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, though the order of arguments matters: -          Running .love joseph erlang will always yield the same result. -          Running .love erlang joseph won't yield the same result as .love joseph erlang - -        If you want to use multiple words for one argument, you must include quotes. -          .love "Zes Vappa" "morning coffee" +        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: Union[Member, str]) -> Coroutine: -            if isinstance(arg, Member): -                # If we are given a member, return name#discrim without any extra changes -                arg = str(arg) -            else: -                # Otherwise normalise case and remove any leading/trailing whitespace -                arg = arg.strip().title() +        def normalize(arg: Member) -> Coroutine:              # This has to be done manually to be applied to usernames -            return clean_content(escape_markdown=True).convert(ctx, arg) - -        who, whom = [await normalize(arg) for arg in (who, whom)] +            return clean_content(escape_markdown=True).convert(ctx, str(arg)) -        # Make sure user didn't provide something silly such as 10 spaces -        if not (who and whom): -            raise BadArgument("Arguments must be non-empty strings.") +        # 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)          # @@ -87,6 +89,7 @@ class LoveCalculator(Cog):              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) | 
