feat: port upstream KOReader sync PRs (#1185, #1217, #1090)

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:
cottongin
2026-03-02 05:19:14 -05:00
parent 42011d5977
commit 3628d8eb37
14 changed files with 1031 additions and 44 deletions

View File

@@ -42,4 +42,31 @@ class KOReaderDocumentId {
// Calculate offset for index i: 1024 << (2*i)
static size_t getOffset(int i);
// Hash cache helpers
// Returns the path to the per-book cache file that stores the precomputed hash.
// Uses the same directory convention as the Epub cache (/.crosspoint/epub_<hash>/).
static std::string getCacheFilePath(const std::string& filePath);
// Returns the cached hash if the file size and fingerprint match, or empty
// string on miss/invalidation.
//
// The fingerprint is derived from the file's modification timestamp. We
// call `FsFile::getModifyDateTime` to retrieve two 16bit packed values
// supplied by the filesystem: one for the date and one for the time. These
// are concatenated and represented as eight hexadecimal digits in the form
// <date><time> (high 16 bits = packed date, low 16 bits = packed time).
//
// The resulting string serves as a lightweight change signal; any modification
// to the file's mtime will alter the packed date/time combo and invalidate
// the cache entry. Since the full document hash is expensive to compute,
// using the packed timestamp gives us a quick way to detect modifications
// without reading file contents.
static std::string loadCachedHash(const std::string& cacheFilePath, size_t fileSize,
const std::string& currentFingerprint);
// Persists the computed hash alongside the file size and fingerprint (the
// modification-timestamp token) used to generate it.
static void saveCachedHash(const std::string& cacheFilePath, size_t fileSize, const std::string& fingerprint,
const std::string& hash);
};