Browse Source

Strip Komet of all of it's useful stuff and leave all the cringe and memes.

main
Nichole Mattera 10 months ago
parent
commit
84b10dc7cf
  1. 211
      Robocop.py
  2. 93
      cogs/admin.py
  3. 57
      cogs/basic.py
  4. 95
      cogs/common.py
  5. 196
      cogs/err.py
  6. 43
      cogs/invites.py
  7. 74
      cogs/links.py
  8. 30
      cogs/lists.py
  9. 263
      cogs/lists_verification.py
  10. 90
      cogs/lockdown.py
  11. 353
      cogs/logs.py
  12. 126
      cogs/meme.py
  13. 551
      cogs/mod.py
  14. 143
      cogs/mod_mail.py
  15. 32
      cogs/mod_note.py
  16. 110
      cogs/mod_reacts.py
  17. 160
      cogs/mod_stats.py
  18. 137
      cogs/mod_timed.py
  19. 221
      cogs/mod_userlog.py
  20. 46
      cogs/mod_watch.py
  21. 157
      cogs/pin.py
  22. 68
      cogs/remind.py
  23. 153
      cogs/robocronp.py
  24. 1
      cogs/uwu.py
  25. 120
      config_template.py
  26. 10
      helpers/checks.py
  27. 1115
      helpers/errcodes.py
  28. 42
      helpers/restrictions.py
  29. 37
      helpers/robocronp.py
  30. 72
      helpers/userlogs.py

211
Robocop.py

