diff --git a/py/image_manager/features/images/router.py b/py/image_manager/features/images/router.py index 167acea..d728a6d 100644 --- a/py/image_manager/features/images/router.py +++ b/py/image_manager/features/images/router.py @@ -1864,7 +1864,7 @@ def _process_image_for_download( return buffer.getvalue() -@routes.post("/meld/api/download/zip") +@routes.post("/meld/download/zip") async def download_zip(request: web.Request) -> web.Response: try: data = await request.json() @@ -1924,7 +1924,7 @@ async def download_zip(request: web.Request) -> web.Response: return web.json_response(ApiResponse(success=False, error=str(e)).to_dict(), status=500) -@routes.post("/meld/api/download/raw") +@routes.post("/meld/download/raw") async def download_raw(request: web.Request) -> web.Response: try: data = await request.json() diff --git a/ui/src/features/images/api/imagesApi.ts b/ui/src/features/images/api/imagesApi.ts index 5c7086b..e1a5255 100644 --- a/ui/src/features/images/api/imagesApi.ts +++ b/ui/src/features/images/api/imagesApi.ts @@ -189,7 +189,7 @@ const fetchImageBlob = async ( resizeValue: number, resizeFilter: string, ): Promise<{ blob: Blob; filename: string }> => { - const res = await api.fetchApi("/meld/api/download/raw", { + const res = await api.fetchApi("/meld/download/raw", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ imageId, removeMetadata, resizeMode, resizeValue, resizeFilter }), @@ -232,6 +232,13 @@ export const downloadZipImages = async ( let i = 0; let totalBytes = 0; for (const imageId of imageIds) { + // Guard: check entry count limit before fetching + if (i >= MAX_ZIP_FILES) { + throw new Error( + `ZIP entry limit reached (${MAX_ZIP_FILES} files). Please reduce the number of images.`, + ); + } + onProgress?.(i, total); const { blob, filename } = await fetchImageBlob( imageId, @@ -241,12 +248,7 @@ export const downloadZipImages = async ( resizeFilter, ); - // Guard: check entry count and total byte size limits before adding to zip - if (i >= MAX_ZIP_FILES) { - throw new Error( - `ZIP entry limit reached (${MAX_ZIP_FILES} files). Please reduce the number of images.`, - ); - } + // Guard: check total byte size limit before adding to zip totalBytes += blob.size; if (totalBytes > MAX_ZIP_BYTES) { throw new Error( diff --git a/ui/src/features/light-table/components/DownloadModal.tsx b/ui/src/features/light-table/components/DownloadModal.tsx index 914e6ff..27bb41a 100644 --- a/ui/src/features/light-table/components/DownloadModal.tsx +++ b/ui/src/features/light-table/components/DownloadModal.tsx @@ -498,7 +498,7 @@ export const DownloadModal: React.FC = ({ imageIds, onSucces role="progressbar" aria-label="Download progress" aria-valuemin={0} - aria-valuemax={downloadProgress.total} + aria-valuemax={100} aria-valuenow={Math.round( (downloadProgress.current / Math.max(1, downloadProgress.total)) * 100, )} diff --git a/web/js/index.js b/web/js/index.js index 10a381d..fb0877c 100644 --- a/web/js/index.js +++ b/web/js/index.js @@ -6505,7 +6505,7 @@ const Eg = (e) => { let n = e.replace(/\\/g, "/").split("/").pop() ?? ""; return n = n.replace(/\.\./g, "").replace(/[\x00-\x1f\x7f]/g, "").trim(), !n || n.length > 255 ? t : n; }, bf = async (e, t, n, r, l) => { - const a = await te.fetchApi("/meld/api/download/raw", { + const a = await te.fetchApi("/meld/download/raw", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ imageId: e, removeMetadata: t, resizeMode: n, resizeValue: r, resizeFilter: l }) @@ -6523,6 +6523,10 @@ const Eg = (e) => { const o = (await import("./jszip.min.js").then((x) => x.j)).default, i = new o(), c = e.length, d = /* @__PURE__ */ new Set(); let p = 0, v = 0; for (const x of e) { + if (p >= Rc) + throw new Error( + `ZIP entry limit reached (${Rc} files). Please reduce the number of images.` + ); a == null || a(p, c); const { blob: _, filename: f } = await bf( x, @@ -6531,10 +6535,6 @@ const Eg = (e) => { r, l ); - if (p >= Rc) - throw new Error( - `ZIP entry limit reached (${Rc} files). Please reduce the number of images.` - ); if (v += _.size, v > Dc) throw new Error( `ZIP size limit reached (${Dc / 1024 / 1024 / 1024} GB). Please reduce the number of images.` @@ -8344,7 +8344,7 @@ const vy = ({ imageIds: e, onSuccess: t, onClose: n }) => { role: "progressbar", "aria-label": "Download progress", "aria-valuemin": 0, - "aria-valuemax": g.total, + "aria-valuemax": 100, "aria-valuenow": Math.round( g.current / Math.max(1, g.total) * 100 ),