mirror of
https://github.com/informaticker/discord-jellyfin-bot.git
synced 2024-11-23 18:21:55 +01:00
✨ Add search result embed
This commit is contained in:
parent
4693b2f75f
commit
2aa2d16e40
@ -3,6 +3,7 @@ import { JellyfinService } from './jellyfin.service';
|
|||||||
|
|
||||||
import { SearchHint } from '@jellyfin/sdk/lib/generated-client/models';
|
import { SearchHint } from '@jellyfin/sdk/lib/generated-client/models';
|
||||||
import { getSearchApi } from '@jellyfin/sdk/lib/utils/api/search-api';
|
import { getSearchApi } from '@jellyfin/sdk/lib/utils/api/search-api';
|
||||||
|
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api/items-api';
|
||||||
import { Logger } from '@nestjs/common/services';
|
import { Logger } from '@nestjs/common/services';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -28,4 +29,20 @@ export class JellyfinSearchService {
|
|||||||
|
|
||||||
return SearchHints;
|
return SearchHints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getById(id: string): Promise<SearchHint> {
|
||||||
|
const api = this.jellyfinService.getApi();
|
||||||
|
|
||||||
|
const searchApi = getItemsApi(api);
|
||||||
|
const { data } = await searchApi.getItems({
|
||||||
|
ids: [id],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.Items.length !== 1) {
|
||||||
|
this.logger.warn(`Failed to retrieve item via id '${id}'`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.Items[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@ export class EnqueueCommand
|
|||||||
dto: TrackRequestDto,
|
dto: TrackRequestDto,
|
||||||
executionContext: TransformedCommandExecutionContext<any>,
|
executionContext: TransformedCommandExecutionContext<any>,
|
||||||
): InteractionReplyOptions | string {
|
): InteractionReplyOptions | string {
|
||||||
const index = this.playbackService.eneuqueTrack({});
|
// const index = this.playbackService.eneuqueTrack({});
|
||||||
|
const index = 0;
|
||||||
return {
|
return {
|
||||||
embeds: [
|
embeds: [
|
||||||
this.discordMessageService.buildMessage({
|
this.discordMessageService.buildMessage({
|
||||||
|
@ -3,21 +3,31 @@ import { TransformPipe } from '@discord-nestjs/common';
|
|||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
DiscordTransformedCommand,
|
DiscordTransformedCommand,
|
||||||
Param,
|
On,
|
||||||
Payload,
|
Payload,
|
||||||
TransformedCommandExecutionContext,
|
TransformedCommandExecutionContext,
|
||||||
UsePipes,
|
UsePipes,
|
||||||
} from '@discord-nestjs/core';
|
} from '@discord-nestjs/core';
|
||||||
|
import { SearchHint } from '@jellyfin/sdk/lib/generated-client/models';
|
||||||
|
import { Logger } from '@nestjs/common/services';
|
||||||
import {
|
import {
|
||||||
APIEmbedField,
|
|
||||||
ComponentType,
|
ComponentType,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
|
Events,
|
||||||
|
Interaction,
|
||||||
InteractionReplyOptions,
|
InteractionReplyOptions,
|
||||||
} from 'discord.js';
|
} from 'discord.js';
|
||||||
import { JellyfinSearchService } from '../clients/jellyfin/jellyfin.search.service';
|
import { JellyfinSearchService } from '../clients/jellyfin/jellyfin.search.service';
|
||||||
import { TrackRequestDto } from '../models/track-request.dto';
|
import { TrackRequestDto } from '../models/track-request.dto';
|
||||||
import { DefaultJellyfinColor } from '../types/colors';
|
import { DefaultJellyfinColor } from '../types/colors';
|
||||||
|
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { DiscordMessageService } from '../clients/discord/discord.message.service';
|
||||||
|
|
||||||
|
import { formatDuration, intervalToDuration } from 'date-fns';
|
||||||
|
import { format } from 'path';
|
||||||
|
import { PlaybackService } from '../playback/playback.service';
|
||||||
|
|
||||||
@Command({
|
@Command({
|
||||||
name: 'search',
|
name: 'search',
|
||||||
description: 'Search for an item on your Jellyfin instance',
|
description: 'Search for an item on your Jellyfin instance',
|
||||||
@ -26,7 +36,13 @@ import { DefaultJellyfinColor } from '../types/colors';
|
|||||||
export class SearchItemCommand
|
export class SearchItemCommand
|
||||||
implements DiscordTransformedCommand<TrackRequestDto>
|
implements DiscordTransformedCommand<TrackRequestDto>
|
||||||
{
|
{
|
||||||
constructor(private readonly jellyfinSearchService: JellyfinSearchService) {}
|
private readonly logger: Logger = new Logger(SearchItemCommand.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly jellyfinSearchService: JellyfinSearchService,
|
||||||
|
private readonly discordMessageService: DiscordMessageService,
|
||||||
|
private readonly playbackService: PlaybackService,
|
||||||
|
) {}
|
||||||
|
|
||||||
async handler(
|
async handler(
|
||||||
@Payload() dto: TrackRequestDto,
|
@Payload() dto: TrackRequestDto,
|
||||||
@ -88,7 +104,7 @@ export class SearchItemCommand
|
|||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
type: ComponentType.StringSelect,
|
type: ComponentType.StringSelect,
|
||||||
customId: 'cool',
|
customId: 'searchItemSelect',
|
||||||
options: selectOptions,
|
options: selectOptions,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -97,6 +113,61 @@ export class SearchItemCommand
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@On(Events.InteractionCreate)
|
||||||
|
async onStringSelect(interaction: Interaction) {
|
||||||
|
if (!interaction.isStringSelectMenu()) return;
|
||||||
|
|
||||||
|
if (interaction.customId !== 'searchItemSelect') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.values.length !== 1) {
|
||||||
|
this.logger.warn(
|
||||||
|
`Failed to process interaction select with values [${interaction.values.length}]`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = await this.jellyfinSearchService.getById(
|
||||||
|
interaction.values[0],
|
||||||
|
);
|
||||||
|
|
||||||
|
const milliseconds = item.RunTimeTicks / 10000;
|
||||||
|
|
||||||
|
const duration = formatDuration(
|
||||||
|
intervalToDuration({
|
||||||
|
start: milliseconds,
|
||||||
|
end: 0,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const artists = item.Artists.join(', ');
|
||||||
|
|
||||||
|
const addedIndex = this.playbackService.eneuqueTrack({
|
||||||
|
jellyfinId: item.Id,
|
||||||
|
name: item.Name,
|
||||||
|
durationInMilliseconds: milliseconds,
|
||||||
|
});
|
||||||
|
|
||||||
|
await interaction.update({
|
||||||
|
embeds: [
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setAuthor({
|
||||||
|
name: 'Jellyfin Search',
|
||||||
|
iconURL:
|
||||||
|
'https://github.com/walkxcode/dashboard-icons/blob/main/png/jellyfin.png?raw=true',
|
||||||
|
})
|
||||||
|
.setTitle(item.Name)
|
||||||
|
.setDescription(
|
||||||
|
`**Duration**: ${duration}\n**Artists**: ${artists}\n\nTrack was added to the queue at position ${addedIndex}`,
|
||||||
|
)
|
||||||
|
.setColor(DefaultJellyfinColor)
|
||||||
|
.toJSON(),
|
||||||
|
],
|
||||||
|
components: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private markSearchTermOverlap(value: string, searchTerm: string) {
|
private markSearchTermOverlap(value: string, searchTerm: string) {
|
||||||
const startIndex = value.indexOf(searchTerm);
|
const startIndex = value.indexOf(searchTerm);
|
||||||
const actualValue = value.substring(
|
const actualValue = value.substring(
|
||||||
|
@ -1 +1,5 @@
|
|||||||
export interface Track {}
|
export interface Track {
|
||||||
|
jellyfinId: string;
|
||||||
|
name: string;
|
||||||
|
durationInMilliseconds: number;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user