diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9818865
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.vscode
+.idea
+errors
+__pycache__
+notsobot_3.log
\ No newline at end of file
diff --git a/.idea/libraries/R_User_Library.xml b/.idea/libraries/R_User_Library.xml
new file mode 100644
index 0000000..71f5ff7
--- /dev/null
+++ b/.idea/libraries/R_User_Library.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 20ba448..cdfbc5b 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,8 @@
**Bot Invite**: `https://discordapp.com/oauth2/authorize?client_id=170903265565736960&scope=bot&permissions=8`
+**Commands**: https://mods.nyc/help/
+
I won't mind if you take some code to learn or improve but please don't be a skid.
Feel free to ask me questions, NotSoSuper#8800 on Discord.
diff --git a/bot.py b/bot.py
index 023836e..626a00b 100644
--- a/bot.py
+++ b/bot.py
@@ -9,10 +9,12 @@
from utils import checks
from utils.funcs import Funcs
+
#Discord Code Block Formats
code = "```py\n{0}\n```"
diff = "```diff\n{0}\n```"
+
def init_logging(shard_id, bot):
logging.root.setLevel(logging.INFO)
logger = logging.getLogger('NotSoBot #{0}'.format(shard_id))
@@ -23,10 +25,13 @@ def init_logging(shard_id, bot):
log.addHandler(handler)
bot.logger = logger
bot.log = log
+#END init_logging()
+
class Object(object):
pass
+
#Bot Utility Functions/Variables
def init_funcs(bot):
#Globals
@@ -38,14 +43,17 @@ def init_funcs(bot):
bot.globals.command_spam = {}
bot.globals.spam_sent = {}
bot.globals.command_deleted_sent = {}
+
#MySQL
global cursor, engine, Session
- if bot.dev_mode:
- db = 'discord_dev'
- elif bot.self_bot:
- db = 'discord_self'
- else:
- db = 'discord'
+ # if bot.dev_mode:
+ # db = 'discord_dev'
+ # elif bot.self_bot:
+ # db = 'discord_self'
+ # else:
+ # db = 'discord'
+ db = 'discord'
+
engine = create_engine('mysql+pymysql://{0}:@localhost/{1}?charset=utf8mb4'.format(bot.shard_id if not bot.self_bot else '', db), encoding='utf8')
session_factory = sessionmaker(bind=engine)
Session = scoped_session(session_factory)
@@ -84,44 +92,50 @@ def init_funcs(bot):
bot.path = Object()
discord_path = bot.path.discord = funcs.discord_path
files_path = bot.path.files = funcs.files_path
+#END init_funcs()
+
#Bot Cogs
modules = [
- 'mods.Logging',
+ #'mods.Logging',
'mods.Commands',
- 'mods.Moderation',
+ #'mods.Moderation',
'mods.Utils',
'mods.Info',
'mods.Fun',
'mods.Chan',
'mods.Repl',
- 'mods.Stats',
+ #'mods.Stats',
'mods.Tags',
'mods.Logs',
'mods.Wc',
# 'mods.AI',
'mods.Changes',
'mods.Markov',
- 'mods.Verification',
+ #'mods.Verification',
'mods.Nsfw',
'mods.Reminders',
'mods.JoinLeave',
'mods.Afk'
]
+
#Console Colors
def prRed(prt): print("\033[91m {}\033[00m" .format(prt))
def prGreen(prt): print("\033[92m {}\033[00m" .format(prt))
+
class NotSoBot(commands.Bot):
def __init__(self, *args, **kwargs):
self.loop = kwargs.pop('loop', asyncio.get_event_loop())
asyncio.get_child_watcher().attach_loop(self.loop)
self.dev_mode = kwargs.pop('dev_mode', False)
- self.token = os.getenv('bot_token') if not self.dev_mode else os.getenv('bot_beta_token')
+ #self.token = os.getenv('bot_token') if not self.dev_mode else os.getenv('bot_beta_token')
+ self.token = "NTQzNTQyMTQ4NjUwMzY5MDUz.Dz-EmQ.oGb9THEL_e_0vJh3knr_D2lKQH4" # Hardcoded
self.self_bot = kwargs.pop('self_bot', False)
if self.self_bot:
- self.token = os.getenv('notsosuper_token')
+ self.token = "NTQzNTQyMTQ4NjUwMzY5MDUz.Dz-EmQ.oGb9THEL_e_0vJh3knr_D2lKQH4" # Hardcoded
+ #self.token = os.getenv('notsosuper_token')
shard_id = kwargs.get('shard_id', 0)
command_prefix = kwargs.pop('command_prefix', commands.when_mentioned_or('.'))
init_logging(shard_id, self)
@@ -133,13 +147,19 @@ def __init__(self, *args, **kwargs):
self.own_task = None
self.last_message = None
self.command_messages = {}
+ #END __init__()
+
def __del__(self):
self.loop.set_exception_handler(lambda *args, **kwargs: None)
+ #END __del__()
+
@property
def get_cursor(self):
return Session()
+ #END get_cursor()
+
async def on_ready(self):
if not self.self_bot:
@@ -171,18 +191,22 @@ async def on_ready(self):
else:
print('------\n{0}\nShard {1}/{2}{3}------'.format(self.user, self.shard_id, self.shard_count-1, '\nDev Mode: Enabled\n' if self.dev_mode else ''))
await self.change_presence(game=discord.Game(name="https://ropestore.org"))
+ #END on_ready()
+
async def on_message(self, message):
self.last_message = message.timestamp
await self.wait_until_ready()
if self.globals.on_ready_write:
self.write_last_time()
+
if self.owner is None:
if self.self_bot:
self.owner = self.user
else:
application_info = await self.application_info()
self.owner = application_info.owner
+
if self.dev_mode and message.author != self.owner:
return
elif self.self_bot and message.author != self.owner:
@@ -191,33 +215,40 @@ async def on_message(self, message):
return
elif message.author.bot:
return
+
blacklisted = await self.is_blacklisted(message)
if blacklisted:
return
+
prefix_result = await self.get_prefix(message)
prefixes = prefix_result[0]
check = prefix_result[1] if not self.self_bot else True
command = None
- invoker = None
+ #invoker = None
pm_only = False
for prefix in prefixes:
if message.content.lower().startswith(prefix) and check and message.content.lower() != prefix:
prefix_escape = re.escape(prefix)
message_regex = re.compile(r'('+prefix_escape+r')'+r'[\s]*(\w+)(.*)', re.I|re.X|re.S)
match = message_regex.findall(message.content)
+
if len(match) == 0:
return
+
match = match[0]
command = match[1].lower()
message.content = match[0].lower()+command+match[2]
if command not in self.commands:
return
+
if message.channel.is_private:
if command in self.commands and self.commands[command].no_pm:
pm_only = True
+
if pm_only is False:
cmd = str(self.commands[command])
command_blacklisted = await self.command_check(message, cmd, prefix)
+
if command_blacklisted:
return
try:
@@ -257,6 +288,8 @@ async def on_message(self, message):
command_spam[message.channel] = {0: [utc+4], 1: [command]}
await self.process_commands(message, command, prefix)
self.command_messages[message] = [command, prefix]
+ #END on_message()
+
async def on_command(self, command, ctx):
embed = discord.Embed()
@@ -266,11 +299,13 @@ async def on_command(self, command, ctx):
embed.add_field(name='Server', value='{0.name} <{0.id}>'.format(ctx.message.server) if ctx.message.server else 'Private Message')
embed.add_field(name='Channel', value='`{0.name}`'.format(ctx.message.channel))
embed.add_field(name='Message', value=ctx.message.clean_content+' '.join([x['url'] for x in ctx.message.attachments]), inline=False)
- embed.color = self.funcs.get_color()()
+ #embed.color = self.funcs.get_color()
embed.timestamp = ctx.message.timestamp
await self.queue_message("178313681786896384", embed)
if ctx.message.author.id == self.owner.id:
ctx.command.reset_cooldown(ctx)
+ #END on_command()
+
async def on_error(self, event, *args, **kwargs):
prRed("Error!")
@@ -280,6 +315,8 @@ async def on_error(self, event, *args, **kwargs):
wrapper = textwrap.TextWrapper(initial_indent='! ', subsequent_indent='- ')
fmt = wrapper.fill(str(traceback.format_exc()))
await self.queue_message("180073721048989696", diff.format(fmt))
+ #END on_error()
+
async def on_command_error(self, e, ctx):
try:
@@ -296,10 +333,7 @@ async def on_command_error(self, e, ctx):
else:
cooldown_sent[ctx.message.channel] = utc+5
await self.send_message(ctx.message.channel, ":no_entry: **Cooldown** `Cannot use again for another {:.2f} seconds.`".format(e.retry_after))
- elif isinstance(e, commands.MissingRequiredArgument):
- await self.command_help(ctx)
- ctx.command.reset_cooldown(ctx)
- elif isinstance(e, commands.BadArgument):
+ elif isinstance(e, commands.MissingRequiredArgument) or isinstance(e, commands.BadArgument):
await self.command_help(ctx)
ctx.command.reset_cooldown(ctx)
elif isinstance(e, checks.No_Perms):
@@ -350,7 +384,7 @@ async def on_command_error(self, e, ctx):
embed.add_field(name='File', value=str(e.__traceback__.tb_frame.f_code.co_filename)+'\nLine: **{0}**'.format(e.__traceback__.tb_lineno), inline=False)
embed.add_field(name='Traceback', value=code.format(''.join(tb)), inline=False)
embed.set_author(name='{0} <{0.id}>'.format(ctx.message.author), icon_url=ctx.message.author.avatar_url)
- embed.color = discord.Color.red()
+ #embed.color = "#FF0000"
embed.timestamp = datetime.datetime.now()
await self.queue_message("180073721048989696", embed)
elif type(e).__name__ == 'NoPrivateMessage':
@@ -365,6 +399,8 @@ async def on_command_error(self, e, ctx):
return
except Exception as e:
print(e)
+ #END on_command_error()
+
async def on_server_join(self, server):
await self.wait_until_ready()
@@ -376,9 +412,11 @@ async def on_server_join(self, server):
embed.add_field(name='Members', value='**{0}**/{1}'.format(sum(1 for x in server.members if x.status == discord.Status.online or x.status == discord.Status.idle), len(server.members)))
embed.add_field(name='Default Channel', value=server.default_channel)
embed.add_field(name='Channels', value='Text: `{0}`\nVoice: `{1}`\nTotal: **{2}**'.format(sum(1 for x in server.channels if x.type == discord.ChannelType.text), sum(1 for x in server.channels if x.type == discord.ChannelType.voice), len(server.channels)))
- embed.color = discord.Color.green()
+ #embed.color = "#00FF00"
embed.timestamp = datetime.datetime.now()
await self.queue_message('211247117816168449', embed)
+ #END on_server_join()
+
async def on_server_remove(self, server):
await self.wait_until_ready()
@@ -393,9 +431,11 @@ async def on_server_remove(self, server):
embed.set_author(name='{0} <{0.id}>'.format(server.owner), icon_url=server.owner.avatar_url)
embed.add_field(name='Server', value='{0.name} <{0.id}>'.format(server))
embed.add_field(name='Members', value='**{0}**/{1}'.format(sum(1 for x in server.members if x.status == discord.Status.online or x.status == discord.Status.idle), len(server.members)))
- embed.color = discord.Color.red()
+ #embed.color = discord.Color.red()
embed.timestamp = datetime.datetime.now()
await self.queue_message('211247117816168449', embed)
+ #END on_server_remove()
+
async def on_resumed(self):
last_time = self.get_last_time()
@@ -408,6 +448,8 @@ async def on_resumed(self):
downtime = str(utc - last_time)
msg = '`[Shard {0}]` {1} has now <@&211727010932719627> after being <@&211727098149076995> since **{2}** for **{3}** second(s) (Current Time: **{4}**)'.format(self.shard_id, self.user.mention, time_msg, downtime, current_time_msg)
await self.queue_message('211247117816168449', msg)
+ #END on_resumed()
+
async def send_message(self, destination, content=None, *, tts=False, embed=None, replace_mentions=False, replace_everyone=True):
if content:
@@ -417,15 +459,23 @@ async def send_message(self, destination, content=None, *, tts=False, embed=None
if replace_mentions:
content = await self.funcs.replace_mentions(content)
return await super().send_message(destination, content, tts=tts, embed=embed)
+ #END send_message()
+
def get_member(self, id:str):
return discord.utils.get(self.get_all_members(), id=id)
+ #END get_member()
+
def run(self):
super().run(self.token)
+ #END run()
+
async def login(self, *args, **kwargs):
return await super().login(self.token, bot=False if self.self_bot else True)
+ #END login()
+
def die(self):
try:
@@ -441,3 +491,5 @@ def die(self):
self.log.removeHandler(handler)
except Exception as e:
print(e)
+ #END die()
+#END_CLASS NotSoBot
\ No newline at end of file
diff --git a/bot0.py b/bot0.py
index 779d820..aedcb37 100644
--- a/bot0.py
+++ b/bot0.py
@@ -3,13 +3,17 @@
import os, sys
from bot import NotSoBot
+
loop = asyncio.get_event_loop()
-dev_mode = str(os.getenv('dev_mode', False))
-if dev_mode == '1' or dev_mode.lower() == 'true':
- dev_mode = True
-else:
- dev_mode = False
+
+# dev_mode = str(os.getenv('dev_mode', False))
+# if dev_mode == '1' or dev_mode.lower() == 'true':
+# dev_mode = True
+# else:
+# dev_mode = False
+dev_mode = False
+
shard_id = [int(s) for s in os.path.realpath(__file__) if s.isdigit()][0]
shard_count = len([s for s in os.listdir() if s.startswith('bot') and s[3].isdigit()])
@@ -19,6 +23,7 @@
if len(sys.argv) > 1:
shard_count = int(sys.argv[2])
+
async def watcher():
await asyncio.sleep(30)
while True:
@@ -34,9 +39,11 @@ async def watcher():
bot = NotSoBot(loop=loop, shard_id=shard_id, shard_count=shard_count, dev_mode=dev_mode, max_messages=10000)
+
if __name__ == "__main__":
try:
task = loop.create_task(bot.run())
+ print("NotSoFork is up and running!")
task.add_done_callback(functools.partial(main, loop))
bot.own_task = task
loop.create_task(watcher())
diff --git a/install-reqs.sh b/install-reqs.sh
new file mode 100644
index 0000000..4b51904
--- /dev/null
+++ b/install-reqs.sh
@@ -0,0 +1,12 @@
+clear
+printf "" > errors # Clear out errors from possible previous runs
+
+while read line; do
+ pip install $line
+
+ if [ $? -ne 0 ]; then
+ printf "ERROR INSTALLING: $line\n" >> errors
+ fi
+
+ printf "##################################################################\n"
+done < "./requirements.txt"
\ No newline at end of file
diff --git a/mods/Fun.py b/mods/Fun.py
index 725a670..22de9ca 100644
--- a/mods/Fun.py
+++ b/mods/Fun.py
@@ -35,11 +35,18 @@ def get_deep_text(element):
except:
return ''
-def posnum(num):
- if num < 0 :
- return - (num)
+
+# updated to handle bad input and use abs function
+def posnum(num):
+ # check if number is int
+ if isinstance(num, int):
+ return abs(num)
+ # check if number is float
+ elif isinstance(num, float):
+ return abs(num)
else:
- return num
+ return False
+
def find_coeffs(pa, pb):
matrix = []
@@ -119,27 +126,35 @@ async def badmeme(self, ctx, direct=None):
b = await self.bytes_download(url)
await self.bot.upload(b, filename='badmeme.png')
+ def getImgs(self, scale, imgs):
+ exif = {}
+ list_imgs = []
+ count = 0
+ for img in imgs:
+ i = wand.image.Image(file=img)
+ i.format = 'jpg'
+ i.alpha_channel = True
+ if i.size >= (3000, 3000):
+ return ':warning: `Image exceeds maximum resolution >= (3000, 3000).`', None
+ exif.update({count: (k[5:], v) for k, v in i.metadata.items() if k.startswith('exif:')})
+ count += 1
+ i.transform(resize='800x800>')
+ i.liquid_rescale(width=int(i.width * 0.5), height=int(i.height * 0.5),
+ delta_x=int(0.5 * scale) if scale else 1, rigidity=0)
+ i.liquid_rescale(width=int(i.width * 1.5), height=int(i.height * 1.5), delta_x=scale if scale else 2,
+ rigidity=0)
+ magikd = BytesIO()
+ i.save(file=magikd)
+ magikd.seek(0)
+ list_imgs.append(magikd)
+ return exif, list_imgs
+
def do_magik(self, scale, *imgs):
try:
- list_imgs = []
- exif = {}
exif_msg = ''
- count = 0
- for img in imgs:
- i = wand.image.Image(file=img)
- i.format = 'jpg'
- i.alpha_channel = True
- if i.size >= (3000, 3000):
- return ':warning: `Image exceeds maximum resolution >= (3000, 3000).`', None
- exif.update({count:(k[5:], v) for k, v in i.metadata.items() if k.startswith('exif:')})
- count += 1
- i.transform(resize='800x800>')
- i.liquid_rescale(width=int(i.width * 0.5), height=int(i.height * 0.5), delta_x=int(0.5 * scale) if scale else 1, rigidity=0)
- i.liquid_rescale(width=int(i.width * 1.5), height=int(i.height * 1.5), delta_x=scale if scale else 2, rigidity=0)
- magikd = BytesIO()
- i.save(file=magikd)
- magikd.seek(0)
- list_imgs.append(magikd)
+
+ exif, list_imgs = self.getImgs(scale, imgs)
+
if len(list_imgs) > 1:
imgs = [PIL.Image.open(i).convert('RGBA') for i in list_imgs]
min_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[0][1]
@@ -201,6 +216,15 @@ async def magik(self, ctx, *urls:str):
except Exception as e:
await self.bot.say(e)
+ def gmagikExcept(self):
+ exc_type, exc_obj, tb = sys.exc_info()
+ f = tb.tb_frame
+ lineno = tb.tb_lineno
+ filename = f.f_code.co_filename
+ linecache.checkcache(filename)
+ line = linecache.getline(filename, lineno, f.f_globals)
+ print('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj))
+
def do_gmagik(self, ctx, gif, gif_dir, rand):
try:
try:
@@ -237,13 +261,7 @@ def do_gmagik(self, ctx, gif, gif_dir, rand):
i.save(filename=image)
return True
except Exception as e:
- exc_type, exc_obj, tb = sys.exc_info()
- f = tb.tb_frame
- lineno = tb.tb_lineno
- filename = f.f_code.co_filename
- linecache.checkcache(filename)
- line = linecache.getline(filename, lineno, f.f_globals)
- print('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj))
+ self.gmagikExcept()
@commands.command(pass_context=True)
@commands.cooldown(1, 20, commands.BucketType.server)
diff --git a/mods/JoinLeave.py b/mods/JoinLeave.py
index 1850910..ac2acce 100644
--- a/mods/JoinLeave.py
+++ b/mods/JoinLeave.py
@@ -10,8 +10,13 @@
default_leave = '**{user}#{discrim}** has left the server.'
#http://stackoverflow.com/a/16671271
+# updated to check for input and use abs function
def number_formating(n):
- return str(n)+("th" if 4<=n%100<=20 else {1:"st",2:"nd",3:"rd"}.get(n%10, "th"))
+ if not isinstance(n, int):
+ return False
+ if n < 1:
+ n = abs(n)
+ return str(n) + ("th" if 4 <= n % 100 <= 20 else {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th"))
class Object():
pass
diff --git a/mods/Tags.py b/mods/Tags.py
index 62f3f93..86d4899 100644
--- a/mods/Tags.py
+++ b/mods/Tags.py
@@ -18,7 +18,18 @@
cool = "```xl\n{0}\n```"
code = "```py\n{0}\n```"
+
+# updated to check for bad inputs
def check_int(k):
+ # if int, return true
+ if isinstance(k, int):
+ return True
+
+ # if float, return false
+ if isinstance(k, float):
+ return False
+
+ # if a string, parse and check if int
if k[0] in ('-', '+'):
return k[1:].isdigit()
return k.isdigit()
diff --git a/mods/__init__.py b/mods/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pixelsort/sorting.py b/pixelsort/sorting.py
index a8f0eb2..d333585 100644
--- a/pixelsort/sorting.py
+++ b/pixelsort/sorting.py
@@ -5,13 +5,31 @@ def lightness(pixel):
return util.lightness(pixel)
+# updated to check inputs
def intensity(pixel):
- return pixel[0] + pixel[1] + pixel[2]
+ if len(pixel) > 3:
+ return False
+ for num in pixel:
+ if not isinstance(num, int):
+ return False
+ return pixel[0] + pixel[1] + pixel[2]
+# updated to check for bad inputs
def maximum(pixel):
- return max(pixel[0], pixel[1], pixel[2])
+ if len(pixel) > 3:
+ return False
+ for num in pixel:
+ if not isinstance(num, int):
+ return False
+ return max(pixel[0], pixel[1], pixel[2])
+# updated to check for bad inputs
def minimum(pixel):
- return min(pixel[0], pixel[1], pixel[2])
+ if len(pixel) > 3:
+ return False
+ for num in pixel:
+ if not isinstance(num, int):
+ return False
+ return min(pixel[0], pixel[1], pixel[2])
diff --git a/pixelsort/util.py b/pixelsort/util.py
index f38d609..1b3b36d 100644
--- a/pixelsort/util.py
+++ b/pixelsort/util.py
@@ -11,8 +11,19 @@ def lightness(pixel):
return rgb_to_hsv(pixel[0], pixel[1], pixel[2])[2] / 255.0 # For backwards compatibility with python2
+# Updated to check for bad input
def random_width(clength):
+ # check if input is an integer
+ if not isinstance(clength, int):
+ return False
+ # if integer is negative, return false
+ if clength < 0:
+ return False
+
+ # get a random number
x = random.random()
+
+ # set width equal a value less than or equal to clength
width = int(clength * (1 - x))
return width
diff --git a/utils/__init__.py b/utils/__init__.py
new file mode 100644
index 0000000..9242569
--- /dev/null
+++ b/utils/__init__.py
@@ -0,0 +1 @@
+# This only exists so that bot.py recognizes "utils" as a module
\ No newline at end of file