From 776728d8e8919b1617b4712f3fd21a62cc32d09f Mon Sep 17 00:00:00 2001 From: jpirnay Date: Wed, 13 May 2026 22:10:13 +0200 Subject: [PATCH] Consolidate cache directories --- src/activities/home/HomeActivity.cpp | 14 +++++------ .../reader/FinishedBookActivity.cpp | 5 ++-- src/activities/reader/ReaderActivity.cpp | 6 +++++ src/activities/reader/ReaderActivity.h | 1 + .../settings/ClearCacheActivity.cpp | 4 +-- src/network/CrossPointWebServer.cpp | 25 +++++++++++++------ src/network/WebDAVHandler.cpp | 12 +++++++++ 7 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index f8c97d97..f0161eb0 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -28,11 +28,8 @@ #include "fontIds.h" namespace { -// Convert a sidecar JPG/PNG cover to a 1-bit BMP in the cache and return the BMP path, or "" on failure. -// fileName is the basename of the output file (without directory), e.g. "340x540.bmp" or "400.bmp". -std::string convertSidecarToBmp(const std::string& bookPath, const std::string& sidecarPath, int width, int height, +std::string convertSidecarToBmp(const std::string& cacheDir, const std::string& sidecarPath, int width, int height, const std::string& fileName) { - const std::string cacheDir = "/.crosspoint/sidecar_" + std::to_string(std::hash{}(bookPath)); Storage.mkdir(cacheDir.c_str()); const std::string bmpPath = cacheDir + "/" + fileName; if (Storage.exists(bmpPath.c_str())) return bmpPath; @@ -180,8 +177,9 @@ void HomeActivity::loadRecentBooks(int maxBooks) { // Also catches books registered before sidecar support (empty coverBmpPath). const std::string sidecar = ReaderActivity::sidecarCoverPath(book.path); if (!sidecar.empty()) { + const std::string bookCache = ReaderActivity::bookCacheDir(book.path); const bool sidecarAlreadyStored = - book.coverBmpPath == sidecar || book.coverBmpPath.find("sidecar_") != std::string::npos; + book.coverBmpPath == sidecar || book.coverBmpPath.find(bookCache) != std::string::npos; LOG_DBG("HOME", "Sidecar for %s: stored=%s alreadyStored=%d", book.path.c_str(), book.coverBmpPath.c_str(), sidecarAlreadyStored ? 1 : 0); if (!sidecarAlreadyStored) { @@ -222,13 +220,13 @@ void HomeActivity::loadRecentCovers(int coverHeight) { // The cache will be rebuilt on the next render. UITheme::getInstance().getMutableTheme().invalidateFrameCache(); - const std::string cacheBase = "/.crosspoint/sidecar_" + std::to_string(std::hash{}(book.path)); + const std::string cacheBase = ReaderActivity::bookCacheDir(book.path); const std::string placeholder = cacheBase + "/[HEIGHT].bmp"; bool success = true; if (!thumbSizes.empty()) { for (const auto& sz : thumbSizes) { const std::string name = std::to_string(sz.first) + "x" + std::to_string(sz.second) + ".bmp"; - if (convertSidecarToBmp(book.path, book.coverBmpPath, sz.first, sz.second, name).empty()) { + if (convertSidecarToBmp(cacheBase, book.coverBmpPath, sz.first, sz.second, name).empty()) { success = false; break; } @@ -236,7 +234,7 @@ void HomeActivity::loadRecentCovers(int coverHeight) { } else { const int w = coverHeight * 6 / 10; const std::string name = std::to_string(coverHeight) + ".bmp"; - if (convertSidecarToBmp(book.path, book.coverBmpPath, w, coverHeight, name).empty()) success = false; + if (convertSidecarToBmp(cacheBase, book.coverBmpPath, w, coverHeight, name).empty()) success = false; } if (success) { LOG_DBG("HOME", "Sidecar converted, placeholder: %s", placeholder.c_str()); diff --git a/src/activities/reader/FinishedBookActivity.cpp b/src/activities/reader/FinishedBookActivity.cpp index 6e20d07a..c8455535 100644 --- a/src/activities/reader/FinishedBookActivity.cpp +++ b/src/activities/reader/FinishedBookActivity.cpp @@ -65,9 +65,8 @@ std::string findUniquePathWithSuffix(const std::string& basePath) { std::string findUniqueCompletedSidecarPath(const std::string& basePath) { return findUniquePathWithSuffix(basePath); } -std::string convertSidecarToBmp(const std::string& bookPath, const std::string& sidecarPath, int width, int height, +std::string convertSidecarToBmp(const std::string& cacheDir, const std::string& sidecarPath, int width, int height, const std::string& fileName) { - const std::string cacheDir = "/.crosspoint/sidecar_" + std::to_string(std::hash{}(bookPath)); if (!Storage.exists(cacheDir.c_str())) { Storage.mkdir(cacheDir.c_str()); } @@ -120,7 +119,7 @@ std::string getSidecarCoverBmpPath(const std::string& bookPath, int width, int h } const std::string fileName = "thumb_" + std::to_string(width) + "x" + std::to_string(height) + ".bmp"; - return convertSidecarToBmp(bookPath, sidecarPath, width, height, fileName); + return convertSidecarToBmp(ReaderActivity::bookCacheDir(bookPath), sidecarPath, width, height, fileName); } bool moveSidecarFilesToCompleted(const std::string& currentBookPath, const std::string& targetBookPath) { diff --git a/src/activities/reader/ReaderActivity.cpp b/src/activities/reader/ReaderActivity.cpp index b3a8d3af..06c2bdb6 100644 --- a/src/activities/reader/ReaderActivity.cpp +++ b/src/activities/reader/ReaderActivity.cpp @@ -71,6 +71,12 @@ std::string ReaderActivity::sidecarCoverPath(const std::string& bookPath) { return ""; } +std::string ReaderActivity::bookCacheDir(const std::string& bookPath) { + if (FsHelpers::hasEpubExtension(bookPath)) return Epub(bookPath, "/.crosspoint").getCachePath(); + if (FsHelpers::hasXtcExtension(bookPath)) return Xtc(bookPath, "/.crosspoint").getCachePath(); + return Txt(bookPath, "/.crosspoint").getCachePath(); +} + std::unique_ptr ReaderActivity::loadEpub(const std::string& path) { if (!Storage.exists(path.c_str())) { LOG_ERR("READER", "File does not exist: %s", path.c_str()); diff --git a/src/activities/reader/ReaderActivity.h b/src/activities/reader/ReaderActivity.h index bc24c94a..84325d18 100644 --- a/src/activities/reader/ReaderActivity.h +++ b/src/activities/reader/ReaderActivity.h @@ -31,6 +31,7 @@ class ReaderActivity final : public Activity { public: static std::string sidecarCoverPath(const std::string& bookPath); + static std::string bookCacheDir(const std::string& bookPath); explicit ReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string initialBookPath) : Activity("Reader", renderer, mappedInput), initialBookPath(std::move(initialBookPath)) {} diff --git a/src/activities/settings/ClearCacheActivity.cpp b/src/activities/settings/ClearCacheActivity.cpp index 698e0a46..e6a7cc2a 100644 --- a/src/activities/settings/ClearCacheActivity.cpp +++ b/src/activities/settings/ClearCacheActivity.cpp @@ -105,8 +105,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_"))) { + if (file.isDirectory() && + (itemName.startsWith("epub_") || itemName.startsWith("xtc_") || itemName.startsWith("txt_"))) { 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 0350d967..c588cb4d 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -5,7 +5,9 @@ #include #include #include +#include #include +#include #include #include @@ -58,16 +60,25 @@ String wsLastCompleteName; size_t wsLastCompleteSize = 0; unsigned long wsLastCompleteAt = 0; -// Helper function to clear epub cache after upload -void clearEpubCacheIfNeeded(const String& filePath) { +void clearBookCacheIfNeeded(const String& filePath) { if (FsHelpers::hasEpubExtension(filePath)) { Epub(filePath.c_str(), "/.crosspoint").clearCache(); LOG_DBG("WEB", "Cleared epub cache for: %s", filePath.c_str()); + } else if (FsHelpers::hasXtcExtension(filePath)) { + Xtc(filePath.c_str(), "/.crosspoint").clearCache(); + LOG_DBG("WEB", "Cleared xtc cache for: %s", filePath.c_str()); + } else if (FsHelpers::hasTxtExtension(filePath) || FsHelpers::hasMarkdownExtension(filePath)) { + const Txt txt(filePath.c_str(), "/.crosspoint"); + const String cachePath = txt.getCachePath().c_str(); + if (Storage.exists(cachePath.c_str())) { + Storage.removeDir(cachePath.c_str()); + LOG_DBG("WEB", "Cleared txt cache for: %s", filePath.c_str()); + } } } -// Recursively clear epub caches for all EPUBs inside a directory -void clearEpubCachesInDirectory(const String& dirPath) { +// Recursively clear book caches for all ebooks inside a directory +void clearBookCachesInDirectory(const String& dirPath) { esp_task_wdt_reset(); yield(); FsFile dir = Storage.open(dirPath.c_str()); @@ -86,10 +97,10 @@ void clearEpubCachesInDirectory(const String& dirPath) { childPath += name; if (entry.isDirectory()) { entry.close(); - clearEpubCachesInDirectory(childPath); + clearBookCachesInDirectory(childPath); } else { entry.close(); - clearEpubCacheIfNeeded(childPath); + clearBookCacheIfNeeded(childPath); } entry = dir.openNextFile(); } @@ -1210,7 +1221,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); + clearBookCacheIfNeeded(itemPath); } if (!success) { diff --git a/src/network/WebDAVHandler.cpp b/src/network/WebDAVHandler.cpp index b6c8a5e1..46ae4450 100644 --- a/src/network/WebDAVHandler.cpp +++ b/src/network/WebDAVHandler.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include namespace { @@ -802,6 +804,16 @@ 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()); + } else if (FsHelpers::hasXtcExtension(path)) { + Xtc(path.c_str(), "/.crosspoint").clearCache(); + LOG_DBG("DAV", "Cleared xtc cache for: %s", path.c_str()); + } else if (FsHelpers::hasTxtExtension(path) || FsHelpers::hasMarkdownExtension(path)) { + const Txt txt(path.c_str(), "/.crosspoint"); + const String cachePath = txt.getCachePath().c_str(); + if (Storage.exists(cachePath.c_str())) { + Storage.removeDir(cachePath.c_str()); + LOG_DBG("DAV", "Cleared txt cache for: %s", path.c_str()); + } } }