@ -1,34 +1,20 @@
import os
import asyncio
import sys
import logging
import logging.handlers
import traceback
import aiohttp
import config
import discord
from discord.ext import commands
script_name = os.path.basename(__file__).split('.')[0]
log_file_name = f"{script_name}.log"
# Limit of discord (non-nitro) is 8MB (not MiB)
max_file_size = 1000 * 1000 * 8
backup_count = 3
file_handler = logging.handlers.RotatingFileHandler(
filename=log_file_name, maxBytes=max_file_size, backupCount=backup_count)
stdout_handler = logging.StreamHandler(sys.stdout)
log_format = logging.Formatter(
'[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s')
file_handler.setFormatter(log_format)
"[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s"
)
stdout_handler.setFormatter(log_format)
log = logging.getLogger('discord')
log = logging.getLogger("discord")
log.setLevel(logging.INFO)
log.addHandler(file_handler)
log.addHandler(stdout_handler)
@ -38,87 +24,49 @@ def get_prefix(bot, message):
return commands.when_mentioned_or(*prefixes)(bot, message)
wanted_jsons = ["data/restrictions.json",
"data/robocronptab.json",
"data/userlog.json",
"data/invites.json"]
initial_extensions = ['cogs.common',
'cogs.admin',
'cogs.mod',
'cogs.mod_mail',
'cogs.mod_note',
'cogs.mod_reacts',
'cogs.mod_stats',
'cogs.mod_userlog',
'cogs.mod_timed',
'cogs.mod_watch',
'cogs.basic',
'cogs.logs',
'cogs.lockdown',
'cogs.links',
'cogs.lists',
'cogs.lists_verification',
'cogs.remind',
'cogs.robocronp',
'cogs.meme',
'cogs.uwu']
bot = commands.Bot(command_prefix=get_prefix,
description=config.bot_description, pm_help=True)
initial_extensions = [
"cogs.common",
"cogs.admin",
"cogs.basic",
"cogs.links",
"cogs.lists",
"cogs.meme",
"cogs.uwu",
]
bot = commands.Bot(
command_prefix=get_prefix, description=config.bot_description, pm_help=True
)
bot.log = log
bot.loop = asyncio.get_event_loop()
bot.config = config
bot.script_name = script_name
bot.wanted_jsons = wanted_jsons
if __name__ == '__main__':
if __name__ == "__main__":
for extension in initial_extensions:
try:
bot.load_extension(extension)
except Exception as e:
log.error(f'Failed to load extension {extension}.')
log.error(f"Failed to load extension {extension}.")
log.error(traceback.print_exc())
@bot.event
async def on_ready():
aioh = {"User-Agent": f"{script_name}/1.0'"}
bot.aiosession = aiohttp.ClientSession(headers=aioh)
bot.app_info = await bot.application_info()
bot.botlog_channel = bot.get_channel(config.botlog_channel)
log.info(f'\nLogged in as: {bot.user.name} - '
f'{bot.user.id}\ndpy version: {discord.__version__}\n')
log.info(
f"\nLogged in as: {bot.user.name} - "
f"{bot.user.id}\ndpy version: {discord.__version__}\n"
)
game_name = f"{config.prefixes[0]}help"
# Send "Robocop has started! x has y members!"
guild = bot.botlog_channel.guild
msg = f"{bot.user.name} has started! "\
f"{guild.name} has {guild.member_count} members!"
data_files = [discord.File(fpath) for fpath in wanted_jsons]
await bot.botlog_channel.send(msg, files=data_files)
msg = f"{bot.user.name} has started! "
await bot.botlog_channel.send(msg)
activity = discord.Activity(name=game_name,
type=discord.ActivityType.listening)
activity = discord.Activity(name=game_name, type=discord.ActivityType.listening)
await bot.change_presence(activity=activity)
@bot.event
async def on_command(ctx):
log_text = f"{ctx.message.author} ({ctx.message.author.id}): "\
f"\"{ctx.message.content}\" "
if ctx.guild: # was too long for tertiary if
log_text += f"on \"{ctx.channel.name}\" ({ctx.channel.id}) "\
f"at \"{ctx.guild.name}\" ({ctx.guild.id})"
else:
log_text += f"on DMs ({ctx.channel.id})"
log.info(log_text)
@bot.event
async def on_error(event_method, *args, **kwargs):
log.error(f"Error on {event_method}: {sys.exc_info()}")
@ -128,9 +76,11 @@ async def on_error(event_method, *args, **kwargs):
async def on_command_error(ctx, error):
error_text = str(error)
err_msg = f"Error with \"{ctx.message.content}\" from "\
f"\"{ctx.message.author} ({ctx.message.author.id}) "\
f"of type {type(error)}: {error_text}"
err_msg = (
f'Error with "{ctx.message.content}" from '
f"{ctx.message.author} ({ctx.message.author.id}) "
f"of type {type(error)}: {error_text}"
)
log.error(err_msg)
@ -141,71 +91,60 @@ async def on_command_error(ctx, error):
if isinstance(error, commands.NoPrivateMessage):
return await ctx.send("This command doesn't work on DMs.")
elif isinstance(error, commands.MissingPermissions):
roles_needed = '\n- '.join(error.missing_perms)
return await ctx.send(f"{ctx.author.mention}: You don't have the right"
" permissions to run this command. You need: "
f"```- {roles_needed}```")
roles_needed = "\n- ".join(error.missing_perms)
return await ctx.send(
f"{ctx.author.mention}: You don't have the right"
" permissions to run this command. You need: "
f"```- {roles_needed}```"
)
elif isinstance(error, commands.BotMissingPermissions):
roles_needed = '\n-'.join(error.missing_perms)
return await ctx.send(f"{ctx.author.mention}: Bot doesn't have "
"the right permissions to run this command. "
"Please add the following roles: "
f"```- {roles_needed}```")
roles_needed = "\n-".join(error.missing_perms)
return await ctx.send(
f"{ctx.author.mention}: Bot doesn't have "
"the right permissions to run this command. "
"Please add the following roles: "
f"```- {roles_needed}```"
)
elif isinstance(error, commands.CommandOnCooldown):
return await ctx.send(f"{ctx.author.mention}: You're being "
"ratelimited. Try in "
f"{error.retry_after:.1f} seconds.")
return await ctx.send(
f"{ctx.author.mention}: You're being "
"ratelimited. Try in "
f"{error.retry_after:.1f} seconds."
)
elif isinstance(error, commands.CheckFailure):
return await ctx.send(f"{ctx.author.mention}: Check failed. "
"You might not have the right permissions "
"to run this command, or you may not be able "
"to run this command in the current channel.")
elif isinstance(error, commands.CommandInvokeError) and\
("Cannot send messages to this user" in error_text):
return await ctx.send(f"{ctx.author.mention}: I can't DM you.\n"
"You might have me blocked or have DMs "
f"blocked globally or for {ctx.guild.name}.\n"
"Please resolve that, then "
"run the command again.")
return await ctx.send(
f"{ctx.author.mention}: Check failed. "
"You might not have the right permissions "
"to run this command, or you may not be able "
"to run this command in the current channel."
)
elif isinstance(error, commands.CommandInvokeError) and (
"Cannot send messages to this user" in error_text
):
return await ctx.send(
f"{ctx.author.mention}: I can't DM you.\n"
"You might have me blocked or have DMs "
f"blocked globally or for {ctx.guild.name}.\n"
"Please resolve that, then "
"run the command again."
)
elif isinstance(error, commands.CommandNotFound):
# Nothing to do when command is not found.
return
help_text = f"Usage of this command is: ```{ctx.prefix}"\
f"{ctx.command.signature}```\nPlease see `{ctx.prefix}help "\
f"{ctx.command.name}` for more info about this command."
help_text = (
f"Usage of this command is: ```{ctx.prefix}"
f"{ctx.command.signature}```\nPlease see `{ctx.prefix}help "
f"{ctx.command.name}` for more info about this command."
)
if isinstance(error, commands.BadArgument):
return await ctx.send(f"{ctx.author.mention}: You gave incorrect "
f"arguments. {help_text}")
return await ctx.send(
f"{ctx.author.mention}: You gave incorrect " f"arguments. {help_text}"
)
elif isinstance(error, commands.MissingRequiredArgument):
return await ctx.send(f"{ctx.author.mention}: You gave incomplete "
f"arguments. {help_text}")
@bot.event
async def on_message(message):
if message.author.bot:
return
if (message.guild) and (message.guild.id not in config.guild_whitelist):
return
# Ignore messages in newcomers channel, unless it's potentially
# an allowed command
welcome_allowed = ["reset", "kick", "ban", "warn"]
if message.channel.id == config.welcome_channel and\
not any(cmd in message.content for cmd in welcome_allowed):
return
ctx = await bot.get_context(message)
await bot.invoke(ctx)
if not os.path.exists("data"):
os.makedirs("data")
return await ctx.send(
f"{ctx.author.mention}: You gave incomplete " f"arguments. {help_text}"
)
for wanted_json in wanted_jsons:
if not os.path.exists(wanted_json):
with open(wanted_json, "w") as f:
f.write("{}")
bot.run(config.token, bot=True, reconnect=True)

93
cogs/admin.py

