From acf4cf19f6545277161af2529c00cbe574ec980c Mon Sep 17 00:00:00 2001 From: Manuel <30572287+manuel-rw@users.noreply.github.com> Date: Tue, 28 Mar 2023 20:58:58 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20playback=20reporting=20at=20J?= =?UTF-8?q?ellyfin=20(#139)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/clients/discord/discord.voice.service.ts | 11 +++++---- .../jellyfin/jellyfin.playstate.service.ts | 23 ++++++++++++++++--- src/commands/stop.command.ts | 2 +- src/models/shared/Playlist.ts | 18 ++++++++++++++- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/clients/discord/discord.voice.service.ts b/src/clients/discord/discord.voice.service.ts index 615fbc9..1e92493 100644 --- a/src/clients/discord/discord.voice.service.ts +++ b/src/clients/discord/discord.voice.service.ts @@ -41,7 +41,7 @@ export class DiscordVoiceService { private readonly eventEmitter: EventEmitter2, ) {} - @OnEvent('internal.audio.announce') + @OnEvent('internal.audio.track.announce') handleOnNewTrack(track: Track) { const resource = createAudioResource( track.getStreamUrl(this.jellyfinStreamBuilder), @@ -264,9 +264,12 @@ export class DiscordVoiceService { this.logger.debug(`Audio player finished playing old resource`); - const hasNextTrack = this.playbackService - .getPlaylistOrDefault() - .hasNextTrackInPlaylist(); + const playlist = this.playbackService.getPlaylistOrDefault(); + const finishedTrack = playlist.getActiveTrack(); + + this.eventEmitter.emit('internal.audio.track.finish', finishedTrack); + + const hasNextTrack = playlist.hasNextTrackInPlaylist(); this.logger.debug( `Playlist has next track: ${hasNextTrack ? 'yes' : 'no'}`, diff --git a/src/clients/jellyfin/jellyfin.playstate.service.ts b/src/clients/jellyfin/jellyfin.playstate.service.ts index 57b1483..c38221b 100644 --- a/src/clients/jellyfin/jellyfin.playstate.service.ts +++ b/src/clients/jellyfin/jellyfin.playstate.service.ts @@ -10,9 +10,9 @@ import { getSessionApi } from '@jellyfin/sdk/lib/utils/api/session-api'; import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; +import { Track } from 'src/models/shared/Track'; import { PlaybackService } from '../../playback/playback.service'; -import { Track } from '../../types/track'; @Injectable() export class JellyinPlaystateService { @@ -46,11 +46,28 @@ export class JellyinPlaystateService { this.logger.debug('Reported playback capabilities sucessfully'); } - @OnEvent('playback.newTrack') + @OnEvent('internal.audio.track.announce') private async onPlaybackNewTrack(track: Track) { + this.logger.debug(`Reporting playback start on track '${track.id}'`); await this.playstateApi.reportPlaybackStart({ playbackStartInfo: { - ItemId: track.jellyfinId, + ItemId: track.id, + }, + }); + } + + @OnEvent('internal.audio.track.finish') + private async onPlaybackFinished(track: Track) { + if (!track) { + this.logger.error( + `Unable to report playback because finished track was undefined`, + ); + return; + } + this.logger.debug(`Reporting playback finish on track '${track.id}'`); + await this.playstateApi.reportPlaybackStopped({ + playbackStopInfo: { + ItemId: track.id, }, }); } diff --git a/src/commands/stop.command.ts b/src/commands/stop.command.ts index d9d1579..b57b129 100644 --- a/src/commands/stop.command.ts +++ b/src/commands/stop.command.ts @@ -30,8 +30,8 @@ export class StopPlaybackCommand { ? 'In addition, your playlist has been cleared' : 'There is no active track in the queue'; if (hasActiveTrack) { - this.playbackService.getPlaylistOrDefault().clear(); this.discordVoiceService.stop(false); + // this.playbackService.getPlaylistOrDefault().clear(); } await interaction.reply({ diff --git a/src/models/shared/Playlist.ts b/src/models/shared/Playlist.ts index f96ebea..bac225b 100644 --- a/src/models/shared/Playlist.ts +++ b/src/models/shared/Playlist.ts @@ -49,6 +49,8 @@ export class Playlist { * @returns if the track has been changed successfully */ setNextTrackAsActiveTrack(): boolean { + this.announceTrackFinishIfSet(); + if (this.activeTrackIndex >= this.tracks.length) { return false; } @@ -66,6 +68,8 @@ export class Playlist { * @returns if the track has been changed successfully */ setPreviousTrackAsActiveTrack(): boolean { + this.announceTrackFinishIfSet(); + if (this.activeTrackIndex <= 0) { return false; } @@ -124,12 +128,24 @@ export class Playlist { this.activeTrackIndex = undefined; } + private announceTrackFinishIfSet() { + if (this.activeTrackIndex === undefined) { + return; + } + + const currentTrack = this.getActiveTrack(); + this.eventEmitter.emit('internal.audio.track.finish', currentTrack); + } + private announceTrackChange() { if (!this.activeTrackIndex) { this.activeTrackIndex = 0; } - this.eventEmitter.emit('internal.audio.announce', this.getActiveTrack()); + this.eventEmitter.emit( + 'internal.audio.track.announce', + this.getActiveTrack(), + ); } private isActiveTrackOutOfSync(): boolean {