async def send_group_help(self, group): ctx = self.context bot = ctx.bot embed = discord.Embed(title=f'Help with `{group.name}`', description=bot.get_command(group.name).help, color=get_colour(ctx)) embed.set_author( name= f'We are currently looking at the {group.cog.qualified_name} cog and its command {group.name}', icon_url=ctx.author.avatar_url) for command in group.walk_commands(): if await command.can_run(ctx): signature = self.get_command_signature(command) description = self.get_command_description(command) aliases = self.get_command_aliases(command) if command.parent: embed.add_field(name=f'**╚╡**{signature}', value=description, inline=False) else: embed.add_field(name=f'{signature} {aliases}', value=description, inline=False) embed.set_footer( text= f'Use "{self.clean_prefix}help <command>" for more info on a command.' ) await ctx.send(embed=embed)
def build_embed(self) -> typing.Optional[discord.Embed]: """Method which builds our players controller embed.""" track = self.current if not track: return channel = self.bot.get_channel(int(self.channel_id)) embed = discord.Embed( title=f'{self.context.emoji.eq} Music Controller | {channel.name}', colour=get_colour(self.context)) embed.description = f'Now Playing:\n**`{track.title}`**\n\n' embed.set_thumbnail(url=track.thumb) embed.add_field( name='⏱ Duration', value=str(datetime.timedelta(milliseconds=int(track.length)))) embed.add_field(name='🎼 Queue Length', value=len(self.queue)) embed.add_field(name=f'{self.context.emoji.voice} Volume', value=f'**`{self.volume}%`**') embed.add_field(name='👥 Requested By', value=track.requester.mention) embed.add_field(name='🎧 DJ', value=self.dj.mention) embed.add_field(name='💿 Video URL', value=f'[Click Here!]({track.uri})') return embed
async def send_cog_help(self, cog): ctx = self.context cog_commands = [ command for command in await self.filter_commands(cog.walk_commands()) ] # get commands embed = discord.Embed( title= f'Help with {cog.qualified_name} ({len(cog_commands)} commands)', description=cog.description, color=get_colour(ctx)) embed.set_author( name= f'We are currently looking at the module {cog.qualified_name} and its commands', icon_url=ctx.author.avatar_url) for c in cog_commands: signature = self.get_command_signature(c) aliases = self.get_command_aliases(c) description = self.get_command_description(c) if c.parent: embed.add_field(name=f'**╚╡**{signature}', value=description) else: embed.add_field(name=f'{signature} {aliases}', value=description, inline=False) embed.set_footer( text= f'Use "{self.clean_prefix}help <command>" for more info on a command.', icon_url=ctx.bot.user.avatar_url) await ctx.send(embed=embed)
async def reload(self, ctx, *, extension=None): """Reload an extension eg. `{prefix}reload staff`""" await ctx.trigger_typing() if extension is None: reloaded = [] failed = [] for extension in self.bot.initial_extensions: try: self.bot.reload_extension(f'Cogs.{extension}') self.bot.dispatch('extension_reload', extension) except commands.ExtensionNotLoaded: try: self.bot.load_extension(f'Cogs.{extension}') except Exception as e: self.bot.dispatch('extension_fail', ctx, extension, e, send=False) failed.append((extension, e)) else: self.bot.dispatch('extension_load', extension) reloaded.append(extension) except Exception as e: self.bot.dispatch('extension_fail', ctx, extension, e, send=False) failed.append((extension, e)) else: self.bot.dispatch('extension_load', extension) reloaded.append(extension) exc = f'\nFailed to load {len(failed)} cog{"s" if len(failed) > 1 else ""} ' \ f'(`{"`, `".join(fail[0] for fail in failed)}`)' if len(failed) > 0 else "" entries = ['\n'.join([f'{ctx.emoji.tick} `{r}`' for r in reloaded])] for f in failed: entries.append(f'{ctx.emoji.cross} `{f[0]}` - Failed\n```py\n{format_error(f[1])}```') reload = buttons.Paginator( title=f'Reloaded `{len(reloaded)}` cog{"s" if len(reloaded) != 1 else ""} {exc}', colour=get_colour(ctx), entries=entries, length=1 ) return await reload.start(ctx) try: self.bot.reload_extension(f'Cogs.{extension}') except commands.ExtensionNotLoaded: if extension in self.bot.initial_extensions: try: self.bot.load_extension(f'Cogs.{extension}') self.bot.dispatch('extension_reload', extension) except Exception as e: self.bot.dispatch('extension_fail', ctx, extension, e) else: await ctx.send(f'**`SUCCESS`** {ctx.emoji.tick} `{extension}` has been loaded') except Exception as e: self.bot.dispatch('extension_fail', ctx, extension, e) else: await ctx.send(f'**`SUCCESS`** {ctx.emoji.tick} `{extension}` has been reloaded')
async def avatar(self, ctx, member: discord.Member = None): """Get a member's avatar with links to download/view in higher quality""" member = member or ctx.author embed = discord.Embed( title=f'{member.display_name}\'s avatar', description=f'[PNG]({member.avatar_url_as(format="png")}) | ' f'[JPEG]({member.avatar_url_as(format="jpg")}) | ' f'[WEBP]({member.avatar_url_as(format="webp")})', colour=get_colour(ctx)) if member.is_avatar_animated(): embed.description += f' | [GIF]({member.avatar_url_as(format="gif")})' embed.set_author(name=member.display_name, icon_url=member.avatar_url) embed.set_image(url=member.avatar_url_as( format='gif' if member.is_avatar_animated() else 'png')) await ctx.send(embed=embed)
async def push(self, ctx, add_first: typing.Optional[bool], *, commit_msg='None given'): """Push changes to the GitHub repo""" errored = ('fatal', 'error') embed = discord.Embed(title='GitHub Commit & Push', description='', colour=get_colour(ctx)) message = await ctx.send(embed=embed) await message.add_reaction(ctx.emoji.loading) if add_first: add = await self.bot.loop.run_in_executor(None, getoutput, 'git add .') if any([word in add.split() for word in errored]): await message.add_reaction(ctx.emoji.cross) await message.remove_reaction(ctx.emoji.loading, ctx.guild.me) embed.description += f'{ctx.emoji.cross} **Add result:**```js\n{add}```\n' return await message.edit(embed=embed) else: add = f'```js\n{add}```' if add else '' embed.description += f'{ctx.emoji.tick} **Add result:**{add}\n' await message.edit(embed=embed) commit = await self.bot.loop.run_in_executor(None, getoutput, f'git commit -m "{commit_msg}"') if any([word in commit.split() for word in errored]): await message.add_reaction(ctx.emoji.cross) await message.remove_reaction(ctx.emoji.loading, ctx.guild.me) embed.description += f'{ctx.emoji.cross} **Commit result:**```js\n{commit}```' return await message.edit(embed=embed) else: embed.description += f'{ctx.emoji.tick} **Commit result:**```js\n{commit}```' await message.edit(embed=embed) push = await self.bot.loop.run_in_executor(None, getoutput, 'git push') if any([word in push.split() for word in errored]): await message.add_reaction(ctx.emoji.cross) await message.remove_reaction(ctx.emoji.loading, ctx.guild.me) embed.description += f'\n{ctx.emoji.cross} **Push result:**```js\n{push}```' return await message.edit(embed=embed) else: await message.add_reaction(ctx.emoji.tick) embed.description += f'\n{ctx.emoji.tick} **Push result:**```js\n{push}```' await message.remove_reaction(ctx.emoji.loading, ctx.guild.me) await message.edit(embed=embed)
async def ping(self, ctx): """Check my ping""" start = perf_counter() await self.bot.session.get('https://discordapp.com') end = perf_counter() discord_duration = (end - start) * 1000 start = perf_counter() embed = discord.Embed(color=get_colour(ctx)).set_author(name='Pong!') m = await ctx.send(embed=embed) end = perf_counter() message_duration = (end - start) * 1000 embed.description = f'{self.bot.user.mention} is online.' embed.set_author(name='Pong!', icon_url=self.bot.user.avatar_url) embed.add_field(name=f':heartbeat: Heartbeat latency is:', value=f'`{self.bot.latency * 1000:.2f}` ms.') embed.add_field(name=f'{ctx.emoji.discord} Discord latency is:', value=f'`{discord_duration:.2f}` ms.') embed.add_field(name=f'{ctx.emoji.text} Message latency is:', value=f'`{message_duration:.2f}` ms.') await m.edit(embed=embed)
async def server(self, ctx, *, server: GuildConverter = None): """Get info in the current server""" guild = server or ctx.guild class Secret: pass secret_member = Secret() secret_member.id = 0 secret_member.roles = [guild.default_role] # figure out what channels are 'secret' secret = Counter() totals = Counter() for channel in guild.channels: perms = channel.permissions_for(secret_member) channel_type = type(channel) totals[channel_type] += 1 if not perms.read_messages: secret[channel_type] += 1 elif isinstance(channel, discord.VoiceChannel) and (not perms.connect or not perms.speak): secret[channel_type] += 1 member_by_status = Counter(str(m.status) for m in guild.members) embed = discord.Embed(title=guild.name, colour=get_colour(ctx)) embed.add_field(name='ID', value=guild.id) embed.add_field(name='Owner', value=guild.owner) if guild.icon: embed.set_thumbnail(url=guild.icon_url) channel_info = [] key_to_emoji = { discord.TextChannel: ctx.emoji.text, discord.VoiceChannel: ctx.emoji.voice } for key, total in totals.items(): secrets = secret[key] try: emoji = key_to_emoji[key] except KeyError: continue if secrets: channel_info.append(f'{emoji} {total} ({secrets} locked)') else: channel_info.append(f'{emoji} {total}') info = [] features = set(guild.features) all_features = { 'PARTNERED': 'Partnered', 'VERIFIED': 'Verified', 'DISCOVERABLE': 'Server Discovery', 'PUBLIC': 'Server Discovery/Public', 'INVITE_SPLASH': 'Invite Splash', 'VIP_REGIONS': 'VIP Voice Servers', 'VANITY_URL': 'Vanity Invite', 'MORE_EMOJI': 'More Emoji', 'COMMERCE': 'Commerce', 'LURKABLE': 'Lurkable', 'NEWS': 'News Channels', 'ANIMATED_ICON': 'Animated Icon', 'BANNER': 'Banner' } for feature, label in all_features.items(): if feature in features: info.append(f'{label}') if info: embed.add_field(name='Features:', value='\n'.join(info)) embed.add_field(name='Channels:', value='\n'.join(channel_info)) embed.add_field(name='Verification level:', value=str(ctx.guild.verification_level).replace( '_', ' ').title()) embed.add_field(name='Region:', value=str(ctx.guild.region).replace('_', ' ').title()) if guild.premium_tier != 0: boosts = f'Level {guild.premium_tier}\n{guild.premium_subscription_count} boosts' last_boost = max(guild.members, key=lambda m: m.premium_since or guild.created_at) if last_boost.premium_since is not None: boosts = f'{boosts}\nLast Boost: {last_boost} ({human_timedelta(last_boost.premium_since, accuracy=2)})' embed.add_field(name='Boosts', value=boosts, inline=False) fmt = f'{ctx.emoji.online} {member_by_status["online"]}\n' \ f'{ctx.emoji.idle} {member_by_status["idle"]}\n' \ f'{ctx.emoji.dnd} {member_by_status["dnd"]}\n' \ f'{ctx.emoji.offline} {member_by_status["offline"]}\n' \ f'Total: {guild.member_count}' embed.add_field(name='Members', value=fmt, inline=False) embed.add_field( name=f'Roles ({len(guild.roles) - 1})', value=human_join([ role.mention for role in sorted([ role for role in guild.roles if role != guild.default_role ], reverse=True, key=lambda r: r.position) ], final='and') if len(guild.roles) < 10 and guild == ctx.guild else f'{len(guild.roles) - 1} roles') await ctx.send(embed=embed)
async def stats(self, ctx): # memory_usage = self.process.memory_full_info().uss rawram = virtual_memory() embed = discord.Embed( title= f'**{self.bot.user.name}** - Official Bot Server Invite & Bot information', description=f'**Commands loaded & Cogs loaded:** ' f'`{len(self.bot.commands)}` commands loaded, ' f'`{len(self.bot.cogs)}` extensions loaded\n\n' f'**Latest Changes:**\n{self.get_last_commits()}\n', colour=get_colour(ctx), timestamp=datetime.now()) embed.set_author(name=str(self.bot.owner), icon_url=self.bot.owner.avatar_url) embed.set_thumbnail(url=self.bot.user.avatar_url) # statistics total_bots = 0 total_members = 0 total_online = 0 total_idle = 0 total_dnd = 0 total_offline = 0 online = discord.Status.online idle = discord.Status.idle dnd = discord.Status.dnd offline = discord.Status.offline all_members = set(self.bot.get_all_members()) for member in all_members: if member.bot: total_bots += 1 continue elif member.status is online: total_online += 1 elif member.status is idle: total_idle += 1 elif member.status is dnd: total_dnd += 1 elif member.status is offline: total_offline += 1 total_members += 1 total_unique = len(all_members) text = 0 voice = 0 guilds = 0 for guild in self.bot.guilds: guilds += 1 for channel in guild.channels: if isinstance(channel, discord.TextChannel): text += 1 elif isinstance(channel, discord.VoiceChannel): voice += 1 embed.add_field(name='Members', value=f'`{total_members}` {ctx.emoji.discord} total\n' f'`{total_bots}` :robot: bots\n' f'`{total_unique}` :star: unique.') embed.add_field(name='Statuses', value=f'`{total_online}` {ctx.emoji.discord} online,\n' f'`{total_idle}` {ctx.emoji.idle} idle,\n' f'`{total_dnd}` {ctx.emoji.dnd} dnd,\n' f'`{total_offline}` {ctx.emoji.offline} offline.') embed.add_field( name='Servers & Channels', value=f'{guilds} total servers\n{text + voice} total channels\n' f'{text} text channels\n{voice} voice channels') # pc info embed.add_field( name=f'{ctx.emoji.ram} RAM Usage', value= f'Using `{naturalsize(rawram[3])}` / `{naturalsize(rawram[0])}` `{round(rawram[3] / rawram[0] * 100, 2)}`% ' ) # f'of your physical memory and `{naturalsize(memory_usage)}` of which unique to this process.') embed.add_field( name=f'{ctx.emoji.cpu} CPU Usage', value=f'`{cpu_percent()}`% used\n\n' f':arrow_up: Uptime\n {self.bot.user.mention} has been online for: {self.get_uptime()}' ) embed.add_field( name=':exclamation:Command prefix', value= f'Your command prefix is `{ctx.prefix}`. Type {ctx.prefix}help to list the ' f'commands you can use') embed.add_field( name='Version info:', value=f'{ctx.emoji.dpy}: `{discord.__version__}`, ' f'{ctx.emoji.postgres}: `{asyncpg.__version__}`' f'{ctx.emoji.python}: `{python_version()}`', # TODO add more version info inline=False) embed.set_footer( text="If you need any help join the help server discord.gg", icon_url=ctx.author.avatar_url) await ctx.send(embed=embed)
async def _eval(self, ctx, *, body: str): """This will evaluate your code-block if type some python code. Input is interpreted as newline separated statements. If the last statement is an expression, if the last line is returnable it will be returned. Usable globals: - `ctx`: the invocation context - `bot`: the bot instance - `discord`: the discord module - `commands`: the discord.ext.commands module **Usage** `{prefix}eval` ```py await ctx.send('lol')``` """ async with ctx.typing(): env = { 'bot': self.bot, 'ctx': ctx, 'discord': discord, 'commands': commands, 'self': self, '_': self._last_result } env.update(globals()) body = strip_code_block(body) stdout = StringIO() split = body.splitlines() previous_lines = '\n'.join(split[:-1]) if split[:-1] else '' last_line = ''.join(split[-1:]) if not last_line.strip().startswith('return'): if not last_line.strip().startswith(('import', 'print', 'raise', 'pass')): body = f'{previous_lines}\n{" " * (len(last_line) - len(last_line.lstrip()))}return {last_line}' to_compile = f'async def func():\n{indent(body, " ")}' try: start = perf_counter() exec(to_compile, env) except Exception as e: end = perf_counter() timer = (end - start) * 1000 await ctx.bool(False) embed = discord.Embed( title=f'{ctx.emoji.cross} {e.__class__.__name__}', description=f'```py\n{format_error(e, strip=True)}```', color=get_colour(ctx, 'colour_bad')) embed.set_footer( text=f'Python: {python_version()} • Process took {timer:.2f} ms to run', icon_url='https://www.python.org/static/apple-touch-icon-144x144-precomposed.png') return await ctx.send(embed=embed) func = env['func'] try: with redirect_stdout(stdout): ret = await self.bot.loop.create_task(asyncio.wait_for(func(), 60)) except Exception as e: value = stdout.getvalue() end = perf_counter() timer = (end - start) * 1000 await ctx.bool(False) embed = discord.Embed( title=f'{ctx.emoji.cross} {e.__class__.__name__}', description=f'```py\n{value}\n{format_error(e, strip=True)}```', color=get_colour(ctx, 'colour_bad')) embed.set_footer( text=f'Python: {python_version()} • Process took {timer:.2f} ms to run', icon_url='https://www.python.org/static/apple-touch-icon-144x144-precomposed.png') return await ctx.send(embed=embed) else: value = stdout.getvalue() end = perf_counter() timer = (end - start) * 1000 await ctx.bool(True) if isinstance(ret, discord.File): await ctx.send(file=ret) elif isinstance(ret, discord.Embed): await ctx.send(embed=ret) else: if not isinstance(value, str): # repr all non-strings value = repr(value) embed = discord.Embed( title=f'Evaluation completed {ctx.author.display_name} {ctx.emoji.tick}', color=get_colour(ctx, 'colour_good')) if not ret: if value: embed.add_field( name='Eval complete', value=f'```py\n{str(value).replace(self.bot.http.token, "[token omitted]")}```') else: self._last_result = ret embed.add_field( name='Eval returned', value=f'```py\n{str(ret).replace(self.bot.http.token, "[token omitted]")}```') embed.set_footer( text=f'Python: {python_version()} • Process took {timer:.2f} ms to run', icon_url='https://www.python.org/static/apple-touch-icon-144x144-precomposed.png') await ctx.send(embed=embed)
async def pull(self, ctx, hard: bool = False): """Pull any changes from the GitHub repo""" errored = ('fatal', 'error') embed = discord.Embed(title=f'GitHub{" Hard" if hard else ""} Pull', description='', colour=get_colour(ctx)) message = await ctx.send(embed=embed) await message.add_reaction(ctx.emoji.loading) if hard: reset = await self.bot.loop.run_in_executor(None, getoutput, 'git reset --hard HEAD') if any([word in reset.split() for word in errored]): await message.add_reaction(ctx.emoji.cross) await message.remove_reaction(ctx.emoji.loading, ctx.guild.me) embed.description += f'\n{ctx.emoji.cross} **Reset result:**```js\n{reset}```' return await message.edit(embed=embed) else: embed.description += f'\n{ctx.emoji.tick} **Reset result:**```js\n{reset}```' pull = await self.bot.loop.run_in_executor(None, getoutput, 'git pull') if any([word in pull.split() for word in errored]): await message.add_reaction(ctx.emoji.cross) await message.remove_reaction(ctx.emoji.loading, ctx.guild.me) embed.description += f'\n{ctx.emoji.cross} **Pull result:**```js\n{pull}```' return await message.edit(embed=embed) else: await ctx.bool(True) embed.description += f'\n{ctx.emoji.tick} **Pull result:**```js\n{pull}```' await message.remove_reaction(ctx.emoji.loading, ctx.guild.me) await message.edit(embed=embed)
async def on_raw_message_delete(self, payload): channel = None message = payload.cached_message if message is None: channel = self.bot.get_channel(payload.channel_id) if message.channel or channel: guild = message.guild or channel.guild if 'message_deletes' in self.bot.config_cache[ guild.id]['logged_events']: if message is None: embed = discord.Embed( description= f'**Message deleted in: {channel.mention}**', color=get_colour(colour='bad_colour', message=message, bot=self.bot)) embed.set_footer(text=f'{datetime.now().strftime("%c")}') return await self.bot.config_cache[ guild.id]['logging_channel'].send(embed=embed) if message.author.bot: return embed = discord.Embed(title='Message deleted', color=discord.Color.red()) embed.add_field( name='Message from:', value= f'**{message.author.mention} deleted in {message.channel.mention}**' ) if message.content: embed.description = f'Content:\n>>> {message.content}' if message.attachments: if len(message.attachments) == 1: if message.attachments[0].filename.endswith( ('.png', '.gif', '.webp,' '.jpg')): embed.set_image( url=message.attachments[0].proxy_url) else: embed.set_footer( text= f'ID: {message.author.id} • {datetime.now().strftime("%c")}', icon_url=message.author.avatar_url) return await message.guild.system_channel.send( f'Deleted message included a non-image attachment, ' f'that cannot be relocated although its name was ' f'`{message.attachments[0].filename}`', embed=embed) elif len(message.attachments) > 1: embed.set_footer( text= f'ID: {message.author.id} • {datetime.now().strftime("%c")}', icon_url=message.author.avatar_url) names = [f.filename for f in message.attachments] for image in message.attachments: if message.attachments[0].filename.endswith( ('.png', '.gif', '.webp,' '.jpg')): embed.set_image(url=image.proxy_url) break embed.set_footer( text= f'ID: {message.author.id} • {datetime.now().strftime("%c")}', icon_url=message.author.avatar_url) return await message.guild.system_channel.send( f'Deleted message included multiple attachments, ' f'that cannot be found :( although there names were:\n' f'`{"`, `".join(names)}`', embed=embed) embed.set_footer( text=f'ID: {message.id} • {datetime.now().strftime("%c")}', icon_url=message.author.avatar_url) await self.bot.config_cache[ guild.id]['logging_channel'].send(embed=embed)