@ -2,22 +2,18 @@ import discord
from discord.ext import commands
from discord.ext.commands import Cog
import traceback
import inspect
import re
import config
from helpers.checks import check_if_bot_manager
from helpers.userlogs import set_userlog
class Admin(Cog):
def __init__(self, bot):
self.bot = bot
self.last_eval_result = None
self.previous_eval_code = None
@commands.guild_only()
@commands.check(check_if_bot_manager)
@commands.command(name='exit', aliases=["quit", "bye", "stop", "kill", "restart", "die"])
@commands.command(
name="exit", aliases=["quit", "bye", "stop", "kill", "restart", "die"]
)
async def _exit(self, ctx):
"""Shuts down the bot, bot manager only."""
await ctx.send(":wave: Goodbye!")
@ -25,53 +21,15 @@ class Admin(Cog):
@commands.guild_only()
@commands.check(check_if_bot_manager)
@commands.command()
async def fetchlog(self, ctx):
"""Returns log"""
await ctx.send("Here's the current log file:",
file=discord.File(f"{self.bot.script_name}.log"))
@commands.guild_only()
@commands.check(check_if_bot_manager)
@commands.command()
async def fetchdata(self, ctx):
"""Returns data files"""
data_files = [discord.File(fpath) for fpath in self.bot.wanted_jsons]
await ctx.send("Here you go:", files=data_files)
@commands.guild_only()
@commands.check(check_if_bot_manager)
@commands.command(name='eval')
@commands.command(name="eval")
async def _eval(self, ctx):
await ctx.send("Fuck off. This doesn't belong in production code!")
async def cog_load_actions(self, cog_name):
if cog_name == "verification":
verif_channel = self.bot.get_channel(config.welcome_channel)
await self.bot.do_resetalgo(verif_channel, "cog load")
@commands.guild_only()
@commands.check(check_if_bot_manager)
@commands.command()
async def pull(self, ctx, auto=False):
"""Does a git pull, bot manager only."""
tmp = await ctx.send('Pulling...')
git_output = await self.bot.async_call_shell("git pull")
await tmp.edit(content=f"Pull complete. Output: ```{git_output}```")
if auto:
cogs_to_reload = re.findall(r'cogs/([a-z_]*).py[ ]*\|', git_output)
for cog in cogs_to_reload:
try:
self.bot.unload_extension("cogs." + cog)
self.bot.load_extension("cogs." + cog)
self.bot.log.info(f'Reloaded ext {cog}')
await ctx.send(f':white_check_mark: `{cog}` '
'successfully reloaded.')
await self.cog_load_actions(cog)
except:
await ctx.send(f':x: Cog reloading failed, traceback: '
f'```\n{traceback.format_exc()}\n```')
return
await ctx.send("Fuck off. This doesn't belong in production code! Bother Nichole instead.")
@commands.guild_only()
@commands.check(check_if_bot_manager)
@ -80,13 +38,14 @@ class Admin(Cog):
"""Loads a cog, bot manager only."""
try:
self.bot.load_extension("cogs." + ext)
await self.cog_load_actions(ext)
except:
await ctx.send(f':x: Cog loading failed, traceback: '
f'```\n{traceback.format_exc()}\n```')
await ctx.send(
f":x: Cog loading failed, traceback: "
f"```\n{traceback.format_exc()}\n```"
)
return
self.bot.log.info(f'Loaded ext {ext}')
await ctx.send(f':white_check_mark: `{ext}` successfully loaded.')
self.bot.log.info(f"Loaded ext {ext}")
await ctx.send(f":white_check_mark: `{ext}` successfully loaded.")
@commands.guild_only()
@commands.check(check_if_bot_manager)
@ -94,8 +53,8 @@ class Admin(Cog):
async def unload(self, ctx, ext: str):
"""Unloads a cog, bot manager only."""
self.bot.unload_extension("cogs." + ext)
self.bot.log.info(f'Unloaded ext {ext}')
await ctx.send(f':white_check_mark: `{ext}` successfully unloaded.')
self.bot.log.info(f"Unloaded ext {ext}")
await ctx.send(f":white_check_mark: `{ext}` successfully unloaded.")
@commands.check(check_if_bot_manager)
@commands.command()
@ -111,28 +70,14 @@ class Admin(Cog):
self.bot.load_extension("cogs." + ext)
await self.cog_load_actions(ext)
except:
await ctx.send(f':x: Cog reloading failed, traceback: '
f'```\n{traceback.format_exc()}\n```')
await ctx.send(
f":x: Cog reloading failed, traceback: "
f"```\n{traceback.format_exc()}\n```"
)
return
self.bot.log.info(f'Reloaded ext {ext}')
await ctx.send(f':white_check_mark: `{ext}` successfully reloaded.')
@commands.guild_only()
@commands.check(check_if_bot_manager)
@commands.command()
async def restoreuserlog(self, ctx, message_id: int):
"""Restores the user log from a saved backup."""
message = await self.bot.botlog_channel.fetch_message(message_id)
if message.author.id != self.bot.user.id or len(message.attachments) == 0:
await ctx.send("Incorrect Message ID.")
self.bot.log.info(f"Reloaded ext {ext}")
await ctx.send(f":white_check_mark: `{ext}` successfully reloaded.")
for attachment in message.attachments:
if attachment.filename == "userlog.json":
logs = (await attachment.read()).decode("utf-8")
set_userlog(logs)
return
await ctx.send("Incorrect Message ID.")
def setup(bot):
bot.add_cog(Admin(bot))

57
cogs/basic.py

