What this release is
Pure refactor + preset-catalog extension. Nothing visibly changes for users yet — this is the foundation PR for a multi-phase feature that will normalize every book cover to your e-reader's aspect ratio across the library, shelves, and search.
What changes if you upgrade
- Same UI, same behavior.
- The cover-picker modal's "Kobo preview" collapsible is renamed to "E-reader preview" since the engine was already device-neutral; subsequent releases will expose Kindle / PocketBook / Boox / generic e-ink presets in the same panel.
- The cover-padding engine now knows about 22 device presets across Kobo / Kindle / PocketBook / Boox / generic e-ink. They're not exposed in the UI yet (that's Phase 4-5 work), but the engine is ready.
- Existing Kobo-sync setups are uninterrupted — admin column names + preset keys preserved.
Pull image
```
docker pull ghcr.io/new-usemame/calibre-web-nextgen:v4.0.50
```
Or use `:latest`.
What's coming next
The full design is at `notes/COVER-NORMALIZATION-DESIGN.md`. Four more phases:
- Phase 2: Per-user-per-book override schema + user-prefs endpoints. Each household member can target their own device and tune individual books.
- Phase 3: `GET /cover//preview` endpoint with disk cache + LRU sweep. The library starts rendering padded covers.
- Phase 4: Cover-editor lock + apply-to-all controls.
- Phase 5: Browse-view settings checkbox + multi-select bulk-apply. The whole library renders uniform on every browse surface.
Under the hood (technical)
- `cps/services/cover_padding.py` → `cps/services/cover_preview.py`. `PaddingSettings` → `CoverPreviewSettings`. `render_kobo_preview_data_url()` → `render_preview_data_url()`.
- Preset catalog: 3 Kobo entries → 22 entries across Kobo / Kindle / PocketBook / Boox / generic e-ink. New `PRESET_LABELS` + `PRESET_GROUPS` dicts power UI grouped dropdowns.
- Cover-picker endpoint `/book//cover/kobo-preview` → `/book//cover/ereader-preview`. Old URL kept as a 308 Permanent Redirect for one release so in-flight bookmarks don't 404.
- 8 new regression tests: `TestPresetCatalogCoverage` (preserves historical Kobo keys, keeps `PRESET_ASPECTS` / `PRESET_LABELS` / `PRESET_GROUPS` in sync) and `TestLegacyKoboPreviewUrlRedirect` (pins 308 + Location target + that the legacy shim contains no business logic).
Verification
- 71 unit tests pass / 24 Wand-gated skips / 0 failures
- Live container build healthy; cover-picker page renders cleanly with the new heading; zero `BuildError` in container logs
- Full report: `notes/PHASE-1-VERIFICATION-2026-05-12.md`
Heads-up for users with the cover-picker open
If you have a cover-picker page open in a tab when you upgrade, the old endpoint URL (`/cover/kobo-preview`) is automatically 308-redirected to the new one (`/cover/ereader-preview`). The POST body is preserved; nothing visible changes for you. The legacy URL stays live for one release after this; it'll be removed in v4.1.0 or similar.