mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-23 09:47:08 +03:00
Create MagnetUri object from BC link or HASH string
This commit is contained in:
parent
f23cd9204c
commit
c57aaf0216
9 changed files with 71 additions and 79 deletions
|
@ -26,6 +26,10 @@
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QRegExp>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
#include <libtorrent/bencode.hpp>
|
#include <libtorrent/bencode.hpp>
|
||||||
#include <libtorrent/error_code.hpp>
|
#include <libtorrent/error_code.hpp>
|
||||||
#include <libtorrent/magnet_uri.hpp>
|
#include <libtorrent/magnet_uri.hpp>
|
||||||
|
@ -33,17 +37,45 @@
|
||||||
#include "base/utils/string.h"
|
#include "base/utils/string.h"
|
||||||
#include "magneturi.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;
|
namespace libt = libtorrent;
|
||||||
using namespace BitTorrent;
|
using namespace BitTorrent;
|
||||||
|
|
||||||
MagnetUri::MagnetUri(const QString &url)
|
MagnetUri::MagnetUri(const QString &source)
|
||||||
: m_valid(false)
|
: 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::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;
|
if (ec) return;
|
||||||
|
|
||||||
m_valid = true;
|
m_valid = true;
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace BitTorrent
|
||||||
class MagnetUri
|
class MagnetUri
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit MagnetUri(const QString &url = QString());
|
explicit MagnetUri(const QString &source = QString());
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
InfoHash hash() const;
|
InfoHash hash() const;
|
||||||
|
|
|
@ -963,16 +963,11 @@ bool Session::addTorrent(QString source, const AddTorrentParams ¶ms)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.startsWith("bc://bt/", Qt::CaseInsensitive)) {
|
MagnetUri magnetUri(source);
|
||||||
qDebug("Converting bc link to magnet link");
|
if (magnetUri.isValid()) {
|
||||||
source = Utils::Misc::bcLinkToMagnet(source);
|
return addTorrent_impl(params, magnetUri);
|
||||||
}
|
}
|
||||||
else if (((source.size() == 40) && !source.contains(QRegExp("[^0-9A-Fa-f]")))
|
else if (Utils::Misc::isUrl(source)) {
|
||||||
|| ((source.size() == 32) && !source.contains(QRegExp("[^2-7A-Za-z]")))) {
|
|
||||||
source = "magnet:?xt=urn:btih:" + source;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Utils::Misc::isUrl(source)) {
|
|
||||||
Logger::instance()->addMessage(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source));
|
Logger::instance()->addMessage(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 = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true);
|
||||||
|
@ -981,9 +976,6 @@ bool Session::addTorrent(QString source, const AddTorrentParams ¶ms)
|
||||||
connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), this, SLOT(handleRedirectedToMagnet(QString, QString)));
|
connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), this, SLOT(handleRedirectedToMagnet(QString, QString)));
|
||||||
m_downloadedTorrents[handler->url()] = params;
|
m_downloadedTorrents[handler->url()] = params;
|
||||||
}
|
}
|
||||||
else if (source.startsWith("magnet:", Qt::CaseInsensitive)) {
|
|
||||||
return addTorrent_impl(addDataFromParams(params), MagnetUri(source));
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return addTorrent_impl(addDataFromParams(params), MagnetUri(), TorrentInfo::loadFromFile(source));
|
return addTorrent_impl(addDataFromParams(params), MagnetUri(), TorrentInfo::loadFromFile(source));
|
||||||
}
|
}
|
||||||
|
@ -1091,15 +1083,12 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
|
||||||
|
|
||||||
// Add a torrent to the BitTorrent session in hidden mode
|
// Add a torrent to the BitTorrent session in hidden mode
|
||||||
// and force it to load its metadata
|
// 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));
|
if (!magnetUri.isValid()) return false;
|
||||||
|
|
||||||
MagnetUri magnet(magnetUri);
|
InfoHash hash = magnetUri.hash();
|
||||||
if (!magnet.isValid()) return false;
|
QString name = magnetUri.name();
|
||||||
|
|
||||||
InfoHash hash = magnet.hash();
|
|
||||||
QString name = magnet.name();
|
|
||||||
|
|
||||||
// We should not add torrent if it already
|
// We should not add torrent if it already
|
||||||
// processed or adding to session
|
// processed or adding to session
|
||||||
|
@ -1111,7 +1100,7 @@ bool Session::loadMetadata(const QString &magnetUri)
|
||||||
qDebug(" -> Hash: %s", qPrintable(hash));
|
qDebug(" -> Hash: %s", qPrintable(hash));
|
||||||
qDebug(" -> Name: %s", qPrintable(name));
|
qDebug(" -> Name: %s", qPrintable(name));
|
||||||
|
|
||||||
libt::add_torrent_params p = magnet.addTorrentParams();
|
libt::add_torrent_params p = magnetUri.addTorrentParams();
|
||||||
|
|
||||||
// Flags
|
// Flags
|
||||||
// Preallocation mode
|
// Preallocation mode
|
||||||
|
|
|
@ -196,7 +196,7 @@ namespace BitTorrent
|
||||||
bool addTorrent(QString source, const AddTorrentParams ¶ms = AddTorrentParams());
|
bool addTorrent(QString source, const AddTorrentParams ¶ms = AddTorrentParams());
|
||||||
bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams ¶ms = AddTorrentParams());
|
bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams ¶ms = AddTorrentParams());
|
||||||
bool deleteTorrent(const QString &hash, bool deleteLocalFiles = false);
|
bool deleteTorrent(const QString &hash, bool deleteLocalFiles = false);
|
||||||
bool loadMetadata(const QString &magnetUri);
|
bool loadMetadata(const MagnetUri &magnetUri);
|
||||||
bool cancelLoadMetadata(const InfoHash &hash);
|
bool cancelLoadMetadata(const InfoHash &hash);
|
||||||
|
|
||||||
void recursiveTorrentDownload(const InfoHash &hash);
|
void recursiveTorrentDownload(const InfoHash &hash);
|
||||||
|
|
|
@ -392,21 +392,6 @@ bool Utils::Misc::isPreviewable(const QString& extension)
|
||||||
return multimedia_extensions.contains(extension.toUpper());
|
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
|
// Take a number of seconds and return an user-friendly
|
||||||
// time duration like "1d 2h 10m".
|
// time duration like "1d 2h 10m".
|
||||||
QString Utils::Misc::userFriendlyDuration(qlonglong seconds)
|
QString Utils::Misc::userFriendlyDuration(qlonglong seconds)
|
||||||
|
|
|
@ -66,7 +66,6 @@ namespace Utils
|
||||||
QString friendlyUnit(qreal val, bool is_speed = false);
|
QString friendlyUnit(qreal val, bool is_speed = false);
|
||||||
bool isPreviewable(const QString& extension);
|
bool isPreviewable(const QString& extension);
|
||||||
|
|
||||||
QString bcLinkToMagnet(QString bc_link);
|
|
||||||
// Take a number of seconds and return an user-friendly
|
// Take a number of seconds and return an user-friendly
|
||||||
// time duration like "1d 2h 10m".
|
// time duration like "1d 2h 10m".
|
||||||
QString userFriendlyDuration(qlonglong seconds);
|
QString userFriendlyDuration(qlonglong seconds);
|
||||||
|
|
|
@ -133,15 +133,6 @@ void AddNewTorrentDialog::saveState()
|
||||||
|
|
||||||
void AddNewTorrentDialog::show(QString source, QWidget *parent)
|
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);
|
AddNewTorrentDialog *dlg = new AddNewTorrentDialog(parent);
|
||||||
|
|
||||||
if (Utils::Misc::isUrl(source)) {
|
if (Utils::Misc::isUrl(source)) {
|
||||||
|
@ -153,8 +144,9 @@ void AddNewTorrentDialog::show(QString source, QWidget *parent)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (source.startsWith("magnet:", Qt::CaseInsensitive))
|
BitTorrent::MagnetUri magnetUri(source);
|
||||||
ok = dlg->loadMagnet(source);
|
if (magnetUri.isValid())
|
||||||
|
ok = dlg->loadMagnet(magnetUri);
|
||||||
else
|
else
|
||||||
ok = dlg->loadTorrent(source);
|
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))
|
if (torrentPath.startsWith("file://", Qt::CaseInsensitive))
|
||||||
m_filePath = QUrl::fromEncoded(torrent_path.toLocal8Bit()).toLocalFile();
|
m_filePath = QUrl::fromEncoded(torrentPath.toLocal8Bit()).toLocalFile();
|
||||||
else
|
else
|
||||||
m_filePath = torrent_path;
|
m_filePath = torrentPath;
|
||||||
|
|
||||||
if (!QFile::exists(m_filePath)) {
|
if (!QFile::exists(m_filePath)) {
|
||||||
MessageBoxRaised::critical(0, tr("I/O Error"), tr("The torrent file does not exist."));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri)
|
bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
|
||||||
{
|
{
|
||||||
BitTorrent::MagnetUri magnet(magnet_uri);
|
if (!magnetUri.isValid()) {
|
||||||
if (!magnet.isValid()) {
|
|
||||||
MessageBoxRaised::critical(0, tr("Invalid magnet link"), tr("This magnet link was not recognized"));
|
MessageBoxRaised::critical(0, tr("Invalid magnet link"), tr("This magnet link was not recognized"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_hash = magnet.hash();
|
m_hash = magnetUri.hash();
|
||||||
// Prevent showing the dialog if download is already present
|
// Prevent showing the dialog if download is already present
|
||||||
if (BitTorrent::Session::instance()->isKnownTorrent(m_hash)) {
|
if (BitTorrent::Session::instance()->isKnownTorrent(m_hash)) {
|
||||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(m_hash);
|
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(m_hash);
|
||||||
if (torrent) {
|
if (torrent) {
|
||||||
torrent->addTrackers(magnet.trackers());
|
torrent->addTrackers(magnetUri.trackers());
|
||||||
torrent->addUrlSeeds(magnet.urlSeeds());
|
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);
|
MessageBoxRaised::information(0, tr("Already in download list"), tr("Magnet link is already in download list. Trackers were merged."), QMessageBox::Ok);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -238,14 +229,14 @@ bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri)
|
||||||
connect(BitTorrent::Session::instance(), SIGNAL(metadataLoaded(BitTorrent::TorrentInfo)), SLOT(updateMetadata(BitTorrent::TorrentInfo)));
|
connect(BitTorrent::Session::instance(), SIGNAL(metadataLoaded(BitTorrent::TorrentInfo)), SLOT(updateMetadata(BitTorrent::TorrentInfo)));
|
||||||
|
|
||||||
// Set dialog title
|
// Set dialog title
|
||||||
QString torrent_name = magnet.name();
|
QString torrent_name = magnetUri.name();
|
||||||
setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name);
|
setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name);
|
||||||
|
|
||||||
setupTreeview();
|
setupTreeview();
|
||||||
// Set dialog position
|
// Set dialog position
|
||||||
setdialogPosition();
|
setdialogPosition();
|
||||||
|
|
||||||
BitTorrent::Session::instance()->loadMetadata(magnet_uri);
|
BitTorrent::Session::instance()->loadMetadata(magnetUri);
|
||||||
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
|
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
|
||||||
ui->lblhash->setText(m_hash);
|
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)
|
void AddNewTorrentDialog::handleRedirectedToMagnet(const QString &url, const QString &magnetUri)
|
||||||
{
|
{
|
||||||
Q_UNUSED(url)
|
Q_UNUSED(url)
|
||||||
if (loadMagnet(magnetUri))
|
if (loadMagnet(BitTorrent::MagnetUri(magnetUri)))
|
||||||
open();
|
open();
|
||||||
else
|
else
|
||||||
this->deleteLater();
|
this->deleteLater();
|
||||||
|
|
|
@ -38,11 +38,15 @@
|
||||||
#include "base/bittorrent/infohash.h"
|
#include "base/bittorrent/infohash.h"
|
||||||
#include "base/bittorrent/torrentinfo.h"
|
#include "base/bittorrent/torrentinfo.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
namespace BitTorrent
|
||||||
namespace Ui {
|
{
|
||||||
|
class MagnetUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
class AddNewTorrentDialog;
|
class AddNewTorrentDialog;
|
||||||
}
|
}
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
class TorrentContentFilterModel;
|
class TorrentContentFilterModel;
|
||||||
class PropListDelegate;
|
class PropListDelegate;
|
||||||
|
@ -79,8 +83,8 @@ protected slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit AddNewTorrentDialog(QWidget *parent = 0);
|
explicit AddNewTorrentDialog(QWidget *parent = 0);
|
||||||
bool loadTorrent(const QString& torrent_path);
|
bool loadTorrent(const QString &torrentPath);
|
||||||
bool loadMagnet(const QString& magnet_uri);
|
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
|
||||||
void loadSavePathHistory();
|
void loadSavePathHistory();
|
||||||
void saveSavePathHistory() const;
|
void saveSavePathHistory() const;
|
||||||
int indexOfSavePath(const QString& save_path);
|
int indexOfSavePath(const QString& save_path);
|
||||||
|
|
|
@ -354,14 +354,6 @@ void WebApplication::action_command_download()
|
||||||
foreach (QString url, list) {
|
foreach (QString url, list) {
|
||||||
url = url.trimmed();
|
url = url.trimmed();
|
||||||
if (!url.isEmpty()) {
|
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()));
|
Net::DownloadManager::instance()->setCookiesFromUrl(cookies, QUrl::fromEncoded(url.toUtf8()));
|
||||||
BitTorrent::Session::instance()->addTorrent(url, params);
|
BitTorrent::Session::instance()->addTorrent(url, params);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue