diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json
index baf10e34..4e210074 100644
--- a/src/assets/locales/en.json
+++ b/src/assets/locales/en.json
@@ -489,6 +489,7 @@
"seasons": "Season/s",
"season": "Season",
"episode": "Episode",
+ "watched": "Watched {{watched}} of {{total}} ({{percentage}}%)",
"airs": "Airs",
"endsAt": "Ends at {{time}}",
"trailer": "Trailer",
diff --git a/src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx b/src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx
index b6eeacb6..5ca72131 100644
--- a/src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx
+++ b/src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx
@@ -23,6 +23,7 @@ export function EpisodeCarousel({
mediaId,
mediaTitle,
mediaPosterUrl,
+ totalEpisodes,
}: EpisodeCarouselProps) {
const [showEpisodeMenu, setShowEpisodeMenu] = useState(false);
const [customSeason, setCustomSeason] = useState("");
@@ -250,6 +251,30 @@ export function EpisodeCarousel({
[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
useEffect(() => {
if (showFavorites && mediaId && favoriteEpisodeIds.length > 0) {
@@ -423,7 +448,7 @@ export function EpisodeCarousel({
{showEpisodeMenu && (
@@ -436,7 +461,7 @@ export function EpisodeCarousel({
onChange={(e) => setCustomSeason(e.target.value)}
min="1"
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")}
/>
@@ -449,7 +474,7 @@ export function EpisodeCarousel({
value={customEpisode}
onChange={(e) => setCustomEpisode(e.target.value)}
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")}
/>
@@ -464,6 +489,15 @@ export function EpisodeCarousel({
)}
+ {totalEpisodes && (
+
+ {t("details.watched", {
+ watched: watchedStats.watched,
+ total: totalEpisodes,
+ percentage: watchedStats.percentage,
+ })}
+
+ )}
{/* Season Watched Confirmation */}
diff --git a/src/components/overlays/detailsModal/components/layout/DetailsContent.tsx b/src/components/overlays/detailsModal/components/layout/DetailsContent.tsx
index 52ff59c2..44db2484 100644
--- a/src/components/overlays/detailsModal/components/layout/DetailsContent.tsx
+++ b/src/components/overlays/detailsModal/components/layout/DetailsContent.tsx
@@ -411,6 +411,7 @@ export function DetailsContent({ data, minimal = false }: DetailsContentProps) {
mediaId={data.id}
mediaTitle={data.title}
mediaPosterUrl={data.posterUrl}
+ totalEpisodes={data.episodes}
/>
)}
diff --git a/src/components/overlays/detailsModal/types.ts b/src/components/overlays/detailsModal/types.ts
index eebdc8d4..b976ebf8 100644
--- a/src/components/overlays/detailsModal/types.ts
+++ b/src/components/overlays/detailsModal/types.ts
@@ -105,6 +105,7 @@ export interface EpisodeCarouselProps {
mediaId?: number;
mediaTitle?: string;
mediaPosterUrl?: string;
+ totalEpisodes?: number;
}
export interface DetailsBodyProps {