Browse Source

Merge pull request #9125 from glassez/downloader

Implement "Sequential downloading" feature. Closes #6835
adaptive-webui-19844
Vladimir Golovnev 6 years ago committed by GitHub
parent
commit
b0afa33e22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      src/base/bittorrent/session.cpp
  2. 2
      src/base/bittorrent/session.h
  3. 59
      src/base/bittorrent/torrentinfo.cpp
  4. 10
      src/base/net/dnsupdater.cpp
  5. 158
      src/base/net/downloadhandler.cpp
  6. 19
      src/base/net/downloadhandler.h
  7. 181
      src/base/net/downloadmanager.cpp
  8. 59
      src/base/net/downloadmanager.h
  9. 2
      src/base/net/geoipmanager.cpp
  10. 7
      src/base/rss/rss_feed.cpp
  11. 4
      src/base/search/searchpluginmanager.cpp
  12. 4
      src/gui/addnewtorrentdialog.cpp
  13. 10
      src/gui/mainwindow.cpp
  14. 5
      src/gui/programupdater.cpp
  15. 30
      src/gui/properties/trackersadditiondialog.cpp
  16. 2
      src/gui/properties/trackersadditiondialog.h
  17. 3
      src/gui/search/pluginselectdialog.cpp
  18. 3
      src/gui/transferlistfilterswidget.cpp

12
src/base/bittorrent/session.cpp

@ -1844,11 +1844,10 @@ void Session::handleRedirectedToMagnet(const QString &url, const QString &magnet
} }
// Add to BitTorrent session the downloaded torrent file // Add to BitTorrent session the downloaded torrent file
void Session::handleDownloadFinished(const QString &url, const QString &filePath) void Session::handleDownloadFinished(const QString &url, const QByteArray &data)
{ {
emit downloadFromUrlFinished(url); emit downloadFromUrlFinished(url);
addTorrent_impl(m_downloadedTorrents.take(url), MagnetUri(), TorrentInfo::loadFromFile(filePath)); addTorrent_impl(m_downloadedTorrents.take(url), MagnetUri(), TorrentInfo::load(data));
Utils::Fs::forceRemove(filePath); // remove temporary file
} }
// Return the torrent handle, given its hash // Return the torrent handle, given its hash
@ -2077,10 +2076,11 @@ bool Session::addTorrent(QString source, const AddTorrentParams &params)
return addTorrent_impl(params, magnetUri); return addTorrent_impl(params, magnetUri);
} }
else if (Utils::Misc::isUrl(source)) { else if (Utils::Misc::isUrl(source)) {
Logger::instance()->addMessage(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source)); LogMsg(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source));
// Launch downloader // Launch downloader
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true); Net::DownloadHandler *handler =
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished) Net::DownloadManager::instance()->download(Net::DownloadRequest(source).limit(10485760 /* 10MB */).handleRedirectToMagnet(true));
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &Session::handleDownloadFinished); , this, &Session::handleDownloadFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &Session::handleDownloadFailed); connect(handler, &Net::DownloadHandler::downloadFailed, this, &Session::handleDownloadFailed);
connect(handler, &Net::DownloadHandler::redirectedToMagnet, this, &Session::handleRedirectedToMagnet); connect(handler, &Net::DownloadHandler::redirectedToMagnet, this, &Session::handleRedirectedToMagnet);

2
src/base/bittorrent/session.h

@ -547,7 +547,7 @@ namespace BitTorrent
void generateResumeData(bool final = false); void generateResumeData(bool final = false);
void handleIPFilterParsed(int ruleCount); void handleIPFilterParsed(int ruleCount);
void handleIPFilterError(); void handleIPFilterError();
void handleDownloadFinished(const QString &url, const QString &filePath); void handleDownloadFinished(const QString &url, const QByteArray &data);
void handleDownloadFailed(const QString &url, const QString &reason); void handleDownloadFailed(const QString &url, const QString &reason);
void handleRedirectedToMagnet(const QString &url, const QString &magnetUri); void handleRedirectedToMagnet(const QString &url, const QString &magnetUri);

59
src/base/bittorrent/torrentinfo.cpp

@ -62,13 +62,32 @@ TorrentInfo &TorrentInfo::operator=(const TorrentInfo &other)
TorrentInfo TorrentInfo::load(const QByteArray &data, QString *error) noexcept TorrentInfo TorrentInfo::load(const QByteArray &data, QString *error) noexcept
{ {
// 2-step construction to overcome default limits of `depth_limit` & `token_limit` which are
// used in `torrent_info()` constructor
const int depthLimit = 100;
const int tokenLimit = 10000000;
libt::error_code ec; libt::error_code ec;
TorrentInfo info(NativePtr(new libt::torrent_info(data.constData(), data.size(), ec)));
if (error) { #if LIBTORRENT_VERSION_NUM < 10100
if (ec) libt::lazy_entry node;
libt::lazy_bdecode(data.constData(), (data.constData() + data.size()), node, ec
, nullptr, depthLimit, tokenLimit);
#else
libt::bdecode_node node;
bdecode(data.constData(), (data.constData() + data.size()), node, ec
, nullptr, depthLimit, tokenLimit);
#endif
if (ec) {
if (error)
*error = QString::fromStdString(ec.message()); *error = QString::fromStdString(ec.message());
else return TorrentInfo();
error->clear(); }
TorrentInfo info {NativePtr(new libt::torrent_info(node, ec))};
if (ec) {
if (error)
*error = QString::fromStdString(ec.message());
return TorrentInfo();
} }
return info; return info;
@ -102,35 +121,7 @@ TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexc
file.close(); file.close();
// 2-step construction to overcome default limits of `depth_limit` & `token_limit` which are return load(data, error);
// used in `torrent_info()` constructor
const int depthLimit = 100;
const int tokenLimit = 10000000;
libt::error_code ec;
#if LIBTORRENT_VERSION_NUM < 10100
libt::lazy_entry node;
libt::lazy_bdecode(data.constData(), (data.constData() + data.size()), node, ec
, nullptr, depthLimit, tokenLimit);
#else
libt::bdecode_node node;
bdecode(data.constData(), (data.constData() + data.size()), node, ec
, nullptr, depthLimit, tokenLimit);
#endif
if (ec) {
if (error)
*error = QString::fromStdString(ec.message());
return TorrentInfo();
}
TorrentInfo info {NativePtr(new libt::torrent_info(node, ec))};
if (ec) {
if (error)
*error = QString::fromStdString(ec.message());
return TorrentInfo();
}
return info;
} }
bool TorrentInfo::isValid() const bool TorrentInfo::isValid() const

