Browse Source

Improve loading of magnet metadata in the background.

Conflicts:
	src/qtlibtorrent/qbtsession.cpp
adaptive-webui-19844
sledgehammer999 11 years ago
parent
commit
14310f9b05
  1. 70
      src/addnewtorrentdialog.cpp
  2. 1
      src/addnewtorrentdialog.h
  3. 90
      src/qtlibtorrent/qbtsession.cpp
  4. 2
      src/qtlibtorrent/qbtsession.h
  5. 11
      src/qtlibtorrent/torrentmodel.cpp
  6. 32
      src/torrentpersistentdata.h

70
src/addnewtorrentdialog.cpp

@ -59,7 +59,6 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent) :
m_contentDelegate(0), m_contentDelegate(0),
m_isMagnet(false), m_isMagnet(false),
m_hasMetadata(false), m_hasMetadata(false),
m_convertingMagnet(false),
m_hasRenamedFile(false) m_hasRenamedFile(false)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -263,7 +262,7 @@ bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path, const QString
bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri) bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri)
{ {
connect(QBtSession::instance(), SIGNAL(metadataReceived(const QTorrentHandle&)), SLOT(updateMetadata(const QTorrentHandle&))); connect(QBtSession::instance(), SIGNAL(metadataReceivedHidden(const QTorrentHandle&)), SLOT(updateMetadata(const QTorrentHandle&)));
m_isMagnet = true; m_isMagnet = true;
m_url = magnet_uri; m_url = magnet_uri;
m_hash = misc::magnetUriToHash(m_url); m_hash = misc::magnetUriToHash(m_url);
@ -291,19 +290,10 @@ bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri)
Preferences pref; Preferences pref;
// Override save path // Override save path
TorrentTempData::setSavePath(m_hash, QString(QDir::tempPath() + QDir::separator() + m_hash).replace("\\", "/")); TorrentTempData::setSavePath(m_hash, QString(QDir::tempPath() + QDir::separator() + m_hash).replace("\\", "/"));
HiddenData::addData(m_hash);
// Temporary override of addInPause setting
bool old_addInPause = pref.addTorrentsInPause();
pref.addTorrentsInPause(false);
pref.sync();
QBtSession::instance()->addMagnetUri(m_url, false); QBtSession::instance()->addMagnetUri(m_url, false);
QBtSession::instance()->resumeTorrent(m_hash);
setMetadataProgressIndicator(true, tr("Retrieving metadata...")); setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
// Restore addInPause setting
pref.addTorrentsInPause(old_addInPause);
return true; return true;
} }
@ -606,18 +596,9 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&) {
void AddNewTorrentDialog::accept() void AddNewTorrentDialog::accept()
{ {
if (m_isMagnet) { if (m_isMagnet)
if (m_convertingMagnet) {
QMessageBox::information(0, tr("Processing metadata..."), tr("Please wait while parsing metadata"), QMessageBox::Ok);
return;
}
disconnect(this, SLOT(updateMetadata(const QTorrentHandle&))); disconnect(this, SLOT(updateMetadata(const QTorrentHandle&)));
}
if (!m_hasMetadata) {
// Metadata retrieval was cancelled
// Kill existing handle and make a new one
QBtSession::instance()->deleteTorrent(m_hash, true);
}
Preferences pref; Preferences pref;
// Save Temporary data about torrent // Save Temporary data about torrent
QString save_path = ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString(); QString save_path = ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString();
@ -626,6 +607,7 @@ void AddNewTorrentDialog::accept()
// TODO: Check if destination actually exists // TODO: Check if destination actually exists
TorrentTempData::setSeedingMode(m_hash, true); TorrentTempData::setSeedingMode(m_hash, true);
} }
pref.addTorrentsInPause(!ui->start_torrent_cb->isChecked());
// Label // Label
const QString label = ui->label_combo->currentText(); const QString label = ui->label_combo->currentText();
@ -640,20 +622,12 @@ void AddNewTorrentDialog::accept()
if (m_hasRenamedFile) if (m_hasRenamedFile)
TorrentTempData::setFilesPath(m_hash, m_filesPath); TorrentTempData::setFilesPath(m_hash, m_filesPath);
// Temporary override of addInPause setting
bool old_addInPause = pref.addTorrentsInPause();
pref.addTorrentsInPause(!ui->start_torrent_cb->isChecked());
pref.sync();
// Add torrent // Add torrent
if (!m_hasMetadata) if (m_isMagnet)
QBtSession::instance()->addMagnetUri(m_url, false); QBtSession::instance()->unhideMagnet(m_hash);
else else
QBtSession::instance()->addTorrent(m_filePath, false, m_url); QBtSession::instance()->addTorrent(m_filePath, false, m_url);
// Restore addInPause setting
pref.addTorrentsInPause(old_addInPause);
saveSavePathHistory(); saveSavePathHistory();
// Save settings // Save settings
pref.useAdditionDialog(!ui->never_show_cb->isChecked()); pref.useAdditionDialog(!ui->never_show_cb->isChecked());
@ -667,10 +641,6 @@ void AddNewTorrentDialog::accept()
void AddNewTorrentDialog::reject() { void AddNewTorrentDialog::reject() {
if (m_isMagnet) { if (m_isMagnet) {
disconnect(this, SLOT(updateMetadata(const QTorrentHandle&))); disconnect(this, SLOT(updateMetadata(const QTorrentHandle&)));
while (m_convertingMagnet) {
// HACK ???
// Force cancel
}
setMetadataProgressIndicator(false); setMetadataProgressIndicator(false);
QBtSession::instance()->deleteTorrent(m_hash, true); QBtSession::instance()->deleteTorrent(m_hash, true);
} }
@ -682,30 +652,11 @@ void AddNewTorrentDialog::updateMetadata(const QTorrentHandle &h) {
if (h.hash() != m_hash) if (h.hash() != m_hash)
return; return;
m_convertingMagnet = true; disconnect(this, SLOT(updateMetadata(const QTorrentHandle&)));
Q_ASSERT(h.has_metadata()); Q_ASSERT(h.has_metadata());
h.pause();
// Try to convert magnet to torrent with full metadata
m_filePath = QDir::tempPath() + h.hash() + ".torrent";
h.save_torrent_file(m_filePath);
if (!QFile::exists(m_filePath)) {
QMessageBox::warning(0, tr("I/O Error"), tr("Failed to save metadata.\nFile list will be unavailable."));
m_convertingMagnet = false;
setMetadataProgressIndicator(false, tr("Failed to save metadata"));
return;
}
try { m_torrentInfo = new torrent_info(h.get_torrent_info());
m_torrentInfo = new torrent_info(m_filePath.toUtf8().data());
Q_ASSERT(m_hash == misc::toQString(m_torrentInfo->info_hash()));
} catch(const std::exception&) {
QMessageBox::critical(0, tr("Invalid metadata"), tr("Metadata corrupted.\nFile list will be unavailable."));
m_convertingMagnet = false;
setMetadataProgressIndicator(false, tr("Invalid metadata"));
return;
}
QBtSession::instance()->deleteTorrent(m_hash, true);
// Good to go // Good to go
m_hasMetadata = true; m_hasMetadata = true;
setMetadataProgressIndicator(true, tr("Parsing metadata...")); setMetadataProgressIndicator(true, tr("Parsing metadata..."));
@ -766,7 +717,6 @@ void AddNewTorrentDialog::updateMetadata(const QTorrentHandle &h) {
showAdvancedSettings(settings.value("AddNewTorrentDialog/expanded").toBool()); showAdvancedSettings(settings.value("AddNewTorrentDialog/expanded").toBool());
// Set dialog position // Set dialog position
setdialogPosition(); setdialogPosition();
m_convertingMagnet = false;
setMetadataProgressIndicator(false, tr("Metadata retrieval complete")); setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
} catch (invalid_handle&) { } catch (invalid_handle&) {
QMessageBox::critical(0, tr("I/O Error"), ("Unknown error.")); QMessageBox::critical(0, tr("I/O Error"), ("Unknown error."));

1
src/addnewtorrentdialog.h

@ -91,7 +91,6 @@ private:
PropListDelegate *m_contentDelegate; PropListDelegate *m_contentDelegate;
bool m_isMagnet; bool m_isMagnet;
bool m_hasMetadata; bool m_hasMetadata;
bool m_convertingMagnet;
QString m_filePath; QString m_filePath;
QString m_url; QString m_url;
QString m_hash; QString m_hash;

90
src/qtlibtorrent/qbtsession.cpp

@ -83,6 +83,8 @@
//initialize static member variables //initialize static member variables
QHash<QString, TorrentTempData::TorrentData> TorrentTempData::data = QHash<QString, TorrentTempData::TorrentData>(); QHash<QString, TorrentTempData::TorrentData> TorrentTempData::data = QHash<QString, TorrentTempData::TorrentData>();
QStringList HiddenData::hashes = QStringList();
unsigned int HiddenData::metadata_counter = 0;
using namespace libtorrent; using namespace libtorrent;
@ -426,9 +428,9 @@ void QBtSession::configureSession() {
#endif #endif
// Queueing System // Queueing System
if (pref.isQueueingSystemEnabled()) { if (pref.isQueueingSystemEnabled()) {
sessionSettings.active_downloads = pref.getMaxActiveDownloads(); sessionSettings.active_downloads = pref.getMaxActiveDownloads() + HiddenData::getDownloadingSize();
sessionSettings.active_seeds = pref.getMaxActiveUploads(); sessionSettings.active_seeds = pref.getMaxActiveUploads();
sessionSettings.active_limit = pref.getMaxActiveTorrents(); sessionSettings.active_limit = pref.getMaxActiveTorrents() + HiddenData::getDownloadingSize();
sessionSettings.dont_count_slow_torrents = pref.ignoreSlowTorrentsForQueueing(); sessionSettings.dont_count_slow_torrents = pref.ignoreSlowTorrentsForQueueing();
setQueueingEnabled(true); setQueueingEnabled(true);
} else { } else {
@ -808,6 +810,8 @@ void QBtSession::deleteTorrent(const QString &hash, bool delete_local_files) {
fsutils::forceRemove(torrentBackup.absoluteFilePath(file)); fsutils::forceRemove(torrentBackup.absoluteFilePath(file));
} }
TorrentPersistentData::deletePersistentData(hash); TorrentPersistentData::deletePersistentData(hash);
TorrentTempData::deleteTempData(hash);
HiddenData::deleteData(hash);
// Remove tracker errors // Remove tracker errors
trackersInfos.remove(hash); trackersInfos.remove(hash);
if (delete_local_files) if (delete_local_files)
@ -984,13 +988,23 @@ QTorrentHandle QBtSession::addMagnetUri(QString magnet_uri, bool resumed, bool f
if (!resumed) { if (!resumed) {
loadTorrentTempData(h, savePath, true); loadTorrentTempData(h, savePath, true);
} }
if (!pref.addTorrentsInPause()) { if (HiddenData::hasData(hash) && pref.isQueueingSystemEnabled()) {
//Internally increase the queue limits to ensure that the magnet is started
libtorrent::session_settings sessionSettings(s->settings());
sessionSettings.active_downloads = pref.getMaxActiveDownloads() + HiddenData::getDownloadingSize();
sessionSettings.active_limit = pref.getMaxActiveTorrents() + HiddenData::getDownloadingSize();
s->set_settings(sessionSettings);
h.queue_position_top();
}
if (!pref.addTorrentsInPause() || HiddenData::hasData(hash)) {
// Start torrent because it was added in paused state // Start torrent because it was added in paused state
h.resume(); h.resume();
} }
// Send torrent addition signal // Send torrent addition signal
addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(magnet_uri)); addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(magnet_uri));
emit addedTorrent(h); if (!HiddenData::hasData(hash))
emit addedTorrent(h);
return h; return h;
} }
@ -2385,7 +2399,20 @@ void QBtSession::readAlerts() {
} }
else if (metadata_received_alert* p = dynamic_cast<metadata_received_alert*>(a.get())) { else if (metadata_received_alert* p = dynamic_cast<metadata_received_alert*>(a.get())) {
QTorrentHandle h(p->handle); QTorrentHandle h(p->handle);
Preferences pref;
if (h.is_valid()) { if (h.is_valid()) {
QString hash(h.hash());
if (HiddenData::hasData(hash)) {
HiddenData::gotMetadata();
if (pref.isQueueingSystemEnabled()) {
//Internally decrease the queue limits to ensure that that other queued items aren't started
libtorrent::session_settings sessionSettings(s->settings());
sessionSettings.active_downloads = pref.getMaxActiveDownloads() + HiddenData::getDownloadingSize();
sessionSettings.active_limit = pref.getMaxActiveTorrents() + HiddenData::getDownloadingSize();
s->set_settings(sessionSettings);
}
h.pause();
}
qDebug("Received metadata for %s", qPrintable(h.hash())); qDebug("Received metadata for %s", qPrintable(h.hash()));
// Save metadata // Save metadata
const QDir torrentBackup(fsutils::BTBackupLocation()); const QDir torrentBackup(fsutils::BTBackupLocation());
@ -2398,8 +2425,12 @@ void QBtSession::readAlerts() {
if (appendqBExtension) if (appendqBExtension)
appendqBextensionToTorrent(h, true); appendqBextensionToTorrent(h, true);
emit metadataReceived(h); if (!HiddenData::hasData(hash))
if (h.is_paused()) { emit metadataReceived(h);
else
emit metadataReceivedHidden(h);
if (h.is_paused() && !HiddenData::hasData(hash)) {
// XXX: Unfortunately libtorrent-rasterbar does not send a torrent_paused_alert // XXX: Unfortunately libtorrent-rasterbar does not send a torrent_paused_alert
// and the torrent can be paused when metadata is received // and the torrent can be paused when metadata is received
emit pausedTorrent(h); emit pausedTorrent(h);
@ -2438,9 +2469,11 @@ void QBtSession::readAlerts() {
else if (torrent_paused_alert* p = dynamic_cast<torrent_paused_alert*>(a.get())) { else if (torrent_paused_alert* p = dynamic_cast<torrent_paused_alert*>(a.get())) {
if (p->handle.is_valid()) { if (p->handle.is_valid()) {
QTorrentHandle h(p->handle); QTorrentHandle h(p->handle);
if (!h.has_error()) if (!HiddenData::hasData(h.hash())) {
h.save_resume_data(); if (!h.has_error())
emit pausedTorrent(h); h.save_resume_data();
emit pausedTorrent(h);
}
} }
} }
else if (tracker_error_alert* p = dynamic_cast<tracker_error_alert*>(a.get())) { else if (tracker_error_alert* p = dynamic_cast<tracker_error_alert*>(a.get())) {
@ -2922,3 +2955,42 @@ void QBtSession::backupPersistentData(const QString &hash, boost::shared_ptr<lib
(*data)["qBt-queuePosition"] = TorrentPersistentData::getPriority(hash); (*data)["qBt-queuePosition"] = TorrentPersistentData::getPriority(hash);
(*data)["qBt-seedStatus"] = (int)TorrentPersistentData::isSeed(hash); (*data)["qBt-seedStatus"] = (int)TorrentPersistentData::isSeed(hash);
} }
void QBtSession::unhideMagnet(const QString &hash) {
Preferences pref;
QTorrentHandle h(getTorrentHandle(hash));
if (!h.is_valid()) {
if (pref.isQueueingSystemEnabled()) {
//Internally decrease the queue limits to ensure that other queued items aren't started
libtorrent::session_settings sessionSettings(s->settings());
sessionSettings.active_downloads = pref.getMaxActiveDownloads() + HiddenData::getDownloadingSize();
sessionSettings.active_limit = pref.getMaxActiveTorrents() + HiddenData::getDownloadingSize();
s->set_settings(sessionSettings);
}
HiddenData::deleteData(hash);
TorrentTempData::deleteTempData(hash);
return;
}
if (!h.has_metadata()) {
if (pref.isQueueingSystemEnabled()) {
//Internally decrease the queue limits to ensure that other queued items aren't started
libtorrent::session_settings sessionSettings(s->settings());
sessionSettings.active_downloads = pref.getMaxActiveDownloads() + HiddenData::getDownloadingSize();
sessionSettings.active_limit = pref.getMaxActiveTorrents() + HiddenData::getDownloadingSize();
s->set_settings(sessionSettings);
}
if (pref.addTorrentsInPause())
h.pause();
}
h.queue_position_bottom();
loadTorrentTempData(h, h.save_path(), !h.has_metadata());
if (!pref.addTorrentsInPause())
h.resume();
HiddenData::deleteData(hash);
h.move_storage(TorrentTempData::getSavePath(hash));
TorrentTempData::deleteTempData(hash);
emit addedTorrent(h);
}

2
src/qtlibtorrent/qbtsession.h

@ -175,6 +175,7 @@ public slots:
void configureSession(); void configureSession();
void banIP(QString ip); void banIP(QString ip);
void recursiveTorrentDownload(const QTorrentHandle &h); void recursiveTorrentDownload(const QTorrentHandle &h);
void unhideMagnet(const QString &hash);
private: private:
QString getSavePath(const QString &hash, bool fromScanDir = false, QString filePath = QString::null); QString getSavePath(const QString &hash, bool fromScanDir = false, QString filePath = QString::null);
@ -226,6 +227,7 @@ signals:
void alternativeSpeedsModeChanged(bool alternative); void alternativeSpeedsModeChanged(bool alternative);
void recursiveTorrentDownloadPossible(const QTorrentHandle &h); void recursiveTorrentDownloadPossible(const QTorrentHandle &h);
void ipFilterParsed(bool error, int ruleCount); void ipFilterParsed(bool error, int ruleCount);
void metadataReceivedHidden(const QTorrentHandle &h);
private: private:
// Bittorrent // Bittorrent

11
src/qtlibtorrent/torrentmodel.cpp

@ -151,9 +151,14 @@ QVariant TorrentModelItem::data(int column, int role) const
if (role != Qt::DisplayRole && role != Qt::UserRole) return QVariant(); if (role != Qt::DisplayRole && role != Qt::UserRole) return QVariant();
switch(column) { switch(column) {
case TR_NAME: case TR_NAME:
return m_name.isEmpty()? m_torrent.name() : m_name; return m_name.isEmpty() ? m_torrent.name() : m_name;
case TR_PRIORITY: case TR_PRIORITY: {
return m_torrent.queue_position(); int pos = m_torrent.queue_position();
if (pos > -1)
return pos - HiddenData::getSize();
else
return pos;
}
case TR_SIZE: case TR_SIZE:
return m_torrent.has_metadata() ? static_cast<qlonglong>(m_torrent.actual_size()) : -1; return m_torrent.has_metadata() ? static_cast<qlonglong>(m_torrent.actual_size()) : -1;
case TR_PROGRESS: case TR_PROGRESS:

32
src/torrentpersistentdata.h

@ -114,6 +114,38 @@ private:
static QHash<QString, TorrentData> data; static QHash<QString, TorrentData> data;
}; };
class HiddenData {
public:
static void addData(const QString &hash) {
hashes.append(hash);
}
static bool hasData(const QString &hash) {
return hashes.contains(hash, Qt::CaseInsensitive);
}
static void deleteData(const QString &hash) {
if (hashes.removeAll(hash))
metadata_counter--;
}
static int getSize() {
return hashes.size();
}
static int getDownloadingSize() {
return hashes.size() - metadata_counter;
}
static void gotMetadata() {
metadata_counter++;
}
private:
static QStringList hashes;
static unsigned int metadata_counter;
};
class TorrentPersistentData { class TorrentPersistentData {
public: public:
enum RatioLimit { enum RatioLimit {

Loading…
Cancel
Save