diff --git a/src/renderer/features/albums/routes/album-detail-route.tsx b/src/renderer/features/albums/routes/album-detail-route.tsx
index 66d57d49..cf069ce7 100644
--- a/src/renderer/features/albums/routes/album-detail-route.tsx
+++ b/src/renderer/features/albums/routes/album-detail-route.tsx
@@ -1,4 +1,4 @@
-import { NativeScrollArea } from '/@/renderer/components';
+import { NativeScrollArea, Spinner } from '/@/renderer/components';
import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared';
import { useRef } from 'react';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
@@ -20,7 +20,11 @@ const AlbumDetailRoute = () => {
const { albumId } = useParams() as { albumId: string };
const server = useCurrentServer();
const detailQuery = useAlbumDetail({ query: { id: albumId }, serverId: server?.id });
- const background = useFastAverageColor(detailQuery.data?.imageUrl, !detailQuery.isLoading);
+ const { color: background, colorId } = useFastAverageColor({
+ id: albumId,
+ src: detailQuery.data?.imageUrl,
+ srcLoaded: !detailQuery.isLoading,
+ });
const handlePlayQueueAdd = usePlayQueueAdd();
const playButtonBehavior = usePlayButtonBehavior();
@@ -34,7 +38,9 @@ const AlbumDetailRoute = () => {
});
};
- if (!background) return null;
+ if (!background || colorId !== albumId) {
+ return ;
+ }
return (
diff --git a/src/renderer/features/artists/routes/album-artist-detail-route.tsx b/src/renderer/features/artists/routes/album-artist-detail-route.tsx
index 5f8f9bb0..6d60499b 100644
--- a/src/renderer/features/artists/routes/album-artist-detail-route.tsx
+++ b/src/renderer/features/artists/routes/album-artist-detail-route.tsx
@@ -1,4 +1,4 @@
-import { NativeScrollArea } from '/@/renderer/components';
+import { NativeScrollArea, Spinner } from '/@/renderer/components';
import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared';
import { useRef } from 'react';
import { useParams } from 'react-router';
@@ -23,7 +23,11 @@ const AlbumArtistDetailRoute = () => {
query: { id: albumArtistId },
serverId: server?.id,
});
- const background = useFastAverageColor(detailQuery.data?.imageUrl, !detailQuery.isLoading);
+ const { color, colorId } = useFastAverageColor({
+ id: albumArtistId,
+ src: detailQuery.data?.imageUrl,
+ srcLoaded: !detailQuery.isLoading,
+ });
const handlePlay = () => {
handlePlayQueueAdd?.({
@@ -35,14 +39,16 @@ const AlbumArtistDetailRoute = () => {
});
};
- if (detailQuery.isLoading || !background) return null;
+ if (detailQuery.isLoading || !color || colorId !== albumArtistId) {
+ return ;
+ }
return (
@@ -57,9 +63,9 @@ const AlbumArtistDetailRoute = () => {
>
-
+
);
diff --git a/src/renderer/features/player/components/full-screen-player-image.tsx b/src/renderer/features/player/components/full-screen-player-image.tsx
index b8991c1f..61ab8b49 100644
--- a/src/renderer/features/player/components/full-screen-player-image.tsx
+++ b/src/renderer/features/player/components/full-screen-player-image.tsx
@@ -122,7 +122,11 @@ export const FullScreenPlayerImage = () => {
const { queue } = usePlayerData();
const useImageAspectRatio = useFullScreenPlayerStore((state) => state.useImageAspectRatio);
const currentSong = queue.current;
- const background = useFastAverageColor(queue.current?.imageUrl, true, 'dominant');
+ const { color: background } = useFastAverageColor({
+ algorithm: 'dominant',
+ src: queue.current?.imageUrl,
+ srcLoaded: true,
+ });
const imageKey = `image-${background}`;
const [imageState, setImageState] = useSetState({
diff --git a/src/renderer/features/player/components/full-screen-player.tsx b/src/renderer/features/player/components/full-screen-player.tsx
index 8ecbae91..c40b96f9 100644
--- a/src/renderer/features/player/components/full-screen-player.tsx
+++ b/src/renderer/features/player/components/full-screen-player.tsx
@@ -193,7 +193,11 @@ export const FullScreenPlayer = () => {
}, [location, setStore]);
const currentSong = useCurrentSong();
- const background = useFastAverageColor(currentSong?.imageUrl, true, 'dominant');
+ const { color: background } = useFastAverageColor({
+ algorithm: 'dominant',
+ src: currentSong?.imageUrl,
+ srcLoaded: true,
+ });
return (
{
@@ -166,7 +160,6 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps)
return (
@@ -217,12 +210,13 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps)
-
+
{
const server = useCurrentServer();
const detailQuery = usePlaylistDetail({ query: { id: playlistId }, serverId: server?.id });
- const background = useFastAverageColor(
- detailQuery?.data?.imageUrl,
- !detailQuery?.isLoading,
- 'sqrt',
- );
+ const { color: background, colorId } = useFastAverageColor({
+ algorithm: 'sqrt',
+ id: playlistId,
+ src: detailQuery?.data?.imageUrl,
+ srcLoaded: !detailQuery?.isLoading,
+ });
const handlePlayQueueAdd = usePlayQueueAdd();
const playButtonBehavior = usePlayButtonBehavior();
@@ -39,7 +40,9 @@ const PlaylistDetailRoute = () => {
});
};
- if (!background) return null;
+ if (!background || colorId !== playlistId) {
+ return ;
+ }
return (
@@ -55,6 +58,7 @@ const PlaylistDetailRoute = () => {
),
+ offset: 200,
target: headerRef,
}}
>
diff --git a/src/renderer/hooks/use-fast-average-color.tsx b/src/renderer/hooks/use-fast-average-color.tsx
index 6f37f75f..d1ae342f 100644
--- a/src/renderer/hooks/use-fast-average-color.tsx
+++ b/src/renderer/hooks/use-fast-average-color.tsx
@@ -1,11 +1,15 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { FastAverageColor } from 'fast-average-color';
-export const useFastAverageColor = (
- src?: string | null,
- srcLoaded?: boolean,
- aglorithm?: 'dominant' | 'simple' | 'sqrt',
-) => {
+export const useFastAverageColor = (args: {
+ algorithm?: 'dominant' | 'simple' | 'sqrt';
+ id?: string;
+ src?: string | null;
+ srcLoaded?: boolean;
+}) => {
+ const { algorithm, src, srcLoaded, id } = args;
+ const idRef = useRef(id);
+
const [color, setColor] = useState(undefined);
useEffect(() => {
@@ -13,7 +17,7 @@ export const useFastAverageColor = (
if (src && srcLoaded) {
fac.getColorAsync(src, {
- algorithm: aglorithm || 'dominant',
+ algorithm: algorithm || 'dominant',
ignoredColor: [
[255, 255, 255, 255, 90], // White
[0, 0, 0, 255, 30], // Black
@@ -22,10 +26,12 @@ export const useFastAverageColor = (
mode: 'precision',
})
.then((color) => {
+ idRef.current = id;
return setColor(color.rgb);
})
.catch((e) => {
console.log('Error fetching average color', e);
+ idRef.current = id;
return setColor('rgba(0, 0, 0, 0)');
});
} else if (srcLoaded) {
@@ -35,7 +41,7 @@ export const useFastAverageColor = (
return () => {
fac.destroy();
};
- }, [aglorithm, srcLoaded, src]);
+ }, [algorithm, srcLoaded, src, id]);
- return color;
+ return { color, colorId: idRef.current };
};