import React, {useEffect, useId, useRef, useState} from 'react' import {View} from 'react-native' import {AppBskyEmbedVideo} from '@atproto/api' import Hls from 'hls.js' import {atoms as a} from '#/alf' import {MediaInsetBorder} from '#/components/MediaInsetBorder' import {Controls} from './web-controls/VideoControls' export function VideoEmbedInnerWeb({ embed, active, setActive, onScreen, }: { embed: AppBskyEmbedVideo.View active: boolean setActive: () => void onScreen: boolean }) { const containerRef = useRef(null) const ref = useRef(null) const [focused, setFocused] = useState(false) const [hasSubtitleTrack, setHasSubtitleTrack] = useState(false) const figId = useId() // send error up to error boundary const [error, setError] = useState(null) if (error) { throw error } const hlsRef = useRef(undefined) useEffect(() => { if (!ref.current) return if (!Hls.isSupported()) throw new HLSUnsupportedError() const hls = new Hls({ capLevelToPlayerSize: true, maxMaxBufferLength: 10, // only load 10s ahead // note: the amount buffered is affected by both maxBufferLength and maxBufferSize // it will buffer until it it's greater than *both* of those values // so we use maxMaxBufferLength to set the actual maximum amount of buffering instead }) hlsRef.current = hls hls.attachMedia(ref.current) hls.loadSource(embed.playlist) // 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) } }) hls.on(Hls.Events.ERROR, (_event, data) => { if (data.fatal) { if ( data.details === 'manifestLoadError' && data.response?.code === 404 ) { setError(new VideoNotFoundError()) } else { setError(data.error) } } }) return () => { hlsRef.current = undefined hls.detachMedia() hls.destroy() } }, [embed.playlist]) return (
) } export class HLSUnsupportedError extends Error { constructor() { super('HLS is not supported') } } export class VideoNotFoundError extends Error { constructor() { super('Video not found') } }