async def purge(self, ctx, limit: int=200): def predicate(m): return m.id != ctx.message.id and (m.author.id == ctx.me.id or ctx.me in m.mentions) try: await ctx.channel.purge(limit=limit, check=predicate) except Exception: fprint(f"Failed to delete message in channel #{ctx.channel.name} ({ctx.channel.id})", file=sys.stderr) await try_react(ctx, "❗") else: await try_react(ctx, "✅")
async def load_cogs(self, ctx, *cogs): try: if len(cogs) == 0: cogs = [cog.__module__ for cog in ctx.bot.cogs.values()] cogs.remove("src.cogs.owner") else: cogs = [cog for cog in map(lambda c: "src.cogs." + c, cogs)] for cog in cogs: assert cog not in [cog.__module__ for cog in ctx.bot.cogs.values()] ctx.bot.load_extension(cog) except AssertionError: await try_react(ctx, "❓") fprint(f"Cannot load cog '{cog}' - Already loaded in the bot.", file=sys.stderr) except ModuleNotFoundError as e: await try_react(ctx, "❓") fprint(f"Cannot load cog '{cog}' - {e.args}", file=sys.stderr) except Exception: await try_react(ctx, "❗") fprint(f"Failed to load cogs ({cog})", file=sys.stderr) print_exc() else: await try_react(ctx, "✅") fprint(f"Successfully loaded cogs ({', '.join(cogs)})")
async def on_command_completion(self, ctx): author = ctx.message.author if await ctx.bot.is_owner(author): return command = ctx.command content = ctx.message.content content.replace(ctx.me.mention, f"@{ctx.me.name}") if len(content) > 100: content = content[:100] + " [...]" fprint( f"{author.name}#{author.discriminator} invoked '{command.name}' command: {content}" )
async def on_command_error(self, ctx, e): if type(e).__name__ in ("CommandNotFound", "CheckFailure", "NotOwner"): return if type(e).__name__ in ("BadArgument", "MissingRequiredArgument"): try: await ctx.send("`%s`" % e) except Exception: traceback.print_exc() return if type(e).__name__ == "CommandInvokeError": if type(e.original).__name__ in ("HTTPException", "NotFound"): return if type(e.original).__name__ == ("ClientException", "Forbidden"): try: await ctx.send("`%s`" % e) except Exception: traceback.print_exc() return fprint(e, file=sys.stderr)
async def on_connect(self): fprint("Connected to Discord...") await self.wait_until_ready() fprint(f"Logged in as: {self.user.name}#{self.user.discriminator}") if len(self.guilds) > 0: guilds = ", ".join([f"\"{g.name}\"" for g in self.guilds[:3]]) fprint(f"Present on {len(self.guilds)} guilds: {guilds}...")
async def reload_cogs(self, ctx, *cogs): try: if len(cogs) == 0: cogs = [cog.__module__ for cog in ctx.bot.cogs.values()] else: cogs = [cog for cog in map(lambda c: "src.cogs." + c, cogs)] for cog in cogs: assert cog in [cog.__module__ for cog in ctx.bot.cogs.values()] ctx.bot.unload_extension(cog) ctx.bot.load_extension(cog) except AssertionError: await try_react(ctx, "❓") fprint(f"Cannot reload cog '{cog}' if not loaded in the bot.") except Exception: await try_react(ctx, "❗") fprint(f"Failed to reload cog ({cog})", file=sys.stderr) print_exc() else: await try_react(ctx, "✅") fprint(f"Successfully reloaded cogs ({', '.join(cogs)})")
async def on_guild_remove(self, guild): fprint(f"Left a guild: '{guild.name}' ({guild.id})") self.db.delete(guild.id)
async def on_guild_join(self, guild): fprint(f"Joined a new guild: '{guild.name}' ({guild.id})") guild_config(self.db, guild.id)
#!/usr/bin/env python3 import sys import traceback import redis from src.bot import Bot from src.utils import fprint from src.const import BOT, TOKEN, REDIS_URL, DEFAULT_COGS db = redis.from_url(REDIS_URL) bot = Bot(db) if __name__ == "__main__": for cog in DEFAULT_COGS: try: bot.load_extension("src.cogs." + cog) except Exception: fprint(f"Failed to load cogs ({cog})", file=sys.stderr) traceback.print_exc() bot.run(TOKEN, bot=BOT, reconnect=True)
async def restart(self, ctx): await try_react(ctx, "👋") await asyncio.sleep(SYNC_TIME) fprint("Restarting...") os.execl(sys.executable, sys.executable, *sys.argv)
async def shutdown(self, ctx): await try_react(ctx, "👋") await asyncio.sleep(SYNC_TIME) await ctx.bot.logout() fprint("Logged out. Shutting down...")
async def update_roles(self, guild): config = guild_config(self.db, guild.id) for channel in guild.text_channels: if int(channel.id) == config.get("channel", 0): break else: if not guild.me.guild_permissions.manage_channels: fprint(f"Couldn't update roles for {guild.name} ({guild.id}):", "Missing permission 'manage_channels'", file=sys.stderr) return try: channel = await guild.create_text_channel("tags") except Exception: return if not guild.me.permissions_in(channel).read_message_history: fprint(f"Couldn't update roles for {guild.name} ({guild.id}):", "Missing permission 'read_message_history'", file=sys.stderr) return async for message in channel.history( limit=500).filter(lambda m: m.author.bot): try: await message.delete() except Exception: fprint(f"Failed to delete message ({message}) in role channel", file=sys.stderr) if not guild.me.permissions_in(channel).send_messages: fprint(f"Couldn't update roles for {guild.name} ({guild.id}):", "Missing permission 'send_messages'", file=sys.stderr) return roles = {} for role in guild.roles: if role.id not in config.get("exceptions", []): roles[role.position] = (role.id, role.name) roles = dict(sorted(roles.items())) role = [] for r in roles.values(): role.append(r[1]) role.pop(0) tags = ["**"] while len(role) > 0: if len(tags[-1] + ", " + role[-1]) < (CHAR_LIMIT - 2): if tags[-1] == "**": tags[-1] += role.pop() else: tags[-1] += ", " + role.pop() else: tags[-1] += "**" tags.append("**") else: tags[-1] += "**" messages = [] for tag in tags: messages += [(await channel.send(content=tag)).id] config["messages"] = messages config["channel"] = channel.id config["roles"] = [ role[0] for role in roles.values() if role[0] not in config.get("exceptions", []) ] guild_config(self.db, guild.id, config) fprint(f"Updated roles for \"{guild.name}\" ({guild.id})")