Skip to content
This repository has been archived by the owner on Feb 16, 2025. It is now read-only.

Commit

Permalink
More options, more info and better GUI
Browse files Browse the repository at this point in the history
  • Loading branch information
cheezos committed Dec 22, 2021
1 parent 2b2e673 commit 7eb02f1
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 44 deletions.
84 changes: 60 additions & 24 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,93 @@
<link rel="stylesheet" href="https://bootswatch.com/5/darkly/bootstrap.min.css" />
<title>Big Slime Video Compressor</title>
</head>

<body style="overflow: hidden">
<!-- Drop Zone -->
<div
id="drop-zone"
style="
display: flex;
flex-flow: column;
align-items: center;
justify-content: center;
text-align: center;
border-radius: 10px;
margin: 10px 10px 10px 10px;
height: 200px;
border: 3px dotted rgb(50, 50, 50);
background: rgb(20, 20, 20);
margin: 10px;
height: 150px;
border: 3px dotted rgb(126, 126, 126);
background: rgb(25, 25, 25);
"
>
<h5><small id="lbl-status" class="text-muted">Drop your videos here.</small></h5>
<h5 id="lbl-status" class="text-muted">Drop your videos here.</h5>
<small id="lbl-status-small" class="text-muted"></small>
</div>

<!-- Progress -->
<div style="margin: 10px 10px 20px 10px" class="progress">
<div style="margin: 10px" class="progress">
<div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 100%"></div>
</div>

<!-- Main Buttons -->
<div style="display: flex; align-items: center; justify-content: center; text-align: center; margin: 10px 10px 10px 10px">
<div style="display: flex; margin: 5px">
<div style="display: flex; flex-flow: row; justify-content: center; margin: 10px; border-radius: 10px; background: rgb(25, 25, 25)">
<div style="display: flex; justify-content: center; margin: 10px">
<button type="button" class="btn btn-primary" id="btn-compress" disabled>Compress</button>
</div>
<div style="display: flex; margin: 5px">
<div style="display: flex; justify-content: center; margin: 10px">
<button type="button" class="btn btn-danger" id="btn-abort" disabled>Abort</button>
</div>
</div>
<!-- Remove Audio -->
<div style="margin: 10px auto 10px auto">
<div style="display: table; margin-left: auto; margin-right: auto" class="form-check form-switch">
<input id="check-remove-audio" class="form-check-input" type="checkbox" />
<label class="form-check-label" for="flexSwitchCheckDefault">Remove Audio</label>

<!-- Options -->
<div style="display: flex; flex-flow: column; justify-content: center; margin: 10px; border-radius: 10px; background: rgb(25, 25, 25)">
<!-- Remove Audio -->
<div style="display: flex; flex-flow: row; justify-content: center; margin: 5px" class="form-check form-switch">
<div style="margin: 3px">
<input id="check-remove-audio" class="form-check-input" type="checkbox" />
</div>
<div style="margin: 3px">
<label class="form-check-label" for="flexSwitchCheckDefault">Remove Audio</label>
</div>
</div>

<!-- h.265 -->
<div style="display: flex; flex-flow: row; justify-content: center; margin: 5px" class="form-check form-switch">
<div style="margin: 3px">
<input id="check-h265" class="form-check-input" type="checkbox" />
</div>
<div style="margin: 3px">
<label class="form-check-label" for="flexSwitchCheckDefault">H.265</label>
</div>
</div>

<!-- Minimum Bitrate -->
<div style="display: flex; flex-flow: row; justify-content: center; margin: 5px">
<div style="margin: 3px">
<input id="input-min-bitrate" class="form-control form-control-sm" style="text-align: center; width: 200px" type="text" placeholder="Minimum bitrate (def: 100)" />
</div>
<div style="margin: 3px">
<label class="form-check-label" for="flexSwitchCheckDefault">Kbps</label>
</div>
</div>

<!-- File Size -->
<div style="display: flex; flex-flow: row; justify-content: center; margin: 5px">
<div style="margin: 3px">
<input id="input-file-size" class="form-control form-control-sm" style="text-align: center; width: 200px" type="text" placeholder="Target file size (def: 8)" />
</div>
<div style="margin: 3px">
<label class="form-check-label" for="flexSwitchCheckDefault">MB</label>
</div>
</div>
</div>
<!-- File Size -->
<div style="display: flex; height: 15px; margin-left: 20%; margin-right: 20%">
<input id="input-file-size" class="form-control form-control-sm" type="text" placeholder="Target file size in megabytes" />
</div>

<!-- Footer -->
<div style="position: absolute; display: flex; justify-content: center; bottom: 0; left: 0; width: 50%; height: 25px; background: rgb(20, 20, 20)">
<button id="btn-support" class="text-muted" style="background: none; border: none; margin: 0; padding: 0; cursor: pointer">
<div style="position: absolute; display: flex; justify-content: center; bottom: 0; left: 0; width: 100%; height: 25px; background: rgb(25, 25, 25)">
<button id="btn-support" class="text-muted" style="background: none; border: none; margin-left: 25px; margin-right: 25px; padding: 0; cursor: pointer">
<small class="text-muted">Buy me a coffee?</small>
</button>
</div>
<div style="position: absolute; display: flex; justify-content: center; bottom: 0; right: 0; width: 50%; height: 25px; background: rgb(20, 20, 20)">
<button id="btn-github" class="text-muted" style="background: none; border: none; margin: 0; padding: 0; cursor: pointer">
<small class="text-muted">Github | v2.0.0</small>
<button id="btn-github" class="text-muted" style="background: none; border: none; margin-left: 25px; margin-right: 25px; padding: 0; cursor: pointer">
<small class="text-muted">Github</small>
</button>
</div>
<script>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "video-compressor",
"version": "1.0.0",
"version": "2.0.1",
"description": "",
"main": "dist/main.js",
"scripts": {
Expand Down
Binary file modified preview.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 24 additions & 10 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let cmd: any = null;
app.on("ready", () => {
mainWindow = new BrowserWindow({
width: 350,
height: 450,
height: 500,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
Expand Down Expand Up @@ -45,11 +45,11 @@ ipcMain.on("droppedVideos", (event, vids: string[]) => {
videoData = getVideoData(vids);
});

ipcMain.on("requestCompress", (event, removeAudio: boolean, targetFileSize: number) => {
ipcMain.on("requestCompress", (event, removeAudio: boolean, h265: boolean, minBitrate: number, targetFileSize: number) => {
currentIndex = 0;
currentProgress = 0;

compressQueue(mainWindow, videoData, removeAudio, targetFileSize)
compressQueue(mainWindow, videoData, removeAudio, h265, minBitrate, targetFileSize)
.then(() => {
event.reply("compressionComplete");
new Notification({ title: "Job done!", body: "Your new videos are located in the same folder." }).show();
Expand All @@ -64,7 +64,14 @@ ipcMain.on("requestAbort", (event) => {
killFFmpeg();
});

export function compressQueue(window: BrowserWindow, videoData: { base: string; path: string; name: string; ext: string }[], removeAudio: boolean, targetFileSize: number): Promise<boolean> {
export function compressQueue(
window: BrowserWindow,
videoData: { base: string; path: string; name: string; ext: string }[],
removeAudio: boolean,
h265: boolean,
minBitrate: number,
targetFileSize: number
): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
window.webContents.send("compressionStart");
totalProgress = videoData.length * 2;
Expand All @@ -74,9 +81,9 @@ export function compressQueue(window: BrowserWindow, videoData: { base: string;

getVideoDuration(videoData[currentIndex].base)
.then((duration: number) => {
const bitrate = getCalculatedVideoBitrate(duration, targetFileSize);
const bitrate = getCalculatedVideoBitrate(duration, minBitrate, targetFileSize);

compressVideo(window, videoData[currentIndex], bitrate, removeAudio)
compressVideo(window, videoData[currentIndex], bitrate, removeAudio, h265)
.then(() => {
if (currentIndex + 1 < videoData.length) {
currentIndex += 1;
Expand All @@ -98,17 +105,24 @@ export function compressQueue(window: BrowserWindow, videoData: { base: string;
});
}

function compressVideo(window: BrowserWindow, videoData: { base: string; path: string; name: string; ext: string }, bitrate: number, removeAudio: boolean): Promise<boolean> {
function compressVideo(window: BrowserWindow, videoData: { base: string; path: string; name: string; ext: string }, bitrate: number, removeAudio: boolean, h265: boolean): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
cmd = FfmpegCommand();

let pass1 = [`-y`, `-c:v libx264`, `-b:v ${bitrate}k`, `-pass 1`, `-an`, `-f mp4`];
let pass2 = [`-c:v libx264`, `-b:v ${bitrate}k`, `-pass 2`, `-c:a aac`, `-b:a 128k`];
let audioArg = "-b:a 128k";
let codec = "-c:v libx264";

if (removeAudio) {
pass2 = [`-c:v libx264`, `-b:v ${bitrate}k`, `-pass 2`, `-an`];
audioArg = "-an";
}

if (h265) {
codec = "-c:v libx265";
}

let pass1 = [`-y`, codec, `-b:v ${bitrate}k`, `-pass 1`, `-an`, `-f mp4`];
let pass2 = [codec, `-b:v ${bitrate}k`, `-pass 2`, `-c:a aac`, audioArg];

cmd.setFfmpegPath(__dirname + "/ffmpeg.exe");
cmd.setFfprobePath(__dirname + "/ffprobe.exe");
cmd.input(videoData.base);
Expand Down
26 changes: 19 additions & 7 deletions src/renderer/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@ const btnAbort: HTMLButtonElement = document.getElementById("btn-abort") as HTML
const btnSupport: HTMLButtonElement = document.getElementById("btn-support") as HTMLButtonElement;
const btnGithub: HTMLButtonElement = document.getElementById("btn-github") as HTMLButtonElement;
const lblStatus: HTMLElement = document.getElementById("lbl-status") as HTMLElement;
const lblStatusSmall: HTMLElement = document.getElementById("lbl-status-small") as HTMLElement;
const dropZone: HTMLElement = document.getElementById("drop-zone") as HTMLElement;
const progressBar: HTMLProgressElement = document.getElementById("progress-bar") as HTMLProgressElement;
const checkRemoveAudio: HTMLInputElement = document.getElementById("check-remove-audio") as HTMLInputElement;
const checkH265: HTMLInputElement = document.getElementById("check-h265") as HTMLInputElement;
const inputMinBitrate: HTMLInputElement = document.getElementById("input-min-bitrate") as HTMLInputElement;
const inputFileSize: HTMLInputElement = document.getElementById("input-file-size") as HTMLInputElement;

let videoPaths: string[] = [];

btnCompress?.addEventListener("click", () => {
const removeAudio = checkRemoveAudio.checked;
const h265 = checkH265.checked;
const minBitrate = parseFloat(inputMinBitrate.value) || 100;
const fileSize = parseFloat(inputFileSize.value) || 8.0;
btnCompress.disabled = true;
ipcRenderer.send("requestCompress", removeAudio, fileSize);
ipcRenderer.send("requestCompress", removeAudio, h265, minBitrate, fileSize);
});

btnAbort?.addEventListener("click", () => {
Expand Down Expand Up @@ -48,43 +53,50 @@ dropZone?.addEventListener("drop", (event) => {
}

lblStatus.innerText = `${videoPaths.length} video(s) ready to compress.`;
lblStatusSmall.innerText = "Click 'Compress' to begin.";
btnCompress.disabled = false;
ipcRenderer.send("droppedVideos", videoPaths);
});

ipcRenderer.on("statusUpdate", (event, msg: string) => {
lblStatus.innerText = msg;
});

ipcRenderer.on("progressUpdate", (event, currentValue: number, totalValue: number) => {
const progress = (currentValue / totalValue) * 100;
const progress = Math.round((currentValue / totalValue) * 100);
console.log(`Progress: ${progress}`);
lblStatusSmall.innerText = `Progress: ${progress}%`;
progressBar.style.width = `${progress}%`;
});

ipcRenderer.on("compressionStart", (event) => {
lblStatus.innerText = "Compressing, please wait...";
lblStatusSmall.innerText = "Large videos can take a long time!";
btnCompress.disabled = true;
btnAbort.disabled = false;
checkRemoveAudio.disabled = true;
checkH265.disabled = true;
inputMinBitrate.disabled = true;
inputFileSize.disabled = true;
progressBar.style.width = "0%";
});

ipcRenderer.on("compressionComplete", (event) => {
lblStatus.innerText = "Compression complete, enjoy!\nPlease consider suppporting me.";
lblStatus.innerText = "Compression complete, enjoy!";
lblStatusSmall.innerText = "Please consider supporting my work :)";
btnCompress.disabled = true;
btnAbort.disabled = true;
checkRemoveAudio.disabled = false;
checkH265.disabled = false;
inputMinBitrate.disabled = false;
inputFileSize.disabled = false;
progressBar.style.width = "100%";
});

ipcRenderer.on("compressionError", (event, err) => {
lblStatus.innerText = err;
lblStatusSmall.innerText = "";
btnCompress.disabled = true;
btnAbort.disabled = true;
checkRemoveAudio.disabled = false;
checkH265.disabled = false;
inputMinBitrate.disabled = false;
inputFileSize.disabled = false;
progressBar.style.width = "100%";
});
4 changes: 2 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export function getVideoDuration(videoPath: string): Promise<number> {
});
}

export function getCalculatedVideoBitrate(duration: number, targetFileSize: number): number {
let magic = Math.max((targetFileSize * 8192.0) / (1.048576 * duration) - 128, 100);
export function getCalculatedVideoBitrate(duration: number, minBitrate: number, targetFileSize: number): number {
let magic = Math.max((targetFileSize * 8192.0) / (1.048576 * duration) - 128, minBitrate);
console.log(`Calculated bitrate: ${magic}`);
return magic;
}

0 comments on commit 7eb02f1

Please sign in to comment.