mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 14:47:37 +03:00
feat: integrate CSS rules caching in Epub loader
- Add cssFiles member to Epub class (moved from BookMetadataCache) - Add getCssRulesCache() and loadCssRulesFromCache() methods - Update parseCssFiles() to save parsed rules to cache - Try loading from css_rules.cache before parsing CSS files - Add skipLoadingCss parameter to Epub::load() for performance - Remove cssFiles from BookMetadataCache (no longer needed) - Revert BookMetadataCache version to 5 (pre-CSS-files format) When loading an EPUB: 1. Try to load cached CSS rules first 2. If cache miss, parse CSS files and save to cache 3. If skipLoadingCss=true, skip CSS entirely (for cover display)
This commit is contained in:
parent
6115bf3cd2
commit
cd61b263e5
@ -86,8 +86,9 @@ bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata) {
|
|||||||
tocNavItem = opfParser.tocNavPath;
|
tocNavItem = opfParser.tocNavPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy CSS files to metadata
|
if (!opfParser.cssFiles.empty()) {
|
||||||
bookMetadata.cssFiles = opfParser.cssFiles;
|
cssFiles = opfParser.cssFiles;
|
||||||
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [EBP] Successfully parsed content.opf\n", millis());
|
Serial.printf("[%lu] [EBP] Successfully parsed content.opf\n", millis());
|
||||||
return true;
|
return true;
|
||||||
@ -207,21 +208,30 @@ bool Epub::parseTocNavFile() const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Epub::parseCssFiles() {
|
std::string Epub::getCssRulesCache() const { return cachePath + "/css_rules.cache"; }
|
||||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
|
||||||
Serial.printf("[%lu] [EBP] Cannot parse CSS, cache not loaded\n", millis());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always create CssParser - needed for inline style parsing even without CSS files
|
bool Epub::loadCssRulesFromCache() const {
|
||||||
cssParser.reset(new CssParser());
|
FsFile cssCacheFile;
|
||||||
|
if (SdMan.openFileForRead("EBP", getCssRulesCache(), cssCacheFile)) {
|
||||||
const auto& cssFiles = bookMetadataCache->coreMetadata.cssFiles;
|
if (cssParser->loadFromCache(cssCacheFile)) {
|
||||||
if (cssFiles.empty()) {
|
cssCacheFile.close();
|
||||||
Serial.printf("[%lu] [EBP] No CSS files to parse, but CssParser created for inline styles\n", millis());
|
Serial.printf("[%lu] [EBP] Loaded CSS rules from cache\n", millis());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
cssCacheFile.close();
|
||||||
|
Serial.printf("[%lu] [EBP] CSS cache invalid, reparsing\n", millis());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Epub::parseCssFiles() const {
|
||||||
|
if (cssFiles.empty()) {
|
||||||
|
Serial.printf("[%lu] [EBP] No CSS files to parse, but CssParser created for inline styles\n", millis());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load from CSS cache first
|
||||||
|
if (!loadCssRulesFromCache()) {
|
||||||
|
// Cache miss - parse CSS files
|
||||||
for (const auto& cssPath : cssFiles) {
|
for (const auto& cssPath : cssFiles) {
|
||||||
Serial.printf("[%lu] [EBP] Parsing CSS file: %s\n", millis(), cssPath.c_str());
|
Serial.printf("[%lu] [EBP] Parsing CSS file: %s\n", millis(), cssPath.c_str());
|
||||||
|
|
||||||
@ -251,22 +261,38 @@ bool Epub::parseCssFiles() {
|
|||||||
SdMan.remove(tmpCssPath.c_str());
|
SdMan.remove(tmpCssPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save to cache for next time
|
||||||
|
FsFile cssCacheFile;
|
||||||
|
if (SdMan.openFileForWrite("EBP", getCssRulesCache(), cssCacheFile)) {
|
||||||
|
cssParser->saveToCache(cssCacheFile);
|
||||||
|
cssCacheFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [EBP] Loaded %zu CSS style rules from %zu files\n", millis(), cssParser->ruleCount(),
|
Serial.printf("[%lu] [EBP] Loaded %zu CSS style rules from %zu files\n", millis(), cssParser->ruleCount(),
|
||||||
cssFiles.size());
|
cssFiles.size());
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load in the meta data for the epub file
|
// load in the meta data for the epub file
|
||||||
bool Epub::load(const bool buildIfMissing) {
|
bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||||
Serial.printf("[%lu] [EBP] Loading ePub: %s\n", millis(), filepath.c_str());
|
Serial.printf("[%lu] [EBP] Loading ePub: %s\n", millis(), filepath.c_str());
|
||||||
|
|
||||||
// Initialize spine/TOC cache
|
// Initialize spine/TOC cache
|
||||||
bookMetadataCache.reset(new BookMetadataCache(cachePath));
|
bookMetadataCache.reset(new BookMetadataCache(cachePath));
|
||||||
|
// Always create CssParser - needed for inline style parsing even without CSS files
|
||||||
|
cssParser.reset(new CssParser());
|
||||||
|
|
||||||
// Try to load existing cache first
|
// Try to load existing cache first
|
||||||
if (bookMetadataCache->load()) {
|
if (bookMetadataCache->load()) {
|
||||||
// Parse CSS files from loaded cache
|
if (!skipLoadingCss && !loadCssRulesFromCache()) {
|
||||||
|
Serial.printf("[%lu] [EBP] Warning: CSS rules cache not found, attempting to parse CSS files\n", millis());
|
||||||
|
// to get CSS file list
|
||||||
|
if (!parseContentOpf(bookMetadataCache->coreMetadata)) {
|
||||||
|
Serial.printf("[%lu] [EBP] Could not parse content.opf from cached bookMetadata for CSS files\n", millis());
|
||||||
|
// continue anyway - book will work without CSS and we'll still load any inline style CSS
|
||||||
|
}
|
||||||
parseCssFiles();
|
parseCssFiles();
|
||||||
|
}
|
||||||
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
|
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -363,8 +389,10 @@ bool Epub::load(const bool buildIfMissing) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skipLoadingCss) {
|
||||||
// Parse CSS files after cache reload
|
// Parse CSS files after cache reload
|
||||||
parseCssFiles();
|
parseCssFiles();
|
||||||
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
|
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -27,12 +27,16 @@ class Epub {
|
|||||||
std::unique_ptr<BookMetadataCache> bookMetadataCache;
|
std::unique_ptr<BookMetadataCache> bookMetadataCache;
|
||||||
// CSS parser for styling
|
// CSS parser for styling
|
||||||
std::unique_ptr<CssParser> cssParser;
|
std::unique_ptr<CssParser> cssParser;
|
||||||
|
// CSS files
|
||||||
|
std::vector<std::string> cssFiles;
|
||||||
|
|
||||||
bool findContentOpfFile(std::string* contentOpfFile) const;
|
bool findContentOpfFile(std::string* contentOpfFile) const;
|
||||||
bool parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata);
|
bool parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata);
|
||||||
bool parseTocNcxFile() const;
|
bool parseTocNcxFile() const;
|
||||||
bool parseTocNavFile() const;
|
bool parseTocNavFile() const;
|
||||||
bool parseCssFiles();
|
void parseCssFiles() const;
|
||||||
|
std::string getCssRulesCache() const;
|
||||||
|
bool loadCssRulesFromCache() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Epub(std::string filepath, const std::string& cacheDir) : filepath(std::move(filepath)) {
|
explicit Epub(std::string filepath, const std::string& cacheDir) : filepath(std::move(filepath)) {
|
||||||
@ -41,7 +45,7 @@ class Epub {
|
|||||||
}
|
}
|
||||||
~Epub() = default;
|
~Epub() = default;
|
||||||
std::string& getBasePath() { return contentBasePath; }
|
std::string& getBasePath() { return contentBasePath; }
|
||||||
bool load(bool buildIfMissing = true);
|
bool load(bool buildIfMissing = true, bool skipLoadingCss = false);
|
||||||
bool clearCache() const;
|
bool clearCache() const;
|
||||||
void setupCacheDir() const;
|
void setupCacheDir() const;
|
||||||
const std::string& getCachePath() const;
|
const std::string& getCachePath() const;
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
#include "FsHelpers.h"
|
#include "FsHelpers.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr uint8_t BOOK_CACHE_VERSION = 6;
|
constexpr uint8_t BOOK_CACHE_VERSION = 5;
|
||||||
constexpr char bookBinFile[] = "/book.bin";
|
constexpr char bookBinFile[] = "/book.bin";
|
||||||
constexpr char tmpSpineBinFile[] = "/spine.bin.tmp";
|
constexpr char tmpSpineBinFile[] = "/spine.bin.tmp";
|
||||||
constexpr char tmpTocBinFile[] = "/toc.bin.tmp";
|
constexpr char tmpTocBinFile[] = "/toc.bin.tmp";
|
||||||
@ -115,14 +115,9 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
|||||||
|
|
||||||
constexpr uint32_t headerASize =
|
constexpr uint32_t headerASize =
|
||||||
sizeof(BOOK_CACHE_VERSION) + /* LUT Offset */ sizeof(uint32_t) + sizeof(spineCount) + sizeof(tocCount);
|
sizeof(BOOK_CACHE_VERSION) + /* LUT Offset */ sizeof(uint32_t) + sizeof(spineCount) + sizeof(tocCount);
|
||||||
// Calculate CSS files size: count + each string (length + data)
|
|
||||||
uint32_t cssFilesSize = sizeof(uint16_t); // count
|
|
||||||
for (const auto& css : metadata.cssFiles) {
|
|
||||||
cssFilesSize += sizeof(uint32_t) + css.size();
|
|
||||||
}
|
|
||||||
const uint32_t metadataSize = metadata.title.size() + metadata.author.size() + metadata.language.size() +
|
const uint32_t metadataSize = metadata.title.size() + metadata.author.size() + metadata.language.size() +
|
||||||
metadata.coverItemHref.size() + metadata.textReferenceHref.size() +
|
metadata.coverItemHref.size() + metadata.textReferenceHref.size() +
|
||||||
sizeof(uint32_t) * 5 + cssFilesSize;
|
sizeof(uint32_t) * 5;
|
||||||
const uint32_t lutSize = sizeof(uint32_t) * spineCount + sizeof(uint32_t) * tocCount;
|
const uint32_t lutSize = sizeof(uint32_t) * spineCount + sizeof(uint32_t) * tocCount;
|
||||||
const uint32_t lutOffset = headerASize + metadataSize;
|
const uint32_t lutOffset = headerASize + metadataSize;
|
||||||
|
|
||||||
@ -137,11 +132,6 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
|||||||
serialization::writeString(bookFile, metadata.language);
|
serialization::writeString(bookFile, metadata.language);
|
||||||
serialization::writeString(bookFile, metadata.coverItemHref);
|
serialization::writeString(bookFile, metadata.coverItemHref);
|
||||||
serialization::writeString(bookFile, metadata.textReferenceHref);
|
serialization::writeString(bookFile, metadata.textReferenceHref);
|
||||||
// CSS files
|
|
||||||
serialization::writePod(bookFile, static_cast<uint16_t>(metadata.cssFiles.size()));
|
|
||||||
for (const auto& css : metadata.cssFiles) {
|
|
||||||
serialization::writeString(bookFile, css);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through spine entries, writing LUT positions
|
// Loop through spine entries, writing LUT positions
|
||||||
spineFile.seek(0);
|
spineFile.seek(0);
|
||||||
@ -395,16 +385,6 @@ bool BookMetadataCache::load() {
|
|||||||
serialization::readString(bookFile, coreMetadata.language);
|
serialization::readString(bookFile, coreMetadata.language);
|
||||||
serialization::readString(bookFile, coreMetadata.coverItemHref);
|
serialization::readString(bookFile, coreMetadata.coverItemHref);
|
||||||
serialization::readString(bookFile, coreMetadata.textReferenceHref);
|
serialization::readString(bookFile, coreMetadata.textReferenceHref);
|
||||||
// CSS files
|
|
||||||
uint16_t cssCount;
|
|
||||||
serialization::readPod(bookFile, cssCount);
|
|
||||||
coreMetadata.cssFiles.clear();
|
|
||||||
coreMetadata.cssFiles.reserve(cssCount);
|
|
||||||
for (uint16_t i = 0; i < cssCount; i++) {
|
|
||||||
std::string cssPath;
|
|
||||||
serialization::readString(bookFile, cssPath);
|
|
||||||
coreMetadata.cssFiles.push_back(std::move(cssPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
loaded = true;
|
loaded = true;
|
||||||
Serial.printf("[%lu] [BMC] Loaded cache data: %d spine, %d TOC entries\n", millis(), spineCount, tocCount);
|
Serial.printf("[%lu] [BMC] Loaded cache data: %d spine, %d TOC entries\n", millis(), spineCount, tocCount);
|
||||||
|
|||||||
@ -14,7 +14,6 @@ class BookMetadataCache {
|
|||||||
std::string language;
|
std::string language;
|
||||||
std::string coverItemHref;
|
std::string coverItemHref;
|
||||||
std::string textReferenceHref;
|
std::string textReferenceHref;
|
||||||
std::vector<std::string> cssFiles;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpineEntry {
|
struct SpineEntry {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user