async def user_info(self, ctx, member: typing.Optional[typing.Union[discord.Member, discord.User]]): member = member or ctx.author embed = SaturnEmbed(description=member.mention, colour=member.colour if isinstance( member, discord.Member) else MAIN, timestamp=utc()) embed.set_thumbnail(url=member.avatar_url) embed.set_author(icon_url=member.avatar_url, name=member) created_delta = (utc() - member.created_at.replace( tzinfo=datetime.timezone.utc)).total_seconds() embed.add_field(name="ID", value=member.id) embed.add_field(name="Joined Discord", value=general_convert_time(created_delta) + ' ago', inline=True) if isinstance(member, discord.Member): join_delta = (utc() - member.joined_at.replace( tzinfo=datetime.timezone.utc)).total_seconds() member_roles = member.roles[1:] roles = " ".join(reversed([f"<@&{r.id}>" for r in member_roles])) embed.add_field(name=f"Joined {ctx.guild}", value=general_convert_time(join_delta) + ' ago', inline=True) if roles: embed.add_field(name="Roles ({})".format(int( len(member_roles))), value=roles) member_perms = await get_permissions(ctx, member) display_perms = [] for permission, value in member_perms.items(): if value: display_perms.append(' '.join( [item.title() for item in str(permission).split('_')])) continue embed.add_field(name="Permissions ({})".format( int(len(display_perms))), value=", ".join(display_perms)) await ctx.send(embed=embed)
async def prompt(self, ctx): em = discord.Embed( description=f'{WARNING} Are you sure you want to {self.msg}?', colour=GOLD, timestamp=utc()) msg = await ctx.send(embed=em) await msg.add_reaction(CHECK) await msg.add_reaction(CROSS) def check(r, u): return u == ctx.author and str(r.emoji) in (CHECK, CROSS) try: reaction, user = await ctx.bot.wait_for('reaction_add', timeout=30.0, check=check) except asyncio.TimeoutError: return False else: if str(reaction.emoji) == CHECK: return True else: em = SaturnEmbed(description=f"{INFO} Action cancelled.", colour=BLUE) await ctx.send(embed=em) return False
async def view_uptime(self, ctx): time = (utc() - self.bot.start_time).total_seconds() formatted_time = str(general_convert_time(time)) await ctx.reply(embed=SaturnEmbed( description= f"{self.bot.__name__} has been online for **{formatted_time}**", colour=MAIN))
async def clear_snipe_cache(self): current_time = utc() snipes = deepcopy(self.bot.snipes) for key, value in snipes.items(): clear_time = value['time'] + relativedelta(seconds=600) if current_time >= clear_time: self.bot.snipes.pop(value['_id'])
async def view_roles(self, ctx, member: typing.Optional[typing.Union[discord.Member, discord.User]]): member = member or ctx.author roles = " ".join(reversed([f"<@&{r.id}>" for r in member.roles[1:]])) em = SaturnEmbed(description=str( roles if roles else f"{member.mention} has no roles!"), colour=member.colour, timestamp=utc()) em.set_image(url=member.avatar_url) em.set_author(icon_url=member.avatar_url, name=f"{member.name}'s roles") await ctx.send(embed=em)
async def export_channel_contents( self, ctx, channel: typing.Optional[discord.TextChannel], limit: typing.Optional[int] = 100): channel = channel or ctx.channel em = SaturnEmbed( description=f"{INFO} This might take a while, please wait...", colour=BLUE) msg = await ctx.send(embed=em) async with channel.typing(): messages = await channel.history(limit=limit, oldest_first=True).flatten() try: await create_export_file(self.bot, ctx, messages, channel) except FileNotFoundError: await asyncio.sleep(0.5) await create_export_file(self.bot, ctx, messages, channel) file = discord.File( f'{self.bot.path}/assets/txt_files/{channel.id}-export.txt') try: await msg.delete() except (discord.NotFound, discord.Forbidden): pass em = SaturnEmbed( title='Channel Export', description=f"Message contents of <#{channel.id}>\n" f"Download the attached .txt file to view the contents.", colour=MAIN, timestamp=utc()) em.set_thumbnail( url="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/" "thumbs/120/mozilla/36/memo_1f4dd.png") await ctx.send(embed=em) await asyncio.sleep(0.5) await ctx.send(file=file)
async def _paginate(self, ctx: commands.Context) -> None: if not self.entries and not self.extra_pages: raise AttributeError( 'You must provide at least one entry or page for pagination.' ) # ^^ if self.entries: self.entries = [self.formatting(entry) for entry in self.entries] entries = list(self.chunker()) else: entries = [] for i, chunk in enumerate(entries, start=1): if not self.use_embed: self._pages.append(self.joiner.join(chunk)) else: title = self.title or (self.change_title[i - 1] if self.change_title else None) em = discord.Embed( title=title, description=self.joiner.join(chunk), colour=self.colour, timestamp=self.timestamp or utc(), ) em.set_footer( text= f"Page {i} out of {len(entries)} pages {f'| {self.footer}' if self.footer else ''}" ) if self.thumbnail: em.set_thumbnail(url=self.thumbnail) self._pages.append(em) self._pages += self.extra_pages if isinstance(self._pages[0], discord.Embed): self.page = await ctx.send(embed=self._pages[0]) else: self.page = await ctx.send(self._pages[0]) self._session_task = ctx.bot.loop.create_task(self._session(ctx))
async def yes_no_poll(self, ctx, channel: typing.Optional[discord.TextChannel], *, question): channel = channel or ctx.channel em = SaturnEmbed(title=question, description=":thumbsup: Yes\n\n:thumbsdown: No", colour=GOLD, timestamp=utc()) em.set_footer(text=f"Yes/no poll by {ctx.author}") msg = await channel.send(embed=em) self.polls[msg.id] = { "type": "ynpoll", "question": question, "choices": ("Yes", "No"), "channel": msg.channel.id, "author": ctx.author.id, "guild": ctx.guild.id, } for emoji in self.yes_no: await msg.add_reaction(emoji)
async def poll(self, ctx, channel: typing.Optional[discord.TextChannel], question, *choices): channel = channel or ctx.channel if not len(choices) or not len(question): em = SaturnEmbed( description= f"{CROSS} Please include both a question and choices. Format looks like\n" f'```poll "dogs or cats?" dogs cats```', color=RED) return await ctx.send(embed=em) if len(choices) > 10 or len(choices) < 2: em = SaturnEmbed( description= f"{CROSS} The amount of choices provided is not within acceptable boundaries.\n" f"```Number of choices must be in between 1 and 10```", color=RED) return await ctx.send(embed=em) em = SaturnEmbed(title=question, description='\n\n'.join([ "{0} {1}".format(self.numbers[num], choice.replace('"', '')) for num, choice in enumerate(choices) ]), colour=BLUE, timestamp=utc()) em.set_footer(text=f"Poll by {ctx.author}") msg = await channel.send(embed=em) self.polls[msg.id] = { "type": "poll", "question": question, "choices": choices, "channel": msg.channel.id, "author": ctx.author.id, "guild": ctx.guild.id, } valid_emotes = self.numbers[:(len(choices))] for emoji in valid_emotes: await msg.add_reaction(emoji)
async def member_count(self, ctx): async with ctx.channel.typing(): bots = len([m for m in ctx.guild.members if m.bot]) bots_with_perms = len([ m for m in ctx.guild.members if m.bot and m.guild_permissions.kick_members ]) users = len(ctx.guild.members) - bots mods = len([ m for m in ctx.guild.members if m.guild_permissions.kick_members ]) - bots_with_perms em = SaturnEmbed(colour=MAIN, timestamp=utc()) em.description = f""" **Members** - {users} **Bots** - {bots} **Moderators** - {mods} """ em.set_author(name=f'Member Statistics for {ctx.guild}', icon_url=ctx.guild.icon_url) await ctx.send(embed=em)
async def on_ready(self): self.default_guild = self.get_guild(793577103794634842) self.stdout = self.default_guild.get_channel(833871407544008704) self.start_time = utc() if not self.ready: self.ready = True for _file in os.listdir(self.path + '/cogs'): if _file.endswith('.py') and not _file.startswith('_'): print(f"Loading {_file[:-3]} cog...") # load all of the cogs self.load_extension(f"cogs.{_file[:-3]}") # i have jishaku here because i find it quite useful self.load_extension('jishaku') mutes, bans = [], [] print("Initializing mute and ban cache...") async for _doc in self.mutes.find({}): mutes.append(_doc) for mute in mutes: self.muted_users[mute["_id"]] = mute async for _doc in self.bans.find({}): bans.append(_doc) for ban in bans: self.banned_users[ban["_id"]] = ban print(f"{self.__name__} is ready") em = SaturnEmbed( description=f"{CHECK} Connected and ready!", colour=GREEN) await self.stdout.send(embed=em) else: print(f"{self.__name__} reconnected") em = SaturnEmbed( description=f"{INFO} Reconnected!", colour=BLUE) await self.stdout.send(embed=em)
async def _default_indexer(self, control, ctx, member): previous = self._index if control == 'stop': return await self.cancel() if control == 'end': self._index = len(self._pages) - 1 elif control == 'start': self._index = 0 elif control == 'info': # info embed yay? em = discord.Embed(description=f""" {PAG_FRONT} - Go to the first page. {PAG_PREVIOUS} - Go back one page. {PAG_NEXT} - Go forward one page. {PAG_BACK} - Go to the last page. {PAG_STOP} - Stop the menu. {PAG_INFO} - Shows this message. {PAG_NUMBERS} - Type a page number in chat to go to. Press any button to continue. """, timestamp=utc(), colour=BLUE) em.set_author(name="How to use the Interactive Menu", icon_url=INFO_URL) return await self.page.edit(embed=em) elif control == 'number': em = discord.Embed( description= f'{INFO} Please specify which page you want to go to in the chat.', colour=BLUE) await ctx.send(embed=em) try: msg = await ctx.bot.wait_for( 'message', check=lambda m: m.author == ctx.author) except asyncio.TimeoutError: em = discord.Embed( description=f'{INFO} User did not respond in time.', colour=BLUE) await ctx.send(embed=em) else: try: _int = int(msg.content) except ValueError: em = discord.Embed( description=f'{CROSS} Invalid page number given.\n' f'```Page must be between 1 and {len(self._pages)}```', colour=RED) return await ctx.send(embed=em) if (len(self._pages) < _int or _int < 1): em = discord.Embed( description=f'{CROSS} Invalid page number given.\n' f'```Page must be between 1 and {len(self._pages)}```', colour=RED) return await ctx.send(embed=em) self._index = _int - 1 em = discord.Embed( description=f'{CHECK} Switched to page `{_int}`', colour=GREEN) await ctx.send(embed=em) else: self._index += control if self._index > len(self._pages) - 1 or self._index < 0: self._index = previous if self._index == previous: pass if isinstance(self._pages[self._index], discord.Embed): await self.page.edit(embed=self._pages[self._index]) else: await self.page.edit(content=self._pages[self._index])