Add kinda of a better user interface
This commit is contained in:
parent
ff75f7ce08
commit
3394e2b5f9
4 changed files with 65 additions and 23 deletions
|
@ -17,7 +17,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Discord Video Sharing</h1>
|
<h1>Discord Video Sharing</h1>
|
||||||
|
<p id="message"></p>
|
||||||
<script src="../dist/scripts/renderer.js"></script>
|
<script src="../dist/scripts/renderer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
33
src/main.ts
33
src/main.ts
|
@ -1,17 +1,14 @@
|
||||||
import { BrowserWindow, app, dialog, ipcMain } from "electron";
|
import { BrowserWindow, app, dialog, ipcMain } from "electron";
|
||||||
import { statSync, unlink } from "fs";
|
import { statSync, unlink } from "fs";
|
||||||
import { getNewFilename, getVideoDuration } from "./utils/misc";
|
import { execute, getNewFilename, getVideoDuration } from "./utils/misc";
|
||||||
import path = require("path");
|
import path = require("path");
|
||||||
import ffmpegPath = require("ffmpeg-static");
|
import ffmpegPath = require("ffmpeg-static");
|
||||||
import child_process = require("child_process");
|
|
||||||
|
|
||||||
const moviesFilter = {
|
const moviesFilter = {
|
||||||
name: "Videos",
|
name: "Videos",
|
||||||
extensions: ["mp4", "mkv"],
|
extensions: ["mp4", "mkv"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const isWindows = process.platform === "win32";
|
|
||||||
|
|
||||||
/** Create a new window */
|
/** Create a new window */
|
||||||
const createWindow = () => {
|
const createWindow = () => {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
|
@ -29,22 +26,22 @@ const createWindow = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Merge all audios track of a video into one */
|
/** Merge all audios track of a video into one */
|
||||||
const mergeAudio = (file: string) => {
|
const mergeAudio = async (file: string) => {
|
||||||
const tmp_file = getNewFilename(file, "TMP_");
|
const tmpFile = getNewFilename(file, "TMP_");
|
||||||
const outFile = getNewFilename(file, "(merged audio) ");
|
const outFile = getNewFilename(file, "(merged audio) ");
|
||||||
|
|
||||||
// Merge 2 audio
|
// Merge 2 audio
|
||||||
child_process.execSync(
|
await execute(
|
||||||
`${ffmpegPath} -y -i "${file}" -filter_complex "[0:a]amerge=inputs=2[a]" -ac 1 -map 0:v -map "[a]" -c:v copy "${tmp_file}"`
|
`${ffmpegPath} -y -i "${file}" -filter_complex "[0:a]amerge=inputs=2[a]" -ac 1 -map 0:v -map "[a]" -c:v copy "${tmpFile}"`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add merged audio as first position to original video
|
// Add merged audio as first position to original video
|
||||||
child_process.execSync(
|
await execute(
|
||||||
`${ffmpegPath} -y -i "${tmp_file}" -i "${file}" -map 0 -map 1:a -c:v copy "${outFile}"`
|
`${ffmpegPath} -y -i "${tmpFile}" -i "${file}" -map 0 -map 1:a -c:v copy "${outFile}"`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Delete the temporary file
|
// Delete the temporary file
|
||||||
unlink(tmp_file, (err) => {
|
unlink(tmpFile, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
@ -57,16 +54,16 @@ const mergeAudio = (file: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Reduce size of a file */
|
/* Reduce size of a file */
|
||||||
const reduceSize = (file: string, bitrate: number) => {
|
const reduceSize = async (file: string, bitrate: number) => {
|
||||||
const audioBitrate = 400; /* keep some room */
|
const audioBitrate = 400; // keep some room
|
||||||
const videoBitrate = Math.floor(bitrate) - audioBitrate;
|
const videoBitrate = bitrate - audioBitrate;
|
||||||
|
|
||||||
/* Trash the output, depends on the platform */
|
|
||||||
const nul = isWindows ? "NUL" : "/dev/null";
|
|
||||||
|
|
||||||
const finalFile = getNewFilename(file, "Compressed - ");
|
const finalFile = getNewFilename(file, "Compressed - ");
|
||||||
|
|
||||||
child_process.execSync(
|
// Trash the output, depends on the platform
|
||||||
|
const nul = process.platform === "win32" ? "NUL" : "/dev/null";
|
||||||
|
|
||||||
|
await execute(
|
||||||
`${ffmpegPath} -y -i "${file}" -c:v libx264 -b:v ${videoBitrate}k -pass 1 -an -f mp4 ${nul} && \
|
`${ffmpegPath} -y -i "${file}" -c:v libx264 -b:v ${videoBitrate}k -pass 1 -an -f mp4 ${nul} && \
|
||||||
${ffmpegPath} -y -i "${file}" -c:v libx264 -b:v ${videoBitrate}k -pass 2 -c:a copy -map 0:0 -map 0:1 -map 0:2 -map 0:3 -f mp4 "${finalFile}"`
|
${ffmpegPath} -y -i "${file}" -c:v libx264 -b:v ${videoBitrate}k -pass 2 -c:a copy -map 0:0 -map 0:1 -map 0:2 -map 0:3 -f mp4 "${finalFile}"`
|
||||||
);
|
);
|
||||||
|
|
|
@ -31,21 +31,53 @@ const getFile = async () => {
|
||||||
return file.join("");
|
return file.join("");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Mode {
|
||||||
|
Write,
|
||||||
|
Append,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update the message to the user */
|
||||||
|
const updateMessage = (message: string, mode: Mode = Mode.Write) => {
|
||||||
|
switch (mode) {
|
||||||
|
case Mode.Write:
|
||||||
|
document.getElementById("message").innerText = message;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mode.Append:
|
||||||
|
document.getElementById("message").innerText += message;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** Main function */
|
/** Main function */
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
const maxSizeDiscord = 25;
|
const maxSizeDiscord = 25;
|
||||||
|
updateMessage("Récupération du fichier...");
|
||||||
const file = await getFile();
|
const file = await getFile();
|
||||||
|
updateMessage("Mélange des pistes audios vers la piste 1...");
|
||||||
const newFile = await internals.mergeAudio(file);
|
const newFile = await internals.mergeAudio(file);
|
||||||
let finalTitle = newFile.title;
|
let finalTitle = newFile.title;
|
||||||
|
updateMessage(`Taille calculée : ${Math.round(newFile.size)}Mo`);
|
||||||
if (newFile.size > maxSizeDiscord) {
|
if (newFile.size > maxSizeDiscord) {
|
||||||
/* TODO: Since this task can take time, add a progress bar to the user */
|
|
||||||
const targetSize = maxSizeDiscord - 2;
|
const targetSize = maxSizeDiscord - 2;
|
||||||
|
|
||||||
|
// https://trac.ffmpeg.org/wiki/Encode/H.264#twopass
|
||||||
|
const bitrate = Math.floor((targetSize * 8388.608) / newFile.duration);
|
||||||
|
|
||||||
|
updateMessage(
|
||||||
|
`\nFichier trop lourd, compression en cours... (bitrate total = ${bitrate})`,
|
||||||
|
Mode.Append
|
||||||
|
);
|
||||||
finalTitle = await internals.reduceSize(
|
finalTitle = await internals.reduceSize(
|
||||||
newFile.title,
|
newFile.title,
|
||||||
// https://trac.ffmpeg.org/wiki/Encode/H.264#twopass
|
|
||||||
(targetSize * 8388.608) / newFile.duration
|
bitrate
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
updateMessage("Fichier prêt ! :)");
|
||||||
await internals.confirmation(`File ok @ ${finalTitle}!`);
|
await internals.confirmation(`File ok @ ${finalTitle}!`);
|
||||||
await internals.exit();
|
await internals.exit();
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import ffprobe = require("ffprobe-static");
|
||||||
import child_process = require("child_process");
|
import child_process = require("child_process");
|
||||||
import path = require("path");
|
import path = require("path");
|
||||||
|
|
||||||
/* Create a new filename from the OG one */
|
/** Create a new filename from the OG one */
|
||||||
export const getNewFilename = (ogFile: string, part: string) => {
|
export const getNewFilename = (ogFile: string, part: string) => {
|
||||||
const oldFile = path.parse(ogFile);
|
const oldFile = path.parse(ogFile);
|
||||||
return path.join(oldFile.dir, `${part}`.concat(oldFile.base));
|
return path.join(oldFile.dir, `${part}`.concat(oldFile.base));
|
||||||
|
@ -14,3 +14,16 @@ export const getVideoDuration = (file: string) => {
|
||||||
const durationString = child_process.execSync(command).toString().trim();
|
const durationString = child_process.execSync(command).toString().trim();
|
||||||
return parseFloat(durationString);
|
return parseFloat(durationString);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Run a command asynchronously */
|
||||||
|
export const execute = (command: string) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
child_process.exec(command, (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
resolve({ stdout, stderr });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue