From 7c15c8aa859f289f1374610e1077a179688a1a17 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Fri, 24 Apr 2026 15:35:56 +0200 Subject: [PATCH] Reestablish 1.37 upload behaviour --- .../koreader-sync-xpath-mapping.md | 12 ++++++---- lib/KOReaderSync/ProgressMapper.cpp | 23 ++++--------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/docs/contributing/koreader-sync-xpath-mapping.md b/docs/contributing/koreader-sync-xpath-mapping.md index f437dd6b..0c47a3b4 100644 --- a/docs/contributing/koreader-sync-xpath-mapping.md +++ b/docs/contributing/koreader-sync-xpath-mapping.md @@ -38,12 +38,16 @@ via a KOReader contributor mapping spine items to DocFragment numbers. Implemented in `ProgressMapper::toKOReader`. 1. Compute overall `percentage` from chapter/page. -2. If a paragraph index is available from the section cache LUT (`CrossPointPosition::hasParagraphIndex`), - generate an XPath directly: `/body/DocFragment[spineIndex + 1]/body/p[paragraphIndex]`. -3. Otherwise, attempt byte-offset estimation via `ChapterXPathIndexer::findXPathForProgress`. -4. If XPath extraction fails, fallback to synthetic chapter path: +2. Generate XPath via byte-offset estimation (`ChapterXPathIndexer::findXPathForProgress`), + producing a `…/text()[K].M` anchor proportional to intra-spine progress. +3. If XPath extraction fails, fallback to synthetic chapter path: - `/body/DocFragment[spineIndex + 1]/body` +The paragraph LUT (see below) is intentionally **not** used for upload: snapping to the +start of `p[N]` when the user is mid-paragraph causes pulled positions to land at the +start of the paragraph (and at the start of the chapter when an opening paragraph spans +many pages). The LUT remains in use for the reverse direction. + ### KOReader -> CrossPoint Implemented in `ProgressMapper::toCrossPoint`. diff --git a/lib/KOReaderSync/ProgressMapper.cpp b/lib/KOReaderSync/ProgressMapper.cpp index eaf7e7ea..b176485a 100644 --- a/lib/KOReaderSync/ProgressMapper.cpp +++ b/lib/KOReaderSync/ProgressMapper.cpp @@ -57,24 +57,11 @@ KOReaderPosition ProgressMapper::toKOReader(const std::shared_ptr& epub, c // Calculate overall book progress (0.0-1.0) result.percentage = epub->calculateProgress(pos.spineIndex, intraSpineProgress); - // Generate XPath for the current position. - // When we have a paragraph index from the section LUT, target that specific

element - // directly — this produces a structurally precise full-ancestry path even for chapters - // where paragraphs are nested inside divs/sections. Fall back to the progress-based - // scan (which works for any content) when no paragraph index is available. - if (pos.hasParagraphIndex && pos.paragraphIndex > 0) { - // When a seek hint is set, the LUT entry's paragraphIndex equals pos.paragraphIndex - // (both describe the same page). The byte offset now points at the body-child element - // that was current at the page break, so re-parsing from there will re-encounter that - // paragraph — seed startParagraphCount with paragraphIndex-1 to avoid double counting. - const uint16_t startCount = - pos.xhtmlSeekHint > 0 && pos.paragraphIndex > 0 ? static_cast(pos.paragraphIndex - 1) : 0; - result.xpath = ChapterXPathIndexer::findXPathForParagraph(epub, pos.spineIndex, pos.paragraphIndex, - pos.xhtmlSeekHint, startCount); - } - if (result.xpath.empty()) { - result.xpath = ChapterXPathIndexer::findXPathForProgress(epub, pos.spineIndex, intraSpineProgress); - } + // Generate XPath for the current position via byte-offset scan. Targeting the + // paragraph LUT entry instead would snap to the start of the paragraph the user + // is inside, which causes pulled positions to land at the start of the chapter + // when an opening paragraph spans many pages. + result.xpath = ChapterXPathIndexer::findXPathForProgress(epub, pos.spineIndex, intraSpineProgress); if (result.xpath.empty()) { result.xpath = generateXPath(pos.spineIndex); }