10
src/base/net/dnsupdater.cpp

@ -75,9 +75,8 @@ void DNSUpdater::checkPublicIP()
{ {
Q_ASSERT(m_state == OK); Q_ASSERT(m_state == OK);
DownloadHandler *handler = DownloadManager::instance()->downloadUrl( DownloadHandler *handler = DownloadManager::instance()->download(
"http://checkip.dyndns.org", false, 0, false, DownloadRequest("http://checkip.dyndns.org").userAgent("qBittorrent/" QBT_VERSION_2));
"qBittorrent/" QBT_VERSION_2);
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished) connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &DNSUpdater::ipRequestFinished); , this, &DNSUpdater::ipRequestFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipRequestFailed); connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipRequestFailed);
@ -123,9 +122,8 @@ void DNSUpdater::updateDNSService()
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
m_lastIPCheckTime = QDateTime::currentDateTime(); m_lastIPCheckTime = QDateTime::currentDateTime();
DownloadHandler *handler = DownloadManager::instance()->downloadUrl( DownloadHandler *handler = DownloadManager::instance()->download(
getUpdateUrl(), false, 0, false, DownloadRequest(getUpdateUrl()).userAgent("qBittorrent/" QBT_VERSION_2));
"qBittorrent/" QBT_VERSION_2);
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished) connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &DNSUpdater::ipUpdateFinished); , this, &DNSUpdater::ipUpdateFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipUpdateFailed); connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipUpdateFailed);

