From df579194c21d0d51d724e45fcd503769f68b73e3 Mon Sep 17 00:00:00 2001 From: Brandon Date: Wed, 1 Feb 2023 16:42:00 -0500 Subject: [PATCH] added jpeg compress to imagmagic, fixed some issues with rolemanagement age --- imagemagic/imagemagic.py | 98 +++++++++++++++++++++++++++++++++----- imagemagic/info.json | 7 ++- rolemanagement/__init__.py | 2 +- rolemanagement/core.py | 19 ++++++-- rolemanagement/info.json | 4 +- 5 files changed, 109 insertions(+), 21 deletions(-) diff --git a/imagemagic/imagemagic.py b/imagemagic/imagemagic.py index fde77d5..40db8a2 100644 --- a/imagemagic/imagemagic.py +++ b/imagemagic/imagemagic.py @@ -4,6 +4,7 @@ from wand.image import Image from io import BytesIO from typing import Optional, Tuple, Literal import asyncio, functools, urllib +from PIL import Image as PILImage MAX_SIZE = 8 * 1024 * 1024 @@ -18,7 +19,9 @@ class ImageMagic(commands.Cog): def __init__(self, bot): super().__init__() - self.config = Config.get_conf(self, identifier=4928034571, force_registration=True) + self.config = Config.get_conf( + self, identifier=4928034571, force_registration=True + ) self.bot = bot async def _get_image(self, ctx, link: str = None) -> Image: @@ -33,7 +36,9 @@ class ImageMagic(commands.Cog): if ctx.message.reference: msg = ctx.message.reference.resolved if msg is None: - msg = await ctx.channel.fetch_message(ctx.message.reference.message_id) + msg = await ctx.channel.fetch_message( + ctx.message.reference.message_id + ) if msg and msg.attachments: for a in msg.attachments: path = urllib.parse.urlparse(a.url).path @@ -61,7 +66,9 @@ class ImageMagic(commands.Cog): except: raise ImageFindError("Invalid filetype") except (OSError, aiohttp.ClientError): - raise ImageFindError("An image could not be found. Make sure you provide a direct link.") + raise ImageFindError( + "An image could not be found. Make sure you provide a direct link." + ) else: # attached image path = urllib.parse.urlparse(ctx.message.attachments[0].url).path if ctx.message.attachments[0].size > max_filesize: @@ -85,6 +92,27 @@ class ImageMagic(commands.Cog): intensity /= 10 return intensity + def _jpeg_compress(self, img: Image, quality: int) -> Image: + # save image to temp variable to load it as a PIL image + temp_file = BytesIO() + img.save(file=temp_file) + temp_file.seek(0) + + # load as PIL image + pil_img = PILImage.open(temp_file) + img = PILImage.new("RGB", pil_img.size) + img.paste(pil_img) + + # compress + temp_file = BytesIO() + img.save(temp_file, "JPEG", quality=quality) + temp_file.seek(0) + + # return as wand image + img = Image(file=temp_file) + + return img, "jpeg.jpeg" + def _distortion(self, img: Image, func: str, args: Tuple) -> Tuple[Image, str]: # distort img.iterator_reset() @@ -110,7 +138,9 @@ class ImageMagic(commands.Cog): return try: - await ctx.reply(file=discord.File(BytesIO(img.make_blob()), name), mention_author=False) + await ctx.reply( + file=discord.File(BytesIO(img.make_blob()), name), mention_author=False + ) except discord.errors.HTTPException: await ctx.reply("That image is too large.", mention_author=False) return @@ -126,8 +156,21 @@ class ImageMagic(commands.Cog): pass @distort.command() - async def barrel(self, ctx, intensity: Optional[float] = 10, *, link: str = None): + async def jpeg(self, ctx, quality: Optional[float] = 10, *, link: str = None): + """ + Applies JPEG compression to image + """ + quality = int(self._intensity(quality) * 100) + async with ctx.typing(): + try: + img = await self._get_image(ctx, link) + except ImageFindError as e: + return await ctx.reply(e, mention_author=False) + await self._command_body(ctx, args=(self._jpeg_compress, img, quality)) + + @distort.command() + async def barrel(self, ctx, intensity: Optional[float] = 10, *, link: str = None): """ Bulges the center of the image outward """ @@ -145,7 +188,10 @@ class ImageMagic(commands.Cog): self._distortion, img, "distort", - ("barrel", (amount * intensity, amount * intensity, amount * intensity, 0)), + ( + "barrel", + (amount * intensity, amount * intensity, amount * intensity, 0), + ), ), ) @@ -162,7 +208,9 @@ class ImageMagic(commands.Cog): except ImageFindError as e: return await ctx.reply(e, mention_author=False) - await self._command_body(ctx, args=(self._distortion, img, "implode", (amount * intensity,))) + await self._command_body( + ctx, args=(self._distortion, img, "implode", (amount * intensity,)) + ) @distort.command() async def swirl(self, ctx, intensity: Optional[float] = 10, *, link: str = None): @@ -170,7 +218,19 @@ class ImageMagic(commands.Cog): Swirls the center of the image """ - switch = {0: 0, 1: 18, 2: 36, 3: 54, 4: 72, 5: 90, 6: 108, 7: 126, 8: 144, 9: 162, 10: 180} + switch = { + 0: 0, + 1: 18, + 2: 36, + 3: 54, + 4: 72, + 5: 90, + 6: 108, + 7: 126, + 8: 144, + 9: 162, + 10: 180, + } intensity = float(switch.get(round(intensity), 180)) async with ctx.typing(): @@ -179,7 +239,9 @@ class ImageMagic(commands.Cog): except ImageFindError as e: return await ctx.reply(e, mention_author=False) - await self._command_body(ctx, args=(self._distortion, img, "swirl", (intensity,))) + await self._command_body( + ctx, args=(self._distortion, img, "swirl", (intensity,)) + ) @distort.command() async def charcoal(self, ctx, intensity: Optional[float], *, link: str = None): @@ -193,7 +255,9 @@ class ImageMagic(commands.Cog): except ImageFindError as e: return await ctx.reply(e, mention_author=False) - await self._command_body(ctx, args=(self._distortion, img, "charcoal", (1.5, 0.5))) + await self._command_body( + ctx, args=(self._distortion, img, "charcoal", (1.5, 0.5)) + ) @distort.command() async def sketch(self, ctx, intensity: Optional[float], *, link: str = None): @@ -207,7 +271,9 @@ class ImageMagic(commands.Cog): except ImageFindError as e: return await ctx.reply(e, mention_author=False) - await self._command_body(ctx, args=(self._distortion, img, "sketch", (0.5, 0.0, 98.0))) + await self._command_body( + ctx, args=(self._distortion, img, "sketch", (0.5, 0.0, 98.0)) + ) @distort.command() async def zoom(self, ctx, intensity: Optional[float], *, link: str = None): @@ -225,7 +291,15 @@ class ImageMagic(commands.Cog): w = img.width img = self._distortion(img, "transform", (f"{w}x{h}", "150%"))[0] - await self._command_body(ctx, args=(self._distortion, img, "transform", (f"{w/1.5}x{h/1.5}+{w/2}+{h/2}",))) + await self._command_body( + ctx, + args=( + self._distortion, + img, + "transform", + (f"{w/1.5}x{h/1.5}+{w/2}+{h/2}",), + ), + ) async def red_delete_data_for_user( diff --git a/imagemagic/info.json b/imagemagic/info.json index 1db353c..593c9a4 100644 --- a/imagemagic/info.json +++ b/imagemagic/info.json @@ -7,5 +7,8 @@ "description": "Manipulates images.", "hidden": false, "end_user_data_statement": "This cog does not store user data.", - "requirements": ["wand"] -} + "requirements": [ + "wand", + "Pillow" + ] +} \ No newline at end of file diff --git a/rolemanagement/__init__.py b/rolemanagement/__init__.py index e9b9d3e..f81f125 100644 --- a/rolemanagement/__init__.py +++ b/rolemanagement/__init__.py @@ -1,6 +1,6 @@ from .core import RoleManagement -__red_end_user_data_statement__ = "This will only store sticky and subscribed roles for users." +__red_end_user_data_statement__ = "This will only store birthdays, sticky, and subscribed roles for users." def setup(bot): diff --git a/rolemanagement/core.py b/rolemanagement/core.py index 5cefdaf..901fa91 100644 --- a/rolemanagement/core.py +++ b/rolemanagement/core.py @@ -101,6 +101,7 @@ class RoleManagement( age_verification=None, ) # subscribed_users maps str(user.id)-> end time in unix timestamp self.config.register_member(roles=[], forbidden=[], birthday=None) + self.config.register_user(birthday=None) self.config.init_custom("REACTROLE", 2) self.config.register_custom( "REACTROLE", roleid=None, channelid=None, guildid=None @@ -176,6 +177,16 @@ class RoleManagement( except RuntimeError: pass + # fix moving birthdays to user config from member config + for guild in self.bot.guilds: + for member in guild.members: + m_age = await self.config.member(member).birthday() + u_age = await self.config.user(member).birthday() + + if m_age and u_age is None: + await self.config.user(member).birthday.set(m_age) + await self.config.member(member).birthday.set(None) + self._ready.set() async def wait_for_ready(self): @@ -295,7 +306,7 @@ class RoleManagement( ) return - await self.config.member(member).birthday.set(dob.strftime("%m/%d/%Y")) + await self.config.user(member).birthday.set(dob.strftime("%m/%d/%Y")) await ctx.tick() @commands.guild_only() @@ -1279,7 +1290,7 @@ class RoleManagement( member = ctx.author guild = member.guild - dob = await self.config.member(member).birthday() + dob = await self.config.user(member).birthday() min_age = await self.config.role(role).age_verification() age_log = await self.config.guild(guild).age_log() today = datetime.utcnow().date() @@ -1351,7 +1362,7 @@ class RoleManagement( await member.send( f"Thank you! Please check back in `{guild}` to confirm you obtained the role. If not, you may not meet the age requirement for the role." ) - await self.config.member(member).birthday.set(dob_str) + await self.config.user(member).birthday.set(dob_str) if age_log: try: await modlog.create_case( @@ -1424,4 +1435,4 @@ class RoleManagement( requester: Literal["discord_deleted_user", "owner", "user", "user_strict"], user_id: int, ): - pass + await self.config.user_from_id(user_id).clear() diff --git a/rolemanagement/info.json b/rolemanagement/info.json index 68aa795..07f3d06 100644 --- a/rolemanagement/info.json +++ b/rolemanagement/info.json @@ -18,5 +18,5 @@ ], "hidden": false, "min_bot_version": "3.4.0", - "end_user_data_statement": "This will only store sticky and subscribed roles for users." -} + "end_user_data_statement": "This will only store birthdays, sticky, and subscribed roles for users." +} \ No newline at end of file