diff --git a/__main__.py b/__main__.py index bbdcc07..2f4712f 100644 --- a/__main__.py +++ b/__main__.py @@ -2,34 +2,38 @@ from commands import * from guildSettings.guildSettings import * -print(f'Starting up: Skybot {version}') +print(f"Starting up: Skybot {version}") + @client.event async def on_ready(): - await client.change_presence(activity=discord.Game(f'({version}) {botInfo["statusMessage"]}')) - print('logged in as {0.user}\n\n'.format(client)) + await client.change_presence( + activity=discord.Game(f'({version}) {botInfo["statusMessage"]}') + ) + print("logged in as {0.user}\n\n".format(client)) + @client.event -async def on_message(message): +async def on_message(message): settings = guildSettings(message) - + if message.author == client.user: return - + await settingsCommands(message, settings) - if (not settings['enableBot']): + if not settings["enableBot"]: return - - if settings['allowMessageResponses']: + + if settings["allowMessageResponses"]: await messageResponses(message) - if message.content.startswith(settings['commandChar']): - args = shlex.split(message.content.lower().replace(settings['commandChar'],'')) + if message.content.startswith(settings["commandChar"]): + args = shlex.split(message.content.lower().replace(settings["commandChar"], "")) command = args.pop(0) - + await userCommands(message, command, args, settings) - if settings['allowJapeCommands']: + if settings["allowJapeCommands"]: await japeCommands(message, command, args, settings) -client.run(config['token']) +client.run(config["token"]) diff --git a/botInfo.json b/botInfo.json index 860a87b..3f3d9d8 100644 --- a/botInfo.json +++ b/botInfo.json @@ -1,49 +1,116 @@ { - "currentVersion" : "0.6.1", - "githubLink" : "https://github.com/SkyKerr/SkyBot", - "profilePic" : "https://cdn.discordapp.com/attachments/958949821308366879/959661099672809482/profilePicture.png", - "description" : "A japes-based open-source discord bot built in Python", - - "style" : { - "skyblue" : "0x87CEEB" - }, - - "jonyCube" : { - "title" : "Jony Cube", - "description" : "You have rolled the Jony Cube, and it came up as Jony.", - "color" : "0x3c2821", - "gif" : "https://github.com/jwhamilton99/jonycube/blob/7e524ab13c6fd856ef47db5387c8d601b39f7b6d/jonycube.gif?raw=true" - - }, - - "marcos" : [ - "Alcaraz!","Alessandrini!","Amelia!","Ament!","Andreolli!","Andretti!","Arment!","Asensio!","Antonio Barrera!","van Basten!","Banderas!","Belinelli!","Biagianti!","Boogers!","Borriello!","Borsato!","Brambilla!","Calliari!","Cassetti!","Castro!","Chiudinelli!","D Amore!","Dapper!","Delvecchio!","Di Vaio!","Donnarumma!","Feingold!","Ferradini!","Fu!","Antonio Garcia Blanco!","Giampaolo!","Grazzini!","Gumabao!","Hietala!","Höger!","Ilsø!","Jaggi!","Khan!","Kreuzpaintner!","Kurz!","Leonardi!","Masini!","Materazzi!","Antonio Mazzini!","Melandri!","Mengoni!","Micone!","Minnemann!","Morales!","Motta!","Paolini!","Pappa!","Parolo!","Pastors!","Pierre White!","Pigossi!","Antonio Pogioli!","Polo!","Reus!","Rojas!","Rosa!","Rossi!","Ruben!","Ruffo!","Scacchi!","Scutaro!","Siffredi!","Silva!","Simoncelli!","Simone!","Solari!","Antonio Solís!","Storari!","Streller!","Tardelli!","Thomas!","Torsiglieri!","Verratti!","Völler!","Werner!","Wilson!","Zoppo!" - ], - - "reactions" : { - "no" : "🚫", - "wave" : "👋", - "eyes" : "👀", - "bee" : "🐝" - }, - - "flippedTable" : "(╯°□°)╯︵ ┻━┻", - "unflippedTable" : "┬─┬ ノ( ゜-゜ノ)", - "tableResponses" : [ - "Respect the table!", - "What did that table ever do to you?", - "If you break that table, someone will be very angry", - "Pick on a table your own size!", - "Keep your paws off of my table!" - ], - - "statusMessage" : "bleep bloop rawr", - "randomStatusMessages" : [ - "A robot dragon made by a non-robot dragon", - "bleep bloop rawr", - "because blue is the best colour", - "stop messing around a get to work", - "Robots don't need to eat food, but if you're reading this, you probably do", - "Blue Dragon Robot" - ] + "currentVersion": "0.6.1", + "githubLink": "https://github.com/SkyKerr/SkyBot", + "profilePic": "https://cdn.discordapp.com/attachments/958949821308366879/959661099672809482/profilePicture.png", + "description": "A japes-based open-source discord bot built in Python", + "style": {"skyblue": "0x87CEEB"}, + "jonyCube": { + "title": "Jony Cube", + "description": "You have rolled the Jony Cube, and it came up as Jony.", + "color": "0x3c2821", + "gif": "https://github.com/jwhamilton99/jonycube/blob/7e524ab13c6fd856ef47db5387c8d601b39f7b6d/jonycube.gif?raw=true", + }, + "marcos": [ + "Alcaraz!", + "Alessandrini!", + "Amelia!", + "Ament!", + "Andreolli!", + "Andretti!", + "Arment!", + "Asensio!", + "Antonio Barrera!", + "van Basten!", + "Banderas!", + "Belinelli!", + "Biagianti!", + "Boogers!", + "Borriello!", + "Borsato!", + "Brambilla!", + "Calliari!", + "Cassetti!", + "Castro!", + "Chiudinelli!", + "D Amore!", + "Dapper!", + "Delvecchio!", + "Di Vaio!", + "Donnarumma!", + "Feingold!", + "Ferradini!", + "Fu!", + "Antonio Garcia Blanco!", + "Giampaolo!", + "Grazzini!", + "Gumabao!", + "Hietala!", + "Höger!", + "Ilsø!", + "Jaggi!", + "Khan!", + "Kreuzpaintner!", + "Kurz!", + "Leonardi!", + "Masini!", + "Materazzi!", + "Antonio Mazzini!", + "Melandri!", + "Mengoni!", + "Micone!", + "Minnemann!", + "Morales!", + "Motta!", + "Paolini!", + "Pappa!", + "Parolo!", + "Pastors!", + "Pierre White!", + "Pigossi!", + "Antonio Pogioli!", + "Polo!", + "Reus!", + "Rojas!", + "Rosa!", + "Rossi!", + "Ruben!", + "Ruffo!", + "Scacchi!", + "Scutaro!", + "Siffredi!", + "Silva!", + "Simoncelli!", + "Simone!", + "Solari!", + "Antonio Solís!", + "Storari!", + "Streller!", + "Tardelli!", + "Thomas!", + "Torsiglieri!", + "Verratti!", + "Völler!", + "Werner!", + "Wilson!", + "Zoppo!", + ], + "reactions": {"no": "🚫", "wave": "👋", "eyes": "👀", "bee": "🐝"}, + "flippedTable": "(╯°□°)╯︵ ┻━┻", + "unflippedTable": "┬─┬ ノ( ゜-゜ノ)", + "tableResponses": [ + "Respect the table!", + "What did that table ever do to you?", + "If you break that table, someone will be very angry", + "Pick on a table your own size!", + "Keep your paws off of my table!", + ], + "statusMessage": "bleep bloop rawr", + "randomStatusMessages": [ + "A robot dragon made by a non-robot dragon", + "bleep bloop rawr", + "because blue is the best colour", + "stop messing around a get to work", + "Robots don't need to eat food, but if you're reading this, you probably do", + "Blue Dragon Robot", + ], } diff --git a/commands.py b/commands.py index 893e239..81de58b 100644 --- a/commands.py +++ b/commands.py @@ -1,124 +1,154 @@ from index import * -async def userCommands(message, command, args, settings): - - if command == 'version': - await message.channel.send(f'Skybot {version}') - - if command == 'echo': - author = message.author.id - - authorTag = (f'<@{author}>') - echoResponse = message.content.replace((settings['commandChar']+'echo'),'').replace('spoopy', 'spooky').replace('@','@​') - response = authorTag + echoResponse - - await message.channel.send(response) - - if command == 'help': - await message.channel.send(f'see the README at <{botInfo["githubLink"]}>') - - if command == 'send': - if not message.author.guild_permissions.manage_messages: - await message.channel.send('Error: Insufficient Permissions') - return - - if len(args) < 2: return - - try: - sendChan = client.get_channel(int(args[0].replace('<#','').replace('>',''))) - except: - sendChan = None - - if sendChan == None: - await message.channel.send('Error: Channel not found') - return - - await sendChan.send(args[1]) - - if command == 'reply': - if not message.author.guild_permissions.manage_messages: - await message.channel.send('Erorr: Insufficient Permissions') - return - - if len(args) < 3: - await message.channel.send('Error: Missing required parameters') - return - - # param 0, channel - try: - sendChan = client.get_channel(int(args[0].replace('<#','').replace('>',''))) - except: - sendChan = None - - if sendChan == None: - await message.channel.send('Error: Channel not found') - return - - # Param 1, Message ID - try: - replyTo = await sendChan.fetch_message(int(args[1])) - except: - replyTo = None - - if replyTo == None: - await message.channel.send('Error: Message not found') - - # Param 3, Ping true/false, optional - if len(args) == 3: - ping = False - elif args[3] == 'true': - ping = True - else: - ping = False - - # Final message send - await replyTo.reply(args[2], mention_author=ping) - + +async def userCommands(message, command, args, settings): + + if command == "version": + await message.channel.send(f"Skybot {version}") + + if command == "echo": + author = message.author.id + + authorTag = f"<@{author}>" + echoResponse = ( + message.content.replace((settings["commandChar"] + "echo"), "") + .replace("spoopy", "spooky") + .replace("@", "@​") + ) + response = authorTag + echoResponse + + await message.channel.send(response) + + if command == "help": + await message.channel.send(f'see the README at <{botInfo["githubLink"]}>') + + if command == "send": + if not message.author.guild_permissions.manage_messages: + await message.channel.send("Error: Insufficient Permissions") + return + + if len(args) < 2: + return + + try: + sendChan = client.get_channel( + int(args[0].replace("<#", "").replace(">", "")) + ) + except: + sendChan = None + + if sendChan == None: + await message.channel.send("Error: Channel not found") + return + + await sendChan.send(args[1]) + + if command == "reply": + if not message.author.guild_permissions.manage_messages: + await message.channel.send("Erorr: Insufficient Permissions") + return + + if len(args) < 3: + await message.channel.send("Error: Missing required parameters") + return + + # param 0, channel + try: + sendChan = client.get_channel( + int(args[0].replace("<#", "").replace(">", "")) + ) + except: + sendChan = None + + if sendChan == None: + await message.channel.send("Error: Channel not found") + return + + # Param 1, Message ID + try: + replyTo = await sendChan.fetch_message(int(args[1])) + except: + replyTo = None + + if replyTo == None: + await message.channel.send("Error: Message not found") + + # Param 3, Ping true/false, optional + if len(args) == 3: + ping = False + elif args[3] == "true": + ping = True + else: + ping = False + + # Final message send + await replyTo.reply(args[2], mention_author=ping) + + async def japeCommands(message, command, args, settings): - if command == 'ping': - await message.channel.send('Pong!') - - if command == 'rolljonycube': - jonyEmbed = discord.Embed(title=botInfo['jonyCube']['title'], description=botInfo['jonyCube']['description'], color=0x3c2821) - jonyEmbed.set_thumbnail(url=botInfo['jonyCube']['gif']) - await message.channel.send(embed=jonyEmbed) - - if command == 'quip': - res = get("https://4fjqh2uxrwehpglicenre7qrny0sduge.lambda-url.us-west-2.on.aws") - await message.channel.send(res.text) - - def chickenify(string): - # im a tryhard ok deal with it -- Justin Hamilton - return ''.join([string[i].upper() if i%2 == 1 else string[i].lower() for i in range(len(string))]) - - if command == 'chickenify': - response = chickenify(message.content.replace((botInfo['commandChar']+'chickenify '),'')) - await message.reply(response, mention_author=False) - - if command == 'marco': - await message.channel.send(r.choice(botInfo['marcos'])) - + if command == "ping": + await message.channel.send("Pong!") + + if command == "rolljonycube": + jonyEmbed = discord.Embed( + title=botInfo["jonyCube"]["title"], + description=botInfo["jonyCube"]["description"], + color=0x3C2821, + ) + jonyEmbed.set_thumbnail(url=botInfo["jonyCube"]["gif"]) + await message.channel.send(embed=jonyEmbed) + + if command == "quip": + res = get( + "https://4fjqh2uxrwehpglicenre7qrny0sduge.lambda-url.us-west-2.on.aws" + ) + await message.channel.send(res.text) + + def chickenify(string): + # im a tryhard ok deal with it -- Justin Hamilton + return "".join( + [ + string[i].upper() if i % 2 == 1 else string[i].lower() + for i in range(len(string)) + ] + ) + + if command == "chickenify": + response = chickenify( + message.content.replace((botInfo["commandChar"] + "chickenify "), "") + ) + await message.reply(response, mention_author=False) + + if command == "marco": + await message.channel.send(r.choice(botInfo["marcos"])) + + async def messageResponses(message): - if 'spoopy' in message.content.lower(): - await message.add_reaction(botInfo['reactions']['no']) - - if 'skybot' in message.content.lower(): - await message.add_reaction(botInfo['reactions']['wave']) - - if message.content.lower() == 'some': - await message.reply("BODY", mention_author=False) - - if client.user in message.mentions: - await message.channel.send(botInfo['reactions']['eyes']) - - if botInfo['flippedTable'] in message.content.lower(): - unflip = botInfo['unflippedTable'] - response = r.choice(botInfo['tableResponses']) - await message.reply(unflip + '\n' + response) - - if 'API' in message.content: - await message.add_reaction(botInfo['reactions']['bee']) - - match = re.match("^i(['‘’]?)m(( (\S)+){1,5})$", message.content.lower().replace("*","").replace("_","")) - if(not(match == None)): - await message.reply("hi "+match.group(2)[1:]+" i'm dad", mention_author=False) \ No newline at end of file + if "spoopy" in message.content.lower(): + await message.add_reaction(botInfo["reactions"]["no"]) + + if "skybot" in message.content.lower(): + await message.add_reaction(botInfo["reactions"]["wave"]) + + if message.content.lower() == "some": + await message.reply("BODY", mention_author=False) + + if client.user in message.mentions: + await message.channel.send(botInfo["reactions"]["eyes"]) + + if botInfo["flippedTable"] in message.content.lower(): + unflip = botInfo["unflippedTable"] + response = r.choice(botInfo["tableResponses"]) + await message.reply(unflip + "\n" + response) + + if "API" in message.content: + await message.add_reaction(botInfo["reactions"]["bee"]) + + match = re.match( + "^i(['‘’]?)m(( (\S)+){1,5})$", + message.content.lower().replace("*", "").replace("_", ""), + ) + if not (match == None): + await message.reply( + "hi " + match.group(2)[1:] + " i'm dad", mention_author=False + ) diff --git a/guildSettings/guildSettings.py b/guildSettings/guildSettings.py index 5925e11..2743b61 100644 --- a/guildSettings/guildSettings.py +++ b/guildSettings/guildSettings.py @@ -1,100 +1,119 @@ from index import * -with open('guildSettings/descriptions.json') as f: - settingDescriptions = json.load(f) + +with open("guildSettings/descriptions.json") as f: + settingDescriptions = json.load(f) # Note: Before v0.5 there is no way to add new settings to existing guilds. For testing in v0.5pre, guild settings *for the testing guild only* should be deleted so that they can be reloaded. def guildSettings(message): - guildID = message.channel.guild.id - filePath = (f'guildSettings/guilds/{guildID}.json') - templateFilePath = (f'guildSettings/template.json') - - if (not exists(filePath)): - sh.copy('guildSettings/template.json', filePath) - - with open(templateFilePath) as f: - templateSettings = json.load(f) - with open(filePath) as f: - settings = json.load(f) - - for setting in templateSettings: - if setting not in settings: - sh.copy(templateFilePath, filePath) - with open(filePath) as f: - settings = json.load(f) - break - - return settings + guildID = message.channel.guild.id + filePath = f"guildSettings/guilds/{guildID}.json" + templateFilePath = f"guildSettings/template.json" + + if not exists(filePath): + sh.copy("guildSettings/template.json", filePath) + + with open(templateFilePath) as f: + templateSettings = json.load(f) + with open(filePath) as f: + settings = json.load(f) + + for setting in templateSettings: + if setting not in settings: + sh.copy(templateFilePath, filePath) + with open(filePath) as f: + settings = json.load(f) + break + + return settings + async def settingsCommands(message, settings): - if not message.content.startswith(settings['commandChar']): - return - args = message.content.lstrip(settings['commandChar']).split(' ') - - # Status command - if args[0] == 'status': - statusEmbed = discord.Embed(title=(f'Skybot {version}'), url=botInfo['githubLink'], description=botInfo['description'], color=0x87CEEB) - if settings['enableBot'] == False: - statusEmbed.add_field(name='Caution', value='The bot is currently disabled. To re-enable, type `$settings enableBot True` with moderator permissions') - - statusEmbed.set_thumbnail(url=botInfo['profilePic']) - - await message.channel.send(embed=statusEmbed) - - # All settings options below - if(args[0].lower() == 'settings'): # Call settings - Settings embed - if len(args)==1: - messageEmbed = discord.Embed(title=(f'Server Settings for {message.channel.guild}')) - - for setting in settings: - messageEmbed.add_field( - name=(f'{setting}'), - value=(f'{settingDescriptions[setting]["description"]}\n**Value:** {settings[setting]}\n**Type:** {settingDescriptions[setting]["type"]}'), - inline=False) - - await message.channel.send(embed=messageEmbed) - return - - if args[1] not in settings: - await message.channel.send('Setting not found') - return - - # Change settings commands - if len(args)==2: - await message.channel.send(f'{args[1]}: {settings[args[1]]}') - return - else: # There are 3 arguments given - setting = args[1] - input = args[2].lower() - - if not message.author.guild_permissions.manage_messages: # Non-moderator users - await message.channel.send('You do not have the permissions to change the settings') - return - - # Test for input type, typecasting - try: - settingType = settingDescriptions[setting]['type'] - if settingType == 'bool': - if input == 'true': - input = True - elif input == 'false': - input = False - else: - raise ValueError('input is not True or False') - if settingType == 'char': - if len(input) != 1: - raise ValueError('input is not a single character') - # No necessary test for string - if settingType == 'int': - input = int(input) - except ValueError as error: - await message.channel.send(f'ValueError: {error}') - return - - # Checks passed - settings[setting] = input - # Write the change to the settings file - with open((f'guildSettings/guilds/{message.channel.guild.id}.json'), 'w') as f: - f.write(json.dumps(settings)) - await message.channel.send(f'{setting} set to {input}') - - \ No newline at end of file + if not message.content.startswith(settings["commandChar"]): + return + args = message.content.lstrip(settings["commandChar"]).split(" ") + + # Status command + if args[0] == "status": + statusEmbed = discord.Embed( + title=(f"Skybot {version}"), + url=botInfo["githubLink"], + description=botInfo["description"], + color=0x87CEEB, + ) + if settings["enableBot"] == False: + statusEmbed.add_field( + name="Caution", + value="The bot is currently disabled. To re-enable, type `$settings enableBot True` with moderator permissions", + ) + + statusEmbed.set_thumbnail(url=botInfo["profilePic"]) + + await message.channel.send(embed=statusEmbed) + + # All settings options below + if args[0].lower() == "settings": # Call settings - Settings embed + if len(args) == 1: + messageEmbed = discord.Embed( + title=(f"Server Settings for {message.channel.guild}") + ) + + for setting in settings: + messageEmbed.add_field( + name=(f"{setting}"), + value=( + f'{settingDescriptions[setting]["description"]}\n**Value:** {settings[setting]}\n**Type:** {settingDescriptions[setting]["type"]}' + ), + inline=False, + ) + + await message.channel.send(embed=messageEmbed) + return + + if args[1] not in settings: + await message.channel.send("Setting not found") + return + + # Change settings commands + if len(args) == 2: + await message.channel.send(f"{args[1]}: {settings[args[1]]}") + return + else: # There are 3 arguments given + setting = args[1] + input = args[2].lower() + + if ( + not message.author.guild_permissions.manage_messages + ): # Non-moderator users + await message.channel.send( + "You do not have the permissions to change the settings" + ) + return + + # Test for input type, typecasting + try: + settingType = settingDescriptions[setting]["type"] + if settingType == "bool": + if input == "true": + input = True + elif input == "false": + input = False + else: + raise ValueError("input is not True or False") + if settingType == "char": + if len(input) != 1: + raise ValueError("input is not a single character") + # No necessary test for string + if settingType == "int": + input = int(input) + except ValueError as error: + await message.channel.send(f"ValueError: {error}") + return + + # Checks passed + settings[setting] = input + # Write the change to the settings file + with open( + (f"guildSettings/guilds/{message.channel.guild.id}.json"), "w" + ) as f: + f.write(json.dumps(settings)) + await message.channel.send(f"{setting} set to {input}") diff --git a/index.py b/index.py index 418cd10..f8c7536 100644 --- a/index.py +++ b/index.py @@ -4,11 +4,11 @@ client = discord.Client() -with open('config.json') as f: - config = json.load(f) -with open('botInfo.json') as f: - botInfo = json.load(f) - +with open("config.json") as f: + config = json.load(f) +with open("botInfo.json") as f: + botInfo = json.load(f) + import random as r import shutil as sh import threading @@ -18,6 +18,6 @@ from os.path import exists import re -version = (f'v{botInfo["currentVersion"]}') -if config['isDev'] : - version += '-dev' \ No newline at end of file +version = f'v{botInfo["currentVersion"]}' +if config["isDev"]: + version += "-dev"