158
src/base/net/downloadhandler.cpp

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -29,6 +29,7 @@
#include "downloadhandler.h" #include "downloadhandler.h"
#include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkCookie> #include <QNetworkCookie>
@ -43,35 +44,46 @@
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "downloadmanager.h" #include "downloadmanager.h"
static QString errorCodeToString(QNetworkReply::NetworkError status); namespace
{
using namespace Net; QString tr(const char *message);
QString errorCodeToString(QNetworkReply::NetworkError status);
}
DownloadHandler::DownloadHandler(QNetworkReply *reply, DownloadManager *manager, bool saveToFile, qint64 limit, bool handleRedirectToMagnet) Net::DownloadHandler::DownloadHandler(QNetworkReply *reply, DownloadManager *manager, const DownloadRequest &downloadRequest)
: QObject(manager) : QObject(manager)
, m_reply(reply) , m_reply(reply)
, m_manager(manager) , m_manager(manager)
, m_saveToFile(saveToFile) , m_downloadRequest(downloadRequest)
, m_sizeLimit(limit)
, m_handleRedirectToMagnet(handleRedirectToMagnet)
, m_url(reply->url().toString())
{ {
init(); if (reply)
assignNetworkReply(reply);
} }
DownloadHandler::~DownloadHandler() Net::DownloadHandler::~DownloadHandler()
{ {
if (m_reply) if (m_reply)
delete m_reply; delete m_reply;
} }
void Net::DownloadHandler::assignNetworkReply(QNetworkReply *reply)
{
Q_ASSERT(reply);
m_reply = reply;
m_reply->setParent(this);
if (m_downloadRequest.limit() > 0)
connect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize);
connect(m_reply, &QNetworkReply::finished, this, &Net::DownloadHandler::processFinishedDownload);
}
// Returns original url // Returns original url
QString DownloadHandler::url() const QString Net::DownloadHandler::url() const
{ {
return m_url; return m_downloadRequest.url();
} }
void DownloadHandler::processFinishedDownload() void Net::DownloadHandler::processFinishedDownload()
{ {
QString url = m_reply->url().toString(); QString url = m_reply->url().toString();
qDebug("Download finished: %s", qUtf8Printable(url)); qDebug("Download finished: %s", qUtf8Printable(url));
@ -79,7 +91,7 @@ void DownloadHandler::processFinishedDownload()
if (m_reply->error() != QNetworkReply::NoError) { if (m_reply->error() != QNetworkReply::NoError) {
// Failure // Failure
qDebug("Download failure (%s), reason: %s", qUtf8Printable(url), qUtf8Printable(errorCodeToString(m_reply->error()))); qDebug("Download failure (%s), reason: %s", qUtf8Printable(url), qUtf8Printable(errorCodeToString(m_reply->error())));
emit downloadFailed(m_url, errorCodeToString(m_reply->error())); emit downloadFailed(m_downloadRequest.url(), errorCodeToString(m_reply->error()));
this->deleteLater(); this->deleteLater();
} }
else { else {
@ -97,15 +109,15 @@ void DownloadHandler::processFinishedDownload()
replyData = Utils::Gzip::decompress(replyData); replyData = Utils::Gzip::decompress(replyData);
} }
if (m_saveToFile) { if (m_downloadRequest.saveToFile()) {
QString filePath; QString filePath;
if (saveToFile(replyData, filePath)) if (saveToFile(replyData, filePath))
emit downloadFinished(m_url, filePath); emit downloadFinished(m_downloadRequest.url(), filePath);
else else
emit downloadFailed(m_url, tr("I/O Error")); emit downloadFailed(m_downloadRequest.url(), tr("I/O Error"));
} }
else { else {
emit downloadFinished(m_url, replyData); emit downloadFinished(m_downloadRequest.url(), replyData);
} }
this->deleteLater(); this->deleteLater();
@ -113,35 +125,27 @@ void DownloadHandler::processFinishedDownload()
} }
} }
void DownloadHandler::checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal) void Net::DownloadHandler::checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal)
{ {
QString msg = tr("The file size is %1. It exceeds the download limit of %2."); QString msg = tr("The file size is %1. It exceeds the download limit of %2.");
if (bytesTotal > 0) { if (bytesTotal > 0) {
// Total number of bytes is available // Total number of bytes is available
if (bytesTotal > m_sizeLimit) { if (bytesTotal > m_downloadRequest.limit()) {
m_reply->abort(); m_reply->abort();
emit downloadFailed(m_url, msg.arg(Utils::Misc::friendlyUnit(bytesTotal), Utils::Misc::friendlyUnit(m_sizeLimit))); emit downloadFailed(m_downloadRequest.url(), msg.arg(Utils::Misc::friendlyUnit(bytesTotal), Utils::Misc::friendlyUnit(m_downloadRequest.limit())));
} }
else { else {
disconnect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize); disconnect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize);
} }
} }
else if (bytesReceived > m_sizeLimit) { else if (bytesReceived > m_downloadRequest.limit()) {
m_reply->abort(); m_reply->abort();
emit downloadFailed(m_url, msg.arg(Utils::Misc::friendlyUnit(bytesReceived), Utils::Misc::friendlyUnit(m_sizeLimit))); emit downloadFailed(m_downloadRequest.url(), msg.arg(Utils::Misc::friendlyUnit(bytesReceived), Utils::Misc::friendlyUnit(m_downloadRequest.limit())));
} }
} }
void DownloadHandler::init() bool Net::DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)
{
m_reply->setParent(this);
if (m_sizeLimit > 0)
connect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize);
connect(m_reply, &QNetworkReply::finished, this, &Net::DownloadHandler::processFinishedDownload);
}
bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)
{ {
QTemporaryFile *tmpfile = new QTemporaryFile(Utils::Fs::tempPath() + "XXXXXX"); QTemporaryFile *tmpfile = new QTemporaryFile(Utils::Fs::tempPath() + "XXXXXX");
if (!tmpfile->open()) { if (!tmpfile->open()) {
@ -168,82 +172,104 @@ bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)
return false; return false;
} }
void DownloadHandler::handleRedirection(QUrl newUrl) void Net::DownloadHandler::handleRedirection(QUrl newUrl)
{ {
// Resolve relative urls // Resolve relative urls
if (newUrl.isRelative()) if (newUrl.isRelative())
newUrl = m_reply->url().resolved(newUrl); newUrl = m_reply->url().resolved(newUrl);
const QString newUrlString = newUrl.toString(); const QString newUrlString = newUrl.toString();
qDebug("Redirecting from %s to %s", qUtf8Printable(m_reply->url().toString()), qUtf8Printable(newUrlString)); qDebug("Redirecting from %s to %s...", qUtf8Printable(m_reply->url().toString()), qUtf8Printable(newUrlString));
// Redirect to magnet workaround // Redirect to magnet workaround
if (newUrlString.startsWith("magnet:", Qt::CaseInsensitive)) { if (newUrlString.startsWith("magnet:", Qt::CaseInsensitive)) {
qDebug("Magnet redirect detected."); qDebug("Magnet redirect detected.");
m_reply->abort(); m_reply->abort();
if (m_handleRedirectToMagnet) if (m_downloadRequest.handleRedirectToMagnet())
emit redirectedToMagnet(m_url, newUrlString); emit redirectedToMagnet(m_downloadRequest.url(), newUrlString);
else else
emit downloadFailed(m_url, tr("Unexpected redirect to magnet URI.")); emit downloadFailed(m_downloadRequest.url(), tr("Unexpected redirect to magnet URI."));
this->deleteLater(); this->deleteLater();
} }
else { else {
DownloadHandler *tmp = m_manager->downloadUrl(newUrlString, m_saveToFile, m_sizeLimit, m_handleRedirectToMagnet); DownloadHandler *redirected = m_manager->download(DownloadRequest(m_downloadRequest).url(newUrlString));
m_reply->deleteLater(); connect(redirected, &DownloadHandler::destroyed, this, &DownloadHandler::deleteLater);
m_reply = tmp->m_reply; connect(redirected, &DownloadHandler::downloadFailed, this, [this](const QString &, const QString &reason)
init(); {
tmp->m_reply = nullptr; emit downloadFailed(url(), reason);
delete tmp; });
connect(redirected, &DownloadHandler::redirectedToMagnet, this, [this](const QString &, const QString &magnetUri)
{
emit redirectedToMagnet(url(), magnetUri);
});
connect(redirected, static_cast<void (DownloadHandler::*)(const QString &, const QString &)>(&DownloadHandler::downloadFinished)
, this, [this](const QString &, const QString &fileName)
{
emit downloadFinished(url(), fileName);
});
connect(redirected, static_cast<void (DownloadHandler::*)(const QString &, const QByteArray &)>(&DownloadHandler::downloadFinished)
, this, [this](const QString &, const QByteArray &data)
{
emit downloadFinished(url(), data);
});
}
} }
namespace
{
QString tr(const char *message)
{
return QCoreApplication::translate("DownloadHandler", message);
} }
QString errorCodeToString(QNetworkReply::NetworkError status) QString errorCodeToString(QNetworkReply::NetworkError status)
{ {
switch (status) { switch (status) {
case QNetworkReply::HostNotFoundError: case QNetworkReply::HostNotFoundError:
return QObject::tr("The remote host name was not found (invalid hostname)"); return tr("The remote host name was not found (invalid hostname)");
case QNetworkReply::OperationCanceledError: case QNetworkReply::OperationCanceledError:
return QObject::tr("The operation was canceled"); return tr("The operation was canceled");
case QNetworkReply::RemoteHostClosedError: case QNetworkReply::RemoteHostClosedError:
return QObject::tr("The remote server closed the connection prematurely, before the entire reply was received and processed"); return tr("The remote server closed the connection prematurely, before the entire reply was received and processed");
case QNetworkReply::TimeoutError: case QNetworkReply::TimeoutError:
return QObject::tr("The connection to the remote server timed out"); return tr("The connection to the remote server timed out");
case QNetworkReply::SslHandshakeFailedError: case QNetworkReply::SslHandshakeFailedError:
return QObject::tr("SSL/TLS handshake failed"); return tr("SSL/TLS handshake failed");
case QNetworkReply::ConnectionRefusedError: case QNetworkReply::ConnectionRefusedError:
return QObject::tr("The remote server refused the connection"); return tr("The remote server refused the connection");
case QNetworkReply::ProxyConnectionRefusedError: case QNetworkReply::ProxyConnectionRefusedError:
return QObject::tr("The connection to the proxy server was refused"); return tr("The connection to the proxy server was refused");
case QNetworkReply::ProxyConnectionClosedError: case QNetworkReply::ProxyConnectionClosedError:
return QObject::tr("The proxy server closed the connection prematurely"); return tr("The proxy server closed the connection prematurely");
case QNetworkReply::ProxyNotFoundError: case QNetworkReply::ProxyNotFoundError:
return QObject::tr("The proxy host name was not found"); return tr("The proxy host name was not found");
case QNetworkReply::ProxyTimeoutError: case QNetworkReply::ProxyTimeoutError:
return QObject::tr("The connection to the proxy timed out or the proxy did not reply in time to the request sent"); return tr("The connection to the proxy timed out or the proxy did not reply in time to the request sent");
case QNetworkReply::ProxyAuthenticationRequiredError: case QNetworkReply::ProxyAuthenticationRequiredError:
return QObject::tr("The proxy requires authentication in order to honor the request but did not accept any credentials offered"); return tr("The proxy requires authentication in order to honor the request but did not accept any credentials offered");
case QNetworkReply::ContentAccessDenied: case QNetworkReply::ContentAccessDenied:
return QObject::tr("The access to the remote content was denied (401)"); return tr("The access to the remote content was denied (401)");
case QNetworkReply::ContentOperationNotPermittedError: case QNetworkReply::ContentOperationNotPermittedError:
return QObject::tr("The operation requested on the remote content is not permitted"); return tr("The operation requested on the remote content is not permitted");
case QNetworkReply::ContentNotFoundError: case QNetworkReply::ContentNotFoundError:
return QObject::tr("The remote content was not found at the server (404)"); return tr("The remote content was not found at the server (404)");
case QNetworkReply::AuthenticationRequiredError: case QNetworkReply::AuthenticationRequiredError:
return QObject::tr("The remote server requires authentication to serve the content but the credentials provided were not accepted"); return tr("The remote server requires authentication to serve the content but the credentials provided were not accepted");
case QNetworkReply::ProtocolUnknownError: case QNetworkReply::ProtocolUnknownError:
return QObject::tr("The Network Access API cannot honor the request because the protocol is not known"); return tr("The Network Access API cannot honor the request because the protocol is not known");
case QNetworkReply::ProtocolInvalidOperationError: case QNetworkReply::ProtocolInvalidOperationError:
return QObject::tr("The requested operation is invalid for this protocol"); return tr("The requested operation is invalid for this protocol");
case QNetworkReply::UnknownNetworkError: case QNetworkReply::UnknownNetworkError:
return QObject::tr("An unknown network-related error was detected"); return tr("An unknown network-related error was detected");
case QNetworkReply::UnknownProxyError: case QNetworkReply::UnknownProxyError:
return QObject::tr("An unknown proxy-related error was detected"); return tr("An unknown proxy-related error was detected");
case QNetworkReply::UnknownContentError: case QNetworkReply::UnknownContentError:
return QObject::tr("An unknown error related to the remote content was detected"); return tr("An unknown error related to the remote content was detected");
case QNetworkReply::ProtocolFailure: case QNetworkReply::ProtocolFailure:
return QObject::tr("A breakdown in protocol was detected"); return tr("A breakdown in protocol was detected");
default: default:
return QObject::tr("Unknown error"); return tr("Unknown error");
}
} }
} }

19
src/base/net/downloadhandler.h

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -31,8 +31,8 @@
#define NET_DOWNLOADHANDLER_H #define NET_DOWNLOADHANDLER_H
#include <QObject> #include <QObject>
#include "downloadmanager.h"
class QNetworkAccessManager;
class QNetworkReply; class QNetworkReply;
class QUrl; class QUrl;
@ -43,10 +43,14 @@ namespace Net
class DownloadHandler : public QObject class DownloadHandler : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(DownloadHandler)
friend class DownloadManager;
DownloadHandler(QNetworkReply *reply, DownloadManager *manager, const DownloadRequest &downloadRequest);
public: public:
DownloadHandler(QNetworkReply *reply, DownloadManager *manager, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false); ~DownloadHandler() override;
~DownloadHandler();
QString url() const; QString url() const;
@ -61,16 +65,13 @@ namespace Net
void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal); void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal);
private: private:
void init(); void assignNetworkReply(QNetworkReply *reply);
bool saveToFile(const QByteArray &replyData, QString &filePath); bool saveToFile(const QByteArray &replyData, QString &filePath);
void handleRedirection(QUrl newUrl); void handleRedirection(QUrl newUrl);
QNetworkReply *m_reply; QNetworkReply *m_reply;
DownloadManager *m_manager; DownloadManager *m_manager;
bool m_saveToFile; const DownloadRequest m_downloadRequest;
qint64 m_sizeLimit;
bool m_handleRedirectToMagnet;
QString m_url;
}; };
} }

