diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 265943ff..cdcea92a 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -77,6 +77,54 @@ bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata) { bookMetadata.author = opfParser.author; bookMetadata.language = opfParser.language; bookMetadata.coverItemHref = opfParser.coverItemHref; + + // Guide-based cover fallback: if no cover found via metadata/properties, + // try extracting the image reference from the guide's cover page XHTML + if (bookMetadata.coverItemHref.empty() && !opfParser.guideCoverPageHref.empty()) { + LOG_DBG("EBP", "No cover from metadata, trying guide cover page: %s", opfParser.guideCoverPageHref.c_str()); + size_t coverPageSize; + uint8_t* coverPageData = readItemContentsToBytes(opfParser.guideCoverPageHref, &coverPageSize, true); + if (coverPageData) { + const std::string coverPageHtml(reinterpret_cast(coverPageData), coverPageSize); + free(coverPageData); + + // Determine base path of the cover page for resolving relative image references + std::string coverPageBase; + const auto lastSlash = opfParser.guideCoverPageHref.rfind('/'); + if (lastSlash != std::string::npos) { + coverPageBase = opfParser.guideCoverPageHref.substr(0, lastSlash + 1); + } + + // Search for image references: xlink:href="..." (SVG) and src="..." (img) + std::string imageRef; + for (const char* pattern : {"xlink:href=\"", "src=\""}) { + auto pos = coverPageHtml.find(pattern); + while (pos != std::string::npos) { + pos += strlen(pattern); + const auto endPos = coverPageHtml.find('"', pos); + if (endPos != std::string::npos) { + const auto ref = coverPageHtml.substr(pos, endPos - pos); + // Check if it's an image file + if (ref.length() >= 4) { + const auto ext = ref.substr(ref.length() - 4); + if (ext == ".png" || ext == ".jpg" || ext == "jpeg" || ext == ".gif") { + imageRef = ref; + break; + } + } + } + pos = coverPageHtml.find(pattern, pos); + } + if (!imageRef.empty()) break; + } + + if (!imageRef.empty()) { + bookMetadata.coverItemHref = FsHelpers::normalisePath(coverPageBase + imageRef); + LOG_DBG("EBP", "Found cover image from guide: %s", bookMetadata.coverItemHref.c_str()); + } + } + } + bookMetadata.textReferenceHref = opfParser.textReferenceHref; if (!opfParser.tocNcxPath.empty()) { diff --git a/lib/Epub/Epub/parsers/ContentOpfParser.cpp b/lib/Epub/Epub/parsers/ContentOpfParser.cpp index fd0708fd..c3a30a3b 100644 --- a/lib/Epub/Epub/parsers/ContentOpfParser.cpp +++ b/lib/Epub/Epub/parsers/ContentOpfParser.cpp @@ -296,23 +296,22 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name // parse the guide if (self->state == IN_GUIDE && (strcmp(name, "reference") == 0 || strcmp(name, "opf:reference") == 0)) { std::string type; - std::string textHref; + std::string guideHref; for (int i = 0; atts[i]; i += 2) { if (strcmp(atts[i], "type") == 0) { type = atts[i + 1]; - if (type == "text" || type == "start") { - continue; - } else { - LOG_DBG("COF", "Skipping non-text reference in guide: %s", type.c_str()); - break; - } } else if (strcmp(atts[i], "href") == 0) { - textHref = FsHelpers::normalisePath(self->baseContentPath + atts[i + 1]); + guideHref = FsHelpers::normalisePath(self->baseContentPath + atts[i + 1]); } } - if ((type == "text" || (type == "start" && !self->textReferenceHref.empty())) && (textHref.length() > 0)) { - LOG_DBG("COF", "Found %s reference in guide: %s.", type.c_str(), textHref.c_str()); - self->textReferenceHref = textHref; + if (!guideHref.empty()) { + if (type == "text" || (type == "start" && !self->textReferenceHref.empty())) { + LOG_DBG("COF", "Found %s reference in guide: %s", type.c_str(), guideHref.c_str()); + self->textReferenceHref = guideHref; + } else if ((type == "cover" || type == "cover-page") && self->guideCoverPageHref.empty()) { + LOG_DBG("COF", "Found cover reference in guide: %s", guideHref.c_str()); + self->guideCoverPageHref = guideHref; + } } return; } diff --git a/lib/Epub/Epub/parsers/ContentOpfParser.h b/lib/Epub/Epub/parsers/ContentOpfParser.h index 1253eae3..89fb3379 100644 --- a/lib/Epub/Epub/parsers/ContentOpfParser.h +++ b/lib/Epub/Epub/parsers/ContentOpfParser.h @@ -63,6 +63,7 @@ class ContentOpfParser final : public Print { std::string tocNcxPath; std::string tocNavPath; // EPUB 3 nav document path std::string coverItemHref; + std::string guideCoverPageHref; // Guide reference with type="cover" or "cover-page" (points to XHTML wrapper) std::string textReferenceHref; std::vector cssFiles; // CSS stylesheet paths