From 36a148bb43672700d91cc6a65c993d54a343886d Mon Sep 17 00:00:00 2001 From: Jerome Wu Date: Tue, 24 Nov 2020 11:26:53 +0800 Subject: [PATCH] Refactor remote script loading code --- src/browser/getCreateFFmpegCore.js | 54 ++++++++++++++++++++++++------ src/createFFmpeg.js | 34 ++++++++++++++++--- src/node/getCreateFFmpegCore.js | 2 +- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/browser/getCreateFFmpegCore.js b/src/browser/getCreateFFmpegCore.js index f94985f..ed38e0b 100644 --- a/src/browser/getCreateFFmpegCore.js +++ b/src/browser/getCreateFFmpegCore.js @@ -1,23 +1,50 @@ +/* eslint-disable no-undef */ const resolveURL = require('resolve-url'); const { log } = require('../utils/log'); +/* + * Fetch data from remote URL and convert to blob URL + * to avoid CORS issue + */ +const toBlobURL = async (url, mimeType) => { + log('info', `fetch ${url}`); + const buf = await (await fetch(url)).arrayBuffer(); + log('info', `${url} file size = ${buf.byteLength} bytes`); + const blob = new Blob([buf], { type: mimeType }); + const blobURL = URL.createObjectURL(blob); + log('info', `${url} blob URL = ${blobURL}`); + return blobURL; +}; + module.exports = async ({ corePath: _corePath }) => { if (typeof _corePath !== 'string') { throw Error('corePath should be a string!'); } - if (typeof window.createFFmpegCore === 'undefined') { - log('info', 'fetch ffmpeg-core.worker.js script'); - const corePath = resolveURL(_corePath); - const workerBlob = await (await fetch(corePath.replace('ffmpeg-core.js', 'ffmpeg-core.worker.js'))).blob(); - window.FFMPEG_CORE_WORKER_SCRIPT = URL.createObjectURL(workerBlob); - log('info', `worker object URL=${window.FFMPEG_CORE_WORKER_SCRIPT}`); - log('info', `download ffmpeg-core script (~25 MB) from ${corePath}`); + const coreRemotePath = resolveURL(_corePath); + const corePath = await toBlobURL( + coreRemotePath, + 'application/javascript', + ); + const wasmPath = await toBlobURL( + coreRemotePath.replace('ffmpeg-core.js', 'ffmpeg-core.wasm'), + 'application/wasm', + ); + const workerPath = await toBlobURL( + coreRemotePath.replace('ffmpeg-core.js', 'ffmpeg-core.worker.js'), + 'application/javascript', + ); + if (typeof createFFmpegCore === 'undefined') { return new Promise((resolve) => { const script = document.createElement('script'); const eventHandler = () => { script.removeEventListener('load', eventHandler); - log('info', 'initialize ffmpeg-core'); - resolve(window.createFFmpegCore); + log('info', 'ffmpeg-core.js script loaded'); + resolve({ + createFFmpegCore, + corePath, + wasmPath, + workerPath, + }); }; script.src = corePath; script.type = 'text/javascript'; @@ -25,6 +52,11 @@ module.exports = async ({ corePath: _corePath }) => { document.getElementsByTagName('head')[0].appendChild(script); }); } - log('info', 'ffmpeg-core is loaded already'); - return Promise.resolve(window.createFFmpegCore); + log('info', 'ffmpeg-core.js script is loaded already'); + return Promise.resolve({ + createFFmpegCore, + corePath, + wasmPath, + workerPath, + }); }; diff --git a/src/createFFmpeg.js b/src/createFFmpeg.js index a300e53..f5e22a6 100644 --- a/src/createFFmpeg.js +++ b/src/createFFmpeg.js @@ -51,15 +51,39 @@ module.exports = (_options = {}) => { log('info', 'load ffmpeg-core'); if (Core === null) { log('info', 'loading ffmpeg-core'); - const createFFmpegCore = await getCreateFFmpegCore(options); + /* + * In node environment, all paths are undefined as there + * is no need to set them. + */ + const { + createFFmpegCore, + corePath, + workerPath, + wasmPath, + } = await getCreateFFmpegCore(options); Core = await createFFmpegCore({ + /* + * Assign mainScriptUrlOrBlob fixes chrome extension web worker issue + * as there is no document.currentScript in the context of content_scripts + */ + mainScriptUrlOrBlob: corePath, printErr: (message) => parseMessage({ type: 'fferr', message }), print: (message) => parseMessage({ type: 'ffout', message }), + /* + * locateFile overrides paths of files that is loaded by main script (ffmpeg-core.js). + * It is critical for browser environment and we override both wasm and worker paths + * as we are using blob URL instead of original URL to avoid cross origin issues. + */ locateFile: (path, prefix) => { - if (typeof window !== 'undefined' - && typeof window.FFMPEG_CORE_WORKER_SCRIPT !== 'undefined' - && path.endsWith('ffmpeg-core.worker.js')) { - return window.FFMPEG_CORE_WORKER_SCRIPT; + if (typeof window !== 'undefined') { + if (typeof wasmPath !== 'undefined' + && path.endsWith('ffmpeg-core.wasm')) { + return wasmPath; + } + if (typeof workerPath !== 'undefined' + && path.endsWith('ffmpeg-core.worker.js')) { + return workerPath; + } } return prefix + path; }, diff --git a/src/node/getCreateFFmpegCore.js b/src/node/getCreateFFmpegCore.js index 49b536f..29314c9 100644 --- a/src/node/getCreateFFmpegCore.js +++ b/src/node/getCreateFFmpegCore.js @@ -3,5 +3,5 @@ const { log } = require('../utils/log'); module.exports = ({ corePath }) => new Promise((resolve) => { log('info', `fetch ffmpeg.wasm-core script from ${corePath}`); // eslint-disable-next-line import/no-dynamic-require - resolve(require(corePath)); + resolve({ createFFmpegCore: require(corePath) }); });