import discord from redbot.core import commands from redbot.core.bot import Red from redbot.core.i18n import Translator, cog_i18n from datetime import datetime import re from redbot.core.utils.chat_formatting import ( bold, humanize_number, humanize_timedelta, ) _ = T_ = Translator("General", __file__) @cog_i18n(_) class Info(commands.Cog): """Provides information on Discord objects.""" def __init__(self, bot: Red) -> None: super().__init__() self.bot = bot async def red_delete_data_for_user(self, **kwargs): """Nothing to delete.""" return @commands.command() @commands.guild_only() @commands.bot_has_permissions(embed_links=True) async def serverinfo(self, ctx, details: bool = False): """ Show server information. `details`: Shows more information when set to `True`. Default to False. """ guild = ctx.guild created_at = _("Created on {date_and_time}. That's {relative_time}!").format( date_and_time=discord.utils.format_dt(guild.created_at), relative_time=discord.utils.format_dt(guild.created_at, "R"), ) online = humanize_number( len([m.status for m in guild.members if m.status != discord.Status.offline]) ) total_users = guild.member_count and humanize_number(guild.member_count) text_channels = humanize_number(len(guild.text_channels)) voice_channels = humanize_number(len(guild.voice_channels)) stage_channels = humanize_number(len(guild.stage_channels)) if not details: data = discord.Embed(description=created_at, colour=await ctx.embed_colour()) data.add_field( name=_("Users online"), value=f"{online}/{total_users}" if total_users else _("Not available"), ) data.add_field(name=_("Text Channels"), value=text_channels) data.add_field(name=_("Voice Channels"), value=voice_channels) data.add_field(name=_("Roles"), value=humanize_number(len(guild.roles))) data.add_field(name=_("Owner"), value=str(guild.owner)) data.set_footer( text=_("Server ID: ") + str(guild.id) + _(" • Use {command} for more info on the server.").format( command=f"{ctx.clean_prefix}serverinfo 1" ) ) if guild.icon: data.set_author(name=guild.name, url=guild.icon) data.set_thumbnail(url=guild.icon) else: data.set_author(name=guild.name) else: def _size(num: int): for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]: if abs(num) < 1024.0: return "{0:.1f}{1}".format(num, unit) num /= 1024.0 return "{0:.1f}{1}".format(num, "YB") def _bitsize(num: int): for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]: if abs(num) < 1000.0: return "{0:.1f}{1}".format(num, unit) num /= 1000.0 return "{0:.1f}{1}".format(num, "YB") shard_info = ( _("\nShard ID: **{shard_id}/{shard_count}**").format( shard_id=humanize_number(guild.shard_id + 1), shard_count=humanize_number(ctx.bot.shard_count), ) if ctx.bot.shard_count > 1 else "" ) # Logic from: https://github.com/TrustyJAID/Trusty-cogs/blob/master/serverstats/serverstats.py#L159 online_stats = { _("Humans: "): lambda x: not x.bot, _(" • Bots: "): lambda x: x.bot, "\N{LARGE GREEN CIRCLE}": lambda x: x.status is discord.Status.online, "\N{LARGE ORANGE CIRCLE}": lambda x: x.status is discord.Status.idle, "\N{LARGE RED CIRCLE}": lambda x: x.status is discord.Status.do_not_disturb, "\N{MEDIUM WHITE CIRCLE}\N{VARIATION SELECTOR-16}": lambda x: ( x.status is discord.Status.offline ), "\N{LARGE PURPLE CIRCLE}": lambda x: any( a.type is discord.ActivityType.streaming for a in x.activities ), "\N{MOBILE PHONE}": lambda x: x.is_on_mobile(), } member_msg = _("Users online: **{online}/{total_users}**\n").format( online=online, total_users=total_users ) count = 1 for emoji, value in online_stats.items(): try: num = len([m for m in guild.members if value(m)]) except Exception as error: print(error) continue else: member_msg += f"{emoji} {bold(humanize_number(num))} " + ( "\n" if count % 2 == 0 else "" ) count += 1 verif = { "none": _("0 - None"), "low": _("1 - Low"), "medium": _("2 - Medium"), "high": _("3 - High"), "highest": _("4 - Highest"), } joined_on = _( "{bot_name} joined this server on {bot_join}. That's over {since_join} days ago!" ).format( bot_name=ctx.bot.user.name, bot_join=guild.me.joined_at.strftime("%d %b %Y %H:%M:%S"), since_join=humanize_number((ctx.message.created_at - guild.me.joined_at).days), ) data = discord.Embed( description=(f"{guild.description}\n\n" if guild.description else "") + created_at, colour=await ctx.embed_colour(), ) data.set_author( name=guild.name, icon_url="https://cdn.discordapp.com/emojis/457879292152381443.png" if "VERIFIED" in guild.features else "https://cdn.discordapp.com/emojis/508929941610430464.png" if "PARTNERED" in guild.features else None, ) if guild.icon: data.set_thumbnail(url=guild.icon) data.add_field(name=_("Members:"), value=member_msg) data.add_field( name=_("Channels:"), value=_( "\N{SPEECH BALLOON} Text: {text}\n" "\N{SPEAKER WITH THREE SOUND WAVES} Voice: {voice}\n" "\N{STUDIO MICROPHONE} Stage: {stage}" ).format( text=bold(text_channels), voice=bold(voice_channels), stage=bold(stage_channels), ), ) data.add_field( name=_("Utility:"), value=_( "Owner: {owner}\nVerif. level: {verif}\nServer ID: {id}{shard_info}" ).format( owner=bold(str(guild.owner)), verif=bold(verif[str(guild.verification_level)]), id=bold(str(guild.id)), shard_info=shard_info, ), inline=False, ) data.add_field( name=_("Misc:"), value=_( "AFK channel: {afk_chan}\nAFK timeout: {afk_timeout}\nCustom emojis: {emoji_count}\nRoles: {role_count}" ).format( afk_chan=bold(str(guild.afk_channel)) if guild.afk_channel else bold(_("Not set")), afk_timeout=bold(humanize_timedelta(seconds=guild.afk_timeout)), emoji_count=bold(humanize_number(len(guild.emojis))), role_count=bold(humanize_number(len(guild.roles))), ), inline=False, ) excluded_features = { # available to everyone since forum channels private beta "THREE_DAY_THREAD_ARCHIVE", "SEVEN_DAY_THREAD_ARCHIVE", # rolled out to everyone already "NEW_THREAD_PERMISSIONS", "TEXT_IN_VOICE_ENABLED", "THREADS_ENABLED", # available to everyone sometime after forum channel release "PRIVATE_THREADS", } custom_feature_names = { "VANITY_URL": "Vanity URL", "VIP_REGIONS": "VIP regions", } features = sorted(guild.features) if "COMMUNITY" in features: features.remove("NEWS") feature_names = [ custom_feature_names.get(feature, " ".join(feature.split("_")).capitalize()) for feature in features if feature not in excluded_features ] if guild.features: data.add_field( name=_("Server features:"), value="\n".join( f"\N{WHITE HEAVY CHECK MARK} {feature}" for feature in feature_names ), ) if guild.premium_tier != 0: nitro_boost = _( "Tier {boostlevel} with {nitroboosters} boosts\n" "File size limit: {filelimit}\n" "Emoji limit: {emojis_limit}\n" "VCs max bitrate: {bitrate}" ).format( boostlevel=bold(str(guild.premium_tier)), nitroboosters=bold(humanize_number(guild.premium_subscription_count)), filelimit=bold(_size(guild.filesize_limit)), emojis_limit=bold(str(guild.emoji_limit)), bitrate=bold(_bitsize(guild.bitrate_limit)), ) data.add_field(name=_("Nitro Boost:"), value=nitro_boost) if guild.splash: data.set_image(url=guild.splash.replace(format="png")) data.set_footer(text=joined_on) await ctx.send(embed=data) @commands.command() @commands.guild_only() async def userinfo(self, ctx, member: discord.Member): """Gives information on a specific person.""" if member.color.value == 0: colorint = 10070709 else: colorint = member.color.value avatarurl = str(member.avatar_url) timestamp_create = int(datetime.timestamp(member.created_at)) timestamp_join = int(datetime.timestamp(member.joined_at)) embed = discord.Embed(title=f"{member.name}#{member.discriminator}", color=colorint) embed.add_field(name="Joined At", value=f"") embed.add_field(name="Created At", value=f"") embed.add_field(name="Avatar", value=f"[Click Here]({avatarurl})") embed.add_field(name="Roles", value=f"{member.roles}") embed.set_thumbnail(url=f"{avatarurl}") embed.set_footer(text=f"ID: {member.id}") await ctx.send(embed=embed) @commands.command() @commands.guild_only() async def roleinfo(self, ctx, role: discord.Role): """Gives information on a specific role.""" permissions = role.permissions if role.color.value == 0: colorint = 10070709 color = "99aab5" else: colorint = role.color.value color = re.sub('#',"",str(role.color)) colorcodelink = f"https://www.color-hex.com/color/{color}" timestamp = int(datetime.timestamp(role.created_at)) if permissions.administrator: embed = discord.Embed(title=f"{role.name}", color=colorint, description=f"**ID:** {role.id}\n**Mention:** {role.mention}\n**Creation Date:** \n**Color:** [#{color}]({colorcodelink})\n**Hoisted:** {role.hoist}\n**Position:** {role.position}\n**Managed:** {role.managed}\n**Mentionable:** {role.mentionable}\n**Administrator:** {role.permissions.administrator}") else: embed = discord.Embed(title=f"{role.name}", color=colorint, description=f"**ID:** {role.id}\n**Mention:** {role.mention}\n**Creation Date:** \n**Color:** [#{color}]({colorcodelink})\n**Hoisted:** {role.hoist}\n**Position:** {role.position}\n**Managed:** {role.managed}\n**Mentionable:** {role.mentionable}\n**Administrator:** {role.permissions.administrator}") embed.add_field(name="Permissions", value=f"**Manage Server:** {permissions.manage_guild}\n**Manage Webhooks:** {permissions.manage_webhooks}\n**Manage Channels:** {permissions.manage_channels}\n**Manage Roles:** {permissions.manage_roles}\n**Manage Emojis:** {permissions.manage_emojis}\n**Manage Messages:** {permissions.manage_messages}\n**Manage Nicknames:** {permissions.manage_nicknames}\n**Mention @everyone**: {permissions.mention_everyone}\n**Ban Members:** {permissions.ban_members}\n**Kick Members:** {permissions.kick_members}") await ctx.send(embed=embed)