mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
298 lines
9.4 KiB
TypeScript
298 lines
9.4 KiB
TypeScript
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
|
import { ImageType } from '@jellyfin/sdk/lib/generated-client/models/image-type';
|
|
import { getImageApi } from '@jellyfin/sdk/lib/utils/api/image-api';
|
|
import { useApi } from 'hooks/useApi';
|
|
import { getDesiredAspect } from '../cardBuilderUtils';
|
|
import { CardShape } from 'utils/card';
|
|
import type { NullableNumber, NullableString } from 'types/base/common/shared/types';
|
|
import type { ItemDto } from 'types/itemDto';
|
|
import type { CardOptions } from 'types/cardOptions';
|
|
|
|
function getPreferThumbInfo(item: ItemDto, cardOptions: CardOptions) {
|
|
let imgType;
|
|
let itemId;
|
|
let imgTag;
|
|
let forceName = false;
|
|
|
|
if (item.ImageTags?.Thumb) {
|
|
imgType = ImageType.Thumb;
|
|
imgTag = item.ImageTags.Thumb;
|
|
itemId = item.Id;
|
|
} else if (item.SeriesThumbImageTag && cardOptions.inheritThumb !== false) {
|
|
imgType = ImageType.Thumb;
|
|
imgTag = item.SeriesThumbImageTag;
|
|
itemId = item.SeriesId;
|
|
} else if (
|
|
item.ParentThumbItemId
|
|
&& cardOptions.inheritThumb !== false
|
|
&& item.MediaType !== 'Photo'
|
|
) {
|
|
imgType = ImageType.Thumb;
|
|
imgTag = item.ParentThumbImageTag;
|
|
itemId = item.ParentThumbItemId;
|
|
} else if (item.BackdropImageTags?.length) {
|
|
imgType = ImageType.Backdrop;
|
|
imgTag = item.BackdropImageTags[0];
|
|
itemId = item.Id;
|
|
forceName = true;
|
|
} else if (
|
|
item.ParentBackdropImageTags?.length
|
|
&& cardOptions.inheritThumb !== false
|
|
&& item.Type === BaseItemKind.Episode
|
|
) {
|
|
imgType = ImageType.Backdrop;
|
|
imgTag = item.ParentBackdropImageTags[0];
|
|
itemId = item.ParentBackdropItemId;
|
|
}
|
|
return {
|
|
itemId: itemId,
|
|
imgTag: imgTag,
|
|
imgType: imgType,
|
|
forceName: forceName
|
|
};
|
|
}
|
|
|
|
function getPreferLogoInfo(item: ItemDto) {
|
|
let imgType;
|
|
let itemId;
|
|
let imgTag;
|
|
|
|
if (item.ImageTags?.Logo) {
|
|
imgType = ImageType.Logo;
|
|
imgTag = item.ImageTags.Logo;
|
|
itemId = item.Id;
|
|
} else if (item.ParentLogoImageTag && item.ParentLogoItemId) {
|
|
imgType = ImageType.Logo;
|
|
imgTag = item.ParentLogoImageTag;
|
|
itemId = item.ParentLogoItemId;
|
|
}
|
|
return {
|
|
itemId: itemId,
|
|
imgTag: imgTag,
|
|
imgType: imgType
|
|
};
|
|
}
|
|
|
|
function getCalculatedHeight(
|
|
itemWidth: NullableNumber,
|
|
itemPrimaryImageAspectRatio: NullableNumber
|
|
) {
|
|
if (itemWidth && itemPrimaryImageAspectRatio) {
|
|
return Math.round(itemWidth / itemPrimaryImageAspectRatio);
|
|
}
|
|
}
|
|
|
|
function isForceName(cardOptions: CardOptions) {
|
|
return !!(cardOptions.preferThumb && cardOptions.showTitle !== false);
|
|
}
|
|
|
|
function isCoverImage(
|
|
itemPrimaryImageAspectRatio: NullableNumber,
|
|
uiAspect: NullableNumber
|
|
) {
|
|
if (itemPrimaryImageAspectRatio && uiAspect) {
|
|
return Math.abs(itemPrimaryImageAspectRatio - uiAspect) / uiAspect <= 0.2;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function shouldShowPreferBanner(
|
|
imageTagsBanner: NullableString,
|
|
cardOptions: CardOptions,
|
|
shape: CardShape | undefined
|
|
): boolean {
|
|
return (
|
|
(cardOptions.preferBanner || shape === CardShape.Banner)
|
|
&& Boolean(imageTagsBanner)
|
|
);
|
|
}
|
|
|
|
function shouldShowPreferDisc(
|
|
imageTagsDisc: string | undefined,
|
|
cardOptions: CardOptions
|
|
): boolean {
|
|
return cardOptions.preferDisc === true && Boolean(imageTagsDisc);
|
|
}
|
|
|
|
function shouldShowImageTagsPrimary(item: ItemDto): boolean {
|
|
return (
|
|
Boolean(item.ImageTags?.Primary) && (item.Type !== BaseItemKind.Episode || item.ChildCount !== 0)
|
|
);
|
|
}
|
|
|
|
function shouldShowImageTagsThumb(item: ItemDto): boolean {
|
|
return item.Type === BaseItemKind.Season && Boolean(item.ImageTags?.Thumb);
|
|
}
|
|
|
|
function shouldShowSeriesThumbImageTag(
|
|
itemSeriesThumbImageTag: NullableString,
|
|
cardOptions: CardOptions
|
|
): boolean {
|
|
return (
|
|
Boolean(itemSeriesThumbImageTag) && cardOptions.inheritThumb !== false
|
|
);
|
|
}
|
|
|
|
function shouldShowParentThumbImageTag(
|
|
itemParentThumbItemId: NullableString,
|
|
cardOptions: CardOptions
|
|
): boolean {
|
|
return (
|
|
Boolean(itemParentThumbItemId) && cardOptions.inheritThumb !== false
|
|
);
|
|
}
|
|
|
|
function shouldShowParentBackdropImageTags(item: ItemDto): boolean {
|
|
return Boolean(item.AlbumId) && Boolean(item.AlbumPrimaryImageTag);
|
|
}
|
|
|
|
function shouldShowPreferThumb(itemType: NullableString, cardOptions: CardOptions): boolean {
|
|
return Boolean(cardOptions.preferThumb) && !(itemType === BaseItemKind.Program || itemType === BaseItemKind.Episode);
|
|
}
|
|
|
|
function getCardImageInfo(
|
|
item: ItemDto,
|
|
cardOptions: CardOptions,
|
|
shape: CardShape | undefined
|
|
) {
|
|
const width = cardOptions.width;
|
|
let height;
|
|
const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
|
|
let forceName = false;
|
|
let imgTag;
|
|
let coverImage = false;
|
|
const uiAspect = getDesiredAspect(shape);
|
|
let imgType;
|
|
let itemId;
|
|
|
|
if (shouldShowPreferThumb(item.Type, cardOptions)) {
|
|
const preferThumbInfo = getPreferThumbInfo(item, cardOptions);
|
|
imgType = preferThumbInfo.imgType;
|
|
imgTag = preferThumbInfo.imgTag;
|
|
itemId = preferThumbInfo.itemId;
|
|
forceName = preferThumbInfo.forceName;
|
|
} else if (shouldShowPreferBanner(item.ImageTags?.Banner, cardOptions, shape)) {
|
|
imgType = ImageType.Banner;
|
|
imgTag = item.ImageTags?.Banner;
|
|
itemId = item.Id;
|
|
} else if (shouldShowPreferDisc(item.ImageTags?.Disc, cardOptions)) {
|
|
imgType = ImageType.Disc;
|
|
imgTag = item.ImageTags?.Disc;
|
|
itemId = item.Id;
|
|
} else if (cardOptions.preferLogo) {
|
|
const preferLogoInfo = getPreferLogoInfo(item);
|
|
imgType = preferLogoInfo.imgType;
|
|
imgTag = preferLogoInfo.imgType;
|
|
itemId = preferLogoInfo.itemId;
|
|
} else if (shouldShowImageTagsPrimary(item)) {
|
|
imgType = ImageType.Primary;
|
|
imgTag = item.ImageTags?.Primary;
|
|
itemId = item.Id;
|
|
height = getCalculatedHeight(width, primaryImageAspectRatio);
|
|
forceName = isForceName(cardOptions);
|
|
coverImage = isCoverImage(primaryImageAspectRatio, uiAspect);
|
|
} else if (item.SeriesPrimaryImageTag) {
|
|
imgType = ImageType.Primary;
|
|
imgTag = item.SeriesPrimaryImageTag;
|
|
itemId = item.SeriesId;
|
|
} else if (item.PrimaryImageTag) {
|
|
imgType = ImageType.Primary;
|
|
imgTag = item.PrimaryImageTag;
|
|
itemId = item.PrimaryImageItemId;
|
|
height = getCalculatedHeight(width, primaryImageAspectRatio);
|
|
forceName = isForceName(cardOptions);
|
|
coverImage = isCoverImage(primaryImageAspectRatio, uiAspect);
|
|
} else if (item.ParentPrimaryImageTag) {
|
|
imgType = ImageType.Primary;
|
|
imgTag = item.ParentPrimaryImageTag;
|
|
itemId = item.ParentPrimaryImageItemId;
|
|
} else if (shouldShowParentBackdropImageTags(item)) {
|
|
imgType = ImageType.Primary;
|
|
imgTag = item.AlbumPrimaryImageTag;
|
|
itemId = item.AlbumId;
|
|
height = getCalculatedHeight(width, primaryImageAspectRatio);
|
|
forceName = isForceName(cardOptions);
|
|
coverImage = isCoverImage(primaryImageAspectRatio, uiAspect);
|
|
} else if (shouldShowImageTagsThumb(item)) {
|
|
imgType = ImageType.Thumb;
|
|
imgTag = item.ImageTags?.Thumb;
|
|
itemId = item.Id;
|
|
} else if (item.BackdropImageTags?.length) {
|
|
imgType = ImageType.Backdrop;
|
|
imgTag = item.BackdropImageTags[0];
|
|
itemId = item.Id;
|
|
} else if (shouldShowSeriesThumbImageTag(item.SeriesThumbImageTag, cardOptions)) {
|
|
imgType = ImageType.Thumb;
|
|
imgTag = item.SeriesThumbImageTag;
|
|
itemId = item.SeriesId;
|
|
} else if (shouldShowParentThumbImageTag(item.ParentThumbItemId, cardOptions)) {
|
|
imgType = ImageType.Thumb;
|
|
imgTag = item.ParentThumbImageTag;
|
|
itemId = item.ParentThumbItemId;
|
|
} else if (
|
|
item.ParentBackdropImageTags?.length
|
|
&& cardOptions.inheritThumb !== false
|
|
) {
|
|
imgType = ImageType.Backdrop;
|
|
imgTag = item.ParentBackdropImageTags[0];
|
|
itemId = item.ParentBackdropItemId;
|
|
}
|
|
|
|
return {
|
|
imgType,
|
|
imgTag,
|
|
itemId,
|
|
width,
|
|
height,
|
|
forceName,
|
|
coverImage
|
|
};
|
|
}
|
|
|
|
interface UseCardImageUrlProps {
|
|
item: ItemDto;
|
|
cardOptions: CardOptions;
|
|
shape: CardShape | undefined;
|
|
}
|
|
|
|
function useCardImageUrl({ item, cardOptions, shape }: UseCardImageUrlProps) {
|
|
const { api } = useApi();
|
|
const imgInfo = getCardImageInfo(item, cardOptions, shape);
|
|
|
|
let width = imgInfo.width;
|
|
let height = imgInfo.height;
|
|
const imgTag = imgInfo.imgTag;
|
|
const imgType = imgInfo.imgType;
|
|
const itemId = imgInfo.itemId;
|
|
const ratio = window.devicePixelRatio || 1;
|
|
let imgUrl;
|
|
let blurhash;
|
|
|
|
if (api && imgTag && imgType && itemId) {
|
|
if (width) {
|
|
width = Math.round(width * ratio);
|
|
}
|
|
|
|
if (height) {
|
|
height = Math.round(height * ratio);
|
|
}
|
|
imgUrl = getImageApi(api).getItemImageUrlById(itemId, imgType, {
|
|
quality: 96,
|
|
fillWidth: width,
|
|
fillHeight: height,
|
|
tag: imgTag
|
|
});
|
|
|
|
blurhash = item?.ImageBlurHashes?.[imgType]?.[imgTag];
|
|
}
|
|
|
|
return {
|
|
imgUrl: imgUrl,
|
|
blurhash: blurhash,
|
|
forceName: imgInfo.forceName,
|
|
coverImage: imgInfo.coverImage
|
|
};
|
|
}
|
|
|
|
export default useCardImageUrl;
|