mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-29 20:03:48 +02:00
Clean up cropping logic
This commit is contained in:
@@ -1,139 +0,0 @@
|
||||
import {
|
||||
Input,
|
||||
Output,
|
||||
WebMOutputFormat,
|
||||
BufferTarget,
|
||||
Conversion,
|
||||
BlobSource,
|
||||
ALL_FORMATS,
|
||||
} from 'mediabunny';
|
||||
|
||||
const selectMediaButton = document.querySelector(
|
||||
'#select-file',
|
||||
) as HTMLButtonElement;
|
||||
const cropButton = document.querySelector('#crop-button') as HTMLButtonElement;
|
||||
const fileNameElement = document.querySelector(
|
||||
'#file-name',
|
||||
) as HTMLParagraphElement;
|
||||
|
||||
let selectedFile: File | null = null;
|
||||
const horizontalRule = document.querySelector('hr') as HTMLHRElement;
|
||||
const outputContainer = document.querySelector(
|
||||
'#output-container',
|
||||
) as HTMLDivElement;
|
||||
const errorElement = document.querySelector(
|
||||
'#error-element',
|
||||
) as HTMLParagraphElement;
|
||||
const cropTopInput = document.querySelector('#crop-top') as HTMLInputElement;
|
||||
const cropLeftInput = document.querySelector('#crop-left') as HTMLInputElement;
|
||||
const cropWidthInput = document.querySelector(
|
||||
'#crop-width',
|
||||
) as HTMLInputElement;
|
||||
const cropHeightInput = document.querySelector(
|
||||
'#crop-height',
|
||||
) as HTMLInputElement;
|
||||
|
||||
const cropVideo = async (file: File) => {
|
||||
fileNameElement.textContent = file.name;
|
||||
horizontalRule.style.display = '';
|
||||
errorElement.textContent = '';
|
||||
outputContainer.innerHTML = '';
|
||||
|
||||
try {
|
||||
const input = new Input({
|
||||
source: new BlobSource(file),
|
||||
formats: ALL_FORMATS,
|
||||
});
|
||||
|
||||
const videoTrack = await input.getPrimaryVideoTrack();
|
||||
if (!videoTrack) {
|
||||
throw new Error('File has no video track.');
|
||||
}
|
||||
|
||||
if (videoTrack.codec === null) {
|
||||
throw new Error('Unsupported video codec.');
|
||||
}
|
||||
|
||||
if (!(await videoTrack.canDecode())) {
|
||||
throw new Error('Unable to decode the video track.');
|
||||
}
|
||||
|
||||
const output = new Output({
|
||||
format: new WebMOutputFormat(),
|
||||
target: new BufferTarget(),
|
||||
});
|
||||
|
||||
const conversion = await Conversion.init({
|
||||
input,
|
||||
output,
|
||||
video: {
|
||||
crop: {
|
||||
top: parseInt(cropTopInput.value) || 0,
|
||||
left: parseInt(cropLeftInput.value) || 0,
|
||||
width: parseInt(cropWidthInput.value) || 300,
|
||||
height: parseInt(cropHeightInput.value) || 300,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await conversion.execute();
|
||||
|
||||
const buffer = output.target.buffer;
|
||||
if (!buffer) {
|
||||
throw new Error('Failed to generate output buffer');
|
||||
}
|
||||
const blob = new Blob([buffer], { type: 'video/webm' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const video = document.createElement('video');
|
||||
video.src = url;
|
||||
video.controls = true;
|
||||
video.className = 'rounded-lg overflow-hidden bg-zinc-100 dark:bg-zinc-800';
|
||||
outputContainer.appendChild(video);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
errorElement.textContent = String(error);
|
||||
outputContainer.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
const updateSelectedFile = (file: File | null) => {
|
||||
selectedFile = file;
|
||||
fileNameElement.textContent = file ? file.name : '';
|
||||
cropButton.disabled = !file;
|
||||
errorElement.textContent = '';
|
||||
outputContainer.innerHTML = '';
|
||||
};
|
||||
|
||||
selectMediaButton.addEventListener('click', () => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.accept = 'video/*,video/x-matroska';
|
||||
fileInput.addEventListener('change', () => {
|
||||
const file = fileInput.files?.[0];
|
||||
updateSelectedFile(file || null);
|
||||
});
|
||||
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
document.addEventListener('dragover', (event) => {
|
||||
event.preventDefault();
|
||||
event.dataTransfer!.dropEffect = 'copy';
|
||||
});
|
||||
|
||||
document.addEventListener('drop', (event) => {
|
||||
event.preventDefault();
|
||||
if (!event.dataTransfer?.files) {
|
||||
updateSelectedFile(null);
|
||||
return;
|
||||
}
|
||||
const file = event.dataTransfer.files[0] ?? null;
|
||||
updateSelectedFile(file);
|
||||
});
|
||||
|
||||
cropButton.addEventListener('click', () => {
|
||||
if (selectedFile) {
|
||||
void cropVideo(selectedFile);
|
||||
}
|
||||
});
|
||||
@@ -1,70 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" translate="no">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Crop example | Mediabunny</title>
|
||||
<script type="module" src="./../base.ts"></script>
|
||||
<script type="module" src="./crop.ts"></script>
|
||||
<link rel="stylesheet" href="../base.css">
|
||||
<link rel="icon" href="../../docs/public/mediabunny-logo.svg">
|
||||
</head>
|
||||
|
||||
<body class="flex flex-col items-center py-10 bg-gray-50 text-gray-800 dark:bg-zinc-900 dark:text-zinc-200 px-2">
|
||||
<h1 class="text-3xl font-bold text-green-500 text-center">Crop example</h1>
|
||||
<p class="max-w-lg text-center">Select or drop a video file and specify the crop dimensions.</p>
|
||||
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<div class="flex gap-2 mt-4">
|
||||
<button id="select-file" class="rounded-lg bg-gray-200 dark:bg-zinc-750 hover:bg-gray-300 dark:hover:bg-zinc-700 px-5 py-2">
|
||||
Select local file
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-4">
|
||||
<button id="crop-button" class="rounded-lg bg-green-500 hover:bg-green-600 text-white px-5 py-2" disabled>
|
||||
Crop Video
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 mt-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<label for="crop-top" class="text-sm">Top</label>
|
||||
<input type="number" id="crop-top" value="0" class="rounded-lg bg-gray-200 dark:bg-zinc-750 px-3 py-1">
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label for="crop-left" class="text-sm">Left</label>
|
||||
<input type="number" id="crop-left" value="0" class="rounded-lg bg-gray-200 dark:bg-zinc-750 px-3 py-1">
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label for="crop-width" class="text-sm">Width</label>
|
||||
<input type="number" id="crop-width" value="300" class="rounded-lg bg-gray-200 dark:bg-zinc-750 px-3 py-1">
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label for="crop-height" class="text-sm">Height</label>
|
||||
<input type="number" id="crop-height" value="300" class="rounded-lg bg-gray-200 dark:bg-zinc-750 px-3 py-1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-xs opacity-60 mt-2" id="file-name"></p>
|
||||
<hr class="w-full max-w-96 my-4 border-gray-300 dark:border-zinc-700" style="display: none;">
|
||||
<p id="error-element" class="text-red-500"></p>
|
||||
<div id="output-container"></div>
|
||||
|
||||
<a href="/" class="fixed top-0 left-0 flex gap-2 py-2 px-5 items-center">
|
||||
<img src="../../docs/public/mediabunny-logo.svg" class="size-6">
|
||||
<p class="text-sm font-medium">Mediabunny</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://github.com/Vanilagy/mediabunny/tree/main/examples/crop"
|
||||
target="_blank"
|
||||
class="flex items-center gap-2 fixed top-0 right-0 py-2 px-5 bg-gray-200 dark:bg-zinc-750 hover:bg-gray-300 dark:hover:bg-zinc-700 rounded-bl-xl"
|
||||
>
|
||||
<img src="../../docs/assets/github-mark.svg" class="size-6 dark:invert">
|
||||
<p>View source code</p>
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user