181
src/base/net/downloadmanager.cpp

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -103,28 +103,46 @@ namespace
return QNetworkCookieJar::setCookiesFromUrl(cookies, url); return QNetworkCookieJar::setCookiesFromUrl(cookies, url);
} }
}; };
}
using namespace Net; QNetworkRequest createNetworkRequest(const Net::DownloadRequest &downloadRequest)
{
QNetworkRequest request {downloadRequest.url()};
if (downloadRequest.userAgent().isEmpty())
request.setRawHeader("User-Agent", DEFAULT_USER_AGENT);
else
request.setRawHeader("User-Agent", downloadRequest.userAgent().toUtf8());
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents
request.setRawHeader("Referer", request.url().toEncoded().data());
// Accept gzip
request.setRawHeader("Accept-Encoding", "gzip");
return request;
}
}
DownloadManager *DownloadManager::m_instance = nullptr; Net::DownloadManager *Net::DownloadManager::m_instance = nullptr;
DownloadManager::DownloadManager(QObject *parent) Net::DownloadManager::DownloadManager(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
connect(&m_networkManager, &QNetworkAccessManager::sslErrors, this, &Net::DownloadManager::ignoreSslErrors); connect(&m_networkManager, &QNetworkAccessManager::sslErrors, this, &Net::DownloadManager::ignoreSslErrors);
#endif #endif
connect(&m_networkManager, &QNetworkAccessManager::finished, this, &DownloadManager::handleReplyFinished);
connect(ProxyConfigurationManager::instance(), &ProxyConfigurationManager::proxyConfigurationChanged
, this, &DownloadManager::applyProxySettings);
m_networkManager.setCookieJar(new NetworkCookieJar(this)); m_networkManager.setCookieJar(new NetworkCookieJar(this));
} }
void DownloadManager::initInstance() void Net::DownloadManager::initInstance()
{ {
if (!m_instance) if (!m_instance)
m_instance = new DownloadManager; m_instance = new DownloadManager;
} }
void DownloadManager::freeInstance() void Net::DownloadManager::freeInstance()
{ {
if (m_instance) { if (m_instance) {
delete m_instance; delete m_instance;
@ -132,62 +150,65 @@ void DownloadManager::freeInstance()
} }
} }
DownloadManager *DownloadManager::instance() Net::DownloadManager *Net::DownloadManager::instance()
{ {
return m_instance; return m_instance;
} }
DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFile, qint64 limit, bool handleRedirectToMagnet, const QString &userAgent) Net::DownloadHandler *Net::DownloadManager::download(const DownloadRequest &downloadRequest)
{ {
// Update proxy settings
applyProxySettings();
// Process download request // Process download request
qDebug("url is %s", qUtf8Printable(url)); const QNetworkRequest request = createNetworkRequest(downloadRequest);
const QUrl qurl = QUrl(url); const ServiceID id = ServiceID::fromURL(request.url());
QNetworkRequest request(qurl); const bool isSequentialService = m_sequentialServices.contains(id);
if (!isSequentialService || !m_busyServices.contains(id)) {
if (userAgent.isEmpty()) qDebug("Downloading %s...", qUtf8Printable(downloadRequest.url()));
request.setRawHeader("User-Agent", DEFAULT_USER_AGENT); if (isSequentialService)
else m_busyServices.insert(id);
request.setRawHeader("User-Agent", userAgent.toUtf8()); return new DownloadHandler {
m_networkManager.get(request), this, downloadRequest};
}
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents auto *downloadHandler = new DownloadHandler {nullptr, this, downloadRequest};
request.setRawHeader("Referer", request.url().toEncoded().data()); connect(downloadHandler, &DownloadHandler::destroyed, this, [this, id, downloadHandler]()
{
m_waitingJobs[id].removeOne(downloadHandler);
});
m_waitingJobs[id].enqueue(downloadHandler);
return downloadHandler;
}
qDebug("Downloading %s...", request.url().toEncoded().data()); void Net::DownloadManager::registerSequentialService(const Net::ServiceID &serviceID)
qDebug() << "Cookies:" << m_networkManager.cookieJar()->cookiesForUrl(request.url()); {
// accept gzip m_sequentialServices.insert(serviceID);
request.setRawHeader("Accept-Encoding", "gzip");
return new DownloadHandler(m_networkManager.get(request), this, saveToFile, limit, handleRedirectToMagnet);
} }
QList<QNetworkCookie> DownloadManager::cookiesForUrl(const QUrl &url) const QList<QNetworkCookie> Net::DownloadManager::cookiesForUrl(const QUrl &url) const
{ {
return m_networkManager.cookieJar()->cookiesForUrl(url); return m_networkManager.cookieJar()->cookiesForUrl(url);
} }
bool DownloadManager::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) bool Net::DownloadManager::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
{ {
return m_networkManager.cookieJar()->setCookiesFromUrl(cookieList, url); return m_networkManager.cookieJar()->setCookiesFromUrl(cookieList, url);
} }
QList<QNetworkCookie> DownloadManager::allCookies() const QList<QNetworkCookie> Net::DownloadManager::allCookies() const
{ {
return static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->allCookies(); return static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->allCookies();
} }
void DownloadManager::setAllCookies(const QList<QNetworkCookie> &cookieList) void Net::DownloadManager::setAllCookies(const QList<QNetworkCookie> &cookieList)
{ {
static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->setAllCookies(cookieList); static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->setAllCookies(cookieList);
} }
bool DownloadManager::deleteCookie(const QNetworkCookie &cookie) bool Net::DownloadManager::deleteCookie(const QNetworkCookie &cookie)
{ {
return static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->deleteCookie(cookie); return static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->deleteCookie(cookie);
} }
void DownloadManager::applyProxySettings() void Net::DownloadManager::applyProxySettings()
{ {
auto proxyManager = ProxyConfigurationManager::instance(); auto proxyManager = ProxyConfigurationManager::instance();
ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration(); ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration();
@ -208,7 +229,7 @@ void DownloadManager::applyProxySettings()
} }
// Authentication? // Authentication?
if (proxyManager->isAuthenticationRequired()) { if (proxyManager->isAuthenticationRequired()) {
qDebug("Proxy requires authentication, authenticating"); qDebug("Proxy requires authentication, authenticating...");
proxy.setUser(proxyConfig.username); proxy.setUser(proxyConfig.username);
proxy.setPassword(proxyConfig.password); proxy.setPassword(proxyConfig.password);
} }
@ -220,11 +241,101 @@ void DownloadManager::applyProxySettings()
m_networkManager.setProxy(proxy); m_networkManager.setProxy(proxy);
} }
void Net::DownloadManager::handleReplyFinished(QNetworkReply *reply)
{
const ServiceID id = ServiceID::fromURL(reply->url());
auto waitingJobsIter = m_waitingJobs.find(id);
if ((waitingJobsIter == m_waitingJobs.end()) || waitingJobsIter.value().isEmpty()) {
m_busyServices.remove(id);
return;
}
DownloadHandler *handler = waitingJobsIter.value().dequeue();
qDebug("Downloading %s...", qUtf8Printable(handler->m_downloadRequest.url()));
handler->assignNetworkReply(m_networkManager.get(createNetworkRequest(handler->m_downloadRequest)));
handler->disconnect(this);
}
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
void DownloadManager::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors) void Net::DownloadManager::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{ {
Q_UNUSED(errors) Q_UNUSED(errors)
// Ignore all SSL errors // Ignore all SSL errors
reply->ignoreSslErrors(); reply->ignoreSslErrors();
} }
#endif #endif
Net::DownloadRequest::DownloadRequest(const QString &url)
: m_url {url}
{
}
QString Net::DownloadRequest::url() const
{
return m_url;
}
Net::DownloadRequest &Net::DownloadRequest::url(const QString &value)
{
m_url = value;
return *this;
}
QString Net::DownloadRequest::userAgent() const
{
return m_userAgent;
}
Net::DownloadRequest &Net::DownloadRequest::userAgent(const QString &value)
{
m_userAgent = value;
return *this;
}
qint64 Net::DownloadRequest::limit() const
{
return m_limit;
}
Net::DownloadRequest &Net::DownloadRequest::limit(qint64 value)
{
m_limit = value;
return *this;
}
bool Net::DownloadRequest::saveToFile() const
{
return m_saveToFile;
}
Net::DownloadRequest &Net::DownloadRequest::saveToFile(bool value)
{
m_saveToFile = value;
return *this;
}
bool Net::DownloadRequest::handleRedirectToMagnet() const
{
return m_handleRedirectToMagnet;
}
Net::DownloadRequest &Net::DownloadRequest::handleRedirectToMagnet(bool value)
{
m_handleRedirectToMagnet = value;
return *this;
}
Net::ServiceID Net::ServiceID::fromURL(const QUrl &url)
{
return {url.host(), url.port(80)};
}
uint Net::qHash(const ServiceID &serviceID, uint seed)
{
return ::qHash(serviceID.hostName, seed) ^ serviceID.port;
}
bool Net::operator==(const ServiceID &lhs, const ServiceID &rhs)
{
return ((lhs.hostName == rhs.hostName) && (lhs.port == rhs.port));
}

