Client-side optimization pipeline with apply-to-J-ID

Backend:
- POST /api/files/J-x/optimize/ applies a browser-processed file: replaces
  every copy (renaming when the extension changes), recomputes MD5, size
  and perceptual hashes, seeds guest visibility; 400 when identical,
  409 when the result matches another item, owner/staff only.

Frontend (no server-side processing by design):
- optimize.worker.ts + pipelines: Mediabunny/WebCodecs for video with a
  prefer-hardware hint and per-browser codec detection; MozJPEG/OxiPNG/
  libwebp (jSquash) for images; gifuct-js+gifenc and UPNG for GIF/APNG.
- OptimizeModal: per-file-type options, original vs processed previews
  with sizes/savings, progress bar with ETA, then Apply (overwrite).
- Optimize button on the library detail for the uploader/staff.
This commit is contained in:
2026-09-17 20:03:22 -05:00
parent 90e61bb333
commit bab9904fc8
14 changed files with 1721 additions and 8 deletions
+116 -2
View File
@@ -1,20 +1,29 @@
{
"name": "vite-scaffold",
"name": "j621-frontend",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vite-scaffold",
"name": "j621-frontend",
"version": "0.0.0",
"dependencies": {
"@jsquash/jpeg": "^1.6.0",
"@jsquash/oxipng": "^2.3.0",
"@jsquash/resize": "^2.1.1",
"@jsquash/webp": "^1.5.0",
"@tanstack/react-query": "^5.103.1",
"clsx": "^2.1.1",
"gifenc": "^1.0.3",
"gifuct-js": "^2.1.2",
"lucide-react": "^1.47.0",
"mediabunny": "^1.58.0",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-router-dom": "^7.18.4",
"tailwind-merge": "^3.7.0",
"upng-js": "^2.1.0",
"wasm-feature-detect": "^1.9.0",
"zustand": "^5.0.15"
},
"devDependencies": {
@@ -79,6 +88,36 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@jsquash/jpeg": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@jsquash/jpeg/-/jpeg-1.6.0.tgz",
"integrity": "sha512-zwN46Awh1VM6gXlIcALwb5WzqK5H2e6+Awcs1QP8AvS8ohsK/sbE4esvmH4jhlhW7+CgiUUww66vg0aTnlSIMA==",
"license": "Apache-2.0"
},
"node_modules/@jsquash/oxipng": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@jsquash/oxipng/-/oxipng-2.3.0.tgz",
"integrity": "sha512-aQ8wiEp6ztlTMXc+RMt/CG8crU3mEHDU+h+JYkIi6ctMhlh8+Ltj5XwQFfBuyzKYrp8NxaFW80Dp824bqjr+zA==",
"license": "Apache-2.0",
"dependencies": {
"wasm-feature-detect": "^1.2.11"
}
},
"node_modules/@jsquash/resize": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@jsquash/resize/-/resize-2.1.1.tgz",
"integrity": "sha512-0R5UL1ZLHUT+carjVikcE1QfA+kfNQ2YamYyGVRmhfh4zttU5EY3bQBGxPIPtY2xIAw1P4Kgyxm2xrceRw1r2w==",
"license": "Apache-2.0"
},
"node_modules/@jsquash/webp": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jsquash/webp/-/webp-1.5.0.tgz",
"integrity": "sha512-KggLoj2MnRSfIqTeKe1EmbljTX2vuV7mh79k89PCL1pyqiDULcPM1L47twxXt0hkb68F70bXiL31MxsuoZtKFw==",
"license": "Apache-2.0",
"dependencies": {
"wasm-feature-detect": "^1.2.11"
}
},
"node_modules/@oxc-project/types": {
"version": "0.150.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.150.0.tgz",
@@ -1299,6 +1338,21 @@
"react": "^18 || ^19"
}
},
"node_modules/@types/dom-mediacapture-transform": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.12.tgz",
"integrity": "sha512-d7/QsLRwF864A5mgIM/YrfiglHoYn7zgCcAoJgW404r+2DwnNr7EBbLnCWpmOMgH8y0te73L1AV6H1bmauaWFw==",
"license": "MIT",
"dependencies": {
"@types/dom-webcodecs": "*"
}
},
"node_modules/@types/dom-webcodecs": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.13.tgz",
"integrity": "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==",
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.13.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.5.tgz",
@@ -1445,6 +1499,21 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/gifenc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/gifenc/-/gifenc-1.0.3.tgz",
"integrity": "sha512-xdr6AdrfGBcfzncONUOlXMBuc5wJDtOueE3c5rdG0oNgtINLD+f2iFZltrBRZYzACRbKr+mSVU/x98zv2u3jmw==",
"license": "MIT"
},
"node_modules/gifuct-js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/gifuct-js/-/gifuct-js-2.1.2.tgz",
"integrity": "sha512-rI2asw77u0mGgwhV3qA+OEgYqaDn5UNqgs+Bx0FGwSpuqfYn+Ir6RQY5ENNQ8SbIiG/m5gVa7CD5RriO4f4Lsg==",
"license": "MIT",
"dependencies": {
"js-binary-schema-parser": "^2.0.3"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -1462,6 +1531,12 @@
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/js-binary-schema-parser": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz",
"integrity": "sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg==",
"license": "MIT"
},
"node_modules/lightningcss": {
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
@@ -1754,6 +1829,24 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/mediabunny": {
"version": "1.58.0",
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.58.0.tgz",
"integrity": "sha512-0jW6vSDVqWwNe3+WBryrMzC2mUBfk6E5KQLGXLdKVGzclceXXIsbayEkAsNDCuoTcoMiVI62sPDnkkFDxiMjGw==",
"license": "MPL-2.0",
"workspaces": [
".",
"packages/*"
],
"dependencies": {
"@types/dom-mediacapture-transform": "^0.1.11",
"@types/dom-webcodecs": "0.1.13"
},
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/Vanilagy"
}
},
"node_modules/nanoid": {
"version": "3.3.19",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz",
@@ -1822,6 +1915,12 @@
}
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -2055,6 +2154,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/upng-js": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/upng-js/-/upng-js-2.1.0.tgz",
"integrity": "sha512-d3xzZzpMP64YkjP5pr8gNyvBt7dLk/uGI67EctzDuVp4lCZyVMo0aJO6l/VDlgbInJYDY6cnClLoBp29eKWI6g==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.5"
}
},
"node_modules/vite": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz",
@@ -2133,6 +2241,12 @@
}
}
},
"node_modules/wasm-feature-detect": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.9.0.tgz",
"integrity": "sha512-zonE+xlIIYtxPy++L24ow0hAD8CICb4+FgPyROd3buyXIqsJvUEDkBgfCCoXOd1Hu3DUr0GOfnPIdcGV+YpNaA==",
"license": "Apache-2.0"
},
"node_modules/zustand": {
"version": "5.0.15",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.15.tgz",