fix: show "Failed to index" when failing to parse epub (#2556)
This commit is contained in:
@@ -18,6 +18,7 @@ STR_NO_CHAPTERS: "No chapters"
|
||||
STR_END_OF_BOOK: "End of book"
|
||||
STR_EMPTY_CHAPTER: "Empty chapter"
|
||||
STR_INDEXING: "Indexing"
|
||||
STR_INDEX_FAILED: "Failed to index - invalid book"
|
||||
STR_MEMORY_ERROR: "Memory error"
|
||||
STR_PAGE_LOAD_ERROR: "Page load error"
|
||||
STR_EMPTY_FILE: "Empty file"
|
||||
|
||||
@@ -893,6 +893,15 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
GUI.drawPopup(renderer, tr(STR_SAVE_PROGRESS_FAILED));
|
||||
};
|
||||
|
||||
// A section build failure (e.g. an invalid/corrupt EPUB that fails XML parsing) leaves the
|
||||
// "Indexing" popup on screen with no way forward. Surface an explicit error instead of hanging.
|
||||
// clearScreen first so the error popup doesn't overlay the stale "Indexing" popup.
|
||||
const auto showBuildError = [this]() {
|
||||
renderer.clearScreen();
|
||||
GUI.drawPopup(renderer, tr(STR_INDEX_FAILED));
|
||||
automaticPageTurnActive = false;
|
||||
};
|
||||
|
||||
// edge case handling for sub-zero spine index
|
||||
if (currentSpineIndex < 0) {
|
||||
currentSpineIndex = 0;
|
||||
@@ -991,7 +1000,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
SETTINGS.imageRendering, SETTINGS.focusReadingEnabled, popupFn)) {
|
||||
LOG_ERR("ERS", "Failed to persist page data to SD");
|
||||
section.reset();
|
||||
showPendingSyncSaveError();
|
||||
showBuildError();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -1033,7 +1042,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
SETTINGS.imageRendering, SETTINGS.focusReadingEnabled)) {
|
||||
LOG_ERR("ERS", "Failed to start section build");
|
||||
section.reset();
|
||||
showPendingSyncSaveError();
|
||||
showBuildError();
|
||||
return;
|
||||
}
|
||||
while (!section->isBuildComplete() &&
|
||||
@@ -1044,7 +1053,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
if (!section->buildSomeMore(BUILD_PAGES_PER_CHUNK)) {
|
||||
LOG_ERR("ERS", "Failed during incremental section build");
|
||||
section.reset();
|
||||
showPendingSyncSaveError();
|
||||
showBuildError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1098,7 +1107,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
SETTINGS.focusReadingEnabled)) {
|
||||
LOG_ERR("ERS", "Failed to start partial extension build");
|
||||
section.reset();
|
||||
showPendingSyncSaveError();
|
||||
showBuildError();
|
||||
return;
|
||||
}
|
||||
// Extend until either the target page exists or the build completes.
|
||||
@@ -1106,7 +1115,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
if (!section->buildSomeMore(BUILD_PAGES_PER_CHUNK)) {
|
||||
LOG_ERR("ERS", "Failed during incremental section build");
|
||||
section.reset();
|
||||
showPendingSyncSaveError();
|
||||
showBuildError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1117,7 +1126,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
if (!section->buildSomeMore(BUILD_PAGES_PER_CHUNK)) {
|
||||
LOG_ERR("ERS", "Failed during incremental section build");
|
||||
section.reset();
|
||||
showPendingSyncSaveError();
|
||||
showBuildError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1167,17 +1176,29 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
auto p = section->loadPage(section->currentPage);
|
||||
if (!p) {
|
||||
LOG_ERR("ERS", "Failed to load page from SD - clearing section cache");
|
||||
automaticPageTurnActive = false;
|
||||
// Retrying rebuilds a transiently corrupt section and usually recovers, but a page that keeps
|
||||
// failing would loop forever on a blank screen, so bound the retries before giving up.
|
||||
const bool giveUp = ++pageLoadRetryCount > MAX_PAGE_LOAD_RETRIES;
|
||||
// Abandon (not suspend) any active build BEFORE clearing: clearCache deletes the files,
|
||||
// and the destructor's suspend would otherwise commit tables into a deleted handle.
|
||||
section->abandonBuild();
|
||||
section->clearCache();
|
||||
section.reset();
|
||||
if (giveUp) {
|
||||
LOG_ERR("ERS", "Page load retry limit reached, aborting");
|
||||
pageLoadRetryCount = 0; // Reset so a later user-initiated navigation can try afresh
|
||||
renderer.clearScreen();
|
||||
renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_PAGE_LOAD_ERROR), true, EpdFontFamily::BOLD);
|
||||
renderer.displayBuffer();
|
||||
showPendingSyncSaveError();
|
||||
return;
|
||||
}
|
||||
requestUpdate(); // Try again after clearing cache
|
||||
// TODO: prevent infinite loop if the page keeps failing to load for some reason
|
||||
automaticPageTurnActive = false;
|
||||
showPendingSyncSaveError();
|
||||
return;
|
||||
}
|
||||
pageLoadRetryCount = 0; // Reset the retry counter once a page loads cleanly
|
||||
|
||||
// Collect footnotes from the loaded page
|
||||
currentPageFootnotes = std::move(p->footnotes);
|
||||
|
||||
@@ -32,6 +32,10 @@ class EpubReaderActivity final : public Activity {
|
||||
float pendingSpineProgress = 0.0f;
|
||||
bool pendingScreenshot = false;
|
||||
bool pendingSyncSaveError = false;
|
||||
// Consecutive page-load failures. Each failure drops the section and rebuilds on the next render,
|
||||
// which recovers a transiently corrupt cache; capped so a persistently bad page can't spin forever.
|
||||
uint8_t pageLoadRetryCount = 0;
|
||||
static constexpr uint8_t MAX_PAGE_LOAD_RETRIES = 3;
|
||||
bool skipNextButtonCheck = false; // Skip button processing for one frame after subactivity exit
|
||||
bool automaticPageTurnActive = false;
|
||||
bool showBookmarkMessage = false;
|
||||
|
||||
Reference in New Issue
Block a user