59
src/base/net/downloadmanager.h

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -30,8 +30,12 @@
#ifndef NET_DOWNLOADMANAGER_H #ifndef NET_DOWNLOADMANAGER_H
#define NET_DOWNLOADMANAGER_H #define NET_DOWNLOADMANAGER_H
#include <QObject> #include <QHash>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QObject>
#include <QQueue>
#include <QSet>
class QNetworkReply; class QNetworkReply;
class QNetworkCookie; class QNetworkCookie;
@ -42,16 +46,57 @@ namespace Net
{ {
class DownloadHandler; class DownloadHandler;
class DownloadRequest
{
public:
DownloadRequest(const QString &url);
DownloadRequest(const DownloadRequest &other) = default;
QString url() const;
DownloadRequest &url(const QString &value);
QString userAgent() const;
DownloadRequest &userAgent(const QString &value);
qint64 limit() const;
DownloadRequest &limit(qint64 value);
bool saveToFile() const;
DownloadRequest &saveToFile(bool value);
bool handleRedirectToMagnet() const;
DownloadRequest &handleRedirectToMagnet(bool value);
private:
QString m_url;
QString m_userAgent;
qint64 m_limit = 0;
bool m_saveToFile = false;
bool m_handleRedirectToMagnet = false;
};
struct ServiceID
{
QString hostName;
int port;
static ServiceID fromURL(const QUrl &url);
};
class DownloadManager : public QObject class DownloadManager : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(DownloadManager)
public: public:
static void initInstance(); static void initInstance();
static void freeInstance(); static void freeInstance();
static DownloadManager *instance(); static DownloadManager *instance();
DownloadHandler *downloadUrl(const QString &url, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false, const QString &userAgent = ""); DownloadHandler *download(const DownloadRequest &downloadRequest);
void registerSequentialService(const ServiceID &serviceID);
QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const; QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url); bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
QList<QNetworkCookie> allCookies() const; QList<QNetworkCookie> allCookies() const;
@ -67,10 +112,18 @@ namespace Net
explicit DownloadManager(QObject *parent = nullptr); explicit DownloadManager(QObject *parent = nullptr);
void applyProxySettings(); void applyProxySettings();
void handleReplyFinished(QNetworkReply *reply);
static DownloadManager *m_instance; static DownloadManager *m_instance;
QNetworkAccessManager m_networkManager; QNetworkAccessManager m_networkManager;
QSet<ServiceID> m_sequentialServices;
QSet<ServiceID> m_busyServices;
QHash<ServiceID, QQueue<DownloadHandler *>> m_waitingJobs;
}; };
uint qHash(const ServiceID &serviceID, uint seed);
bool operator==(const ServiceID &lhs, const ServiceID &rhs);
} }
#endif // NET_DOWNLOADMANAGER_H #endif // NET_DOWNLOADMANAGER_H

