diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 941e11ba..2ddc6db6 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -75,6 +75,7 @@ bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata) { // TODO: Parse author bookMetadata.author = ""; bookMetadata.coverItemHref = opfParser.coverItemHref; + bookMetadata.textReferenceHref = opfParser.textReferenceHref; if (!opfParser.tocNcxPath.empty()) { tocNcxItem = opfParser.tocNcxPath; @@ -414,6 +415,35 @@ size_t Epub::getBookSize() const { return getCumulativeSpineItemSize(getSpineItemsCount() - 1); } +int Epub::getSpineIndexForTextReference() const { + if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { + Serial.printf("[%lu] [EBP] getSpineIndexForTextReference called but cache not loaded\n", millis()); + return 0; + } + Serial.printf("[%lu] [ERS] Core Metadata: cover(%d)=%s, textReference(%d)=%s\n", millis(), + bookMetadataCache->coreMetadata.coverItemHref.size(), + bookMetadataCache->coreMetadata.coverItemHref.c_str(), + bookMetadataCache->coreMetadata.textReferenceHref.size(), + bookMetadataCache->coreMetadata.textReferenceHref.c_str()); + + if (bookMetadataCache->coreMetadata.textReferenceHref.empty()) { + // there was no textReference in epub, so we return 0 (the first chapter) + return 0; + } + + // loop through spine items to get the correct index matching the text href + for (size_t i = 0; i < getSpineItemsCount(); i++) { + if (getSpineItem(i).href == bookMetadataCache->coreMetadata.textReferenceHref) { + Serial.printf("[%lu] [ERS] Text reference %s found at index %d\n", millis(), + bookMetadataCache->coreMetadata.textReferenceHref.c_str(), i); + return i; + } + } + // This should not happen, as we checked for empty textReferenceHref earlier + Serial.printf("[%lu] [EBP] Section not found for text reference\n", millis()); + return 0; +} + // Calculate progress in book uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) const { const size_t bookSize = getBookSize(); diff --git a/lib/Epub/Epub.h b/lib/Epub/Epub.h index c7850081..178c48c6 100644 --- a/lib/Epub/Epub.h +++ b/lib/Epub/Epub.h @@ -51,6 +51,7 @@ class Epub { int getSpineIndexForTocIndex(int tocIndex) const; int getTocIndexForSpineIndex(int spineIndex) const; size_t getCumulativeSpineItemSize(int spineIndex) const; + int getSpineIndexForTextReference() const; size_t getBookSize() const; uint8_t calculateProgress(int currentSpineIndex, float currentSpineRead) const; diff --git a/lib/Epub/Epub/BookMetadataCache.cpp b/lib/Epub/Epub/BookMetadataCache.cpp index 8fcee282..1f6a96e9 100644 --- a/lib/Epub/Epub/BookMetadataCache.cpp +++ b/lib/Epub/Epub/BookMetadataCache.cpp @@ -88,8 +88,8 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta constexpr size_t headerASize = sizeof(BOOK_CACHE_VERSION) + /* LUT Offset */ sizeof(size_t) + sizeof(spineCount) + sizeof(tocCount); - const size_t metadataSize = - metadata.title.size() + metadata.author.size() + metadata.coverItemHref.size() + sizeof(uint32_t) * 3; + const size_t metadataSize = metadata.title.size() + metadata.author.size() + metadata.coverItemHref.size() + + metadata.textReferenceHref.size() + sizeof(uint32_t) * 4; const size_t lutSize = sizeof(size_t) * spineCount + sizeof(size_t) * tocCount; const size_t lutOffset = headerASize + metadataSize; @@ -102,6 +102,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta serialization::writeString(bookFile, metadata.title); serialization::writeString(bookFile, metadata.author); serialization::writeString(bookFile, metadata.coverItemHref); + serialization::writeString(bookFile, metadata.textReferenceHref); // Loop through spine entries, writing LUT positions spineFile.seek(0); @@ -286,6 +287,7 @@ bool BookMetadataCache::load() { serialization::readString(bookFile, coreMetadata.title); serialization::readString(bookFile, coreMetadata.author); serialization::readString(bookFile, coreMetadata.coverItemHref); + serialization::readString(bookFile, coreMetadata.textReferenceHref); loaded = true; Serial.printf("[%lu] [BMC] Loaded cache data: %d spine, %d TOC entries\n", millis(), spineCount, tocCount); diff --git a/lib/Epub/Epub/BookMetadataCache.h b/lib/Epub/Epub/BookMetadataCache.h index 7f9f419c..5a54cc1a 100644 --- a/lib/Epub/Epub/BookMetadataCache.h +++ b/lib/Epub/Epub/BookMetadataCache.h @@ -10,6 +10,7 @@ class BookMetadataCache { std::string title; std::string author; std::string coverItemHref; + std::string textReferenceHref; }; struct SpineEntry { diff --git a/lib/Epub/Epub/parsers/ContentOpfParser.cpp b/lib/Epub/Epub/parsers/ContentOpfParser.cpp index 85604d2e..085bda56 100644 --- a/lib/Epub/Epub/parsers/ContentOpfParser.cpp +++ b/lib/Epub/Epub/parsers/ContentOpfParser.cpp @@ -219,19 +219,19 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name for (int i = 0; atts[i]; i += 2) { if (strcmp(atts[i], "type") == 0) { type = atts[i + 1]; - if (type == "text") { + if (type == "text" || type == "start") { continue; } else { Serial.printf("[%lu] [COF] Skipping non-text reference in guide: %s\n", millis(), type.c_str()); break; } } else if (strcmp(atts[i], "href") == 0) { - textHref = atts[i + 1]; + textHref = self->baseContentPath + atts[i + 1]; } } - if ((type == "text") && (textHref.length() > 0)) { - Serial.printf("[%lu] [COF] Found text reference in guide: %s.\n", millis(), textHref.c_str()); - // TODO: now this has to become the chapter we display + if ((type == "text" || (type == "start" && !self->textReferenceHref.empty())) && (textHref.length() > 0)) { + Serial.printf("[%lu] [COF] Found %s reference in guide: %s.\n", millis(), type.c_str(), textHref.c_str()); + self->textReferenceHref = textHref; } return; } diff --git a/lib/Epub/Epub/parsers/ContentOpfParser.h b/lib/Epub/Epub/parsers/ContentOpfParser.h index 252ebee1..c7764fc2 100644 --- a/lib/Epub/Epub/parsers/ContentOpfParser.h +++ b/lib/Epub/Epub/parsers/ContentOpfParser.h @@ -34,6 +34,7 @@ class ContentOpfParser final : public Print { std::string title; std::string tocNcxPath; std::string coverItemHref; + std::string textReferenceHref; explicit ContentOpfParser(const std::string& cachePath, const std::string& baseContentPath, const size_t xmlSize, BookMetadataCache* cache) diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 6864a563..a535240a 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -64,6 +64,16 @@ void EpubReaderActivity::onEnter() { } f.close(); } + // TODO: Need a better condition to detect if we are opening for the first time. This will trigger if the book is + // re-opened at Chapter 0. + if (currentSpineIndex == 0) { + int textSpineIndex = epub->getSpineIndexForTextReference(); + if (textSpineIndex != 0) { + currentSpineIndex = textSpineIndex; + Serial.printf("[%lu] [ERS] Opened for first time, navigating to text reference at index %d\n", millis(), + textSpineIndex); + } + } // Save current epub as last opened epub APP_STATE.openEpubPath = epub->getPath();