UNPKG

remotion

Version:

Make videos programmatically

166 lines (165 loc) • 7.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Img = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const SequenceContext_js_1 = require("./SequenceContext.js"); const cancel_render_js_1 = require("./cancel-render.js"); const delay_render_js_1 = require("./delay-render.js"); const get_cross_origin_value_js_1 = require("./get-cross-origin-value.js"); const prefetch_js_1 = require("./prefetch.js"); const use_buffer_state_js_1 = require("./use-buffer-state.js"); function exponentialBackoff(errorCount) { return 1000 * 2 ** (errorCount - 1); } const ImgRefForwarding = ({ onError, maxRetries = 2, src, pauseWhenLoading, delayRenderRetries, delayRenderTimeoutInMilliseconds, onImageFrame, crossOrigin, ...props }, ref) => { const imageRef = (0, react_1.useRef)(null); const errors = (0, react_1.useRef)({}); const { delayPlayback } = (0, use_buffer_state_js_1.useBufferState)(); const sequenceContext = (0, react_1.useContext)(SequenceContext_js_1.SequenceContext); if (!src) { throw new Error('No "src" prop was passed to <Img>.'); } const _propsValid = true; if (!_propsValid) { throw new Error('typecheck error'); } (0, react_1.useImperativeHandle)(ref, () => { return imageRef.current; }, []); const actualSrc = (0, prefetch_js_1.usePreload)(src); const retryIn = (0, react_1.useCallback)((timeout) => { if (!imageRef.current) { return; } const currentSrc = imageRef.current.src; setTimeout(() => { var _a; if (!imageRef.current) { // Component has been unmounted, do not retry return; } const newSrc = (_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src; if (newSrc !== currentSrc) { // src has changed, do not retry return; } imageRef.current.removeAttribute('src'); imageRef.current.setAttribute('src', newSrc); }, timeout); }, []); const didGetError = (0, react_1.useCallback)((e) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; if (!errors.current) { return; } errors.current[(_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src] = ((_c = errors.current[(_b = imageRef.current) === null || _b === void 0 ? void 0 : _b.src]) !== null && _c !== void 0 ? _c : 0) + 1; if (onError && ((_e = errors.current[(_d = imageRef.current) === null || _d === void 0 ? void 0 : _d.src]) !== null && _e !== void 0 ? _e : 0) > maxRetries) { onError(e); return; } if (((_g = errors.current[(_f = imageRef.current) === null || _f === void 0 ? void 0 : _f.src]) !== null && _g !== void 0 ? _g : 0) <= maxRetries) { const backoff = exponentialBackoff((_j = errors.current[(_h = imageRef.current) === null || _h === void 0 ? void 0 : _h.src]) !== null && _j !== void 0 ? _j : 0); // eslint-disable-next-line no-console console.warn(`Could not load image with source ${(_k = imageRef.current) === null || _k === void 0 ? void 0 : _k.src}, retrying again in ${backoff}ms`); retryIn(backoff); return; } (0, cancel_render_js_1.cancelRender)('Error loading image with src: ' + ((_l = imageRef.current) === null || _l === void 0 ? void 0 : _l.src)); }, [maxRetries, onError, retryIn]); if (typeof window !== 'undefined') { const isPremounting = Boolean(sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.premounting); // eslint-disable-next-line react-hooks/rules-of-hooks (0, react_1.useLayoutEffect)(() => { var _a, _b; if (((_b = (_a = window.process) === null || _a === void 0 ? void 0 : _a.env) === null || _b === void 0 ? void 0 : _b.NODE_ENV) === 'test') { if (imageRef.current) { imageRef.current.src = actualSrc; } return; } const { current } = imageRef; if (!current) { return; } const newHandle = (0, delay_render_js_1.delayRender)('Loading <Img> with src=' + actualSrc, { retries: delayRenderRetries !== null && delayRenderRetries !== void 0 ? delayRenderRetries : undefined, timeoutInMilliseconds: delayRenderTimeoutInMilliseconds !== null && delayRenderTimeoutInMilliseconds !== void 0 ? delayRenderTimeoutInMilliseconds : undefined, }); const unblock = pauseWhenLoading && !isPremounting ? delayPlayback().unblock : () => undefined; let unmounted = false; const onComplete = () => { var _a, _b, _c, _d; // the decode() promise isn't cancelable -- it may still resolve after unmounting if (unmounted) { (0, delay_render_js_1.continueRender)(newHandle); return; } if (((_b = errors.current[(_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src]) !== null && _b !== void 0 ? _b : 0) > 0) { delete errors.current[(_c = imageRef.current) === null || _c === void 0 ? void 0 : _c.src]; // eslint-disable-next-line no-console console.info(`Retry successful - ${(_d = imageRef.current) === null || _d === void 0 ? void 0 : _d.src} is now loaded`); } if (current) { onImageFrame === null || onImageFrame === void 0 ? void 0 : onImageFrame(current); } unblock(); (0, delay_render_js_1.continueRender)(newHandle); }; if (!imageRef.current) { onComplete(); return; } current.src = actualSrc; if (current.complete) { onComplete(); } else { current .decode() .then(onComplete) .catch((err) => { // fall back to onload event if decode() fails // eslint-disable-next-line no-console console.warn(err); if (current.complete) { onComplete(); } else { current.addEventListener('load', onComplete); } }); } // If tag gets unmounted, clear pending handles because image is not going to load return () => { unmounted = true; current.removeEventListener('load', onComplete); unblock(); (0, delay_render_js_1.continueRender)(newHandle); }; }, [ actualSrc, delayPlayback, delayRenderRetries, delayRenderTimeoutInMilliseconds, pauseWhenLoading, isPremounting, onImageFrame, ]); } const crossOriginValue = (0, get_cross_origin_value_js_1.getCrossOriginValue)({ crossOrigin, requestsVideoFrame: false, }); // src gets set once we've loaded and decoded the image. return ((0, jsx_runtime_1.jsx)("img", { ...props, ref: imageRef, crossOrigin: crossOriginValue, onError: didGetError })); }; /* * @description Works just like a regular HTML img tag. When you use the <Img> tag, Remotion will ensure that the image is loaded before rendering the frame. * @see [Documentation](https://remotion.dev/docs/img) */ exports.Img = (0, react_1.forwardRef)(ImgRefForwarding);