diff --git a/frontend/src/components/Buttons/SubtitleSelectionButton.vue b/frontend/src/components/Buttons/SubtitleSelectionButton.vue index 2b73f9dc1c2..953a3e00290 100644 --- a/frontend/src/components/Buttons/SubtitleSelectionButton.vue +++ b/frontend/src/components/Buttons/SubtitleSelectionButton.vue @@ -79,8 +79,7 @@ export default defineComponent({ }, computed: { tracks(): PlaybackTrack[] { - const subs = this.playbackManager - .currentItemParsedSubtitleTracks as PlaybackTrack[]; + const subs = this.playbackManager.currentItemParsedSubtitleTracks ?? []; return [ { diff --git a/frontend/src/components/Item/ItemMenu.vue b/frontend/src/components/Item/ItemMenu.vue index aed7e98b239..651735e7369 100644 --- a/frontend/src/components/Item/ItemMenu.vue +++ b/frontend/src/components/Item/ItemMenu.vue @@ -226,8 +226,12 @@ function getLibraryOptions(): MenuOption[] { action: async (): Promise => { if (remote.sdk.api) { try { + if (!menuProps.item.Id) { + throw new Error('Expected item to have id'); + } + await getItemRefreshApi(remote.sdk.api).refreshItem({ - itemId: menuProps.item.Id as string, + itemId: menuProps.item.Id, replaceAllImages: false, replaceAllMetadata: false }); diff --git a/frontend/src/components/Layout/Carousel/Carousel.vue b/frontend/src/components/Layout/Carousel/Carousel.vue index 200530e7a2e..a664eb8ea67 100644 --- a/frontend/src/components/Layout/Carousel/Carousel.vue +++ b/frontend/src/components/Layout/Carousel/Carousel.vue @@ -97,12 +97,10 @@ function onSlideChange(): void { swiperInstance.value?.updateSlides(); } - // Propagate events to children - emit( - 'on-slide-change', - currentIndex.value, - swiperInstance.value as SwiperType - ); + if (swiperInstance.value) { + // Propagate events to children + emit('on-slide-change', currentIndex.value, swiperInstance.value); + } } /** * Handle touch events @@ -111,7 +109,9 @@ function onTouch(): void { isPaused.value = !isPaused.value; // Propagate events to children - emit('on-touch', isPaused.value, swiperInstance.value as SwiperType); + if (swiperInstance.value) { + emit('on-touch', isPaused.value, swiperInstance.value); + } } /** diff --git a/frontend/src/components/Playback/DraggableQueue.vue b/frontend/src/components/Playback/DraggableQueue.vue index b011f9f2015..9fde3ab3f03 100644 --- a/frontend/src/components/Playback/DraggableQueue.vue +++ b/frontend/src/components/Playback/DraggableQueue.vue @@ -72,9 +72,7 @@ const queue = computed({ }, set(newValue: BaseItemDto[]) { playbackManager.setNewQueue( - newValue.map((item) => { - return item.Id as string; - }) + newValue.map((item) => item.Id).filter((id): id is string => !!id) ); } }); diff --git a/frontend/src/pages/settings/index.vue b/frontend/src/pages/settings/index.vue index b802056c698..946e53394b3 100644 --- a/frontend/src/pages/settings/index.vue +++ b/frontend/src/pages/settings/index.vue @@ -141,10 +141,10 @@ import { version as clientVersion } from '@/../package.json'; const { t } = useI18n(); const route = useRoute(); const remote = useRemote(); -let systemInfo = {} as SystemInfo; route.meta.title = t('settings.settings'); +let systemInfo: SystemInfo = {}; if (remote.auth.currentUser?.Policy?.IsAdministrator) { systemInfo = (await remote.sdk.newUserApi(getSystemApi).getSystemInfo()).data; } diff --git a/frontend/src/plugins/remote/auth/index.ts b/frontend/src/plugins/remote/auth/index.ts index 947498f5c44..4887735b072 100644 --- a/frontend/src/plugins/remote/auth/index.ts +++ b/frontend/src/plugins/remote/auth/index.ts @@ -93,16 +93,18 @@ class RemotePluginAuth { const { data } = await getSystemApi(api).getPublicSystemInfo(); delete data.LocalAddress; - serv = data as ServerInfo; - serv.PublicAddress = serverUrl; - serv.isDefault = isDefault; + serv = { + ...data, + PublicAddress: serverUrl, + isDefault: isDefault + }; } catch (error) { useSnackbar(i18n.t('login.serverNotFound'), 'error'); - throw new Error(error as string); + throw error; } - const semverMajor = Number.parseInt(serv.Version?.split('.')[0] as string); - const semverMinor = Number.parseInt(serv.Version?.split('.')[1] as string); + const semverMajor = Number(serv.Version?.split('.')[0]); + const semverMinor = Number(serv.Version?.split('.')[1]); const isServerVersionSupported = semverMajor > 10 || (semverMajor === 10 && semverMinor >= 7); @@ -121,11 +123,15 @@ class RemotePluginAuth { state.value.servers.push(serv); } - state.value.currentServerIndex = state.value.servers.indexOf( - state.value.servers.find( - (serv) => serv.PublicAddress === serverUrl - ) as ServerInfo + const serverInfo = state.value.servers.find( + (serv) => serv.PublicAddress === serverUrl ); + if (!serverInfo) { + throw new Error('expected to find server by url'); + } + + state.value.currentServerIndex = + state.value.servers.indexOf(serverInfo); } } else { useSnackbar(i18n.t('login.serverVersionTooLow'), 'error'); @@ -219,7 +225,11 @@ class RemotePluginAuth { state.value.users.splice(state.value.users.indexOf(storeUser), 1); } - delete state.value.accessTokens[user.Id as string]; + if (!user.Id) { + throw new Error('expected user to have id'); + } + + delete state.value.accessTokens[user.Id]; } } /** diff --git a/frontend/src/store/items.ts b/frontend/src/store/items.ts index 269f8b1eb75..9c075fc02ce 100644 --- a/frontend/src/store/items.ts +++ b/frontend/src/store/items.ts @@ -156,7 +156,7 @@ class ItemsStore { state.value.collectionById[parent.Id] = childIds; - return this.getChildrenOfParent(parent.Id) as BaseItemDto[]; + return this.getChildrenOfParent(parent.Id) ?? []; }; /** @@ -196,7 +196,11 @@ class ItemsStore { if (childItems.Items) { const parent = this.getItemById(parentId); - return this.addCollection(parent as BaseItemDto, childItems.Items); + if (!parent) { + throw new Error('expected item to be found'); + } + + return this.addCollection(parent, childItems.Items); } }; diff --git a/frontend/src/utils/images.ts b/frontend/src/utils/images.ts index f9e62b13d5d..7b2445dacf8 100644 --- a/frontend/src/utils/images.ts +++ b/frontend/src/utils/images.ts @@ -372,7 +372,11 @@ export function getImageInfo( itemId = item.Id; } - const url_string = remote.sdk.api?.getItemImageUrl(itemId as string, imgType); + if (!itemId) { + throw new Error('expected itemId to have been set'); + } + + const url_string = remote.sdk.api?.getItemImageUrl(itemId, imgType); if (imgTag && imgType && itemId && url_string) { url = new URL(url_string); diff --git a/frontend/src/utils/supported-features.ts b/frontend/src/utils/supported-features.ts index 25d5b281fa2..62dc399ba20 100644 --- a/frontend/src/utils/supported-features.ts +++ b/frontend/src/utils/supported-features.ts @@ -34,17 +34,15 @@ function supportsFullscreen(): boolean { } const element = document.documentElement; + const video = document.createElement('video'); return !!( element.requestFullscreen || - // @ts-expect-error -- Non-standard property - element.mozRequestFullScreen || - // @ts-expect-error -- Non-standard property - element.webkitRequestFullscreen || - // @ts-expect-error -- Non-standard property - element.msRequestFullscreen || - // @ts-expect-error -- Non-standard property - document.createElement('video').webkitEnterFullscreen + // check properties that are not recorded on the element type + ('mozRequestFullScreen' in element && element.mozRequestFullScreen) || + ('webkitRequestFullscreen' in element && element.webkitRequestFullscreen) || + ('msRequestFullscreen' in element && element.msRequestFullscreen) || + ('webkitEnterFullscreen' in video && video.webkitEnterFullscreen) ); } @@ -52,13 +50,11 @@ const video = document.createElement('video'); if ( // Check non-standard Safari PiP support - // @ts-expect-error - Non-standard functions doesn't have typings - (typeof video.webkitSupportsPresentationMode === 'function' && - // @ts-expect-error - Non-standard functions doesn't have typings + ('webkitSupportsPresentationMode' in video && + typeof video.webkitSupportsPresentationMode === 'function' && video.webkitSupportsPresentationMode('picture-in-picture') && - // @ts-expect-error - Non-standard functions doesn't have typings - typeof video.webkitSetPresentationMode === 'function') || - // Check standard PiP support + 'webkitSetPresentationMode' in video && + typeof video.webkitSetPresentationMode) || document.pictureInPictureEnabled ) { supportedFeatures.pictureInPicture = true;