From beb34b7d7cacc9425d09fc8a4b224c5ff4f455a6 Mon Sep 17 00:00:00 2001 From: Manuel Ruwe Date: Fri, 16 Dec 2022 13:48:39 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20nestjs=20discord=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + src/app.module.ts | 12 +- src/clients/discord/discord.module.ts | 21 +--- src/clients/discord/discord.service.ts | 46 -------- .../discord/jellyfin.config.service.ts | 18 +++ src/clients/jellyfin/jellyfin.service.ts | 10 +- src/commands/abstractCommand.ts | 6 - src/commands/command.module.ts | 12 ++ .../handler/command-handler.module.ts | 10 -- .../handler/command-handler.service.ts | 107 ------------------ src/commands/help.command.ts | 90 +++++++++++++++ tsconfig.json | 3 +- yarn.lock | 83 ++++++++++++++ 13 files changed, 230 insertions(+), 190 deletions(-) delete mode 100644 src/clients/discord/discord.service.ts create mode 100644 src/clients/discord/jellyfin.config.service.ts delete mode 100644 src/commands/abstractCommand.ts create mode 100644 src/commands/command.module.ts delete mode 100644 src/commands/handler/command-handler.module.ts delete mode 100644 src/commands/handler/command-handler.service.ts create mode 100644 src/commands/help.command.ts diff --git a/package.json b/package.json index f2eec95..2e6e0e1 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { + "@discord-nestjs/common": "^4.0.8", + "@discord-nestjs/core": "^4.3.1", "@discordjs/opus": "^0.9.0", "@jellyfin/sdk": "^0.7.0", "@nestjs/common": "^9.0.0", diff --git a/src/app.module.ts b/src/app.module.ts index f34c13a..1e67a10 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,14 +1,16 @@ import { Module } from '@nestjs/common'; import * as Joi from 'joi'; -import { EventEmitterModule } from '@nestjs/event-emitter'; +import { DiscordModule } from '@discord-nestjs/core'; import { ConfigModule } from '@nestjs/config'; +import { EventEmitterModule } from '@nestjs/event-emitter'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { DiscordClientModule } from './clients/discord/discord.module'; -import { CommandHandlerModule } from './commands/handler/command-handler.module'; import { JellyfinClientModule } from './clients/jellyfin/jellyfin.module'; +import { CommandModule } from './commands/command.module'; +import { DiscordConfigService } from './clients/discord/jellyfin.config.service'; @Module({ imports: [ @@ -20,10 +22,14 @@ import { JellyfinClientModule } from './clients/jellyfin/jellyfin.module'; JELLYFIN_AUTHENTICATION_PASSWORD: Joi.string().required(), }), }), + DiscordModule.forRootAsync({ + useClass: DiscordConfigService, + }), + DiscordModule, EventEmitterModule.forRoot(), + CommandModule, DiscordClientModule, JellyfinClientModule, - CommandHandlerModule, ], controllers: [AppController], providers: [AppService], diff --git a/src/clients/discord/discord.module.ts b/src/clients/discord/discord.module.ts index 1e61691..86d2df1 100644 --- a/src/clients/discord/discord.module.ts +++ b/src/clients/discord/discord.module.ts @@ -1,21 +1,10 @@ -import { Module, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; -import { DiscordService } from './discord.service'; +import { Module } from '@nestjs/common'; +import { DiscordConfigService } from './jellyfin.config.service'; @Module({ imports: [], controllers: [], - providers: [DiscordService], - exports: [DiscordService], + providers: [DiscordConfigService], + exports: [DiscordConfigService], }) -export class DiscordClientModule implements OnModuleInit, OnModuleDestroy { - constructor(private discordService: DiscordService) {} - onModuleDestroy() { - this.discordService.destroyClient(); - } - - onModuleInit() { - this.discordService.initializeClient(); - this.discordService.registerEventHandlers(); - this.discordService.connectAndLogin(); - } -} +export class DiscordClientModule {} diff --git a/src/clients/discord/discord.service.ts b/src/clients/discord/discord.service.ts deleted file mode 100644 index d6cf09d..0000000 --- a/src/clients/discord/discord.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { EventEmitter2 } from '@nestjs/event-emitter'; - -import { Client } from 'discord.js'; - -@Injectable() -export class DiscordService { - private readonly logger = new Logger(DiscordService.name); - private client: Client; - - constructor(private eventEmitter: EventEmitter2) {} - - initializeClient() { - this.client = new Client({ - intents: ['Guilds', 'GuildMessages', 'MessageContent'], - }); - this.logger.debug('Initialized Discord client'); - } - - connectAndLogin() { - this.client.login(process.env.DISCORD_CLIENT_TOKEN); - } - - registerEventHandlers() { - this.client.on('ready', () => { - this.logger.debug(`Connected as '${this.client.user.tag}' and ready!`); - this.eventEmitter.emit('client.discord.ready'); - }); - - this.client.on('messageCreate', async (message) => { - if (message.author.bot) { - return; - } - - await message.channel.send('nice'); - }); - } - - destroyClient() { - this.client.destroy(); - } - - getClient() { - return this.client; - } -} diff --git a/src/clients/discord/jellyfin.config.service.ts b/src/clients/discord/jellyfin.config.service.ts new file mode 100644 index 0000000..c8c8d7f --- /dev/null +++ b/src/clients/discord/jellyfin.config.service.ts @@ -0,0 +1,18 @@ +import { + DiscordModuleOption, + DiscordOptionsFactory, +} from '@discord-nestjs/core'; +import { Injectable } from '@nestjs/common'; +import { GatewayIntentBits } from 'discord.js'; + +@Injectable() +export class DiscordConfigService implements DiscordOptionsFactory { + createDiscordOptions(): DiscordModuleOption { + return { + token: process.env.DISCORD_CLIENT_TOKEN, + discordClientOptions: { + intents: [GatewayIntentBits.Guilds], + }, + }; + } +} diff --git a/src/clients/jellyfin/jellyfin.service.ts b/src/clients/jellyfin/jellyfin.service.ts index efa5dbb..3c750a9 100644 --- a/src/clients/jellyfin/jellyfin.service.ts +++ b/src/clients/jellyfin/jellyfin.service.ts @@ -35,10 +35,18 @@ export class JellyfinService { process.env.JELLYFIN_AUTHENTICATION_PASSWORD, ) .then((response) => { + if (response.data.SessionInfo === undefined) { + this.logger.error( + `Failed to authenticate with response code ${response.status}: '${response.data}'`, + ); + return; + } + this.logger.debug( `Connected using user '${response.data.SessionInfo.UserId}'`, ); - }).catch((test) => { + }) + .catch((test) => { this.logger.error(test); }); } diff --git a/src/commands/abstractCommand.ts b/src/commands/abstractCommand.ts deleted file mode 100644 index fd87fb7..0000000 --- a/src/commands/abstractCommand.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { SlashCommandBuilder } from "discord.js"; - -export abstract class Command { - abstract builder(): SlashCommandBuilder; - abstract execute(): void; -} \ No newline at end of file diff --git a/src/commands/command.module.ts b/src/commands/command.module.ts new file mode 100644 index 0000000..e816157 --- /dev/null +++ b/src/commands/command.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { DiscordModule } from '@discord-nestjs/core'; + +import { HelpCommand } from './help.command'; + +@Module({ + imports: [DiscordModule.forFeature()], + controllers: [], + providers: [HelpCommand], + exports: [], +}) +export class CommandModule {} diff --git a/src/commands/handler/command-handler.module.ts b/src/commands/handler/command-handler.module.ts deleted file mode 100644 index f9a52b3..0000000 --- a/src/commands/handler/command-handler.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Module } from '@nestjs/common'; -import { DiscordClientModule } from '../../clients/discord/discord.module'; -import { CommandHandlerService } from './command-handler.service'; - -@Module({ - imports: [DiscordClientModule], - controllers: [], - providers: [CommandHandlerService], -}) -export class CommandHandlerModule {} diff --git a/src/commands/handler/command-handler.service.ts b/src/commands/handler/command-handler.service.ts deleted file mode 100644 index 2048c3c..0000000 --- a/src/commands/handler/command-handler.service.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { EmbedBuilder } from '@discordjs/builders'; -import { Injectable, Logger } from '@nestjs/common'; -import { OnEvent } from '@nestjs/event-emitter'; -import { - ApplicationCommand, - SlashCommandBuilder, - SlashCommandSubcommandBuilder, -} from 'discord.js'; -import { DiscordService } from 'src/clients/discord/discord.service'; -import { Command } from '../abstractCommand'; - -@Injectable() -export class CommandHandlerService { - private logger: Logger = new Logger(CommandHandlerService.name); - - constructor(private discordService: DiscordService) {} - - @OnEvent('client.discord.ready') - async handleOnDiscordClientReady() { - var commands = [ - new SlashCommandBuilder() - .setName('play') - .setDescription('Immideatly play a track') - .addStringOption((option) => - option - .setName('track') - .setDescription('the track name') - .setRequired(true), - ), - new SlashCommandBuilder() - .setName('summon') - .setDescription('Join your current voice channel'), - new SlashCommandBuilder() - .setName('disconnect') - .setDescription('Disconnect from the current voice channel'), - new SlashCommandBuilder() - .setName('enqueue') - .setDescription('Enqueue a track to the current playlist') - .addStringOption((option) => - option - .setName('track') - .setDescription('the track name') - .setRequired(true), - ), - new SlashCommandBuilder() - .setName('current') - .setDescription('Print the current track information'), - new SlashCommandBuilder() - .setName('pause') - .setDescription('Pause or resume the playback of the current track'), - new SlashCommandBuilder() - .setName('skip') - .setDescription('Skip the current track'), - new SlashCommandBuilder() - .setName('stop') - .setDescription( - 'Stop playback entirely and clear the current playlist', - ), - new SlashCommandBuilder() - .setName('help') - .setDescription('Get help for this Discord Bot'), - ]; - - await this.discordService - .getClient() - .application.commands.set(commands.map((x) => x.toJSON())); - - this.discordService - .getClient() - .on('interactionCreate', async (interaction) => { - if (!interaction.isChatInputCommand()) { - return; - } - - await interaction.reply({ - embeds: [ - new EmbedBuilder() - .setAuthor({ - name: 'Jellyfin Discord Bot', - iconURL: - 'https://github.com/walkxcode/dashboard-icons/blob/main/png/jellyfin.png?raw=true', - url: 'https://github.com/manuel-rw/jellyfin-discord-music-bot', - }) - .setTitle('Help Information') - .setDescription( - 'Jellyfin Discord Music bot is an easy way to broadcast your music collection to a Discord voicechannel.', - ) - .addFields([ - { - name: 'Report an issue', - value: - 'https://github.com/manuel-rw/jellyfin-discord-music-bot/issues/new/choose', - inline: true, - }, - { - name: 'Source code', - value: - 'https://github.com/manuel-rw/jellyfin-discord-music-bot', - inline: true, - }, - ]) - .toJSON(), - ], - }); - }); - } -} diff --git a/src/commands/help.command.ts b/src/commands/help.command.ts new file mode 100644 index 0000000..b011fbc --- /dev/null +++ b/src/commands/help.command.ts @@ -0,0 +1,90 @@ +import { TransformPipe } from '@discord-nestjs/common'; + +import { + Command, + DiscordTransformedCommand, + TransformedCommandExecutionContext, + UsePipes, +} from '@discord-nestjs/core'; +import { EmbedBuilder } from '@discordjs/builders'; +import { InteractionReplyOptions, MessagePayload } from 'discord.js'; + +@Command({ + name: 'help', + description: 'ejifejf', +}) +@UsePipes(TransformPipe) +export class HelpCommand implements DiscordTransformedCommand { + handler( + dto: unknown, + executionContext: TransformedCommandExecutionContext, + ): + | string + | void + | MessagePayload + | InteractionReplyOptions + | Promise { + return { + embeds: [ + new EmbedBuilder() + .setAuthor({ + name: 'Jellyfin Discord Bot', + iconURL: + 'https://github.com/walkxcode/dashboard-icons/blob/main/png/jellyfin.png?raw=true', + url: 'https://github.com/manuel-rw/jellyfin-discord-music-bot', + }) + .setTitle('Help Information') + .setDescription( + 'Jellyfin Discord Music bot is an easy way to broadcast your music collection to a Discord voicechannel.', + ) + .addFields([ + { + name: 'Report an issue', + value: + 'https://github.com/manuel-rw/jellyfin-discord-music-bot/issues/new/choose', + inline: true, + }, + { + name: 'Source code', + value: 'https://github.com/manuel-rw/jellyfin-discord-music-bot', + inline: true, + }, + ]) + .toJSON(), + ], + }; + } + + /* + handler( + dto: unknown, + executionContext: TransformedCommandExecutionContext, + ) { + return new EmbedBuilder() + .setAuthor({ + name: 'Jellyfin Discord Bot', + iconURL: + 'https://github.com/walkxcode/dashboard-icons/blob/main/png/jellyfin.png?raw=true', + url: 'https://github.com/manuel-rw/jellyfin-discord-music-bot', + }) + .setTitle('Help Information') + .setDescription( + 'Jellyfin Discord Music bot is an easy way to broadcast your music collection to a Discord voicechannel.', + ) + .addFields([ + { + name: 'Report an issue', + value: + 'https://github.com/manuel-rw/jellyfin-discord-music-bot/issues/new/choose', + inline: true, + }, + { + name: 'Source code', + value: 'https://github.com/manuel-rw/jellyfin-discord-music-bot', + inline: true, + }, + ]) + .toJSON(); + } + */ +} diff --git a/tsconfig.json b/tsconfig.json index adb614c..efc026f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,7 @@ "noImplicitAny": false, "strictBindCallApply": false, "forceConsistentCasingInFileNames": false, - "noFallthroughCasesInSwitch": false + "noFallthroughCasesInSwitch": false, + "useDefineForClassFields": true } } diff --git a/yarn.lock b/yarn.lock index bc84168..306355c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -491,6 +491,39 @@ __metadata: languageName: node linkType: hard +"@discord-nestjs/common@npm:^4.0.8": + version: 4.0.8 + resolution: "@discord-nestjs/common@npm:4.0.8" + dependencies: + "@nestjs/mapped-types": 1.2.0 + class-transformer: 0.5.1 + class-validator: 0.13.2 + peerDependencies: + "@discord-nestjs/core": "*" + "@nestjs/common": 8.* || 9.* + "@nestjs/core": 8.* || 9.* + discord.js: 14.* + reflect-metadata: ^0.1.13 + rxjs: ^7.* + checksum: 254f740d6762f3cfe827500b7c0b0a1357c631032a95fe82a1425dbbebe97e442add85a5d85dfaf333a53cb16caea293a8345bb8e17832f8f67c605676bca69f + languageName: node + linkType: hard + +"@discord-nestjs/core@npm:^4.3.1": + version: 4.3.1 + resolution: "@discord-nestjs/core@npm:4.3.1" + dependencies: + class-transformer: 0.5.1 + peerDependencies: + "@nestjs/common": 8.* || 9.* + "@nestjs/core": 8.* || 9.* + discord.js: 14.* + reflect-metadata: ^0.1.13 + rxjs: ^7.* + checksum: 2a9013126359520d9133fa547f4a08f46eb9f3d7329aa516ef22c9c779794815ba4b1e1cb5b7e899a9e16c11568931d8a14f9cb52e3944d80bf8e292e6a6daba + languageName: node + linkType: hard + "@discordjs/builders@npm:^1.4.0": version: 1.4.0 resolution: "@discordjs/builders@npm:1.4.0" @@ -1076,6 +1109,23 @@ __metadata: languageName: node linkType: hard +"@nestjs/mapped-types@npm:1.2.0": + version: 1.2.0 + resolution: "@nestjs/mapped-types@npm:1.2.0" + peerDependencies: + "@nestjs/common": ^7.0.8 || ^8.0.0 || ^9.0.0 + class-transformer: ^0.2.0 || ^0.3.0 || ^0.4.0 || ^0.5.0 + class-validator: ^0.11.1 || ^0.12.0 || ^0.13.0 + reflect-metadata: ^0.1.12 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + checksum: cc625310873c5caf69521bc03c75a6780467f662fd4c8b2402f6e65228268eec1244c131dbf65c81c985680feacee50dae7d3c1f2b7bced7bad79922389aa38f + languageName: node + linkType: hard + "@nestjs/platform-express@npm:^9.0.0": version: 9.2.1 resolution: "@nestjs/platform-express@npm:9.2.1" @@ -2547,6 +2597,23 @@ __metadata: languageName: node linkType: hard +"class-transformer@npm:0.5.1": + version: 0.5.1 + resolution: "class-transformer@npm:0.5.1" + checksum: f191c8b4cc4239990f5efdd790cabdd852c243ed66248e39f6616a349c910c6eed2d9fd1fbf7ee6ea89f69b4f1d0b493b27347fe0cd0ae26b47c3745a805b6d3 + languageName: node + linkType: hard + +"class-validator@npm:0.13.2": + version: 0.13.2 + resolution: "class-validator@npm:0.13.2" + dependencies: + libphonenumber-js: ^1.9.43 + validator: ^13.7.0 + checksum: 0deb4c29faa18345f6989fd7eaaaa07b05caae5298603fcd6485531c6daad503e5d2b24cc1342e4fc88ae5ba0acffdc24d0fc333110ef3f21a667cd8a79e1258 + languageName: node + linkType: hard + "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -4361,6 +4428,8 @@ __metadata: version: 0.0.0-use.local resolution: "jellyfin-discord-music-bot@workspace:." dependencies: + "@discord-nestjs/common": ^4.0.8 + "@discord-nestjs/core": ^4.3.1 "@discordjs/opus": ^0.9.0 "@jellyfin/sdk": ^0.7.0 "@nestjs/cli": ^9.0.0 @@ -4995,6 +5064,13 @@ __metadata: languageName: node linkType: hard +"libphonenumber-js@npm:^1.9.43": + version: 1.10.15 + resolution: "libphonenumber-js@npm:1.10.15" + checksum: 94283206159b9eaf07e4af9c002dda2b0b171099a8116baa0b6871f6312475112ec92121cca85916968fa9fb1220641205f6ee2349a1cc33197d811a69572198 + languageName: node + linkType: hard + "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" @@ -7137,6 +7213,13 @@ __metadata: languageName: node linkType: hard +"validator@npm:^13.7.0": + version: 13.7.0 + resolution: "validator@npm:13.7.0" + checksum: 2b83283de1222ca549a7ef57f46e8d49c6669213348db78b7045bce36a3b5843ff1e9f709ebf74574e06223461ee1f264f8cc9a26a0060a79a27de079d8286ef + languageName: node + linkType: hard + "vary@npm:^1, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2"