feat: add script to get discord guild count
Node.js CI / Lint and Test (push) Failing after 22s

This commit is contained in:
2025-12-03 13:53:51 -08:00
parent 18f3d15791
commit dc324a307b
3 changed files with 177 additions and 15 deletions
+165
View File
@@ -0,0 +1,165 @@
/**
* @copyright NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
/* eslint-disable complexity, max-lines-per-function -- This is a chonky boi script. */
/**
* DISCORD SERVER STATS ANALYZER
* * Instructions:
* 1. Get your User Token (Open Discord in Browser -> F12 -> Network Tab -> Type a message -> Look for "authorization" in request headers).
* 2. Set it in the .env file as TOKEN.
* 3. Run with: node discord_stats.js.
*/
interface Guild {
name?: string;
permissions?: string;
features?: Array<string>;
owner?: boolean;
id: string;
}
interface Stats {
community: Array<string>;
moderating: Array<string>;
owned: Array<string>;
partnered: Array<string>;
total: number;
verified: Array<string>;
}
// Permission Flags (BigInt)
const permissions = {
administrator: 0x00_00_00_00_00_00_00_08n,
banMembers: 0x00_00_00_00_00_00_00_04n,
kickMembers: 0x00_00_00_00_00_00_00_02n,
manageGuild: 0x00_00_00_00_00_00_00_20n,
manageMessages: 0x00_00_00_00_00_00_20_00n,
moderateMembers: 0x00_00_01_00_00_00_00_00n,
};
const printList = (title: string, list: Array<string>, icon: string): void => {
console.log(`${icon} ${title}: ${list.length.toString()}`);
if (list.length > 0) {
for (const name of list) {
console.log(` - ${name}`);
}
}
console.log("\n");
};
const printReport = (stats: Stats): void => {
console.log("\n====== DISCORD SERVER BREAKDOWN ======");
console.log(`Total Servers Joined: ${stats.total.toString()}\n`);
printList("Owned Servers", stats.owned, "👑");
printList("Moderating (Non-Owned)", stats.moderating, "🛡️ ");
printList("Partnered Servers", stats.partnered, "🤝");
printList("Verified Servers", stats.verified, "✅");
printList("Community/Public Servers", stats.community, "🌍");
console.log(`======================================\n`);
};
const checkForPermission = (perms: bigint, permission: bigint): boolean => {
// eslint-disable-next-line no-bitwise -- Since Discord uses bit flags...
return (perms & permission) === permission;
};
const analyzeGuilds = (guilds: Array<Guild>): void => {
// Arrays to store names instead of just counts
const stats: Stats = {
community: [],
moderating: [],
owned: [],
partnered: [],
total: guilds.length,
verified: [],
};
for (const guild of guilds) {
const perms = BigInt(guild.permissions ?? 0);
const features = guild.features ?? [];
const { name, owner, id } = guild;
// 1. Ownership
if (owner === true) {
stats.owned.push(name ?? "Unknown");
}
/*
* 2. Moderation
* We consider you a "Moderator" if you have specific mod permissions,
* Even if you don't own the server.
*/
const isModerator
= checkForPermission(perms, permissions.administrator)
|| checkForPermission(perms, permissions.manageGuild)
|| checkForPermission(perms, permissions.banMembers)
|| checkForPermission(perms, permissions.kickMembers)
|| checkForPermission(perms, permissions.moderateMembers);
if (isModerator && owner !== true) {
stats.moderating.push(name ?? id);
}
// 3. Partnered
if (features.includes("PARTNERED")) {
stats.partnered.push(name ?? id);
}
// 4. Verified
if (features.includes("VERIFIED")) {
stats.verified.push(name ?? id);
}
/*
* 5. Community / Public
* "COMMUNITY" feature enables public facing screens (Welcome Screen, Rules, etc)
* "DISCOVERABLE" means it appears in Server Discovery
*/
if (features.includes("COMMUNITY") || features.includes("DISCOVERABLE")) {
stats.community.push(name ?? id);
}
}
printReport(stats);
};
/**
*
*/
async function getGuilds(): Promise<void> {
const token = process.env.TOKEN;
if (token === undefined) {
throw new Error("Missing TOKEN");
}
console.log("Fetching servers...");
// Discord allows max 200 servers per user (with Nitro), so limit=200 catches all.
const response = await fetch(
"https://discord.com/api/v10/users/@me/guilds?limit=200",
{
headers: {
authorization: token,
},
},
);
if (!response.ok) {
if (response.status === 401) {
console.error("Error: Invalid Token. Please check your TOKEN.");
} else {
console.error(`Error: API returned status ${response.status.toString()}`);
}
return;
}
const guilds: Array<Guild> = await response.json();
analyzeGuilds(guilds);
}
await getGuilds();
export { getGuilds };