1
0
Fork 0
mirror of https://github.com/myned/modufur.git synced 2024-12-24 14:27:27 +00:00

Merge branch 'dev'

This commit is contained in:
Myned 2017-10-20 16:26:23 -04:00
commit 5eed4f3dcf
10 changed files with 1861 additions and 1778 deletions

View file

@ -25,7 +25,7 @@ class MsG:
self.LIMIT = 100
self.HISTORY_LIMIT = 100
self.RATE_LIMIT = u.RATE_LIMIT
self.queue = asyncio.Queue()
self.qualiqueue = asyncio.Queue()
self.qualitifying = False
self.favorites = u.setdefault('cogs/favorites.pkl', {'tags': set(), 'posts': set()})
@ -36,11 +36,35 @@ class MsG:
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))
self.bot.loop.create_task(self.qualiqueue_for_qualitification(temp))
print('AUTO-QUALITIFYING : #{}'.format(temp.name))
self.bot.loop.create_task(self._qualitify())
self.qualitifying = True
async def get_post(self, channel):
post_request = await u.fetch('https://e621.net/post/index.json', json=True)
@commands.command()
async def auto_post(self, ctx):
try:
if ctx.channel.id not in u.tasks['auto_post']:
u.tasks['auto_post'].append(ctx.channel.id)
u.dump(u.tasks, 'cogs/tasks.pkl')
self.bot.loop.create_task(self.qualiqueue_for_qualitification(ctx.channel))
if not self.qualitifying:
self.bot.loop.create_task(self._qualitify())
self.qualitifying = True
print('AUTO-POSTING : #{}'.format(ctx.channel.name))
await ctx.send('**Auto-posting all images in {}.**'.format(ctx.channel.mention), delete_after=5)
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
else:
raise exc.Exists
except exc.Exists:
await ctx.send('**Already auto-posting in {}.** Type `stop` to stop.'.format(ctx.channel.mention), delete_after=10)
await ctx.message.add_reaction('\N{CROSS MARK}')
# Tag search
@commands.command(aliases=['rel'], brief='e621 Search for related tags', description='e621 | NSFW\nReturn related tags for a number of given tags', usage='[related|rel]')
@checks.del_ctx()
@ -351,7 +375,7 @@ class MsG:
async def _qualitify(self):
while self.qualitifying:
message = await self.queue.get()
message = await self.qualiqueue.get()
for match in re.finditer('(http[a-z]?:\/\/[^ ]*\.(?:gif|png|jpg|jpeg))', message.content):
try:
@ -402,7 +426,7 @@ class MsG:
try:
while not self.bot.is_closed():
message = await self.bot.wait_for('message', check=check)
await self.queue.put(message)
await self.qualiqueue.put(message)
await message.add_reaction('\N{HOURGLASS WITH FLOWING SAND}')
except exc.Abort:
@ -420,7 +444,7 @@ class MsG:
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))
self.bot.loop.create_task(self.qualiqueue_for_qualitification(ctx.channel))
if not self.qualitifying:
self.bot.loop.create_task(self._qualitify())
self.qualitifying = True
@ -448,7 +472,7 @@ class MsG:
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):
elif msg.content.isdigit():
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
@ -505,7 +529,7 @@ class MsG:
return False
def on_message(msg):
with suppress(ValueError):
if msg.content.isdigit():
if int(msg.content) <= len(posts) and msg.author is ctx.author and msg.channel is ctx.channel:
return True
return False
@ -523,7 +547,8 @@ class MsG:
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'])
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)
embed.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)),
@ -597,18 +622,12 @@ class MsG:
except UnboundLocalError:
await dest.send('**Exited paginator.**')
finally:
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
except asyncio.TimeoutError:
try:
await paginator.edit(content='**Paginator timed out.**')
except UnboundLocalError:
await dest.send('**Paginator timed out.**')
finally:
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
except exc.NotFound:
await ctx.send('**Pool not found.**', delete_after=10)
await ctx.message.add_reaction('\N{CROSS MARK}')
@ -617,11 +636,16 @@ class MsG:
await ctx.message.add_reaction('\N{CROSS MARK}')
finally:
if starred:
await ctx.message.add_reaction('\N{HOURGLASS WITH FLOWING SAND}')
for url in starred:
await ctx.author.send('`{} / {}`\n{}'.format(starred.index(url) + 1, len(starred), url))
if len(starred) > 5:
await asyncio.sleep(self.RATE_LIMIT)
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
# 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(
@ -690,7 +714,7 @@ class MsG:
return False
def on_message(msg):
with suppress(ValueError):
if msg.content.isdigit():
if int(msg.content) <= len(posts) and msg.author is ctx.author and msg.channel is ctx.channel:
return True
return False
@ -711,7 +735,8 @@ class MsG:
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'])
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)
embed.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)),
@ -793,18 +818,12 @@ class MsG:
except UnboundLocalError:
await dest.send('**Exited paginator.**')
finally:
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
except asyncio.TimeoutError:
try:
await paginator.edit(content='**Paginator timed out.**')
except UnboundLocalError:
await dest.send('**Paginator timed out.**')
finally:
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
except exc.NotFound as e:
await ctx.send('`{}` **not found.**'.format(e), delete_after=10)
await ctx.message.add_reaction('\N{CROSS MARK}')
@ -822,11 +841,16 @@ class MsG:
await ctx.message.add_reaction('\N{CROSS MARK}')
finally:
if starred:
await ctx.message.add_reaction('\N{HOURGLASS WITH FLOWING SAND}')
for url in starred:
await ctx.author.send('`{} / {}`\n{}'.format(starred.index(url) + 1, len(starred), url))
if len(starred) > 5:
await asyncio.sleep(self.RATE_LIMIT)
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
@e621_paginator.error
async def e621_paginator_error(self, ctx, error):
if isinstance(error, errext.CheckFailure):

