Merge pull request #84 from jpirnay/fix-pr1664
feat: support two-step OpenSearch Description for OPDS search (upstream PR 1664 by philips)
This commit is contained in:
@@ -70,6 +70,7 @@ bool OpdsParser::error() const { return errorOccured; }
|
||||
void OpdsParser::clear() {
|
||||
entries.clear();
|
||||
searchTemplate.clear();
|
||||
osdUrl.clear();
|
||||
nextPageUrl.clear();
|
||||
prevPageUrl.clear();
|
||||
currentEntry = OpdsEntry{};
|
||||
@@ -105,6 +106,8 @@ void XMLCALL OpdsParser::startElement(void* userData, const XML_Char* name, cons
|
||||
std::string sHref(href);
|
||||
if (sHref.find("{searchTerms}") != std::string::npos) {
|
||||
self->searchTemplate = sHref;
|
||||
} else if (type && strcmp(type, "application/opensearchdescription+xml") == 0) {
|
||||
self->osdUrl = sHref;
|
||||
}
|
||||
} else if (rel && strcmp(rel, "next") == 0 && !self->inEntry) {
|
||||
self->nextPageUrl = href;
|
||||
|
||||
@@ -50,6 +50,7 @@ class OpdsParser final : public Print {
|
||||
|
||||
// Disable copy
|
||||
const std::string& getSearchTemplate() const { return searchTemplate; }
|
||||
const std::string& getOsdUrl() const { return osdUrl; }
|
||||
const std::string& getNextPageUrl() const { return nextPageUrl; }
|
||||
const std::string& getPrevPageUrl() const { return prevPageUrl; }
|
||||
OpdsParser(const OpdsParser&) = delete;
|
||||
@@ -89,6 +90,7 @@ class OpdsParser final : public Print {
|
||||
static void XMLCALL characterData(void* userData, const XML_Char* s, int len);
|
||||
|
||||
std::string searchTemplate;
|
||||
std::string osdUrl;
|
||||
std::string nextPageUrl;
|
||||
std::string prevPageUrl;
|
||||
// Helper to find attribute value
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <Logging.h>
|
||||
#include <OpdsStream.h>
|
||||
#include <WiFi.h>
|
||||
#include <expat.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
@@ -245,6 +246,9 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
|
||||
}
|
||||
|
||||
searchTemplate = parser.getSearchTemplate();
|
||||
if (searchTemplate.empty() && !parser.getOsdUrl().empty()) {
|
||||
fetchOsdTemplate(UrlUtils::buildUrl(url, parser.getOsdUrl()));
|
||||
}
|
||||
const auto& nextUrl = parser.getNextPageUrl();
|
||||
const auto& prevUrl = parser.getPrevPageUrl();
|
||||
entries = std::move(parser).getEntries();
|
||||
@@ -336,6 +340,42 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) {
|
||||
}
|
||||
}
|
||||
|
||||
void OpdsBookBrowserActivity::fetchOsdTemplate(const std::string& osdUrl) {
|
||||
std::string content;
|
||||
if (!HttpDownloader::fetchUrl(osdUrl, content)) {
|
||||
LOG_ERR("OPDS", "Failed to fetch OSD: %s", osdUrl.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
struct OsdState {
|
||||
std::string templateUrl;
|
||||
static void XMLCALL onStart(void* ud, const XML_Char* name, const XML_Char** atts) {
|
||||
if (strcmp(name, "Url") != 0 && strstr(name, ":Url") == nullptr) return;
|
||||
auto* state = static_cast<OsdState*>(ud);
|
||||
for (int i = 0; atts[i]; i += 2) {
|
||||
if (strcmp(atts[i], "template") == 0 && strstr(atts[i + 1], "{searchTerms}") != nullptr) {
|
||||
state->templateUrl = atts[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} osdState;
|
||||
|
||||
XML_Parser p = XML_ParserCreate(nullptr);
|
||||
if (!p) {
|
||||
LOG_ERR("OPDS", "OSD parser alloc failed");
|
||||
return;
|
||||
}
|
||||
XML_SetUserData(p, &osdState);
|
||||
XML_SetElementHandler(p, OsdState::onStart, nullptr);
|
||||
XML_Parse(p, content.c_str(), static_cast<int>(content.size()), XML_TRUE);
|
||||
XML_ParserFree(p);
|
||||
|
||||
if (!osdState.templateUrl.empty()) {
|
||||
searchTemplate = UrlUtils::buildUrl(osdUrl, osdState.templateUrl);
|
||||
}
|
||||
}
|
||||
|
||||
void OpdsBookBrowserActivity::launchSearch() {
|
||||
consumeConfirm = true;
|
||||
state = BrowserState::SEARCH_INPUT;
|
||||
|
||||
@@ -46,6 +46,7 @@ class OpdsBookBrowserActivity final : public Activity {
|
||||
void navigateToEntry(const OpdsEntry& entry);
|
||||
void navigateBack();
|
||||
void downloadBook(const OpdsEntry& book);
|
||||
void fetchOsdTemplate(const std::string& osdUrl);
|
||||
void launchSearch();
|
||||
void performSearch(const std::string& query);
|
||||
bool preventAutoSleep() override { return true; }
|
||||
|
||||
Reference in New Issue
Block a user