feat: implement CSS enumeration through OPF directory when missing from manifest (#2148)
This commit is contained in:
+40
-1
@@ -255,6 +255,38 @@ bool Epub::parseTocNavFile() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Epub::discoverCssFilesFromZip() {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
LOG_ERR("EBP", "Cannot discover CSS from ZIP because book metadata cache is not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
ZipFile zf(filepath);
|
||||
|
||||
if (!zf.loadAllFileStatSlims()) {
|
||||
LOG_ERR("EBP", "Failed to load ZIP file stat slims for CSS discovery");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t lastSlash = contentBasePath.find_last_of('/');
|
||||
|
||||
std::string opfDir = (lastSlash != std::string::npos) ? contentBasePath.substr(0, lastSlash + 1) : "";
|
||||
|
||||
zf.enumerateFilePaths([&](std::string_view filePath) {
|
||||
if (!opfDir.empty() && filePath.find(opfDir) != 0) {
|
||||
return; // Skip files that are not in the same directory as OPF manifest, as CSS files are typically located
|
||||
// there or in subfolders
|
||||
}
|
||||
|
||||
if (FsHelpers::hasCssExtension(filePath)) {
|
||||
if (std::find(cssFiles.begin(), cssFiles.end(), filePath) == cssFiles.end()) {
|
||||
LOG_DBG("EBP", "Discovered CSS file via ZIP enumeration: %.*s", (int)filePath.size(), filePath.data());
|
||||
cssFiles.push_back(std::string{filePath});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Epub::parseCssFiles() const {
|
||||
// Maximum CSS file size we'll attempt to parse (uncompressed)
|
||||
// Larger files risk memory exhaustion on ESP32
|
||||
@@ -329,9 +361,9 @@ void Epub::parseCssFiles() const {
|
||||
if (!cssParser->saveToCache()) {
|
||||
LOG_ERR("EBP", "Failed to save CSS rules to cache");
|
||||
}
|
||||
cssParser->clear();
|
||||
|
||||
LOG_DBG("EBP", "Loaded %zu CSS style rules from %zu files", cssParser->ruleCount(), cssFiles.size());
|
||||
cssParser->clear();
|
||||
}
|
||||
|
||||
// load in the meta data for the epub file
|
||||
@@ -354,6 +386,10 @@ bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||
if (!parseContentOpf(bookMetadataCache->coreMetadata)) {
|
||||
LOG_ERR("EBP", "Could not parse content.opf from cached bookMetadata for CSS files");
|
||||
// continue anyway - book will work without CSS and we'll still load any inline style CSS
|
||||
} else {
|
||||
// Handle case where CSS files are not listed in OPF manifest
|
||||
// but are still referenced by HTML files - discover and parse them too
|
||||
discoverCssFilesFromZip();
|
||||
}
|
||||
parseCssFiles();
|
||||
// Invalidate section caches so they are rebuilt with the new CSS
|
||||
@@ -457,6 +493,9 @@ bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||
}
|
||||
|
||||
if (!skipLoadingCss) {
|
||||
// Handle case where CSS files are not listed in OPF manifest
|
||||
// but are still referenced by HTML files - discover and parse them too
|
||||
discoverCssFilesFromZip();
|
||||
// Parse CSS files after cache reload
|
||||
parseCssFiles();
|
||||
Storage.removeDir((cachePath + "/sections").c_str());
|
||||
|
||||
@@ -35,6 +35,7 @@ class Epub {
|
||||
bool parseTocNcxFile() const;
|
||||
bool parseTocNavFile() const;
|
||||
void parseCssFiles() const;
|
||||
void discoverCssFilesFromZip();
|
||||
|
||||
public:
|
||||
explicit Epub(std::string filepath, const std::string& cacheDir) : filepath(std::move(filepath)) {
|
||||
|
||||
Reference in New Issue
Block a user