Skip to content

feat(koplugin): bulk sync annotations#84

Merged
tku137 merged 23 commits into
GeorgeSG:masterfrom
tku137:bulk-sync
Feb 1, 2026
Merged

feat(koplugin): bulk sync annotations#84
tku137 merged 23 commits into
GeorgeSG:masterfrom
tku137:bulk-sync

Conversation

@tku137
Copy link
Copy Markdown
Collaborator

@tku137 tku137 commented Jan 11, 2026

This adds the possibility to bulk-sync annotations. It is probably a rarely used feature, I used it to have an initial sync of all book annotations without the need to open each book individually.

Unfortunately, getting annotations is only available for the currently opened book in koreaders api, see #79. Crawling the whole library directory for sidecar files would be pretty heavy. So in this PR, I use koreaders history api, which gives a list of books opened in the past. This includes read, reading, paused and so on books. So my thinking is: for a book to have highlights, it must have been opened at one point and thus is listed in the history.

Having a list of books from koreaders history, we then can loop over all these books and sync their annotations one by one.

Several improvements have been made along the way, for example:

  • only open docsettings once (instead of three times)
  • reduce function calling (extract common functions)
  • use md5 from sidecar files, no need to query the statistics database for the md5 value

@tku137
Copy link
Copy Markdown
Collaborator Author

tku137 commented Jan 11, 2026

Hm, need to look into why the test was failing. Not sure why any of the changes I made here affected ths.

@GeorgeSG
Copy link
Copy Markdown
Owner

The test is flaky :/ I hit this earlier this morning.

Comment thread plugins/koinsight.koplugin/annotation_reader.lua Outdated
@GeorgeSG
Copy link
Copy Markdown
Owner

@tku137 can we chat directly on another platform? Discord or something else?

@tku137
Copy link
Copy Markdown
Collaborator Author

tku137 commented Jan 11, 2026

@tku137 can we chat directly on another platform? Discord or something else?

Sure, I have a Discord account. I could send you a mail with my handle if you like? Or just send me an invite.

@GeorgeSG
Copy link
Copy Markdown
Owner

@tku137 can we chat directly on another platform? Discord or something else?

Sure, I have a Discord account. I could send you a mail with my handle if you like? Or just send me an invite.

Yup, perfect! Shoot an email at georgi@gar.dev

Comment thread plugins/koinsight.koplugin/annotation_reader.lua Outdated
@GeorgeSG
Copy link
Copy Markdown
Owner

The current sync method also bulk syncs all books, it just doesn't bulk sync with highlights, correct? I'm wondering if we should be keeping both of the syncs - seems kinda confusing. If this implementation bulk syncs all books with annotations, we can probably keep only that and remove the old one?

Also, maybe it's a nice idea to sync only the current book on suspend? So maybe it's worth implementing a "Sync current book" alongside "Sync all books with all highlights"?

…for bulk operations

There were too many requires inside functions all over the place. Also,
I saw a nicer Koreader API to get doc_settings. But I encountered an
error once, turns out that after rebooting KoReader, there is a chance
that ReaderUI is not yet there, failing requires at module level. I used
lazy loading, which seems to run just fine.

Its still nicer to require once, not for every function call, ESPECIALLY
during bulk sync!

This prevents crashes when requiring the module outside the reader,
preserves live in-memory settings during normal usage, and makes bulk
annotation reads safe and non-destructive.
@tku137
Copy link
Copy Markdown
Collaborator Author

tku137 commented Jan 21, 2026

The current sync method also bulk syncs all books, it just doesn't bulk sync with highlights, correct? I'm wondering if we should be keeping both of the syncs - seems kinda confusing. If this implementation bulk syncs all books with annotations, we can probably keep only that and remove the old one?

Also, maybe it's a nice idea to sync only the current book on suspend? So maybe it's worth implementing a "Sync current book" alongside "Sync all books with all highlights"?

This is an excellent idea. I think we should have a single "Synchronize data" button in the menu that syncs statistics (only available in bulk) and annotations in bulk, while keeping a "sync statistics as usual and annotations for opened book" version in the sync-on-suspend path.

I am still somehow worried about the performance of bulk-syncing annotations, but given how "bulky" a statistics sync already is and how basically instantaneous an annotations sync is, I guess even for a couple hundred books, this still is pretty fast, since we utilize the Koreader history of opened books without crawling through a huge library.

@coveralls
Copy link
Copy Markdown

coveralls commented Jan 21, 2026

Coverage Status

coverage: 53.944% (+0.3%) from 53.632%
when pulling 683c16a on tku137:bulk-sync
into 1eb7dcd on GeorgeSG:master.

…tistics in full sync

- rename sync functions for clarity: sync() → syncCurrentBook(), bulkSync() → syncAllBooks()
- merge "Bulk Sync All Books" into single "Synchronize data" menu option
- fix syncAllBooks() to include full statistics sync from database (was only syncing annotations)
- sync-on-suspend now explicitly use syncCurrentBook() for fast, targeted sync

Manual sync now properly syncs all statistics + all annotations.
Suspend sync remains fast, syncing all statistics + current book only.
I am unsure about the performance impact on syncing all anotations
actually is though...
@tku137 tku137 requested a review from GeorgeSG January 21, 2026 19:52
Copy link
Copy Markdown
Owner

@GeorgeSG GeorgeSG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again, this looks very good! Added some questions, this is more for my understanding of what's going on :D

Comment thread packages/common/types/book.ts Outdated
Comment thread plugins/koinsight.koplugin/annotation_reader.lua

if not book_md5 then
logger.warn("[KoInsight] Could not determine MD5 for current book, skipping annotations")
return annotations_by_book
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should return nil or {} to be sure this is hardcoded empty (just in case something somewhere pushes data to annotations_by_book.

Comment thread plugins/koinsight.koplugin/annotation_reader.lua
Comment thread plugins/koinsight.koplugin/main.lua
@GeorgeSG
Copy link
Copy Markdown
Owner

We should also probably bump the plugin version

@tku137
Copy link
Copy Markdown
Collaborator Author

tku137 commented Jan 30, 2026

Wrap up of recent decelopments:

Copy link
Copy Markdown
Owner

@GeorgeSG GeorgeSG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I won't get too lazy maintaining the changelog file, but looks good! 😅

Comment thread apps/server/src/upload/upload-service.ts Outdated
Comment thread packages/common/types/book.ts Outdated
@tku137 tku137 merged commit 86e740d into GeorgeSG:master Feb 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants