Fix initial horrible performance for books without a cover
This commit is contained in:
+62
-23
@@ -76,6 +76,7 @@ bool Epub::findContentOpfFile(std::string* contentOpfFile) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata, OpfCacheMode cacheMode) {
|
bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata, OpfCacheMode cacheMode) {
|
||||||
|
const unsigned long opfParseStart = millis();
|
||||||
std::string contentOpfFilePath;
|
std::string contentOpfFilePath;
|
||||||
if (!findContentOpfFile(&contentOpfFilePath)) {
|
if (!findContentOpfFile(&contentOpfFilePath)) {
|
||||||
LOG_ERR("EBP", "Could not find content.opf in zip");
|
LOG_ERR("EBP", "Could not find content.opf in zip");
|
||||||
@@ -91,6 +92,7 @@ bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata, OpfCac
|
|||||||
LOG_ERR("EBP", "Could not get size of content.opf");
|
LOG_ERR("EBP", "Could not get size of content.opf");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
LOG_DBG("EBP", "content.opf size=%zu bytes", contentOpfSize);
|
||||||
|
|
||||||
ContentOpfParser opfParser(getCachePath(), getBasePath(), contentOpfSize,
|
ContentOpfParser opfParser(getCachePath(), getBasePath(), contentOpfSize,
|
||||||
cacheMode == OpfCacheMode::Enabled ? bookMetadataCache.get() : nullptr);
|
cacheMode == OpfCacheMode::Enabled ? bookMetadataCache.get() : nullptr);
|
||||||
@@ -99,10 +101,18 @@ bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata, OpfCac
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unsigned long streamStart = millis();
|
||||||
if (!readItemContentsToStream(contentOpfFilePath, opfParser, 1024)) {
|
if (!readItemContentsToStream(contentOpfFilePath, opfParser, 1024)) {
|
||||||
LOG_ERR("EBP", "Could not read content.opf");
|
LOG_ERR("EBP", "Could not read content.opf");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const unsigned long streamMs = millis() - streamStart;
|
||||||
|
LOG_DBG("EBP",
|
||||||
|
"content.opf stream=%lu ms, parser.write_calls=%zu, bytes=%zu, parse_buffer=%lu ms, manifest_open=%lu ms, "
|
||||||
|
"spine_open=%lu ms, guide_open=%lu ms, itemrefs=%zu, itemref_lookup=%lu ms, create_spine=%lu ms",
|
||||||
|
streamMs, opfParser.stats.writeCalls, opfParser.stats.bytesParsed, opfParser.stats.parseBufferMs,
|
||||||
|
opfParser.stats.manifestOpenMs, opfParser.stats.spineOpenMs, opfParser.stats.guideOpenMs,
|
||||||
|
opfParser.stats.itemRefCount, opfParser.stats.itemRefLookupMs, opfParser.stats.createSpineEntryMs);
|
||||||
|
|
||||||
// Grab data from opfParser into epub
|
// Grab data from opfParser into epub
|
||||||
bookMetadata.title = opfParser.title;
|
bookMetadata.title = opfParser.title;
|
||||||
@@ -241,34 +251,62 @@ bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata, OpfCac
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& baseDir : baseDirs) {
|
const unsigned long coverBatchStart = millis();
|
||||||
for (const char* subDir : kCoverSubdirs) {
|
ZipFile zip(filepath);
|
||||||
for (const char* baseName : kCoverBaseNames) {
|
const bool zipIndexLoaded = zip.loadAllFileStatSlims();
|
||||||
const std::string lowerBase = baseName;
|
LOG_DBG("EBP", "Common cover fallback indexed ZIP in %lu ms (ok=%d)", millis() - coverBatchStart,
|
||||||
const std::string upperBase = toUpper(lowerBase);
|
zipIndexLoaded ? 1 : 0);
|
||||||
for (const std::string* baseVariant : {&lowerBase, &upperBase}) {
|
|
||||||
for (const char* ext : kCoverExtensions) {
|
if (zipIndexLoaded) {
|
||||||
const std::string lowerExt = ext;
|
int checkedCandidates = 0;
|
||||||
const std::string upperExt = toUpper(lowerExt);
|
const auto tryCandidate = [&](const std::string& candidate) {
|
||||||
for (const std::string* extVariant : {&lowerExt, &upperExt}) {
|
checkedCandidates++;
|
||||||
const std::string candidate =
|
size_t coverSize = 0;
|
||||||
FsHelpers::normalisePath(baseDir + subDir + *baseVariant + "." + *extVariant);
|
if (zip.getInflatedFileSize(candidate.c_str(), &coverSize) && coverSize > 0) {
|
||||||
if (hasReadableSupportedCover(candidate)) {
|
bookMetadata.coverItemHref = candidate;
|
||||||
bookMetadata.coverItemHref = candidate;
|
LOG_DBG("EBP", "Found cover image via common candidate fallback after %d checks in %lu ms: %s",
|
||||||
LOG_DBG("EBP", "Found cover image via common candidate fallback: %s",
|
checkedCandidates, millis() - coverBatchStart, bookMetadata.coverItemHref.c_str());
|
||||||
bookMetadata.coverItemHref.c_str());
|
return true;
|
||||||
goto cover_fallback_done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool foundCoverCandidate = false;
|
||||||
|
for (const auto& baseDir : baseDirs) {
|
||||||
|
for (const char* subDir : kCoverSubdirs) {
|
||||||
|
for (const char* baseName : kCoverBaseNames) {
|
||||||
|
const std::string lowerBase = baseName;
|
||||||
|
const std::string upperBase = toUpper(lowerBase);
|
||||||
|
for (const std::string* baseVariant : {&lowerBase, &upperBase}) {
|
||||||
|
for (const char* ext : kCoverExtensions) {
|
||||||
|
const std::string lowerExt = ext;
|
||||||
|
const std::string upperExt = toUpper(lowerExt);
|
||||||
|
for (const std::string* extVariant : {&lowerExt, &upperExt}) {
|
||||||
|
const std::string candidate =
|
||||||
|
FsHelpers::normalisePath(baseDir + subDir + *baseVariant + "." + *extVariant);
|
||||||
|
if (tryCandidate(candidate)) {
|
||||||
|
foundCoverCandidate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundCoverCandidate) break;
|
||||||
|
}
|
||||||
|
if (foundCoverCandidate) break;
|
||||||
|
}
|
||||||
|
if (foundCoverCandidate) break;
|
||||||
|
}
|
||||||
|
if (foundCoverCandidate) break;
|
||||||
|
}
|
||||||
|
if (foundCoverCandidate) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundCoverCandidate) {
|
||||||
|
LOG_DBG("EBP", "Common cover fallback checked %d cached candidates in %lu ms with no match", checkedCandidates,
|
||||||
|
millis() - coverBatchStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cover_fallback_done:
|
|
||||||
|
|
||||||
bookMetadata.textReferenceHref = opfParser.textReferenceHref;
|
bookMetadata.textReferenceHref = opfParser.textReferenceHref;
|
||||||
|
|
||||||
if (!opfParser.tocNcxPath.empty()) {
|
if (!opfParser.tocNcxPath.empty()) {
|
||||||
@@ -283,6 +321,7 @@ cover_fallback_done:
|
|||||||
cssFiles = opfParser.cssFiles;
|
cssFiles = opfParser.cssFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_DBG("EBP", "parseContentOpf total=%lu ms", millis() - opfParseStart);
|
||||||
LOG_DBG("EBP", "Successfully parsed content.opf");
|
LOG_DBG("EBP", "Successfully parsed content.opf");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user