diff --git a/main.lua b/main.lua index fb9d717..2faac39 100644 --- a/main.lua +++ b/main.lua @@ -827,19 +827,21 @@ function Bookhoard:collectAnnotations() if not all_bookmarks then return bookmarks, highlights, notes end - local file_sha256 = self:getFileSHA256() local total_pages = self.ui.document:getPageCount() + local has_pages = self.ui.document.info.has_pages for _, bm in ipairs(all_bookmarks) do - local page_num = bm.page - if type(page_num) == "string" and self.ui.document.info.has_pages == false then - page_num = self.ui.document:getPageFromXPointer(page_num) - end - page_num = tonumber(page_num) or 0 + -- Thin-client policy: no per-annotation CRE lookups here (a + -- getPageFromXPointer call each is the most expensive thing this + -- loop can do on weak hardware). Percentages are arithmetic for + -- paging documents and simply omitted for CRE documents — the + -- server derives them from the locator against the actual book. + local page_num = tonumber(bm.page) or 0 + local percentage = has_pages and total_pages > 0 and (page_num / total_pages) or nil - local percentage = total_pages > 0 and (page_num / total_pages) or 0 local chapter = bm.chapter or "" + if type(chapter) == "table" then chapter = "" end local entry = { chapter = chapter, @@ -849,9 +851,11 @@ function Bookhoard:collectAnnotations() pos1 = bm.pos1 or "", page = tostring(bm.page or ""), text = bm.text or "", - percentage = Math.roundPercent(percentage), book_sha256 = file_sha256, } + if percentage then + entry.percentage = Math.roundPercent(percentage) + end local has_text = bm.text and bm.text ~= "" local has_notes = bm.notes and bm.notes ~= "" @@ -1159,9 +1163,23 @@ function Bookhoard:applyServerAnnotations(annotations) return pos0 end + local function isValidPos0(pos0) + -- Rolling (CRE) documents address bookmarks/highlights by xpointer; + -- paging documents (PDF/comics/DjVu) by page number. Anything else + -- (a raw "cfi:" locator, an epubcfi(...) string, a JSON anchor, …) + -- cannot be placed in this document and must not become a local + -- bookmark: it could never be matched again and would be re-pushed + -- to the server as a junk duplicate on the next sync. + if pos0 == "" then return false end + if has_pages then + return tonumber(pos0) ~= nil + end + return pos0:sub(1, 7) == "/body/" + end + local function addOrUpdate(server_entry, has_text) local pos0 = server_entry.pos0 or "" - if pos0 == "" then return end + if not isValidPos0(pos0) then return end local idx = findLocalByPos0(pos0) if idx then local bm = local_bms[idx]