From ad7a89b7b81a17a09b85e219b54f20399bab5cd8 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Thu, 24 Sep 2020 00:37:14 +0200 Subject: [PATCH] implement allowRemoteRequests #60 #61 --- README.md | 6 ++++-- cli.js | 5 ++++- examples/remote.json5 | 9 +++++++++ index.js | 19 +++++++++++++------ sources/fabric/fabricFrameSources.js | 4 ++-- util.js | 3 +++ 6 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 examples/remote.json5 diff --git a/README.md b/README.md index f55f9ced..74149a74 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ Edit specs are JavaScript / JSON objects describing the whole edit operation wit audioFilePath, loopAudio: false, keepSourceAudio: false, + allowRemoteRequests: false, clips: [ { transition, @@ -156,8 +157,9 @@ Edit specs are JavaScript / JSON objects describing the whole edit operation wit | `height` | `--height` | Height which all media will be converted to | auto based on `width` and aspect ratio of **first video** | | | `fps` | `--fps` | FPS which all videos will be converted to | First video FPS or `25` | | | `audioFilePath` | `--audio-file-path` | Set an audio track for the whole video | | | -| `loopAudio` | `--loop-audio` | Loop the audio track if it is shorter than video? | | | -| `keepSourceAudio` | `--keep-source-audio` | Keep audio from source files | | | +| `loopAudio` | `--loop-audio` | Loop the audio track if it is shorter than video? | `false` | | +| `keepSourceAudio` | `--keep-source-audio` | Keep audio from source files | `false` | | +| `allowRemoteRequests` | `--allow-remote-requests` | Allow remote URLs as paths | `false` | | | `fast` | `--fast`, `-f` | Fast mode (low resolution and FPS, useful for getting a quick preview) | `false` | | | `defaults.layer.fontPath` | `--font-path` | Set default font to a .ttf | System font | | | `defaults.layer.*` | | Set any layer parameter that all layers will inherit | | | diff --git a/cli.js b/cli.js index 1d7dbcc4..cfe89c10 100644 --- a/cli.js +++ b/cli.js @@ -34,6 +34,7 @@ const cli = meow(` --audio-file-path Add an audio track --loop-audio Loop the audio track if it is shorter than video? --keep-source-audio Keep audio from source files + --allow-remote-requests --fast, -f Fast mode (low resolution and FPS, useful for getting a quick preview) --verbose, -v @@ -48,6 +49,7 @@ const cli = meow(` flags: { verbose: { type: 'boolean', alias: 'v' }, keepSourceAudio: { type: 'boolean' }, + allowRemoteRequests: { type: 'boolean' }, fast: { type: 'boolean', alias: 'f' }, transitionDuration: { type: 'number' }, clipDuration: { type: 'number' }, @@ -96,7 +98,7 @@ const cli = meow(` params.clips = clips.map((clip) => ({ layers: [clip] })); } - const { verbose, transitionName, transitionDuration, clipDuration, width, height, fps, audioFilePath, fontPath, fast, out: outPath, keepSourceAudio, loopAudio } = cli.flags; + const { verbose, transitionName, transitionDuration, clipDuration, width, height, fps, audioFilePath, fontPath, fast, out: outPath, keepSourceAudio, loopAudio, allowRemoteRequests } = cli.flags; if (transitionName || transitionDuration != null) { params.defaults.transition = {}; @@ -116,6 +118,7 @@ const cli = meow(` if (audioFilePath) params.audioFilePath = audioFilePath; if (loopAudio) params.loopAudio = loopAudio; if (keepSourceAudio) params.keepSourceAudio = true; + if (allowRemoteRequests) params.allowRemoteRequests = true; if (width) params.width = width; if (height) params.height = height; if (fps) params.fps = fps; diff --git a/examples/remote.json5 b/examples/remote.json5 new file mode 100644 index 00000000..48cb481e --- /dev/null +++ b/examples/remote.json5 @@ -0,0 +1,9 @@ +{ + outPath: './remote.mp4', + allowRemoteRequests: true, + clips: [ + { layers: [{ type: 'image', path: 'https://picsum.photos/400/400' }] }, + { layers: [{ type: 'image', path: 'https://picsum.photos/200/400' }] }, + { layers: [{ type: 'image', path: 'https://picsum.photos/400/200' }] }, + ], +} \ No newline at end of file diff --git a/index.js b/index.js index 29a72d88..c8442438 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,7 @@ const JSON5 = require('json5'); const fs = require('fs-extra'); const { nanoid } = require('nanoid'); -const { parseFps, readVideoFileInfo, readAudioFileInfo, multipleOf2 } = require('./util'); +const { parseFps, readVideoFileInfo, readAudioFileInfo, multipleOf2, isUrl } = require('./util'); const { registerFont } = require('./sources/fabric'); const { createFrameSource } = require('./sources/frameSource'); const { calcTransition } = require('./transitions'); @@ -21,8 +21,6 @@ const loadedFonts = []; // See #16 const checkTransition = (transition) => assert(transition == null || typeof transition === 'object', 'Transition must be an object'); -const assertFileExists = async (path) => assert(await fs.exists(path), `File does not exist ${path}`); - module.exports = async (config = {}) => { const { // Testing options: @@ -39,17 +37,26 @@ module.exports = async (config = {}) => { audioFilePath: audioFilePathIn, loopAudio, keepSourceAudio, + allowRemoteRequests, ffmpegPath = 'ffmpeg', ffprobePath = 'ffprobe', } = config; + const assertFileValid = async (path) => { + if (isUrl(path)) { + assert(allowRemoteRequests, 'Remote requests are not allowed'); + return; + } + assert(await fs.exists(path), `File does not exist ${path}`); + }; + const isGif = outPath.toLowerCase().endsWith('.gif'); let audioFilePath; if (!isGif) audioFilePath = audioFilePathIn; - if (audioFilePath) await assertFileExists(audioFilePath); + if (audioFilePath) await assertFileValid(audioFilePath); checkTransition(defaultsIn.transition); @@ -73,9 +80,9 @@ module.exports = async (config = {}) => { // https://github.com/mifi/editly/issues/39 if (['image', 'image-overlay'].includes(type)) { - await assertFileExists(restLayer.path); + await assertFileValid(restLayer.path); } else if (type === 'gl') { - await assertFileExists(restLayer.fragmentPath); + await assertFileValid(restLayer.fragmentPath); } if (['fabric', 'canvas'].includes(type)) assert(typeof layer.func === 'function', '"func" must be a function'); diff --git a/sources/fabric/fabricFrameSources.js b/sources/fabric/fabricFrameSources.js index e9aba406..12dd40d6 100644 --- a/sources/fabric/fabricFrameSources.js +++ b/sources/fabric/fabricFrameSources.js @@ -3,14 +3,14 @@ const fileUrl = require('file-url'); const { getRandomGradient, getRandomColors } = require('../../colors'); const { easeOutExpo, easeInOutCubic } = require('../../transitions'); -const { getPositionProps, getFrameByKeyFrames } = require('../../util'); +const { getPositionProps, getFrameByKeyFrames, isUrl } = require('../../util'); // http://fabricjs.com/kitchensink const defaultFontFamily = 'sans-serif'; -const loadImage = async (path) => new Promise((resolve) => fabric.util.loadImage(fileUrl(path), resolve)); +const loadImage = async (pathOrUrl) => new Promise((resolve) => fabric.util.loadImage(isUrl(pathOrUrl) ? pathOrUrl : fileUrl(pathOrUrl), resolve)); function getZoomParams({ progress, zoomDirection, zoomAmount }) { let scaleFactor = 1; diff --git a/util.js b/util.js index ef08103c..229a7756 100644 --- a/util.js +++ b/util.js @@ -151,6 +151,8 @@ function getFrameByKeyFrames(keyframes, progress) { return Object.fromEntries(Object.entries(prevKeyframe.props).map(([propName, prevVal]) => ([propName, prevVal + ((nextKeyframe.props[propName] - prevVal) * interProgress)]))); } +const isUrl = (path) => /^https?:\/\//.test(path); + module.exports = { parseFps, @@ -161,4 +163,5 @@ module.exports = { readFileStreams, getPositionProps, getFrameByKeyFrames, + isUrl, };