2
src/base/net/geoipmanager.cpp

@ -118,7 +118,7 @@ void GeoIPManager::manageDatabaseUpdate()
void GeoIPManager::downloadDatabaseFile() void GeoIPManager::downloadDatabaseFile()
{ {
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(DATABASE_URL); DownloadHandler *handler = DownloadManager::instance()->download({DATABASE_URL});
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished) connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &GeoIPManager::downloadFinished); , this, &GeoIPManager::downloadFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &GeoIPManager::downloadFailed); connect(handler, &Net::DownloadHandler::downloadFailed, this, &GeoIPManager::downloadFailed);

7
src/base/rss/rss_feed.cpp

@ -88,6 +88,8 @@ Feed::Feed(const QUuid &uid, const QString &url, const QString &path, Session *s
else else
connect(m_session, &Session::processingStateChanged, this, &Feed::handleSessionProcessingEnabledChanged); connect(m_session, &Session::processingStateChanged, this, &Feed::handleSessionProcessingEnabledChanged);
Net::DownloadManager::instance()->registerSequentialService(Net::ServiceID::fromURL(m_url));
load(); load();
} }
@ -127,7 +129,7 @@ void Feed::refresh()
// NOTE: Should we allow manually refreshing for disabled session? // NOTE: Should we allow manually refreshing for disabled session?
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url); Net::DownloadHandler *handler = Net::DownloadManager::instance()->download({m_url});
connect(handler connect(handler
, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished) , static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &Feed::handleDownloadFinished); , this, &Feed::handleDownloadFinished);
@ -416,7 +418,8 @@ void Feed::downloadIcon()
// XXX: This works for most sites but it is not perfect // XXX: This works for most sites but it is not perfect
const QUrl url(m_url); const QUrl url(m_url);
auto iconUrl = QString("%1://%2/favicon.ico").arg(url.scheme(), url.host()); auto iconUrl = QString("%1://%2/favicon.ico").arg(url.scheme(), url.host());
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl, true); Net::DownloadHandler *handler = Net::DownloadManager::instance()->download(
Net::DownloadRequest(iconUrl).saveToFile(true));
connect(handler connect(handler
, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished) , static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished)
, this, &Feed::handleIconDownloadFinished); , this, &Feed::handleIconDownloadFinished);

