Userscript
Single file: userscript/manga-bookmark.user.js. One IIFE, no GM_* APIs, so
it runs unchanged in Bromite's native engine and in desktop
Tampermonkey/Violentmonkey for fast iteration.
Structure
- Site adapters — one per host.
detect(location, document)returns pagetype+ IDs, keyed off URL regex (most stable signal).title/covercome fromog:title/og:imagemeta tags, not CSS classes. - API client —
apiGet/apiPut/apiDeletewith bearer header.localStoragekeymangabm:cachegives instant render + offline fallback. - Progress logic — auto-upserts
last_chapteronly whenchapterNum >= stored last_chapter_num(re-reading old chapters never regresses progress; an unparseable number just sets the current chapter). Manual panel override forces any value regardless. - UI — rendered inside a Shadow DOM root, isolating it from site CSS (critical on mobile where site styles are unpredictable).
- SPA navigation — Asura is Astro, client-routed on comic/chapter pages:
the script patches
history.pushState/replaceStateand listenspopstate, re-runningdetect()on URL change so auto-update fires without a full reload. Demonic does classic reloads, so an initialdocument-idlerun is enough there.
Config
Edit the block at the top of the file:
const API_BASE = "https://manga-api.<domain>"; // no trailing slash
const API_TOKEN = "<same token as backend's API_TOKEN>";
The token lives in the userscript's isolated world — the manga sites' own JS cannot read it.
Site adapter reference (verified live 2026-07-24)
| Site | Series URL | Chapter URL | series_id |
|---|---|---|---|
Asura (asurascans.com) |
/comics/<slug-hash> |
/comics/<slug-hash>/chapter/<n> |
<slug-hash> |
Demonic (demonicscans.org) |
/manga/<slug> |
/title/<slug>/chapter/<n>/<page> (chaptered.php?manga=<id>&chapter=<n> 301s here) |
<slug> |
Notes:
asuracomic.netdeep links 301 to the root ofasurascans.com, discarding the path — dead end, useasurascans.comdirectly. The host stays in@matchin case the redirect starts preserving paths again.- Asura
og:titlehas aChapter N - Read Online | Asura Scanssuffix the adapter strips; Demonic chapterog:titleis<Title> Chapter N. - Demonic's
<slug>is identical on/manga/…and the canonical/title/…reader, so a bookmark set from the series page and an auto-update from the reader resolve to the same key. - If either site changes its URL shape, update the regex in that site's adapter and re-verify against a live page before trusting it.
Install on Bromite (mobile)
- Bromite → Settings → User scripts → enable (accept the permission prompt).
- Save the configured
manga-bookmark.user.jsto the device (or open its raw URL) — Bromite detects.user.jsand offers to install. - Confirm install; the
@matchlist covers both sites. - Open a series on either site — a 📑 button appears bottom-right.
Menu wording varies by Bromite build. If "User scripts" is absent, update Bromite or use a build that has it.
Day-to-day use
- Bookmark: panel → + Bookmark this.
- Auto-progress: opening a chapter of a bookmarked series records it when the chapter number is ≥ the stored one.
- Manual override: panel → Edit on any row forces a specific chapter.
- Continue: jumps to the last-read chapter (or the series page).
- Latest chapter: rows show
Read: … · Latest: …once the newest published chapter is known and ahead of your progress. - Favourites: ☆ toggles per row; ★ Favourites tab narrows the list. Favourited series still show under All. The flag syncs across devices; the chosen tab does not.
- Bookmarks made on one site appear when the panel opens on the other — the backend is the shared store.
- Neither favouriting nor a newly-learned chapter reorders the list — only reading progress does (see Backend-API).
- Offline / backend down: changes cache in
localStorage, retried on the next successful load (last-write-wins).
How "latest chapter" is found
Only a series page lists every chapter; the backend can't fetch either site itself (Cloudflare blocks server-side requests, no API/feed exists). So the userscript does the looking, from your own browser session:
- Opening a bookmarked series page records its newest chapter directly.
- Otherwise it background-fetches series pages — same-origin only, so
browsing Asura refreshes Asura bookmarks and vice versa. At most one series
check per navigation, at most one check per series every 4 hours
(
LATEST_CHECK_BATCH/LATEST_CHECK_THROTTLE_MS). Failures are silent, retried after the window.
Freshness (mangabm:lastchecked in localStorage) is per-device and
deliberately not synced — each device checks on its own. The backend also
runs its own independent poller (see Backend-API) so latest_chapter
stays fresh even when you aren't browsing.