|
|
|
@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
|
|
|
|
|
import { ReactNode, useEffect, useMemo, useRef } from "react"; |
|
|
|
|
|
|
|
|
|
import { makeVideoElementDisplayInterface } from "@/components/player/display/base"; |
|
|
|
|
import { convertSubtitlesToDataurl } from "@/components/player/utils/captions"; |
|
|
|
|
import { convertSubtitlesToObjectUrl } from "@/components/player/utils/captions"; |
|
|
|
|
import { playerStatus } from "@/stores/player/slices/source"; |
|
|
|
|
import { usePlayerStore } from "@/stores/player/store"; |
|
|
|
|
|
|
|
|
@ -37,16 +37,39 @@ export function useShouldShowVideoElement() {
@@ -37,16 +37,39 @@ export function useShouldShowVideoElement() {
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function useObjectUrl(cb: () => string | null, deps: any[]) { |
|
|
|
|
const lastObjectUrl = useRef<string | null>(null); |
|
|
|
|
const output = useMemo(() => { |
|
|
|
|
if (lastObjectUrl.current) URL.revokeObjectURL(lastObjectUrl.current); |
|
|
|
|
const data = cb(); |
|
|
|
|
lastObjectUrl.current = data; |
|
|
|
|
return data; |
|
|
|
|
// deps are passed in, cb is known not to be changed
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, deps); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
return () => { |
|
|
|
|
// this is intentionally done only in cleanup
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
if (lastObjectUrl.current) URL.revokeObjectURL(lastObjectUrl.current); |
|
|
|
|
}; |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
return output; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function VideoElement() { |
|
|
|
|
const videoEl = useRef<HTMLVideoElement>(null); |
|
|
|
|
const trackEl = useRef<HTMLTrackElement>(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 trackData = useMemo(() => { |
|
|
|
|
return srtData ? convertSubtitlesToDataurl(srtData) : null; |
|
|
|
|
}, [srtData]); |
|
|
|
|
const trackObjectUrl = useObjectUrl( |
|
|
|
|
() => (srtData ? convertSubtitlesToObjectUrl(srtData) : null), |
|
|
|
|
[srtData] |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// report video element to display interface
|
|
|
|
|
useEffect(() => { |
|
|
|
@ -55,14 +78,21 @@ function VideoElement() {
@@ -55,14 +78,21 @@ function VideoElement() {
|
|
|
|
|
} |
|
|
|
|
}, [display, videoEl]); |
|
|
|
|
|
|
|
|
|
// select track as showing if it exists
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (trackEl.current) { |
|
|
|
|
trackEl.current.track.mode = "showing"; |
|
|
|
|
} |
|
|
|
|
}, [trackEl]); |
|
|
|
|
|
|
|
|
|
let subtitleTrack: ReactNode = null; |
|
|
|
|
if (captionAsTrack && trackData && language) |
|
|
|
|
if (captionAsTrack && trackObjectUrl && language) |
|
|
|
|
subtitleTrack = ( |
|
|
|
|
<track |
|
|
|
|
label="Subtitles" |
|
|
|
|
label="movie-web" |
|
|
|
|
kind="subtitles" |
|
|
|
|
srcLang={language} |
|
|
|
|
src={trackData} |
|
|
|
|
src={trackObjectUrl} |
|
|
|
|
default |
|
|
|
|
/> |
|
|
|
|
); |
|
|
|
|