async def _prefix(self, ctx, *, new_prefix: str = None): """Get prefix and set server prefix. Use the argument 'reset' to reset the guild prefix to default. """ bot = ctx.bot default_prefix = bot.default_prefix if not ctx.guild: if new_prefix: embed = make_embed( msg_type='error', title=f"Prefix can only be changed in guilds.") await ctx.send(embed=embed) else: embed = make_embed(msg_type='info', title=f"Prefix is {default_prefix}") await ctx.send(embed=embed) else: if new_prefix: await ctx.guild_dm.prefix(new_prefix) if new_prefix.lower() == 'reset': new_prefix = bot.default_prefix embed = make_embed(msg_type='success', title=f"Prefix set to {new_prefix}") ctx.bot.prefixes[ctx.guild.id] = new_prefix return await ctx.send(embed=embed) guild_prefix = await ctx.guild_dm.prefix(new_prefix) prefix = guild_prefix if guild_prefix else default_prefix embed = make_embed(msg_type='info', title=f"Prefix is {prefix}") await ctx.send(embed=embed)
async def guild(self, ctx, *, guild: Guild): """Lookup Guild info""" if guild: if guild.unavailable: embed = make_embed(msg_type='error', title='Guild found, but unavailable!') else: embed = make_embed(msg_type='info', thumbnail=guild.icon_url_as(format='png')) date_created = datetime.strftime(guild.created_at, "UTC %Y/%m/%d %H:%M") basic_info = (f"ID: {guild.id}\n" f"Owner: {guild.owner}\n" f"Created: {date_created}\n" f"Region: {guild.region}\n") embed.add_field(name=guild.name, value=basic_info, inline=False) stats_info = (f"Members: {guild.member_count}\n" f"Roles: {len(guild.roles)}\n" f"Text Channels: {len(guild.text_channels)}\n" f"Channel Categories: {len(guild.categories)}") embed.add_field(name='Stats', value=stats_info, inline=False) guild_perms = guild.me.guild_permissions req_perms = ctx.bot.req_perms perms_compare = guild_perms >= req_perms core_dir = ctx.bot.core_dir data_dir = os.path.join(core_dir, '..', 'data') data_file = 'permissions.json' perms_info = f"Value: {guild_perms.value}\n" perms_info += f"Meets Requirements: {perms_compare}\n" with open(os.path.join(data_dir, data_file), "r") as perm_json: perm_dict = json.load(perm_json) for perm, bitshift in perm_dict.items(): if bool((req_perms.value >> bitshift) & 1): if bool((guild_perms.value >> bitshift) & 1): perms_info += ":white_small_square: {}\n".format( perm) else: perms_info += ":black_small_square: {}\n".format( perm) embed.add_field(name='Permissions', value=perms_info, inline=False) bot_list = [m for m in guild.members if m.bot] bot_info = f"Bots: {len(bot_list)}\n" if 1 <= len(bot_list) <= 20: for bot in bot_list: online = bot.status == discord.Status.online status = "\U000025ab" if online else "\U000025aa" bot_info += f"{status} {bot}\n" embed.add_field(name='Bots', value=bot_info, inline=False) else: embed = make_embed(msg_type='error', title='Guild not found') await ctx.send(embed=embed)
async def check_perms( self, ctx, member_or_role: Multi(discord.Member, discord.Role), guild_or_channel: Multi(discord.Guild, discord.TextChannel, discord.VoiceChannel) = None): """Show permissions of a member or role for the guild and channel.""" if guild_or_channel: if isinstance(guild_or_channel, discord.Guild): guild_perms = ctx.guild.me.guild_permissions else: guild_perms = ctx.guild.me.guild_permissions if isinstance(member_or_role, discord.Member): chan_perms = ctx.channel.permissions_for(member_or_role) else: return await ctx.send("Role Permissions aren't done yet.") req_perms = ctx.bot.req_perms g_perms_compare = guild_perms >= req_perms c_perms_compare = chan_perms >= req_perms core_dir = ctx.bot.core_dir data_dir = os.path.join(core_dir, '..', 'data') data_file = 'permissions.json' msg = f"**Guild:**\n{ctx.guild}\nID {ctx.guild.id}\n" msg += f"**Channel:**\n{ctx.channel}\nID {ctx.channel.id}\n" msg += "```py\nGuild | Channel\n" msg += "----------|----------\n" msg += "{} | {}\n".format(guild_perms.value, chan_perms.value) msg += "{0:9} | {1}```".format(str(g_perms_compare), str(c_perms_compare)) y_emj = ":white_small_square:" n_emj = ":black_small_square:" with open(os.path.join(data_dir, data_file), "r") as perm_json: perm_dict = json.load(perm_json) for perm, bitshift in perm_dict.items(): if bool((req_perms.value >> bitshift) & 1): guild_bool = bool((guild_perms.value >> bitshift) & 1) channel_bool = bool((chan_perms.value >> bitshift) & 1) guild_e = y_emj if guild_bool else n_emj channel_e = y_emj if channel_bool else n_emj msg += f"{guild_e} {channel_e} {perm}\n" try: if chan_perms.embed_links: embed = make_embed(msg_type='info', title=f'Permissions for {member_or_role}', content=msg) await ctx.send(embed=embed) else: await ctx.send(msg) except discord.errors.Forbidden: embed = make_embed(msg_type='info', title=f'Permissions for {member_or_role}', content=msg) await ctx.author.send(embed=embed)
async def guild_perms(self, ctx, guild_id=None): """Gets bot's permissions for the guild.""" if not ctx.guild and not guild_id: await ctx.send(embed=make_embed( msg_type='error', title="This is a DM. Please provide ID.")) return if guild_id: guild = ctx.bot.get_guild(int(guild_id)) if not guild: await ctx.send( embed=make_embed(msg_type='error', title="Guild not found") ) return else: guild = ctx.guild guild_perms = guild.me.guild_permissions req_perms = ctx.bot.req_perms perms_compare = guild_perms >= req_perms core_dir = ctx.bot.core_dir data_dir = os.path.join(core_dir, '..', 'data') data_file = 'permissions.json' msg = f"{guild}\nID {guild.id}\n" msg += f"```py\n{guild_perms.value}\n" msg += f"{perms_compare}```" with open(os.path.join(data_dir, data_file), "r") as perm_json: perm_dict = json.load(perm_json) for perm, bitshift in perm_dict.items(): if bool((req_perms.value >> bitshift) & 1): if bool((guild_perms.value >> bitshift) & 1): msg += ":white_small_square: {}\n".format(perm) else: msg += ":black_small_square: {}\n".format(perm) try: if not isinstance(ctx.channel, discord.DMChannel): if not ctx.channel.permissions_for(ctx.guild.me).embed_links: await ctx.send(msg) return embed = make_embed(msg_type='info', title='Guild Permissions', content=msg) await ctx.send(embed=embed) except discord.errors.Forbidden: embed = make_embed(msg_type='info', title='Guild Permissions', content=msg) await ctx.author.send(embed=embed)
async def channel_perms(self, ctx, channel_id=None): """Gets bot's permissions for the channel.""" if channel_id: channel = ctx.bot.get_channel(int(channel_id)) if not channel: await ctx.send(embed=make_embed(msg_type='error', title="Channel not found")) return else: channel = ctx.channel dm_channel = isinstance(channel, discord.DMChannel) me = ctx.bot.user if dm_channel else channel.guild.me chan_perms = channel.permissions_for(me) req_perms = ctx.bot.req_perms perms_compare = chan_perms >= req_perms core_dir = ctx.bot.core_dir data_dir = os.path.join(core_dir, '..', 'data') data_file = 'permissions.json' msg = "" if not dm_channel: msg += f"{channel.guild}\nID {channel.guild.id}\n" msg += f"{channel}\nID {channel.id}\n" msg += f"```py\n{chan_perms.value}\n" msg += f"{perms_compare}```" with open(os.path.join(data_dir, data_file), "r") as perm_json: perm_dict = json.load(perm_json) for perm, bitshift in perm_dict.items(): if bool((req_perms.value >> bitshift) & 1): if bool((chan_perms.value >> bitshift) & 1): msg += f":white_small_square: {perm}\n" else: msg += f":black_small_square: {perm}\n" try: if not isinstance(ctx.channel, discord.DMChannel): if not ctx.channel.permissions_for(ctx.guild.me).embed_links: await ctx.send(msg) return embed = make_embed(msg_type='info', title='Channel Permissions', content=msg) await ctx.send(embed=embed) except discord.errors.Forbidden: embed = make_embed(msg_type='info', title='Channel Permissions', content=msg) await ctx.author.send(embed=embed)
async def _nickname(self, ctx, *, nickname: str): """Sets bot's nickname""" try: await ctx.guild.me.edit(nick=nickname) except discord.Forbidden: embed = make_embed( msg_type='error', title="Failed to set nickname", content=("I'm missing permissions to change my nickname. " "Use **{}get guildperms** to check permissions." "").format(ctx.prefix)) await ctx.send() else: embed = make_embed(msg_type='success', title="Nickname set.") await ctx.send(embed=embed)
async def reload_cm(self, ctx): """Reload Cog Manager.""" bot = ctx.bot try: bot.unload_extension('meowth.core.cog_manager') bot.load_extension('meowth.core.cog_manager') embed = make_embed(msg_type='success', title='Cog Manager reloaded.') await ctx.send(embed=embed) except Exception as e: msg = "{}: {}".format(type(e).__name__, e) embed = make_embed(msg_type='error', title='Error loading Cog Manager', content=msg) await ctx.send(embed=embed)
async def _username(self, ctx, *, username: str): """Sets bot's username""" try: await ctx.bot.user.edit(username=username) except discord.HTTPException: embed = make_embed( msg_type='error', title="Failed to change name", content=("Remember that you can only do it up to 2 times an " "hour. Use nicknames if you need frequent changes. " "**{}set nickname**").format(ctx.prefix)) await ctx.send(embed=embed) else: embed = make_embed(msg_type='success', title="Username set.") await ctx.send(embed=embed)
def make_trade_embed(lister, wanted_pokemon, offered_pokemon, note=None): """Returns a formatted embed message with trade details.""" wants = [ f'{i+1}\u20e3: {pkmn}' for i, pkmn in enumerate(wanted_pokemon) ] fields_obj = { "Wants": '\n'.join(wants), "Offers": offered_pokemon.full_name } if note: fields_obj["Note"] = note return utils.make_embed(title="Pokemon Trade - {}".format( lister.display_name), msg_colour=0x63b2f7, icon=Trade.icon_url, fields=fields_obj, inline=True, footer=lister.display_name, footer_icon=lister.avatar_url_as(format='png', size=256), thumbnail=offered_pokemon.img_url)
async def _game(self, ctx, *, game: str): """Sets the bot's activity""" status = ctx.me.status game = discord.Game(name=game) await ctx.bot.change_presence(status=status, activity=game) embed = make_embed(msg_type='success', title='Game set.') await ctx.send(embed=embed)
async def embed(self, title, description=None, plain_msg='', *, msg_type=None, title_url=None, colour=None, icon=None, thumbnail='', image='', fields: dict = None, footer=None, footer_icon=None, send=True, inline=False): """Send or build an embed using context details.""" embed = make_embed(title=title, content=description, msg_type=msg_type, title_url=title_url, msg_colour=colour, icon=icon, thumbnail=thumbnail, image=image, guild=self.guild) if fields: for key, value in fields.items(): ilf = inline if not isinstance(value, str): ilf = value[0] value = value[1] embed.add_field(name=key, value=value, inline=ilf) if footer: footer = {'text':footer} if footer_icon: footer['icon_url'] = footer_icon embed.set_footer(**footer) if not send: return embed return await self.send(plain_msg, embed=embed)
async def status(self, ctx, *, status: str): """Sets the bot's online status Available statuses: online idle dnd """ statuses = { "online": discord.Status.online, "idle": discord.Status.idle, "dnd": discord.Status.dnd, "invisible": discord.Status.invisible } game = ctx.me.activity try: status = statuses[status.lower()] except KeyError: await ctx.bot.send_cmd_help(ctx) else: await ctx.bot.change_presence(status=status, activity=game) embed = make_embed(msg_type='success', title="Status changed to {}.".format(status)) await ctx.send(embed=embed)
async def _break(self, ctx): """Simulates a sudden disconnection.""" embed = make_embed(msg_type='warning', title='Faking a crash...') try: await ctx.send(embed=embed) except discord.HTTPException: pass await ctx.bot.logout()
async def on_ready(self): intro = "Meowth - Discord bot for Pokemon Go Communities" intro_deco = "{0}\n{1}\n{0}".format('='*len(intro), intro) if not self.launch_time: self.launch_time = datetime.utcnow() if not self.launcher: print(intro_deco) if self.from_restart: print("We're back!\n") else: print("We're on!\n") print(f"Bot Version: {self.version}\n") if self.debug: print(f"Python Version: {self.py_version}") print(f"Discord.py Version: {self.dpy_version}") print(f"Platform: {self.platform}\n") guilds = len(self.guilds) users = len(list(self.get_all_members())) if guilds: print(f"Servers: {guilds}") print(f"Members: {users}") else: print("I'm not in any server yet, so be sure to invite me!") if self.invite_url: print(f"\nInvite URL: {self.invite_url}\n") # load extensions marked for preload in config for ext in self.preload_ext: ext_name = ("meowth.exts."+ext) self.load_extension(ext_name) if self.from_restart: table = self.dbi.table('restart_savedata') table.query.order_by(table['restart_snowflake'], asc=False) table.query.limit(1) last_restart = (await table.query.get())[0] embed = make_embed(title='Restart Complete.', msg_type='success') guild = self.get_guild(last_restart['restart_guild']) if guild: channel = guild.get_channel(last_restart['restart_channel']) if channel: original_message = await channel.fetch_message( last_restart['restart_message']) return await original_message.edit(embed=embed) else: channel = self.get_user(last_restart['restart_by']) if not channel: channel = self.get_user(self.owner) if not channel: return self.logger.error('Bot owner not found.') return await channel.send(embed=embed)
async def runas(self, ctx, member: discord.Member, *, new_cmd): """Run a command as a different member.""" if await ctx.bot.is_owner(member): await ctx.send(embed=make_embed( msg_type='error', title='No, you may not run as owner.')) return ctx.message.content = new_cmd ctx.message.author = member await ctx.bot.process_commands(ctx.message)
async def _shutdown(self, ctx): """Shuts down the bot""" embed = make_embed(title='Shutting down.', msg_colour='red', icon="https://i.imgur.com/uBYS8DR.png") try: await ctx.send(embed=embed) except discord.HTTPException: pass await ctx.bot.shutdown()
async def _stats(self, ctx): """Shows stats about bot""" bot = ctx.bot owner = await bot.get_user_info(ctx.bot.owner) uptime_str = bot.uptime_str cpu_p = await ctx.bot.loop.run_in_executor(None, self.get_cpu) mem = psutil.virtual_memory() mem_p = round((mem.available / mem.total) * 100, 2) bot_process = psutil.Process() ppid = bot_process.ppid() p_mem = bot_process.memory_info().rss swapped = psutil.swap_memory().used data_sizes = {'B': 1, 'KB': 1024, 'MB': 1048576, 'GB': 1073741824} for size, value in data_sizes.items(): if (p_mem / value) > 1 < 1024: p_mem_str = "{} {}".format(round(p_mem / value, 2), size) if (swapped / value) > 1 < 1024: swap_str = "{} {}".format(round(swapped / value, 2), size) member_count = 0 server_count = 0 for guild in bot.guilds: server_count += 1 member_count += guild.member_count msg_table = bot.dbi.table('discord_messages') msg_table.query(msg_table['*'].count) message_count = await msg_table.query.get_value() cmd_table = bot.dbi.table('command_log') cmd_table.query(cmd_table['*'].count) command_count = await cmd_table.query.get_value() embed = make_embed(msg_type='info', title="Bot Statistics") instance_msg = (f"**Owner:** {owner}\n**Uptime:** {uptime_str}\n" f"**Version:** {bot.version}\n" f"**D.Py Ver:** {bot.dpy_version}\n" f"**Python:** {bot.py_version}") session_msg = ( f"**Servers:** {server_count}\n**Members:** {member_count}\n" f"**Messages:** {message_count}\n" f"**Commands:** {command_count}\n" f"**Reconnections:** {bot.resumed_count}") process_msg = (f"**PID:** {ppid}\n**Process RAM:** {p_mem_str}\n" f"**Swap File:** {swap_str}\n**System RAM:** {mem_p}\n" f"**System CPU:** {cpu_p}\n") embed.add_field(name="ACTIVITY", value=session_msg) embed.add_field(name="PROCESS", value=process_msg) embed.add_field(name="INSTANCE", value=instance_msg) try: await ctx.send(embed=embed) except discord.HTTPException: await ctx.send("I need the `Embed links` permission to send this")
async def purge(self, ctx, msg_number: int = 10): """Delete a number of messages from the channel. Default is 10. Max 100.""" if msg_number > 100: embed = make_embed( msg_type='info', title="ERROR", content="No more than 100 messages can be purged at a time.", guild=ctx.guild) await ctx.send(embed=embed) return def is_unpinned(m): return not m.pinned deleted = await ctx.channel.purge(limit=msg_number, check=is_unpinned) embed = make_embed(msg_type='success', title='Deleted {} message{}'.format( len(deleted), "s" if len(deleted) > 1 else "")) result_msg = await ctx.send(embed=embed) await asyncio.sleep(3) await result_msg.delete()
def make_offer_embed(trader, listed_pokemon, offer): return utils.make_embed(title="Pokemon Trade Offer - {}".format( trader.display_name), msg_colour=0x63b2f7, icon=Trade.icon_url, fields={ "You Offered": listed_pokemon.full_name, "They Offer": offer.full_name }, inline=True, footer=trader.display_name, footer_icon=trader.avatar_url_as(format='png', size=256), thumbnail=offer.img_url)
async def _bot_invite(self, ctx, plain_url: bool = False): """Shows bot's invite url""" invite_url = ctx.bot.invite_url if plain_url: await ctx.send("Invite URL: <{}>".format(invite_url)) return else: embed = make_embed(title='Click to invite me to your server!', title_url=invite_url, msg_colour='blue', icon="https://i.imgur.com/DtPWJPG.png") try: await ctx.send(embed=embed) except discord.errors.Forbidden: await ctx.send("Invite URL: <{}>".format(invite_url))
async def _about(self, ctx): """Shows info about the bot""" bot = ctx.bot author_repo = "https://github.com/FoglyOgly" bot_repo = author_repo + "/Meowth" uptime_str = bot.uptime_str owner = await ctx.get.user(ctx.bot.owner) invite_str = "[Invite Me!]({})".format(bot.invite_url) if ctx.guild: prefix = bot.prefixes.get(ctx.guild.id, bot.default_prefix) else: prefix = bot.default_prefix member_count = 0 server_count = 0 server_count = len(bot.guilds) member_count = sum([g.member_count for g in bot.guilds]) about = [ "A Bot for Pokemon Go Communities!", f"**[Docs & Source!]({bot_repo})** | **{invite_str}**\n\n", f"Guild Prefix: `{prefix}`\n", f"Help: `{prefix}help`\n\n", f"**Owner:** {owner}", f"**Uptime:** {uptime_str}", f"**Servers:** {server_count}", f"**Members:** {member_count}" ] # embed_colour = await url_color(bot.avatar_small) embed = make_embed( icon=bot.avatar_small, title=f"{bot.user}", content='\n'.join(about), # msg_colour=embed_colour ) embed.set_thumbnail(url=bot.avatar) try: await ctx.send(embed=embed) except discord.HTTPException: await ctx.send("I need the `Embed links` permission to send this")
async def _restart(self, ctx): """Restarts the bot""" embed = make_embed(title='Restarting...', msg_colour='red', icon="https://i.imgur.com/uBYS8DR.png") try: restart_msg = await ctx.send(embed=embed) except discord.HTTPException: restart_msg = None data = { 'restart_snowflake': next(snowflake.create()), 'restart_by': ctx.author.id, 'restart_channel': ctx.channel.id, 'restart_guild': ctx.guild.id } if restart_msg: data['restart_message'] = restart_msg.id table = ctx.bot.dbi.table('restart_savedata') table.insert(**data) await table.insert.commit() await ctx.bot.shutdown(restart=True)
async def _resumed(self, ctx): """Gets the number of websocket reconnections.""" r_c = ctx.bot.resumed_count embed = make_embed(msg_type='info', title=f"Connections Resumed: {r_c}") await ctx.send(embed=embed)