add game role commands (roles, role, unroll) with emoji role picker
This commit is contained in:
+152
@@ -0,0 +1,152 @@
|
||||
require("dotenv").config();
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const yaml = require("js-yaml");
|
||||
const readline = require("node:readline/promises");
|
||||
const { stdin: input, stdout: output } = require("node:process");
|
||||
|
||||
const DISCORD_BOT_TOKEN = process.env.DISCORD_BOT_TOKEN;
|
||||
const DISCORD_API = "https://discord.com/api/v10";
|
||||
const ROLES_PATH = path.join(__dirname, "roles.yaml");
|
||||
|
||||
if (!DISCORD_BOT_TOKEN) {
|
||||
console.error("DISCORD_BOT_TOKEN is not set in .env. Run bash install.sh first to set it up.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function loadRoles() {
|
||||
try {
|
||||
const data = yaml.load(fs.readFileSync(ROLES_PATH, "utf8"));
|
||||
return (data && typeof data === "object") ? data : {};
|
||||
} catch (err) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function fetchBotGuilds() {
|
||||
const res = await fetch(DISCORD_API + "/users/@me/guilds", {
|
||||
headers: { Authorization: "Bot " + DISCORD_BOT_TOKEN }
|
||||
});
|
||||
if (!res.ok) throw new Error("Discord guild list failed: " + res.status);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function fetchGuildRoles(guildId) {
|
||||
const res = await fetch(DISCORD_API + "/guilds/" + guildId + "/roles", {
|
||||
headers: { Authorization: "Bot " + DISCORD_BOT_TOKEN }
|
||||
});
|
||||
if (!res.ok) throw new Error("Discord role list failed: " + res.status);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function renameRole(guildId, roleId, name) {
|
||||
const res = await fetch(DISCORD_API + "/guilds/" + guildId + "/roles/" + roleId, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
Authorization: "Bot " + DISCORD_BOT_TOKEN,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({ name: name })
|
||||
});
|
||||
if (!res.ok) throw new Error("role rename failed: " + res.status + " " + (await res.text()));
|
||||
}
|
||||
|
||||
async function pickFromList(rl, label, items, formatItem) {
|
||||
console.log("");
|
||||
console.log(label);
|
||||
items.forEach((item, i) => {
|
||||
console.log(" " + (i + 1) + ". " + formatItem(item));
|
||||
});
|
||||
|
||||
while (true) {
|
||||
const answer = (await rl.question("Enter a number (or 0 to cancel): ")).trim();
|
||||
const n = parseInt(answer, 10);
|
||||
if (n === 0) return null;
|
||||
if (!isNaN(n) && n >= 1 && n <= items.length) return items[n - 1];
|
||||
console.log("Not a valid choice, try again.");
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const roles = loadRoles();
|
||||
const keys = Object.keys(roles);
|
||||
if (keys.length === 0) {
|
||||
console.log("No roles in roles.yaml, nothing to sync.");
|
||||
return;
|
||||
}
|
||||
|
||||
let guilds;
|
||||
try {
|
||||
guilds = await fetchBotGuilds();
|
||||
} catch (err) {
|
||||
console.error("Could not load your Discord server list:", err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!guilds || guilds.length === 0) {
|
||||
console.error("The bot is not in any Discord server yet.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let guild = guilds[0];
|
||||
if (guilds.length > 1) {
|
||||
const rl = readline.createInterface({ input, output });
|
||||
guild = await pickFromList(rl, "Which Discord server?", guilds, (g) => g.name);
|
||||
rl.close();
|
||||
if (!guild) return;
|
||||
}
|
||||
|
||||
let discordRoles;
|
||||
try {
|
||||
discordRoles = await fetchGuildRoles(guild.id);
|
||||
} catch (err) {
|
||||
console.error("Could not load server roles:", err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const byId = {};
|
||||
discordRoles.forEach((r) => {
|
||||
byId[r.id] = r;
|
||||
});
|
||||
|
||||
let updated = 0;
|
||||
let skipped = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const key of keys) {
|
||||
const entry = roles[key];
|
||||
const desiredName = entry.emoji + " " + entry.title;
|
||||
const current = byId[entry.roleId];
|
||||
|
||||
if (!current) {
|
||||
console.error("Role for \"" + entry.title + "\" no longer exists in Discord, skipping.");
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current.name === desiredName) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
await renameRole(guild.id, entry.roleId, desiredName);
|
||||
console.log("Updated \"" + current.name + "\" to \"" + desiredName + "\".");
|
||||
updated++;
|
||||
} catch (err) {
|
||||
failed++;
|
||||
console.error("Could not update the role for \"" + entry.title + "\":", err.message);
|
||||
}
|
||||
await sleep(300);
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("Done. Updated: " + updated + ", already in sync or skipped: " + skipped +
|
||||
(failed > 0 ? ", failed: " + failed : "") + ".");
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user