diff options
Diffstat (limited to 'src/view/com/util/post-embeds/VideoEmbedInner.web.tsx')
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbedInner.web.tsx | 119 |
1 files changed, 80 insertions, 39 deletions
diff --git a/src/view/com/util/post-embeds/VideoEmbedInner.web.tsx b/src/view/com/util/post-embeds/VideoEmbedInner.web.tsx index cb02743c6..f5f47db50 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner.web.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner.web.tsx @@ -1,52 +1,93 @@ -import React, {useEffect, useRef} from 'react' +import React, {useEffect, useRef, useState} from 'react' +import {View} from 'react-native' import Hls from 'hls.js' import {atoms as a} from '#/alf' +import {Controls} from './VideoWebControls' -export const VideoEmbedInner = ({source}: {source: string}) => { +export function VideoEmbedInner({ + source, + active, + setActive, + onScreen, +}: { + source: string + active: boolean + setActive: () => void + onScreen: boolean +}) { + const containerRef = useRef<HTMLDivElement>(null) const ref = useRef<HTMLVideoElement>(null) + const [focused, setFocused] = useState(false) + const [hasSubtitleTrack, setHasSubtitleTrack] = useState(false) + + const hlsRef = useRef<Hls | undefined>(undefined) - // Use HLS.js to play HLS video useEffect(() => { - if (ref.current) { - if (ref.current.canPlayType('application/vnd.apple.mpegurl')) { - ref.current.src = source - } else if (Hls.isSupported()) { - var hls = new Hls() - hls.loadSource(source) - hls.attachMedia(ref.current) - } else { - // TODO: fallback + if (!ref.current) return + if (!Hls.isSupported()) throw new HLSUnsupportedError() + + const hls = new Hls({capLevelToPlayerSize: true}) + hlsRef.current = hls + + hls.attachMedia(ref.current) + hls.loadSource(source) + + // initial value, later on it's managed by Controls + hls.autoLevelCapping = 0 + + hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, (event, data) => { + if (data.subtitleTracks.length > 0) { + setHasSubtitleTrack(true) } + }) + + return () => { + hlsRef.current = undefined + hls.detachMedia() + hls.destroy() } }, [source]) - useEffect(() => { - if (ref.current) { - const observer = new IntersectionObserver( - ([entry]) => { - if (ref.current) { - if (entry.isIntersecting) { - if (ref.current.paused) { - ref.current.play() - } - } else { - if (!ref.current.paused) { - ref.current.pause() - } - } - } - }, - {threshold: 0}, - ) - - observer.observe(ref.current) - - return () => { - observer.disconnect() - } - } - }, []) + return ( + <View + style={[ + a.w_full, + a.rounded_sm, + // TODO: get from embed metadata + // max should be 1 / 1 + {aspectRatio: 16 / 9}, + a.overflow_hidden, + ]}> + <div + ref={containerRef} + style={{width: '100%', height: '100%', display: 'flex'}}> + <video + ref={ref} + style={{width: '100%', height: '100%', objectFit: 'contain'}} + playsInline + preload="none" + loop + muted={!focused} + /> + <Controls + videoRef={ref} + hlsRef={hlsRef} + active={active} + setActive={setActive} + focused={focused} + setFocused={setFocused} + onScreen={onScreen} + fullscreenRef={containerRef} + hasSubtitleTrack={hasSubtitleTrack} + /> + </div> + </View> + ) +} - return <video ref={ref} style={a.flex_1} controls playsInline autoPlay loop /> +export class HLSUnsupportedError extends Error { + constructor() { + super('HLS is not supported') + } } |