goat
command
إعدادات
إعدادات البوت العامة
0
views
0
likes
0
installs
Aliases: setting, settings
raw source
const fs = require("fs");
const path = require("path");
function getPath(obj, keys) {
return keys.reduce((o, k) => (o == null ? o : o[k]), obj);
}
function setPath(obj, keys, value) {
let cur = obj;
for (let i = 0; i < keys.length - 1; i++) {
cur[keys[i]] = cur[keys[i]] || {};
cur = cur[keys[i]];
}
cur[keys[keys.length - 1]] = value;
}
function status(val) {
return val ? "ON ✦" : "OFF ◌";
}
function wrapItem(text, maxWidth) {
const words = text.split(" ");
const lines = [];
let cur = "";
for (const w of words) {
const test = cur ? `${cur} ${w}` : w;
if (test.length > maxWidth && cur) {
lines.push(cur);
cur = w;
} else {
cur = test;
}
}
if (cur) lines.push(cur);
return lines;
}
function renderBox(headerIcon, headerTitle, subtitleLines, boxLabel, itemLines, footer) {
const lines = [`╭─ ${headerIcon} ${headerTitle.toUpperCase()}`];
subtitleLines.forEach(l => lines.push(`├ ${l}`));
lines.push("");
lines.push(`┌─ ${boxLabel.toUpperCase()} ─┐`);
itemLines.forEach(item => {
wrapItem(item, 22).forEach(w => lines.push(`│ ${w}`));
});
lines.push("└─────────────┘");
lines.push("");
lines.push(`╰─ ${footer}`);
return lines.join("\n");
}
function masked(val) {
if (val === undefined || val === null || val === "" || val === " ") return "Not set ✕";
return "Set ✦ (" + String(val).length + " chars)";
}
const BOOL_GROUPS = {
hideNoti: {
title: "🔕 Hide Notification Messages",
path: ["hideNotiMessage"],
items: [
["commandNotFound", "Command Not Found"],
["adminOnly", "Admin Only"],
["threadBanned", "Thread Banned"],
["userBanned", "User Banned"],
["needRoleToUseCmd", "Need Role To Use Cmd"],
["needRoleToUseCmdOnReply", "…On Reply"],
["needRoleToUseCmdOnReaction", "…On Reaction"]
]
},
logEvents: {
title: "📝 Log Events",
path: ["logEvents"],
items: [
["disableAll", "Disable All"],
["message", "Message"],
["message_reaction", "Message Reaction"],
["message_unsend", "Message Unsend"],
["message_reply", "Message Reply"],
["event", "Event"],
["read_receipt", "Read Receipt"],
["typ", "Typing"],
["presence", "Presence"]
]
},
fcaOptions: {
title: "🧩 FCA Options",
path: ["optionsFca"],
items: [
["forceLogin", "Force Login"],
["listenEvents", "Listen Events"],
["updatePresence", "Update Presence"],
["listenTyping", "Listen Typing"],
["selfListen", "Self Listen"],
["selfListenEvent", "Self Listen Event"],
["autoMarkDelivery", "Auto Mark Delivery"],
["autoReconnect", "Auto Reconnect"]
],
afterToggle: (api, key, val) => {
try { api.setOptions({ [key]: val }); } catch (e) { }
}
},
notiMqttGmail: {
title: "📧 MQTT Error Notify — Gmail",
path: ["notiWhenListenMqttError", "gmail"],
items: [["enable", "Enable"]]
},
notiMqttTelegram: {
title: "📨 MQTT Error Notify — Telegram",
path: ["notiWhenListenMqttError", "telegram"],
items: [["enable", "Enable"]]
},
notiMqttDiscord: {
title: "📢 MQTT Error Notify — Discord",
path: ["notiWhenListenMqttError", "discordHook"],
items: [["enable", "Enable"]]
}
};
function renderBoolGroupMenu(config, groupKey) {
const group = BOOL_GROUPS[groupKey];
const sub = getPath(config, group.path) || {};
const itemLines = group.items.map(([key, label], i) => `${i + 1}. ${label} — ${status(sub[key])}`);
return renderBox("⚙️", group.title.replace(/^[^\w]*/, "").trim(), [`Items : ${group.items.length}`], "toggles", itemLines, "Reply a number to toggle, or 0 to go back");
}
const CATEGORIES = [
{
title: "🔐 Account & Security",
items: [
{ num: 1, label: "Facebook Account" },
{ num: 17, label: "Credentials (Gmail / reCAPTCHA)" }
]
},
{
title: "🤖 Bot Behavior",
items: [
{ num: 2, label: "Bot Behavior" },
{ num: 5, label: "No Prefix" },
{ num: 7, label: "Nickname" },
{ num: 9, label: "Typing Indicator" }
]
},
{
title: "👥 Access Control",
items: [
{ num: 3, label: "Admin Manage" },
{ num: 4, label: "Whitelist Manage" },
{ num: 6, label: "React Unsend" }
]
},
{
title: "🧩 Connection (FCA / MQTT)",
items: [
{ num: 8, label: "FCA Options" },
{ num: 13, label: "Restart Listen MQTT" },
{ num: 14, label: "MQTT Error Notify" },
{ num: 18, label: "E2EE" }
]
},
{
title: "🗄️ Database & Storage",
items: [
{ num: 10, label: "Database" }
]
},
{
title: "📊 Dashboard & Monitoring",
items: [
{ num: 11, label: "Dashboard & Uptime" },
{ num: 12, label: "Auto Load Scripts" }
]
},
{
title: "📝 Logging",
items: [
{ num: 15, label: "Hide Notification Messages" },
{ num: 16, label: "Log Events" }
]
}
];
function renderCategoryList() {
const itemLines = CATEGORIES.map((cat, i) => `${i + 1}. ${cat.title.replace(/^[^\w]*/, "").trim()}`);
return renderBox("⚙️", "Bot Settings", [`Categories : ${CATEGORIES.length}`, "Author : EryXenX"], "categories", itemLines, `Reply 1-${CATEGORIES.length} to enter a category`);
}
function renderCategoryItems(catIndex) {
const cat = CATEGORIES[catIndex];
const itemLines = cat.items.map((item, i) => `${i + 1}. ${item.label}`);
return renderBox("🧩", cat.title.replace(/^[^\w]*/, "").trim(), [`Items : ${cat.items.length}`], "items", itemLines, "Reply a number, or 0 to go back to categories");
}
module.exports = {
config: {
name: "إعدادات",
aliases: ["setting", "settings"],
version: "8.0.0",
author: "EryXenX",
countDown: 5,
role: 2,
shortDescription: "إعدادات البوت العامة",
longDescription: "إعدادات البوت العامة",
category: "admin",
guide: "{pn}"
},
onStart: async function ({ event, message }) {
const sent = await message.reply(renderCategoryList());
global.GoatBot.onReply.set(sent.messageID, {
commandName: "إعدادات",
messageID: sent.messageID,
author: event.senderID,
state: "categories"
});
},
onReply: async function ({ api, event, Reply, message }) {
const { author, state } = Reply;
if (event.senderID !== author) return;
const configPath = path.join(process.cwd(), "config.json");
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
const input = event.body.trim();
let num = parseInt(input);
function saveConfig() {
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
}
async function sendAndListen(text, newState, extra = {}) {
const sent = await message.reply(text);
global.GoatBot.onReply.set(sent.messageID, {
commandName: "إعدادات",
messageID: sent.messageID,
author,
state: newState,
...extra
});
}
async function backToCategories() {
return await sendAndListen(renderCategoryList(), "categories");
}
if (state === "categories") {
const cat = CATEGORIES[num - 1];
if (!cat) return message.reply(`𝗫 Invalid selection. Reply 1-${CATEGORIES.length}.`);
return await sendAndListen(renderCategoryItems(num - 1), "categoryItems", { catIndex: num - 1 });
}
if (state === "categoryItems") {
if (num === 0) return backToCategories();
const cat = CATEGORIES[Reply.catIndex];
const item = cat && cat.items[num - 1];
if (!item) return message.reply("𝗫 Invalid selection.");
num = item.num; // fall through to the existing item logic below
}
if (BOOL_GROUPS[state]) {
const group = BOOL_GROUPS[state];
if (num === 0) return backToCategories();
const item = group.items[num - 1];
if (!item) return message.reply("𝗫 Invalid selection. Reply a number from the list, or 0 to go back.");
const [key] = item;
const sub = getPath(config, group.path) || {};
sub[key] = !sub[key];
setPath(config, group.path, sub);
saveConfig();
if (group.afterToggle) group.afterToggle(api, key, sub[key]);
return await sendAndListen(renderBoolGroupMenu(config, state), state);
}
if (state === "categoryItems" || state === "itemMenu") {
if (num === 1) {
const fb = config.facebookAccount || {};
const menu = renderBox("👤", "Facebook Account", [], "fields", [
`1. ${"Email"} — ${fb.email || "Not set ✕"}`,
`2. ${"Password"} — ${masked(fb.password)}`,
`3. ${"2FA Secret"} — ${masked(fb["2FASecret"])}`,
`4. ${"i_user"} — ${masked(fb.i_user)}`,
`5. ${"Proxy"} — ${fb.proxy || "Not set ✕"}`,
`6. ${"User Agent"} — ${fb.userAgent ? "Set ✦" : "Not set ✕"}`,
`7. ${"Cookie Refresh Interval"} — ${fb.intervalGetNewCookie ?? "Not set"} min`
], "Reply 1-7 · ⚠️ needs a bot restart to take effect");
return await sendAndListen(menu, "fbAccount");
}
if (num === 2) {
const menu = renderBox("🤖", "Bot Behavior", [], "fields", [
`1. ${"Prefix"} — ${config.prefix || "/"}`,
`2. ${"Language"} — ${config.language || "en"}`,
`3. ${"Time Zone"} — ${config.timeZone || "Not set"}`,
`4. ${"Anti Inbox"} — ${status(config.antiInbox)}`,
`5. ${"Admin Only"} — ${status(config.adminOnly?.enable)}`,
`6. ${"Only Admin Box"} — ${status(config.onlyAdminBox)}`,
`7. ${"Auto Refresh Fbstate"} — ${status(config.autoRefreshFbstate)}`,
`8. ${"Auto Relogin On Account Change"} — ${status(config.autoReloginWhenChangeAccount)}`,
`9. ${"Auto Restart On MQTT Error"} — ${status(config.autoRestartWhenListenMqttError)}`,
`10. ${"Auto Restart Time (cron/ms)"} — ${config.autoRestart?.time ?? "Not set"}`
], "Reply 1-10");
return await sendAndListen(menu, "botBehavior");
}
if (num === 3) {
const menu = renderBox("⚙️", "Admin Manage", [], "actions", [
`1. ${"Add Admin"}`,
`2. ${"Remove Admin"}`,
`3. ${"List Admins"}`
], "Reply 1-3");
return await sendAndListen(menu, "adminManage");
}
if (num === 4) {
const menu = renderBox("⚙️", "Whitelist Manage", [], "actions", [
`1. ${"Thread Whitelist"} — ${status(config.whiteListModeThread?.enable)}`,
`2. ${"Add Thread"}`,
`3. ${"Remove Thread"}`,
`4. ${"User Whitelist"} — ${status(config.whiteListMode?.enable)}`,
`5. ${"Add User"}`,
`6. ${"Remove User"}`
], "Reply 1-6");
return await sendAndListen(menu, "whitelist");
}
if (num === 5) {
config.noPrefix = config.noPrefix || {};
config.noPrefix.enable = !config.noPrefix.enable;
saveConfig();
return message.reply(`✦ No Prefix is now ${status(config.noPrefix.enable)}`);
}
if (num === 6) {
const menu = renderBox("⚙️", "React Unsend", [], "fields", [
`1. ${"Toggle"} — ${status(config.reactUnsend?.enable)}`,
`2. ${"Only Admin"} — ${status(config.reactUnsend?.onlyAdmin)}`,
`3. ${"Add Emoji"}`,
`4. ${"Remove Emoji"}`,
`5. ${"List Emojis"}`
], "Reply 1-5");
return await sendAndListen(menu, "reactUnsend");
}
if (num === 7) {
const current = config.nickNameBot || "Not set";
const menu = renderBox("⚙️", "Nickname", [`Current : ${current}`], "actions", [
`1. ${"Set Nickname (this group)"}`,
`2. ${"Set Nickname (all groups)"}`,
`3. ${"Reset Nickname"}`
], "Reply 1-3");
return await sendAndListen(menu, "nickname");
}
if (num === 8) return await sendAndListen(renderBoolGroupMenu(config, "fcaOptions"), "fcaOptions");
if (num === 9) {
const menu = renderBox("⚙️", "Typing Indicator", [], "fields", [
`1. ${"Toggle"} — ${status(config.enableTypingIndicator)}`,
`2. ${"Duration"} — ${config.typingDuration || 2000}ms`
], "Reply 1-2");
return await sendAndListen(menu, "typingIndicator");
}
if (num === 10) {
const db = config.database || {};
const menu = renderBox("🗄️", "Database", [], "fields", [
`1. ${"Type"} — ${db.type || "Not set"} (needs restart to change)`,
`2. ${"MongoDB URI"} — ${masked(db.uriMongodb)}`,
`3. ${"Auto Sync When Start"} — ${status(db.autoSyncWhenStart)}`,
`4. ${"Auto Refresh Thread Info (first time)"} — ${status(db.autoRefreshThreadInfoFirstTime)}`
], "Reply 1-4");
return await sendAndListen(menu, "database");
}
if (num === 11) {
const dash = config.dashBoard || {};
const up = config.serverUptime || {};
const auto = config.autoUptime || {};
const menu = renderBox("📊", "Dashboard & Uptime", [], "fields", [
`1. ${"Dashboard Enable"} — ${status(dash.enable)}`,
`2. ${"Dashboard Port"} — ${dash.port ?? "Not set"}`,
`3. ${"Dashboard Verify Code Expiry (ms)"} — ${dash.expireVerifyCode ?? "Not set"}`,
`4. ${"Server Uptime Enable"} — ${status(up.enable)}`,
`5. ${"Server Uptime Port"} — ${up.port ?? "Not set"}`,
`6. ${"Server Uptime Socket Enable"} — ${status(up.socket?.enable)}`,
`7. ${"Server Uptime Channel Name"} — ${up.socket?.channelName || "Not set"}`,
`8. ${"Auto Uptime Enable"} — ${status(auto.enable)}`,
`9. ${"Auto Uptime Interval (s)"} — ${auto.timeInterval ?? "Not set"}`,
`10. ${"Auto Uptime URL"} — ${auto.url || "Not set"}`
], "Reply 1-10");
return await sendAndListen(menu, "dashboardUptime");
}
if (num === 12) {
const a = config.autoLoadScripts || {};
const menu = renderBox("📜", "Auto Load Scripts", [], "fields", [
`1. ${"Enable"} — ${status(a.enable)}`,
`2. ${"Ignore Commands"} — ${a.ignoreCmds || "(none)"}`,
`3. ${"Ignore Events"} — ${a.ignoreEvents || "(none)"}`
], "Reply 1-3");
return await sendAndListen(menu, "autoLoadScripts");
}
if (num === 13) {
const r = config.restartListenMqtt || {};
const menu = renderBox("🔁", "Restart Listen MQTT", [], "fields", [
`1. ${"Enable"} — ${status(r.enable)}`,
`2. ${"Restart Interval (ms)"} — ${r.timeRestart ?? "Not set"}`,
`3. ${"Delay After Stop (ms)"} — ${r.delayAfterStopListening ?? "Not set"}`,
`4. ${"Log Notification"} — ${status(r.logNoti)}`
], "Reply 1-4");
return await sendAndListen(menu, "restartListenMqtt");
}
if (num === 14) {
const menu = renderBox("🔔", "MQTT Error Notify", [], "channels", [
`1. ${"Gmail"}`,
`2. ${"Telegram"}`,
`3. ${"Discord"}`
], "Reply 1-3");
return await sendAndListen(menu, "notiMqttPick");
}
if (num === 15) return await sendAndListen(renderBoolGroupMenu(config, "hideNoti"), "hideNoti");
if (num === 16) return await sendAndListen(renderBoolGroupMenu(config, "logEvents"), "logEvents");
if (num === 17) {
const g = config.credentials?.gmailAccount || {};
const r = config.credentials?.gRecaptcha || {};
const menu = renderBox("🔑", "Credentials", [], "fields", [
`1. ${"Gmail Email"} — ${g.email || "Not set ✕"}`,
`2. ${"Gmail Client ID"} — ${masked(g.clientId)}`,
`3. ${"Gmail Client Secret"} — ${masked(g.clientSecret)}`,
`4. ${"Gmail Refresh Token"} — ${masked(g.refreshToken)}`,
`5. ${"Gmail API Key"} — ${masked(g.apiKey)}`,
`6. ${"reCAPTCHA Site Key"} — ${masked(r.siteKey)}`,
`7. ${"reCAPTCHA Secret Key"} — ${masked(r.secretKey)}`
], "Reply 1-7");
return await sendAndListen(menu, "credentials");
}
if (num === 18) {
config.e2ee = config.e2ee || {};
const was = config.e2ee.enable;
config.e2ee.enable = !was;
saveConfig();
const sent = await message.reply(`✦ E2EE is now ${status(config.e2ee.enable)}\n⚠️ Needs a bot restart to take effect.\n› React to this message to restart now, or select E2EE again later to switch it back without restarting.`);
global.GoatBot.onReaction.set(sent.messageID, {
commandName: "إعدادات",
messageID: sent.messageID,
type: "e2eeRestartConfirm",
author
});
return;
}
}
if (state === "fbAccount") {
const fields = [
["email", "Email", "text"],
["password", "Password", "text"],
["2FASecret", "2FA Secret", "text"],
["i_user", "i_user", "text"],
["proxy", "Proxy", "text"],
["userAgent", "User Agent", "text"],
["intervalGetNewCookie", "Cookie Refresh Interval (minutes)", "number"]
];
const field = fields[num - 1];
if (!field) return message.reply("𝗫 Invalid selection.");
const [key, label, type] = field;
return await sendAndListen(`› Reply with new value for ${label}:`, "fbAccountSet", { fieldKey: key, fieldType: type });
}
if (state === "fbAccountSet") {
const { fieldKey, fieldType } = Reply;
let value = input;
if (fieldType === "number") {
if (isNaN(num)) return message.reply("𝗫 Invalid number.");
value = num;
}
config.facebookAccount = config.facebookAccount || {};
config.facebookAccount[fieldKey] = value;
saveConfig();
return message.reply(`✦ Updated. (Restart the bot for this to take effect.)`);
}
if (state === "botBehavior") {
if (num === 1) return await sendAndListen("› Reply with new prefix:", "prefixSet");
if (num === 2) return await sendAndListen("› Reply with new language code (e.g. en, bn):", "languageSet");
if (num === 3) return await sendAndListen("› Reply with new time zone (e.g. Asia/Dhaka):", "timeZoneSet");
if (num === 4) {
config.antiInbox = !config.antiInbox;
saveConfig();
return message.reply(`✦ Anti Inbox — ${status(config.antiInbox)}`);
}
if (num === 5) {
config.adminOnly = config.adminOnly || {};
config.adminOnly.enable = !config.adminOnly.enable;
saveConfig();
return message.reply(`✦ Admin Only — ${status(config.adminOnly.enable)}`);
}
if (num === 6) {
config.onlyAdminBox = !config.onlyAdminBox;
saveConfig();
return message.reply(`✦ Only Admin Box — ${status(config.onlyAdminBox)}`);
}
if (num === 7) {
config.autoRefreshFbstate = !config.autoRefreshFbstate;
saveConfig();
return message.reply(`✦ Auto Refresh Fbstate — ${status(config.autoRefreshFbstate)}`);
}
if (num === 8) {
config.autoReloginWhenChangeAccount = !config.autoReloginWhenChangeAccount;
saveConfig();
return message.reply(`✦ Auto Relogin On Account Change — ${status(config.autoReloginWhenChangeAccount)}`);
}
if (num === 9) {
config.autoRestartWhenListenMqttError = !config.autoRestartWhenListenMqttError;
saveConfig();
return message.reply(`✦ Auto Restart On MQTT Error — ${status(config.autoRestartWhenListenMqttError)}`);
}
if (num === 10) return await sendAndListen("› Reply with new Auto Restart time (ms, or cron string, or 'null' to disable):", "autoRestartTimeSet");
}
if (state === "prefixSet") {
if (!input) return message.reply("𝗫 Invalid prefix.");
config.prefix = input;
saveConfig();
return message.reply(`✦ Prefix set to: ${input}`);
}
if (state === "languageSet") {
if (!input) return message.reply("𝗫 Invalid language code.");
config.language = input;
saveConfig();
return message.reply(`✦ Language set to: ${input}`);
}
if (state === "timeZoneSet") {
if (!input) return message.reply("𝗫 Invalid time zone.");
config.timeZone = input;
saveConfig();
return message.reply(`✦ Time Zone set to: ${input}`);
}
if (state === "autoRestartTimeSet") {
config.autoRestart = config.autoRestart || {};
config.autoRestart.time = input === "null" ? null : (isNaN(num) ? input : num);
saveConfig();
return message.reply(`✦ Auto Restart time set to: ${config.autoRestart.time}`);
}
if (state === "adminManage") {
if (num === 1) return await sendAndListen("› Reply with UID or tag user to add as admin:", "adminAdd");
if (num === 2) {
const admins = config.adminBot || [];
if (!admins.length) return message.reply("𝗫 No admins found.");
const list = admins.map((id, i) => `${i + 1}. ${id}`);
await message.reply(renderBox("⚙️", "Remove Admin", [], "admins", list, "Reply number"));
return await sendAndListen("› Waiting...", "adminRemoveSelect");
}
if (num === 3) {
const admins = config.adminBot || [];
if (!admins.length) return message.reply("𝗫 No admins found.");
return message.reply(renderBox("⚙️", "Admins", [], "list", admins.map((id, i) => `${i + 1}. ${id}`), "Reply 1 to go back to categories"));
}
}
if (state === "adminAdd") {
let uid = input;
if (event.mentions && Object.keys(event.mentions).length > 0) uid = Object.keys(event.mentions)[0];
if (!uid || isNaN(uid)) return message.reply("𝗫 Invalid UID.");
config.adminBot = config.adminBot || [];
if (config.adminBot.includes(uid)) return message.reply("𝗫 Already an admin.");
config.adminBot.push(uid);
saveConfig();
return message.reply(`✦ Added ${uid} as admin.`);
}
if (state === "adminRemoveSelect") {
const admins = config.adminBot || [];
const idx = num - 1;
if (isNaN(num) || !admins[idx]) return message.reply("𝗫 Invalid selection.");
const removed = admins.splice(idx, 1)[0];
config.adminBot = admins;
saveConfig();
return message.reply(`✦ Removed ${removed} from admins.`);
}
if (state === "whitelist") {
if (num === 1) {
config.whiteListModeThread = config.whiteListModeThread || {};
config.whiteListModeThread.enable = !config.whiteListModeThread.enable;
saveConfig();
return message.reply(`✦ Thread Whitelist is now ${status(config.whiteListModeThread.enable)}`);
}
if (num === 2) return await sendAndListen("› Reply with Thread ID to add:", "threadAdd");
if (num === 3) {
const threads = config.whiteListModeThread?.whiteListThreadIds || [];
if (!threads.length) return message.reply("𝗫 No threads found.");
const list = threads.map((id, i) => `${i + 1}. ${id}`);
await message.reply(renderBox("⚙️", "Remove Thread", [], "threads", list, "Reply number"));
return await sendAndListen("› Waiting...", "threadRemoveSelect");
}
if (num === 4) {
config.whiteListMode = config.whiteListMode || {};
config.whiteListMode.enable = !config.whiteListMode.enable;
saveConfig();
return message.reply(`✦ User Whitelist is now ${status(config.whiteListMode.enable)}`);
}
if (num === 5) return await sendAndListen("› Reply with UID or tag user to add:", "userAdd");
if (num === 6) {
const users = config.whiteListMode?.whiteListIds || [];
if (!users.length) return message.reply("𝗫 No users found.");
const list = users.map((id, i) => `${i + 1}. ${id}`);
await message.reply(renderBox("⚙️", "Remove User", [], "users", list, "Reply number"));
return await sendAndListen("› Waiting...", "userRemoveSelect");
}
}
if (state === "threadAdd") {
const tid = input;
if (!tid || isNaN(tid)) return message.reply("𝗫 Invalid Thread ID.");
config.whiteListModeThread = config.whiteListModeThread || {};
config.whiteListModeThread.whiteListThreadIds = config.whiteListModeThread.whiteListThreadIds || [];
if (config.whiteListModeThread.whiteListThreadIds.includes(tid)) return message.reply("𝗫 Already in whitelist.");
config.whiteListModeThread.whiteListThreadIds.push(tid);
saveConfig();
return message.reply(`✦ Thread ${tid} added.`);
}
if (state === "threadRemoveSelect") {
const threads = config.whiteListModeThread?.whiteListThreadIds || [];
const idx = num - 1;
if (isNaN(num) || !threads[idx]) return message.reply("𝗫 Invalid selection.");
const removed = threads.splice(idx, 1)[0];
config.whiteListModeThread.whiteListThreadIds = threads;
saveConfig();
return message.reply(`✦ Thread ${removed} removed.`);
}
if (state === "userAdd") {
let uid = input;
if (event.mentions && Object.keys(event.mentions).length > 0) uid = Object.keys(event.mentions)[0];
if (!uid || isNaN(uid)) return message.reply("𝗫 Invalid UID.");
config.whiteListMode = config.whiteListMode || {};
config.whiteListMode.whiteListIds = config.whiteListMode.whiteListIds || [];
if (config.whiteListMode.whiteListIds.includes(uid)) return message.reply("𝗫 Already in whitelist.");
config.whiteListMode.whiteListIds.push(uid);
saveConfig();
return message.reply(`✦ User ${uid} added.`);
}
if (state === "userRemoveSelect") {
const users = config.whiteListMode?.whiteListIds || [];
const idx = num - 1;
if (isNaN(num) || !users[idx]) return message.reply("𝗫 Invalid selection.");
const removed = users.splice(idx, 1)[0];
config.whiteListMode.whiteListIds = users;
saveConfig();
return message.reply(`✦ User ${removed} removed.`);
}
if (state === "reactUnsend") {
if (num === 1) {
config.reactUnsend = config.reactUnsend || {};
config.reactUnsend.enable = !config.reactUnsend.enable;
saveConfig();
return message.reply(`✦ React Unsend — ${status(config.reactUnsend.enable)}`);
}
if (num === 2) {
config.reactUnsend = config.reactUnsend || {};
config.reactUnsend.onlyAdmin = !config.reactUnsend.onlyAdmin;
saveConfig();
return message.reply(`✦ Only Admin — ${status(config.reactUnsend.onlyAdmin)}`);
}
if (num === 3) return await sendAndListen("› Reply with emoji to add:", "emojiAdd");
if (num === 4) {
const emojis = config.reactUnsend?.emojis || [];
if (!emojis.length) return message.reply("𝗫 No emojis found.");
const list = emojis.map((e, i) => `${i + 1}. ${e}`);
await message.reply(renderBox("⚙️", "Remove Emoji", [], "emojis", list, "Reply number"));
return await sendAndListen("› Waiting...", "emojiRemoveSelect");
}
if (num === 5) {
const emojis = config.reactUnsend?.emojis || [];
if (!emojis.length) return message.reply("𝗫 No emojis.");
return message.reply(renderBox("⚙️", "Emojis", [], "list", [emojis.join(" ")], "Reply 1 to go back to categories"));
}
}
if (state === "emojiAdd") {
const emoji = input.trim();
if (!emoji) return message.reply("𝗫 Invalid emoji.");
config.reactUnsend = config.reactUnsend || {};
config.reactUnsend.emojis = config.reactUnsend.emojis || [];
if (config.reactUnsend.emojis.includes(emoji)) return message.reply("𝗫 Already added.");
config.reactUnsend.emojis.push(emoji);
saveConfig();
return message.reply(`✦ Emoji ${emoji} added.`);
}
if (state === "emojiRemoveSelect") {
const emojis = config.reactUnsend?.emojis || [];
const idx = num - 1;
if (isNaN(num) || !emojis[idx]) return message.reply("𝗫 Invalid selection.");
const removed = emojis.splice(idx, 1)[0];
config.reactUnsend.emojis = emojis;
saveConfig();
return message.reply(`✦ Emoji ${removed} removed.`);
}
if (state === "nickname") {
if (num === 1) return await sendAndListen("› Reply with new nickname:", "nicknameSet");
if (num === 2) return await sendAndListen("› Reply with new nickname (will set in all groups):", "nicknameSetAll");
if (num === 3) {
config.nickNameBot = "";
saveConfig();
try { await api.changeNickname("", event.threadID, api.getCurrentUserID()); } catch (e) { }
return message.reply("✦ Nickname reset.");
}
}
if (state === "nicknameSet") {
const nickname = input;
if (!nickname) return message.reply("𝗫 Invalid nickname.");
config.nickNameBot = nickname;
saveConfig();
try { await api.changeNickname(nickname, event.threadID, api.getCurrentUserID()); } catch (e) { }
return message.reply(`✦ Nickname set to: ${nickname}`);
}
if (state === "nicknameSetAll") {
const nickname = input;
if (!nickname) return message.reply("𝗫 Invalid nickname.");
config.nickNameBot = nickname;
saveConfig();
const threads = await api.getThreadList(100, null, ["INBOX"]);
let success = 0;
for (const thread of threads) {
if (!thread.isGroup) continue;
try { await api.changeNickname(nickname, thread.threadID, api.getCurrentUserID()); success++; } catch (e) { }
}
return message.reply(`✦ Nickname set to: ${nickname}\n› Updated in ${success} groups.`);
}
if (state === "typingIndicator") {
if (num === 1) {
config.enableTypingIndicator = !config.enableTypingIndicator;
saveConfig();
return message.reply(`✦ Typing Indicator — ${status(config.enableTypingIndicator)}`);
}
if (num === 2) return await sendAndListen("› Reply with duration in milliseconds (e.g. 2000 for 2s):", "typingDurationSet");
}
if (state === "typingDurationSet") {
if (isNaN(num) || num < 500 || num > 15000) return message.reply("𝗫 Invalid duration. Use a value between 500 and 15000 ms.");
config.typingDuration = num;
saveConfig();
return message.reply(`✦ Typing Duration set to: ${num}ms`);
}
if (state === "database") {
if (num === 1) return message.reply("𝗫 Database type can't be changed live — edit config.json manually and restart the bot.");
if (num === 2) return await sendAndListen("› Reply with new MongoDB URI:", "mongoUriSet");
if (num === 3) {
config.database = config.database || {};
config.database.autoSyncWhenStart = !config.database.autoSyncWhenStart;
saveConfig();
return message.reply(`✦ Auto Sync When Start — ${status(config.database.autoSyncWhenStart)}`);
}
if (num === 4) {
config.database = config.database || {};
config.database.autoRefreshThreadInfoFirstTime = !config.database.autoRefreshThreadInfoFirstTime;
saveConfig();
return message.reply(`✦ Auto Refresh Thread Info — ${status(config.database.autoRefreshThreadInfoFirstTime)}`);
}
}
if (state === "mongoUriSet") {
if (!input) return message.reply("𝗫 Invalid URI.");
config.database = config.database || {};
config.database.uriMongodb = input;
saveConfig();
return message.reply("✦ MongoDB URI updated. (Restart the bot for this to take effect.)");
}
if (state === "dashboardUptime") {
config.dashBoard = config.dashBoard || {};
config.serverUptime = config.serverUptime || {};
config.serverUptime.socket = config.serverUptime.socket || {};
config.autoUptime = config.autoUptime || {};
if (num === 1) {
config.dashBoard.enable = !config.dashBoard.enable;
saveConfig();
return message.reply(`✦ Dashboard Enable — ${status(config.dashBoard.enable)}`);
}
if (num === 2) return await sendAndListen("› Reply with new Dashboard port:", "dashPortSet");
if (num === 3) return await sendAndListen("› Reply with new Verify Code expiry (ms):", "dashExpirySet");
if (num === 4) {
config.serverUptime.enable = !config.serverUptime.enable;
saveConfig();
return message.reply(`✦ Server Uptime Enable — ${status(config.serverUptime.enable)}`);
}
if (num === 5) return await sendAndListen("› Reply with new Server Uptime port:", "uptimePortSet");
if (num === 6) {
config.serverUptime.socket.enable = !config.serverUptime.socket.enable;
saveConfig();
return message.reply(`✦ Server Uptime Socket Enable — ${status(config.serverUptime.socket.enable)}`);
}
if (num === 7) return await sendAndListen("› Reply with new channel name:", "uptimeChannelSet");
if (num === 8) {
config.autoUptime.enable = !config.autoUptime.enable;
saveConfig();
return message.reply(`✦ Auto Uptime Enable — ${status(config.autoUptime.enable)}`);
}
if (num === 9) return await sendAndListen("› Reply with new interval in seconds:", "autoUptimeIntervalSet");
if (num === 10) return await sendAndListen("› Reply with new Auto Uptime URL:", "autoUptimeUrlSet");
}
if (state === "dashPortSet") {
if (isNaN(num)) return message.reply("𝗫 Invalid port.");
config.dashBoard.port = num;
saveConfig();
return message.reply(`✦ Dashboard port set to: ${num}`);
}
if (state === "dashExpirySet") {
if (isNaN(num)) return message.reply("𝗫 Invalid value.");
config.dashBoard.expireVerifyCode = num;
saveConfig();
return message.reply(`✦ Verify Code expiry set to: ${num}ms`);
}
if (state === "uptimePortSet") {
if (isNaN(num)) return message.reply("𝗫 Invalid port.");
config.serverUptime.port = num;
saveConfig();
return message.reply(`✦ Server Uptime port set to: ${num}`);
}
if (state === "uptimeChannelSet") {
if (!input) return message.reply("𝗫 Invalid channel name.");
config.serverUptime.socket.channelName = input;
saveConfig();
return message.reply(`✦ Channel name set to: ${input}`);
}
if (state === "autoUptimeIntervalSet") {
if (isNaN(num)) return message.reply("𝗫 Invalid value.");
config.autoUptime.timeInterval = num;
saveConfig();
return message.reply(`✦ Interval set to: ${num}s`);
}
if (state === "autoUptimeUrlSet") {
if (!input) return message.reply("𝗫 Invalid URL.");
config.autoUptime.url = input;
saveConfig();
return message.reply(`✦ URL set to: ${input}`);
}
if (state === "autoLoadScripts") {
config.autoLoadScripts = config.autoLoadScripts || {};
if (num === 1) {
config.autoLoadScripts.enable = !config.autoLoadScripts.enable;
saveConfig();
return message.reply(`✦ Auto Load Scripts — ${status(config.autoLoadScripts.enable)}`);
}
if (num === 2) return await sendAndListen("› Reply with comma-separated command names to ignore:", "ignoreCmdsSet");
if (num === 3) return await sendAndListen("› Reply with comma-separated event names to ignore:", "ignoreEventsSet");
}
if (state === "ignoreCmdsSet") {
config.autoLoadScripts.ignoreCmds = input;
saveConfig();
return message.reply(`✦ Ignore Commands set to: ${input || "(none)"}`);
}
if (state === "ignoreEventsSet") {
config.autoLoadScripts.ignoreEvents = input;
saveConfig();
return message.reply(`✦ Ignore Events set to: ${input || "(none)"}`);
}
if (state === "restartListenMqtt") {
config.restartListenMqtt = config.restartListenMqtt || {};
if (num === 1) {
config.restartListenMqtt.enable = !config.restartListenMqtt.enable;
saveConfig();
return message.reply(`✦ Restart Listen MQTT Enable — ${status(config.restartListenMqtt.enable)}`);
}
if (num === 2) return await sendAndListen("› Reply with new restart interval (ms):", "mqttTimeRestartSet");
if (num === 3) return await sendAndListen("› Reply with new delay after stop (ms):", "mqttDelaySet");
if (num === 4) {
config.restartListenMqtt.logNoti = !config.restartListenMqtt.logNoti;
saveConfig();
return message.reply(`✦ Log Notification — ${status(config.restartListenMqtt.logNoti)}`);
}
}
if (state === "mqttTimeRestartSet") {
if (isNaN(num)) return message.reply("𝗫 Invalid value.");
config.restartListenMqtt.timeRestart = num;
saveConfig();
return message.reply(`✦ Restart interval set to: ${num}ms`);
}
if (state === "mqttDelaySet") {
if (isNaN(num)) return message.reply("𝗫 Invalid value.");
config.restartListenMqtt.delayAfterStopListening = num;
saveConfig();
return message.reply(`✦ Delay set to: ${num}ms`);
}
if (state === "notiMqttPick") {
if (num === 1) return await sendAndListen(renderBoolGroupMenu(config, "notiMqttGmail") + "\n\n2. Set Notify Email\n0. Back", "notiMqttGmailMenu");
if (num === 2) return await sendAndListen(renderBoolGroupMenu(config, "notiMqttTelegram") + "\n\n2. Set Bot Token\n3. Set Chat ID\n0. Back", "notiMqttTelegramMenu");
if (num === 3) return await sendAndListen(renderBoolGroupMenu(config, "notiMqttDiscord") + "\n\n2. Set Webhook URL\n0. Back", "notiMqttDiscordMenu");
}
if (state === "notiMqttGmailMenu") {
config.notiWhenListenMqttError = config.notiWhenListenMqttError || {};
config.notiWhenListenMqttError.gmail = config.notiWhenListenMqttError.gmail || {};
if (num === 0) {
const menu = renderBox("🔔", "MQTT Error Notify", [], "channels", [
`1. ${"Gmail"}`,
`2. ${"Telegram"}`,
`3. ${"Discord"}`
], "Reply 1-3");
return await sendAndListen(menu, "notiMqttPick");
}
if (num === 1) {
config.notiWhenListenMqttError.gmail.enable = !config.notiWhenListenMqttError.gmail.enable;
saveConfig();
return message.reply(`✦ Gmail Notify — ${status(config.notiWhenListenMqttError.gmail.enable)}`);
}
if (num === 2) return await sendAndListen("› Reply with notify email:", "notiGmailEmailSet");
}
if (state === "notiGmailEmailSet") {
if (!input) return message.reply("𝗫 Invalid email.");
config.notiWhenListenMqttError.gmail.emailGetNoti = input;
saveConfig();
return message.reply(`✦ Notify email set to: ${input}`);
}
if (state === "notiMqttTelegramMenu") {
config.notiWhenListenMqttError = config.notiWhenListenMqttError || {};
config.notiWhenListenMqttError.telegram = config.notiWhenListenMqttError.telegram || {};
if (num === 1) {
config.notiWhenListenMqttError.telegram.enable = !config.notiWhenListenMqttError.telegram.enable;
saveConfig();
return message.reply(`✦ Telegram Notify — ${status(config.notiWhenListenMqttError.telegram.enable)}`);
}
if (num === 2) return await sendAndListen("› Reply with bot token:", "notiTgTokenSet");
if (num === 3) return await sendAndListen("› Reply with chat ID:", "notiTgChatSet");
}
if (state === "notiTgTokenSet") {
config.notiWhenListenMqttError.telegram.botToken = input;
saveConfig();
return message.reply("✦ Bot token updated.");
}
if (state === "notiTgChatSet") {
config.notiWhenListenMqttError.telegram.chatId = input;
saveConfig();
return message.reply(`✦ Chat ID set to: ${input}`);
}
if (state === "notiMqttDiscordMenu") {
config.notiWhenListenMqttError = config.notiWhenListenMqttError || {};
config.notiWhenListenMqttError.discordHook = config.notiWhenListenMqttError.discordHook || {};
if (num === 1) {
config.notiWhenListenMqttError.discordHook.enable = !config.notiWhenListenMqttError.discordHook.enable;
saveConfig();
return message.reply(`✦ Discord Notify — ${status(config.notiWhenListenMqttError.discordHook.enable)}`);
}
if (num === 2) return await sendAndListen("› Reply with webhook URL:", "notiDiscordUrlSet");
}
if (state === "notiDiscordUrlSet") {
config.notiWhenListenMqttError.discordHook.webhookUrl = input;
saveConfig();
return message.reply("✦ Webhook URL updated.");
}
if (state === "credentials") {
config.credentials = config.credentials || {};
config.credentials.gmailAccount = config.credentials.gmailAccount || {};
config.credentials.gRecaptcha = config.credentials.gRecaptcha || {};
const fields = [
["gmailAccount", "email", "Gmail Email"],
["gmailAccount", "clientId", "Gmail Client ID"],
["gmailAccount", "clientSecret", "Gmail Client Secret"],
["gmailAccount", "refreshToken", "Gmail Refresh Token"],
["gmailAccount", "apiKey", "Gmail API Key"],
["gRecaptcha", "siteKey", "reCAPTCHA Site Key"],
["gRecaptcha", "secretKey", "reCAPTCHA Secret Key"]
];
const field = fields[num - 1];
if (!field) return message.reply("𝗫 Invalid selection.");
const [section, key, label] = field;
return await sendAndListen(`› Reply with new value for ${label}:`, "credentialSet", { credSection: section, credKey: key });
}
if (state === "credentialSet") {
const { credSection, credKey } = Reply;
config.credentials[credSection][credKey] = input;
saveConfig();
return message.reply("✦ Updated.");
}
},
onReaction: async function ({ api, event, Reaction, message }) {
if (Reaction.type !== "e2eeRestartConfirm") return;
if (event.userID !== Reaction.author) return;
const fs = require("fs");
const pathFile = `${__dirname}/tmp/restart.txt`;
fs.writeFileSync(pathFile, `${event.threadID} ${Date.now()}`);
await message.reply("🔄 | Restarting bot to apply E2EE change...");
process.exit(2);
}
};