Persist blob sizes (covers + chapter pages) and surface upload storage usage to admins in two places: - Admin System tab: total/covers/chapters totals, ratio of disk, average image sizes, and top-5 largest mangas/chapters leaderboards, behind a new GET /api/v1/admin/storage endpoint (separate from /admin/system so the cheap DB aggregates aren't coupled to its 250ms CPU sample). - Manga detail page: total chapter-content size and per-chapter size, with an em-dash for uncrawled or not-yet-measured chapters. Sizes are captured at write time (crawler put_stream return, uploaded page/cover byte length) into nullable pages.size_bytes / mangas.cover_size_bytes columns; NULL means "not yet measured", distinct from a real 0. A one-shot, idempotent admin "Backfill sizes" action (POST /api/v1/admin/storage/backfill) stats pre-existing blobs in keyset-paginated, capped batches and reports more_remaining so a large legacy library can be drained over multiple runs. Aggregates and leaderboards treat NULL honestly (only fully-measured entities are ranked); a dashboard banner flags unmeasured rows so partial figures aren't read as complete. persist_pages now prunes stale page rows on a shrinking re-crawl so totals and page_count stay consistent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
21 lines
1.1 KiB
SQL
21 lines
1.1 KiB
SQL
-- Persist blob sizes so storage-usage stats are a pure DB aggregate
|
|
-- rather than a filesystem stat per page. Sizes are captured at write
|
|
-- time (the crawler's put_stream already returns bytes written; uploads
|
|
-- and covers know their byte length). Pre-existing rows carry NULL until
|
|
-- the admin "backfill sizes" action stats their blobs.
|
|
|
|
-- NULL = "size unknown / not yet backfilled". A measured value (even 0)
|
|
-- is distinct from unknown, so a crawled-but-un-backfilled page is never
|
|
-- mistaken for a genuinely empty one. SUM/AVG ignore NULL, so an
|
|
-- un-backfilled library reports honest partial totals rather than zeros.
|
|
ALTER TABLE pages ADD COLUMN size_bytes BIGINT;
|
|
|
|
-- Nullable for the same reason, mirroring the nullable cover_image_path.
|
|
ALTER TABLE mangas ADD COLUMN cover_size_bytes BIGINT;
|
|
|
|
-- Covering index: makes the per-chapter / per-manga SUM(size_bytes)
|
|
-- roll-ups (chapter list, leaderboards) index-only. The existing
|
|
-- pages_chapter_idx (chapter_id, page_number) can serve the WHERE filter
|
|
-- but not the SUM without heap visits.
|
|
CREATE INDEX pages_chapter_size_idx ON pages (chapter_id) INCLUDE (size_bytes);
|