2023-07-30 02:40:05 +02:00
|
|
|
import { BrowserWindow, app, dialog, ipcMain } from "electron";
|
2023-08-01 09:34:41 +02:00
|
|
|
import { statSync, unlink } from "fs";
|
2023-08-01 09:59:37 +02:00
|
|
|
import {
|
|
|
|
execute,
|
|
|
|
getNewFilename,
|
|
|
|
getVideoDuration,
|
|
|
|
printAndDevTool,
|
|
|
|
} from "./utils/misc";
|
2023-07-29 14:29:14 +02:00
|
|
|
import path = require("path");
|
2023-07-29 19:23:18 +02:00
|
|
|
import ffmpegPath = require("ffmpeg-static");
|
2023-07-30 13:44:47 +02:00
|
|
|
|
|
|
|
const moviesFilter = {
|
|
|
|
name: "Videos",
|
|
|
|
extensions: ["mp4", "mkv"],
|
|
|
|
};
|
|
|
|
|
2023-07-30 00:14:20 +02:00
|
|
|
/** Create a new window */
|
2023-07-28 02:32:18 +02:00
|
|
|
const createWindow = () => {
|
|
|
|
const win = new BrowserWindow({
|
2023-08-01 11:07:29 +02:00
|
|
|
width: 600,
|
|
|
|
height: 340,
|
2023-08-01 10:18:08 +02:00
|
|
|
icon: "./image/icon.ico",
|
2023-08-01 11:07:29 +02:00
|
|
|
autoHideMenuBar: true,
|
2023-07-29 14:29:14 +02:00
|
|
|
webPreferences: {
|
|
|
|
preload: path.join(__dirname, "preload.js"),
|
|
|
|
},
|
2023-07-28 02:32:18 +02:00
|
|
|
});
|
|
|
|
|
2023-07-29 15:30:41 +02:00
|
|
|
win.loadFile(path.join(path.resolve(__dirname, ".."), "pages", "index.html"));
|
2023-07-30 02:01:16 +02:00
|
|
|
|
|
|
|
return win;
|
2023-07-28 02:32:18 +02:00
|
|
|
};
|
2023-07-29 15:30:41 +02:00
|
|
|
|
2023-07-30 02:40:05 +02:00
|
|
|
/* Ready to create the window */
|
2023-07-28 02:32:18 +02:00
|
|
|
app.whenReady().then(() => {
|
2023-07-30 02:01:16 +02:00
|
|
|
const win = createWindow();
|
|
|
|
|
|
|
|
/** Ask user a file */
|
2023-08-01 11:10:35 +02:00
|
|
|
const askFile = () => {
|
2023-07-30 02:01:16 +02:00
|
|
|
return dialog.showOpenDialogSync(win, {
|
|
|
|
filters: [moviesFilter],
|
|
|
|
properties: ["openFile", "dontAddToRecent"],
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Send confirmation to user */
|
|
|
|
const confirmation = async (message: string) => {
|
2023-08-01 11:10:35 +02:00
|
|
|
await dialog.showMessageBox(win, { message });
|
2023-07-30 02:01:16 +02:00
|
|
|
};
|
|
|
|
|
2023-08-01 09:59:37 +02:00
|
|
|
/** Merge all audios track of a video into one */
|
|
|
|
const mergeAudio = async (file: string) => {
|
|
|
|
const tmpFile = getNewFilename(file, "TMP_");
|
|
|
|
const outFile = getNewFilename(file, "(merged audio) ");
|
|
|
|
|
|
|
|
// Merge 2 audio
|
|
|
|
await execute(
|
2023-08-01 15:21:34 +02:00
|
|
|
`"${ffmpegPath}" -y -i "${file}" -filter_complex "[0:a]amerge=inputs=2[a]" -ac 1 -map 0:v -map "[a]" -c:v copy "${tmpFile}"`
|
2023-08-01 09:59:37 +02:00
|
|
|
).catch((e) => printAndDevTool(win, e));
|
|
|
|
|
|
|
|
// Add merged audio as first position to original video
|
|
|
|
await execute(
|
2023-08-01 15:21:34 +02:00
|
|
|
`"${ffmpegPath}" -y -i "${tmpFile}" -i "${file}" -map 0 -map 1:a -c:v copy "${outFile}"`
|
2023-08-01 09:59:37 +02:00
|
|
|
).catch((e) => printAndDevTool(win, e));
|
|
|
|
|
|
|
|
// Delete the temporary file
|
|
|
|
unlink(tmpFile, (err) => {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-08-01 15:14:04 +02:00
|
|
|
const duration = await getVideoDuration(outFile);
|
2023-08-01 09:59:37 +02:00
|
|
|
const stats = statSync(outFile);
|
|
|
|
|
|
|
|
return { title: outFile, size: stats.size / 1024 / 1024, duration };
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Reduce size of a file */
|
|
|
|
const reduceSize = async (file: string, bitrate: number) => {
|
|
|
|
const audioBitrate = 400; // keep some room
|
|
|
|
const videoBitrate = bitrate - audioBitrate;
|
|
|
|
|
|
|
|
const finalFile = getNewFilename(file, "Compressed - ");
|
|
|
|
|
|
|
|
// Trash the output, depends on the platform
|
|
|
|
const nul = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
|
|
|
|
|
|
await execute(
|
2023-08-01 15:21:34 +02:00
|
|
|
`"${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}"`
|
2023-08-01 09:59:37 +02:00
|
|
|
).catch((e) => printAndDevTool(win, e));
|
|
|
|
|
|
|
|
// Delete the old file
|
|
|
|
unlink(file, (err) => {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return finalFile;
|
|
|
|
};
|
|
|
|
|
2023-07-30 00:14:20 +02:00
|
|
|
/* Context bridge */
|
2023-07-29 20:20:55 +02:00
|
|
|
ipcMain.handle("argv", () => process.argv);
|
2023-07-30 00:14:20 +02:00
|
|
|
ipcMain.handle("allowedExtensions", () => moviesFilter);
|
2023-07-30 01:40:06 +02:00
|
|
|
ipcMain.handle("askFile", () => askFile());
|
|
|
|
ipcMain.handle("mergeAudio", (_, file: string) => mergeAudio(file));
|
2023-07-30 13:44:47 +02:00
|
|
|
ipcMain.handle("reduceSize", (_, file: string, bitrate: number) =>
|
|
|
|
reduceSize(file, bitrate)
|
|
|
|
);
|
2023-08-01 11:10:35 +02:00
|
|
|
ipcMain.handle("exit", () => app.quit());
|
|
|
|
ipcMain.handle("confirmation", (_, text: string) => confirmation(text));
|
2023-07-28 02:32:18 +02:00
|
|
|
});
|