4
src/base/search/searchpluginmanager.cpp

@ -171,7 +171,7 @@ void SearchPluginManager::installPlugin(const QString &source)
if (Utils::Misc::isUrl(source)) { if (Utils::Misc::isUrl(source)) {
using namespace Net; using namespace Net;
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(source, true); DownloadHandler *handler = DownloadManager::instance()->download(DownloadRequest(source).saveToFile(true));
connect(handler, static_cast<void (DownloadHandler::*)(const QString &, const QString &)>(&DownloadHandler::downloadFinished) connect(handler, static_cast<void (DownloadHandler::*)(const QString &, const QString &)>(&DownloadHandler::downloadFinished)
, this, &SearchPluginManager::pluginDownloaded); , this, &SearchPluginManager::pluginDownloaded);
connect(handler, &DownloadHandler::downloadFailed, this, &SearchPluginManager::pluginDownloadFailed); connect(handler, &DownloadHandler::downloadFailed, this, &SearchPluginManager::pluginDownloadFailed);
@ -275,7 +275,7 @@ void SearchPluginManager::checkForUpdates()
{ {
// Download version file from update server // Download version file from update server
using namespace Net; using namespace Net;
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(m_updateUrl + "versions.txt"); DownloadHandler *handler = DownloadManager::instance()->download({m_updateUrl + "versions.txt"});
connect(handler, static_cast<void (DownloadHandler::*)(const QString &, const QByteArray &)>(&DownloadHandler::downloadFinished) connect(handler, static_cast<void (DownloadHandler::*)(const QString &, const QByteArray &)>(&DownloadHandler::downloadFinished)
, this, &SearchPluginManager::versionInfoDownloaded); , this, &SearchPluginManager::versionInfoDownloaded);
connect(handler, &DownloadHandler::downloadFailed, this, &SearchPluginManager::versionInfoDownloadFailed); connect(handler, &DownloadHandler::downloadFailed, this, &SearchPluginManager::versionInfoDownloadFailed);

4
src/gui/addnewtorrentdialog.cpp

@ -230,7 +230,9 @@ void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParam
if (Utils::Misc::isUrl(source)) { if (Utils::Misc::isUrl(source)) {
// Launch downloader // Launch downloader
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true); // TODO: Don't save loaded torrent to file, just use downloaded data!
Net::DownloadHandler *handler = Net::DownloadManager::instance()->download(
Net::DownloadRequest(source).limit(10485760 /* 10MB */).handleRedirectToMagnet(true).saveToFile(true));
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished) connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished)
, dlg, &AddNewTorrentDialog::handleDownloadFinished); , dlg, &AddNewTorrentDialog::handleDownloadFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, dlg, &AddNewTorrentDialog::handleDownloadFailed); connect(handler, &Net::DownloadHandler::downloadFailed, dlg, &AddNewTorrentDialog::handleDownloadFailed);

10
src/gui/mainwindow.cpp

@ -2041,11 +2041,11 @@ void MainWindow::installPython()
{ {
setCursor(QCursor(Qt::WaitCursor)); setCursor(QCursor(Qt::WaitCursor));
// Download python // Download python
Net::DownloadHandler *handler = nullptr; const QString installerURL = ((QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) ? "https://www.python.org/ftp/python/3.5.2/python-3.5.2.exe"
handler = Net::DownloadManager::instance()->downloadUrl("https://www.python.org/ftp/python/3.5.2/python-3.5.2.exe", true); : "https://www.python.org/ftp/python/3.4.4/python-3.4.4.msi");
else Net::DownloadHandler *handler = Net::DownloadManager::instance()->download(
handler = Net::DownloadManager::instance()->downloadUrl("https://www.python.org/ftp/python/3.4.4/python-3.4.4.msi", true); Net::DownloadRequest(installerURL).saveToFile(true));
using Func = void (Net::DownloadHandler::*)(const QString &, const QString &); using Func = void (Net::DownloadHandler::*)(const QString &, const QString &);
connect(handler, static_cast<Func>(&Net::DownloadHandler::downloadFinished), this, &MainWindow::pythonDownloadSuccess); connect(handler, static_cast<Func>(&Net::DownloadHandler::downloadFinished), this, &MainWindow::pythonDownloadSuccess);

5
src/gui/programupdater.cpp

@ -61,11 +61,10 @@ ProgramUpdater::ProgramUpdater(QObject *parent, bool invokedByUser)
void ProgramUpdater::checkForUpdates() void ProgramUpdater::checkForUpdates()
{ {
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(
RSS_URL, false, 0, false,
// Don't change this User-Agent. In case our updater goes haywire, // Don't change this User-Agent. In case our updater goes haywire,
// the filehost can identify it and contact us. // the filehost can identify it and contact us.
"qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)"); Net::DownloadHandler *handler = Net::DownloadManager::instance()->download(
Net::DownloadRequest(RSS_URL).userAgent("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)"));
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished) connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &ProgramUpdater::rssDownloadFinished); , this, &ProgramUpdater::rssDownloadFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &ProgramUpdater::rssDownloadFailed); connect(handler, &Net::DownloadHandler::downloadFailed, this, &ProgramUpdater::rssDownloadFailed);

30
src/gui/properties/trackersadditiondialog.cpp

@ -25,9 +25,10 @@
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*/ */
#include "trackersadditiondialog.h" #include "trackersadditiondialog.h"
#include <QFile> #include <QBuffer>
#include <QMessageBox> #include <QMessageBox>
#include <QStringList> #include <QStringList>
#include <QUrl> #include <QUrl>
@ -70,25 +71,16 @@ QStringList TrackersAdditionDialog::newTrackers() const
void TrackersAdditionDialog::on_uTorrentListButton_clicked() void TrackersAdditionDialog::on_uTorrentListButton_clicked()
{ {
m_ui->uTorrentListButton->setEnabled(false); m_ui->uTorrentListButton->setEnabled(false);
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_ui->list_url->text(), true); Net::DownloadHandler *handler = Net::DownloadManager::instance()->download({m_ui->list_url->text()});
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished) connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &TrackersAdditionDialog::parseUTorrentList); , this, &TrackersAdditionDialog::parseUTorrentList);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &TrackersAdditionDialog::getTrackerError); connect(handler, &Net::DownloadHandler::downloadFailed, this, &TrackersAdditionDialog::getTrackerError);
// Just to show that it takes times // Just to show that it takes times
setCursor(Qt::WaitCursor); setCursor(Qt::WaitCursor);
} }
void TrackersAdditionDialog::parseUTorrentList(const QString &, const QString &path) void TrackersAdditionDialog::parseUTorrentList(const QString &, const QByteArray &data)
{ {
QFile listFile(path);
if (!listFile.open(QFile::ReadOnly)) {
QMessageBox::warning(this, tr("I/O Error"), tr("Error while trying to open the downloaded file."), QMessageBox::Ok);
setCursor(Qt::ArrowCursor);
m_ui->uTorrentListButton->setEnabled(true);
Utils::Fs::forceRemove(path);
return;
}
// Load from torrent handle // Load from torrent handle
QList<BitTorrent::TrackerEntry> existingTrackers = m_torrent->trackers(); QList<BitTorrent::TrackerEntry> existingTrackers = m_torrent->trackers();
// Load from current user list // Load from current user list
@ -103,18 +95,20 @@ void TrackersAdditionDialog::parseUTorrentList(const QString &, const QString &p
if (!m_ui->trackers_list->toPlainText().isEmpty() && !m_ui->trackers_list->toPlainText().endsWith('\n')) if (!m_ui->trackers_list->toPlainText().isEmpty() && !m_ui->trackers_list->toPlainText().endsWith('\n'))
m_ui->trackers_list->insertPlainText("\n"); m_ui->trackers_list->insertPlainText("\n");
int nb = 0; int nb = 0;
while (!listFile.atEnd()) { QBuffer buffer;
const QString line = listFile.readLine().trimmed(); buffer.setData(data);
buffer.open(QBuffer::ReadOnly);
while (!buffer.atEnd()) {
const QString line = buffer.readLine().trimmed();
if (line.isEmpty()) continue; if (line.isEmpty()) continue;
BitTorrent::TrackerEntry newTracker(line); BitTorrent::TrackerEntry newTracker(line);
if (!existingTrackers.contains(newTracker)) { if (!existingTrackers.contains(newTracker)) {
m_ui->trackers_list->insertPlainText(line + '\n'); m_ui->trackers_list->insertPlainText(line + '\n');
++nb; ++nb;
} }
} }
// Clean up
listFile.close();
Utils::Fs::forceRemove(path);
// To restore the cursor ... // To restore the cursor ...
setCursor(Qt::ArrowCursor); setCursor(Qt::ArrowCursor);
m_ui->uTorrentListButton->setEnabled(true); m_ui->uTorrentListButton->setEnabled(true);

2
src/gui/properties/trackersadditiondialog.h

@ -57,7 +57,7 @@ public:
public slots: public slots:
void on_uTorrentListButton_clicked(); void on_uTorrentListButton_clicked();
void parseUTorrentList(const QString &, const QString &path); void parseUTorrentList(const QString &, const QByteArray &data);
void getTrackerError(const QString &, const QString &error); void getTrackerError(const QString &, const QString &error);
private: private:

3
src/gui/search/pluginselectdialog.cpp

@ -292,7 +292,8 @@ void PluginSelectDialog::addNewPlugin(QString pluginName)
else { else {
// Icon is missing, we must download it // Icon is missing, we must download it
using namespace Net; using namespace Net;
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(plugin->url + "/favicon.ico", true); DownloadHandler *handler = DownloadManager::instance()->download(
DownloadRequest(plugin->url + "/favicon.ico").saveToFile(true));
connect(handler, static_cast<void (DownloadHandler::*)(const QString &, const QString &)>(&DownloadHandler::downloadFinished) connect(handler, static_cast<void (DownloadHandler::*)(const QString &, const QString &)>(&DownloadHandler::downloadFinished)
, this, &PluginSelectDialog::iconDownloaded); , this, &PluginSelectDialog::iconDownloaded);
connect(handler, &DownloadHandler::downloadFailed, this, &PluginSelectDialog::iconDownloadFailed); connect(handler, &DownloadHandler::downloadFailed, this, &PluginSelectDialog::iconDownloadFailed);

3
src/gui/transferlistfilterswidget.cpp

@ -404,7 +404,8 @@ void TrackerFiltersList::trackerWarning(const QString &hash, const QString &trac
void TrackerFiltersList::downloadFavicon(const QString& url) void TrackerFiltersList::downloadFavicon(const QString& url)
{ {
if (!m_downloadTrackerFavicon) return; if (!m_downloadTrackerFavicon) return;
Net::DownloadHandler *h = Net::DownloadManager::instance()->downloadUrl(url, true); Net::DownloadHandler *h = Net::DownloadManager::instance()->download(
Net::DownloadRequest(url).saveToFile(true));
using Func = void (Net::DownloadHandler::*)(const QString &, const QString &); using Func = void (Net::DownloadHandler::*)(const QString &, const QString &);
connect(h, static_cast<Func>(&Net::DownloadHandler::downloadFinished), this connect(h, static_cast<Func>(&Net::DownloadHandler::downloadFinished), this
, &TrackerFiltersList::handleFavicoDownload); , &TrackerFiltersList::handleFavicoDownload);

Loading…
Cancel
Save