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

Configure Feed

Select the types of activity you want to include in your feed.

fix native subtitle streaming

Pas ebfa034c 9fec88fc

+41
+32
src/components/player/display/base.ts
··· 87 87 let videoElement: HTMLVideoElement | null = null; 88 88 let containerElement: HTMLElement | null = null; 89 89 let isFullscreen = false; 90 + let isPictureInPicture = false; 90 91 let isPausedBeforeSeeking = false; 91 92 let isSeeking = false; 92 93 let startAt = 0; ··· 326 327 vid.currentTime = startAt; 327 328 } 328 329 330 + function webkitPresentationModeChange() { 331 + if (!videoElement) return; 332 + const webkitPlayer = videoElement as any; 333 + const isInWebkitPip = 334 + webkitPlayer.webkitPresentationMode === "picture-in-picture"; 335 + isPictureInPicture = isInWebkitPip; 336 + // Use native tracks in WebKit PiP mode for iOS compatibility 337 + emit("needstrack", isInWebkitPip); 338 + } 339 + 329 340 function setSource() { 330 341 if (!videoElement || !source) return; 331 342 setupSource(videoElement, source); ··· 406 417 } 407 418 }, 408 419 ); 420 + videoElement.addEventListener( 421 + "webkitpresentationmodechanged", 422 + webkitPresentationModeChange, 423 + ); 409 424 videoElement.addEventListener("ratechange", () => { 410 425 if (videoElement) emit("playbackrate", videoElement.playbackRate); 411 426 }); ··· 453 468 } 454 469 fscreen.addEventListener("fullscreenchange", fullscreenChange); 455 470 471 + function pictureInPictureChange() { 472 + isPictureInPicture = !!document.pictureInPictureElement; 473 + // Use native tracks in PiP mode for better compatibility with iOS and other platforms 474 + emit("needstrack", isPictureInPicture); 475 + } 476 + 477 + document.addEventListener("enterpictureinpicture", pictureInPictureChange); 478 + document.addEventListener("leavepictureinpicture", pictureInPictureChange); 479 + 456 480 return { 457 481 on, 458 482 off, ··· 462 486 destroy: () => { 463 487 destroyVideoElement(); 464 488 fscreen.removeEventListener("fullscreenchange", fullscreenChange); 489 + document.removeEventListener( 490 + "enterpictureinpicture", 491 + pictureInPictureChange, 492 + ); 493 + document.removeEventListener( 494 + "leavepictureinpicture", 495 + pictureInPictureChange, 496 + ); 465 497 }, 466 498 load(ops) { 467 499 if (!ops.source) unloadSource();
+9
src/components/player/hooks/useCaptions.ts
··· 23 23 24 24 const captionList = usePlayerStore((s) => s.captionList); 25 25 const getHlsCaptionList = usePlayerStore((s) => s.display?.getCaptionList); 26 + const source = usePlayerStore((s) => s.source); 26 27 27 28 const getSubtitleTracks = usePlayerStore((s) => s.display?.getSubtitleTracks); 28 29 const setSubtitlePreference = usePlayerStore( 29 30 (s) => s.display?.setSubtitlePreference, 30 31 ); 32 + const setCaptionAsTrack = usePlayerStore((s) => s.setCaptionAsTrack); 31 33 32 34 const captions = useMemo( 33 35 () => ··· 82 84 setCaption(captionToSet); 83 85 resetSubtitleSpecificSettings(); 84 86 setLanguage(caption.language); 87 + 88 + // Use native tracks for MP4 streams instead of custom rendering 89 + if (source?.type === "file") { 90 + setCaptionAsTrack(true); 91 + } 85 92 }, 86 93 [ 87 94 setIsOpenSubtitles, ··· 91 98 resetSubtitleSpecificSettings, 92 99 getSubtitleTracks, 93 100 setSubtitlePreference, 101 + source, 102 + setCaptionAsTrack, 94 103 ], 95 104 ); 96 105