mirror of
https://github.com/informaticker/discord-jellyfin-bot.git
synced 2024-10-18 19:35:04 +02:00
♻️ Model names (#246)
This commit is contained in:
parent
56d7f0f03d
commit
e04e5cae50
@ -16,10 +16,10 @@ import { Logger } from '@nestjs/common/services';
|
||||
import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
|
||||
import { Interval } from '@nestjs/schedule';
|
||||
|
||||
import { GuildMember } from 'discord.js';
|
||||
import { APIEmbed, GuildMember, InteractionEditReplyOptions, InteractionReplyOptions, MessagePayload } from 'discord.js';
|
||||
|
||||
import { GenericTryHandler } from '../../models/generic-try-handler';
|
||||
import { Track } from '../../models/shared/Track';
|
||||
import { TryResult } from '../../models/TryResult';
|
||||
import { Track } from '../../models/music/Track';
|
||||
import { PlaybackService } from '../../playback/playback.service';
|
||||
import { JellyfinStreamBuilderService } from '../jellyfin/jellyfin.stream.builder.service';
|
||||
import { JellyfinWebSocketService } from '../jellyfin/jellyfin.websocket.service';
|
||||
@ -54,7 +54,7 @@ export class DiscordVoiceService {
|
||||
|
||||
tryJoinChannelAndEstablishVoiceConnection(
|
||||
member: GuildMember,
|
||||
): GenericTryHandler {
|
||||
): TryResult<InteractionReplyOptions> {
|
||||
if (this.voiceConnection !== undefined) {
|
||||
this.logger.debug(
|
||||
'Avoided joining the voice channel because voice connection is already defined',
|
||||
@ -182,7 +182,7 @@ export class DiscordVoiceService {
|
||||
return true;
|
||||
}
|
||||
|
||||
disconnect(): GenericTryHandler {
|
||||
disconnect(): TryResult<string | MessagePayload | InteractionEditReplyOptions> {
|
||||
if (this.voiceConnection === undefined) {
|
||||
return {
|
||||
success: false,
|
||||
|
@ -11,7 +11,7 @@ import { getSessionApi } from '@jellyfin/sdk/lib/utils/api/session-api';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { Interval } from '@nestjs/schedule';
|
||||
import { Track } from '../../models/shared/Track';
|
||||
import { Track } from '../../models/music/Track';
|
||||
|
||||
import { PlaybackService } from '../../playback/playback.service';
|
||||
|
||||
|
@ -12,9 +12,9 @@ import { getSearchApi } from '@jellyfin/sdk/lib/utils/api/search-api';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Logger } from '@nestjs/common/services';
|
||||
|
||||
import { AlbumSearchHint } from '../../models/search/AlbumSearchHint';
|
||||
import { PlaylistSearchHint } from '../../models/search/PlaylistSearchHint';
|
||||
import { SearchHint } from '../../models/search/SearchHint';
|
||||
import { AlbumSearchItem } from '../../models/search/AlbumSearchItem';
|
||||
import { PlaylistSearchItem } from '../../models/search/PlaylistSearchItem';
|
||||
import { SearchItem } from '../../models/search/SearchItem';
|
||||
|
||||
import { JellyfinService } from './jellyfin.service';
|
||||
|
||||
@ -32,7 +32,7 @@ export class JellyfinSearchService {
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.Playlist,
|
||||
],
|
||||
): Promise<SearchHint[]> {
|
||||
): Promise<SearchItem[]> {
|
||||
const api = this.jellyfinService.getApi();
|
||||
const searchApi = getSearchApi(api);
|
||||
|
||||
@ -64,14 +64,14 @@ export class JellyfinSearchService {
|
||||
|
||||
return SearchHints.map((hint) =>
|
||||
this.transformToSearchHintFromHint(hint),
|
||||
).filter((x) => x !== null) as SearchHint[];
|
||||
).filter((x) => x !== null) as SearchItem[];
|
||||
} catch (err) {
|
||||
this.logger.error(`Failed to search on Jellyfin: ${err}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getPlaylistitems(id: string): Promise<SearchHint[]> {
|
||||
async getPlaylistitems(id: string): Promise<SearchItem[]> {
|
||||
const api = this.jellyfinService.getApi();
|
||||
const searchApi = getPlaylistsApi(api);
|
||||
|
||||
@ -95,11 +95,11 @@ export class JellyfinSearchService {
|
||||
}
|
||||
|
||||
return axiosResponse.data.Items.map((hint) =>
|
||||
SearchHint.constructFromBaseItem(hint),
|
||||
SearchItem.constructFromBaseItem(hint),
|
||||
);
|
||||
}
|
||||
|
||||
async getAlbumItems(albumId: string): Promise<SearchHint[]> {
|
||||
async getAlbumItems(albumId: string): Promise<SearchItem[]> {
|
||||
const api = this.jellyfinService.getApi();
|
||||
const searchApi = getSearchApi(api);
|
||||
const axiosResponse = await searchApi.get({
|
||||
@ -125,13 +125,13 @@ export class JellyfinSearchService {
|
||||
|
||||
return [...axiosResponse.data.SearchHints]
|
||||
.reverse()
|
||||
.map((hint) => SearchHint.constructFromHint(hint));
|
||||
.map((hint) => SearchItem.constructFromHint(hint));
|
||||
}
|
||||
|
||||
async getById(
|
||||
id: string,
|
||||
includeItemTypes: BaseItemKind[],
|
||||
): Promise<SearchHint | undefined> {
|
||||
): Promise<SearchItem | undefined> {
|
||||
const api = this.jellyfinService.getApi();
|
||||
|
||||
const searchApi = getItemsApi(api);
|
||||
@ -152,7 +152,7 @@ export class JellyfinSearchService {
|
||||
async getAllById(
|
||||
ids: string[],
|
||||
includeItemTypes: BaseItemKind[] = [BaseItemKind.Audio],
|
||||
): Promise<SearchHint[]> {
|
||||
): Promise<SearchItem[]> {
|
||||
const api = this.jellyfinService.getApi();
|
||||
|
||||
const searchApi = getItemsApi(api);
|
||||
@ -169,7 +169,7 @@ export class JellyfinSearchService {
|
||||
|
||||
return data.Items.map((item) =>
|
||||
this.transformToSearchHintFromBaseItemDto(item),
|
||||
).filter((searchHint) => searchHint !== undefined) as SearchHint[];
|
||||
).filter((searchHint) => searchHint !== undefined) as SearchItem[];
|
||||
}
|
||||
|
||||
async getRemoteImageById(id: string, limit = 20): Promise<RemoteImageResult> {
|
||||
@ -233,7 +233,7 @@ export class JellyfinSearchService {
|
||||
}
|
||||
|
||||
return response.data.Items.map((item) => {
|
||||
return SearchHint.constructFromBaseItem(item);
|
||||
return SearchItem.constructFromBaseItem(item);
|
||||
});
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
@ -246,11 +246,11 @@ export class JellyfinSearchService {
|
||||
private transformToSearchHintFromHint(jellyifnHint: JellyfinSearchHint) {
|
||||
switch (jellyifnHint.Type) {
|
||||
case BaseItemKind[BaseItemKind.Audio]:
|
||||
return SearchHint.constructFromHint(jellyifnHint);
|
||||
return SearchItem.constructFromHint(jellyifnHint);
|
||||
case BaseItemKind[BaseItemKind.MusicAlbum]:
|
||||
return AlbumSearchHint.constructFromHint(jellyifnHint);
|
||||
return AlbumSearchItem.constructFromHint(jellyifnHint);
|
||||
case BaseItemKind[BaseItemKind.Playlist]:
|
||||
return PlaylistSearchHint.constructFromHint(jellyifnHint);
|
||||
return PlaylistSearchItem.constructFromHint(jellyifnHint);
|
||||
default:
|
||||
this.logger.warn(
|
||||
`Received unexpected item type from Jellyfin search: ${jellyifnHint.Type}`,
|
||||
@ -262,11 +262,11 @@ export class JellyfinSearchService {
|
||||
private transformToSearchHintFromBaseItemDto(baseItemDto: BaseItemDto) {
|
||||
switch (baseItemDto.Type) {
|
||||
case BaseItemKind[BaseItemKind.Audio]:
|
||||
return SearchHint.constructFromBaseItem(baseItemDto);
|
||||
return SearchItem.constructFromBaseItem(baseItemDto);
|
||||
case BaseItemKind[BaseItemKind.MusicAlbum]:
|
||||
return AlbumSearchHint.constructFromBaseItem(baseItemDto);
|
||||
return AlbumSearchItem.constructFromBaseItem(baseItemDto);
|
||||
case BaseItemKind[BaseItemKind.Playlist]:
|
||||
return PlaylistSearchHint.constructFromBaseItem(baseItemDto);
|
||||
return PlaylistSearchItem.constructFromBaseItem(baseItemDto);
|
||||
default:
|
||||
this.logger.warn(
|
||||
`Received unexpected item type from Jellyfin search: ${baseItemDto.Type}`,
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import { convertToTracks } from 'src/utils/trackConverter';
|
||||
import { flatMapTrackItems } from 'src/utils/trackConverter';
|
||||
|
||||
import { WebSocket } from 'ws';
|
||||
|
||||
@ -105,7 +105,7 @@ export class JellyfinWebSocketService implements OnModuleDestroy {
|
||||
`Processing ${ids.length} ids received via websocket and adding them to the queue`,
|
||||
);
|
||||
const searchHints = await this.jellyfinSearchService.getAllById(ids);
|
||||
const tracks = convertToTracks(searchHints, this.jellyfinSearchService);
|
||||
const tracks = flatMapTrackItems(searchHints, this.jellyfinSearchService);
|
||||
this.playbackService.getPlaylistOrDefault().enqueueTracks(tracks);
|
||||
break;
|
||||
case SessionMessageType[SessionMessageType.Playstate]:
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
import { DiscordMessageService } from '../../clients/discord/discord.message.service';
|
||||
import { DiscordVoiceService } from '../../clients/discord/discord.voice.service';
|
||||
import { JellyfinSearchService } from '../../clients/jellyfin/jellyfin.search.service';
|
||||
import { SearchHint } from '../../models/search/SearchHint';
|
||||
import { SearchItem } from '../../models/search/SearchItem';
|
||||
import { PlaybackService } from '../../playback/playback.service';
|
||||
import { formatMillisecondsAsHumanReadable } from '../../utils/timeUtils';
|
||||
|
||||
@ -55,7 +55,7 @@ export class PlayItemCommand {
|
||||
|
||||
const baseItems = PlayCommandParams.getBaseItemKinds(dto.type);
|
||||
|
||||
let item: SearchHint | undefined;
|
||||
let item: SearchItem | undefined;
|
||||
if (dto.name.startsWith('native-')) {
|
||||
item = await this.jellyfinSearchService.getById(
|
||||
dto.name.replace('native-', ''),
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
} from 'discord.js';
|
||||
|
||||
import { DiscordMessageService } from '../../clients/discord/discord.message.service';
|
||||
import { Track } from '../../models/shared/Track';
|
||||
import { Track } from '../../models/music/Track';
|
||||
import { PlaybackService } from '../../playback/playback.service';
|
||||
import { chunkArray } from '../../utils/arrayUtils';
|
||||
import {
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
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 { SearchItem } from 'src/models/search/SearchItem';
|
||||
import { PlaybackService } from 'src/playback/playback.service';
|
||||
import { RandomCommandParams } from './random.params';
|
||||
import { defaultMemberPermissions } from 'src/utils/environment';
|
||||
@ -65,7 +65,7 @@ export class EnqueueRandomItemsCommand {
|
||||
});
|
||||
}
|
||||
|
||||
private async getTracks(hints: SearchHint[]) {
|
||||
private async getTracks(hints: SearchItem[]) {
|
||||
const promises = await Promise.all(
|
||||
hints.flatMap(async (item) => {
|
||||
const tracks = await item.toTracks(this.jellyfinSearchService);
|
||||
|
@ -8,7 +8,7 @@ import { CommandInteraction } from 'discord.js';
|
||||
import { DiscordMessageService } from 'src/clients/discord/discord.message.service';
|
||||
import { DiscordVoiceService } from 'src/clients/discord/discord.voice.service';
|
||||
import { PlaybackService } from 'src/playback/playback.service';
|
||||
import { sleep } from 'src/utils/timeUtils';
|
||||
import { sleepAsync } from 'src/utils/timeUtils';
|
||||
import { VolumeCommandParams } from './volume.params';
|
||||
import { defaultMemberPermissions } from 'src/utils/environment';
|
||||
|
||||
@ -56,7 +56,7 @@ export class VolumeCommand {
|
||||
this.discordVoiceService.changeVolume(volume);
|
||||
|
||||
// Discord takes some time to react. Confirmation message should appear after actual change
|
||||
await sleep(1500);
|
||||
await sleepAsync(1500);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [
|
||||
|
4
src/models/TryResult.ts
Normal file
4
src/models/TryResult.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface TryResult<T> {
|
||||
success: boolean;
|
||||
reply: T;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import { InteractionEditReplyOptions, MessagePayload } from 'discord.js';
|
||||
|
||||
export interface GenericTryHandler {
|
||||
success: boolean;
|
||||
reply: string | MessagePayload | InteractionEditReplyOptions;
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import { SearchHint as JellyfinSearchHint } from '@jellyfin/sdk/lib/generated-client/models';
|
||||
|
||||
import { Track } from '../shared/Track';
|
||||
import { Track } from '../music/Track';
|
||||
import { JellyfinSearchService } from '../../clients/jellyfin/jellyfin.search.service';
|
||||
|
||||
import { SearchHint } from './SearchHint';
|
||||
import { SearchItem } from './SearchItem';
|
||||
import { trimStringToFixedLength } from 'src/utils/stringUtils/stringUtils';
|
||||
|
||||
export class AlbumSearchHint extends SearchHint {
|
||||
export class AlbumSearchItem extends SearchItem {
|
||||
override toString(): string {
|
||||
return `🎶 ${this.name}`;
|
||||
}
|
||||
@ -22,7 +22,7 @@ export class AlbumSearchHint extends SearchHint {
|
||||
artist = hint.AlbumArtist + " - "
|
||||
}
|
||||
|
||||
return new AlbumSearchHint(
|
||||
return new AlbumSearchItem(
|
||||
hint.Id,
|
||||
trimStringToFixedLength(artist + hint.Name, 70),
|
||||
hint.RunTimeTicks / 10000,
|
@ -1,13 +1,13 @@
|
||||
import { SearchHint as JellyfinSearchHint } from '@jellyfin/sdk/lib/generated-client/models';
|
||||
|
||||
import { Track } from '../shared/Track';
|
||||
import { Track } from '../music/Track';
|
||||
import { JellyfinSearchService } from '../../clients/jellyfin/jellyfin.search.service';
|
||||
|
||||
import { SearchHint } from './SearchHint';
|
||||
import { convertToTracks } from 'src/utils/trackConverter';
|
||||
import { SearchItem } from './SearchItem';
|
||||
import { flatMapTrackItems } from 'src/utils/trackConverter';
|
||||
import { trimStringToFixedLength } from 'src/utils/stringUtils/stringUtils';
|
||||
|
||||
export class PlaylistSearchHint extends SearchHint {
|
||||
export class PlaylistSearchItem extends SearchItem {
|
||||
override toString(): string {
|
||||
return `🎧 ${this.name}`;
|
||||
}
|
||||
@ -19,7 +19,7 @@ export class PlaylistSearchHint extends SearchHint {
|
||||
);
|
||||
}
|
||||
|
||||
return new PlaylistSearchHint(
|
||||
return new PlaylistSearchItem(
|
||||
hint.Id,
|
||||
trimStringToFixedLength(hint.Name, 50),
|
||||
hint.RunTimeTicks / 10000,
|
||||
@ -30,6 +30,6 @@ export class PlaylistSearchHint extends SearchHint {
|
||||
searchService: JellyfinSearchService,
|
||||
): Promise<Track[]> {
|
||||
const playlistItems = await searchService.getPlaylistitems(this.id);
|
||||
return convertToTracks(playlistItems, searchService);
|
||||
return flatMapTrackItems(playlistItems, searchService);
|
||||
}
|
||||
}
|
@ -5,10 +5,10 @@ import {
|
||||
import { z } from 'zod';
|
||||
|
||||
import { JellyfinSearchService } from '../../clients/jellyfin/jellyfin.search.service';
|
||||
import { Track } from '../shared/Track';
|
||||
import { Track } from '../music/Track';
|
||||
import { trimStringToFixedLength } from 'src/utils/stringUtils/stringUtils';
|
||||
|
||||
export class SearchHint {
|
||||
export class SearchItem {
|
||||
constructor(
|
||||
protected readonly id: string,
|
||||
protected readonly name: string,
|
||||
@ -54,7 +54,7 @@ export class SearchHint {
|
||||
artist += " - "
|
||||
}
|
||||
}
|
||||
return new SearchHint(
|
||||
return new SearchItem(
|
||||
result.data.Id,
|
||||
trimStringToFixedLength(artist + result.data.Name, 70),
|
||||
result.data.RunTimeTicks / 10000,
|
||||
@ -67,7 +67,7 @@ export class SearchHint {
|
||||
'Unable to construct search hint from base item, required properties were undefined',
|
||||
);
|
||||
}
|
||||
return new SearchHint(
|
||||
return new SearchItem(
|
||||
baseItem.Id,
|
||||
trimStringToFixedLength(baseItem.Name, 50),
|
||||
baseItem.RunTimeTicks / 10000,
|
@ -1,7 +1,7 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
|
||||
|
||||
import { Playlist } from '../models/shared/Playlist';
|
||||
import { Playlist } from '../models/music/Playlist';
|
||||
|
||||
@Injectable()
|
||||
export class PlaybackService {
|
||||
|
@ -3,7 +3,7 @@ import axios from 'axios';
|
||||
import { Client, GuildMember } from 'discord.js';
|
||||
import { Constants } from '../utils/constants';
|
||||
import { DiscordMessageService } from '../clients/discord/discord.message.service';
|
||||
import { GithubRelease } from '../models/github-release';
|
||||
import { GithubRelease } from '../models/GithubRelease';
|
||||
import { useDefaultMockerToken } from '../utils/tests/defaultMockerToken';
|
||||
import { UpdatesService } from './updates.service';
|
||||
import { InjectionToken } from '@nestjs/common';
|
||||
|
@ -6,7 +6,7 @@ import axios from 'axios';
|
||||
import { formatRelative, parseISO } from 'date-fns';
|
||||
import { ActionRowBuilder, ButtonStyle, Client } from 'discord.js';
|
||||
import { DiscordMessageService } from '../clients/discord/discord.message.service';
|
||||
import { GithubRelease } from '../models/github-release';
|
||||
import { GithubRelease } from '../models/GithubRelease';
|
||||
import { Constants } from '../utils/constants';
|
||||
|
||||
@Injectable()
|
||||
|
@ -16,6 +16,6 @@ export const formatMillisecondsAsHumanReadable = (
|
||||
return duration;
|
||||
};
|
||||
|
||||
export function sleep(ms: number) {
|
||||
export function sleepAsync(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { JellyfinSearchService } from 'src/clients/jellyfin/jellyfin.search.service';
|
||||
import { SearchHint } from 'src/models/search/SearchHint';
|
||||
import { Track } from 'src/models/shared/Track';
|
||||
import { SearchItem } from 'src/models/search/SearchItem';
|
||||
import { Track } from 'src/models/music/Track';
|
||||
|
||||
export const convertToTracks = (
|
||||
hints: SearchHint[],
|
||||
export const flatMapTrackItems = (
|
||||
hints: SearchItem[],
|
||||
jellyfinSearchService: JellyfinSearchService,
|
||||
): Track[] => {
|
||||
let tracks: Track[] = [];
|
||||
|
Loading…
Reference in New Issue
Block a user