97 lines
3.4 KiB
JavaScript
97 lines
3.4 KiB
JavaScript
|
const fs = require('fs')
|
||
|
const { exec, execSync } = require('child_process')
|
||
|
const readline = require("readline")
|
||
|
const { stdout, stderr } = require('process')
|
||
|
const cliProgress = require('cli-progress')
|
||
|
const { finished } = require('stream')
|
||
|
|
||
|
//Create terminal readlines
|
||
|
|
||
|
const rl = readline.createInterface({
|
||
|
input: process.stdin,
|
||
|
output: process.stdout
|
||
|
})
|
||
|
|
||
|
//Parse file inputs (Drag n drop or arguments)
|
||
|
inputList = process.argv.slice(2)
|
||
|
input = inputList[0]
|
||
|
|
||
|
file = input.split("\\")
|
||
|
file = file[file.length - 1]
|
||
|
|
||
|
fileType = file.split(".")[1]
|
||
|
|
||
|
if (fileType == "jpg" || fileType == "JPG" || fileType == "png" || fileType == "PNG" || fileType == "webp") {
|
||
|
//encodePicture(input)
|
||
|
}
|
||
|
else if (fileType == "webm" || fileType == "mp4" || fileType == "mov" || fileType == "mkv" || fileType == "avi") {
|
||
|
encodeVideo(input, file.split(".")[0])
|
||
|
}
|
||
|
else {
|
||
|
console.log("Unsupported format")
|
||
|
rl.question("press enter to exit...", () => { process.exit() })
|
||
|
process.exit()
|
||
|
}
|
||
|
|
||
|
//create progress bar
|
||
|
const bar1 = new cliProgress.SingleBar({
|
||
|
synchronousUpdate: true,
|
||
|
align: "left",
|
||
|
hideCursor: true
|
||
|
}, cliProgress.Presets.shades_classic)
|
||
|
|
||
|
|
||
|
async function getDuration(file) {
|
||
|
let result = await ffprobe(file)
|
||
|
result = result.split("Duration: ")[1].split(",")[0]
|
||
|
const arr = result.split(":") // splitting the string by colon
|
||
|
const seconds = arr[0] * 3600 + arr[1] * 60 + (+arr[2]) // converting to s
|
||
|
return Number.parseFloat(seconds)
|
||
|
}
|
||
|
|
||
|
function ffprobe(file) {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
exec(`ffprobe "${file}"`, (error, stdout, stderr) => {
|
||
|
resolve(stderr)
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
|
||
|
async function encodeVideo(path, out) {
|
||
|
//Calculates video bitrate to fit right under 8mb @224kb vorbis audio bitrate
|
||
|
duration = await getDuration(input)
|
||
|
bitrateLimit = Math.round(7776 / duration)
|
||
|
console.log(`compressing ${path} to ${out}.webm at ${bitrateLimit}K's`)
|
||
|
const encoder = exec(`ffmpeg.exe -y -i "${path}" -vcodec libvpx-vp9 -acodec libvorbis -qscale:a 7 -cpu-used 3 -crf 20 -b:v ${bitrateLimit}k -pass 1 -f webm NUL && ffmpeg.exe -y -i "${path}" -vcodec libvpx-vp9 -acodec libvorbis -qscale:a 7 -cpu-used 3 -crf 20 -b:v ${bitrateLimit}k -pass 2 "${out}.webm"`)
|
||
|
bar1.start(duration, 0, { speed: "N/A" })
|
||
|
|
||
|
let isPastHalf = false
|
||
|
encoder.stderr.on("data", (chunk) => {
|
||
|
currentTime = chunk.split("time=")[1]?.split(" ")[0]
|
||
|
if (currentTime) {
|
||
|
const arr = currentTime.split(":") // splitting the string by colon
|
||
|
let seconds = Number.parseFloat(arr[0] * 3600 + arr[1] * 60 + (+arr[2])) // converting to s
|
||
|
|
||
|
console.clear()
|
||
|
console.log(`Encoding ${out}.webm...`)
|
||
|
//If 2nd pass add that portion in
|
||
|
if (seconds / 2 >= (duration - 0.2) / 2) isPastHalf = true
|
||
|
isPastHalf ? bar1.update(Math.round(seconds * 50) / 100 + (duration / 2)) : bar1.update(Math.round(seconds * 50) / 100)
|
||
|
}
|
||
|
})
|
||
|
encoder.on("close", () => {
|
||
|
console.clear()
|
||
|
bar1.stop()
|
||
|
fs.rm("ffmpeg2pass-0.log", (error) => { error })
|
||
|
console.log("Finished!")
|
||
|
rl.question("press enter to exit...", () => { process.exit() })
|
||
|
})
|
||
|
encoder.on("exit", () => {
|
||
|
console.clear()
|
||
|
bar1.stop()
|
||
|
fs.rm("ffmpeg2pass-0.log", (error) => { error })
|
||
|
console.log("Finished!")
|
||
|
rl.question("press enter to exit...", () => { process.exit() })
|
||
|
})
|
||
|
}
|