200 lines
7.0 KiB
TypeScript
200 lines
7.0 KiB
TypeScript
import { APIEmbed, ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, CacheType, ChannelType, Client, ComponentType, MessageCreateOptions, ReadonlyCollection, TextBasedChannel, User } from "discord.js";
|
|
import { existsSync } from "fs";
|
|
import { MysqlError, createPool } from "mysql";
|
|
|
|
if (!existsSync("config.json")) throw new Error("config.json neexistuje");
|
|
const konfig = require("../../config.json");
|
|
if (!konfig.ignoreUnknownKeys)
|
|
for (const klic of Object.keys(konfig)) {
|
|
if (!["adminChannel", "adminID", "DBPwd", "DBUser", "dieOnError", "ignoreMess", "ignorePresence", "ignoreSpink", "ignoreUnknownKeys", "noGeneralSync", "prefix", "sachyDomena", "statPass", "token"].includes(klic)) throw new Error(`config.json obsahuje neznámý klíč: ${klic}`);
|
|
}
|
|
process.env = { ...process.env, ...konfig };
|
|
|
|
export const oddiakritikovat = (a: string) => {
|
|
return a
|
|
.replace(/[àáâãäåæāăą]/g, "a")
|
|
.replace(/[çćĉċč]/g, "c")
|
|
.replace(/[ďđ]/g, "d")
|
|
.replace(/[èéêëðēĕėęě]/g, "e")
|
|
.replace(/[ĝğġģǵ]/g, "g")
|
|
.replace(/[ĥħ]/g, "h")
|
|
.replace(/[ìíîïĩīĭįı]/g, "i")
|
|
.replace(/[ĵ]/g, "j")
|
|
.replace(/[ķĸ]/g, "k")
|
|
.replace(/[ĺļľŀł]/g, "l")
|
|
.replace(/[ñńņňʼnŋ]/g, "n")
|
|
.replace(/[òóôõöøōŏőœ]/g, "o")
|
|
.replace(/[þ]/g, "p")
|
|
.replace(/[ŕŗř]/g, "r")
|
|
.replace(/[ßśŝşšſ]/g, "s")
|
|
.replace(/[ţťŧ]/g, "t")
|
|
.replace(/[ùúûüũūŭůűų]/g, "u")
|
|
.replace(/[ŵ]/g, "w")
|
|
.replace(/[ÿýŷ]/g, "y")
|
|
.replace(/[źżž]/g, "z")
|
|
.replace(/[ÀÁÂÃÄÅÆĀĂĄ]/g, "A")
|
|
.replace(/[ÇĆĈĊČ]/g, "C")
|
|
.replace(/[Ď]/g, "D")
|
|
.replace(/[ÈÉÊËÐĒĔĖĘĚ]/g, "E")
|
|
.replace(/[ĜĞĠĢ]/g, "G")
|
|
.replace(/[Ĵ]/g, "J")
|
|
.replace(/[Ķ]/g, "K")
|
|
.replace(/[ĤĦ]/g, "H")
|
|
.replace(/[ÌÍÎÏĨĪĬĮİ]/g, "I")
|
|
.replace(/[ĹĻĽĿŁ]/g, "L")
|
|
.replace(/[ÑŃŅŇŊ]/g, "N")
|
|
.replace(/[ÒÓÔÕÖØŌŎŐŒ]/g, "O")
|
|
.replace(/[Þ]/g, "P")
|
|
.replace(/[ŔŖŘ]/g, "R")
|
|
.replace(/[ŚŜŞŠ]/g, "S")
|
|
.replace(/[ŢŤŦ]/g, "T")
|
|
.replace(/[ÙÚÛÜŨŪŬŮŰŲ]/g, "U")
|
|
.replace(/[Ŵ]/g, "W")
|
|
.replace(/[ÝŶŸ]/g, "Y")
|
|
.replace(/[ŹŻŽ]/g, "Z");
|
|
};
|
|
|
|
/**
|
|
* returns relative time in format `x hodin x minut a x se kund`
|
|
* @param cas Number of seconds to convert
|
|
*/
|
|
export const formatCas = (cas: number) => {
|
|
const h = Math.floor(cas / 3600);
|
|
const m = Math.floor(cas % 3600 / 60);
|
|
const s = Math.floor(cas % 3600 % 60);
|
|
|
|
return `${h} hodin ${m} mynut a ${s} se kund`;
|
|
};
|
|
|
|
/**
|
|
* Returns absolute date in format `d. m. h:mm:ss`
|
|
* @param date Date object to convert
|
|
*/
|
|
export const formatter = new Intl.DateTimeFormat("cs", { day: "numeric", month: "short", hour: "numeric", minute: "numeric", second: "numeric" }).format;
|
|
|
|
export const ping = /^<@!?\d+>$/;
|
|
|
|
export function adminLog(client: Client, text: string, err?: string | Error) {
|
|
if (process.env.adminChannel) {
|
|
const adminChannel = client.channels.cache.get(process.env.adminChannel);
|
|
if (adminChannel?.type == ChannelType.GuildText)
|
|
adminChannel.send(err ? `${text}\n\`\`\`${err}\`\`\`` : text);
|
|
}
|
|
if (process.env.adminID) {
|
|
const user = client.users.cache.get(process.env.adminID);
|
|
if (user) sendDM(user, err ? `${text}\n\`\`\`${err}\`\`\`` : text);
|
|
}
|
|
}
|
|
|
|
export function log(...content: unknown[]) {
|
|
const jo = content.map(h => {
|
|
if (h instanceof Error) return `\x1b[31m${h.stack || h}\x1b[0m`;
|
|
return h;
|
|
});
|
|
|
|
const d = new Date();
|
|
console.log(`[${d.getDate()}.${d.getMonth() + 1}. ${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}]:`, ...jo);
|
|
}
|
|
|
|
export async function sendDM(user: User, txt: string) {
|
|
user.send(txt).catch(() => log(new Error(`dementovi ${user} nejde poslat DM`)));
|
|
}
|
|
|
|
export const rand = (max: number) => Math.floor(Math.random() * max);
|
|
|
|
export const prefix = process.env.prefix || "more";
|
|
|
|
type Nastaveni = {
|
|
nabidka: (string | (({ val: string; } | { emoji: string; }) & { disabled?: boolean; }))[];
|
|
channel: TextBasedChannel;
|
|
zpravec: MessageCreateOptions;
|
|
onCollect: (i: ButtonInteraction, id: number, radek: ActionRowBuilder<ButtonBuilder>) => void;
|
|
timeout?: number;
|
|
} & ({
|
|
onEnd: (c: ReadonlyCollection<string, ButtonInteraction<CacheType>>) => void;
|
|
} | {
|
|
konecnaZprava: string;
|
|
stejne?: boolean;
|
|
});
|
|
|
|
export async function nabidni(nastaveni: Nastaveni) {
|
|
const radek = new ActionRowBuilder<ButtonBuilder>();
|
|
nastaveni.nabidka.forEach((moznost, i) => {
|
|
const component = new ButtonBuilder({ customId: `${i}`, style: ButtonStyle.Primary });
|
|
|
|
const ejtoString = typeof moznost == "string";
|
|
|
|
if (ejtoString || "val" in moznost) {
|
|
const value = ejtoString ? moznost : moznost.val;
|
|
const nazev = value.length > 80 ? `${value.slice(0, 77)}...` : value;
|
|
component.setLabel(nazev);
|
|
} else {
|
|
component.setEmoji(moznost.emoji);
|
|
}
|
|
if (!ejtoString && moznost.disabled) component.setDisabled();
|
|
radek.addComponents(component);
|
|
});
|
|
|
|
const zprava = await nastaveni.channel.send({ ...nastaveni.zpravec, components: [radek] });
|
|
const collector = nastaveni.channel.createMessageComponentCollector<ComponentType.Button>({ filter: i => i.message.id == zprava.id, time: nastaveni.timeout ?? 18e4 });
|
|
|
|
collector.on("collect", i => {
|
|
const lookupId = Number(i.customId);
|
|
if (isNaN(lookupId)) return void nastaveni.channel.send("neco nefunguje idk");
|
|
|
|
nastaveni.onCollect(i, lookupId, radek);
|
|
});
|
|
|
|
collector.on("end", c => {
|
|
if ("onEnd" in nastaveni)
|
|
nastaveni.onEnd(c);
|
|
else if (!c.size || nastaveni.stejne) {
|
|
radek.components.forEach(btn => btn.setDisabled());
|
|
zprava.edit({ content: nastaveni.konecnaZprava, components: [radek] });
|
|
}
|
|
});
|
|
}
|
|
|
|
export const strankovani = (channel: TextBasedChannel, embed: APIEmbed, zacatekNazvu: string, stranky: string[][]) => {
|
|
let aktualniStranka = 0;
|
|
nabidni({
|
|
channel: channel,
|
|
nabidka: [{ emoji: "⬅️", disabled: true }, { emoji: "➡️" }],
|
|
zpravec: { embeds: [embed] },
|
|
onCollect: (i, id, radek) => {
|
|
// Výpočet nový stánky
|
|
aktualniStranka += (!id) ? -1 : 1;
|
|
|
|
// Úprava aktivnosti tlačítek
|
|
radek.components[0].setDisabled(!aktualniStranka);
|
|
radek.components[1].setDisabled(aktualniStranka + 1 == stranky.length);
|
|
|
|
// Úprava embedu
|
|
embed.fields![0] = {
|
|
name: `${zacatekNazvu} (${aktualniStranka + 1}/${stranky.length})`,
|
|
value: `• ${stranky[aktualniStranka].join("\n• ")}`
|
|
};
|
|
|
|
// Odeslání
|
|
i.update({ embeds: [embed], components: [radek] });
|
|
},
|
|
konecnaZprava: "",
|
|
stejne: true
|
|
});
|
|
};
|
|
|
|
// Připojení do databáze
|
|
export const bazenek = createPool({
|
|
host: "127.0.0.1",
|
|
user: process.env.DBUser,
|
|
password: process.env.DBPwd,
|
|
database: "denim",
|
|
charset: "utf8mb4_unicode_ci"
|
|
});
|
|
|
|
export const safeQuery = <T>(query: string, parametry?: string[]) => new Promise<{ data: T[]; err: MysqlError | null; }>(res => {
|
|
bazenek.query({ sql: query, values: parametry }, (err, odpoved) => {
|
|
res({ data: odpoved, err });
|
|
});
|
|
});
|