async def on_command_error(self, ctx, error): channel = ctx.message.channel cmd = ctx.command if isinstance(error, commands.MissingRequiredArgument) or isinstance( error, commands.BadArgument): await self.show_cmd_help(ctx) return elif isinstance(error, commands.CommandNotFound): return elif isinstance(error, commands.CheckFailure): await channel.send( "You do not have permission to use that command!") return elif isinstance(error, commands.CommandOnCooldown): await channel.send("This command is currently on cooldown. {}" "".format(str(error).split(". ")[1])) return else: err = traceback.format_exception(type(error), error, error.__traceback__) Logger.write(err) await channel.send("**Error in '{}' Command!**\n" "{}\n" "See the log for more details".format( cmd.name, error)) return
async def reload_all(self, ctx): """Reload all cogs""" msg = await ctx.send( "Reloading all non critical cogs (excludes cog_management and logging)" ) reloaded = 0 cog_list = [cog for cog in self.bot.extensions] cog_count = len(cog_list) for cog in cog_list: if cog in ["cogs.cog_management", "cogs.logging"]: cog_count -= 1 continue try: self.bot.unload_extension(cog) except Exception as e: Logger.write(e) cog_list.remove(cog) continue try: self.bot.load_extension(cog) reloaded += 1 except Exception as e: Logger.write(e) continue await msg.edit( content="{} cogs out of {} successfully reload " "(cog_management and logging must be reload manually)\n" "Any errors can be found in the logs.".format(reloaded, cog_count))
async def load(self, ctx, *, cog: str): """Load a cog""" cog_list = [] for c_file in os.listdir(os.path.join(self.bot.base_directory, "cogs")): if c_file.endswith(".py"): cog_list.append("cogs.{}".format(c_file.replace(".py", ""))) l_cog_name = "cogs.{}".format(cog) # print(cog, cog_name, cog_list) if l_cog_name in cog_list: try: self.bot.load_extension(l_cog_name) await ctx.send("Successfully loaded cog '{}'.".format(cog)) except Exception as e: Logger.write(e) await ctx.send("Failed to load cog '{}'. Reason: {}. \n {}".format(cog, type(e).__name__, e.args)) return else: await ctx.send("No cog called '{}'.".format(cog)) return data = IO.read_settings_as_json() if data is None: await ctx.send(IO.settings_fail_read) return data['cogs'][cog] = True if IO.write_settings(data) is False: await ctx.send(IO.settings_fail_write) return
async def find_member_from_id_or_mention(ctx, user): # self, """Takes message context to check for mentions and user input to check if its an id and returns the member object should it find one, or none if it does not""" target = None if user is None: target = ctx.author else: # Check for mention try: mentions = ctx.message.mentions if len(mentions) == 1: target = mentions[0] elif len(mentions) > 1: return None except AttributeError: pass # Check for id if target is None: try: user_id = int(user) user_find = ctx.message.guild.get_member(user_id) if user_find is not None: target = user_find except ValueError: return None except Exception as e: Logger.write(e) return None return target
async def ps3(self, ctx, *, search_term: str): """Search for PS3 games on the UK Playstation Store""" msg = await ctx.send(self.fetching) try: await msg.edit(embed=playstation_search("PS3", search_term)) except Exception as e: Logger.write(e) await msg.edit("PS3 Game Search Failed")
async def on_disconnect(self): dc_time = datetime.now() dc_msg = "Bot disconnected at {}".format(dc_time) Logger.log_write( "----------------------------------------------------------\n" "{}\n" "".format(dc_msg)) print(dc_msg)
async def on_ready(self): # https://discordpy.readthedocs.io/en/latest/api.html#discord.on_connect self.update_json_time(update_reconnect_time=True) login_msg = "Bot Connected at {}".format(str(datetime.now())) Logger.log_write( "----------------------------------------------------------\n" "{}\n" "".format(login_msg)) print(login_msg)
def __write_json(data, file_path): """Write data to the settings file. Returns true if successful, False if not""" try: with open(file_path, "w") as f: json.dump(data, f, indent=4) return True except Exception as e: Logger.write(e) return False
def __read_json(file_path): """Read the settings.json file and then return as python object Returns none if failed""" try: with open(file_path, "r") as f: r_data = f.read() data = json.loads(r_data) return data except Exception as e: Logger.write(e) return None
async def on_ready(self): DiscordComponents(self) self.reconnect_time = datetime.utcnow() login_msg = "Bot Connected at {} UTC".format(str(datetime.utcnow())) Logger.log_write( "----------------------------------------------------------\n" "{}\n" "".format(login_msg)) print(login_msg) self.ensure_all_fields_server() IO.write_server(self.servers_config)
def __init__(self, *args, **kwargs): self.logger = Logger("bot") self.settings = Settings() super().__init__(*args, command_prefix=self.prefix_manager, pm_help=False, **kwargs)
async def origin_search(self, ctx, *, search_term: str): """Search for games on Origin""" msg = await ctx.send(self.fetching) try: data = Origin.search_by_name(search_term) except Exception as e: Logger.write(traceback.format_exception(type(e), e, e.__traceback__)) await msg.edit(content="Failed to fetch data from Origin. Check log for more details.") return url_base = "https://www.origin.com/gbr/en-us/store" if data['success'] is False: await msg.edit(content="Failed to fetch data from Origin\n" "Reason: {}".format(data['reason'])) return count = 0 limit = 5 embed = discord.Embed(title="Origin Search Results for '{}'".format(search_term), colour=discord.Colour.orange()) if len(data['results']) > 0: for item in data['results']: embed.add_field(name=item['name'], value="Description: {}\n" "Price: {} {}\n" "Type: {}\n" "URL: {}{}" "".format(item['desc'], item['price'], item['currency'], item['type'], url_base, item['url_end'])) count += 1 if count == limit: break else: await msg.edit(content="No Results for Origin Search '{}'".format(search_term)) return await msg.edit(embed=embed)
def playstation_search(platform, term): if platform == "PS4": s_url = Playstation.format_url(["games", "bundles"], ["ps4"], term) elif platform == "PS3": s_url = Playstation.format_url(["games", "bundles"], ["ps3"], term) else: Logger.write("Invalid platform '{}' given to playstation_search function in games.py".format(platform)) return discord.Embed(title="Error whilst fetching results, Admin please check bot logs", colour=discord.Colour.red()) url_base = "https://store.playstation.com" search_data = Playstation.get_data(s_url) if search_data == "Empty": return discord.Embed(title="Search found no results", colour=discord.Colour.red(), description="Try checking your spellings and try again.") elif search_data == "Error": return discord.Embed(title="Error occurred whilst fetching results", colour=discord.Colour.red(), description="Try again later.") results = discord.Embed(title="{} PSN Search for '{}'".format(platform, term), colour=discord.Colour.dark_blue(), description="Search results from Playstation Store UK") count = 0 limit = 5 for game in search_data: count += 1 if count == limit: break results.add_field(name="{}\n".format(game['title']), value="Price: {}\n" "Link: {}\n" "".format(game['price'], (url_base + game['id']))) return results
def ensure_all_fields_server(self): servers = self.guilds fields = \ { "tracking": { "last_message": False, # track last message from users in db "ignore_categories": [] # categories to ignore tracking in }, "invites": { "log": None, # channel to log to "ignore_channels": [], # don't delete invites in these channels "ignore_categories": [], # don't delete invites in these categories "ignore_roles": [] # don't delete invites from users with these roles }, "logging": { "join_leave_log": None, # channel to log joins/leaves to "kick_ban_log": None # channel to log kicks/bans to }, "anti-raid": { "lockdown_categories": [], # categories to lockdown "lockdown_channels": [], # channels to indiviaully lockdown "lockdown_roles": [], # roles to enforce lockdown on "caution": True, # if true kick, if false ban } } for server in servers: gid = str(server.id) # print(gid) try: self.servers_config[gid] except KeyError: self.servers_config[gid] = fields continue for top_field in fields: if top_field in self.servers_config[gid]: for inner_field in fields[top_field]: if inner_field not in self.servers_config[gid][ top_field]: self.servers_config[gid][top_field][ inner_field] = fields[top_field][inner_field] Logger.write( "Servers.json - Added inner field '{}' to category '{}'" "".format(inner_field, top_field)) else: self.servers_config[top_field] = {} Logger.write( "Servers.json - Added category '{}'".format(top_field)) for inner_field in fields[top_field]: if inner_field not in self.servers_config[gid][ top_field]: self.servers_config[gid][top_field][ inner_field] = fields[top_field][inner_field] Logger.write( "Servers.json - Added inner field '{}' to category '{}'" "".format(inner_field, top_field))
async def reload(self, ctx, *, cog: str): """Reload a cog""" ext_list = self.bot.extensions cog_list = [cog for cog in ext_list] cog_n = "cogs.{}".format(cog) if cog_n in cog_list: try: self.bot.unload_extension(cog_n) except Exception as e: Logger.write(e) await ctx.send("Failed to unload cog '{}'".format(cog)) return else: await ctx.send("No loaded cogs called '{}'".format(cog)) return try: self.bot.load_extension(cog_n) await ctx.send("Successfully reloaded cog '{}'".format(cog)) except Exception as e: Logger.write(e) await ctx.send("Failed to reload cog '{}'") return
def ensure_all_fields(settings_data: dict): fields = \ { "keys": { "token": None }, "cogs": { }, "reddit": { "username": None, "password": None, "client_id": None, "client_secret": None, "user_agent": None, "post_title": None, "post_url": None } } sd_len = len(settings_data) if sd_len == 0: settings_data = fields return settings_data else: for top_field in fields: if top_field in settings_data: for inner_field in fields[top_field]: if inner_field not in settings_data[top_field]: settings_data[top_field][inner_field] = None Logger.write( "Settings.json - Added inner field '{}' to category '{}'" .format(inner_field, top_field)) else: settings_data[top_field] = {} Logger.write("Settings.json - Added category '{}'".format( top_field)) for inner_field in fields[top_field]: if inner_field not in settings_data[top_field]: settings_data[top_field][inner_field] = None Logger.write( "Settings.json - Added inner field '{}' to category '{}'" .format(inner_field, top_field)) return settings_data
def ensure_all_fields(settings_data): fields = \ { "keys": { "token": None, "itad-api-key": None }, "cogs": {}, "info": { "start-time": None, "reconnect-time": None } } sd_len = len(settings_data) if sd_len == 0: settings_data = fields return settings_data else: for top_field in fields: if top_field in settings_data: for inner_field in fields[top_field]: if inner_field not in settings_data[top_field]: settings_data[top_field][inner_field] = None Logger.write( "Settings.json - Added inner field '{}' to category '{}'" .format(inner_field, top_field)) else: settings_data[top_field] = {} Logger.write("Settings.json - Added category '{}'".format( top_field)) for inner_field in fields[top_field]: if inner_field not in settings_data[top_field]: settings_data[top_field][inner_field] = None Logger.write( "Settings.json - Added inner field '{}' to category '{}'" .format(inner_field, top_field)) return settings_data
async def emotepls(self, ctx, *, message_id: str): """Steal emotes from a message Input must be a message id""" msg_channel = ctx.channel try: int(message_id) except ValueError: await ctx.send("`{}` is an invalid message id!".format(message_id)) return channels = ctx.guild.text_channels message = None try: message = await msg_channel.fetch_message(message_id) except discord.NotFound: pass if message is None: for channel in channels: if channel.category_id in self.bot.servers_config[str(ctx.guild.id)]['tracking']['ignore_categories']: continue if channel == msg_channel: continue try: message = await channel.fetch_message(message_id) break except discord.NotFound: continue if message is None: await ctx.send("Couldn't find message with the id `{}`!".format(message_id)) return custom_emojis = re.findall(r'<\w*:\w*:\d*>', message.content) custom_emojis = list(dict.fromkeys(custom_emojis)) if len(custom_emojis) >= 25: await ctx.send("Message contains too many emojis. (26 or more)") return result = discord.Embed(title="Emojis found in message with id '{}'".format(message_id)) if len(custom_emojis) > 0: for emote in custom_emojis: file_type = "png" is_animated = str(emote.split(":")[0]).replace("<", "") if len(is_animated) != 0: file_type = "gif" emoji_id = str(emote.split(":")[-1]).replace(">", "") link = "<https://cdn.discordapp.com/emojis/{}.{}?v=1>".format(emoji_id, file_type) result.add_field(name="{}".format(str(emote.split(":")[-2])), value="[Link]({})".format(link)) await ctx.send(embed=result) reactions = message.reactions if len(reactions) != 0: reacts = discord.Embed(title="Reactions to message with id '{}'".format(message_id)) for reaction in reactions: try: link = "<https://cdn.discordapp.com/emojis/{}.png?v=1>".format(reaction.emoji.id) reacts.add_field(name="{}".format(reaction.emoji.name), value="[Link]({})".format(link)) except Exception as e: Logger.write(e) continue if len(reacts.fields) >= 1: await ctx.send(embed=reacts)
async def log(self, ctx): """DM latest log file""" log_file = os.path.join(self.bot.base_directory, "logs", Logger.get_filename()) await ctx.author.send(file=discord.File(log_file)) await ctx.send("DM'd latest log file <:somewhere_nice:766664959979159553>")
def run(self): first_time = False s_data = {} """First time run check""" if os.path.isfile(IO.settings_file_path) is False: Logger.write_and_print("First Time Run") configs_f = os.path.join(self.base_directory, "configs") if not os.path.exists(configs_f): os.mkdir(configs_f) first_time = True else: s_data = IO.read_settings_as_json() if s_data is None: raise Exception(IO.settings_fail_read) s_data = self.ensure_all_fields(s_data) """Load cogs""" folder_cogs = self.get_cogs_in_folder() for folder_cog in folder_cogs: cog_path = "cogs.{}".format(folder_cog) if first_time is True: s_data['cogs'][folder_cog] = True else: try: should_load = s_data['cogs'][folder_cog] except KeyError: Logger.write_and_print("New Cog '{}'".format(folder_cog)) s_data['cogs'][folder_cog] = True should_load = True if should_load is True: try: self.load_extension(cog_path) except Exception as exc: print("Failed to load cog '{}', Reason: {}".format( folder_cog, type(exc).__name__)) Logger.write(exc) s_data['cogs'][folder_cog] = False """Read in discord token""" if first_time is True: if IO.write_settings(s_data) is False: raise Exception(IO.settings_fail_write) token = None else: token = s_data['keys']['token'] """Clean up removed cogs from settings""" r_cogs = self.get_cogs_in_folder() f_cogs = self.get_cogs_in_settings() for f_cog in f_cogs: if f_cog not in r_cogs: Logger.write_and_print( "Cog '{}' no longer exists, removing settings entry". format(f_cog)) del s_data['cogs'][f_cog] """Write settings to file""" if IO.write_settings(s_data) is False: raise Exception(IO.settings_fail_write) if token: self.update_json_time(update_start_time=True) super().run(token) else: Logger.write_and_print( "Token is not set! Go to {} and change the token parameter!" "".format(IO.settings_file_path))
from traceback import format_exception from os import chdir, path from argparse import ArgumentParser from discord.ext import commands from cogs.utils.logger import Logger from cogs.utils.config import Config logger = Logger(__name__) __VERSION_NUMBER__ = (0, 1, 0) __VERSION__ = ".".join([str(y) for y in __VERSION_NUMBER__]) _startup_msg = "Starting Nukebot Version {0}".format(__VERSION__) print(_startup_msg) logger.info(_startup_msg) directory = path.dirname(path.realpath(__file__)) chdir(directory) def parse_cmd_arguments(): # allows for arguments parser = ArgumentParser(description="nukebot") parser.add_argument( "--reset-config", # Allows for Testing of mac related code action="store_true", help="Reruns the setup") return parser args = parse_cmd_arguments().parse_args()
async def show(self, ctx): """Show the current server settings""" settings_embed = discord.Embed(title="{} Server Settings".format(ctx.guild.name), colour=discord.Colour.gold()) config = self.bot.servers_config[str(ctx.guild.id)] for top_setting in config: field_name = self.capitalise_every_word(top_setting) field_text = "" for inner_setting in config[top_setting]: field_text += "{}:\n".format(self.capitalise_every_word(inner_setting, "_")) inner_value = config[top_setting][inner_setting] if isinstance(inner_value, bool): normal_inner_value = str(inner_value) elif isinstance(inner_value, type(None)): normal_inner_value = "Not set" elif isinstance(inner_value, int): normal_inner_value = "{} ".format(ctx.guild.get_channel(inner_value).mention) elif isinstance(inner_value, list): list_of = str(inner_setting).split("_")[1:][0] if len(inner_value) == 0: normal_inner_value = "None set" elif list_of == "categories": names_list = [] for value in inner_value: try: names_list.append(ctx.guild.get_channel(value).name) except AttributeError as e: Logger.write_and_print("Couldn't find category with id '{}'".format(value)) Logger.write_and_print(e) continue normal_inner_value = ", ".join(names_list) elif list_of == "channels": mention_list = [] for value in inner_value: try: mention_list.append(ctx.guild.get_channel(value).mention) except AttributeError as e: Logger.write_and_print("Couldn't find channel with id '{}'".format(value)) Logger.write_and_print(e) continue normal_inner_value = ", ".join(mention_list) elif list_of == "roles": mention_list = [] for value in inner_value: try: mention_list.append(ctx.guild.get_role(value).mention) except AttributeError as e: Logger.write_and_print("Couldn't find role with id '{}'".format(value)) Logger.write_and_print(e) continue normal_inner_value = ", ".join(mention_list) else: normal_inner_value = "Unhandled list of {}".format(list_of) else: normal_inner_value = "Unhandled inner type of {}".format(type(inner_value)) field_text += "{}\n\n".format(normal_inner_value) settings_embed.add_field(name=field_name, value=field_text) await ctx.send(embed=settings_embed)