diff --git a/commands/tools.py b/commands/tools.py index fb4e8d5..261c6f6 100644 --- a/commands/tools.py +++ b/commands/tools.py @@ -1,9 +1,159 @@ import re -import arguments +import disnake +import requests +import arguments import commands import utils +from constants import APPLICATION_FLAGS, BADGE_EMOJIS, EMBED_COLOR, PUBLIC_FLAGS +from state import client + + +async def lookup(message): + tokens = commands.tokenize(message.content) + parser = arguments.ArgumentParser( + tokens[0], + "look up a user or application on discord by their ID", + ) + parser.add_argument( + "-a", + "--application", + action="store_true", + help="search for applications instead of users", + ) + parser.add_argument( + "id", + type=int, + help="the ID to perform a search for", + ) + if not (args := await parser.parse_args(message, tokens)): + return + + if args.application: + response = requests.get( + f"https://discord.com/api/v9/applications/{args.id}/rpc" + ).json() + if "code" in response.keys(): + await utils.reply(message, "application not found!") + return + + embed = disnake.Embed(description=response["description"], color=EMBED_COLOR) + embed.set_thumbnail( + url=f"https://cdn.discordapp.com/app-icons/{response['id']}/{response['icon']}.webp" + ) + embed.add_field(name="Application Name", value=response["name"]) + embed.add_field(name="Application ID", value="`" + response["id"] + "`") + embed.add_field( + name="Public Bot", + value=f"{'`'+str(response['bot_public'])+'`' if 'bot_public' in response.keys() != None else 'No bot'}", + ) + embed.add_field(name="Public Flags", value="`" + str(response["flags"]) + "`") + embed.add_field( + name="Terms of Service", + value=( + "None" + if "terms_of_service_url" not in response.keys() + else f"[Link]({response['terms_of_service_url']})" + ), + ) + embed.add_field( + name="Privacy Policy", + value=( + "None" + if "privacy_policy_url" not in response.keys() + else f"[Link]({response['privacy_policy_url']})" + ), + ) + embed.add_field( + name="Creation Time", + value=f"", + ) + embed.add_field( + name="Default Invite URL", + value=( + "None" + if "install_params" not in response.keys() + else f"[Link](https://discord.com/oauth2/authorize?client_id={response['id']}&permissions={response['install_params']['permissions']}&scope={'%20'.join(response['install_params']['scopes'])})" + ), + ) + embed.add_field( + name="Custom Invite URL", + value=( + "None" + if "custom_install_url" not in response.keys() + else f"[Link]({response['custom_install_url']})" + ), + ) + + bot_intents = [] + for application_flag, intent_name in APPLICATION_FLAGS.items(): + if response["flags"] & application_flag == application_flag: + if intent_name.replace(" (unverified)", "") not in bot_intents: + bot_intents.append(intent_name) + embed.add_field( + name="Application Flags", + value=", ".join(bot_intents) if bot_intents else "None", + ) + + bot_tags = "" + if "tags" in response.keys(): + for tag in response["tags"]: + bot_tags += tag + ", " + embed.add_field( + name="Tags", value="None" if bot_tags == "" else bot_tags[:-2], inline=False + ) + else: + try: + user = await client.fetch_user(args.id) + except Exception: + await utils.reply(message, "user not found!") + return + + badges = "" + for flag, flag_name in PUBLIC_FLAGS.items(): + if user.public_flags.value & flag == flag: + if flag_name != "None": + try: + badges += BADGE_EMOJIS[PUBLIC_FLAGS[flag]] + except: + raise Exception(f"unable to find badge: {PUBLIC_FLAGS[flag]}") + + accent_color = 0x000000 + user_object = await client.fetch_user(user.id) + if user_object.accent_color != None: + accent_color = user_object.accent_color + + embed = disnake.Embed(color=accent_color) + embed.add_field( + name="User ID", + value=f"`{user.id}`", + ) + embed.add_field( + name="Discriminator", + value=f"`{user.name}#{user.discriminator}`", + ) + embed.add_field( + name="Creation Time", + value=f"", + ) + embed.add_field( + name="Public Flags", + value=f"`{user.public_flags.value}` {badges}", + ) + embed.add_field( + name="Bot User", + value=f"`{user.bot}`", + ) + embed.add_field( + name="System User", + value=f"`{user.system}`", + ) + embed.set_thumbnail(url=user.avatar if user.avatar else user.default_avatar) + if user_object.banner: + embed.set_image(url=user_object.banner) + + await utils.reply(message, embed=embed) async def clear(message): diff --git a/commands/utils.py b/commands/utils.py index df57a37..19e11ef 100644 --- a/commands/utils.py +++ b/commands/utils.py @@ -12,6 +12,7 @@ class Command(Enum): HELP = "help" JOIN = "join" LEAVE = "leave" + LOOKUP = "lookup" PAUSE = "pause" PING = "ping" PLAY = "play" diff --git a/constants.py b/constants.py index ac15c0a..695bd10 100644 --- a/constants.py +++ b/constants.py @@ -40,6 +40,50 @@ RELOADABLE_MODULES = [ "voice", "youtubedl", ] +PUBLIC_FLAGS = { + 1: "Discord Employee", + 2: "Discord Partner", + 4: "HypeSquad Events", + 8: "Bug Hunter Level 1", + 64: "HypeSquad Bravery", + 128: "HypeSquad Brilliance", + 256: "HypeSquad Balance", + 512: "Early Supporter", + 1024: "Team User", + 16384: "Bug Hunter Level 2", + 65536: "Verified Bot", + 131072: "Verified Bot Developer", + 262144: "Discord Certified Moderator", + 524288: "HTTP Interactions Only", + 4194304: "Active Developer", +} +BADGE_EMOJIS = { + "Discord Employee": "<:DiscordStaff:879666899980546068>", + "Discord Partner": "<:DiscordPartner:879668340434534400>", + "HypeSquad Events": "<:HypeSquadEvents:879666970310606848>", + "Bug Hunter Level 1": "<:BugHunter1:879666851448234014>", + "HypeSquad Bravery": "<:HypeSquadBravery:879666945153175612>", + "HypeSquad Brilliance": "<:HypeSquadBrilliance:879666956884643861>", + "HypeSquad Balance": "<:HypeSquadBalance:879666934717771786>", + "Early Supporter": "<:EarlySupporter:879666916493496400>", + "Team User": "<:TeamUser:890866907996127305>", + "Bug Hunter Level 2": "<:BugHunter2:879666866971357224>", + "Verified Bot": "<:VerifiedBot:879670687554498591>", + "Verified Bot Developer": "<:VerifiedBotDeveloper:879669786550890507>", + "Discord Certified Moderator": "<:DiscordModerator:879666882976837654>", + "HTTP Interactions Only": "<:HTTPInteractionsOnly:1047141867806015559>", + "Active Developer": "<:ActiveDeveloper:1047141451244523592>", +} +APPLICATION_FLAGS = { + 1 << 12: "Presence Intent", + 1 << 13: "Presence Intent (unverified)", + 1 << 14: "Guild Members Intent", + 1 << 15: "Guild Members Intent (unverified)", + 1 << 16: "Unusual Growth (verification suspended)", + 1 << 18: "Message Content Intent", + 1 << 19: "Message Content Intent (unverified)", + 1 << 23: "Suports Application Commands", +} SECRETS = { "TOKEN": os.getenv("BOT_TOKEN"), diff --git a/core.py b/core.py index 6016765..95e2347 100644 --- a/core.py +++ b/core.py @@ -147,6 +147,8 @@ async def on_message(message, edited=False): await commands.bot.status(message) case C.PING: await commands.bot.ping(message) + case C.LOOKUP: + await commands.tools.lookup(message) except Exception as e: await utils.reply( message, diff --git a/utils.py b/utils.py index b19b38b..5485321 100644 --- a/utils.py +++ b/utils.py @@ -83,6 +83,10 @@ def format_duration(duration: int, natural: bool = False, short: bool = False): return separator.join(segments[:-1]) + f" and {segments[-1]}" +def parse_snowflake(id): + return round(((id >> 22) + 1420070400000) / 1000) + + async def add_check_reaction(message): await message.add_reaction("✅")