Reading progress sync: push EPUB progress to Kavita #8
Loading…
Reference in a new issue
No description provided.
Delete branch "refs/pull/8/head"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Pushes EPUB reading progress from the device to Kavita, automatically when the app opens and on demand via a Sync button.
Design spec: docs/superpowers/specs/2026-07-15-progress-sync-design.md
Scope (locked with Richard)
Structure
core/DeviceReadingDb— real sqlite3, host-tested against a temp DB built in the test. The join to books_settings is a LEFT join: a loaded-but-never-opened book has no row and must read as zeros, not vanish.core/SyncEngine— pure. Takes a candidate, returns Push or Skip. No sqlite, no HTTP, no inkview.core/KavitaClient— getProgress / setProgress.main.cpp— executes actions.Two bugs the live verification caught
The plan required verifying Kavita's PageNum convention before shipping rather than assuming it. Doing so confirmed the design was right (pageNum == chapter.pages means finished) but found the client was non-functional in two ways, both silent:
Neither was reachable by a unit test: the fakes faithfully replayed the shape we believed in, so green tests measured our belief rather than Kavita. Both came from endpoint notes that were simply wrong. Confirmed against Kavita's source (Kavita.Server/Controllers/ReaderController.cs, Kavita.Models/DTOs/Progress/ProgressDto.cs).
Not guessing which book a filename means
A filename can match more than one Kavita chapter, and first-match-wins could mark a never-downloaded book as read. Ambiguous matches are skipped. This was not hypothetical: at the time it was written, the only book on the device matched two chapters of the same series.
Verification
83 host tests, clean cross-build.
End-to-end on device, against the live server: device at page 10/102 of Ikigai (9.8%); Kavita gives that chapter 22 pages; SyncEngine computed round(10/102*22) = 2; Kavita now holds pageNum 2 with libraryId 4 recorded. Sync before reading correctly reported "Nothing to sync".