Port three unmerged upstream PRs with adaptations for the fork's callback-based ActivityWithSubactivity architecture: - PR #1185: Cache KOReader document hash using mtime fingerprint + file size validation to avoid repeated MD5 computation on sync. - PR #1217: Proper KOReader XPath synchronisation via new ChapterXPathIndexer (Expat-based on-demand XHTML parsing) with XPath-first mapping and percentage fallback in ProgressMapper. - PR #1090: Push Progress & Sleep menu option with PUSH_ONLY sync mode. Adapted to fork's callback pattern with deferFinish() for thread-safe completion. Modified to sleep silently on any failure (hash, upload, no credentials) rather than returning to reader. Made-with: Cursor
This commit is contained in:
67
lib/KOReaderSync/ChapterXPathIndexer.h
Normal file
67
lib/KOReaderSync/ChapterXPathIndexer.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <Epub.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Lightweight XPath/progress bridge for KOReader sync.
|
||||
*
|
||||
* Why this exists:
|
||||
* - CrossPoint stores reading position as chapter/page.
|
||||
* - KOReader sync uses XPath + percentage.
|
||||
*
|
||||
* This utility reparses exactly one spine XHTML item with Expat and builds
|
||||
* transient text anchors (<xpath, textOffset>) so we can translate in both
|
||||
* directions without keeping a full DOM in memory.
|
||||
*
|
||||
* Design constraints (ESP32-C3):
|
||||
* - No persistent full-book structures.
|
||||
* - Parse-on-demand and free memory immediately.
|
||||
* - Keep fallback behavior deterministic if parsing/matching fails.
|
||||
*/
|
||||
class ChapterXPathIndexer {
|
||||
public:
|
||||
/**
|
||||
* Convert an intra-spine progress ratio to the nearest element-level XPath.
|
||||
*
|
||||
* @param epub Loaded EPUB instance
|
||||
* @param spineIndex Current spine item index
|
||||
* @param intraSpineProgress Position within the spine item [0.0, 1.0]
|
||||
* @return Best matching XPath for KOReader, or empty string on failure
|
||||
*/
|
||||
static std::string findXPathForProgress(const std::shared_ptr<Epub>& epub, int spineIndex, float intraSpineProgress);
|
||||
|
||||
/**
|
||||
* Resolve a KOReader XPath to an intra-spine progress ratio.
|
||||
*
|
||||
* Matching strategy:
|
||||
* 1) exact anchor path match,
|
||||
* 2) index-insensitive path match,
|
||||
* 3) ancestor fallback.
|
||||
*
|
||||
* @param epub Loaded EPUB instance
|
||||
* @param spineIndex Spine item index to parse
|
||||
* @param xpath Incoming KOReader XPath
|
||||
* @param outIntraSpineProgress Resolved position within spine [0.0, 1.0]
|
||||
* @param outExactMatch True only for full exact path match
|
||||
* @return true if any match was resolved; false means caller should fallback
|
||||
*/
|
||||
static bool findProgressForXPath(const std::shared_ptr<Epub>& epub, int spineIndex, const std::string& xpath,
|
||||
float& outIntraSpineProgress, bool& outExactMatch);
|
||||
|
||||
/**
|
||||
* Parse DocFragment index from KOReader-style path segment:
|
||||
* /body/DocFragment[N]/body/...
|
||||
*
|
||||
* KOReader uses 1-based DocFragment indices; N is converted to the 0-based
|
||||
* spine index stored in outSpineIndex (i.e. outSpineIndex = N - 1).
|
||||
*
|
||||
* @param xpath KOReader XPath
|
||||
* @param outSpineIndex 0-based spine index derived from DocFragment[N]
|
||||
* @return true when DocFragment[N] exists and N is a valid integer >= 1
|
||||
* (converted to 0-based outSpineIndex); false otherwise
|
||||
*/
|
||||
static bool tryExtractSpineIndexFromXPath(const std::string& xpath, int& outSpineIndex);
|
||||
};
|
||||
Reference in New Issue
Block a user