pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/

Update PauseOverlay.tsx

Pas 24132618 498f5d9a

+72 -5
+72 -5
src/components/player/overlays/PauseOverlay.tsx
··· 1 1 import { useEffect, useState } from "react"; 2 2 import { useIdle } from "react-use"; 3 3 4 - import { getMediaLogo } from "@/backend/metadata/tmdb"; 4 + import { getMediaDetails, getMediaLogo } from "@/backend/metadata/tmdb"; 5 5 import { TMDBContentTypes } from "@/backend/metadata/types/tmdb"; 6 + import { useShouldShowControls } from "@/components/player/hooks/useShouldShowControls"; 7 + import { useIsMobile } from "@/hooks/useIsMobile"; 8 + import { playerStatus } from "@/stores/player/slices/source"; 6 9 import { usePlayerStore } from "@/stores/player/store"; 7 10 import { usePreferencesStore } from "@/stores/preferences"; 11 + 12 + interface PauseDetails { 13 + voteAverage: number | null; 14 + genres: string[]; 15 + } 8 16 9 17 export function PauseOverlay() { 10 - const isIdle = useIdle(10e3); // 10 seconds 18 + const isIdle = useIdle(5e3); // 5 seconds 11 19 const isPaused = usePlayerStore((s) => s.mediaPlaying.isPaused); 20 + const status = usePlayerStore((s) => s.status); 12 21 const meta = usePlayerStore((s) => s.meta); 13 22 const enablePauseOverlay = usePreferencesStore((s) => s.enablePauseOverlay); 14 23 const enableImageLogos = usePreferencesStore((s) => s.enableImageLogos); 24 + const { isMobile } = useIsMobile(); 25 + const { showTargets } = useShouldShowControls(); 15 26 const [logoUrl, setLogoUrl] = useState<string | null>(null); 27 + const [details, setDetails] = useState<PauseDetails>({ 28 + voteAverage: null, 29 + genres: [], 30 + }); 16 31 17 - const shouldShow = isPaused && isIdle && enablePauseOverlay; 32 + let shouldShow = isPaused && isIdle && enablePauseOverlay; 33 + if (isMobile && status === playerStatus.SCRAPING) shouldShow = false; 34 + if (isMobile && showTargets) shouldShow = false; 18 35 19 36 useEffect(() => { 20 37 let mounted = true; ··· 40 57 }; 41 58 }, [meta?.tmdbId, meta?.type, enableImageLogos]); 42 59 60 + useEffect(() => { 61 + let mounted = true; 62 + const fetchDetails = async () => { 63 + if (!meta?.tmdbId) { 64 + setDetails({ voteAverage: null, genres: [] }); 65 + return; 66 + } 67 + try { 68 + const type = 69 + meta.type === "movie" ? TMDBContentTypes.MOVIE : TMDBContentTypes.TV; 70 + const data = await getMediaDetails(meta.tmdbId, type, false); 71 + if (mounted && data) { 72 + const voteAverage = 73 + typeof data.vote_average === "number" ? data.vote_average : null; 74 + const genres = (data.genres ?? []).map( 75 + (g: { name: string }) => g.name, 76 + ); 77 + setDetails({ voteAverage, genres }); 78 + } 79 + } catch { 80 + if (mounted) setDetails({ voteAverage: null, genres: [] }); 81 + } 82 + }; 83 + 84 + fetchDetails(); 85 + return () => { 86 + mounted = false; 87 + }; 88 + }, [meta?.tmdbId, meta?.type]); 89 + 43 90 if (!meta) return null; 44 91 45 92 const overview = 46 93 meta.type === "show" ? meta.episode?.overview : meta.overview; 47 94 48 95 // Don't render anything if we don't have content, but keep structure for fade if valid 49 - const hasContent = overview || logoUrl || meta.title; 96 + const hasDetails = details.voteAverage !== null || details.genres.length > 0; 97 + const hasContent = overview || logoUrl || meta.title || hasDetails; 50 98 if (!hasContent) return null; 51 99 52 100 return ( ··· 55 103 shouldShow ? "opacity-100" : "opacity-0" 56 104 }`} 57 105 > 58 - <div className="ml-16 max-w-2xl p-8"> 106 + <div className="md:ml-16 max-w-sm lg:max-w-2xl p-8"> 59 107 {logoUrl ? ( 60 108 <img 61 109 src={logoUrl} ··· 72 120 <h2 className="mb-2 text-2xl font-semibold text-white/90 drop-shadow-md"> 73 121 {meta.episode.title} 74 122 </h2> 123 + )} 124 + 125 + {(details.voteAverage !== null || details.genres.length > 0) && ( 126 + <div className="mb-3 flex flex-wrap items-center gap-x-2 gap-y-1 text-sm text-white/80 drop-shadow-md"> 127 + {details.voteAverage !== null && ( 128 + <span> 129 + {details.voteAverage.toFixed(1)} 130 + <span className="text-white/60 ml-0.5">/10</span> 131 + </span> 132 + )} 133 + {details.genres.length > 0 && ( 134 + <> 135 + {details.voteAverage !== null && ( 136 + <span className="text-white/60">•</span> 137 + )} 138 + <span>{details.genres.slice(0, 4).join(", ")}</span> 139 + </> 140 + )} 141 + </div> 75 142 )} 76 143 77 144 {overview && (