204 lines
7.7 KiB
TypeScript
204 lines
7.7 KiB
TypeScript
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<ListenerFunkce[]> = {};
|
|
const superEventy: SRecord<SuperListenerFunkce[]> = {};
|
|
const kuldan_log: SRecord<SRecord<number>> = {};
|
|
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 = /^(?<s>super_)?on_(?<h>.+)/.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<ButtonBuilder>();
|
|
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<ComponentType.Button>({ 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);
|