276 lines
9.7 KiB
TypeScript
276 lines
9.7 KiB
TypeScript
// Modul dedikovaný funkci spinkáček
|
|
|
|
import { ChannelType, Message, Role, TextBasedChannel, User } from "discord.js";
|
|
import fetch from "node-fetch";
|
|
import { emouty } from "../utils/emotes";
|
|
import { Modul, Spinkackar, SRecord } from "../utils/types";
|
|
import { formatCas, formatter, log, oddiakritikovat, ping, sendDM } from "../utils/utils";
|
|
|
|
let spinkacky: SRecord<Spinkackar>;
|
|
const budouciSpinky: SRecord<NodeJS.Timeout> = {};
|
|
const autoSpinky: SRecord<[boolean, TextBasedChannel]> = {};
|
|
|
|
const contactSpinkServer = async (akce: string, id: string, nick: string = "", avatar: string | null = "") => {
|
|
const options = `heslo=${process.env.spinkPass}&akce=${akce}&id=${id}&nick=${encodeURIComponent(nick)}&avatar=${encodeURIComponent(avatar ?? "")}`;
|
|
return fetch(`https://spinkacek.deadfish.cz/extapi.php?${options}`)
|
|
.then(r => r.text());
|
|
};
|
|
|
|
const syncSpink = () => {
|
|
fetch("https://spinkacek.deadfish.cz/api/spinkacky")
|
|
.then(r => r.json() as Promise<{ spinkacky: SRecord<Spinkackar>; }>)
|
|
.then(d => {
|
|
const data = d.spinkacky;
|
|
const keys = Object.keys(data);
|
|
const values = Object.values(data);
|
|
spinkacky = {};
|
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const k = keys[i];
|
|
if (k[0] != "d") continue;
|
|
const vstav = values[i].timeup;
|
|
spinkacky[k.slice(8)] = { spinkacek: values[i].spinkacek, timeup: vstav === false ? false : vstav * 1000 };
|
|
}
|
|
});
|
|
};
|
|
|
|
if (!process.env.ignoreSpink)
|
|
syncSpink();
|
|
|
|
const handleSpink = async (act: "spinkacek" | "vstavacek", user: User) => {
|
|
const ok = act == "spinkacek"
|
|
? await contactSpinkServer(act, user.id, user.username, user.avatarURL())
|
|
: await contactSpinkServer(act, user.id);
|
|
return ok.startsWith("OK") ? ok : false;
|
|
};
|
|
|
|
const ifUzRemove = (m: Message) => {
|
|
const id = m.author.id;
|
|
const uzPgn = budouciSpinky[id];
|
|
if (uzPgn) {
|
|
clearTimeout(uzPgn);
|
|
delete budouciSpinky[id];
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
const tovjemamvolepreceroliky = async (roliky: User, rictCas?: boolean) => {
|
|
const odpoved = await handleSpink("vstavacek", roliky);
|
|
if (!odpoved) return "uz jsi vzhuru ty hajzle";
|
|
const cas = Number(odpoved.slice(3));
|
|
const formatedCas = formatCas(cas);
|
|
|
|
const zacatek = `dobry rano hajzle ${roliky}`;
|
|
if (!rictCas) return zacatek;
|
|
|
|
let zpr = "";
|
|
if (cas >= 57600) zpr = "mas dat more vstavacek uz kdyz vstanes retarde";
|
|
else if (cas >= 43200) zpr = "extrémní bídák";
|
|
else if (cas >= 36000) zpr = "fakt bídák";
|
|
else if (cas < 30) zpr = "dobrej mikrospánek debile";
|
|
else if (cas < 10800) zpr = "dobrej fake spink debile";
|
|
|
|
return `${zacatek}\nspal sy ${formatedCas}\n${zpr}`;
|
|
};
|
|
|
|
function hmsToCislo(reg: RegExpExecArray | null) {
|
|
if (!reg || reg.input == "") return NaN;
|
|
const g = reg.groups!;
|
|
return (Number(g.h) * 3600 || 0) + (Number(g.m) * 60 || 0) + (Number(g.s) || 0);
|
|
}
|
|
|
|
const exp: Modul = {
|
|
more_komandy: {
|
|
|
|
spinkacek: {
|
|
als: ["spink", "spoink", "spinkake", "spoinkacek", "gn", emouty.spinkacek, emouty.gn],
|
|
run: async mes => {
|
|
if (mes.author.bot) return `až někdy${emouty.kapp}`;
|
|
if (await handleSpink("spinkacek", mes.author)) {
|
|
mes.react(emouty.spinkacek);
|
|
ifUzRemove(mes);
|
|
}
|
|
else return 'nespis uz?????';
|
|
}
|
|
},
|
|
|
|
vstavacek: {
|
|
als: ["vstavcacek", "gm", "unspinkacek"],
|
|
run: async (mes, arg) => {
|
|
if (mes.author.bot) return emouty.sjeta;
|
|
|
|
return tovjemamvolepreceroliky(mes.author, arg.toLowerCase() == "fejk");
|
|
}
|
|
},
|
|
|
|
pgn: {
|
|
als: [`p${emouty.gn}`],
|
|
run: (mes, kdy) => {
|
|
if (mes.author.bot) return emouty.sjeta;
|
|
|
|
const ted = new Date();
|
|
const tedT = Number(ted);
|
|
const spink = new Date();
|
|
let random = false;
|
|
|
|
if (kdy.startsWith("random")) {
|
|
random = true;
|
|
let rozdil = 540;
|
|
let min = 60;
|
|
if (kdy.length > 7) {
|
|
const t = kdy.slice(7).replace(/ /g, "").split("-");
|
|
if (t.length != 2) return "cos to napsal kkte";
|
|
const regex = /^(?:(?<h>\d+)h)?(?:(?<m>\d+)m)?(?:(?<s>\d+)s?)?$/;
|
|
const [from, to] = [regex.exec(t[0]), regex.exec(t[1])].map(v => hmsToCislo(v));
|
|
if (Number.isNaN(from) || Number.isNaN(to)) return "cislo musy bit v formate xh xm xs";
|
|
if (to <= from) return "ja teda nevim jestli ti vys jak funguje cas ael vym ze tam mas chibu";
|
|
|
|
rozdil = to - from;
|
|
min = from;
|
|
}
|
|
spink.setTime(tedT + (Math.random() * rozdil + min) * 1000);
|
|
log(`random spink pro ${oddiakritikovat(mes.member?.displayName || "neznamejmeno")} byl nastaven na ${formatter(spink)}`);
|
|
} else if (/^\d+$/.test(kdy) || !kdy)
|
|
spink.setTime(tedT + Number(kdy || 7200) * 1000);
|
|
else {
|
|
const cojavim = /^((?<d>\d+)\. ?((?<mo>\d+)\.)? ?)?(?<h>\d+)(:(?<m>\d+)(:(?<s>\d+))?)? ?(?<p>am|pm)?$/.exec(kdy.toLowerCase());
|
|
if (!cojavim) return `cos to tam napsal ty kokote?`;
|
|
|
|
const g = cojavim.groups!;
|
|
if (g.d) spink.setDate(Number(g.d));
|
|
if (g.mo) spink.setMonth(Number(g.mo) - 1);
|
|
const h = Number(g.h);
|
|
spink.setHours(g.p == "pm" && h < 12 ? h + 12 : h);
|
|
spink.setMinutes(Number(g.m) || 0);
|
|
spink.setSeconds(Number(g.s) || 0);
|
|
if (Number(spink) < tedT) spink.setDate(ted.getDate() + 1);
|
|
}
|
|
|
|
ifUzRemove(mes);
|
|
|
|
budouciSpinky[mes.author.id] = setTimeout(() => {
|
|
handleSpink("spinkacek", mes.author);
|
|
mes.react(emouty.spinkacek);
|
|
}, Number(spink) - tedT);
|
|
if (!random) return `tvuj spinkacek byl naplanovan na ${formatter(spink)}`;
|
|
mes.react(emouty.lajk);
|
|
}
|
|
},
|
|
|
|
ps: {
|
|
als: ["poslednispink"],
|
|
arg: "kdo (nepovinné)",
|
|
run: (mes, arg) => {
|
|
const f = arg != "";
|
|
if (!ping.test(arg) && f) return "sikkt";
|
|
const id = f ? mes.mentions.members?.first()?.id : mes.author.id;
|
|
const tajmUp = spinkacky[id ?? ""]?.timeup;
|
|
if (tajmUp == undefined) return `tuten kkt jeste nespal ${emouty.lukiw}`;
|
|
if (!tajmUp) return "ten kkt jiz ickon spi";
|
|
const cas = Number(new Date()) - Number(new Date(tajmUp));
|
|
return `uz ${f ? "je" : "jsi"} vzhuru ${formatCas(cas / 1000)}`;
|
|
}
|
|
},
|
|
|
|
zruspgn: {
|
|
als: ["zpgn", "cancelpgn", "cpgn", "unpgn", `unp${emouty.gn}`],
|
|
run: mes => {
|
|
if (!ifUzRemove(mes)) return `spinkacek ale nemas naplanovanej ty kkte ${mes.author}`;
|
|
return "to bylo teda trapny debile";
|
|
}
|
|
},
|
|
|
|
autospink: mes =>
|
|
`autospink je ${autoSpinky[mes.author.id] ? (delete autoSpinky[mes.author.id], "vypnut") : (autoSpinky[mes.author.id] = [true, mes.channel], "zapnut")}`,
|
|
|
|
autoautospink: {
|
|
als: ["🚗🚗spink"],
|
|
run: mes =>
|
|
`autoautospink je ${autoSpinky[mes.author.id] ? (delete autoSpinky[mes.author.id], "vypnut") : (autoSpinky[mes.author.id] = [false, mes.channel], "zapnut")}`
|
|
}
|
|
},
|
|
|
|
on_voiceStateUpdate: (bef, aft) => {
|
|
if (!aft.channel || bef.channel) return;
|
|
if (spinkacky[aft.id]?.spinkacek) aft.disconnect("spinkacek")
|
|
.catch(err => log("spinkacek odpojit se nepovedlo nebo co:", err));
|
|
},
|
|
|
|
super_on_messageCreate: (mes, cmd?: string) => {
|
|
if (mes.author.id === '831318260493844494') {
|
|
syncSpink();
|
|
const uzivatel = mes.content.match(/(?<=discord_)\d+/)?.[0];
|
|
if (!uzivatel) return false;
|
|
for (const [, guild] of mes.client.guilds.cache) {
|
|
const member = guild.members.cache.get(uzivatel);
|
|
if (!member) continue;
|
|
|
|
const c = guild.roles.cache;
|
|
const spinkRole = c.find(r => r.name == "spink");
|
|
const adminRole = c.find(r => r.name == "admin");
|
|
|
|
const make = (akce: "a" | "r", role: Role) => {
|
|
const handle = (e: Error) => {
|
|
if (["Missing Permissions", "Missing Access"].includes(e.message)) return;
|
|
log("chyba pri davani/odebirani role", e);
|
|
};
|
|
if (akce == "a") member.roles.add(role).catch(handle);
|
|
else member.roles.remove(role).catch(handle);
|
|
};
|
|
|
|
if (mes.content[0] == "s") {
|
|
if (spinkRole) make("a", spinkRole);
|
|
if (adminRole) make("r", adminRole);
|
|
} else {
|
|
if (spinkRole) make("r", spinkRole);
|
|
if (adminRole) make("a", adminRole);
|
|
continue;
|
|
}
|
|
for (const [, channel] of guild.channels.cache) {
|
|
if (channel.type != ChannelType.GuildVoice) continue;
|
|
for (const [, member] of channel.members) {
|
|
if (member.id !== uzivatel) continue;
|
|
member.voice.disconnect("spinkacek");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
} else if (spinkacky[mes.author.id]?.spinkacek && cmd != "vstavacek") {
|
|
if (mes.channel.type == ChannelType.DM) {
|
|
mes.channel.send("drz hubu");
|
|
return true;
|
|
}
|
|
|
|
mes.delete().catch((e: Error) => {
|
|
if (e.name == "DiscordAPIError[5OO13]") return;
|
|
log("chyba pri mazani", e);
|
|
});
|
|
sendDM(mes.author, "spis tak nepis");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
// autoSpink handeler
|
|
on_userPresenceUpdate: async (bef, aft) => {
|
|
if (!bef) return;
|
|
const befoff = bef.status == "offline";
|
|
const aftoff = aft.status == "offline";
|
|
const prop = autoSpinky[aft.userId];
|
|
if (!prop) return;
|
|
if (!befoff && aftoff) {
|
|
handleSpink("spinkacek", aft.member!.user);
|
|
}
|
|
if (befoff && !aftoff) {
|
|
if (prop[0]) delete autoSpinky[aft.userId];
|
|
const kanel = prop[1];
|
|
if (kanel?.type == ChannelType.GuildText) kanel.send(await tovjemamvolepreceroliky(aft.member!.user));
|
|
}
|
|
}
|
|
};
|
|
|
|
if (!process.env.ignoreSpink)
|
|
module.exports = exp;
|