added jpeg compress to imagmagic, fixed some issues with rolemanagement age

This commit is contained in:
Brandon 2023-02-01 16:42:00 -05:00
parent b56b54578a
commit df579194c2
5 changed files with 109 additions and 21 deletions

View file

@ -4,6 +4,7 @@ from wand.image import Image
from io import BytesIO from io import BytesIO
from typing import Optional, Tuple, Literal from typing import Optional, Tuple, Literal
import asyncio, functools, urllib import asyncio, functools, urllib
from PIL import Image as PILImage
MAX_SIZE = 8 * 1024 * 1024 MAX_SIZE = 8 * 1024 * 1024
@ -18,7 +19,9 @@ class ImageMagic(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
super().__init__() 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 self.bot = bot
async def _get_image(self, ctx, link: str = None) -> Image: async def _get_image(self, ctx, link: str = None) -> Image:
@ -33,7 +36,9 @@ class ImageMagic(commands.Cog):
if ctx.message.reference: if ctx.message.reference:
msg = ctx.message.reference.resolved msg = ctx.message.reference.resolved
if msg is None: 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: if msg and msg.attachments:
for a in msg.attachments: for a in msg.attachments:
path = urllib.parse.urlparse(a.url).path path = urllib.parse.urlparse(a.url).path
@ -61,7 +66,9 @@ class ImageMagic(commands.Cog):
except: except:
raise ImageFindError("Invalid filetype") raise ImageFindError("Invalid filetype")
except (OSError, aiohttp.ClientError): 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 else: # attached image
path = urllib.parse.urlparse(ctx.message.attachments[0].url).path path = urllib.parse.urlparse(ctx.message.attachments[0].url).path
if ctx.message.attachments[0].size > max_filesize: if ctx.message.attachments[0].size > max_filesize:
@ -85,6 +92,27 @@ class ImageMagic(commands.Cog):
intensity /= 10 intensity /= 10
return intensity 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]: def _distortion(self, img: Image, func: str, args: Tuple) -> Tuple[Image, str]:
# distort # distort
img.iterator_reset() img.iterator_reset()
@ -110,7 +138,9 @@ class ImageMagic(commands.Cog):
return return
try: 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: except discord.errors.HTTPException:
await ctx.reply("That image is too large.", mention_author=False) await ctx.reply("That image is too large.", mention_author=False)
return return
@ -126,8 +156,21 @@ class ImageMagic(commands.Cog):
pass pass
@distort.command() @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 Bulges the center of the image outward
""" """
@ -145,7 +188,10 @@ class ImageMagic(commands.Cog):
self._distortion, self._distortion,
img, img,
"distort", "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: except ImageFindError as e:
return await ctx.reply(e, mention_author=False) 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() @distort.command()
async def swirl(self, ctx, intensity: Optional[float] = 10, *, link: str = None): 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 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)) intensity = float(switch.get(round(intensity), 180))
async with ctx.typing(): async with ctx.typing():
@ -179,7 +239,9 @@ class ImageMagic(commands.Cog):
except ImageFindError as e: except ImageFindError as e:
return await ctx.reply(e, mention_author=False) 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() @distort.command()
async def charcoal(self, ctx, intensity: Optional[float], *, link: str = None): async def charcoal(self, ctx, intensity: Optional[float], *, link: str = None):
@ -193,7 +255,9 @@ class ImageMagic(commands.Cog):
except ImageFindError as e: except ImageFindError as e:
return await ctx.reply(e, mention_author=False) 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() @distort.command()
async def sketch(self, ctx, intensity: Optional[float], *, link: str = None): async def sketch(self, ctx, intensity: Optional[float], *, link: str = None):
@ -207,7 +271,9 @@ class ImageMagic(commands.Cog):
except ImageFindError as e: except ImageFindError as e:
return await ctx.reply(e, mention_author=False) 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() @distort.command()
async def zoom(self, ctx, intensity: Optional[float], *, link: str = None): async def zoom(self, ctx, intensity: Optional[float], *, link: str = None):
@ -225,7 +291,15 @@ class ImageMagic(commands.Cog):
w = img.width w = img.width
img = self._distortion(img, "transform", (f"{w}x{h}", "150%"))[0] 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( async def red_delete_data_for_user(

View file

@ -7,5 +7,8 @@
"description": "Manipulates images.", "description": "Manipulates images.",
"hidden": false, "hidden": false,
"end_user_data_statement": "This cog does not store user data.", "end_user_data_statement": "This cog does not store user data.",
"requirements": ["wand"] "requirements": [
} "wand",
"Pillow"
]
}

View file

@ -1,6 +1,6 @@
from .core import RoleManagement 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): def setup(bot):

View file

@ -101,6 +101,7 @@ class RoleManagement(
age_verification=None, age_verification=None,
) # subscribed_users maps str(user.id)-> end time in unix timestamp ) # subscribed_users maps str(user.id)-> end time in unix timestamp
self.config.register_member(roles=[], forbidden=[], birthday=None) self.config.register_member(roles=[], forbidden=[], birthday=None)
self.config.register_user(birthday=None)
self.config.init_custom("REACTROLE", 2) self.config.init_custom("REACTROLE", 2)
self.config.register_custom( self.config.register_custom(
"REACTROLE", roleid=None, channelid=None, guildid=None "REACTROLE", roleid=None, channelid=None, guildid=None
@ -176,6 +177,16 @@ class RoleManagement(
except RuntimeError: except RuntimeError:
pass 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() self._ready.set()
async def wait_for_ready(self): async def wait_for_ready(self):
@ -295,7 +306,7 @@ class RoleManagement(
) )
return 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() await ctx.tick()
@commands.guild_only() @commands.guild_only()
@ -1279,7 +1290,7 @@ class RoleManagement(
member = ctx.author member = ctx.author
guild = member.guild 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() min_age = await self.config.role(role).age_verification()
age_log = await self.config.guild(guild).age_log() age_log = await self.config.guild(guild).age_log()
today = datetime.utcnow().date() today = datetime.utcnow().date()
@ -1351,7 +1362,7 @@ class RoleManagement(
await member.send( 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." 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: if age_log:
try: try:
await modlog.create_case( await modlog.create_case(
@ -1424,4 +1435,4 @@ class RoleManagement(
requester: Literal["discord_deleted_user", "owner", "user", "user_strict"], requester: Literal["discord_deleted_user", "owner", "user", "user_strict"],
user_id: int, user_id: int,
): ):
pass await self.config.user_from_id(user_id).clear()

View file

@ -18,5 +18,5 @@
], ],
"hidden": false, "hidden": false,
"min_bot_version": "3.4.0", "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."
} }