Complete rearranging for modularity and dev cmds

This commit is contained in:
Adriene Hutchins 2020-02-28 23:14:34 -05:00
parent 8c29e6683a
commit 9da190a078
5 changed files with 745 additions and 121 deletions

Binary file not shown.

170
extensions/core.py Normal file
View File

@ -0,0 +1,170 @@
import discord
import os
from discord.ext import commands
import time
import asyncio
import sys
import cpuinfo
import math
import psutil
class Core(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.settings = {
'extensions': []
}
self._init_extensions()
def _init_extensions(self):
"""Initializes extensions."""
for ext in os.listdir('extensions'):
if ext.endswith('.py') and not ext.startswith('core'):
try:
self.bot.load_extension(f'extensions.{ext[:-3]}')
self.settings['extensions'].append(
f'extensions.{ext[:-3]}')
except:
pass
def _humanbytes(self, B) -> str: # function lifted from StackOverflow
"""Return the given bytes as a human friendly KB, MB, GB, or TB string."""
B = float(B)
KB = float(1024)
MB = float(KB ** 2) # 1,048,576
GB = float(KB ** 3) # 1,073,741,824
TB = float(KB ** 4) # 1,099,511,627,776
if B < KB:
return '{0} {1}'.format(
B, 'Bytes' if 0 == B > 1 else 'Byte')
elif KB <= B < MB:
return '{0:.2f} KB'.format(B/KB)
elif MB <= B < GB:
return '{0:.2f} MB'.format(B/MB)
elif GB <= B < TB:
return '{0:.2f} GB'.format(B/GB)
elif TB <= B:
return '{0:.2f} TB'.format(B/TB)
@commands.command(aliases=['info', 'source', 'server'])
async def about(self, ctx):
"""Returns information about this bot."""
msg = f"**{self.bot.description}**\n"
msg += f"Created by **taciturasa#4365**, this instance by **{self.bot.appinfo.owner}.**\n\n"
msg += "**Source Code:** _<https://github.com/taciturasa/searchbot-discord>_\n"
msg += "**Support Server:** _<https://discord.gg/4BpReNV>_\n"
msg += "_Note: Please attempt to contact the hoster of any separate instances before this server._\n\n"
msg += f"_See **{ctx.prefix}** `help` for help, `invite` to add the bot, and `stats` for statistics._"
await ctx.send(msg)
@commands.command(aliases=['addbot', 'connect', 'join'])
async def invite(self, ctx):
"""Gets a link to invite this bot to your server."""
msg = (
"**Thanks for checking me out!**\n\n"
"Use the following link to add me:\n"
f"*<https://discordapp.com/oauth2/authorize?client_id={self.bot.user.id}&permissions={self.bot.config['PERMS']}&scope=bot>*"
)
await ctx.send(msg)
@commands.command()
async def stats(self, ctx):
"""Provides statistics on the bot itself."""
mem = psutil.virtual_memory()
currproc = psutil.Process(os.getpid())
total_ram = self._humanbytes(mem[0])
available_ram = self._humanbytes(mem[1])
usage = self._humanbytes(currproc.memory_info().rss)
msg = f"""
```
Total RAM: {total_ram}
Available RAM: {available_ram}
RAM used by bot: {usage}
Number of bot commands: {len(ctx.bot.commands)}
Number of extensions present: {len(ctx.bot.cogs)}
```
"""
await ctx.send(msg)
@commands.command()
async def ping(self, ctx):
"""Checks the ping of the bot."""
before = time.monotonic()
pong = await ctx.send("...")
after = time.monotonic()
ping = (after - before) * 1000
await pong.edit(content="`PING discordapp.com {}ms`".format(int(ping)))
@commands.command()
@commands.is_owner()
async def load(self, ctx, name: str):
"""Load an extension into the bot."""
m = await ctx.send(f'Loading {name}')
extension_name = 'extensions.{0}'.format(name)
if extension_name not in self.settings['extensions']:
try:
self.bot.load_extension(extension_name)
self.settings['extensions'].append(extension_name)
await m.edit(content='Extension loaded.')
except Exception as e:
await m.edit(
content=f'Error while loading {name}\n`{type(e).__name__}: {e}`')
else:
await m.edit(content='Extension already loaded.')
@commands.command(aliases=["ule", "ul"])
@commands.is_owner()
async def unload(self, ctx, name: str):
"""Unload an extension from the bot."""
m = await ctx.send(f'Unloading {name}')
extension_name = 'extensions.{0}'.format(name)
if extension_name in self.settings['extensions']:
self.bot.unload_extension(extension_name)
self.settings['extensions'].remove(extension_name)
await m.edit(content='Extension unloaded.')
else:
await m.edit(content='Extension not found or not loaded.')
@commands.command(aliases=["rle", "rl"])
@commands.is_owner()
async def reload(self, ctx, name: str):
"""Reload an extension of the bot."""
m = await ctx.send(f'Reloading {name}')
extension_name = 'extensions.{0}'.format(name)
if extension_name in self.settings['extensions']:
self.bot.unload_extension(extension_name)
try:
self.bot.load_extension(extension_name)
await m.edit(content='Extension reloaded.')
except Exception as e:
self.settings['extensions'].remove(extension_name)
await m.edit(
content=f'Failed to reload extension\n`{type(e).__name__}: {e}`')
else:
await m.edit(content='Extension isn\'t loaded.')
@commands.command(aliases=['exit', 'reboot'])
@commands.is_owner()
async def restart(self, ctx):
"""Turns the bot off."""
await ctx.send(':zzz: **Restarting.**')
exit()
def setup(bot):
bot.add_cog(Core(bot))

View File

@ -8,111 +8,519 @@
import discord
from discord.ext import commands
import os
# import psutil
import aiohttp
import random
import datetime
import collections
from contextlib import redirect_stdout
import traceback
import time
import io
import inspect
import textwrap
import subprocess
class Developer(commands.Cog):
def __init__(self, bot):
def __init__(self, bot):
self.bot = bot
self.request = bot.request
self.instances = bot.instances
self.repl_sessions = {}
self.repl_embeds = {}
self._eval = {}
async def _instance_check(self, instance, info):
'''Checks the quality of an instance.'''
def _cleanup_code(self, content):
"""Automatically removes code blocks from the code."""
# remove ```py\n```
if content.startswith('```') and content.endswith('```'):
return '\n'.join(content.split('\n')[1:-1])
# Makes sure proper values exist
if 'error' in info:
return False
if not ('engines' in info and 'initial' in info['timing']):
return False
if not ('google' in info['engines'] and 'enabled' in info['engines']['google']):
return False
# remove `foo`
return content.strip('` \n')
# Makes sure google is enabled
if not info['engines']['google']['enabled']:
return False
def _get_syntax_error(self, err):
"""Returns SyntaxError formatted for repl reply."""
return '```py\n{0.text}{1:>{0.offset}}\n{2}: {0}```'.format(
err,
'^',
type(err).__name__)
# Makes sure is not Tor
if info['network_type'] != 'normal':
return False
async def _post_to_hastebin(self, string):
"""Posts a string to hastebin."""
url = "https://hastebin.com/documents"
data = string.encode('utf-8')
async with self.request.post(url=url, data=data) as haste_response:
haste_key = (await haste_response.json())['key']
haste_url = f"http://hastebin.com/{haste_key}"
# data = {'sprunge': ''}
# data['sprunge'] = string
# haste_url = await self.aioclient.post(url='http://sprunge.us',
# data=data)
return haste_url
# Only picks instances that are fast enough
timing = int(info['timing']['initial'])
if timing > 0.20:
return False
@commands.group(name='shell',
aliases=['ipython', 'repl', 'longexec'])
async def repl(self, ctx, *, name: str = None):
"""Head on impact with an interactive python shell."""
# TODO Minimize local variables
# TODO Minimize branches
session = ctx.message.channel.id
embed = discord.Embed(
description="_Enter code to execute or evaluate. "
"`exit()` or `quit` to exit._",
timestamp=datetime.datetime.now())
embed.set_footer(
text="Interactive Python Shell",
icon_url="https://upload.wikimedia.org/wikipedia/commons/thumb"
"/c/c3/Python-logo-notext.svg/1024px-Python-logo-notext.svg.png")
if name is not None:
embed.title = name.strip(" ")
history = collections.OrderedDict()
variables = {
'ctx': ctx,
'bot': self.bot,
'message': ctx.message,
'server': ctx.message.guild,
'channel': ctx.message.channel,
'author': ctx.message.author,
'discord': discord,
'_': None
}
if session in self.repl_sessions:
error_embed = discord.Embed(
color=15746887,
description="**Error**: "
"_Shell is already running in channel._")
await ctx.send(embed=error_embed)
return
shell = await ctx.send(embed=embed)
self.repl_sessions[session] = shell
self.repl_embeds[shell] = embed
while True:
response = await self.bot.wait_for(
'message',
check=lambda m: m.content.startswith(
'`') and m.author == ctx.author and m.channel == ctx.channel
)
cleaned = self._cleanup_code(response.content)
shell = self.repl_sessions[session]
# Regular Bot Method
try:
await ctx.message.channel.fetch_message(
self.repl_sessions[session].id)
except discord.NotFound:
new_shell = await ctx.send(embed=self.repl_embeds[shell])
self.repl_sessions[session] = new_shell
embed = self.repl_embeds[shell]
del self.repl_embeds[shell]
self.repl_embeds[new_shell] = embed
shell = self.repl_sessions[session]
try:
await response.delete()
except discord.Forbidden:
pass
if len(self.repl_embeds[shell].fields) >= 7:
self.repl_embeds[shell].remove_field(0)
if cleaned in ('quit', 'exit', 'exit()'):
self.repl_embeds[shell].color = 16426522
if self.repl_embeds[shell].title is not discord.Embed.Empty:
history_string = "History for {}\n\n\n".format(
self.repl_embeds[shell].title)
else:
history_string = "History for latest session\n\n\n"
for item in history.keys():
history_string += ">>> {}\n{}\n\n".format(
item,
history[item])
haste_url = await self._post_to_hastebin(history_string)
return_msg = "[`Leaving shell session. "\
"History hosted on hastebin.`]({})".format(
haste_url)
self.repl_embeds[shell].add_field(
name="`>>> {}`".format(cleaned),
value=return_msg,
inline=False)
await self.repl_sessions[session].edit(
embed=self.repl_embeds[shell])
del self.repl_embeds[shell]
del self.repl_sessions[session]
return
executor = exec
if cleaned.count('\n') == 0:
# single statement, potentially 'eval'
try:
code = compile(cleaned, '<repl session>', 'eval')
except SyntaxError:
pass
else:
executor = eval
if executor is exec:
try:
code = compile(cleaned, '<repl session>', 'exec')
except SyntaxError as err:
self.repl_embeds[shell].color = 15746887
return_msg = self._get_syntax_error(err)
history[cleaned] = return_msg
if len(cleaned) > 800:
cleaned = "<Too big to be printed>"
if len(return_msg) > 800:
haste_url = await self._post_to_hastebin(return_msg)
return_msg = "[`SyntaxError too big to be printed. "\
"Hosted on hastebin.`]({})".format(
haste_url)
self.repl_embeds[shell].add_field(
name="`>>> {}`".format(cleaned),
value=return_msg,
inline=False)
await self.repl_sessions[session].edit(
embed=self.repl_embeds[shell])
continue
variables['message'] = response
fmt = None
stdout = io.StringIO()
try:
with redirect_stdout(stdout):
result = executor(code, variables)
if inspect.isawaitable(result):
result = await result
except Exception as err:
self.repl_embeds[shell].color = 15746887
value = stdout.getvalue()
fmt = '```py\n{}{}\n```'.format(
value,
traceback.format_exc())
else:
self.repl_embeds[shell].color = 4437377
value = stdout.getvalue()
if result is not None:
fmt = '```py\n{}{}\n```'.format(
value,
result)
variables['_'] = result
elif value:
fmt = '```py\n{}\n```'.format(value)
history[cleaned] = fmt
if len(cleaned) > 800:
cleaned = "<Too big to be printed>"
try:
if fmt is not None:
if len(fmt) >= 800:
haste_url = await self._post_to_hastebin(fmt)
self.repl_embeds[shell].add_field(
name="`>>> {}`".format(cleaned),
value="[`Content too big to be printed. "
"Hosted on hastebin.`]({})".format(
haste_url),
inline=False)
await self.repl_sessions[session].edit(
embed=self.repl_embeds[shell])
else:
self.repl_embeds[shell].add_field(
name="`>>> {}`".format(cleaned),
value=fmt,
inline=False)
await self.repl_sessions[session].edit(
embed=self.repl_embeds[shell])
else:
self.repl_embeds[shell].add_field(
name="`>>> {}`".format(cleaned),
value="`Empty response, assumed successful.`",
inline=False)
await self.repl_sessions[session].edit(
embed=self.repl_embeds[shell])
except discord.Forbidden:
pass
except discord.HTTPException as err:
error_embed = discord.Embed(
color=15746887,
description='**Error**: _{}_'.format(err))
await ctx.send(embed=error_embed)
@repl.command(name='jump',
aliases=['hop', 'pull', 'recenter', 'whereditgo'])
async def repljump(self, ctx):
"""Brings the shell back down so you can see it again."""
session = ctx.message.channel.id
if session not in self.repl_sessions:
error_embed = discord.Embed(
color=15746887,
description="**Error**: _No shell running in channel._")
await ctx.send(embed=error_embed)
return
shell = self.repl_sessions[session]
embed = self.repl_embeds[shell]
# Check for Google captcha
test_search = f'{instance}/search?q=test&format=json&lang=en-US'
try:
async with self.request.get(test_search) as resp:
response = await resp.json()
response['results'][0]['content']
except (aiohttp.ClientError, KeyError, IndexError):
return False
await ctx.message.delete()
except discord.Forbidden:
pass
# Reached if passes all checks
return True
try:
await shell.delete()
except discord.errors.NotFound:
pass
new_shell = await ctx.send(embed=embed)
self.repl_sessions[session] = new_shell
del self.repl_embeds[shell]
self.repl_embeds[new_shell] = embed
@repl.command(name='clear',
aliases=['clean', 'purge', 'cleanup',
'ohfuckme', 'deletthis'])
async def replclear(self, ctx):
"""Clears the fields of the shell and resets the color."""
session = ctx.message.channel.id
if session not in self.repl_sessions:
error_embed = discord.Embed(
color=15746887,
description="**Error**: _No shell running in channel._")
await ctx.send(embed=error_embed)
return
shell = self.repl_sessions[session]
self.repl_embeds[shell].color = discord.Color.default()
self.repl_embeds[shell].clear_fields()
try:
await ctx.message.delete()
except discord.Forbidden:
pass
await shell.edit(embed=self.repl_embeds[shell])
@commands.command(name='eval')
async def eval_cmd(self, ctx, *, code: str):
"""Evaluates Python code."""
if self._eval.get('env') is None:
self._eval['env'] = {}
if self._eval.get('count') is None:
self._eval['count'] = 0
codebyspace = code.split(" ")
print(codebyspace)
silent = False
if codebyspace[0] == "--silent" or codebyspace[0] == "-s":
silent = True
codebyspace = codebyspace[1:]
code = " ".join(codebyspace)
self._eval['env'].update({
'self': self.bot,
'ctx': ctx,
'message': ctx.message,
'channel': ctx.message.channel,
'guild': ctx.message.guild,
'author': ctx.message.author,
})
# let's make this safe to work with
code = code.replace('```py\n', '').replace('```', '').replace('`', '')
_code = (
'async def func(self):\n try:\n{}\n '
'finally:\n self._eval[\'env\'].update(locals())').format(
textwrap.indent(code, ' '))
before = time.monotonic()
# noinspection PyBroadException
try:
exec(_code, self._eval['env'])
func = self._eval['env']['func']
output = await func(self)
if output is not None:
output = repr(output)
except Exception as e:
output = '{}: {}'.format(type(e).__name__, e)
after = time.monotonic()
self._eval['count'] += 1
count = self._eval['count']
code = code.split('\n')
if len(code) == 1:
_in = 'In [{}]: {}'.format(count, code[0])
else:
_first_line = code[0]
_rest = code[1:]
_rest = '\n'.join(_rest)
_countlen = len(str(count)) + 2
_rest = textwrap.indent(_rest, '...: ')
_rest = textwrap.indent(_rest, ' ' * _countlen)
_in = 'In [{}]: {}\n{}'.format(count, _first_line, _rest)
message = '```py\n{}'.format(_in)
if output is not None:
message += '\nOut[{}]: {}'.format(count, output)
ms = int(round((after - before) * 1000))
if ms > 100: # noticeable delay
message += '\n# {} ms\n```'.format(ms)
else:
message += '\n```'
try:
if ctx.author.id == self.bot.user.id:
await ctx.message.edit(content=message)
else:
if not silent:
await ctx.send(message)
except discord.HTTPException:
if not silent:
with aiohttp.ClientSession() as sesh:
async with sesh.post(
"https://hastebin.com/documents/",
data=output,
headers={"Content-Type": "text/plain"}) as r:
r = await r.json()
embed = discord.Embed(
description=(
"[View output - click]"
"(https://hastebin.com/raw/{})").format(
r["key"]))
await ctx.send(embed=embed)
@commands.command(aliases=['sys', 'sh'])
async def system(self, ctx, *, command: str):
"""Runs system commands."""
message = await ctx.send('<a:typing:401162479041773568> Processing...')
result = []
try:
process = subprocess.Popen(command.split(
' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result = process.communicate()
except FileNotFoundError:
stderr = f'Command not found: {command}'
embed = discord.Embed(
title="Command output"
)
if len(result) >= 1 and result[0] in [None, b'']:
stdout = 'No output.'
if len(result) >= 2 and result[0] in [None, b'']:
stderr = 'No output.'
if len(result) >= 1 and result[0] not in [None, b'']:
stdout = result[0].decode('utf-8')
if len(result) >= 2 and result[1] not in [None, b'']:
stderr = result[1].decode('utf-8')
string = ""
if len(result) >= 1:
if (len(result[0]) >= 1024):
stdout = result[0].decode('utf-8')
string = string + f'[[STDOUT]]\n{stdout}'
link = await self._post_to_hastebin(string)
await message.edit(
content=f":x: Content too long. {link}",
embed=None)
return
if len(result) >= 2:
if (len(result[1]) >= 1024):
stdout = result[0].decode('utf-8')
string = string + f'[[STDERR]]\n{stdout}'
link = await self._post_to_hastebin(string)
await message.edit(
content=f":x: Content too long. {link}",
embed=None)
return
embed.add_field(
name="stdout",
value=f'```{stdout}```' if 'stdout' in locals() else 'No output.',
inline=False)
embed.add_field(
name="stderr",
value=f'```{stderr}```' if 'stderr' in locals() else 'No output.',
inline=False)
await message.edit(content='', embed=embed)
# @commands.command()
# async def git(self, ctx, sub, flags=""):
# """Runs some git commands in Discord."""
# if sub == "gud":
# if not flags:
# return await ctx.send("```You are now so gud!```")
# else:
# return await ctx.send(
# "```{} is now so gud!```".format(flags))
# elif sub == "rekt":
# if not flags:
# return await ctx.send("```You got #rekt!```")
# else:
# return await ctx.send(
# "```{} got #rekt!```".format(flags))
# else:
# process_msg = await ctx.send(
# "<a:typing:401162479041773568> Processing...")
# process = subprocess.Popen(
# f"git {sub + flags}",
# stdout=subprocess.PIPE,
# stderr=subprocess.PIPE)
# res = process.communicate()
# if res[0] == b'':
# content = "Successful!"
# else:
# content = res[0].decode("utf8")
# return await process_msg.edit(content=f"```{content}```")
@commands.command()
async def rejson(self, ctx):
'''Refreshes the list of instances for searx.'''
msg = await ctx.send('<a:updating:403035325242540032> Refreshing instance list...\n\n'
'(Due to extensive quality checks, this may take a bit.)')
plausible = []
# Get, parse, and quality check all instances
async with self.request.get('https://searx.space/data/instances.json') as r:
# Parsing
searx_json = await r.json()
instances = searx_json['instances']
# Quality Check
for i in instances:
info = instances.get(i)
is_good = await self._instance_check(i, info)
if is_good:
plausible.append(i)
# Save new list
self.instances = plausible
with open('searxes.txt', 'w') as f:
f.write('\n'.join(plausible))
await msg.edit(content='Instances refreshed!')
@commands.command(aliases=['exit', 'reboot'])
async def restart(self, ctx):
await ctx.send(':zzz: **Restarting.**')
exit()
# @commands.command()
# async def stats(self, ctx):
# mem = psutil.virtual_memory()
# currproc = psutil.Process(os.getpid())
# total_ram = self.humanbytes(mem[0])
# available_ram = self.humanbytes(mem[1])
# usage = self.humanbytes(currproc.memory_info().rss)
# text = f"""
# ```
# Total RAM: {total_ram}
# Available RAM: {available_ram}
# RAM used by bot: {usage}
# Number of bot commands: {len(ctx.bot.commands)}
# Number of extensions present: {len(ctx.bot.cogs)}
# Number of users: {len(ctx.bot.users)}
# ```
# """
# await ctx.send(text)
@commands.command(hidden=True)
async def error(self, ctx):
"""Makes the bot error out."""
3 / 0
async def cog_check(self, ctx):
return (ctx.author.id == self.bot.appinfo.owner.id)
def setup(bot):
bot.add_cog(Developer(bot))
bot.add_cog(Developer(bot))

View File

@ -11,8 +11,9 @@ import aiohttp
import random
import sys
class Search(commands.Cog):
def __init__(self, bot):
def __init__(self, bot):
self.bot = bot
self.request = bot.request
self.instances = bot.instances
@ -52,8 +53,8 @@ class Search(commands.Cog):
# Error Template
error_msg = ("**An error occured!**\n\n"
f"There was a problem with `{instance}`. Please try again later.\n"
f"_If problems with this instance persist, contact`{self.bot.appinfo.owner}` to have it removed._")
f"There was a problem with `{instance}`. Please try again later.\n"
f"_If problems with this instance persist, contact`{self.bot.appinfo.owner}` to have it removed._")
# Create the URL to make an API call to
call = f'{instance}/search?q={query}&format=json&language=en-US'
@ -103,17 +104,54 @@ class Search(commands.Cog):
[f"**{entry['title']}** <{entry['url']}>" for entry in results[1:5]])
# Instance Info
msg += f"\n\n_Results retrieved from instance `{instance}`._"
# Reached if error with returned results
except (KeyError, IndexError) as e:
# Logging
print(f"{e} with instance {instance}, trying again.")
self.instances.remove(instance) # Weed the instance out
return await self._search_logic(query, is_nsfw) # Recurse until good response
self.instances.remove(instance) # Weed the instance out
# Recurse until good response
return await self._search_logic(query, is_nsfw)
return msg
async def _instance_check(self, instance, info):
'''Checks the quality of an instance.'''
# Makes sure proper values exist
if 'error' in info:
return False
if not ('engines' in info and 'initial' in info['timing']):
return False
if not ('google' in info['engines'] and 'enabled' in info['engines']['google']):
return False
# Makes sure google is enabled
if not info['engines']['google']['enabled']:
return False
# Makes sure is not Tor
if info['network_type'] != 'normal':
return False
# Only picks instances that are fast enough
timing = int(info['timing']['initial'])
if timing > 0.20:
return False
# Check for Google captcha
test_search = f'{instance}/search?q=test&format=json&lang=en-US'
try:
async with self.request.get(test_search) as resp:
response = await resp.json()
response['results'][0]['content']
except (aiohttp.ClientError, KeyError, IndexError):
return False
# Reached if passes all checks
return True
@commands.command()
async def search(self, ctx, *, query: str):
"""Search online for results."""
@ -126,12 +164,41 @@ class Search(commands.Cog):
msg = await self._search_logic(query, ctx.channel.is_nsfw())
await ctx.send(msg)
@commands.command()
@commands.is_owner()
async def rejson(self, ctx):
'''Refreshes the list of instances for searx.'''
msg = await ctx.send('<a:updating:403035325242540032> Refreshing instance list...\n\n'
'(Due to extensive quality checks, this may take a bit.)')
plausible = []
# Get, parse, and quality check all instances
async with self.request.get('https://searx.space/data/instances.json') as r:
# Parsing
searx_json = await r.json()
instances = searx_json['instances']
# Quality Check
for i in instances:
info = instances.get(i)
is_good = await self._instance_check(i, info)
if is_good:
plausible.append(i)
# Save new list
self.instances = plausible
with open('searxes.txt', 'w') as f:
f.write('\n'.join(plausible))
await msg.edit(content='Instances refreshed!')
@commands.Cog.listener()
async def on_command_error(self, ctx, error):
"""Listener makes no command fallback to searching."""
if isinstance(error, commands.CommandNotFound) or \
isinstance(error, commands.CheckFailure):
isinstance(error, commands.CheckFailure):
# Logging
print(f"\n\nNEW CALL: {ctx.author} from {ctx.guild}.\n")
@ -147,4 +214,4 @@ class Search(commands.Cog):
def setup(bot):
bot.add_cog(Search(bot))
bot.add_cog(Search(bot))

35
main.py
View File

@ -21,7 +21,7 @@ class Bot(commands.Bot):
'''Custom Bot Class that overrides the commands.ext one'''
def __init__(self, **options):
super().__init__(self.get_prefix_new, **options)
super().__init__(self._get_prefix_new, **options)
print('Performing initialization...\n')
# Get Config Values
@ -37,7 +37,9 @@ class Bot(commands.Bot):
print('Initialization complete.\n\n')
async def get_prefix_new(self, bot, msg):
async def _get_prefix_new(self, bot, msg):
'''Full flexible check for prefix.'''
if isinstance(msg.channel, discord.DMChannel) and self.config['PREFIXLESS_DMS']:
plus_none = self.prefix.copy()
plus_none.append('')
@ -45,18 +47,11 @@ class Bot(commands.Bot):
else:
return commands.when_mentioned_or(*self.prefix)(bot, msg)
def init_extensions(self):
for ext in os.listdir('extensions'):
if ext.endswith('.py'):
self.load_extension(f'extensions.{ext[:-3]}')
async def start(self, *args, **kwargs):
async with aiohttp.ClientSession() as self.request:
self.init_extensions()
await super().start(*args, **kwargs)
async def on_ready(self):
self.request = aiohttp.ClientSession()
self.appinfo = await self.application_info()
# EXTENSION ENTRY POINT
self.load_extension('extensions.core')
msg = "CONNECTED!\n"
msg += "-----------------------------\n"
@ -92,24 +87,8 @@ bot = Bot(
case_insensitive=True)
@bot.command(aliases=['info', 'source', 'server'])
async def about(ctx):
'''Returns information about this bot.'''
appinfo = await bot.application_info()
msg = f"**{bot.description}**\n"
msg += f"Created by **taciturasa#4365**, this instance by **{appinfo.owner}.**\n\n"
msg += "**Source Code:** _<https://github.com/taciturasa/searchbot-discord>_\n"
msg += "**Support Server:** _<https://discord.gg/4BpReNV>_\n"
msg += "_Note: Please attempt to contact the hoster of any separate instances before this server._\n\n"
msg += f"_See **{ctx.prefix}** `help` for help, and `stats` for statistics._"
await ctx.send(msg)
@bot.listen()
async def on_command_error(ctx, error):
if isinstance(error, commands.CommandNotFound):
return
elif isinstance(error, commands.CommandInvokeError):