HiddenPhox/src/modules/utility.js

2473 lines
71 KiB
JavaScript

const Command = require("../lib/command.js");
const CATEGORY = "utility";
// {{{ imports
const sharp = require("sharp");
const {Constants, VoiceChannel} = require("@projectdysnomia/dysnomia");
const Endpoints = require("@projectdysnomia/dysnomia/lib/rest/Endpoints.js");
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 AVATAR_DECORATION_BASE = CDN + "avatar-decoration-presets/";
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 decoration = new Command("decoration");
decoration.category = CATEGORY;
decoration.helpText = "Get decoration of a user";
decoration.usage = "<user>";
decoration.addAlias("decor");
decoration.callback = async function (msg, line, [user]) {
let id = msg.author.id;
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
);
let decor;
try {
const decorRes = await fetch(
`https://decor.fieryflames.dev/api/users/${id}/decoration`,
{
headers: {
"User-Agent":
"HiddenPhox/decoration (https://gitdab.com/Cynosphere/HiddenPhox)",
},
}
).then((res) => res.json());
decor = `https://decorcdn.fieryflames.dev/${decorRes.animated ? "a_" : ""}${
decorRes.hash
}.png`;
} catch {
// noop
}
if (!userObj.avatar_decoration_data && !decor)
return "This user does not have a decoration.";
const normalUrl =
userObj.avatar_decoration_data &&
`${AVATAR_DECORATION_BASE}${userObj.avatar_decoration_data.asset}.png?size=4096&passthrough=true`;
const baseEmbed = {
title: `Decoration for \`${formatUsername(userObj)}\``,
};
baseEmbed.description = (
(normalUrl ? `[Normal decoration](${normalUrl})` : "") +
(decor ? `\n[Decor decoration](${decor})` : "")
).trim();
if (
userObj.avatar_decoration_data?.asset.startsWith("a_") ||
decor?.indexOf("/a_") > -1
) {
baseEmbed.description += "\n(Animated decoration, open in browser to view)";
baseEmbed.description = baseEmbed.description.trim();
}
baseEmbed.url = normalUrl || decor;
const decorEmbed = {...baseEmbed};
baseEmbed.image = {url: normalUrl || decor};
decorEmbed.image = {url: decor};
return {
embeds: [normalUrl && baseEmbed, decor && decorEmbed].filter(
(x) => x != null
),
};
};
hf.registerCommand(decoration);
const lookupinvite = new Command("lookupinvite");
lookupinvite.category = CATEGORY;
lookupinvite.helpText = "Lookup an invite";
lookupinvite.usage = "<invite code>";
lookupinvite.addAlias("linvite");
lookupinvite.addAlias("inviteinfo");
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|(app)?.com\/invite)\//, "");
if (decodeURI(line).indexOf("../") > -1) return "nuh uh";
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)
user = await hf.bot.requestHandler.request(
"GET",
Endpoints.USER(id),
true
);
if (!user) {
return "Failed to get user.";
} else {
return `\`${formatUsername(user)}\`'s public flags:\n\`\`\`${flagsFromInt(
user.public_flags ?? 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.";
const snowflake = line.match(SNOWFLAKE_REGEX)[1];
try {
const _app = await hf.bot.requestHandler.request(
"GET",
`/applications/${snowflake}/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("guild");
guildinfo.addAlias("ginfo");
guildinfo.addAlias("gi");
guildinfo.addAlias("serverinfo");
guildinfo.addAlias("server");
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.";
const snowflake = line.match(SNOWFLAKE_REGEX)[1];
_guild = await getGuild(snowflake);
}
if (!_guild) return "Guild not found.";
const guild = _guild.data;
switch (_guild.source) {
case "local": {
const roles = Array.from(guild.roles.values());
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++;
let defaultPermissions = channel.permissionOverwrites.get(guild.id);
if (!defaultPermissions && channel.parentID) {
defaultPermissions = guild.channels
.get(channel.parentID)
.permissionOverwrites.get(guild.id);
}
if (
defaultPermissions &&
(channel instanceof VoiceChannel
? (defaultPermissions.deny & Constants.Permissions.voiceConnect) ===
Constants.Permissions.voiceConnect
: (defaultPermissions.deny & Constants.Permissions.viewChannel) ===
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,
},
guild.emojis.length > 0 && {
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,
},
guild.stickers.length > 0 && {
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,
},
guild.emojis.length > 0 && {
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,
},
guild.stickers.length > 0 && {
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),
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.replace(
/(https?:\/\/)?discord(\.gg|(app)?.com\/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](${ICON_BASE}${invite.guild.id}/${invite.guild.icon}.png?size=4096`
);
}
if (invite.guild.splash) {
images.push(
`[Invite Splash](${SPLASH_BASE}${invite.guild.id}/${invite.guild.splash}.png?size=4096)`
);
}
if (invite.guild.banner) {
images.push(
`[Banner](${BANNER_BASE}${invite.guild.id}/${invite.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);
// }}}