diff --git a/README.md b/README.md index 7efbfc6..ec088b7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # aikaterna-cogs v3 Cogs for Red-DiscordBot by Twentysix26. +antiphoneclapper - Detects and removes bad GIFs posted in chat that have malformed frames. Thanks to Sitryk for all of the code that actually mattered for detection in this cog. Config stuff tacked on by me. Later iterations will include emoji recognizing and possibly link detection for these bad images. + away - Originally by Paddo, written for v3 by Axas, final tests by aikaterna. Set and unset a user as being "away". blurplefy - Make an avatar or an image upload blurple for Discord's 3rd anniversary. diff --git a/antiphoneclapper/__init__.py b/antiphoneclapper/__init__.py new file mode 100644 index 0000000..2184f20 --- /dev/null +++ b/antiphoneclapper/__init__.py @@ -0,0 +1,5 @@ +from .antiphoneclapper import AntiPhoneClapper + + +async def setup(bot): + bot.add_cog(AntiPhoneClapper(bot)) diff --git a/antiphoneclapper/antiphoneclapper.py b/antiphoneclapper/antiphoneclapper.py new file mode 100644 index 0000000..fcff47d --- /dev/null +++ b/antiphoneclapper/antiphoneclapper.py @@ -0,0 +1,100 @@ +from PIL import Image +from io import BytesIO +import aiohttp +import discord + +from redbot.core import commands, checks, Config + +BaseCog = getattr(commands, "Cog", object) + + +class AntiPhoneClapper(BaseCog): + """This cog deletes bad GIFs that will crash phone clients.""" + def __init__(self, bot): + self.bot = bot + self.config = Config.get_conf(self, 2719371001, force_registration=True) + + default_guild = {"watching": []} + + self.config.register_guild(**default_guild) + + @commands.group() + @checks.mod_or_permissions(administrator=True) + @commands.guild_only() + async def nogif(self, ctx): + """Configuration options.""" + pass + + @nogif.command() + async def watch(self, ctx, channel: discord.TextChannel): + """Add a channel to watch. Gifs that break mobile clients will be removed in these channels.""" + channel_list = await self.config.guild(ctx.guild).watching() + if channel.id not in channel_list: + channel_list.append(channel.id) + await self.config.guild(ctx.guild).watching.set(channel_list) + await ctx.send(f"{self.bot.get_channel(channel.id).mention} will have bad gifs removed.") + + @nogif.command() + async def watchlist(self, ctx): + """List the channels being watched.""" + channel_list = await self.config.guild(ctx.guild).watching() + msg = "Bad gifs will be removed in:\n" + for channel in channel_list: + channel_obj = self.bot.get_channel(channel) + msg += f"{channel_obj.mention}\n" + await ctx.send(msg) + + @nogif.command() + async def unwatch(self, ctx, channel: discord.TextChannel): + """Remove a channel from the watch list.""" + channel_list = await self.config.guild(ctx.guild).watching() + if channel.id in channel_list: + channel_list.remove(channel.id) + else: + return await ctx.send("Channel is not being watched.") + await self.config.guild(ctx.guild).watching.set(channel_list) + await ctx.send(f"{self.bot.get_channel(channel.id).mention} will not have bad gifs removed.") + + def is_phone_clapper(self, im): + limit = im.size + tile_sizes = [] + for frame in range(im.n_frames): + im.seek(frame) + tile_sizes.append(im.tile[0][1][2:]) + return any([x[0] > limit[0] or x[1] > limit[1] for x in tile_sizes]) + + async def on_message(self, m): + if not m.attachments: + return + if isinstance(m.channel, discord.abc.PrivateChannel): + return + if m.author.bot: + return + watch_channel_list = await self.config.guild(m.guild).watching() + if not watch_channel_list: + return + + for att in m.attachments: + if not att.filename.endswith('.gif') or att.size > 200000: + continue + + async with aiohttp.ClientSession().get(att.url) as resp: + data = await resp.content.read() + f = BytesIO(data) + try: + img = Image.open(f) + phone_clapper = self.is_phone_clapper(img) + except Image.DecompressionBombError: + phone_clapper = True + + if phone_clapper: + try: + await m.delete() + await m.channel.send(f"{m.author.mention} just tried to send a phone-killing GIF and I removed it.") + return + except discord.errors.Forbidden: + await m.channel.send(f"Don't send GIFs that do that, {m.author.mention}") + print(f'Failed to delete message ({m.id}) that contained phone killing gif') + return + else: + return diff --git a/antiphoneclapper/info.json b/antiphoneclapper/info.json new file mode 100644 index 0000000..e5f3b3c --- /dev/null +++ b/antiphoneclapper/info.json @@ -0,0 +1,15 @@ +{ + "author": [ + "sitryk", "aikaterna" + ], + "description": "Deletes messages with malformed GIFs.", + "install_msg": "Thanks for installing, have fun.", + "permissions" : [ + "manage_messages", + ], + "requirements": [ + "pillow", + ], + "short": "Deletes messages with malformed GIFs.", + "type": "COG" +} \ No newline at end of file