From aec90cbc96598a57a597fae91d70b707272bdb85 Mon Sep 17 00:00:00 2001 From: TheMelmacian <76712303+TheMelmacian@users.noreply.github.com> Date: Fri, 7 Jul 2023 22:51:19 +0200 Subject: [PATCH] use random backdrop image on item details pages --- CONTRIBUTORS.md | 1 + src/controllers/itemDetails/index.js | 29 ++------------- src/utils/url.ts | 55 ++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 52006a7b4..eccfd4cf2 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -65,6 +65,7 @@ - [Merlin Sievers](https://github.com/dann-merlin) - [Fishbigger](https://github.com/fishbigger) - [sleepycatcoding](https://github.com/sleepycatcoding) + - [TheMelmacian](https://github.com/TheMelmacian) # Emby Contributors diff --git a/src/controllers/itemDetails/index.js b/src/controllers/itemDetails/index.js index 37f5d3108..719c1b267 100644 --- a/src/controllers/itemDetails/index.js +++ b/src/controllers/itemDetails/index.js @@ -36,6 +36,7 @@ import Dashboard from '../../utils/dashboard'; import ServerConnections from '../../components/ServerConnections'; import confirm from '../../components/confirm/confirm'; import { download } from '../../scripts/fileDownloader'; +import { getRandomItemBackdropImageUrl } from '../../utils/url'; function autoFocus(container) { import('../../components/autoFocuser').then(({ default: autoFocuser }) => { @@ -501,34 +502,12 @@ function renderDetailPageBackdrop(page, item, apiClient) { return false; } - let imgUrl; let hasbackdrop = false; const itemBackdropElement = page.querySelector('#itemBackdrop'); - if (item.BackdropImageTags?.length) { - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Backdrop', - maxWidth: dom.getScreenWidth(), - index: 0, - tag: item.BackdropImageTags[0] - }); - imageLoader.lazyImage(itemBackdropElement, imgUrl); - hasbackdrop = true; - } else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { - imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: 'Backdrop', - maxWidth: dom.getScreenWidth(), - index: 0, - tag: item.ParentBackdropImageTags[0] - }); - imageLoader.lazyImage(itemBackdropElement, imgUrl); - hasbackdrop = true; - } else if (item.ImageTags?.Primary) { - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Primary', - maxWidth: dom.getScreenWidth(), - tag: item.ImageTags.Primary - }); + const imgUrl = getRandomItemBackdropImageUrl(apiClient, item, { maxWitdh: dom.getScreenWidth() }); + + if (imgUrl) { imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else { diff --git a/src/utils/url.ts b/src/utils/url.ts index 1c65b2343..e65df92ab 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -1,3 +1,7 @@ +import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'; +import { randomInt } from './number'; +import { ApiClient } from 'jellyfin-apiclient'; + /** * Gets the url search string. * This function should be used instead of location.search alone, because the app router @@ -33,3 +37,54 @@ export const getParameterByName = (name: string, url?: string | null | undefined // eslint-disable-next-line compat/compat return new URLSearchParams(url).get(name) || ''; }; + +export interface ScaleImageOptions { + maxWidth?: number; + width?: number; + maxHeight?: number; + height?: number; + fillWidth?: number; + fillHeight?: number; + quality?: number; +} + +/** + * Returns the url of a random backdrop image of an item. + * If the item has no backdrop image, the url of a random backdrop image of the parent item is returned. + * Falls back to the primary image (cover) of the item, if neither the item nor it's parent have at least one backdrop image. + * Returns undefined if no usable image was found. + * @param apiClient The ApiClient to generate the url. + * @param item The item for which the backdrop image is requested. + * @param options Optional; allows to scale the backdrop image. + * @returns The url of a random backdrop image of the provided item. + */ +export const getRandomItemBackdropImageUrl = (apiClient: ApiClient, item: BaseItemDto, options: ScaleImageOptions = {}): string | undefined => { + let imgUrl; + + if (item.BackdropImageTags && item.BackdropImageTags.length) { + const backdropImgIndex = randomInt(0, item.BackdropImageTags.length - 1); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + imgUrl = apiClient.getScaledImageUrl(item.Id!, { + type: 'Backdrop', + index: backdropImgIndex, + tag: item.BackdropImageTags[backdropImgIndex], + ...options + }); + } else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { + const backdropImgIndex = randomInt(0, item.ParentBackdropImageTags.length - 1); + imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { + type: 'Backdrop', + index: backdropImgIndex, + tag: item.ParentBackdropImageTags[backdropImgIndex], + ...options + }); + } else if (item.ImageTags && item.ImageTags.Primary) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + imgUrl = apiClient.getScaledImageUrl(item.Id!, { + type: 'Primary', + tag: item.ImageTags.Primary, + ...options + }); + } + return imgUrl; +};