tangled
alpha
login
or
join now
dunkirk.sh
/
pstream-ng
1
fork
atom
pstream is dead; long live pstream
taciturnaxolotl.github.io/pstream-ng/
1
fork
atom
overview
issues
pulls
pipelines
Update PauseOverlay.tsx
Pas
3 weeks ago
24132618
498f5d9a
+72
-5
1 changed file
expand all
collapse all
unified
split
src
components
player
overlays
PauseOverlay.tsx
+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
4
-
import { getMediaLogo } from "@/backend/metadata/tmdb";
4
4
+
import { getMediaDetails, getMediaLogo } from "@/backend/metadata/tmdb";
5
5
import { TMDBContentTypes } from "@/backend/metadata/types/tmdb";
6
6
+
import { useShouldShowControls } from "@/components/player/hooks/useShouldShowControls";
7
7
+
import { useIsMobile } from "@/hooks/useIsMobile";
8
8
+
import { playerStatus } from "@/stores/player/slices/source";
6
9
import { usePlayerStore } from "@/stores/player/store";
7
10
import { usePreferencesStore } from "@/stores/preferences";
11
11
+
12
12
+
interface PauseDetails {
13
13
+
voteAverage: number | null;
14
14
+
genres: string[];
15
15
+
}
8
16
9
17
export function PauseOverlay() {
10
10
-
const isIdle = useIdle(10e3); // 10 seconds
18
18
+
const isIdle = useIdle(5e3); // 5 seconds
11
19
const isPaused = usePlayerStore((s) => s.mediaPlaying.isPaused);
20
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
24
+
const { isMobile } = useIsMobile();
25
25
+
const { showTargets } = useShouldShowControls();
15
26
const [logoUrl, setLogoUrl] = useState<string | null>(null);
27
27
+
const [details, setDetails] = useState<PauseDetails>({
28
28
+
voteAverage: null,
29
29
+
genres: [],
30
30
+
});
16
31
17
17
-
const shouldShow = isPaused && isIdle && enablePauseOverlay;
32
32
+
let shouldShow = isPaused && isIdle && enablePauseOverlay;
33
33
+
if (isMobile && status === playerStatus.SCRAPING) shouldShow = false;
34
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
60
+
useEffect(() => {
61
61
+
let mounted = true;
62
62
+
const fetchDetails = async () => {
63
63
+
if (!meta?.tmdbId) {
64
64
+
setDetails({ voteAverage: null, genres: [] });
65
65
+
return;
66
66
+
}
67
67
+
try {
68
68
+
const type =
69
69
+
meta.type === "movie" ? TMDBContentTypes.MOVIE : TMDBContentTypes.TV;
70
70
+
const data = await getMediaDetails(meta.tmdbId, type, false);
71
71
+
if (mounted && data) {
72
72
+
const voteAverage =
73
73
+
typeof data.vote_average === "number" ? data.vote_average : null;
74
74
+
const genres = (data.genres ?? []).map(
75
75
+
(g: { name: string }) => g.name,
76
76
+
);
77
77
+
setDetails({ voteAverage, genres });
78
78
+
}
79
79
+
} catch {
80
80
+
if (mounted) setDetails({ voteAverage: null, genres: [] });
81
81
+
}
82
82
+
};
83
83
+
84
84
+
fetchDetails();
85
85
+
return () => {
86
86
+
mounted = false;
87
87
+
};
88
88
+
}, [meta?.tmdbId, meta?.type]);
89
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
49
-
const hasContent = overview || logoUrl || meta.title;
96
96
+
const hasDetails = details.voteAverage !== null || details.genres.length > 0;
97
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
58
-
<div className="ml-16 max-w-2xl p-8">
106
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
123
+
)}
124
124
+
125
125
+
{(details.voteAverage !== null || details.genres.length > 0) && (
126
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
127
+
{details.voteAverage !== null && (
128
128
+
<span>
129
129
+
{details.voteAverage.toFixed(1)}
130
130
+
<span className="text-white/60 ml-0.5">/10</span>
131
131
+
</span>
132
132
+
)}
133
133
+
{details.genres.length > 0 && (
134
134
+
<>
135
135
+
{details.voteAverage !== null && (
136
136
+
<span className="text-white/60">•</span>
137
137
+
)}
138
138
+
<span>{details.genres.slice(0, 4).join(", ")}</span>
139
139
+
</>
140
140
+
)}
141
141
+
</div>
75
142
)}
76
143
77
144
{overview && (