Offline retry queue for userscript writes #5
@@ -78,11 +78,24 @@ Bromite userscript (isolated world, per-site adapters, localStorage cache)
|
||||
1. **Site adapters** — one per host, `detect(location, document)` returns page `type` + IDs. Identify type/IDs from **URL regex** (most stable); pull `title`/`cover` from **`og:title`/`og:image` meta tags**, not CSS classes.
|
||||
2. **API client** — `apiGet/apiPut/apiDelete` with bearer header; `localStorage` key `mangabm:cache` for instant render + offline fallback.
|
||||
3. **Progress logic** — auto-upsert `last_chapter` only when `chapterNum >= stored last_chapter_num` (re-reading old chapters must not regress progress; unparseable -> set current). Manual panel override forces any value.
|
||||
4. **UI** — rendered inside a **Shadow DOM** root to isolate from site CSS
|
||||
4. **Retry queue** — every write goes through `pushBookmark`/`pushDelete`, so a
|
||||
failed mutation is parked in `localStorage` (`mangabm:queue`) and replayed on
|
||||
the next navigation, reconnect, or `refresh()`. Entries are markers
|
||||
(`{key, op, sendStatus, attempts}`), never payloads — the body is read from
|
||||
the cache at send time, so one entry per key gives ordering and coalescing for
|
||||
free. `sendStatus` is **sticky**: while an archive is pending, later writes to
|
||||
that key keep carrying the bucket, which is what stops a successful
|
||||
in-between write from silently un-archiving the series. `refresh()` drains
|
||||
before it fetches and overlays anything still pending, so the list never
|
||||
flaps. A 400 drops the entry, a 401 aborts the pass and keeps the queue, and
|
||||
transient failures retry to a cap of 10. Latest-chapter writes deliberately
|
||||
stay out of the queue. See
|
||||
`docs/superpowers/specs/2026-07-27-offline-retry-queue-design.md`.
|
||||
5. **UI** — rendered inside a **Shadow DOM** root to isolate from site CSS
|
||||
(critical on mobile). Three tabs (All / Favourites / Archived) and a row of
|
||||
link chips to the web UI and both manga sites; `WEB_BASE` sits in the CONFIG
|
||||
block next to `API_BASE`.
|
||||
5. **SPA navigation** — Asura is Astro, client-routed on the comic/chapter pages: patch `history.pushState`/`replaceState` + listen `popstate`, re-run `detect()` on URL change so auto-update fires without reload. Demonic uses classic reloads (initial `document-idle` run suffices).
|
||||
6. **SPA navigation** — Asura is Astro, client-routed on the comic/chapter pages: patch `history.pushState`/`replaceState` + listen `popstate`, re-run `detect()` on URL change so auto-update fires without reload. Demonic uses classic reloads (initial `document-idle` run suffices).
|
||||
|
||||
### Live URL shapes (verified 2026-07-26, may drift — re-check against live pages before trusting)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Manga Bookmark Sync
|
||||
// @namespace mangabm
|
||||
// @version 1.3.0
|
||||
// @version 1.4.0
|
||||
// @description Track read progress on Asura & Demonic and sync to a self-hosted backend. Bromite-compatible (no GM_* APIs).
|
||||
// @author you
|
||||
// @match https://asuracomic.net/*
|
||||
|
||||
Reference in New Issue
Block a user