diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index e30da68d1..271932fbc 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1662,11 +1662,11 @@ void MainWindow::handleUpdateCheckFinished(ProgramUpdater *updater, const bool i updater->deleteLater(); }; - const QString newVersion = updater->getNewVersion(); - if (!newVersion.isEmpty()) + const auto newVersion = updater->getNewVersion(); + if (newVersion.isValid()) { const QString msg {tr("A new version is available.") + u"
" - + tr("Do you want to download %1?").arg(newVersion) + u"

" + + tr("Do you want to download %1?").arg(newVersion.toString()) + u"

" + u"%1"_s.arg(tr("Open changelog..."))}; auto *msgBox = new QMessageBox {QMessageBox::Question, tr("qBittorrent Update Available"), msg , (QMessageBox::Yes | QMessageBox::No), this}; diff --git a/src/gui/programupdater.cpp b/src/gui/programupdater.cpp index 063bc5473..dc6965f29 100644 --- a/src/gui/programupdater.cpp +++ b/src/gui/programupdater.cpp @@ -35,10 +35,13 @@ #include #include #include +#include +#include #include #include #include "base/global.h" +#include "base/logger.h" #include "base/net/downloadmanager.h" #include "base/preferences.h" #include "base/utils/version.h" @@ -46,23 +49,20 @@ namespace { - bool isVersionMoreRecent(const QString &remoteVersion) + bool isVersionMoreRecent(const ProgramUpdater::Version &remoteVersion) { - using Version = Utils::Version<4, 3>; - - const auto newVersion = Version::fromString(remoteVersion); - if (!newVersion.isValid()) + if (!remoteVersion.isValid()) return false; - const Version currentVersion {QBT_VERSION_MAJOR, QBT_VERSION_MINOR, QBT_VERSION_BUGFIX, QBT_VERSION_BUILD}; - if (newVersion == currentVersion) + const ProgramUpdater::Version currentVersion {QBT_VERSION_MAJOR, QBT_VERSION_MINOR, QBT_VERSION_BUGFIX, QBT_VERSION_BUILD}; + if (remoteVersion == currentVersion) { const bool isDevVersion = QStringLiteral(QBT_VERSION_STATUS).contains( QRegularExpression(u"(alpha|beta|rc)"_s)); if (isDevVersion) return true; } - return (newVersion > currentVersion); + return (remoteVersion > currentVersion); } QString buildVariant() @@ -82,30 +82,34 @@ namespace void ProgramUpdater::checkForUpdates() const { + const auto USER_AGENT = QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)"); const auto RSS_URL = u"https://www.fosshub.com/feed/5b8793a7f9ee5a5c3e97a3b2.xml"_s; + const auto FALLBACK_URL = u"https://www.qbittorrent.org/versions.json"_s; + // Don't change this User-Agent. In case our updater goes haywire, // the filehost can identify it and contact us. - Net::DownloadManager::instance()->download( - Net::DownloadRequest(RSS_URL).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)")) + Net::DownloadManager::instance()->download(Net::DownloadRequest(RSS_URL).userAgent(USER_AGENT) , Preferences::instance()->useProxyForGeneralPurposes(), this, &ProgramUpdater::rssDownloadFinished); + Net::DownloadManager::instance()->download(Net::DownloadRequest(FALLBACK_URL).userAgent(USER_AGENT) + , Preferences::instance()->useProxyForGeneralPurposes(), this, &ProgramUpdater::fallbackDownloadFinished); + + m_hasCompletedOneReq = false; } -QString ProgramUpdater::getNewVersion() const +ProgramUpdater::Version ProgramUpdater::getNewVersion() const { - return m_newVersion; + return shouldUseFallback() ? m_fallbackRemoteVersion : m_remoteVersion; } void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) { if (result.status != Net::DownloadStatus::Success) { - qDebug() << "Downloading the new qBittorrent updates RSS failed:" << result.errorString; - emit updateCheckFinished(); + LogMsg(tr("Failed to download the update info. URL: %1. Error: %2").arg(result.url, result.errorString) , Log::WARNING); + handleFinishedRequest(); return; } - qDebug("Finished downloading the new qBittorrent updates RSS"); - const auto getStringValue = [](QXmlStreamReader &xml) -> QString { xml.readNext(); @@ -146,9 +150,10 @@ void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) if (!version.isEmpty()) { qDebug("Detected version is %s", qUtf8Printable(version)); - if (isVersionMoreRecent(version)) + const ProgramUpdater::Version tmpVer {version}; + if (isVersionMoreRecent(tmpVer)) { - m_newVersion = version; + m_remoteVersion = tmpVer; m_updateURL = updateLink; } } @@ -163,10 +168,50 @@ void ProgramUpdater::rssDownloadFinished(const Net::DownloadResult &result) } } - emit updateCheckFinished(); + handleFinishedRequest(); +} + +void ProgramUpdater::fallbackDownloadFinished(const Net::DownloadResult &result) +{ + if (result.status != Net::DownloadStatus::Success) + { + LogMsg(tr("Failed to download the update info. URL: %1. Error: %2").arg(result.url, result.errorString) , Log::WARNING); + handleFinishedRequest(); + return; + } + + const auto json = QJsonDocument::fromJson(result.data); + +#if defined(Q_OS_MACOS) + const QString platformKey = u"macos"_s; +#elif defined(Q_OS_WIN) + const QString platformKey = u"win"_s; +#endif + + if (const QJsonValue verJSON = json[platformKey][u"version"_s]; verJSON.isString()) + { + const ProgramUpdater::Version tmpVer {verJSON.toString()}; + if (isVersionMoreRecent(tmpVer)) + m_fallbackRemoteVersion = tmpVer; + } + + handleFinishedRequest(); } bool ProgramUpdater::updateProgram() const { - return QDesktopServices::openUrl(m_updateURL); + return QDesktopServices::openUrl(shouldUseFallback() ? u"https://www.qbittorrent.org/download"_s : m_updateURL); +} + +void ProgramUpdater::handleFinishedRequest() +{ + if (m_hasCompletedOneReq) + emit updateCheckFinished(); + else + m_hasCompletedOneReq = true; +} + +bool ProgramUpdater::shouldUseFallback() const +{ + return m_fallbackRemoteVersion > m_remoteVersion; } diff --git a/src/gui/programupdater.h b/src/gui/programupdater.h index 88d41985f..531d12118 100644 --- a/src/gui/programupdater.h +++ b/src/gui/programupdater.h @@ -30,9 +30,10 @@ #pragma once #include -#include #include +#include "base/utils/version.h" + namespace Net { struct DownloadResult; @@ -45,9 +46,10 @@ class ProgramUpdater final : public QObject public: using QObject::QObject; + using Version = Utils::Version<4, 3>; void checkForUpdates() const; - QString getNewVersion() const; + Version getNewVersion() const; bool updateProgram() const; signals: @@ -55,8 +57,14 @@ signals: private slots: void rssDownloadFinished(const Net::DownloadResult &result); + void fallbackDownloadFinished(const Net::DownloadResult &result); private: - QString m_newVersion; + void handleFinishedRequest(); + bool shouldUseFallback() const; + + mutable bool m_hasCompletedOneReq = false; + Version m_remoteVersion; + Version m_fallbackRemoteVersion; QUrl m_updateURL; };