Commit Graph
4 Commits
Author SHA1 Message Date
JakeBreath fed1e8bb5a Fix chunk assembly order and surface video duration in the optimizer
- 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).
2026-09-17 20:45:12 -05:00
JakeBreath 58f030878e Fix duplicate React keys and the MP4 encoder probe
- 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.
2026-09-17 20:41:16 -05:00
JakeBreath f7e2242e5f Fix the client optimizer: PNG init, GIF compositing, streaming video
- 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.
2026-09-17 20:10:31 -05:00
JakeBreath bab9904fc8 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.
2026-09-17 20:03:22 -05:00