mirror of
https://github.com/informaticker/discord-jellyfin-bot.git
synced 2024-11-25 02:51:57 +01:00
✨ Add websocket control for grouped items
This commit is contained in:
parent
538b2451f6
commit
9ecce22f14
@ -95,6 +95,7 @@ export class JellyfinSearchService {
|
|||||||
const searchApi = getItemsApi(api);
|
const searchApi = getItemsApi(api);
|
||||||
const { data } = await searchApi.getItems({
|
const { data } = await searchApi.getItems({
|
||||||
ids: [id],
|
ids: [id],
|
||||||
|
userId: this.jellyfinService.getUserId(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (data.Items.length !== 1) {
|
if (data.Items.length !== 1) {
|
||||||
|
@ -8,6 +8,7 @@ import { PlaybackService } from '../../playback/playback.service';
|
|||||||
import { JellyfinSearchService } from './jellyfin.search.service';
|
import { JellyfinSearchService } from './jellyfin.search.service';
|
||||||
import { JellyfinStreamBuilderService } from './jellyfin.stream.builder.service';
|
import { JellyfinStreamBuilderService } from './jellyfin.stream.builder.service';
|
||||||
import { Track } from '../../types/track';
|
import { Track } from '../../types/track';
|
||||||
|
import { PlayNowCommand } from '../../types/websocket';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JellyfinWebSocketService implements OnModuleDestroy {
|
export class JellyfinWebSocketService implements OnModuleDestroy {
|
||||||
@ -87,15 +88,22 @@ export class JellyfinWebSocketService implements OnModuleDestroy {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case SessionMessageType[SessionMessageType.Play]:
|
case SessionMessageType[SessionMessageType.Play]:
|
||||||
const data = msg.Data as { ItemIds: string[]; StartIndex: number };
|
const data = msg.Data as PlayNowCommand;
|
||||||
const ids = data.ItemIds;
|
data.hasSelection = PlayNowCommand.prototype.hasSelection;
|
||||||
|
data.getSelection = PlayNowCommand.prototype.getSelection;
|
||||||
|
const ids = data.getSelection();
|
||||||
|
|
||||||
|
this.logger.debug(
|
||||||
|
`Adding ${ids.length} ids to the queue using controls from the websocket`,
|
||||||
|
);
|
||||||
|
|
||||||
|
ids.forEach((id, index) => {
|
||||||
this.jellyfinSearchService
|
this.jellyfinSearchService
|
||||||
.getById(ids[data.StartIndex])
|
.getById(id)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const track: Track = {
|
const track: Track = {
|
||||||
name: response.Name,
|
name: response.Name,
|
||||||
durationInMilliseconds: response.RunTimeTicks / 1000,
|
durationInMilliseconds: response.RunTimeTicks / 10000,
|
||||||
jellyfinId: response.Id,
|
jellyfinId: response.Id,
|
||||||
streamUrl: this.jellyfinStreamBuilderService.buildStreamUrl(
|
streamUrl: this.jellyfinStreamBuilderService.buildStreamUrl(
|
||||||
response.Id,
|
response.Id,
|
||||||
@ -107,7 +115,19 @@ export class JellyfinWebSocketService implements OnModuleDestroy {
|
|||||||
TotalRecordCount: 0,
|
TotalRecordCount: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.playbackService.enqueTrackAndInstantyPlay(track);
|
|
||||||
|
const trackId = this.playbackService.enqueueTrack(track);
|
||||||
|
|
||||||
|
if (index !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playbackService.setActiveTrack(trackId);
|
||||||
|
this.playbackService.getActiveTrackAndEmitEvent();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.logger.error(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -43,7 +43,7 @@ export class PlaybackService {
|
|||||||
|
|
||||||
const newKey = keys[index + 1];
|
const newKey = keys[index + 1];
|
||||||
this.setActiveTrack(newKey);
|
this.setActiveTrack(newKey);
|
||||||
this.controlAudioPlayer();
|
this.getActiveTrackAndEmitEvent();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ export class PlaybackService {
|
|||||||
const keys = this.getTrackIds();
|
const keys = this.getTrackIds();
|
||||||
const newKey = keys[index - 1];
|
const newKey = keys[index - 1];
|
||||||
this.setActiveTrack(newKey);
|
this.setActiveTrack(newKey);
|
||||||
this.controlAudioPlayer();
|
this.getActiveTrackAndEmitEvent();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,10 +80,10 @@ export class PlaybackService {
|
|||||||
|
|
||||||
if (emptyBefore) {
|
if (emptyBefore) {
|
||||||
this.setActiveTrack(this.playlist.tracks.find((x) => x.id === uuid).id);
|
this.setActiveTrack(this.playlist.tracks.find((x) => x.id === uuid).id);
|
||||||
this.controlAudioPlayer();
|
this.getActiveTrackAndEmitEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.playlist.tracks.findIndex((x) => x.id === uuid);
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
enqueTrackAndInstantyPlay(track: Track) {
|
enqueTrackAndInstantyPlay(track: Track) {
|
||||||
@ -95,7 +95,7 @@ export class PlaybackService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.setActiveTrack(uuid);
|
this.setActiveTrack(uuid);
|
||||||
this.controlAudioPlayer();
|
this.getActiveTrackAndEmitEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
set(tracks: Track[]) {
|
set(tracks: Track[]) {
|
||||||
@ -133,7 +133,7 @@ export class PlaybackService {
|
|||||||
return this.getTrackIds().indexOf(this.playlist.activeTrack);
|
return this.getTrackIds().indexOf(this.playlist.activeTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
private controlAudioPlayer() {
|
getActiveTrackAndEmitEvent() {
|
||||||
const activeTrack = this.getActiveTrack();
|
const activeTrack = this.getActiveTrack();
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`A new track (${activeTrack.id}) was requested and will be emmitted as an event`,
|
`A new track (${activeTrack.id}) was requested and will be emmitted as an event`,
|
||||||
|
37
src/types/websocket.ts
Normal file
37
src/types/websocket.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
export class PlayNowCommand {
|
||||||
|
/**
|
||||||
|
* A list of all items available in the parent element.
|
||||||
|
* Usually, this is a list of all tracks in an album or playlist.
|
||||||
|
*/
|
||||||
|
ItemIds: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A nullable index, that references an item in the ItemIds array.
|
||||||
|
* If this index is present, the command sender wishes to play only this specific item.
|
||||||
|
* If there is no index present, the sender would like to play all items in the ItemIds array.
|
||||||
|
*/
|
||||||
|
StartIndex?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum of possible play modes.
|
||||||
|
* PlayNow: Play the selection immideatly
|
||||||
|
*/
|
||||||
|
PlayCommand: 'PlayNow';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user who has sent the command via web socket
|
||||||
|
*/
|
||||||
|
ControllingUserId: string;
|
||||||
|
|
||||||
|
hasSelection() {
|
||||||
|
return this.StartIndex !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelection(): string[] {
|
||||||
|
if (this.hasSelection()) {
|
||||||
|
return [this.ItemIds[this.StartIndex]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ItemIds;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user