View file

@ -178,3 +178,15 @@ class Administration:
await ctx.send('**Delete command invocations:** `{}`'.format(ctx.guild.id in u.settings['del_ctx']))
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
@commands.command(name='setprefix', aliases=['setpre', 'spre'])
@commands.has_permissions(administrator=True)
async def set_prefix(self, ctx, prefix=None):
if prefix is not None:
u.settings['prefixes'][ctx.guild.id] = prefix
else:
with suppress(KeyError):
del u.settings['prefixes'][ctx.guild.id]
await ctx.send(f'**Prefix set to:** `{"` or `".join(prefix if ctx.guild.id in u.settings["prefixes"] else u.config["prefix"])}`')
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')

View file

@ -5,6 +5,7 @@ import os
import re
import sys
import traceback as tb
from contextlib import suppress
import discord as d
import pyrasite as pyr
@ -14,8 +15,6 @@ from misc import exceptions as exc
from misc import checks
from utils import utils as u
nl = re.compile('\n')
class Bot:
@ -99,9 +98,8 @@ class Tools:
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:
output = m.content[9:-3]
if len(re.findall('\n', 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)))
@ -117,57 +115,89 @@ class Tools:
@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:
if msg.content.startswith('exe') and msg.author is ctx.author and msg.channel is ctx.channel:
results.cancel()
return True
else:
return False
def evaluate(msg):
if msg.content.startswith('eval') and msg.author is ctx.author and msg.channel is ctx.channel:
results.cancel()
return True
return False
def exit(reaction, user):
if reaction.emoji == '\N{LEFTWARDS ARROW WITH HOOK}' and user is ctx.author and reaction.message.id == ctx.message.id:
results.cancel()
raise exc.Abort
return False
try:
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
console = await self.generate(ctx)
exception = await self.generate_err(ctx)
await ctx.message.add_reaction('\N{LEFTWARDS ARROW WITH HOOK}')
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()
results = await asyncio.gather([self.bot.wait_for('message', check=execute), self.bot.wait_for('message', check=evaluate), self.bot.wait_for('reaction_add', check=exit)], return_exceptions=True)
print(results)
except exc.Execute:
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())
await self.refresh(console, exe.content, sys.stdout.getvalue() if sys.stdout.getvalue() != console.content else None)
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
except exc.Evaluate:
try:
sys.stdout = io.StringIO()
sys.stderr = io.StringIO()
eval(exe.content)
except Exception:
await self.refresh_err(exception, tb.format_exc(limit=1))
finally:
await self.refresh(console, exe.content, sys.stdout.getvalue() if sys.stdout.getvalue() != console.content else None)
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
finally:
with suppress(d.NotFound):
await exe.delete()
except exc.Abort:
await ctx.send('\N{LEFTWARDS ARROW WITH HOOK} **Exited console.**')
pass
finally:
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
print('Reset sys output.')
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
@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('\N{WHITE HEAVY CHECK MARK}')
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.')
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
@commands.group(aliases=[',db'], hidden=True)
@commands.is_owner()

View file

@ -56,7 +56,7 @@ class Utils:
@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.send('**Prefix:** `{}`'.format('` or `'.join(u.settings['prefixes'][ctx.guild.id] if ctx.guild.id in u.settings['prefixes'] else u.config['prefix'])))
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
@commands.group(name=',send', aliases=[',s'], hidden=True)
@ -67,7 +67,7 @@ class Utils:
@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 discord.utils.get(self.bot.get_all_channels(), guild_name=guild, name=channel).send(message)
await ctx.message.add_reaction('\N{WHITE HEAVY CHECK MARK}')
@send.command(name='user', aliases=['u', 'member', 'm'])

View file

