Skip to content
dgreen52Public

About

Reading companion for Archive of Our Own - themes, resume position, content filters, private library, and EPUB export via a from-scratch in-browser EPUB builder.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

Ribbon — a reading companion for AO3

A polished Chrome (Manifest V3) extension for readers on Archive of Our Own. Resume where you left off, theme the reader to taste, mute tropes you don't want to see, and keep a private library with notes. Everything is stored on-device.

Unaffiliated with AO3 / the Organization for Transformative Works.


Why this niche

AO3 has millions of devoted daily readers who already mod the site with fragile, technical userscripts (AO3 Savior, reader tweaks, etc.) — proven appetite for tooling, but no polished, one-click, freemium extension occupying that slot. The audience is sticky and passionate, the problems are recurring, and every feature here runs client-side, so there's no server to host and no per-user cost. That's the combination the 2026 extension market rewards: narrow audience, real pain, near-zero marginal cost, freemium Pro.

Features

Free

  • Resume reading — remembers your scroll position per work/chapter and offers to jump back in.
  • Reading themes — Paper / Sepia / Dusk / Midnight, plus typeface, text size, line spacing, and line width controls. Applied live.
  • Accurate reading time in the corner toolbar.
  • Progress bar across the top of long chapters.
  • NSFW filter — a one-click toggle that redacts a built-in list of slurs and SA/abuse trigger words (in the summary, notes and prose) to a solid bar. Click a bar to reveal (handles false positives like "Maine Coon"); passive reading never reveals. Toggles live.

Pro

  • Library with private notes — save works, set status (To read / Reading / Finished), jot notes, search and sort. Backup and restore via JSON.
  • Mute filters — hide works on any listing by tag/trope, fandom, or author, with * wildcards. Nothing is deleted — muted works collapse to a "hidden because…" row with a Show anyway link. Edits apply live (no reload).
  • Word masking — your own custom list, replaced with **** across the summary, notes and prose. Click a masked word to reveal it. Reversible/live.
  • Highlighter — select any passage and highlight it; highlights persist across reloads/closures, and "resume" jumps straight to your most recent one — a manual bookmark that's exactly where you stopped. Click a highlight to remove.
  • EPUB export — download any work as a valid (XHTML-clean) EPUB, built entirely in the browser.

Install (load unpacked)

  1. Open chrome://extensions.
  2. Toggle Developer mode (top right).
  3. Click Load unpacked and select this folder (Exte).
  4. Visit any work on https://archiveofourown.org and look bottom-right.

Pro, the trial, and pricing

Pro is sold through ExtensionPay (extension id ribbon-ao3), which handles Stripe checkout, receipts, and paid-status sync — no server of our own.

  • Model (Option 1): free tier forever + 1-month free Pro trial + $4.99 one-time to keep Pro. Set in src/lib/licensing.js: TRIAL_DAYS = 30, GATE_EVERYTHING = false.
  • Switch to Option 2 (whole extension paywalled after the trial) by setting GATE_EVERYTHING = true — that's the only change needed.
  • From the popup: Start 1-month free trial or Get Pro — $4.99. During the trial the popup shows days remaining.

Testing without paying: use ExtensionPay test mode (test Stripe card 4242 4242 4242 4242) — start a trial or "buy" and Pro unlocks with no real charge. There is intentionally no offline license-key path, so there's no free-Pro backdoor in the shipped code.

Pricing/products are configured in your ExtensionPay dashboard — set the one-time price to $4.99 and enable the free trial there to match the in-app copy.

How the money layer works

The Pro gate lives in src/lib/licensing.js and is backed by ExtensionPay:

  • isPro() is the single gate the whole app asks. It returns true if the user is paid, within the 1-month trial (trialStartedAt + TRIAL_DAYS), or has a valid offline dev key.
  • status() powers the popup (paid / on-trial / days-left).
  • openTrialPage() / openPaymentPage() hand off to ExtensionPay's hosted Stripe pages. onPaid() unlocks open tabs instantly after purchase.
  • The service worker runs extpay.startBackground() so paid status syncs across the popup, content scripts, and library page.

Because ExtensionPay tracks status per account on their server, you get real enforcement: seat limits, revocation, refunds, and trial expiry are handled for you — none of the "a client-side key can't be revoked" problem. The offline checksum keys remain only as a dev/comp convenience and are clearly secondary.

Setup checklist (mostly done):

  1. ✅ ExtPay SDK vendored at src/lib/ExtPay.js, wired into background, popup, content scripts, and library.
  2. ✅ Extension id ribbon-ao3 set in licensing.js.
  3. ⬜ In your ExtensionPay dashboard: connect Stripe, set the product to a $4.99 one-time purchase, and enable a free trial.

Project layout

manifest.json            MV3 manifest
src/background.js         service worker (seeds defaults, opens library)
src/lib/
  ao3.js                 read-only AO3 DOM parsing (the one file to fix if AO3 changes markup)
  storage.js             chrome.storage wrapper + data shape
  licensing.js           the Pro gate (ExtensionPay + trial + offline dev keys)
  ExtPay.js              vendored ExtensionPay SDK (do not edit)
  epub.js                in-browser EPUB builder + tiny STORE-only ZIP writer
src/content/
  reader.js / reader.css the on-page experience (theme, progress, toolbar, highlighter, masking)
  blocklist.js           Pro mute filters on listing pages
src/popup/               settings + Pro unlock UI
src/library/             the saved-works dashboard (Pro)
icons/                   16/48/128 px

Notes for maintainers

  • AO3 markup is the one fragile dependency. If a feature breaks after an AO3 redesign, the selectors are centralized in src/lib/ao3.js.
  • The only network calls are ExtensionPay's (to extensionpay.com, for paid status/checkout). No analytics, no other remote code. Permissions are storage + the AO3 and extensionpay.com hosts — keep this in mind for the Web Store privacy disclosure.

About

Reading companion for Archive of Our Own - themes, resume position, content filters, private library, and EPUB export via a from-scratch in-browser EPUB builder.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages