class Code(Category): # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Class Fields # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # MAX_BRAINFUCK_LENGTH = 2**15 # 32736 QR_API_CALL = "https://api.qrserver.com/v1/create-qr-code/?size={0}x{0}&data={1}" MORSE_API_CALL = "https://www.fellowhashbrown.com/api/morse/{}?text={}" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Errors # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # BASE_MISMATCH = "BASE_MISMATCH" BASE_OUT_OF_RANGE = "BASE_OUT_OF_RANGE" INVALID_LANGUAGE = "INVALID_LANGUAGE" INVALID_BASE = "INVALID_BASE" INVALID_PARAMETER = "INVALID_PARAMETER" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Constructor # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def __init__(self, client): super().__init__(client, "Code", description="Commands that have to do with coding!", embed_color=0xFFFF00, locally_inactive_error=Server.getInactiveError, globally_inactive_error=OmegaPsi.getInactiveError, locally_active_check=Server.isCommandActive, globally_active_check=OmegaPsi.isCommandActive) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Commands self._brainfuck = Command( commandDict={ "alternatives": ["brainf", "bf"], "info": "Runs brainfuck code. Kinda confusing stuff at first glance.", "min_parameters": 1, "parameters": { "code": { "optional": False, "info": "The code to run." }, "parameters": { "optional": True, "info": "The parameters to use in the code." } }, "errors": { Code.NOT_ENOUGH_PARAMETERS: { "messages": [ "The brainfuck command requires at least the brainfuck code." ] }, Code.TOO_MANY_PARAMETERS: { "messages": [ "The brainfuck command only needs the code and the parameters. Make sure you remove spaces from both." ] } }, "command": self.brainfuck }) self._convert = Command( commandDict={ "alternatives": ["convert", "conversion", "baseConversion", "baseConverter"], "info": "Converts a number from one base to another base.", "min_parameters": 2, "max_parameters": 3, "parameters": { "startBase": { "info": "The base the number starts at.", "optional": True }, "endBase": { "info": "The base the number ends at.", "optional": False }, "number": { "info": "The number to convert.", "optional": False } }, "errors": { Code.NOT_ENOUGH_PARAMETERS: { "messages": [ "You need at least the end base and the number to convert." ] }, Code.TOO_MANY_PARAMETERS: { "messages": [ "You only need the start base, the end base, and the number." ] }, Code.INVALID_BASE: { "messages": ["A base you entered is not a valid base."] }, Code.BASE_MISMATCH: { "messages": [ "The number you entered does not match the start base." ] } }, "command": self.convert }) self._base64 = Command( commandDict={ "alternatives": ["base64", "b64"], "info": "Encodes or decodes text to base64.", "min_parameters": 2, "parameters": { "conversion": { "info": "Whether to encode/decode text into/from base64.", "optional": False, "accepted_parameters": { "encode": { "alternatives": ["encode", "enc", "e"], "info": "Encode text into base64." }, "decode": { "alternatives": ["decode", "dec", "d"], "info": "Decode text from base64." } } }, "text": { "info": "The text to encode or decode.", "optional": False } }, "errors": { Code.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to encode or decode text, you need the conversion type and the text." ] }, Code.INVALID_PARAMETER: { "messages": ["That is not a valid conversion type."] } }, "command": self.base64 }) self._morse = Command( commandDict={ "alternatives": ["morse", "m"], "info": "Encodes or decodes text to Morse code.", "parameters": { "conversion": { "info": "Whether to encode/decode text into/from Morse Code.", "optional": False, "accepted": { "encode": { "alternatives": ["encode", "enc", "e"], "info": "Encodes text into Morse Code." }, "decode": { "alternatives": ["decode", "dec", "d"], "info": "Decodes text from Morse Code." } } }, "text": { "info": "The text to encode or decode.", "optional": False } }, "errors": { Code.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to encode or decode text, you need the conversion type and the text." ] }, Code.INVALID_PARAMETER: { "messages": ["That is not a valid conversion type."] } }, "command": self.morse }) self._qrCode = Command( commandDict={ "alternatives": ["qrCode", "qr"], "info": "Turns text into a QR code.", "parameters": { "data": { "info": "The data to set for the QR code.", "optional": False } }, "errors": { Code.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to get the QR code for data, you need to type in the data." ] } }, "command": self.qrCode }) self.setCommands([ self._brainfuck, self._convert, self._base64, self._morse, self._qrCode ]) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Command Methods # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def __brainfuck(self, code, parameters): # Keep track of pointers and data data = [0] * Code.MAX_BRAINFUCK_LENGTH dataPointer = 0 paramPointer = 0 output = "" loop = 0 # Iterate through code char = 0 while char < len(code): # char is > (move pointer right) if code[char] == ">": dataPointer = 0 if dataPointer == Code.MAX_BRAINFUCK_LENGTH - 1 else dataPointer + 1 # char is < (move pointer left) elif code[char] == "<": dataPointer = Code.MAX_BRAINFUCK_LENGTH - 1 if dataPointer == 0 else dataPointer - 1 # char is + (increase value at pointer) elif code[char] == "+": data[dataPointer] += 1 if data[dataPointer] > 255: data[dataPointer] -= 256 # char is - (decrease value at pointer) elif code[char] == "-": data[dataPointer] -= 1 if data[dataPointer] < 0: data[dataPointer] += 256 # char is . (add data to output) elif code[char] == ".": output += str(chr(data[dataPointer])) # char is , (add data to input) elif code[char] == ",": if paramPointer >= len(parameters): data[dataPointer] = 0 else: data[dataPointer] = ord(parameters[paramPointer]) paramPointer += 1 # char is [ (open loop) elif code[char] == "[": if data[dataPointer] == 0: char += 1 while loop > 0 or code[char] != "]": if code[char] == "[": loop += 1 if code[char] == "]": loop -= 1 char += 1 # char is ] (close loop) elif code[char] == "]": if data[dataPointer] != 0: char -= 1 while loop > 0 or code[char] != "[": if code[char] == "]": loop += 1 if code[char] == "[": loop -= 1 char -= 1 char -= 1 char += 1 return output async def brainfuck(self, message, parameters): """Runs brainfuck code and returns the result.\n Parameters: code: The brainfuck code to run.\n parameters: The parameters to insert into the brainfuck code.\n """ # Check for not enough parameters if len(parameters) < self._brainfuck.getMinParameters(): embed = getErrorMessage(self._brainfuck, Code.NOT_ENOUGH_PARAMETERS) # Check for too many parameters elif len(parameters) > self._brainfuck.getMaxParameters(): embed = getErrorMessage(self._brainfuck, Code.TOO_MANY_PARAMETERS) # There were a proper amount of parameters else: code = parameters[0] if len(parameters) == 2: parameters = parameters[1] else: parameters = [] # Remove all invalid symbols validSymbols = "<>+-.,[]" newCode = "" for char in code: if char in validSymbols: newCode += char code = newCode try: async with async_timeout.timeout(5): description = await loop.run_in_executor( None, self.__brainfuck, code, parameters) except: description = "Timed out" # Create and return embed for result embed = discord.Embed(title="Result", description=description, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def convert(self, message, parameters): """Converts a number from the start base to the end base.\n Parameters: startBase: The base to convert from.\n endBase: The base to convert to.\n number: The number to convert.\n """ # Check for not enough parameters if len(parameters) < self._convert.getMinParameters(): embed = getErrorMessage(self._convert, Code.NOT_ENOUGH_PARAMETERS) # Check for too many parameters elif len(parameters) > self._convert.getMaxParameters(): embed = getErrorMessage(self._convert, Code.TOO_MANY_PARAMETERS) # There were the proper amount of parameters else: startBase = "10" endBase = parameters[0] number = parameters[1] if len(parameters) == 3: startBase = parameters[0] endBase = parameters[1] number = parameters[2] # Only run if start base and end base are valid if startBase.isdigit() and endBase.isdigit(): startBase = int(startBase) endBase = int(endBase) if startBase >= 2 and startBase <= 64 and endBase >= 2 and endBase <= 64: # Try converting number from startBase to base-10 # Test to see if number is not zero start = number title = "Base-{} to Base-{}".format(startBase, endBase) description = "`{} --> {}`".format(start, number) # Check if number is not zero; Convert it if number not in ["0", 0]: number = convert(number, startBase, endBase) # Check if number is None; Invalid number for a base if number == None: embed = getErrorMessage(self._convert, Code.BASE_MISMATCH) # Number is not None; Valid base else: # Return number description = "`{} --> {}`".format(start, number) embed = discord.Embed( title=title, description=description, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) # Number is zero; Just send that else: embed = discord.Embed( title=title, description=description, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) # Bases were not within range else: embed = getErrorMessage(self._convert, Code.BASE_OUT_OF_RANGE) # Bases were not numbers else: embed = getErrorMessage(self._convert, Code.INVALID_BASE) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def base64(self, message, parameters): """Encodes or decodes text to or from base64.\n Parameters: conversionType: Whether to encode or decode text.\n text: The text to encode or decode.\n """ # Check for not enough parameters if len(parameters) < self._base64.getMinParameters(): embed = getErrorMessage(self._base64, Code.NOT_ENOUGH_PARAMETERS) # There were enough parameters else: # Conversion type is first parameter; Text is all parameters after conversionType = parameters[0] text = " ".join(parameters[1:]) # Conversion is Encode if conversionType in self._base64.getAcceptedParameter( "conversion", "encode").getAlternatives(): converted = base64.b64encode(text.encode()).decode() encoded = True embed = discord.Embed( title="`{}` {} Base64".format( text if len(text) < 180 else "[text is greater than 200 characters]", "encoded to" if encoded else "decoded from"), description=converted, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) # Conversion is Decode elif conversionType in self._base64.getAcceptedParameter( "conversion", "decode").getAlternatives(): converted = base64.b64decode(text.encode()).decode() encoded = False embed = discord.Embed( title="`{}` {} Base64".format( text if len(text) < 180 else "[text is greater than 200 characters]", "encoded to" if encoded else "decoded from"), description=converted, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) # Conversion is Invalid else: embed = getErrorMessage(self._base64, Code.INVALID_PARAMETER) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def morse(self, message, parameters): """Turns text into/from morse code """ # Check for not enough parameters if len(parameters) < self._morse.getMinParameters(): embed = getErrorMessage(self._morse, Code.NOT_ENOUGH_PARAMETERS) # There were the proper amount of parameters else: conversion = parameters[0] text = " ".join(parameters[1:]) # Check if the conversion is valid valid = True if conversion in self._morse.getAcceptedParameter( "conversion", "encode").getAlternatives(): conversion = "encode" elif conversion in self._morse.getAcceptedParameter( "conversion", "decode").getAlternatives(): conversion = "decode" # Conversion is invalid else: embed = getErrorMessage(self._morse, Code.INVALID_PARAMETER) valid = False if valid: response = await loop.run_in_executor( None, requests.get, Code.MORSE_API_CALL.format(conversion, text)) response = response.json() # Check if the API call was a success if response["success"]: value = response["value"] else: value = response["error"] embed = discord.Embed( title="{}".format("Text to Morse" if conversion == "encode" else "Morse To Text") if response["success"] else "Failed to convert", description="`{}`".format(value), colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def qrCode(self, message, parameters): """Turns data into a QR code. """ # Check for not enough parameters if len(parameters) < self._qrCode.getMinParameters(): embed = getErrorMessage(self._qrCode, Code.NOT_ENOUGH_PARAMETERS) # There were the proper amount of parameters else: data = " ".join(parameters) # The size should be a function of the data's length # Use this --> size = 10(length // 20) + 200 size = 10 * (len(data) // 20) + 200 embed = discord.Embed( title=" ", description=" ", colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color).set_image( url=Code.QR_API_CALL.format(size, data.replace(" ", "+"))) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Parsing # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # async def on_message(self, message): """Parses a message and runs a Code Category command if it can Parameters: message: The Discord Message to parse.\n """ # Make sure message starts with the prefix if await Server.startsWithPrefix( message.guild, message.content) and not message.author.bot: # Split up into command and parameters if possible command, parameters = Category.parseText( await Server.getPrefixes(message.guild), message.content) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Iterate through commands for cmd in self.getCommands(): if command in cmd.getAlternatives(): async with message.channel.typing(): # Run the command but don't try running others await self.run(message, cmd, cmd.getCommand(), message, parameters) break
class NSFW(Category): # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Class Fields # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # BOOBS_URL = "http://media.oboobs.ru/boobs_preview/{}.jpg" BOOTY_URL = "http://media.obutts.ru/butts_preview/{}.jpg" URBAN_API_CALL = "https://api.urbandictionary.com/v0/define?term={}" URBAN_ICON = "https://vignette.wikia.nocookie.net/creation/images/b/b7/Urban_dictionary_--_logo.jpg/revision/latest?cb=20161002212954" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Errors # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # NO_TERM = "NO_TERM" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Constructor # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def __init__(self, client): super().__init__( client, "NSFW", description="An NSFW category for 18+", embed_color=0xFFAAAA, restriction_info= "You should be 18+ to run the commands in this category!", nsfw_category=True, nsfw_channel_error=Server.getNSFWChannelError) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Commands self._boobs = Command( commandDict={ "alternatives": ["boobs", "boob"], "info": "Sends a random picture of boobs.", "errors": { NSFW.TOO_MANY_PARAMETERS: { "messages": [ "In order to get some boobs, you don't need any parameters." ] } }, "command": self.boobs }) self._booty = Command( commandDict={ "alternatives": ["booty", "ass"], "info": "Sends a random picture of some booty.", "errors": { NSFW.TOO_MANY_PARAMETERS: { "messages": [ "In order to get some booty, you don't need any parameters." ] } }, "command": self.booty }) self._urban = Command( commandDict={ "alternatives": ["urban", "urbanDictionary", "urbanDict"], "info": "Gives you the top 5 urban dictionary entries for a term.", "nsfw": True, "parameters": { "term": { "info": "The term to look up in urban dictionary.", "optional": False } }, "errors": { NSFW.NOT_ENOUGH_PARAMETERS: { "messages": [ "You need the term to look something up in urban dictionary." ] }, NSFW.NO_TERM: { "messages": [ "The term you entered does not exist on urban dictionary." ] } }, "command": self.urban }) self.setCommands([self._boobs, self._booty, self._urban]) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Command Methods # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # async def boobs(self, message, parameters): """Sends a random picture of some boobs. """ # Check for too many parameters if len(parameters) > self._boobs.getMaxParameters(): embed = getErrorMessage(self._boobs, NSFW.TOO_MANY_PARAMETERS) # There were the proper amount of parameters else: # Load image from URL, temporarily save it, send image while True: # Generate random number for an image; Add 0's to beginning until pad is reached (5) boobNumber = str(random.randint(1, 12500)) boobNumber = boobNumber.rjust(5, "0") # Try loading the Image try: loadImageFromUrl(NSFW.BOOBS_URL.format(boobNumber)) break # Image load failed; Retry using new number. except: pass embed = discord.Embed( title="Boobs Number {}".format(boobNumber), description=" ", colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color).set_image( url=NSFW.BOOBS_URL.format(boobNumber)) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def booty(self, message, parameters): """Sends a random picture of some booty. """ # Check for too many parameters if len(parameters) > self._booty.getMaxParameters(): return getErrorMessage(self._booty, NSFW.TOO_MANY_PARAMETERS) # There were the proper amount of parameters else: # Load image from URL, temporarily save it, send image while True: # Generate random number for an image; Add 0's to beginning until pad is reached (5) bootyNumber = str(random.randint(1, 5400)) bootyNumber = bootyNumber.rjust(5, "0") # Try loading the image try: loadImageFromUrl(NSFW.BOOTY_URL.format(bootyNumber)) break # Image load failed; Retry using new number. except: pass embed = discord.Embed( title="Booty Number {}".format(bootyNumber), description=" ", colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color).set_image( url=NSFW.BOOTY_URL.format(bootyNumber)) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def urban(self, message, parameters): """Returns the top 5 urban dictionary entries for the specified term.\n - term - The term to search on urban dictionary.\n - discordChannel - The Discord Channel the definition is being sent in.\n """ # Check for not enough parameters if len(parameters) < self._urban.getMinParameters(): embed = getErrorMessage(self._urban, NSFW.NOT_ENOUGH_PARAMETERS) # There were the proper amount of parameters else: term = " ".join(parameters) # Use requests to get the data in JSON try: urlCall = NSFW.URBAN_API_CALL.format(term.replace(" ", "+")) urbanData = await loop.run_in_executor(None, requests.get, urlCall) urbanData = urbanData.json() # Get first 5 values (or values if there are less than 5) if len(urbanData["list"]) < 5: definitions = urbanData["list"] else: definitions = urbanData["list"][:5] # Create discord embed embed = discord.Embed( title="{} Results Of `{}`".format( "Top 5" if len(definitions) > 5 else "", term), description=" ", colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color).set_thumbnail( url=NSFW.URBAN_ICON) # Add definitions defCount = 0 for definition in definitions: defCount += 1 # Get definition; Split up into multiple fields if necessary definitionFields = splitText(definition["definition"], OmegaPsi.MESSAGE_THRESHOLD) count = 0 for field in definitionFields: count += 1 embed.add_field(name="Definition {} {}".format( defCount, "({} / {})".format(count, len(definitionFields)) if len(definitionFields) > 1 else ""), value=field, inline=False) except: embed = getErrorMessage(self._urban, NSFW.NO_TERM) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Parsing # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # async def on_message(self, message): """Parses a message and runs an NSFW Category command if it can.\n message - The Discord Message to parse.\n """ # Make sure message starts with the prefix if await Server.startsWithPrefix( message.guild, message.content) and not message.author.bot: # Split up into command and parameters if possible command, parameters = Category.parseText( await Server.getPrefixes(message.guild), message.content) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Iterate through commands for cmd in self.getCommands(): if command in cmd.getAlternatives(): async with message.channel.typing(): # Run the command but don't try running others await self.run(message, cmd, cmd.getCommand(), message, parameters) break
class BotModerator(Category): # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Class Fields # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # EMBED_COLOR = 0xA456B0 BOT_MARKDOWN = "botMarkdown.md" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Errors # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # CANT_BE_DEACTIVATED = "CANT_BE_DEACTIVATED" INVALID_ACTIVITY = "INVALID_ACTIVITY" INVALID_COMMAND = "INVALID_COMMAND" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Constructor # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def __init__(self, client): super().__init__(client, "Bot Moderator", description="Very private stuff.", restriction_info= "You must be a Bot Moderator to run these commands.", bot_mod_category=True, bot_mod_error=OmegaPsi.getNoAccessError, locally_inactive_error=Server.getInactiveError, globally_inactive_error=OmegaPsi.getInactiveError, locally_active_check=Server.isCommandActive, globally_active_check=OmegaPsi.isCommandActive) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Commands self._addModerator = Command( commandDict={ "alternatives": ["addBotModerator", "addBotMod", "abm"], "info": "Allows you to add a bot moderator to the bot.", "bot_moderator_only": True, "min_parameters": 1, "parameters": { "member(s)...": { "info": "The member(s) to add as a bot moderator.", "optional": False } }, "errors": { BotModerator.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to add a bot moderator, you need to mention them." ] } }, "command": self.addModerator }) self._removeModerator = Command( commandDict={ "alternatives": ["removeBotModerator", "removeBotMod", "remBotMod", "rbm"], "info": "Allows you to remove a bot moderator from the bot.", "bot_moderator_only": True, "min_parameters": 1, "parameters": { "member(s)...": { "info": "The member(s) to remove as a bot moderator.", "optional": False } }, "errors": { BotModerator.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to remove a bot moderator, you need to mention them." ] } }, "command": self.removeModerator }) self._activate = Command( commandDict={ "alternatives": ["activateGlobally", "enableGlobally"], "info": "Allows you to activate a command, or commands, globally.", "bot_moderator_only": True, "min_parameters": 1, "parameters": { "command(s)": { "info": "The command(s) to activate globally.", "optional": False } }, "errors": { BotModerator.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to activate a command globally, you need to type it in." ] }, BotModerator.INVALID_COMMAND: { "messages": ["That is not a valid command."] } }, "command": self.activate }) self._deactivate = Command( commandDict={ "alternatives": ["deactivateGlobally", "disableGlobally"], "info": "Allows you to deactivate a command globally.", "bot_moderator_only": True, "min_parameters": 1, "parameters": { "command": { "info": "The command to deactivate globally.", "optional": False }, "reason": { "info": "The reason the command is being deactivated globally.", "optional": True } }, "errors": { BotModerator.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to deactivate a command globally, you need to type it in." ] }, BotModerator.INVALID_COMMAND: { "messages": ["That is not a valid command."] }, BotModerator.CANT_BE_DEACTIVATED: { "messages": ["This command cannot be deactivated."] } }, "command": self.deactivate }) self._servers = Command( commandDict={ "alternatives": ["servers", "botServers"], "info": "Allows you to get a list of servers the bot is in.", "bot_moderator_only": True, "parameters": { "markdown": { "info": "Whether or not to send a markdown version of all the server information.", "optional": True } }, "errors": { BotModerator.TOO_MANY_PARAMETERS: { "messages": [ "In order to get a list of servers the bot is in, you only need 1 parameter which is optional." ] } }, "command": self.getServers }) self._status = Command( commandDict={ "alternatives": ["setStatus", "status"], "info": "Allows you to change the presence of the bot.", "bot_moderator_only": True, "min_parameters": 2, "parameters": { "activity": { "info": "The activity to set for the presence.", "optional": False, "accepted_parameters": { "playing": { "alternatives": ["playing", "Playing"], "info": "The playing activity type." }, "streaming": { "alternatives": ["streaming", "Streaming"], "info": "The streaming activity type." }, "listening": { "alternatives": [ "listening", "Listening", "listening to", "Listening to" ], "info": "The listening activity type." }, "watching": { "alternatives": ["watching", "Watching"], "info": "The watching activity type." } } }, "text": { "info": "The text to set as the presence.", "optional": False } }, "errors": { BotModerator.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to set the status, you need the status type and the text to set." ] }, BotModerator.INVALID_ACTIVITY: { "messages": ["The given activity is not a valid activity."] } }, "command": self.setStatus }) self._todo = Command( commandDict={ "alternatives": ["todo"], "info": "Adds, removes, or lists things in the TODO list.", "parameters": { "action": { "info": "The action to do.", "optional": True, "accepted": { "add": { "alternatives": ["add", "a"], "info": "Adds something to the TODO list." }, "remove": { "alternatives": ["remove", "r"], "info": "Removes something from the TODO list." } } }, "item": { "info": "The item to add or remove.", "optional": True } }, "errors": { BotModerator.NOT_ENOUGH_PARAMETERS: { "messages": [ "In order to add or remove something, you need the item to add or remove." ] }, BotModerator.INVALID_PARAMETER: { "messages": ["That is not a valid parameter."] } }, "command": self.todo }) self._kill = Command( commandDict={ "alternatives": ["stop", "quit", "kill"], "info": "Kills the bot.", "bot_moderator_only": True, "max_parameters": 1, "parameters": { "process": { "info": "The process number to kill.", "optional": True } }, "errors": { BotModerator.TOO_MANY_PARAMETERS: { "messages": [ "In order to kill the bot, you don't need anything other than the process." ] } }, "command": self.kill }) self._debug = Command( commandDict={ "alternatives": ["debug"], "info": "Debugs the bot.", "bot_moderator_only": True, "max_parameters": 0, "errors": { BotModerator.TOO_MANY_PARAMETERS: { "messages": ["To debug the bot, you don't need any parameters."] } }, "command": self.debug }) self.setCommands([ self._addModerator, self._removeModerator, self._activate, self._deactivate, self._servers, self._status, self._todo, self._kill, self._debug ]) self._todo.setBotModeratorOnly(False) self._categories = { "Code": Code(None), "Game": Game(None), "Image": Image(None), "Insult": Insult(None), "Internet": Internet(None), "Math": Math(None), "Meme": Meme(None), "Misc": Misc(None), "NSFW": NSFW(None), "Rank": Rank(None), "Updates": Updates(None) } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Command Methods # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # async def addModerator(self, message, parameters): """Adds bot moderators to the bot.\n Parameters: parameters: The Discord Users to add as a bot moderator.\n """ # Check if message has no mentions if len(message.mentions) < self._addModerator.getMinParameters(): return getErrorMessage(self._addModerator, BotModerator.NOT_ENOUGH_PARAMETERS) # There was at least one mention else: # Iterate through each member result = "" for member in message.mentions: result += "{} {}".format( member.mention, " was successfully added as a bot moderator." if await OmegaPsi.addModerator(member) else (" is already a bot moderator.")) embed = discord.Embed(name="Added bot Moderators", description=result, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def removeModerator(self, message, parameters): """Removes a bot moderator from the bot.\n Parameters: parameters: The Discord Users to remove as a bot moderator.\n """ # Check if message has no mentions if len(message.mentions) < self._removeModerator.getMinParameters(): embed = getErrorMessage(self._removeModerator, BotModerator.NOT_ENOUGH_PARAMETERS) # There was at least one mention else: # Iterate through each member result = "" for member in message.mentions: result += "{} {} a bot moderator.".format( member.mention, "was successfully removed as" if await OmegaPsi.removeModerator(member) else ("is not")) embed = discord.Embed(name="Removed Moderators", description=result, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def activate(self, message, parameters): """Activates commands globally in the bot. Parameters: parameters: The parameters to process. """ # Check if there are not enough parameters if len(parameters) < self._activate.getMinParameters(): embed = getErrorMessage(self._activate, BotModerator.NOT_ENOUGH_PARAMETERS) # Parameters had the minimum amount of parameters else: # Commands held in each parameter commands = parameters # Open bot file bot = await OmegaPsi.openOmegaPsi() # Iterate through commands if len(commands) > 0: result = "" acCommands = [] for command in commands: # Iterate through categories added = False for category in self._categories: # Check if command was part of category commandObject = self._categories[category].getCommand( command) if commandObject != None: acCommands.append(commandObject) added = True if not added: result += "`{}` is not a valid command.\n".format( command) # Activate commands for command in acCommands: if command.getAlternatives( )[0] in bot["inactive_commands"]: bot["inactive_commands"].pop( command.getAlternatives()[0]) result += "`{}` was activated globally.\n".format( command.getAlternatives()[0]) else: result += "`{}` is already globally active.\n".format( command.getAlternatives()[0]) else: result = "" for command in bot["inactive_commands"]: result += "`{}` was activated globally.\n".format(command) bot["inactive_commands"] = {} # Close bot file await OmegaPsi.closeOmegaPsi(bot) embed = discord.Embed(name="Activated", description=result, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def deactivate(self, message, parameters): """Deactivates a command globally in the bot.\n Parameters: command: The command to globally deactivate.\n reason: The reason the command is being globally deactivated.\n """ # Check for minimum amount of parameters if len(parameters) < self._deactivate.getMinParameters(): embed = getErrorMessage(self._deactivate, BotModerator.NOT_ENOUGH_PARAMETERS) # Parameters had the minimum amount of parameters else: # Command to be deactivated is first parameter; Reason is every parameter after command = parameters[0] reason = "No Reason" if len(parameters) > 1: reason = " ".join(parameters[1:]) # Open bot file bot = await OmegaPsi.openOmegaPsi() # Check if command is valid commandObject = None for category in self._categories: commandObject = self._categories[category].getCommand(command) if commandObject != None: break if commandObject == None: result = "`{}` is not a valid command.".format(command) else: bot["inactive_commands"][commandObject.getAlternatives() [0]] = reason result = "`{}` was globally deactivated.\nReason: {}".format( commandObject.getAlternatives()[0], reason) # Close bot file await OmegaPsi.closeOmegaPsi(bot) embed = discord.Embed(name="Deactivated", description=result, colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def getServers(self, message, parameters): """Returns a list of servers the bot is in.\n """ # Check if parameters exceeds maximum parameters if len(parameters) > self._servers.getMaxParameters(): embed = getErrorMessage(self._servers, BotModerator.TOO_MANY_PARAMETERS) # Parameters do not exceed maximum parameters else: # Getting results through embed if len(parameters) == 0: # Add results to fields fields = [] fieldText = "" for server in self.client.guilds: text = "`{}` | Owner: {}\n".format(server.name, server.owner.mention) if len(fieldText) + len( text) >= OmegaPsi.MESSAGE_THRESHOLD: fields.append(fieldText) fieldText = "" fieldText += text # Add trailing field text if len(fieldText) > 0: fields.append(fieldText) # Create embed object embed = discord.Embed( title="Servers", description="A list of servers that Omega Psi is in.", colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) # Add fields to embed object count = 0 for field in fields: count += 1 embed.add_field( name="Servers {}".format("({} / {})".format( count, len(fields)) if len(fields) > 1 else ""), value=field, inline=False) # Getting results through markdown file else: # Setup markdown text markdown = "# Omega Psi Server Information\n" # Iterate through servers bot is in for guild in self.client.guilds: # Load file server = await Server.openServer(guild) # Add server information (owner, name) try: markdown += "## {} - {}\n".format( guild.name, guild.owner.name + "#" + guild.owner.discriminator) except: markdown += "## {} - No Owner\n".format(guild.name) # Iterate through members in server dictionary for member in server["members"]: member = server["members"][member] discordMember = guild.get_member(int(member["id"])) markdown += ( " * {} ({})\n" + " * Moderator? {}\n" + " * Experience: {}\n" + " * Level: {}\n" + " * Experience until next level: {}\n").format( discordMember.name + "#" + discordMember.discriminator, discordMember.nick, "Yes" if discordMember.guild_permissions.manage_guild else "No", member["experience"], member["level"], Server.getExpFromLevel(member["level"] + 1) - member["experience"]) # Save markdown temporarily mdFile = open(BotModerator.BOT_MARKDOWN, "w") mdFile.write(markdown) mdFile.close() mdFile = open(BotModerator.BOT_MARKDOWN, "r") # Send file to DMs; Then delete await message.author.send(file=discord.File(mdFile)) os.remove(BotModerator.BOT_MARKDOWN) embed = discord.Embed( title="File sent.", description= "The server information has been sent to your DM's", colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def setStatus(self, message, parameters): """Sets the presence of the bot given the activity type and text.\n Parameters: activityType: The type of activity to set for the presence.\n text: The text to set.\n """ # Check if parameters is less than minimum parameters if len(parameters) < self._status.getMinParameters(): embed = getErrorMessage(self._status, BotModerator.NOT_ENOUGH_PARAMETERS) # Parameters has minumum parameters else: # Activity type is first parameter; Text is every parameter after activityType = parameters[0] text = " ".join(parameters[1:]) # Get the specific activity type activityText = activityType if activityType in self._status.getAcceptedParameter( "activity", "playing").getAlternatives(): activityType = discord.ActivityType.playing activityText = "Playing" elif activityType in self._status.getAcceptedParameter( "activity", "streaming").getAlternatives(): activityType = discord.ActivityType.streaming activityText = "Streaming" elif activityType in self._status.getAcceptedParameter( "activity", "listening").getAlternatives(): activityType = discord.ActivityType.listening activityText = "Listening" elif activityType in self._status.getAcceptedParameter( "activity", "watching").getAlternatives(): activityType = discord.ActivityType.watching activityText = "Watching" # Update the bot's activity setting await OmegaPsi.setActivityType(activityType) await OmegaPsi.setActivityName(text) # Change the presence of the bot await self.client.change_presence( status=discord.Status.online, activity=discord.Activity( name=text, type=activityType, url="https://www.twitch.tv/FellowHashbrown")) embed = discord.Embed( title="Presence Set", description="Activity: {}\nText: {}\n".format( activityText, text), colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def todo(self, message, parameters): """Runs the todo command. Parameters: action (str): What action to perform for the todo command. item (str): The item to add/remove to/from the TODO list. """ # Check for no parameters; list the TODO list if len(parameters) == 0: todoList = await OmegaPsi.getToDoList() todoText = "" for item in range(len(todoList)): todoText += "`{}.) {}`\n".format(item + 1, todoList[item]) embed = discord.Embed( title="TODO List", description=todoText if len(todoText) > 0 else "Nothing Yet", colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) # Check for 2 or more parameters else: # Check if author is a bot moderator if await OmegaPsi.isAuthorModerator(message.author): action = parameters[0] # There is nothing to add if len(parameters) == 1: embed = getErrorMessage(self._todo, BotModerator.NOT_ENOUGH_PARAMETERS) # Check if action is valid elif action in self._todo.getAcceptedParameter( "action", "add").getAlternatives(): # Check if index is given if parameters[1].isdigit(): index = int(parameters[1]) item = " ".join(parameters[2:]) else: index = 0 item = " ".join(parameters[1:]) success = await OmegaPsi.addToDo(item, index) embed = discord.Embed( title="Added TODO Item" if success["success"] else "Failed to add TODO Item", description=success["reason"], colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) elif action in self._todo.getAcceptedParameter( "action", "remove").getAlternatives(): success = await OmegaPsi.removeToDo(" ".join( parameters[1:])) embed = discord.Embed( title="Removed TODO Item" if success["success"] else "Failed to remove TODO Item", description=success["reason"], colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) # Action is invalid else: embed = getErrorMessage(self._todo, BotModerator.INVALID_PARAMETER) # Author is not bot moderator else: embed = OmegaPsi.getNoAccessError() await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) async def kill(self, message, parameters): """Kills the bot and logs out. """ processId = OmegaPsi.PROCESS_ID # Check if parameters exceeds maximum parameters if len(parameters) > self._kill.getMaxParameters(): embed = getErrorMessage(self._kill, BotModerator.TOO_MANY_PARAMETERS) # Parameters do not exceed maximum parameters else: processId = OmegaPsi.PROCESS_ID if len( parameters) == 0 else parameters[0] embed = discord.Embed( title="Bot Killed", description="Omega Psi was killed (Process {})".format( OmegaPsi.PROCESS_ID), colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) # Only kill if processId is OmegaPsi.PROCESS_ID if str(processId) == str(OmegaPsi.PROCESS_ID): await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) await self.client.logout() async def debug(self, message, parameters): """Debugs the bot. """ # Check if parameters exceeds maximum parameters if len(parameters) > self._debug.getMaxParameters(): embed = getErrorMessage(self._debug, BotModerator.TOO_MANY_PARAMETERS) # Parameters do not exceed maximum parameters else: embed = discord.Embed( title="Omega Psi Debugging", description="Process ID: {}".format(OmegaPsi.PROCESS_ID), colour=self.getEmbedColor() if message.guild == None else message.author.top_role.color) await sendMessage( self.client, message, embed=embed.set_footer(text="Requested by {}#{}".format( message.author.name, message.author.discriminator), icon_url=message.author.avatar_url)) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Parsing # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # async def on_message(self, message): """Parses a message and runs a Bot Moderator command if it can.\n Parameters: message: The Discord Message to parse.\n """ # Make sure message starts with the prefix if await Server.startsWithPrefix( message.guild, message.content) and not message.author.bot: # Split up into command and parameters if possible command, parameters = Category.parseText( await Server.getPrefixes(message.guild), message.content) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Iterate through commands for cmd in self.getCommands(): if command in cmd.getAlternatives(): async with message.channel.typing(): # Run the command but don't try running others await self.run(message, cmd, cmd.getCommand(), message, parameters) break