@ -5,6 +5,14 @@ async def send_error(ctx, error):
await ctx.send('{}\n```\n{}```'.format(base, error))
class Execute(Exception):
pass
class Evaluate(Exception):
pass
class Left(Exception):
pass

View file

@ -18,20 +18,25 @@ from utils import utils as u
# log.basicConfig(level=log.INFO)
bot = commands.Bot(command_prefix=u.config['prefix'], description='Experimental miscellaneous bot')
def get_prefix(bot, message):
if isinstance(message.guild, d.Guild) and message.guild.id in u.settings['prefixes']:
return u.settings['prefixes'][message.guild.id]
return u.config['prefix']
bot = commands.Bot(command_prefix=get_prefix, description='Experimental miscellaneous bot')
# 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
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))
for cog in (tools.Utils(bot), owner.Bot(bot), owner.Tools(bot), management.Administration(bot), info.Info(bot), booru.MsG(bot)):
bot.add_cog(cog)
print(f'COG : {type(cog).__name__}')
# bot.loop.create_task(u.clear(booru.temp_urls, 30*60))
@ -50,12 +55,25 @@ async def on_ready():
u.temp.clear()
@bot.event
async def on_message(message):
if message.author.bot or message.author is bot.user:
return
await bot.process_commands(message)
@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))
await bot.get_user(u.config['owner_id']).send('**ERROR** \N{WARNING SIGN} `{}`'.format(error))
await bot.get_channel(u.config['info_channel']).send('**ERROR** \N{WARNING SIGN} `{}`'.format(error))
if u.temp:
channel = bot.get_channel(u.temp['restart_ch'])
message = await channel.get_message(u.temp['restart_msg'])
await message.add_reaction('\N{WARNING SIGN}')
u.temp.clear()
# u.notify('E R R O R')
await bot.logout()
u.close(bot.loop)
@ -73,10 +91,10 @@ async def on_command_error(ctx, error):
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 bot.get_user(u.config['owner_id']).send('**COMMAND ERROR** \N{WARNING SIGN} `{}`'.format(error))
await bot.get_channel(u.config['info_channel']).send('**COMMAND ERROR** \N{WARNING SIGN} `{}`'.format(error))
await exc.send_error(ctx, error)
await ctx.message.add_reaction('')
await ctx.message.add_reaction('\N{WARNING SIGN}')
# u.notify('C O M M A N D E R R O R')
@ -117,16 +135,8 @@ def after(voice, error):
@commands.is_owner()
@checks.del_ctx()
async def test(ctx):
def check(react, user):
return reaction.emoji == '\N{THUMBS UP SIGN}'
# channel = bot.get_channel(int(cid))
# voice = await channel.connect()
# voice.play(d.AudioSource, after=lambda: after(voice))
test = await ctx.send('thumbs up!')
while True:
done, pending = await asyncio.wait([bot.wait_for('reaction_add', check=check), bot.wait_for('reaction_remove', check=check)], return_when=asyncio.FIRST_COMPLETED)
await ctx.send('well doneeee')
# bot.add_listener(on_reaction_add)
# bot.add_listener(on_reaction_remove)
channel = bot.get_channel(int(cid))
voice = await channel.connect()
voice.play(d.AudioSource, after=lambda: after(voice))
bot.run(u.config['token'])

View file

@ -22,23 +22,23 @@ print('\nPID : {}\n'.format(os.getpid()))
try:
with open('config.json') as infile:
config = jsn.load(infile)
print('config.json loaded.')
print('LOADED : config.json')
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': [',', 'm,'], '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.')
'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))
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))
print('FILE NOT FOUND : {} created and loaded with default values'.format(filename))
pkl.dump(default, iofile)
iofile.seek(0)
return pkl.load(iofile)
@ -62,7 +62,7 @@ def dump(obj, filename, *, json=False):
jsn.dump(obj, outfile, indent=4, sort_keys=True)
settings = setdefault('settings.pkl', {'del_ctx': []})
settings = setdefault('settings.pkl', {'del_ctx': [], 'prefixes': {}})
tasks = setdefault('cogs/tasks.pkl', {'auto_del': [], 'auto_qual': [], 'auto_rev': []})
temp = setdefault('temp.pkl', {})
@ -106,7 +106,7 @@ def close(loop):
async def fetch(url, *, params={}, json=False):
global session
async with session.get(url, params=params, headers={'user-agent': 'Modumind/0.0.1 (Myned)'}) as r:
async with session.get(url, params=params, headers={'User-Agent': 'Myned/Modumind/0.0.1'}) as r:
if json:
return await r.json()
return await r.read()
@ -137,8 +137,7 @@ def get_kwargs(ctx, args, *, limit=False):
if limit:
for arg in remaining:
if 1 <= len(arg) <= 2:
with suppress(ValueError):
if arg.isdigit():
if 1 <= int(arg) <= limit:
lim = int(arg)
remaining.remove(arg)