diff --git a/qml/pages/BookDetailPage.qml b/qml/pages/BookDetailPage.qml index 23cf451..15948da 100644 --- a/qml/pages/BookDetailPage.qml +++ b/qml/pages/BookDetailPage.qml @@ -121,6 +121,11 @@ Page { if (u.indexOf("http://") === 0 || u.indexOf("https://") === 0) return u var base = appSettings.baseUrl + // il server dietro sottopath (es. /calibre) emette link che lo includono già: + // evita di raddoppiarlo + var basePath = base.replace(/^https?:\/\/[^\/]+/, "") + if (basePath.length > 1 && u.indexOf(basePath) === 0) + return base + u.substring(basePath.length) return base + (u.charAt(0) === "/" ? u : "/" + u) } diff --git a/src/apiclient.cpp b/src/apiclient.cpp index 5cfa8a3..0c93168 100644 --- a/src/apiclient.cpp +++ b/src/apiclient.cpp @@ -31,10 +31,10 @@ QString ApiClient::resolveUrl(const QString &relative) const if (relative.startsWith(QLatin1String("http://")) || relative.startsWith(QLatin1String("https://"))) return relative; - const QString base = m_settings->baseUrl(); - if (relative.startsWith(QLatin1Char('/'))) - return base + relative; - return base + QLatin1Char('/') + relative; + // risoluzione RFC 3986: gestisce i path assoluti del server (es. /calibre/opds/books) + // senza raddoppiare il sottopath già presente nel baseUrl + QUrl base(m_settings->baseUrl()); + return base.resolved(QUrl(relative)).toString(); } void ApiClient::applyAuth(QNetworkRequest &request) @@ -105,10 +105,24 @@ void ApiClient::getFeed(const QString &url) << "entries:" << entries.size(); emit feedReady(entries, resolveUrl(nextUrl), feedTitle); } else { - qDebug() << "getFeed parse error:" << parseError; - emit feedError(parseError.isEmpty() - ? QStringLiteral("Risposta non valida dal server") - : parseError); + // risposta 2xx ma non XML: quasi sempre una pagina HTML (redirect/login/URL errato) + const QByteArray contentType = reply->header( + QNetworkRequest::ContentTypeHeader).toByteArray(); + QString message; + if (contentType.contains("html") || body.trimmed().startsWith("