Consolidate cache directories
This commit is contained in:
@@ -28,11 +28,8 @@
|
|||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Convert a sidecar JPG/PNG cover to a 1-bit BMP in the cache and return the BMP path, or "" on failure.
|
std::string convertSidecarToBmp(const std::string& cacheDir, const std::string& sidecarPath, int width, int height,
|
||||||
// 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,
|
|
||||||
const std::string& fileName) {
|
const std::string& fileName) {
|
||||||
const std::string cacheDir = "/.crosspoint/sidecar_" + std::to_string(std::hash<std::string>{}(bookPath));
|
|
||||||
Storage.mkdir(cacheDir.c_str());
|
Storage.mkdir(cacheDir.c_str());
|
||||||
const std::string bmpPath = cacheDir + "/" + fileName;
|
const std::string bmpPath = cacheDir + "/" + fileName;
|
||||||
if (Storage.exists(bmpPath.c_str())) return bmpPath;
|
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).
|
// Also catches books registered before sidecar support (empty coverBmpPath).
|
||||||
const std::string sidecar = ReaderActivity::sidecarCoverPath(book.path);
|
const std::string sidecar = ReaderActivity::sidecarCoverPath(book.path);
|
||||||
if (!sidecar.empty()) {
|
if (!sidecar.empty()) {
|
||||||
|
const std::string bookCache = ReaderActivity::bookCacheDir(book.path);
|
||||||
const bool sidecarAlreadyStored =
|
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(),
|
LOG_DBG("HOME", "Sidecar for %s: stored=%s alreadyStored=%d", book.path.c_str(), book.coverBmpPath.c_str(),
|
||||||
sidecarAlreadyStored ? 1 : 0);
|
sidecarAlreadyStored ? 1 : 0);
|
||||||
if (!sidecarAlreadyStored) {
|
if (!sidecarAlreadyStored) {
|
||||||
@@ -222,13 +220,13 @@ void HomeActivity::loadRecentCovers(int coverHeight) {
|
|||||||
// The cache will be rebuilt on the next render.
|
// The cache will be rebuilt on the next render.
|
||||||
UITheme::getInstance().getMutableTheme().invalidateFrameCache();
|
UITheme::getInstance().getMutableTheme().invalidateFrameCache();
|
||||||
|
|
||||||
const std::string cacheBase = "/.crosspoint/sidecar_" + std::to_string(std::hash<std::string>{}(book.path));
|
const std::string cacheBase = ReaderActivity::bookCacheDir(book.path);
|
||||||
const std::string placeholder = cacheBase + "/[HEIGHT].bmp";
|
const std::string placeholder = cacheBase + "/[HEIGHT].bmp";
|
||||||
bool success = true;
|
bool success = true;
|
||||||
if (!thumbSizes.empty()) {
|
if (!thumbSizes.empty()) {
|
||||||
for (const auto& sz : thumbSizes) {
|
for (const auto& sz : thumbSizes) {
|
||||||
const std::string name = std::to_string(sz.first) + "x" + std::to_string(sz.second) + ".bmp";
|
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;
|
success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -236,7 +234,7 @@ void HomeActivity::loadRecentCovers(int coverHeight) {
|
|||||||
} else {
|
} else {
|
||||||
const int w = coverHeight * 6 / 10;
|
const int w = coverHeight * 6 / 10;
|
||||||
const std::string name = std::to_string(coverHeight) + ".bmp";
|
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) {
|
if (success) {
|
||||||
LOG_DBG("HOME", "Sidecar converted, placeholder: %s", placeholder.c_str());
|
LOG_DBG("HOME", "Sidecar converted, placeholder: %s", placeholder.c_str());
|
||||||
|
|||||||
@@ -65,9 +65,8 @@ std::string findUniquePathWithSuffix(const std::string& basePath) {
|
|||||||
|
|
||||||
std::string findUniqueCompletedSidecarPath(const std::string& basePath) { return findUniquePathWithSuffix(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& fileName) {
|
||||||
const std::string cacheDir = "/.crosspoint/sidecar_" + std::to_string(std::hash<std::string>{}(bookPath));
|
|
||||||
if (!Storage.exists(cacheDir.c_str())) {
|
if (!Storage.exists(cacheDir.c_str())) {
|
||||||
Storage.mkdir(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";
|
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) {
|
bool moveSidecarFilesToCompleted(const std::string& currentBookPath, const std::string& targetBookPath) {
|
||||||
|
|||||||
@@ -71,6 +71,12 @@ std::string ReaderActivity::sidecarCoverPath(const std::string& bookPath) {
|
|||||||
return "";
|
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<Epub> ReaderActivity::loadEpub(const std::string& path) {
|
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
|
||||||
if (!Storage.exists(path.c_str())) {
|
if (!Storage.exists(path.c_str())) {
|
||||||
LOG_ERR("READER", "File does not exist: %s", path.c_str());
|
LOG_ERR("READER", "File does not exist: %s", path.c_str());
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class ReaderActivity final : public Activity {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static std::string sidecarCoverPath(const std::string& bookPath);
|
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)
|
explicit ReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string initialBookPath)
|
||||||
: Activity("Reader", renderer, mappedInput), initialBookPath(std::move(initialBookPath)) {}
|
: Activity("Reader", renderer, mappedInput), initialBookPath(std::move(initialBookPath)) {}
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ void ClearCacheActivity::clearCache() {
|
|||||||
file.getName(name, sizeof(name));
|
file.getName(name, sizeof(name));
|
||||||
String itemName(name);
|
String itemName(name);
|
||||||
|
|
||||||
// Only delete directories starting with epub_ or xtc_
|
if (file.isDirectory() &&
|
||||||
if (file.isDirectory() && (itemName.startsWith("epub_") || itemName.startsWith("xtc_"))) {
|
(itemName.startsWith("epub_") || itemName.startsWith("xtc_") || itemName.startsWith("txt_"))) {
|
||||||
String fullPath = "/.crosspoint/" + itemName;
|
String fullPath = "/.crosspoint/" + itemName;
|
||||||
LOG_DBG("CLEAR_CACHE", "Removing cache: %s", fullPath.c_str());
|
LOG_DBG("CLEAR_CACHE", "Removing cache: %s", fullPath.c_str());
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <HalStorage.h>
|
#include <HalStorage.h>
|
||||||
#include <Logging.h>
|
#include <Logging.h>
|
||||||
|
#include <Txt.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
#include <Xtc.h>
|
||||||
#include <esp_task_wdt.h>
|
#include <esp_task_wdt.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -58,16 +60,25 @@ String wsLastCompleteName;
|
|||||||
size_t wsLastCompleteSize = 0;
|
size_t wsLastCompleteSize = 0;
|
||||||
unsigned long wsLastCompleteAt = 0;
|
unsigned long wsLastCompleteAt = 0;
|
||||||
|
|
||||||
// Helper function to clear epub cache after upload
|
void clearBookCacheIfNeeded(const String& filePath) {
|
||||||
void clearEpubCacheIfNeeded(const String& filePath) {
|
|
||||||
if (FsHelpers::hasEpubExtension(filePath)) {
|
if (FsHelpers::hasEpubExtension(filePath)) {
|
||||||
Epub(filePath.c_str(), "/.crosspoint").clearCache();
|
Epub(filePath.c_str(), "/.crosspoint").clearCache();
|
||||||
LOG_DBG("WEB", "Cleared epub cache for: %s", filePath.c_str());
|
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
|
// Recursively clear book caches for all ebooks inside a directory
|
||||||
void clearEpubCachesInDirectory(const String& dirPath) {
|
void clearBookCachesInDirectory(const String& dirPath) {
|
||||||
esp_task_wdt_reset();
|
esp_task_wdt_reset();
|
||||||
yield();
|
yield();
|
||||||
FsFile dir = Storage.open(dirPath.c_str());
|
FsFile dir = Storage.open(dirPath.c_str());
|
||||||
@@ -86,10 +97,10 @@ void clearEpubCachesInDirectory(const String& dirPath) {
|
|||||||
childPath += name;
|
childPath += name;
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
entry.close();
|
entry.close();
|
||||||
clearEpubCachesInDirectory(childPath);
|
clearBookCachesInDirectory(childPath);
|
||||||
} else {
|
} else {
|
||||||
entry.close();
|
entry.close();
|
||||||
clearEpubCacheIfNeeded(childPath);
|
clearBookCacheIfNeeded(childPath);
|
||||||
}
|
}
|
||||||
entry = dir.openNextFile();
|
entry = dir.openNextFile();
|
||||||
}
|
}
|
||||||
@@ -1210,7 +1221,7 @@ void CrossPointWebServer::handleDelete() const {
|
|||||||
// It's a file (or couldn't open as dir) — remove file
|
// It's a file (or couldn't open as dir) — remove file
|
||||||
if (f) f.close();
|
if (f) f.close();
|
||||||
success = Storage.remove(itemPath.c_str());
|
success = Storage.remove(itemPath.c_str());
|
||||||
clearEpubCacheIfNeeded(itemPath);
|
clearBookCacheIfNeeded(itemPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <HalStorage.h>
|
#include <HalStorage.h>
|
||||||
#include <Logging.h>
|
#include <Logging.h>
|
||||||
|
#include <Txt.h>
|
||||||
|
#include <Xtc.h>
|
||||||
#include <esp_task_wdt.h>
|
#include <esp_task_wdt.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -802,6 +804,16 @@ void WebDAVHandler::clearEpubCacheIfNeeded(const String& path) const {
|
|||||||
if (FsHelpers::hasEpubExtension(path)) {
|
if (FsHelpers::hasEpubExtension(path)) {
|
||||||
Epub(path.c_str(), "/.crosspoint").clearCache();
|
Epub(path.c_str(), "/.crosspoint").clearCache();
|
||||||
LOG_DBG("DAV", "Cleared epub cache for: %s", path.c_str());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user