1
0
Fork 0
mirror of https://github.com/myned/modufur.git synced 2024-11-01 21:02:38 +00:00

Merge branch 'dev'

This commit is contained in:
Myned 2017-10-11 03:12:54 -04:00
commit 046a897458
9 changed files with 838 additions and 302 deletions

View file

@ -1,48 +1,44 @@
import json import json
try: try:
with open('global_blacklist.json') as infile: with open('blacklists.json') as infile:
global_blacklist = json.load(infile) blacklists = json.load(infile)
print('\"global_blacklist.json\" loaded.') print('\"blacklists.json\" loaded.')
except FileNotFoundError: except FileNotFoundError:
with open('global_blacklist.json', 'w+') as iofile: with open('blacklists.json', 'w+') as iofile:
print('Blacklist file not found: \"global_blacklist.json\" created.') print('Blacklists file not found: \"blacklists.json\" created and loaded.')
json.dump([], iofile, indent=4, sort_keys=True) json.dump({'global_blacklist': [], 'guild_blacklist': {}, 'user_blacklist': {}}, iofile, indent=4, sort_keys=True)
iofile.seek(0) iofile.seek(0)
global_blacklist = json.load(iofile) blacklists = json.load(iofile)
try: try:
with open('guild_blacklist.json') as infile: with open('aliases.json') as infile:
guild_blacklist = json.load(infile) aliases = json.load(infile)
print('\"guild_blacklist.json\" loaded.') print('\"aliases.json\" loaded.')
except FileNotFoundError: except FileNotFoundError:
with open('guild_blacklist.json', 'w+') as iofile: with open('aliases.json', 'w+') as iofile:
print('Blacklist file not found: \"guild_blacklist.json\" created.') print('Aliases file not found: \"aliases.json\" created and loaded.')
json.dump({}, iofile, indent=4, sort_keys=True) json.dump({'global_blacklist': {}, 'guild_blacklist': {}, 'user_blacklist': {}}, iofile, indent=4, sort_keys=True)
iofile.seek(0) iofile.seek(0)
guild_blacklist = json.load(iofile) aliases = json.load(iofile)
try:
with open('user_blacklist.json') as infile:
user_blacklist = json.load(infile)
print('\"user_blacklist.json\" loaded.')
except FileNotFoundError:
with open('user_blacklist.json', 'w+') as iofile:
print('Blacklist file not found: \"user_blacklist.json\" created.')
json.dump({}, iofile, indent=4, sort_keys=True)
iofile.seek(0)
user_blacklist = json.load(iofile)
import asyncio import asyncio
import discord import discord as d
import requests import requests
import traceback import traceback as tb
import discord as d
from discord import reaction from discord import reaction
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import errors from discord.ext.commands import errors as errext
from discord import errors as err
from cogs import tools
from misc import checks from misc import checks
from misc import exceptions as exc from misc import exceptions as exc
from utils import formatter, scraper from utils import formatter, scraper
from utils import utils as u
last_command = {} HEADERS = {'user-agent': 'Modumind/0.0.1 (Myned)'}
# temp_urls = {}
class MsG: class MsG:
@ -69,8 +65,23 @@ class MsG:
except exc.ImageError: except exc.ImageError:
await ctx.send('' + ctx.message.author.mention + ' **No image found.**') await ctx.send('' + ctx.message.author.mention + ' **No image found.**')
except Exception: except Exception:
await ctx.send(exc.base) await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
traceback.print_exc(limit=1) tb.print_exc()
# Tag aliases
@commands.command(aliases=['alias', 'a'], brief='e621 Tag aliases', description='e621 | NSFW\nSearch aliases for given tag')
@checks.del_ctx()
async def aliases(self, ctx, tag):
global HEADERS
aliases = []
try:
alias_request = requests.get('https://e621.net/tag_alias/index.json?aliased_to=' + tag + '&approved=true', headers=HEADERS).json()
for dic in alias_request:
aliases.append(dic['name'])
await ctx.send('✅ `' + tag + '` **aliases:**\n```' + formatter.tostring(aliases) + '```')
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc()
# Reverse image searches a linked image using the public iqdb # 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') @commands.command(name='reverse', aliases=['rev', 'ris'], brief='e621 Reverse image search', description='e621 | NSFW\nReverse-search an image with given URL')
@ -78,106 +89,201 @@ class MsG:
async def reverse_image_search(self, ctx, url): async def reverse_image_search(self, ctx, url):
try: try:
await ctx.trigger_typing() await ctx.trigger_typing()
await ctx.send('' + ctx.message.author.mention + ' **Probable match:**\n' + scraper.check_match('http://iqdb.harry.lu/?url=' + url)) await ctx.send('' + ctx.message.author.mention + ' **Probable match:**\n' + scraper.check_match('http://iqdb.harry.lu/?url={}'.format(url)))
except exc.MatchError: except exc.MatchError:
await ctx.send('' + ctx.message.author.mention + ' **No probable match.**') await ctx.send('' + ctx.message.author.mention + ' **No probable match.**', delete_after=10)
except Exception: except Exception:
await ctx.send(exc.base) await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
traceback.print_exc(limit=1) tb.print_exc()
@commands.command(name='e621p', aliases=['e6p', '6p'])
@checks.del_ctx()
@checks.is_nsfw()
async def e621_paginator(self, ctx, *args):
def react(reaction, user):
if reaction.emoji == '' and reaction.message.content == paginator.content and user is ctx.message.author: raise exc.Left
elif reaction.emoji == '🚫' and reaction.message.content == paginator.content and user is ctx.message.author: raise exc.Abort
elif reaction.emoji == '📁' and reaction.message.content == paginator.content and user is ctx.message.author: raise exc.Save
elif reaction.emoji == '' and reaction.message.content == paginator.content and user is ctx.message.author: raise exc.Right
else: return False
user = ctx.message.author
args = list(args)
limit = 100
try:
await ctx.trigger_typing()
c = 1
posts = self.check_return_posts(ctx=ctx, booru='e621', tags=args, limit=limit)
starred = []
embed = d.Embed(title='/post/{}'.format(list(posts.keys())[c-1]), url='https://e621.net/post/show/{}'.format(list(posts.keys())[c-1]), color=ctx.me.color).set_image(url=list(posts.values())[c-1])
embed.set_author(name=formatter.tostring(args, random=True), url='https://e621.net/post?tags={}'.format(','.join(args)), icon_url=user.avatar_url)
embed.set_footer(text='e621', icon_url='http://ndl.mgccw.com/mu3/app/20141013/18/1413204353554/icon/icon_xl.png')
paginator = await ctx.send(embed=embed)
await paginator.add_reaction('')
await paginator.add_reaction('🚫')
await paginator.add_reaction('📁')
await paginator.add_reaction('')
await asyncio.sleep(1)
while True:
try:
await self.bot.wait_for('reaction_add', check=react, timeout=5*60)
except exc.Left:
if c > 1:
c -= 1
embed.title = '/post/{}'.format(list(posts.keys())[c-1])
embed.url = 'https://e621.net/post/show/{}'.format(list(posts.keys())[c-1])
embed.set_image(url=list(posts.values())[c-1])
await paginator.edit(embed=embed)
except exc.Save:
if list(posts.values())[c-1] not in starred:
starred.append(list(posts.values())[c-1])
except exc.Right:
if c % limit == 0:
await ctx.trigger_typing()
try: posts.update(self.check_return_posts(ctx=ctx, booru='e621', tags=args, limit=limit, previous=posts))
except exc.NotFound:
await paginator.edit(content='❌ **No more images found.**')
c += 1
embed.title = '/post/{}'.format(list(posts.keys())[c-1])
embed.url = 'https://e621.net/post/show/{}'.format(list(posts.keys())[c-1])
embed.set_image(url=list(posts.values())[c-1])
await paginator.edit(embed=embed)
except exc.Abort: await paginator.edit(content='🚫 **Exited paginator.**')
except exc.TagBlacklisted as e: await ctx.send('❌ `{}` **blacklisted.**'.format(e), delete_after=10)
except exc.TagBoundsError as e: await ctx.send('❌ `{}` **out of bounds.** Tags limited to 5, currently.'.format(e), delete_after=10)
except exc.Timeout: await ctx.send('❌ **Request timed out.**')
except asyncio.TimeoutError: await paginator.edit(content='❌ **Paginator timed out.**')
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc()
finally:
if starred:
for url in starred: await user.send(url)
@e621_paginator.error
async def e621_paginator_error(self, ctx, error):
if isinstance(error, errext.CheckFailure):
return await ctx.send('❌ <#' + str(ctx.message.channel.id) + '> **is not an NSFW channel.**', delete_after=10)
# Searches for and returns images from e621.net given tags when not blacklisted # Searches for and returns images from e621.net given tags when not blacklisted
@commands.command(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])') @commands.command(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.del_ctx()
@checks.is_nsfw() @checks.is_nsfw()
async def e621(self, ctx, *args): async def e621(self, ctx, *args):
global global_blacklist, guild_blacklist, user_blacklist # global temp_urls
args = list(args) args = list(args)
limit = 1
try: try:
await ctx.trigger_typing() await ctx.trigger_typing()
await self.check_send_urls(ctx, 'e621', args) # Checks for, defines, and removes limit from args
except exc.TagBlacklisted as e: for arg in args:
await ctx.send('❌ `' + str(e) + '` **blacklisted.**', delete_after=10) if len(arg) == 1:
except exc.BoundsError as e: if int(arg) <= 6 and int(arg) >= 1:
await ctx.send('❌ `' + str(e) + '` **out of bounds.**', delete_after=10) limit = int(arg)
except exc.TagBoundsError as e: args.remove(arg)
await ctx.send('❌ `' + str(e) + '` **out of bounds.** Tags limited to 5, currently.', delete_after=10) else: raise exc.BoundsError(arg)
posts = self.check_return_posts(ctx=ctx, booru='e621', tags=args, limit=limit)#, previous=temp_urls.get(ctx.message.author.id, []))
for ident, url in posts.items():
embed = d.Embed(title='/post/{}'.format(ident), url='https://e621.net/post/show/{}'.format(ident), color=ctx.me.color).set_image(url=url)
embed.set_author(name=formatter.tostring(args, random=True), url='https://e621.net/post?tags={}'.format(','.join(args)), icon_url=ctx.message.author.avatar_url)
embed.set_footer(text='e621', icon_url='http://ndl.mgccw.com/mu3/app/20141013/18/1413204353554/icon/icon_xl.png')
await ctx.send(embed=embed)
# temp_urls.setdefault(ctx.message.author.id, []).extend(posts.values())
except exc.TagBlacklisted as e: await ctx.send('❌ `' + str(e) + '` **blacklisted.**', delete_after=10)
except exc.BoundsError as e: await ctx.send('❌ `' + str(e) + '` **out of bounds.**', delete_after=10)
except exc.TagBoundsError as e: await ctx.send('❌ `' + str(e) + '` **out of bounds.** Tags limited to 5, currently.', delete_after=10)
except exc.NotFound as e: await ctx.send('❌ `' + str(e) + '` **not found.**', delete_after=10)
except exc.Timeout: await ctx.send('❌ **Request timed out.**')
except Exception: except Exception:
await ctx.send(exc.base) await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
traceback.print_exc() tb.print_exc()
tools.command_dict.setdefault(str(ctx.message.author.id), {}).update({'command': ctx.command, 'args': ctx.args})
@e621.error @e621.error
async def e621_error(self, ctx, error): async def e621_error(self, ctx, error):
if isinstance(error, errors.CheckFailure): if isinstance(error, errext.CheckFailure):
return await ctx.send('❌ <#' + str(ctx.message.channel.id) + '> **is not an NSFW channel.**', delete_after=10) return await ctx.send('❌ <#' + str(ctx.message.channel.id) + '> **is not an NSFW channel.**', delete_after=10)
# Searches for and returns images from e926.net given tags when not blacklisted # 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])') @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() @checks.del_ctx()
async def e926(self, ctx, *args): async def e926(self, ctx, *args):
global global_blacklist, guild_blacklist, user_blacklist # global temp_urls
args = list(args) args = list(args)
limit = 1
try: try:
await ctx.trigger_typing() await ctx.trigger_typing()
await self.check_send_urls(ctx, 'e926', args) # Checks for, defines, and removes limit from args
except exc.TagBlacklisted as e: for arg in args:
await ctx.send('❌ `' + str(e) + '` **blacklisted.**', delete_after=10) if len(arg) == 1:
except exc.BoundsError as e: if int(arg) <= 6 and int(arg) >= 1:
await ctx.send('❌ `' + str(e) + '` **out of bounds.**', delete_after=10) limit = int(arg)
except exc.TagBoundsError as e: args.remove(arg)
await ctx.send('❌ `' + str(e) + '` **out of bounds.** Tags limited to 5, currently.', delete_after=10) else: raise exc.BoundsError(arg)
posts = self.check_return_posts(ctx=ctx, booru='e926', tags=args, limit=limit)#, previous=temp_urls.get(ctx.message.author.id, []))
for ident, url in posts.items():
embed = d.Embed(title='/post/{}'.format(ident), url='https://e926.net/post/show/{}'.format(ident), color=ctx.me.color).set_image(url=url)
embed.set_author(name=formatter.tostring(args, random=True), url='https://e621.net/post?tags={}'.format(','.join(args)), icon_url=ctx.message.author.avatar_url)
embed.set_footer(text='e926', icon_url='http://ndl.mgccw.com/mu3/app/20141013/18/1413204353554/icon/icon_xl.png')
await ctx.send(embed=embed)
# temp_urls.setdefault(ctx.message.author.id, []).extend(posts.values())
except exc.TagBlacklisted as e: await ctx.send('❌ `' + str(e) + '` **blacklisted.**', delete_after=10)
except exc.BoundsError as e: await ctx.send('❌ `' + str(e) + '` **out of bounds.**', delete_after=10)
except exc.TagBoundsError as e: await ctx.send('❌ `' + str(e) + '` **out of bounds.** Tags limited to 5, currently.', delete_after=10)
except exc.NotFound as e: await ctx.send('❌ `' + str(e) + '` **not found.**', delete_after=10)
except exc.Timeout: await ctx.send('❌ **Request timed out.**')
except Exception: except Exception:
await ctx.send(exc.base) await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
traceback.print_exc(limit=1) tb.print_exc()
# Messy code that checks image limit and tags in blacklists # Messy code that checks image limit and tags in blacklists
async def check_send_urls(self, ctx, booru, args): def check_return_posts(self, *, ctx, booru='e621', tags=[], limit=1, previous=[]):
global global_blacklist, guild_blacklist, user_blacklist global blacklists, aliases, HEADERS
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild if isinstance(ctx.message.guild, d.Guild): guild = ctx.message.guild
else: else: guild = ctx.message.channel
guild = ctx.message.channel
channel = ctx.message.channel channel = ctx.message.channel
user = ctx.message.author user = ctx.message.author
urls = [] blacklist = []
limit = 1
# Checks if tags are in the file blacklists # Creates temp blacklist based on context
if args: for k, v in aliases['global_blacklist'].items(): blacklist.extend([k] + v)
for tag in args: for k, v in aliases['guild_blacklist'].get(str(guild.id), {}).get(str(channel.id), {}).items(): blacklist.extend([k] + v)
if tag == 'swf' or tag == 'webm' or tag in global_blacklist or tag in guild_blacklist.get(str(guild.id), {}).get(str(channel.id), []) or tag in user_blacklist.get(str(user.id), []): for k, v in aliases['user_blacklist'].get(str(user.id), {}).items(): blacklist.extend([k] + v)
raise exc.TagBlacklisted(tag) # Checks if tags are in local blacklists
if len(args) > 5: if tags:
raise exc.TagBoundsError(formatter.tostring(args[5:])) if len(tags) > 5: raise exc.TagBoundsError(formatter.tostring(tags[5:]))
# Checks for, defines, and removes limit from end of args for tag in tags:
if args and len(args[-1]) == 1: if tag == 'swf' or tag == 'webm' or tag in blacklist: raise exc.TagBlacklisted(tag)
if int(args[-1]) <= 6 and int(args[-1]) >= 1:
limit = int(args[-1])
args.pop()
else:
raise exc.BoundsError(args[-1])
# Checks for blacklisted tags in endpoint blacklists - try/except is for continuing the parent loop # Checks for blacklisted tags in endpoint blacklists - try/except is for continuing the parent loop
while len(urls) < limit: posts = {}
request = requests.get('https://' + booru + '.net/post/index.json?limit=6&tags=order:random' + formatter.tostring_commas(args)).json() c = 0
while len(posts) < limit:
if c == 50 + limit: raise exc.Timeout
request = requests.get('https://{}.net/post/index.json?tags={}'.format(booru, ','.join(['order:random'] + tags)), headers=HEADERS).json()
if len(request) == 0: raise exc.NotFound(formatter.tostring(tags))
if len(request) < limit: limit = len(request)
for post in request: for post in request:
if 'swf' in post['file_ext'] or 'webm' in post['file_ext']: if 'swf' in post['file_ext'] or 'webm' in post['file_ext']: continue
continue
try: try:
for tag in global_blacklist: for tag in blacklist:
if tag in post['tags']: if tag in post['tags']: raise exc.Continue
raise exc.Continue except exc.Continue: continue
for tag in guild_blacklist.get(str(guild.id), {}).get(str(channel.id), []): if post['file_url'] not in posts.values() and post['file_url'] not in previous: posts[post['id']] = post['file_url']
if tag in post['tags']: if len(posts) == limit: break
raise exc.Continue c += 1
for tag in user_blacklist.get(str(user.id), []): return posts
if tag in post['tags']:
raise exc.Continue
except exc.Continue:
continue
if post['file_url'] not in urls:
urls.append(post['file_url'])
if len(urls) == limit:
break
for url in urls:
await ctx.send('`' + formatter.tostring(args) + '`\n' + url)
# Umbrella command structure to manage global, channel, and user blacklists # 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])') @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])')
@ -185,238 +291,254 @@ class MsG:
async def blacklist(self, ctx): async def blacklist(self, ctx):
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send('❌ **Use a flag to manage blacklists.**\n*Type* `' + ctx.prefix + 'help bl` *for more info.*', delete_after=10) await ctx.send('❌ **Use a flag to manage blacklists.**\n*Type* `' + ctx.prefix + 'help bl` *for more info.*', delete_after=10)
@blacklist.error @blacklist.error
async def blacklist_error(self, ctx, error): async def blacklist_error(self, ctx, error):
if isinstance(error, commands.CheckFailure): if isinstance(error, commands.CheckFailure):
return await ctx.send('❌ **Insufficient permissions.**', delete_after=10) return await ctx.send('❌ **Insufficient permissions.**')
if isinstance(error, exc.TagExists):
return await ctx.send('❌ `' + str(exc.TagExists) + '` **already in blacklist.**', delete_after=10)
if isinstance(error, exc.TagError):
return await ctx.send('❌ `' + str(exc.TagError) + '` **not in blacklist.**', delete_after=10)
if isinstance(error, KeyError): if isinstance(error, KeyError):
return await ctx.send('❌ **Blacklist does not exist.**', delete_after=10) return await ctx.send('❌ **Blacklist does not exist.**', delete_after=10)
@blacklist.command(name='update', aliases=['upd', 'up'])
async def _update_blacklists(self, ctx):
global global_blacklist, guild_blacklist, user_blacklist
with open('global_blacklist.json', 'w') as outfile:
json.dump(global_blacklist, outfile, indent=4, sort_keys=True)
with open('guild_blacklist.json', 'w') as outfile:
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True)
with open('user_blacklist.json', 'w') as outfile:
json.dump(user_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Blacklists updated.**')
@blacklist.group(name='get', aliases=['g']) @blacklist.group(name='get', aliases=['g'])
async def _get_blacklist(self, ctx): async def _get_blacklist(self, ctx):
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**') await ctx.send('❌ **Invalid blacklist.**')
@_get_blacklist.command(name='global', aliases=['gl', 'g']) @_get_blacklist.command(name='global', aliases=['gl', 'g'])
async def __get_global_blacklist(self, ctx): async def __get_global_blacklist(self, ctx):
global global_blacklist global blacklists
await ctx.send('🚫 **Global blacklist:**\n```' + formatter.tostring(global_blacklist) + '```') await ctx.send('🚫 **Global blacklist:**\n```' + formatter.tostring(blacklists['global_blacklist']) + '```')
@_get_blacklist.command(name='channel', aliases=['ch', 'c']) @_get_blacklist.command(name='channel', aliases=['ch', 'c'])
async def __get_channel_blacklist(self, ctx): async def __get_channel_blacklist(self, ctx):
global guild_blacklist global blacklists
if isinstance(ctx.message.guild, discord.Guild): if isinstance(ctx.message.guild, d.Guild):
guild = ctx.message.guild guild = ctx.message.guild
else: else:
guild = ctx.message.channel guild = ctx.message.channel
channel = ctx.message.channel channel = ctx.message.channel
await ctx.send('🚫 <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(guild_blacklist.get(str(guild.id), {}).get(str(channel.id), [])) + '```') await ctx.send('🚫 <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(blacklists['guild_blacklist'].get(str(guild.id), {}).get(str(channel.id), [])) + '```')
@_get_blacklist.command(name='me', aliases=['m']) @_get_blacklist.command(name='me', aliases=['m'])
async def __get_user_blacklist(self, ctx): async def __get_user_blacklist(self, ctx):
global user_blacklist global blacklists
user = ctx.message.author user = ctx.message.author
await ctx.send('🚫 ' + user.mention + '**\'s blacklist:**\n```' + formatter.tostring(user_blacklist.get(str(user.id), [])) + '```', delete_after=10) await ctx.send('🚫 ' + user.mention + '**\'s blacklist:**\n```' + formatter.tostring(blacklists['user_blacklist'].get(str(user.id), [])) + '```', delete_after=10)
@_get_blacklist.command(name='here', aliases=['h']) @_get_blacklist.command(name='here', aliases=['h'])
async def __get_here_blacklists(self, ctx): async def __get_here_blacklists(self, ctx):
global global_blacklist, guild_blacklist global blacklists
if isinstance(ctx.message.guild, discord.Guild): if isinstance(ctx.message.guild, d.Guild):
guild = ctx.message.guild guild = ctx.message.guild
else: else:
guild = ctx.message.channel guild = ctx.message.channel
channel = ctx.message.channel channel = ctx.message.channel
await ctx.send('🚫 **__Blacklisted:__**\n\n**Global:**\n```' + formatter.tostring(global_blacklist) + '```\n**<#' + str(channel.id) + '>:**\n```' + formatter.tostring(guild_blacklist.get(str(guild.id), {}).get(str(channel.id), [])) + '```') await ctx.send('🚫 **__Blacklisted:__**\n\n**Global:**\n```' + formatter.tostring(blacklists['global_blacklist']) + '```\n**<#' + str(channel.id) + '>:**\n```' + formatter.tostring(blacklists['guild_blacklist'].get(str(guild.id), {}).get(str(channel.id), [])) + '```')
@_get_blacklist.group(name='all', aliases=['a']) @_get_blacklist.group(name='all', aliases=['a'])
async def __get_all_blacklists(self, ctx): async def __get_all_blacklists(self, ctx):
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**') await ctx.send('❌ **Invalid blacklist.**')
@__get_all_blacklists.command(name='guild', aliases=['g']) @__get_all_blacklists.command(name='guild', aliases=['g'])
@commands.has_permissions(manage_channels=True) @commands.has_permissions(manage_channels=True)
async def ___get_all_guild_blacklists(self, ctx): async def ___get_all_guild_blacklists(self, ctx):
global guild_blacklist global blacklists
if isinstance(ctx.message.guild, discord.Guild): if isinstance(ctx.message.guild, d.Guild):
guild = ctx.message.guild guild = ctx.message.guild
else: else:
guild = ctx.message.channel guild = ctx.message.channel
await ctx.send('🚫 **__' + guild.name + ' blacklists:__**\n\n' + formatter.dict_tostring(guild_blacklist.get(str(guild.id), {}))) await ctx.send('🚫 **__' + guild.name + ' blacklists:__**\n\n' + formatter.dict_tostring(blacklists['guild_blacklist'].get(str(guild.id), {})))
@__get_all_blacklists.command(name='user', aliases=['u', 'member', 'm']) @__get_all_blacklists.command(name='user', aliases=['u', 'member', 'm'])
@commands.is_owner() @commands.is_owner()
async def ___get_all_user_blacklists(self, ctx): async def ___get_all_user_blacklists(self, ctx):
global user_blacklist global blacklists
await ctx.send('🚫 **__User blacklists:__**\n\n' + formatter.dict_tostring(user_blacklist)) await ctx.send('🚫 **__User blacklists:__**\n\n' + formatter.dict_tostring(blacklists['user_blacklist']))
@blacklist.group(name='add', aliases=['a']) @blacklist.group(name='add', aliases=['a'])
async def _add_tags(self, ctx): async def _add_tags(self, ctx):
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**') await ctx.send('❌ **Invalid blacklist.**')
@_add_tags.command(name='global', aliases=['gl', 'g']) @_add_tags.command(name='global', aliases=['gl', 'g'])
@commands.is_owner() @commands.is_owner()
async def __add_global_tags(self, ctx, *tags): async def __add_global_tags(self, ctx, *tags):
global global_blacklist global blacklists, aliases, HEADERS
for tag in tags: try:
if tag in global_blacklist: for tag in tags:
raise exc.TagExists(tag) if tag in blacklists['global_blacklist']:
global_blacklist.extend(tags) raise exc.TagExists(tag)
with open('global_blacklist.json', 'w') as outfile: blacklists['global_blacklist'].extend(tags)
json.dump(global_blacklist, outfile, indent=4, sort_keys=True) for tag in tags:
await ctx.send('✅ **Added to global blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5) alias_request = requests.get('https://e621.net/tag_alias/index.json?aliased_to=' + tag + '&approved=true', headers=HEADERS).json()
for dic in alias_request:
aliases['global_blacklist'].setdefault(tag, []).append(dic['name'])
with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
with open('aliases.json', 'w') as outfile:
json.dump(aliases, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Added to global blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
except exc.TagExists as e:
await ctx.send('❌ `' + str(e) + '` **already in blacklist.**', delete_after=10)
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc()
@_add_tags.command(name='channel', aliases=['ch', 'c']) @_add_tags.command(name='channel', aliases=['ch', 'c'])
@commands.has_permissions(manage_channels=True) @commands.has_permissions(manage_channels=True)
async def __add_channel_tags(self, ctx, *tags): async def __add_channel_tags(self, ctx, *tags):
global guild_blacklist global blacklists, aliases, HEADERS
if isinstance(ctx.message.guild, discord.Guild): if isinstance(ctx.message.guild, d.Guild):
guild = ctx.message.guild guild = ctx.message.guild
else: else:
guild = ctx.message.channel guild = ctx.message.channel
channel = ctx.message.channel channel = ctx.message.channel
for tag in tags: try:
if tag in guild_blacklist.get(str(guild.id), {}).get(str(channel.id), []): for tag in tags:
raise exc.TagExists(tag) if tag in blacklists['guild_blacklist'].get(str(guild.id), {}).get(str(channel.id), []):
guild_blacklist.setdefault(str(guild.id), {}).setdefault(str(channel.id), []).extend(tags) raise exc.TagExists(tag)
with open('guild_blacklist.json', 'w') as outfile: blacklists['guild_blacklist'].setdefault(str(guild.id), {}).setdefault(str(channel.id), []).extend(tags)
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True) for tag in tags:
await ctx.send('✅ **Added to** <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5) alias_request = requests.get('https://e621.net/tag_alias/index.json?aliased_to=' + tag + '&approved=true', headers=HEADERS).json()
for dic in alias_request:
aliases['guild_blacklist'].setdefault(str(guild.id), {}).setdefault(str(channel.id), {}).setdefault(tag, []).append(dic['name'])
with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
with open('aliases.json', 'w') as outfile:
json.dump(aliases, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Added to** <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
except exc.TagExists as e:
await ctx.send('❌ `' + str(e) + '` **already in blacklist.**', delete_after=10)
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc()
@_add_tags.command(name='me', aliases=['m']) @_add_tags.command(name='me', aliases=['m'])
async def __add_user_tags(self, ctx, *tags): async def __add_user_tags(self, ctx, *tags):
global user_blacklist global blacklists, aliases, HEADERS
user = ctx.message.author user = ctx.message.author
for tag in tags: try:
if tag in user_blacklist.get(str(user.id), []): for tag in tags:
raise exc.TagExists(tag) if tag in blacklists['user_blacklist'].get(str(user.id), []):
user_blacklist.setdefault(str(user.id), []).extend(tags) raise exc.TagExists(tag)
with open('user_blacklist.json', 'w') as outfile: blacklists['user_blacklist'].setdefault(str(user.id), []).extend(tags)
json.dump(user_blacklist, outfile, indent=4, sort_keys=True) for tag in tags:
await ctx.send('' + user.mention + ' **added:**\n```' + formatter.tostring(tags) + '```', delete_after=5) alias_request = requests.get('https://e621.net/tag_alias/index.json?aliased_to=' + tag + '&approved=true', headers=HEADERS).json()
for dic in alias_request:
aliases['user_blacklist'].setdefault(str(user.id), {}).setdefault(tag, []).append(dic['name'])
with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
with open('aliases.json', 'w') as outfile:
json.dump(aliases, outfile, indent=4, sort_keys=True)
await ctx.send('' + user.mention + ' **added:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
except exc.TagExists as e:
await ctx.send('❌ `' + str(e) + '` **already in blacklist.**', delete_after=10)
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc()
@blacklist.group(name='remove', aliases=['rm', 'r']) @blacklist.group(name='remove', aliases=['rm', 'r'])
async def _remove_tags(self, ctx): async def _remove_tags(self, ctx):
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**') await ctx.send('❌ **Invalid blacklist.**')
@_remove_tags.command(name='global', aliases=['gl', 'g']) @_remove_tags.command(name='global', aliases=['gl', 'g'])
@commands.is_owner() @commands.is_owner()
async def __remove_global_tags(self, ctx, *tags): async def __remove_global_tags(self, ctx, *tags):
global global_blacklist global blacklists, aliases
for tag in tags: try:
if tag in global_blacklist: for tag in tags:
global_blacklist.remove(tag) if tag in blacklists['global_blacklist']:
else: blacklists['global_blacklist'].remove(tag)
raise exc.TagError(tag) del aliases['global_blacklist'][tag]
with open('global_blacklist.json', 'w') as outfile: else:
json.dump(global_blacklist, outfile, indent=4, sort_keys=True) raise exc.TagError(tag)
await ctx.send('✅ **Removed from global blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5) with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
with open('aliases.json', 'w') as outfile:
json.dump(aliases, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Removed from global blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
except exc.TagError as e:
await ctx.send('❌ `' + str(e) + '` **not in blacklist.**', delete_after=10)
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc()
@_remove_tags.command(name='channel', aliases=['ch', 'c']) @_remove_tags.command(name='channel', aliases=['ch', 'c'])
@commands.has_permissions(manage_channels=True) @commands.has_permissions(manage_channels=True)
async def __remove_channel_tags(self, ctx, *tags): async def __remove_channel_tags(self, ctx, *tags):
global guild_blacklist global blacklists, aliases
if isinstance(ctx.message.guild, discord.Guild): if isinstance(ctx.message.guild, d.Guild):
guild = ctx.message.guild guild = ctx.message.guild
else: else:
guild = ctx.message.channel guild = ctx.message.channel
channel = ctx.message.channel channel = ctx.message.channel
for tag in tags: try:
if tag in guild_blacklist.get(str(guild.id), {}).get(str(channel.id), []): for tag in tags:
guild_blacklist.get(str(guild.id), {})[str(channel.id)].remove(tag) if tag in blacklists['guild_blacklist'][str(guild.id)][str(channel.id)]:
else: blacklists['guild_blacklist'][str(guild.id)][str(channel.id)].remove(tag)
raise exc.TagError(tag) del aliases['guild_blacklist'][str(guild.id)][str(channel.id)][tag]
with open('guild_blacklist.json', 'w') as outfile: else:
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True) raise exc.TagError(tag)
await ctx.send('✅ **Removed from** <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5) with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
with open('aliases.json', 'w') as outfile:
json.dump(aliases, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Removed from** <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
except exc.TagError as e:
await ctx.send('❌ `' + str(e) + '` **not in blacklist.**', delete_after=10)
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc()
@_remove_tags.command(name='me', aliases=['m']) @_remove_tags.command(name='me', aliases=['m'])
async def __remove_user_tags(self, ctx, *tags): async def __remove_user_tags(self, ctx, *tags):
global user_blacklist global blacklists, aliases
user = ctx.message.author user = ctx.message.author
for tag in tags: try:
if tag in user_blacklist.get(str(user.id), []): for tag in tags:
user_blacklist.get[str(user.id)].remove(tag) if tag in blacklists['user_blacklist'][str(user.id)]:
else: blacklists['user_blacklist'][str(user.id)].remove(tag)
raise exc.TagError(tag) del aliases['user_blacklist'][str(user.id)][tag]
with open('user_blacklist.json', 'w') as outfile: else:
json.dump(user_blacklist, outfile, indent=4, sort_keys=True) raise exc.TagError(tag)
await ctx.send('' + user.mention + ' **removed:**\n```' + formatter.tostring(tags) + '```', delete_after=5) with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
@blacklist.group(name='set', aliases=['s']) with open('aliases.json', 'w') as outfile:
async def _set_blacklist(self, ctx): json.dump(aliases, outfile, indent=4, sort_keys=True)
if ctx.invoked_subcommand is None: await ctx.send('' + user.mention + ' **removed:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
await ctx.send('❌ **Invalid blacklist.**') except exc.TagError as e:
await ctx.send('❌ `' + str(e) + '` **not in blacklist.**', delete_after=10)
@_set_blacklist.command(name='global', aliases=['gl', 'g']) except Exception:
@commands.is_owner() await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
async def __set_global_blacklist(self, ctx, *tags): tb.print_exc()
global global_blacklist
global_blacklist = tags[:]
with open('global_blacklist.json', 'w') as outfile:
json.dump(global_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Global blacklist set to:**\n```' + formatter.tostring(global_blacklist) + '```', delete_after=10)
@_set_blacklist.command(name='channel', aliases=['ch', 'c'])
@commands.has_permissions(manage_channels=True)
async def __set_channel_blacklist(self, ctx, *tags):
global guild_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
channel = ctx.message.channel
guild_blacklist.setdefault(str(guild.id), {})[str(channel.id)] = tags[:]
with open('guild_blacklist.json', 'w') as outfile:
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ <#' + str(channel.id) + '> **blacklist set to:**\n```' + formatter.tostring(guild_blacklist.get(str(guild.id), {}).get(str(channel.id), [])) + '```', delete_after=10)
@_set_blacklist.command(name='me', aliases=['m'])
async def __set_user_blacklist(self, ctx, *tags):
global user_blacklist
user = ctx.message.author
user_blacklist[str(user.id)] = tags[:]
with open('user_blacklist.json', 'w') as outfile:
json.dump(user_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('' + user.mention + '**\'s blacklist set to:**\n```' + formatter.tostring(user_blacklist.get(str(user.id), [])) + '```', delete_after=10)
@blacklist.group(name='clear', aliases=['cl', 'c']) @blacklist.group(name='clear', aliases=['cl', 'c'])
async def _clear_blacklist(self, ctx): async def _clear_blacklist(self, ctx):
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**') await ctx.send('❌ **Invalid blacklist.**')
@_clear_blacklist.command(name='global', aliases=['gl', 'g']) @_clear_blacklist.command(name='global', aliases=['gl', 'g'])
@commands.is_owner() @commands.is_owner()
async def __clear_global_blacklist(self, ctx): async def __clear_global_blacklist(self, ctx):
global global_blacklist global blacklists, aliases
del global_blacklist del blacklists['global_blacklist']
with open('global_blacklist.json', 'w') as outfile: del aliases['global_blacklist']
json.dump(global_blacklist, outfile, indent=4, sort_keys=True) with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
with open('aliases.json', 'w') as outfile:
json.dump(aliases, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Global blacklist cleared.**', delete_after=5) await ctx.send('✅ **Global blacklist cleared.**', delete_after=5)
@_clear_blacklist.command(name='channel', aliases=['ch', 'c']) @_clear_blacklist.command(name='channel', aliases=['ch', 'c'])
@commands.has_permissions(manage_channels=True) @commands.has_permissions(manage_channels=True)
async def __clear_channel_blacklist(self, ctx): async def __clear_channel_blacklist(self, ctx):
global guild_blacklist global blacklists, aliases
if isinstance(ctx.message.guild, discord.Guild): if isinstance(ctx.message.guild, d.Guild):
guild = ctx.message.guild guild = ctx.message.guild
else: else:
guild = ctx.message.channel guild = ctx.message.channel
channel = ctx.message.channel channel = ctx.message.channel
del guild_blacklist.get(str(guild.id), {})[str(channel.id)] del blacklists['guild_blacklist'][str(guild.id)][str(channel.id)]
with open('guild_blacklist.json', 'w') as outfile: del aliases['guild_blacklist'][str(guild.id)][str(channel.id)]
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True) with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
with open('aliases.json', 'w') as outfile:
json.dump(aliases, outfile, indent=4, sort_keys=True)
await ctx.send('✅ <#' + str(channel.id) + '> **blacklist cleared.**', delete_after=5) await ctx.send('✅ <#' + str(channel.id) + '> **blacklist cleared.**', delete_after=5)
@_clear_blacklist.command(name='me', aliases=['m']) @_clear_blacklist.command(name='me', aliases=['m'])
async def __clear_user_blacklist(self, ctx): async def __clear_user_blacklist(self, ctx):
global user_blacklist global blacklists, aliases
user = ctx.message.author user = ctx.message.author
del user_blacklist[str(user.id)] del blacklists['user_blacklist'][str(user.id)]
with open('user_blacklist.json', 'w') as outfile: del aliases['user_blacklist'][str(user.id)]
json.dump(user_blacklist, outfile, indent=4, sort_keys=True) with open('blacklists.json', 'w') as outfile:
json.dump(blacklists, outfile, indent=4, sort_keys=True)
with open('aliases.json', 'w') as outfile:
json.dump(aliases, outfile, indent=4, sort_keys=True)
await ctx.send('' + user.mention + '**\'s blacklist cleared.**', delete_after=5) await ctx.send('' + user.mention + '**\'s blacklist cleared.**', delete_after=5)

176
src/main/cogs/management.py Normal file
View file

@ -0,0 +1,176 @@
import asyncio
import discord as d
import traceback
from discord.ext import commands
from misc import checks
from misc import exceptions as exc
from utils import utils as u
RATE_LIMIT = 2.1
class Administration:
def __init__(self, bot):
self.bot = bot
self.queue = asyncio.Queue()
if u.background.get('management', {}):
if u.background['management'].get('auto_delete', {}):
for channel in u.background['management']['auto_delete']:
temp = self.bot.get_channel(channel)
self.bot.loop.create_task(self.on_message(temp))
self.bot.loop.create_task(self.delete())
print('Looping {}'.format(temp.id))
# @commands.group(aliases=['pr', 'clear', 'cl'])
# @commands.is_owner()
# @checks.del_ctx()
# async def prune(self, ctx):
# pass
#
# @prune.group(name='all', aliases=['a'])
# async def _all(self, ctx):
# pass
# @_all.group(name='user')
# async def __user(self, ctx, user: d.Member):
# channels = ctx.message.guild.text_channels
# bulk_history = {}
# bulk = {}
# history = []
# c = 0
# if ctx.invoked_subcommand is None:
# for channel in channels:
# bulk_history[channel] = await channel.history(limit=None, after=dt.datetime.utcnow() - dt.timedelta(days=14)).flatten()
# await ch_sent.edit(content='🗄 **Cached** `' + str(channels.index(channel) + 1) + '/' + str(len(channels)) + '` **channels.**')
# await asyncio.sleep(RATE_LIMIT)
# for channel, messages in bulk_history.items():
# bulk[channel] = [message for message in messages if message.author.id == int(uid)]
# for channel, messages in bulk_history.items():
# bulk[channel] = [bulk[channel][i:i+100] for i in range(0, len(bulk[channel]), 100)]
# await ctx.send('⏱ **Estimated time to delete `bulk-history`:** `' + str(int(RATE_LIMIT * sum([len(v) for v in bulk.values()]) / 60)) + ' mins ' + str(int(RATE_LIMIT * sum([len(v) for v in bulk.values()]) % 60)) + ' secs`')
# check = await ctx.send(ctx.author.mention + ' **Continue?** `Y` or `N`')
# await self.bot.wait_for('message', check=yes, timeout=60)
# del_sent = await ctx.send('🗑 **Deleting messages...**')
# for channel, messages in bulk.items():
# for chunk in messages:
# c += len(chunk)
# await channel.delete_messages(chunk)
# await del_sent.edit(content='🗑 **Deleted** `' + str(c) + '/' + str(sum([len(v) for v in bulk.values()])) + '` **messages.**')
# await asyncio.sleep(5)
# await ctx.send('✅ `' + str(sum([len(v) for v in bulk.values()])) + '` **of** <@' + uid + '>**\'s messages deleted from** ' + ctx.message.guild.name + '**.**')
# for channel in channels:
# history.extend(await channel.history(limit=None, before=dt.datetime.utcnow() - dt.timedelta(days=14)).flatten())
# await ch_sent.edit(content='🗄 **Cached** `' + str(channels.index(channel) + 1) + '/' + str(len(channels)) + '` **channels.**')
# await asyncio.sleep(RATE_LIMIT)
@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, uid, when=None, reference=None):
global RATE_LIMIT
def yes(msg):
if msg.content.lower() == 'y' and msg.channel is ctx.message.channel and msg.author is ctx.message.author:
return True
elif msg.content.lower() == 'n' and msg.channel is ctx.message.channel and msg.author is ctx.message.author:
raise exc.CheckFail
else:
return False
channels = ctx.message.guild.text_channels
if reference is not None:
for channel in channels:
try:
ref = await channel.get_message(reference)
except d.errors.NotFound:
continue
history = []
try:
pru_sent = await ctx.send('⌛️ **Pruning** <@{}>**\'s messages will take some time.**'.format(uid))
ch_sent = await ctx.send('🗄 **Caching channels...**')
if when is None:
for channel in channels:
history.extend(await channel.history(limit=None).flatten())
await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
await asyncio.sleep(RATE_LIMIT)
elif when =='before':
for channel in channels:
history.extend(await channel.history(limit=None, before=ref.created_at).flatten())
await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
await asyncio.sleep(RATE_LIMIT)
elif when == 'after':
for channel in channels:
history.extend(await channel.history(limit=None, after=ref.created_at).flatten())
await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
await asyncio.sleep(RATE_LIMIT)
elif when == 'about':
for channel in channels:
history.extend(await channel.history(limit=101, about=ref.created_at).flatten())
await ch_sent.edit(content='🗄 **Cached** `{}/{}` **channels.**'.format(channels.index(channel) + 1, len(channels)))
await asyncio.sleep(RATE_LIMIT)
history = [message for message in history if message.author.id == int(uid)]
est_sent = await ctx.send('⏱ **Estimated time to delete history:** `{}m {}s`'.format(int(RATE_LIMIT * len(history) / 60), int(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=60)
await cont_sent.delete()
del_sent = await ctx.send('🗑 **Deleting messages...**')
for message in history:
try: await message.delete()
except d.NotFound: pass
# print('Deleted {}/{} messages.'.format(history.index(message) + 1, len(history)))
await del_sent.edit(content='🗑 **Deleted** `{}/{}` **messages.**'.format(history.index(message) + 1, len(history)))
await asyncio.sleep(RATE_LIMIT)
await del_sent.edit(content='🗑 `{}` **of** <@{}>**\'s messages deleted from** {}**.**'.format(len(history), uid, ctx.message.guild.name))
except exc.CheckFail:
await ctx.send('❌ **Deletion aborted.**', delete_after=10)
except TimeoutError:
await ctx.send('❌ **Deletion timed out.**', delete_after=10)
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, traceback.format_exc(limit=1)))
traceback.print_exc(limit=1)
async def delete(self):
while True:
message = await self.queue.get()
await asyncio.sleep(RATE_LIMIT)
await message.delete()
async def on_message(self, channel):
def check(msg):
if msg.content == '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
else:
return False
try:
while True:
message = await self.bot.wait_for('message', check=check)
await self.queue.put(message)
except d.errors.NotFound:
pass
except exc.Abort:
u.background['management']['auto_delete'].remove(channel.id)
u.update(u.background, 'background.json')
print('Stopped looping {}'.format(channel.id))
await channel.send('✅ **Stopped deleting messages in** {}**.**'.format(channel.mention), delete_after=5)
except AttributeError:
pass
except Exception:
await channel.send(exc.base + '\n```' + traceback.format_exc(limit=1) + '```')
traceback.print_exc(limit=1)
@commands.command(name='autodelete', aliases=['autodel', 'ad'])
@commands.has_permissions(administrator=True)
@checks.del_ctx()
async def auto_delete(self, ctx):
channel = ctx.message.channel
u.background.setdefault('management', {}).setdefault('auto_delete', []).append(channel.id)
u.update(u.background, 'background.json')
self.bot.loop.create_task(self.on_message(channel))
self.bot.loop.create_task(self.delete())
print('Looping {}'.format(channel.id))
await ctx.send('✅ **Auto-deleting all messages in this channel.**', delete_after=5)

98
src/main/cogs/owner.py Normal file
View file

@ -0,0 +1,98 @@
import asyncio
import code
import io
import pyrasite as pyr
import re
import sys
import traceback as tb
import discord as d
from discord.ext import commands
from misc import checks
from misc import exceptions as exc
nl = re.compile('\n')
class Tools:
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)
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:-3]
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 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.message.author:
raise exc.CheckFail
elif msg.author is ctx.message.author and msg.channel is ctx.message.channel: return True
else: return False
try:
console = await self.generate(ctx)
exception = await self.generate_err(ctx)
while True:
exe = await self.bot.wait_for('message', check=execute)
await exe.delete()
sys.stdout = io.StringIO()
sys.stderr = io.StringIO()
try: exec(exe.content)
except Exception: tb.print_exc(limit=1)
await self.refresh(console, exe.content, sys.stdout.getvalue())
await self.refresh_err(exception, sys.stderr.getvalue())
await ctx.send(console.content[10:-3])
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
except exc.CheckFail:
await ctx.send('↩️ **Exited console.**')
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc(limit=1, file=sys.__stderr__)
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):
try:
sys.stdout = io.StringIO()
exec(exe)
await self.generate(ctx, exe, sys.stdout.getvalue())
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, tb.format_exc(limit=1)))
tb.print_exc(limit=1)
finally:
sys.stdout = sys.__stdout__
print('Reset stdout.')
@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

View file

@ -1,58 +1,116 @@
import asyncio import asyncio
import datetime as dt
import discord import discord
import httplib2
import mimetypes
import os
import requests_oauthlib as ro
import tempfile
import traceback import traceback
import webbrowser
from discord.ext import commands from discord.ext import commands
#from run import config
from cogs import booru from cogs import booru
from misc import checks from misc import checks
from misc import exceptions as exc from misc import exceptions as exc
from utils import formatter from utils import formatter
from apiclient.discovery import build
from apiclient import http
from oauth2client.client import flow_from_clientsecrets
youtube = None
tempfile.tempdir = os.getcwd()
command_dict = {}
class Utils: class Utils:
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
def last():
pass
@commands.command(name='last', aliases=['l', ','], brief='Reinvokes last command', description='Reinvokes previous command executed', hidden=True) @commands.command(name='last', aliases=['l', ','], brief='Reinvokes last command', description='Reinvokes previous command executed', hidden=True)
async def last_command(self, ctx): async def last_command(self, ctx):
global command_dict
try: try:
# await ctx.invoke(command, args) if command_dict.get(str(ctx.message.author.id), {}).get('args', None) is not None:
await ctx.send('`' + booru.last_command[ctx.message.author.id] + '`') args = command_dict.get(str(ctx.message.author.id), {})['args']
print(command_dict)
await ctx.invoke(command_dict.get(str(ctx.message.author.id), {}).get('command', None), args)
except Exception: except Exception:
await ctx.send(exceptions.base) await ctx.send(exc.base + '\n```' + traceback.format_exc(limit=1) + '```')
traceback.print_exc(limit=1) traceback.print_exc(limit=1)
# [prefix]ping -> Pong! # [prefix]ping -> Pong!
@commands.command(aliases=['p'], brief='Pong!', description='Returns latency from bot to Discord servers, not to user') @commands.command(aliases=['p'], brief='Pong!', description='Returns latency from bot to Discord servers, not to user')
@checks.del_ctx() @checks.del_ctx()
async def ping(self, ctx): async def ping(self, ctx):
global command_dict
try: try:
await ctx.send(ctx.message.author.mention + ' 🏓 `' + str(int(self.bot.latency * 1000)) + 'ms`', delete_after=5) await ctx.send(ctx.message.author.mention + ' 🏓 `' + str(int(self.bot.latency * 1000)) + 'ms`', delete_after=5)
except Exception: except Exception:
await ctx.send(exceptions.base) await ctx.send(exc.base + '\n```' + traceback.format_exc(limit=1) + '```')
traceback.print_exc(limit=1) traceback.print_exc(limit=1)
command_dict.setdefault(str(ctx.message.author.id), {}).update({'command': ctx.command})
@commands.command(aliases=['pre'], brief='List bot prefixes', description='Shows all used prefixes') @commands.command(aliases=['pre'], brief='List bot prefixes', description='Shows all used prefixes')
@checks.del_ctx() @checks.del_ctx()
async def prefix(self, ctx): async def prefix(self, ctx):
try: try:
await ctx.send('**Prefix:** `,` or ' + ctx.me.mention) await ctx.send('**Prefix:** `,`')
except Exception: except Exception:
await ctx.send(exceptions.base) await ctx.send(exc.base + '\n```' + traceback.format_exc(limit=1) + '```')
traceback.print_exc(limit=1) traceback.print_exc(limit=1)
@commands.group(name=',send', aliases=[',s'], hidden=True) @commands.group(name=',send', aliases=[',s'], hidden=True)
@commands.is_owner() @commands.is_owner()
@checks.del_ctx()
async def send(self, ctx): async def send(self, ctx):
pass pass
@send.command(name='guild', aliases=['g', 'server', 's']) @send.command(name='guild', aliases=['g', 'server', 's'])
@checks.del_ctx()
async def send_guild(self, ctx, guild, channel, *message): async def send_guild(self, ctx, guild, channel, *message):
await discord.utils.get(self.bot.get_all_channels(), guild__name=guild, name=channel).send(formatter.tostring(message)) await discord.utils.get(self.bot.get_all_channels(), guild__name=guild, name=channel).send(formatter.tostring(message))
@send.command(name='user', aliases=['u', 'member', 'm']) @send.command(name='user', aliases=['u', 'member', 'm'])
@checks.del_ctx()
async def send_user(self, ctx, user, *message): async def send_user(self, ctx, user, *message):
await discord.utils.get(self.bot.get_all_members(), id=int(user)).send(formatter.tostring(message)) await discord.utils.get(self.bot.get_all_members(), id=int(user)).send(formatter.tostring(message))
@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'])
@checks.is_listed()
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)
except Exception:
await ctx.send(exc.base + '\n```' + traceback.format_exc(limit=1) + '```')
traceback.print_exc(limit=1)
@upload.error
async def upload_error(self, ctx, error):
pass
# http.

View file

@ -9,6 +9,7 @@ with open('config.json') as infile:
config = json.load(infile) config = json.load(infile)
owner_id = config['owner_id'] owner_id = config['owner_id']
listed_ids = config['listed_ids']
def is_owner(): def is_owner():
async def predicate(ctx): async def predicate(ctx):
@ -22,6 +23,10 @@ def is_mod():
def predicate(ctx): def predicate(ctx):
return ctx.message.author.guild_permissions.ban_members return ctx.message.author.guild_permissions.ban_members
return commands.check(predicate) return commands.check(predicate)
def is_listed():
def predicate(ctx):
return ctx.message.author.id in listed_ids
return commands.check(predicate)
def owner(ctx): def owner(ctx):
return ctx.message.author.id == owner_id return ctx.message.author.id == owner_id

View file

@ -1,24 +1,23 @@
base = ' **An internal error has occurred.** Please notify my master! 🐺' base = ' **An internal error has occurred.** Please notify my master! 🐺'
class PostError(Exception): class Left(Exception): pass
pass class Right(Exception): pass
class ImageError(Exception): class Save(Exception): pass
pass class PostError(Exception): pass
class MatchError(Exception): class ImageError(Exception): pass
pass class MatchError(Exception): pass
class TagBlacklisted(Exception): class TagBlacklisted(Exception): pass
pass class BoundsError(Exception): pass
class BoundsError(Exception): class TagBoundsError(Exception): pass
pass class TagExists(Exception): pass
class TagBoundsError(Exception): class TagError(Exception): pass
pass class FlagError(Exception): pass
class TagExists(Exception): class BlacklistError(Exception): pass
pass class NotFound(Exception): pass
class TagError(Exception): class Timeout(Exception): pass
pass class InvalidVideoFile(Exception): pass
class FlagError(Exception): class MissingAttachment(Exception): pass
pass class TooManyAttachments(Exception): pass
class BlacklistError(Exception): class CheckFail(Exception): pass
pass class Abort(Exception): pass
class Continue(Exception): class Continue(Exception): pass
pass

View file

@ -6,76 +6,114 @@ try:
print('\"config.json\" loaded.') print('\"config.json\" loaded.')
except FileNotFoundError: except FileNotFoundError:
with open('config.json', 'w') as outfile: with open('config.json', 'w') as outfile:
json.dump({'client_id': 0, 'owner_id': 0, 'permissions': 388160, 'prefix': ',', 'shutdown_channel': 0, 'startup_channel': 0, 'token': 'str'}, outfile, indent=4, sort_keys=True) json.dump({'client_id': 0, 'listed_ids': [0], 'owner_id': 0, 'permissions': 388160, 'prefix': ',', 'shutdown_channel': 0, 'startup_channel': 0, '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.') raise FileNotFoundError('Config file not found: \"config.json\" created with abstract values. Restart \"run.py\" with correct values.')
import asyncio import asyncio
import discord import datetime as dt
import discord as d
import os
import subprocess
import sys
import traceback import traceback
from discord import utils from discord import utils
from discord.ext import commands from discord.ext import commands
from cogs import booru, info, tools from cogs import booru, info, owner, management, tools
from misc import checks from misc import checks
from misc import exceptions as exc from misc import exceptions as exc
from utils import utils as u
bot = commands.Bot(command_prefix=commands.when_mentioned_or(config['prefix']), description='Experimental booru bot') import logging
logging.basicConfig(level=logging.INFO)
print('PID {}'.format(os.getpid()))
bot = commands.Bot(command_prefix=config['prefix'], description='Experimental booru bot')
# Send and print ready message to #testing and console after logon # Send and print ready message to #testing and console after logon
@bot.event @bot.event
async def on_ready(): async def on_ready():
if isinstance(bot.get_channel(config['startup_channel']), discord.TextChannel): global bot
await bot.get_channel(config['startup_channel']).send('Hello how are? **Have day.** 🌈\n<embed>[STARTUP-INFO]</embed>')
print('Connected.') bot.add_cog(tools.Utils(bot))
print('Username: ' + bot.user.name) 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))
if isinstance(bot.get_channel(config['startup_channel']), d.TextChannel):
await bot.get_channel(config['startup_channel']).send('**Started.** ☀️')
print('CONNECTED')
print(bot.user.name)
print('-------') print('-------')
# Close connection to Discord - immediate offline # Close connection to Discord - immediate offline
@bot.command(name=',die', aliases=[',d', ',close', ',kill'], brief='Kills the bot', description='BOT OWNER ONLY\nCloses the connection to Discord', hidden=True) @bot.command(name=',die', aliases=[',d'], brief='Kills the bot', description='BOT OWNER ONLY\nCloses the connection to Discord', hidden=True)
@checks.del_ctx()
@commands.is_owner() @commands.is_owner()
@checks.del_ctx()
async def die(ctx): async def die(ctx):
try: try:
await bot.get_channel(config['shutdown_channel']).send('Am go bye. **Have night.** 💤\n<embed>[SHUTDOWN-INFO]</embed>') if isinstance(bot.get_channel(config['startup_channel']), d.TextChannel):
await bot.get_channel(config['shutdown_channel']).send('**Shutting down...** 🌙')
await bot.close() await bot.close()
print('-------') print('-------')
print('Closed.') print('CLOSED')
except Exception: except Exception:
await ctx.send(exc.base) await ctx.send(exc.base + '\n```' + traceback.format_exc(limit=1) + '```')
traceback.print_exc(limit=1)
@bot.command(name=',restart', aliases=[',res', ',r'], hidden=True)
@commands.is_owner()
@checks.del_ctx()
async def restart(ctx):
try:
print('RESTARTING')
print('-------')
if isinstance(bot.get_channel(config['startup_channel']), d.TextChannel):
await bot.get_channel(config['shutdown_channel']).send('**Restarting...** 💤')
os.execl(sys.executable, 'python3', 'run.py')
except Exception:
await ctx.send('{}\n```{}```'.format(exc.base, traceback.format_exc(limit=1)))
traceback.print_exc(limit=1) traceback.print_exc(limit=1)
# Invite bot to bot owner's server # Invite bot to bot owner's server
@bot.command(name=',invite', aliases=[',inv', ',link'], brief='Invite the bot', description='BOT OWNER ONLY\nInvite the bot to a server (Requires admin)', hidden=True) @bot.command(name=',invite', aliases=[',inv', ',link'], brief='Invite the bot', description='BOT OWNER ONLY\nInvite the bot to a server (Requires admin)', hidden=True)
@checks.del_ctx()
@commands.is_owner() @commands.is_owner()
@checks.del_ctx()
async def invite(ctx): async def invite(ctx):
try: try:
await ctx.send('🔗 https://discordapp.com/oauth2/authorize?&client_id=' + str(config['client_id']) + '&scope=bot&permissions=' + str(config['permissions'])) await ctx.send('🔗 https://discordapp.com/oauth2/authorize?&client_id={}&scope=bot&permissions={}'.format(config['client_id'], config['permissions']), delete_after=10)
except Exception: except Exception:
await ctx.send(exc.base) await ctx.send('{}\n```{}```'.format(exc.base, traceback.format_exc(limit=1)))
traceback.print_exc(limit=1) traceback.print_exc(limit=1)
@bot.command(brief='[IN TESTING]', description='[IN TESTING]', hidden=True) @bot.command(brief='[IN TESTING]', description='[IN TESTING]', hidden=True)
async def hi(ctx): async def hi(ctx):
user = ctx.message.author
try: try:
hello = 'Hello, ' + ctx.message.author.mention + '.' hello = 'Hewwo, {}.'.format(user.mention)
if ctx.message.author.id == checks.owner_id: if user.id == checks.owner_id:
hello += '.. ***Master.*** uwu' hello += '.. ***Master.*** uwu'
elif ctx.message.author.guild_permissions.administrator: elif user.guild_permissions.administrator:
hello = hello[:7] + '**Admin** ' + hello[7:] hello = '{} **Admin** {}'.format(hello[:7], hello[7:])
elif ctx.message.author.guild_permissions.ban_members: elif user.guild_permissions.ban_members:
hello = hello[:7] + '**Mod** ' + hello[7:] hello = '{} **Mod** {}'.format(hello[:7], hello[7:])
await ctx.send(hello) await ctx.send(hello)
except Exception: except Exception:
await ctx.send(exc.base) await ctx.send('{}\n```{}```'.format(exc.base, traceback.format_exc(limit=1)))
traceback.print_exc(limit=1) traceback.print_exc(limit=1)
@bot.command(hidden=True) @bot.command(name=',test', hidden=True)
@commands.is_owner()
@checks.del_ctx() @checks.del_ctx()
async def test(ctx): async def test(ctx):
pass embed = d.Embed(title='/post/xxxxxx', url='https://static1.e621.net/data/4b/3e/4b3ec0c2e8580f418e4ce019dfd5ac32.png', timestamp=dt.datetime.utcnow(), color=ctx.me.color)
embed.set_image(url='https://static1.e621.net/data/27/0f/270fd28caa5e6d8bf542a76515848e02.png')
bot.add_cog(info.Info(bot)) embed.set_footer(text='e621', icon_url='http://ndl.mgccw.com/mu3/app/20141013/18/1413204353554/icon/icon_xl.png')
bot.add_cog(tools.Utils(bot)) embed.set_author(name='tags', url=ctx.message.author.avatar_url, icon_url=ctx.message.author.avatar_url)
bot.add_cog(booru.MsG(bot)) embed.add_field(name='Link', value='https://static1.e621.net/data/c2/55/c255792b5a307ee6efa51d6bb3edf878.jpg')
await ctx.send(embed=embed)
bot.run(config['token']) bot.run(config['token'])

View file

@ -1,9 +1,13 @@
def tostring(i): def tostring(i, *, random=False):
o = ' ' o = ''
if i: if i:
for v in i: for v in i:
o += v + ' ' o += v + ' '
o = o[1:-1] o = o[:-1]
elif random is True:
o += 'order:random'
else:
o = ' '
return o return o
def tostring_commas(i): def tostring_commas(i):

36
src/main/utils/utils.py Normal file
View file

@ -0,0 +1,36 @@
import json
try:
with open('background.json') as infile:
background = json.load(infile)
print('\"background.json\" loaded.')
except FileNotFoundError:
with open('background.json', 'w+') as iofile:
print('Background file not found: \"background.json\" created and loaded.')
json.dump({}, iofile, indent=4, sort_keys=True)
iofile.seek(0)
background = json.load(iofile)
with open('config.json') as infile:
config = json.load(infile)
def update(out, file):
with open(file, 'w') as outfile:
json.dump(out, outfile, indent=4, sort_keys=True)
import asyncio
async def clear(obj, interval=10*60, replace=None):
if replace is None:
if type(obj) is list:
replace = []
elif type(obj) is dict:
replace = {}
elif type(obj) is int:
replace = 0
elif type(obj) is str:
replace = ''
while True:
obj = replace
asyncio.sleep(interval)