diff --git a/src/main/cogs/booru.py b/src/main/cogs/booru.py
index ce82483..3fa5425 100644
--- a/src/main/cogs/booru.py
+++ b/src/main/cogs/booru.py
@@ -19,1265 +19,1262 @@ from utils import formatter, scraper
class MsG:
- def __init__(self, bot):
- self.bot = bot
- self.color = d.Color(0x1A1A1A)
- self.LIMIT = 100
- self.RATE_LIMIT = u.RATE_LIMIT
- self.queue = asyncio.Queue()
+ def __init__(self, bot):
+ self.bot = bot
+ self.color = d.Color(0x1A1A1A)
+ self.LIMIT = 100
+ self.RATE_LIMIT = u.RATE_LIMIT
+ self.HISTORY_LIMIT = 99
+ self.queue = asyncio.Queue()
+ self.qualitifying = False
+
+ self.favorites = u.setdefault('cogs/favorites.pkl', {'tags': set(), 'posts': set()})
+ self.blacklists = u.setdefault(
+ 'cogs/blacklists.pkl', {'global_blacklist': set(), 'guild_blacklist': {}, 'user_blacklist': {}})
+ self.aliases = u.setdefault('cogs/aliases.pkl', {})
+
+ if u.tasks['auto_qual']:
+ for channel in u.tasks['auto_qual']:
+ temp = self.bot.get_channel(channel)
+ self.bot.loop.create_task(self.queue_for_qualitification(temp))
+ print('AUTO-QUALITIFYING : #{}'.format(temp.name))
+ self.bot.loop.create_task(self._qualitify())
+ self.qualitifying = True
+
+ # Tag search
+ @commands.command(aliases=['rel'], brief='e621 Related tag search', description='e621 | NSFW\nReturn a link search for given tags')
+ @checks.del_ctx()
+ async def related(self, ctx, *args):
+ dest, tags = u.get_args(ctx, args, rem=True)
+ related = []
+
+ await dest.trigger_typing()
+
+ for tag in tags:
+ tag_request = await u.fetch('https://e621.net/tag/related.json', params={'tags': tag, 'type': 'general'}, json=True)
+ for rel in tag_request.get(tag, [None]):
+ related.append(rel[0])
+
+ await dest.send('`{}` **related tags:**\n```\n{}```'.format(tag, formatter.tostring(related)))
+
+ related.clear()
+
+ await ctx.message.add_reaction('✅')
+
+ # Tag aliases
+ @commands.command(name='aliases', aliases=['alias'], brief='e621 Tag aliases', description='e621 | NSFW\nSearch aliases for given tag')
+ @checks.del_ctx()
+ async def tag_aliases(self, ctx, *args):
+ dest, tags = u.get_args(ctx, args, rem=True)
+ aliases = []
+
+ await dest.trigger_typing()
+
+ for tag in tags:
+ alias_request = await u.fetch('https://e621.net/tag_alias/index.json', params={'aliased_to': tag, 'approved': 'true'}, json=True)
+ for dic in alias_request:
+ aliases.append(dic['name'])
+
+ await dest.send('`{}` **aliases:**\n```\n{}```'.format(tag, formatter.tostring(aliases)))
+
+ aliases.clear()
+
+ await ctx.message.add_reaction('✅')
+
+ @commands.command(name='getimage', aliases=['geti', 'gi'])
+ @checks.del_ctx()
+ async def get_image(self, ctx, *args):
+ try:
+ dest, urls = u.get_args(ctx, args, rem=True)
+
+ if not urls:
+ raise exc.MissingArgument
+
+ for url in urls:
+ try:
+ await dest.trigger_typing()
+
+ await dest.send('{}'.format(await scraper.get_image(url)))
+
+ finally:
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ await ctx.message.add_reaction('✅')
+
+ except exc.MissingArgument:
+ await ctx.send('**Invalid url or file.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ # Reverse image searches a linked image using the public iqdb
+ @commands.command(name='reverse', aliases=['rev', 'ris'], brief='e621 Reverse image search', description='e621 | NSFW\nReverse-search an image with given URL')
+ @checks.del_ctx()
+ async def reverse_image_search(self, ctx, *args):
+ try:
+ dest, urls = u.get_args(ctx, args, rem=True)
+ c = 0
+
+ if not urls and not ctx.message.attachments:
+ raise exc.MissingArgument
+
+ for url in urls:
+ try:
+ await dest.trigger_typing()
+
+ await dest.send('**Probable match:**\n{}'.format(await scraper.get_post(url)))
+
+ c += 1
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ except exc.MatchError as e:
+ await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+
+ for attachment in ctx.message.attachments:
+ try:
+ await dest.trigger_typing()
+
+ await dest.send('**Probable match:**\n{}'.format(await scraper.get_post(attachment.url)))
+
+ c += 1
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ except exc.MatchError as e:
+ await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+
+ if c:
+ await ctx.message.add_reaction('✅')
+ else:
+ await ctx.message.add_reaction('❌')
+
+ except exc.MissingArgument:
+ await ctx.send('**Invalid url or file.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ @commands.command(name='quality', aliases=['qual', 'qrev', 'qis'])
+ @checks.del_ctx()
+ async def quality_reverse_image_search(self, ctx, *args):
+ try:
+ dest, urls = u.get_args(ctx, args, rem=True)
+ c = 0
+
+ if not urls and not ctx.message.attachments:
+ raise exc.MissingArgument
+
+ for url in urls:
+ try:
+ await dest.trigger_typing()
+
+ post = await scraper.get_post(url)
+
+ await dest.send('**Probable match:**\n{}'.format(await scraper.get_image(post)))
+
+ c += 1
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ except exc.MatchError as e:
+ await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+
+ for attachment in ctx.message.attachments:
+ try:
+ await dest.trigger_typing()
+
+ post = await scraper.get_post(attachment.url)
+
+ await dest.send('**Probable match:**\n{}'.format(await scraper.get_image(post)))
+
+ c += 1
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ except exc.MatchError as e:
+ await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+
+ if c:
+ await ctx.message.add_reaction('✅')
+ else:
+ await ctx.message.add_reaction('❌')
+
+ except exc.MissingArgument:
+ await ctx.send('**Invalid url or file.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ @commands.command(name='reversify', aliases=['revify', 'risify', 'rify'])
+ @checks.del_ctx()
+ async def reversify(self, ctx, *args):
+ try:
+ dest, remove, limit = u.get_args(ctx, args, rm=True, lim=self.HISTORY_LIMIT)
+ urls = []
+ attachments = []
+
+ if not ctx.author.permissions_in(ctx.channel).manage_messages:
+ dest = ctx.author
+
+ async for message in ctx.channel.history(limit=limit + 1):
+ if message.author.id != self.bot.user.id and re.search('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content) is not None:
+ urls.append(message)
+ await message.add_reaction('⏳')
+ elif message.author.id != self.bot.user.id and message.attachments:
+ attachments.append(message)
+ await message.add_reaction('⏳')
+
+ if not urls and not attachments:
+ raise exc.NotFound
+
+ for message in urls:
+ for match in re.finditer('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content):
+ try:
+ await dest.trigger_typing()
+
+ await dest.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_post(match.group(0))))
+ await message.add_reaction('✅')
+
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ if remove:
+ with suppress(err.NotFound):
+ await message.delete()
+
+ except exc.MatchError as e:
+ await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+ await message.add_reaction('❌')
+
+ for message in attachments:
+ for attachment in message.attachments:
+ try:
+ await dest.trigger_typing()
+
+ await dest.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_post(attachment.url)))
+ await message.add_reaction('✅')
+
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ if remove:
+ with suppress(err.NotFound):
+ await message.delete()
+
+ except exc.MatchError as e:
+ await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+ await message.add_reaction('❌')
+
+ await ctx.message.add_reaction('✅')
+
+ except exc.NotFound:
+ await ctx.send('**No matches found.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except ValueError:
+ await ctx.send('**Invalid limit.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ @commands.command(name='qualitify', aliases=['qualify', 'qrevify', 'qrisify', 'qify'])
+ @checks.del_ctx()
+ async def qualitify(self, ctx, *args):
+ try:
+ dest, remove, limit = u.get_args(ctx, args, rm=True, lim=self.HISTORY_LIMIT)
+ urls = []
+ attachments = []
+
+ if not ctx.author.permissions_in(ctx.channel).manage_messages:
+ dest = ctx.author
+
+ async for message in ctx.channel.history(limit=limit + 1):
+ if message.author.id != self.bot.user.id and re.search('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content) is not None:
+ urls.append(message)
+ await message.add_reaction('⏳')
+ elif message.author.id != self.bot.user.id and message.attachments:
+ attachments.append(message)
+ await message.add_reaction('⏳')
+
+ if not urls and not attachments:
+ raise exc.NotFound
+
+ for message in urls:
+ for match in re.finditer('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content):
+ try:
+ await dest.trigger_typing()
+
+ post = await scraper.get_post(match.group(0))
+
+ await dest.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_image(post)))
+ await message.add_reaction('✅')
+
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ if remove:
+ with suppress(err.NotFound):
+ await message.delete()
+
+ except exc.MatchError as e:
+ await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+ await message.add_reaction('❌')
+
+ for message in attachments:
+ for attachment in message.attachments:
+ try:
+ await dest.trigger_typing()
+
+ post = await scraper.get_post(attachment.url)
+
+ await dest.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_image(post)))
+ await message.add_reaction('✅')
+
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ if remove:
+ with suppress(err.NotFound):
+ await message.delete()
+
+ except exc.MatchError as e:
+ await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+ await message.add_reaction('❌')
+
+ await ctx.message.add_reaction('✅')
+
+ except exc.NotFound:
+ await ctx.send('**No matches found.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except ValueError:
+ await ctx.send('**Invalid limit.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ async def _qualitify(self):
+ while self.qualitifying:
+ message = await self.queue.get()
+
+ for match in re.finditer('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content):
+ try:
+ await message.channel.trigger_typing()
+
+ post = await scraper.get_post(match.group(0))
+
+ await message.channel.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_image(post)))
+ await message.add_reaction('✅')
+
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ with suppress(err.NotFound):
+ await message.delete()
+
+ except exc.MatchError as e:
+ await message.channel.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+ await message.add_reaction('❌')
+
+ for attachment in message.attachments:
+ try:
+ await message.channel.trigger_typing()
+
+ post = await scraper.get_post(attachment.url)
+
+ await message.channel.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_image(post)))
+ await message.add_reaction('✅')
+
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ with suppress(err.NotFound):
+ await message.delete()
+
+ except exc.MatchError as e:
+ await message.channel.send('**No probable match for:** `{}`'.format(e), delete_after=10)
+ await message.add_reaction('❌')
+
+ print('STOPPED : qualitifying')
+
+ async def queue_for_qualitification(self, channel):
+ def check(msg):
+ if msg.content.lower() == 'stop' and msg.channel is channel and msg.author.guild_permissions.administrator:
+ raise exc.Abort
+ elif msg.channel is channel and message.author.id != self.bot.user.id and (re.search('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', msg.content) is not None or msg.attachments):
+ return True
+ return False
+
+ try:
+ while not self.bot.is_closed():
+ message = await self.bot.wait_for('message', check=check)
+ await self.queue.put(message)
+ await message.add_reaction('⏳')
+
+ except exc.Abort:
+ u.tasks['auto_qual'].remove(channel.id)
+ u.dump(u.tasks, 'cogs/tasks.pkl')
+ if not u.tasks['auto_qual']:
self.qualitifying = False
+ print('STOPPED : qualitifying #{}'.format(channel.name))
+ await channel.send('**Stopped queueing messages for qualitification in** {}**.**'.format(channel.mention), delete_after=5)
- self.favorites = u.setdefault('cogs/favorites.pkl', {'tags': set(), 'posts': set()})
- self.blacklists = u.setdefault(
- 'cogs/blacklists.pkl', {'global_blacklist': set(), 'guild_blacklist': {}, 'user_blacklist': {}})
- self.aliases = u.setdefault('cogs/aliases.pkl', {})
-
- if u.tasks['auto_qual']:
- for channel in u.tasks['auto_qual']:
- temp = self.bot.get_channel(channel)
- self.bot.loop.create_task(self.queue_for_qualitification(temp))
- print('AUTO-QUALITIFYING : #{}'.format(temp.name))
- self.bot.loop.create_task(self._qualitify())
- self.qualitifying = True
-
- # Tag search
- @commands.command(aliases=['rel'], brief='e621 Related tag search', description='e621 | NSFW\nReturn a link search for given tags')
- @checks.del_ctx()
- async def related(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
- related = []
-
- await dest.trigger_typing()
-
- for tag in tags:
- tag_request = await u.fetch('https://e621.net/tag/related.json', params={'tags': tag, 'type': 'general'}, json=True)
- for rel in tag_request.get(tag, [None]):
- related.append(rel[0])
-
- await dest.send('`{}` **related tags:**\n```\n{}```'.format(tag, formatter.tostring(related)))
-
- related.clear()
+ @commands.command(name='autoqualitify', aliases=['autoqual'])
+ @commands.has_permissions(manage_channels=True)
+ async def auto_qualitify(self, ctx):
+ try:
+ if ctx.channel.id not in u.tasks['auto_qual']:
+ u.tasks['auto_qual'].append(ctx.channel.id)
+ u.dump(u.tasks, 'cogs/tasks.pkl')
+ self.bot.loop.create_task(self.queue_for_qualitification(ctx.channel))
+ if not self.qualitifying:
+ self.bot.loop.create_task(self._qualitify())
+ self.qualitifying = True
+ print('AUTO-QUALITIFYING : #{}'.format(ctx.channel.name))
+ await ctx.send('**Auto-qualitifying all images in {}.**'.format(ctx.channel.mention), delete_after=5)
await ctx.message.add_reaction('✅')
+ else:
+ raise exc.Exists
- # Tag aliases
- @commands.command(name='aliases', aliases=['alias'], brief='e621 Tag aliases', description='e621 | NSFW\nSearch aliases for given tag')
- @checks.del_ctx()
- async def tag_aliases(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
- aliases = []
+ except exc.Exists:
+ await ctx.send('**Already auto-qualitifying in {}.** Type `stop` to stop.'.format(ctx.channel.mention), delete_after=10)
+ await ctx.message.add_reaction('❌')
- await dest.trigger_typing()
+ def get_favorites(self, ctx, args):
+ if '-f' in args or '-favs' in args or '-faves' in args or '-favorites' in args:
+ if self.favorites.get(ctx.author.id, {}).get('tags', set()):
+ args = ['~{}'.format(tag) for tag in self.favorites[ctx.author.id]['tags']]
+ else:
+ raise exc.FavoritesNotFound
- for tag in tags:
- alias_request = await u.fetch('https://e621.net/tag_alias/index.json', params={'aliased_to': tag, 'approved': 'true'}, json=True)
- for dic in alias_request:
- aliases.append(dic['name'])
+ return args
- await dest.send('`{}` **aliases:**\n```\n{}```'.format(tag, formatter.tostring(aliases)))
+ async def return_pool(self, ctx, *, booru='e621', query=[]):
+ def on_message(msg):
+ if msg.content.lower() == 'cancel' and msg.author is ctx.author and msg.channel is ctx.channel:
+ raise exc.Abort
+ with suppress(ValueError):
+ if int(msg.content) <= len(pools) and int(msg.content) > 0 and msg.author is ctx.author and msg.channel is ctx.channel:
+ return True
+ return False
- aliases.clear()
+ posts = {}
+ pool = {}
- await ctx.message.add_reaction('✅')
+ pools = []
+ pool_request = await u.fetch('https://{}.net/pool/index.json'.format(booru), params={'query': ' '.join(query)}, json=True)
+ if len(pool_request) > 1:
+ for pool in pool_request:
+ pools.append(pool['name'])
+ match = await ctx.send('**Multiple pools found.** Type in the correct match.\n```\n{}```\nor `cancel` to cancel.'.format('\n'.join(['{} {}'.format(c, elem) for c, elem in enumerate(pools, 1)])))
+ try:
+ selection = await self.bot.wait_for('message', check=on_message, timeout=10 * 60)
+ except exc.Abort:
+ raise exc.Abort
+ finally:
+ await match.delete()
+ tempool = [pool for pool in pool_request if pool['name']
+ == pools[int(selection.content) - 1]][0]
+ await selection.delete()
+ pool = {'name': tempool['name'], 'id': tempool['id']}
+ elif pool_request:
+ tempool = pool_request[0]
+ pool = {'name': pool_request[0]['name'], 'id': pool_request[0]['id']}
+ else:
+ raise exc.NotFound
- @commands.command(name='getimage', aliases=['geti', 'gi'])
- @checks.del_ctx()
- async def get_image(self, ctx, *args):
- dest, urls = u.get_args(ctx, args, rem=True)
+ page = 1
+ while len(posts) < tempool['post_count']:
+ posts_request = await u.fetch('https://{}.net/pool/show.json'.format(booru), params={'id': tempool['id'], 'page': page}, json=True)
+ for post in posts_request['posts']:
+ posts[post['id']] = {'author': post['author'], 'url': post['file_url']}
+ page += 1
+ return pool, posts
+
+ # Creates reaction-based paginator for linked pools
+ @commands.command(name='pool', aliases=['e6pp'], brief='e621 pool paginator', description='e621 | NSFW\nShow pools in a page format', hidden=True)
+ @checks.del_ctx()
+ async def pool_paginator(self, ctx, *args):
+ def on_reaction(reaction, user):
+ if reaction.emoji == '🚫' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.Abort
+ elif reaction.emoji == '📁' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.Save
+ elif reaction.emoji == '⬅' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.Left
+ elif reaction.emoji == '🔢' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.GoTo
+ elif reaction.emoji == '➡' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.Right
+ return False
+
+ def on_message(msg):
+ with suppress(ValueError):
+ if int(msg.content) <= len(posts) and msg.author is ctx.author and msg.channel is ctx.channel:
+ return True
+ return False
+
+ try:
+ dest, query = u.get_args(ctx, args, rem=True)
+ starred = []
+ c = 1
+
+ await dest.trigger_typing()
+
+ pool, posts = await self.return_pool(ctx, booru='e621', query=query)
+ keys = list(posts.keys())
+ values = list(posts.values())
+
+ embed = d.Embed(
+ title=values[c - 1]['author'], url='https://e621.net/post/show/{}'.format(keys[c - 1]), color=dest.me.color if isinstance(dest.channel, d.TextChannel) else self.color).set_image(url=values[c - 1]['url'])
+ embed.set_author(name=pool['name'],
+ url='https://e621.net/pool/show?id={}'.format(pool['id']), icon_url=ctx.author.avatar_url)
+ embed.set_footer(text='{} / {}'.format(c, len(posts)),
+ icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+
+ paginator = await dest.send(embed=embed)
+
+ await paginator.add_reaction('🚫')
+ await paginator.add_reaction('📁')
+ await paginator.add_reaction('⬅')
+ await paginator.add_reaction('🔢')
+ await paginator.add_reaction('➡')
+ await asyncio.sleep(1)
+ await ctx.message.add_reaction('✅')
+
+ while not self.bot.is_closed():
try:
- if not urls:
- raise exc.MissingArgument
+ await self.bot.wait_for('reaction_add', check=on_reaction, timeout=10 * 60)
- for url in urls:
- try:
- await dest.trigger_typing()
-
- await dest.send('{}'.format(await scraper.get_image(url)))
-
- finally:
- await asyncio.sleep(self.RATE_LIMIT)
-
- await ctx.message.add_reaction('✅')
-
- except exc.MissingArgument:
- await ctx.send('**Invalid url or file.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- # Reverse image searches a linked image using the public iqdb
- @commands.command(name='reverse', aliases=['rev', 'ris'], brief='e621 Reverse image search', description='e621 | NSFW\nReverse-search an image with given URL')
- @checks.del_ctx()
- async def reverse_image_search(self, ctx, *args):
- dest, urls = u.get_args(ctx, args, rem=True)
- c = 0
-
- try:
- if not urls and not ctx.message.attachments:
- raise exc.MissingArgument
-
- for url in urls:
- try:
- await dest.trigger_typing()
-
- await dest.send('**Probable match:**\n{}'.format(await scraper.get_post(url)))
-
- c += 1
- await asyncio.sleep(self.RATE_LIMIT)
-
- except exc.MatchError as e:
- await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
-
- for attachment in ctx.message.attachments:
- try:
- await dest.trigger_typing()
-
- await dest.send('**Probable match:**\n{}'.format(await scraper.get_post(attachment.url)))
-
- c += 1
- await asyncio.sleep(self.RATE_LIMIT)
-
- except exc.MatchError as e:
- await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
-
- if c:
- await ctx.message.add_reaction('✅')
- else:
- await ctx.message.add_reaction('❌')
-
- except exc.MissingArgument:
- await ctx.send('**Invalid url or file.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @commands.command(name='quality', aliases=['qual', 'qrev', 'qis'])
- @checks.del_ctx()
- async def quality_reverse_image_search(self, ctx, *args):
- dest, urls = u.get_args(ctx, args, rem=True)
- c = 0
-
- try:
- if not urls and not ctx.message.attachments:
- raise exc.MissingArgument
-
- for url in urls:
- try:
- await dest.trigger_typing()
-
- post = await scraper.get_post(url)
-
- await dest.send('**Probable match:**\n{}'.format(await scraper.get_image(post)))
-
- c += 1
- await asyncio.sleep(self.RATE_LIMIT)
-
- except exc.MatchError as e:
- await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
-
- for attachment in ctx.message.attachments:
- try:
- await dest.trigger_typing()
-
- post = await scraper.get_post(attachment.url)
-
- await dest.send('**Probable match:**\n{}'.format(await scraper.get_image(post)))
-
- c += 1
- await asyncio.sleep(self.RATE_LIMIT)
-
- except exc.MatchError as e:
- await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
-
- if c:
- await ctx.message.add_reaction('✅')
- else:
- await ctx.message.add_reaction('❌')
-
- except exc.MissingArgument:
- await ctx.send('**Invalid url or file.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @commands.command(name='reversify', aliases=['revify', 'risify', 'rify'])
- @checks.del_ctx()
- async def reversify(self, ctx, *args):
- dest, limit, remove = u.get_args(ctx, args, rem=True, rm=True)
- urls = []
- attachments = []
-
- if not ctx.author.permissions_in(ctx.channel).manage_messages:
- dest = ctx.author
-
- try:
- limit = int(limit)
-
- async for message in ctx.channel.history(limit=limit + 1):
- if message.author.id != self.bot.user.id and re.search('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content) is not None:
- urls.append(message)
- await message.add_reaction('⏳')
- elif message.author.id != self.bot.user.id and message.attachments:
- attachments.append(message)
- await message.add_reaction('⏳')
-
- if not urls and not attachments:
- raise exc.NotFound
-
- for message in urls:
- for match in re.finditer('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content):
- try:
- await dest.trigger_typing()
-
- await dest.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_post(match.group(0))))
- await message.add_reaction('✅')
-
- await asyncio.sleep(self.RATE_LIMIT)
-
- if remove:
- with suppress(err.NotFound):
- await message.delete()
-
- except exc.MatchError as e:
- await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
- await message.add_reaction('❌')
-
- for message in attachments:
- for attachment in message.attachments:
- try:
- await dest.trigger_typing()
-
- await dest.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_post(attachment.url)))
- await message.add_reaction('✅')
-
- await asyncio.sleep(self.RATE_LIMIT)
-
- if remove:
- with suppress(err.NotFound):
- await message.delete()
-
- except exc.MatchError as e:
- await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
- await message.add_reaction('❌')
-
- await ctx.message.add_reaction('✅')
-
- except exc.NotFound:
- await ctx.send('**No matches found.**', delete_after=10)
- await ctx.message.add_reaction('❌')
- except ValueError:
- await ctx.send('**Invalid limit.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @commands.command(name='qualitify', aliases=['qualify', 'qrevify', 'qrisify', 'qify'])
- @checks.del_ctx()
- async def qualitify(self, ctx, *args):
- dest, limit, remove = u.get_args(ctx, args, rem=True, rm=True)
- urls = []
- attachments = []
-
- if not ctx.author.permissions_in(ctx.channel).manage_messages:
- dest = ctx.author
-
- try:
- limit = int(limit)
-
- async for message in ctx.channel.history(limit=limit + 1):
- if message.author.id != self.bot.user.id and re.search('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content) is not None:
- urls.append(message)
- await message.add_reaction('⏳')
- elif message.author.id != self.bot.user.id and message.attachments:
- attachments.append(message)
- await message.add_reaction('⏳')
-
- if not urls and not attachments:
- raise exc.NotFound
-
- for message in urls:
- for match in re.finditer('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content):
- try:
- await dest.trigger_typing()
-
- post = await scraper.get_post(match.group(0))
-
- await dest.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_image(post)))
- await message.add_reaction('✅')
-
- await asyncio.sleep(self.RATE_LIMIT)
-
- if remove:
- with suppress(err.NotFound):
- await message.delete()
-
- except exc.MatchError as e:
- await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
- await message.add_reaction('❌')
-
- for message in attachments:
- for attachment in message.attachments:
- try:
- await dest.trigger_typing()
-
- post = await scraper.get_post(attachment.url)
-
- await dest.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_image(post)))
- await message.add_reaction('✅')
-
- await asyncio.sleep(self.RATE_LIMIT)
-
- if remove:
- with suppress(err.NotFound):
- await message.delete()
-
- except exc.MatchError as e:
- await ctx.send('**No probable match for:** `{}`'.format(e), delete_after=10)
- await message.add_reaction('❌')
-
- await ctx.message.add_reaction('✅')
-
- except exc.NotFound:
- await ctx.send('**No matches found.**', delete_after=10)
- await ctx.message.add_reaction('❌')
- except ValueError:
- await ctx.send('**Invalid limit.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- async def _qualitify(self):
- while self.qualitifying:
- message = await self.queue.get()
-
- for match in re.finditer('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content):
- try:
- await message.channel.trigger_typing()
-
- post = await scraper.get_post(match.group(0))
-
- await message.channel.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_image(post)))
- await message.add_reaction('✅')
-
- await asyncio.sleep(self.RATE_LIMIT)
-
- with suppress(err.NotFound):
- await message.delete()
-
- except exc.MatchError as e:
- await message.channel.send('**No probable match for:** `{}`'.format(e), delete_after=10)
- await message.add_reaction('❌')
-
- for attachment in message.attachments:
- try:
- await message.channel.trigger_typing()
-
- post = await scraper.get_post(attachment.url)
-
- await message.channel.send('**Probable match from** {}**:**\n{}'.format(message.author.display_name, await scraper.get_image(post)))
- await message.add_reaction('✅')
-
- await asyncio.sleep(self.RATE_LIMIT)
-
- with suppress(err.NotFound):
- await message.delete()
-
- except exc.MatchError as e:
- await message.channel.send('**No probable match for:** `{}`'.format(e), delete_after=10)
- await message.add_reaction('❌')
-
- print('STOPPED : qualitifying')
-
- async def queue_for_qualitification(self, channel):
- def check(msg):
- if msg.content.lower() == 'stop' and msg.channel is channel and msg.author.guild_permissions.administrator:
- raise exc.Abort
- elif msg.channel is channel and message.author.id != self.bot.user.id and (re.search('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', msg.content) is not None or msg.attachments):
- return True
- return False
-
- try:
- while not self.bot.is_closed():
- message = await self.bot.wait_for('message', check=check)
- await self.queue.put(message)
- await message.add_reaction('⏳')
-
- except exc.Abort:
- u.tasks['auto_qual'].remove(channel.id)
- u.dump(u.tasks, 'cogs/tasks.pkl')
- if not u.tasks['auto_qual']:
- self.qualitifying = False
- print('STOPPED : qualitifying #{}'.format(channel.name))
- await channel.send('**Stopped queueing messages for qualitification in** {}**.**'.format(channel.mention), delete_after=5)
-
- @commands.command(name='autoqualitify', aliases=['autoqual'])
- @commands.has_permissions(manage_channels=True)
- async def auto_qualitify(self, ctx):
- try:
- if ctx.channel.id not in u.tasks['auto_qual']:
- u.tasks['auto_qual'].append(ctx.channel.id)
- u.dump(u.tasks, 'cogs/tasks.pkl')
- self.bot.loop.create_task(self.queue_for_qualitification(ctx.channel))
- if not self.qualitifying:
- self.bot.loop.create_task(self._qualitify())
- self.qualitifying = True
-
- print('AUTO-QUALITIFYING : #{}'.format(ctx.channel.name))
- await ctx.send('**Auto-qualitifying all images in {}.**'.format(ctx.channel.mention), delete_after=5)
- await ctx.message.add_reaction('✅')
- else:
- raise exc.Exists
-
- except exc.Exists:
- await ctx.send('**Already auto-qualitifying in {}.** Type `stop` to stop.'.format(ctx.channel.mention), delete_after=10)
- await ctx.message.add_reaction('❌')
-
- def get_favorites(self, ctx, args):
- if '-f' in args or '-favs' in args or '-faves' in args or '-favorites' in args:
- if self.favorites.get(ctx.author.id, {}).get('tags', set()):
- args = ['~{}'.format(tag) for tag in self.favorites[ctx.author.id]['tags']]
- else:
- raise exc.FavoritesNotFound
-
- return args
-
- async def return_pool(self, ctx, *, booru='e621', query=[]):
- def on_message(msg):
- if msg.content.lower() == 'cancel' and msg.author is ctx.author and msg.channel is ctx.channel:
- raise exc.Abort
- with suppress(ValueError):
- if int(msg.content) <= len(pools) and int(msg.content) > 0 and msg.author is ctx.author and msg.channel is ctx.channel:
- return True
- return False
-
- posts = {}
- pool = {}
-
- pools = []
- pool_request = await u.fetch('https://{}.net/pool/index.json'.format(booru), params={'query': ' '.join(query)}, json=True)
- if len(pool_request) > 1:
- for pool in pool_request:
- pools.append(pool['name'])
- match = await ctx.send('**Multiple pools found.** Type in the correct match.\n```\n{}```\nor `cancel` to cancel.'.format('\n'.join(['{} {}'.format(c, elem) for c, elem in enumerate(pools, 1)])))
- try:
- selection = await self.bot.wait_for('message', check=on_message, timeout=10 * 60)
- except exc.Abort:
- raise exc.Abort
- finally:
- await match.delete()
- tempool = [pool for pool in pool_request if pool['name']
- == pools[int(selection.content) - 1]][0]
- await selection.delete()
- pool = {'name': tempool['name'], 'id': tempool['id']}
- elif pool_request:
- tempool = pool_request[0]
- pool = {'name': pool_request[0]['name'], 'id': pool_request[0]['id']}
- else:
- raise exc.NotFound
-
- page = 1
- while len(posts) < tempool['post_count']:
- posts_request = await u.fetch('https://{}.net/pool/show.json'.format(booru), params={'id': tempool['id'], 'page': page}, json=True)
- for post in posts_request['posts']:
- posts[post['id']] = {'author': post['author'], 'url': post['file_url']}
- page += 1
-
- return pool, posts
-
- # Creates reaction-based paginator for linked pools
- @commands.command(name='pool', aliases=['e6pp'], brief='e621 pool paginator', description='e621 | NSFW\nShow pools in a page format', hidden=True)
- @checks.del_ctx()
- async def pool_paginator(self, ctx, *args):
- def on_reaction(reaction, user):
- if reaction.emoji == '🚫' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.Abort
- elif reaction.emoji == '📁' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.Save
- elif reaction.emoji == '⬅' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.Left
- elif reaction.emoji == '🔢' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.GoTo
- elif reaction.emoji == '➡' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.Right
- return False
-
- def on_message(msg):
- with suppress(ValueError):
- if int(msg.content) <= len(posts) and msg.author is ctx.author and msg.channel is ctx.channel:
- return True
- return False
-
- dest, query = u.get_args(ctx, args, rem=True)
- starred = []
- c = 1
-
- try:
- await dest.trigger_typing()
-
- pool, posts = await self.return_pool(ctx, booru='e621', query=query)
- keys = list(posts.keys())
- values = list(posts.values())
-
- embed = d.Embed(
- title=values[c - 1]['author'], url='https://e621.net/post/show/{}'.format(keys[c - 1]), color=dest.me.color if isinstance(dest.channel, d.TextChannel) else self.color).set_image(url=values[c - 1]['url'])
- embed.set_author(name=pool['name'],
- url='https://e621.net/pool/show?id={}'.format(pool['id']), icon_url=ctx.author.avatar_url)
+ except exc.Left:
+ if c > 1:
+ c -= 1
+ embed.title = values[c - 1]['author']
+ embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
embed.set_footer(text='{} / {}'.format(c, len(posts)),
icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ embed.set_image(url=values[c - 1]['url'])
- paginator = await dest.send(embed=embed)
+ await paginator.edit(content=None, embed=embed)
+ else:
+ await paginator.edit(content='**First image.**')
- await paginator.add_reaction('🚫')
- await paginator.add_reaction('📁')
- await paginator.add_reaction('⬅')
- await paginator.add_reaction('🔢')
- await paginator.add_reaction('➡')
- await asyncio.sleep(1)
- await ctx.message.add_reaction('✅')
+ except exc.GoTo:
+ await paginator.edit(content='**Enter image number...**')
+ number = await self.bot.wait_for('message', check=on_message, timeout=10 * 60)
- while not self.bot.is_closed():
- try:
- await self.bot.wait_for('reaction_add', check=on_reaction, timeout=10 * 60)
+ c = int(number.content)
+ await number.delete()
+ embed.title = values[c - 1]['author']
+ embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
+ embed.set_footer(text='{} / {}'.format(c, len(posts)),
+ icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ embed.set_image(url=values[c - 1]['url'])
- except exc.Left:
- if c > 1:
- c -= 1
- embed.title = values[c - 1]['author']
- embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
- embed.set_footer(text='{} / {}'.format(c, len(posts)),
- icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
- embed.set_image(url=values[c - 1]['url'])
+ await paginator.edit(content=None, embed=embed)
- await paginator.edit(content=None, embed=embed)
- else:
- await paginator.edit(content='**First image.**')
+ except exc.Save:
+ if values[c - 1]['url'] not in starred:
+ starred.append(values[c - 1]['url'])
- except exc.GoTo:
- await paginator.edit(content='**Enter image number...**')
- number = await self.bot.wait_for('message', check=on_message, timeout=10 * 60)
+ await paginator.edit(content='**Image** `{}` **saved.**'.format(len(starred)))
+ else:
+ starred.remove(values[c - 1])['url']
- c = int(number.content)
- await number.delete()
- embed.title = values[c - 1]['author']
- embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
- embed.set_footer(text='{} / {}'.format(c, len(posts)),
- icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
- embed.set_image(url=values[c - 1]['url'])
+ await paginator.edit(content='**Image removed.**')
- await paginator.edit(content=None, embed=embed)
-
- except exc.Save:
- if values[c - 1]['url'] not in starred:
- starred.append(values[c - 1]['url'])
-
- await paginator.edit(content='**Image** `{}` **saved.**'.format(len(starred)))
- else:
- starred.remove(values[c - 1])['url']
-
- await paginator.edit(content='**Image removed.**')
-
- except exc.Right:
- if c < len(keys):
- c += 1
- embed.title = values[c - 1]['author']
- embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
- embed.set_footer(text='{} / {}'.format(c, len(posts)),
- icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
- embed.set_image(url=values[c - 1]['url'])
-
- await paginator.edit(content=None, embed=embed)
-
- except exc.Abort:
- try:
- await paginator.edit(content='🚫 **Exited paginator.**')
-
- except UnboundLocalError:
- await dest.send('🚫 **Exited paginator.**')
- await ctx.message.add_reaction('🚫')
- except asyncio.TimeoutError:
- try:
- await paginator.edit(content='🚫 **Paginator timed out.**')
-
- except UnboundLocalError:
- await dest.send('🚫 **Paginator timed out.**')
- await ctx.message.add_reaction('🚫')
- except exc.NotFound:
- await ctx.send('**Pool not found.**', delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.Timeout:
- await ctx.send('**Request timed out.**')
- await ctx.message.add_reaction('❌')
-
- finally:
- for url in starred:
- await ctx.author.send(url)
- if len(starred) > 5:
- await asyncio.sleep(self.RATE_LIMIT)
-
- # Messy code that checks image limit and tags in blacklists
- async def check_return_posts(self, ctx, *, booru='e621', tags=[], limit=1, previous={}):
- guild = ctx.guild if isinstance(
- ctx.guild, d.Guild) else ctx.channel
-
- blacklist = set()
- # Creates temp blacklist based on context
- for tag in self.blacklists['global_blacklist']:
- blacklist.update(list(self.aliases[tag]) + [tag])
- for tag in self.blacklists['guild_blacklist'].get(guild.id, {}).get(ctx.channel.id, set()):
- blacklist.update(list(self.aliases[tag]) + [tag])
- for tag in self.blacklists['user_blacklist'].get(ctx.author.id, set()):
- blacklist.update(list(self.aliases[tag]) + [tag])
- # Checks if tags are in local blacklists
- if tags:
- if len(tags) > 5:
- raise exc.TagBoundsError(formatter.tostring(tags[5:]))
- for tag in tags:
- if tag == 'swf' or tag == 'webm' or tag in blacklist:
- raise exc.TagBlacklisted(tag)
-
- # Checks for blacklisted tags in endpoint blacklists - try/except is for continuing the parent loop
- posts = {}
- c = 0
- while len(posts) < limit:
- if c == limit * 5 + self.LIMIT:
- raise exc.Timeout
- request = await u.fetch('https://{}.net/post/index.json'.format(booru), params={'tags': ','.join(['order:random'] + tags), 'limit': int(self.LIMIT * limit)}, json=True)
- if len(request) == 0:
- raise exc.NotFound(formatter.tostring(tags))
- if len(request) < limit:
- limit = len(request)
-
- for post in request:
- if 'swf' in post['file_ext'] or 'webm' in post['file_ext']:
- continue
- try:
- for tag in blacklist:
- if tag in post['tags']:
- raise exc.Continue
- except exc.Continue:
- continue
- if post['id'] not in posts.keys() and post['id'] not in previous.keys():
- posts[post['id']] = {'author': post['author'], 'url': post['file_url']}
- if len(posts) == limit:
- break
+ except exc.Right:
+ if c < len(keys):
c += 1
+ embed.title = values[c - 1]['author']
+ embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
+ embed.set_footer(text='{} / {}'.format(c, len(posts)),
+ icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ embed.set_image(url=values[c - 1]['url'])
- return posts
+ await paginator.edit(content=None, embed=embed)
- @commands.command(name='e621p', aliases=['e6p', '6p'])
- @checks.del_ctx()
- @checks.is_nsfw()
- async def e621_paginator(self, ctx, *args):
- def on_reaction(reaction, user):
- if reaction.emoji == '🚫' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.Abort
- elif reaction.emoji == '📁' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.Save
- elif reaction.emoji == '⬅' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.Left
- elif reaction.emoji == '🔢' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.GoTo
- elif reaction.emoji == '➡' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
- raise exc.Right
- return False
+ except exc.Abort:
+ try:
+ await paginator.edit(content='🚫 **Exited paginator.**')
- def on_message(msg):
- with suppress(ValueError):
- if int(msg.content) <= len(posts) and msg.author is ctx.author and msg.channel is ctx.channel:
- return True
- return False
+ except UnboundLocalError:
+ await dest.send('🚫 **Exited paginator.**')
+ await ctx.message.add_reaction('🚫')
+ except asyncio.TimeoutError:
+ try:
+ await paginator.edit(content='🚫 **Paginator timed out.**')
- dest, tags = u.get_args(ctx, args, rem=True)
- limit = self.LIMIT / 5
- starred = []
- c = 1
+ except UnboundLocalError:
+ await dest.send('🚫 **Paginator timed out.**')
+ await ctx.message.add_reaction('🚫')
+ except exc.NotFound:
+ await ctx.send('**Pool not found.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.Timeout:
+ await ctx.send('**Request timed out.**')
+ await ctx.message.add_reaction('❌')
+ finally:
+ for url in starred:
+ await ctx.author.send(url)
+ if len(starred) > 5:
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ # Messy code that checks image limit and tags in blacklists
+ async def check_return_posts(self, ctx, *, booru='e621', tags=[], limit=1, previous={}):
+ guild = ctx.guild if isinstance(
+ ctx.guild, d.Guild) else ctx.channel
+
+ blacklist = set()
+ # Creates temp blacklist based on context
+ for tag in self.blacklists['global_blacklist']:
+ blacklist.update(list(self.aliases[tag]) + [tag])
+ for tag in self.blacklists['guild_blacklist'].get(guild.id, {}).get(ctx.channel.id, set()):
+ blacklist.update(list(self.aliases[tag]) + [tag])
+ for tag in self.blacklists['user_blacklist'].get(ctx.author.id, set()):
+ blacklist.update(list(self.aliases[tag]) + [tag])
+ # Checks if tags are in local blacklists
+ if tags:
+ if len(tags) > 5:
+ raise exc.TagBoundsError(formatter.tostring(tags[5:]))
+ for tag in tags:
+ if tag == 'swf' or tag == 'webm' or tag in blacklist:
+ raise exc.TagBlacklisted(tag)
+
+ # Checks for blacklisted tags in endpoint blacklists - try/except is for continuing the parent loop
+ posts = {}
+ c = 0
+ while len(posts) < limit:
+ if c == limit * 5 + self.LIMIT:
+ raise exc.Timeout
+ request = await u.fetch('https://{}.net/post/index.json'.format(booru), params={'tags': ','.join(['order:random'] + tags), 'limit': int(self.LIMIT * limit)}, json=True)
+ if len(request) == 0:
+ raise exc.NotFound(formatter.tostring(tags))
+ if len(request) < limit:
+ limit = len(request)
+
+ for post in request:
+ if 'swf' in post['file_ext'] or 'webm' in post['file_ext']:
+ continue
try:
- tags = self.get_favorites(ctx, tags)
+ for tag in blacklist:
+ if tag in post['tags']:
+ raise exc.Continue
+ except exc.Continue:
+ continue
+ if post['id'] not in posts.keys() and post['id'] not in previous.keys():
+ posts[post['id']] = {'author': post['author'], 'url': post['file_url']}
+ if len(posts) == limit:
+ break
+ c += 1
- await ctx.trigger_typing()
+ return posts
+
+ @commands.command(name='e621p', aliases=['e6p', '6p'])
+ @checks.del_ctx()
+ @checks.is_nsfw()
+ async def e621_paginator(self, ctx, *args):
+ def on_reaction(reaction, user):
+ if reaction.emoji == '🚫' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.Abort
+ elif reaction.emoji == '📁' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.Save
+ elif reaction.emoji == '⬅' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.Left
+ elif reaction.emoji == '🔢' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.GoTo
+ elif reaction.emoji == '➡' and reaction.message.content == paginator.content and (user is ctx.author or user.id == u.config['owner_id']):
+ raise exc.Right
+ return False
+
+ def on_message(msg):
+ with suppress(ValueError):
+ if int(msg.content) <= len(posts) and msg.author is ctx.author and msg.channel is ctx.channel:
+ return True
+ return False
+
+ try:
+ dest, tags = u.get_args(ctx, args, rem=True)
+ limit = self.LIMIT / 5
+ starred = []
+ c = 1
+
+ tags = self.get_favorites(ctx, tags)
+
+ await ctx.trigger_typing()
+
+ posts = await self.check_return_posts(ctx, booru='e621', tags=tags, limit=limit)
+ keys = list(posts.keys())
+ values = list(posts.values())
+
+ embed = d.Embed(
+ title=values[c - 1]['author'], url='https://e621.net/post/show/{}'.format(keys[c - 1]), color=ctx.me.color if isinstance(ctx.channel, d.TextChannel) else self.color).set_image(url=values[c - 1]['url'])
+ embed.set_author(name=formatter.tostring(tags, random=True),
+ url='https://e621.net/post?tags={}'.format(','.join(tags)), icon_url=ctx.author.avatar_url)
+ embed.set_footer(text='{} / {}'.format(c, len(posts)),
+ icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+
+ paginator = await dest.send(embed=embed)
+
+ await paginator.add_reaction('🚫')
+ await paginator.add_reaction('📁')
+ await paginator.add_reaction('⬅')
+ await paginator.add_reaction('🔢')
+ await paginator.add_reaction('➡')
+ await asyncio.sleep(1)
+ await ctx.message.add_reaction('✅')
+
+ while not self.bot.is_closed():
+ try:
+ await self.bot.wait_for('reaction_add', check=on_reaction, timeout=10 * 60)
+
+ except exc.Left:
+ if c > 1:
+ c -= 1
+ embed.title = values[c - 1]['author']
+ embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
+ embed.set_footer(text='{} / {}'.format(c, len(posts)),
+ icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ embed.set_image(url=values[c - 1]['url'])
+ await paginator.edit(content=None, embed=embed)
+ else:
+ await paginator.edit(content='**First image.**')
+
+ except exc.GoTo:
+ await paginator.edit(content='**Enter image number...**')
+ number = await self.bot.wait_for('message', check=on_message, timeout=10 * 60)
+
+ c = int(number.content)
+ await number.delete()
+ embed.title = values[c - 1]['author']
+ embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
+ embed.set_footer(text='{} / {}'.format(c, len(posts)),
+ icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ embed.set_image(url=values[c - 1]['url'])
+
+ await paginator.edit(content=None, embed=embed)
+
+ except exc.Save:
+ if values[c - 1]['url'] not in starred:
+ starred.append(values[c - 1]['url'])
+
+ await paginator.edit(content='**Image** `{}` **saved.**'.format(len(starred)))
+ else:
+ starred.remove(values[c - 1])['url']
+
+ await paginator.edit(content='**Image removed.**')
+
+ except exc.Right:
+ if c % limit == 0:
+ await dest.trigger_typing()
+ try:
+ posts.update(await self.check_return_posts(ctx, booru='e621', tags=tags, limit=limit, previous=posts))
+
+ except exc.NotFound:
+ await paginator.edit(content='**No more images found.**')
- posts = await self.check_return_posts(ctx, booru='e621', tags=tags, limit=limit)
keys = list(posts.keys())
values = list(posts.values())
- embed = d.Embed(
- title=values[c - 1]['author'], url='https://e621.net/post/show/{}'.format(keys[c - 1]), color=ctx.me.color if isinstance(ctx.channel, d.TextChannel) else self.color).set_image(url=values[c - 1]['url'])
- embed.set_author(name=formatter.tostring(tags, random=True),
- url='https://e621.net/post?tags={}'.format(','.join(tags)), icon_url=ctx.author.avatar_url)
- embed.set_footer(text='{} / {}'.format(c, len(posts)),
- icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ c += 1
+ embed.title = values[c - 1]['author']
+ embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
+ embed.set_footer(text='{} / {}'.format(c, len(posts)),
+ icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ embed.set_image(url=values[c - 1]['url'])
+ await paginator.edit(content=None, embed=embed)
- paginator = await dest.send(embed=embed)
+ except exc.Abort:
+ try:
+ await paginator.edit(content='🚫 **Exited paginator.**')
- await paginator.add_reaction('🚫')
- await paginator.add_reaction('📁')
- await paginator.add_reaction('⬅')
- await paginator.add_reaction('🔢')
- await paginator.add_reaction('➡')
- await asyncio.sleep(1)
- await ctx.message.add_reaction('✅')
+ except UnboundLocalError:
+ await dest.send('🚫 **Exited paginator.**')
+ await ctx.message.add_reaction('🚫')
+ except asyncio.TimeoutError:
+ try:
+ await paginator.edit(content='🚫 **Paginator timed out.**')
- while not self.bot.is_closed():
- try:
- await self.bot.wait_for('reaction_add', check=on_reaction, timeout=10 * 60)
+ except UnboundLocalError:
+ await dest.send('🚫 **Paginator timed out.**')
+ await ctx.message.add_reaction('🚫')
+ except exc.NotFound as e:
+ await ctx.send('`{}` **not found.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.TagBlacklisted as e:
+ await ctx.send('🚫 `{}` **blacklisted.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('🚫')
+ except exc.TagBoundsError as e:
+ await ctx.send('`{}` **out of bounds.** Tags limited to 5, currently.'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.FavoritesNotFound:
+ await ctx.send('**You have no favorite tags.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.Timeout:
+ await ctx.send('**Request timed out.**')
+ await ctx.message.add_reaction('❌')
- except exc.Left:
- if c > 1:
- c -= 1
- embed.title = values[c - 1]['author']
- embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
- embed.set_footer(text='{} / {}'.format(c, len(posts)),
- icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
- embed.set_image(url=values[c - 1]['url'])
- await paginator.edit(content=None, embed=embed)
- else:
- await paginator.edit(content='**First image.**')
+ finally:
+ for url in starred:
+ await ctx.author.send(url)
+ if len(starred) > 5:
+ await asyncio.sleep(self.RATE_LIMIT)
- except exc.GoTo:
- await paginator.edit(content='**Enter image number...**')
- number = await self.bot.wait_for('message', check=on_message, timeout=10 * 60)
+ @e621_paginator.error
+ async def e621_paginator_error(self, ctx, error):
+ if isinstance(error, errext.CheckFailure):
+ await ctx.send('⛔️ {} **is not an NSFW channel.**'.format(ctx.channel.mention), delete_after=10)
+ return await ctx.message.add_reaction('⛔️')
- c = int(number.content)
- await number.delete()
- embed.title = values[c - 1]['author']
- embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
- embed.set_footer(text='{} / {}'.format(c, len(posts)),
- icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
- embed.set_image(url=values[c - 1]['url'])
+ # Searches for and returns images from e621.net given tags when not blacklisted
+ @commands.group(aliases=['e6', '6'], brief='e621 | NSFW', description='e621 | NSFW\nTag-based search for e621.net\n\nYou can only search 5 tags and 6 images at once for now.\ne6 [tags...] ([# of images])')
+ @checks.del_ctx()
+ @checks.is_nsfw()
+ async def e621(self, ctx, *args):
+ try:
+ dest, args, limit = u.get_args(ctx, args, rem=True, lim=3)
- await paginator.edit(content=None, embed=embed)
+ tags = self.get_favorites(ctx, args)
- except exc.Save:
- if values[c - 1]['url'] not in starred:
- starred.append(values[c - 1]['url'])
+ await dest.trigger_typing()
- await paginator.edit(content='**Image** `{}` **saved.**'.format(len(starred)))
- else:
- starred.remove(values[c - 1])['url']
+ posts = await self.check_return_posts(ctx, booru='e621', tags=tags, limit=limit)
- await paginator.edit(content='**Image removed.**')
+ for ident, post in posts.items():
+ embed = d.Embed(title=post['author'], url='https://e621.net/post/show/{}'.format(ident),
+ color=ctx.me.color if isinstance(ctx.channel, d.TextChannel) else self.color).set_image(url=post['url'])
+ embed.set_author(name=formatter.tostring(tags, random=True),
+ url='https://e621.net/post?tags={}'.format(','.join(tags)), icon_url=ctx.author.avatar_url)
+ embed.set_footer(
+ text=str(ident), icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
- except exc.Right:
- if c % limit == 0:
- await dest.trigger_typing()
- try:
- posts.update(await self.check_return_posts(ctx, booru='e621', tags=tags, limit=limit, previous=posts))
+ await dest.send(embed=embed)
- except exc.NotFound:
- await paginator.edit(content='**No more images found.**')
+ await ctx.message.add_reaction('✅')
- keys = list(posts.keys())
- values = list(posts.values())
+ except exc.TagBlacklisted as e:
+ await ctx.send('`{}` **blacklisted.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.BoundsError as e:
+ await ctx.send('`{}` **out of bounds.** Images limited to 3.'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.TagBoundsError as e:
+ await ctx.send('`{}` **out of bounds.** Tags limited to 5.'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.NotFound as e:
+ await ctx.send('`{}` **not found.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.FavoritesNotFound:
+ await ctx.send('**You have no favorite tags.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.Timeout:
+ await ctx.send('**Request timed out.**')
+ await ctx.message.add_reaction('❌')
- c += 1
- embed.title = values[c - 1]['author']
- embed.url = 'https://e621.net/post/show/{}'.format(keys[c - 1])
- embed.set_footer(text='{} / {}'.format(c, len(posts)),
- icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
- embed.set_image(url=values[c - 1]['url'])
- await paginator.edit(content=None, embed=embed)
+ # tools.command_dict.setdefault(str(ctx.author.id), {}).update(
+ # {'command': ctx.command, 'args': ctx.args})
- except exc.Abort:
- try:
- await paginator.edit(content='🚫 **Exited paginator.**')
+ @e621.error
+ async def e621_error(self, ctx, error):
+ if isinstance(error, errext.CheckFailure):
+ await ctx.send('⛔️ {} **is not an NSFW channel.**'.format(ctx.channel.mention), delete_after=10)
+ return await ctx.message.add_reaction('⛔️')
- except UnboundLocalError:
- await dest.send('🚫 **Exited paginator.**')
- await ctx.message.add_reaction('🚫')
- except asyncio.TimeoutError:
- try:
- await paginator.edit(content='🚫 **Paginator timed out.**')
+ # Searches for and returns images from e926.net given tags when not blacklisted
+ @commands.command(aliases=['e9', '9'], brief='e926 | SFW', description='e926 | SFW\nTag-based search for e926.net\n\nYou can only search 5 tags and 6 images at once for now.\ne9 [tags...] ([# of images])')
+ @checks.del_ctx()
+ async def e926(self, ctx, *args):
+ try:
+ dest, args, limit = u.get_args(ctx, args, rem=True, lim=3)
- except UnboundLocalError:
- await dest.send('🚫 **Paginator timed out.**')
- await ctx.message.add_reaction('🚫')
- except exc.NotFound as e:
- await ctx.send('`{}` **not found.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.TagBlacklisted as e:
- await ctx.send('🚫 `{}` **blacklisted.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('🚫')
- except exc.TagBoundsError as e:
- await ctx.send('`{}` **out of bounds.** Tags limited to 5, currently.'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.FavoritesNotFound:
- await ctx.send('**You have no favorite tags.**', delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.Timeout:
- await ctx.send('**Request timed out.**')
- await ctx.message.add_reaction('❌')
+ tags = self.get_favorites(ctx, args)
- finally:
- for url in starred:
- await ctx.author.send(url)
- if len(starred) > 5:
- await asyncio.sleep(self.RATE_LIMIT)
+ await dest.trigger_typing()
- @e621_paginator.error
- async def e621_paginator_error(self, ctx, error):
- if isinstance(error, errext.CheckFailure):
- await ctx.send('⛔️ {} **is not an NSFW channel.**'.format(ctx.channel.mention), delete_after=10)
- return await ctx.message.add_reaction('⛔️')
+ posts = await self.check_return_posts(ctx, booru='e926', tags=tags, limit=limit)
- # Searches for and returns images from e621.net given tags when not blacklisted
- @commands.group(aliases=['e6', '6'], brief='e621 | NSFW', description='e621 | NSFW\nTag-based search for e621.net\n\nYou can only search 5 tags and 6 images at once for now.\ne6 [tags...] ([# of images])')
- @checks.del_ctx()
- @checks.is_nsfw()
- async def e621(self, ctx, *args):
- dest, args, limit = u.get_args(ctx, args, rem=True, lim=True)
+ for ident, post in posts.items():
+ embed = d.Embed(title=post['author'], url='https://e926.net/post/show/{}'.format(ident),
+ color=ctx.me.color if isinstance(ctx.channel, d.TextChannel) else self.color).set_image(url=post['url'])
+ embed.set_author(name=formatter.tostring(tags, random=True),
+ url='https://e621.net/post?tags={}'.format(','.join(tags)), icon_url=ctx.author.avatar_url)
+ embed.set_footer(
+ text=str(ident), icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ await dest.send(embed=embed)
+
+ await ctx.message.add_reaction('✅')
+
+ except exc.TagBlacklisted as e:
+ await ctx.send('`{}` **blacklisted.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.BoundsError as e:
+ await ctx.send('`{}` **out of bounds.** Images limited to 3.'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.TagBoundsError as e:
+ await ctx.send('`{}` **out of bounds.** Tags limited to 5.'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.NotFound as e:
+ await ctx.send('`{}` **not found.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.FavoritesNotFound:
+ await ctx.send('**You have no favorite tags.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.Timeout:
+ await ctx.send('**Request timed out.**')
+ await ctx.message.add_reaction('❌')
+
+ @commands.group(aliases=['fave', 'fav', 'f'])
+ @checks.del_ctx()
+ async def favorite(self, ctx):
+ if ctx.invoked_subcommand is None:
+ await ctx.send('**Use a flag to manage favorites.**\n*Type* `{}help fav` *for more info.*'.format(ctx.prefix), delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ @favorite.error
+ async def favorite_error(self, ctx, error):
+ pass
+
+ @favorite.group(name='get', aliases=['g'])
+ async def _get_favorite(self, ctx):
+ pass
+
+ @_get_favorite.command(name='tags', aliases=['t'])
+ async def __get_favorite_tags(self, ctx, *args):
+ dest = u.get_args(ctx, *args)
+
+ await dest.send('⭐ {}**\'s favorite tags:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(self.favorites.get(ctx.author.id, {}).get('tags', set()))), delete_after=10)
+ await ctx.message.add_reaction('✅')
+
+ @_get_favorite.command(name='posts', aliases=['p'])
+ async def __get_favorite_posts(self, ctx):
+ pass
+
+ @favorite.group(name='add', aliases=['a'])
+ async def _add_favorite(self, ctx):
+ pass
+
+ @_add_favorite.command(name='tags', aliases=['t'])
+ async def __add_favorite_tags(self, ctx, *args):
+ try:
+ dest, tags = u.get_args(ctx, args, rem=True)
+
+ for tag in tags:
+ if tag in self.blacklists['user_blacklist'].get(ctx.author.id, set()):
+ raise exc.TagBlacklisted(tag)
+ if len(self.favorites[ctx.author.id]['tags']) + len(tags) > 5:
+ raise exc.BoundsError
+
+ self.favorites.setdefault(ctx.author.id, {}).setdefault('tags', set()).update(tags)
+ u.dump(self.favorites, 'cogs/favorites.pkl')
+
+ await dest.send('{} **added to their favorites:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(tags)), delete_after=5)
+ await ctx.message.add_reaction('✅')
+
+ except exc.BoundsError:
+ await ctx.send('**Favorites list currently limited to:** `5`', delete_after=10)
+ await ctx.message.add_reaction('❌')
+ except exc.TagBlacklisted as e:
+ await ctx.send('🚫 `{}` **blacklisted.**', delete_after=10)
+ await ctx.message.add_reaction('🚫')
+
+ @_add_favorite.command(name='posts', aliases=['p'])
+ async def __add_favorite_posts(self, ctx, *posts):
+ pass
+
+ @favorite.group(name='remove', aliases=['r'])
+ async def _remove_favorite(self, ctx):
+ pass
+
+ @_remove_favorite.command(name='tags', aliases=['t'])
+ async def __remove_favorite_tags(self, ctx, *args):
+ try:
+ dest, tags = u.get_args(ctx, args, rem=True)
+
+ for tag in tags:
try:
- tags = self.get_favorites(ctx, args)
+ self.favorites[ctx.author.id].get('tags', set()).remove(tag)
- await dest.trigger_typing()
+ except KeyError:
+ raise exc.TagError(tag)
- posts = await self.check_return_posts(ctx, booru='e621', tags=tags, limit=limit)
+ u.dump(self.favorites, 'cogs/favorites.pkl')
- for ident, post in posts.items():
- embed = d.Embed(title=post['author'], url='https://e621.net/post/show/{}'.format(ident),
- color=ctx.me.color if isinstance(ctx.channel, d.TextChannel) else self.color).set_image(url=post['url'])
- embed.set_author(name=formatter.tostring(tags, random=True),
- url='https://e621.net/post?tags={}'.format(','.join(tags)), icon_url=ctx.author.avatar_url)
- embed.set_footer(
- text=str(ident), icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ await dest.send('{} **removed from their favorites:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(tags)), delete_after=5)
+ await ctx.message.add_reaction('✅')
- await dest.send(embed=embed)
+ except exc.TagError as e:
+ await ctx.send('`{}` **not in favorites.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
- await ctx.message.add_reaction('✅')
+ @_remove_favorite.command(name='posts', aliases=['p'])
+ async def __remove_favorite_posts(self, ctx):
+ pass
- except exc.TagBlacklisted as e:
- await ctx.send('`{}` **blacklisted.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.BoundsError as e:
- await ctx.send('`{}` **out of bounds.** Images limited to 3.'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.TagBoundsError as e:
- await ctx.send('`{}` **out of bounds.** Tags limited to 5.'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.NotFound as e:
- await ctx.send('`{}` **not found.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.FavoritesNotFound:
- await ctx.send('**You have no favorite tags.**', delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.Timeout:
- await ctx.send('**Request timed out.**')
- await ctx.message.add_reaction('❌')
+ @favorite.group(name='clear', aliases=['c'])
+ async def _clear_favorite(self, ctx):
+ pass
- # tools.command_dict.setdefault(str(ctx.author.id), {}).update(
- # {'command': ctx.command, 'args': ctx.args})
+ @_clear_favorite.command(name='tags', aliases=['t'])
+ async def __clear_favorite_tags(self, ctx, *args):
+ dest = u.get_args(ctx, args)
- @e621.error
- async def e621_error(self, ctx, error):
- if isinstance(error, errext.CheckFailure):
- await ctx.send('⛔️ {} **is not an NSFW channel.**'.format(ctx.channel.mention), delete_after=10)
- return await ctx.message.add_reaction('⛔️')
+ with suppress(KeyError):
+ del self.favorites[ctx.author.id]
+ u.dump(self.favorites, 'cogs/favorites.pkl')
- # Searches for and returns images from e926.net given tags when not blacklisted
- @commands.command(aliases=['e9', '9'], brief='e926 | SFW', description='e926 | SFW\nTag-based search for e926.net\n\nYou can only search 5 tags and 6 images at once for now.\ne9 [tags...] ([# of images])')
- @checks.del_ctx()
- async def e926(self, ctx, *args):
- dest, args, limit = u.get_args(ctx, args, rem=True, lim=True)
+ await dest.send('{}**\'s favorites cleared.**'.format(ctx.author.mention), delete_after=5)
+ await ctx.message.add_reaction('✅')
+ @_clear_favorite.command(name='posts', aliases=['p'])
+ async def __clear_favorite_posts(self, ctx):
+ pass
+
+ # Umbrella command structure to manage global, channel, and user blacklists
+ @commands.group(aliases=['bl', 'b'], brief='Manage blacklists', description='Blacklist base command for managing blacklists\n\n`bl get [blacklist]` to show a blacklist\n`bl set [blacklist] [tags]` to replace a blacklist\n`bl clear [blacklist]` to clear a blacklist\n`bl add [blacklist] [tags]` to add tags to a blacklist\n`bl remove [blacklist] [tags]` to remove tags from a blacklist', usage='[flag] [blacklist] ([tags])')
+ @checks.del_ctx()
+ async def blacklist(self, ctx):
+ if ctx.invoked_subcommand is None:
+ await ctx.send('**Use a flag to manage blacklists.**\n*Type* `{}help bl` *for more info.*'.format(ctx.prefix), delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ # @blacklist.error
+ # async def blacklist_error(self, ctx, error):
+ # if isinstance(error, KeyError):
+ # return await ctx.send('**Blacklist does not exist.**', delete_after=10)
+
+ @blacklist.group(name='get', aliases=['g'])
+ async def _get_blacklist(self, ctx):
+ if ctx.invoked_subcommand is None:
+ await ctx.send('**Invalid blacklist.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ @_get_blacklist.command(name='global', aliases=['gl', 'g'])
+ async def __get_global_blacklist(self, ctx, *args):
+ dest = u.get_args(ctx, args)
+
+ await dest.send('🚫 **Global blacklist:**\n```\n{}```'.format(formatter.tostring(self.blacklists['global_blacklist'])))
+ await ctx.message.add_reaction('✅')
+
+ @_get_blacklist.command(name='channel', aliases=['ch', 'c'])
+ async def __get_channel_blacklist(self, ctx, *args):
+ dest = u.get_args(ctx, args)
+
+ guild = ctx.guild if isinstance(
+ ctx.guild, d.Guild) else ctx.channel
+
+ await dest.send('🚫 {} **blacklist:**\n```\n{}```'.format(ctx.channel.mention, formatter.tostring(self.blacklists['guild_blacklist'].get(guild.id, {}).get(ctx.channel.id, set()))))
+ await ctx.message.add_reaction('✅')
+
+ @_get_blacklist.command(name='me', aliases=['m'])
+ async def __get_user_blacklist(self, ctx, *args):
+ dest = u.get_args(ctx, args)
+
+ await dest.send('🚫 {}**\'s blacklist:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(self.blacklists['user_blacklist'].get(ctx.author.id, set()))), delete_after=10)
+ await ctx.message.add_reaction('✅')
+
+ @_get_blacklist.command(name='here', aliases=['h'])
+ async def __get_here_blacklists(self, ctx, *args):
+ dest = u.get_args(ctx, args)
+
+ guild = ctx.guild if isinstance(
+ ctx.guild, d.Guild) else ctx.channel
+
+ await dest.send('🚫 **__Blacklisted:__**\n\n**Global:**\n```\n{}```\n**{}:**\n```\n{}```'.format(formatter.tostring(self.blacklists['global_blacklist']), ctx.channel.mention, formatter.tostring(self.blacklists['guild_blacklist'].get(guild.id, {}).get(ctx.channel.id, set()))))
+ await ctx.message.add_reaction('✅')
+
+ @_get_blacklist.group(name='all', aliases=['a'])
+ async def __get_all_blacklists(self, ctx):
+ if ctx.invoked_subcommand is None:
+ await ctx.send('**Invalid blacklist.**')
+ await ctx.message.add_reaction('❌')
+
+ @__get_all_blacklists.command(name='guild', aliases=['g'])
+ @commands.has_permissions(manage_channels=True)
+ async def ___get_all_guild_blacklists(self, ctx, *args):
+ dest = u.get_args(ctx, args)
+
+ guild = ctx.guild if isinstance(
+ ctx.guild, d.Guild) else ctx.channel
+
+ await dest.send('🚫 **__{} blacklists:__**\n\n{}'.format(guild.name, formatter.dict_tostring(self.blacklists['guild_blacklist'].get(guild.id, {}))))
+ await ctx.message.add_reaction('✅')
+
+ @__get_all_blacklists.command(name='user', aliases=['u', 'member', 'm'])
+ @commands.is_owner()
+ async def ___get_all_user_blacklists(self, ctx, *args):
+ dest = u.get_args(ctx, args)
+
+ await dest.send('🚫 **__User blacklists:__**\n\n{}'.format(formatter.dict_tostring(self.blacklists['user_blacklist'])))
+ await ctx.message.add_reaction('✅')
+
+ @blacklist.group(name='add', aliases=['a'])
+ async def _add_tags(self, ctx):
+ if ctx.invoked_subcommand is None:
+ await ctx.send('**Invalid blacklist.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ @_add_tags.command(name='global', aliases=['gl', 'g'])
+ @commands.is_owner()
+ async def __add_global_tags(self, ctx, *args):
+ dest, tags = u.get_args(ctx, args, rem=True)
+
+ await dest.trigger_typing()
+
+ self.blacklists['global_blacklist'].update(tags)
+ for tag in tags:
+ alias_request = await u.fetch('https://e621.net/tag_alias/index.json', params={'aliased_to': tag, 'approved': 'true'}, json=True)
+ if alias_request:
+ for dic in alias_request:
+ self.aliases.setdefault(tag, set()).add(dic['name'])
+ else:
+ self.aliases.setdefault(tag, set())
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
+ u.dump(self.aliases, 'cogs/aliases.pkl')
+
+ await dest.send('**Added to global blacklist:**\n```\n{}```'.format(formatter.tostring(tags)), delete_after=5)
+ await ctx.message.add_reaction('✅')
+
+ @_add_tags.command(name='channel', aliases=['ch', 'c'])
+ @commands.has_permissions(manage_channels=True)
+ async def __add_channel_tags(self, ctx, *args):
+ dest, tags = u.get_args(ctx, args, rem=True)
+
+ guild = ctx.guild if isinstance(
+ ctx.guild, d.Guild) else ctx.channel
+
+ await dest.trigger_typing()
+
+ self.blacklists['guild_blacklist'].setdefault(
+ guild.id, {}).setdefault(ctx.channel.id, set()).update(tags)
+ for tag in tags:
+ alias_request = await u.fetch('https://e621.net/tag_alias/index.json', params={'aliased_to': tag, 'approved': 'true'}, json=True)
+ if alias_request:
+ for dic in alias_request:
+ self.aliases.setdefault(tag, set()).add(dic['name'])
+ else:
+ self.aliases.setdefault(tag, set())
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
+ u.dump(self.aliases, 'cogs/aliases.pkl')
+
+ await dest.send('**Added to** {} **blacklist:**\n```\n{}```'.format(ctx.channel.mention, formatter.tostring(tags)), delete_after=5)
+ await ctx.message.add_reaction('✅')
+
+ @_add_tags.command(name='me', aliases=['m'])
+ async def __add_user_tags(self, ctx, *args):
+ dest, tags = u.get_args(ctx, args, rem=True)
+
+ await dest.trigger_typing()
+
+ self.blacklists['user_blacklist'].setdefault(ctx.author.id, set()).update(tags)
+ for tag in tags:
+ alias_request = await u.fetch('https://e621.net/tag_alias/index.json', params={'aliased_to': tag, 'approved': 'true'}, json=True)
+ if alias_request:
+ for dic in alias_request:
+ self.aliases.setdefault(tag, set()).add(dic['name'])
+ else:
+ self.aliases.setdefault(tag, set())
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
+ u.dump(self.aliases, 'cogs/aliases.pkl')
+
+ await dest.send('{} **added to their blacklist:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(tags)), delete_after=5)
+ await ctx.message.add_reaction('✅')
+
+ @blacklist.group(name='remove', aliases=['rm', 'r'])
+ async def _remove_tags(self, ctx):
+ if ctx.invoked_subcommand is None:
+ await ctx.send('**Invalid blacklist.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ @_remove_tags.command(name='global', aliases=['gl', 'g'])
+ @commands.is_owner()
+ async def __remove_global_tags(self, ctx, *args):
+ try:
+ dest, tags = u.get_args(ctx, args, rem=True)
+
+ for tag in tags:
try:
- tags = self.get_favorites(ctx, args)
+ self.blacklists['global_blacklist'].remove(tag)
- await dest.trigger_typing()
+ except KeyError:
+ raise exc.TagError(tag)
- posts = await self.check_return_posts(ctx, booru='e926', tags=tags, limit=limit)
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
- for ident, post in posts.items():
- embed = d.Embed(title=post['author'], url='https://e926.net/post/show/{}'.format(ident),
- color=ctx.me.color if isinstance(ctx.channel, d.TextChannel) else self.color).set_image(url=post['url'])
- embed.set_author(name=formatter.tostring(tags, random=True),
- url='https://e621.net/post?tags={}'.format(','.join(tags)), icon_url=ctx.author.avatar_url)
- embed.set_footer(
- text=str(ident), icon_url='http://lh6.ggpht.com/d3pNZNFCcJM8snBsRSdKUhR9AVBnJMcYYrR92RRDBOzCrxZMhuTeoGOQSmSEn7DAPQ=w300')
+ await dest.send('**Removed from global blacklist:**\n```\n{}```'.format(formatter.tostring(tags)), delete_after=5)
+ await ctx.message.add_reaction('✅')
- await dest.send(embed=embed)
+ except exc.TagError as e:
+ await ctx.send('`{}` **not in blacklist.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
- await ctx.message.add_reaction('✅')
+ @_remove_tags.command(name='channel', aliases=['ch', 'c'])
+ @commands.has_permissions(manage_channels=True)
+ async def __remove_channel_tags(self, ctx, *args):
+ try:
+ dest, tags = u.get_args(ctx, args, rem=True)
- except exc.TagBlacklisted as e:
- await ctx.send('`{}` **blacklisted.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.BoundsError as e:
- await ctx.send('`{}` **out of bounds.** Images limited to 3.'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.TagBoundsError as e:
- await ctx.send('`{}` **out of bounds.** Tags limited to 5.'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.NotFound as e:
- await ctx.send('`{}` **not found.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.FavoritesNotFound:
- await ctx.send('**You have no favorite tags.**', delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.Timeout:
- await ctx.send('**Request timed out.**')
- await ctx.message.add_reaction('❌')
-
- @commands.group(aliases=['fave', 'fav', 'f'])
- @checks.del_ctx()
- async def favorite(self, ctx):
- if ctx.invoked_subcommand is None:
- await ctx.send('**Use a flag to manage favorites.**\n*Type* `{}help fav` *for more info.*'.format(ctx.prefix), delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @favorite.error
- async def favorite_error(self, ctx, error):
- pass
-
- @favorite.group(name='get', aliases=['g'])
- async def _get_favorite(self, ctx):
- pass
-
- @_get_favorite.command(name='tags', aliases=['t'])
- async def __get_favorite_tags(self, ctx, *args):
- dest = u.get_args(ctx, *args)
-
- await dest.send('⭐ {}**\'s favorite tags:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(self.favorites.get(ctx.author.id, {}).get('tags', set()))), delete_after=10)
- await ctx.message.add_reaction('✅')
-
- @_get_favorite.command(name='posts', aliases=['p'])
- async def __get_favorite_posts(self, ctx):
- pass
-
- @favorite.group(name='add', aliases=['a'])
- async def _add_favorite(self, ctx):
- pass
-
- @_add_favorite.command(name='tags', aliases=['t'])
- async def __add_favorite_tags(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
+ guild = ctx.guild if isinstance(
+ ctx.guild, d.Guild) else ctx.channel
+ for tag in tags:
try:
- for tag in tags:
- if tag in self.blacklists['user_blacklist'].get(ctx.author.id, set()):
- raise exc.TagBlacklisted(tag)
- if len(self.favorites[ctx.author.id]['tags']) + len(tags) > 5:
- raise exc.BoundsError
+ self.blacklists['guild_blacklist'][guild.id][ctx.channel.id].remove(tag)
- self.favorites.setdefault(ctx.author.id, {}).setdefault('tags', set()).update(tags)
- u.dump(self.favorites, 'cogs/favorites.pkl')
+ except KeyError:
+ raise exc.TagError(tag)
- await dest.send('{} **added to their favorites:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(tags)), delete_after=5)
- await ctx.message.add_reaction('✅')
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
- except exc.BoundsError:
- await ctx.send('**Favorites list currently limited to:** `5`', delete_after=10)
- await ctx.message.add_reaction('❌')
- except exc.TagBlacklisted as e:
- await ctx.send('🚫 `{}` **blacklisted.**', delete_after=10)
- await ctx.message.add_reaction('🚫')
+ await dest.send('**Removed from** {} **blacklist:**\n```\n{}```'.format(ctx.channel.mention, formatter.tostring(tags), delete_after=5))
+ await ctx.message.add_reaction('✅')
- @_add_favorite.command(name='posts', aliases=['p'])
- async def __add_favorite_posts(self, ctx, *posts):
- pass
+ except exc.TagError as e:
+ await ctx.send('`{}` **not in blacklist.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
- @favorite.group(name='remove', aliases=['r'])
- async def _remove_favorite(self, ctx):
- pass
-
- @_remove_favorite.command(name='tags', aliases=['t'])
- async def __remove_favorite_tags(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
+ @_remove_tags.command(name='me', aliases=['m'])
+ async def __remove_user_tags(self, ctx, *args):
+ try:
+ dest, tags = u.get_args(ctx, args, rem=True)
+ for tag in tags:
try:
- for tag in tags:
- try:
- self.favorites[ctx.author.id].get('tags', set()).remove(tag)
+ self.blacklists['user_blacklist'][ctx.author.id].remove(tag)
- except KeyError:
- raise exc.TagError(tag)
+ except KeyError:
+ raise exc.TagError(tag)
- u.dump(self.favorites, 'cogs/favorites.pkl')
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
- await dest.send('{} **removed from their favorites:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(tags)), delete_after=5)
- await ctx.message.add_reaction('✅')
+ await dest.send('{} **removed from their blacklist:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(tags)), delete_after=5)
+ await ctx.message.add_reaction('✅')
- except exc.TagError as e:
- await ctx.send('`{}` **not in favorites.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
+ except exc.TagError as e:
+ await ctx.send('`{}` **not in blacklist.**'.format(e), delete_after=10)
+ await ctx.message.add_reaction('❌')
- @_remove_favorite.command(name='posts', aliases=['p'])
- async def __remove_favorite_posts(self, ctx):
- pass
+ @blacklist.group(name='clear', aliases=['cl', 'c'])
+ async def _clear_blacklist(self, ctx):
+ if ctx.invoked_subcommand is None:
+ await ctx.send('**Invalid blacklist.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
- @favorite.group(name='clear', aliases=['c'])
- async def _clear_favorite(self, ctx):
- pass
+ @_clear_blacklist.command(name='global', aliases=['gl', 'g'])
+ @commands.is_owner()
+ async def __clear_global_blacklist(self, ctx, *args):
+ dest = u.get_args(ctx, args)
- @_clear_favorite.command(name='tags', aliases=['t'])
- async def __clear_favorite_tags(self, ctx, *args):
- dest = u.get_args(ctx, args)
+ self.blacklists['global_blacklist'].clear()
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
- with suppress(KeyError):
- del self.favorites[ctx.author.id]
- u.dump(self.favorites, 'cogs/favorites.pkl')
+ await dest.send('**Global blacklist cleared.**', delete_after=5)
+ await ctx.message.add_reaction('✅')
- await dest.send('{}**\'s favorites cleared.**'.format(ctx.author.mention), delete_after=5)
- await ctx.message.add_reaction('✅')
+ @_clear_blacklist.command(name='channel', aliases=['ch', 'c'])
+ @commands.has_permissions(manage_channels=True)
+ async def __clear_channel_blacklist(self, ctx, *args):
+ dest = u.get_args(ctx, args)
- @_clear_favorite.command(name='posts', aliases=['p'])
- async def __clear_favorite_posts(self, ctx):
- pass
+ guild = ctx.guild if isinstance(
+ ctx.guild, d.Guild) else ctx.channel
- # Umbrella command structure to manage global, channel, and user blacklists
- @commands.group(aliases=['bl', 'b'], brief='Manage blacklists', description='Blacklist base command for managing blacklists\n\n`bl get [blacklist]` to show a blacklist\n`bl set [blacklist] [tags]` to replace a blacklist\n`bl clear [blacklist]` to clear a blacklist\n`bl add [blacklist] [tags]` to add tags to a blacklist\n`bl remove [blacklist] [tags]` to remove tags from a blacklist', usage='[flag] [blacklist] ([tags])')
- @checks.del_ctx()
- async def blacklist(self, ctx):
- if ctx.invoked_subcommand is None:
- await ctx.send('**Use a flag to manage blacklists.**\n*Type* `{}help bl` *for more info.*'.format(ctx.prefix), delete_after=10)
- await ctx.message.add_reaction('❌')
+ with suppress(KeyError):
+ del self.blacklists['guild_blacklist'][guild.id][ctx.channel.id]
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
- # @blacklist.error
- # async def blacklist_error(self, ctx, error):
- # if isinstance(error, KeyError):
- # return await ctx.send('**Blacklist does not exist.**', delete_after=10)
+ await dest.send('{} **blacklist cleared.**'.format(ctx.channel.mention), delete_after=5)
+ await ctx.message.add_reaction('✅')
- @blacklist.group(name='get', aliases=['g'])
- async def _get_blacklist(self, ctx):
- if ctx.invoked_subcommand is None:
- await ctx.send('**Invalid blacklist.**', delete_after=10)
- await ctx.message.add_reaction('❌')
+ @_clear_blacklist.command(name='me', aliases=['m'])
+ async def __clear_user_blacklist(self, ctx, *args):
+ dest = u.get_args(ctx, args)
- @_get_blacklist.command(name='global', aliases=['gl', 'g'])
- async def __get_global_blacklist(self, ctx, *args):
- dest = u.get_args(ctx, args)
+ with suppress(KeyError):
+ del self.blacklists['user_blacklist'][ctx.author.id]
+ u.dump(self.blacklists, 'cogs/blacklists.pkl')
- await dest.send('🚫 **Global blacklist:**\n```\n{}```'.format(formatter.tostring(self.blacklists['global_blacklist'])))
- await ctx.message.add_reaction('✅')
-
- @_get_blacklist.command(name='channel', aliases=['ch', 'c'])
- async def __get_channel_blacklist(self, ctx, *args):
- dest = u.get_args(ctx, args)
-
- guild = ctx.guild if isinstance(
- ctx.guild, d.Guild) else ctx.channel
-
- await dest.send('🚫 {} **blacklist:**\n```\n{}```'.format(ctx.channel.mention, formatter.tostring(self.blacklists['guild_blacklist'].get(guild.id, {}).get(ctx.channel.id, set()))))
- await ctx.message.add_reaction('✅')
-
- @_get_blacklist.command(name='me', aliases=['m'])
- async def __get_user_blacklist(self, ctx, *args):
- dest = u.get_args(ctx, args)
-
- await dest.send('🚫 {}**\'s blacklist:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(self.blacklists['user_blacklist'].get(ctx.author.id, set()))), delete_after=10)
- await ctx.message.add_reaction('✅')
-
- @_get_blacklist.command(name='here', aliases=['h'])
- async def __get_here_blacklists(self, ctx, *args):
- dest = u.get_args(ctx, args)
-
- guild = ctx.guild if isinstance(
- ctx.guild, d.Guild) else ctx.channel
-
- await dest.send('🚫 **__Blacklisted:__**\n\n**Global:**\n```\n{}```\n**{}:**\n```\n{}```'.format(formatter.tostring(self.blacklists['global_blacklist']), ctx.channel.mention, formatter.tostring(self.blacklists['guild_blacklist'].get(guild.id, {}).get(ctx.channel.id, set()))))
- await ctx.message.add_reaction('✅')
-
- @_get_blacklist.group(name='all', aliases=['a'])
- async def __get_all_blacklists(self, ctx):
- if ctx.invoked_subcommand is None:
- await ctx.send('**Invalid blacklist.**')
- await ctx.message.add_reaction('❌')
-
- @__get_all_blacklists.command(name='guild', aliases=['g'])
- @commands.has_permissions(manage_channels=True)
- async def ___get_all_guild_blacklists(self, ctx, *args):
- dest = u.get_args(ctx, args)
-
- guild = ctx.guild if isinstance(
- ctx.guild, d.Guild) else ctx.channel
-
- await dest.send('🚫 **__{} blacklists:__**\n\n{}'.format(guild.name, formatter.dict_tostring(self.blacklists['guild_blacklist'].get(guild.id, {}))))
- await ctx.message.add_reaction('✅')
-
- @__get_all_blacklists.command(name='user', aliases=['u', 'member', 'm'])
- @commands.is_owner()
- async def ___get_all_user_blacklists(self, ctx, *args):
- dest = u.get_args(ctx, args)
-
- await dest.send('🚫 **__User blacklists:__**\n\n{}'.format(formatter.dict_tostring(self.blacklists['user_blacklist'])))
- await ctx.message.add_reaction('✅')
-
- @blacklist.group(name='add', aliases=['a'])
- async def _add_tags(self, ctx):
- if ctx.invoked_subcommand is None:
- await ctx.send('**Invalid blacklist.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @_add_tags.command(name='global', aliases=['gl', 'g'])
- @commands.is_owner()
- async def __add_global_tags(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
-
- await dest.trigger_typing()
-
- self.blacklists['global_blacklist'].update(tags)
- for tag in tags:
- alias_request = await u.fetch('https://e621.net/tag_alias/index.json', params={'aliased_to': tag, 'approved': 'true'}, json=True)
- if alias_request:
- for dic in alias_request:
- self.aliases.setdefault(tag, set()).add(dic['name'])
- else:
- self.aliases.setdefault(tag, set())
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
- u.dump(self.aliases, 'cogs/aliases.pkl')
-
- await dest.send('**Added to global blacklist:**\n```\n{}```'.format(formatter.tostring(tags)), delete_after=5)
- await ctx.message.add_reaction('✅')
-
- @_add_tags.command(name='channel', aliases=['ch', 'c'])
- @commands.has_permissions(manage_channels=True)
- async def __add_channel_tags(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
-
- guild = ctx.guild if isinstance(
- ctx.guild, d.Guild) else ctx.channel
-
- await dest.trigger_typing()
-
- self.blacklists['guild_blacklist'].setdefault(
- guild.id, {}).setdefault(ctx.channel.id, set()).update(tags)
- for tag in tags:
- alias_request = await u.fetch('https://e621.net/tag_alias/index.json', params={'aliased_to': tag, 'approved': 'true'}, json=True)
- if alias_request:
- for dic in alias_request:
- self.aliases.setdefault(tag, set()).add(dic['name'])
- else:
- self.aliases.setdefault(tag, set())
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
- u.dump(self.aliases, 'cogs/aliases.pkl')
-
- await dest.send('**Added to** {} **blacklist:**\n```\n{}```'.format(ctx.channel.mention, formatter.tostring(tags)), delete_after=5)
- await ctx.message.add_reaction('✅')
-
- @_add_tags.command(name='me', aliases=['m'])
- async def __add_user_tags(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
-
- await dest.trigger_typing()
-
- self.blacklists['user_blacklist'].setdefault(ctx.author.id, set()).update(tags)
- for tag in tags:
- alias_request = await u.fetch('https://e621.net/tag_alias/index.json', params={'aliased_to': tag, 'approved': 'true'}, json=True)
- if alias_request:
- for dic in alias_request:
- self.aliases.setdefault(tag, set()).add(dic['name'])
- else:
- self.aliases.setdefault(tag, set())
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
- u.dump(self.aliases, 'cogs/aliases.pkl')
-
- await dest.send('{} **added to their blacklist:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(tags)), delete_after=5)
- await ctx.message.add_reaction('✅')
-
- @blacklist.group(name='remove', aliases=['rm', 'r'])
- async def _remove_tags(self, ctx):
- if ctx.invoked_subcommand is None:
- await ctx.send('**Invalid blacklist.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @_remove_tags.command(name='global', aliases=['gl', 'g'])
- @commands.is_owner()
- async def __remove_global_tags(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
-
- try:
- for tag in tags:
- try:
- self.blacklists['global_blacklist'].remove(tag)
-
- except KeyError:
- raise exc.TagError(tag)
-
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
-
- await dest.send('**Removed from global blacklist:**\n```\n{}```'.format(formatter.tostring(tags)), delete_after=5)
- await ctx.message.add_reaction('✅')
-
- except exc.TagError as e:
- await ctx.send('`{}` **not in blacklist.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @_remove_tags.command(name='channel', aliases=['ch', 'c'])
- @commands.has_permissions(manage_channels=True)
- async def __remove_channel_tags(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
-
- guild = ctx.guild if isinstance(
- ctx.guild, d.Guild) else ctx.channel
-
- try:
- for tag in tags:
- try:
- self.blacklists['guild_blacklist'][guild.id][ctx.channel.id].remove(tag)
-
- except KeyError:
- raise exc.TagError(tag)
-
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
-
- await dest.send('**Removed from** {} **blacklist:**\n```\n{}```'.format(ctx.channel.mention, formatter.tostring(tags), delete_after=5))
- await ctx.message.add_reaction('✅')
-
- except exc.TagError as e:
- await ctx.send('`{}` **not in blacklist.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @_remove_tags.command(name='me', aliases=['m'])
- async def __remove_user_tags(self, ctx, *args):
- dest, tags = u.get_args(ctx, args, rem=True)
-
- try:
- for tag in tags:
- try:
- self.blacklists['user_blacklist'][ctx.author.id].remove(tag)
-
- except KeyError:
- raise exc.TagError(tag)
-
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
-
- await dest.send('{} **removed from their blacklist:**\n```\n{}```'.format(ctx.author.mention, formatter.tostring(tags)), delete_after=5)
- await ctx.message.add_reaction('✅')
-
- except exc.TagError as e:
- await ctx.send('`{}` **not in blacklist.**'.format(e), delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @blacklist.group(name='clear', aliases=['cl', 'c'])
- async def _clear_blacklist(self, ctx):
- if ctx.invoked_subcommand is None:
- await ctx.send('**Invalid blacklist.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @_clear_blacklist.command(name='global', aliases=['gl', 'g'])
- @commands.is_owner()
- async def __clear_global_blacklist(self, ctx, *args):
- dest = u.get_args(ctx, args)
-
- self.blacklists['global_blacklist'].clear()
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
-
- await dest.send('**Global blacklist cleared.**', delete_after=5)
- await ctx.message.add_reaction('✅')
-
- @_clear_blacklist.command(name='channel', aliases=['ch', 'c'])
- @commands.has_permissions(manage_channels=True)
- async def __clear_channel_blacklist(self, ctx, *args):
- dest = u.get_args(ctx, args)
-
- guild = ctx.guild if isinstance(
- ctx.guild, d.Guild) else ctx.channel
-
- with suppress(KeyError):
- del self.blacklists['guild_blacklist'][guild.id][ctx.channel.id]
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
-
- await dest.send('{} **blacklist cleared.**'.format(ctx.channel.mention), delete_after=5)
- await ctx.message.add_reaction('✅')
-
- @_clear_blacklist.command(name='me', aliases=['m'])
- async def __clear_user_blacklist(self, ctx, *args):
- dest = u.get_args(ctx, args)
-
- with suppress(KeyError):
- del self.blacklists['user_blacklist'][ctx.author.id]
- u.dump(self.blacklists, 'cogs/blacklists.pkl')
-
- await dest.send('{}**\'s blacklist cleared.**'.format(ctx.author.mention), delete_after=5)
- await ctx.message.add_reaction('✅')
+ await dest.send('{}**\'s blacklist cleared.**'.format(ctx.author.mention), delete_after=5)
+ await ctx.message.add_reaction('✅')
diff --git a/src/main/cogs/info.py b/src/main/cogs/info.py
index 920e189..d1ba053 100644
--- a/src/main/cogs/info.py
+++ b/src/main/cogs/info.py
@@ -10,40 +10,40 @@ from utils import utils as u
class Info:
- def __init__(self, bot):
- self.bot = bot
+ def __init__(self, bot):
+ self.bot = bot
- # @commands.command(name='helptest', aliases=['h'], hidden=True)
- # async def list_commands(self, ctx):
- # embed = d.Embed(title='All possible commands:', color=ctx.me.color)
- # embed.set_author(name=ctx.me.display_name, icon_url=ctx.me.avatar_url)
- # embed.add_field(
- # name='Booru', value='\n{}bl umbrella command for managing blacklists'.format(u.config['prefix']))
- #
- # await ctx.send(embed=embed)
+ # @commands.command(name='helptest', aliases=['h'], hidden=True)
+ # async def list_commands(self, ctx):
+ # embed = d.Embed(title='All possible commands:', color=ctx.me.color)
+ # embed.set_author(name=ctx.me.display_name, icon_url=ctx.me.avatar_url)
+ # embed.add_field(
+ # name='Booru', value='\n{}bl umbrella command for managing blacklists'.format(u.config['prefix']))
+ #
+ # await ctx.send(embed=embed)
- @commands.command(hidden=True)
- async def hi(self, ctx, *args):
- dest = u.get_args(ctx, args)
+ @commands.command(hidden=True)
+ async def hi(self, ctx, *args):
+ dest = u.get_args(ctx, args)
- hello = 'Hewwo, {}.'.format(ctx.author.mention)
- if ctx.author.id == checks.owner_id:
- hello += '.. ***Master.*** uwu'
- elif ctx.author.guild_permissions.administrator:
- hello = '{} **Admin** {}'.format(hello[:7], hello[7:])
- elif ctx.author.guild_permissions.ban_members:
- hello = '{} **Mod** {}'.format(hello[:7], hello[7:])
- await dest.send(hello)
+ hello = 'Hewwo, {}.'.format(ctx.author.mention)
+ if ctx.author.id == checks.owner_id:
+ hello += '.. ***Master.*** uwu'
+ elif ctx.author.guild_permissions.administrator:
+ hello = '{} **Admin** {}'.format(hello[:7], hello[7:])
+ elif ctx.author.guild_permissions.ban_members:
+ hello = '{} **Mod** {}'.format(hello[:7], hello[7:])
+ await dest.send(hello)
- @commands.group(name='info', aliases=['i'])
- async def info(self, ctx):
- if invoked_subcommand is None:
- await ctx.send('')
+ @commands.group(name='info', aliases=['i'])
+ async def info(self, ctx):
+ if invoked_subcommand is None:
+ await ctx.send('')
- @info.command(aliases=['g', 'server', 's'], brief='Provides info about a guild', hidden=True)
- async def guild(self, ctx):
- pass
+ @info.command(aliases=['g', 'server', 's'], brief='Provides info about a guild', hidden=True)
+ async def guild(self, ctx):
+ pass
- @info.command(aliases=['u', 'member', 'm'], brief='Provides info about a user', hidden=True)
- async def user(self, ctx):
- pass
+ @info.command(aliases=['u', 'member', 'm'], brief='Provides info about a user', hidden=True)
+ async def user(self, ctx):
+ pass
diff --git a/src/main/cogs/management.py b/src/main/cogs/management.py
index 67c669b..03814a8 100644
--- a/src/main/cogs/management.py
+++ b/src/main/cogs/management.py
@@ -13,168 +13,168 @@ from utils import utils as u
class Administration:
- def __init__(self, bot):
- self.bot = bot
- self.RATE_LIMIT = u.RATE_LIMIT
- self.queue = asyncio.Queue()
+ def __init__(self, bot):
+ self.bot = bot
+ self.RATE_LIMIT = u.RATE_LIMIT
+ self.queue = asyncio.Queue()
+ self.deleting = False
+
+ if u.tasks['auto_del']:
+ for channel in u.tasks['auto_del']:
+ temp = self.bot.get_channel(channel)
+ self.bot.loop.create_task(self.queue_for_deletion(temp))
+ print('AUTO-DELETING : #{}'.format(temp.id))
+ self.bot.loop.create_task(self.delete())
+ self.deleting = True
+
+ @commands.command(name=',prunefromguild', aliases=[',pfg', ',prunefromserver', ',pfs'], brief='Prune a user\'s messages from the guild', description='about flag centers on message 50 of 101 messages\n\npfg \{user id\} [before|after|about] [\{message id\}]\n\nExample:\npfg \{user id\} before \{message id\}')
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def prune_all_user(self, ctx, user, when=None, reference=None):
+ def yes(msg):
+ if msg.content.lower() == 'y' and msg.channel is ctx.channel and msg.author is ctx.author:
+ return True
+ elif msg.content.lower() == 'n' and msg.channel is ctx.channel and msg.author is ctx.author:
+ raise exc.CheckFail
+ else:
+ return False
+
+ channels = ctx.guild.text_channels
+ if reference is not None:
+ for channel in channels:
+ try:
+ ref = await channel.get_message(reference)
+
+ except err.NotFound:
+ continue
+
+ history = []
+ try:
+ pru_sent = await ctx.send('⏳ **Pruning** <@{}>**\'s messages will take some time.**'.format(user))
+ ch_sent = await ctx.send('🗄 **Caching channels...**')
+
+ if when is None:
+ for channel in channels:
+ async for message in channel.history(limit=None):
+ if message.author.id == int(user):
+ history.append(message)
+ await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
+ await asyncio.sleep(self.RATE_LIMIT)
+ elif when == 'before':
+ for channel in channels:
+ async for message in channel.history(limit=None, before=ref.created_at):
+ if message.author.id == int(user):
+ history.append(message)
+ await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
+ await asyncio.sleep(self.RATE_LIMIT)
+ elif when == 'after':
+ for channel in channels:
+ async for message in channel.history(limit=None, after=ref.created_at):
+ if message.author.id == int(user):
+ history.append(message)
+ await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
+ await asyncio.sleep(self.RATE_LIMIT)
+ elif when == 'about':
+ for channel in channels:
+ async for message in channel.history(limit=None, about=ref.created_at):
+ if message.author.id == int(user):
+ history.append(message)
+ await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
+ await asyncio.sleep(self.RATE_LIMIT)
+
+ est_sent = await ctx.send('⏱ **Estimated time to delete history:** `{}m {}s`'.format(int(self.RATE_LIMIT * len(history) / 60), int(self.RATE_LIMIT * len(history) % 60)))
+ cont_sent = await ctx.send('{} **Continue?** `Y` or `N`'.format(ctx.author.mention))
+ await self.bot.wait_for('message', check=yes, timeout=10 * 60)
+ await cont_sent.delete()
+ del_sent = await ctx.send('🗑 **Deleting messages...**')
+ await del_sent.pin()
+ c = 0
+ for message in history:
+ with suppress(err.NotFound):
+ await message.delete()
+ c += 1
+ await del_sent.edit(content='🗑 **Deleted** `{}/{}` **messages.**'.format(history.index(message) + 1, len(history)))
+ await asyncio.sleep(self.RATE_LIMIT)
+ await del_sent.unpin()
+
+ await ctx.send('🗑 `{}` **of** <@{}>**\'s messages left in** {}**.**'.format(len(history) - c, user, ctx.guild.name))
+ await ctx.message.add_reaction('✅')
+
+ except exc.CheckFail:
+ await ctx.send('**Deletion aborted.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ except TimeoutError:
+ await ctx.send('**Deletion timed out.**', delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ async def delete(self):
+ while self.deleting:
+ message = await self.queue.get()
+ await asyncio.sleep(self.RATE_LIMIT)
+ with suppress(err.NotFound):
+ if not message.pinned:
+ await message.delete()
+
+ print('STOPPED : deleting')
+
+ async def queue_for_deletion(self, channel):
+ def check(msg):
+ if msg.content.lower() == 'stop' and msg.channel is channel and msg.author.guild_permissions.administrator:
+ raise exc.Abort
+ elif msg.channel is channel and not msg.pinned:
+ return True
+ return False
+
+ try:
+ async for message in channel.history(limit=None):
+ if message.content.lower() == 'stop' and message.author.guild_permissions.administrator:
+ raise exc.Abort
+ if not message.pinned:
+ await self.queue.put(message)
+
+ while not self.bot.is_closed():
+ message = await self.bot.wait_for('message', check=check)
+ await self.queue.put(message)
+
+ except exc.Abort:
+ u.tasks['auto_del'].remove(channel.id)
+ u.dump(u.tasks, 'cogs/tasks.pkl')
+ if not u.tasks['auto_del']:
self.deleting = False
+ print('STOPPED : deleting #{}'.format(channel.id))
+ await channel.send('**Stopped queueing messages for deletion in** {}**.**'.format(channel.mention), delete_after=5)
- if u.tasks['auto_del']:
- for channel in u.tasks['auto_del']:
- temp = self.bot.get_channel(channel)
- self.bot.loop.create_task(self.queue_for_deletion(temp))
- print('AUTO-DELETING : #{}'.format(temp.id))
- self.bot.loop.create_task(self.delete())
- self.deleting = True
-
- @commands.command(name=',prunefromguild', aliases=[',pfg', ',prunefromserver', ',pfs'], brief='Prune a user\'s messages from the guild', description='about flag centers on message 50 of 101 messages\n\npfg \{user id\} [before|after|about] [\{message id\}]\n\nExample:\npfg \{user id\} before \{message id\}')
- @commands.is_owner()
- @checks.del_ctx()
- async def prune_all_user(self, ctx, user, when=None, reference=None):
- def yes(msg):
- if msg.content.lower() == 'y' and msg.channel is ctx.channel and msg.author is ctx.author:
- return True
- elif msg.content.lower() == 'n' and msg.channel is ctx.channel and msg.author is ctx.author:
- raise exc.CheckFail
- else:
- return False
-
- channels = ctx.guild.text_channels
- if reference is not None:
- for channel in channels:
- try:
- ref = await channel.get_message(reference)
-
- except err.NotFound:
- continue
-
- history = []
- try:
- pru_sent = await ctx.send('⏳ **Pruning** <@{}>**\'s messages will take some time.**'.format(user))
- ch_sent = await ctx.send('🗄 **Caching channels...**')
-
- if when is None:
- for channel in channels:
- async for message in channel.history(limit=None):
- if message.author.id == int(user):
- history.append(message)
- await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
- await asyncio.sleep(self.RATE_LIMIT)
- elif when == 'before':
- for channel in channels:
- async for message in channel.history(limit=None, before=ref.created_at):
- if message.author.id == int(user):
- history.append(message)
- await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
- await asyncio.sleep(self.RATE_LIMIT)
- elif when == 'after':
- for channel in channels:
- async for message in channel.history(limit=None, after=ref.created_at):
- if message.author.id == int(user):
- history.append(message)
- await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
- await asyncio.sleep(self.RATE_LIMIT)
- elif when == 'about':
- for channel in channels:
- async for message in channel.history(limit=None, about=ref.created_at):
- if message.author.id == int(user):
- history.append(message)
- await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
- await asyncio.sleep(self.RATE_LIMIT)
-
- est_sent = await ctx.send('⏱ **Estimated time to delete history:** `{}m {}s`'.format(int(self.RATE_LIMIT * len(history) / 60), int(self.RATE_LIMIT * len(history) % 60)))
- cont_sent = await ctx.send('{} **Continue?** `Y` or `N`'.format(ctx.author.mention))
- await self.bot.wait_for('message', check=yes, timeout=10 * 60)
- await cont_sent.delete()
- del_sent = await ctx.send('🗑 **Deleting messages...**')
- await del_sent.pin()
- c = 0
- for message in history:
- with suppress(err.NotFound):
- await message.delete()
- c += 1
- await del_sent.edit(content='🗑 **Deleted** `{}/{}` **messages.**'.format(history.index(message) + 1, len(history)))
- await asyncio.sleep(self.RATE_LIMIT)
- await del_sent.unpin()
-
- await ctx.send('🗑 `{}` **of** <@{}>**\'s messages left in** {}**.**'.format(len(history) - c, user, ctx.guild.name))
- await ctx.message.add_reaction('✅')
-
- except exc.CheckFail:
- await ctx.send('**Deletion aborted.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- except TimeoutError:
- await ctx.send('**Deletion timed out.**', delete_after=10)
- await ctx.message.add_reaction('❌')
-
- async def delete(self):
- while self.deleting:
- message = await self.queue.get()
- await asyncio.sleep(self.RATE_LIMIT)
- with suppress(err.NotFound):
- if not message.pinned:
- await message.delete()
-
- print('STOPPED : deleting')
-
- async def queue_for_deletion(self, channel):
- def check(msg):
- if msg.content.lower() == 'stop' and msg.channel is channel and msg.author.guild_permissions.administrator:
- raise exc.Abort
- elif msg.channel is channel and not msg.pinned:
- return True
- return False
-
- try:
- async for message in channel.history(limit=None):
- if message.content.lower() == 'stop' and message.author.guild_permissions.administrator:
- raise exc.Abort
- if not message.pinned:
- await self.queue.put(message)
-
- while not self.bot.is_closed():
- message = await self.bot.wait_for('message', check=check)
- await self.queue.put(message)
-
- except exc.Abort:
- u.tasks['auto_del'].remove(channel.id)
- u.dump(u.tasks, 'cogs/tasks.pkl')
- if not u.tasks['auto_del']:
- self.deleting = False
- print('STOPPED : deleting #{}'.format(channel.id))
- await channel.send('**Stopped queueing messages for deletion in** {}**.**'.format(channel.mention), delete_after=5)
-
- @commands.command(name='autodelete', aliases=['autodel', 'ad'])
- @commands.has_permissions(administrator=True)
- @checks.del_ctx()
- async def auto_delete(self, ctx):
- try:
- if ctx.channel.id not in u.tasks['auto_del']:
- u.tasks['auto_del'].append(ctx.channel.id)
- u.dump(u.tasks, 'cogs/tasks.pkl')
- self.bot.loop.create_task(self.queue_for_deletion(ctx.channel))
- if not self.deleting:
- self.bot.loop.create_task(self.delete())
- self.deleting = True
- print('AUTO-DELETING : #{}'.format(ctx.channel.id))
- await ctx.send('**Auto-deleting all messages in {}.**'.format(ctx.channel.mention), delete_after=5)
- await ctx.message.add_reaction('✅')
- else:
- raise exc.Exists
-
- except exc.Exists:
- await ctx.send('**Already auto-deleting in {}.** Type `stop` to stop.'.format(ctx.channel.mention), delete_after=10)
- await ctx.message.add_reaction('❌')
-
- @commands.command(name='deletecommands', aliases=['delcmds'])
- @commands.has_permissions(administrator=True)
- async def delete_commands(self, ctx):
- if ctx.guild.id not in u.settings['del_ctx']:
- u.settings['del_ctx'].append(ctx.guild.id)
- else:
- u.settings['del_ctx'].remove(ctx.guild.id)
- u.dump(u.settings, 'settings.pkl')
-
- await ctx.send('**Delete command invocations:** `{}`'.format(ctx.guild.id in u.settings['del_ctx']))
+ @commands.command(name='autodelete', aliases=['autodel', 'ad'])
+ @commands.has_permissions(administrator=True)
+ @checks.del_ctx()
+ async def auto_delete(self, ctx):
+ try:
+ if ctx.channel.id not in u.tasks['auto_del']:
+ u.tasks['auto_del'].append(ctx.channel.id)
+ u.dump(u.tasks, 'cogs/tasks.pkl')
+ self.bot.loop.create_task(self.queue_for_deletion(ctx.channel))
+ if not self.deleting:
+ self.bot.loop.create_task(self.delete())
+ self.deleting = True
+ print('AUTO-DELETING : #{}'.format(ctx.channel.id))
+ await ctx.send('**Auto-deleting all messages in {}.**'.format(ctx.channel.mention), delete_after=5)
await ctx.message.add_reaction('✅')
+ else:
+ raise exc.Exists
+
+ except exc.Exists:
+ await ctx.send('**Already auto-deleting in {}.** Type `stop` to stop.'.format(ctx.channel.mention), delete_after=10)
+ await ctx.message.add_reaction('❌')
+
+ @commands.command(name='deletecommands', aliases=['delcmds'])
+ @commands.has_permissions(administrator=True)
+ async def delete_commands(self, ctx):
+ if ctx.guild.id not in u.settings['del_ctx']:
+ u.settings['del_ctx'].append(ctx.guild.id)
+ else:
+ u.settings['del_ctx'].remove(ctx.guild.id)
+ u.dump(u.settings, 'settings.pkl')
+
+ await ctx.send('**Delete command invocations:** `{}`'.format(ctx.guild.id in u.settings['del_ctx']))
+ await ctx.message.add_reaction('✅')
diff --git a/src/main/cogs/owner.py b/src/main/cogs/owner.py
index 3edecae..7976395 100644
--- a/src/main/cogs/owner.py
+++ b/src/main/cogs/owner.py
@@ -19,166 +19,166 @@ nl = re.compile('\n')
class Bot:
- def __init__(self, bot):
- self.bot = bot
+ def __init__(self, bot):
+ self.bot = bot
- # Close connection to Discord - immediate offline
- @commands.command(name=',die', aliases=[',d'], brief='Kills the bot', description='BOT OWNER ONLY\nCloses the connection to Discord', hidden=True)
- @commands.is_owner()
- @checks.del_ctx()
- async def die(self, ctx):
- await ctx.message.add_reaction('🌙')
+ # Close connection to Discord - immediate offline
+ @commands.command(name=',die', aliases=[',d'], brief='Kills the bot', description='BOT OWNER ONLY\nCloses the connection to Discord', hidden=True)
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def die(self, ctx):
+ await ctx.message.add_reaction('🌙')
- await self.bot.get_channel(u.config['info_channel']).send('**Shutting down** 🌙 . . .')
- # loop = self.bot.loop.all_tasks()
- # for task in loop:
- # task.cancel()
- await self.bot.logout()
- u.close(self.bot.loop)
- print('\n/ / / / / / / / / / / /\nD I S C O N N E C T E D\n\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\\n')
- # u.notify('D I S C O N N E C T E D')
+ await self.bot.get_channel(u.config['info_channel']).send('**Shutting down** 🌙 . . .')
+ # loop = self.bot.loop.all_tasks()
+ # for task in loop:
+ # task.cancel()
+ await self.bot.logout()
+ u.close(self.bot.loop)
+ print('\n/ / / / / / / / / / / /\nD I S C O N N E C T E D\n\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\\n')
+ # u.notify('D I S C O N N E C T E D')
- @commands.command(name=',restart', aliases=[',res', ',r'], hidden=True)
- @commands.is_owner()
- @checks.del_ctx()
- async def restart(self, ctx):
- await ctx.message.add_reaction('💤')
+ @commands.command(name=',restart', aliases=[',res', ',r'], hidden=True)
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def restart(self, ctx):
+ await ctx.message.add_reaction('💤')
- print('\n| | | | | | | | | |\nR E S T A R T I N G\n| | | | | | | | | |\n')
- await self.bot.get_channel(u.config['info_channel']).send('**Restarting** 💤 . . .')
- # u.notify('R E S T A R T I N G')
+ print('\n| | | | | | | | | |\nR E S T A R T I N G\n| | | | | | | | | |\n')
+ await self.bot.get_channel(u.config['info_channel']).send('**Restarting** 💤 . . .')
+ # u.notify('R E S T A R T I N G')
- u.temp['restart_ch'] = ctx.channel.id
- u.temp['restart_msg'] = ctx.message.id
- u.dump(u.temp, 'temp/temp.pkl')
+ u.temp['restart_ch'] = ctx.channel.id
+ u.temp['restart_msg'] = ctx.message.id
+ u.dump(u.temp, 'temp.pkl')
- # loop = self.bot.loop.all_tasks()
- # for task in loop:
- # task.cancel()
- await self.bot.logout()
- u.close(self.bot.loop)
- os.execl(sys.executable, 'python3', 'run.py')
+ # loop = self.bot.loop.all_tasks()
+ # for task in loop:
+ # task.cancel()
+ await self.bot.logout()
+ u.close(self.bot.loop)
+ os.execl(sys.executable, 'python3', 'run.py')
- # Invite bot to bot owner's server
- @commands.command(name=',invite', aliases=[',inv', ',link'], brief='Invite the bot', description='BOT OWNER ONLY\nInvite the bot to a server (Requires admin)', hidden=True)
- @commands.is_owner()
- @checks.del_ctx()
- async def invite(self, ctx):
- await ctx.message.add_reaction('✉️')
+ # Invite bot to bot owner's server
+ @commands.command(name=',invite', aliases=[',inv', ',link'], brief='Invite the bot', description='BOT OWNER ONLY\nInvite the bot to a server (Requires admin)', hidden=True)
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def invite(self, ctx):
+ await ctx.message.add_reaction('✉️')
- await ctx.send('🔗 https://discordapp.com/oauth2/authorize?&client_id={}&scope=bot&permissions={}'.format(u.config['client_id'], u.config['permissions']), delete_after=10)
+ await ctx.send('🔗 https://discordapp.com/oauth2/authorize?&client_id={}&scope=bot&permissions={}'.format(u.config['client_id'], u.config['permissions']), delete_after=10)
- @commands.command(name=',status', aliases=[',presence', ',game'], hidden=True)
- @commands.is_owner()
- @checks.del_ctx()
- async def status(self, ctx, *, game=None):
- if game is not None:
- await self.bot.change_presence(game=d.Game(name=game))
- u.config['playing'] = game
- u.dump(u.config, 'config.json', json=True)
- else:
- await self.bot.change_presence(game=None)
- u.config['playing'] = 'None'
- u.dump(u.config, 'config.json', json=True)
+ @commands.command(name=',status', aliases=[',presence', ',game'], hidden=True)
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def status(self, ctx, *, game=None):
+ if game is not None:
+ await self.bot.change_presence(game=d.Game(name=game))
+ u.config['playing'] = game
+ u.dump(u.config, 'config.json', json=True)
+ else:
+ await self.bot.change_presence(game=None)
+ u.config['playing'] = 'None'
+ u.dump(u.config, 'config.json', json=True)
- await ctx.message.add_reaction('✅')
+ await ctx.message.add_reaction('✅')
class Tools:
- def __init__(self, bot):
- self.bot = bot
+ def __init__(self, bot):
+ self.bot = bot
- def format(self, i='', o=''):
- if len(o) > 1:
- return '>>> {}\n{}'.format(i, o)
- else:
- return '>>> {}'.format(i)
+ def format(self, i='', o=''):
+ if len(o) > 1:
+ return '>>> {}\n{}'.format(i, o)
+ else:
+ return '>>> {}'.format(i)
- async def generate(self, d, i='', o=''):
- return await d.send('```python\n{}```'.format(self.format(i, o)))
+ async def generate(self, d, i='', o=''):
+ return await d.send('```python\n{}```'.format(self.format(i, o)))
- async def refresh(self, m, i='', o=''):
- global nl
- output = m.content[10:-2]
- if len(nl.findall(output)) <= 20:
- await m.edit(content='```python\n{}\n{}\n>>>```'.format(output, self.format(i, o)))
- else:
- await m.edit(content='```python\n{}```'.format(self.format(i, o)))
+ async def refresh(self, m, i='', o=''):
+ global nl
+ output = m.content[10:-2]
+ if len(nl.findall(output)) <= 20:
+ await m.edit(content='```python\n{}\n{}\n>>>```'.format(output, self.format(i, o)))
+ else:
+ await m.edit(content='```python\n{}```'.format(self.format(i, o)))
- async def generate_err(self, d, o=''):
- return await d.send('```\n{}```'.format(o))
+ async def generate_err(self, d, o=''):
+ return await d.send('```\n{}```'.format(o))
- async def refresh_err(self, m, o=''):
- await m.edit(content='```\n{}```'.format(o))
+ async def refresh_err(self, m, o=''):
+ await m.edit(content='```\n{}```'.format(o))
- @commands.command(name=',console', aliases=[',con', ',c'], hidden=True)
- @commands.is_owner()
- @checks.del_ctx()
- async def console(self, ctx):
- def execute(msg):
- if msg.content == 'exit' and msg.author is ctx.author:
- raise exc.Abort
- elif msg.author is ctx.author and msg.channel is ctx.channel:
- return True
- else:
- return False
+ @commands.command(name=',console', aliases=[',con', ',c'], hidden=True)
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def console(self, ctx):
+ def execute(msg):
+ if msg.content == 'exit' and msg.author is ctx.author:
+ raise exc.Abort
+ elif msg.author is ctx.author and msg.channel is ctx.channel:
+ return True
+ else:
+ return False
+ try:
+ await ctx.message.add_reaction('✅')
+
+ console = await self.generate(ctx)
+ exception = await self.generate_err(ctx)
+ while not self.bot.is_closed():
try:
- await ctx.message.add_reaction('✅')
-
- console = await self.generate(ctx)
- exception = await self.generate_err(ctx)
- while not self.bot.is_closed():
- try:
- exe = await self.bot.wait_for('message', check=execute)
- except exc.Abort:
- raise exc.Abort
- await exe.delete()
- try:
- sys.stdout = io.StringIO()
- sys.stderr = io.StringIO()
- exec(exe.content)
- except Exception:
- await self.refresh_err(exception, tb.format_exc(limit=1))
- finally:
- await self.refresh(console, exe.content, sys.stdout.getvalue())
- sys.stdout = sys.__stdout__
- sys.stderr = sys.__stderr__
+ exe = await self.bot.wait_for('message', check=execute)
except exc.Abort:
- await ctx.send('↩️ **Exited console.**')
- finally:
- sys.stdout = sys.__stdout__
- sys.stderr = sys.__stderr__
- print('Reset sys output.')
-
- @commands.command(name='arbitrary', aliases=[',arbit', ',ar'])
- @commands.is_owner()
- @checks.del_ctx()
- async def arbitrary(self, ctx, *, exe):
+ raise exc.Abort
+ await exe.delete()
try:
- await ctx.message.add_reaction('✅')
-
- sys.stdout = io.StringIO()
- exec(exe)
- await self.generate(ctx, exe, sys.stdout.getvalue())
+ sys.stdout = io.StringIO()
+ sys.stderr = io.StringIO()
+ exec(exe.content)
except Exception:
- await ctx.send('```\n{}```'.format(tb.format_exc(limit=1)))
- tb.print_exc(limit=1)
+ await self.refresh_err(exception, tb.format_exc(limit=1))
finally:
- sys.stdout = sys.__stdout__
- print('Reset stdout.')
+ await self.refresh(console, exe.content, sys.stdout.getvalue())
+ sys.stdout = sys.__stdout__
+ sys.stderr = sys.__stderr__
+ except exc.Abort:
+ await ctx.send('↩️ **Exited console.**')
+ finally:
+ sys.stdout = sys.__stdout__
+ sys.stderr = sys.__stderr__
+ print('Reset sys output.')
- @commands.group(aliases=[',db'], hidden=True)
- @commands.is_owner()
- @checks.del_ctx()
- async def debug(self, ctx):
- console = await self.generate(ctx)
+ @commands.command(name='arbitrary', aliases=[',arbit', ',ar'])
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def arbitrary(self, ctx, *, exe):
+ try:
+ await ctx.message.add_reaction('✅')
- @debug.command(name='inject', aliases=['inj'])
- async def _inject(self, ctx, *, input_):
- pass
+ sys.stdout = io.StringIO()
+ exec(exe)
+ await self.generate(ctx, exe, sys.stdout.getvalue())
+ except Exception:
+ await ctx.send('```\n{}```'.format(tb.format_exc(limit=1)))
+ tb.print_exc(limit=1)
+ finally:
+ sys.stdout = sys.__stdout__
+ print('Reset stdout.')
- @debug.command(name='inspect', aliases=['ins'])
- async def _inspect(self, ctx, *, input_):
- pass
+ @commands.group(aliases=[',db'], hidden=True)
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def debug(self, ctx):
+ console = await self.generate(ctx)
+
+ @debug.command(name='inject', aliases=['inj'])
+ async def _inject(self, ctx, *, input_):
+ pass
+
+ @debug.command(name='inspect', aliases=['ins'])
+ async def _inspect(self, ctx, *, input_):
+ pass
diff --git a/src/main/cogs/tools.py b/src/main/cogs/tools.py
index 413e80e..6772b94 100644
--- a/src/main/cogs/tools.py
+++ b/src/main/cogs/tools.py
@@ -30,88 +30,88 @@ command_dict = {}
class Utils:
- def __init__(self, bot):
- self.bot = bot
+ def __init__(self, bot):
+ self.bot = bot
- @commands.command(name='last', aliases=['l', ','], brief='Reinvokes last command', description='Reinvokes previous command executed', hidden=True)
- async def last_command(self, ctx):
- global command_dict
+ @commands.command(name='last', aliases=['l', ','], brief='Reinvokes last command', description='Reinvokes previous command executed', hidden=True)
+ async def last_command(self, ctx):
+ global command_dict
- if command_dict.get(str(ctx.author.id), {}).get('args', None) is not None:
- args = command_dict.get(str(ctx.author.id), {})['args']
- print(command_dict)
- await ctx.invoke(command_dict.get(str(ctx.author.id), {}).get('command', None), args)
+ if command_dict.get(str(ctx.author.id), {}).get('args', None) is not None:
+ args = command_dict.get(str(ctx.author.id), {})['args']
+ print(command_dict)
+ await ctx.invoke(command_dict.get(str(ctx.author.id), {}).get('command', None), args)
- # [prefix]ping -> Pong!
- @commands.command(aliases=['p'], brief='Pong!', description='Returns latency from bot to Discord servers, not to user')
- @checks.del_ctx()
- async def ping(self, ctx):
- global command_dict
+ # [prefix]ping -> Pong!
+ @commands.command(aliases=['p'], brief='Pong!', description='Returns latency from bot to Discord servers, not to user')
+ @checks.del_ctx()
+ async def ping(self, ctx):
+ global command_dict
- await ctx.message.add_reaction('🏓')
+ await ctx.message.add_reaction('🏓')
- await ctx.send(ctx.author.mention + ' 🏓 `' + str(round(self.bot.latency * 1000)) + 'ms`', delete_after=5)
- command_dict.setdefault(str(ctx.author.id), {}).update({'command': ctx.command})
+ await ctx.send(ctx.author.mention + ' 🏓 `' + str(round(self.bot.latency * 1000)) + 'ms`', delete_after=5)
+ command_dict.setdefault(str(ctx.author.id), {}).update({'command': ctx.command})
- @commands.command(aliases=['pre'], brief='List bot prefixes', description='Shows all used prefixes')
- @checks.del_ctx()
- async def prefix(self, ctx):
- await ctx.send('**Prefix:** `{}`'.format(u.config['prefix']))
- await ctx.message.add_reaction('✅')
+ @commands.command(aliases=['pre'], brief='List bot prefixes', description='Shows all used prefixes')
+ @checks.del_ctx()
+ async def prefix(self, ctx):
+ await ctx.send('**Prefix:** `{}`'.format(u.config['prefix']))
+ await ctx.message.add_reaction('✅')
- @commands.group(name=',send', aliases=[',s'], hidden=True)
- @commands.is_owner()
- @checks.del_ctx()
- async def send(self, ctx):
- pass
+ @commands.group(name=',send', aliases=[',s'], hidden=True)
+ @commands.is_owner()
+ @checks.del_ctx()
+ async def send(self, ctx):
+ pass
- @send.command(name='guild', aliases=['g', 'server', 's'])
- async def send_guild(self, ctx, guild, channel, *, message):
- await discord.utils.get(self.bot.get_all_channels(), guild__name=guild, name=channel).send(message)
- await ctx.message.add_reaction('✅')
+ @send.command(name='guild', aliases=['g', 'server', 's'])
+ async def send_guild(self, ctx, guild, channel, *, message):
+ await discord.utils.get(self.bot.get_all_channels(), guild__name=guild, name=channel).send(message)
+ await ctx.message.add_reaction('✅')
- @send.command(name='user', aliases=['u', 'member', 'm'])
- async def send_user(self, ctx, user, *, message):
- await discord.utils.get(self.bot.get_all_members(), id=int(user)).send(message)
- await ctx.message.add_reaction('✅')
+ @send.command(name='user', aliases=['u', 'member', 'm'])
+ async def send_user(self, ctx, user, *, message):
+ await discord.utils.get(self.bot.get_all_members(), id=int(user)).send(message)
+ await ctx.message.add_reaction('✅')
- @commands.command(aliases=['authenticateupload', 'authupload', 'authup', 'auth'])
- async def authenticate_upload(self, ctx):
- global youtube
- flow = flow_from_clientsecrets('client_secrets.json', scope='https://www.googleapis.com/auth/youtube.upload',
- login_hint='botmyned@gmail.com', redirect_uri='urn:ietf:wg:oauth:2.0:oob')
- flow.params['access_type'] = 'offline'
- webbrowser.open_new_tab(flow.step1_get_authorize_url())
- credentials = flow.step2_exchange(input('Authorization code: '))
- youtube = build('youtube', 'v3', http=credentials.authorize(http.build_http()))
- print('Service built.')
+ @commands.command(aliases=['authenticateupload', 'authupload', 'authup', 'auth'])
+ async def authenticate_upload(self, ctx):
+ global youtube
+ flow = flow_from_clientsecrets('client_secrets.json', scope='https://www.googleapis.com/auth/youtube.upload',
+ login_hint='botmyned@gmail.com', redirect_uri='urn:ietf:wg:oauth:2.0:oob')
+ flow.params['access_type'] = 'offline'
+ webbrowser.open_new_tab(flow.step1_get_authorize_url())
+ credentials = flow.step2_exchange(input('Authorization code: '))
+ youtube = build('youtube', 'v3', http=credentials.authorize(http.build_http()))
+ print('Service built.')
- @commands.command(aliases=['up', 'u', 'vid', 'v'])
- @commands.has_permissions(administrator=True)
- async def upload(self, ctx):
- global youtube
- attachments = ctx.message.attachments
- try:
- if not attachments:
- raise exc.MissingAttachment
- if len(attachments) > 1:
- raise exc.TooManyAttachments(len(attachments))
- mime = mimetypes.guess_type(attachments[0].filename)[0]
- if 'video/' in mime:
- with tempfile.NamedTemporaryFile() as temp:
- await attachments[0].save(temp)
- else:
- raise exc.InvalidVideoFile(mime)
- print('https://www.youtube.com/watch?v=' + youtube.videos().insert(part='snippet',
- body={'categoryId': '24', 'title': 'Test'}, media_body=http.MediaFileUpload(temp.name, chunksize=-1)))
- except exc.InvalidVideoFile as e:
- await ctx.send('`' + str(e) + '` **not valid video type.**', delete_after=10)
- except exc.TooManyAttachments as e:
- await ctx.send('`' + str(e) + '` **too many attachments.** Only one attachment is permitted to upload.', delete_after=10)
- except exc.MissingAttachment:
- await ctx.send('**Missing attachment.**', delete_after=10)
+ @commands.command(aliases=['up', 'u', 'vid', 'v'])
+ @commands.has_permissions(administrator=True)
+ async def upload(self, ctx):
+ global youtube
+ attachments = ctx.message.attachments
+ try:
+ if not attachments:
+ raise exc.MissingAttachment
+ if len(attachments) > 1:
+ raise exc.TooManyAttachments(len(attachments))
+ mime = mimetypes.guess_type(attachments[0].filename)[0]
+ if 'video/' in mime:
+ with tempfile.NamedTemporaryFile() as temp:
+ await attachments[0].save(temp)
+ else:
+ raise exc.InvalidVideoFile(mime)
+ print('https://www.youtube.com/watch?v=' + youtube.videos().insert(part='snippet',
+ body={'categoryId': '24', 'title': 'Test'}, media_body=http.MediaFileUpload(temp.name, chunksize=-1)))
+ except exc.InvalidVideoFile as e:
+ await ctx.send('`' + str(e) + '` **not valid video type.**', delete_after=10)
+ except exc.TooManyAttachments as e:
+ await ctx.send('`' + str(e) + '` **too many attachments.** Only one attachment is permitted to upload.', delete_after=10)
+ except exc.MissingAttachment:
+ await ctx.send('**Missing attachment.**', delete_after=10)
- @upload.error
- async def upload_error(self, ctx, error):
- pass
+ @upload.error
+ async def upload_error(self, ctx, error):
+ pass
# http.
diff --git a/src/main/misc/checks.py b/src/main/misc/checks.py
index 1c080e8..261911f 100644
--- a/src/main/misc/checks.py
+++ b/src/main/misc/checks.py
@@ -14,48 +14,48 @@ owner_id = u.config['owner_id']
def is_owner():
- async def predicate(ctx):
- return ctx.message.author.id == owner_id
- return commands.check(predicate)
+ async def predicate(ctx):
+ return ctx.message.author.id == owner_id
+ return commands.check(predicate)
def is_admin():
- def predicate(ctx):
- return ctx.message.author.guild_permissions.administrator
- return commands.check(predicate)
+ def predicate(ctx):
+ return ctx.message.author.guild_permissions.administrator
+ return commands.check(predicate)
def is_mod():
- def predicate(ctx):
- return ctx.message.author.guild_permissions.ban_members
- return commands.check(predicate)
+ def predicate(ctx):
+ return ctx.message.author.guild_permissions.ban_members
+ return commands.check(predicate)
def owner(ctx):
- return ctx.message.author.id == owner_id
+ return ctx.message.author.id == owner_id
def admin(ctx):
- return ctx.message.author.guild_permissions.administrator
+ return ctx.message.author.guild_permissions.administrator
def mod(ctx):
- return ctx.message.author.guild_permissions.ban_members
+ return ctx.message.author.guild_permissions.ban_members
def is_nsfw():
- def predicate(ctx):
- if isinstance(ctx.message.channel, d.TextChannel):
- return ctx.message.channel.is_nsfw()
- return True
- return commands.check(predicate)
+ def predicate(ctx):
+ if isinstance(ctx.message.channel, d.TextChannel):
+ return ctx.message.channel.is_nsfw()
+ return True
+ return commands.check(predicate)
def del_ctx():
- async def predicate(ctx):
- with suppress(AttributeError):
- if ctx.guild.id in u.settings['del_ctx'] and ctx.me.permissions_in(ctx.channel).manage_messages and isinstance(ctx.message.channel, d.TextChannel):
- with suppress(err.NotFound):
- await ctx.message.delete()
- return True
- return commands.check(predicate)
+ async def predicate(ctx):
+ with suppress(AttributeError):
+ if ctx.guild.id in u.settings['del_ctx'] and ctx.me.permissions_in(ctx.channel).manage_messages and isinstance(ctx.message.channel, d.TextChannel):
+ with suppress(err.NotFound):
+ await ctx.message.delete()
+ return True
+ return commands.check(predicate)
diff --git a/src/main/misc/exceptions.py b/src/main/misc/exceptions.py
index b715226..a782fc4 100644
--- a/src/main/misc/exceptions.py
+++ b/src/main/misc/exceptions.py
@@ -2,104 +2,104 @@ base = '⚠️ **An internal error has occurred.** This has been reported to my
async def send_error(ctx, error):
- await ctx.send('{}\n```\n{}```'.format(base, error))
+ await ctx.send('{}\n```\n{}```'.format(base, error))
class Left(Exception):
- pass
+ pass
class Right(Exception):
- pass
+ pass
class Save(Exception):
- pass
+ pass
class GoTo(Exception):
- pass
+ pass
class Exists(Exception):
- pass
+ pass
class MissingArgument(Exception):
- pass
+ pass
class FavoritesNotFound(Exception):
- pass
+ pass
class PostError(Exception):
- pass
+ pass
class ImageError(Exception):
- pass
+ pass
class MatchError(Exception):
- pass
+ pass
class TagBlacklisted(Exception):
- pass
+ pass
class BoundsError(Exception):
- pass
+ pass
class TagBoundsError(Exception):
- pass
+ pass
class TagExists(Exception):
- pass
+ pass
class TagError(Exception):
- pass
+ pass
class FlagError(Exception):
- pass
+ pass
class BlacklistError(Exception):
- pass
+ pass
class NotFound(Exception):
- pass
+ pass
class Timeout(Exception):
- pass
+ pass
class InvalidVideoFile(Exception):
- pass
+ pass
class MissingAttachment(Exception):
- pass
+ pass
class TooManyAttachments(Exception):
- pass
+ pass
class CheckFail(Exception):
- pass
+ pass
class Abort(Exception):
- pass
+ pass
class Continue(Exception):
- pass
+ pass
diff --git a/src/main/run.py b/src/main/run.py
index 2b14485..c15b144 100644
--- a/src/main/run.py
+++ b/src/main/run.py
@@ -24,88 +24,90 @@ bot = commands.Bot(command_prefix=u.config['prefix'], description='Experimental
# Send and print ready message to #testing and console after logon
@bot.event
async def on_ready():
- from cogs import booru, info, management, owner, tools
+ from cogs import booru, info, management, owner, tools
- bot.add_cog(tools.Utils(bot))
- bot.add_cog(owner.Bot(bot))
- bot.add_cog(owner.Tools(bot))
- bot.add_cog(management.Administration(bot))
- bot.add_cog(info.Info(bot))
- bot.add_cog(booru.MsG(bot))
+ bot.add_cog(tools.Utils(bot))
+ bot.add_cog(owner.Bot(bot))
+ bot.add_cog(owner.Tools(bot))
+ bot.add_cog(management.Administration(bot))
+ bot.add_cog(info.Info(bot))
+ bot.add_cog(booru.MsG(bot))
- # bot.loop.create_task(u.clear(booru.temp_urls, 30*60))
+ # bot.loop.create_task(u.clear(booru.temp_urls, 30*60))
- if u.config['playing'] is not 'None':
- await bot.change_presence(game=d.Game(name=u.config['playing']))
- else:
- await bot.change_presence(game=None)
+ if u.config['playing'] is not 'None':
+ await bot.change_presence(game=d.Game(name=u.config['playing']))
+ else:
+ await bot.change_presence(game=None)
- print('\n\\ \\ \\ \\ \\ \\ \\ \\ \\\nC O N N E C T E D : {}\n/ / / / / / / / /\n'.format(bot.user.name))
- await bot.get_channel(u.config['info_channel']).send('**Started** ☀️ .')
- # u.notify('C O N N E C T E D')
- if u.temp:
- channel = bot.get_channel(u.temp['restart_ch'])
- message = await channel.get_message(u.temp['restart_msg'])
- await message.add_reaction('✅')
- u.temp.clear()
+ print('\n\\ \\ \\ \\ \\ \\ \\ \\ \\\nC O N N E C T E D : {}\n/ / / / / / / / /\n'.format(bot.user.name))
+ await bot.get_channel(u.config['info_channel']).send('**Started** ☀️ .')
+ # u.notify('C O N N E C T E D')
+ if u.temp:
+ channel = bot.get_channel(u.temp['restart_ch'])
+ message = await channel.get_message(u.temp['restart_msg'])
+ await message.add_reaction('✅')
+ u.temp.clear()
@bot.event
async def on_error(error, *args, **kwargs):
- print('\n! ! ! ! !\nE R R O R : {}\n! ! ! ! !\n'.format(error), file=sys.stderr)
- tb.print_exc()
- await bot.get_user(u.config['owner_id']).send('**ERROR** ⚠️ `{}`'.format(error))
- await bot.get_channel(u.config['info_channel']).send('**ERROR** ⚠️ `{}`'.format(error))
- # u.notify('E R R O R')
- await bot.logout()
- u.close(bot.loop)
+ print('\n! ! ! ! !\nE R R O R : {}\n! ! ! ! !\n'.format(error), file=sys.stderr)
+ tb.print_exc()
+ await bot.get_user(u.config['owner_id']).send('**ERROR** ⚠ `{}`'.format(error))
+ await bot.get_channel(u.config['info_channel']).send('**ERROR** ⚠ `{}`'.format(error))
+ # u.notify('E R R O R')
+ await bot.logout()
+ u.close(bot.loop)
@bot.event
async def on_command_error(ctx, error):
- if isinstance(error, errext.CheckFailure):
- await ctx.send('⛔️ **Insufficient permissions.**', delete_after=10)
- await ctx.message.add_reaction('⛔️')
- elif isinstance(error, errext.CommandNotFound):
- print('INVALID COMMAND : {}'.format(error), file=sys.stderr)
- else:
- print('\n! ! ! ! ! ! ! ! ! ! ! !\nC O M M A N D E R R O R : {}\n! ! ! ! ! ! ! ! ! ! ! !\n'.format(
- error), file=sys.stderr)
- tb.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
- await bot.get_user(u.config['owner_id']).send('**COMMAND ERROR** ⚠️ `{}`'.format(error))
- await bot.get_channel(u.config['info_channel']).send('**COMMAND ERROR** ⚠️ `{}`'.format(error))
- await exc.send_error(ctx, error)
- # u.notify('C O M M A N D E R R O R')
+ if isinstance(error, errext.CheckFailure):
+ await ctx.send('⛔️ **Insufficient permissions.**', delete_after=10)
+ await ctx.message.add_reaction('⛔️')
+ elif isinstance(error, errext.CommandNotFound):
+ print('INVALID COMMAND : {}'.format(error), file=sys.stderr)
+ await ctx.message.add_reaction('❌')
+ else:
+ print('\n! ! ! ! ! ! ! ! ! ! ! !\nC O M M A N D E R R O R : {}\n! ! ! ! ! ! ! ! ! ! ! !\n'.format(
+ error), file=sys.stderr)
+ tb.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
+ await bot.get_user(u.config['owner_id']).send('**COMMAND ERROR** ⚠ `{}`'.format(error))
+ await bot.get_channel(u.config['info_channel']).send('**COMMAND ERROR** ⚠ `{}`'.format(error))
+ await exc.send_error(ctx, error)
+ await ctx.message.add_reaction('⚠')
+ # u.notify('C O M M A N D E R R O R')
async def on_reaction_add(r, u):
- pass
+ pass
async def on_reaction_remove(r, u):
- pass
+ pass
async def reaction_add(r, u):
- bot.add_listener(on_reaction_add)
- print('Reacted')
- bot.remove_listener(on_reaction_remove)
+ bot.add_listener(on_reaction_add)
+ print('Reacted')
+ bot.remove_listener(on_reaction_remove)
async def reaction_remove(r, u):
- bot.add_listener(on_reaction_remove)
- print('Removed')
- bot.remove_listener(on_reaction_remove)
+ bot.add_listener(on_reaction_remove)
+ print('Removed')
+ bot.remove_listener(on_reaction_remove)
@bot.command(name=',test', hidden=True)
@commands.is_owner()
@checks.del_ctx()
async def test(ctx):
- test = await ctx.send('Test')
- raise Exception
- # await test.add_reaction('✅')
- # bot.add_listener(on_reaction_add)
- # bot.add_listener(on_reaction_remove)
+ test = await ctx.send('Test')
+ raise Exception
+ # await test.add_reaction('✅')
+ # bot.add_listener(on_reaction_add)
+ # bot.add_listener(on_reaction_remove)
bot.run(u.config['token'])
diff --git a/src/main/utils/formatter.py b/src/main/utils/formatter.py
index 3dc87d4..d2644cf 100644
--- a/src/main/utils/formatter.py
+++ b/src/main/utils/formatter.py
@@ -1,38 +1,38 @@
def tostring(i, *, random=False):
- o = ''
- if i:
- for v in i:
- o += v + ' '
- o = o[:-1]
- elif random is True:
- o += 'order:random'
- else:
- o = ' '
- return o
+ o = ''
+ if i:
+ for v in i:
+ o += v + ' '
+ o = o[:-1]
+ elif random is True:
+ o += 'order:random'
+ else:
+ o = ' '
+ return o
def tostring_commas(i):
- if i:
- o = ','
- for v in i:
- o += v + ','
- return o[:-1]
- return ''
+ if i:
+ o = ','
+ for v in i:
+ o += v + ','
+ return o[:-1]
+ return ''
def dict_tostring(i):
- o = ''
- if i:
- for k, v in i.items():
- o += '**' + k + ':** `' + tostring(v) + '`\n'
- return o
+ o = ''
+ if i:
+ for k, v in i.items():
+ o += '**' + k + ':** `' + tostring(v) + '`\n'
+ return o
def dictelem_tostring(i):
- o = ''
- if i:
- for dic, elem in i.items():
- o += '**__' + dic + '__**\n'
- for k, v in elem.items():
- o += '***' + k + ':*** `' + tostring(v) + '`\n'
- return o
+ o = ''
+ if i:
+ for dic, elem in i.items():
+ o += '**__' + dic + '__**\n'
+ for k, v in elem.items():
+ o += '***' + k + ':*** `' + tostring(v) + '`\n'
+ return o
diff --git a/src/main/utils/scraper.py b/src/main/utils/scraper.py
index 1c4fabc..afdac07 100644
--- a/src/main/utils/scraper.py
+++ b/src/main/utils/scraper.py
@@ -8,26 +8,26 @@ from utils import utils as u
async def get_post(url):
- content = await u.fetch('http://iqdb.harry.lu', params={'url': url})
+ content = await u.fetch('http://iqdb.harry.lu', params={'url': url})
+ try:
+ value = BeautifulSoup(content, 'html.parser').find_all('a')[1].get('href')
+ if value != '#':
+ return value
+ else:
+ raise IndexError
+ except IndexError:
try:
- value = BeautifulSoup(content, 'html.parser').find_all('a')[1].get('href')
- if value != '#':
- return value
- else:
- raise IndexError
- except IndexError:
- try:
- raise exc.MatchError(re.search('\/([^\/]+)$', url).group(1))
+ raise exc.MatchError(re.search('\/([^\/]+)$', url).group(1))
- except AttributeError:
- raise exc.MissingArgument
+ except AttributeError:
+ raise exc.MissingArgument
async def get_image(url):
- content = await u.fetch(url)
+ content = await u.fetch(url)
- value = html.fromstring(content).xpath(
- 'string(/html/body/div[@id="content"]/div[@id="post-view"]/div[@class="content"]/div[2]/img/@src)')
+ value = html.fromstring(content).xpath(
+ 'string(/html/body/div[@id="content"]/div[@id="post-view"]/div[@class="content"]/div[2]/img/@src)')
- return value
+ return value
diff --git a/src/main/utils/utils.py b/src/main/utils/utils.py
index 738003d..00a659b 100644
--- a/src/main/utils/utils.py
+++ b/src/main/utils/utils.py
@@ -18,46 +18,46 @@ print('\nPID : {}\n'.format(os.getpid()))
try:
- with open('config.json') as infile:
- config = jsn.load(infile)
- print('config.json loaded.')
+ with open('config.json') as infile:
+ config = jsn.load(infile)
+ print('config.json loaded.')
except FileNotFoundError:
- with open('config.json', 'w') as outfile:
- jsn.dump({'client_id': 0, 'info_channel': 0, 'owner_id': 0, 'permissions': 126016,
- 'playing': 'a game', 'prefix': ',', 'token': 'str'}, outfile, indent=4, sort_keys=True)
- raise FileNotFoundError(
- 'Config file not found: config.json created with abstract values. Restart run.py with correct values.')
+ with open('config.json', 'w') as outfile:
+ jsn.dump({'client_id': 0, 'info_channel': 0, 'owner_id': 0, 'permissions': 126016,
+ 'playing': 'a game', 'prefix': ',', 'token': 'str'}, outfile, indent=4, sort_keys=True)
+ raise FileNotFoundError(
+ 'Config file not found: config.json created with abstract values. Restart run.py with correct values.')
def setdefault(filename, default=None):
- try:
- with open(filename, 'rb') as infile:
- print('{} loaded.'.format(filename))
- return pkl.load(infile)
- except FileNotFoundError:
- with open(filename, 'wb+') as iofile:
- print('File not found: {} created and loaded with default values.'.format(filename))
- pkl.dump(default, iofile)
- iofile.seek(0)
- return pkl.load(iofile)
+ try:
+ with open(filename, 'rb') as infile:
+ print('{} loaded.'.format(filename))
+ return pkl.load(infile)
+ except FileNotFoundError:
+ with open(filename, 'wb+') as iofile:
+ print('File not found: {} created and loaded with default values.'.format(filename))
+ pkl.dump(default, iofile)
+ iofile.seek(0)
+ return pkl.load(iofile)
def load(filename, *, json=False):
- if not json:
- with open(filename, 'rb') as infile:
- return pkl.load(infile)
- else:
- with open(filename) as infile:
- return jsn.load(infile)
+ if not json:
+ with open(filename, 'rb') as infile:
+ return pkl.load(infile)
+ else:
+ with open(filename) as infile:
+ return jsn.load(infile)
def dump(obj, filename, *, json=False):
- if not json:
- with open(filename, 'wb') as outfile:
- pkl.dump(obj, outfile)
- else:
- with open(filename, 'w') as outfile:
- jsn.dump(obj, outfile, indent=4, sort_keys=True)
+ if not json:
+ with open(filename, 'wb') as outfile:
+ pkl.dump(obj, outfile)
+ else:
+ with open(filename, 'w') as outfile:
+ jsn.dump(obj, outfile, indent=4, sort_keys=True)
settings = setdefault('settings.pkl', {'del_ctx': []})
@@ -85,78 +85,82 @@ session = aiohttp.ClientSession()
def close(loop):
- global session
+ global session
- if session:
- session.close()
+ if session:
+ session.close()
- loop.stop()
- pending = asyncio.Task.all_tasks()
- for task in pending:
- task.cancel()
- # with suppress(asyncio.CancelledError):
- # loop.run_until_complete(task)
- # loop.close()
+ loop.stop()
+ pending = asyncio.Task.all_tasks()
+ for task in pending:
+ task.cancel()
+ # with suppress(asyncio.CancelledError):
+ # loop.run_until_complete(task)
+ # loop.close()
- print('Finished cancelling tasks.')
+ print('Finished cancelling tasks.')
async def fetch(url, *, params={}, json=False):
- global session
+ global session
- async with session.get(url, params=params, headers={'user-agent': 'Modumind/0.0.1 (Myned)'}) as r:
- if json:
- return await r.json()
- return await r.read()
+ async with session.get(url, params=params, headers={'user-agent': 'Modumind/0.0.1 (Myned)'}) as r:
+ if json:
+ return await r.json()
+ return await r.read()
# def geneate_embed(**kwargs):
# embed = d.Embed(title=kwargs['title'], )
def get_args(ctx, args, *, rem=False, rm=False, lim=False):
- destination = ctx
- remaining = list(args[:])
- remove = False
- limit = 1
+ destination = ctx
+ remaining = list(args[:])
+ remove = False
+ limit = lim
- if '-d' in remaining or '-dm' in remaining:
- destination = ctx.author
+ if '-d' in remaining or '-dm' in remaining:
+ destination = ctx.author
+ try:
+ remaining.remove('-d')
+ except ValueError:
+ remaining.remove('-dm')
+
+ if rm:
+ if ('-r' in remaining or '-rm' in remaining or '-remove' in remaining) and ctx.author.permissions_in(ctx.channel).manage_messages:
+ remove = True
+ print('remove')
+
+ try:
+ remaining.remove('-r')
+ except ValueError:
try:
- remaining.remove('-d')
+ remaining.remove('-rm')
except ValueError:
- remaining.remove('-dm')
+ remaining.remove('-remove')
+ if lim:
+ for arg in remaining:
+ if 1 <= len(arg) <= 2:
+ with suppress(ValueError):
+ if 1 <= int(arg) <= lim:
+ limit = int(arg)
+ remaining.remove(arg)
+ break
+ else:
+ raise exc.BoundsError(arg)
+
+ if rem:
+ if rm and lim:
+ return destination, remaining, remove, limit
if rm:
- if ('-r' in remaining or '-rm' in remaining or '-remove' in remaining) and ctx.author.permissions_in(ctx.channel).manage_messages:
- remove = True
- print('remove')
-
- try:
- remaining.remove('-r')
- except ValueError:
- try:
- remaining.remove('-rm')
- except ValueError:
- remaining.remove('-remove')
-
+ return destination, remaining, remove
if lim:
- for arg in remaining:
- if len(arg) == 1:
- with suppress(ValueError):
- if int(arg) <= 3 and int(arg) >= 1:
- limit = int(arg)
- remaining.remove(arg)
- break
- else:
- raise exc.BoundsError(arg)
-
- if rem:
- if rm and lim:
- return destination, remaining, remove, limit
- if rm:
- return destination, remaining, remove
- if lim:
- return destination, remaining, limit
- return destination, remaining
- return destination
+ return destination, remaining, limit
+ return destination, remaining
+ if rm:
+ return destination, remove
+ if lim:
+ return destination, limit
+ return destination