import { useQuery } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { SCRUB_MANIFEST, scrubManifestSchema, videoUrl, type ScrubManifest } from "~/lib/video";
/** Attaches the HLS master to `video`: hls.js where MSE exists, native HLS (Safari/iOS) otherwise. */
export function useHlsSource(video: HTMLVideoElement | null, src: string): string | null {
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!video) return;
let disposed = false;
let destroy: (() => void) | undefined;
setError(null);
void import("hls.js").then(({ default: Hls }) => {
if (disposed) return;
if (!Hls.isSupported()) {
if (video.canPlayType("application/vnd.apple.mpegurl")) video.src = src;
else setError("This browser cannot play HLS video");
return;
}
const hls = new Hls({ capLevelToPlayerSize: true, startLevel: -1 });
hls.on(Hls.Events.ERROR, (_event, data) => {
if (!data.fatal) return;
if (data.type === Hls.ErrorTypes.NETWORK_ERROR) hls.startLoad();
else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) hls.recoverMediaError();
else setError("Video playback failed");
});
hls.loadSource(src);
hls.attachMedia(video);
destroy = () => hls.destroy();
});
return () => {
disposed = true;
destroy?.();
};
}, [video, src]);
return error;
}
/** Loads the scrub sprite manifest; a video without one still plays, it just scrubs without thumbnails. */
export function useScrubManifest(id: string, version: string): ScrubManifest | null {