From d906b46daf9b1d41b0713aaae726ccc5b8ad3692 Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 14:00:24 -0500 Subject: [PATCH 1/9] Changed notifications settings so that a mod can set a certain channel, for all notifications --- cogs/mod.py | 9 +++++++++ cogs/picarto.py | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cogs/mod.py b/cogs/mod.py index 907416e..d63fe81 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -12,6 +12,15 @@ class Mod: def __init__(self, bot): self.bot = bot + + @commands.command(pass_context=True, no_pm=True) + @checks.customPermsOrRole(kick_members=True) + async def alerts(self, ctx, channel = discord.Channel) + """This command is used to set a channel as the server's 'notifications' channel + Any notifications (like someone going live on Twitch, or Picarto) will go to that channel""" + server_alerts = config.getContent('server_alerts') or {} + server_alerts[ctx.message.server.id] = ctx.message.channel.id + @commands.command(pass_context=True, no_pm=True) @checks.customPermsOrRole(kick_members=True) async def usernotify(self, ctx, on_off:str): diff --git a/cogs/picarto.py b/cogs/picarto.py index cb2028f..d0d2594 100644 --- a/cogs/picarto.py +++ b/cogs/picarto.py @@ -41,8 +41,10 @@ class Picarto: online = await check_online(user) if not live and notify and online: - for server_id, channel_id in r['servers'].items(): + for server_id in r['servers'].items(): server = self.bot.get_server(server_id) + server_alerts = config.getContent('server_alerts') or {} + channel_id = server_alerts.get(server_id) or server_id channel = self.bot.get_channel(channel_id) member = discord.utils.find(lambda m: m.id == m_id, server.members) @@ -53,6 +55,8 @@ class Picarto: elif live and not online: for server_id, channel_id in r['servers'].items(): server = self.bot.get_server(server_id) + server_alerts = config.getContent('server_alerts') or {} + channel_id = server_alerts.get(server_id) or server_id channel = self.bot.get_channel(channel_id) member = discord.utils.find(lambda m: m.id == m_id, server.members) From 31459b8f1828e8deae2f4291bbabe5579cefa718 Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 14:00:55 -0500 Subject: [PATCH 2/9] corrected syntax error --- cogs/mod.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cogs/mod.py b/cogs/mod.py index d63fe81..f40ab89 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -15,7 +15,7 @@ class Mod: @commands.command(pass_context=True, no_pm=True) @checks.customPermsOrRole(kick_members=True) - async def alerts(self, ctx, channel = discord.Channel) + async def alerts(self, ctx, channel = discord.Channel): """This command is used to set a channel as the server's 'notifications' channel Any notifications (like someone going live on Twitch, or Picarto) will go to that channel""" server_alerts = config.getContent('server_alerts') or {} From 12f8fb3964ee24c01e38c58d0ca3b292fa875166 Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 14:02:47 -0500 Subject: [PATCH 3/9] Corrected which channel's ID's are saved --- cogs/mod.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cogs/mod.py b/cogs/mod.py index f40ab89..715bf3d 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -19,7 +19,9 @@ class Mod: """This command is used to set a channel as the server's 'notifications' channel Any notifications (like someone going live on Twitch, or Picarto) will go to that channel""" server_alerts = config.getContent('server_alerts') or {} - server_alerts[ctx.message.server.id] = ctx.message.channel.id + server_alerts[ctx.message.server.id] = channel.id + await self.bot.say("I have just changed this server's 'notifications' channel" + "All notifications will now go to {}".format(channel)) @commands.command(pass_context=True, no_pm=True) @checks.customPermsOrRole(kick_members=True) From 0f1e566b04ddae366f784cf12da5b8a8aad2feb9 Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 14:04:25 -0500 Subject: [PATCH 4/9] Corrected syntax error --- cogs/mod.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cogs/mod.py b/cogs/mod.py index 715bf3d..ca12e26 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -15,7 +15,7 @@ class Mod: @commands.command(pass_context=True, no_pm=True) @checks.customPermsOrRole(kick_members=True) - async def alerts(self, ctx, channel = discord.Channel): + async def alerts(self, ctx, channel: discord.Channel): """This command is used to set a channel as the server's 'notifications' channel Any notifications (like someone going live on Twitch, or Picarto) will go to that channel""" server_alerts = config.getContent('server_alerts') or {} From dee1b616f28103154e7cdf746526562e9fac56c1 Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 14:33:19 -0500 Subject: [PATCH 5/9] Changed which endpoint was checked, so there's no need to make an http request for every user to check if they are online --- cogs/mod.py | 4 ++-- cogs/picarto.py | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cogs/mod.py b/cogs/mod.py index ca12e26..d941cae 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -21,7 +21,7 @@ class Mod: server_alerts = config.getContent('server_alerts') or {} server_alerts[ctx.message.server.id] = channel.id await self.bot.say("I have just changed this server's 'notifications' channel" - "All notifications will now go to {}".format(channel)) + "\nAll notifications will now go to `{}`".format(channel)) @commands.command(pass_context=True, no_pm=True) @checks.customPermsOrRole(kick_members=True) @@ -33,7 +33,7 @@ class Mod: notifications = config.getContent('user_notifications') or {} notifications[ctx.message.server.id] = on_off config.saveContent('user_notifications',notifications) - fmt = "notify, in this channel" if on_off else "not notify" + fmt = "notify" if on_off else "not notify" await self.bot.say("This server will now {} if someone has joined or left".format(fmt)) @commands.group(pass_context=True, no_pm=True) diff --git a/cogs/picarto.py b/cogs/picarto.py index d0d2594..b6aa6f2 100644 --- a/cogs/picarto.py +++ b/cogs/picarto.py @@ -14,16 +14,19 @@ base_url = 'https://ptvappapi.picarto.tv' key = '03e26294-b793-11e5-9a41-005056984bd4' -async def check_online(stream): +async def online_users(): try: - url = '{}/channel/{}?key={}'.format(base_url, stream, key) + url = '{}/online/all?key={}'.format(base_url, key) with aiohttp.ClientSession(headers={"User-Agent": "Bonfire/1.0.0"}) as s: async with s.get(url) as r: response = await r.text() - return json.loads(response).get('is_online') + return json.loads(response) except: - return False + return {} +def check_online(online_channels, channel): + matches = [stream for stream in online_channels if stream['channel_name'].lower() == channel.lower()] + return len(matches) > 0 class Picarto: def __init__(self, bot): @@ -33,12 +36,13 @@ class Picarto: await self.bot.wait_until_ready() while not self.bot.is_closed: picarto = config.getContent('picarto') or {} + online_users = await online_users() for m_id, r in picarto.items(): url = r['picarto_url'] live = r['live'] notify = r['notifications_on'] user = re.search("(?<=picarto.tv/)(.*)", url).group(1) - online = await check_online(user) + online = check_online(online_users, user) if not live and notify and online: for server_id in r['servers'].items(): From 3fde0c20bad71468a364aba7bbd349e2f1fd6471 Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 21:12:21 -0500 Subject: [PATCH 6/9] Added the log file to the files to ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5d6c1a9..74bdfd6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ autoupdate.php error_log images/* .ftpquota +bonfire.log From 96c58d4341eb4aef9f140d04dc635d585f8e7032 Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 21:13:02 -0500 Subject: [PATCH 7/9] Changing directory to the one the main file is in, so relative paths can be used reliably. This allows the code to easily be used by others if needed --- bot.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bot.py b/bot.py index 709e635..9d71abf 100644 --- a/bot.py +++ b/bot.py @@ -5,6 +5,8 @@ import traceback import logging import datetime import pendulum +import os + from discord.ext import commands from cogs.utils import config @@ -25,6 +27,7 @@ extensions = ['cogs.interaction', bot = commands.Bot(command_prefix=config.commandPrefix, description=config.botDescription, pm_help=None) discord_logger = logging.getLogger('discord') discord_logger.setLevel(logging.WARNING) +os.chdir(os.path.dirname(os.path.realpath(__file__))) log = logging.getLogger() log.setLevel(logging.INFO) @@ -98,7 +101,7 @@ async def on_command_error(error, ctx): await bot.send_message(ctx.message.channel, error) elif not isinstance(error, commands.CommandNotFound): now = datetime.datetime.now() - with open("/home/phxntx5/public_html/Bonfire/error_log", 'a') as f: + with open("error_log", 'a') as f: print("In server '{0.message.server}' at {1}\nFull command: `{0.message.content}`".format(ctx, str(now)), file=f) try: From 89ca7b0469eb861e2610824456d1c603602eb828 Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 21:13:35 -0500 Subject: [PATCH 8/9] Changed pathing to relative pathing --- cogs/core.py | 6 ++---- cogs/owner.py | 8 +++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/cogs/core.py b/cogs/core.py index d4fe726..2947f34 100644 --- a/cogs/core.py +++ b/cogs/core.py @@ -77,8 +77,7 @@ class Core: async def doggo(self, ctx): """Use this to print a random doggo image. Doggo is love, doggo is life.""" - os.chdir('/home/phxntx5/public_html/Bonfire/images') - f = glob.glob('doggo*')[random.randint(0, len(glob.glob('doggo*')) - 1)] + f = glob.glob('images/doggo*')[random.randint(0, len(glob.glob('doggo*')) - 1)] with open(f, 'rb') as f: await self.bot.upload(f) @@ -87,8 +86,7 @@ class Core: async def snek(self, ctx): """Use this to print a random snek image. Sneks are o3o""" - os.chdir('/home/phxntx5/public_html/Bonfire/images') - f = glob.glob('snek*')[random.randint(0, len(glob.glob('snek*')) - 1)] + f = glob.glob('images/snek*')[random.randint(0, len(glob.glob('snek*')) - 1)] with open(f, 'rb') as f: await self.bot.upload(f) diff --git a/cogs/owner.py b/cogs/owner.py index 74df817..31af3d0 100644 --- a/cogs/owner.py +++ b/cogs/owner.py @@ -32,8 +32,7 @@ class Owner: @commands.check(checks.isOwner) async def adddoggo(self, url: str): """Saves a URL as an image to add for the doggo command""" - os.chdir('/home/phxntx5/public_html/Bonfire/images') - local_path = 'doggo{}.jpg'.format(len(glob.glob('doggo*'))) + local_path = 'images/doggo{}.jpg'.format(len(glob.glob('doggo*'))) with aiohttp.ClientSession() as s: async with s.get(url) as r: val = await r.read() @@ -46,8 +45,7 @@ class Owner: @commands.check(checks.isOwner) async def addsnek(self, url: str): """Saves a URL as an image to add for the snek command""" - os.chdir('/home/phxntx5/public_html/Bonfire/images') - local_path = 'snek{}.jpg'.format(len(glob.glob('snek*'))) + local_path = 'images/snek{}.jpg'.format(len(glob.glob('snek*'))) with aiohttp.ClientSession() as s: async with s.get(url) as r: val = await r.read() @@ -90,7 +88,7 @@ class Owner: @commands.check(checks.isOwner) async def avatar(self, content: str): """Changes the avatar for the bot to the filename following the command""" - file = '/home/phxntx5/public_html/bot/images/' + content + file = 'images/' + content with open(file, 'rb') as fp: await self.bot.edit_profile(avatar=fp.read()) From a65c1b8f9ca4183dcfa93aa46bf7a881d61c556c Mon Sep 17 00:00:00 2001 From: Phxntxm Date: Thu, 11 Aug 2016 21:14:30 -0500 Subject: [PATCH 9/9] Using relative pathing; also adding failure messages upon attempting to run the bot without a valid config.yml file --- cogs/utils/config.py | 50 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/cogs/utils/config.py b/cogs/utils/config.py index 9398e23..a874c91 100644 --- a/cogs/utils/config.py +++ b/cogs/utils/config.py @@ -4,39 +4,51 @@ import json loop = asyncio.get_event_loop() -with open("/home/phxntx5/public_html/Bonfire/config.yml", "r") as f: - global_config = yaml.load(f) - -connection = None +try: + with open("config.yml", "r") as f: + global_config = yaml.load(f) +except FileNotFoundError: + print("You have no config file setup! Please use config.yml.sample to setup a valid config file") + quit() botDescription = global_config.get("description") commandPrefix = global_config.get("command_prefix", "!") -discord_bots_key = global_config.get('discord_bots_key') +discord_bots_key = global_config.get('discord_bots_key', "") battleWins = global_config.get("battleWins", []) defaultStatus = global_config.get("default_status", "") -botToken = global_config.get("bot_token", "") -owner_ids = global_config.get("owner_id", []) +try: + botToken = global_config["bot_token"] +except KeyError: + print("You have no bot_token saved, this is a requirement for running a bot.") + print("Please use config.yml.sample to setup a valid config file") + quit() + +try: + owner_ids = global_config["owner_id"] +except KeyError: + print("You have no owner_id saved! You're not going to be able to run certain commands without this.") + print("Please use config.yml.sample to setup a valid config file") + quit() def saveContent(key: str, content): - with open("/home/phxntx5/public_html/Bonfire/config.json", "r+") as jf: - data = json.load(jf) - jf.seek(0) - data[key] = content + with open("config.json", "a+") as jf: try: - json.dumps(data) - except: - return False - else: - jf.truncate() - json.dump(data, jf, indent=4) - return True + data = json.load(jf) + except json.JSONDecodeError: + data = {} + data[key] = content + jf.seek(0) + jf.truncate() + json.dump(data, jf, indent=4) def getContent(key: str): try: - with open("/home/phxntx5/public_html/Bonfire/config.json", "r+") as jf: + with open("config.json", "r+") as jf: return json.load(jf)[key] except KeyError: return None + except FileNotFoundError: + return None