diff --git a/src/clients/discord/discord.voice.service.ts b/src/clients/discord/discord.voice.service.ts index ed204e1..f5ad7e7 100644 --- a/src/clients/discord/discord.voice.service.ts +++ b/src/clients/discord/discord.voice.service.ts @@ -107,6 +107,14 @@ export class DiscordVoiceService { ); } + /** + * Gets the current audio player status + * @returns The current audio player status + */ + getPlayerStatus(): AudioPlayerStatus { + return this.createAndReturnOrGetAudioPlayer().state.status; + } + /** * Checks if the current state is paused or not and toggles the states to the opposite. * @returns The new paused state - true: paused, false: unpaused diff --git a/src/commands/help.command.ts b/src/commands/help.command.ts index 4ed6db8..baa548c 100644 --- a/src/commands/help.command.ts +++ b/src/commands/help.command.ts @@ -1,9 +1,8 @@ import { TransformPipe } from '@discord-nestjs/common'; import { Command, DiscordCommand, UsePipes } from '@discord-nestjs/core'; -import { EmbedBuilder } from '@discordjs/builders'; import { CommandInteraction } from 'discord.js'; -import { DefaultJellyfinColor } from 'src/types/colors'; +import { DiscordMessageService } from '../clients/discord/discord.message.service'; import { GenericCustomReply } from '../models/generic-try-handler'; @Command({ @@ -12,35 +11,39 @@ import { GenericCustomReply } from '../models/generic-try-handler'; }) @UsePipes(TransformPipe) export class HelpCommand implements DiscordCommand { + constructor(private readonly discordMessageService: DiscordMessageService) {} + handler(commandInteraction: CommandInteraction): GenericCustomReply { 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', - }) - .setColor(DefaultJellyfinColor) - .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(), + this.discordMessageService.buildMessage({ + title: 'a', + description: + 'Jellyfin Discord Bot is an open source and self-hosted Discord bot, that integrates with your Jellyfin Media server and enables you to playback music from your libraries. You can use the Discord Slash Commands to invoke bot commands.', + mixin(embedBuilder) { + return 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', + }) + .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, + }, + ]); + }, + }), ], }; } diff --git a/src/commands/status.command.ts b/src/commands/status.command.ts index b4aadb7..de72ff6 100644 --- a/src/commands/status.command.ts +++ b/src/commands/status.command.ts @@ -2,33 +2,40 @@ import { TransformPipe } from '@discord-nestjs/common'; import { Command, - DiscordTransformedCommand, + DiscordCommand, InjectDiscordClient, - TransformedCommandExecutionContext, UsePipes, } from '@discord-nestjs/core'; -import { EmbedBuilder } from '@discordjs/builders'; -import { Client, InteractionReplyOptions, Status } from 'discord.js'; -import { DefaultJellyfinColor } from 'src/types/colors'; +import { + Client, + CommandInteraction, + InteractionReplyOptions, + Status, +} from 'discord.js'; import { formatDuration, intervalToDuration } from 'date-fns'; +import { DiscordMessageService } from '../clients/discord/discord.message.service'; +import { JellyfinService } from '../clients/jellyfin/jellyfin.service'; import { Constants } from '../utils/constants'; +import { getSystemApi } from '@jellyfin/sdk/lib/utils/api/system-api'; + @Command({ name: 'status', description: 'Display the current status for troubleshooting', }) @UsePipes(TransformPipe) -export class StatusCommand implements DiscordTransformedCommand { +export class StatusCommand implements DiscordCommand { constructor( @InjectDiscordClient() private readonly client: Client, + private readonly discordMessageService: DiscordMessageService, + private readonly jellyfinService: JellyfinService, ) {} - handler( - dto: unknown, - executionContext: TransformedCommandExecutionContext, - ): InteractionReplyOptions { + async handler( + commandInteraction: CommandInteraction, + ): Promise { const ping = this.client.ws.ping; const status = Status[this.client.ws.status]; @@ -38,34 +45,49 @@ export class StatusCommand implements DiscordTransformedCommand { }); const formattedDuration = formatDuration(interval); + const jellyfinSystemApi = getSystemApi(this.jellyfinService.getApi()); + const jellyfinSystemInformation = await jellyfinSystemApi.getSystemInfo(); + return { embeds: [ - new EmbedBuilder() - .setTitle('Online and ready') - .setColor(DefaultJellyfinColor) - .addFields([ - { - name: 'Version', - value: Constants.Metadata.Version, - inline: false, - }, - { - name: 'Ping', - value: `${ping}ms`, - inline: true, - }, - { - name: 'Status', - value: `${status}`, - inline: true, - }, - { - name: 'Uptime', - value: `${formattedDuration}`, - inline: true, - }, - ]) - .toJSON(), + this.discordMessageService.buildMessage({ + title: 'Discord Bot Status', + mixin(embedBuilder) { + return embedBuilder.addFields([ + { + name: 'Bot Version', + value: Constants.Metadata.Version, + inline: true, + }, + { + name: 'Discord Bot Ping', + value: `${ping}ms`, + inline: true, + }, + { + name: 'Discord Bot Status', + value: `${status}`, + inline: true, + }, + { + name: 'Discord Bot Uptime', + value: `${formattedDuration}`, + inline: false, + }, + { + name: 'Jellyfin Server Version', + value: jellyfinSystemInformation.data.Version ?? 'unknown', + inline: true, + }, + { + name: 'Jellyfin Server Operating System', + value: + jellyfinSystemInformation.data.OperatingSystem ?? 'unknown', + inline: true, + }, + ]); + }, + }), ], }; } diff --git a/src/playback/playback.service.ts b/src/playback/playback.service.ts index 62e0f29..fa3629f 100644 --- a/src/playback/playback.service.ts +++ b/src/playback/playback.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { Playlist } from '../types/playlist'; import { Track } from '../types/track'; @@ -7,6 +7,8 @@ import { EventEmitter2 } from '@nestjs/event-emitter'; @Injectable() export class PlaybackService { + private readonly logger = new Logger(PlaybackService.name); + private readonly playlist: Playlist = { tracks: [], activeTrack: null, @@ -19,7 +21,6 @@ export class PlaybackService { } setActiveTrack(trackId: string) { - console.log(`getting track by id ${trackId}`); const track = this.getTrackById(trackId); if (!track) { @@ -31,15 +32,12 @@ export class PlaybackService { nextTrack() { const keys = this.getTrackIds(); - console.log('keys:'); - console.log(keys); - const index = this.getActiveIndex(); - console.log(keys); - console.log(index); - if (!this.hasActiveTrack() || index + 1 >= keys.length) { + this.logger.debug( + `Unable to go to next track, because playback has reached end of the playlist`, + ); return false; } @@ -53,6 +51,9 @@ export class PlaybackService { const index = this.getActiveIndex(); if (!this.hasActiveTrack() || index < 1) { + this.logger.debug( + `Unable to go to previous track, because there is no previous track in the playlist`, + ); return false; } @@ -118,6 +119,9 @@ export class PlaybackService { private controlAudioPlayer() { const activeTrack = this.getActiveTrack(); + this.logger.debug( + `A new track (${activeTrack.id}) was requested and will be emmitted as an event`, + ); this.eventEmitter.emit('playback.newTrack', activeTrack.track); } }