feat: improve media delivery and web upload pipeline
All checks were successful
CI / test (push) Successful in 26s
All checks were successful
CI / test (push) Successful in 26s
- make minio bucket downloadable for direct media links - switch object keys to random uuid-based names - add client-side image compression before upload
This commit is contained in:
@@ -84,6 +84,55 @@ export function MessageComposer() {
|
||||
return "file";
|
||||
}
|
||||
|
||||
function loadImageFromFile(file: File): Promise<HTMLImageElement> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image();
|
||||
const url = URL.createObjectURL(file);
|
||||
image.onload = () => {
|
||||
URL.revokeObjectURL(url);
|
||||
resolve(image);
|
||||
};
|
||||
image.onerror = () => {
|
||||
URL.revokeObjectURL(url);
|
||||
reject(new Error("Failed to load image"));
|
||||
};
|
||||
image.src = url;
|
||||
});
|
||||
}
|
||||
|
||||
async function compressImageForWeb(file: File): Promise<File> {
|
||||
const image = await loadImageFromFile(file);
|
||||
const maxSide = 1920;
|
||||
const ratio = Math.min(1, maxSide / Math.max(image.width, image.height));
|
||||
const width = Math.max(1, Math.round(image.width * ratio));
|
||||
const height = Math.max(1, Math.round(image.height * ratio));
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) {
|
||||
return file;
|
||||
}
|
||||
ctx.drawImage(image, 0, 0, width, height);
|
||||
|
||||
const blob = await new Promise<Blob | null>((resolve) => {
|
||||
canvas.toBlob((result) => resolve(result), "image/jpeg", 0.82);
|
||||
});
|
||||
if (!blob || blob.size >= file.size) {
|
||||
return file;
|
||||
}
|
||||
const baseName = file.name.replace(/\.[^/.]+$/, "");
|
||||
return new File([blob], `${baseName || "image"}-web.jpg`, { type: "image/jpeg" });
|
||||
}
|
||||
|
||||
async function prepareFileForUpload(file: File, fileType: "file" | "image" | "video" | "audio"): Promise<File> {
|
||||
if (fileType === "image") {
|
||||
return compressImageForWeb(file);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
async function startRecord() {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
@@ -129,7 +178,8 @@ export function MessageComposer() {
|
||||
if (!selectedFile) {
|
||||
return;
|
||||
}
|
||||
await handleUpload(selectedFile, selectedType);
|
||||
const uploadFile = await prepareFileForUpload(selectedFile, selectedType);
|
||||
await handleUpload(uploadFile, selectedType);
|
||||
if (previewUrl) {
|
||||
URL.revokeObjectURL(previewUrl);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user