Merge branch 'feat-koysnc-xpath' of https://github.com/jpirnay/crosspoint-reader into mybuild
This commit is contained in:
@@ -45,7 +45,7 @@ struct ParserState {
|
||||
std::vector<std::unordered_map<std::string, int>> siblingCounters;
|
||||
std::vector<XPathAnchor> anchors;
|
||||
|
||||
std::string baseXPath() const { return "/body/DocFragment[" + std::to_string(spineIndex + 1) + "]/body"; }
|
||||
std::string baseXPath() const { return "/body/docfragment[" + std::to_string(spineIndex + 1) + "]/body"; }
|
||||
|
||||
// Canonicalize incoming KOReader XPath before matching:
|
||||
// - remove all whitespace
|
||||
@@ -135,7 +135,7 @@ struct ParserState {
|
||||
const std::string& anchorPath = ignoreIndices ? anchor.xpathNoIndex : anchor.xpath;
|
||||
if (anchorPath == probe) {
|
||||
const int depth = pathDepth(anchorPath);
|
||||
if (!found || depth > bestDepth || (depth == bestDepth && anchor.textOffset < bestOffset)) {
|
||||
if (!found || depth > bestDepth || (depth == bestDepth && anchor.textOffset > bestOffset)) {
|
||||
found = true;
|
||||
bestDepth = depth;
|
||||
bestOffset = anchor.textOffset;
|
||||
@@ -463,11 +463,63 @@ static std::optional<ParserState> parseSpineItem(const std::shared_ptr<Epub>& ep
|
||||
return state;
|
||||
}
|
||||
|
||||
// Keep a single parsed spine in memory to avoid repeated decompress+parse work
|
||||
// in the KO sync flow.
|
||||
//
|
||||
// Why this helps here:
|
||||
// - Sync result screen calls both mapping directions (remote->local for compare,
|
||||
// local->KOReader for display).
|
||||
// - If the user chooses Upload, local->KOReader mapping is performed again.
|
||||
// - Without caching, the same chapter can be decompressed and reparsed multiple
|
||||
// times during one activity session.
|
||||
//
|
||||
// Why the cache is exactly one entry:
|
||||
// - We only need to accelerate immediate repeat lookups for the current chapter.
|
||||
// - A single-entry cache bounds RAM use and avoids long-lived heap growth on
|
||||
// ESP32-C3.
|
||||
static const ParserState* getParsedStateCached(const std::shared_ptr<Epub>& epub, const int spineIndex) {
|
||||
static const Epub* cachedEpub = nullptr;
|
||||
static int cachedSpineIndex = -1;
|
||||
static std::string cachedHref;
|
||||
static std::optional<ParserState> cachedState;
|
||||
|
||||
if (!epub || spineIndex < 0 || spineIndex >= epub->getSpineItemsCount()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto spineItem = epub->getSpineItem(spineIndex);
|
||||
if (spineItem.href.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bool cacheHit = cachedState.has_value() && cachedEpub == epub.get() && cachedSpineIndex == spineIndex &&
|
||||
cachedHref == spineItem.href;
|
||||
if (cacheHit) {
|
||||
LOG_DBG("KOX", "Cache hit: spine=%d anchors=%zu textBytes=%zu", spineIndex, cachedState->anchors.size(),
|
||||
cachedState->totalTextBytes);
|
||||
return &cachedState.value();
|
||||
}
|
||||
|
||||
auto parsed = parseSpineItem(epub, spineIndex);
|
||||
if (!parsed) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cachedEpub = epub.get();
|
||||
cachedSpineIndex = spineIndex;
|
||||
cachedHref = spineItem.href;
|
||||
cachedState = std::move(parsed);
|
||||
|
||||
LOG_DBG("KOX", "Cache store: spine=%d anchors=%zu textBytes=%zu", spineIndex, cachedState->anchors.size(),
|
||||
cachedState->totalTextBytes);
|
||||
return &cachedState.value();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string ChapterXPathIndexer::findXPathForProgress(const std::shared_ptr<Epub>& epub, const int spineIndex,
|
||||
const float intraSpineProgress) {
|
||||
const auto state = parseSpineItem(epub, spineIndex);
|
||||
const auto* state = getParsedStateCached(epub, spineIndex);
|
||||
if (!state) {
|
||||
return "";
|
||||
}
|
||||
@@ -488,7 +540,7 @@ bool ChapterXPathIndexer::findProgressForXPath(const std::shared_ptr<Epub>& epub
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto state = parseSpineItem(epub, spineIndex);
|
||||
const auto* state = getParsedStateCached(epub, spineIndex);
|
||||
if (!state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -203,6 +203,7 @@ void KOReaderSyncActivity::onEnter() {
|
||||
|
||||
// Check if already connected (e.g. from settings page auth)
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
LOG_DBG("KOSync", "Already connected to WiFi");
|
||||
onWifiSelectionComplete(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user