diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index e4c6f9fd9..e78e9373a 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -225,7 +225,10 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) { void OpdsBookBrowserActivity::navigateToEntry(const OpdsEntry& entry) { navigationHistory.push_back(currentPath); - currentPath = entry.href; + // Resolve to a full URL so sub-sub-navigation retains parent path context + const std::string feedUrl = UrlUtils::buildUrl(SETTINGS.opdsServerUrl, currentPath); + currentPath = UrlUtils::buildUrl(feedUrl, entry.href); + state = BrowserState::LOADING; statusMessage = tr(STR_LOADING); entries.clear(); @@ -255,10 +258,12 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) { downloadProgress = downloadTotal = 0; requestUpdate(true); - std::string downloadUrl = - (book.href.find("http") == 0) ? book.href : UrlUtils::buildUrl(SETTINGS.opdsServerUrl, book.href); + // Build full download URL relative to the current feed, not the root server URL + const std::string feedUrl = UrlUtils::buildUrl(SETTINGS.opdsServerUrl, currentPath); + std::string downloadUrl = UrlUtils::buildUrl(feedUrl, book.href); std::string filename = "/" + StringUtils::sanitizeFilename(book.title + (book.author.empty() ? "" : " - " + book.author)) + ".epub"; + LOG_DBG("OPDS", "Downloading: %s -> %s", downloadUrl.c_str(), filename.c_str()); const auto result = HttpDownloader::downloadToFile(downloadUrl, filename, [this](const size_t downloaded, const size_t total) { diff --git a/src/util/UrlUtils.cpp b/src/util/UrlUtils.cpp index a2156552b..34e24914e 100644 --- a/src/util/UrlUtils.cpp +++ b/src/util/UrlUtils.cpp @@ -37,11 +37,16 @@ std::string buildUrl(const std::string& serverUrl, const std::string& path) { // Absolute path - use just the host return extractHost(urlWithProtocol) + path; } - // Relative path - append to server URL - if (urlWithProtocol.back() == '/') { - return urlWithProtocol + path; + // Relative path - strip query string from base before appending + std::string base = urlWithProtocol; + const size_t queryPos = base.find('?'); + if (queryPos != std::string::npos) { + base.resize(queryPos); } - return urlWithProtocol + "/" + path; + if (base.back() == '/') { + return base + path; + } + return base + "/" + path; } } // namespace UrlUtils