206 lines
7.7 KiB
JavaScript
206 lines
7.7 KiB
JavaScript
"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, tag: '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;
|