Files
KohakuHub/scripts/dev
narugo1992 173b5d29d4 feat(ui/indexed-tar): lazy in-listing thumbnails for image members
Image rows inside an indexed-tar listing now lazily decode a small
preview in place of the static placeholder icon. The work is gated
on visibility (IntersectionObserver), bandwidth-aware (per-format
strategy chain), and globally togglable (localStorage-persisted).

Strategy chain — first non-null wins:

  1. jpeg-exif       Range-read first 64 KB; parse JPEG markers;
                     extract APP1 / IFD1 thumbnail JPEG. Saves
                     up to 99% of bandwidth on EXIF-bearing JPEGs.
  2. small-image     ≤ 256 KB images: full read + canvas resize.
  3. medium-image    256 KB – 5 MB images: full read + canvas
                     resize (head bytes from #1 are reused via
                     a shared ExtractionContext).
  > 5 MB             no strategy matches → placeholder stays.

The chain is registered in `_STRATEGIES`, so future formats
(video first-frame, etc.) plug in by appending another entry.

Pure-client end to end: no backend thumbnail service, no extra API.
Concurrency capped at 4 in flight; an LRU of 100 thumbnail blob URLs
caches across folder navigation and revokes the oldest when evicted.

A toolbar switch in the panel persists the user's choice via
localStorage (key: kohaku-tar-thumbnail-enabled). Default ON; OFF
short-circuits everything — no IO subscription, no Range read, no
cache lookup.

Failure semantics: every error path (network 5xx, decode failure,
abort) silently falls back to the placeholder. Never a thrown
render, never a toast. The user just sees the same icon they would
have seen pre-feature.

Test fixtures generated via scripts/dev/generate_preview_test_fixtures.py:

  - with_exif_thumb.jpg — JPEG carrying an embedded thumbnail in
    APP1 / IFD1, exercises the EXIF probe success path.
  - no_exif_thumb.jpg   — same visual, EXIF stripped, exercises
    the parser's null-return + caller's strategy fall-through.

Coverage on the new modules:
  TarMemberThumbnail.vue   100% / 100%
  TarBrowserPanel.vue       99.42% / 84.72%   (was 95.98%)
  tar-thumbnail.js          78.98% / 75.75%   (canvas-decode path
                                              is jsdom-untestable)

Total UI suite: 363 passing across 40 files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:14:46 +08:00
..
2026-04-21 12:50:30 +08:00