John O'Keefe d584f17092 fix(sync): bail out of deferred sync tasks when the document is gone
Every push and pull runs deferred — updateProgress and getProgress hand
their work to UIManager:scheduleIn(0.5), and API replies are consumed in
UIManager:nextTick closures — so by the time the task runs, the ReaderUI
may have released its document (close/teardown race) or a slow async
load may not have attached it yet (the CRE full-render window: "cached
rendering is invalid" leaves the reader document-less for seconds on
big EPUBs). The task then dereferenced self.ui.document unguarded and
the unhandled error inside a UIManager task killed the whole app:

    main.lua:846: attempt to index field 'document' (a nil value)

    ...in function 'collectBookData'
    ...in function '_doUpdateProgress'
    ...in function 'action' (uimanager _checkTasks)

Observed as a hard crash on the auto-push (pages_before_update = 2)
right after opening an EPUB that needed a full re-render.

getBookhoardUUID and getContextText already nil-guarded their document
access; the task entry points never did. Guard them:

- _doUpdateProgress: bail before collectBookData — the single choke
  point for every push source (periodic, close, suspend, menu, the
  legacy bootstrap push), so one guard covers the whole class
- _doGetProgress: bail at entry, and re-validate first thing inside the
  nextTick closure (its body and applyServerAnnotations touch
  document.info long after the request was issued)
- getFileSHA256: return nil instead of indexing doc_settings/document
  (all callers already handle nil)

No sync-payload or endpoint changes; server behavior untouched.
2026-09-19 10:35:48 -04:00
2026-05-29 20:42:10 -04:00

Bookhoard KOReader Plugin

Sync your reading progress, bookmarks, highlights, and notes between KOReader and your Bookhoard server.

Features

  • Reading progress sync — push/pull progress across all your KOReader devices
  • Annotation sync — bookmarks, highlights, and notes
  • In-plugin device registration — no need to type long tokens on an e-ink screen
  • Configurable sync behavior — silent, prompt, or disable for forward/backward progress
  • OPDS catalog helper — quickly set up wireless book browsing/downloading
  • Offline tolerant — syncs when connectivity is available

Requirements

  • KOReader 2024.01 or later
  • A running Bookhoard server accessible from your device (local network or public URL)

Installation

Copy the bookhoard.koplugin/ directory into KOReader's plugin folder on your device:

Kindle:

/mnt/us/koreader/plugins/bookhoard.koplugin/

Kobo:

/.adds/koreader/plugins/bookhoard.koplugin/

PocketBook:

/applications/koreader/plugins/bookhoard.koplugin/

Alternatively, clone this repo directly into the plugins directory:

git clone <repo-url> /path/to/koreader/plugins/bookhoard.koplugin

Restart KOReader after installation.

Setup

1. Configure server URL

Open KOReader → menu (≡) → Tools → Bookhoard sync → Server URL

Enter your Bookhoard server address (e.g. http://192.168.1.100:8765).

2. Register your device

Tap Register device in the plugin menu. The plugin will display an approval URL. Open that URL on your phone or computer, log in to Bookhoard, and approve the device. The plugin polls automatically and completes registration within a few seconds of approval.

3. Enable auto sync (optional)

Toggle Automatically keep documents in sync in the plugin menu. This will sync progress on page turns, document close, suspend/resume, and network changes.

Note: On most devices, you should set Network → Action when Wi-Fi is off to turn on for auto sync to work without constant WiFi prompts.

Usage

Reading progress

Progress syncs automatically when auto sync is enabled. You can also manually:

  • Push progress — upload your current position to the server
  • Pull progress — download the latest position from the server
  • Sync now — push and pull in one action

Annotations

Bookmarks, highlights, and notes are synced when you close a document. Enable/disable each type in What to sync in the plugin menu.

OPDS catalog (wireless book delivery)

Tap Setup OPDS catalog in the plugin menu to get your OPDS URL. Add it as an OPDS catalog in KOReader's home screen (+ → OPDS Catalog) to browse and download books wirelessly from your Bookhoard library.

Sync behavior

Configure how the plugin handles progress conflicts:

  • Sync to a newer state — what to do when the server has a later position (silent/prompt/never)
  • Sync to an older state — what to do when the server has an earlier position (silent/prompt/never)

File structure

bookhoard.koplugin/
├── _meta.lua              Plugin metadata
├── main.lua               Plugin logic, events, menu
└── BookhoardAPI.lua       HTTP client for Bookhoard API

How it works

  1. The plugin hooks into KOReader's reader events (page turn, document open/close, suspend/resume)
  2. On push, it collects progress data (percentage, xpointer, page, chapter) and annotations, then sends them to the Bookhoard API
  3. On pull, it fetches the latest progress from the server and navigates to that position
  4. Book matching uses SHA-256 hashing (primary), file path, and title/author — the server handles all conflict resolution

License

Same as Bookhoard.

S
Description
No description provided
Readme
560 KiB
Languages
Lua 100%