Compare commits

..

No commits in common. "main" and "v1.0.3" have entirely different histories.
main ... v1.0.3

7 changed files with 2018 additions and 4086 deletions

View File

@ -4,8 +4,6 @@ Node script to generate flicker videos by interweaving frames from multiple vide
--------
## Git URL [git.sixteenmillimeter.com/16mm/frameloom](https://git.sixteenmillimeter.com/16mm/frameloom)
## Requirements
This script relies on `ffmpeg` to export and stitch video back together
@ -23,15 +21,13 @@ chmod +x frameloom
## Basic Usage
```bash
./frameloom -i /path/to/video1:/path/to/video2 -o /path/to/output
```
```./frameloom -i /path/to/video1:/path/to/video2 -o /path/to/output```
## Options
Run `./frameloom -h` to display help screen.
```bash
```
Usage: frameloom [options]
Options:
@ -43,19 +39,11 @@ Options:
-t, --tmp [dir] Specify tmp directory for exporting frames
-a, --avconv Specify avconv if preferred to ffmpeg
-R, --random Randomize frames. Ignores pattern if included
-s, --spin Randomly rotate frames before rendering
-e, --exec Command to execute on every frame. Specify {{i}} and {{o}} if the command requires
it, otherwise frame path will be appended to command
-q, --quiet Suppresses all log messages
-h, --help display help for command
-h, --help output usage information
```
## License
## TODO
Copyright 2018-2021 M McWilliams
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* Generate example videos automatically
* Publish example videos

View File

@ -8,10 +8,6 @@
<dt><a href="#delay">delay(ms)</a><code>Promise</code></dt>
<dd><p>Delays process for specified amount of time in milliseconds.</p>
</dd>
<dt><a href="#log">log()</a></dt>
<dd><p>Log function wrapper that can silences logs when
QUIET == true</p>
</dd>
<dt><a href="#zeroPad">zeroPad(i, max)</a><code>string</code></dt>
<dd><p>Pads a numerical value with preceding zeros to make strings same length.</p>
</dd>
@ -19,18 +15,15 @@ QUIET == true</p>
<dd><p>Shuffles an array into a random state.</p>
</dd>
<dt><a href="#clear">clear()</a></dt>
<dd><p>Clears the temporary directory of all files.
<dd><p>Clears the temporary directory of all files.
Establishes a directory if none exists.</p>
</dd>
<dt><a href="#frames">frames(video, order, avconv)</a><code>string</code></dt>
<dt><a href="#frames">frames(video, order)</a><code>string</code></dt>
<dd><p>Exports all frames from video. Appends number to the string
to keep frames in alternating order to be quickly stitched together
or re-sorted.</p>
</dd>
<dt><a href="#subExec">subExec(cmd)</a></dt>
<dd><p>Shells out to run a sub command on every frame to perform effects</p>
</dd>
<dt><a href="#weave">weave(pattern, realtime, random)</a></dt>
<dt><a href="#weave">weave(pattern, realtime)</a></dt>
<dd><p>Re-arranges the frames into the order specified in the pattern.
Calls <code>patternSort()</code> to perform the rename and unlink actions</p>
</dd>
@ -43,7 +36,7 @@ QUIET == true</p>
<dt><a href="#randomSort">randomSort(list, pattern, realtime)</a></dt>
<dd><p>Ramdomly sort frames for re-stitching.</p>
</dd>
<dt><a href="#render">render(output, avconv)</a></dt>
<dt><a href="#render">render(output)</a></dt>
<dd><p>Render the frames into a video using ffmpeg.</p>
</dd>
<dt><a href="#main">main(arg)</a></dt>
@ -77,13 +70,6 @@ Delays process for specified amount of time in milliseconds.
| --- | --- | --- |
| ms | <code>integer</code> | Milliseconds to delay for |
<a name="log"></a>
## log()
Log function wrapper that can silences logs when
QUIET == true
**Kind**: global function
<a name="zeroPad"></a>
## zeroPad(i, max) ⇒ <code>string</code>
@ -111,13 +97,13 @@ Shuffles an array into a random state.
<a name="clear"></a>
## clear()
Clears the temporary directory of all files.
Clears the temporary directory of all files.
Establishes a directory if none exists.
**Kind**: global function
<a name="frames"></a>
## frames(video, order, avconv) ⇒ <code>string</code>
## frames(video, order) ⇒ <code>string</code>
Exports all frames from video. Appends number to the string
to keep frames in alternating order to be quickly stitched together
or re-sorted.
@ -129,22 +115,10 @@ Exports all frames from video. Appends number to the string
| --- | --- | --- |
| video | <code>string</code> | String representing path to video |
| order | <code>integer</code> | Integer to be appended to pathname of file |
| avconv | <code>boolean</code> | Whether or not to use avconv instead of ffmpeg |
<a name="subExec"></a>
## subExec(cmd)
Shells out to run a sub command on every frame to perform effects
**Kind**: global function
| Param | Type | Description |
| --- | --- | --- |
| cmd | <code>string</code> | Command to execute on every frame |
<a name="weave"></a>
## weave(pattern, realtime, random)
## weave(pattern, realtime)
Re-arranges the frames into the order specified in the pattern.
Calls `patternSort()` to perform the rename and unlink actions
@ -154,7 +128,6 @@ Re-arranges the frames into the order specified in the pattern.
| --- | --- | --- |
| pattern | <code>array</code> | Pattern of the frames per input |
| realtime | <code>boolean</code> | Flag to turn on or off realtime behavior (drop frames / number of vids) |
| random | <code>boolean</code> | Whether or not to randomize frames |
<a name="altSort"></a>
@ -197,7 +170,7 @@ Ramdomly sort frames for re-stitching.
<a name="render"></a>
## render(output, avconv)
## render(output)
Render the frames into a video using ffmpeg.
**Kind**: global function
@ -205,7 +178,6 @@ Render the frames into a video using ffmpeg.
| Param | Type | Description |
| --- | --- | --- |
| output | <code>string</code> | Path to export the video to |
| avconv | <code>boolean</code> | Whether or not to use avconv in place of ffmpeg |
<a name="main"></a>

View File

@ -1,15 +1,15 @@
#!/usr/bin/env node
'use strict';
const execRaw = require('child_process').exec;
const { tmpdir } = require('os');
const { join, extname } = require('path');
const os = require('os');
const path = require('path');
const program = require('commander');
const { move, exists, unlink, readdir, mkdir } = require('fs-extra');
const { version } = require('./package.json');
const fs = require('fs-extra');
const pkg = require('./package.json');
const OUTPUT_RE = new RegExp('{{o}}', 'g');
const INPUT_RE = new RegExp('{{i}}', 'g');
let QUIET = false;
let TMPDIR = tmpdir() || '/tmp';
let TMPDIR = os.tmpdir() || '/tmp';
let TMPPATH;
/**
* Shells out to execute a command with async/await.
@ -97,14 +97,14 @@ function randomInt(min, max) {
**/
async function clear() {
let cmd = `rm -r "${TMPPATH}"`;
let dirExists;
let exists;
try {
dirExists = await exists(TMPPATH);
exists = await fs.exists(TMPPATH);
}
catch (err) {
log('Error checking if file exists', err);
}
if (dirExists) {
if (exists) {
log(`Clearing temp directory "${TMPPATH}"`);
try {
await exec(cmd);
@ -115,7 +115,7 @@ async function clear() {
}
}
try {
await mkdir(TMPPATH);
await fs.mkdir(TMPPATH);
}
catch (err) {
if (err.code !== 'EEXIST') {
@ -140,7 +140,7 @@ async function frames(video, order, avconv) {
let exe = avconv ? 'avconv' : 'ffmpeg';
let tmpoutput;
let cmd;
tmpoutput = join(TMPPATH, `export-%05d_${order}.${ext}`);
tmpoutput = path.join(TMPPATH, `export-%05d_${order}.${ext}`);
cmd = `${exe} -i "${video}" -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"`;
log(`Exporting ${video} as single frames...`);
try {
@ -150,7 +150,7 @@ async function frames(video, order, avconv) {
log('Error exporting video', err);
return process.exit(3);
}
return join(TMPPATH, `export-%05d_${order}`);
return path.join(TMPPATH, `export-%05d_${order}`);
}
/**
* Shells out to run a sub command on every frame to perform effects
@ -163,7 +163,7 @@ async function subExec(cmd) {
let frameCmd;
let framePath;
try {
frames = await readdir(TMPPATH);
frames = await fs.readdir(TMPPATH);
}
catch (err) {
log('Error reading tmp directory', err);
@ -173,7 +173,7 @@ async function subExec(cmd) {
return true;
});
for (let frame of frames) {
framePath = join(TMPPATH, frame);
framePath = path.join(TMPPATH, frame);
if (cmd.indexOf('{{i}}') !== -1 || cmd.indexOf('{{o}}')) {
frameCmd = cmd.replace(INPUT_RE, framePath)
.replace(OUTPUT_RE, framePath);
@ -204,7 +204,7 @@ async function weave(pattern, realtime, random) {
let alt = false;
log('Weaving frames...');
try {
frames = await readdir(TMPPATH);
frames = await fs.readdir(TMPPATH);
}
catch (err) {
log('Error reading tmp directory', err);
@ -268,7 +268,7 @@ async function altSort(list, pattern, realtime) {
let oldPath;
let newName;
let newPath;
let ext = extname(list[0]);
let ext = path.extname(list[0]);
let x;
let i;
for (x = 0; x < pattern.length; x++) {
@ -298,12 +298,12 @@ async function altSort(list, pattern, realtime) {
continue;
}
oldName = String(groups[patternIndexes[i]][0]);
oldPath = join(TMPPATH, oldName);
oldPath = path.join(TMPPATH, oldName);
groups[patternIndexes[i]].shift();
if (skip) {
log(`Skipping ${oldName}`);
try {
await unlink(oldPath);
await fs.unlink(oldPath);
}
catch (err) {
log('Error deleting frame', err);
@ -311,10 +311,10 @@ async function altSort(list, pattern, realtime) {
continue;
}
newName = `./render_${zeroPad(frameCount)}${ext}`;
newPath = join(TMPPATH, newName);
newPath = path.join(TMPPATH, newName);
log(`Renaming ${oldName} -> ${newName}`);
try {
await move(oldPath, newPath);
await fs.move(oldPath, newPath);
newList.push(newName);
frameCount++;
}
@ -339,7 +339,7 @@ async function standardSort(list, pattern, realtime) {
let step;
let skipCount;
let skip;
let ext = extname(list[0]);
let ext = path.extname(list[0]);
let oldPath;
let newName;
let newPath;
@ -356,11 +356,11 @@ async function standardSort(list, pattern, realtime) {
skipCount = pattern.length;
}
}
oldPath = join(TMPPATH, list[i]);
oldPath = path.join(TMPPATH, list[i]);
if (skip) {
log(`Skipping ${list[i]}`);
try {
await unlink(oldPath);
await fs.unlink(oldPath);
}
catch (err) {
log('Error deleting frame', err);
@ -368,10 +368,10 @@ async function standardSort(list, pattern, realtime) {
continue;
}
newName = `./render_${zeroPad(frameCount)}${ext}`;
newPath = join(TMPPATH, newName);
newPath = path.join(TMPPATH, newName);
log(`Renaming ${list[i]} -> ${newName}`);
try {
await move(oldPath, newPath);
await fs.move(oldPath, newPath);
newList.push(newName);
frameCount++;
}
@ -391,7 +391,7 @@ async function standardSort(list, pattern, realtime) {
**/
async function randomSort(list, pattern, realtime) {
let frameCount = 0;
let ext = extname(list[0]);
let ext = path.extname(list[0]);
let oldPath;
let newName;
let newPath;
@ -405,10 +405,10 @@ async function randomSort(list, pattern, realtime) {
list = list.slice(0, removeLen);
log(`Skipping extra frames...`);
for (let i = 0; i < remove.length; i++) {
oldPath = join(TMPPATH, remove[i]);
oldPath = path.join(TMPPATH, remove[i]);
log(`Skipping ${list[i]}`);
try {
await unlink(oldPath);
await fs.unlink(oldPath);
}
catch (err) {
log('Error deleting frame', err);
@ -416,12 +416,12 @@ async function randomSort(list, pattern, realtime) {
}
}
for (let i = 0; i < list.length; i++) {
oldPath = join(TMPPATH, list[i]);
oldPath = path.join(TMPPATH, list[i]);
newName = `./render_${zeroPad(frameCount)}${ext}`;
newPath = join(TMPPATH, newName);
newPath = path.join(TMPPATH, newName);
log(`Renaming ${list[i]} -> ${newName}`);
try {
await move(oldPath, newPath);
await fs.move(oldPath, newPath);
newList.push(newName);
}
catch (err) {
@ -440,7 +440,7 @@ async function spinFrames() {
let rotate;
console.log('Spinning frames...');
try {
frames = await readdir(TMPPATH);
frames = await fs.readdir(TMPPATH);
}
catch (err) {
console.error('Error reading tmp directory', err);
@ -451,7 +451,7 @@ async function spinFrames() {
return true;
});
for (let frame of frames) {
framePath = join(TMPPATH, frame);
framePath = path.join(TMPPATH, frame);
rotate = '';
flip = '';
flop = '';
@ -487,7 +487,7 @@ async function spinFrames() {
**/
async function render(output, avconv) {
//process.exit()
let frames = join(TMPPATH, `render_%05d.tif`);
let frames = path.join(TMPPATH, `render_%05d.tif`);
let exe = avconv ? 'avconv' : 'ffmpeg';
let resolution = '1920x1080'; //TODO: make variable/argument
//TODO: make object configurable with shorthand names
@ -512,8 +512,7 @@ async function render(output, avconv) {
*
* @param {object} arg Object containing all arguments
**/
async function main(program) {
const arg = program.opts();
async function main(arg) {
let input = arg.input.split(':');
let output = arg.output;
let pattern = [];
@ -522,7 +521,7 @@ async function main(program) {
let random = false;
let e = false;
let exe = arg.avconv ? 'avconv' : 'ffmpeg';
let fileExists;
let exists;
console.time('frameloom');
if (input.length < 2) {
log('Must provide more than 1 input', {});
@ -559,13 +558,13 @@ async function main(program) {
}
}
try {
fileExists = await exec(`which ${exe}`);
exists = await exec(`which ${exe}`);
}
catch (err) {
log(`Error checking for ${exe}`);
process.exit(11);
}
if (!fileExists || fileExists === '' || fileExists.indexOf(exe) === -1) {
if (!exists || exists === '' || exists.indexOf(exe) === -1) {
log(`${exe} is required and is not installed. Please install ${exe} to use frameloom.`);
process.exit(12);
}
@ -575,7 +574,7 @@ async function main(program) {
}
if (arg.realtime)
realtime = true;
TMPPATH = join(TMPDIR, 'frameloom');
TMPPATH = path.join(TMPDIR, 'frameloom');
try {
await clear();
}
@ -635,7 +634,7 @@ async function main(program) {
console.timeEnd('frameloom');
}
program
.version(version)
.version(pkg.version)
.option('-i, --input [files]', 'Specify input videos with paths seperated by colon')
.option('-o, --output [file]', 'Specify output path of video')
.option('-p, --pattern [pattern]', 'Specify a pattern for the flicker 1:1 is standard')

35
frameloom.sh Normal file
View File

@ -0,0 +1,35 @@
#!/bin/sh
# Simple shell script version of frameloom
# Only creates a 1:1 pattern between 2 videos
# Usage : sh frameloom.sh examples/A.mp4 examples/B.mp4 examples/OUTPUT.mp4
TMPDIR=/tmp/frameloom/
i=0
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] ;
then
echo "Not enough arguments supplied"
fi
mkdir -p $TMPDIR
#relies on the alphanumeric sorting that occurs when getting
#the list of files in the for loop below
ffmpeg -i "$1" -compression_algo raw -pix_fmt rgb24 "${TMPDIR}export-%05d_a.tif"
ffmpeg -i "$2" -compression_algo raw -pix_fmt rgb24 "${TMPDIR}export-%05d_b.tif"
#rm -r $TMP
for filename in ${TMPDIR}*.tif; do
value=`printf %05d $i`
#echo $filename
#echo "${TMPDIR}render_${value}.tif"
mv "$filename" "${TMPDIR}render_${value}.tif"
i=`expr $i + 1`
done
ffmpeg -r 30 -f image2 -s 1920x1080 -i "${TMPDIR}render_%05d.tif" -c:v prores_ks -profile:v 3 -y "$3"
rm -r $TMPDIR

5819
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,15 +16,15 @@
"author": "sixteenmillimeter",
"license": "MIT",
"dependencies": {
"commander": "^7.2.0",
"fs-extra": "^9.1.0"
"commander": "^2.19.0",
"fs-extra": "^7.0.1"
},
"devDependencies": {
"@types/node": "^14.14.36",
"jsdoc-to-markdown": "^7.0.1",
"pkg": "^4.5.1",
"qunit": "^2.14.1",
"typescript": "^4.2.3"
"@types/node": "^11.13.0",
"jsdoc-to-markdown": "^4.0.1",
"pkg": "^4.4.0",
"qunit": "^2.8.0",
"typescript": "^3.4.1"
},
"pkg": {
"scripts": [

View File

@ -3,18 +3,18 @@
'use strict'
const execRaw = require('child_process').exec
const { tmpdir } = require('os')
const { join, extname } = require('path')
const os = require('os')
const path = require('path')
const program = require('commander')
const { move, exists, unlink, readdir, mkdir } = require('fs-extra')
const fs = require('fs-extra')
const { version } = require('./package.json')
const pkg : any = require('./package.json')
const OUTPUT_RE : RegExp = new RegExp('{{o}}', 'g')
const INPUT_RE : RegExp = new RegExp('{{i}}', 'g')
let QUIET : boolean = false
let TMPDIR : string = tmpdir() || '/tmp'
let TMPDIR : string = os.tmpdir() || '/tmp'
let TMPPATH : string
/**
@ -25,7 +25,7 @@ let TMPPATH : string
*
* @returns {Promise} Promise containing the complete stdio
**/
async function exec (cmd : string) : Promise<string> {
async function exec (cmd : string) {
return new Promise((resolve : any, reject : any) => {
return execRaw(cmd, { maxBuffer : 500 * 1024 * 1024}, (err : any, stdio : string, stderr : string) => {
if (err) return reject(err)
@ -40,7 +40,7 @@ async function exec (cmd : string) : Promise<string> {
*
* @returns {Promise} Promise that resolves after set time
**/
async function delay (ms : number) : Promise<any> {
async function delay (ms : number) {
return new Promise((resolve : any, reject : any) =>{
return setTimeout(resolve, ms)
})
@ -49,7 +49,7 @@ async function delay (ms : number) : Promise<any> {
* Log function wrapper that can silences logs when
* QUIET == true
*/
function log (msg : string, err : any = false) : boolean {
function log (msg : string, err : any = false) {
if (QUIET) return false
if (err) {
console.error(msg, err)
@ -102,15 +102,15 @@ function randomInt (min : number, max : number) {
**/
async function clear () {
let cmd : string = `rm -r "${TMPPATH}"`
let dirExists : boolean
let exists : boolean
try {
dirExists = await exists(TMPPATH)
exists = await fs.exists(TMPPATH)
} catch (err) {
log('Error checking if file exists', err)
}
if (dirExists) {
if (exists) {
log(`Clearing temp directory "${TMPPATH}"`)
try {
await exec(cmd)
@ -121,7 +121,7 @@ async function clear () {
}
try {
await mkdir(TMPPATH)
await fs.mkdir(TMPPATH)
} catch (err) {
if (err.code !== 'EEXIST') {
log('Error making directory', err)
@ -141,13 +141,13 @@ async function clear () {
*
* @returns {string} String with the export order, not sure why I did this
**/
async function frames (video : string, order : number, avconv : boolean) : Promise<string> {
async function frames (video : string, order : number, avconv : boolean) {
let ext : string = 'tif'
let exe : string = avconv ? 'avconv' : 'ffmpeg'
let tmpoutput : string
let cmd : string
tmpoutput = join(TMPPATH, `export-%05d_${order}.${ext}`)
tmpoutput = path.join(TMPPATH, `export-%05d_${order}.${ext}`)
cmd = `${exe} -i "${video}" -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"`
@ -160,7 +160,7 @@ async function frames (video : string, order : number, avconv : boolean) : Promi
return process.exit(3)
}
return join(TMPPATH, `export-%05d_${order}`)
return path.join(TMPPATH, `export-%05d_${order}`)
}
/**
* Shells out to run a sub command on every frame to perform effects
@ -174,7 +174,7 @@ async function subExec (cmd : string) {
let framePath : string
try {
frames = await readdir(TMPPATH)
frames = await fs.readdir(TMPPATH)
} catch (err) {
log('Error reading tmp directory', err)
}
@ -184,7 +184,7 @@ async function subExec (cmd : string) {
})
for (let frame of frames) {
framePath = join(TMPPATH, frame)
framePath = path.join(TMPPATH, frame)
if (cmd.indexOf('{{i}}') !== -1 || cmd.indexOf('{{o}}')) {
frameCmd = cmd.replace(INPUT_RE, framePath)
.replace(OUTPUT_RE, framePath)
@ -216,7 +216,7 @@ async function weave (pattern : number[], realtime : boolean, random : boolean)
log('Weaving frames...')
try {
frames = await readdir(TMPPATH)
frames = await fs.readdir(TMPPATH)
} catch (err) {
log('Error reading tmp directory', err)
}
@ -275,7 +275,7 @@ async function altSort (list : string[], pattern : number[], realtime : boolean)
let oldPath : string
let newName : string
let newPath : string
let ext : string = extname(list[0])
let ext : string = path.extname(list[0])
let x : number
let i : number
@ -313,14 +313,14 @@ async function altSort (list : string[], pattern : number[], realtime : boolean)
}
oldName = String(groups[patternIndexes[i]][0])
oldPath = join(TMPPATH, oldName)
oldPath = path.join(TMPPATH, oldName)
groups[patternIndexes[i]].shift()
if (skip) {
log(`Skipping ${oldName}`)
try {
await unlink(oldPath)
await fs.unlink(oldPath)
} catch (err) {
log('Error deleting frame', err)
}
@ -328,11 +328,11 @@ async function altSort (list : string[], pattern : number[], realtime : boolean)
}
newName = `./render_${zeroPad(frameCount)}${ext}`
newPath = join(TMPPATH, newName)
newPath = path.join(TMPPATH, newName)
log(`Renaming ${oldName} -> ${newName}`)
try {
await move(oldPath, newPath)
await fs.move(oldPath, newPath)
newList.push(newName)
frameCount++
} catch (err) {
@ -357,7 +357,7 @@ async function standardSort (list : string[], pattern : number[], realtime : boo
let step : any
let skipCount : number
let skip : boolean
let ext : string = extname(list[0])
let ext : string = path.extname(list[0])
let oldPath : string
let newName : string
let newPath : string
@ -377,12 +377,12 @@ async function standardSort (list : string[], pattern : number[], realtime : boo
}
}
oldPath = join(TMPPATH, list[i])
oldPath = path.join(TMPPATH, list[i])
if (skip) {
log(`Skipping ${list[i]}`)
try {
await unlink(oldPath)
await fs.unlink(oldPath)
} catch (err) {
log('Error deleting frame', err)
}
@ -390,11 +390,11 @@ async function standardSort (list : string[], pattern : number[], realtime : boo
}
newName = `./render_${zeroPad(frameCount)}${ext}`
newPath = join(TMPPATH, newName)
newPath = path.join(TMPPATH, newName)
log(`Renaming ${list[i]} -> ${newName}`)
try {
await move(oldPath, newPath)
await fs.move(oldPath, newPath)
newList.push(newName)
frameCount++
} catch (err) {
@ -416,7 +416,7 @@ async function standardSort (list : string[], pattern : number[], realtime : boo
**/
async function randomSort (list : string[], pattern : number[], realtime : boolean) {
let frameCount : number = 0
let ext : string = extname(list[0])
let ext : string = path.extname(list[0])
let oldPath : string
let newName : string
let newPath : string
@ -433,10 +433,10 @@ async function randomSort (list : string[], pattern : number[], realtime : boole
log(`Skipping extra frames...`)
for (let i : number = 0; i < remove.length; i++) {
oldPath = join(TMPPATH, remove[i])
oldPath = path.join(TMPPATH, remove[i])
log(`Skipping ${list[i]}`)
try {
await unlink(oldPath)
await fs.unlink(oldPath)
} catch (err) {
log('Error deleting frame', err)
}
@ -444,14 +444,14 @@ async function randomSort (list : string[], pattern : number[], realtime : boole
}
for (let i : number = 0; i < list.length; i++) {
oldPath = join(TMPPATH, list[i])
oldPath = path.join(TMPPATH, list[i])
newName = `./render_${zeroPad(frameCount)}${ext}`
newPath = join(TMPPATH, newName)
newPath = path.join(TMPPATH, newName)
log(`Renaming ${list[i]} -> ${newName}`)
try {
await move(oldPath, newPath)
await fs.move(oldPath, newPath)
newList.push(newName)
} catch (err) {
log('Error moving frame', err)
@ -474,7 +474,7 @@ async function spinFrames () {
console.log('Spinning frames...')
try {
frames = await readdir(TMPPATH)
frames = await fs.readdir(TMPPATH)
} catch (err) {
console.error('Error reading tmp directory', err)
}
@ -485,7 +485,7 @@ async function spinFrames () {
})
for (let frame of frames) {
framePath = join(TMPPATH, frame)
framePath = path.join(TMPPATH, frame)
rotate = ''
flip = ''
flop = ''
@ -521,7 +521,7 @@ async function spinFrames () {
**/
async function render (output : string, avconv : boolean) {
//process.exit()
let frames : string = join(TMPPATH, `render_%05d.tif`)
let frames : string = path.join(TMPPATH, `render_%05d.tif`)
let exe : string = avconv ? 'avconv' : 'ffmpeg'
let resolution : string = '1920x1080' //TODO: make variable/argument
//TODO: make object configurable with shorthand names
@ -547,8 +547,7 @@ async function render (output : string, avconv : boolean) {
*
* @param {object} arg Object containing all arguments
**/
async function main (program : any) {
const arg = program.opts();
async function main (arg : any) {
let input : string[] = arg.input.split(':')
let output : string = arg.output
let pattern : any[] = []
@ -557,7 +556,7 @@ async function main (program : any) {
let random : boolean = false
let e : any = false
let exe : string = arg.avconv ? 'avconv' : 'ffmpeg'
let fileExists : any
let exists : any
console.time('frameloom')
@ -603,13 +602,13 @@ async function main (program : any) {
}
try {
fileExists = await exec(`which ${exe}`)
exists = await exec(`which ${exe}`)
} catch (err) {
log(`Error checking for ${exe}`)
process.exit(11)
}
if (!fileExists || fileExists === '' || fileExists.indexOf(exe) === -1) {
if (!exists || exists === '' || exists.indexOf(exe) === -1) {
log(`${exe} is required and is not installed. Please install ${exe} to use frameloom.`)
process.exit(12)
}
@ -621,7 +620,7 @@ async function main (program : any) {
if (arg.realtime) realtime = true;
TMPPATH = join(TMPDIR, 'frameloom');
TMPPATH = path.join(TMPDIR, 'frameloom');
try {
await clear()
@ -684,7 +683,7 @@ async function main (program : any) {
}
program
.version(version)
.version(pkg.version)
.option('-i, --input [files]', 'Specify input videos with paths seperated by colon')
.option('-o, --output [file]', 'Specify output path of video')
.option('-p, --pattern [pattern]', 'Specify a pattern for the flicker 1:1 is standard')