docs: download and history in README, architecture, decisions; test refused storage

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-15 11:38:34 +02:00
1 parent 2da992fd81
commit 2a0e786e6f
5 files changed
+49 -7

No files matched your search

+12 -3
View File
@@ -34,7 +34,8 @@ A command-line version (Bun) may follow.
2. **Collect covers.**
- **Current:** the portrait poster, the square thumbnail, and the banner and
hero art.
- **Historical:** cover images in archived copies of the series page on the
- **Historical** (tick "Old covers from the Wayback Machine"; off by default,
it takes minutes): cover images in archived copies of the series page on the
[Wayback Machine](https://web.archive.org), up to one snapshot per month.
3. **Check each image.** It downloads each image to get its size and hash,
classifies it by shape (portrait → `volume`, square → `other`, wide →
@@ -55,11 +56,19 @@ A command-line version (Bun) may follow.
A link must still work when a MangaBaka moderator looks at the request. If
it has expired by then, run the tool again.
6. **Hand it to you.**
- **Without API access (most users):** copy the hosted URLs and paste them
into MangaBaka's cover form for the series (the page links to it).
- **Without API access (most users):** press **Download selected (ZIP)** for
the cover files plus a `covers.txt` with each one's type, rating and note,
and upload them in MangaBaka's cover form for the series (the page links to
it). No rehosting needed. Or rehost them and paste the hosted URLs instead.
- **With a personal access token:** the tool shows MangaBaka's preview diff
and, after you confirm, submits the request for review.
The page keeps a **history** of the series you searched, in your browser: the
covers, your ticks, notes and ratings, and what you did with them (downloaded,
rehosted, filed). Pick one from **History** or the start screen to reopen it
instantly; **Search again** refreshes it and keeps your edits. It holds the 30
latest series (up to 300 MB) and stays in this browser only.
Nothing is uploaded or sent to MangaBaka without your action, and submissions
always go to review. You choose the content rating (default `safe`); titles
Webtoons marks as mature show a warning. Your token is sent only to
+8 -4
View File
@@ -12,8 +12,10 @@ self-hosted Bun server (primary), a userscript, and later a Bun CLI.
| Path | Responsibility |
|---|---|
| `src/core/` | Pure pipeline: sources, Wayback history, image inspection, dedupe, seed, MangaBaka client. No DOM, Bun, Node or `GM_*` APIs. |
| `src/core/session.ts` | Review state shared by the page and the userscript: cards, main cover, rehosting, manual text, token flow (preview → confirm → save for review). |
| `src/web/` | Built. The page ("Obi Shelf" design, see `DESIGN.md`): `template.ts` markup shared with the userscript panel, `app.ts` wiring (`mountApp`), `render.ts` shelf and timeline views, `view-model.ts` pure helpers, `transport.ts` (direct to MangaBaka/litterbox, everything else via `/api/fetch`), `styles.css` scoped for a shadow root, `dark-reader.ts` (switches to the page's own dark theme and locks Dark Reader out when that extension is darkening the page). |
| `src/core/session.ts` | Review state shared by the page and the userscript: cards, main cover, rehosting (cards remember host, cache key and expiry), manual text, the download bundle, `restore` from history, token flow (preview → confirm → save for review). |
| `src/core/zip.ts`, `download.ts` | Store-only ZIP writer (CRC-32, UTF-8 names); the download bundle: file names `NN_role_lang[_YYYY]_WxH.ext` and `covers.txt` (spec 002 §2). |
| `src/core/saved.ts` | History model (spec 002 §3): `SavedSearch` (plain data, source by id), `toSaved`/`fromSaved` (drops expired links), `carryEdits` (search again), `pruneIds` (30 entries, 300 MB), `HistoryStore` interface and an in-memory one. |
| `src/web/` | Built. The page ("Obi Shelf" design, see `DESIGN.md`): `template.ts` markup shared with the userscript panel, `app.ts` wiring (`mountApp`), `render.ts` shelf and timeline views, `view-model.ts` pure helpers, `transport.ts` (direct to MangaBaka/litterbox, everything else via `/api/fetch`), `styles.css` scoped for a shadow root, `save-file.ts` (Blob download, works in the panel's shadow root), `history-db.ts` (IndexedDB `HistoryStore`; null when storage is refused), `recent.ts` (History list and the start screen's recent shelf; the page only), `dark-reader.ts` (switches to the page's own dark theme and locks Dark Reader out when that extension is darkening the page). |
| `src/server/` | Built. `app.ts`: web-standard handler (`createApp(env)`) — static assets, `/api/config`, `/api/fetch` allowlisted proxy (redirects re-checked, 20 MB cap), `/api/upload` (store or catbox; takes a source URL, never bytes), `/covers/*`. `storage.ts` (interface, in-memory) and `storage-dir.ts` (folder, size cap, 30-day sweep). `config.ts` (env, client IP), `rate-limit.ts`, `assets-path.ts`. `bun.ts`: thin `Bun.serve` entry. Gate and Workers entry deferred. |
| `src/userscript/` | Built. `gm.ts`: `GM_xmlhttpRequest` transport (no proxy; honest User-Agent for Wayback) and GM storage. `main.ts`: a "Seed covers" launcher on MangaBaka series pages (follows client-side navigation) opening the page's app in a shadow-root panel; optional server URL in its settings. Built by `scripts/build-userscript.ts` into `dist/web/mbseed.user.js`, served at `/mbseed.user.js`. |
| `src/cli/` | Later: Bun CLI. |
@@ -23,8 +25,10 @@ self-hosted Bun server (primary), a userscript, and later a Bun CLI.
`runCovers` (pipeline.ts): links → MangaBaka series, links and images (direct) → `source.resolve` and
`currentCovers` → `waybackHistory` (optional) → `inspectAll` (bytes, size, sha256, shape) → `dedupeByHash`
→ `splitExisting` against MangaBaka → `pickDefault`. `Session` (session.ts) turns that into review cards; the
user edits them, then `rehost` (explicit) → `manualText` for the cover form, or `preview` → confirm → `submit`
(`save_mode: "review"`).
user edits them, then `bundle` → ZIP download, or `rehost` (explicit) → `manualText` for the cover form, or
`preview` → confirm → `submit` (`save_mode: "review"`). On the page each search is saved to IndexedDB
(`toSaved` → `saveAndPrune`) after the run, edits, rehosting, download and filing; opening an entry runs
`fromSaved` → `Session.restore`, and a new search of a saved series runs `carryEdits`.
## Running the server
`bun run build` then `bun run start`. Environment:
+19
View File
@@ -16,6 +16,25 @@ the repo every session — measurably slower and more tokens).
**Consequences:** Rule changes happen in one file; pointer files must stay thin. Plans are working
artefacts: kept after merge they go stale and contradict the code, so the spec is the record.
## 2026-10-15 — Download as a ZIP, and a history in IndexedDB (spec 002)
**Status:** accepted
**Context:** First user review: contributors without a token want the cover files to upload by hand, and a
way back to series they searched before. Design approved in chat (instant restore; history on the page only;
one ZIP).
**Decision:**
- Our own store-only ZIP writer (`core/zip.ts`, ~100 lines): covers don't compress, and it avoids a
dependency. Downloads go through a Blob URL and `<a download>`; this works in the userscript's shadow root
on mangabaka.org (checked in Chrome under the site's CSP), so `GM_download` isn't needed.
- History lives in IndexedDB on the page's origin (`summaries` for the list, `searches` with the bytes),
one entry per MangaBaka series, 30 entries / 300 MB, newest always kept. Stored as plain data with the
source by id (and its name for the list). Expired litterbox/server links are dropped on restore; cards
record `hosting` (host, cache key, expiry) when rehosted.
- Searching a saved series again carries the user's edits over by SHA-256, and keeps the entry's marks.
**Alternatives:** A ZIP library (fflate) — a new dependency for ~100 lines; history in localStorage (5 MB,
strings) or re-running the search on open (minutes with Wayback); history on our server (privacy, accounts).
**Consequences:** History is per browser and lost with site data. Old entries can show covers MangaBaka has
since gained; filing always fetches a fresh snapshot, and the "Found …" line shows the age.
## 2026-10-15 — Wayback history starts off
**Status:** accepted (amends spec 001 §4.9 "include history (on)")
**Context:** First user review: a Wayback run takes minutes at the 10 s pace, while the current covers
+2
View File
@@ -27,6 +27,8 @@ Design: [specs/001-webtoons-covers.md](specs/001-webtoons-covers.md).
- [ ] Mobile layout (the user deferred it, 2026-10-15): the page stacks under 1000px but was only checked at 760px.
## Verify with real services (once possible)
- [ ] Download from the userscript panel in **Firefox** with Tampermonkey/Violentmonkey (checked in Chrome only);
if the Blob link is blocked there, add `GM_download` (spec 002 §6).
- [ ] Which of our servers and domain hosts it (`MBSEED_PUBLIC_URL`); where the covers folder lives.
- [ ] Does catbox accept uploads from our server?
- [ ] Does MangaBaka accept our storage URLs, litterbox/catbox URLs, and
+8
View File
@@ -0,0 +1,8 @@
import { expect, test } from "bun:test";
import { openHistory } from "../src/web/history-db";
test("no IndexedDB, or a browser that refuses it: the page runs without history", async () => {
expect(await openHistory(undefined)).toBeNull();
const refusing = { open: () => { throw new DOMException("blocked", "SecurityError"); } } as unknown as IDBFactory;
expect(await openHistory(refusing)).toBeNull();
});