Fork of Readest Android (v0.11.18) with native BookOrbit sync built in — reading position, sessions/stats, two-way highlights and book status sync to a self-hosted BookOrbit instance. Ports the BookOrbit KOReader plugin into Readest's TypeScript codebase.
  • TypeScript 80.5%
  • MDX 8%
  • Lua 3.5%
  • Rust 3.2%
  • Swift 1.3%
  • Other 3.3%
Find a file
jontstaz f51b7876c0
Some checks failed
Android Production Release / build-android (release) Failing after 30m53s
Merge remote-tracking branch 'upstream/main'
Notable: upstream merged its own official BookOrbit integration (#5487).
Kept the fork's BookOrbit implementation (bookorbit service, form,
useBookOrbit hook, provision-file import) since it has fork-specific
features; upstream's notes-sync engine files (annotationExchange,
notesPass, BookOrbitSyncStore...) land alongside as new shared modules.
Both hooks mount in FoliateViewer — fork's useBookOrbit plus upstream's
bookOrbitProgressProvider via useKOSync.

- Kept .github/workflows deleted (Forgejo migration)
- Kept fork README
- Kept fork BookOrbitForm/BookOrbitClient/types/constants (ours)
- IntegrationsPanel, BooknoteItem: took upstream (supersede fork tweaks)
- Submodules foliate-js, tao advanced to upstream pins
2026-08-13 21:17:03 +10:00
.devcontainer fix(docker): fix Docker image latest tag and production runtime errors; add dev compose file, Codespace support, and semver release tagging (#7) (#4277) 2026-05-23 10:39:15 +08:00
.forgejo/workflows fix(ci): sign releases with persistent keystore from secrets 2026-07-29 16:07:27 +10:00
.github chore(deps): bump the github-actions group with 6 updates (#5668) 2026-08-13 07:16:18 +02:00
.husky feat(send): Send to Readest — multi-channel capture into your library (#4230) 2026-05-19 20:06:52 +02:00
.vscode chore: switch code formatter from Prettier to Biome (#4223) 2026-05-19 08:13:36 +02:00
.zed chore: enable setting to let vstls report on the entire codebase (#5098) 2026-07-14 03:50:07 +02:00
apps Merge remote-tracking branch 'upstream/main' 2026-08-13 21:17:03 +10:00
data release: version 0.12.1 (#5581) 2026-08-08 19:02:59 +02:00
docker fix(docker): apply db migrations on first boot and let the font CDN be overridden (#5550) (#5551) 2026-08-07 10:19:44 +02:00
fastlane chore(store): replace Play listing images instead of appending (#5574) 2026-08-08 08:25:22 +02:00
ops fix: install playwright browsers in nix flake (#5454) 2026-08-03 05:29:15 +02:00
packages fix(reader): stop iOS 16 WebContent crash when opening a book (#5654) 2026-08-12 18:16:48 +02:00
patches chore(deps): bump Next.js to version 16.2.6 (#4143) 2026-05-13 10:57:06 +02:00
.dockerignore ci: optimize build time for Docker and CI workflows (#4263) 2026-05-22 18:43:33 +02:00
.editorconfig dev: add editorconfig (#206) 2025-01-21 07:18:00 +01:00
.gitignore Merge remote-tracking branch 'upstream/main' 2026-08-13 21:17:03 +10:00
.gitmodules feat(ios): CarPlay support and native TTS playout with Now Playing integration (#5085) 2026-07-13 10:53:31 +02:00
biome.json fix(nix): get nix devshell working (#4883) 2026-07-04 12:56:21 +02:00
Cargo.lock fix(localsend): let Readest devices discover each other (#5626) 2026-08-11 11:50:00 +02:00
Cargo.toml feat(ios): CarPlay support and native TTS playout with Now Playing integration (#5085) 2026-07-13 10:53:31 +02:00
CONTRIBUTING.md chore: migrate away from numtide devshell (#5131) 2026-07-24 16:53:40 +02:00
Dockerfile build(web): standalone Docker image + drop Turbopack build cache (#4619) 2026-06-16 21:21:24 +02:00
LICENSE Add AGPLv3 license 2024-11-11 21:25:22 +01:00
package.json fix(reader): scroll oversized blocks in-place instead of turning the page (#4400) (#4415) 2026-06-02 14:45:18 +02:00
pnpm-lock.yaml feat(reader): render math in annotation notes (#5571) 2026-08-08 08:26:40 +02:00
pnpm-workspace.yaml chore(deps): bump transitive dependencies for security advisories (#5518) 2026-08-05 17:23:28 +02:00
README.md docs(readme): revert the Sponsors / TestMu AI section 2026-08-10 21:00:04 +02:00
SECURITY.md docs: add threat model and incident response plan to SECURITY.md (#3788) 2026-04-07 19:17:56 +02:00
tsconfig.json chore: enforce prettier, ignore submodules and vendor files (#3018) 2026-01-21 14:53:02 +01:00

Readest for BookOrbit

A fork of Readest (v0.11.18) with native BookOrbit sync built in — reading position, reading sessions/stats, two-way highlights, and book status all flow between Readest and your self-hosted BookOrbit instance, no KOReader required.

Platform Readest BookOrbit Server License


Why this fork exists

BookOrbit ships an official KOReader plugin (bookorbit.koplugin, Lua) that syncs progress, reading sessions, highlights and book status. Readest is a Next.js + Tauri ebook reader — it has no Lua runtime, so the KOReader plugin cannot be loaded into it. It does ship a KOSync client, which gets you reading position only against BookOrbit's kosync-compatible endpoints.

This fork ports the BookOrbit plugin's behaviour into Readest's TypeScript codebase, so the full sync feature set works natively in Readest on Android — without needing KOReader installed alongside it.

Sync feature Stock Readest + KOSync This fork
Reading position (kosync-compatible)
Reading sessions / page-read events (Reading Log)
Two-way highlights & notes
Book status (reading / finished / …)
OPDS catalog browse + download (built-in)

Download

Pre-built, signed APK for Android (arm64-v8a):

Builds for other arches / platforms aren't produced here. If you need x86_64 / armv7 / iOS / desktop, build from source (below) — the BookOrbit integration code is platform-agnostic.

Set up sync in the app

  1. Install the APK (enable "Install unknown apps" for your file manager when prompted).
  2. Add your BookOrbit OPDS library: Settings → OPDS Catalogs → Add, point it at https://<your-bookorbit>/opds/{token} (same as you'd do in stock Readest). Browse and download books.
  3. Open Settings → Integrations → BookOrbit and configure:
    • Server URL: https://<your-bookorbit-host>
    • Username / Password: your BookOrbit web login
    • (or tap Import provision and pick the bookorbit_provision.lua you downloaded from BookOrbit's web settings — it pre-fills server/user/key, you just enter the password)
  4. Toggle which of the four sync types you want (all on by default).

Sync is then fully automatic:

  • On open → match-check registers the book with BookOrbit, pulls remote position + highlights.
  • While reading → reading position auto-pushes ~5s after each page turn (debounced); reading time is recorded locally as page-stat events.
  • On close → full snapshot sync uploads progress + reading sessions + highlights + book status to BookOrbit.

How books match

Readest's Book.hash is the partial MD5 of the file — identical to KOReader's book identity — so books downloaded via BookOrbit's OPDS catalog match their library entries on BookOrbit automatically. Highlight identity uses the same md5(datetime|pos0) key as the KOReader plugin, so highlights round-trip across KOReader, Readest and the BookOrbit web reader.

Scope & limitations (v1)

  • Reading status syncs (unread / reading / finished / abandoned). Readest has no native rating field, so ratings are not pushed from Readest.
  • Two-way highlights: Readest pushes its set and applies remote adds/edits (anchored via XPointer → CFI). Readest will not delete a local highlight based on a server signal (safe default); deletions made in Readest do propagate up.
  • Self-signed APK: install updates only from builds signed with the same key as the one in this repo. The signing keystore is not committed; rebuilds you make locally will need an uninstall first (see APK Signing).

Building from source

Prerequisites

  • Node 20+ / pnpm 11+ / Rust (stable) / Java 21 (JDK)
  • Android SDK (API 36 + Build-Tools 35) and NDK r27b
  • ~6 GB free for toolchain + build artifacts

One-time setup

git submodule update --init --recursive
pnpm install --ignore-scripts          # sharp fails to build from source; not needed for the APK

# Build the wasm vendors (simplecc, jieba) — only once per checkout
cd packages/simplecc-wasm
  make generate-dicts                  # builds the OpenCC dictionaries simplecc embeds
  npm run build:cargo                  # cargo build --release --target wasm32-unknown-unknown
  wasm-bindgen target/wasm32-unknown-unknown/release/simplecc_wasm.wasm \
    --out-dir ./pkg/web --target web
  mkdir -p dist/web && cp pkg/web/* dist/web/
cd -
cd apps/readest-app && pnpm setup-vendors   # stages pdfjs + simplecc + jieba into public/vendor

Environment

export ANDROID_HOME=$HOME/Android/sdk          # writable SDK root (needs platform-36, build-tools;35)
export ANDROID_SDK_ROOT=$ANDROID_HOME
export NDK_HOME=$HOME/Android/ndk/android-ndk-r27b
export ANDROID_NDK_HOME=$NDK_HOME
export ANDROID_NDK_ROOT=$NDK_HOME
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
export PATH=$JAVA_HOME/bin:$ANDROID_HOME/platform-tools:$PATH

Build the APK

cd apps/readest-app
pnpm exec tauri android init              # one-time; generates gen/android + gradle wrapper
# After init, patch the generated launcher icon (workaround for upstream tauri-cli quirk):
#   gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
#     @color/ic_launcher_background  ->  @drawable/ic_launcher_background
pnpm exec tauri android build -t aarch64

The unsigned APK lands at: apps/readest-app/src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release-unsigned.apk

APK signing

Android won't install an unsigned APK. Generate a keystore once and reuse it for every build (so updates install over the existing app without an uninstall):

BT=$ANDROID_HOME/build-tools/35.0.0
keytool -genkeypair -keystore ~/readest-bookorbit.jks -alias readest \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -storepass readest123 -keypass readest123 \
  -dname "CN=Readest BookOrbit, O=Self-signed, C=AU"

$BT/zipalign -p -f 4 app-universal-release-unsigned.apk app-aligned.apk
$BT/apksigner sign --ks ~/readest-bookorbit.jks --ks-pass pass:readest123 \
  --key-pass pass:readest123 --out Readest-BookOrbit-arm64.apk app-aligned.apk
$BT/apksigner verify Readest-BookOrbit-arm64.apk

Keep your keystore safe. Anyone with ~/readest-bookorbit.jks can sign APKs that install as updates over yours.

Where the BookOrbit integration lives

apps/readest-app/src/
├── services/bookorbit/
│   ├── BookOrbitClient.ts        # HTTP client (port of bookorbit_api.lua)
│   ├── types.ts                  # BookOrbit wire formats
│   ├── pageStats.ts              # build page-stats payload from Readest's stats DB
│   ├── annotations.ts            # two-way highlight mapping
│   ├── bookStates.ts             # book status → wire format
│   └── provision.ts              # parse bookorbit_provision.lua without a Lua runtime
├── types/settings.ts             # BookOrbitSettings type
├── services/constants.ts         # DEFAULT_BOOKORBIT_SETTINGS
├── components/settings/integrations/
│   └── BookOrbitForm.tsx         # the Integrations → BookOrbit sub-page
├── components/settings/
│   └── IntegrationsPanel.tsx     # adds the BookOrbit row
└── app/reader/hooks/
    └── useBookOrbit.ts           # per-book sync lifecycle (match / pull / push / exchange)

The original BookOrbit KOReader plugin source is kept under ref/bookorbit.koplugin/ for reference while porting.

Compatibility

Component Tested with
BookOrbit server v2.2.0 (plugin protocol 1.2.0)
Readest upstream v0.11.18
Android arm64-v8a, API 26+

Credits

  • Readest — by Bilingify and contributors, licensed AGPL-3.0. This fork is a derivative and remains AGPL-3.0.
  • BookOrbit — self-hostable ebook library + reading-stats platform; its KOReader plugin (bookorbit.koplugin) was the reference implementation this port was written against.

License

AGPL-3.0 — same as upstream Readest. See LICENSE.