Files
readest/apps/readest-app/.claude/memory/MEMORY.md
T
Huang Xin 6b403d019e feat(calibre): add Readest calibre plugin to push books and metadata (#4918)
* feat(calibre): add Readest calibre plugin to push books and metadata (#4863)

Add apps/readest-calibre-plugin, a calibre GUI plugin that uploads
selected books with their metadata into the user's Readest cloud
library, modeled on BookFusion's open-source plugin.

- Selective manual push from the calibre toolbar with per-book status
  (uploaded / updated / up to date / failed) and quota handling
- Books are content-addressed with the same partial MD5 as the apps,
  so re-pushing updates the existing entry instead of duplicating;
  metadata edits re-push without re-uploading the file
- Metadata mapping includes series, tags, identifiers and optional
  calibre custom columns; carries over server-side fields (progress,
  reading status, grouping, cover) that POST /sync would null out
- Auth mirrors readest.koplugin and the desktop app: email/password
  plus browser OAuth (Google/Apple/GitHub/Discord) through a localhost
  callback server with the fragment-to-query relay
- Pure-logic modules (api.py, wire.py, oauth.py) are calibre-free and
  covered by 56 unit tests (make test); make zip builds the plugin

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(release): package readest-calibre-plugin in releases

Mirror the KOReader plugin packaging: a build-calibre-plugin job stamps
PLUGIN_VERSION in __init__.py with the release version from
apps/readest-app/package.json, builds the zip via make, and uploads
Readest-<version>.calibre-plugin.zip to the GitHub release. The version
committed in git stays a development placeholder.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(agent): add calibre plugin project memory

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(calibre): embed metadata in OPF and dedupe by calibre uuid

Rework book identity so metadata can be embedded into the uploaded file
without creating duplicates, as requested in review:

- Embed calibre metadata (including custom columns) into a temporary
  copy of the book file at upload time via calibre's set_metadata; the
  library file is never modified
- Dedupe by the calibre book uuid carried in the entry's metadata
  identifier, which survives file-byte changes, with a live-row
  preference when both hash and uuid match rows
- Detect file content changes via calibreSourceHash, the raw library
  file fingerprint stored in the pushed metadata, so detection works
  from any machine; v1 rows fall back to book_hash which equals the
  raw hash for them
- A changed file now replaces the old entry in one sync push (new row
  with carried-over reading status, grouping, progress and created
  date, plus a tombstone for the old row) and deletes the old cloud
  files to reclaim quota
- Metadata-only edits still update the library entry without
  re-uploading the file

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(calibre): set copyright holder to Bilingify LLC

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:40:16 +02:00

16 KiB
Raw Blame History

Readest Project Memory

Key Reference Documents (aggregators)

Safety & Security

Paginator & Scroll

Critical Files (Most Bug-Prone)

  • src/utils/style.ts EPUB CSS hub · packages/foliate-js/paginator.js layout/image/bg · src/services/tts/TTSController.ts TTS state machine
  • src/hooks/useSafeAreaInsets.ts insets · src/app/reader/components/FoliateViewer.tsx view orchestration · .../annotator/Annotator.tsx annotation lifecycle

Sync Notes

Build, Testing & CI

Platform Compat

Reader Features & UI

Library Fixes

Architecture & Patterns

  • foliate-js submodule at packages/foliate-js/; multiview paginator preloads adjacent sections
  • Markdown .md support (#774) — in-memory foliate book (no EPUB) in src/utils/md.ts;
  • Style: getLayoutStyles() always, getColorStyles() when overriding color; transformStylesheet() rewrites EPUB CSS at load
  • TTS independent section tracking (#ttsSectionIndex); safe insets: native plugin → useSafeAreaInsets → styles; Dropdowns DropdownContext
  • Stale settings closure: store-hook settings stale across await; persist useSettingsStore.getState().settings (#4780
  • Foliate touch-listener capture phase — suppress gestures via
  • iframe cross-realm instanceofinstanceof Element false; duck-type `'closest'
  • Virtuoso + OverlayScrollbars — useOverlayScrollbars for mobile webviews
  • Design system → DESIGN.md — never pl/pr/ml/mr/text-left/right (RTL)

Workflow & Feedback