Get version from package.json
This commit is contained in:
parent
b1370447bf
commit
cf39232d70
148
frameloom
148
frameloom
|
@ -8,6 +8,12 @@ const path = require('path')
|
||||||
const program = require('commander')
|
const program = require('commander')
|
||||||
const fs = require('fs-extra')
|
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 = os.tmpdir() || '/tmp'
|
let TMPDIR = os.tmpdir() || '/tmp'
|
||||||
let TMPPATH
|
let TMPPATH
|
||||||
|
|
||||||
|
@ -39,6 +45,19 @@ async function delay (ms) {
|
||||||
return setTimeout(resolve, ms)
|
return setTimeout(resolve, ms)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Log function wrapper that can silences logs when
|
||||||
|
* QUIET == true
|
||||||
|
*/
|
||||||
|
function log (msg, err) {
|
||||||
|
if (QUIET) return false
|
||||||
|
if (err) {
|
||||||
|
console.error(msg, err)
|
||||||
|
} else {
|
||||||
|
console.log(msg)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Pads a numerical value with preceding zeros to make strings same length.
|
* Pads a numerical value with preceding zeros to make strings same length.
|
||||||
*
|
*
|
||||||
|
@ -77,11 +96,11 @@ async function clear () {
|
||||||
try {
|
try {
|
||||||
exists = await fs.exists(TMPPATH)
|
exists = await fs.exists(TMPPATH)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error checking if file exists', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exists) {
|
if (exists) {
|
||||||
console.log(`Clearing temp directory "${TMPPATH}"`)
|
log(`Clearing temp directory "${TMPPATH}"`)
|
||||||
try {
|
try {
|
||||||
await exec(cmd)
|
await exec(cmd)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -94,7 +113,7 @@ async function clear () {
|
||||||
await fs.mkdir(TMPPATH)
|
await fs.mkdir(TMPPATH)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code !== 'EEXIST') {
|
if (err.code !== 'EEXIST') {
|
||||||
console.error(err)
|
log('Error making directory', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +129,7 @@ async function clear () {
|
||||||
*
|
*
|
||||||
* @returns {string} String with the export order, not sure why I did this
|
* @returns {string} String with the export order, not sure why I did this
|
||||||
**/
|
**/
|
||||||
async function frames (video, order, avconv) {
|
async function frames (video, order, avconv, e) {
|
||||||
let ext = 'tif'
|
let ext = 'tif'
|
||||||
let exe = avconv ? 'avconv' : 'ffmpeg'
|
let exe = avconv ? 'avconv' : 'ffmpeg'
|
||||||
let tmpoutput
|
let tmpoutput
|
||||||
|
@ -120,17 +139,53 @@ async function frames (video, order, avconv) {
|
||||||
|
|
||||||
cmd = `${exe} -i "${video}" -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"`
|
cmd = `${exe} -i "${video}" -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"`
|
||||||
|
|
||||||
console.log(`Exporting ${video} as single frames...`)
|
log(`Exporting ${video} as single frames...`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await exec(cmd)
|
await exec(cmd)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error exporting video', err)
|
log('Error exporting video', err)
|
||||||
return process.exit(3)
|
return process.exit(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.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
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
async function subExec (cmd) {
|
||||||
|
let frames
|
||||||
|
let frameCmd
|
||||||
|
let framePath
|
||||||
|
|
||||||
|
try {
|
||||||
|
frames = await fs.readdir(TMPPATH)
|
||||||
|
} catch (err) {
|
||||||
|
log('Error reading tmp directory', err)
|
||||||
|
}
|
||||||
|
|
||||||
|
frames = frames.filter (file =>{
|
||||||
|
if (file.indexOf('.tif') !== -1) return true
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let frame of frames) {
|
||||||
|
framePath = path.join(TMPPATH, frame)
|
||||||
|
if (cmd.indexOf('{{i}}') !== -1 || cmd.indexOf('{{o}}')) {
|
||||||
|
frameCmd = cmd.replace(INPUT_RE, framePath)
|
||||||
|
.replace(OUTPUT_RE, framePath)
|
||||||
|
} else {
|
||||||
|
frameCmd = `${cmd} ${framePath}`
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await exec(frameCmd)
|
||||||
|
} catch (err) {
|
||||||
|
log('Error executing sub command on frame', err)
|
||||||
|
return process.exit(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Re-arranges the frames into the order specified in the pattern.
|
* Re-arranges the frames into the order specified in the pattern.
|
||||||
* Calls `patternSort()` to perform the rename and unlink actions
|
* Calls `patternSort()` to perform the rename and unlink actions
|
||||||
|
@ -145,12 +200,12 @@ async function weave (pattern, realtime, random) {
|
||||||
let seq
|
let seq
|
||||||
let alt = false
|
let alt = false
|
||||||
|
|
||||||
console.log('Weaving frames...')
|
log('Weaving frames...')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
frames = await fs.readdir(TMPPATH)
|
frames = await fs.readdir(TMPPATH)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error reading tmp directory', err)
|
log('Error reading tmp directory', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.dir(frames)
|
//console.dir(frames)
|
||||||
|
@ -166,21 +221,21 @@ async function weave (pattern, realtime, random) {
|
||||||
try {
|
try {
|
||||||
seq = await randomSort(frames, realtime)
|
seq = await randomSort(frames, realtime)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error sorting frames')
|
log('Error sorting frames', err)
|
||||||
}
|
}
|
||||||
} else if (!alt) {
|
} else if (!alt) {
|
||||||
try {
|
try {
|
||||||
seq = await standardSort(frames, pattern, realtime)
|
seq = await standardSort(frames, pattern, realtime)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error sorting frames')
|
log('Error sorting frames', err)
|
||||||
}
|
}
|
||||||
} else if (alt) {
|
} else if (alt) {
|
||||||
console.warn('This feature is not ready, please check https://github.com/sixteenmillimeter/frameloom.git')
|
log('This feature is not ready, please check https://github.com/sixteenmillimeter/frameloom.git', {})
|
||||||
process.exit(10)
|
process.exit(10)
|
||||||
try {
|
try {
|
||||||
seq = await altSort(frames, pattern, realtime)
|
seq = await altSort(frames, pattern, realtime)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error sorting frames')
|
log('Error sorting frames', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//console.dir(seq)
|
//console.dir(seq)
|
||||||
|
@ -215,13 +270,13 @@ async function altSort (list, pattern, realtime) {
|
||||||
newName = `./render_${zeroPad(frameCount)}${ext}`;
|
newName = `./render_${zeroPad(frameCount)}${ext}`;
|
||||||
newPath = path.join(TMPPATH, newName);
|
newPath = path.join(TMPPATH, newName);
|
||||||
|
|
||||||
console.log(`Renaming ${list[i]} -> ${newName}`);
|
log(`Renaming ${list[i]} -> ${newName}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//await fs.move(oldPath, newPath, { overwrite: true })
|
//await fs.move(oldPath, newPath, { overwrite: true })
|
||||||
newList.push(newName);
|
newList.push(newName);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
log(err);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
frameCount++
|
frameCount++
|
||||||
|
@ -266,25 +321,25 @@ async function standardSort (list, pattern, realtime) {
|
||||||
oldPath = path.join(TMPPATH, list[i])
|
oldPath = path.join(TMPPATH, list[i])
|
||||||
|
|
||||||
if (skip) {
|
if (skip) {
|
||||||
console.log(`Skipping ${list[i]}`)
|
log(`Skipping ${list[i]}`)
|
||||||
try {
|
try {
|
||||||
await fs.unlink(oldPath)
|
await fs.unlink(oldPath)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error deleting frame', err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
newName = `./render_${zeroPad(frameCount)}${ext}`
|
newName = `./render_${zeroPad(frameCount)}${ext}`
|
||||||
newPath = path.join(TMPPATH, newName)
|
newPath = path.join(TMPPATH, newName)
|
||||||
console.log(`Renaming ${list[i]} -> ${newName}`)
|
log(`Renaming ${list[i]} -> ${newName}`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.move(oldPath, newPath)
|
await fs.move(oldPath, newPath)
|
||||||
newList.push(newName)
|
newList.push(newName)
|
||||||
frameCount++
|
frameCount++
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error renaming frame', err)
|
||||||
return process.exit(10)
|
return process.exit(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,14 +372,14 @@ async function randomSort (list, pattern, realtime) {
|
||||||
remove = list.slice(removeLen, list.length)
|
remove = list.slice(removeLen, list.length)
|
||||||
list = list.slice(0, removeLen)
|
list = list.slice(0, removeLen)
|
||||||
|
|
||||||
console.log(`Skipping extra frames...`)
|
log(`Skipping extra frames...`)
|
||||||
for (let i = 0; i < remove.length; i++) {
|
for (let i = 0; i < remove.length; i++) {
|
||||||
oldPath = path.join(TMPPATH, remove[i])
|
oldPath = path.join(TMPPATH, remove[i])
|
||||||
console.log(`Skipping ${list[i]}`)
|
log(`Skipping ${list[i]}`)
|
||||||
try {
|
try {
|
||||||
await fs.unlink(oldPath)
|
await fs.unlink(oldPath)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error deleting frame', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,13 +389,13 @@ async function randomSort (list, pattern, realtime) {
|
||||||
|
|
||||||
newName = `./render_${zeroPad(frameCount)}${ext}`
|
newName = `./render_${zeroPad(frameCount)}${ext}`
|
||||||
newPath = path.join(TMPPATH, newName)
|
newPath = path.join(TMPPATH, newName)
|
||||||
console.log(`Renaming ${list[i]} -> ${newName}`)
|
log(`Renaming ${list[i]} -> ${newName}`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.move(oldPath, newPath)
|
await fs.move(oldPath, newPath)
|
||||||
newList.push(newName)
|
newList.push(newName)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error moving frame', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
frameCount++
|
frameCount++
|
||||||
|
@ -364,19 +419,19 @@ async function render (output, avconv) {
|
||||||
let framerate = `24`
|
let framerate = `24`
|
||||||
const cmd = `${exe} -r ${framerate} -f image2 -s ${resolution} -i ${frames} ${format} -y ${output}`
|
const cmd = `${exe} -r ${framerate} -f image2 -s ${resolution} -i ${frames} ${format} -y ${output}`
|
||||||
|
|
||||||
console.log(`Exporting video ${output}`)
|
log(`Exporting video ${output}`)
|
||||||
console.log(cmd)
|
log(cmd)
|
||||||
|
|
||||||
/*try {
|
/*try {
|
||||||
await exec(`ls "${TMPPATH}"`)
|
await exec(`ls "${TMPPATH}"`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
log(err)
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await exec(cmd)
|
await exec(cmd)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error rendering video with ffmpeg', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -392,15 +447,16 @@ async function main (arg) {
|
||||||
let realtime = false
|
let realtime = false
|
||||||
let avconv = false
|
let avconv = false
|
||||||
let random = false
|
let random = false
|
||||||
|
let e = false
|
||||||
console.time('frameloom')
|
console.time('frameloom')
|
||||||
|
|
||||||
if (input.length < 2) {
|
if (input.length < 2) {
|
||||||
console.error('Must provide more than 1 input')
|
log('Must provide more than 1 input', {})
|
||||||
return process.exit(1)
|
return process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!output) {
|
if (!output) {
|
||||||
console.error('Must provide video output path')
|
log('Must provide video output path', {})
|
||||||
return process.exit(2)
|
return process.exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,6 +472,14 @@ async function main (arg) {
|
||||||
TMPDIR = arg.tmp
|
TMPDIR = arg.tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg.exec) {
|
||||||
|
e = arg.exec
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.quiet) {
|
||||||
|
QUIET = true
|
||||||
|
}
|
||||||
|
|
||||||
if (arg.pattern) {
|
if (arg.pattern) {
|
||||||
pattern = arg.pattern.split(':')
|
pattern = arg.pattern.split(':')
|
||||||
pattern = pattern.map(el =>{
|
pattern = pattern.map(el =>{
|
||||||
|
@ -434,39 +498,49 @@ async function main (arg) {
|
||||||
try {
|
try {
|
||||||
await clear()
|
await clear()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error clearing temp directory', err)
|
||||||
return process.exit(3)
|
return process.exit(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Processing video files ${input.join(', ')} into ${output} with pattern ${pattern.join(':')}`)
|
log(`Processing video files ${input.join(', ')} into ${output} with pattern ${pattern.join(':')}`)
|
||||||
|
|
||||||
for (let i = 0; i < input.length; i++) {
|
for (let i = 0; i < input.length; i++) {
|
||||||
try {
|
try {
|
||||||
await frames(input[i], i, avconv)
|
await frames(input[i], i, avconv)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error exporting video fie to image sequence', err)
|
||||||
return process.exit(4)
|
return process.exit(4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log('Weaving frames')
|
||||||
try {
|
try {
|
||||||
await weave(pattern, realtime, random)
|
await weave(pattern, realtime, random)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error weaving', err)
|
||||||
return process.exit(5)
|
return process.exit(5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
try {
|
||||||
|
await subExec(e)
|
||||||
|
} catch (err) {
|
||||||
|
log('Error performing subcommand', err)
|
||||||
|
return process.exit(7)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await render(output, avconv)
|
await render(output, avconv)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error rendering', err)
|
||||||
return process.exit(6)
|
return process.exit(6)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await clear()
|
await clear()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
log('Error clearing files', err)
|
||||||
return process.exit(7)
|
return process.exit(7)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +548,7 @@ async function main (arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('1.0.0')
|
.version(pkg.version)
|
||||||
.option('-i, --input [files]', 'Specify input videos with paths seperated by colon')
|
.option('-i, --input [files]', 'Specify input videos with paths seperated by colon')
|
||||||
.option('-o, --output [file]', 'Specify output path of video')
|
.option('-o, --output [file]', 'Specify output path of video')
|
||||||
.option('-p, --pattern [pattern]', 'Specify a pattern for the flicker 1:1 is standard')
|
.option('-p, --pattern [pattern]', 'Specify a pattern for the flicker 1:1 is standard')
|
||||||
|
@ -482,6 +556,8 @@ program
|
||||||
.option('-t, --tmp [dir]', 'Specify tmp directory for exporting frames')
|
.option('-t, --tmp [dir]', 'Specify tmp directory for exporting frames')
|
||||||
.option('-a, --avconv', 'Specify avconv if preferred to ffmpeg')
|
.option('-a, --avconv', 'Specify avconv if preferred to ffmpeg')
|
||||||
.option('-R, --random', 'Randomize frames. Ignores pattern if included')
|
.option('-R, --random', 'Randomize frames. Ignores pattern if included')
|
||||||
|
.option('-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')
|
||||||
|
.option('-q, --quiet', 'Suppresses all log messages')
|
||||||
.parse(process.argv)
|
.parse(process.argv)
|
||||||
|
|
||||||
main(program)
|
main(program)
|
Loading…
Reference in New Issue