From b761c5ca0e69e13a6f978354cccd121d924c986a Mon Sep 17 00:00:00 2001 From: flifloo Date: Mon, 22 Nov 2021 15:57:31 +0100 Subject: [PATCH] Implement events and voice auto disconnect --- src/lib/Command.ts | 15 +---- src/lib/Component.ts | 21 +++++++ src/lib/Event.ts | 5 ++ src/lib/Module.ts | 62 +++++++++++++++++--- src/lib/Modules.ts | 2 +- src/modules/Music/events/VoiceStateUpdate.ts | 36 ++++++++++++ 6 files changed, 121 insertions(+), 20 deletions(-) create mode 100644 src/lib/Component.ts create mode 100644 src/lib/Event.ts create mode 100644 src/modules/Music/events/VoiceStateUpdate.ts diff --git a/src/lib/Command.ts b/src/lib/Command.ts index 343ba61..c3b87da 100644 --- a/src/lib/Command.ts +++ b/src/lib/Command.ts @@ -1,26 +1,17 @@ import {ApplicationCommandData, CommandInteraction} from "discord.js"; import {Module} from "./Module"; -import {Logger} from "./Logger"; +import {Component} from "./Component"; -export abstract class Command { - module: Module; +export abstract class Command extends Component { data: ApplicationCommandData; - logger: Logger; protected constructor(module: Module, data: ApplicationCommandData) { + super(module, data.name); this.module = module; this.data = data; this.logger = this.module.logger.createChild(this.data.name); } abstract execute(interaction: CommandInteraction): void; - - load(): any { - - }; - - unload(): any { - - }; } diff --git a/src/lib/Component.ts b/src/lib/Component.ts new file mode 100644 index 0000000..1688015 --- /dev/null +++ b/src/lib/Component.ts @@ -0,0 +1,21 @@ +import {Module} from "./Module"; +import {Logger} from "./Logger"; + + +export abstract class Component { + module: Module; + logger: Logger; + + protected constructor(module: Module, name: string | null = null) { + this.module = module; + this.logger = this.module.logger.createChild(name || this.constructor.name); + } + + load(): any { + + }; + + unload(): any { + + }; +} diff --git a/src/lib/Event.ts b/src/lib/Event.ts new file mode 100644 index 0000000..eece8a2 --- /dev/null +++ b/src/lib/Event.ts @@ -0,0 +1,5 @@ +import {Component} from "./Component"; + +export abstract class Event extends Component { + +} diff --git a/src/lib/Module.ts b/src/lib/Module.ts index 0e80012..887e78a 100644 --- a/src/lib/Module.ts +++ b/src/lib/Module.ts @@ -1,34 +1,82 @@ import {Command} from "./Command"; import {Modules} from "./Modules"; import {Logger} from "./Logger"; -import {readdirSync} from "fs"; +import {readdirSync, existsSync} from "fs"; +import {Event} from "./Event"; export abstract class Module { modules: Modules; logger: Logger; loadedCommands: Command[] = []; + loadedEvents: Event[] = []; protected constructor(modules: Modules, name: string) { this.modules = modules; this.logger = this.modules.client.logger.createChild(name); } + private getComponent(name: string) { + const folder = `${__dirname}/../modules/${this.constructor.name}/${name}`; + if (existsSync(folder)) + return readdirSync(folder, {withFileTypes: true}) + .filter(file => file.isDirectory() || file.name.endsWith(".js")) + .map(file => require(`${folder}/${file.name}`)[file.name.charAt(0).toUpperCase() + file.name.replace(/\.js$/, "").slice(1)+name.charAt(0).toUpperCase() + name.slice(1).replace(/s$/, "")]); + else + return []; + } + get commands() { - const folder = `${__dirname}/../modules/${this.constructor.name}/commands`; - return readdirSync(folder, {withFileTypes: true}) - .filter(file => file.isDirectory() || file.name.endsWith(".js")) - .map(file => (require(`${folder}/${file.name}`)[file.name.charAt(0).toUpperCase() + file.name.replace(/\.js$/, "").slice(1)+"Command"])); + return this.getComponent("commands"); + } + + get events() { + return this.getComponent("events"); } async load() { - const commands = this.commands.map(cmd => new cmd(this)); - await Promise.all(commands.map(cmd => cmd.load())); + await this.loadCommands(); + await this.loadEvents(); + } + + async loadCommands() { + const commands: Command[] = []; + + for (const command of this.commands) { + try { + const cmd: Command = new command(this); + await cmd.load(); + commands.push(cmd); + } catch (error) { + this.logger.err(`Fail to load command ${command}`); + this.logger.err(error); + } + } + this.loadedCommands = this.loadedCommands.concat(commands); } + async loadEvents() { + const events: Event[] = []; + + for (const event of this.events) { + try { + const env: Event = new event(this); + await env.load(); + events.push(env); + } catch (error) { + this.logger.err(`Fail to load event ${event}`); + this.logger.err(error); + } + } + + this.loadedEvents = this.loadedEvents.concat(events); + } + async unload() { await Promise.all(this.loadedCommands.map(cmd => cmd.unload())); this.loadedCommands = []; + await Promise.all(this.loadedEvents.map(cmd => cmd.unload())); + this.loadedEvents = []; } } diff --git a/src/lib/Modules.ts b/src/lib/Modules.ts index 285ca98..6baab78 100644 --- a/src/lib/Modules.ts +++ b/src/lib/Modules.ts @@ -21,7 +21,7 @@ export class Modules { if (createCommand) await this.registerCommand(module.loadedCommands.map(c => c.data)); - module.logger.info(`loaded`) + module.logger.info("loaded"); } catch (error) { this.client.logger.err(`Fail to load module ${name}`); this.client.logger.err(error); diff --git a/src/modules/Music/events/VoiceStateUpdate.ts b/src/modules/Music/events/VoiceStateUpdate.ts new file mode 100644 index 0000000..2f3b0ee --- /dev/null +++ b/src/modules/Music/events/VoiceStateUpdate.ts @@ -0,0 +1,36 @@ +import {Event} from "../../../lib/Event"; +import {VoiceState} from "discord.js"; +import {Music} from "../index"; + +export class VoiceStateUpdateEvent extends Event { + module: Music; + private readonly callback; + + constructor(module: Music) { + super(module); + this.module = module; + this.callback = async (oldState: VoiceState, newState: VoiceState) => { + const player = this.module.players.get(oldState.guild.id); + + if (!player) + return; + + if (!oldState.channel || oldState.channelId != player.connexion.joinConfig.channelId || (newState.channelId == oldState.channelId)) + return; + + await oldState.channel.fetch(true); + if (oldState.channel.members.size == 1) { + player.disconnect(); + this.module.players.delete(oldState.guild.id); + } + } + } + + load() { + this.module.modules.client.on("voiceStateUpdate", this.callback); + } + + unload() { + this.module.modules.client.removeListener("voiceStateUpdate", this.callback); + } +}