diff --git a/web/media/loadable-video.react.js b/web/media/loadable-video.react.js --- a/web/media/loadable-video.react.js +++ b/web/media/loadable-video.react.js @@ -2,10 +2,14 @@ import invariant from 'invariant'; import * as React from 'react'; +import videojs from 'video.js'; +import 'video.js/dist/video-js.css'; + +import type { Dimensions } from 'lib/types/media-types.js'; import { useFetchAndDecryptMedia } from './encryption-utils.js'; import { preloadImage } from './media-utils.js'; -import type { CSSStyle } from '../types/styles'; +import type { CSSStyle } from '../types/styles.js'; type ThumbnailSource = | { @@ -21,6 +25,8 @@ +thumbHashDataURL?: ?string, +elementStyle?: ?Partial, +multimediaClassName?: string, + +loop?: boolean, + +dimensions?: ?Dimensions, }; function LoadableVideo( @@ -33,6 +39,8 @@ thumbnailSource, elementStyle, multimediaClassName, + loop, + dimensions, } = props; const { thumbnailURI, thumbnailBlobURI, thumbnailEncryptionKey } = thumbnailSource; @@ -82,11 +90,45 @@ fetchAndDecryptMedia, ]); + const poster = thumbnailImage ?? thumbHashDataURL; + + const hlsPlayer = React.useMemo(() => { + if (!uri || !uri.endsWith('.m3u8')) { + return null; + } + const videoJsOptions = { + autoplay: false, + controls: true, + responsive: true, + fluid: false, + loop, + videoWidth: dimensions?.width, + videoHeight: dimensions?.height, + poster, + sources: [ + { + src: uri, + type: 'application/x-mpegURL', + }, + ], + }; + return ( + + ); + }, [uri, elementStyle, multimediaClassName, loop, poster, dimensions]); + + if (hlsPlayer) { + return hlsPlayer; + } + let videoSource; if (uri) { videoSource = ; } - const poster = thumbnailImage ?? thumbHashDataURL; return (