mirror of
https://github.com/informaticker/discord-jellyfin-bot.git
synced 2024-11-25 02:51:57 +01:00
✨ Add enqueue random items command (#130)
This commit is contained in:
parent
2141880b44
commit
2c15e38b94
@ -39,7 +39,7 @@ export class DiscordMessageService {
|
|||||||
}: {
|
}: {
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
authorUrl?: string;
|
authorUrl?: string | undefined;
|
||||||
mixin?: (embedBuilder: EmbedBuilder) => EmbedBuilder;
|
mixin?: (embedBuilder: EmbedBuilder) => EmbedBuilder;
|
||||||
}): APIEmbed {
|
}): APIEmbed {
|
||||||
let embedBuilder = new EmbedBuilder()
|
let embedBuilder = new EmbedBuilder()
|
||||||
|
@ -170,6 +170,30 @@ export class JellyfinSearchService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getRandomTracks(limit: number) {
|
||||||
|
const api = this.jellyfinService.getApi();
|
||||||
|
const searchApi = getItemsApi(api);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await searchApi.getItems({
|
||||||
|
includeItemTypes: [BaseItemKind.Audio],
|
||||||
|
limit: limit,
|
||||||
|
sortBy: ['random'],
|
||||||
|
userId: this.jellyfinService.getUserId(),
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data.Items.map((item) => {
|
||||||
|
return SearchHint.constructFromBaseItem(item);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
this.logger.error(
|
||||||
|
`Unabele to retrieve random items from Jellyfin: ${err}`,
|
||||||
|
);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private transformToSearchHint(jellyifnHint: JellyfinSearchHint) {
|
private transformToSearchHint(jellyifnHint: JellyfinSearchHint) {
|
||||||
switch (jellyifnHint.Type) {
|
switch (jellyifnHint.Type) {
|
||||||
case BaseItemKind[BaseItemKind.Audio]:
|
case BaseItemKind[BaseItemKind.Audio]:
|
||||||
|
@ -15,6 +15,7 @@ import { StatusCommand } from './status.command';
|
|||||||
import { StopPlaybackCommand } from './stop.command';
|
import { StopPlaybackCommand } from './stop.command';
|
||||||
import { SummonCommand } from './summon.command';
|
import { SummonCommand } from './summon.command';
|
||||||
import { PlaylistInteractionCollector } from './playlist/playlist.interaction-collector';
|
import { PlaylistInteractionCollector } from './playlist/playlist.interaction-collector';
|
||||||
|
import { EnqueueRandomItemsCommand } from './random/random.command';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@ -28,6 +29,7 @@ import { PlaylistInteractionCollector } from './playlist/playlist.interaction-co
|
|||||||
PlaylistInteractionCollector,
|
PlaylistInteractionCollector,
|
||||||
HelpCommand,
|
HelpCommand,
|
||||||
StatusCommand,
|
StatusCommand,
|
||||||
|
EnqueueRandomItemsCommand,
|
||||||
PlaylistCommand,
|
PlaylistCommand,
|
||||||
DisconnectCommand,
|
DisconnectCommand,
|
||||||
PausePlaybackCommand,
|
PausePlaybackCommand,
|
||||||
|
77
src/commands/random/random.command.ts
Normal file
77
src/commands/random/random.command.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { SlashCommandPipe } from '@discord-nestjs/common';
|
||||||
|
import { Command, Handler, IA, InteractionEvent } from '@discord-nestjs/core';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import {
|
||||||
|
CommandInteraction,
|
||||||
|
GuildMember,
|
||||||
|
InteractionReplyOptions,
|
||||||
|
} from 'discord.js';
|
||||||
|
import { DiscordMessageService } from 'src/clients/discord/discord.message.service';
|
||||||
|
import { DiscordVoiceService } from 'src/clients/discord/discord.voice.service';
|
||||||
|
import { JellyfinSearchService } from 'src/clients/jellyfin/jellyfin.search.service';
|
||||||
|
import { SearchHint } from 'src/models/search/SearchHint';
|
||||||
|
import { Track } from 'src/models/shared/Track';
|
||||||
|
import { PlaybackService } from 'src/playback/playback.service';
|
||||||
|
import { RandomCommandParams } from './random.params';
|
||||||
|
|
||||||
|
@Command({
|
||||||
|
name: 'random',
|
||||||
|
description: 'Enqueues a random selection of tracks to your playlist',
|
||||||
|
})
|
||||||
|
@Injectable()
|
||||||
|
export class EnqueueRandomItemsCommand {
|
||||||
|
constructor(
|
||||||
|
private readonly playbackService: PlaybackService,
|
||||||
|
private readonly discordVoiceService: DiscordVoiceService,
|
||||||
|
private readonly discordMessageService: DiscordMessageService,
|
||||||
|
private readonly jellyfinSearchService: JellyfinSearchService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@Handler()
|
||||||
|
async handler(
|
||||||
|
@InteractionEvent(SlashCommandPipe) dto: RandomCommandParams,
|
||||||
|
@IA() interaction: CommandInteraction,
|
||||||
|
): Promise<void> {
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
const guildMember = interaction.member as GuildMember;
|
||||||
|
|
||||||
|
const tryResult =
|
||||||
|
this.discordVoiceService.tryJoinChannelAndEstablishVoiceConnection(
|
||||||
|
guildMember,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!tryResult.success) {
|
||||||
|
const replyOptions = tryResult.reply as InteractionReplyOptions;
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: replyOptions.embeds,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = await this.jellyfinSearchService.getRandomTracks(dto.count);
|
||||||
|
const tracks = await this.getTracks(items);
|
||||||
|
|
||||||
|
this.playbackService.getPlaylistOrDefault().enqueueTracks(tracks);
|
||||||
|
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
this.discordMessageService.buildMessage({
|
||||||
|
title: `Added ${tracks.length} tracks to your playlist`,
|
||||||
|
description: 'Use ``/playlist`` to see them',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getTracks(hints: SearchHint[]) {
|
||||||
|
const promises = await Promise.all(
|
||||||
|
hints.flatMap(async (item) => {
|
||||||
|
const tracks = await item.toTracks(this.jellyfinSearchService);
|
||||||
|
return tracks;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return promises.flatMap((x) => x);
|
||||||
|
}
|
||||||
|
}
|
12
src/commands/random/random.params.ts
Normal file
12
src/commands/random/random.params.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Param, ParamType } from '@discord-nestjs/core';
|
||||||
|
|
||||||
|
export class RandomCommandParams {
|
||||||
|
@Param({
|
||||||
|
required: false,
|
||||||
|
description: 'Count of items to search for',
|
||||||
|
type: ParamType.INTEGER,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 10000,
|
||||||
|
})
|
||||||
|
count = 20;
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
import { SearchHint as JellyfinSearchHint } from '@jellyfin/sdk/lib/generated-client/models';
|
import {
|
||||||
|
BaseItemDto,
|
||||||
|
SearchHint as JellyfinSearchHint,
|
||||||
|
} from '@jellyfin/sdk/lib/generated-client/models';
|
||||||
|
|
||||||
import { Track } from '../shared/Track';
|
|
||||||
import { JellyfinSearchService } from '../../clients/jellyfin/jellyfin.search.service';
|
import { JellyfinSearchService } from '../../clients/jellyfin/jellyfin.search.service';
|
||||||
|
import { Track } from '../shared/Track';
|
||||||
|
|
||||||
export class SearchHint {
|
export class SearchHint {
|
||||||
constructor(
|
constructor(
|
||||||
@ -28,4 +31,12 @@ export class SearchHint {
|
|||||||
static constructFromHint(hint: JellyfinSearchHint) {
|
static constructFromHint(hint: JellyfinSearchHint) {
|
||||||
return new SearchHint(hint.Id, hint.Name, hint.RunTimeTicks / 10000);
|
return new SearchHint(hint.Id, hint.Name, hint.RunTimeTicks / 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constructFromBaseItem(baseItem: BaseItemDto) {
|
||||||
|
return new SearchHint(
|
||||||
|
baseItem.Id,
|
||||||
|
baseItem.Name,
|
||||||
|
baseItem.RunTimeTicks / 10000,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user