@ -5,6 +5,7 @@ from discord.ext import commands
from discord.ext.commands import Cog
from helpers.checks import check_if_verified
class Basic(Cog):
def __init__(self, bot):
self.bot = bot
@ -17,64 +18,68 @@ class Basic(Cog):
await ctx.send(f"Hello {ctx.author.mention}!")
@commands.check(check_if_verified)
@commands.command(aliases=['aboutkosmos'])
@commands.command(aliases=["aboutkosmos"])
async def about(self, ctx):
"""Shows what kosmos is and what it includes"""
await ctx.send("Kosmos is a CFW bundle that comes with Atmosphere, Hekate, and some homebrew. You can see all the homebrew that is included here: https://github.com/AtlasNX/Kosmos#featuring")
await ctx.send(
"Kosmos is a CFW bundle that comes with Atmosphere, Hekate, and some homebrew. You can see all the homebrew that is included here: https://github.com/AtlasNX/Kosmos#featuring"
)
@commands.check(check_if_verified)
@commands.command(aliases=["fat32"])
async def exfat(self, ctx):
"""Displays a helpful message on why not to use exFAT"""
embed = discord.Embed(title="GUIFormat",
url="http://www.ridgecrop.demon.co.uk/guiformat.exe",
description="A useful tool for formatting SD cards over 32GB as FAT32 on Windows.")
message_text=("The exFAT drivers built into the Switch has been known "
"to corrupt SD cards and homebrew only makes this worse. "
"Backup everything on your SD card as soon as possible "
"and format it to FAT32. On Windows, if your SD card is "
"over 32GB then it will not let you select FAT32 from "
"the built-in format tool, however you can use a tool "
"like GUIFormat to format it.")
await ctx.send(content=message_text,
embed=embed)
embed = discord.Embed(
title="GUIFormat",
url="http://www.ridgecrop.demon.co.uk/guiformat.exe",
description="A useful tool for formatting SD cards over 32GB as FAT32 on Windows.",
)
message_text = (
"The exFAT drivers built into the Switch has been known "
"to corrupt SD cards and homebrew only makes this worse. "
"Backup everything on your SD card as soon as possible "
"and format it to FAT32. On Windows, if your SD card is "
"over 32GB then it will not let you select FAT32 from "
"the built-in format tool, however you can use a tool "
"like GUIFormat to format it."
)
await ctx.send(content=message_text, embed=embed)
@commands.guild_only()
@commands.check(check_if_verified)
@commands.command()
async def membercount(self, ctx):
"""Prints the member count of the server."""
await ctx.send(f"{ctx.guild.name} has "
f"{ctx.guild.member_count} members!")
await ctx.send(f"{ctx.guild.name} has " f"{ctx.guild.member_count} members!")
@commands.check(check_if_verified)
@commands.command(aliases=["robocopng", "robocop-ng", "komet", "komet-cl"])
async def robocop(self, ctx):
"""Shows a quick embed with bot info."""
embed = discord.Embed(title="Komet",
url=config.source_url,
description=config.embed_desc)
embed = discord.Embed(
title="Komet", url=config.source_url, description=config.embed_desc
)
embed.set_thumbnail(url=self.bot.user.avatar_url)
await ctx.send(embed=embed)
@commands.check(check_if_verified)
@commands.command(aliases=['p', "ddos"])
@commands.command(aliases=["p", "ddos"])
async def ping(self, ctx):
"""Shows ping values to discord.
RTT = Round-trip time, time taken to send a message to discord
GW = Gateway Ping"""
before = time.monotonic()
tmp = await ctx.send('Calculating ping...')
tmp = await ctx.send("Calculating ping...")
after = time.monotonic()
rtt_ms = (after - before) * 1000
gw_ms = self.bot.latency * 1000
message_text = f":ping_pong:\n"\
f"rtt: `{rtt_ms:.1f}ms`\n"\
f"gw: `{gw_ms:.1f}ms`"
message_text = (
f":ping_pong:\n" f"rtt: `{rtt_ms:.1f}ms`\n" f"gw: `{gw_ms:.1f}ms`"
)
self.bot.log.info(message_text)
await tmp.edit(content=message_text)

95
cogs/common.py

@ -7,6 +7,7 @@ import math
import parsedatetime
from discord.ext.commands import Cog
class Common(Cog):
def __init__(self, bot):
self.bot = bot
@ -30,9 +31,14 @@ class Common(Cog):
res_timestamp = math.floor(time.mktime(time_struct))
return res_timestamp
def get_relative_timestamp(self, time_from=None, time_to=None,
humanized=False, include_from=False,
include_to=False):
def get_relative_timestamp(
self,
time_from=None,
time_to=None,
humanized=False,
include_from=False,
include_to=False,
):
# Setting default value to utcnow() makes it show time from cog load
# which is not what we want
if not time_from:
@ -42,17 +48,19 @@ class Common(Cog):
if humanized:
humanized_string = humanize.naturaltime(time_from - time_to)
if include_from and include_to:
str_with_from_and_to = f"{humanized_string} "\
f"({str(time_from).split('.')[0]} "\
f"- {str(time_to).split('.')[0]})"
str_with_from_and_to = (
f"{humanized_string} "
f"({str(time_from).split('.')[0]} "
f"- {str(time_to).split('.')[0]})"
)
return str_with_from_and_to
elif include_from:
str_with_from = f"{humanized_string} "\
f"({str(time_from).split('.')[0]})"
str_with_from = (
f"{humanized_string} " f"({str(time_from).split('.')[0]})"
)
return str_with_from
elif include_to:
str_with_to = f"{humanized_string} "\
f"({str(time_to).split('.')[0]})"
str_with_to = f"{humanized_string} " f"({str(time_to).split('.')[0]})"
return str_with_to
return humanized_string
else:
@ -60,8 +68,7 @@ class Common(Cog):
epoch_from = (time_from - epoch).total_seconds()
epoch_to = (time_to - epoch).total_seconds()
second_diff = epoch_to - epoch_from
result_string = str(datetime.timedelta(
seconds=second_diff)).split('.')[0]
result_string = str(datetime.timedelta(seconds=second_diff)).split(".")[0]
return result_string
async def aioget(self, url):
@ -72,11 +79,12 @@ class Common(Cog):
self.bot.log.info(f"Data from {url}: {text_data}")
return text_data
else:
self.bot.log.error(f"HTTP Error {data.status} "
"while getting {url}")
self.bot.log.error(f"HTTP Error {data.status} " "while getting {url}")
except:
self.bot.log.error(f"Error while getting {url} "
f"on aiogetbytes: {traceback.format_exc()}")
self.bot.log.error(
f"Error while getting {url} "
f"on aiogetbytes: {traceback.format_exc()}"
)
async def aiogetbytes(self, url):
try:
@ -86,11 +94,12 @@ class Common(Cog):
self.bot.log.debug(f"Data from {url}: {byte_data}")
return byte_data
else:
self.bot.log.error(f"HTTP Error {data.status} "
"while getting {url}")
self.bot.log.error(f"HTTP Error {data.status} " "while getting {url}")
except:
self.bot.log.error(f"Error while getting {url} "
f"on aiogetbytes: {traceback.format_exc()}")
self.bot.log.error(
f"Error while getting {url} "
f"on aiogetbytes: {traceback.format_exc()}"
)
async def aiojson(self, url):
try:
@ -98,18 +107,19 @@ class Common(Cog):
if data.status == 200:
text_data = await data.text()
self.bot.log.info(f"Data from {url}: {text_data}")
content_type = data.headers['Content-Type']
content_type = data.headers["Content-Type"]
return await data.json(content_type=content_type)
else:
self.bot.log.error(f"HTTP Error {data.status} "
"while getting {url}")
self.bot.log.error(f"HTTP Error {data.status} " "while getting {url}")
except:
self.bot.log.error(f"Error while getting {url} "
f"on aiogetbytes: {traceback.format_exc()}")
self.bot.log.error(
f"Error while getting {url} "
f"on aiogetbytes: {traceback.format_exc()}"
)
def hex_to_int(self, color_hex: str):
"""Turns a given hex color into an integer"""
return int("0x" + color_hex.strip('#'), 16)
return int("0x" + color_hex.strip("#"), 16)
def escape_message(self, text: str):
"""Escapes unfun stuff from messages"""
@ -129,10 +139,12 @@ class Common(Cog):
"""Slices a message into multiple messages"""
if len(text) > size * self.max_split_length:
haste_url = await self.haste(text)
return [f"Message is too long ({len(text)} > "
f"{size * self.max_split_length} "
f"({size} * {self.max_split_length}))"
f", go to haste: <{haste_url}>"]
return [
f"Message is too long ({len(text)} > "
f"{size * self.max_split_length} "
f"({size} * {self.max_split_length}))"
f", go to haste: <{haste_url}>"
]
reply_list = []
size_wo_fix = size - len(prefix) - len(suffix)
while len(text) > size_wo_fix:
@ -141,28 +153,28 @@ class Common(Cog):
reply_list.append(f"{prefix}{text}{suffix}")
return reply_list
async def haste(self, text, instance='https://mystb.in/'):
response = await self.bot.aiosession.post(f"{instance}documents",
data=text)
async def haste(self, text, instance="https://mystb.in/"):
response = await self.bot.aiosession.post(f"{instance}documents", data=text)
if response.status == 200:
result_json = await response.json()
return f"{instance}{result_json['key']}"
else:
return f"Error {response.status}: {response.text}"
async def async_call_shell(self, shell_command: str,
inc_stdout=True, inc_stderr=True):
async def async_call_shell(
self, shell_command: str, inc_stdout=True, inc_stderr=True
):
pipe = asyncio.subprocess.PIPE
proc = await asyncio.create_subprocess_shell(str(shell_command),
stdout=pipe,
stderr=pipe)
proc = await asyncio.create_subprocess_shell(
str(shell_command), stdout=pipe, stderr=pipe
)
if not (inc_stdout or inc_stderr):
return "??? you set both stdout and stderr to False????"
proc_result = await proc.communicate()
stdout_str = proc_result[0].decode('utf-8').strip()
stderr_str = proc_result[1].decode('utf-8').strip()
stdout_str = proc_result[0].decode("utf-8").strip()
stderr_str = proc_result[1].decode("utf-8").strip()
if inc_stdout and not inc_stderr:
return stdout_str
@ -170,8 +182,7 @@ class Common(Cog):
return stderr_str
if stdout_str and stderr_str:
return f"stdout:\n\n{stdout_str}\n\n"\
f"======\n\nstderr:\n\n{stderr_str}"
return f"stdout:\n\n{stdout_str}\n\n" f"======\n\nstderr:\n\n{stderr_str}"
elif stdout_str:
return f"stdout:\n\n{stdout_str}"
elif stderr_str:

196
cogs/err.py

@ -1,196 +0,0 @@
import re
import discord
from discord.ext import commands
from discord.ext.commands import Cog
from helpers.checks import check_if_verified
from helpers.errcodes import *
class Err(Cog):
"""Everything related to Nintendo 3DS, Wii U and Switch error codes"""
def __init__(self, bot):
self.bot = bot
self.dds_re = re.compile(r'0\d{2}\-\d{4}')
self.wiiu_re = re.compile(r'1\d{2}\-\d{4}')
self.switch_re = re.compile(r'2\d{3}\-\d{4}')
self.no_err_desc = "It seems like your error code is unknown. "\
"You should report relevant details to "\
"<@141532589725974528> (tomGER#7462) "\
"so it can be added to the bot."
self.rickroll = "https://www.youtube.com/watch?v=4uj896lr3-E"
@commands.check(check_if_verified)
@commands.command(aliases=["3dserr", "3err", "dserr"])
async def dderr(self, ctx, err: str):
"""Searches for 3DS error codes!
Usage: .ddserr/.3err/.dserr/.3dserr <Error Code>"""
if self.dds_re.match(err): # 3DS - dds -> Drei DS -> Three DS
if err in dds_errcodes:
err_description = dds_errcodes[err]
else:
err_description = self.no_err_desc
# Make a nice Embed out of it
embed = discord.Embed(title=err,
url=self.rickroll,
description=err_description)
embed.set_footer(text="Console: 3DS")
# Send message, crazy
await ctx.send(embed=embed)
# These are not similar to the other errors apparently ... ?
elif err.startswith("0x"):
derr = err[2:]
derr = derr.strip()
rc = int(derr, 16)
desc = rc & 0x3FF
mod = (rc >> 10) & 0xFF
summ = (rc >> 21) & 0x3F
level = (rc >> 27) & 0x1F
embed = discord.Embed(title=f"0x{rc:X}")
embed.add_field(name="Module", value=dds_modules.get(mod, mod))
embed.add_field(name="Description",
value=dds_descriptions.get(desc, desc))
embed.add_field(name="Summary", value=dds_summaries.get(summ, summ))
embed.add_field(name="Level", value=dds_levels.get(level, level))
embed.set_footer(text="Console: 3DS")
await ctx.send(embed=embed)
return
else:
await ctx.send("Unknown Format - This is either "
"no error code or you made some mistake!")
@commands.check(check_if_verified)
@commands.command(aliases=["wiiuserr", "uerr", "wuerr", "mochaerr"])
async def wiiuerr(self, ctx, err: str):
"""Searches for Wii U error codes!
Usage: .wiiuserr/.uerr/.wuerr/.mochaerr <Error Code>"""
if self.wiiu_re.match(err): # Wii U
module = err[2:3] # Is that even true, idk just guessing
desc = err[5:8]
if err in wii_u_errors:
err_description = wii_u_errors[err]
else:
err_description = self.no_err_desc
# Make a nice Embed out of it
embed = discord.Embed(title=err,
url=self.rickroll,
description=err_description)
embed.set_footer(text="Console: Wii U")
embed.add_field(name="Module", value=module, inline=True)
embed.add_field(name="Description", value=desc, inline=True)
# Send message, crazy
await ctx.send(embed=embed)
else:
await ctx.send("Unknown Format - This is either "
"no error code or you made some mistake!")
@commands.check(check_if_verified)
@commands.command(aliases=["nxerr", "serr"])
async def err(self, ctx, err: str):
"""Searches for Switch error codes!
Usage: .serr/.nxerr/.err <Error Code>"""
if self.switch_re.match(err) or err.startswith("0x"): # Switch
if err.startswith("0x"):
err = err[2:]
errcode = int(err, 16)
module = errcode & 0x1FF
desc = (errcode >> 9) & 0x3FFF
else:
module = int(err[0:4]) - 2000
desc = int(err[5:9])
errcode = (desc << 9) + module
str_errcode = f'{(module + 2000):04}-{desc:04}'
# Searching for Modules in list
if module in switch_modules:
err_module = switch_modules[module]
else:
err_module = "Unknown"
# Set initial value unconditionally
err_description = self.no_err_desc
# Searching for error codes related to the Switch
# (doesn't include special cases)
if errcode in switch_known_errcodes:
err_description = switch_known_errcodes[errcode]
elif errcode in switch_support_page:
err_description = switch_support_page[errcode]
elif module in switch_known_errcode_ranges:
for errcode_range in switch_known_errcode_ranges[module]:
if desc >= errcode_range[0] and desc <= errcode_range[1]:
err_description = errcode_range[2]
# Make a nice Embed out of it
embed = discord.Embed(title=f"{str_errcode} / {hex(errcode)}",
url=self.rickroll,
description=err_description)
embed.add_field(name="Module",
value=f"{err_module} ({module})",
inline=True)
embed.add_field(name="Description", value=desc, inline=True)
if "ban" in err_description:
embed.set_footer("F to you | Console: Switch")
else:
embed.set_footer(text="Console: Switch")
await ctx.send(embed=embed)
# Special case handling because Nintendo feels like
# its required to break their format lol
elif err in switch_game_err:
game, desc = switch_game_err[err].split(":")
embed = discord.Embed(title=err,
url=self.rickroll,
description=desc)
embed.set_footer(text="Console: Switch")
embed.add_field(name="Game", value=game, inline=True)
await ctx.send(embed=embed)
else:
await ctx.send("Unknown Format - This is either "
"no error code or you made some mistake!")
@commands.check(check_if_verified)
@commands.command(aliases=["e2h"])
async def err2hex(self, ctx, err: str):
"""Converts Nintendo Switch errors to hex
Usage: .err2hex <Error Code>"""
if self.switch_re.match(err):
module = int(err[0:4]) - 2000
desc = int(err[5:9])
errcode = (desc << 9) + module
await ctx.send(hex(errcode))
else:
await ctx.send("This doesn't follow the typical"
" Nintendo Switch 2XXX-XXXX format!")
@commands.check(check_if_verified)
@commands.command(aliases=["h2e"])
async def hex2err(self, ctx, err: str):
"""Converts Nintendo Switch errors to hex
Usage: .hex2err <Hex>"""
if err.startswith("0x"):
err = err[2:]
err = int(err, 16)
module = err & 0x1FF
desc = (err >> 9) & 0x3FFF
errcode = f'{(module + 2000):04}-{desc:04}'
await ctx.send(errcode)
else:
await ctx.send("This doesn't look like typical hex!")
def setup(bot):
bot.add_cog(Err(bot))

