-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from tahsinature/node-implementation
Node implementation
- Loading branch information
Showing
13 changed files
with
318 additions
and
148 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import path from "path"; | ||
import fs from "fs"; | ||
|
||
export class File { | ||
dir: string; | ||
originalFullPath: string; | ||
fileNameWithoutExtension: string; | ||
cmd = null as string | null; | ||
outputFullPath = null as string | null; | ||
|
||
constructor(fullPath: string) { | ||
this.originalFullPath = fullPath; | ||
this.dir = path.dirname(fullPath); | ||
this.fileNameWithoutExtension = path.basename(fullPath, path.extname(fullPath)); | ||
} | ||
|
||
async deleteOriginal() { | ||
return fs.promises.unlink(this.originalFullPath); | ||
} | ||
|
||
async deleteOutput() { | ||
if (this.outputFullPath) fs.promises.unlink(this.outputFullPath); | ||
else console.error(`Output file not found for ${this.originalFullPath}`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { runShellCommandAndReturnLine } from "./utils"; | ||
|
||
const checkIfBinaryExists = async (binary: string) => { | ||
const lines: string[] = []; | ||
await runShellCommandAndReturnLine(`which ${binary}`, (l) => l && lines.push(l)); | ||
return lines.length > 0; | ||
}; | ||
|
||
const requiredBinaries = [ | ||
{ | ||
name: "HandBrakeCLI", | ||
purpose: "HandBrake Command Line Version to encode videos.", | ||
howTo: `Download HandBrake Command Line Version from: https://handbrake.fr/downloads.php`, | ||
}, | ||
{ | ||
name: "fzf", | ||
purpose: "Fuzzy Finder to select multiple files.", | ||
howTo: `Install fzf from: https://github.com/junegunn/fzf#installation`, | ||
}, | ||
{ | ||
name: "fd", | ||
purpose: "To find and filter files.", | ||
howTo: `Install fd from: https://github.com/sharkdp/fd#installation`, | ||
}, | ||
]; | ||
|
||
export const checkRequiredBinaries = async () => { | ||
const missing = []; | ||
|
||
for (const binary of requiredBinaries) { | ||
const isFound = await checkIfBinaryExists(binary.name); | ||
if (!isFound) missing.push(binary); | ||
} | ||
|
||
if (missing.length) { | ||
console.error(`The following binaries are required to run this program: | ||
----------`); | ||
for (const binary of missing) { | ||
console.error(`- ${binary.name}: ${binary.purpose}`); | ||
console.error(binary.howTo); | ||
} | ||
process.exit(1); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,39 @@ | ||
import { execSync, spawn } from "child_process"; | ||
import blessed from "blessed"; | ||
import contrib, { Widgets } from "blessed-contrib"; | ||
import path from "path"; | ||
import type { File } from "./blueprints"; | ||
import { ProgressBar } from "./progress"; | ||
import { runShellCommandAndReturnLine } from "./utils"; | ||
|
||
const ping = (server: string, log: Widgets.LogElement) => { | ||
const command = `ping ${server}`; | ||
// console.log current ping | ||
// on each ping, update the console.log. no new lines | ||
const getProgressAndRemainingTime = (line: string) => { | ||
const progressMatch = line.match(/Encoding: task 1 of 1, (\d+\.\d+) %/); | ||
const progress = progressMatch ? parseFloat(progressMatch[1]) : null; | ||
|
||
var out = spawn(command, { stdio: ["inherit", "pipe", "inherit"], shell: true, argv0: "node" }); | ||
const remainingTimeMatch = line.match(/ETA (\d+h\d+m\d+s)/); | ||
const remainingTime = remainingTimeMatch ? remainingTimeMatch[1] : null; | ||
|
||
out.stdout.setEncoding("utf-8"); | ||
out.stdout.on("readable", () => { | ||
const data = out.stdout.read(); | ||
log.log(data); | ||
}); | ||
return { progress, remainingTime }; | ||
}; | ||
|
||
export const main = async () => { | ||
const screen = blessed.screen(); | ||
export const main = async (files: File[], preset: string) => { | ||
for (const file of files) { | ||
const outputFileName = `${file.fileNameWithoutExtension}__HandBraked__${preset}.mp4`; | ||
file.outputFullPath = path.resolve(file.dir, outputFileName); | ||
file.cmd = `HandBrakeCLI -i '${file.originalFullPath}' -o '${file.outputFullPath}' -Z '${preset}'`; | ||
} | ||
|
||
screen.key(["escape", "q", "C-c"], function (ch, key) { | ||
screen.destroy(); | ||
// screen.removeAllListeners(); | ||
// return process.exit(0); | ||
}); | ||
const grid = new contrib.grid({ rows: 2, cols: 1, screen }); | ||
const progressBar = new ProgressBar(files.length); | ||
|
||
const log1 = grid.set(0, 0, 1, 1, contrib.log, { fg: "green", selectedFg: "green", label: "Google Log", height: 2 }); | ||
const log2 = grid.set(1, 0, 1, 1, contrib.log, { fg: "green", selectedFg: "green", label: "Yahoo Log", height: "100%" }); | ||
for (const file of files) { | ||
if (!file.cmd) throw new Error(`Command not found for file: ${file.originalFullPath}`); | ||
|
||
ping("google.com", log1); | ||
ping("yahoo.com", log2); | ||
|
||
// const runShellCommand = async (cmd: string): Promise<string> => { | ||
// return new Promise((resolve, reject) => { | ||
// var out = spawn(cmd, { | ||
// stdio: ["inherit", "pipe", "inherit"], | ||
// shell: true, | ||
// argv0: "node", | ||
// }); | ||
|
||
// out.stdout.setEncoding("utf-8"); | ||
// out.stdout.on("readable", () => resolve(out.stdout.read())); | ||
// }); | ||
// }; | ||
|
||
// const askFiles = async () => { | ||
// const files = await runShellCommand("fzf --multi"); | ||
// const filtered = files.split("\n").filter(Boolean); | ||
// return filtered.map((file) => path.resolve(file)); | ||
// }; | ||
|
||
// const printHandBrakeCLIVersion = async () => { | ||
// const o = execSync("HandBrakeCLI --version", { stdio: ["inherit", "pipe"] }); | ||
// const out = o.toString().split("\n").filter(Boolean); | ||
|
||
// console.log(out[0]); | ||
// }; | ||
|
||
// printHandBrakeCLIVersion(); | ||
|
||
// const files = await askFiles(); | ||
|
||
// for (const file of files) { | ||
// console.log(file); | ||
// // const cmd = `hardbrake -i ${file} -o ${file}.mp4`; | ||
// // console.log(cmd); | ||
// // await runShellCommand(cmd); | ||
// } | ||
|
||
// function clearLine() { | ||
// readline.cursorTo(process.stdout, 0, 0); | ||
// readline.clearLine(process.stdout, 0); | ||
// } | ||
|
||
// var log = contrib.log({ fg: "green", selectedFg: "green", label: "Server Log" }); | ||
|
||
// log.log("Starting server..."); | ||
|
||
const displayCurrentTask = async () => { | ||
const command = `ping facebook.com.com`; | ||
// console.log current ping | ||
// on each ping, update the console.log. no new lines | ||
|
||
var out = spawn(command, { stdio: ["inherit", "pipe", "inherit"], shell: true, argv0: "node" }); | ||
|
||
out.stdout.setEncoding("utf-8"); | ||
out.stdout.on("readable", () => { | ||
const data = out.stdout.read(); | ||
log1.log(data); | ||
// clearLine(); | ||
// process.stdout.write(data); | ||
await runShellCommandAndReturnLine(file.cmd, (line) => { | ||
const { progress, remainingTime } = getProgressAndRemainingTime(line); | ||
if (progress && remainingTime) { | ||
progressBar.handleNewLine(progress, remainingTime, file.fileNameWithoutExtension); | ||
} | ||
}); | ||
}; | ||
|
||
displayCurrentTask(); | ||
progressBar.handleOneFileDone(); | ||
} | ||
|
||
screen.append(log1); | ||
screen.append(log2); | ||
screen.render(); | ||
progressBar.stop(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,28 @@ | ||
import path from "path"; | ||
import { askFiles, askPreset, askToggle } from "./prompts"; | ||
import { main } from "./engine"; | ||
import { checkRequiredBinaries } from "./check"; | ||
|
||
await main(); | ||
await checkRequiredBinaries(); | ||
|
||
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); | ||
const files = await askFiles(); | ||
if (files.length === 0) { | ||
console.log("No files selected. Exiting."); | ||
process.exit(0); | ||
} | ||
|
||
await wait(1000); | ||
console.log("hehe"); | ||
const preset = await askPreset(); | ||
|
||
await main(files, preset); | ||
|
||
const happyWithResults = await askToggle("Are you happy with the results?"); | ||
if (!happyWithResults) { | ||
for (const file of files) await file.deleteOutput(); | ||
console.log("Deleted all the output files."); | ||
process.exit(0); | ||
} | ||
|
||
const deleteOriginalFiles = await askToggle("Do you want to delete the original files?"); | ||
if (deleteOriginalFiles) { | ||
for (const file of files) await file.deleteOriginal(); | ||
console.log("Deleted all the original files."); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import cliProgress from "cli-progress"; | ||
|
||
export class ProgressBar { | ||
multibar = new cliProgress.MultiBar( | ||
{ | ||
clearOnComplete: false, | ||
hideCursor: true, | ||
format: "{context} {bar} | {percent} | ETA: {eta}s | ETA HB: {etaHB} | {filename}", | ||
}, | ||
cliProgress.Presets.shades_grey | ||
); | ||
|
||
b1 = this.multibar.create(100, 0, { | ||
context: "Current", | ||
}); | ||
|
||
b2 = this.multibar.create(0, 0, { | ||
context: " Total", | ||
percent: "-", | ||
etaHB: "-", | ||
filename: "-", | ||
}); | ||
|
||
constructor(totalFiles: number) { | ||
this.b2.setTotal(totalFiles); | ||
} | ||
|
||
handleNewLine(percent: number, eta: string, filename: string) { | ||
this.b1.update(percent, { | ||
filename, | ||
percent: `${percent}%`, | ||
etaHB: eta, | ||
}); | ||
} | ||
|
||
handleOneFileDone() { | ||
this.b1.update(100, { | ||
percent: "100%", | ||
etaHB: "0s", | ||
}); | ||
this.b2.increment(); | ||
} | ||
|
||
stop() { | ||
this.multibar.stop(); | ||
this.b1.stop(); | ||
this.b2.stop(); | ||
} | ||
} | ||
|
||
// const files = ["file1.mp4", "file2.mp4", "file3.mp4", "file4.mp4", "file5.mp4"]; | ||
|
||
// const progress = new ProgressBar(files.length); | ||
// for (const file of files) { | ||
// for (let i = 0; i <= 97; i++) { | ||
// progress.handleNewLine(i, "10s", file); | ||
// await sleep(10); | ||
// } | ||
|
||
// progress.handleOneFileDone(); | ||
// } | ||
|
||
// await sleep(1000); | ||
// progress.stop(); |
Oops, something went wrong.