diff --git a/changelog.d/general/2382.enhancement.rst b/changelog.d/general/2382.enhancement.rst new file mode 100644 index 000000000..d36b53e06 --- /dev/null +++ b/changelog.d/general/2382.enhancement.rst @@ -0,0 +1 @@ +Show more details in [p]serverinfo command when using a toggle. diff --git a/redbot/cogs/general/general.py b/redbot/cogs/general/general.py index 1fbd8f578..ae20d5382 100644 --- a/redbot/cogs/general/general.py +++ b/redbot/cogs/general/general.py @@ -8,7 +8,13 @@ import discord from redbot.core import commands from redbot.core.i18n import Translator, cog_i18n from redbot.core.utils.menus import menu, DEFAULT_CONTROLS -from redbot.core.utils.chat_formatting import escape, italics, humanize_number +from redbot.core.utils.chat_formatting import ( + bold, + escape, + italics, + humanize_number, + humanize_timedelta, +) _ = T_ = Translator("General", __file__) @@ -234,38 +240,213 @@ class General(commands.Cog): @commands.command() @commands.guild_only() - async def serverinfo(self, ctx): - """Show server information.""" + @commands.bot_has_permissions(embed_links=True) + async def serverinfo(self, ctx, details: bool = False): + """ + Show server information. + + `details`: Toggle it to `True` to show more information about this server. + Default to False. + """ guild = ctx.guild + passed = (ctx.message.created_at - guild.created_at).days + created_at = _("Created on {date}. That's over {num} days ago!").format( + date=guild.created_at.strftime("%d %b %Y %H:%M"), num=humanize_number(passed), + ) online = humanize_number( len([m.status for m in guild.members if m.status != discord.Status.offline]) ) - total_users = humanize_number(len(guild.members)) + total_users = humanize_number(guild.member_count) text_channels = humanize_number(len(guild.text_channels)) voice_channels = humanize_number(len(guild.voice_channels)) - passed = (ctx.message.created_at - guild.created_at).days - created_at = _("Since {date}. That's over {num} days ago!").format( - date=guild.created_at.strftime("%d %b %Y %H:%M"), num=passed - ) - data = discord.Embed(description=created_at, colour=(await ctx.embed_colour())) - data.add_field(name=_("Region"), value=str(guild.region)) - data.add_field(name=_("Users"), value=f"{online}/{total_users}") - 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)) - - if guild.icon_url: - data.set_author(name=guild.name, url=guild.icon_url) - data.set_thumbnail(url=guild.icon_url) + if not details: + data = discord.Embed(description=created_at, colour=await ctx.embed_colour()) + data.add_field(name=_("Region"), value=str(guild.region)) + data.add_field(name=_("Users online"), value=f"{online}/{total_users}") + 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)) + if guild.icon_url: + data.set_author(name=guild.name, url=guild.icon_url) + data.set_thumbnail(url=guild.icon_url) + else: + data.set_author(name=guild.name) else: - data.set_author(name=guild.name) - try: - await ctx.send(embed=data) - except discord.Forbidden: - await ctx.send(_("I need the `Embed links` permission to send this.")) + 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") + + # 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 == discord.Status.online, + "\N{LARGE ORANGE CIRCLE}": lambda x: x.status == discord.Status.idle, + "\N{LARGE RED CIRCLE}": lambda x: x.status == discord.Status.do_not_disturb, + "\N{MEDIUM WHITE CIRCLE}": lambda x: x.status == discord.Status.offline, + "\N{LARGE PURPLE CIRCLE}": lambda x: x.activity == discord.Streaming, + "\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 + + vc_regions = { + "vip-us-east": _("__VIP__ US East ") + "\U0001F1FA\U0001F1F8", + "vip-us-west": _("__VIP__ US West ") + "\U0001F1FA\U0001F1F8", + "vip-amsterdam": _("__VIP__ Amsterdam ") + "\U0001F1F3\U0001F1F1", + "eu-west": _("EU West ") + "\U0001F1EA\U0001F1FA", + "eu-central": _("EU Central ") + "\U0001F1EA\U0001F1FA", + "europe": _("Europe ") + "\U0001F1EA\U0001F1FA", + "london": _("London ") + "\U0001F1EC\U0001F1E7", + "frankfurt": _("Frankfurt ") + "\U0001F1E9\U0001F1EA", + "amsterdam": _("Amsterdam ") + "\U0001F1F3\U0001F1F1", + "us-west": _("US West ") + "\U0001F1FA\U0001F1F8", + "us-east": _("US East ") + "\U0001F1FA\U0001F1F8", + "us-south": _("US South ") + "\U0001F1FA\U0001F1F8", + "us-central": _("US Central ") + "\U0001F1FA\U0001F1F8", + "singapore": _("Singapore ") + "\U0001F1F8\U0001F1EC", + "sydney": _("Sydney ") + "\U0001F1E6\U0001F1FA", + "brazil": _("Brazil ") + "\U0001F1E7\U0001F1F7", + "hongkong": _("Hong Kong ") + "\U0001F1ED\U0001F1F0", + "russia": _("Russia ") + "\U0001F1F7\U0001F1FA", + "japan": _("Japan ") + "\U0001F1EF\U0001F1F5", + "southafrica": _("South Africa ") + "\U0001F1FF\U0001F1E6", + "india": _("India ") + "\U0001F1EE\U0001F1F3", + "dubai": _("Dubai ") + "\U0001F1E6\U0001F1EA", + "south-korea": _("South Korea ") + "\U0001f1f0\U0001f1f7", + } + verif = { + "none": _("0 - None"), + "low": _("1 - Low"), + "medium": _("2 - Medium"), + "high": _("3 - High"), + "extreme": _("4 - Extreme"), + } + + features = { + "PARTNERED": _("Partnered"), + "VERIFIED": _("Verified"), + "DISCOVERABLE": _("Server Discovery"), + "FEATURABLE": _("Featurable"), + "PUBLIC": _("Public"), + "PUBLIC_DISABLED": _("Public disabled"), + "INVITE_SPLASH": _("Splash Invite"), + "VIP_REGIONS": _("VIP Voice Servers"), + "VANITY_URL": _("Vanity URL"), + "MORE_EMOJI": _("More Emojis"), + "COMMERCE": _("Commerce"), + "NEWS": _("News Channels"), + "ANIMATED_ICON": _("Animated Icon"), + "BANNER": _("Banner Image"), + "MEMBER_LIST_DISABLED": _("Member list disabled"), + } + guild_features_list = [ + f"✅ {name}" for feature, name in features.items() if feature in guild.features + ] + + 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 discord.Embed.Empty, + ) + if guild.icon_url: + data.set_thumbnail(url=guild.icon_url) + 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}" + ).format(text=bold(text_channels), voice=bold(voice_channels)), + ) + data.add_field( + name=_("Utility:"), + value=_( + "Owner: {owner}\nVoice region: {region}\nVerif. level: {verif}\nServer ID: {id}" + ).format( + owner=bold(str(guild.owner)), + region=f"**{vc_regions.get(str(guild.region)) or str(guild.region)}**", + verif=bold(verif[str(guild.verification_level)]), + id=bold(str(guild.id)), + ), + 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, + ) + if guild_features_list: + data.add_field(name=_("Server features:"), value="\n".join(guild_features_list)) + if guild.premium_tier != 0: + nitro_boost = _( + "Tier {boostlevel} with {nitroboosters} boosters\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_url_as(format="png")) + data.set_footer(text=joined_on) + + await ctx.send(embed=data) @commands.command() async def urban(self, ctx, *, word):