import { z } from "zod"; import { useCallback, useMemo, useState } from "react"; import { getProgress, renderVideo } from "./api"; import { CompositionProps } from "~/remotion/schemata"; export type State = | { status: "init"; } | { status: "invoking"; } | { renderId: string; bucketName: string; progress: number; status: "rendering"; } | { renderId: string | null; status: "error"; error: Error; } | { url: string; size: number; status: "done"; }; const wait = async (milliSeconds: number) => { await new Promise((resolve) => { setTimeout(() => { resolve(); }, milliSeconds); }); }; export const useRendering = ( id: string, inputProps: z.infer, ) => { const [state, setState] = useState({ status: "init", }); const renderMedia = useCallback(async () => { setState({ status: "invoking", }); try { const { renderId, bucketName } = await renderVideo({ inputProps }); setState({ status: "rendering", progress: 0, renderId: renderId, bucketName: bucketName, }); let pending = true; while (pending) { const result = await getProgress({ id: renderId, bucketName: bucketName, }); switch (result.type) { case "error": { setState({ status: "error", renderId: renderId, error: new Error(result.message), }); pending = false; break; } case "done": { setState({ size: result.size, url: result.url, status: "done", }); pending = false; break; } case "progress": { setState({ status: "rendering", bucketName: bucketName, progress: result.progress, renderId: renderId, }); await wait(1000); } } } } catch (err) { setState({ status: "error", error: err as Error, renderId: null, }); } }, [inputProps]); const undo = useCallback(() => { setState({ status: "init" }); }, []); return useMemo(() => { return { renderMedia, state, undo, }; }, [renderMedia, state, undo]); };