mirror of
https://github.com/informaticker/discord-jellyfin-bot.git
synced 2024-11-25 02:51:57 +01:00
✨ Reimplement websocket controls
This commit is contained in:
parent
8c5739a9e5
commit
fc74d1b4f3
@ -116,6 +116,7 @@ export class DiscordVoiceService {
|
||||
/**
|
||||
* Pauses the current audio player
|
||||
*/
|
||||
@OnEvent('internal.voice.controls.pause')
|
||||
pause() {
|
||||
this.createAndReturnOrGetAudioPlayer().pause();
|
||||
this.eventEmitter.emit('playback.state.pause', true);
|
||||
@ -124,6 +125,7 @@ export class DiscordVoiceService {
|
||||
/**
|
||||
* Stops the audio player
|
||||
*/
|
||||
@OnEvent('internal.voice.controls.stop')
|
||||
stop(force: boolean): boolean {
|
||||
const stopped = this.createAndReturnOrGetAudioPlayer().stop(force);
|
||||
this.eventEmitter.emit('playback.state.stop');
|
||||
@ -161,6 +163,7 @@ export class DiscordVoiceService {
|
||||
* 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
|
||||
*/
|
||||
@OnEvent('internal.voice.controls.togglePause')
|
||||
togglePaused(): boolean {
|
||||
if (this.isPaused()) {
|
||||
this.unpause();
|
||||
|
@ -71,4 +71,23 @@ export class JellyinPlaystateService {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@OnEvent('playback.state.pause')
|
||||
private async onPlaybackPause(paused: boolean) {
|
||||
const track = this.playbackService.getPlaylistOrDefault().getActiveTrack();
|
||||
|
||||
if (!track) {
|
||||
this.logger.error(
|
||||
`Unable to report changed playstate to Jellyfin because no track was active`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.playstateApi.reportPlaybackProgress({
|
||||
playbackProgressInfo: {
|
||||
IsPaused: paused,
|
||||
ItemId: track.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +130,27 @@ export class JellyfinSearchService {
|
||||
return this.transformToSearchHint(data.Items[0]);
|
||||
}
|
||||
|
||||
async getAllById(
|
||||
ids: string[],
|
||||
includeItemTypes: BaseItemKind[] = [BaseItemKind.Audio],
|
||||
): Promise<SearchHint[]> | undefined {
|
||||
const api = this.jellyfinService.getApi();
|
||||
|
||||
const searchApi = getItemsApi(api);
|
||||
const { data } = await searchApi.getItems({
|
||||
ids: ids,
|
||||
userId: this.jellyfinService.getUserId(),
|
||||
includeItemTypes: includeItemTypes,
|
||||
});
|
||||
|
||||
if (data.Items.length !== 1) {
|
||||
this.logger.warn(`Failed to retrieve item via id '${ids}'`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return data.Items.map((item) => this.transformToSearchHint(item));
|
||||
}
|
||||
|
||||
async getRemoteImageById(id: string, limit = 20): Promise<RemoteImageResult> {
|
||||
const api = this.jellyfinService.getApi();
|
||||
const remoteImageApi = getRemoteImageApi(api);
|
||||
|
@ -1,11 +1,13 @@
|
||||
import {
|
||||
PlaystateCommand,
|
||||
SessionMessageType,
|
||||
UserItemDataDto,
|
||||
} from '@jellyfin/sdk/lib/generated-client/models';
|
||||
|
||||
import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import { Session } from 'inspector';
|
||||
|
||||
import { WebSocket } from 'ws';
|
||||
|
||||
@ -14,11 +16,9 @@ import {
|
||||
PlayNowCommand,
|
||||
SessionApiSendPlaystateCommandRequest,
|
||||
} from '../../types/websocket';
|
||||
import { Track } from '../../models/shared/Track';
|
||||
|
||||
import { JellyfinSearchService } from './jellyfin.search.service';
|
||||
import { JellyfinService } from './jellyfin.service';
|
||||
import { JellyfinStreamBuilderService } from './jellyfin.stream.builder.service';
|
||||
|
||||
@Injectable()
|
||||
export class JellyfinWebSocketService implements OnModuleDestroy {
|
||||
@ -28,9 +28,8 @@ export class JellyfinWebSocketService implements OnModuleDestroy {
|
||||
|
||||
constructor(
|
||||
private readonly jellyfinService: JellyfinService,
|
||||
private readonly jellyfinSearchService: JellyfinSearchService,
|
||||
private readonly playbackService: PlaybackService,
|
||||
private readonly jellyfinStreamBuilderService: JellyfinStreamBuilderService,
|
||||
private readonly jellyfinSearchService: JellyfinSearchService,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) {}
|
||||
|
||||
@ -103,14 +102,29 @@ export class JellyfinWebSocketService implements OnModuleDestroy {
|
||||
data.hasSelection = PlayNowCommand.prototype.hasSelection;
|
||||
data.getSelection = PlayNowCommand.prototype.getSelection;
|
||||
const ids = data.getSelection();
|
||||
this.logger.log(
|
||||
`Processing ${ids.length} ids received via websocket and adding them to the queue`,
|
||||
);
|
||||
const searchHints = await this.jellyfinSearchService.getAllById(ids);
|
||||
|
||||
// TODO: Implement this again
|
||||
const tracks = await Promise.all(
|
||||
searchHints.map(async (x) =>
|
||||
(
|
||||
await x.toTracks(this.jellyfinSearchService)
|
||||
).find((x) => x !== null),
|
||||
),
|
||||
);
|
||||
|
||||
this.playbackService.getPlaylistOrDefault().enqueueTracks(tracks);
|
||||
break;
|
||||
case SessionMessageType[SessionMessageType.Playstate]:
|
||||
const sendPlaystateCommandRequest =
|
||||
msg.Data as SessionApiSendPlaystateCommandRequest;
|
||||
this.handleSendPlaystateCommandRequest(sendPlaystateCommandRequest);
|
||||
break;
|
||||
case SessionMessageType[SessionMessageType.UserDataChanged]:
|
||||
this.logger.debug(`Received update for user session data`);
|
||||
break;
|
||||
default:
|
||||
this.logger.warn(
|
||||
`Received a package from the socket of unknown type: ${msg.MessageType}`,
|
||||
@ -124,13 +138,13 @@ export class JellyfinWebSocketService implements OnModuleDestroy {
|
||||
) {
|
||||
switch (request.Command) {
|
||||
case PlaystateCommand.PlayPause:
|
||||
this.eventEmitter.emitAsync('playback.control.togglePause');
|
||||
this.eventEmitter.emitAsync('internal.voice.controls.togglePause');
|
||||
break;
|
||||
case PlaystateCommand.Pause:
|
||||
this.eventEmitter.emitAsync('playback.control.pause');
|
||||
this.eventEmitter.emitAsync('internal.voice.controls.pause');
|
||||
break;
|
||||
case PlaystateCommand.Stop:
|
||||
this.eventEmitter.emitAsync('playback.control.stop');
|
||||
this.eventEmitter.emitAsync('internal.voice.controls.stop');
|
||||
break;
|
||||
default:
|
||||
this.logger.warn(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
|
||||
|
||||
import { Track } from './Track';
|
||||
|
||||
|
@ -39,6 +39,7 @@ export class Track {
|
||||
this.name = name;
|
||||
this.duration = duration;
|
||||
this.remoteImages = remoteImages;
|
||||
this.playing = false;
|
||||
}
|
||||
|
||||
getDuration() {
|
||||
|
Loading…
Reference in New Issue
Block a user