mirror of
https://github.com/p-stream/p-stream.git
synced 2026-05-17 14:52:01 +00:00
show total watched to details modal
This commit is contained in:
parent
e544334bea
commit
310a7839ef
4 changed files with 40 additions and 3 deletions
|
|
@ -489,6 +489,7 @@
|
||||||
"seasons": "Season/s",
|
"seasons": "Season/s",
|
||||||
"season": "Season",
|
"season": "Season",
|
||||||
"episode": "Episode",
|
"episode": "Episode",
|
||||||
|
"watched": "Watched {{watched}} of {{total}} ({{percentage}}%)",
|
||||||
"airs": "Airs",
|
"airs": "Airs",
|
||||||
"endsAt": "Ends at {{time}}",
|
"endsAt": "Ends at {{time}}",
|
||||||
"trailer": "Trailer",
|
"trailer": "Trailer",
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export function EpisodeCarousel({
|
||||||
mediaId,
|
mediaId,
|
||||||
mediaTitle,
|
mediaTitle,
|
||||||
mediaPosterUrl,
|
mediaPosterUrl,
|
||||||
|
totalEpisodes,
|
||||||
}: EpisodeCarouselProps) {
|
}: EpisodeCarouselProps) {
|
||||||
const [showEpisodeMenu, setShowEpisodeMenu] = useState(false);
|
const [showEpisodeMenu, setShowEpisodeMenu] = useState(false);
|
||||||
const [customSeason, setCustomSeason] = useState("");
|
const [customSeason, setCustomSeason] = useState("");
|
||||||
|
|
@ -250,6 +251,30 @@ export function EpisodeCarousel({
|
||||||
[mediaId, getFavoriteEpisodes],
|
[mediaId, getFavoriteEpisodes],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Calculate watched episodes count and percentage
|
||||||
|
const watchedStats = useMemo(() => {
|
||||||
|
if (!mediaId || !totalEpisodes) return { watched: 0, percentage: 0 };
|
||||||
|
|
||||||
|
let watchedCount = 0;
|
||||||
|
episodes.forEach((episode) => {
|
||||||
|
const episodeProgress =
|
||||||
|
progress[mediaId.toString()]?.episodes?.[episode.id];
|
||||||
|
const percentage = episodeProgress
|
||||||
|
? getProgressPercentage(
|
||||||
|
episodeProgress.progress.watched,
|
||||||
|
episodeProgress.progress.duration,
|
||||||
|
)
|
||||||
|
: 0;
|
||||||
|
if (percentage > 90) {
|
||||||
|
watchedCount += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const percentage = Math.round((watchedCount / totalEpisodes) * 100);
|
||||||
|
|
||||||
|
return { watched: watchedCount, percentage };
|
||||||
|
}, [episodes, progress, mediaId, totalEpisodes]);
|
||||||
|
|
||||||
// Load favorite episodes when favorites is selected
|
// Load favorite episodes when favorites is selected
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showFavorites && mediaId && favoriteEpisodeIds.length > 0) {
|
if (showFavorites && mediaId && favoriteEpisodeIds.length > 0) {
|
||||||
|
|
@ -423,7 +448,7 @@ export function EpisodeCarousel({
|
||||||
{showEpisodeMenu && (
|
{showEpisodeMenu && (
|
||||||
<div
|
<div
|
||||||
ref={episodeMenuRef}
|
ref={episodeMenuRef}
|
||||||
className="absolute top-full left-0 mt-2 p-4 bg-background-main rounded-lg shadow-lg border border-white/10 z-50 min-w-[250px]"
|
className="absolute top-full left-0 mt-2 p-4 bg-background-main rounded-xl shadow-lg z-50 min-w-[250px]"
|
||||||
>
|
>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -436,7 +461,7 @@ export function EpisodeCarousel({
|
||||||
onChange={(e) => setCustomSeason(e.target.value)}
|
onChange={(e) => setCustomSeason(e.target.value)}
|
||||||
min="1"
|
min="1"
|
||||||
max={seasons.length}
|
max={seasons.length}
|
||||||
className="w-full px-3 py-2 bg-white/5 rounded border border-white/10 text-white focus:outline-none focus:border-white/30"
|
className="w-full px-3 py-2 bg-white/5 rounded-xl text-white focus:outline-none focus:border-white/30"
|
||||||
placeholder={t("details.season")}
|
placeholder={t("details.season")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -449,7 +474,7 @@ export function EpisodeCarousel({
|
||||||
value={customEpisode}
|
value={customEpisode}
|
||||||
onChange={(e) => setCustomEpisode(e.target.value)}
|
onChange={(e) => setCustomEpisode(e.target.value)}
|
||||||
min="1"
|
min="1"
|
||||||
className="w-full px-3 py-2 bg-white/5 rounded border border-white/10 text-white focus:outline-none focus:border-white/30"
|
className="w-full px-3 py-2 bg-white/5 rounded-xl text-white focus:outline-none focus:border-white/30"
|
||||||
placeholder={t("details.episode")}
|
placeholder={t("details.episode")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -464,6 +489,15 @@ export function EpisodeCarousel({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{totalEpisodes && (
|
||||||
|
<span className="text-xs md:text-sm text-white/70">
|
||||||
|
{t("details.watched", {
|
||||||
|
watched: watchedStats.watched,
|
||||||
|
total: totalEpisodes,
|
||||||
|
percentage: watchedStats.percentage,
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Season Watched Confirmation */}
|
{/* Season Watched Confirmation */}
|
||||||
|
|
|
||||||
|
|
@ -411,6 +411,7 @@ export function DetailsContent({ data, minimal = false }: DetailsContentProps) {
|
||||||
mediaId={data.id}
|
mediaId={data.id}
|
||||||
mediaTitle={data.title}
|
mediaTitle={data.title}
|
||||||
mediaPosterUrl={data.posterUrl}
|
mediaPosterUrl={data.posterUrl}
|
||||||
|
totalEpisodes={data.episodes}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ export interface EpisodeCarouselProps {
|
||||||
mediaId?: number;
|
mediaId?: number;
|
||||||
mediaTitle?: string;
|
mediaTitle?: string;
|
||||||
mediaPosterUrl?: string;
|
mediaPosterUrl?: string;
|
||||||
|
totalEpisodes?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DetailsBodyProps {
|
export interface DetailsBodyProps {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue