Compare commits

...

2 Commits

Author SHA1 Message Date
b2fff4357b
Create progress bar 2025-01-28 20:03:05 +01:00
39fa99da63
Implement showing video you just selected 2025-01-28 19:33:50 +01:00
4 changed files with 164 additions and 36 deletions

View File

@ -2,41 +2,49 @@ async function compress() {
showSection("loading");
const filesize = document.getElementById("filesize").value;
const filesizeUnit = document.getElementById("filesize-unit").value;
const file = document.getElementById("file-input").files[0];
updateProgress(0);
const ffmpeg = new FFmpegWASM.FFmpeg();
ffmpeg.on("progress", data => {
console.log(data.progress);
console.log(data);
updateProgress(data.progress);
});
await ffmpeg.load({ coreURL: "/assets/scripts/core/package/dist/umd/ffmpeg-core.js" });
await ffmpeg.writeFile(file.name, await readFromBlob(file));
await ffmpeg.exec(["-i", file.name, "-fs", filesize + "M", "compressed.mp4"]);
await ffmpeg.exec(["-i", file.name, "-preset", "veryfast", "-fs", filesize + filesizeUnit, "compressed.mp4"]);
const video = await ffmpeg.readFile("compressed.mp4");
location.href = URL.createObjectURL(new Blob([video.buffer], { type: "video/mp4" }));
}
function selectFile() {
function updateProgress(progress) {
const percent = (progress * 100).toFixed(1) + "%";
document.getElementById("progress-percentage").innerText = percent;
document.getElementById("progress-indicator").style.clipPath = `rect(0 ${percent} 100% 0)`;
}
function openFileSelector() {
document.getElementById("file-input").click();
}
function showSection(section) {
for (const section of document.getElementsByTagName("section")) {
section.style.opacity = "0";
}
function selectFile() {
setTimeout(() => {
for (const section of document.getElementsByTagName("section")) {
section.style.display = "none";
}
const file = document.getElementById("file-input").files[0];
document.getElementById(section + "-section").style.display = "block";
document.getElementById(section + "-section").style.opacity = "1";
}, 400);
document.getElementById("uploaded-video").src = URL.createObjectURL(file);
document.getElementById("uploaded-video").load();
hideElements("#file-drop-area", "#file-input-spacing");
showElements("#uploaded-video", "#change-file");
}, 200);
}
// https://github.com/ffmpegwasm/ffmpeg.wasm/blob/main/packages/util/src/index.ts

View File

@ -0,0 +1,43 @@
const TRANSITION_TIME = 300;
function showSection(section) {
for (const section of document.getElementsByTagName("section")) {
hideElements(section);
}
showElements(`#${section}-section`);
}
function hideElements() {
for (const input of arguments) {
const elem = input instanceof Element ? input : document.querySelector(input);
if (getComputedStyle(elem).display === "none")
continue;
elem.style.opacity = "0";
elem.dataset.oldDisplay = getComputedStyle(elem).display;
setTimeout(() => {
elem.style.display = "none";
}, TRANSITION_TIME);
}
}
function showElements() {
setTimeout(() => {
for (const input of arguments) {
const elem = input instanceof Element ? input : document.querySelector(input);
elem.style.opacity = "0";
elem.style.display = elem.dataset.oldDisplay || "block";
elem.dataset.oldDisplay = null;
setTimeout(() => {
elem.style.opacity = "1";
}, 10);
}
}, TRANSITION_TIME);
}

View File

@ -20,36 +20,44 @@ h1 {
margin-bottom: 1rem;
}
h3 {
color: #757575;
font-size: 4rem;
font-weight: 400;
margin: 0;
}
p {
color: #9E9E9E;
font-size: 0.8rem;
}
section {
transition: opacity ease-in 400ms;
* {
opacity: 1;
transition: opacity 300ms;
}
#file-input {
video {
width: 355px;
height: 200px;
border: 2px solid #212121;
background-color: black;
border-radius: 1rem;
box-shadow: 0 5px 5px rgba(0, 0, 0, 0.2);
}
#file-input, #change-file {
display: none;
opacity: 0;
}
#file-input-spacing * {
visibility: hidden;
}
#file-drop-area {
max-width: 355px;
height: 200px;
height: 198px;
border: 3px dotted #BDBDBD;
margin: 3rem auto;
margin: 3rem auto 1rem auto;
border-radius: 1rem;
display: flex;
justify-content: center;
align-items: center;
transition: background-color ease-in 200ms;
transition: all 300ms;
cursor: pointer;
}
@ -62,7 +70,13 @@ section {
outline: none;
}
button {
#uploaded-video {
display: none;
opacity: 0;
margin: 3rem auto 1rem auto;
}
button.primary {
background-image: linear-gradient(to right, #4CAF50, #00BCD4);
border: none;
color: white;
@ -74,19 +88,32 @@ button {
cursor: pointer;
}
button:hover {
button.primary:hover {
filter: brightness(1.1);
}
button:active {
button.primary:active {
filter: brightness(0.8);
}
button:focus {
button.primary:focus {
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.2);
outline: 2px solid black;
}
button.simple {
border: none;
background-color: transparent;
transition: color 100ms;
cursor: pointer;
color: #9E9E9E;
margin: 1rem auto;
}
button.simple:hover {
color: black;
}
input, select {
background-color: white;
padding: 0.5rem 1rem;
@ -121,3 +148,40 @@ input:focus, select:focus {
margin-left: 1rem;
}
#loading-title {
color: #757575;
font-size: 3rem;
font-weight: bold;
margin-top: 4rem;
margin-bottom: 0;
}
#loading-description {
font-size: 1rem;
}
#progress-container {
width: 80vw;
height: 2rem;
max-width: 500px;
border-radius: 2rem;
margin: auto;
background-color: #E0E0E0;
position: relative;
margin-top: 3rem;
}
#progress-indicator {
position: absolute;
inset: 0;
background-image: linear-gradient(to right, #4CAF50, #00BCD4);
border-radius: 2rem;
transition: clip-path 200ms;
}
#progress-percentage {
color: #757575;
font-weight: bold;
font-size: 1.2rem;
}

View File

@ -4,6 +4,7 @@
<meta charset="UTF-8">
<title>Video Compressor</title>
<script defer src="/assets/scripts/ffmpeg/package/dist/umd/ffmpeg.js"></script>
<script defer src="/assets/scripts/ui.js"></script>
<script defer src="/assets/scripts/main.js"></script>
<link rel="stylesheet" href="/assets/style/main.css">
</head>
@ -12,10 +13,16 @@
<p>Compress video files to a specific file size, so you can upload them to your favorite social media and messaging apps!</p>
<section id="file-picker-section">
<div id="file-drop-area" onclick="selectFile()" onkeydown="['Enter', 'Space'].includes(event.code) && selectFile()" tabindex="0">
<div id="file-drop-area" onclick="openFileSelector()" onkeydown="['Enter', 'Space'].includes(event.code) && openFileSelector()" tabindex="0">
<span>Drag and drop a file here!</span>
</div>
<input id="file-input" type="file" accept="video/*" tabindex="-1">
<input id="file-input" oninput="selectFile()" type="file" accept="video/*" tabindex="-1">
<div id="file-input-spacing" style="margin-top: -1rem">
<button class="simple">.</button>
</div>
<video id="uploaded-video" controls autoplay></video>
<button id="change-file" onclick="openFileSelector()" class="simple">Change video</button>
<input id="filesize" type="number" value="10" size="3" placeholder="#"><!--
@ -25,12 +32,18 @@
<option value="G">GB</option>
</select>
<button id="compress" onclick="compress()">Go!</button>
<button id="compress" onclick="compress()" class="primary">Go!</button>
</section>
<section id="loading-section" style="opacity: 0; display: none;">
<h3>Please wait...</h3>
<p>This may take a while</p>
<h3 id="loading-title">Please wait...</h3>
<p id="loading-description">This may take a while</p>
<div id="progress-container">
<div id="progress-indicator"></div>
</div>
<p id="progress-percentage">0%</p>
</section>
</body>
</html>