Browse Source

implement allowRemoteRequests #60 #61

layer-manipulation
Mikael Finstad 6 years ago
parent
commit
ad7a89b7b8
  1. 6
      README.md
  2. 5
      cli.js
  3. 9
      examples/remote.json5
  4. 19
      index.js
  5. 4
      sources/fabric/fabricFrameSources.js
  6. 3
      util.js

6
README.md

@ -125,6 +125,7 @@ Edit specs are JavaScript / JSON objects describing the whole edit operation wit
audioFilePath, audioFilePath,
loopAudio: false, loopAudio: false,
keepSourceAudio: false, keepSourceAudio: false,
allowRemoteRequests: false,
clips: [ clips: [
{ {
transition, 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** | | | `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` | | | `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 | | | | `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` | | | `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.fontPath` | `--font-path` | Set default font to a .ttf | System font | |
| `defaults.layer.*` | | Set any layer parameter that all layers will inherit | | | | `defaults.layer.*` | | Set any layer parameter that all layers will inherit | | |

5
cli.js

@ -34,6 +34,7 @@ const cli = meow(`
--audio-file-path Add an audio track --audio-file-path Add an audio track
--loop-audio Loop the audio track if it is shorter than video? --loop-audio Loop the audio track if it is shorter than video?
--keep-source-audio Keep audio from source files --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) --fast, -f Fast mode (low resolution and FPS, useful for getting a quick preview)
--verbose, -v --verbose, -v
@ -48,6 +49,7 @@ const cli = meow(`
flags: { flags: {
verbose: { type: 'boolean', alias: 'v' }, verbose: { type: 'boolean', alias: 'v' },
keepSourceAudio: { type: 'boolean' }, keepSourceAudio: { type: 'boolean' },
allowRemoteRequests: { type: 'boolean' },
fast: { type: 'boolean', alias: 'f' }, fast: { type: 'boolean', alias: 'f' },
transitionDuration: { type: 'number' }, transitionDuration: { type: 'number' },
clipDuration: { type: 'number' }, clipDuration: { type: 'number' },
@ -96,7 +98,7 @@ const cli = meow(`
params.clips = clips.map((clip) => ({ layers: [clip] })); 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) { if (transitionName || transitionDuration != null) {
params.defaults.transition = {}; params.defaults.transition = {};
@ -116,6 +118,7 @@ const cli = meow(`
if (audioFilePath) params.audioFilePath = audioFilePath; if (audioFilePath) params.audioFilePath = audioFilePath;
if (loopAudio) params.loopAudio = loopAudio; if (loopAudio) params.loopAudio = loopAudio;
if (keepSourceAudio) params.keepSourceAudio = true; if (keepSourceAudio) params.keepSourceAudio = true;
if (allowRemoteRequests) params.allowRemoteRequests = true;
if (width) params.width = width; if (width) params.width = width;
if (height) params.height = height; if (height) params.height = height;
if (fps) params.fps = fps; if (fps) params.fps = fps;

9
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' }] },
],
}

19
index.js

@ -7,7 +7,7 @@ const JSON5 = require('json5');
const fs = require('fs-extra'); const fs = require('fs-extra');
const { nanoid } = require('nanoid'); 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 { registerFont } = require('./sources/fabric');
const { createFrameSource } = require('./sources/frameSource'); const { createFrameSource } = require('./sources/frameSource');
const { calcTransition } = require('./transitions'); const { calcTransition } = require('./transitions');
@ -21,8 +21,6 @@ const loadedFonts = [];
// See #16 // See #16
const checkTransition = (transition) => assert(transition == null || typeof transition === 'object', 'Transition must be an object'); 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 = {}) => { module.exports = async (config = {}) => {
const { const {
// Testing options: // Testing options:
@ -39,17 +37,26 @@ module.exports = async (config = {}) => {
audioFilePath: audioFilePathIn, audioFilePath: audioFilePathIn,
loopAudio, loopAudio,
keepSourceAudio, keepSourceAudio,
allowRemoteRequests,
ffmpegPath = 'ffmpeg', ffmpegPath = 'ffmpeg',
ffprobePath = 'ffprobe', ffprobePath = 'ffprobe',
} = config; } = 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'); const isGif = outPath.toLowerCase().endsWith('.gif');
let audioFilePath; let audioFilePath;
if (!isGif) audioFilePath = audioFilePathIn; if (!isGif) audioFilePath = audioFilePathIn;
if (audioFilePath) await assertFileExists(audioFilePath);
if (audioFilePath) await assertFileValid(audioFilePath);
checkTransition(defaultsIn.transition); checkTransition(defaultsIn.transition);
@ -73,9 +80,9 @@ module.exports = async (config = {}) => {
// https://github.com/mifi/editly/issues/39 // https://github.com/mifi/editly/issues/39
if (['image', 'image-overlay'].includes(type)) { if (['image', 'image-overlay'].includes(type)) {
await assertFileExists(restLayer.path);
await assertFileValid(restLayer.path);
} else if (type === 'gl') { } 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'); if (['fabric', 'canvas'].includes(type)) assert(typeof layer.func === 'function', '"func" must be a function');

4
sources/fabric/fabricFrameSources.js

@ -3,14 +3,14 @@ const fileUrl = require('file-url');
const { getRandomGradient, getRandomColors } = require('../../colors'); const { getRandomGradient, getRandomColors } = require('../../colors');
const { easeOutExpo, easeInOutCubic } = require('../../transitions'); const { easeOutExpo, easeInOutCubic } = require('../../transitions');
const { getPositionProps, getFrameByKeyFrames } = require('../../util');
const { getPositionProps, getFrameByKeyFrames, isUrl } = require('../../util');
// http://fabricjs.com/kitchensink // http://fabricjs.com/kitchensink
const defaultFontFamily = 'sans-serif'; 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 }) { function getZoomParams({ progress, zoomDirection, zoomAmount }) {
let scaleFactor = 1; let scaleFactor = 1;

3
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)]))); 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 = { module.exports = {
parseFps, parseFps,
@ -161,4 +163,5 @@ module.exports = {
readFileStreams, readFileStreams,
getPositionProps, getPositionProps,
getFrameByKeyFrames, getFrameByKeyFrames,
isUrl,
}; };
Loading…
Cancel
Save