UNPKG

remotion

Version:

Make videos programmatically

206 lines (205 loc) • 7.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.prefetch = exports.usePreload = exports.getSrcWithoutHash = exports.removeAndGetHashFragment = void 0; const react_1 = require("react"); const get_remotion_environment_js_1 = require("./get-remotion-environment.js"); const log_js_1 = require("./log.js"); const playback_logging_js_1 = require("./playback-logging.js"); const prefetch_state_js_1 = require("./prefetch-state.js"); const removeAndGetHashFragment = (src) => { const hashIndex = src.indexOf('#'); if (hashIndex === -1) { return null; } return hashIndex; }; exports.removeAndGetHashFragment = removeAndGetHashFragment; const getSrcWithoutHash = (src) => { const hashIndex = (0, exports.removeAndGetHashFragment)(src); if (hashIndex === null) { return src; } return src.slice(0, hashIndex); }; exports.getSrcWithoutHash = getSrcWithoutHash; const usePreload = (src) => { const preloads = (0, react_1.useContext)(prefetch_state_js_1.PreloadContext); const hashFragmentIndex = (0, exports.removeAndGetHashFragment)(src); const withoutHashFragment = (0, exports.getSrcWithoutHash)(src); if (!preloads[withoutHashFragment]) { return src; } if (hashFragmentIndex !== null) { return preloads[withoutHashFragment] + src.slice(hashFragmentIndex); } return preloads[withoutHashFragment]; }; exports.usePreload = usePreload; const blobToBase64 = function (blob) { const reader = new FileReader(); return new Promise((resolve, reject) => { reader.onload = function () { const dataUrl = reader.result; resolve(dataUrl); }; reader.onerror = (err) => { return reject(err); }; reader.readAsDataURL(blob); }); }; const getBlobFromReader = async ({ reader, contentType, contentLength, onProgress, }) => { let receivedLength = 0; const chunks = []; while (true) { const { done, value } = await reader.read(); if (done) { break; } chunks.push(value); receivedLength += value.length; if (onProgress) { onProgress({ loadedBytes: receivedLength, totalBytes: contentLength }); } } const chunksAll = new Uint8Array(receivedLength); let position = 0; for (const chunk of chunks) { chunksAll.set(chunk, position); position += chunk.length; } return new Blob([chunksAll], { type: contentType !== null && contentType !== void 0 ? contentType : undefined, }); }; /* * @description When you call the prefetch() function, an asset will be fetched and kept in memory so it is ready when you want to play it in a <Player>. * @see [Documentation](https://www.remotion.dev/docs/prefetch) */ const prefetch = (src, options) => { var _a, _b, _c; const method = (_a = options === null || options === void 0 ? void 0 : options.method) !== null && _a !== void 0 ? _a : 'blob-url'; const logLevel = (_b = options === null || options === void 0 ? void 0 : options.logLevel) !== null && _b !== void 0 ? _b : 'info'; const srcWithoutHash = (0, exports.getSrcWithoutHash)(src); if ((0, get_remotion_environment_js_1.getRemotionEnvironment)().isRendering) { return { free: () => undefined, waitUntilDone: () => Promise.resolve(srcWithoutHash), }; } log_js_1.Log.verbose(logLevel, `[prefetch] Starting prefetch ${srcWithoutHash}`); let canceled = false; let objectUrl = null; let resolve = () => undefined; let reject = () => undefined; const waitUntilDone = new Promise((res, rej) => { resolve = res; reject = rej; }); const controller = new AbortController(); let canBeAborted = true; fetch(srcWithoutHash, { signal: controller.signal, credentials: (_c = options === null || options === void 0 ? void 0 : options.credentials) !== null && _c !== void 0 ? _c : undefined, }) .then((res) => { var _a, _b, _c; canBeAborted = false; if (canceled) { return null; } if (!res.ok) { throw new Error(`HTTP error, status = ${res.status}`); } const headerContentType = res.headers.get('Content-Type'); const contentType = (_a = options === null || options === void 0 ? void 0 : options.contentType) !== null && _a !== void 0 ? _a : headerContentType; const hasProperContentType = contentType && (contentType.startsWith('video/') || contentType.startsWith('audio/') || contentType.startsWith('image/')); if (!hasProperContentType) { // eslint-disable-next-line no-console console.warn(`Called prefetch() on ${srcWithoutHash} which returned a "Content-Type" of ${headerContentType}. Prefetched content should have a proper content type (video/... or audio/...) or a contentType passed the options of prefetch(). Otherwise, prefetching will not work properly in all browsers.`); } if (!res.body) { throw new Error(`HTTP response of ${srcWithoutHash} has no body`); } const reader = res.body.getReader(); return getBlobFromReader({ reader, contentType: (_c = (_b = options === null || options === void 0 ? void 0 : options.contentType) !== null && _b !== void 0 ? _b : headerContentType) !== null && _c !== void 0 ? _c : null, contentLength: res.headers.get('Content-Length') ? parseInt(res.headers.get('Content-Length'), 10) : null, onProgress: options === null || options === void 0 ? void 0 : options.onProgress, }); }) .then((buf) => { if (!buf) { return; } const actualBlob = (options === null || options === void 0 ? void 0 : options.contentType) ? new Blob([buf], { type: options.contentType }) : buf; if (method === 'base64') { return blobToBase64(actualBlob); } return URL.createObjectURL(actualBlob); }) .then((url) => { if (canceled) { return; } (0, playback_logging_js_1.playbackLogging)({ logLevel, tag: 'prefetch', message: `Finished prefetch ${srcWithoutHash} with method ${method}`, mountTime: null, }); objectUrl = url; (0, prefetch_state_js_1.setPreloads)((p) => ({ ...p, [srcWithoutHash]: objectUrl, })); resolve(objectUrl); }) .catch((err) => { if (err === null || err === void 0 ? void 0 : err.message.includes('free() called')) { return; } reject(err); }); return { free: () => { (0, playback_logging_js_1.playbackLogging)({ logLevel, tag: 'prefetch', message: `Freeing ${srcWithoutHash}`, mountTime: null, }); if (objectUrl) { if (method === 'blob-url') { URL.revokeObjectURL(objectUrl); } (0, prefetch_state_js_1.setPreloads)((p) => { const copy = { ...p }; delete copy[srcWithoutHash]; return copy; }); } else { canceled = true; if (canBeAborted) { try { controller.abort(new Error('free() called')); } catch (_a) { } } } }, waitUntilDone: () => { return waitUntilDone; }, }; }; exports.prefetch = prefetch;