import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, Client, ComponentType, GatewayIntentBits, Message, Partials } from "discord.js"; import { readdirSync } from "fs"; import { CUser, EventSOn, KomandNaExport, Komand, ListenerFunkce, Modul, SRecord, SuperListenerFunkce, RunFunkce, CClient, HelpServer } from "./utils/types"; import { adminLog, formatCas, oddiakritikovat, log } from "./utils/utils.js"; import levenshtein from "js-levenshtein"; import { emouty } from "./utils/emotes"; import { existsSync } from "fs"; if (!existsSync("config.json")) throw new Error("config.json neexistuje"); process.env = { ...process.env, ...require("../config.json") }; const ints = GatewayIntentBits; const client = new Client({ partials: [Partials.Channel], intents: [ints.Guilds, ints.GuildVoiceStates, ints.GuildPresences, ints.GuildMessages, ints.DirectMessages, ints.MessageContent] }) as CClient; const prefix = process.env.prefix || "more"; const modulFolder = `${__dirname}/modules/`; const eventy: SRecord = {}; const superEventy: SRecord = {}; const kuldan_log: SRecord> = {}; const komandyNaPoslani: KomandNaExport[] = []; const helpServer: HelpServer = require("./utils/helpServer"); client.komandy = {}; client.aliasy = {}; function getFirstArg(fn: RunFunkce | string) { if (typeof fn != "function") return; return fn.toString() .match(/(?:function\s.*?)?\(([^)]*)\)|\w+ =>/)![1] ?.split(",")[1] ?.trim(); } const runEvent = (name: string, args: unknown[]) => { for (const listener of superEventy[name] || []) { if (!listener) continue; // [after] pozice v superEventy arrayi se dají nastavovat a teoreticky může nastat mezera try { if (listener(...args)) return true; // if listener returns true, it means, we shouldn't continue with execustion } catch (e) { if (process.env.dieOnError) throw e; log("error pri spusteni super listeneru", e as Error); adminLog(client, "error pri supereventu"); } } eventy[name]?.forEach(listener => { try { listener(...args); } catch (e) { if (process.env.dieOnError) throw e; log("error pri spousteni eventu", e as Error); adminLog(client, "error pri eventu"); } }); }; // Loading of modules readdirSync(modulFolder).forEach(soubor => { if (!soubor.endsWith(".js")) return; const modul: Modul = require(`${modulFolder}${soubor}`); log(`Loaded: ${modulFolder}${soubor}`); modul.client = client; Object.keys(modul).forEach(name => { const prefix = /^(?super_)?on_(?.+)/.exec(name); if (prefix) { const groups = prefix.groups!; const ev = groups.s ? superEventy : eventy; if (!ev[groups.h]) { ev[groups.h] = []; if (!["messageCreate", "userPresenceUpdate"].includes(groups.h)) client.on(groups.h, (...args) => void runEvent(groups.h, args)); } const n = modul[name as EventSOn]!; if (typeof n == "object") { const prev = ev[groups.h][n.pos]; ev[groups.h][n.pos] = n.fun; if (prev) ev[groups.h].push(prev); } else ev[groups.h].push(n); } else if (name === "more_komandy") { const n = modul[name]!; Object.keys(n).forEach(cmdName => { const value = n[cmdName]; const toCoExportuju: KomandNaExport = { name: cmdName }; let hide = false; if (typeof value !== "object") { client.komandy[cmdName] = { run: value }; toCoExportuju.arg = getFirstArg(value); } else { client.komandy[cmdName] = { run: value.run, cd: value.cd, DMUnsafe: value.DMUnsafe }; Object.assign(toCoExportuju, { als: value.als, arg: value.arg ?? getFirstArg(value.run) }); hide = !!value.hidden; value.als?.forEach(al => client.aliasy[al] = cmdName); } if (!hide) komandyNaPoslani.push(toCoExportuju); }); } }); }); helpServer.komandy = komandyNaPoslani; const maKuldan = (id: string, komand: string, kuldan_komandu: number) => { if (!kuldan_log[komand]) kuldan_log[komand] = {}; const cas_ted = Date.now() / 1000; const rozdil = cas_ted - kuldan_log[komand][id]; if (rozdil < kuldan_komandu) return kuldan_komandu - rozdil; kuldan_log[komand][id] = cas_ted; return 0; }; async function runKomand(mes: Message, cmd: Komand, cmdName: string, arg: string) { if (cmd.cd) { const zbyva = Math.round(maKuldan(mes.author.id, cmdName, cmd.cd)); if (zbyva) return void mes.channel.send(`si kkt vole maz kuldan jeste ${formatCas(zbyva)}`); } const akce = cmd.run; if (typeof akce == "string") return void mes.channel.send(akce); try { const result = await akce(mes, arg); if (result) mes.channel.send(result); } catch (e) { if (process.env.dieOnError) throw e; log("error pri spousteni akce", e as Error); const admin = process.env.adminID; mes.channel.send(`pri spousteni thohoto komandu nastala chyba ${admin ? `<@${admin}> uz?` : ""}`); } } client.on("messageCreate", async mes => { if (process.env.ignoreMess) return; const [mesPrefix, komandSDiakritikou, ...args] = mes.content.split(" "); if (oddiakritikovat(mesPrefix.toLowerCase()) != prefix) return void runEvent("messageCreate", [mes]); if (!komandSDiakritikou) { if (!runEvent("messageCreate", [mes])) mes.channel.send("coe voe"); return; } const celArgs = args.join(" "); const komandBez = oddiakritikovat(komandSDiakritikou).toLowerCase(); const cmdName = client.aliasy[komandBez] ?? komandBez; if (runEvent("messageCreate", [mes, cmdName])) return; const komand = client.komandy[cmdName]; if (mes.channel.type == ChannelType.DM && komand?.DMUnsafe) return void mes.channel.send("tuten komand bohuzel v sz nefunkuje"); if (komand) return void runKomand(mes, komand, cmdName, celArgs); // neměl jsi na mysli? const slova: string[] = []; [...Object.keys(client.komandy), ...Object.keys(client.aliasy)].forEach(cmd => { const distance = levenshtein(cmd, cmdName); if (distance <= Math.ceil(cmdName.length * 0.3)) slova.push(cmd); }); if (!slova.length) return void mes.channel.send("co to znamena ti gadzovko"); const nabidka = slova.sort().slice(0, 5); const radek = new ActionRowBuilder(); nabidka.forEach((cmd, i) => { const nazev = cmd.length > 80 ? `${cmd.slice(0, 77)}...` : cmd; radek.addComponents(new ButtonBuilder({ customId: `${i}`, label: nazev, style: ButtonStyle.Primary })); }); const zprava = await mes.channel.send({ content: "nemnel sy na misli:", components: [radek] }); const collector = mes.channel.createMessageComponentCollector({ filter: i => i.message.id == zprava.id && mes.author.id == i.user.id, time: 18e4 }); collector.on("collect", i => { const lookupId = Number(i.customId); if (isNaN(lookupId)) return void mes.channel.send("neco nefunguje idk"); const komand = nabidka[lookupId]; const cmdName = client.aliasy[komand] ?? komand; const cmd = client.komandy[cmdName]; radek.components.forEach(btn => btn.setDisabled()); i.update({ content: `ok vole ${emouty.d3k}`, components: [radek] }); runKomand(mes, cmd, cmdName, celArgs); }); collector.on("end", c => { if (c.size) return; radek.components.forEach(btn => btn.setDisabled()); zprava.edit({ content: "pozde", components: [radek] }); }); }); // Simulation of userPresenceUpdate event client.on("presenceUpdate", (bef, aft) => { const user = aft.user as CUser | null; if (!user) return; if (!user.presence) user.presence = {}; if (JSON.stringify(aft.clientStatus) == JSON.stringify(user.presence)) return; user.presence = aft.clientStatus || {}; runEvent("userPresenceUpdate", [bef, aft]); }); client.login(process.env.token);