diff --git a/eslint.config.mjs b/eslint.config.mjs index 27bfc245..20a351df 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -12,6 +12,7 @@ export default [ jsdoc.configs['flat/recommended'], eslintPluginPrettierRecommended, ...tseslint.configs.strict, + ...tseslint.configs.stylisticTypeChecked, promise.configs['flat/recommended'], importPlugin.flatConfigs.errors, importPlugin.flatConfigs.warnings, diff --git a/src/components/__tests__/jellyfinApi.test.ts b/src/components/__tests__/jellyfinApi.test.ts index fc905c65..e1390249 100644 --- a/src/components/__tests__/jellyfinApi.test.ts +++ b/src/components/__tests__/jellyfinApi.test.ts @@ -3,7 +3,7 @@ import { JellyfinApi } from '../jellyfinApi'; import { version } from '../../../package.json'; const setupMockCastSenders = (): void => { - const getSenders = (): Array => [{ id: 'thisIsSenderId' }]; // eslint-disable-line @typescript-eslint/no-explicit-any + const getSenders = (): any[] => [{ id: 'thisIsSenderId' }]; // eslint-disable-line @typescript-eslint/no-explicit-any const getInstance = (): any => ({ getSenders }); // eslint-disable-line @typescript-eslint/no-explicit-any // @ts-expect-error cast is already defined globally, however since we're mocking it we need to redefine it. diff --git a/src/components/codecSupportHelper.ts b/src/components/codecSupportHelper.ts index bcf931df..92e017e8 100644 --- a/src/components/codecSupportHelper.ts +++ b/src/components/codecSupportHelper.ts @@ -191,7 +191,7 @@ export function getH265LevelSupport(deviceId: DeviceIds): number { * Get VPX (VP8, VP9) codecs supported by the active Cast device. * @returns Supported VPX codecs. */ -export function getSupportedVPXVideoCodecs(): Array { +export function getSupportedVPXVideoCodecs(): string[] { const codecs = []; if (hasVP8Support()) { @@ -209,7 +209,7 @@ export function getSupportedVPXVideoCodecs(): Array { * Get supported video codecs suitable for use in an MP4 container. * @returns Supported MP4 video codecs. */ -export function getSupportedMP4VideoCodecs(): Array { +export function getSupportedMP4VideoCodecs(): string[] { const codecs = ['h264']; if (hasH265Support()) { @@ -224,7 +224,7 @@ export function getSupportedMP4VideoCodecs(): Array { * Get supported audio codecs suitable for use in an MP4 container. * @returns Supported MP4 audio codecs. */ -export function getSupportedMP4AudioCodecs(): Array { +export function getSupportedMP4AudioCodecs(): string[] { const codecs = []; if (hasEAC3Support()) { @@ -245,7 +245,7 @@ export function getSupportedMP4AudioCodecs(): Array { * Get supported video codecs suitable for use with HLS. * @returns Supported HLS video codecs. */ -export function getSupportedHLSVideoCodecs(): Array { +export function getSupportedHLSVideoCodecs(): string[] { // Currently the server does not support fmp4 which is required // by the HLS spec for streaming H.265 video. return ['h264']; @@ -255,7 +255,7 @@ export function getSupportedHLSVideoCodecs(): Array { * Get supported audio codecs suitable for use with HLS. * @returns All supported HLS audio codecs. */ -export function getSupportedHLSAudioCodecs(): Array { +export function getSupportedHLSAudioCodecs(): string[] { // HLS basically supports whatever MP4 supports. return getSupportedMP4AudioCodecs(); } @@ -264,7 +264,7 @@ export function getSupportedHLSAudioCodecs(): Array { * Get supported audio codecs suitable for use in a WebM container. * @returns All supported WebM audio codecs. */ -export function getSupportedWebMAudioCodecs(): Array { +export function getSupportedWebMAudioCodecs(): string[] { return ['vorbis', 'opus']; } @@ -272,6 +272,6 @@ export function getSupportedWebMAudioCodecs(): Array { * Get supported audio codecs suitable for use in a WebM container. * @returns All supported WebM audio codecs. */ -export function getSupportedAudioCodecs(): Array { +export function getSupportedAudioCodecs(): string[] { return ['opus', 'mp3', 'aac', 'flac', 'webma', 'wav']; } diff --git a/src/components/commandHandler.ts b/src/components/commandHandler.ts index 43c8ba59..6c070119 100644 --- a/src/components/commandHandler.ts +++ b/src/components/commandHandler.ts @@ -55,36 +55,36 @@ export abstract class CommandHandler { } static playNextHandler(data: DataMessage): void { - translateItems(data, data.options, data.command); + translateItems(data, data.options as PlayRequest, data.command); } static playNowHandler(data: DataMessage): void { - translateItems(data, data.options, data.command); + translateItems(data, data.options as PlayRequest, data.command); } static playLastHandler(data: DataMessage): void { - translateItems(data, data.options, data.command); + translateItems(data, data.options as PlayRequest, data.command); } static shuffleHandler(data: DataMessage): void { shuffle( data, - data.options, - (data.options).items[0] + data.options as PlayRequest, + (data.options as PlayRequest).items[0] ); } static instantMixHandler(data: DataMessage): void { instantMix( data, - data.options, - (data.options).items[0] + data.options as PlayRequest, + (data.options as PlayRequest).items[0] ); } static displayContentHandler(data: DataMessage): void { if (!PlaybackManager.isPlaying()) { - DocumentManager.showItemId((data.options).ItemId); + DocumentManager.showItemId((data.options as DisplayRequest).ItemId); } } @@ -103,14 +103,14 @@ export abstract class CommandHandler { static setAudioStreamIndexHandler(data: DataMessage): void { setAudioStreamIndex( PlaybackManager.playbackState, - (data.options).index + (data.options as SetIndexRequest).index ); } static setSubtitleStreamIndexHandler(data: DataMessage): void { setSubtitleStreamIndex( PlaybackManager.playbackState, - (data.options).index + (data.options as SetIndexRequest).index ); } @@ -155,7 +155,7 @@ export abstract class CommandHandler { static SeekHandler(data: DataMessage): void { seek( PlaybackManager.playbackState, - (data.options).position * TicksPerSecond + (data.options as SeekRequest).position * TicksPerSecond ); } @@ -189,7 +189,7 @@ export abstract class CommandHandler { } static SetRepeatModeHandler(data: DataMessage): void { - window.repeatMode = (data.options).RepeatMode; + window.repeatMode = (data.options as SetRepeatModeRequest).RepeatMode; window.reportEventType = 'repeatmodechange'; } @@ -200,7 +200,7 @@ export abstract class CommandHandler { // We should avoid using a defaulthandler that has a purpose other than informing the dev/user // Currently all unhandled commands will be treated as play commands. static defaultHandler(data: DataMessage): void { - translateItems(data, data.options, 'play'); + translateItems(data, data.options as PlayRequest, 'play'); } static processMessage(data: DataMessage, command: string): void { diff --git a/src/components/credentialManager.ts b/src/components/credentialManager.ts index 953c4d77..75b18042 100644 --- a/src/components/credentialManager.ts +++ b/src/components/credentialManager.ts @@ -4,9 +4,7 @@ export interface ServerCredential { serverBasePath?: string; } -interface CredentialStore { - [id: string]: ServerCredential; -} +type CredentialStore = Record; export class credentialManager { /** diff --git a/src/components/deviceprofileBuilder.ts b/src/components/deviceprofileBuilder.ts index 1bf1751a..c535114b 100644 --- a/src/components/deviceprofileBuilder.ts +++ b/src/components/deviceprofileBuilder.ts @@ -68,7 +68,7 @@ function createProfileCondition( * @todo Why does this always return an empty array? * @returns Container profiles. */ -function getContainerProfiles(): Array { +function getContainerProfiles(): ContainerProfile[] { return []; } @@ -76,8 +76,8 @@ function getContainerProfiles(): Array { * Get direct play profiles * @returns Direct play profiles. */ -function getDirectPlayProfiles(): Array { - const DirectPlayProfiles: Array = []; +function getDirectPlayProfiles(): DirectPlayProfile[] { + const DirectPlayProfiles: DirectPlayProfile[] = []; if (currentDeviceId !== DeviceIds.AUDIO) { const mp4VideoCodecs = getSupportedMP4VideoCodecs(); @@ -140,8 +140,8 @@ function getDirectPlayProfiles(): Array { * Get codec profiles * @returns Codec profiles. */ -function getCodecProfiles(): Array { - const CodecProfiles: Array = []; +function getCodecProfiles(): CodecProfile[] { + const CodecProfiles: CodecProfile[] = []; const audioConditions: CodecProfile = { Codec: 'flac', @@ -285,8 +285,8 @@ function getCodecProfiles(): Array { * Get transcoding profiles * @returns Transcoding profiles. */ -function getTranscodingProfiles(): Array { - const TranscodingProfiles: Array = []; +function getTranscodingProfiles(): TranscodingProfile[] { + const TranscodingProfiles: TranscodingProfile[] = []; const hlsAudioCodecs = getSupportedHLSAudioCodecs(); const audioChannels: number = hasSurroundSupport() ? 6 : 2; @@ -364,8 +364,8 @@ function getTranscodingProfiles(): Array { * Get subtitle profiles * @returns Subtitle profiles. */ -function getSubtitleProfiles(): Array { - const subProfiles: Array = []; +function getSubtitleProfiles(): SubtitleProfile[] { + const subProfiles: SubtitleProfile[] = []; if (hasTextTrackSupport(currentDeviceId)) { subProfiles.push({ diff --git a/src/components/documentManager.ts b/src/components/documentManager.ts index c493bff7..f4212876 100644 --- a/src/components/documentManager.ts +++ b/src/components/documentManager.ts @@ -304,11 +304,7 @@ export abstract class DocumentManager { let src: string | null = null; if (item != null) { - if ( - item.BackdropImageTags && - item.BackdropImageTags.length && - item.Id - ) { + if (item.BackdropImageTags?.length && item.Id) { // get first backdrop of image if applicable src = JellyfinApi.createImageUrl( item.Id, @@ -317,8 +313,7 @@ export abstract class DocumentManager { ); } else if ( item.ParentBackdropItemId && - item.ParentBackdropImageTags && - item.ParentBackdropImageTags.length + item.ParentBackdropImageTags?.length ) { // otherwise get first backdrop from parent src = JellyfinApi.createImageUrl( @@ -376,7 +371,7 @@ export abstract class DocumentManager { let src: string | null = null; let item: BaseItemDto | null = null; - if (result.Items && result.Items[0]) { + if (result.Items?.[0]) { item = result.Items[0]; src = await DocumentManager.getWaitingBackdropUrl(item); } @@ -459,11 +454,7 @@ export abstract class DocumentManager { let backdropUrl: string | null = null; - if ( - item.BackdropImageTags && - item.BackdropImageTags.length && - item.Id - ) { + if (item.BackdropImageTags?.length && item.Id) { backdropUrl = JellyfinApi.createImageUrl( item.Id, 'Backdrop', @@ -471,8 +462,7 @@ export abstract class DocumentManager { ); } else if ( item.ParentBackdropItemId && - item.ParentBackdropImageTags && - item.ParentBackdropImageTags.length + item.ParentBackdropImageTags?.length ) { backdropUrl = JellyfinApi.createImageUrl( item.ParentBackdropItemId, @@ -521,7 +511,8 @@ export abstract class DocumentManager { * @param item - source for the displayed name */ private static setDisplayName(item: BaseItemDto): void { - const name: string = item.EpisodeTitle ?? item.Name; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const name: string = item.EpisodeTitle ?? item.Name!; let displayName: string = name; @@ -555,7 +546,7 @@ export abstract class DocumentManager { private static setGenres(name: string | null): void { const element = this.querySelector('.genres'); - element.innerHTML = name || ''; + element.innerHTML = name ?? ''; } /** @@ -565,7 +556,7 @@ export abstract class DocumentManager { private static setOverview(name: string | null): void { const element = this.querySelector('.overview'); - element.innerHTML = name || ''; + element.innerHTML = name ?? ''; } /** @@ -574,9 +565,9 @@ export abstract class DocumentManager { * @param value - Percentage to set */ private static setPlayedPercentage(value = 0): void { - const element = ( - this.querySelector('.itemProgressBar') - ); + const element = this.querySelector( + '.itemProgressBar' + ) as HTMLInputElement; element.value = value.toString(); } @@ -590,9 +581,9 @@ export abstract class DocumentManager { const element = this.querySelector('.detailImageProgressContainer'); if (value) { - (element).classList.remove('d-none'); + (element as HTMLElement).classList.remove('d-none'); } else { - (element).classList.add('d-none'); + (element as HTMLElement).classList.add('d-none'); } } @@ -643,7 +634,7 @@ export abstract class DocumentManager { * @param item - to look up */ private static setMiscInfo(item: BaseItemDto): void { - const info: Array = []; + const info: string[] = []; if (item.Type == 'Episode') { if (item.PremiereDate) { diff --git a/src/components/fetchhelper.ts b/src/components/fetchhelper.ts index 371a22e7..7122ced1 100644 --- a/src/components/fetchhelper.ts +++ b/src/components/fetchhelper.ts @@ -128,7 +128,7 @@ export async function ajax(request: any): Promise { request.dataType === 'text' || (response.headers.get('Content-Type') || '') .toLowerCase() - .indexOf('text/') === 0 + .startsWith('text/') ) { return response.text(); } else { diff --git a/src/components/jellyfinApi.ts b/src/components/jellyfinApi.ts index eaaf2782..b98690b1 100644 --- a/src/components/jellyfinApi.ts +++ b/src/components/jellyfinApi.ts @@ -58,15 +58,15 @@ export abstract class JellyfinApi { }; if (this.accessToken) { - parameters['Token'] = this.accessToken; + parameters.Token = this.accessToken; } if (this.deviceId) { - parameters['DeviceId'] = this.deviceId; + parameters.DeviceId = this.deviceId; } if (this.deviceName) { - parameters['Device'] = this.deviceName; + parameters.Device = this.deviceName; } let header = 'MediaBrowser'; @@ -93,7 +93,7 @@ export abstract class JellyfinApi { } // Remove leading slashes - while (path.charAt(0) === '/') { + while (path.startsWith('/')) { path = path.substring(1); } @@ -104,7 +104,7 @@ export abstract class JellyfinApi { public static createUserUrl(path: string | null = null): string { if (path) { // Remove leading slashes - while (path.charAt(0) === '/') { + while (path.startsWith('/')) { path = path.substring(1); } diff --git a/src/components/maincontroller.ts b/src/components/maincontroller.ts index f5d82680..5a25232b 100644 --- a/src/components/maincontroller.ts +++ b/src/components/maincontroller.ts @@ -98,7 +98,7 @@ export function onMediaElementPlaying(): void { * @param event - event */ function onMediaElementVolumeChange(event: framework.system.Event): void { - window.volume = (event).data; + window.volume = (event as framework.system.SystemVolumeChangedEvent).data; console.log(`Received volume update: ${window.volume.level}`); if (JellyfinApi.serverAddress !== null) { @@ -386,11 +386,11 @@ export function setSubtitleStreamIndex( let positionTicks; // FIXME: Possible index error when MediaStreams is undefined. - const currentSubtitleStream = state.mediaSource?.MediaStreams?.filter( + const currentSubtitleStream = state.mediaSource?.MediaStreams?.find( (m: MediaStream) => { return m.Index == state.subtitleStreamIndex && m.Type == 'Subtitle'; } - )[0]; + ); const currentDeliveryMethod = currentSubtitleStream ? currentSubtitleStream.DeliveryMethod @@ -414,11 +414,8 @@ export function setSubtitleStreamIndex( const mediaStreams = state.PlaybackMediaSource?.MediaStreams; - const subtitleStream = getStreamByIndex( - mediaStreams, - 'Subtitle', - index - ); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const subtitleStream = getStreamByIndex(mediaStreams!, 'Subtitle', index); if (!subtitleStream) { console.log( @@ -519,17 +516,12 @@ export async function changeStream( // @ts-expect-error is possible here return await PlaybackManager.playItemInternal(state.item, { - audioStreamIndex: - params.AudioStreamIndex == null - ? state.audioStreamIndex - : params.AudioStreamIndex, + audioStreamIndex: params.AudioStreamIndex ?? state.audioStreamIndex, liveStreamId: state.liveStreamId, mediaSourceId: state.mediaSourceId, startPositionTicks: ticks, subtitleStreamIndex: - params.SubtitleStreamIndex == null - ? state.subtitleStreamIndex - : params.SubtitleStreamIndex + params.SubtitleStreamIndex ?? state.subtitleStreamIndex }); } @@ -707,25 +699,26 @@ export function showPlaybackInfoErrorMessage(error: string): void { * @returns stream */ export function getOptimalMediaSource( - versions: Array -): MediaSourceInfo { - let optimalVersion = versions.filter((v) => { + versions: MediaSourceInfo[] +): MediaSourceInfo | null { + let optimalVersion = versions.find((v) => { checkDirectPlay(v); return v.SupportsDirectPlay; - })[0]; + }); if (!optimalVersion) { - optimalVersion = versions.filter((v) => { + optimalVersion = versions.find((v) => { return v.SupportsDirectStream; - })[0]; + }); } return ( - optimalVersion || - versions.filter((s) => { + optimalVersion ?? + versions.find((s) => { return s.SupportsTranscoding; - })[0] + }) ?? + null ); } @@ -738,8 +731,7 @@ export function checkDirectPlay(mediaSource: MediaSourceInfo): void { if ( mediaSource.SupportsDirectPlay && mediaSource.Protocol == 'Http' && - (!mediaSource.RequiredHttpHeaders || - !mediaSource.RequiredHttpHeaders.length) + !mediaSource.RequiredHttpHeaders?.length ) { return; } @@ -763,7 +755,7 @@ export function setTextTrack(index: number | null): void { return; } - const tracks: Array = + const tracks: framework.messages.Track[] = textTracksManager.getTracks(); const subtitleTrack: framework.messages.Track | undefined = tracks.find( (track: framework.messages.Track) => { @@ -771,7 +763,7 @@ export function setTextTrack(index: number | null): void { } ); - if (subtitleTrack && subtitleTrack.trackId !== undefined) { + if (subtitleTrack?.trackId !== undefined) { textTracksManager.setActiveByIds([subtitleTrack.trackId]); const subtitleAppearance = window.subtitleAppearance; diff --git a/src/components/playbackManager.ts b/src/components/playbackManager.ts index 9532697d..10d7792b 100644 --- a/src/components/playbackManager.ts +++ b/src/components/playbackManager.ts @@ -54,7 +54,7 @@ export interface PlaybackState { // eslint-disable-next-line @typescript-eslint/no-extraneous-class export abstract class PlaybackManager { private static playerManager: framework.PlayerManager; - private static activePlaylist: Array; + private static activePlaylist: BaseItemDto[]; private static activePlaylistIndex: number; static playbackState: PlaybackState = { diff --git a/src/helpers.ts b/src/helpers.ts index 04a13eb1..291ac32d 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -93,11 +93,11 @@ export function getSenderReportingData( const nowPlayingItem = state.NowPlayingItem; nowPlayingItem.ServerId = item.ServerId; - nowPlayingItem.Chapters = item.Chapters || []; + nowPlayingItem.Chapters = item.Chapters ?? []; - const mediaSource = item.MediaSources?.filter((m: MediaSourceInfo) => { + const mediaSource = item.MediaSources?.find((m: MediaSourceInfo) => { return m.Id == reportingData.MediaSourceId; - })[0]; + }); nowPlayingItem.MediaStreams = mediaSource ? mediaSource.MediaStreams @@ -116,7 +116,7 @@ export function getSenderReportingData( nowPlayingItem.Album = item.Album; nowPlayingItem.Artists = item.Artists; - const imageTags = item.ImageTags || {}; + const imageTags = item.ImageTags ?? {}; if (item.SeriesPrimaryImageTag) { nowPlayingItem.PrimaryImageItemId = item.SeriesId; @@ -129,13 +129,10 @@ export function getSenderReportingData( nowPlayingItem.PrimaryImageTag = item.AlbumPrimaryImageTag; } - if (item.BackdropImageTags && item.BackdropImageTags.length) { + if (item.BackdropImageTags?.length) { nowPlayingItem.BackdropItemId = item.Id; nowPlayingItem.BackdropImageTag = item.BackdropImageTags[0]; - } else if ( - item.ParentBackdropImageTags && - item.ParentBackdropImageTags.length - ) { + } else if (item.ParentBackdropImageTags?.length) { nowPlayingItem.BackdropItemId = item.ParentBackdropItemId; nowPlayingItem.BackdropImageTag = item.ParentBackdropImageTags[0]; } @@ -219,8 +216,7 @@ export function getMetadata(item: BaseItemDto): any { } else if (item.Type == 'Audio') { metadata = new cast.framework.messages.MusicTrackMediaMetadata(); metadata.songName = item.Name; - metadata.artist = - item.Artists && item.Artists.length ? item.Artists.join(', ') : ''; + metadata.artist = item.Artists?.length ? item.Artists.join(', ') : ''; metadata.albumArtist = item.AlbumArtist; metadata.albumName = item.Album; @@ -239,9 +235,9 @@ export function getMetadata(item: BaseItemDto): any { } // previously: p.PersonType == 'Type'.. wtf? - const composer = (item.People || []).filter( + const composer = (item.People ?? []).find( (p: BaseItemPerson) => p.Type == 'Composer' - )[0]; + ); if (composer) { metadata.composer = composer.Name; @@ -263,7 +259,7 @@ export function getMetadata(item: BaseItemDto): any { ).toISOString(); } - if (item.Studios && item.Studios.length) { + if (item.Studios?.length) { metadata.studio = item.Studios[0]; } } @@ -326,25 +322,22 @@ export function createStreamInfo( `videos/${item.Id}/stream.${mediaSource.Container}?mediaSourceId=${mediaSource.Id}&api_key=${JellyfinApi.accessToken}&static=true${seekParam}` ); isStatic = true; - playerStartPositionTicks = startPosition || 0; + playerStartPositionTicks = startPosition ?? 0; } else { // TODO deal with !TranscodingUrl - mediaUrl = JellyfinApi.createUrl( - mediaSource.TranscodingUrl - ); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + mediaUrl = JellyfinApi.createUrl(mediaSource.TranscodingUrl!); if (isHlsStream(mediaSource)) { mediaUrl += seekParam; - playerStartPositionTicks = startPosition || 0; + playerStartPositionTicks = startPosition ?? 0; contentType = 'application/x-mpegURL'; streamContainer = 'm3u8'; } else { contentType = `video/${mediaSource.TranscodingContainer}`; streamContainer = mediaSource.TranscodingContainer; - if ( - mediaUrl.toLowerCase().indexOf('copytimestamps=true') != -1 - ) { + if (mediaUrl.toLowerCase().includes('copytimestamps=true')) { startPosition = 0; } } @@ -355,13 +348,13 @@ export function createStreamInfo( if (mediaSource.SupportsDirectPlay) { mediaUrl = mediaSource.Path; isStatic = true; - playerStartPositionTicks = startPosition || 0; + playerStartPositionTicks = startPosition ?? 0; } else { const isDirectStream = mediaSource.SupportsDirectStream; if (isDirectStream) { const outputContainer = ( - mediaSource.Container || '' + mediaSource.Container ?? '' ).toLowerCase(); mediaUrl = JellyfinApi.createUrl( @@ -373,16 +366,15 @@ export function createStreamInfo( contentType = `audio/${mediaSource.TranscodingContainer}`; // TODO deal with !TranscodingUrl - mediaUrl = JellyfinApi.createUrl( - mediaSource.TranscodingUrl - ); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + mediaUrl = JellyfinApi.createUrl(mediaSource.TranscodingUrl!); } } } // TODO: Remove the second half of the expression by supporting changing the mediaElement src dynamically. // It is a pain and will require unbinding all event handlers during the operation - const canSeek = (mediaSource.RunTimeTicks || 0) > 0; + const canSeek = (mediaSource.RunTimeTicks ?? 0) > 0; // eslint-disable-next-line @typescript-eslint/no-explicit-any const info: any = { @@ -403,7 +395,7 @@ export function createStreamInfo( mediaSource.MediaStreams?.filter((stream: MediaStream) => { return stream.Type === 'Subtitle'; }) ?? []; - const subtitleTracks: Array = []; + const subtitleTracks: framework.messages.Track[] = []; // eslint-disable-next-line @typescript-eslint/no-explicit-any subtitleStreams.forEach((subtitleStream: any) => { @@ -450,14 +442,14 @@ export function createStreamInfo( * @returns first first matching stream */ export function getStreamByIndex( - streams: Array, + streams: MediaStream[], type: string, index: number // eslint-disable-next-line @typescript-eslint/no-explicit-any ): any { - return streams.filter((s) => { + return streams.find((s) => { return s.Type == type && s.Index == index; - })[0]; + }); } // defined for use in the 3 next functions @@ -560,7 +552,7 @@ export async function getItemsForPlayback( query: ItemQuery ): Promise { query.UserId = userId; - query.Limit = query.Limit || 100; + query.Limit = query.Limit ?? 100; query.Fields = requiredItemFields; query.ExcludeLocationTypes = 'Virtual'; @@ -640,7 +632,7 @@ export function getUser(): Promise { */ export async function translateRequestedItems( userId: string, - items: Array, + items: BaseItemDto[], smart = false ): Promise { const firstItem = items[0]; @@ -720,7 +712,7 @@ export async function translateRequestedItems( } ); - episodesResult.TotalRecordCount = episodesResult.Items?.length || 0; + episodesResult.TotalRecordCount = episodesResult.Items?.length ?? 0; return episodesResult; } diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 6a54b6af..ccb7a6a4 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -9,9 +9,7 @@ import type { } from '@jellyfin/sdk/lib/generated-client'; import { TextTrackEdgeType } from 'chromecast-caf-receiver/cast.framework.messages'; -export interface Dictionary { - [Key: string]: T; -} +export type Dictionary = Record; // Jellyfin Server // Why doesn't the API have a type for this? @@ -85,9 +83,7 @@ export interface DataMessage { command: string; } -interface SupportedCommands { - [command: string]: (data: DataMessage) => void; -} +type SupportedCommands = Record void>; // /From commandHandler interface SubtitleAppearance {