tak teď to je dokonalý. Už to nemůže bejt lepší

clueless
This commit is contained in:
Histmy 2023-07-27 14:11:50 +02:00
parent 88a82655af
commit f216d445dd
5 changed files with 104 additions and 81 deletions

View File

@ -1,38 +1,37 @@
// Tady bude muzika, vole // Tady bude muzika, vole
import { AudioPlayerStatus, getVoiceConnection } from "@discordjs/voice"; import { AudioPlayerStatus, VoiceConnectionStatus } from "@discordjs/voice";
import { Client, VoiceBasedChannel } from "discord.js"; import { Client } from "discord.js";
import { search, soundcloud, stream, validate, video_basic_info } from "play-dl"; import { search, soundcloud, stream, validate, video_basic_info } from "play-dl";
import { emouty } from "../utils/emotes"; import { emouty } from "../utils/emotes";
import { Modul, SRecord } from "../utils/types"; import { Modul } from "../utils/types";
import { adminLog, log } from "../utils/utils"; import { adminLog, log } from "../utils/utils";
import { novejPlay, Priority, stopPlayer } from "../utils/voice"; import { getConn, novejJoin, novejPlay, Priority, stopPlayer } from "../utils/voice";
const kjus: SRecord<{ name: string; url: string; }[]> = {}; const guildy = new Map<string, { kju: { name: string; url: string; }[]; loop: boolean; }>();
async function playNext(channel: VoiceBasedChannel, seek?: number) { async function playNext(guildId: string, seek?: number) {
try { try {
const kju = kjus[channel.guildId]!; const guilda = guildy.get(guildId)!;
const kju = guilda.kju;
const item = kju[0]; const item = kju[0];
const src = await stream(item.url, { seek }); const src = await stream(item.url, { seek });
novejPlay(channel, { src: src.stream, volume: 1, type: src.type }, Priority.Music) novejPlay(guildId, { src: src.stream, volume: 1, type: src.type }, Priority.Music)
.then(state => { .then(state => {
if (state.status != AudioPlayerStatus.Idle) return; if (state.status != AudioPlayerStatus.Idle) return;
kju.shift(); if (!guilda.loop) kju.shift();
if (kju.length) if (kju.length)
return playNext(channel); return playNext(guildId);
delete kjus[channel.guildId];
}) })
.catch(e => { .catch(e => {
log("chyba v muziki", e); log("chyba v muziki", e);
}); });
} catch (e) { } catch (e) {
if (e instanceof Error && e.message.startsWith("Seeking beyond limit")) if (e instanceof Error && e.message.startsWith("Seeking beyond limit"))
return stopPlayer(channel.guildId, Priority.Music); return stopPlayer(guildId, Priority.Music);
log(e); log(e);
const client: Client = module.exports.client; const client: Client = module.exports.client;
@ -45,9 +44,10 @@ const exp: Modul = {
zahraj: { zahraj: {
DMUnsafe: true, DMUnsafe: true,
run: async (mes, txt) => { run: async (mes, txt) => {
const kanel = mes.member?.voice.channel; const kanel = mes.member?.voice.channelId;
if (!kanel) return "nejsi ve vojsu ty kkt"; if (!kanel) return "nejsi ve vojsu ty kkt";
const guildId = mes.guildId!;
const ajtem = { name: "", url: "" }; const ajtem = { name: "", url: "" };
const druh = await validate(txt); const druh = await validate(txt);
if (druh && druh != "search") { if (druh && druh != "search") {
@ -79,12 +79,19 @@ const exp: Modul = {
msg.then(m => void m.edit(`zahraju \`${ajtem.name}\``)); msg.then(m => void m.edit(`zahraju \`${ajtem.name}\``));
} }
const kju = (kjus[mes.guildId!] ??= []); if (!guildy.has(guildId)) {
guildy.set(guildId, { kju: [], loop: false });
}
const kju = guildy.get(guildId)!.kju;
kju.push(ajtem); kju.push(ajtem);
if (kju.length != 1) return; if (kju.length != 1) return;
playNext(mes.member.voice.channel); await novejJoin(mes.guild!, kanel);
getConn(guildId)?.once(VoiceConnectionStatus.Destroyed, () => {
kju.length = 0;
});
playNext(guildId);
} }
}, },
@ -92,8 +99,8 @@ const exp: Modul = {
als: ["q", "kju"], als: ["q", "kju"],
DMUnsafe: true, DMUnsafe: true,
run: mes => { run: mes => {
const kju = kjus[mes.guildId!]; const kju = guildy.get(mes.guildId!)?.kju;
if (!kju) return "nehraje nic"; if (!kju?.length) return "nehraje nic";
return `tuto je kurentni repertoar:\n${kju.reduce((acc, cur, i) => { return `tuto je kurentni repertoar:\n${kju.reduce((acc, cur, i) => {
const jmeno = `${cur.name} (<${cur.url}>)`; const jmeno = `${cur.name} (<${cur.url}>)`;
@ -105,8 +112,8 @@ const exp: Modul = {
skip: { skip: {
DMUnsafe: true, DMUnsafe: true,
run: mes => { run: mes => {
const kju = kjus[mes.guildId!]; const kju = guildy.get(mes.guildId!)?.kju;
if (!kju) return "nic nehraje"; if (!kju?.length) return "nehraje nic";
stopPlayer(mes.guildId!, Priority.Music); stopPlayer(mes.guildId!, Priority.Music);
mes.react(emouty.d3k); mes.react(emouty.d3k);
@ -120,8 +127,8 @@ const exp: Modul = {
const numero = Number(arg); const numero = Number(arg);
if (isNaN(numero)) return "cokundo?"; if (isNaN(numero)) return "cokundo?";
const kju = kjus[mes.guildId!]; const kju = guildy.get(mes.guildId!)?.kju;
if (!kju) return "nic nehraje"; if (!kju?.length) return "nehraje nic";
if (kju.length <= numero) return "tolik toho nehrae"; if (kju.length <= numero) return "tolik toho nehrae";
@ -136,14 +143,27 @@ const exp: Modul = {
const numero = Number(arg); const numero = Number(arg);
if (isNaN(numero)) return "huh?"; if (isNaN(numero)) return "huh?";
const kju = kjus[mes.guildId!]; const kju = guildy.get(mes.guildId!)?.kju;
if (!kju) return "nehraje nic"; if (!kju?.length) return "nehraje nic";
const channel = mes.client.channels.cache.get(getVoiceConnection(mes.guildId!)?.joinConfig.channelId ?? "") as VoiceBasedChannel; playNext(mes.guildId!, numero);
if (!channel) return "neco nefunguje";
playNext(channel, numero);
mes.react(emouty.d3k); mes.react(emouty.d3k);
} }
},
loop: {
DMUnsafe: true,
run: mes => {
if (!guildy.has(mes.guildId!)) {
guildy.set(mes.guildId!, { kju: [], loop: false });
}
const guilda = guildy.get(mes.guildId!)!;
guilda.loop = !guilda.loop;
return `lup je ${guilda.loop ? "zapnutej" : "ukoncen"}`;
}
} }
} }
}; };

View File

@ -26,14 +26,18 @@ const vytahnout = (member: GuildMember, patro: number) => {
setTimeout(() => vytahnout(member, patro), 1e3); setTimeout(() => vytahnout(member, patro), 1e3);
}; };
async function playAndFukOff(mes: Message, jinak: string, zvuk: string) { async function playAndFukOff(mes: Message, jinak: string, zvuk: string | Hratelny[]) {
const channel = mes.member?.voice.channel; const channel = mes.member?.voice.channel;
if (!channel) return jinak; if (!channel) return jinak;
await novejPlay(channel, zvuk, Priority.Etc, true) const prev = await novejJoin(mes.guild!, channel.id);
await novejPlay(mes.guildId!, zvuk, Priority.Etc)
.catch(e => { .catch(e => {
log("Pičo chyba při fukofování", e); log("Pičo chyba při fukofování", e);
}); });
handlePrevVoice(prev, mes.guild!);
} }
const exp: Modul = { const exp: Modul = {
@ -51,9 +55,9 @@ const exp: Modul = {
const nahlas = !arg.startsWith("potichu"); const nahlas = !arg.startsWith("potichu");
if (nahlas) mes.channel.send("<@&591306633196339261> vojs"); if (nahlas) mes.channel.send("<@&591306633196339261> vojs");
novejJoin(channel) novejJoin(mes.guild!, channel.id)
.then(prev => { .then(prev => {
if (prev != true && nahlas) novejPlay(channel, "zvuky/nazdar.ogg", Priority.Etc); if (prev != true && nahlas) novejPlay(mes.guildId!, "zvuky/nazdar.ogg", Priority.Etc);
}); });
} }
}, },
@ -110,7 +114,7 @@ const exp: Modul = {
const je = h > 1 && h < 5 ? "jsou" : "je"; const je = h > 1 && h < 5 ? "jsou" : "je";
const channel = mes.member?.voice.channel; const channel = mes.member?.voice.channel;
if (!channel) return `${je} ${h} ${hod} ${m} ${min}`; if (!channel) return;
const zvuky: Hratelny[] = [{ src: `${pre}${je}.mp3`, volume: 2.5 }]; const zvuky: Hratelny[] = [{ src: `${pre}${je}.mp3`, volume: 2.5 }];
@ -121,12 +125,7 @@ const exp: Modul = {
zvuky.push({ src: `${pre}${min}.mp3`, volume: 2.5 }); zvuky.push({ src: `${pre}${min}.mp3`, volume: 2.5 });
} }
const prev = await novejJoin(channel); playAndFukOff(mes, `${je} ${h} ${hod} ${m} ${min}`, zvuky);
await novejPlay(channel, zvuky, Priority.Etc)
.catch(e => {
log("chyba tady, si to najdi", e);
});
handlePrevVoice(prev, mes.guildId!);
} }
}, },
@ -158,11 +157,8 @@ const exp: Modul = {
const conn = getVoiceConnection(aft.guild.id); const conn = getVoiceConnection(aft.guild.id);
if (!aft.channel || !conn || aft.member?.user.id == aft.client.user?.id) return; if (!aft.channel || !conn || aft.member?.user.id == aft.client.user?.id) return;
const channel = aft.client.channels.cache.get(conn.joinConfig.channelId ?? "") as VoiceBasedChannel;
if (!channel) return log(new Error("kanela jsem nenasel"));
if (neodposlouchavani && aft.selfMute && !aft.deaf) { if (neodposlouchavani && aft.selfMute && !aft.deaf) {
novejPlay(channel, { src: "./zvuky/neodposlouchavej.ogg", volume: 0.38 }, Priority.Etc) novejPlay(aft.channel.guildId, { src: "./zvuky/neodposlouchavej.ogg", volume: 0.38 }, Priority.Etc)
.then(() => { .then(() => {
if (!aft.selfMute) return; if (!aft.selfMute) return;
aft.setDeaf(true, "otposlouchávala ta gadza"); aft.setDeaf(true, "otposlouchávala ta gadza");

View File

@ -74,12 +74,6 @@ export interface ZmenovejObjekt {
status?: string; status?: string;
} }
export interface MuzikaFace {
name: string | Readable;
volume: number;
type?: StreamType;
}
export type KomandNaExport = { export type KomandNaExport = {
name: string; name: string;
custom?: true; custom?: true;

View File

@ -91,7 +91,7 @@ export function log(...content: unknown[]) {
} }
export async function sendDM(user: User, txt: string) { export async function sendDM(user: User, txt: string) {
user.send(txt).catch(() => console.log(`dementovi ${user} nejde poslat DM`)); user.send(txt).catch(() => log(new Error(`dementovi ${user} nejde poslat DM`)));
} }
export const rand = (max: number) => Math.floor(Math.random() * max); export const rand = (max: number) => Math.floor(Math.random() * max);

View File

@ -1,5 +1,5 @@
import { AudioPlayer, AudioPlayerState, AudioPlayerStatus, AudioResource, createAudioPlayer, createAudioResource, entersState, joinVoiceChannel, StreamType, VoiceConnection, VoiceConnectionStatus } from "@discordjs/voice"; import { AudioPlayer, AudioPlayerState, AudioPlayerStatus, AudioResource, createAudioPlayer, createAudioResource, entersState, joinVoiceChannel, StreamType, VoiceConnection, VoiceConnectionStatus } from "@discordjs/voice";
import { VoiceBasedChannel } from "discord.js"; import { Guild } from "discord.js";
import { log } from "./utils"; import { log } from "./utils";
import { Readable } from "node:stream"; import { Readable } from "node:stream";
@ -10,7 +10,6 @@ export type Hratelny = string | Readable | {
}; };
type Vojska = { type Vojska = {
channel: VoiceBasedChannel;
conn: VoiceConnection; conn: VoiceConnection;
players: [AudioPlayer, AudioPlayer, AudioPlayer]; players: [AudioPlayer, AudioPlayer, AudioPlayer];
queues: [AudioResource[], AudioResource[], AudioResource[]]; queues: [AudioResource[], AudioResource[], AudioResource[]];
@ -31,28 +30,46 @@ const getId = () => `Id:${lastId++}`;
* @returns Předchozí stav bota, před tímto příkazem * @returns Předchozí stav bota, před tímto příkazem
* `true` znamená, že byl bot do tohoto kanelu již připojen * `true` znamená, že byl bot do tohoto kanelu již připojen
* `false` znamená, že nebyl připojen nikam * `false` znamená, že nebyl připojen nikam
* `VoiceBasedChannel` znamená, že v tutý gildě byl předtím připojenej do daného kanelu * `channelId` znamená, že v tutý gildě byl předtím připojenej do kanelu s tímto ID
*/ */
export const novejJoin = (channel: VoiceBasedChannel) => new Promise<boolean | VoiceBasedChannel>(async (resolve, reject) => { export const novejJoin = (guild: Guild, channelId: string) => new Promise<boolean | string>(async (resolve, reject) => {
const guildId = channel.guildId; const guildId = guild.id;
let prev: boolean | VoiceBasedChannel = false; let prev: false | string = false;
const gildina = vojsy.get(guildId); const gildina = vojsy.get(guildId);
if (gildina) { if (gildina) {
if (gildina.channel.id == channel.id) { const con = gildina.conn;
if (gildina.conn.state.status != VoiceConnectionStatus.Ready) { if (con.joinConfig.channelId == channelId) {
if (con.state.status != VoiceConnectionStatus.Ready) {
log(`pri pripojovani do vojsu tady uz existovalo stejny pripojeni, ale status byl ${gildina.conn.state.status}, tak jsem to zahodil`); log(`pri pripojovani do vojsu tady uz existovalo stejny pripojeni, ale status byl ${gildina.conn.state.status}, tak jsem to zahodil`);
novejLeave(guildId); novejLeave(guildId);
} }
else return resolve(true); else return resolve(true);
} }
else prev = gildina.channel; else {
prev = con.joinConfig.channelId!;
if (!prev) {
log(new Error("fakt tam nic neni, jak je to mozny?"));
prev = false;
}
// Přesunout se
const state = guild.voiceStates.cache.get(guild.client.user!.id);
if (state) {
await state.setChannel(channelId);
resolve(prev);
return;
}
// Z nějakýho neznámího důvodu se nepodařilo přepojit, prostě vytvoříme noví připojení
log(new Error("jo tak tuto nechapu"));
novejLeave(guildId);
};
} }
const conn = joinVoiceChannel({ const conn = joinVoiceChannel({
channelId: channel.id, channelId: channelId,
guildId, guildId,
adapterCreator: channel.guild.voiceAdapterCreator adapterCreator: guild.voiceAdapterCreator
}); });
await entersState(conn, VoiceConnectionStatus.Ready, 1e4) await entersState(conn, VoiceConnectionStatus.Ready, 1e4)
@ -76,7 +93,6 @@ export const novejJoin = (channel: VoiceBasedChannel) => new Promise<boolean | V
conn.subscribe(player); conn.subscribe(player);
vojsy.set(guildId, { vojsy.set(guildId, {
channel,
conn, conn,
players: [createAudioPlayer(), createAudioPlayer(), createAudioPlayer()], players: [createAudioPlayer(), createAudioPlayer(), createAudioPlayer()],
queues: [[], [], []] queues: [[], [], []]
@ -134,7 +150,7 @@ function handelieren(vojska: Vojska, priority: Priority) {
} }
if (nejprioritnejsi != -1) if (nejprioritnejsi != -1)
handelieren(vojska, nejprioritnejsi); handelieren(vojska, nejprioritnejsi);
}; }
vojska.players[priority].on("stateChange", nasafunkca); vojska.players[priority].on("stateChange", nasafunkca);
} }
@ -155,14 +171,10 @@ function convert(resources: { id: string; res: AudioResource; }[]) {
return odpoved; return odpoved;
} }
export const novejPlay = (channel: VoiceBasedChannel, co: Hratelny | Hratelny[], priority: Priority, handlePrev?: true) => new Promise<AudioPlayerState>(async (resolve, reject) => { export const novejPlay = (guildId: string, co: Hratelny | Hratelny[], priority: Priority) => new Promise<AudioPlayerState>(async (resolve, reject) => {
let prev: Awaited<ReturnType<typeof novejJoin>>;
if (!(vojsy.get(channel.guildId)?.channel.id == channel.id)) {
prev = await novejJoin(channel);
}
const vojska = vojsy.get(channel.guildId); const vojska = vojsy.get(guildId);
if (!vojska) return reject("silenost"); if (!vojska) return reject("nejsi pripojenej do vojsu debile");
const resources: { id: string; res: AudioResource; }[] = []; const resources: { id: string; res: AudioResource; }[] = [];
if (!Array.isArray(co)) { if (!Array.isArray(co)) {
@ -175,7 +187,7 @@ export const novejPlay = (channel: VoiceBasedChannel, co: Hratelny | Hratelny[],
}); });
} }
// Tuto se možná může někdy hodit, třeba už za 5 minut, třeba nikdy, kdovi // Tuto se možná může někdy hodit, třeba nikdy, kdovi
// if (neprepisovat) { // if (neprepisovat) {
// vojska.queues[priority].push(resource); // vojska.queues[priority].push(resource);
// } else { // } else {
@ -187,23 +199,22 @@ export const novejPlay = (channel: VoiceBasedChannel, co: Hratelny | Hratelny[],
const posledniId = resources.at(-1)?.id; const posledniId = resources.at(-1)?.id;
function nasafunkca(pred: AudioPlayerState, po: AudioPlayerState) { function nasafunkca(pred: AudioPlayerState, po: AudioPlayerState) {
log({ id: posledniId, pred: pred.status, po: po.status });
if (!(("resource" in pred && pred.resource.metadata == posledniId) && (("resource" in po && po.resource.metadata != posledniId) || !("resource" in po)))) return; if (!(("resource" in pred && pred.resource.metadata == posledniId) && (("resource" in po && po.resource.metadata != posledniId) || !("resource" in po)))) return;
log("odebiram sa", { id: posledniId });
vojska?.players[priority].removeListener("stateChange", nasafunkca); vojska?.players[priority].removeListener("stateChange", nasafunkca);
if (handlePrev) handlePrevVoice(prev, channel.guildId);
resolve(po); resolve(po);
}; }
vojska.players[priority].on("stateChange", nasafunkca); vojska.players[priority].on("stateChange", nasafunkca);
handelieren(vojska, priority); handelieren(vojska, priority);
}); });
export const handlePrevVoice = (prev: boolean | VoiceBasedChannel, guildId: string) => { export const handlePrevVoice = (prev: boolean | string, guild: Guild) => {
if (prev === true) return; // Byl jsem v tomdle vojsu if (prev === true) return; // Byl jsem v tomdle vojsu
if (prev === false) return novejLeave(guildId); // Nebyl jsem ve vojsu vůbec if (prev === false) return novejLeave(guild.id); // Nebyl jsem ve vojsu vůbec
novejJoin(prev); // Byl jsem jinde novejJoin(guild, prev); // Byl jsem jinde
}; };
export function stopPlayer(guildId: string, priorita: Priority) { export function stopPlayer(guildId: string, priorita: Priority) {
@ -214,23 +225,25 @@ export function stopPlayer(guildId: string, priorita: Priority) {
return true; return true;
} }
export const getConn = (guildId: string) => vojsy.get(guildId)?.conn;
// Ohlašování času // Ohlašování času
const timeouty = new Map<string, NodeJS.Timeout>(); const timeouty = new Map<string, NodeJS.Timeout>();
const nula = (a: number) => a < 10 ? `0${a}` : a; const nula = (a: number) => a < 10 ? `0${a}` : a;
const vypocitatCas = (channel: VoiceBasedChannel) => { const vypocitatCas = (guildId: string) => {
const d = new Date(); const d = new Date();
d.setMinutes((d.getMinutes() >= 30 ? 60 : 30)); d.setMinutes((d.getMinutes() >= 30 ? 60 : 30));
d.setSeconds(0); d.setSeconds(0);
timeouty.set(channel.guildId, setTimeout(() => rekniCas(channel, `${nula(d.getHours())}${nula(d.getMinutes())}`), Number(d) - Number(new Date()))); timeouty.set(guildId, setTimeout(() => rekniCas(guildId, `${nula(d.getHours())}${nula(d.getMinutes())}`), Number(d) - Number(new Date())));
}; };
const rekniCas = (channel: VoiceBasedChannel, cas: string) => { const rekniCas = (guildId: string, cas: string) => {
novejPlay(channel, [{ src: "zvuky/intro.mp3", volume: 0.8 }, { src: `zvuky/${cas}.mp3`, volume: 2 }, { src: "zvuky/grg.mp3", volume: 0.5 }], Priority.Time) novejPlay(guildId, [{ src: "zvuky/intro.mp3", volume: 0.8 }, { src: `zvuky/${cas}.mp3`, volume: 2 }, { src: "zvuky/grg.mp3", volume: 0.5 }], Priority.Time)
.then(() => { .then(() => {
vypocitatCas(channel); vypocitatCas(guildId);
}) })
.catch(err => { log("cas error:", err); }); .catch(err => { log("cas error:", err); });
}; };