diff --git a/README.md b/README.md
index a611b591..51c207c5 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,6 @@
[](https://docs.pstream.mov)
-**I _do not_ endorse piracy of any kind I simply enjoy programming and large user counts.**
-
## Quick Deploy
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fp-stream%2Fp-stream)
@@ -27,12 +25,7 @@
## Referrers
-- [FMHY (Voted as #1 multi-server streaming site of 2024)](https://fmhy.net)
-- [Piracy Subreddit Megathread](https://www.reddit.com/r/Piracy/s/iymSloEpXn)
-- [Toon's Instances](https://erynith.github.io/movie-web-instances)
-- [Entertainment Empire](https://discord.gg/8NSDNEMfja)
-- Search Engines: DuckDuckGo, Bing, Google
-- Rentry.co
+- [FMHY (Voted as #1 streaming site of 2024, 2025)](https://fmhy.net)
## Running Locally
diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json
index df981271..f0a680a5 100644
--- a/src/assets/locales/en.json
+++ b/src/assets/locales/en.json
@@ -777,8 +777,8 @@
"refreshing": "Refreshing...",
"empty": "There are no provided subtitles for this.",
"notFound": "None of the available options match your query",
- "useNativeSubtitles": "Use native video subtitles",
- "useNativeSubtitlesDescription": "May fix subtitles when casting and in PiP",
+ "useNativeSubtitles": "Native video subtitles",
+ "useNativeSubtitlesDescription": "Broadcast subtitles for native fullscreen and PiP",
"delayLate": "Heard audio",
"delayEarly": "Saw caption"
},
diff --git a/src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx b/src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx
index 9fec2494..b6eeacb6 100644
--- a/src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx
+++ b/src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx
@@ -45,39 +45,6 @@ export function EpisodeCarousel({
const updateItem = useProgressStore((s) => s.updateItem);
const confirmModal = useModal("season-watch-confirm");
- const [canScrollLeft, setCanScrollLeft] = useState(false);
- const [canScrollRight, setCanScrollRight] = useState(false);
-
- const updateScrollState = () => {
- if (!carouselRef.current) {
- setCanScrollLeft(false);
- setCanScrollRight(false);
- return;
- }
-
- const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current;
- const isAtStart = scrollLeft <= 1;
- const isAtEnd = scrollLeft + clientWidth >= scrollWidth - 1;
-
- setCanScrollLeft(!isAtStart);
- setCanScrollRight(!isAtEnd);
- };
-
- useEffect(() => {
- const carousel = carouselRef.current;
- if (!carousel) return;
-
- updateScrollState();
-
- carousel.addEventListener("scroll", updateScrollState);
- window.addEventListener("resize", updateScrollState);
-
- return () => {
- carousel.removeEventListener("scroll", updateScrollState);
- window.removeEventListener("resize", updateScrollState);
- };
- }, []);
-
const handleScroll = (direction: "left" | "right") => {
if (!carouselRef.current) return;
@@ -563,17 +530,15 @@ export function EpisodeCarousel({
{/* Episodes Carousel */}
{/* Left scroll button */}
- {canScrollLeft && (
-
-
-
- )}
+
+
+
{/* Right scroll button */}
- {canScrollRight && (
-
-
-
- )}
+
+
+
);
diff --git a/src/components/player/atoms/Episodes.tsx b/src/components/player/atoms/Episodes.tsx
index 8b9bf424..2d081980 100644
--- a/src/components/player/atoms/Episodes.tsx
+++ b/src/components/player/atoms/Episodes.tsx
@@ -766,39 +766,6 @@ export function EpisodesView({
],
);
- const [canScrollLeft, setCanScrollLeft] = useState(false);
- const [canScrollRight, setCanScrollRight] = useState(false);
-
- const updateScrollState = () => {
- if (!carouselRef.current) {
- setCanScrollLeft(false);
- setCanScrollRight(false);
- return;
- }
-
- const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current;
- const isAtStart = scrollLeft <= 1;
- const isAtEnd = scrollLeft + clientWidth >= scrollWidth - 1;
-
- setCanScrollLeft(!isAtStart);
- setCanScrollRight(!isAtEnd);
- };
-
- useEffect(() => {
- const carousel = carouselRef.current;
- if (!carousel) return;
-
- updateScrollState();
-
- carousel.addEventListener("scroll", updateScrollState);
- window.addEventListener("resize", updateScrollState);
-
- return () => {
- carousel.removeEventListener("scroll", updateScrollState);
- window.removeEventListener("resize", updateScrollState);
- };
- }, []);
-
const handleScroll = (direction: "left" | "right") => {
if (!carouselRef.current) return;
@@ -949,22 +916,20 @@ export function EpisodesView({
content = (
{/* Horizontal scroll buttons */}
- {canScrollLeft && (
-
+
- )}
+
+
+
{/* Right scroll button */}
- {canScrollRight && (
-
+ handleScroll("right")}
>
- handleScroll("right")}
- >
-
-
-
- )}
+
+
+
);
}
diff --git a/src/components/player/base/SubtitleView.tsx b/src/components/player/base/SubtitleView.tsx
index aadc31bb..b526806a 100644
--- a/src/components/player/base/SubtitleView.tsx
+++ b/src/components/player/base/SubtitleView.tsx
@@ -8,6 +8,7 @@ import {
} from "@/components/player/utils/captions";
import { Transition } from "@/components/utils/Transition";
import { usePlayerStore } from "@/stores/player/store";
+import { usePreferencesStore } from "@/stores/preferences";
import { SubtitleStyling, useSubtitleStore } from "@/stores/subtitles";
const wordOverrides: Record = {
@@ -151,12 +152,17 @@ export function SubtitleRenderer() {
export function SubtitleView(props: { controlsShown: boolean }) {
const caption = usePlayerStore((s) => s.caption.selected);
- const captionAsTrack = usePlayerStore((s) => s.caption.asTrack);
+ const source = usePlayerStore((s) => s.source);
const display = usePlayerStore((s) => s.display);
const isCasting = display?.getType() === "casting";
const styling = useSubtitleStore((s) => s.styling);
+ const enableNativeSubtitles = usePreferencesStore(
+ (s) => s.enableNativeSubtitles,
+ );
- if (captionAsTrack || !caption || isCasting) return null;
+ // Hide custom captions when native subtitles are enabled
+ const shouldUseNativeTrack = enableNativeSubtitles && source !== null;
+ if (shouldUseNativeTrack || !caption || isCasting) return null;
return (
diff --git a/src/components/player/internals/VideoContainer.tsx b/src/components/player/internals/VideoContainer.tsx
index 89d34433..87dec420 100644
--- a/src/components/player/internals/VideoContainer.tsx
+++ b/src/components/player/internals/VideoContainer.tsx
@@ -4,6 +4,7 @@ import { makeVideoElementDisplayInterface } from "@/components/player/display/ba
import { convertSubtitlesToObjectUrl } from "@/components/player/utils/captions";
import { playerStatus } from "@/stores/player/slices/source";
import { usePlayerStore } from "@/stores/player/store";
+import { usePreferencesStore } from "@/stores/preferences";
import { useInitializeSource } from "../hooks/useInitializePlayer";
@@ -66,13 +67,19 @@ function VideoElement() {
const trackEl = useRef(null);
const display = usePlayerStore((s) => s.display);
const srtData = usePlayerStore((s) => s.caption.selected?.srtData);
- const captionAsTrack = usePlayerStore((s) => s.caption.asTrack);
const language = usePlayerStore((s) => s.caption.selected?.language);
+ const source = usePlayerStore((s) => s.source);
+ const enableNativeSubtitles = usePreferencesStore(
+ (s) => s.enableNativeSubtitles,
+ );
const trackObjectUrl = useObjectUrl(
() => (srtData ? convertSubtitlesToObjectUrl(srtData) : null),
[srtData],
);
+ // Use native tracks when the setting is enabled
+ const shouldUseNativeTrack = enableNativeSubtitles && source !== null;
+
// report video element to display interface
useEffect(() => {
if (display && videoEl.current) {
@@ -80,17 +87,20 @@ function VideoElement() {
}
}, [display, videoEl]);
- // select track as showing if it exists
+ // Control track visibility based on setting
useEffect(() => {
if (trackEl.current) {
- trackEl.current.track.mode = "showing";
+ trackEl.current.track.mode = shouldUseNativeTrack ? "showing" : "hidden";
}
- }, [trackEl]);
+ }, [shouldUseNativeTrack, trackEl]);
+ // Attach track when native subtitles are enabled
+ // SubtitleView handles showing custom captions when native subtitles are disabled
let subtitleTrack: ReactNode = null;
- if (captionAsTrack && trackObjectUrl && language)
+ if (shouldUseNativeTrack && trackObjectUrl && language) {
subtitleTrack = (
);
+ }
return (