From 2dd491b62e14f8cb3acc9c0359b45c3d478d5f98 Mon Sep 17 00:00:00 2001 From: WuTofu <5987870+WuTofu@users.noreply.github.com> Date: Thu, 21 May 2026 19:44:10 +0800 Subject: [PATCH] refactor: unify book cache clearing for epub, txt, and xtc files (#1875) --- lib/Txt/Txt.cpp | 15 ++++++++ lib/Txt/Txt.h | 1 + .../browser/OpdsBookBrowserActivity.cpp | 4 +-- .../settings/ClearCacheActivity.cpp | 5 +-- src/network/CrossPointWebServer.cpp | 23 ++++--------- src/network/WebDAVHandler.cpp | 16 +++------ src/network/WebDAVHandler.h | 1 - src/util/BookCacheUtils.cpp | 34 +++++++++++++++++++ src/util/BookCacheUtils.h | 10 ++++++ 9 files changed, 77 insertions(+), 32 deletions(-) create mode 100644 src/util/BookCacheUtils.cpp create mode 100644 src/util/BookCacheUtils.h diff --git a/lib/Txt/Txt.cpp b/lib/Txt/Txt.cpp index 0209923a..b5d22259 100644 --- a/lib/Txt/Txt.cpp +++ b/lib/Txt/Txt.cpp @@ -155,6 +155,21 @@ bool Txt::generateCoverBmp() const { return false; } +bool Txt::clearCache() const { + if (!Storage.exists(cachePath.c_str())) { + LOG_DBG("TXT", "Cache does not exist, no action needed"); + return true; + } + + if (!Storage.removeDir(cachePath.c_str())) { + LOG_ERR("TXT", "Failed to clear cache"); + return false; + } + + LOG_DBG("TXT", "Cache cleared successfully"); + return true; +} + bool Txt::readContent(uint8_t* buffer, size_t offset, size_t length) const { if (!loaded) { return false; diff --git a/lib/Txt/Txt.h b/lib/Txt/Txt.h index b342ca88..859ae23b 100644 --- a/lib/Txt/Txt.h +++ b/lib/Txt/Txt.h @@ -22,6 +22,7 @@ class Txt { [[nodiscard]] size_t getFileSize() const { return fileSize; } void setupCacheDir() const; + bool clearCache() const; // Cover image support - looks for cover.bmp/jpg/jpeg/png in same folder as txt file [[nodiscard]] std::string getCoverBmpPath() const; diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 40eada07..6ff5b719 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -1,6 +1,5 @@ #include "OpdsBookBrowserActivity.h" -#include #include #include #include @@ -14,6 +13,7 @@ #include "components/UITheme.h" #include "fontIds.h" #include "network/HttpDownloader.h" +#include "util/BookCacheUtils.h" #include "util/StringUtils.h" #include "util/UrlUtils.h" @@ -283,7 +283,7 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) { nullptr, server.username, server.password); if (result == HttpDownloader::OK) { - Epub(filename, "/.crosspoint").clearCache(); + clearBookCache(filename); state = BrowserState::BROWSING; } else { state = BrowserState::ERROR; diff --git a/src/activities/settings/ClearCacheActivity.cpp b/src/activities/settings/ClearCacheActivity.cpp index c4fc4347..b0dcbfbb 100644 --- a/src/activities/settings/ClearCacheActivity.cpp +++ b/src/activities/settings/ClearCacheActivity.cpp @@ -8,6 +8,7 @@ #include "MappedInputManager.h" #include "components/UITheme.h" #include "fontIds.h" +#include "util/BookCacheUtils.h" void ClearCacheActivity::onEnter() { Activity::onEnter(); @@ -94,8 +95,8 @@ void ClearCacheActivity::clearCache() { file.getName(name, sizeof(name)); String itemName(name); - // Only delete directories starting with epub_ or xtc_ - if (file.isDirectory() && (itemName.startsWith("epub_") || itemName.startsWith("xtc_"))) { + // Only delete directories matching known book cache names. + if (file.isDirectory() && isBookCacheDirectoryName(itemName.c_str())) { String fullPath = "/.crosspoint/" + itemName; LOG_DBG("CLEAR_CACHE", "Removing cache: %s", fullPath.c_str()); diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index 1631746d..87210b11 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -1,7 +1,6 @@ #include "CrossPointWebServer.h" #include -#include #include #include #include @@ -23,6 +22,7 @@ #include "html/HomePageHtml.generated.h" #include "html/SettingsPageHtml.generated.h" #include "html/js/jszip_minJs.generated.h" +#include "util/BookCacheUtils.h" namespace { // Folders/files to hide from the web interface file browser @@ -48,15 +48,6 @@ String wsLastCompleteName; size_t wsLastCompleteSize = 0; unsigned long wsLastCompleteAt = 0; -// Helper function to clear epub cache after upload -void clearEpubCacheIfNeeded(const String& filePath) { - // Only clear cache for .epub files - if (FsHelpers::hasEpubExtension(filePath)) { - Epub(filePath.c_str(), "/.crosspoint").clearCache(); - LOG_DBG("WEB", "Cleared epub cache for: %s", filePath.c_str()); - } -} - String normalizeWebPath(const String& inputPath) { if (inputPath.isEmpty() || inputPath == "/") { return "/"; @@ -732,7 +723,7 @@ void CrossPointWebServer::handleUpload(UploadState& state) const { String filePath = state.path; if (!filePath.endsWith("/")) filePath += "/"; filePath += state.fileName; - clearEpubCacheIfNeeded(filePath); + clearBookCache(filePath.c_str()); } } } else if (upload.status == UPLOAD_FILE_ABORTED) { @@ -878,7 +869,7 @@ void CrossPointWebServer::handleRename() const { return; } - clearEpubCacheIfNeeded(itemPath); + clearBookCache(itemPath.c_str()); const bool success = file.rename(newPath.c_str()); file.close(); @@ -971,7 +962,7 @@ void CrossPointWebServer::handleMove() const { return; } - clearEpubCacheIfNeeded(itemPath); + clearBookCache(itemPath.c_str()); const bool success = file.rename(newPath.c_str()); file.close(); @@ -1090,7 +1081,7 @@ void CrossPointWebServer::handleDelete() const { // It's a file (or couldn't open as dir) — remove file if (f) f.close(); success = Storage.remove(itemPath.c_str()); - clearEpubCacheIfNeeded(itemPath); + clearBookCache(itemPath.c_str()); } if (!success) { @@ -1636,7 +1627,7 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t* wsLastCompleteSize = 0; wsLastCompleteAt = millis(); LOG_DBG("WS", "Zero-byte upload complete: %s", filePath.c_str()); - clearEpubCacheIfNeeded(filePath); + clearBookCache(filePath.c_str()); wsServer->sendTXT(num, "DONE"); wsLastProgressSent = 0; break; @@ -1705,7 +1696,7 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t* String filePath = wsUploadPath; if (!filePath.endsWith("/")) filePath += "/"; filePath += wsUploadFileName; - clearEpubCacheIfNeeded(filePath); + clearBookCache(filePath.c_str()); wsServer->sendTXT(num, "DONE"); wsLastProgressSent = 0; diff --git a/src/network/WebDAVHandler.cpp b/src/network/WebDAVHandler.cpp index f20e8261..0fafb680 100644 --- a/src/network/WebDAVHandler.cpp +++ b/src/network/WebDAVHandler.cpp @@ -1,11 +1,12 @@ #include "WebDAVHandler.h" -#include #include #include #include #include +#include "util/BookCacheUtils.h" + namespace { constexpr const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"}; @@ -384,7 +385,7 @@ void WebDAVHandler::handlePut(WebServer& s) { return; } - clearEpubCacheIfNeeded(path); + clearBookCache(path.c_str()); s.send(_putExisted ? 204 : 201); LOG_DBG("DAV", "PUT complete: %s", path.c_str()); } @@ -433,7 +434,7 @@ void WebDAVHandler::handleDelete(WebServer& s) { } } else { file.close(); - clearEpubCacheIfNeeded(path); + clearBookCache(path.c_str()); if (Storage.remove(path.c_str())) { s.send(204); } else { @@ -542,7 +543,7 @@ void WebDAVHandler::handleMove(WebServer& s) { return; } - clearEpubCacheIfNeeded(srcPath); + clearBookCache(srcPath.c_str()); bool success = file.rename(dstPath.c_str()); file.close(); @@ -797,13 +798,6 @@ bool WebDAVHandler::getOverwrite(WebServer& s) const { return true; // Default is T } -void WebDAVHandler::clearEpubCacheIfNeeded(const String& path) const { - if (FsHelpers::hasEpubExtension(path)) { - Epub(path.c_str(), "/.crosspoint").clearCache(); - LOG_DBG("DAV", "Cleared epub cache for: %s", path.c_str()); - } -} - String WebDAVHandler::getMimeType(const String& path) const { if (FsHelpers::hasEpubExtension(path)) return "application/epub+zip"; if (FsHelpers::checkFileExtension(path, ".pdf")) return "application/pdf"; diff --git a/src/network/WebDAVHandler.h b/src/network/WebDAVHandler.h index 5911203f..e11e184b 100644 --- a/src/network/WebDAVHandler.h +++ b/src/network/WebDAVHandler.h @@ -38,7 +38,6 @@ class WebDAVHandler : public RequestHandler { bool isProtectedPath(const String& path) const; int getDepth(WebServer& s) const; bool getOverwrite(WebServer& s) const; - void clearEpubCacheIfNeeded(const String& path) const; void sendPropEntry(WebServer& s, const String& href, bool isDir, size_t size, const String& lastModified) const; String getMimeType(const String& path) const; }; diff --git a/src/util/BookCacheUtils.cpp b/src/util/BookCacheUtils.cpp new file mode 100644 index 00000000..a539c053 --- /dev/null +++ b/src/util/BookCacheUtils.cpp @@ -0,0 +1,34 @@ +#include "BookCacheUtils.h" + +#include +#include +#include +#include +#include + +bool isBookCacheDirectoryName(const char* name) { + if (!name) { + return false; + } + + constexpr char EPUB_PREFIX[] = "epub_"; + constexpr char TXT_PREFIX[] = "txt_"; + constexpr char XTC_PREFIX[] = "xtc_"; + + return strncmp(name, EPUB_PREFIX, std::size(EPUB_PREFIX) - 1) == 0 || + strncmp(name, TXT_PREFIX, std::size(TXT_PREFIX) - 1) == 0 || + strncmp(name, XTC_PREFIX, std::size(XTC_PREFIX) - 1) == 0; +} + +void clearBookCache(const std::string& path) { + if (FsHelpers::hasEpubExtension(path)) { + Epub(path, "/.crosspoint").clearCache(); + } else if (FsHelpers::hasXtcExtension(path)) { + Xtc(path, "/.crosspoint").clearCache(); + } else if (FsHelpers::hasTxtExtension(path)) { + Txt(path, "/.crosspoint").clearCache(); + } else { + return; + } + LOG_DBG("BookCache", "Done checking metadata cache for: %s", path.c_str()); +} diff --git a/src/util/BookCacheUtils.h b/src/util/BookCacheUtils.h new file mode 100644 index 00000000..c10c8a22 --- /dev/null +++ b/src/util/BookCacheUtils.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +// Clears the reading cache for a book file if its extension is recognised +// (EPUB, XTC, or TXT). Does nothing for other file types. +void clearBookCache(const std::string& path); + +// Returns true if the directory name matches a book cache entry. +bool isBookCacheDirectoryName(const char* name);