43
cogs/invites.py

@ -1,43 +0,0 @@
from discord.ext import commands
from discord.ext.commands import Cog
from helpers.checks import check_if_collaborator
import config
import json
class Invites(Cog):
def __init__(self, bot):
self.bot = bot
@commands.command()
@commands.guild_only()
@commands.check(check_if_collaborator)
async def invite(self, ctx):
welcome_channel = self.bot.get_channel(config.welcome_channel)
author = ctx.message.author
reason = f"Created by {str(author)} ({author.id})"
invite = await welcome_channel.create_invite(max_age = 0,
max_uses = 1, temporary = True, unique = True, reason = reason)
with open("data/invites.json", "r") as f:
invites = json.load(f)
invites[invite.id] = {
"uses": 0,
"url": invite.url,
"max_uses": 1,
"code": invite.code
}
with open("data/invites.json", "w") as f:
f.write(json.dumps(invites))
await ctx.message.add_reaction("๐Ÿ†—")
try:
await ctx.author.send(f"Created single-use invite {invite.url}")
except discord.errors.Forbidden:
await ctx.send(f"{ctx.author.mention} I could not send you the \
invite. Send me a DM so I can reply to you.")
def setup(bot):
bot.add_cog(Invites(bot))

74
cogs/links.py

@ -4,6 +4,7 @@ from discord.ext import commands
from discord.ext.commands import Cog
from helpers.checks import check_if_verified
class Links(Cog):
"""
Commands for easily linking to projects.
@ -28,65 +29,45 @@ class Links(Cog):
@commands.command(hidden=True, aliases=["bootloader"])
async def hekate(self, ctx):
"""Link to the Hekate repo"""
await ctx.send("https://github.com/CTCaer/hekate")
await ctx.send("https://github.com/CTCaer/hekate")
@commands.check(check_if_verified)
@commands.command(hidden=True, aliases=["xyproblem"])
async def xy(self, ctx):
"""Link to the "What is the XY problem?" post from SE"""
await ctx.send("<https://meta.stackexchange.com/q/66377/285481>\n\n"
"TL;DR: It's asking about your attempted solution "
"rather than your actual problem.\n"
"It's perfectly okay to want to learn about a "
"solution, but please be clear about your intentions "
"if you're not actually trying to solve a problem.")
await ctx.send(
"<https://meta.stackexchange.com/q/66377/285481>\n\n"
"TL;DR: It's asking about your attempted solution "
"rather than your actual problem.\n"
"It's perfectly okay to want to learn about a "
"solution, but please be clear about your intentions "
"if you're not actually trying to solve a problem."
)
@commands.check(check_if_verified)
@commands.command(hidden=True, aliases=["guides", "link"])
async def guide(self, ctx):
"""Link to the guide(s)"""
message_text=("**Generic starter guides:**\n"
"AtlasNX's Guide: "
"<https://switch.homebrew.guide>\n"
"\n"
"**Specific guides:**\n"
"Manually Updating/Downgrading (with HOS): "
"<https://switch.homebrew.guide/usingcfw/manualupgrade>\n"
"Manually Repairing/Downgrading (without HOS): "
"<https://switch.homebrew.guide/usingcfw/manualchoiupgrade>\n"
"How to get started developing Homebrew: "
"<https://switch.homebrew.guide/homebrew_dev/introduction>\n"
"\n")
try:
support_faq_channel = self.bot.get_channel(config.support_faq_channel)
if support_faq_channel is None:
message_text += "Check out #support-faq for additional help."
else:
message_text += f"Check out {support_faq_channel.mention} for additional help."
except AttributeError:
message_text += "Check out #support-faq for additional help."
await ctx.send(message_text)
@commands.check(check_if_verified)
@commands.command(hidden=True, aliases=["patron"])
async def patreon(self, ctx):
"""Link to the patreon"""
await ctx.send("https://patreon.teamatlasnx.com")
@commands.check(check_if_verified)
@commands.command(hidden=True, aliases=["coffee"])
async def kofi(self, ctx):
"""Link to Ko-fi"""
await ctx.send("https://kofi.teamatlasnx.com")
await ctx.send(
"**Generic starter guides:**\n"
"SDSetup Guide: "
"<https://switch.homebrew.guide>\n"
"\n"
"**Specific guides:**\n"
"Manually Updating/Downgrading (with HOS): "
"<https://switch.homebrew.guide/usingcfw/manualupgrade>\n"
"Manually Repairing/Downgrading (without HOS): "
"<https://switch.homebrew.guide/usingcfw/manualchoiupgrade>\n"
"How to get started developing Homebrew: "
"<https://switch.homebrew.guide/homebrew_dev/introduction>"
)
@commands.check(check_if_verified)
@commands.command(hidden=True, aliases=["sdfiles"])
async def kosmos(self, ctx):
"""Link to the latest Kosmos release"""
await ctx.send("https://github.com/AtlasNX/Kosmos/releases/latest")
await ctx.send("https://github.com/Team-Neptune/DeepSea/releases/latest")
@commands.check(check_if_verified)
@commands.command(hidden=True, aliases=["sd"])
@ -98,8 +79,11 @@ class Links(Cog):
@commands.command()
async def source(self, ctx):
"""Gives link to source code."""
await ctx.send(f"You can find my source at {config.source_url}. "
"Serious PRs and issues welcome!")
await ctx.send(
f"You can find my source at {config.source_url}. "
"Serious PRs and issues welcome!"
)
def setup(bot):
bot.add_cog(Links(bot))

30
cogs/lists.py

@ -209,22 +209,6 @@ class Lists(Cog):
mod_cog, ctx=ctx, target=target, reason=f"Rule {number} - {reason}"
)
@commands.guild_only()
@commands.check(check_if_verified)
@commands.command(aliases=["faq"])
async def support(self, ctx, number: int):
"""Link to a specific list item in #support-faq"""
channel = ctx.guild.get_channel(config.support_faq_channel)
await self.link_list_item(ctx, channel, number)
@commands.guild_only()
@commands.check(check_if_verified)
@commands.command(aliases=["es", "fs", "acid", "piracy"])
async def patches(self, ctx):
"""Link to the list item in #support-faq about patches"""
channel = ctx.guild.get_channel(config.support_faq_channel)
await self.link_list_item(ctx, channel, 1)
# Listeners
@Cog.listener()
@ -324,7 +308,7 @@ class Lists(Cog):
await message.delete()
return
log_channel = self.bot.get_channel(config.log_channel)
botlog_channel = self.bot.get_channel(config.botlog_channel)
channel = message.channel
content = message.content
user = message.author
@ -363,7 +347,7 @@ class Lists(Cog):
for reaction in reactions:
await reaction.remove(user)
await log_channel.send(
await botlog_channel.send(
self.create_log_message("๐Ÿ’ฌ", "List item added:", user, channel)
)
return
@ -377,14 +361,14 @@ class Lists(Cog):
await targeted_message.edit(content=content)
await targeted_reaction.remove(user)
await log_channel.send(
await botlog_channel.send(
self.create_log_message("๐Ÿ“", "List item edited:", user, channel)
)
elif self.is_delete(targeted_reaction):
await targeted_message.delete()
await log_channel.send(
await botlog_channel.send(
self.create_log_message(
"โŒ", "List item deleted:", user, channel, content
)
@ -403,7 +387,7 @@ class Lists(Cog):
for message in messages:
await self.send_cached_message(channel, message)
await log_channel.send(
await botlog_channel.send(
self.create_log_message(
"โ™ป", "List item recycled:", user, channel, content
)
@ -430,7 +414,7 @@ class Lists(Cog):
for message in messages:
await self.send_cached_message(channel, message)
await log_channel.send(
await botlog_channel.send(
self.create_log_message("๐Ÿ’ฌ", "List item added:", user, channel)
)
@ -457,7 +441,7 @@ class Lists(Cog):
for message in messages:
await self.send_cached_message(channel, message)
await log_channel.send(
await botlog_channel.send(
self.create_log_message("๐Ÿ’ฌ", "List item added:", user, channel)
)

263
cogs/lists_verification.py

@ -1,263 +0,0 @@
import asyncio
import config
import discord
from discord.ext import commands
from discord.ext.commands import Cog
from helpers.checks import check_if_staff
import io
import os
import random
import re
class ListsVerification(Cog):
def __init__(self, bot):
self.bot = bot
self.verification = ""
if os.path.exists("data/verification.txt"):
with open("data/verification.txt", "r") as f:
self.verification = f.read()
bot.loop.create_task(self.daily())
def generate_verification_phrase(self):
random_words = [
"colony",
"carriage",
"be",
"employee",
"empirical",
"flourish",
"moral",
"troop",
"waterfall",
"reduction",
"fraction",
"goalkeeper",
"conscious",
"acceptable",
"advertising",
"visual",
"spin",
"margin",
"greeting",
"continuation",
"sandwich",
"upset",
"stake",
"safe",
"rally",
"reservoir",
"effort",
"integration",
"extent",
"expression",
"echo",
"prove",
"precedent",
"inhibition",
"expect",
"theft",
"distinct",
"part",
"revolution",
"player",
"fragrant",
"waste",
"value",
"profession",
"quote",
"room",
"master",
"utter",
"aloof",
"quantity",
]
self.verification = (
random.choice(random_words)
+ "_"
+ random.choice(random_words)
+ "_"
+ random.choice(random_words)
)
with open("data/verification.txt", "w") as f:
f.write(self.verification)
async def reset_verification_channel(self, rules_channel, verification_channel):
self.generate_verification_phrase()
# Get all the rules from the rules channel.
rules_messages = []
number_of_rules = 0
async for message in rules_channel.history(limit=None, oldest_first=True):
if len(message.content.strip()) != 0:
number_of_rules += 1
rules_messages.append(message)
if number_of_rules == 0:
return
# Randomly choose which rule to inject the hidden message in.
random_rule = 0
if number_of_rules != 1:
if number_of_rules < 2:
random_rule = random.randint(0, number_of_rules - 1)
else:
# Don't include the first or last rule.
random_rule = random.randint(1, number_of_rules - 2)
# Delete all messages from the welcome channel.
await verification_channel.purge(limit=None)
# Put all rules in the welcome channel.
i = 0
for message in rules_messages:
content = message.content
if content.strip():
i += 1
if i == random_rule:
# Find all of the sentences in the random rule.
matches = list(re.finditer(r"[.|!|?][\W]*\s*", content))
# Randomly choose where to put the random message in our random rule.
random_sentence = 0
if len(matches) != 1:
random_sentence = random.randint(0, len(matches) - 1)
# Insert our verification text.
pos = matches[random_sentence].end()
content = (
content[:pos]
+ f' When you have finished reading all of the rules, send a message in this channel that includes "{self.verification}", and the bot will automatically grant you access to the other channels. '
+ content[pos:]
)
message_file = None
if len(message.attachments) != 0:
# Lists will only reupload a single image per message.
attachment = next(
(
a
for a in message.attachments
if os.path.splitext(a.filename)[1] in [".png", ".jpg", ".jpeg"]
),
None,
)
if attachment is not None:
message_file = discord.File(
io.BytesIO(await attachment.read()),
filename=attachment.filename,
)
await verification_channel.send(content=content, file=message_file)
# Commands
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command()
async def reset(self, ctx):
"""Resets the verification channel with the latest rules"""
rules_channel_id = getattr(config, "rules_channel", 0)
verification_channel_id = getattr(config, "verification_channel", 0)
rules_channel = None
if rules_channel_id != 0:
rules_channel = self.bot.get_channel(rules_channel_id)
verification_channel = None
if verification_channel_id != 0:
verification_channel = self.bot.get_channel(verification_channel_id)
if rules_channel is not None and verification_channel is not None:
await self.reset_verification_channel(rules_channel, verification_channel)
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command()
async def verifyall(self, ctx):
"""Gives everyone the verification role"""
verified_role = ctx.guild.get_role(config.verified_role)
for member in ctx.guild.members:
if verified_role not in member.roles:
await member.add_roles(verified_role)
await ctx.send("All members verified.")
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command()
async def verifiedcount(self, ctx):
"""Prints the number of verified members"""
verified_role = ctx.guild.get_role(config.verified_role)
await ctx.send(
f"{ctx.guild.name} has " f"{len(verified_role.members)} verified members!"
)
# Listeners
@Cog.listener()
async def on_message(self, message):
await self.bot.wait_until_ready()
if not hasattr(config, "verification_channel"):
return
# We only care about messages in Rules, and Support FAQ
if message.channel.id != config.verification_channel:
return
# We don't care about messages from bots.
if message.author.bot:
return
await message.delete()
# We only care if the message contained the verification phrase.
if self.verification not in message.content:
return
# Grant user the verified role.
verified_role = message.guild.get_role(config.verified_role)
await message.author.add_roles(verified_role)
# Tasks
async def daily(self):
await self.bot.wait_until_ready()
if (
not hasattr(config, "log_channel")
or not hasattr(config, "rules_channel")
or not hasattr(config, "verification_channel")
):
return
log_channel = self.bot.get_channel(config.log_channel)
rules_channel = self.bot.get_channel(config.rules_channel)
verification_channel = self.bot.get_channel(config.verification_channel)
# Make sure the bot is open.
while not self.bot.is_closed():
# Reset the verification channel
try:
await self.reset_verification_channel(
rules_channel, verification_channel
)
except:
await log_channel.send(
"Verification reset has errored: ```" f"{traceback.format_exc()}```"
)
# Wait 1 day
await asyncio.sleep(86400)
def setup(bot):
bot.add_cog(ListsVerification(bot))

90
cogs/lockdown.py

@ -1,90 +0,0 @@
from discord.ext import commands
from discord.ext.commands import Cog
import config
import discord
from helpers.checks import check_if_staff
class Lockdown(Cog):
def __init__(self, bot):
self.bot = bot