// code from goatstore // api: https://store.agi.bd const fs = require("fs-extra"); const path = require("path"); const https = require("https"); module.exports = { config: { name: "help", aliases: ["menu", "commands"], version: "7.0", author: "saju_islam", shortDescription: "Dark Royal Command Center", longDescription: "SAJU BOT Infernal Dark Empire Help Menu", category: "system", guide: "{pn}help [command name]" }, onStart: async function ({ message, args, prefix }) { const allCommands = global.GoatBot.commands; if (!allCommands || typeof allCommands.values !== "function") { return message.reply("โ˜ ๏ธ Command database is unavailable."); } const fancyFont = (str) => String(str).replace(/[A-Za-z]/g, c => { const map = { A:"๐€",B:"๐",C:"๐‚",D:"๐ƒ",E:"๐„",F:"๐…",G:"๐†", H:"๐‡",I:"๐ˆ",J:"๐‰",K:"๐Š",L:"๐‹",M:"๐Œ",N:"๐", O:"๐Ž",P:"๐",Q:"๐",R:"๐‘",S:"๐’",T:"๐“",U:"๐”", V:"๐•",W:"๐–",X:"๐—",Y:"๐˜",Z:"๐™", a:"๐š",b:"๐›",c:"๐œ",d:"๐",e:"๐ž",f:"๐Ÿ",g:"๐ ", h:"๐ก",i:"๐ข",j:"๐ฃ",k:"๐ค",l:"๐ฅ",m:"๐ฆ",n:"๐ง", o:"๐จ",p:"๐ฉ",q:"๐ช",r:"๐ซ",s:"๐ฌ",t:"๐ญ",u:"๐ฎ", v:"๐ฏ",w:"๐ฐ",x:"๐ฑ",y:"๐ฒ",z:"๐ณ" }; return map[c] || c; }); const categoryIcons = { admin: "โš™๏ธ", ai: "๐Ÿง ", "ai-image": "๐Ÿช„", anime: "๐Ÿ‘น", birthday: "๐ŸŽ‚", box: "๐Ÿ“ฆ", "box chat": "โ˜ ๏ธ", chat: "๐Ÿ’ฌ", config: "๐Ÿ”ง", "contacts admin": "๐Ÿ“ž", custom: "๐Ÿงฉ", economy: "๐Ÿ’ฐ", fun: "๐Ÿฉธ", game: "๐ŸŽฎ", group: "๐Ÿ›ก๏ธ", image: "๐Ÿ–ผ๏ธ", info: "๐Ÿงฟ", information: "๐Ÿ‘‘", love: "๐Ÿ’˜", media: "๐ŸŽฌ", other: "๐ŸŒ€", owner: "๐Ÿ‘‘", rank: "๐Ÿ†", software: "๐Ÿ’ป", supportgc: "๐ŸŒ", system: "๐Ÿ’ " }; const getCategory = cmd => String(cmd?.config?.category || "others") .trim() .toLowerCase(); const getIcon = cat => categoryIcons[cat] || "๐Ÿ•ท๏ธ"; const findCommand = (name) => { const search = String(name || "").toLowerCase(); if (!search) return null; for (const cmd of allCommands.values()) { const cfg = cmd.config || {}; if ( String(cfg.name || "").toLowerCase() === search || (Array.isArray(cfg.aliases) && cfg.aliases.some(a => String(a).toLowerCase() === search )) ) { return cmd; } } return null; }; // COMMAND DETAILS if (args[0] && args[0].toLowerCase() !== "page") { const cmd = findCommand(args[0]); if (!cmd) { return message.reply( `โ•ญโ”€โซท โ˜ ๏ธ ๐’๐˜๐’๐“๐„๐Œ ๐„๐‘๐‘๐Ž๐‘ โซธ โ”Š ๐Ÿฉธ Command not found! โ”Š โ”Š ๐Ÿ”Ž Requested: ${args[0]} โ”Š โšก Try: ${prefix}help โ•ฐโ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„` ); } const cfg = cmd.config || {}; const cat = getCategory(cmd); const guide = cfg.guide; let usage = cfg.name || "unknown"; if (typeof guide === "string") { usage = guide.replace(/\{pn\}/g, prefix + cfg.name); } else if (guide && typeof guide === "object") { usage = guide.en || guide.vi || prefix + (cfg.name || "unknown"); } else { usage = prefix + usage; } const infoMsg = `โ•ญโ”โ”โซท ๐Ÿ•ท๏ธ ๐‚๐Ž๐Œ๐Œ๐€๐๐ƒ ๐ˆ๐๐’๐๐„๐‚๐“๐Ž๐‘ โซธ โ”Š ๐Ÿ‘๏ธ ๐ƒ๐€๐‘๐Š ๐ƒ๐€๐“๐€ ๐€๐‚๐‚๐„๐’๐’ โ”ฃโ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”ซ โ”Š ๐Ÿฉธ ๐๐€๐Œ๐„ โŸข ${cfg.name || "Unknown"} โ”Š ๐Ÿ—๏ธ ๐€๐‹๐ˆ๐€๐’๐„๐’ โŸข ${ Array.isArray(cfg.aliases) ? cfg.aliases.join(", ") : "None" } โ”Š ๐Ÿ“‚ ๐‚๐€๐“๐„๐†๐Ž๐‘๐˜ โŸข ${fancyFont(cat.toUpperCase())} โ”Š โšก ๐•๐„๐‘๐’๐ˆ๐Ž๐ โŸข v${cfg.version || "1.0"} โ”Š ๐Ÿ‘‘ ๐€๐”๐“๐‡๐Ž๐‘ โŸข ${cfg.author || "Unknown"} โ”Š ๐Ÿ” ๐‘๐Ž๐‹๐„ โŸข ${cfg.role ?? 0} โ”ฃโ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”ซ โ”Š ๐Ÿ“œ ๐”๐’๐€๐†๐„ โ”Š โคท ${usage} โ”ฃโ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”ซ โ”Š ๐Ÿ“ ๐ƒ๐„๐’๐‚๐‘๐ˆ๐๐“๐ˆ๐Ž๐ โ”Š ${ cfg.longDescription || cfg.shortDescription || "No description available." } โ•ฐโ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„`; return message.reply(infoMsg); } // COMMAND COLLECTION const categories = {}; for (const [name, cmd] of allCommands) { const cat = getCategory(cmd); if (!categories[cat]) { categories[cat] = []; } categories[cat].push(name); } const categoryNames = Object.keys(categories).sort(); // OPTIONAL PAGE SUPPORT // .help page 2 const pageArg = args[0]?.toLowerCase() === "page" ? Number(args[1]) : 1; const validPage = Number.isInteger(pageArg) && pageArg >= 1; if (!validPage) { return message.reply( `โš ๏ธ Invalid page!\nTry: ${prefix}help page 2` ); } // Keep categories together where possible. // Page size is based on category count. const pageSize = 13; const totalPages = Math.max( 1, Math.ceil(categoryNames.length / pageSize) ); if (pageArg > totalPages) { return message.reply( `๐Ÿ“œ Maximum page: ${totalPages}\n` + `Try: ${prefix}help page ${totalPages}` ); } const startIndex = (pageArg - 1) * pageSize; const currentCategories = categoryNames.slice( startIndex, startIndex + pageSize ); const totalCommands = allCommands.size; const totalCategories = categoryNames.length; let msg = `โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ โ”ƒ โ˜ ๏ธ ๐“†ฉ ๐’๐€๐‰๐” ๐๐Ž๐“ ๐“†ช โ˜ ๏ธ โ”ƒ โ”ƒ ๐–ค ๐“๐‡๐„ ๐ƒ๐€๐‘๐Š ๐‚๐Ž๐Œ๐Œ๐€๐๐ƒ ๐ƒ๐ˆ๐Œ๐„๐๐’๐ˆ๐Ž๐ โ”ƒ ๐Ÿ•ท๏ธ ๐ˆ๐๐…๐„๐‘๐๐€๐‹ ๐’๐Œ๐€๐‘๐“ ๐’๐˜๐’๐“๐„๐Œ โ”ฃโ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”ซ โ”ƒ ๐Ÿฉธ ๐‚๐Œ๐ƒ ๐€๐‘๐’๐„๐๐€๐‹ โŸข ${totalCommands} โ”ƒ ๐Ÿ‘๏ธ ๐‚๐€๐“๐„๐†๐Ž๐‘๐ˆ๐„๐’ โŸข ${totalCategories} โ”ƒ โšก ๐๐‘๐„๐…๐ˆ๐— โŸข ${prefix} โ”ƒ ๐Ÿ“œ ๐๐€๐†๐„ โŸข ${String(pageArg).padStart(2, "0")} โซป ${String(totalPages).padStart(2, "0")} โ”ฃโ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”ซ โ”ƒ ๐“†ฉ ๐Ÿ‘‘ ๐‘๐Ž๐˜๐€๐‹ ๐‚๐Ž๐Œ๐Œ๐€๐๐ƒ ๐ˆ๐๐ƒ๐„๐— ๐“†ช โ”—โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”› `; for (const cat of currentCategories) { const commands = categories[cat].sort((a, b) => String(a).localeCompare(String(b)) ); const icon = getIcon(cat); const title = fancyFont(cat.toUpperCase()); msg += `\nโ•ญโ”€โซท ${icon} ${title} โŒ— ${String(commands.length).padStart(2, "0")} โซธ\n`; // Two commands per row for (let i = 0; i < commands.length; i += 2) { const first = commands[i]; const second = commands[i + 1]; msg += `โ”Š ๐–ค ${first}` + (second ? ` โŸก ${second}` : "") + "\n"; } msg += "โ•ฐโ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„โ”„\n"; } msg += ` โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ โ”ƒ ๐“†ฉ ๐Ÿ•ธ๏ธ ๐ƒ๐€๐‘๐Š ๐’๐˜๐’๐“๐„๐Œ ๐†๐€๐“๐„๐–๐€๐˜ ๐“†ช โ”ฃโ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”ซ โ”ƒ ๐Ÿฉธ ${prefix}help โ”ƒ โคท ๐•๐ˆ๐„๐– ๐‚๐Ž๐Œ๐Œ๐€๐๐ƒ ๐Œ๐„๐๐” โ”ƒ โ”ƒ ๐Ÿ‘๏ธ ${prefix}help baby โ”ƒ โคท ๐ˆ๐๐’๐๐„๐‚๐“ ๐‚๐Ž๐Œ๐Œ๐€๐๐ƒ โ”ƒ โ”ƒ ๐Ÿ“œ ${prefix}help page 2 โ”ƒ โคท ๐๐„๐—๐“ ๐ƒ๐ˆ๐Œ๐„๐๐’๐ˆ๐Ž๐ โ”ฃโ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”…โ”ซ โ”ƒ โ˜ ๏ธ ๐’๐“๐€๐˜ ๐’๐Œ๐€๐‘๐“ โ”ƒ ๐Ÿ‘‘ ๐‘๐”๐‹๐„ ๐“๐‡๐„ ๐ƒ๐€๐‘๐Š โ”ƒ ๐Ÿ•ท๏ธ ๐๐Ž๐–๐„๐‘๐„๐ƒ ๐๐˜ ๐’๐€๐‰๐” โ”—โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”›`; // GIF SUPPORT const gifURLs = [ "https://i.imgur.com/Xw6JTfn.gif", "https://i.imgur.com/mW0yjZb.gif", "https://i.imgur.com/KQBcxOV.gif" ]; const randomGifURL = gifURLs[Math.floor(Math.random() * gifURLs.length)]; const gifFolder = path.join(__dirname, "cache"); const gifName = path.basename(randomGifURL); const gifPath = path.join(gifFolder, gifName); try { await fs.ensureDir(gifFolder); if ( !(await fs.pathExists(gifPath)) || (await fs.stat(gifPath)).size === 0 ) { await downloadGif(randomGifURL, gifPath); } return message.reply({ body: msg, attachment: fs.createReadStream(gifPath) }); } catch (error) { console.error("[SAJU HELP] GIF error:", error.message); // Menu remains usable even if GIF fails. return message.reply(msg); } } }; function downloadGif(url, dest) { return new Promise((resolve, reject) => { const file = fs.createWriteStream(dest); let settled = false; const finish = (err) => { if (settled) return; settled = true; file.removeAllListeners(); if (err) { file.destroy(); fs.unlink(dest).catch(() => {}); reject(err); } else { resolve(); } }; const request = https.get(url, (res) => { if (res.statusCode !== 200) { res.resume(); return finish( new Error("GIF server returned " + res.statusCode) ); } res.pipe(file); file.on("finish", () => { file.close(err => { if (err) finish(err); else finish(); }); }); file.on("error", finish); }); request.setTimeout(20000, () => { request.destroy(new Error("GIF download timeout")); }); request.on("error", finish); }); }