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_END_OF_BOOK: "End of book"
|
||||||
STR_EMPTY_CHAPTER: "Empty chapter"
|
STR_EMPTY_CHAPTER: "Empty chapter"
|
||||||
STR_INDEXING: "Indexing"
|
STR_INDEXING: "Indexing"
|
||||||
|
STR_INDEX_FAILED: "Failed to index - invalid book"
|
||||||
STR_MEMORY_ERROR: "Memory error"
|
STR_MEMORY_ERROR: "Memory error"
|
||||||
STR_PAGE_LOAD_ERROR: "Page load error"
|
STR_PAGE_LOAD_ERROR: "Page load error"
|
||||||
STR_EMPTY_FILE: "Empty file"
|
STR_EMPTY_FILE: "Empty file"
|
||||||
|
|||||||
@@ -893,6 +893,15 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
|||||||
GUI.drawPopup(renderer, tr(STR_SAVE_PROGRESS_FAILED));
|
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
|
// edge case handling for sub-zero spine index
|
||||||
if (currentSpineIndex < 0) {
|
if (currentSpineIndex < 0) {
|
||||||
currentSpineIndex = 0;
|
currentSpineIndex = 0;
|
||||||
@@ -991,7 +1000,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
|||||||
SETTINGS.imageRendering, SETTINGS.focusReadingEnabled, popupFn)) {
|
SETTINGS.imageRendering, SETTINGS.focusReadingEnabled, popupFn)) {
|
||||||
LOG_ERR("ERS", "Failed to persist page data to SD");
|
LOG_ERR("ERS", "Failed to persist page data to SD");
|
||||||
section.reset();
|
section.reset();
|
||||||
showPendingSyncSaveError();
|
showBuildError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1033,7 +1042,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
|||||||
SETTINGS.imageRendering, SETTINGS.focusReadingEnabled)) {
|
SETTINGS.imageRendering, SETTINGS.focusReadingEnabled)) {
|
||||||
LOG_ERR("ERS", "Failed to start section build");
|
LOG_ERR("ERS", "Failed to start section build");
|
||||||
section.reset();
|
section.reset();
|
||||||
showPendingSyncSaveError();
|
showBuildError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (!section->isBuildComplete() &&
|
while (!section->isBuildComplete() &&
|
||||||
@@ -1044,7 +1053,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
|||||||
if (!section->buildSomeMore(BUILD_PAGES_PER_CHUNK)) {
|
if (!section->buildSomeMore(BUILD_PAGES_PER_CHUNK)) {
|
||||||
LOG_ERR("ERS", "Failed during incremental section build");
|
LOG_ERR("ERS", "Failed during incremental section build");
|
||||||
section.reset();
|
section.reset();
|
||||||
showPendingSyncSaveError();
|
showBuildError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1098,7 +1107,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
|||||||
SETTINGS.focusReadingEnabled)) {
|
SETTINGS.focusReadingEnabled)) {
|
||||||
LOG_ERR("ERS", "Failed to start partial extension build");
|
LOG_ERR("ERS", "Failed to start partial extension build");
|
||||||
section.reset();
|
section.reset();
|
||||||
showPendingSyncSaveError();
|
showBuildError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Extend until either the target page exists or the build completes.
|
// 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)) {
|
if (!section->buildSomeMore(BUILD_PAGES_PER_CHUNK)) {
|
||||||
LOG_ERR("ERS", "Failed during incremental section build");
|
LOG_ERR("ERS", "Failed during incremental section build");
|
||||||
section.reset();
|
section.reset();
|
||||||
showPendingSyncSaveError();
|
showBuildError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1117,7 +1126,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
|||||||
if (!section->buildSomeMore(BUILD_PAGES_PER_CHUNK)) {
|
if (!section->buildSomeMore(BUILD_PAGES_PER_CHUNK)) {
|
||||||
LOG_ERR("ERS", "Failed during incremental section build");
|
LOG_ERR("ERS", "Failed during incremental section build");
|
||||||
section.reset();
|
section.reset();
|
||||||
showPendingSyncSaveError();
|
showBuildError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1167,17 +1176,29 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
|||||||
auto p = section->loadPage(section->currentPage);
|
auto p = section->loadPage(section->currentPage);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
LOG_ERR("ERS", "Failed to load page from SD - clearing section cache");
|
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,
|
// 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.
|
// and the destructor's suspend would otherwise commit tables into a deleted handle.
|
||||||
section->abandonBuild();
|
section->abandonBuild();
|
||||||
section->clearCache();
|
section->clearCache();
|
||||||
section.reset();
|
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
|
requestUpdate(); // Try again after clearing cache
|
||||||
// TODO: prevent infinite loop if the page keeps failing to load for some reason
|
|
||||||
automaticPageTurnActive = false;
|
|
||||||
showPendingSyncSaveError();
|
showPendingSyncSaveError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
pageLoadRetryCount = 0; // Reset the retry counter once a page loads cleanly
|
||||||
|
|
||||||
// Collect footnotes from the loaded page
|
// Collect footnotes from the loaded page
|
||||||
currentPageFootnotes = std::move(p->footnotes);
|
currentPageFootnotes = std::move(p->footnotes);
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ class EpubReaderActivity final : public Activity {
|
|||||||
float pendingSpineProgress = 0.0f;
|
float pendingSpineProgress = 0.0f;
|
||||||
bool pendingScreenshot = false;
|
bool pendingScreenshot = false;
|
||||||
bool pendingSyncSaveError = 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 skipNextButtonCheck = false; // Skip button processing for one frame after subactivity exit
|
||||||
bool automaticPageTurnActive = false;
|
bool automaticPageTurnActive = false;
|
||||||
bool showBookmarkMessage = false;
|
bool showBookmarkMessage = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user