goat
command
cmd
No description
0
views
0
likes
0
installs
raw source
const axios = require("axios");
const { execSync } = require("child_process");
const fs = require("fs-extra");
const path = require("path");
const cheerio = require("cheerio");
const { client } = global;
const { configCommands } = global.GoatBot;
const { log, loading, removeHomeDir, getPrefix } = global.utils;
function getDomain(url) {
const regex = /^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:/\n]+)/im;
const match = url.match(regex);
return match ? match[1] : null;
}
function isURL(str) {
try {
new URL(str);
return true;
}
catch (e) {
return false;
}
}
module.exports = {
config: {
name: "cmd",
version: "2.4.78",
author: "ST",
countDown: 5,
role: 2,
description: {
vi: "Quản lý các tệp lệnh của bạn",
en: "Manage your command files"
},
category: "owner",
guide: {
vi: " {pn} load <tên file lệnh>"
+ "\n {pn} loadAll"
+ "\n {pn} unload <tên file lệnh>"
+ "\n {pn} del <tên file lệnh>: Xóa file lệnh"
+ "\n {pn} install <url> <tên file lệnh>: Tải xuống và cài đặt một tệp lệnh từ một url, url là đường dẫn đến tệp lệnh (raw)"
+ "\n {pn} install <tên file lệnh> <code>: Tải xuống và cài đặt một tệp lệnh từ một code, code là mã của lệnh",
en: " {pn} load <command file name>"
+ "\n {pn} loadAll"
+ "\n {pn} unload <command file name>"
+ "\n {pn} del <command file name>: Delete command file"
+ "\n {pn} install <url> <command file name>: Download and install a command file from a url, url is the path to the file (raw)"
+ "\n {pn} install <command file name> <code>: Download and install a command file from a code, code is the code of the command"
}
},
langs: {
vi: {
missingFileName: "⚠️ | Vui lòng nhập vào tên lệnh bạn muốn reload",
loaded: "✅ | Đã load command \"%1\" thành công",
loadedError: "❌ | Load command \"%1\" thất bại với lỗi\n%2: %3",
loadedSuccess: "✅ | Đã load thành công (%1) command",
loadedFail: "❌ | Load thất bại (%1) command\n%2",
openConsoleToSeeError: "👀 | Hãy mở console để xem chi tiết lỗi",
missingCommandNameUnload: "⚠️ | Vui lòng nhập vào tên lệnh bạn muốn unload",
unloaded: "✅ | Đã unload command \"%1\" thành công",
unloadedError: "❌ | Unload command \"%1\" thất bại với lỗi\n%2: %3",
missingUrlCodeOrFileName: "⚠️ | Vui lòng nhập vào url hoặc code và tên file lệnh bạn muốn cài đặt",
missingUrlOrCode: "⚠️ | Vui lòng nhập vào url hoặc code của tệp lệnh bạn muốn cài đặt",
missingFileNameInstall: "⚠️ | Vui lòng nhập vào tên file để lưu lệnh (đuôi .js)",
invalidUrl: "⚠️ | Vui lòng nhập vào url hợp lệ",
invalidUrlOrCode: "⚠️ | Không thể lấy được mã lệnh",
alreadExist: "⚠️ | File lệnh đã tồn tại, bạn có chắc chắn muốn ghi đè lên file lệnh cũ không?\nThả cảm xúc bất kì vào tin nhắn này để tiếp tục",
installed: "✅ | Đã cài đặt command \"%1\" thành công, file lệnh được lưu tại %2",
installedError: "❌ | Cài đặt command \"%1\" thất bại với lỗi\n%2: %3",
missingFile: "⚠️ | Không tìm thấy tệp lệnh \"%1\"",
invalidFileName: "⚠️ | Tên tệp lệnh không hợp lệ",
unloadedFile: "✅ | Đã unload lệnh \"%1\"",
deletedFile: "✅ | Đã xóa file lệnh \"%1\" thành công",
deleteError: "❌ | Xóa file lệnh \"%1\" thất bại với lỗi: %2",
confirmDelete: "⚠️ | Bạn có chắc chắn muốn xóa file lệnh \"%1\" không?\nThả cảm xúc bất kì vào tin nhắn này để xác nhận"
},
en: {
missingFileName: "⚠️ | Please enter the command name you want to reload",
loaded: "✅ | Loaded command \"%1\" successfully",
loadedError: "❌ | Failed to load command \"%1\" with error\n%2: %3",
loadedSuccess: "✅ | Loaded successfully (%1) command",
loadedFail: "❌ | Failed to load (%1) command\n%2",
openConsoleToSeeError: "👀 | Open console to see error details",
missingCommandNameUnload: "⚠️ | Please enter the command name you want to unload",
unloaded: "✅ | Unloaded command \"%1\" successfully",
unloadedError: "❌ | Failed to unload command \"%1\" with error\n%2: %3",
missingUrlCodeOrFileName: "⚠️ | Please enter the url or code and command file name you want to install",
missingUrlOrCode: "⚠️ | Please enter the url or code of the command file you want to install",
missingFileNameInstall: "⚠️ | Please enter the file name to save the command (with .js extension)",
invalidUrl: "⚠️ | Please enter a valid url",
invalidUrlOrCode: "⚠️ | Unable to get command code",
alreadExist: "⚠️ | The command file already exists, are you sure you want to overwrite the old command file?\nReact to this message to continue",
installed: "✅ | Installed command \"%1\" successfully, the command file is saved at %2",
installedError: "❌ | Failed to install command \"%1\" with error\n%2: %3",
missingFile: "⚠️ | Command file \"%1\" not found",
invalidFileName: "⚠️ | Invalid command file name",
unloadedFile: "✅ | Unloaded command \"%1\"",
deletedFile: "✅ | Deleted command file \"%1\" successfully",
deleteError: "❌ | Failed to delete command file \"%1\" with error: %2",
confirmDelete: "⚠️ | Are you sure you want to delete command file \"%1\"?\nReact to this message to confirm"
}
},
ST: async ({ args, message, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, event, commandName, getLang }) => {
const { unloadScripts, loadScripts } = global.utils;
if (
args[0] == "load"
&& args.length == 2
) {
if (!args[1])
return message.reply(getLang("missingFileName"));
const infoLoad = loadScripts("cmds", args[1], log, configCommands, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getLang);
if (infoLoad.status == "success")
message.reply(getLang("loaded", infoLoad.name));
else {
message.reply(
getLang("loadedError", infoLoad.name, infoLoad.error.name, infoLoad.error.message)
+ "\n" + infoLoad.error.stack
);
console.log(infoLoad.errorWithThoutRemoveHomeDir);
}
}
else if (
(args[0] || "").toLowerCase() == "loadall"
|| (args[0] == "load" && args.length > 2)
) {
const fileNeedToLoad = args[0].toLowerCase() == "loadall" ?
fs.readdirSync(__dirname)
.filter(file =>
file.endsWith(".js") &&
!file.match(/(eg)\.js$/g) &&
!configCommands.commandUnload?.includes(file)
)
.map(item => item = item.split(".")[0]) :
args.slice(1);
const arraySucces = [];
const arrayFail = [];
for (const fileName of fileNeedToLoad) {
const infoLoad = loadScripts("cmds", fileName, log, configCommands, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getLang);
if (infoLoad.status == "success")
arraySucces.push(fileName);
else
arrayFail.push(` ❗ ${fileName} => ${infoLoad.error.name}: ${infoLoad.error.message}`);
}
let msg = "";
if (arraySucces.length > 0)
msg += getLang("loadedSuccess", arraySucces.length);
if (arrayFail.length > 0) {
msg += (msg ? "\n" : "") + getLang("loadedFail", arrayFail.length, arrayFail.join("\n"));
msg += "\n" + getLang("openConsoleToSeeError");
}
message.reply(msg);
}
else if (args[0] == "unload") {
if (!args[1])
return message.reply(getLang("missingCommandNameUnload"));
const infoUnload = unloadScripts("cmds", args[1], configCommands, getLang);
infoUnload.status == "success" ?
message.reply(getLang("unloaded", infoUnload.name)) :
message.reply(getLang("unloadedError", infoUnload.name, infoUnload.error.name, infoUnload.error.message));
}
else if (args[0] == "del" || args[0] == "delete") {
if (!args[1])
return message.reply(getLang("missingCommandNameUnload"));
const fileName = args[1].endsWith('.js') ? args[1] : args[1] + '.js';
const filePath = path.join(__dirname, fileName);
if (!fs.existsSync(filePath))
return message.reply(getLang("missingFile", fileName));
// If user provided "confirm" as third argument, delete immediately
if (args[2] && args[2].toLowerCase() === "confirm") {
try {
// First unload the command if it's loaded
try {
const commandNameFromFile = fileName.endsWith('.js') ? fileName.slice(0, -3) : fileName;
unloadScripts("cmds", commandNameFromFile, configCommands, getLang);
} catch (unloadError) {
// Continue with deletion even if unload fails
}
// Then delete the file
if (fs.existsSync(filePath)) {
// GitHub sync before deletion
const githubSync = global.utils.getGitHubSync();
if (githubSync && githubSync.enabled) {
await githubSync.syncFile("delete", filePath);
}
fs.unlinkSync(filePath);
message.reply(getLang("deletedFile", fileName));
} else {
message.reply(getLang("missingFile", fileName));
}
} catch (error) {
message.reply(getLang("deleteError", fileName, error.message));
}
}
// Otherwise, ask for confirmation via reaction or reply
return message.reply(getLang("confirmDelete", fileName) + "\n\n💡 You can also reply 'yes' to confirm or use: " + getPrefix(event.threadID) + "cmd del " + args[1] + " confirm", (err, info) => {
global.GoatBot.onReaction.set(info.messageID, {
commandName,
messageID: info.messageID,
type: "delete",
author: event.senderID,
data: {
fileName: args[1],
filePath
}
});
global.GoatBot.onReply.set(info.messageID, {
commandName: "cmd",
messageID: info.messageID,
type: "delete",
author: event.senderID,
data: {
fileName: args[1],
filePath
}
});
});
}
else if (args[0] == "install") {
let url = args[1];
let fileName = args[2];
let rawCode;
// Check if user is replying to a message with URL
if (event.messageReply && event.messageReply.body) {
const repliedText = event.messageReply.body.trim();
// If replying with a URL and filename is provided in command
if (isURL(repliedText) && args[1] && args[1].endsWith('.js')) {
url = repliedText;
fileName = args[1];
}
}
// If only filename is provided, ask for URL via reply
if (args[1] && !args[2] && args[1].endsWith('.js') && !isURL(args[1]) && !event.messageReply) {
fileName = args[1];
return message.reply(`📥 Please reply to this message with the URL of the command file to install as "${fileName}"`, (err, info) => {
global.GoatBot.onReply.set(info.messageID, {
commandName: "cmd",
messageID: info.messageID,
type: "install_url",
author: event.senderID,
data: {
fileName
}
});
});
}
if (!url || !fileName)
return message.reply(getLang("missingUrlCodeOrFileName"));
if (
url.endsWith(".js")
&& !isURL(url)
) {
const tmp = fileName;
fileName = url;
url = tmp;
}
if (url.match(/(https?:\/\/(?:www\.|(?!www)))/)) {
console.log("install", "url", url);
if (!fileName || !fileName.endsWith(".js"))
return message.reply(getLang("missingFileNameInstall"));
const domain = getDomain(url);
if (!domain)
return message.reply(getLang("invalidUrl"));
if (domain == "pastebin.com") {
const regex = /https:\/\/pastebin\.com\/(?!raw\/)(.*)/;
if (url.match(regex))
url = url.replace(regex, "https://pastebin.com/raw/$1");
if (url.endsWith("/"))
url = url.slice(0, -1);
}
else if (domain == "github.com") {
const regex = /https:\/\/github\.com\/(.*)\/blob\/(.*)/;
if (url.match(regex))
url = url.replace(regex, "https://raw.githubusercontent.com/$1/$2");
}
rawCode = (await axios.get(url)).data;
if (domain == "savetext.net") {
const $ = cheerio.load(rawCode);
rawCode = $("#content").text();
}
}
else {
console.log("install", "code", args.slice(1).join(" "));
if (args[args.length - 1].endsWith(".js")) {
fileName = args[args.length - 1];
rawCode = event.body.slice(event.body.indexOf('install') + 7, event.body.indexOf(fileName) - 1);
}
else if (args[1].endsWith(".js")) {
fileName = args[1];
rawCode = event.body.slice(event.body.indexOf(fileName) + fileName.length + 1);
}
else
return message.reply(getLang("missingFileNameInstall"));
}
if (!rawCode)
return message.reply(getLang("invalidUrlOrCode"));
if (fs.existsSync(path.join(__dirname, fileName)))
return message.reply(getLang("alreadExist"), (err, info) => {
global.GoatBot.onReaction.set(info.messageID, {
commandName,
messageID: info.messageID,
type: "install",
author: event.senderID,
data: {
fileName,
rawCode
}
});
});
else {
const infoLoad = loadScripts("cmds", fileName, log, configCommands, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getLang, rawCode);
if (infoLoad.status == "success") {
const filePath = path.join(__dirname, fileName);
message.reply(getLang("installed", infoLoad.name, filePath.replace(process.cwd(), "")));
// GitHub sync
try {
const githubSync = global.utils.getGitHubSync();
if (githubSync && githubSync.enabled && githubSync.autoCommit) {
await githubSync.syncFile("upload", filePath, rawCode);
}
} catch (syncError) {
console.log("GitHub sync warning:", syncError.message);
}
} else {
message.reply(getLang("installedError", infoLoad.name, infoLoad.error.name, infoLoad.error.message));
}
}
}
else
message.SyntaxError();
},
onReply: async function ({ Reply, message, event, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getLang }) {
const { author, type, data } = Reply;
// Check if the user replying is the same as the author of the original command
if (event.senderID != author) {
return message.reply("❌ Only the original command author can confirm this action");
}
// Check if user is bot admin
const { config } = global.GoatBot;
const userID = event.senderID;
const isAdminBot = config.adminBot.includes(userID.toString()) || config.adminBot.includes(userID);
if (!isAdminBot) {
return message.reply("❌ Only bot's admin can use this command");
}
const userResponse = event.body.trim();
// Handle install via URL reply
if (type == "install_url") {
const { fileName } = data;
const url = userResponse;
// Delete the reply message
Reply.delete();
// Check if response is a valid URL
if (!isURL(url)) {
return message.reply("❌ Invalid URL. Please provide a valid URL to the command file.");
}
try {
let rawCode;
const domain = getDomain(url);
let processedUrl = url;
if (!domain) {
return message.reply(getLang("invalidUrl"));
}
// Process different URL types
if (domain == "pastebin.com") {
const regex = /https:\/\/pastebin\.com\/(?!raw\/)(.*)/;
if (processedUrl.match(regex))
processedUrl = processedUrl.replace(regex, "https://pastebin.com/raw/$1");
if (processedUrl.endsWith("/"))
processedUrl = processedUrl.slice(0, -1);
}
else if (domain == "github.com") {
const regex = /https:\/\/github\.com\/(.*)\/blob\/(.*)/;
if (processedUrl.match(regex))
processedUrl = processedUrl.replace(regex, "https://raw.githubusercontent.com/$1/$2");
}
// Fetch the code
rawCode = (await axios.get(processedUrl)).data;
if (domain == "savetext.net") {
const $ = cheerio.load(rawCode);
rawCode = $("#content").text();
}
if (!rawCode) {
return message.reply(getLang("invalidUrlOrCode"));
}
// Check if file already exists
if (fs.existsSync(path.join(__dirname, fileName))) {
return message.reply(getLang("alreadExist"), (err, info) => {
global.GoatBot.onReaction.set(info.messageID, {
commandName: "cmd",
messageID: info.messageID,
type: "install",
author: event.senderID,
data: {
fileName,
rawCode
}
});
});
}
// Install the command
const { loadScripts } = global.utils;
const { configCommands } = global.GoatBot;
const infoLoad = loadScripts("cmds", fileName, log, configCommands, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getLang, rawCode);
if (infoLoad.status == "success") {
const filePath = path.join(__dirname, fileName);
message.reply(getLang("installed", infoLoad.name, filePath.replace(process.cwd(), "")));
// GitHub sync
try {
const githubSync = global.utils.getGitHubSync();
if (githubSync && githubSync.enabled && githubSync.autoCommit) {
await githubSync.syncFile("upload", filePath, rawCode);
}
} catch (syncError) {
console.log("GitHub sync warning:", syncError.message);
}
} else {
message.reply(getLang("installedError", infoLoad.name, infoLoad.error.name, infoLoad.error.message));
}
} catch (error) {
message.reply(`❌ Failed to install command: ${error.message}`);
}
}
// Handle delete confirmation
else if (type == "delete" && (userResponse.toLowerCase() === "yes" || userResponse.toLowerCase() === "y" || userResponse.toLowerCase() === "confirm")) {
const { unloadScripts } = global.utils;
const { fileName, filePath } = data;
const { configCommands } = global.GoatBot;
// Delete the reply message
Reply.delete();
try {
// First unload the command if it's loaded
try {
const commandNameFromFile = fileName.endsWith('.js') ? fileName.slice(0, -3) : fileName;
unloadScripts("cmds", commandNameFromFile, configCommands, getLang);
} catch (unloadError) {
// Continue with deletion even if unload fails
}
// Then delete the file
if (fs.existsSync(filePath)) {
// GitHub sync before deletion
const githubSync = global.utils.getGitHubSync();
if (githubSync && githubSync.enabled) {
await githubSync.syncFile("delete", filePath);
}
fs.unlinkSync(filePath);
message.reply(getLang("deletedFile", fileName));
} else {
message.reply(getLang("missingFile", fileName));
}
} catch (error) {
message.reply(getLang("deleteError", fileName, error.message));
}
} else if (type == "delete") {
Reply.delete();
message.reply("❌ Deletion cancelled. Please reply with 'yes' or 'confirm' to delete the file.");
}
},
onReaction: async function ({ Reaction, message, event, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getLang }) {
const { loadScripts, unloadScripts } = global.utils;
const { author, type, data } = Reaction;
// Check if user is bot admin first
const { config } = global.GoatBot;
const userID = event.userID;
const isAdminBot = config.adminBot.includes(userID.toString()) || config.adminBot.includes(userID);
if (!isAdminBot) {
return message.reply("❌ Only bot's admin can use the reaction function of the command 'cmd'");
}
// For cmd command, allow any admin to react, not just the author
// This is because cmd is an admin-only command
// Delete the reaction message after processing
Reaction.delete();
if (type == "install") {
const { fileName, rawCode } = data;
const { configCommands } = global.GoatBot;
const infoLoad = loadScripts("cmds", fileName, log, configCommands, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getLang, rawCode);
infoLoad.status == "success" ?
message.reply(getLang("installed", infoLoad.name, path.join(__dirname, fileName).replace(process.cwd(), ""))) :
message.reply(getLang("installedError", infoLoad.name, infoLoad.error.name, infoLoad.error.message));
}
else if (type == "delete") {
const { fileName, filePath } = data;
const { configCommands } = global.GoatBot;
try {
// First unload the command if it's loaded
try {
const commandNameFromFile = fileName.endsWith('.js') ? fileName.slice(0, -3) : fileName;
unloadScripts("cmds", commandNameFromFile, configCommands, getLang);
} catch (unloadError) {
// Continue with deletion even if unload fails
}
// Then delete the file
if (fs.existsSync(filePath)) {
// GitHub sync before deletion
const githubSync = global.utils.getGitHubSync();
if (githubSync && githubSync.enabled) {
await githubSync.syncFile("delete", filePath);
}
fs.unlinkSync(filePath);
message.reply(getLang("deletedFile", fileName));
} else {
message.reply(getLang("missingFile", fileName));
}
} catch (error) {
message.reply(getLang("deleteError", fileName, error.message));
}
}
}
};
// do not edit this code because it use for obfuscate code
const packageAlready = [];
const spinner = "\\|/-";
let count = 0;
function loadScripts(folder, fileName, log, configCommands, api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getLang, rawCode) {
// global.GoatBot[folderModules == "cmds" ? "commandFilesPath" : "eventCommandsFilesPath"].push({
// filePath: pathCommand,
// commandName: [commandName, ...validAliases]
// });
const storageCommandFilesPath = global.GoatBot[folder == "cmds" ? "commandFilesPath" : "eventCommandsFilesPath"];
try {
if (rawCode) {
fileName = fileName.slice(0, -3);
fs.writeFileSync(path.normalize(`${process.cwd()}/scripts/${folder}/${fileName}.js`), rawCode);
}
const regExpCheckPackage = /require(\s+|)\((\s+|)[`'"]([^`'"]+)[`'"](\s+|)\)/g;
const { GoatBot } = global;
const { onFirstChat: allOnFirstChat, onChat: allOnChat, onEvent: allOnEvent, onAnyEvent: allOnAnyEvent } = GoatBot;
let setMap, typeEnvCommand, commandType;
if (folder == "cmds") {
typeEnvCommand = "envCommands";
setMap = "commands";
commandType = "command";
}
else if (folder == "events") {
typeEnvCommand = "envEvents";
setMap = "eventCommands";
commandType = "event command";
}
// const pathCommand = path.normalize(path.normalize(process.cwd() + `/${folder}/${fileName}.js`));
let pathCommand;
pathCommand = path.normalize(process.cwd() + `/scripts/${folder}/${fileName}.js`);
// ————————————————— CHECK PACKAGE ————————————————— //
const contentFile = fs.readFileSync(pathCommand, "utf8");
let allPackage = contentFile.match(regExpCheckPackage);
if (allPackage) {
allPackage = allPackage
.map(p => p.match(/[`'"]([^`'"]+)[`'"]/)[1])
.filter(p => p.indexOf("/") !== 0 && p.indexOf("./") !== 0 && p.indexOf("../") !== 0 && p.indexOf(__dirname) !== 0);
for (let packageName of allPackage) {
// @user/abc => @user/abc
// @user/abc/dist/xyz.js => @user/abc
// @user/abc/dist/xyz => @user/abc
if (packageName.startsWith('@'))
packageName = packageName.split('/').slice(0, 2).join('/');
else
packageName = packageName.split('/')[0];
if (!packageAlready.includes(packageName)) {
packageAlready.push(packageName);
if (!fs.existsSync(`${process.cwd()}/node_modules/${packageName}`)) {
let wating;
try {
wating = setInterval(() => {
count++;
loading.info("PACKAGE", `Installing ${packageName} ${spinner[count % spinner.length]}`);
}, 80);
execSync(`npm install ${packageName} --save`, { stdio: "pipe" });
clearInterval(wating);
process.stderr.clearLine();
}
catch (error) {
clearInterval(wating);
process.stderr.clearLine();
throw new Error(`Can't install package ${packageName}`);
}
}
}
}
}
// ———————————————— GET OLD COMMAND ———————————————— //
const oldCommand = require(pathCommand);
const oldCommandName = oldCommand?.config?.name;
// —————————————— CHECK COMMAND EXIST ——————————————— //
if (!oldCommandName) {
if (GoatBot[setMap].get(oldCommandName)?.location != pathCommand)
throw new Error(`${commandType} name "${oldCommandName}" is already exist in command "${removeHomeDir(GoatBot[setMap].get(oldCommandName)?.location || "")}"`);
}
// ————————————————— CHECK ALIASES ————————————————— //
if (oldCommand.config.aliases) {
let oldAliases = oldCommand.config.aliases;
if (typeof oldAliases == "string")
oldAliases = [oldAliases];
for (const alias of oldAliases)
GoatBot.aliases.delete(alias);
}
// ——————————————— DELETE OLD COMMAND ——————————————— //
delete require.cache[require.resolve(pathCommand)];
// —————————————————————————————————————————————————— //
// ———————————————— GET NEW COMMAND ———————————————— //
const command = require(pathCommand);
command.location = pathCommand;
const configCommand = command.config;
if (!configCommand || typeof configCommand != "object")
throw new Error("config of command must be an object");
// —————————————————— CHECK SYNTAX —————————————————— //
const scriptName = configCommand.name;
// Check onChat function
const indexOnChat = allOnChat.findIndex(item => item == oldCommandName);
if (indexOnChat != -1)
allOnChat.splice(indexOnChat, 1);
// Check onFirstChat function
const indexOnFirstChat = allOnChat.findIndex(item => item == oldCommandName);
let oldOnFirstChat;
if (indexOnFirstChat != -1) {
oldOnFirstChat = allOnFirstChat[indexOnFirstChat];
allOnFirstChat.splice(indexOnFirstChat, 1);
}
// Check onEvent function
const indexOnEvent = allOnEvent.findIndex(item => item == oldCommandName);
if (indexOnEvent != -1)
allOnEvent.splice(indexOnEvent, 1);
// Check onAnyEvent function
const indexOnAnyEvent = allOnAnyEvent.findIndex(item => item == oldCommandName);
if (indexOnAnyEvent != -1)
allOnAnyEvent.splice(indexOnAnyEvent, 1);
// Check onLoad function
if (command.onLoad)
command.onLoad({ api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData });
const { envGlobal, envConfig } = configCommand;
if (!command.onStart && !command.ST)
throw new Error(`onStart or ST function of ${commandType} "${scriptName}" is required`);
if (command.onStart && typeof command.onStart !== "function")
throw new Error(`onStart of ${commandType} "${scriptName}" must be a function`);
if (command.ST && typeof command.ST !== "function")
throw new Error(`ST of ${commandType} "${scriptName}" must be a function`);
if (!scriptName)
throw new Error('Name of command is missing!');
// ————————————————— CHECK ALIASES ————————————————— //
if (configCommand.aliases) {
let { aliases } = configCommand;
if (typeof aliases == "string")
aliases = [aliases];
for (const alias of aliases) {
if (aliases.filter(item => item == alias).length > 1)
throw new Error(`alias "${alias}" duplicate in ${commandType} "${scriptName}" with file name "${removeHomeDir(pathCommand || "")}"`);
if (GoatBot.aliases.has(alias))
throw new Error(`alias "${alias}" is already exist in ${commandType} "${GoatBot.aliases.get(alias)}" with file name "${removeHomeDir(GoatBot[setMap].get(GoatBot.aliases.get(alias))?.location || "")}"`);
GoatBot.aliases.set(alias, scriptName);
}
}
// ————————————————— CHECK ENVCONFIG ————————————————— //
// env Global
if (envGlobal) {
if (typeof envGlobal != "object" || Array.isArray(envGlobal))
throw new Error("envGlobal must be an object");
for (const key in envGlobal)
configCommands.envGlobal[key] = envGlobal[key];
}
// env Config
if (envConfig && typeof envConfig == "object" && !Array.isArray(envConfig)) {
if (!configCommands[typeEnvCommand][scriptName])
configCommands[typeEnvCommand][scriptName] = {};
configCommands[typeEnvCommand][scriptName] = envConfig;
}
GoatBot[setMap].delete(oldCommandName);
GoatBot[setMap].set(scriptName, command);
fs.writeFileSync(client.dirConfigCommands, JSON.stringify(configCommands, null, 2));
const keyUnloadCommand = folder == "cmds" ? "commandUnload" : "commandEventUnload";
const findIndex = (configCommands[keyUnloadCommand] || []).indexOf(`${fileName}.js`);
if (findIndex != -1)
configCommands[keyUnloadCommand].splice(findIndex, 1);
fs.writeFileSync(client.dirConfigCommands, JSON.stringify(configCommands, null, 2));
if (command.onChat)
allOnChat.push(scriptName);
if (command.onFirstChat)
allOnFirstChat.push({ commandName: scriptName, threadIDsChattedFirstTime: oldOnFirstChat?.threadIDsChattedFirstTime || [] });
if (command.onEvent)
allOnEvent.push(scriptName);
if (command.onAnyEvent)
allOnAnyEvent.push(scriptName);
const indexStorageCommandFilesPath = storageCommandFilesPath.findIndex(item => item.filePath == pathCommand);
if (indexStorageCommandFilesPath != -1)
storageCommandFilesPath.splice(indexStorageCommandFilesPath, 1);
storageCommandFilesPath.push({
filePath: pathCommand,
commandName: [scriptName, ...configCommand.aliases || []]
});
return {
status: "success",
name: fileName,
command
};
}
catch (err) {
const defaultError = new Error();
defaultError.name = err.name;
defaultError.message = err.message;
defaultError.stack = err.stack;
err.stack ? err.stack = removeHomeDir(err.stack || "") : "";
fs.writeFileSync(global.client.dirConfigCommands, JSON.stringify(configCommands, null, 2));
return {
status: "failed",
name: fileName,
error: err,
errorWithThoutRemoveHomeDir: defaultError
};
}
}
function unloadScripts(folder, fileName, configCommands, getLang) {
const pathCommand = `${process.cwd()}/scripts/${folder}/${fileName}.js`;
if (!fs.existsSync(pathCommand)) {
const err = new Error(getLang("missingFile", `${fileName}.js`));
err.name = "FileNotFound";
throw err;
}
const command = require(pathCommand);
const commandName = command.config?.name;
if (!commandName)
throw new Error(getLang("invalidFileName", `${fileName}.js`));
const { GoatBot } = global;
const { onChat: allOnChat, onEvent: allOnEvent, onAnyEvent: allOnAnyEvent } = GoatBot;
const indexOnChat = allOnChat.findIndex(item => item == commandName);
if (indexOnChat != -1)
allOnChat.splice(indexOnChat, 1);
const indexOnEvent = allOnEvent.findIndex(item => item == commandName);
if (indexOnEvent != -1)
allOnEvent.splice(indexOnEvent, 1);
const indexOnAnyEvent = allOnAnyEvent.findIndex(item => item == commandName);
if (indexOnAnyEvent != -1)
allOnAnyEvent.splice(indexOnAnyEvent, 1);
// ————————————————— CHECK ALIASES ————————————————— //
if (command.config.aliases) {
let aliases = command.config?.aliases || [];
if (typeof aliases == "string")
aliases = [aliases];
for (const alias of aliases)
GoatBot.aliases.delete(alias);
}
const setMap = folder == "cmds" ? "commands" : "eventCommands";
delete require.cache[require.resolve(pathCommand)];
GoatBot[setMap].delete(commandName);
log.master("UNLOADED", getLang("unloaded", commandName));
const commandUnload = configCommands[folder == "cmds" ? "commandUnload" : "commandEventUnload"] || [];
if (!commandUnload.includes(`${fileName}.js`))
commandUnload.push(`${fileName}.js`);
configCommands[folder == "cmds" ? "commandUnload" : "commandEventUnload"] = commandUnload;
fs.writeFileSync(global.client.dirConfigCommands, JSON.stringify(configCommands, null, 2));
return {
status: "success",
name: fileName
};
}
global.utils.loadScripts = loadScripts;
global.utils.unloadScripts = unloadScripts;