mirror of
https://github.com/jeffvli/feishin.git
synced 2026-06-11 14:53:47 +02:00
Add image URL generation at runtime to allow for dynamic image sizes (#1439)
* add getImageUrl to domain endpoints * add new ItemImage component and hooks to generate image url * add configuration for image resolution based on types
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import clsx from 'clsx';
|
||||
import { AnimatePresence, HTMLMotionProps, motion, Variants } from 'motion/react';
|
||||
import { Fragment, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { generatePath } from 'react-router';
|
||||
import { Link } from 'react-router';
|
||||
import { Fragment, useEffect, useRef } from 'react';
|
||||
import { generatePath, Link } from 'react-router';
|
||||
|
||||
import styles from './full-screen-player-image.module.css';
|
||||
|
||||
import { useItemImageUrl } from '/@/renderer/components/item-image/item-image';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { usePlayerData, usePlayerSong } from '/@/renderer/store';
|
||||
import { useSettingsStore } from '/@/renderer/store/settings.store';
|
||||
@@ -17,6 +17,7 @@ import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { useSetState } from '/@/shared/hooks/use-set-state';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const imageVariants: Variants = {
|
||||
closed: {
|
||||
@@ -41,13 +42,6 @@ const imageVariants: Variants = {
|
||||
},
|
||||
};
|
||||
|
||||
const scaleImageUrl = (imageSize: number, url?: null | string) => {
|
||||
return url
|
||||
?.replace(/&size=\d+/, `&size=${imageSize}`)
|
||||
.replace(/\?width=\d+/, `?width=${imageSize}`)
|
||||
.replace(/&height=\d+/, `&height=${imageSize}`);
|
||||
};
|
||||
|
||||
const MotionImage = motion.img;
|
||||
|
||||
const ImageWithPlaceholder = ({
|
||||
@@ -85,44 +79,27 @@ const ImageWithPlaceholder = ({
|
||||
|
||||
export const FullScreenPlayerImage = () => {
|
||||
const mainImageRef = useRef<HTMLImageElement | null>(null);
|
||||
const [mainImageDimensions, setMainImageDimensions] = useState({ idealSize: 1 });
|
||||
|
||||
const albumArtRes = useSettingsStore((store) => store.general.albumArtRes);
|
||||
|
||||
const currentSong = usePlayerSong();
|
||||
const { nextSong } = usePlayerData();
|
||||
|
||||
const [imageState, setImageState] = useSetState({
|
||||
bottomImage: scaleImageUrl(mainImageDimensions.idealSize, nextSong?.imageUrl),
|
||||
current: 0,
|
||||
topImage: scaleImageUrl(mainImageDimensions.idealSize, currentSong?.imageUrl),
|
||||
const currentImageUrl = useItemImageUrl({
|
||||
id: currentSong?.id,
|
||||
itemType: LibraryItem.SONG,
|
||||
type: 'fullScreenPlayer',
|
||||
});
|
||||
|
||||
const updateImageSize = useCallback(() => {
|
||||
if (mainImageRef.current) {
|
||||
setMainImageDimensions({
|
||||
idealSize:
|
||||
albumArtRes ||
|
||||
Math.ceil((mainImageRef.current as HTMLDivElement).offsetHeight / 100) * 100,
|
||||
});
|
||||
const nextImageUrl = useItemImageUrl({
|
||||
id: nextSong?.id,
|
||||
itemType: LibraryItem.SONG,
|
||||
type: 'fullScreenPlayer',
|
||||
});
|
||||
|
||||
setImageState({
|
||||
bottomImage: scaleImageUrl(mainImageDimensions.idealSize, nextSong?.imageUrl),
|
||||
current: 0,
|
||||
topImage: scaleImageUrl(mainImageDimensions.idealSize, currentSong?.imageUrl),
|
||||
});
|
||||
}
|
||||
}, [
|
||||
mainImageDimensions.idealSize,
|
||||
setImageState,
|
||||
albumArtRes,
|
||||
currentSong?.imageUrl,
|
||||
nextSong?.imageUrl,
|
||||
]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
updateImageSize();
|
||||
}, [updateImageSize]);
|
||||
const [imageState, setImageState] = useSetState({
|
||||
bottomImage: nextImageUrl,
|
||||
current: 0,
|
||||
topImage: currentImageUrl,
|
||||
});
|
||||
|
||||
// Track previous song to detect changes
|
||||
const previousSongRef = useRef<string | undefined>(currentSong?._uniqueId);
|
||||
@@ -133,15 +110,13 @@ export const FullScreenPlayerImage = () => {
|
||||
imageStateRef.current = imageState;
|
||||
}, [imageState]);
|
||||
|
||||
// Update images when song changes
|
||||
// Update images when song or size changes
|
||||
useEffect(() => {
|
||||
if (currentSong?._uniqueId === previousSongRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isTop = imageStateRef.current.current === 0;
|
||||
const currentImageUrl = scaleImageUrl(mainImageDimensions.idealSize, currentSong?.imageUrl);
|
||||
const nextImageUrl = scaleImageUrl(mainImageDimensions.idealSize, nextSong?.imageUrl);
|
||||
|
||||
setImageState({
|
||||
bottomImage: isTop ? currentImageUrl : nextImageUrl,
|
||||
@@ -150,13 +125,7 @@ export const FullScreenPlayerImage = () => {
|
||||
});
|
||||
|
||||
previousSongRef.current = currentSong?._uniqueId;
|
||||
}, [
|
||||
currentSong?._uniqueId,
|
||||
currentSong?.imageUrl,
|
||||
nextSong?.imageUrl,
|
||||
mainImageDimensions.idealSize,
|
||||
setImageState,
|
||||
]);
|
||||
}, [currentSong?._uniqueId, currentImageUrl, nextSong?._uniqueId, nextImageUrl, setImageState]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
|
||||
Reference in New Issue
Block a user