From f800251de143a95dadee4db396c4cac14d8d2c55 Mon Sep 17 00:00:00 2001 From: Xoconoch Date: Thu, 28 Aug 2025 08:40:39 -0600 Subject: [PATCH] fix: load playlist image on frontend --- requirements.txt | 2 +- spotizerr-ui/src/routes/album.tsx | 10 ++++++ spotizerr-ui/src/routes/artist.tsx | 10 ++++++ spotizerr-ui/src/routes/playlist.tsx | 49 +++++++++++++++++++++++++--- spotizerr-ui/src/types/librespot.ts | 1 + 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index db9629c..d3c468d 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ fastapi==0.116.1 uvicorn[standard]==0.35.0 celery==5.5.3 -deezspot-spotizerr==3.1.4 +deezspot-spotizerr==3.1.5 httpx==0.28.1 bcrypt==4.2.1 PyJWT==2.10.1 diff --git a/spotizerr-ui/src/routes/album.tsx b/spotizerr-ui/src/routes/album.tsx index c7de14f..a72d7dc 100644 --- a/spotizerr-ui/src/routes/album.tsx +++ b/spotizerr-ui/src/routes/album.tsx @@ -135,6 +135,16 @@ export const Album = () => { }; }, [loadMore]); + // Auto progressive loading regardless of scroll + useEffect(() => { + if (!album) return; + if (!hasMore || isLoadingMore) return; + const t = setTimeout(() => { + loadMore(); + }, 300); + return () => clearTimeout(t); + }, [album, hasMore, isLoadingMore, loadMore]); + const handleDownloadTrack = (track: LibrespotTrackType) => { if (!track.id) return; toast.info(`Adding ${track.name} to queue...`); diff --git a/spotizerr-ui/src/routes/artist.tsx b/spotizerr-ui/src/routes/artist.tsx index 0a4845e..0c5d496 100644 --- a/spotizerr-ui/src/routes/artist.tsx +++ b/spotizerr-ui/src/routes/artist.tsx @@ -303,6 +303,16 @@ export const Artist = () => { return () => observer.disconnect(); }, [fetchMoreAlbums, hasMore]); + // Auto progressive loading regardless of scroll + useEffect(() => { + if (!artist) return; + if (!hasMore || loading || loadingMore) return; + const t = setTimeout(() => { + fetchMoreAlbums(); + }, 350); + return () => clearTimeout(t); + }, [artist, hasMore, loading, loadingMore, fetchMoreAlbums]); + // --- existing handlers (unchanged) --- const handleDownloadTrack = (track: LibrespotTrackType) => { if (!track.id) return; diff --git a/spotizerr-ui/src/routes/playlist.tsx b/spotizerr-ui/src/routes/playlist.tsx index a8e850b..38f5f85 100644 --- a/spotizerr-ui/src/routes/playlist.tsx +++ b/spotizerr-ui/src/routes/playlist.tsx @@ -153,6 +153,16 @@ export const Playlist = () => { } }, [playlistMetadata, items.length, totalTracks, loadMoreTracks]); + // Auto progressive loading regardless of scroll + useEffect(() => { + if (!playlistMetadata) return; + if (!hasMoreTracks || loadingTracks) return; + const t = setTimeout(() => { + loadMoreTracks(); + }, 300); + return () => clearTimeout(t); + }, [playlistMetadata, hasMoreTracks, loadingTracks, loadMoreTracks]); + const handleDownloadTrack = (track: LibrespotTrackType) => { if (!track?.id) return; addItem({ spotifyId: track.id, type: "track", name: track.name }); @@ -227,11 +237,40 @@ export const Playlist = () => { {/* Playlist Header - Mobile Optimized */}
- {playlistMetadata.name} + {playlistMetadata.picture ? ( + {playlistMetadata.name} + ) : ( +
+ {(Array.from( + new Map( + filteredItems + .map(({ track }) => (track as any)?.album?.images?.at(-1)?.url) + .filter((u) => !!u) + .map((u) => [u, u] as const) + ).values() + ) as string[]).slice(0, 4).map((url, i) => ( + {`Cover + ))} + {filteredItems.length === 0 && ( + {playlistMetadata.name} + )} +
+ )}

{playlistMetadata.name}

{playlistMetadata.description && ( diff --git a/spotizerr-ui/src/types/librespot.ts b/spotizerr-ui/src/types/librespot.ts index a38864f..57704b9 100644 --- a/spotizerr-ui/src/types/librespot.ts +++ b/spotizerr-ui/src/types/librespot.ts @@ -142,6 +142,7 @@ export interface LibrespotPlaylistType { snapshot_id: string; tracks: LibrespotPlaylistTracksPageType; type: "playlist"; + picture?: string; } // Type guards