tg-bot-ts/scripts/upload-emojis.ts
2026-06-03 01:51:26 +01:00

110 lines
No EOL
3.7 KiB
TypeScript

/**
* Bulk emoji upload script
* Usage: npx ts-node scripts/upload-emojis.ts [emoji_dir]
*
* Place emoji PNG files in a directory named after the emoji key.
* Example: fb.png, wi.png, capella.png, wrank_1.png, wrank_1_gold.png
*
* Automatically updates messages/emojis.json with the uploaded emoji IDs.
*/
import { REST, Routes } from "discord.js";
import fs from "fs";
import path from "path";
// Load .env manually since we're outside the bot
const envPath = path.join(__dirname, "../.env");
if (fs.existsSync(envPath)) {
for (const line of fs.readFileSync(envPath, "utf8").split("\n")) {
const [key, ...rest] = line.split("=");
if (key && rest.length) process.env[key.trim()] = rest.join("=").trim();
}
}
const TOKEN = process.env.DISCORD_TOKEN!;
const GUILD_ID = process.env.GUILD_ID!;
if (!TOKEN || !GUILD_ID) {
console.error("❌ DISCORD_TOKEN and GUILD_ID must be set in .env");
process.exit(1);
}
const emojiDir = process.argv[2] ?? path.join(__dirname, "../emoji-uploads");
const emojisPath = path.join(__dirname, "../messages/emojis.json");
if (!fs.existsSync(emojiDir)) {
console.error(`❌ Emoji directory not found: ${emojiDir}`);
console.error(` Create it and place your emoji PNG files inside.`);
process.exit(1);
}
const rest = new REST({ version: "10" }).setToken(TOKEN);
async function uploadEmojis(): Promise<void> {
const files = fs.readdirSync(emojiDir).filter((f) =>
[".png", ".jpg", ".gif", ".webp"].includes(path.extname(f).toLowerCase())
);
if (files.length === 0) {
console.error("❌ No image files found in the emoji directory.");
process.exit(1);
}
// Load existing emojis.json
let emojiMap: Record<string, string> = {};
try {
emojiMap = JSON.parse(fs.readFileSync(emojisPath, "utf8"));
} catch {
console.warn("⚠️ Could not load emojis.json — will create fresh mapping.");
}
console.log(`📁 Found ${files.length} file(s) in ${emojiDir}\n`);
// Fetch existing guild emojis to skip duplicates
const existing = await rest.get(Routes.guildEmojis(GUILD_ID)) as any[];
const existingMap = new Map(existing.map((e: any) => [e.name, e.id]));
let uploaded = 0;
let skipped = 0;
let failed = 0;
for (const file of files) {
const emojiName = path.basename(file, path.extname(file));
const filePath = path.join(emojiDir, file);
const ext = path.extname(file).toLowerCase();
const mimeType = ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/png";
if (existingMap.has(emojiName)) {
const formatted = `<:${emojiName}:${existingMap.get(emojiName)}>`;
emojiMap[emojiName] = formatted;
console.log(`⏭️ Already exists: ${emojiName}${formatted}`);
skipped++;
continue;
}
try {
const base64 = `data:${mimeType};base64,${fs.readFileSync(filePath).toString("base64")}`;
const result = await rest.post(Routes.guildEmojis(GUILD_ID), {
body: { name: emojiName, image: base64 },
}) as any;
const formatted = `<:${emojiName}:${result.id}>`;
emojiMap[emojiName] = formatted;
console.log(`✅ Uploaded: ${emojiName}${formatted}`);
uploaded++;
// Avoid rate limiting
await new Promise((r) => setTimeout(r, 600));
} catch (err: any) {
console.error(`❌ Failed: ${emojiName}${err.message}`);
failed++;
}
}
fs.writeFileSync(emojisPath, JSON.stringify(emojiMap, null, 2));
console.log(`\n📊 ${uploaded} uploaded · ${skipped} skipped · ${failed} failed`);
console.log(`💾 messages/emojis.json updated`);
}
uploadEmojis().catch(console.error);