diff --git a/src/base/bittorrent/magneturi.cpp b/src/base/bittorrent/magneturi.cpp index 84673fffc..cad119c77 100644 --- a/src/base/bittorrent/magneturi.cpp +++ b/src/base/bittorrent/magneturi.cpp @@ -26,6 +26,10 @@ * exception statement from your version. */ +#include +#include +#include + #include #include #include @@ -33,17 +37,45 @@ #include "base/utils/string.h" #include "magneturi.h" +namespace +{ + QString bcLinkToMagnet(QString bcLink) + { + QByteArray rawBc = bcLink.toUtf8(); + rawBc = rawBc.mid(8); // skip bc://bt/ + rawBc = QByteArray::fromBase64(rawBc); // Decode base64 + // Format is now AA/url_encoded_filename/size_bytes/info_hash/ZZ + QStringList parts = QString(rawBc).split("/"); + if (parts.size() != 5) return QString(); + + QString filename = parts.at(1); + QString hash = parts.at(3); + QString magnet = "magnet:?xt=urn:btih:" + hash; + magnet += "&dn=" + filename; + return magnet; + } +} + namespace libt = libtorrent; using namespace BitTorrent; -MagnetUri::MagnetUri(const QString &url) +MagnetUri::MagnetUri(const QString &source) : m_valid(false) - , m_url(url) + , m_url(source) { - if (url.isEmpty()) return; + if (source.isEmpty()) return; + + if (source.startsWith("bc://bt/", Qt::CaseInsensitive)) { + qDebug("Creating magnet link from bc link"); + m_url = bcLinkToMagnet(source); + } + else if (((source.size() == 40) && !source.contains(QRegExp("[^0-9A-Fa-f]"))) + || ((source.size() == 32) && !source.contains(QRegExp("[^2-7A-Za-z]")))) { + m_url = "magnet:?xt=urn:btih:" + source; + } libt::error_code ec; - libt::parse_magnet_uri(url.toUtf8().constData(), m_addTorrentParams, ec); + libt::parse_magnet_uri(m_url.toUtf8().constData(), m_addTorrentParams, ec); if (ec) return; m_valid = true; diff --git a/src/base/bittorrent/magneturi.h b/src/base/bittorrent/magneturi.h index b4b303753..e7e23becf 100644 --- a/src/base/bittorrent/magneturi.h +++ b/src/base/bittorrent/magneturi.h @@ -43,7 +43,7 @@ namespace BitTorrent class MagnetUri { public: - explicit MagnetUri(const QString &url = QString()); + explicit MagnetUri(const QString &source = QString()); bool isValid() const; InfoHash hash() const; diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index e80fdd0f4..3ee7322d4 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -100,16 +100,6 @@ static void torrentQueuePositionDown(const libt::torrent_handle &handle); static void torrentQueuePositionTop(const libt::torrent_handle &handle); static void torrentQueuePositionBottom(const libt::torrent_handle &handle); -// AddTorrentParams - -AddTorrentParams::AddTorrentParams() - : disableTempPath(false) - , sequential(false) - , ignoreShareRatio(false) - , skipChecking(false) -{ -} - // Session Session *Session::m_instance = 0; @@ -713,7 +703,7 @@ void Session::handleDownloadFailed(const QString &url, const QString &reason) void Session::handleRedirectedToMagnet(const QString &url, const QString &magnetUri) { - addTorrent_impl(addDataFromParams(m_downloadedTorrents.take(url)), MagnetUri(magnetUri)); + addTorrent_impl(m_downloadedTorrents.take(url), MagnetUri(magnetUri)); } void Session::switchToAlternativeMode(bool alternative) @@ -725,7 +715,7 @@ void Session::switchToAlternativeMode(bool alternative) void Session::handleDownloadFinished(const QString &url, const QString &filePath) { emit downloadFromUrlFinished(url); - addTorrent_impl(addDataFromParams(m_downloadedTorrents.take(url)), MagnetUri(), TorrentInfo::loadFromFile(filePath)); + addTorrent_impl(m_downloadedTorrents.take(url), MagnetUri(), TorrentInfo::loadFromFile(filePath)); Utils::Fs::forceRemove(filePath); // remove temporary file } @@ -939,40 +929,14 @@ TorrentStatusReport Session::torrentStatusReport() const return m_torrentStatusReport; } -// source - .torrent file path/url or magnet uri (hash for preloaded torrent) +// source - .torrent file path/url or magnet uri bool Session::addTorrent(QString source, const AddTorrentParams ¶ms) { - InfoHash hash = source; - if (hash.isValid() && m_loadedMetadata.contains(hash)) { - // Adding preloaded torrent - m_loadedMetadata.remove(hash); - libt::torrent_handle handle = m_nativeSession->find_torrent(hash); - --m_extraLimit; - - try { - handle.auto_managed(false); - handle.pause(); - } - catch (std::exception &) {} - - adjustLimits(); - - // use common 2nd step of torrent addition - m_addingTorrents.insert(hash, addDataFromParams(params)); - createTorrentHandle(handle); - return true; - } - - if (source.startsWith("bc://bt/", Qt::CaseInsensitive)) { - qDebug("Converting bc link to magnet link"); - source = Utils::Misc::bcLinkToMagnet(source); + MagnetUri magnetUri(source); + if (magnetUri.isValid()) { + return addTorrent_impl(params, magnetUri); } - else if (((source.size() == 40) && !source.contains(QRegExp("[^0-9A-Fa-f]"))) - || ((source.size() == 32) && !source.contains(QRegExp("[^2-7A-Za-z]")))) { - source = "magnet:?xt=urn:btih:" + source; - } - - 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)); // Launch downloader Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true); @@ -981,11 +945,8 @@ bool Session::addTorrent(QString source, const AddTorrentParams ¶ms) connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), this, SLOT(handleRedirectedToMagnet(QString, QString))); m_downloadedTorrents[handler->url()] = params; } - else if (source.startsWith("magnet:", Qt::CaseInsensitive)) { - return addTorrent_impl(addDataFromParams(params), MagnetUri(source)); - } else { - return addTorrent_impl(addDataFromParams(params), MagnetUri(), TorrentInfo::loadFromFile(source)); + return addTorrent_impl(params, MagnetUri(), TorrentInfo::loadFromFile(source)); } return false; @@ -995,13 +956,26 @@ bool Session::addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams { if (!torrentInfo.isValid()) return false; - return addTorrent_impl(addDataFromParams(params), MagnetUri(), torrentInfo); + return addTorrent_impl(params, MagnetUri(), torrentInfo); } // Add a torrent to the BitTorrent session bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri, const TorrentInfo &torrentInfo, const QByteArray &fastresumeData) { + if (!addData.resumed) { + // manage save path + QString defaultSavePath = this->defaultSavePath(); + if (addData.savePath.isEmpty()) + addData.savePath = defaultSavePath; + if (!addData.savePath.endsWith("/")) + addData.savePath += "/"; + if (useAppendLabelToSavePath()) { + if ((addData.savePath == defaultSavePath) && !addData.label.isEmpty()) + addData.savePath += QString("%1/").arg(addData.label); + } + } + libt::add_torrent_params p; InfoHash hash; std::vector buf(fastresumeData.constData(), fastresumeData.constData() + fastresumeData.size()); @@ -1009,8 +983,29 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri bool fromMagnetUri = magnetUri.isValid(); if (fromMagnetUri) { - p = magnetUri.addTorrentParams(); hash = magnetUri.hash(); + + if (m_loadedMetadata.contains(hash)) { + // Adding preloaded torrent + m_loadedMetadata.remove(hash); + libt::torrent_handle handle = m_nativeSession->find_torrent(hash); + --m_extraLimit; + + try { + handle.auto_managed(false); + handle.pause(); + } + catch (std::exception &) {} + + adjustLimits(); + + // use common 2nd step of torrent addition + m_addingTorrents.insert(hash, addData); + createTorrentHandle(handle); + return true; + } + + p = magnetUri.addTorrentParams(); } else if (torrentInfo.isValid()) { // Metadata @@ -1091,15 +1086,12 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri // Add a torrent to the BitTorrent session in hidden mode // and force it to load its metadata -bool Session::loadMetadata(const QString &magnetUri) +bool Session::loadMetadata(const MagnetUri &magnetUri) { - Q_ASSERT(magnetUri.startsWith("magnet:", Qt::CaseInsensitive)); - - MagnetUri magnet(magnetUri); - if (!magnet.isValid()) return false; + if (!magnetUri.isValid()) return false; - InfoHash hash = magnet.hash(); - QString name = magnet.name(); + InfoHash hash = magnetUri.hash(); + QString name = magnetUri.name(); // We should not add torrent if it already // processed or adding to session @@ -1111,7 +1103,7 @@ bool Session::loadMetadata(const QString &magnetUri) qDebug(" -> Hash: %s", qPrintable(hash)); qDebug(" -> Name: %s", qPrintable(name)); - libt::add_torrent_params p = magnet.addTorrentParams(); + libt::add_torrent_params p = magnetUri.addTorrentParams(); // Flags // Preallocation mode @@ -2358,6 +2350,11 @@ bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &out, MagnetUr if (ec || (fast.type() != libt::lazy_entry::dict_t)) return false; out.savePath = Utils::Fs::fromNativePath(Utils::String::fromStdString(fast.dict_find_string_value("qBt-savePath"))); + if (out.savePath.isEmpty()) { + Logger::instance()->addMessage("Empty torrent save path was loaded from .fastresume file! Using default one...", Log::WARNING); + out.savePath = Preferences::instance()->getSavePath(); + } + out.ratioLimit = Utils::String::fromStdString(fast.dict_find_string_value("qBt-ratioLimit")).toDouble(); out.label = Utils::String::fromStdString(fast.dict_find_string_value("qBt-label")); out.name = Utils::String::fromStdString(fast.dict_find_string_value("qBt-name")); @@ -2432,33 +2429,3 @@ void torrentQueuePositionBottom(const libt::torrent_handle &handle) qDebug() << Q_FUNC_INFO << " fails: " << exc.what(); } } - -AddTorrentData Session::addDataFromParams(const AddTorrentParams ¶ms) -{ - AddTorrentData data; - - data.resumed = false; - data.name = params.name; - data.label = params.label; - data.savePath = params.savePath; - data.disableTempPath = params.disableTempPath; - data.sequential = params.sequential; - data.hasSeedStatus = params.skipChecking; // do not react on 'torrent_finished_alert' when skipping - data.skipChecking = params.skipChecking; - data.addForced = params.addForced; - data.addPaused = params.addPaused; - data.filePriorities = params.filePriorities; - data.ratioLimit = params.ignoreShareRatio ? TorrentHandle::NO_RATIO_LIMIT : TorrentHandle::USE_GLOBAL_RATIO; - - // normalize save path - if (data.savePath.isEmpty()) { - data.savePath = m_defaultSavePath; - if (m_appendLabelToSavePath && !data.label.isEmpty()) - data.savePath += QString("%1/").arg(data.label); - } - else if (!data.savePath.endsWith("/")) { - data.savePath += "/"; - } - - return data; -} diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 6eea60981..0289d335b 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -127,15 +127,13 @@ namespace BitTorrent QString name; QString label; QString savePath; - bool disableTempPath; // e.g. for imported torrents - bool sequential; + bool disableTempPath = false; // e.g. for imported torrents + bool sequential = false; TriStateBool addForced; TriStateBool addPaused; QVector filePriorities; // used if TorrentInfo is set - bool ignoreShareRatio; - bool skipChecking; - - AddTorrentParams(); + bool ignoreShareRatio = false; + bool skipChecking = false; }; struct TorrentStatusReport @@ -196,7 +194,7 @@ namespace BitTorrent bool addTorrent(QString source, const AddTorrentParams ¶ms = AddTorrentParams()); bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams ¶ms = AddTorrentParams()); bool deleteTorrent(const QString &hash, bool deleteLocalFiles = false); - bool loadMetadata(const QString &magnetUri); + bool loadMetadata(const MagnetUri &magnetUri); bool cancelLoadMetadata(const InfoHash &hash); void recursiveTorrentDownload(const InfoHash &hash); @@ -334,8 +332,6 @@ namespace BitTorrent void dispatchAlerts(std::auto_ptr alertPtr); void getPendingAlerts(QVector &out, ulong time = 0); - AddTorrentData addDataFromParams(const AddTorrentParams ¶ms); - // BitTorrent libtorrent::session *m_nativeSession; diff --git a/src/base/bittorrent/torrenthandle.cpp b/src/base/bittorrent/torrenthandle.cpp index 4707b5f77..caac99d20 100644 --- a/src/base/bittorrent/torrenthandle.cpp +++ b/src/base/bittorrent/torrenthandle.cpp @@ -65,10 +65,31 @@ static const char QB_EXT[] = ".!qB"; namespace libt = libtorrent; using namespace BitTorrent; -// TrackerInfo +// AddTorrentData -TrackerInfo::TrackerInfo() - : numPeers(0) +AddTorrentData::AddTorrentData() + : resumed(false) + , disableTempPath(false) + , sequential(false) + , hasSeedStatus(false) + , skipChecking(false) + , ratioLimit(TorrentHandle::USE_GLOBAL_RATIO) +{ +} + +AddTorrentData::AddTorrentData(const AddTorrentParams ¶ms) + : resumed(false) + , name(params.name) + , label(params.label) + , savePath(params.savePath) + , disableTempPath(params.disableTempPath) + , sequential(params.sequential) + , hasSeedStatus(params.skipChecking) // do not react on 'torrent_finished_alert' when skipping + , skipChecking(params.skipChecking) + , addForced(params.addForced) + , addPaused(params.addPaused) + , filePriorities(params.filePriorities) + , ratioLimit(params.ignoreShareRatio ? TorrentHandle::NO_RATIO_LIMIT : TorrentHandle::USE_GLOBAL_RATIO) { } @@ -188,7 +209,11 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle , m_pauseAfterRecheck(false) , m_needSaveResumeData(false) { - initialize(); + Q_ASSERT(!m_savePath.isEmpty()); + + updateStatus(); + m_hash = InfoHash(m_nativeStatus.info_hash); + adjustActualSavePath(); if (!data.resumed) { setSequentialDownload(data.sequential); @@ -1704,13 +1729,6 @@ void TorrentHandle::updateTorrentInfo() #endif } -void TorrentHandle::initialize() -{ - updateStatus(); - m_hash = InfoHash(m_nativeStatus.info_hash); - adjustActualSavePath(); -} - bool TorrentHandle::isMoveInProgress() const { return !m_newPath.isEmpty(); diff --git a/src/base/bittorrent/torrenthandle.h b/src/base/bittorrent/torrenthandle.h index 882cdb029..0f1ee3fce 100644 --- a/src/base/bittorrent/torrenthandle.h +++ b/src/base/bittorrent/torrenthandle.h @@ -102,14 +102,15 @@ namespace BitTorrent QVector filePriorities; // for resumed torrents qreal ratioLimit; + + AddTorrentData(); + AddTorrentData(const AddTorrentParams ¶ms); }; struct TrackerInfo { QString lastMessage; - quint32 numPeers; - - TrackerInfo(); + quint32 numPeers = 0; }; class TorrentState @@ -349,7 +350,6 @@ namespace BitTorrent private: typedef boost::function EventTrigger; - void initialize(); void updateStatus(); void updateStatus(const libtorrent::torrent_status &nativeStatus); void updateState(); diff --git a/src/base/utils/misc.cpp b/src/base/utils/misc.cpp index 7e34f0a97..580fa7ad1 100644 --- a/src/base/utils/misc.cpp +++ b/src/base/utils/misc.cpp @@ -392,21 +392,6 @@ bool Utils::Misc::isPreviewable(const QString& extension) return multimedia_extensions.contains(extension.toUpper()); } -QString Utils::Misc::bcLinkToMagnet(QString bc_link) -{ - QByteArray raw_bc = bc_link.toUtf8(); - raw_bc = raw_bc.mid(8); // skip bc://bt/ - raw_bc = QByteArray::fromBase64(raw_bc); // Decode base64 - // Format is now AA/url_encoded_filename/size_bytes/info_hash/ZZ - QStringList parts = QString(raw_bc).split("/"); - if (parts.size() != 5) return QString::null; - QString filename = parts.at(1); - QString hash = parts.at(3); - QString magnet = "magnet:?xt=urn:btih:" + hash; - magnet += "&dn=" + filename; - return magnet; -} - // Take a number of seconds and return an user-friendly // time duration like "1d 2h 10m". QString Utils::Misc::userFriendlyDuration(qlonglong seconds) diff --git a/src/base/utils/misc.h b/src/base/utils/misc.h index fd62a637b..bfc4d00e4 100644 --- a/src/base/utils/misc.h +++ b/src/base/utils/misc.h @@ -66,7 +66,6 @@ namespace Utils QString friendlyUnit(qreal val, bool is_speed = false); bool isPreviewable(const QString& extension); - QString bcLinkToMagnet(QString bc_link); // Take a number of seconds and return an user-friendly // time duration like "1d 2h 10m". QString userFriendlyDuration(qlonglong seconds); diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 4c74a1973..eb844f02f 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -133,15 +133,6 @@ void AddNewTorrentDialog::saveState() void AddNewTorrentDialog::show(QString source, QWidget *parent) { - if (source.startsWith("bc://bt/", Qt::CaseInsensitive)) { - qDebug("Converting bc link to magnet link"); - source = Utils::Misc::bcLinkToMagnet(source); - } - else if (((source.size() == 40) && !source.contains(QRegExp("[^0-9A-Fa-f]"))) - || ((source.size() == 32) && !source.contains(QRegExp("[^2-7A-Za-z]")))) { - source = "magnet:?xt=urn:btih:" + source; - } - AddNewTorrentDialog *dlg = new AddNewTorrentDialog(parent); if (Utils::Misc::isUrl(source)) { @@ -153,8 +144,9 @@ void AddNewTorrentDialog::show(QString source, QWidget *parent) } else { bool ok = false; - if (source.startsWith("magnet:", Qt::CaseInsensitive)) - ok = dlg->loadMagnet(source); + BitTorrent::MagnetUri magnetUri(source); + if (magnetUri.isValid()) + ok = dlg->loadMagnet(magnetUri); else ok = dlg->loadTorrent(source); @@ -165,12 +157,12 @@ void AddNewTorrentDialog::show(QString source, QWidget *parent) } } -bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path) +bool AddNewTorrentDialog::loadTorrent(const QString &torrentPath) { - if (torrent_path.startsWith("file://", Qt::CaseInsensitive)) - m_filePath = QUrl::fromEncoded(torrent_path.toLocal8Bit()).toLocalFile(); + if (torrentPath.startsWith("file://", Qt::CaseInsensitive)) + m_filePath = QUrl::fromEncoded(torrentPath.toLocal8Bit()).toLocalFile(); else - m_filePath = torrent_path; + m_filePath = torrentPath; if (!QFile::exists(m_filePath)) { MessageBoxRaised::critical(0, tr("I/O Error"), tr("The torrent file does not exist.")); @@ -212,21 +204,20 @@ bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path) return true; } -bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri) +bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri) { - BitTorrent::MagnetUri magnet(magnet_uri); - if (!magnet.isValid()) { + if (!magnetUri.isValid()) { MessageBoxRaised::critical(0, tr("Invalid magnet link"), tr("This magnet link was not recognized")); return false; } - m_hash = magnet.hash(); + m_hash = magnetUri.hash(); // Prevent showing the dialog if download is already present if (BitTorrent::Session::instance()->isKnownTorrent(m_hash)) { BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(m_hash); if (torrent) { - torrent->addTrackers(magnet.trackers()); - torrent->addUrlSeeds(magnet.urlSeeds()); + torrent->addTrackers(magnetUri.trackers()); + torrent->addUrlSeeds(magnetUri.urlSeeds()); MessageBoxRaised::information(0, tr("Already in download list"), tr("Magnet link is already in download list. Trackers were merged."), QMessageBox::Ok); } else { @@ -238,14 +229,14 @@ bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri) connect(BitTorrent::Session::instance(), SIGNAL(metadataLoaded(BitTorrent::TorrentInfo)), SLOT(updateMetadata(BitTorrent::TorrentInfo))); // Set dialog title - QString torrent_name = magnet.name(); + QString torrent_name = magnetUri.name(); setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name); setupTreeview(); // Set dialog position setdialogPosition(); - BitTorrent::Session::instance()->loadMetadata(magnet_uri); + BitTorrent::Session::instance()->loadMetadata(magnetUri); setMetadataProgressIndicator(true, tr("Retrieving metadata...")); ui->lblhash->setText(m_hash); @@ -732,7 +723,7 @@ void AddNewTorrentDialog::handleDownloadFailed(const QString &url, const QString void AddNewTorrentDialog::handleRedirectedToMagnet(const QString &url, const QString &magnetUri) { Q_UNUSED(url) - if (loadMagnet(magnetUri)) + if (loadMagnet(BitTorrent::MagnetUri(magnetUri))) open(); else this->deleteLater(); diff --git a/src/gui/addnewtorrentdialog.h b/src/gui/addnewtorrentdialog.h index ae54f208a..8b1cd2576 100644 --- a/src/gui/addnewtorrentdialog.h +++ b/src/gui/addnewtorrentdialog.h @@ -38,11 +38,15 @@ #include "base/bittorrent/infohash.h" #include "base/bittorrent/torrentinfo.h" -QT_BEGIN_NAMESPACE -namespace Ui { +namespace BitTorrent +{ + class MagnetUri; +} + +namespace Ui +{ class AddNewTorrentDialog; } -QT_END_NAMESPACE class TorrentContentFilterModel; class PropListDelegate; @@ -79,8 +83,8 @@ protected slots: private: explicit AddNewTorrentDialog(QWidget *parent = 0); - bool loadTorrent(const QString& torrent_path); - bool loadMagnet(const QString& magnet_uri); + bool loadTorrent(const QString &torrentPath); + bool loadMagnet(const BitTorrent::MagnetUri &magnetUri); void loadSavePathHistory(); void saveSavePathHistory() const; int indexOfSavePath(const QString& save_path); diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index 05659a9c3..2cfab6f2a 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -354,14 +354,6 @@ void WebApplication::action_command_download() foreach (QString url, list) { url = url.trimmed(); if (!url.isEmpty()) { - if (url.startsWith("bc://bt/", Qt::CaseInsensitive)) { - qDebug("Converting bc link to magnet link"); - url = Utils::Misc::bcLinkToMagnet(url); - } - if ((url.size() == 40 && !url.contains(QRegExp("[^0-9A-Fa-f]"))) - || (url.size() == 32 && !url.contains(QRegExp("[^2-7A-Za-z]")))) - url = "magnet:?xt=urn:btih:" + url; - Net::DownloadManager::instance()->setCookiesFromUrl(cookies, QUrl::fromEncoded(url.toUtf8())); BitTorrent::Session::instance()->addTorrent(url, params); }