diff --git a/.gitignore b/.gitignore index 585b92c..0575760 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ node_modules *.webm *.exe *.zip -.gitignore +*.webp +*.ogg settings.json -*test* \ No newline at end of file +/testing ground/ +/bin/index regular terminal.js \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..fb8b0b5 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ + +loglevel=silent \ No newline at end of file diff --git a/README.md b/README.md index b5b1ea9..6cd5892 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,15 @@ Easy to use: Just drag a file on the executable and off it goes! ![explorer_e0Y0mYI4fH](https://user-images.githubusercontent.com/25299243/166175734-8e0a8783-3bac-4617-8762-db0ddfaa761a.gif) +How to install(Windows with binaries): +1. make a folder in `C:\Program Files` called "DMC", put release binaries and [ffmpeg windows full-build executables](https://github.com/GyanD/codexffmpeg/releases/) into `C:\Program Files\DMC\` +2. Add ffmpeg to PATH: `[Win BTN] + R`, type `SystemPropertiesAdvanced`, click `Environment Variables`, under "User variables for (user)" find variable Path, click on it and edit, in the now open window click `new`, and paste `C:\Program Files\DMC\`. +3. If the command `ffmpeg` in cmd works, you can now drag and drop files onto the binary and have it work! +4. to set performance preset, doubleclick the binary + +How to install(Windows, Linux, MacOS): +1. get node.js from [here](https://nodejs.org) +2. clone repo into any folder you like. +3. run `npm install --save` to get all dependencies +4. run `npm install -g {PATH_TO_PROJECT_FOLDER}` *might have bugs, currently videos only and windows only. Future plans will include audio: .ogg, and photos: .webm* diff --git a/bin/index.js b/bin/index.js new file mode 100644 index 0000000..db36378 --- /dev/null +++ b/bin/index.js @@ -0,0 +1,121 @@ +import fs from 'fs' +import { Encoder } from "../lib/encoder.js" +import { UI } from "../lib/ui.js" +import termkit from "terminal-kit" +import { SettingsManager } from "../lib/settingsManager.js" +import path from "path" +//get settings +let settings = new SettingsManager() +await settings.start() +let resolve = path.resolve +let term = termkit.terminal +const ui = new UI(settings.settings, settings.currentSetting) + + +/** + * TODO : Adapt audio quality as well to accomodate long videos(Currently 5m is too much) + * FIND A WAY TO COMPILE THIS:.. + */ + +const inputList = process.argv.slice(2) +//if launched without params +if (!inputList[0]) { + ui.startMenu() //stops program here +} + +//Parse file inputs (n Drag n drop or arguments) +let filePaths = [], fileNames = [], fileTypes = [] +let presetIndexArg = undefined +//if preset argument go through list from 2 and add argument +if (inputList[0] == "-preset") { + presetIndexArg = inputList[1] + + for (let i = 2; i < inputList.length; i++) { + let file + file = resolve(inputList[i]) + + filePaths.push(file) + + file = file.split("\\") + file = file[file.length - 1] + file = file.split(".") + + fileTypes.push(file[1]) + fileNames.push(file[0]) + } +} +else { + for (let i = 0; i < inputList.length; i++) { + let file + file = resolve(inputList[i]) + + filePaths.push(file) + + file = file.split("\\") + file = file[file.length - 1] + file = file.split(".") + + fileTypes.push(file[1]) + fileNames.push(file[0]) + } +} +main() + +async function main() { + + //file checks + let isListEncodable = true + //check if all files exist + for (let i = 0; i < filePaths.length; i++) { + if (!fs.existsSync(filePaths[i])) { + term.italic(`${filePaths[i]}`).bold.red(" <- Path or File doesn't exist\n") + term.grey("press enter to exit...") + isListEncodable = false + term.inputField(function () { process.exit() }) + } + } + + //check if all files are valid formats + if (isListEncodable) { + for (let i = 0; i < filePaths.length; i++) { + if (fileTypes[i] == "jpg" || fileTypes[i] == "JPG" || fileTypes[i] == "png" || fileTypes[i] == "PNG" || fileTypes[i] == "webp" || + fileTypes[i] == "webm" || fileTypes[i] == "mp4" || fileTypes[i] == "mov" || fileTypes[i] == "mkv" || fileTypes[i] == "avi" || + fileTypes[i] == "ogg" || fileTypes[i] == "mp3" || fileTypes[i] == "aiff" || fileTypes[i] == "wav" || fileTypes[i] == "flac") { + } + else { + term.italic(`${fileTypes[i]}`).bold.red(` <- Unsupported format\n`) + term.grey("press enter to exit...") + isListEncodable = false + term.inputField(function () { process.exit() }) + } + } + + } + //start encoding all + if (isListEncodable) { + + let encoder = [] + for (let i = 0; i < filePaths.length; i++) { + encoder.push(new Encoder(settings.settings, settings.currentSetting, presetIndexArg)) + console.log(`Encoding with "${settings.currentSetting.name}" preset...`) + + if (fileTypes[i] == "jpg" || fileTypes[i] == "JPG" || fileTypes[i] == "png" || fileTypes[i] == "PNG" || fileTypes[i] == "webp") { + ui.newBar(await encoder[i].encodePicture(filePaths[i], fileNames[i])) + ui.updateBar("time=00:00:01", i, false, true) + encoder[i].on("close", () => { ui.encodeFinished(i) }) + } + else if (fileTypes[i] == "webm" || fileTypes[i] == "mp4" || fileTypes[i] == "mov" || fileTypes[i] == "mkv" || fileTypes[i] == "avi") { + ui.newBar(await encoder[i].encodeVideo(filePaths[i], fileNames[i])) + encoder[i].on("update", (chunk) => { ui.updateBar(chunk, i) }) + encoder[i].on("close", () => { ui.encodeFinished(i) }) + } + else if (fileTypes[i] == "ogg" || fileTypes[i] == "mp3" || fileTypes[i] == "aiff" || fileTypes[i] == "wav" || fileTypes[i] == "flac") { + ui.newBar(await encoder[i].encodeAudio(filePaths[i], fileNames[i])) + encoder[i].on("update", (chunk) => { ui.updateBar(chunk, i, false) }) + encoder[i].on("close", () => { ui.encodeFinished(i) }) + } + } + } + + +} \ No newline at end of file diff --git a/fieldTest.cjs b/fieldTest.cjs new file mode 100644 index 0000000..d63d511 --- /dev/null +++ b/fieldTest.cjs @@ -0,0 +1,26 @@ +const child_process = require("child_process") +const FileHound = require('filehound') + +let exec = child_process.exec + +let command = "npm run start" +let testFiles = FileHound.create() + .path("testing ground") + .findSync() + +testFiles.forEach((value, index) => { + console.log(value, index) + command += ` "${value}"` +}) +console.log(command) +let test = exec(command) +test.stdout.on("data", (chunk) => { + console.log(chunk) +}) +test.stderr.on("data", (chunk) => { + console.log(chunk) +}) + +test.on("close", () => { + console.log("finished") +}) \ No newline at end of file diff --git a/index.js b/index.js deleted file mode 100644 index 48e50ee..0000000 --- a/index.js +++ /dev/null @@ -1,423 +0,0 @@ -const fs = require('fs') -const { exec, execSync } = require('child_process') -const cliProgress = require('cli-progress') -const term = require("terminal-kit").terminal - -/** - * TODO : Adapt audio quality as well to accomodate long videos(Currently 5m is too much) - * FIND A WAY TO COMPILE THIS:.. - */ - -//Parse file inputs (Drag n drop or arguments) -inputList = process.argv.slice(2) -input = inputList[0] -let file, fileType, bar1 -//if launched without params -if (!input) { - startMenu() -} -else { - file = input.split("\\") - file = file[file.length - 1] - - fileType = file.split(".")[1] - - if (!fs.existsSync(input)) { - term.italic(`${input}`).bold.red(" <- Path or File doesn't exist\n") - term.grey("press enter to exit...") - term.inputField(function () { process.exit() }) - } - else { - bar1 = new cliProgress.SingleBar({ - synchronousUpdate: true, - align: "left", - hideCursor: true - }, cliProgress.Presets.shades_classic) - - if (fileType == "jpg" || fileType == "JPG" || fileType == "png" || fileType == "PNG" || fileType == "webp") { - encodePicture(input, file.split(".")[0]) - } - else if (fileType == "webm" || fileType == "mp4" || fileType == "mov" || fileType == "mkv" || fileType == "avi") { - encodeVideo(input, file.split(".")[0]) - } - else if ("ogg" || "mp3" || "aiff" || "wav" || "flac") { - encodeAudio(input, file.split(".")[0]) - } - else { - term.italic(`${file}`).bold.red(` <- Unsupported format\n`) - term.grey("press enter to exit...") - term.inputField(function () { process.exit() }) - } - } -} - -async function encodeVideo(path, out) { - //create progress bar - - const [command, presetName, duration, isTwoPass] = await constructVideoCommand(path, out) - bar1.start(duration, 0, { speed: "N/A" }) - let isPastHalf = false - let encoder = exec(command) - 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() - //If 2nd pass add that portion in - console.log(`Encoding ${out}.webm with "${presetName}" preset...`) - if (isTwoPass) { - 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) - } - else { - bar1.update(Math.round(seconds * 100) / 100) - } - } - }) - - encoder.on("close", () => { - console.clear() - bar1.stop() - fs.rm("ffmpeg2pass-0.log", (error) => { error }) - term.bold.green("Finished!\n") - term.grey("press enter to exit...\n") - term.inputField(() => { process.exit() }) - }) -} -async function encodeAudio(path, out) { - let [duration, resolution] = await getDurationAndResolution(path) - const bitrateLimit = Math.round(62000 / duration) - - bar1.start(duration, 0, { speed: "N/A" }) - - const encoder = exec(`ffmpeg -y -i "${path}" -c:a libvorbis -b:a ${bitrateLimit}k ${out}.ogg`) - - encoder.stderr.on("data", (chunk) => { - currentTime = chunk.split("time=")[1]?.split(" ")[0] - if (currentTime) { - const arr = currentTime.split(":") - let seconds = Number.parseFloat(arr[0] * 3600 + arr[1] * 60 + (+arr[2])) // converting to s - console.clear() - console.log(`Encoding ${out}.ogg`) - bar1.update(Math.round(seconds * 100) / 100) - } - }) - encoder.on("close", () => { - console.clear() - term.bold.green("Finished!\n") - term.grey("press enter to exit...\n") - term.inputField(() => { process.exit() }) - }) -} - -async function encodePicture(path, out) { - const encoder = exec(`ffmpeg -y -i "${path}" -qscale 80 -compression_level 6 ${out}.webp`) - encoder.stderr.on("data", (chunk) => { - console.clear() - term.yellow(`Encoding ${out}.webp...`) - - }) - encoder.on("close", () => { - console.clear() - term.bold.green("Finished!\n") - term.grey("press enter to exit...\n") - term.inputField(() => { process.exit() }) - }) -} - -async function constructVideoCommand(path, out) { - - //gets settings file, if doesnt exist makes a new file and uses those defaults - let settings = await getSettings().catch(async (err) => { - settings = undefined - }) - if (!settings) settings = await makeNewSettingsFile() - settings = JSON.parse(settings.toString()) - settings = settings.presets[settings.currentSetting] - - let [duration, resolutionHeight] = await getDurationAndResolution(path) - //Calculates video bitrate to fit right under 8mb @224kb vorbis audio bitrate - const bitrateLimit = Math.round((62000 - (224 * duration)) / duration) - - let command = "" - let crfIndex = 0 - let isTwoPass = true - while (resolutionHeight > settings.crfMap[crfIndex].resolution) { - crfIndex++ - //if the resolution is still higher, just use highest res - if (!settings.crfMap[crfIndex]?.resolution) { - crfIndex-- - break - } - } - - for (pass = 1; pass <= 2; pass++) { - command += `ffmpeg -y -i "${path}" -vcodec libvpx-vp9 -acodec libvorbis -qscale:a 7 ` - command += `-deadline ${settings.deadline} ` - command += `-cpu-used ${settings.cpuUsed} ` - if (settings?.minrate) { - command += `-b:v ${Math.round(bitrateLimit * 0.95)}k ` - command += `-minrate ${Math.round(bitrateLimit / 100 * settings.minrate)}k ` - command += `-maxrate ${bitrateLimit}k ` - } - else { - command += `-b:v ${bitrateLimit}k ` - command += `-crf ${settings.crfMap[crfIndex].crf} ` - } - //realtime doesnt support two pass - if (settings.deadline == "realtime") { - command += `-row-mt 1 "${out}.webm"` - isTwoPass = false - break - } - pass == 1 ? command += `-pass 1 -row-mt 1 -f webm NUL && ` : command += `-pass 2 -row-mt 1 "${out}.webm" ` - } - return [command, settings.name, duration, isTwoPass] -} - -async function getDurationAndResolution(file) { - let query = await ffprobe(file) - //duration in seconds - duration = query.split("Duration: ")[1].split(",")[0] - const arr = duration.split(":") // splitting the string by colon - const seconds = arr[0] * 3600 + arr[1] * 60 + (+arr[2]) // converting to s - - //resolution height - resolutionHeight = query.split("Stream #0:0")[1]?.split(",")[2].split(" ")[1].split("x")[1] - - return [Number.parseFloat(seconds), resolutionHeight] -} - -function ffprobe(file) { - return new Promise((resolve, reject) => { - exec(`ffprobe "${file}"`, (error, stdout, stderr) => { - resolve(stderr) - }) - }) -} - -function getSettings() { - return new Promise((resolve, reject) => { - getSettings = fs.readFile("settings.json", (err, data) => { - resolve(data) - reject(err) - }) - }) -} - -async function startMenu() { - console.clear() - //gets settings file, if doesnt exist makes a new file and uses those defaults - let settings = await getSettings().catch(async (err) => { - settings = undefined - }) - if (!settings) settings = await makeNewSettingsFile() - - settings = JSON.parse(settings.toString()) - let menu = [] - for (i = 0; i < settings.presets.length; i++) { - menu.push(`${i}. ${settings.presets[i].name}`) - } - term.italic("How to convert: [app] [filename.extension]\n") - term.yellow("Hello! This menu is for selecting performance/speed preset.\n") - term.yellow("Currently using ").bgMagenta(`"${settings.presets[settings.currentSetting].name}"`).yellow(" preset") - term.singleColumnMenu(menu, (error, response) => { - settings.currentSetting = response.selectedIndex - fs.writeFileSync("settings.json", JSON.stringify(settings)) - term.green("\n Using").green.bold(` ${settings.presets[settings.currentSetting].name} `).green("setting\n") - term.grey("Press enter to exit...") - term.inputField(() => { process.exit() }) - }) -} - -function makeNewSettingsFile() { - const settings = ` - { - "currentSetting": 2, - "presets": [{ - "name": "Most efficient 8 megabytes of your life", - "cpuUsed": 0, - "deadline": "best", - "minrate": 90, - "crfMap": [{ - "resolution": 240, - "crf": 1 - }, - { - "resolution": 360, - "crf": 1 - }, - { - "resolution": 480, - "crf": 1 - }, - { - "resolution": 720, - "crf": 1 - }, - { - "resolution": 1080, - "crf": 1 - }, - { - "resolution": 1440, - "crf": 1 - }, - { - "resolution": 2160, - "crf": 1 - } - ] - }, - { - "name": "I have some time to kill", - "cpuUsed": 1, - "deadline": "good", - "minrate": 75, - "crfMap": [{ - "resolution": 240, - "crf": 20 - }, - { - "resolution": 360, - "crf": 20 - }, - { - "resolution": 480, - "crf": 20 - }, - { - "resolution": 720, - "crf": 20 - }, - { - "resolution": 1080, - "crf": 17 - }, - { - "resolution": 1440, - "crf": 15 - }, - { - "resolution": 2160, - "crf": 10 - } - ] - }, - { - "name": "Mid", - "cpuUsed": 3, - "deadline": "good", - "minrate":75, - "crfMap": [{ - "resolution": 240, - "crf": 30 - }, - { - "resolution": 360, - "crf": 30 - }, - { - "resolution": 480, - "crf": 30 - }, - { - "resolution": 720, - "crf": 25 - }, - { - "resolution": 1080, - "crf": 20 - }, - { - "resolution": 1440, - "crf": 15 - }, - { - "resolution": 2160, - "crf": 10 - } - ] - }, - { - "name": "I don't like waiting", - "cpuUsed": 4, - "deadline": 100, - "minrate": 90, - "crfMap": [{ - "resolution": 240, - "crf": 45 - }, - { - "resolution": 360, - "crf": 42 - }, - { - "resolution": 480, - "crf": 40 - }, - { - "resolution": 720, - "crf": 35 - }, - { - "resolution": 1080, - "crf": 30 - }, - { - "resolution": 1440, - "crf": 25 - }, - { - "resolution": 2160, - "crf": 20 - } - ] - }, - { - "name": "I want it, NOW!", - "cpuUsed": 4, - "deadline": "realtime", - "minrate": 50, - "crfMap": [{ - "resolution": 240, - "crf": 40 - }, - { - "resolution": 360, - "crf": 35 - }, - { - "resolution": 480, - "crf": 30 - }, - { - "resolution": 720, - "crf": 25 - }, - { - "resolution": 1080, - "crf": 20 - }, - { - "resolution": 1440, - "crf": 15 - }, - { - "resolution": 2160, - "crf": 10 - } - ] - } - - ] -} - ` - return new Promise((resolve, reject) => { - fs.writeFile("settings.json", settings, () => { - resolve(settings) - }) - }) -} \ No newline at end of file diff --git a/lib/encoder.js b/lib/encoder.js new file mode 100644 index 0000000..5ac0407 --- /dev/null +++ b/lib/encoder.js @@ -0,0 +1,138 @@ +import { exec } from 'child_process' + +export class Encoder { + currentSetting + settings + encoder + encodePresetIndexArg + constructor(settings, currentSetting, encodePresetIndexArg = undefined) { + this.settings = settings + this.currentSetting = currentSetting + this.encodePresetIndexArg = encodePresetIndexArg + } + + /** + * + * @param {String} path absolute path to file + * @param {String} out output filename + * @returns [duration, isTwoPass] + */ + async encodeVideo(path, out) { + //create progress bar + const [command, duration, isTwoPass] = await this.#constructVideoCommand(path, out) + this.encoder = exec(command) + return [duration, out, isTwoPass] + } + + /** + * + * @param {String} path absolute path to file + * @param {String} out output filename + * @returns duration + */ + async encodeAudio(path, out) { + let [duration, resolution] = await this.#getDurationAndResolution(path) + const videoBitRate = Math.round(62000 / duration) + this.encoder = exec(`ffmpeg -y -i "${path}" -c:a libvorbis -b:a ${videoBitRate}k ${out}.ogg`) + return [duration, out, undefined] + } + + /** + * + * @param {String} path absolute path to file + * @param {String} out output filename + */ + async encodePicture(path, out) { + this.encoder = exec(`ffmpeg -y -i "${path}" -qscale 80 -compression_level 6 ${out}.webp`) + return [1, out, undefined] + } + + async #constructVideoCommand(path, out) { + let [duration, resolutionHeight] = await this.#getDurationAndResolution(path) + + //Calculates video bitrate to fit right under 8mb 2:6 audio:video + const audioBitRate = Math.round(62000 / 8 * 2 / duration) + const videoBitRate = Math.round(62000 / 8 * 6 / duration) + + //if command had argument of anotehr quality setting change to use that setting + if (this.encodePresetIndexArg) { + this.currentSetting = this.settings.presets[this.encodePresetIndexArg] + } + + let command = "" + let crfIndex = 0 + let isTwoPass = true + //Compares current video height to CRFMAP to determine optimal CRF + while (resolutionHeight > this.currentSetting.crfMap[crfIndex].resolution) { + crfIndex++ + //if the resolution is still higher, just use highest res + if (!this.currentSetting.crfMap[crfIndex]?.resolution) { + crfIndex-- + break + } + } + + for (let pass = 1; pass <= 2; pass++) { + command += `ffmpeg -y -i "${path}" -vcodec libvpx-vp9 -acodec libvorbis ` + command += `-deadline ${this.currentSetting.deadline} ` + command += `-cpu-used ${this.currentSetting.cpuUsed} ` + if (this.currentSetting?.minrate) { + command += `-b:v ${Math.round(videoBitRate * 0.95)}k ` + command += `-minrate ${Math.round(videoBitRate / 100 * this.currentSetting.minrate)}k ` + command += `-maxrate ${videoBitRate}k ` + } + else { + command += `-b:v ${videoBitRate}k ` + command += `-b:a ${audioBitRate}k ` + command += `-crf ${this.currentSetting.crfMap[crfIndex].crf} ` + } + //realtime doesnt support two pass + if (this.currentSetting.deadline == "realtime") { + command += `-row-mt 1 "${out}.webm"` + isTwoPass = false + break + } + pass == 1 ? command += `-pass 1 -row-mt 1 -f webm NUL && ` : command += `-pass 2 -row-mt 1 "${out}.webm" ` + } + return [command, duration, isTwoPass] + } + + async #getDurationAndResolution(file) { + let query = await this.#ffprobe(file) + //duration in seconds + const duration = query.split("Duration: ")[1].split(",")[0] + const arr = duration.split(":") // splitting the string by colon + const seconds = arr[0] * 3600 + arr[1] * 60 + (+arr[2]) // converting to s + + //resolution height + const resolutionHeight = query.split("Stream #0:0")[1]?.split(",")[2].split(" ")[1].split("x")[1] + + return [Number.parseFloat(seconds), resolutionHeight] + } + + #ffprobe(file) { + return new Promise((resolve, reject) => { + exec(`ffprobe "${file}"`, (error, stdout, stderr) => { + resolve(stderr) + }) + }) + } + + on(channel, callback) { + switch (channel) { + case "close": + this.encoder.on("close", () => { + callback(true) + }) + break + case "update": + this.encoder.stderr.on("data", (chunk) => { + callback(chunk) + }) + break + default: + throw new Error("Incorrect Channel") + } + + } +} \ No newline at end of file diff --git a/lib/settingsManager.js b/lib/settingsManager.js new file mode 100644 index 0000000..42a3480 --- /dev/null +++ b/lib/settingsManager.js @@ -0,0 +1,221 @@ +import fs from "fs" + +export class SettingsManager { + + settings + currentSetting + + constructor() { + } + + async start() { + await this.#init() + } + + async #init() { + this.settings = await this.#getSettings().catch(async (err) => { + this.settings = undefined + }) + if (!this.settings) this.settings = await this.#makeNewSettingsFile() + this.settings = JSON.parse(this.settings.toString()) + this.currentSetting = this.settings.presets[this.settings.currentSetting] + } + async #getSettings() { + return new Promise((resolve, reject) => { + getSettings = fs.readFile("settings.json", (err, data) => { + resolve(data) + reject(err) + }) + }) + } + + async #makeNewSettingsFile() { + const settings = ` + { + "currentSetting": 2, + "presets": [{ + "name": "Most efficient 8 megabytes of your life", + "cpuUsed": 0, + "deadline": "best", + "minrate": 90, + "crfMap": [{ + "resolution": 240, + "crf": 1 + }, + { + "resolution": 360, + "crf": 1 + }, + { + "resolution": 480, + "crf": 1 + }, + { + "resolution": 720, + "crf": 1 + }, + { + "resolution": 1080, + "crf": 1 + }, + { + "resolution": 1440, + "crf": 1 + }, + { + "resolution": 2160, + "crf": 1 + } + ] + }, + { + "name": "I have some time to kill", + "cpuUsed": 1, + "deadline": "good", + "minrate": 75, + "crfMap": [{ + "resolution": 240, + "crf": 20 + }, + { + "resolution": 360, + "crf": 20 + }, + { + "resolution": 480, + "crf": 20 + }, + { + "resolution": 720, + "crf": 20 + }, + { + "resolution": 1080, + "crf": 17 + }, + { + "resolution": 1440, + "crf": 15 + }, + { + "resolution": 2160, + "crf": 10 + } + ] + }, + { + "name": "Mid", + "cpuUsed": 3, + "deadline": "good", + "minrate":75, + "crfMap": [{ + "resolution": 240, + "crf": 30 + }, + { + "resolution": 360, + "crf": 30 + }, + { + "resolution": 480, + "crf": 30 + }, + { + "resolution": 720, + "crf": 25 + }, + { + "resolution": 1080, + "crf": 20 + }, + { + "resolution": 1440, + "crf": 15 + }, + { + "resolution": 2160, + "crf": 10 + } + ] + }, + { + "name": "I don't like waiting", + "cpuUsed": 4, + "deadline": 100, + "minrate": 90, + "crfMap": [{ + "resolution": 240, + "crf": 45 + }, + { + "resolution": 360, + "crf": 42 + }, + { + "resolution": 480, + "crf": 40 + }, + { + "resolution": 720, + "crf": 35 + }, + { + "resolution": 1080, + "crf": 30 + }, + { + "resolution": 1440, + "crf": 25 + }, + { + "resolution": 2160, + "crf": 20 + } + ] + }, + { + "name": "I want it, NOW!", + "cpuUsed": 4, + "deadline": "realtime", + "minrate": 50, + "crfMap": [{ + "resolution": 240, + "crf": 40 + }, + { + "resolution": 360, + "crf": 35 + }, + { + "resolution": 480, + "crf": 30 + }, + { + "resolution": 720, + "crf": 25 + }, + { + "resolution": 1080, + "crf": 20 + }, + { + "resolution": 1440, + "crf": 15 + }, + { + "resolution": 2160, + "crf": 10 + } + ] + } + + ] +} + ` + return new Promise((resolve, reject) => { + fs.writeFile("settings.json", settings, () => { + resolve(settings) + }) + }) + } +} \ No newline at end of file diff --git a/lib/ui.js b/lib/ui.js new file mode 100644 index 0000000..c22d360 --- /dev/null +++ b/lib/ui.js @@ -0,0 +1,121 @@ +import termkit from "terminal-kit" +import cliProgress from "cli-progress" +import fs from "fs" + +export class UI { + term + bars = [] + multibar + settings + currentSetting + + constructor(settings, currentSetting) { + this.term = termkit.terminal + + this.multibar = new cliProgress.MultiBar({ + format: '[{bar}] {percentage}% | output: "{filename}" | ETA: {eta}s | {value}/{total}', + align: "left", + hideCursor: true, + autopadding: true, + }, cliProgress.Presets.shades_grey) + + this.settings = settings + this.currentSetting = currentSetting + + } + /** + * + * @param {Number} duration Duration of the encoded media + * @param {String} filename name of the encoding file + * @param {Boolean} isTwoPass is the encoded media two pass + * @returns + */ + async newBar(encoderOutput) { + let duration = encoderOutput[0] + let filename = encoderOutput[1] + let isTwoPass = encoderOutput[2] + this.bars.push({ + "bar": this.multibar.create(duration, 0, { speed: "N/A" }), + "isTwoPass": isTwoPass, + "isPastHalf": false, + "filename": filename, + "duration": duration, + "finished": false + } + ) + const barIndex = this.bars.length - 1 + return barIndex + } + + async updateBar(chunk, barIndex = 0, isVideo = true, isImage = false) { + if (!chunk) return + if (isImage) { + this.bars[barIndex]?.bar.update(1, { filename: `${this.bars[barIndex].filename}.webp` }) + return + } + if (isVideo) { + const currentTime = chunk.split("time=")[1]?.split(" ")[0] + if (!currentTime) return + const arr = currentTime.split(":") + let seconds = Number.parseFloat(arr[0] * 3600 + arr[1] * 60 + (+arr[2])) // converting to s + + //If 2 pass divide bar into two parts to show both in progress in one progress + if (this.bars[barIndex].isTwoPass) { + if (seconds / 2 >= (this.bars[barIndex].duration - 0.2) / 2) this.bars[barIndex].isPastHalf = true + + if (this.bars[barIndex].isPastHalf) this.bars[barIndex].bar.update(Math.round(seconds * 50) / 100 + (this.bars[barIndex].duration / 2), { filename: `${this.bars[barIndex].filename}.webm` }) + else this.bars[barIndex].bar.update(Math.round(seconds * 50) / 100, { filename: `${this.bars[barIndex].filename}.webm` }) + } + else { + this.bars[barIndex].bar.update(Math.round(seconds * 100) / 100, { filename: `${this.bars[barIndex].filename}.webm` }) + } + } + else { + const currentTime = chunk.split("time=")[1]?.split(" ")[0] + if (!currentTime) return + const arr = currentTime.split(":") + let seconds = Number.parseFloat(arr[0] * 3600 + arr[1] * 60 + (+arr[2])) // converting to s + this.bars[barIndex].bar.update(Math.round(seconds * 100) / 100, { filename: `${this.bars[barIndex].filename}.ogg` }) + } + } + + encodeFinished(barIndex) { + this.bars[barIndex].fininshed = true + // if all are finished stop multibars and exit + for (let i = 0; i < this.bars.length; i++) { + if (this.bars[i].finished) return + } + this.multibar.stop() + fs.rm("ffmpeg2pass-0.log", (error) => { error }) + console.clear() + this.term.bold.green("Finished!\n") + this.term.grey("press enter to exit...\n") + this.term.inputField(() => { process.exit() }) + } + + async startMenu() { + await this.#menu() + } + async #menu() { + console.clear() + let menu = [] + for (let i = 0; i < settings.presets.length; i++) { + menu.push(`${i}. ${settings.presets[i].name}`) + } + this.term("How to convert: [app] [optional: -preset {Index}] [filename.extension(s)]\n") + this.term("examples: \n") + this.term.italic(" npx DMC -preset 0 file.mp3 file4.mov img.jpg\n") + this.term.italic(" DMC.exe -preset 2 file34.wav file2.mp3\n\n") + this.term.yellow("Hello! This menu is for selecting performance/speed preset.\n") + this.term.yellow("Currently using ").bgMagenta(`"${settings.presets[settings.currentSetting].name}"`).yellow(" preset") + this.term.singleColumnMenu(menu, (error, response) => { + currentSetting = response.selectedIndex + fs.writeFileSync("settings.json", JSON.stringify(settings)) + this.term.green("\n Using").green.bold(` ${settings.presets[settings.currentSetting].name} `).green("setting\n") + this.term.grey("Press enter to exit...") + this.term.inputField(() => { process.exit() }) + }) + } + + +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 391a8bf..6b5bb37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,22 @@ { "name": "discord-media-compressor-8mb", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "discord-media-compressor-8mb", - "version": "1.0.0", + "version": "1.0.1", "license": "ISC", "dependencies": { "cli-progress": "^3.11.0", + "filehound": "^1.17.6", "pkg": "^5.6.0", "require-runtime": "^2.0.0", "terminal-kit": "^2.4.0" }, "bin": { - "discord-media-compressor-8mb": "index.js" + "DMC": "bin/index.js" } }, "node_modules/@babel/helper-validator-identifier": { @@ -157,6 +158,11 @@ "node": ">= 4.0.0" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -199,6 +205,19 @@ "node": ">= 6" } }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -383,6 +402,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -481,6 +505,11 @@ "once": "^1.4.0" } }, + "node_modules/err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -546,6 +575,11 @@ "node": ">=6" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -574,6 +608,49 @@ "reusify": "^1.0.4" } }, + "node_modules/file-js": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/file-js/-/file-js-0.3.0.tgz", + "integrity": "sha1-+rRr94I0bJKUSZ8fDSrQfYOPJdE=", + "dependencies": { + "bluebird": "^3.4.7", + "minimatch": "^3.0.3", + "proper-lockfile": "^1.2.0" + } + }, + "node_modules/file-js/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/file-js/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/filehound": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/filehound/-/filehound-1.17.6.tgz", + "integrity": "sha512-5q4zjFkI8W2zLmvbvyvI//K882IpEj6sMNXPUQlk5H6W4Wh3OSSylEAIEmMLELP9G7ileYjTKPXOn0YzzS55Lg==", + "dependencies": { + "bluebird": "^3.7.2", + "file-js": "0.3.0", + "lodash": "^4.17.21", + "minimatch": "^5.0.0", + "moment": "^2.29.1", + "unit-compare": "^1.0.1" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -869,6 +946,11 @@ "node": ">= 0.8.0" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -911,6 +993,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", @@ -921,6 +1014,14 @@ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, + "node_modules/moment": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz", + "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1230,6 +1331,17 @@ "node": ">=0.4.0" } }, + "node_modules/proper-lockfile": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-1.2.0.tgz", + "integrity": "sha1-zv9d2J0+XxD7deHo52vHWAGlnDQ=", + "dependencies": { + "err-code": "^1.0.0", + "extend": "^3.0.0", + "graceful-fs": "^4.1.2", + "retry": "^0.10.0" + } + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1315,6 +1427,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "engines": { + "node": "*" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -1633,6 +1753,14 @@ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" }, + "node_modules/unit-compare": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unit-compare/-/unit-compare-1.0.1.tgz", + "integrity": "sha1-DHRZ8OW/U2N+qHPKPO4Y3i7so4Y=", + "dependencies": { + "moment": "^2.14.1" + } + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -1917,6 +2045,11 @@ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -1944,6 +2077,19 @@ } } }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -2076,6 +2222,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -2151,6 +2302,11 @@ "once": "^1.4.0" } }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2188,6 +2344,11 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -2213,6 +2374,48 @@ "reusify": "^1.0.4" } }, + "file-js": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/file-js/-/file-js-0.3.0.tgz", + "integrity": "sha1-+rRr94I0bJKUSZ8fDSrQfYOPJdE=", + "requires": { + "bluebird": "^3.4.7", + "minimatch": "^3.0.3", + "proper-lockfile": "^1.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "filehound": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/filehound/-/filehound-1.17.6.tgz", + "integrity": "sha512-5q4zjFkI8W2zLmvbvyvI//K882IpEj6sMNXPUQlk5H6W4Wh3OSSylEAIEmMLELP9G7ileYjTKPXOn0YzzS55Lg==", + "requires": { + "bluebird": "^3.7.2", + "file-js": "0.3.0", + "lodash": "^4.17.21", + "minimatch": "^5.0.0", + "moment": "^2.29.1", + "unit-compare": "^1.0.1" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2435,6 +2638,11 @@ "type-check": "~0.3.2" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2462,6 +2670,14 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "requires": { + "brace-expansion": "^2.0.1" + } + }, "minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", @@ -2472,6 +2688,11 @@ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, + "moment": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz", + "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -2698,6 +2919,17 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, + "proper-lockfile": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-1.2.0.tgz", + "integrity": "sha1-zv9d2J0+XxD7deHo52vHWAGlnDQ=", + "requires": { + "err-code": "^1.0.0", + "extend": "^3.0.0", + "graceful-fs": "^4.1.2", + "retry": "^0.10.0" + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -2757,6 +2989,11 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -2988,6 +3225,14 @@ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" }, + "unit-compare": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unit-compare/-/unit-compare-1.0.1.tgz", + "integrity": "sha1-DHRZ8OW/U2N+qHPKPO4Y3i7so4Y=", + "requires": { + "moment": "^2.14.1" + } + }, "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", diff --git a/package.json b/package.json index d71b125..55018ce 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,14 @@ "version": "1.0.1", "description": "helps free discord users to send any media(image, video, audio) and not get limited by discords 8mb file limit", "main": "index.js", - "bin": "./index.js", + "bin": { + "DMC": "./bin/index.js" + }, + "type": "module", "scripts": { - "start": "node index.js", - "build": "pkg -t --compress GZip package.json" + "start": "node bin/index.js", + "build": "pkg .", + "test": "node fieldTest.cjs" }, "keywords": [ "discord", @@ -18,6 +22,7 @@ "license": "ISC", "dependencies": { "cli-progress": "^3.11.0", + "filehound": "^1.17.6", "pkg": "^5.6.0", "require-runtime": "^2.0.0", "terminal-kit": "^2.4.0"