diff --git a/cogs/audio.py b/cogs/audio.py index 6c4a8ebc5..f1568d63a 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -41,7 +41,6 @@ class Audio: self.playlist = [] self.current = -1 #current track index in self.playlist self.downloader = {"DONE" : False, "TITLE" : False, "ID" : False, "URL" : False, "DURATION" : False, "DOWNLOADING" : False} - self.quit_manager = False self.skip_votes = [] self.sing = ["https://www.youtube.com/watch?v=zGTkAVsrfg8", "https://www.youtube.com/watch?v=cGMWL8cOeAU", @@ -422,7 +421,7 @@ class Audio: return False async def queue_manager(self): - while not self.quit_manager: + while "Audio" in self.bot.cogs: if self.queue and not self.music_player.is_playing(): new_link = self.queue[0] self.queue.pop(0) @@ -453,10 +452,7 @@ class Audio: async def incoming_messages(self, msg): # Workaround, need to fix if msg.author.id != self.bot.user.id: - cmds = ("unload cogs.audio", "reload cogs.audio") - if msg.content in cmds: - self.quit_manager = True if msg.channel.is_private and msg.attachments != []: await self.transfer_playlist(msg) if not msg.channel.is_private: diff --git a/cogs/general.py b/cogs/general.py index 58210f3b7..aef8a356b 100644 --- a/cogs/general.py +++ b/cogs/general.py @@ -133,30 +133,50 @@ class General: await self.bot.say("http://lmgtfy.com/?q=" + text) @commands.command(no_pm=True, hidden=True) - async def hug(self, member : discord.Member = None): + async def hug(self, user : discord.Member = None): """Because everyone likes hugs""" - await self.bot.say("(っ´▽`)っ" + " *" + member.name + "*") + await self.bot.say("(っ´▽`)っ" + " *" + user.name + "*") @commands.command(pass_context=True, no_pm=True) - async def info(self, ctx, member : discord.Member = None): - """Shows member's information""" + async def info(self, ctx, user : discord.Member = None): + """Shows users's informations""" author = ctx.message.author - if not member: - member = author + if not user: + user = author roles = [] - for m in member.roles: + for m in user.roles: if m.name != "@everyone": roles.append('"' + m.name + '"') #.replace("@", "@\u200b") if not roles: roles = ["None"] data = "```\n" - data += "Name: " + member.name + "\n" - data += "ID: " + member.id + "\n" - data += "Joined: " + str(member.joined_at) + "\n" + data += "Name: " + user.name + "\n" + data += "ID: " + user.id + "\n" + data += "Joined: " + str(user.joined_at) + "\n" data += "Roles: " + " ".join(roles) + "\n" - data += "Avatar: " + member.avatar_url + "\n" + data += "Avatar: " + user.avatar_url + "\n" data += "```" await self.bot.say(data) + @commands.command(pass_context=True, no_pm=True) + async def server(self, ctx): + """Shows server's informations""" + server = ctx.message.server + online = str(len([m.status for m in server.members if str(m.status) == "online" or str(m.status) == "idle"])) + total = str(len(server.members)) + + data = "```\n" + data += "Name: " + server.name + "\n" + data += "ID: " + server.id + "\n" + data += "Region: " + server.region.name + "\n" + data += "Users: " + online + "/" + total + "\n" + data += "Channels: " + str(len(server.channels)) + "\n" + data += "Roles: " + str(len(server.roles)) + "\n" + data += "Created: " + str(server.owner.joined_at) + "\n" + data += "Owner: " + server.owner.name + "\n" + data += "Icon: " + str(server.icon_url) + "\n" + data += "```" + await self.bot.say(data) + @commands.command() async def urban(self, *, search_terms : str): """Urban Dictionary search""" @@ -275,4 +295,4 @@ class NewPoll(): def setup(bot): n = General(bot) bot.add_listener(n.check_poll_votes, "on_message") - bot.add_cog(n) + bot.add_cog(n) \ No newline at end of file diff --git a/cogs/mod.py b/cogs/mod.py index d406de517..cfd329c53 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -2,19 +2,16 @@ import discord from discord.ext import commands from .utils import checks from .utils.dataIO import fileIO -import __main__ import os -main_path = os.path.dirname(os.path.realpath(__main__.__file__)) - - class Mod: """Moderation tools.""" def __init__(self, bot): self.bot = bot - self.whitelist_list = fileIO(main_path + "/data/mod/whitelist.json", "load") - self.blacklist_list = fileIO(main_path + "/data/mod/blacklist.json", "load") + self.whitelist_list = fileIO("data/mod/whitelist.json", "load") + self.blacklist_list = fileIO("data/mod/blacklist.json", "load") + self.ignore_list = fileIO("data/mod/ignorelist.json", "load") @commands.command(no_pm=True) @checks.admin_or_permissions(kick_members=True) @@ -130,7 +127,7 @@ class Mod: """Adds user to bot's blacklist""" if user.id not in self.blacklist_list: self.blacklist_list.append(user.id) - fileIO(main_path + "/data/mod/blacklist.json", "save", self.blacklist_list) + fileIO("data/mod/blacklist.json", "save", self.blacklist_list) await self.bot.say("User has been added to blacklist.") else: await self.bot.say("User is already blacklisted.") @@ -140,7 +137,7 @@ class Mod: """Removes user to bot's blacklist""" if user.id in self.blacklist_list: self.blacklist_list.remove(user.id) - fileIO(main_path + "/data/mod/blacklist.json", "save", self.blacklist_list) + fileIO("data/mod/blacklist.json", "save", self.blacklist_list) await self.bot.say("User has been removed from blacklist.") else: await self.bot.say("User is not in blacklist.") @@ -162,7 +159,7 @@ class Mod: else: msg = "" self.whitelist_list.append(user.id) - fileIO(main_path + "/data/mod/whitelist.json", "save", self.whitelist_list) + fileIO("data/mod/whitelist.json", "save", self.whitelist_list) await self.bot.say("User has been added to whitelist." + msg) else: await self.bot.say("User is already whitelisted.") @@ -172,11 +169,99 @@ class Mod: """Removes user to bot's whitelist""" if user.id in self.whitelist_list: self.whitelist_list.remove(user.id) - fileIO(main_path + "/data/mod/whitelist.json", "save", self.whitelist_list) + fileIO("data/mod/whitelist.json", "save", self.whitelist_list) await self.bot.say("User has been removed from whitelist.") else: await self.bot.say("User is not in whitelist.") + @commands.group(pass_context=True, no_pm=True) + @checks.admin_or_permissions(manage_channels=True) + async def ignore(self, ctx): + """Adds servers/channels to ignorelist""" + if ctx.invoked_subcommand is None: + + await self.bot.say(self.count_ignored() + "Type help ignore for info.") + + @ignore.command(name="channel", pass_context=True) + async def ignore_channel(self, ctx, channel : discord.Channel=None): + """Ignores channel + + Defaults to current one""" + current_ch = ctx.message.channel + if not channel: + if current_ch.id not in self.ignore_list["CHANNELS"]: + self.ignore_list["CHANNELS"].append(current_ch.id) + fileIO("data/mod/ignorelist.json", "save", self.ignore_list) + await self.bot.say("Channel added to ignore list.") + else: + await self.bot.say("Channel already in ignore list.") + else: + if channel.id not in self.ignore_list["CHANNELS"]: + self.ignore_list["CHANNELS"].append(channel.id) + fileIO("data/mod/ignorelist.json", "save", self.ignore_list) + await self.bot.say("Channel added to ignore list.") + else: + await self.bot.say("Channel already in ignore list.") + + + @ignore.command(name="server", pass_context=True) + async def ignore_server(self, ctx): + """Ignores current server""" + server = ctx.message.server + if server.id not in self.ignore_list["SERVERS"]: + self.ignore_list["SERVERS"].append(server.id) + fileIO("data/mod/ignorelist.json", "save", self.ignore_list) + await self.bot.say("This server has been added to the ignore list.") + else: + await self.bot.say("This server is already being ignored.") + + @commands.group(pass_context=True, no_pm=True) + @checks.admin_or_permissions(manage_channels=True) + async def unignore(self, ctx): + """Removes servers/channels from ignorelist""" + if ctx.invoked_subcommand is None: + await self.bot.say(self.count_ignored() + "Type help unignore for info.") + + @unignore.command(name="channel", pass_context=True) + async def unignore_channel(self, ctx, channel : discord.Channel=None): + """Removes channel from ignore list + + Defaults to current one""" + current_ch = ctx.message.channel + if not channel: + if current_ch.id in self.ignore_list["CHANNELS"]: + self.ignore_list["CHANNELS"].remove(current_ch.id) + fileIO("data/mod/ignorelist.json", "save", self.ignore_list) + await self.bot.say("This channel has been removed from the ignore list.") + else: + await self.bot.say("This channel is not in the ignore list.") + else: + if channel.id in self.ignore_list["CHANNELS"]: + self.ignore_list["CHANNELS"].remove(channel.id) + fileIO("data/mod/ignorelist.json", "save", self.ignore_list) + await self.bot.say("Channel removed from ignore list.") + else: + await self.bot.say("That channel is not in the ignore list.") + + + @unignore.command(name="server", pass_context=True) + async def unignore_server(self, ctx): + """Removes current server from ignore list""" + server = ctx.message.server + if server.id in self.ignore_list["SERVERS"]: + self.ignore_list["SERVERS"].remove(server.id) + fileIO("data/mod/ignorelist.json", "save", self.ignore_list) + await self.bot.say("This server has been removed from the ignore list.") + else: + await self.bot.say("This server is not in the ignore list.") + + def count_ignored(self): + msg = "```Currently ignoring:\n" + msg += str(len(self.ignore_list["CHANNELS"])) + " channels\n" + msg += str(len(self.ignore_list["SERVERS"])) + " servers\n```\n" + return msg + + def check_folders(): folders = ("data", "data/mod/") for folder in folders: @@ -185,13 +270,19 @@ def check_folders(): os.makedirs(folder) def check_files(): - if not os.path.isfile(main_path + "/data/mod/blacklist.json"): - print("Creating empty blacklist.json...") - fileIO(main_path + "/data/mod/blacklist.json", "save", []) + ignore_list = {"SERVERS" : [], "CHANNELS" : []} - if not os.path.isfile(main_path + "/data/mod/whitelist.json"): + if not os.path.isfile("data/mod/blacklist.json"): + print("Creating empty blacklist.json...") + fileIO("data/mod/blacklist.json", "save", []) + + if not os.path.isfile("data/mod/whitelist.json"): print("Creating empty whitelist.json...") - fileIO(main_path + "/data/mod/whitelist.json", "save", []) + fileIO("data/mod/whitelist.json", "save", []) + + if not os.path.isfile("data/mod/ignorelist.json"): + print("Creating empty ignorelist.json...") + fileIO("data/mod/ignorelist.json", "save", ignore_list) def setup(bot): check_folders() diff --git a/red.py b/red.py index 4e6f64f74..72ae46126 100644 --- a/red.py +++ b/red.py @@ -9,6 +9,7 @@ import copy import glob import os import time +import sys # # Red, a Discord bot by Twentysix, based on discord.py and its command extension @@ -26,7 +27,7 @@ Red - A multifunction Discord bot by Twentysix formatter = commands.HelpFormatter(show_check_failure=False) bot = commands.Bot(command_prefix=["_"], formatter=formatter, - description=description, pm_help=True) + description=description, pm_help=None) lock = False @@ -65,6 +66,13 @@ async def on_message(message): if author.id not in mod.whitelist_list: return + if not message.channel.is_private: + if message.server.id in mod.ignore_list["SERVERS"]: + return + + if message.channel.id in mod.ignore_list["CHANNELS"]: + return + await bot.process_commands(message) @bot.command() @@ -168,6 +176,18 @@ async def shutdown(): """Shuts down Red""" exit(1) +@bot.command() +@checks.is_owner() +async def join(invite_url : discord.Invite): + """Joins new server""" + try: + await bot.accept_invite(invite_url) + await bot.say("Server joined.") + except discord.NotFound: + await bot.say("The invite was invalid or expired.") + except discord.HTTPException: + await bot.say("I wasn't able to accept the invite. Try again.") + @bot.command() @checks.is_owner() async def setprefix(*text): @@ -237,9 +257,6 @@ def check_configs(): settings_path = "data/red/settings.json" settings = {"EMAIL" : "EmailHere", "PASSWORD" : "PasswordHere", "OWNER" : "id_here", "PREFIXES" : [], "ADMIN_ROLE" : "Transistor", "MOD_ROLE" : "Process"} if not os.path.isfile(settings_path): - print("Creating new settings.json...") - with open(settings_path, "w") as f: - f.write(json.dumps(settings)) print("Red - First run configuration") print("If you don't have one, create a NEW ACCOUNT for Red. Do *not* use yours. (https://discordapp.com)") @@ -255,7 +272,7 @@ def check_configs(): print("\nChoose a prefix (or multiple ones, one at once) for the commands. Type exit when you're done. Example prefix: !") settings["PREFIXES"] = [] new_prefix = "" - while new_prefix.lower() != "exit": + while new_prefix.lower() != "exit" or settings["PREFIXES"] == []: new_prefix = input("Prefix> ") if new_prefix.lower() != "exit" and new_prefix != "": settings["PREFIXES"].append(new_prefix) @@ -303,6 +320,14 @@ def set_cog(cog, value): f.write(json.dumps(data)) def load_cogs(): + try: + if sys.argv[1] == "--no-prompt": + no_prompt = True + else: + no_prompt = False + except: + no_prompt = False + with open('data/red/cogs.json', "r") as f: data = json.load(f) register = tuple(data.keys()) #known cogs @@ -320,17 +345,18 @@ def load_cogs(): print(e) failed.append(extension) else: - print("\nNew extension: " + extension) - print("Load it?(y/n)") - if get_answer(): - data[extension] = True - try: - bot.load_extension(extension) - except Exception as e: - print(e) - failed.append(extension) - else: - data[extension] = False + if not no_prompt: + print("\nNew extension: " + extension) + print("Load it?(y/n)") + if get_answer(): + data[extension] = True + try: + bot.load_extension(extension) + except Exception as e: + print(e) + failed.append(extension) + else: + data[extension] = False if extensions: with open('data/red/cogs.json', "w") as f: @@ -342,12 +368,26 @@ def load_cogs(): print(m + " ", end="") print("\n") -check_folders() -check_configs() -settings = load_settings() - -if __name__ == '__main__': +def main(): + global settings + check_folders() + check_configs() + settings = load_settings() checks.owner = settings["OWNER"] load_cogs() bot.command_prefix = settings["PREFIXES"] - bot.run(settings['EMAIL'], settings['PASSWORD']) + yield from bot.login(settings["EMAIL"], settings["PASSWORD"]) + yield from bot.connect() + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + try: + loop.run_until_complete(main()) + except discord.LoginFailure: + print("Invalid login credentials. Restart Red and configure it properly.") + os.remove('data/red/settings.json') # Hopefully this won't backfire in case of discord servers' problems + except Exception as e: + print(e) + loop.run_until_complete(bot.logout()) + finally: + loop.close()