feat(sync): add full sync option for annotations in koplugin, closes #3710 (#3718)
Some checks are pending
PR checks / rust_lint (push) Waiting to run
PR checks / build_web_app (push) Waiting to run
PR checks / build_tauri_app (push) Waiting to run
Deploy to vercel on merge / build_and_deploy (push) Waiting to run

Add "Full sync all annotations" menu item that pushes and pulls all
annotations regardless of the last sync timestamp, enabling users to
sync old highlights that were created before the plugin was installed.

Changes:
- Add full_sync parameter to push/pull that bypasses timestamp filter
  and uses since=0 for pulling all server annotations
- Deduplicate by annotation ID alongside position-based dedup
- Store server ID on pulled annotations and reuse it when pushing
- Parse ISO 8601 timestamps from server to preserve original
  created/updated dates instead of using current time
- Resolve KOReader page numbers from xpointers via getPageFromXPointer
- Resolve Readest page numbers from CFI via getCFIProgress on pull

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Huang Xin 2026-04-01 21:35:48 +08:00 committed by GitHub
parent 74401fc1bb
commit b8ddb5475e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 94 additions and 23 deletions

View file

@ -137,6 +137,15 @@ function ReadestSync:addToMainMenu(menu_items)
callback = function()
self:pullBookNotes(true)
end,
},
{
text = _("Full sync all annotations"),
enabled_func = function()
return self.settings.access_token ~= nil and self.ui.document ~= nil
end,
callback = function()
self:fullSyncBookNotes()
end,
separator = true,
},
{
@ -227,22 +236,22 @@ end
-- ── Annotation sync ────────────────────────────────────────────────
function ReadestSync:pushBookNotes(interactive)
if interactive and NetworkMgr:willRerunWhenOnline(function() self:pushBookNotes(interactive) end) then
function ReadestSync:pushBookNotes(interactive, full_sync)
if interactive and NetworkMgr:willRerunWhenOnline(function() self:pushBookNotes(interactive, full_sync) end) then
return
end
local client = self:ensureClient(interactive)
if not client then return end
SyncAnnotations:push(self.ui, self.settings, client, interactive)
SyncAnnotations:push(self.ui, self.settings, client, interactive, full_sync)
end
function ReadestSync:pullBookNotes(interactive)
function ReadestSync:pullBookNotes(interactive, full_sync)
local book_hash, meta_hash = self:getBookIdentifiers()
if not book_hash or not meta_hash then return end
if NetworkMgr:willRerunWhenOnline(function() self:pullBookNotes(interactive) end) then
if NetworkMgr:willRerunWhenOnline(function() self:pullBookNotes(interactive, full_sync) end) then
return
end
@ -250,10 +259,16 @@ function ReadestSync:pullBookNotes(interactive)
if not client then return end
SyncAnnotations:pull(
self.ui, self.settings, client, book_hash, meta_hash, self.dialog, interactive
self.ui, self.settings, client, book_hash, meta_hash, self.dialog, interactive, full_sync
)
end
function ReadestSync:fullSyncBookNotes()
-- Push all annotations first, then pull all
self:pushBookNotes(true, true)
self:pullBookNotes(true, true)
end
-- ── Event handlers ─────────────────────────────────────────────────
function ReadestSync:onReadestSyncToggleAutoSync(toggle)