Go to the guide::text reference when book is first opened.

This commit is contained in:
Jonas Diemer 2025-12-29 19:19:54 +01:00
parent 1e59aa6d5d
commit b66e4486fc
7 changed files with 52 additions and 7 deletions

View File

@ -75,6 +75,7 @@ bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata) {
// TODO: Parse author // TODO: Parse author
bookMetadata.author = ""; bookMetadata.author = "";
bookMetadata.coverItemHref = opfParser.coverItemHref; bookMetadata.coverItemHref = opfParser.coverItemHref;
bookMetadata.textReferenceHref = opfParser.textReferenceHref;
if (!opfParser.tocNcxPath.empty()) { if (!opfParser.tocNcxPath.empty()) {
tocNcxItem = opfParser.tocNcxPath; tocNcxItem = opfParser.tocNcxPath;
@ -414,6 +415,35 @@ size_t Epub::getBookSize() const {
return getCumulativeSpineItemSize(getSpineItemsCount() - 1); 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 // Calculate progress in book
uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) const { uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) const {
const size_t bookSize = getBookSize(); const size_t bookSize = getBookSize();

View File

@ -51,6 +51,7 @@ class Epub {
int getSpineIndexForTocIndex(int tocIndex) const; int getSpineIndexForTocIndex(int tocIndex) const;
int getTocIndexForSpineIndex(int spineIndex) const; int getTocIndexForSpineIndex(int spineIndex) const;
size_t getCumulativeSpineItemSize(int spineIndex) const; size_t getCumulativeSpineItemSize(int spineIndex) const;
int getSpineIndexForTextReference() const;
size_t getBookSize() const; size_t getBookSize() const;
uint8_t calculateProgress(int currentSpineIndex, float currentSpineRead) const; uint8_t calculateProgress(int currentSpineIndex, float currentSpineRead) const;

View File

@ -88,8 +88,8 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
constexpr size_t headerASize = constexpr size_t headerASize =
sizeof(BOOK_CACHE_VERSION) + /* LUT Offset */ sizeof(size_t) + sizeof(spineCount) + sizeof(tocCount); sizeof(BOOK_CACHE_VERSION) + /* LUT Offset */ sizeof(size_t) + sizeof(spineCount) + sizeof(tocCount);
const size_t metadataSize = const size_t metadataSize = metadata.title.size() + metadata.author.size() + metadata.coverItemHref.size() +
metadata.title.size() + metadata.author.size() + metadata.coverItemHref.size() + sizeof(uint32_t) * 3; metadata.textReferenceHref.size() + sizeof(uint32_t) * 4;
const size_t lutSize = sizeof(size_t) * spineCount + sizeof(size_t) * tocCount; const size_t lutSize = sizeof(size_t) * spineCount + sizeof(size_t) * tocCount;
const size_t lutOffset = headerASize + metadataSize; 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.title);
serialization::writeString(bookFile, metadata.author); serialization::writeString(bookFile, metadata.author);
serialization::writeString(bookFile, metadata.coverItemHref); serialization::writeString(bookFile, metadata.coverItemHref);
serialization::writeString(bookFile, metadata.textReferenceHref);
// Loop through spine entries, writing LUT positions // Loop through spine entries, writing LUT positions
spineFile.seek(0); spineFile.seek(0);
@ -286,6 +287,7 @@ bool BookMetadataCache::load() {
serialization::readString(bookFile, coreMetadata.title); serialization::readString(bookFile, coreMetadata.title);
serialization::readString(bookFile, coreMetadata.author); serialization::readString(bookFile, coreMetadata.author);
serialization::readString(bookFile, coreMetadata.coverItemHref); serialization::readString(bookFile, coreMetadata.coverItemHref);
serialization::readString(bookFile, coreMetadata.textReferenceHref);
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);

View File

@ -10,6 +10,7 @@ class BookMetadataCache {
std::string title; std::string title;
std::string author; std::string author;
std::string coverItemHref; std::string coverItemHref;
std::string textReferenceHref;
}; };
struct SpineEntry { struct SpineEntry {

View File

@ -219,19 +219,19 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
for (int i = 0; atts[i]; i += 2) { for (int i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "type") == 0) { if (strcmp(atts[i], "type") == 0) {
type = atts[i + 1]; type = atts[i + 1];
if (type == "text") { if (type == "text" || type == "start") {
continue; continue;
} else { } else {
Serial.printf("[%lu] [COF] Skipping non-text reference in guide: %s\n", millis(), type.c_str()); Serial.printf("[%lu] [COF] Skipping non-text reference in guide: %s\n", millis(), type.c_str());
break; break;
} }
} else if (strcmp(atts[i], "href") == 0) { } else if (strcmp(atts[i], "href") == 0) {
textHref = atts[i + 1]; textHref = self->baseContentPath + atts[i + 1];
} }
} }
if ((type == "text") && (textHref.length() > 0)) { if ((type == "text" || (type == "start" && !self->textReferenceHref.empty())) && (textHref.length() > 0)) {
Serial.printf("[%lu] [COF] Found text reference in guide: %s.\n", millis(), textHref.c_str()); Serial.printf("[%lu] [COF] Found %s reference in guide: %s.\n", millis(), type.c_str(), textHref.c_str());
// TODO: now this has to become the chapter we display self->textReferenceHref = textHref;
} }
return; return;
} }

View File

@ -34,6 +34,7 @@ class ContentOpfParser final : public Print {
std::string title; std::string title;
std::string tocNcxPath; std::string tocNcxPath;
std::string coverItemHref; std::string coverItemHref;
std::string textReferenceHref;
explicit ContentOpfParser(const std::string& cachePath, const std::string& baseContentPath, const size_t xmlSize, explicit ContentOpfParser(const std::string& cachePath, const std::string& baseContentPath, const size_t xmlSize,
BookMetadataCache* cache) BookMetadataCache* cache)

View File

@ -64,6 +64,16 @@ void EpubReaderActivity::onEnter() {
} }
f.close(); 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 // Save current epub as last opened epub
APP_STATE.openEpubPath = epub->getPath(); APP_STATE.openEpubPath = epub->getPath();