2363 lines
68 KiB
JavaScript
2363 lines
68 KiB
JavaScript
const Command = require("../lib/command.js");
|
|
const CATEGORY = "utility";
|
|
|
|
// {{{ imports
|
|
|
|
const sharp = require("sharp");
|
|
const {Constants, VoiceChannel} = require("@projectdysnomia/dysnomia");
|
|
|
|
const {
|
|
formatTime,
|
|
hastebin,
|
|
lookupUser,
|
|
formatUsername,
|
|
safeString,
|
|
snowflakeToTimestamp,
|
|
} = require("../lib/utils.js");
|
|
const {getNamesFromString} = require("../lib/unicode.js");
|
|
|
|
const GameData = require("../../data/games.json");
|
|
|
|
const EmojiData = require("../../data/emoji.json");
|
|
const EMOJI_NAMES = [];
|
|
for (const emoji of EmojiData) {
|
|
EMOJI_NAMES[emoji.char] = emoji.name.replace(/ /g, "_");
|
|
}
|
|
|
|
// }}}
|
|
|
|
// {{{ constants
|
|
|
|
const CDN = "https://cdn.discordapp.com/";
|
|
const ICON_BASE = CDN + "icons/";
|
|
const AVATAR_BASE = CDN + "avatars/";
|
|
const SPLASH_BASE = CDN + "splashes/";
|
|
const BANNER_BASE = CDN + "banners/";
|
|
const EMOTE_BASE = CDN + "emojis/";
|
|
const CHANNEL_ICON_BASE = CDN + "channel-icons/";
|
|
const APP_ICON_BASE = CDN + "app-icons/";
|
|
const APP_ASSET_BASE = CDN + "app-assets/";
|
|
const DISCOVERY_SPLASH_BASE = CDN + "discovery-splashes/";
|
|
|
|
const DEFAULT_GROUP_DM_AVATARS = [
|
|
"/assets/ee9275c5a437f7dc7f9430ba95f12ebd.png",
|
|
"/assets/9baf45aac2a0ec2e2dab288333acb9d9.png",
|
|
"/assets/7ba11ffb1900fa2b088cb31324242047.png",
|
|
"/assets/f90fca70610c4898bc57b58bce92f587.png",
|
|
"/assets/e2779af34b8d9126b77420e5f09213ce.png",
|
|
"/assets/c6851bd0b03f1cca5a8c1e720ea6ea17.png",
|
|
"/assets/f7e38ac976a2a696161c923502a8345b.png",
|
|
"/assets/3cb840d03313467838d658bbec801fcd.png",
|
|
];
|
|
|
|
const CUSTOM_EMOTE_REGEX = /<(?:\u200b|&)?(a)?:(\w+):(\d+)>/;
|
|
const POMELO_REGEX = /^[a-z0-9._]{1,32}$/;
|
|
const SNOWFLAKE_REGEX = /[0-9]{17,21}/;
|
|
|
|
const NOWPLAYING_BAR_LENGTH = 30;
|
|
|
|
const PRESENCE_ICONS = {
|
|
desktop: {
|
|
online: "<:desktop_online:1028887024670871552>",
|
|
idle: "<:desktop_idle:1028887022938624033>",
|
|
dnd: "<:desktop_dnd:1028887021848121364>",
|
|
},
|
|
mobile: {
|
|
online: "<:mobile_online:1028887017637036043>",
|
|
idle: "<:mobile_idle:1028887019226669116>",
|
|
dnd: "<:mobile_dnd:1028887020560449637>",
|
|
},
|
|
web: {
|
|
online: "<:web_online:1104972136730345552>",
|
|
idle: "<:web_idle:1104972138735218729>",
|
|
dnd: "<:web_dnd:1104972140685570150>",
|
|
},
|
|
embedded: {
|
|
online: "<:embedded_online:1104972131265167411>",
|
|
idle: "<:embedded_idle:1104972132687024189>",
|
|
dnd: "<:embedded_dnd:1104972134964543518>",
|
|
},
|
|
};
|
|
const OS_ICONS = {
|
|
darwin: "\u{1f34e}",
|
|
win32: "\u{1fa9f}",
|
|
linux: "\u{1f427}",
|
|
};
|
|
|
|
const PRESENCE_TYPES = [
|
|
"Playing",
|
|
"Streaming",
|
|
"Listening to",
|
|
"Watching",
|
|
"Custom Status",
|
|
"Competing in",
|
|
];
|
|
|
|
const USER_FLAGS = [
|
|
"STAFF",
|
|
"PARTNER",
|
|
"HYPESQUAD",
|
|
"BUG_HUNTER_LEVEL_1",
|
|
"MFA_SMS",
|
|
"PREMIUM_PROMO_DISMISSED",
|
|
"HYPESQUAD_ONLINE_HOUSE_1",
|
|
"HYPESQUAD_ONLINE_HOUSE_2",
|
|
"HYPESQUAD_ONLINE_HOUSE_3",
|
|
"PREMIUM_EARLY_SUPPORTER",
|
|
"TEAM_PSEUDO_USER",
|
|
"<Internal Application (Partner, etc) Flag>", // leaked
|
|
"SYSTEM",
|
|
"HAS_UNREAD_URGENT_MESSAGES",
|
|
"BUG_HUNTER_LEVEL_2",
|
|
"UNDERAGE_DELETED",
|
|
"VERIFIED_BOT",
|
|
"VERIFIED_DEVELOPER",
|
|
"CERTIFIED_MODERATOR",
|
|
"BOT_HTTP_INTERACTIONS",
|
|
"SPAMMER",
|
|
"DISABLE_PREMIUM",
|
|
"ACTIVE_DEVELOPER",
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
"HIGH_GLOBAL_RATE_LIMIT", // start admin panel leak aug 2022
|
|
"DELETED",
|
|
"DISABLED_SUSPICIOUS_ACTIVITY",
|
|
"SELF_DELETED",
|
|
"PREMIUM_DISCRIMINATOR",
|
|
"USED_DESKTOP_CLIENT",
|
|
"USED_WEB_CLIENT",
|
|
"USED_MOBILE_CLIENT",
|
|
"DISABLED",
|
|
undefined,
|
|
"VERIFIED_EMAIL", // end admin panel leak aug 2022
|
|
"QUARANTINED",
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
"COLLABORATOR",
|
|
"RESTRICTED_COLLABORATOR",
|
|
];
|
|
|
|
const APPLICATION_FLAGS = [
|
|
undefined,
|
|
"Embedded Release (deprecated)",
|
|
"Create Managed Emoji",
|
|
"Embedded In-App Purchaces",
|
|
"Create Group DMs",
|
|
"RPC Private Beta",
|
|
"Uses AutoMod",
|
|
undefined,
|
|
"Allow Assets (deprecated)",
|
|
"Allow Spectate (deprecated)",
|
|
"Allow Join Requests (deprecated)",
|
|
"Has Used RPC (deprecated)",
|
|
"Presence Intent",
|
|
"Presence Intent (Unverified)",
|
|
"Guild Members Intent",
|
|
"Guild Members Intent (Unverified)",
|
|
"Suspicious Growth",
|
|
"Embedded",
|
|
"Message Content Intent",
|
|
"Message Content Intent (Unverified)",
|
|
"Embedded (First Party)",
|
|
undefined,
|
|
undefined,
|
|
"Supports Commands",
|
|
"Active",
|
|
undefined,
|
|
"iframe Modals",
|
|
];
|
|
|
|
const APPLICATION_TYPES = [
|
|
undefined,
|
|
"Game",
|
|
"Music",
|
|
"Ticketed Event",
|
|
"Creator Monetization",
|
|
];
|
|
|
|
// https://discord-userdoccers.vercel.app/resources/guild#guild-features
|
|
const GUILD_FEATURES = {
|
|
ACTIVITIES_ALPHA: {icon: "\u{1f680}"},
|
|
ACTIVITIES_EMPLOYEE: {icon: "\u{1f680}"},
|
|
ACTIVITIES_INTERNAL_DEV: {icon: "\u{1f680}"},
|
|
ANIMATED_BANNER: {icon: "\u{1f39e}"},
|
|
ANIMATED_ICON: {icon: "\u{1f39e}"},
|
|
APPLICATION_COMMAND_PERMISSIONS_V2: {icon: "\u2699\ufe0f"},
|
|
AUTO_MODERATION: {icon: "\u{1f6e1}"},
|
|
AUTOMOD_TRIGGER_KEYWORD_FILTER: {icon: "\u{1f6e1}"},
|
|
AUTOMOD_TRIGGER_ML_SPAM_FILTER: {icon: "\u{1f6e1}"},
|
|
AUTOMOD_TRIGGER_SPAM_LINK_FILTER: {icon: "\u{1f6e1}"},
|
|
AUTOMOD_TRIGGER_USER_PROFILE: {icon: "\u{1faaa}"},
|
|
BANNER: {icon: "\u{1f5bc}"},
|
|
BFG: {icon: "\u{1f388}", name: "BFG"},
|
|
BOOSTING_TIERS_EXPERIMENT_MEDIUM_GUILD: {icon: "\u{1f48e}"},
|
|
BOOSTING_TIERS_EXPERIMENT_SMALL_GUILD: {icon: "\u{1f48e}"},
|
|
BOT_DEVELOPER_EARLY_ACCESS: {icon: "\u{1f9ea}"},
|
|
BURST_REACTIONS: {icon: "\u2728", name: "Super Reactions"},
|
|
CHANNEL_BANNER: {icon: "\u{1f5bc}"},
|
|
CHANNEL_ICON_EMOJIS_GENERATED: {icon: "\u{1f603}"},
|
|
CHANNEL_HIGHLIGHTS: {icon: "\u{1f5c3}"},
|
|
CHANNEL_HIGHLIGHTS_DISABLED: {icon: "\u{1f6ab}"},
|
|
CLYDE_DISABLED: {icon: "\u{1f6ab}"},
|
|
CLYDE_ENABLED: {icon: "\u{1f916}"},
|
|
CLYDE_EXPERIMENT_ENABLED: {icon: "\u{1f9ea}"},
|
|
COMMERCE: {icon: "\u{1f6cd}"},
|
|
COMMUNITY: {icon: "\u{1f3d8}"},
|
|
COMMUNITY_CANARY: {icon: "\u{1f9ea}"},
|
|
COMMUNITY_EXP_LARGE_GATED: {icon: "\u{1f3d8}"},
|
|
COMMUNITY_EXP_LARGE_UNGATED: {icon: "\u{1f3d8}"},
|
|
COMMUNITY_EXP_MEDIUM: {icon: "\u{1f3d8}"},
|
|
CREATOR_ACCEPTED_NEW_TERMS: {icon: "\u2611\ufe0f"},
|
|
CREATOR_MONETIZABLE: {icon: "\u{1f4b0}"},
|
|
CREATOR_MONETIZABLE_DISABLED: {icon: "\u{1f6ab}"},
|
|
CREATOR_MONETIZABLE_PENDING_NEW_OWNER_ONBOARDING: {icon: "\u{1f4b1}"},
|
|
CREATOR_MONETIZABLE_PROVISIONAL: {icon: "\u{1f4b0}"},
|
|
CREATOR_MONETIZABLE_RESTRICTED: {icon: "\u26d4"},
|
|
CREATOR_MONETIZABLE_WHITEGLOVE: {icon: "\u{1f9ea}"},
|
|
CREATOR_MONETIZATION_APPLICATION_ALLOWLIST: {icon: "\u{1f4dc}"},
|
|
CREATOR_STORE_PAGE: {icon: "\u{1f6d2}"},
|
|
DEVELOPER_SUPPORT_SERVER: {icon: "\u2754"},
|
|
DISCOVERABLE: {icon: "\u{1f9ed}"},
|
|
DISCOVERABLE_DISABLED: {icon: "\u{1f6ab}"},
|
|
ENABLED_DISCOVERABLE_BEFORE: {icon: "\u{1f9ed}"},
|
|
EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT: {icon: "\u{1f9ea}"},
|
|
EXPOSED_TO_BOOSTING_TIERS_EXPERIMENT: {icon: "\u{1f9ea}"},
|
|
FEATURABLE: {icon: "\u{1f9ed}"},
|
|
FORCE_RELAY: {icon: "\u{1f4fb}"},
|
|
GUESTS_ENABLED: {icon: "\u{1f465}"},
|
|
GUILD_AUTOMOD_DEFAULT_LIST: {icon: "\u{1f6e1}"},
|
|
GUILD_COMMUNICATION_DISABLED_GUILDS: {icon: "\u{1f6d1}"},
|
|
GUILD_HOME_DEPRECATION_OVERRIDE: {icon: "\u{1f3da}"},
|
|
GUILD_HOME_OVERRIDE: {icon: "\u{1f3e0}"},
|
|
GUILD_HOME_TEST: {icon: "\u{1f9ea}"},
|
|
GUILD_MEMBER_VERIFICATION_EXPERIMENT: {icon: "\u{1f9ea}"},
|
|
GUILD_ONBOARDING: {icon: "\u{1f5f3}"},
|
|
GUILD_ONBOARDING_ADMIN_ONLY: {icon: "\u{1f5f3}"},
|
|
GUILD_ONBOARDING_EVER_ENABLED: {icon: "\u{1f5f3}"},
|
|
GUILD_ONBOARDING_HAS_PROMPTS: {icon: "\u{1f5f3}"},
|
|
GUILD_PRODUCTS: {icon: "\u{1f6cd}"},
|
|
GUILD_ROLE_SUBSCRIPTIONS: {icon: "\u{1f4b3}"},
|
|
GUILD_ROLE_SUBSCRIPTION_PURCHASE_FEEDBACK_LOOP: {icon: "\u{1f4b3}"},
|
|
GUILD_ROLE_SUBSCRIPTION_TIER_TEMPLATE: {icon: "\u{1f4b3}"},
|
|
GUILD_ROLE_SUBSCRIPTION_TRIALS: {icon: "\u{1f4b3}"},
|
|
GUILD_SERVER_GUIDE: {icon: "\u{1f9ae}"},
|
|
GUILD_WEB_PAGE_VANITY_URL: {icon: "\u{1f4c4}"},
|
|
HAD_EARLY_ACTIVITIES_ACCESS: {icon: "\u{1f680}"},
|
|
HAS_DIRECTORY_ENTRY: {icon: "\u{1faa7}"},
|
|
HIDE_FROM_EXPERIMENT_UI: {icon: "\u{1f9ea}"},
|
|
HUB: {icon: "\u{1f3eb}"},
|
|
INCREASED_THREAD_LIMIT: {icon: "\u{1f9f5}"},
|
|
INTERNAL_EMPLOYEE_ONLY: {icon: "\u{1f6e0}"},
|
|
INVITE_SPLASH: {icon: "\u{1f5bc}"},
|
|
INVITES_DISABLED: {icon: "\u26d4"},
|
|
LINKED_TO_HUB: {icon: "\u{1f3eb}"},
|
|
LURKABLE: {icon: "\u{1f441}"},
|
|
MARKETPLACES_CONNECTION_ROLES: {icon: "\u{1f517}"},
|
|
MEDIA_CHANNEL_ALPHA: {icon: "\u{1f5bc}"},
|
|
MEMBER_LIST_DISABLED: {icon: "\u{1f6ab}"},
|
|
MEMBER_PROFILES: {icon: "\u{1faaa}"},
|
|
MEMBER_SAFETY_PAGE_ROLLOUT: {icon: "\u{1f6e1}"},
|
|
MEMBER_VERIFICATION_GATE_ENABLED: {icon: "\u{1f6e1}"},
|
|
MEMBER_VERIFICATION_MANUAL_APPROVAL: {icon: "\u2705"},
|
|
MOBILE_WEB_ROLE_SUBSCRIPTION_PURCHASE_PAGE: {icon: "\u{1f4b3}"},
|
|
MONETIZATION_ENABLED: {icon: "\u{1f4b0}"},
|
|
MORE_EMOJI: {icon: "\u{1f603}"},
|
|
MORE_STICKERS: {icon: "\u{1f5bc}"},
|
|
NEWS: {icon: "\u{1f4f0}"},
|
|
NEW_THREAD_PERMISSIONS: {icon: "\u{1f9f5}"},
|
|
NON_COMMUNITY_RAID_ALERTS: {icon: "\u{1f6a8}"},
|
|
PARTNERED: {icon: "\u267e\ufe0f"},
|
|
PREMIUM_TIER_3_OVERRIDE: {icon: "\u{1f48e}"},
|
|
PREVIEW_ENABLED: {icon: "\u{1f441}"},
|
|
PRIVATE_THREADS: {icon: "\u{1f9f5}"},
|
|
PRODUCTS_AVAILABLE_FOR_PURCHASE: {icon: "\u{1f6cd}"},
|
|
PUBLIC: {icon: "\u{1f9ed}"},
|
|
PUBLIC_DISABLED: {icon: "\u{1f6ab}"},
|
|
RAID_ALERTS_DISABLED: {icon: "\u{1f6ab}"},
|
|
RAID_ALERTS_ENABLED: {icon: "\u{1f6a8}"},
|
|
RELAY_ENABLED: {icon: "\u{1f4fb}"},
|
|
RESTRICT_SPAM_RISK_GUILDS: {icon: "\u{1f6d1}"},
|
|
ROLE_ICONS: {icon: "\u{1f3f7}"},
|
|
ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE: {icon: "\u{1f4b3}"},
|
|
ROLE_SUBSCRIPTIONS_ENABLED: {icon: "\u{1f4b3}"},
|
|
ROLE_SUBSCRIPTIONS_ENABLED_FOR_PURCHASE: {icon: "\u{1f4b3}"},
|
|
SEVEN_DAY_THREAD_ARCHIVE: {icon: "\u{1f9f5}"},
|
|
SHARD: {icon: "\u{1f4a0}"},
|
|
SHARED_CANVAS_FRIENDS_AND_FAMILY_TEST: {icon: "\u{1f58c}"},
|
|
SOUNDBOARD: {icon: "\u{1f50a}"},
|
|
SUMMARIES_ENABLED: {icon: "\u{1f4da}"},
|
|
SUMMARIES_ENABLED_GA: {
|
|
icon: "\u{1f4da}",
|
|
name: "Summaries Enabled (General Access)",
|
|
},
|
|
SUMMARIES_DISABLED_BY_USER: {icon: "\u26d4"},
|
|
SUMMARIES_ENABLED_BY_USER: {icon: "\u{1f4da}"},
|
|
SUMMARIES_LONG_LOOKBACK: {icon: "\u{1f5c2}"},
|
|
STAFF_LEVEL_COLLABORATOR_REQUIRED: {icon: "\u{1f6e0}"},
|
|
STAFF_LEVEL_RESTRICTED_COLLABORATOR_REQUIRED: {icon: "\u{1f6e0}"},
|
|
TEXT_IN_STAGE_ENABLED: {icon: "\u{1f5e8}"},
|
|
TEXT_IN_VOICE_ENABLED: {icon: "\u{1f5e8}"},
|
|
THREADS_ENABLED_TESTING: {icon: "\u{1f9f5}"},
|
|
THREADS_ENABLED: {icon: "\u{1f9f5}"},
|
|
THREAD_DEFAULT_AUTO_ARCHIVE_DURATION: {icon: "\u{1f9f5}"},
|
|
THREADS_ONLY_CHANNEL: {icon: "\u{1f5e8}", name: "Forum Channels"},
|
|
THREE_DAY_THREAD_ARCHIVE: {icon: "\u{1f9f5}"},
|
|
TICKETED_EVENTS_ENABLED: {icon: "\u{1f39f}"},
|
|
TICKETING_ENABLED: {icon: "\u{1f39f}"},
|
|
VANITY_URL: {icon: "\u{1f517}"},
|
|
VERIFIED: {icon: "\u2b50"},
|
|
VIP_REGIONS: {icon: "\u{1f399}"},
|
|
VOICE_CHANNEL_EFFECTS: {icon: "\u2728"},
|
|
VOICE_IN_THREADS: {icon: "\u{1f399}"},
|
|
WELCOME_SCREEN_ENABLED: {icon: "\u{1f44b}"},
|
|
};
|
|
|
|
const GUILD_VERIFICATION_LEVELS = [
|
|
"None",
|
|
"Low",
|
|
"Medium",
|
|
"(╯°□°)╯︵ ┻━┻ (High)",
|
|
"┻━┻ ミヽ(ಠ益ಠ)ノ彡┻━┻ (Very High/Phone)",
|
|
];
|
|
const GUILD_CONTENT_FILTER = [
|
|
"Disabled",
|
|
"Members without roles",
|
|
"All members",
|
|
];
|
|
|
|
const CHANNEL_TYPE_NAMES = {
|
|
0: "text",
|
|
2: "voice",
|
|
4: "category",
|
|
5: "announcement",
|
|
13: "stage",
|
|
14: "hub directory",
|
|
15: "forum",
|
|
16: "media",
|
|
};
|
|
|
|
const EMOJI_SETS = {
|
|
blobs: {
|
|
prefix:
|
|
"https://cdn.jsdelivr.net/gh/googlefonts/noto-emoji@e456654119cc3a5f9bebb7bbd00512456f983d2d/svg/emoji_u",
|
|
sep: "_",
|
|
suffix: ".svg",
|
|
},
|
|
noto: {
|
|
prefix: "https://gitcdn.xyz/repo/googlefonts/noto-emoji/master/svg/emoji_u",
|
|
sep: "_",
|
|
suffix: ".svg",
|
|
},
|
|
twemoji: {
|
|
prefix: "https://twemoji.maxcdn.com/v/latest/svg/",
|
|
sep: "-",
|
|
suffix: ".svg",
|
|
},
|
|
mustd: {
|
|
prefix:
|
|
"https://cdn.jsdelivr.net/gh/Mstrodl/mutant-standard-mirror@0435227d9d8c0d6a346c8ae4c12b08a5cdc37041/emoji/",
|
|
sep: "-",
|
|
suffix: ".svg",
|
|
},
|
|
apple: {
|
|
prefix: "https://intrnl.github.io/assetsEmoji/AppleColor/emoji_u",
|
|
sep: "_",
|
|
suffix: ".png",
|
|
},
|
|
facebook: {
|
|
prefix: "https://intrnl.github.io/assetsEmoji/facebook/emoji_u",
|
|
sep: "_",
|
|
suffix: ".png",
|
|
},
|
|
};
|
|
EMOJI_SETS["noto-old"] = EMOJI_SETS.blobs;
|
|
EMOJI_SETS.mutant = EMOJI_SETS.mustd;
|
|
EMOJI_SETS.mutstd = EMOJI_SETS.mustd;
|
|
EMOJI_SETS.ms = EMOJI_SETS.mustd;
|
|
EMOJI_SETS.twitter = EMOJI_SETS.twemoji;
|
|
EMOJI_SETS.fb = EMOJI_SETS.facebook;
|
|
|
|
// }}}
|
|
|
|
// {{{ helpers
|
|
|
|
function flagsFromInt(int, flags, withRaw = true) {
|
|
const bits = int.toString(2);
|
|
const splitBits = bits.split("").reverse();
|
|
|
|
const reassignedBits = {};
|
|
|
|
for (const shift in splitBits) {
|
|
reassignedBits[shift] = splitBits[shift];
|
|
}
|
|
|
|
const assignedFlags = Object.keys(reassignedBits).filter(
|
|
(bit) => reassignedBits[bit] == 1
|
|
);
|
|
|
|
const out = [];
|
|
|
|
for (const flag of assignedFlags) {
|
|
out.push(
|
|
`${flags[flag] ?? "<Undocumented Flag>"}${
|
|
withRaw == true || flags[flag] == null
|
|
? ` (1 << ${flag}, ${1n << BigInt(flag)})`
|
|
: ""
|
|
}`
|
|
);
|
|
}
|
|
|
|
return out.join("\n");
|
|
}
|
|
|
|
async function getGuild(id) {
|
|
if (hf.bot.guilds.has(id)) {
|
|
return {source: "local", data: hf.bot.guilds.get(id)};
|
|
}
|
|
|
|
try {
|
|
const preview = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/guilds/${id}/preview`,
|
|
true
|
|
);
|
|
if (preview) return {source: "preview", data: preview};
|
|
} catch {
|
|
try {
|
|
const discovery = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/discovery/${id}`,
|
|
false
|
|
);
|
|
if (discovery) return {source: "discovery", data: discovery};
|
|
} catch {
|
|
try {
|
|
const widget = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/guilds/${id}/widget.json`,
|
|
false
|
|
);
|
|
if (widget) return {source: "widget", data: widget};
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// }}}
|
|
|
|
// {{{ commands
|
|
|
|
const avatar = new Command("avatar");
|
|
avatar.category = CATEGORY;
|
|
avatar.helpText = "Get avatar of a user";
|
|
avatar.usage = "<user>";
|
|
avatar.callback = async function (msg, line, [user], {server, guild}) {
|
|
if (server || guild) {
|
|
if (!msg.guildID) {
|
|
return "`--server/--guild` can only be used within guilds.";
|
|
} else {
|
|
const guild = msg.channel.guild || hf.bot.guilds.get(msg.guildID);
|
|
const url = `${ICON_BASE}${guild.id}/${guild.icon}.${
|
|
guild.icon.startsWith("a_") ? "gif?size=4096&_=.gif" : "png?size=4096"
|
|
}`;
|
|
return {
|
|
embeds: [
|
|
{
|
|
title: "Server Icon",
|
|
url,
|
|
image: {
|
|
url,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
}
|
|
} else if (user) {
|
|
const lookup = await lookupUser(msg, user);
|
|
if (
|
|
lookup == "No results" ||
|
|
lookup == "Canceled" ||
|
|
lookup == "Request timed out"
|
|
) {
|
|
return lookup;
|
|
} else {
|
|
let member = lookup;
|
|
const guild = msg.channel.guild || hf.bot.guilds.get(msg.guildID);
|
|
if (guild) {
|
|
if (guild.members.has(lookup.id)) {
|
|
member = guild.members.get(lookup.id);
|
|
} else {
|
|
const fetched = await guild.fetchMembers({
|
|
userIDs: [lookup.id],
|
|
});
|
|
member = fetched[0];
|
|
}
|
|
}
|
|
|
|
const baseEmbed = {
|
|
title: `Avatar for \`${formatUsername(member)}\``,
|
|
};
|
|
|
|
const normalAvatar = member.user.avatar;
|
|
const guildAvatar = member.avatar;
|
|
|
|
const normalUrl =
|
|
AVATAR_BASE +
|
|
member.id +
|
|
"/" +
|
|
normalAvatar +
|
|
"." +
|
|
(normalAvatar.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096");
|
|
const guildUrl =
|
|
guildAvatar &&
|
|
"https://cdn.discordapp.com/guilds/" +
|
|
guild.id +
|
|
"/users/" +
|
|
member.id +
|
|
"/avatars/" +
|
|
guildAvatar +
|
|
"." +
|
|
(guildAvatar.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096");
|
|
|
|
baseEmbed.description =
|
|
`[Normal avatar](${normalUrl})` +
|
|
(guild && guildAvatar ? `\n[Guild avatar](${guildUrl})` : "");
|
|
baseEmbed.url = normalUrl;
|
|
|
|
const guildEmbed = {...baseEmbed};
|
|
baseEmbed.image = {url: normalUrl};
|
|
guildEmbed.image = {url: guildUrl};
|
|
|
|
return {
|
|
embeds: [baseEmbed, guildAvatar && guildEmbed].filter((x) => x != null),
|
|
};
|
|
}
|
|
} else {
|
|
const guild = msg.channel.guild || hf.bot.guilds.get(msg.guildID);
|
|
|
|
const baseEmbed = {
|
|
title: `Avatar for \`${formatUsername(msg.author)}\``,
|
|
};
|
|
|
|
const normalAvatar = msg.author.avatar;
|
|
const guildAvatar = msg.member?.avatar;
|
|
|
|
const normalUrl =
|
|
AVATAR_BASE +
|
|
msg.author.id +
|
|
"/" +
|
|
normalAvatar +
|
|
"." +
|
|
(normalAvatar.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096");
|
|
const guildUrl =
|
|
guildAvatar &&
|
|
"https://cdn.discordapp.com/guilds/" +
|
|
guild.id +
|
|
"/users/" +
|
|
msg.author.id +
|
|
"/avatars/" +
|
|
guildAvatar +
|
|
"." +
|
|
(guildAvatar.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096");
|
|
|
|
baseEmbed.description =
|
|
`[Normal avatar](${normalUrl})` +
|
|
(guild && guildAvatar ? `\n[Guild avatar](${guildUrl})` : "");
|
|
baseEmbed.url = normalUrl;
|
|
|
|
const guildEmbed = {...baseEmbed};
|
|
baseEmbed.image = {url: normalUrl};
|
|
guildEmbed.image = {url: guildUrl};
|
|
|
|
return {
|
|
embeds: [baseEmbed, guildAvatar && guildEmbed].filter((x) => x != null),
|
|
};
|
|
}
|
|
};
|
|
hf.registerCommand(avatar);
|
|
|
|
const banner = new Command("banner");
|
|
banner.category = CATEGORY;
|
|
banner.helpText = "Get banner of a user";
|
|
banner.usage = "<user>";
|
|
banner.callback = async function (msg, line, [user], {server, guild}) {
|
|
let id = msg.author.id;
|
|
|
|
if (server || guild) {
|
|
if (!msg.guildID) {
|
|
return "`--server/--guild` can only be used within guilds.";
|
|
} else {
|
|
const guild = msg.channel.guild || hf.bot.guilds.get(msg.guildID);
|
|
|
|
if (!guild.banner) return "This guild does not have a banner.";
|
|
|
|
const url = `${BANNER_BASE}${guild.id}/${guild.banner}.${
|
|
guild.banner.startsWith("a_") ? "gif?size=4096&_=.gif" : "png?size=4096"
|
|
}`;
|
|
return {
|
|
embeds: [
|
|
{
|
|
title: "Server Banner",
|
|
url,
|
|
image: {
|
|
url,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
}
|
|
} else if (user) {
|
|
const lookup = await lookupUser(msg, user);
|
|
if (
|
|
lookup == "No results" ||
|
|
lookup == "Canceled" ||
|
|
lookup == "Request timed out"
|
|
) {
|
|
return lookup;
|
|
} else {
|
|
id = lookup.id;
|
|
}
|
|
}
|
|
|
|
const userObj = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
"/users/" + id,
|
|
true
|
|
);
|
|
|
|
if (!userObj.banner) return "This user does not have a banner.";
|
|
|
|
const url = `${BANNER_BASE}${userObj.id}/${userObj.banner}.${
|
|
userObj.banner.startsWith("a_") ? "gif?size=4096&_=.gif" : "png?size=4096"
|
|
}`;
|
|
return {
|
|
embeds: [
|
|
{
|
|
title: `Banner for \`${formatUsername(userObj)}\``,
|
|
url,
|
|
image: {
|
|
url,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
};
|
|
hf.registerCommand(banner);
|
|
|
|
const lookupinvite = new Command("lookupinvite");
|
|
lookupinvite.category = CATEGORY;
|
|
lookupinvite.helpText = "Lookup an invite";
|
|
lookupinvite.usage = "<invite code>";
|
|
lookupinvite.addAlias("linvite");
|
|
lookupinvite.addAlias("iinfo");
|
|
lookupinvite.addAlias("ii");
|
|
lookupinvite.callback = async function (msg, line) {
|
|
if (!line || line == "") {
|
|
return "No arguments passed.";
|
|
}
|
|
|
|
line = line.replace(/(https?:\/\/)?discord\.gg\//, "");
|
|
|
|
let bail = false;
|
|
let error;
|
|
let invite;
|
|
try {
|
|
invite = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/invites/${line}?with_counts=true&with_expiration=true`
|
|
);
|
|
} catch (err) {
|
|
bail = true;
|
|
error = err;
|
|
}
|
|
if (bail && error) {
|
|
if (error.message.includes("Unknown Invite")) {
|
|
return "Invite provided is not valid.";
|
|
} else {
|
|
return `:warning: Got error \`${safeString(error)}\``;
|
|
}
|
|
}
|
|
if (!invite) return ":warning: No data returned.";
|
|
|
|
if (invite.message) {
|
|
if (invite.message == "Unknown Invite") {
|
|
return "Invite provided is not valid.";
|
|
} else {
|
|
return `:warning: Got error \`${invite.code}: "${invite.message}"\``;
|
|
}
|
|
} else {
|
|
const embed = {
|
|
title: `Invite Info: \`${invite.code}\``,
|
|
description: invite.description,
|
|
fields: [],
|
|
};
|
|
|
|
const expires = {
|
|
name: "Expires",
|
|
value:
|
|
invite.expires_at == null
|
|
? "Never"
|
|
: `<t:${Math.floor(new Date(invite.expires_at).getTime() / 1000)}>`,
|
|
inline: true,
|
|
};
|
|
const inviter = invite.inviter
|
|
? {
|
|
name: "Inviter",
|
|
value: `**${formatUsername(invite.inviter)}** (${invite.inviter.id})`,
|
|
inline: false,
|
|
}
|
|
: null;
|
|
|
|
const features = invite.guild.features.sort().map(
|
|
(feature) =>
|
|
(GUILD_FEATURES[feature]?.icon ?? "\u2753") +
|
|
" " +
|
|
(GUILD_FEATURES[feature]?.name ??
|
|
feature
|
|
.split("_")
|
|
.map((x) => x[0] + x.substring(1).toLowerCase())
|
|
.join(" "))
|
|
);
|
|
|
|
if (invite.type == 0) {
|
|
embed.fields.push(
|
|
...[
|
|
{
|
|
name: "Guild",
|
|
value: `**${invite.guild.name}** (${invite.guild.id})`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Channel",
|
|
value: `**${invite.channel.name}** (${invite.channel.id})`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Boosts",
|
|
value: invite.guild.premium_subscription_count ?? 0,
|
|
inline: true,
|
|
},
|
|
expires,
|
|
{
|
|
name: "Member Count",
|
|
value: `<:online:1152111668856361010>${invite.approximate_presence_count} online\t\t<:offline:1152111682886316042>${invite.approximate_member_count} members`,
|
|
inline: false,
|
|
},
|
|
inviter,
|
|
invite.guild.welcome_screen && {
|
|
name: "Welcome Screen",
|
|
value: `"${
|
|
invite.guild.welcome_screen.description
|
|
}"\n${invite.guild.welcome_screen.welcome_channels
|
|
.map(
|
|
(c) =>
|
|
`${
|
|
c.emoji_id
|
|
? `[:${c.emoji_name}:](${EMOTE_BASE}${c.emoji_id}.webp)`
|
|
: c.emoji_name
|
|
} ${c.description} \`(${c.channel_id})\``
|
|
)
|
|
.join("\n")}`,
|
|
inline: false,
|
|
},
|
|
{
|
|
name: `Features (${features.length})`,
|
|
value:
|
|
features.length > 0
|
|
? features.slice(0, Math.ceil(features.length / 2)).join("\n")
|
|
: "None",
|
|
inline: true,
|
|
},
|
|
features.length > 1
|
|
? {
|
|
name: "\u200b",
|
|
value: features
|
|
.slice(Math.ceil(features.length / 2), features.length)
|
|
.join("\n"),
|
|
inline: true,
|
|
}
|
|
: null,
|
|
].filter((x) => !!x)
|
|
);
|
|
embed.thumbnail = {
|
|
url:
|
|
invite.guild.icon &&
|
|
`${ICON_BASE}${invite.guild.id}/${invite.guild.icon}.${
|
|
invite.guild.icon.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096"
|
|
}`,
|
|
};
|
|
|
|
if (
|
|
invite.guild &&
|
|
(invite.guild.icon || invite.guild.splash || invite.guild.banner)
|
|
) {
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: `${
|
|
invite.guild.icon
|
|
? `[Icon](${ICON_BASE}${invite.guild.id}/${invite.guild.icon}.${
|
|
invite.guild.icon.startsWith("a_")
|
|
? "gif?size=4096"
|
|
: "png?size=4096"
|
|
})`
|
|
: ""
|
|
}${
|
|
invite.guild.splash
|
|
? `${invite.guild.icon ? " | " : ""}[Splash](${SPLASH_BASE}${
|
|
invite.guild.id
|
|
}/${invite.guild.splash}.png?size=4096)`
|
|
: ""
|
|
}${
|
|
invite.guild.banner
|
|
? `${
|
|
invite.guild.icon || invite.guild.splash ? " | " : ""
|
|
}[Banner](${BANNER_BASE}${invite.guild.id}/${
|
|
invite.guild.banner
|
|
}.${
|
|
invite.guild.banner.startsWith("a_")
|
|
? "gif?size=4096"
|
|
: "png?size=4096"
|
|
})`
|
|
: ""
|
|
}`,
|
|
inline: false,
|
|
});
|
|
}
|
|
|
|
if (invite.guild?.splash) {
|
|
embed.image = {
|
|
url: `${SPLASH_BASE}${invite.guild.id}/${invite.guild.splash}.png?size=256`,
|
|
};
|
|
}
|
|
} else if (invite.type == 1) {
|
|
embed.title += " (Group DM)";
|
|
embed.fields.push(
|
|
...[
|
|
{
|
|
name: "Channel",
|
|
value: `**${
|
|
invite.channel.name ??
|
|
invite.channel.recipients
|
|
.map((member) => member.username)
|
|
.join(", ")
|
|
}** (${invite.channel.id})`,
|
|
inline: false,
|
|
},
|
|
{
|
|
name: "Member Count",
|
|
value: `<:offline:1152111682886316042>${invite.approximate_member_count} members`,
|
|
inline: true,
|
|
},
|
|
expires,
|
|
invite.channel.name != null && {
|
|
name: "Recipients",
|
|
value: invite.channel.recipients
|
|
.map((member) => member.username)
|
|
.join(", "),
|
|
inline: false,
|
|
},
|
|
inviter,
|
|
].filter((x) => !!x)
|
|
);
|
|
|
|
const groupIcon = invite.channel.icon
|
|
? `${CHANNEL_ICON_BASE}${invite.channel.id}/${invite.channel.icon}.${
|
|
invite.channel.icon.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096"
|
|
}`
|
|
: "https://discord.com" +
|
|
DEFAULT_GROUP_DM_AVATARS[
|
|
(Math.floor(Number(invite.channel.id) / Math.pow(2, 22)) +
|
|
1420070400000) %
|
|
DEFAULT_GROUP_DM_AVATARS.length
|
|
];
|
|
|
|
embed.thumbnail = {
|
|
url: groupIcon,
|
|
};
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: `[Icon](${groupIcon})`,
|
|
inline: false,
|
|
});
|
|
} else if (invite.type == 2) {
|
|
embed.title += " (Friend)";
|
|
embed.fields.push(expires, inviter);
|
|
|
|
const avatarURL =
|
|
invite.inviter?.avatar &&
|
|
`${AVATAR_BASE}${invite.inviter.id}/${invite.inviter.avatar}.${
|
|
invite.inviter.avatar.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096"
|
|
}`;
|
|
|
|
if (avatarURL) {
|
|
embed.thumbnail = {
|
|
url: avatarURL,
|
|
};
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: `[Avatar](${avatarURL})`,
|
|
inline: false,
|
|
});
|
|
}
|
|
} else {
|
|
return `Unhandled invite type: \`${invite.type}\``;
|
|
}
|
|
|
|
return {embed};
|
|
}
|
|
};
|
|
hf.registerCommand(lookupinvite);
|
|
|
|
const snowflake = new Command("snowflake");
|
|
snowflake.category = CATEGORY;
|
|
snowflake.helpText = "Converts a snowflake ID into readable time.";
|
|
snowflake.usage = "<--twitter> [snowflake]";
|
|
snowflake.callback = function (msg, line, [snowflake], {twitter}) {
|
|
const num = Number(snowflake);
|
|
if (!isNaN(num)) {
|
|
return `The timestamp for \`${snowflake}\` is <t:${Math.floor(
|
|
snowflakeToTimestamp(num, twitter) / 1000
|
|
)}:F>`;
|
|
} else {
|
|
return "Argument provided is not a number.";
|
|
}
|
|
};
|
|
hf.registerCommand(snowflake);
|
|
|
|
const flagdump = new Command("flagdump");
|
|
flagdump.category = CATEGORY;
|
|
flagdump.helpText = "Dumps Discord user flags.";
|
|
flagdump.usage = "[flags or user mention]";
|
|
flagdump.callback = async function (msg, line, [numOrMention], {id, list}) {
|
|
const num = Number(numOrMention);
|
|
if (list) {
|
|
let allFlags = 0n;
|
|
for (const index in USER_FLAGS) {
|
|
if (USER_FLAGS[index] == undefined) continue;
|
|
allFlags += 1n << BigInt(index);
|
|
}
|
|
return `All flags:\n\`\`\`${flagsFromInt(allFlags, USER_FLAGS)}\`\`\``;
|
|
} else if (/<@!?(\d+)>/.test(numOrMention) || !isNaN(id)) {
|
|
const targetId = id || numOrMention.match(/<@!?(\d+)>/)?.[1];
|
|
if (!targetId) return "Got null ID.";
|
|
const guild = msg.channel.guild || hf.bot.guilds.get(msg.guildID);
|
|
let user = guild && (await guild.fetchMembers({userIDs: [targetId]}));
|
|
if (!user || !user[0]) {
|
|
user = hf.bot.users.get(id);
|
|
} else {
|
|
user = user[0].user;
|
|
}
|
|
|
|
if (!user) {
|
|
return "User not cached.";
|
|
} else {
|
|
return `\`${formatUsername(user)}\`'s public flags:\n\`\`\`${flagsFromInt(
|
|
user.publicFlags,
|
|
USER_FLAGS
|
|
)}\`\`\``;
|
|
}
|
|
} else if (!isNaN(num)) {
|
|
return `\`\`\`\n${flagsFromInt(num, USER_FLAGS)}\`\`\``;
|
|
} else {
|
|
return `\`${formatUsername(
|
|
msg.author
|
|
)}\`'s public flags:\n\`\`\`${flagsFromInt(
|
|
msg.author.publicFlags,
|
|
USER_FLAGS
|
|
)}\`\`\``;
|
|
}
|
|
};
|
|
hf.registerCommand(flagdump);
|
|
|
|
const jumbo = new Command("jumbo");
|
|
jumbo.category = CATEGORY;
|
|
jumbo.helpText = "Gets the raw image of an emoji.";
|
|
jumbo.usage = "<emoji>";
|
|
jumbo.addAlias("e");
|
|
jumbo.addAlias("emote");
|
|
jumbo.addAlias("emoji");
|
|
jumbo.callback = async function (msg, line) {
|
|
if (CUSTOM_EMOTE_REGEX.test(line)) {
|
|
const [_, animatedFlag, name, id] = line.match(CUSTOM_EMOTE_REGEX);
|
|
const animated = animatedFlag === "a";
|
|
|
|
return {
|
|
embeds: [
|
|
{
|
|
title: `:${name}: - \`${id}\``,
|
|
url: `${EMOTE_BASE}${id}.${animated ? "gif" : "png"}?v=1`,
|
|
image: {
|
|
url: `${EMOTE_BASE}${id}.${animated ? "gif" : "png"}?v=1`,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
} else {
|
|
let setName = "twemoji";
|
|
for (const set in EMOJI_SETS) {
|
|
if (line.startsWith(`--${set} `)) {
|
|
setName = set;
|
|
line = line.replace(`--${set} `, "");
|
|
}
|
|
}
|
|
|
|
const set = EMOJI_SETS[setName];
|
|
|
|
const emoji = Array.from(line)
|
|
.map((char) => char.codePointAt().toString(16))
|
|
.join(set.sep);
|
|
const url = set.prefix + emoji + set.suffix;
|
|
|
|
const name = EMOJI_NAMES[line]
|
|
? `\\:${EMOJI_NAMES[line]}\\:`
|
|
: await getNamesFromString(line).then((name) =>
|
|
name.map((x) => x[1]).join(", ")
|
|
);
|
|
|
|
const emojiFound = await fetch(url, {method: "HEAD"}).then((res) => res.ok);
|
|
|
|
if (emojiFound) {
|
|
return "Emoji not found. The emoji set chosen might not have this emote as an image.";
|
|
}
|
|
|
|
if (set.suffix == ".svg") {
|
|
const svg = await fetch(url)
|
|
.then((res) => res.arrayBuffer())
|
|
.then((b) => Buffer.from(b));
|
|
const converted = await sharp(svg, {density: 2400})
|
|
.resize(1024)
|
|
.toBuffer();
|
|
|
|
return {
|
|
embeds: [
|
|
{
|
|
title: `${name} (${emoji.toUpperCase().replace(/[-_]/g, ", ")})`,
|
|
url,
|
|
image: {
|
|
url: "attachment://emoji.png",
|
|
},
|
|
},
|
|
],
|
|
file: {
|
|
file: converted,
|
|
name: "emoji.png",
|
|
},
|
|
};
|
|
} else {
|
|
return {
|
|
embeds: [
|
|
{
|
|
title: `${name} (${emoji.toUpperCase().replace(/[-_]/g, ", ")})`,
|
|
url,
|
|
image: {
|
|
url,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
}
|
|
}
|
|
};
|
|
hf.registerCommand(jumbo);
|
|
|
|
const charinfo = new Command("charinfo");
|
|
charinfo.category = CATEGORY;
|
|
charinfo.helpText = "Get information about a set of characters.";
|
|
charinfo.usage = "[characters]";
|
|
charinfo.addAlias("char");
|
|
charinfo.callback = async function (msg, line) {
|
|
const names = await getNamesFromString(line);
|
|
const chars = [...line];
|
|
const lines = names
|
|
.map(
|
|
([code, name], index) =>
|
|
`\`\\u${code}\`: ${name} - ${chars[index]} - <http://www.fileformat.info/info/unicode/char/${code}>`
|
|
)
|
|
.join("\n");
|
|
|
|
if (lines.length > 2000) {
|
|
return "Output too long: " + (await hastebin(lines));
|
|
} else {
|
|
return lines;
|
|
}
|
|
};
|
|
hf.registerCommand(charinfo);
|
|
|
|
const presence = new Command("presence");
|
|
presence.category = CATEGORY;
|
|
presence.helpText = "Get presences of a user.";
|
|
presence.usage = "<user>";
|
|
presence.addAlias("status");
|
|
presence.callback = async function (msg, line) {
|
|
if (!msg.guildID) return "Can only be used in guilds.";
|
|
|
|
let target;
|
|
if (line) {
|
|
const user = await lookupUser(msg, line);
|
|
if (
|
|
user == "No results" ||
|
|
user == "Canceled" ||
|
|
user == "Request timed out"
|
|
) {
|
|
return user;
|
|
} else {
|
|
let member = user;
|
|
const guild = msg.channel.guild || hf.bot.guilds.get(msg.guildID);
|
|
if (guild) {
|
|
if (guild.members.has(user.id)) {
|
|
member = guild.members.get(user.id);
|
|
} else {
|
|
const fetched = await guild.fetchMembers({
|
|
userIDs: [user.id],
|
|
});
|
|
member = fetched[0];
|
|
}
|
|
target = member;
|
|
}
|
|
}
|
|
} else {
|
|
target = msg.member;
|
|
}
|
|
|
|
if (target) {
|
|
if (!target.clientStatus)
|
|
return `**${formatUsername(target)}** is offline.`;
|
|
|
|
const icons = [];
|
|
for (const platform of Object.keys(target.clientStatus)) {
|
|
const status = target.clientStatus[platform];
|
|
if (status == "offline") continue;
|
|
|
|
icons.push(PRESENCE_ICONS[platform][status]);
|
|
}
|
|
|
|
const embeds = [];
|
|
const files = [];
|
|
|
|
for (const index in target.activities) {
|
|
const activity = target.activities[index];
|
|
if (activity.type == 4) {
|
|
const embed = {};
|
|
|
|
if (activity.emoji) {
|
|
if (activity.emoji.id) {
|
|
const url = `${EMOTE_BASE}${activity.emoji.id}.${
|
|
activity.emoji.animated ? "gif" : "png"
|
|
}`;
|
|
embed.author = {
|
|
url,
|
|
icon_url: url,
|
|
name: activity.state ?? "\u200b",
|
|
};
|
|
} else {
|
|
embed.title = `${activity.emoji.name} ${activity.state ?? ""}`;
|
|
}
|
|
} else {
|
|
embed.title = activity.state ?? "";
|
|
}
|
|
|
|
embeds.push(embed);
|
|
} else {
|
|
const embed = {
|
|
title: `${PRESENCE_TYPES[activity.type]} **${activity.name}**`,
|
|
fields: [],
|
|
};
|
|
const descLines = [];
|
|
if (activity.type == 2) {
|
|
if (activity.details) {
|
|
let details = activity.details;
|
|
if (activity.name == "Spotify" && activity.sync_id) {
|
|
details = `[${details}](https://open.spotify.com/track/${activity.sync_id})`;
|
|
}
|
|
descLines.push(`**${details}**`);
|
|
}
|
|
if (activity.state) descLines.push(activity.state);
|
|
if (activity.assets?.large_text)
|
|
descLines.push(activity.assets.large_text);
|
|
} else {
|
|
if (activity.details) descLines.push(activity.details);
|
|
if (activity.state) {
|
|
let stateLine = activity.state;
|
|
if (activity.party?.size) {
|
|
stateLine += ` (${activity.party.size[0]} of ${activity.party.size[1]})`;
|
|
}
|
|
descLines.push(stateLine);
|
|
}
|
|
}
|
|
|
|
if (activity.timestamps) {
|
|
if (activity.timestamps.start && !activity.timestamps.end) {
|
|
descLines.push(
|
|
formatTime(Date.now() - activity.timestamps.start) + " elapsed"
|
|
);
|
|
} else if (!activity.timestamps.start && activity.timestamps.end) {
|
|
descLines.push(
|
|
formatTime(activity.timestamps.end - Date.now()) + " remaining"
|
|
);
|
|
} else if (
|
|
activity.timestamps.start != null &&
|
|
activity.timestamps.end != null
|
|
) {
|
|
const position = Date.now() - activity.timestamps.start;
|
|
const length = activity.timestamps.end - activity.timestamps.start;
|
|
|
|
const timeEnd = formatTime(length);
|
|
const timePos = formatTime(position);
|
|
|
|
const progress = position >= length ? 1 : position / length;
|
|
const barLength = Math.round(progress * NOWPLAYING_BAR_LENGTH);
|
|
|
|
const bar = `\`[${"=".repeat(barLength)}${" ".repeat(
|
|
NOWPLAYING_BAR_LENGTH - barLength
|
|
)}]\``;
|
|
const time = `\`${timePos}${" ".repeat(
|
|
NOWPLAYING_BAR_LENGTH + 2 - timePos.length - timeEnd.length
|
|
)}${timeEnd}\``;
|
|
|
|
descLines.push(bar);
|
|
descLines.push(time);
|
|
}
|
|
}
|
|
|
|
if (activity.assets?.large_text && activity.type != 2) {
|
|
embed.fields.push({
|
|
name: "Large Text",
|
|
value: activity.assets.large_text,
|
|
});
|
|
}
|
|
|
|
if (activity.assets?.small_text) {
|
|
embed.fields.push({
|
|
name: "Small Text",
|
|
value: activity.assets.small_text,
|
|
});
|
|
}
|
|
|
|
if (activity.application_id) {
|
|
embed.fields.push({
|
|
name: "Application ID",
|
|
value: `\`${activity.application_id}\``,
|
|
});
|
|
}
|
|
|
|
embed.description = descLines.join("\n");
|
|
|
|
if (activity.assets) {
|
|
if (activity.assets.large_image != null) {
|
|
let largeUrl;
|
|
if (activity.assets.large_image.startsWith("mp:")) {
|
|
largeUrl = activity.assets.large_image.replace(
|
|
"mp:",
|
|
"https://media.discordapp.net/"
|
|
);
|
|
} else if (activity.assets.large_image.startsWith("spotify:")) {
|
|
largeUrl = activity.assets.large_image.replace(
|
|
"spotify:",
|
|
"https://i.scdn.co/image/"
|
|
);
|
|
} else {
|
|
largeUrl = `https://cdn.discordapp.com/app-assets/${activity.application_id}/${activity.assets.large_image}.png`;
|
|
}
|
|
|
|
let smallUrl;
|
|
if (activity.assets.small_image != null) {
|
|
if (activity.assets.small_image.startsWith("mp:")) {
|
|
smallUrl = activity.assets.small_image.replace(
|
|
"mp:",
|
|
"https://media.discordapp.net/"
|
|
);
|
|
} else {
|
|
smallUrl = `https://cdn.discordapp.com/app-assets/${activity.application_id}/${activity.assets.small_image}.png`;
|
|
}
|
|
}
|
|
|
|
const largeImage = await fetch(largeUrl)
|
|
.then((res) => res.arrayBuffer())
|
|
.then((b) => Buffer.from(b));
|
|
const presenceImage = sharp(largeImage).resize(60, 60);
|
|
if (smallUrl) {
|
|
const smallImage = await fetch(smallUrl)
|
|
.then((res) => res.arrayBuffer())
|
|
.then((b) => Buffer.from(b));
|
|
const smallImageBuffer = await sharp(smallImage)
|
|
.resize(20, 20)
|
|
.toBuffer();
|
|
|
|
presenceImage.composite([
|
|
{
|
|
input: smallImageBuffer,
|
|
gravity: "southeast",
|
|
},
|
|
]);
|
|
}
|
|
|
|
files.push({
|
|
contents: await presenceImage.toBuffer(),
|
|
name: `${index}.png`,
|
|
});
|
|
embed.thumbnail = {
|
|
url: `attachment://${index}.png`,
|
|
};
|
|
} else if (
|
|
!activity.assets.large_image &&
|
|
activity.assets.small_image != null
|
|
) {
|
|
let smallUrl;
|
|
if (activity.assets.small_image.startsWith("mp:")) {
|
|
smallUrl = activity.assets.small_image.replace(
|
|
"mp:",
|
|
"https://media.discordapp.net/"
|
|
);
|
|
} else {
|
|
smallUrl = `https://cdn.discordapp.com/app-assets/${activity.application_id}/${activity.assets.small_image}.png`;
|
|
}
|
|
|
|
const smallImage = await fetch(smallUrl)
|
|
.then((res) => res.arrayBuffer())
|
|
.then((b) => Buffer.from(b));
|
|
const presenceImage = await sharp(smallImage)
|
|
.resize(60, 60)
|
|
.toBuffer();
|
|
|
|
files.push({
|
|
contents: presenceImage,
|
|
name: `${index}.png`,
|
|
});
|
|
embed.thumbnail = {
|
|
url: `attachment://${index}.png`,
|
|
};
|
|
}
|
|
}
|
|
|
|
if (
|
|
activity.application_id &&
|
|
!activity.assets?.large_image &&
|
|
!activity.assets?.small_image
|
|
) {
|
|
const game = GameData.find(
|
|
(game) => game.id == activity.application_id
|
|
);
|
|
if (game?.icon) {
|
|
embed.thumbnail = {
|
|
url: `https://cdn.discordapp.com/app-icons/${game.id}/${game.icon}.png?size=40&keep_aspect_ratio=false`,
|
|
};
|
|
}
|
|
}
|
|
|
|
embeds.push(embed);
|
|
}
|
|
}
|
|
|
|
return {
|
|
content: `Presence for **${formatUsername(target)}**: ${icons.join(" ")}`,
|
|
embeds,
|
|
files,
|
|
};
|
|
} else {
|
|
return ":warning: Could not get user???";
|
|
}
|
|
};
|
|
hf.registerCommand(presence);
|
|
|
|
const pomelo = new Command("pomelo");
|
|
pomelo.category = CATEGORY;
|
|
pomelo.helpText = "Check to see if a username is taken or not";
|
|
pomelo.usage = "[username] <...username>";
|
|
pomelo.callback = async function (msg, line) {
|
|
if (!line || line === "") return "Arguments required.";
|
|
|
|
const usernames = line.toLowerCase().split(" ");
|
|
|
|
if (usernames.length == 1) {
|
|
const name = usernames[0];
|
|
if (name.length > 32 || !POMELO_REGEX.test(name))
|
|
return {reaction: "\u{1f6ab}"};
|
|
|
|
const res = await hf.bot.requestHandler.request(
|
|
"POST",
|
|
"/unique-username/username-attempt-unauthed",
|
|
false,
|
|
{username: name}
|
|
);
|
|
return {reaction: res.taken ? "\u274c" : "\u2705"};
|
|
} else {
|
|
const lines = [];
|
|
|
|
for (const name of usernames) {
|
|
if (name.length > 32 || !POMELO_REGEX.test(name)) {
|
|
lines.push(`\u{1f6ab} \`${name}\``);
|
|
} else {
|
|
try {
|
|
const res = await hf.bot.requestHandler.request(
|
|
"POST",
|
|
"/unique-username/username-attempt-unauthed",
|
|
false,
|
|
{username: name}
|
|
);
|
|
lines.push(`${res.taken ? "\u274c" : "\u2705"} \`${name}\``);
|
|
} catch {
|
|
lines.push(`\u26a0\ufe0f \`${name}\``);
|
|
}
|
|
}
|
|
}
|
|
|
|
return lines.join("\n");
|
|
}
|
|
};
|
|
hf.registerCommand(pomelo);
|
|
|
|
const appinfo = new Command("appinfo");
|
|
appinfo.category = CATEGORY;
|
|
appinfo.helpText = "Get information on an application";
|
|
appinfo.usage = "[application id]";
|
|
appinfo.addAlias("ainfo");
|
|
appinfo.addAlias("ai");
|
|
appinfo.callback = async function (msg, line) {
|
|
if (!line || line === "") return "Arguments required.";
|
|
if (!SNOWFLAKE_REGEX.test(line)) return "Not a snowflake.";
|
|
|
|
try {
|
|
const _app = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/applications/${line}/rpc`,
|
|
false
|
|
);
|
|
|
|
let app = _app;
|
|
const game = GameData.find((game) => game.id == app.id);
|
|
if (game) {
|
|
app = Object.assign(app, game);
|
|
}
|
|
|
|
const assets = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/oauth2/applications/${app.id}/assets`,
|
|
false
|
|
);
|
|
|
|
const embed = {
|
|
title: `${app.name}`,
|
|
description:
|
|
app.description.length > 0 ? app.description : "*No description*.",
|
|
fields: [
|
|
{
|
|
name: "Created",
|
|
value: `<t:${Math.floor(snowflakeToTimestamp(app.id) / 1000)}:R>`,
|
|
inline: true,
|
|
},
|
|
],
|
|
};
|
|
|
|
if (app.icon) {
|
|
embed.thumbnail = {
|
|
url: `${APP_ICON_BASE}${app.id}/${app.icon}.png?size=4096`,
|
|
};
|
|
}
|
|
|
|
if (app.type) {
|
|
embed.fields.push({
|
|
name: "Type",
|
|
value: `${APPLICATION_TYPES[app.type] ?? "<unknown type>"} (\`${
|
|
app.type
|
|
}\`)`,
|
|
inline: true,
|
|
});
|
|
}
|
|
|
|
if (app.guild_id) {
|
|
const guild = await getGuild(app.guild_id);
|
|
if (guild) {
|
|
embed.fields.push({
|
|
name: "Guild",
|
|
value: `${guild.data.name} (\`${app.guild_id}\`)`,
|
|
inline: true,
|
|
});
|
|
} else {
|
|
embed.fields.push({
|
|
name: "Guild ID",
|
|
value: `\`${app.guild_id}\``,
|
|
inline: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (app.tags) {
|
|
embed.fields.push({
|
|
name: "Tags",
|
|
value: app.tags.join(", "),
|
|
inline: true,
|
|
});
|
|
}
|
|
|
|
if (app.publishers || app.developers) {
|
|
embed.fields.push({
|
|
name: "Game Companies",
|
|
value: `**Developers:** ${
|
|
app.developers?.length > 0
|
|
? app.developers.map((x) => x.name).join(", ")
|
|
: "<unknown>"
|
|
}\n**Publishers:** ${
|
|
app.publishers?.length > 0
|
|
? app.publishers.map((x) => x.name).join(", ")
|
|
: "<unknown>"
|
|
}`,
|
|
inline: true,
|
|
});
|
|
}
|
|
|
|
if (app.executables) {
|
|
embed.fields.push({
|
|
name: "Game Executables",
|
|
value: app.executables
|
|
.map(
|
|
(exe) =>
|
|
`${OS_ICONS[exe.os] ?? "\u2753"} \`${exe.name}\`${
|
|
exe.is_launcher ? " (launcher)" : ""
|
|
}`
|
|
)
|
|
.join("\n"),
|
|
inline: true,
|
|
});
|
|
}
|
|
|
|
if (app.third_party_skus) {
|
|
embed.fields.push({
|
|
name: "Game Distributors",
|
|
value: app.third_party_skus
|
|
.map((sku) =>
|
|
sku.distributor == "steam"
|
|
? `[Steam](https://steamdb.info/app/${sku.id})`
|
|
: sku.distributor == "discord"
|
|
? `[Discord](https://discord.com/store/skus/${sku.id})`
|
|
: `${sku.distributor
|
|
.split("_")
|
|
.map((x) => x[0].toUpperCase() + x.substring(1).toLowerCase())
|
|
.join(" ")
|
|
.replace(" Net", ".net")}: \`${sku.id}\``
|
|
)
|
|
.join("\n"),
|
|
inline: true,
|
|
});
|
|
}
|
|
|
|
if (app.bot_public != null || app.integration_public != null) {
|
|
if (
|
|
(app.bot_public && !app.bot_require_code_grant) ||
|
|
(app.integration_public && !app.integration_require_code_grant)
|
|
) {
|
|
let scope = "bot";
|
|
let permissions = "";
|
|
if (app.install_params) {
|
|
if (app.install_params.scopes) {
|
|
scope = app.install_params.scopes.join("+");
|
|
}
|
|
if (app.install_params.permissions) {
|
|
permissions = "&permissions=" + app.install_params.permissions;
|
|
}
|
|
}
|
|
embed.url = `https://discord.com/oauth2/authorize?client_id=${app.id}&scope=${scope}${permissions}`;
|
|
}
|
|
|
|
try {
|
|
const bot = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/users/${app.id}`,
|
|
true
|
|
);
|
|
|
|
embed.fields.push({
|
|
name: "Bot",
|
|
value:
|
|
formatUsername(bot) + ((bot.flags & 65536) != 0 ? " \u2713" : ""),
|
|
inline: false,
|
|
});
|
|
} catch {
|
|
embed.fields.push({
|
|
name: "Bot",
|
|
value: "<app id and bot id mismatch or other error>",
|
|
inline: false,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (app.custom_install_url) {
|
|
embed.url = app.custom_install_url;
|
|
}
|
|
|
|
if (app.flags > 0) {
|
|
const flags = flagsFromInt(app.flags, APPLICATION_FLAGS, false).split(
|
|
"\n"
|
|
);
|
|
|
|
embed.fields.push({
|
|
name: "Flags",
|
|
value: "- " + flags.slice(0, Math.ceil(flags.length / 2)).join("\n- "),
|
|
inline: true,
|
|
});
|
|
if (flags.length > 1)
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value:
|
|
"- " +
|
|
flags.slice(Math.ceil(flags.length / 2), flags.length).join("\n- "),
|
|
inline: true,
|
|
});
|
|
}
|
|
|
|
const images = [];
|
|
if (app.icon) {
|
|
images.push(`[Icon](${embed.thumbnail.url})`);
|
|
}
|
|
if (app.cover_image) {
|
|
images.push(
|
|
`[Cover](${APP_ICON_BASE}${app.id}/${app.cover_image}.png?size=2048)`
|
|
);
|
|
}
|
|
if (app.splash) {
|
|
images.push(
|
|
`[Splash](${APP_ICON_BASE}${app.id}/${app.splash}.png?size=2048)`
|
|
);
|
|
}
|
|
|
|
const links = [];
|
|
if (app.terms_of_service_url) {
|
|
links.push(`[Terms of Service](${app.terms_of_service_url})`);
|
|
}
|
|
if (app.privacy_policy_url) {
|
|
links.push(`[Privacy Policy](${app.privacy_policy_url})`);
|
|
}
|
|
if (assets.length > 0) {
|
|
links.push(
|
|
`[Assets](https://discord.com/api/v10/oauth2/applications/${app.id}/assets)`
|
|
);
|
|
}
|
|
|
|
if (images.length > 0 || links.length > 0) {
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: (images.join(" | ") + "\n" + links.join(" | ")).trim(),
|
|
inline: false,
|
|
});
|
|
}
|
|
|
|
if (assets.length > 0) {
|
|
if (images.length == 0 && links.length == 0) {
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: "\u200b",
|
|
inline: false,
|
|
});
|
|
}
|
|
|
|
const mappedAssets = assets.map(
|
|
(asset) =>
|
|
`[${
|
|
asset.name.length > 32
|
|
? asset.name.substring(0, 32) + "\u2026"
|
|
: asset.name
|
|
}](${APP_ASSET_BASE}${app.id}/${asset.id}.png)`
|
|
);
|
|
|
|
let left =
|
|
"- " +
|
|
mappedAssets.slice(0, Math.ceil(mappedAssets.length / 2)).join("\n- ");
|
|
let right =
|
|
"- " +
|
|
mappedAssets
|
|
.slice(Math.ceil(mappedAssets.length / 2), mappedAssets.length)
|
|
.join("\n- ");
|
|
|
|
if (left.length > 1024 || right.length > 1024) {
|
|
const linklessAssets = assets.map((asset) =>
|
|
asset.name.length > 32
|
|
? asset.name.substring(0, 32) + "\u2026"
|
|
: asset.name
|
|
);
|
|
left =
|
|
"- " +
|
|
linklessAssets
|
|
.slice(0, Math.ceil(linklessAssets.length / 2))
|
|
.join("\n- ");
|
|
right =
|
|
"- " +
|
|
linklessAssets
|
|
.slice(Math.ceil(linklessAssets.length / 2), linklessAssets.length)
|
|
.join("\n- ");
|
|
}
|
|
|
|
if (left.length <= 1024 && right.length <= 1024) {
|
|
embed.fields.push({
|
|
name: `Assets (${assets.length})`,
|
|
value: left,
|
|
inline: true,
|
|
});
|
|
if (mappedAssets.length > 1)
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: right,
|
|
inline: true,
|
|
});
|
|
} else {
|
|
const assetList = assets
|
|
.map((asset) =>
|
|
asset.name.length > 32
|
|
? asset.name.substring(0, 31) + "\u2026"
|
|
: asset.name
|
|
)
|
|
.join(", ");
|
|
if (assetList.length <= 1024) {
|
|
embed.fields.push({
|
|
name: `Assets (${assets.length})`,
|
|
value: assetList,
|
|
inline: false,
|
|
});
|
|
} else {
|
|
embed.fields.push({
|
|
name: `Assets (${assets.length})`,
|
|
value: "*Exceeds 1024 characters.*",
|
|
inline: false,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return {embed};
|
|
} catch (error) {
|
|
if (error.message === "Unknown Application") {
|
|
return "ID provided does not point to a valid application.";
|
|
} else {
|
|
return `:warning: Got error \`${safeString(error)}\``;
|
|
}
|
|
}
|
|
};
|
|
hf.registerCommand(appinfo);
|
|
|
|
const guildinfo = new Command("guildinfo");
|
|
guildinfo.category = CATEGORY;
|
|
guildinfo.helpText = "Get information on a guild";
|
|
guildinfo.usage = "<guild id>";
|
|
guildinfo.addAlias("ginfo");
|
|
guildinfo.addAlias("gi");
|
|
guildinfo.addAlias("serverinfo");
|
|
guildinfo.addAlias("sinfo");
|
|
guildinfo.addAlias("si");
|
|
guildinfo.callback = async function (msg, line) {
|
|
let _guild;
|
|
if (!line || line == "") {
|
|
if (!msg.guildID) return "Not in a guild.";
|
|
_guild = {source: "local", data: msg.channel.guild};
|
|
} else {
|
|
if (!SNOWFLAKE_REGEX.test(line)) return "Not a snowflake.";
|
|
_guild = await getGuild(line);
|
|
}
|
|
|
|
if (!_guild) return "Guild not found.";
|
|
|
|
const guild = _guild.data;
|
|
switch (_guild.source) {
|
|
case "local": {
|
|
const roles = Array.from(guild.roles.values());
|
|
const defaultRole = roles.find((role) => role.name == "@everyone");
|
|
|
|
const channelTypeCounts = {};
|
|
let nsfwChannels = 0;
|
|
let hiddenChannels = 0;
|
|
for (const channel of guild.channels.values()) {
|
|
if (!channelTypeCounts[channel.type])
|
|
channelTypeCounts[channel.type] = 0;
|
|
channelTypeCounts[channel.type]++;
|
|
|
|
if (channel.nsfw) nsfwChannels++;
|
|
|
|
const defaultPermissions = channel.permissionOverwrites.get(
|
|
defaultRole.id
|
|
);
|
|
if (
|
|
defaultPermissions &&
|
|
(channel instanceof VoiceChannel
|
|
? !defaultPermissions.has(Constants.Permissions.voiceConnect)
|
|
: !defaultPermissions.has(Constants.Permissions.viewChannel))
|
|
) {
|
|
hiddenChannels++;
|
|
}
|
|
}
|
|
|
|
const embed = {
|
|
title: guild.name,
|
|
description: guild.description ?? "*No description.*",
|
|
fields: [
|
|
guild.ownerID && {
|
|
name: "Owner",
|
|
value: `<@${guild.ownerID}>`,
|
|
inline: true,
|
|
},
|
|
guild.vanityURL && {
|
|
name: "Vanity URL",
|
|
value: `https://discord.gg/${guild.vanityURL}`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Created",
|
|
value: `<t:${Math.floor(snowflakeToTimestamp(guild.id) / 1000)}:R>`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Max Members",
|
|
value: guild.maxMembers,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Max Video Channel Users",
|
|
value: `Normal: ${guild.maxVideoChannelUsers}\nStage: ${guild.maxStageVideoChannelUsers}`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Verification Level",
|
|
value: GUILD_VERIFICATION_LEVELS[guild.verificationLevel],
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Content Filter",
|
|
value: GUILD_CONTENT_FILTER[guild.explicitContentFilter],
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Moderation 2FA",
|
|
value: guild.mfaLevel == 0 ? "Off" : "On",
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Boost Status",
|
|
value: `**Level ${guild.premiumTier}**, ${guild.premiumSubscriptionCount} Boosts`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Locale",
|
|
value: guild.preferredLocale,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: "Default Notifications",
|
|
value:
|
|
guild.defaultNotifications == 0
|
|
? "All Messages"
|
|
: "Only Mentions",
|
|
inline: true,
|
|
},
|
|
guild.rulesChannelID && {
|
|
name: "Rules",
|
|
value: `<#${guild.rulesChannelID}>`,
|
|
inline: true,
|
|
},
|
|
guild.systemChannelID && {
|
|
name: "System Messages",
|
|
value: `<#${guild.systemChannelID}>`,
|
|
inline: true,
|
|
},
|
|
guild.publicUpdatesChannelID && {
|
|
name: "Community Updates",
|
|
value: `<#${guild.publicUpdatesChannelID}>`,
|
|
inline: true,
|
|
},
|
|
guild.safetyAlertsChannelID && {
|
|
name: "Safety Alerts",
|
|
value: `<#${guild.safetyAlertsChannelID}>`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: `Channels (${guild.channels.size})`,
|
|
value:
|
|
Object.entries(channelTypeCounts)
|
|
.map(([type, count]) => `${count} ${CHANNEL_TYPE_NAMES[type]}`)
|
|
.join(", ") +
|
|
`\n${nsfwChannels} age restricted, ${hiddenChannels} hidden`,
|
|
inline: false,
|
|
},
|
|
{
|
|
name: `Roles (${guild.roles.size})`,
|
|
value: `${roles.filter((role) => role.managed).length} managed, ${
|
|
roles.filter((role) => role.tags?.guild_connections).length
|
|
} linked, ${
|
|
roles.filter((role) => role.tags?.integration_id != null).length
|
|
} integration`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: `Emotes (${guild.emojis.length})`,
|
|
value: `${
|
|
guild.emojis.filter((e) => e.animated).length
|
|
} animated, ${
|
|
guild.emojis.filter((e) => e.managed).length
|
|
} managed\n${
|
|
guild.emojis.filter((e) => !e.available).length
|
|
} unavailable`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: `Stickers (${guild.stickers.length})`,
|
|
value: `${
|
|
guild.stickers.filter((s) => s.format_type == 1).length
|
|
} PNG, ${
|
|
guild.stickers.filter((s) => s.format_type == 2).length
|
|
} APNG, ${
|
|
guild.stickers.filter((s) => s.format_type == 4).length
|
|
} GIF, ${
|
|
guild.stickers.filter((s) => s.format_type == 3).length
|
|
} Lottie\n${
|
|
guild.stickers.filter((s) => !s.available).length
|
|
} unavailable`,
|
|
inline: true,
|
|
},
|
|
].filter((x) => !!x),
|
|
};
|
|
|
|
if (guild.icon) {
|
|
embed.thumbnail = {
|
|
url: `${ICON_BASE}${guild.id}/${guild.icon}.${
|
|
guild.icon.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096"
|
|
}`,
|
|
};
|
|
}
|
|
|
|
const members = Array.from(guild.members.values());
|
|
const online = members.filter(
|
|
(member) => member.status != null && member.status != "offline"
|
|
).length;
|
|
const bots = members.filter((member) => member.bot).length;
|
|
const verfifiedBots = members.filter(
|
|
(member) => member.bot && (member.user.publicFlags & 65536) != 0
|
|
).length;
|
|
embed.fields.push({
|
|
name: "Member Count",
|
|
value: `<:online:1152111668856361010>${online} online\t\t<:offline:1152111682886316042>${guild.memberCount} members\n<:boat:546212361472835584> ${bots}, \u2713 ${verfifiedBots}`,
|
|
inline: false,
|
|
});
|
|
|
|
const features = guild.features.sort().map(
|
|
(feature) =>
|
|
(GUILD_FEATURES[feature]?.icon ?? "\u2753") +
|
|
" " +
|
|
(GUILD_FEATURES[feature]?.name ??
|
|
feature
|
|
.split("_")
|
|
.map((x) => x[0] + x.substring(1).toLowerCase())
|
|
.join(" "))
|
|
);
|
|
|
|
embed.fields.push({
|
|
name: `Features (${features.length})`,
|
|
value:
|
|
features.length > 0
|
|
? features.slice(0, Math.ceil(features.length / 2)).join("\n")
|
|
: "None",
|
|
inline: true,
|
|
});
|
|
if (features.length > 1)
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: features
|
|
.slice(Math.ceil(features.length / 2), features.length)
|
|
.join("\n"),
|
|
inline: true,
|
|
});
|
|
|
|
const images = [];
|
|
if (guild.icon) {
|
|
images.push(`[Icon](${embed.thumbnail.url})`);
|
|
}
|
|
if (guild.banner) {
|
|
images.push(
|
|
`[Banner](${BANNER_BASE}${guild.id}/${guild.banner}.png?size=4096)`
|
|
);
|
|
}
|
|
if (guild.splash) {
|
|
images.push(
|
|
`[Invite Splash](${SPLASH_BASE}${guild.id}/${guild.splash}.png?size=4096)`
|
|
);
|
|
}
|
|
if (guild.discoverySplash) {
|
|
images.push(
|
|
`[Discovery Splash](${DISCOVERY_SPLASH_BASE}${guild.id}/${guild.discoverySplash}.png?size=4096)`
|
|
);
|
|
}
|
|
|
|
if (images.length > 0) {
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: images.join(" | "),
|
|
inline: false,
|
|
});
|
|
}
|
|
|
|
return {embed};
|
|
}
|
|
case "preview": {
|
|
const embed = {
|
|
title: guild.name,
|
|
description: guild.description ?? "*No description.*",
|
|
fields: [
|
|
{
|
|
name: "Created",
|
|
value: `<t:${Math.floor(snowflakeToTimestamp(guild.id) / 1000)}:R>`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: `Emotes (${guild.emojis.length})`,
|
|
value: `${
|
|
guild.emojis.filter((e) => e.animated).length
|
|
} animated, ${
|
|
guild.emojis.filter((e) => e.managed).length
|
|
} managed\n${
|
|
guild.emojis.filter((e) => !e.available).length
|
|
} unavailable`,
|
|
inline: true,
|
|
},
|
|
{
|
|
name: `Stickers (${guild.stickers.length})`,
|
|
value: `${
|
|
guild.stickers.filter((s) => s.format_type == 1).length
|
|
} PNG, ${
|
|
guild.stickers.filter((s) => s.format_type == 2).length
|
|
} APNG, ${
|
|
guild.stickers.filter((s) => s.format_type == 4).length
|
|
} GIF, ${
|
|
guild.stickers.filter((s) => s.format_type == 3).length
|
|
} Lottie\n${
|
|
guild.stickers.filter((s) => !s.available).length
|
|
} unavailable`,
|
|
inline: true,
|
|
},
|
|
],
|
|
footer: {
|
|
text: "Fetched from guild preview",
|
|
},
|
|
};
|
|
|
|
if (guild.icon) {
|
|
embed.thumbnail = {
|
|
url: `${ICON_BASE}${guild.id}/${guild.icon}.${
|
|
guild.icon.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096"
|
|
}`,
|
|
};
|
|
}
|
|
|
|
embed.fields.push({
|
|
name: "Member Count",
|
|
value: `<:online:1152111668856361010>${guild.approximate_presence_count} online\t\t<:offline:1152111682886316042>${guild.approximate_member_count} members`,
|
|
inline: false,
|
|
});
|
|
|
|
const features = guild.features.sort().map(
|
|
(feature) =>
|
|
(GUILD_FEATURES[feature]?.icon ?? "\u2753") +
|
|
" " +
|
|
(GUILD_FEATURES[feature]?.name ??
|
|
feature
|
|
.split("_")
|
|
.map((x) => x[0] + x.substring(1).toLowerCase())
|
|
.join(" "))
|
|
);
|
|
|
|
embed.fields.push({
|
|
name: `Features (${features.length})`,
|
|
value:
|
|
features.length > 0
|
|
? features.slice(0, Math.ceil(features.length / 2)).join("\n")
|
|
: "None",
|
|
inline: true,
|
|
});
|
|
if (features.length > 1)
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: features
|
|
.slice(Math.ceil(features.length / 2), features.length)
|
|
.join("\n"),
|
|
inline: true,
|
|
});
|
|
|
|
const images = [];
|
|
if (guild.icon) {
|
|
images.push(`[Icon](${embed.thumbnail.url})`);
|
|
}
|
|
if (guild.splash) {
|
|
images.push(
|
|
`[Invite Splash](${SPLASH_BASE}${guild.id}/${guild.splash}.png?size=4096)`
|
|
);
|
|
}
|
|
if (guild.discovery_splash) {
|
|
images.push(
|
|
`[Discovery Splash](${DISCOVERY_SPLASH_BASE}${guild.id}/${guild.discoverySplash}.png?size=4096)`
|
|
);
|
|
}
|
|
|
|
if (images.length > 0) {
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: images.join(" | "),
|
|
inline: false,
|
|
});
|
|
}
|
|
|
|
return {embed};
|
|
}
|
|
case "discovery": {
|
|
if (!guild.store_page) {
|
|
return "Got discovery data but no store page.";
|
|
}
|
|
|
|
const guildObj = guild.store_page.guild;
|
|
|
|
let invite;
|
|
if (
|
|
guildObj.invite?.code ||
|
|
guild.store_page.role_subscription.purchase_page_invite?.code
|
|
) {
|
|
const code =
|
|
guildObj.invite?.code ??
|
|
guild.store_page.role_subscription.purchase_page_invite?.code;
|
|
invite = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/invites/${code}?with_counts=true&with_expiration=true`
|
|
);
|
|
}
|
|
|
|
const embed = {
|
|
title: guildObj.name,
|
|
description: invite?.guild?.description ?? "*No description.*",
|
|
fields: [
|
|
{
|
|
name: "Created",
|
|
value: `<t:${Math.floor(
|
|
snowflakeToTimestamp(guildObj.id) / 1000
|
|
)}:R>`,
|
|
inline: true,
|
|
},
|
|
],
|
|
footer: {
|
|
text: "Fetched from discovery" + (invite ? " + invite" : ""),
|
|
},
|
|
};
|
|
|
|
if (guildObj.icon_hash) {
|
|
embed.thumbnail = {
|
|
url: `${ICON_BASE}${guildObj.id}/${guildObj.icon_hash}.${
|
|
guildObj.icon_hash.startsWith("a_")
|
|
? "gif?size=4096&_=.gif"
|
|
: "png?size=4096"
|
|
}`,
|
|
};
|
|
}
|
|
|
|
const invites = [];
|
|
if (guildObj.invite?.code) invites.push(guildObj.invite.code);
|
|
if (guild.store_page.role_subscription.purchase_page_invite?.code)
|
|
invites.push(
|
|
guild.store_page.role_subscription.purchase_page_invite.code
|
|
);
|
|
|
|
if (invites.length > 0) {
|
|
embed.fields.push({
|
|
name: "Invites",
|
|
value: invites.map((code) => "https://discord.gg/" + code).join("\n"),
|
|
inline: true,
|
|
});
|
|
}
|
|
|
|
embed.fields.push({
|
|
name: "Member Count",
|
|
value: `<:online:1152111668856361010>${guildObj.approximate_presence_count} online\t\t<:offline:1152111682886316042>${guildObj.approximate_member_count} members`,
|
|
inline: false,
|
|
});
|
|
|
|
if (invite?.guild?.features) {
|
|
const features = invite.guild.features.sort().map(
|
|
(feature) =>
|
|
(GUILD_FEATURES[feature]?.icon ?? "\u2753") +
|
|
" " +
|
|
(GUILD_FEATURES[feature]?.name ??
|
|
feature
|
|
.split("_")
|
|
.map((x) => x[0] + x.substring(1).toLowerCase())
|
|
.join(" "))
|
|
);
|
|
|
|
embed.fields.push({
|
|
name: `Features (${features.length})`,
|
|
value:
|
|
features.length > 0
|
|
? features.slice(0, Math.ceil(features.length / 2)).join("\n")
|
|
: "None",
|
|
inline: true,
|
|
});
|
|
if (features.length > 1)
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: features
|
|
.slice(Math.ceil(features.length / 2), features.length)
|
|
.join("\n"),
|
|
inline: true,
|
|
});
|
|
}
|
|
|
|
const images = [];
|
|
if (guildObj.icon_hash) {
|
|
images.push(`[Icon](${embed.thumbnail.url})`);
|
|
}
|
|
if (invite?.guild?.splash) {
|
|
images.push(
|
|
`[Invite Splash](${SPLASH_BASE}${guild.id}/${guild.splash}.png?size=4096)`
|
|
);
|
|
}
|
|
if (invite?.guild?.banner) {
|
|
images.push(
|
|
`[Banner](${BANNER_BASE}${guild.id}/${guild.banner}.png?size=4096)`
|
|
);
|
|
}
|
|
|
|
if (images.length > 0) {
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: images.join(" | "),
|
|
inline: false,
|
|
});
|
|
}
|
|
|
|
return {embed};
|
|
}
|
|
case "widget": {
|
|
let invite;
|
|
if (guild.instant_invite) {
|
|
invite = await hf.bot.requestHandler.request(
|
|
"GET",
|
|
`/invites/${guild.instant_invite}?with_counts=true&with_expiration=true`
|
|
);
|
|
}
|
|
|
|
const embed = {
|
|
title: guild.name,
|
|
description: invite?.guild?.description ?? "*No description.*",
|
|
fields: [
|
|
{
|
|
name: "Created",
|
|
value: `<t:${Math.floor(snowflakeToTimestamp(guild.id) / 1000)}:R>`,
|
|
inline: true,
|
|
},
|
|
],
|
|
footer: {
|
|
text: "Fetched from widget" + (invite ? " + invite" : ""),
|
|
},
|
|
};
|
|
|
|
if (invite) {
|
|
embed.fields.push({
|
|
name: "Invite",
|
|
value: "https://discord.gg/" + guild.instant_invite,
|
|
inline: true,
|
|
});
|
|
|
|
embed.fields.push({
|
|
name: "Member Count",
|
|
value: `<:online:1152111668856361010>${invite.approximate_presence_count} online\t\t<:offline:1152111682886316042>${invite.approximate_member_count} members`,
|
|
inline: false,
|
|
});
|
|
|
|
const features = invite.guild.features.sort().map(
|
|
(feature) =>
|
|
(GUILD_FEATURES[feature]?.icon ?? "\u2753") +
|
|
" " +
|
|
(GUILD_FEATURES[feature]?.name ??
|
|
feature
|
|
.split("_")
|
|
.map((x) => x[0] + x.substring(1).toLowerCase())
|
|
.join(" "))
|
|
);
|
|
|
|
embed.fields.push({
|
|
name: `Features (${features.length})`,
|
|
value:
|
|
features.length > 0
|
|
? features.slice(0, Math.ceil(features.length / 2)).join("\n")
|
|
: "None",
|
|
inline: true,
|
|
});
|
|
if (features.length > 1)
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: features
|
|
.slice(Math.ceil(features.length / 2), features.length)
|
|
.join("\n"),
|
|
inline: true,
|
|
});
|
|
|
|
const images = [];
|
|
if (invite.guild.icon) {
|
|
images.push(`[Icon](${embed.thumbnail.url})`);
|
|
}
|
|
if (invite.guild.splash) {
|
|
images.push(
|
|
`[Invite Splash](${SPLASH_BASE}${guild.id}/${guild.splash}.png?size=4096)`
|
|
);
|
|
}
|
|
if (invite.guild.banner) {
|
|
images.push(
|
|
`[Banner](${BANNER_BASE}${guild.id}/${guild.banner}.png?size=4096)`
|
|
);
|
|
}
|
|
|
|
if (images.length > 0) {
|
|
embed.fields.push({
|
|
name: "\u200b",
|
|
value: images.join(" | "),
|
|
inline: false,
|
|
});
|
|
}
|
|
} else {
|
|
embed.fields.push({
|
|
name: "Member Count",
|
|
value: `<:online:1152111668856361010>${guild.presence_count} online`,
|
|
inline: false,
|
|
});
|
|
}
|
|
|
|
return {embed};
|
|
}
|
|
default:
|
|
return "Guild not found.";
|
|
}
|
|
};
|
|
hf.registerCommand(guildinfo);
|
|
|
|
// }}}
|