Fix: compress cover uploads and raise API payload limit

This commit is contained in:
Ponte
2026-02-14 23:00:54 +01:00
parent 23352d85d0
commit e04a5a0a25
2 changed files with 50 additions and 5 deletions

View File

@@ -27,11 +27,12 @@ function sendJson(response, statusCode, payload) {
async function readJsonBody(request) {
const chunks = [];
let size = 0;
const maxPayloadSizeBytes = 8 * 1024 * 1024;
for await (const chunk of request) {
size += chunk.length;
if (size > 1024 * 1024) {
throw new Error("Payload too large");
if (size > maxPayloadSizeBytes) {
throw new Error("Payload too large (max 8MB)");
}
chunks.push(chunk);
}

50
app.js
View File

@@ -94,11 +94,11 @@ coverFileInput.addEventListener("change", async (event) => {
}
try {
const dataUrl = await fileToDataUrl(file);
const dataUrl = await imageFileToOptimizedDataUrl(file);
coverUrlInput.value = dataUrl;
} catch (error) {
console.error(error);
alert("Impossible de charger cette image.");
alert("Impossible de charger/comprimer cette image.");
} finally {
input.value = "";
}
@@ -299,7 +299,7 @@ gameForm.addEventListener("submit", async (event) => {
return;
} catch (error) {
console.error(error);
alert("Impossible d'enregistrer ce jeu via l'API.");
alert(`Impossible d'enregistrer ce jeu via l'API: ${error.message}`);
}
}
@@ -977,6 +977,50 @@ function fileToDataUrl(file) {
});
}
async function imageFileToOptimizedDataUrl(file) {
const originalDataUrl = await fileToDataUrl(file);
const image = await loadImageFromDataUrl(originalDataUrl);
const maxWidth = 240;
const maxHeight = 320;
const scale = Math.min(1, maxWidth / image.width, maxHeight / image.height);
const targetWidth = Math.max(1, Math.round(image.width * scale));
const targetHeight = Math.max(1, Math.round(image.height * scale));
const canvas = document.createElement("canvas");
canvas.width = targetWidth;
canvas.height = targetHeight;
const ctx = canvas.getContext("2d");
if (!ctx) {
throw new Error("canvas unavailable");
}
ctx.drawImage(image, 0, 0, targetWidth, targetHeight);
let quality = 0.82;
let optimized = canvas.toDataURL("image/jpeg", quality);
// Stay comfortably below API payload thresholds.
while (optimized.length > 380_000 && quality > 0.45) {
quality -= 0.08;
optimized = canvas.toDataURL("image/jpeg", quality);
}
if (optimized.length > 520_000) {
throw new Error("image too large after compression");
}
return optimized;
}
function loadImageFromDataUrl(dataUrl) {
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => resolve(image);
image.onerror = () => reject(new Error("image decode failed"));
image.src = dataUrl;
});
}
function updateScannerStatus(message) {
if (scannerStatus) {
scannerStatus.textContent = message;