From b80f8c5ab6ab6ccca85b968ffd85607b7cb65cbe Mon Sep 17 00:00:00 2001 From: matiasperz Date: Mon, 4 Apr 2022 20:45:35 -0300 Subject: [PATCH 1/7] Adding enhansed components --- src/components/primitives/mux-video.tsx | 76 ++++++++++++++++++------- src/hooks/use-intersection-observer.ts | 50 ++++++++++------ 2 files changed, 89 insertions(+), 37 deletions(-) diff --git a/src/components/primitives/mux-video.tsx b/src/components/primitives/mux-video.tsx index 8f647ff..74d4622 100644 --- a/src/components/primitives/mux-video.tsx +++ b/src/components/primitives/mux-video.tsx @@ -1,47 +1,81 @@ -import Hls, { Events } from 'hls.js' +import type THls from 'hls.js' import * as React from 'react' import mergeRefs from 'react-merge-refs' +import { createObserver } from '~/hooks/use-intersection-observer' + export type MuxVideoProps = { muxSrc: string + lazy?: boolean } & Omit +const supportsHls = (videoElm: HTMLVideoElement) => + videoElm.canPlayType('application/vnd.apple.mpegurl') + export const MuxVideo = React.forwardRef( - ({ muxSrc, className, ...rest }, ref) => { + ({ muxSrc, lazy = true, className, ...rest }, ref) => { + const hls = React.useRef(null) const videoRef = React.useRef(null) - React.useEffect(() => { - let hls: Hls + const loadVideo = React.useCallback( + (videoElm: HTMLVideoElement) => { + if (hls.current) { + hls.current?.loadSource(muxSrc) + } else if (videoElm && supportsHls(videoElm)) { + videoElm.src = muxSrc + } else { + console.error('Unable to reproduce video') + } + }, + [muxSrc] + ) - if (videoRef.current) { - const video = videoRef.current + const importHls = React.useCallback( + async (videoElm: HTMLVideoElement) => { + const Hls = (await import('hls.js')).default - if (video.canPlayType('application/vnd.apple.mpegurl')) { - // Some browers (safari and ie edge) support HLS natively - video.src = muxSrc - video.defaultMuted = true - } else if (Hls.isSupported()) { + if (Hls.isSupported() && videoElm) { // This will run in all other modern browsers - hls = new Hls() - hls.attachMedia(video) - hls.on(Events.MEDIA_ATTACHED, () => { - hls?.loadSource(muxSrc) - hls?.on(Events.MANIFEST_PARSED, (_event, data) => { + hls.current = new Hls() + hls.current.attachMedia(videoElm) + hls.current.on(Hls.Events.MEDIA_ATTACHED, () => { + !lazy && loadVideo(videoElm) + + hls.current?.on(Hls.Events.MANIFEST_PARSED, (_event, data) => { // Maximum quality available - hls.nextLevel ??= data.levels.length - 1 + hls.current!.nextLevel ??= data.levels.length - 1 }) }) } else { console.error("This is a legacy browser that doesn't support MSE") } + }, + [lazy, loadVideo] + ) + + React.useEffect(() => { + if (!videoRef.current) return + + const video = videoRef.current + + if (video.canPlayType('application/vnd.apple.mpegurl')) { + // Some browers (safari and ie edge) support HLS natively + video.defaultMuted = true + !lazy && loadVideo(video) + } else { + importHls(videoRef.current) + } + + if (lazy) { + createObserver(videoRef.current, { triggerOnce: true }, () => + loadVideo(video) + ) } return () => { - if (hls) { - hls.destroy() - } + hls.current?.destroy?.() } - }, [videoRef, muxSrc]) + }, [videoRef, muxSrc, lazy, importHls, loadVideo]) return (