2017-10-11 02:59:06 -04:00
import asyncio
import code
import io
2017-10-12 22:26:57 -04:00
import os
2017-10-11 02:59:06 -04:00
import re
import sys
import traceback as tb
2017-11-07 01:49:42 -05:00
from contextlib import redirect_stdout , suppress
2017-10-11 02:59:06 -04:00
import discord as d
2017-10-12 22:26:57 -04:00
import pyrasite as pyr
2017-11-20 06:18:42 -05:00
from discord . ext import commands as cmds
2017-10-11 02:59:06 -04:00
from misc import exceptions as exc
2017-10-12 22:26:57 -04:00
from misc import checks
from utils import utils as u
2018-11-06 15:22:44 -05:00
from utils import formatter
2017-10-11 02:59:06 -04:00
2017-10-12 22:26:57 -04:00
class Bot :
2017-10-20 16:24:43 -04:00
def __init__ ( self , bot ) :
self . bot = bot
# Close connection to Discord - immediate offline
2017-11-20 06:18:42 -05:00
@cmds.command ( name = ' ,die ' , aliases = [ ' ,d ' ] , brief = ' Kills the bot ' , description = ' BOT OWNER ONLY \n Closes the connection to Discord ' , hidden = True )
@cmds.is_owner ( )
2017-10-20 16:24:43 -04:00
async def die ( self , ctx ) :
2017-11-06 02:00:58 -05:00
await ctx . message . add_reaction ( ' \N{CRESCENT MOON} ' )
2017-10-20 16:24:43 -04:00
2017-11-06 02:00:58 -05:00
await self . bot . get_channel ( u . config [ ' info_channel ' ] ) . send ( ' **Shutting down** \N{CRESCENT MOON} . . . ' )
2017-10-30 15:48:00 -04:00
2017-11-20 08:45:39 -05:00
chantype = ' guild ' if isinstance ( ctx . channel , d . TextChannel ) else ' private '
u . temp [ ' startup ' ] = ( chantype , ctx . channel . id if chantype == ' guild ' else ctx . author . id , ctx . message . id )
u . dump ( u . temp , ' temp/temp.pkl ' )
2017-10-30 15:48:00 -04:00
2017-10-20 16:24:43 -04:00
# loop = self.bot.loop.all_tasks()
# for task in loop:
# task.cancel()
2017-10-31 16:13:54 -04:00
print ( ' \n < < < < < < < < < < < < \n D I S C O N N E C T E D \n < < < < < < < < < < < < \n ' )
2017-10-20 16:24:43 -04:00
# u.notify('D I S C O N N E C T E D')
2018-11-03 17:02:25 -04:00
await self . bot . logout ( )
2017-10-20 16:24:43 -04:00
2017-11-20 06:18:42 -05:00
@cmds.command ( name = ' ,restart ' , aliases = [ ' ,res ' , ' ,r ' ] , hidden = True )
@cmds.is_owner ( )
2017-10-20 16:24:43 -04:00
async def restart ( self , ctx ) :
2017-11-06 02:00:58 -05:00
await ctx . message . add_reaction ( ' \N{SLEEPING SYMBOL} ' )
2017-10-20 16:24:43 -04:00
2017-10-31 16:13:54 -04:00
print ( ' \n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ \n R E S T A R T I N G \n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ \n ' )
2017-11-06 02:00:58 -05:00
await self . bot . get_channel ( u . config [ ' info_channel ' ] ) . send ( ' **Restarting** \N{SLEEPING SYMBOL} . . . ' )
2017-10-20 16:24:43 -04:00
# u.notify('R E S T A R T I N G')
2017-11-20 08:45:39 -05:00
chantype = ' guild ' if isinstance ( ctx . channel , d . TextChannel ) else ' private '
u . temp [ ' startup ' ] = ( chantype , ctx . channel . id if chantype == ' guild ' else ctx . author . id , ctx . message . id )
u . dump ( u . temp , ' temp/temp.pkl ' )
2017-10-20 16:24:43 -04:00
# loop = self.bot.loop.all_tasks()
# for task in loop:
# task.cancel()
await self . bot . logout ( )
os . execl ( sys . executable , ' python3 ' , ' run.py ' )
# Invite bot to bot owner's server
2017-11-20 06:18:42 -05:00
@cmds.command ( name = ' ,invite ' , aliases = [ ' ,inv ' , ' ,link ' ] , brief = ' Invite the bot ' , description = ' BOT OWNER ONLY \n Invite the bot to a server (Requires admin) ' , hidden = True )
@cmds.is_owner ( )
2017-10-20 16:24:43 -04:00
async def invite ( self , ctx ) :
2017-11-06 02:00:58 -05:00
await ctx . message . add_reaction ( ' \N{ENVELOPE} ' )
2017-10-20 16:24:43 -04:00
2018-11-06 02:55:08 -05:00
await ctx . send ( ' https://discordapp.com/oauth2/authorize?&client_id= {} &scope=bot&permissions= {} ' . format ( u . config [ ' client_id ' ] , u . config [ ' permissions ' ] ) )
2017-10-20 16:24:43 -04:00
2018-02-19 12:59:37 -05:00
@cmds.command ( name = ' ,guilds ' , aliases = [ ' ,glds ' , ' ,servers ' , ' ,svrs ' ] )
2018-01-14 02:16:46 -05:00
@cmds.is_owner ( )
async def guilds ( self , ctx ) :
paginator = cmds . Paginator ( )
for guild in self . bot . guilds :
2018-11-06 13:33:22 -05:00
paginator . add_line ( f ' { guild . name } - @ { guild . owner } ' )
2018-01-14 02:16:46 -05:00
for page in paginator . pages :
await ctx . send ( f ' **Guilds:** \n { page } ' )
2018-11-06 15:22:44 -05:00
@cmds.command ( name = ' ,permissions ' , aliases = [ ' ,permission ' , ' ,perms ' , ' ,perm ' ] )
@cmds.is_owner ( )
async def permissions ( self , ctx , * args : d . Member ) :
members = list ( args )
permissions = { }
if not members :
members . append ( ctx . guild . me )
for member in members :
permissions [ member . mention ] = [ ]
for k , v in dict ( ctx . channel . permissions_for ( member ) ) . items ( ) :
if v :
permissions [ member . mention ] . append ( k )
2018-11-06 16:28:19 -05:00
await ctx . send ( f ' **Permissions:** \n \n { formatter . dict_tostring ( permissions , f = False , newline = True ) } ' )
2018-11-06 15:22:44 -05:00
@cmds.command ( name = ' ,tasks ' , aliases = [ ' ,task ' ] )
@cmds.is_owner ( )
async def tasks ( self , ctx ) :
tasks = [ task for task in asyncio . Task . all_tasks ( ) if not task . done ( ) ]
await ctx . send ( f ' **Tasks active:** ` { int ( ( len ( tasks ) - 6 ) / 3 ) } ` ' )
2017-11-20 06:18:42 -05:00
@cmds.command ( name = ' ,status ' , aliases = [ ' ,presence ' , ' ,game ' ] , hidden = True )
@cmds.is_owner ( )
2017-11-20 06:05:08 -05:00
async def change_status ( self , ctx , * , game = None ) :
if game :
2017-10-20 16:24:43 -04:00
await self . bot . change_presence ( game = d . Game ( name = game ) )
u . config [ ' playing ' ] = game
u . dump ( u . config , ' config.json ' , json = True )
2017-11-20 06:08:16 -05:00
await ctx . send ( f ' **Game changed to** ` { game } ` ' )
2017-10-20 16:24:43 -04:00
else :
await self . bot . change_presence ( game = None )
2017-12-01 19:27:42 -05:00
u . config [ ' playing ' ] = ' '
2017-10-20 16:24:43 -04:00
u . dump ( u . config , ' config.json ' , json = True )
2017-11-20 06:08:16 -05:00
await ctx . send ( ' **Game changed to** ` ` ' )
2017-10-20 16:24:43 -04:00
2017-11-20 06:18:42 -05:00
@cmds.command ( name = ' ,username ' , aliases = [ ' ,user ' ] , hidden = True )
@cmds.is_owner ( )
2017-11-20 06:08:31 -05:00
async def change_username ( self , ctx , * , username = None ) :
if username :
2017-11-20 06:36:24 -05:00
await self . bot . user . edit ( username = username )
2017-11-20 06:08:31 -05:00
await ctx . send ( f ' **Username changed to** ` { username } ` ' )
else :
2018-11-06 02:55:08 -05:00
await ctx . send ( ' **Invalid string** ' )
2017-11-20 06:08:31 -05:00
await ctx . message . add_reaction ( ' \N{CROSS MARK} ' )
2017-10-12 22:26:57 -04:00
2017-10-11 02:59:06 -04:00
class Tools :
2017-10-20 16:24:43 -04:00
def __init__ ( self , bot ) :
self . bot = bot
2017-10-17 19:04:45 -04:00
2017-10-20 16:24:43 -04:00
def format ( self , i = ' ' , o = ' ' ) :
if len ( o ) > 1 :
return ' >>> {} \n {} ' . format ( i , o )
else :
return ' >>> {} ' . format ( i )
2017-10-17 19:04:45 -04:00
2017-10-20 16:24:43 -04:00
async def generate ( self , d , i = ' ' , o = ' ' ) :
return await d . send ( ' ```python \n {} ``` ' . format ( self . format ( i , o ) ) )
2017-10-17 19:04:45 -04:00
2017-10-20 16:24:43 -04:00
async def refresh ( self , m , i = ' ' , o = ' ' ) :
2017-10-20 16:24:19 -04:00
output = m . content [ 9 : - 3 ]
if len ( re . findall ( ' \n ' , output ) ) < = 20 :
2017-10-20 16:24:43 -04:00
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 ) )
2017-11-20 06:18:42 -05:00
@cmds.command ( name = ' ,console ' , aliases = [ ' ,con ' , ' ,c ' ] , hidden = True )
@cmds.is_owner ( )
2017-10-20 16:24:43 -04:00
async def console ( self , ctx ) :
def execute ( msg ) :
2017-11-07 01:50:00 -05:00
if msg . content . lower ( ) . startswith ( ' exec ' ) and msg . author is ctx . author and msg . channel is ctx . channel :
msg . content = msg . content [ 5 : ]
2017-10-20 16:24:43 -04:00
return True
return False
def evaluate ( msg ) :
2017-11-07 01:50:00 -05:00
if msg . content . lower ( ) . startswith ( ' eval ' ) and msg . author is ctx . author and msg . channel is ctx . channel :
msg . content = msg . content [ 5 : ]
2017-10-20 16:24:43 -04:00
return True
return False
def exit ( reaction , user ) :
2017-11-07 01:50:00 -05:00
if reaction . emoji == ' \N{OCTAGONAL SIGN} ' and user is ctx . author and reaction . message . id == ctx . message . id :
2017-10-20 16:24:43 -04:00
raise exc . Abort
return False
2017-10-11 02:59:06 -04:00
try :
2017-10-20 16:24:43 -04:00
console = await self . generate ( ctx )
exception = await self . generate_err ( ctx )
2017-11-07 01:50:00 -05:00
await ctx . message . add_reaction ( ' \N{OCTAGONAL SIGN} ' )
2017-10-20 16:24:43 -04:00
while not self . bot . is_closed ( ) :
try :
2017-11-07 01:50:00 -05:00
done , pending = await asyncio . wait ( [ self . bot . wait_for ( ' message ' , check = execute ) , self . bot . wait_for ( ' message ' , check = evaluate ) , self . bot . wait_for ( ' reaction_add ' , check = exit ) ] , return_when = asyncio . FIRST_COMPLETED )
message = done . pop ( ) . result ( )
print ( message . content )
2017-10-20 16:24:43 -04:00
except exc . Execute :
try :
sys . stdout = io . StringIO ( )
sys . stderr = io . StringIO ( )
2017-11-07 01:50:00 -05:00
exec ( message . content )
2017-10-20 16:24:43 -04:00
except Exception :
await self . refresh_err ( exception , tb . format_exc ( limit = 1 ) )
finally :
2017-11-07 01:50:00 -05:00
await self . refresh ( console , message . content , sys . stdout . getvalue ( ) if sys . stdout . getvalue ( ) != console . content else None )
2017-10-20 16:24:43 -04:00
sys . stdout = sys . __stdout__
sys . stderr = sys . __stderr__
2017-11-07 01:50:00 -05:00
with suppress ( d . NotFound ) :
await message . delete ( )
2017-10-20 16:24:43 -04:00
except exc . Evaluate :
try :
sys . stdout = io . StringIO ( )
sys . stderr = io . StringIO ( )
2017-11-07 01:50:00 -05:00
eval ( message . content )
2017-10-20 16:24:43 -04:00
except Exception :
await self . refresh_err ( exception , tb . format_exc ( limit = 1 ) )
finally :
2017-11-07 01:50:00 -05:00
await self . refresh ( console , message . content , sys . stdout . getvalue ( ) if sys . stdout . getvalue ( ) != console . content else None )
2017-10-20 16:24:43 -04:00
sys . stdout = sys . __stdout__
sys . stderr = sys . __stderr__
2017-11-07 01:50:00 -05:00
with suppress ( d . NotFound ) :
await message . delete ( )
2017-10-20 16:24:43 -04:00
2017-10-13 21:53:44 -04:00
except exc . Abort :
2017-10-20 16:24:43 -04:00
pass
finally :
sys . stdout = sys . __stdout__
sys . stderr = sys . __stderr__
2018-01-14 02:16:27 -05:00
print ( ' RESET : sys.std output/error ' )
2017-10-20 16:24:43 -04:00
2017-11-20 06:18:42 -05:00
@cmds.command ( name = ' ,execute ' , aliases = [ ' ,exec ' ] , hidden = True )
@cmds.is_owner ( )
2017-11-07 01:49:42 -05:00
async def execute ( self , ctx , * , exe ) :
2017-10-11 02:59:06 -04:00
try :
2017-11-07 01:49:42 -05:00
with io . StringIO ( ) as buff , redirect_stdout ( buff ) :
2017-11-07 01:50:00 -05:00
exec ( exe )
2017-11-19 23:08:59 -05:00
await self . generate ( ctx , exe , f ' \n { buff . getvalue ( ) } ' )
2017-11-07 01:49:42 -05:00
2017-10-11 02:59:06 -04:00
except Exception :
2017-11-19 23:08:59 -05:00
await self . generate ( ctx , exe , f ' \n { tb . format_exc ( ) } ' )
2017-11-07 01:49:42 -05:00
2017-11-20 06:18:42 -05:00
@cmds.command ( name = ' ,evaluate ' , aliases = [ ' ,eval ' ] , hidden = True )
@cmds.is_owner ( )
2017-11-07 01:49:42 -05:00
async def evaluate ( self , ctx , * , evl ) :
try :
with io . StringIO ( ) as buff , redirect_stdout ( buff ) :
eval ( evl )
2017-11-19 23:08:59 -05:00
await self . generate ( ctx , evl , f ' \n { buff . getvalue ( ) } ' )
2017-11-07 01:49:42 -05:00
except Exception :
2017-11-19 23:08:59 -05:00
await self . generate ( ctx , evl , f ' \n { tb . format_exc ( ) } ' )
2017-11-07 01:49:42 -05:00
2017-11-20 06:18:42 -05:00
@cmds.group ( aliases = [ ' ,db ' ] , hidden = True )
@cmds.is_owner ( )
2017-10-20 16:24:43 -04:00
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
2017-10-21 16:41:22 -04:00
2017-11-20 06:18:42 -05:00
# @cmds.command(name='endpoint', aliases=['end'])
2017-10-21 16:41:22 -04:00
# async def get_endpoint(self, ctx, *args):
# await ctx.send(f'```\n{await u.fetch(f"https://{args[0]}/{args[1]}/{args[2]}", params={args[3]: args[4], "limit": 1}, json=True)}```')