From 5304086bcdccd16e1a8e20a077a51ba929c1a738 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Sun, 10 May 2026 21:06:55 +0200 Subject: [PATCH] Fixes --- lib/OpdsParser/OpdsParser.cpp | 8 +++++-- lib/OpdsParser/OpdsParser.h | 17 ++++++++------ .../browser/OpdsBookBrowserActivity.cpp | 8 +++++-- src/main.cpp | 3 --- test/opds_parser/OpdsParserTest.cpp | 22 +++++++++++++------ 5 files changed, 37 insertions(+), 21 deletions(-) diff --git a/lib/OpdsParser/OpdsParser.cpp b/lib/OpdsParser/OpdsParser.cpp index 0986efd1..a2d6501f 100644 --- a/lib/OpdsParser/OpdsParser.cpp +++ b/lib/OpdsParser/OpdsParser.cpp @@ -4,6 +4,7 @@ #include #include +#include namespace { // Returns the length of href after trimming trailing slashes. @@ -198,7 +199,7 @@ void XMLCALL OpdsParser::startElement(void* userData, const XML_Char* name, cons self->currentEntry.acquisitionLinks.push_back(acquisition); } } else if (rel && type && strstr(rel, "opds-spec.org/image") != nullptr && - strstr(rel, "thumbnail") == nullptr && strstr(type, "image/jpeg") != nullptr && + strstr(rel, "thumbnail") == nullptr && strncmp(type, "image/", 6) == 0 && self->currentEntry.imageHref.empty()) { self->currentEntry.imageHref = href; } else if (type && strstr(type, "application/atom+xml") != nullptr) { @@ -238,7 +239,10 @@ void XMLCALL OpdsParser::endElement(void* userData, const XML_Char* name) { if (strcmp(name, "entry") == 0 || strstr(name, ":entry") != nullptr) { if (!self->currentEntry.title.empty() && !self->currentEntry.href.empty()) { - if (self->onEntryParsed) self->onEntryParsed(self->currentEntry); + if (self->onEntryParsed) { + self->onEntryParsed(std::move(self->currentEntry)); + self->currentEntry = OpdsEntry{}; + } } self->inEntry = false; } else if (self->inEntry) { diff --git a/lib/OpdsParser/OpdsParser.h b/lib/OpdsParser/OpdsParser.h index d5f863b5..8c53e4e5 100644 --- a/lib/OpdsParser/OpdsParser.h +++ b/lib/OpdsParser/OpdsParser.h @@ -43,14 +43,17 @@ using OpdsBook = OpdsEntry; * * Usage: * OpdsParser parser; - * if (parser.parse(xmlData, xmlLength)) { - * for (const auto& entry : parser.getEntries()) { - * if (entry.type == OpdsEntryType::BOOK) { - * // Downloadable book - * } else { - * // Navigation link to another catalog - * } + * parser.onEntryParsed = [](OpdsEntry entry) { + * if (entry.type == OpdsEntryType::BOOK) { + * // Process downloadable book + * } else { + * // Process navigation link * } + * }; + * + * // Entries are emitted immediately as they are parsed from the stream. + * if (parser.parse(xmlData, xmlLength)) { + * // Parsing completed successfully * } */ class OpdsParser final : public Print { diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 563346f8..62d6b86f 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -403,6 +403,8 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) { return; } + entryOffsets.clear(); + std::string url = (path.find("http") == 0) ? path : UrlUtils::buildUrl(server.url, path); LOG_DBG("OPDS", "Fetching: %s", url.c_str()); @@ -448,12 +450,14 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) { const auto& prevUrl = parser.getPrevPageUrl(); if (!prevUrl.empty()) { - OpdsEntry prevEntry{OpdsEntryType::NAVIGATION, tr(STR_PREV_PAGE), "", prevUrl, ""}; + std::string resolvedPrevUrl = UrlUtils::buildUrl(url, prevUrl); + OpdsEntry prevEntry{OpdsEntryType::NAVIGATION, tr(STR_PREV_PAGE), "", resolvedPrevUrl, ""}; entryOffsets.insert(entryOffsets.begin(), cacheFile.position()); writeEntryToCache(cacheFile, prevEntry); } if (!nextUrl.empty()) { - OpdsEntry nextEntry{OpdsEntryType::NAVIGATION, tr(STR_NEXT_PAGE), "", nextUrl, ""}; + std::string resolvedNextUrl = UrlUtils::buildUrl(url, nextUrl); + OpdsEntry nextEntry{OpdsEntryType::NAVIGATION, tr(STR_NEXT_PAGE), "", resolvedNextUrl, ""}; entryOffsets.push_back(cacheFile.position()); writeEntryToCache(cacheFile, nextEntry); } diff --git a/src/main.cpp b/src/main.cpp index f8751668..75f25acd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -509,9 +509,6 @@ void loop() { while (buttonEventManager.consumeEvent(ev)) { const uint8_t action = actionFor(ev); if (action == BA::BTN_DEFAULT) { - if (ev.type == ButtonEventManager::PressType::Double) { - continue; - } defaultEvents.push_back(ev); continue; } diff --git a/test/opds_parser/OpdsParserTest.cpp b/test/opds_parser/OpdsParserTest.cpp index d0cb0b3b..7b88ea57 100644 --- a/test/opds_parser/OpdsParserTest.cpp +++ b/test/opds_parser/OpdsParserTest.cpp @@ -51,7 +51,9 @@ bool parseSingleBookEntry(OpdsEntry& entryOut, const char* href, const char* typ )"; + std::vector entries; OpdsParser parser; + parser.onEntryParsed = [&](OpdsEntry e) { entries.push_back(std::move(e)); }; parser.write(reinterpret_cast(xml.data()), xml.size()); parser.flush(); @@ -60,7 +62,6 @@ bool parseSingleBookEntry(OpdsEntry& entryOut, const char* href, const char* typ testsFailed++; return false; } - const auto& entries = parser.getEntries(); if (entries.size() != 1) { fprintf(stderr, " FAIL: %s:%d: entries.size() == %zu, expected 1\n", __FILE__, __LINE__, entries.size()); testsFailed++; @@ -153,12 +154,13 @@ void testDistinctAcquisitionFormatsRemainSeparate() { )"; + std::vector entries; OpdsParser parser; + parser.onEntryParsed = [&](OpdsEntry e) { entries.push_back(std::move(e)); }; parser.write(reinterpret_cast(xml), strlen(xml)); parser.flush(); ASSERT_TRUE(!parser.error()); - const auto& entries = parser.getEntries(); ASSERT_SIZE(entries.size(), 1); const auto& links = entries.front().acquisitionLinks; ASSERT_SIZE(links.size(), 4); @@ -181,12 +183,14 @@ void testUnsupportedMimeType() { )"; + std::vector entries; OpdsParser parser; + parser.onEntryParsed = [&](OpdsEntry e) { entries.push_back(std::move(e)); }; parser.write(reinterpret_cast(xml), strlen(xml)); parser.flush(); ASSERT_TRUE(!parser.error()); - ASSERT_SIZE(parser.getEntries().size(), 0); + ASSERT_SIZE(entries.size(), 0); PASS(); } @@ -220,12 +224,13 @@ void testEmptyHrefOrType() { )"; + std::vector entries; OpdsParser parser; + parser.onEntryParsed = [&](OpdsEntry e) { entries.push_back(std::move(e)); }; parser.write(reinterpret_cast(xml), strlen(xml)); parser.flush(); ASSERT_TRUE(!parser.error()); - const auto& entries = parser.getEntries(); ASSERT_SIZE(entries.size(), 0); PASS(); } @@ -243,12 +248,13 @@ void testDuplicateAcquisitionLinks() { )"; + std::vector entries; OpdsParser parser; + parser.onEntryParsed = [&](OpdsEntry e) { entries.push_back(std::move(e)); }; parser.write(reinterpret_cast(xml), strlen(xml)); parser.flush(); ASSERT_TRUE(!parser.error()); - const auto& entries = parser.getEntries(); ASSERT_SIZE(entries.size(), 1); const auto& links = entries.front().acquisitionLinks; ASSERT_SIZE(links.size(), 2); @@ -272,12 +278,13 @@ void testIdenticalHrefAcquisitionLinksAreDeduplicated() { )"; + std::vector entries; OpdsParser parser; + parser.onEntryParsed = [&](OpdsEntry e) { entries.push_back(std::move(e)); }; parser.write(reinterpret_cast(xml), strlen(xml)); parser.flush(); ASSERT_TRUE(!parser.error()); - const auto& entries = parser.getEntries(); ASSERT_SIZE(entries.size(), 1); const auto& links = entries.front().acquisitionLinks; ASSERT_SIZE(links.size(), 1); @@ -299,12 +306,13 @@ void testSlashVariantHrefAcquisitionLinksAreDeduplicated() { )"; + std::vector entries; OpdsParser parser; + parser.onEntryParsed = [&](OpdsEntry e) { entries.push_back(std::move(e)); }; parser.write(reinterpret_cast(xml), strlen(xml)); parser.flush(); ASSERT_TRUE(!parser.error()); - const auto& entries = parser.getEntries(); ASSERT_SIZE(entries.size(), 1); const auto& links = entries.front().acquisitionLinks; ASSERT_SIZE(links.size(), 1);