- The streaming assembler applied chunks sorted by position, so header
patches written last could be overwritten by earlier data. Chunks now
apply in arrival order (newest write wins per byte range) and are only
laid out by position afterwards.
- The Optimize modal now reads the media metadata itself: both previews
show resolution and duration, and the processed video is flagged in red
when it comes out shorter than the original (a truncated encode is no
longer something you have to guess by file size).
- MatchCard and IqdbCard are siblings in the library detail aside and
both used key={item.j_id}, so React warned about duplicate children
(J-81 twice). Their keys are now unique per card.
- The video pipeline no longer decides "this browser can't encode" from
a single getFirstEncodableVideoCodec probe with source dimensions.
It now probes Conversion.init with the real (even) output size across
codec candidates and hardware preferences, uses the first valid
configuration, and reports exactly what was tried when nothing works.
It also fails fast with a clear message if VideoEncoder is missing in
the worker.
- PNG failed because wasm-bindgen's init only accepts a URL string (or a
module/buffer): passing { module_or_path } broke every PNG optimization.
- GIF/APNG showed flashing colors because patches were written with
putImageData, which ignores the transparency that means "keep the
previous frame". Patches now blend through drawImage with correct
disposal handling, and quantization keeps a transparent palette entry.
- Video no longer downloads the whole file into memory: Mediabunny reads
it with range requests (UrlSource) and the muxer streams into Blob
chunks (StreamTarget) that are assembled with last-write-wins range
merging. BufferTarget held the entire output in memory, which crashed
the tab on large files.
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.