From 14310f9b0503d3dffa48bdb1bf9bdd5c754fa9d4 Mon Sep 17 00:00:00 2001 From: sledgehammer999 Date: Wed, 18 Sep 2013 00:44:18 +0300 Subject: [PATCH] Improve loading of magnet metadata in the background. Conflicts: src/qtlibtorrent/qbtsession.cpp --- src/addnewtorrentdialog.cpp | 70 ++++------------------- src/addnewtorrentdialog.h | 1 - src/qtlibtorrent/qbtsession.cpp | 92 +++++++++++++++++++++++++++---- src/qtlibtorrent/qbtsession.h | 2 + src/qtlibtorrent/torrentmodel.cpp | 11 +++- src/torrentpersistentdata.h | 32 +++++++++++ 6 files changed, 134 insertions(+), 74 deletions(-) diff --git a/src/addnewtorrentdialog.cpp b/src/addnewtorrentdialog.cpp index 8df66315d..2340f23fd 100644 --- a/src/addnewtorrentdialog.cpp +++ b/src/addnewtorrentdialog.cpp @@ -59,7 +59,6 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent) : m_contentDelegate(0), m_isMagnet(false), m_hasMetadata(false), - m_convertingMagnet(false), m_hasRenamedFile(false) { ui->setupUi(this); @@ -263,7 +262,7 @@ bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path, const QString 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_url = magnet_uri; m_hash = misc::magnetUriToHash(m_url); @@ -291,19 +290,10 @@ bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri) Preferences pref; // Override save path TorrentTempData::setSavePath(m_hash, QString(QDir::tempPath() + QDir::separator() + m_hash).replace("\\", "/")); - - // Temporary override of addInPause setting - bool old_addInPause = pref.addTorrentsInPause(); - pref.addTorrentsInPause(false); - pref.sync(); - + HiddenData::addData(m_hash); QBtSession::instance()->addMagnetUri(m_url, false); - QBtSession::instance()->resumeTorrent(m_hash); setMetadataProgressIndicator(true, tr("Retrieving metadata...")); - // Restore addInPause setting - pref.addTorrentsInPause(old_addInPause); - return true; } @@ -606,18 +596,9 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&) { void AddNewTorrentDialog::accept() { - if (m_isMagnet) { - if (m_convertingMagnet) { - QMessageBox::information(0, tr("Processing metadata..."), tr("Please wait while parsing metadata"), QMessageBox::Ok); - return; - } + if (m_isMagnet) 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; // Save Temporary data about torrent 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 TorrentTempData::setSeedingMode(m_hash, true); } + pref.addTorrentsInPause(!ui->start_torrent_cb->isChecked()); // Label const QString label = ui->label_combo->currentText(); @@ -640,20 +622,12 @@ void AddNewTorrentDialog::accept() if (m_hasRenamedFile) 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 - if (!m_hasMetadata) - QBtSession::instance()->addMagnetUri(m_url, false); + if (m_isMagnet) + QBtSession::instance()->unhideMagnet(m_hash); else QBtSession::instance()->addTorrent(m_filePath, false, m_url); - // Restore addInPause setting - pref.addTorrentsInPause(old_addInPause); - saveSavePathHistory(); // Save settings pref.useAdditionDialog(!ui->never_show_cb->isChecked()); @@ -667,10 +641,6 @@ void AddNewTorrentDialog::accept() void AddNewTorrentDialog::reject() { if (m_isMagnet) { disconnect(this, SLOT(updateMetadata(const QTorrentHandle&))); - while (m_convertingMagnet) { - // HACK ??? - // Force cancel - } setMetadataProgressIndicator(false); QBtSession::instance()->deleteTorrent(m_hash, true); } @@ -682,30 +652,11 @@ void AddNewTorrentDialog::updateMetadata(const QTorrentHandle &h) { if (h.hash() != m_hash) return; - m_convertingMagnet = true; + disconnect(this, SLOT(updateMetadata(const QTorrentHandle&))); 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(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); + m_torrentInfo = new torrent_info(h.get_torrent_info()); + // Good to go m_hasMetadata = true; setMetadataProgressIndicator(true, tr("Parsing metadata...")); @@ -766,7 +717,6 @@ void AddNewTorrentDialog::updateMetadata(const QTorrentHandle &h) { showAdvancedSettings(settings.value("AddNewTorrentDialog/expanded").toBool()); // Set dialog position setdialogPosition(); - m_convertingMagnet = false; setMetadataProgressIndicator(false, tr("Metadata retrieval complete")); } catch (invalid_handle&) { QMessageBox::critical(0, tr("I/O Error"), ("Unknown error.")); diff --git a/src/addnewtorrentdialog.h b/src/addnewtorrentdialog.h index dec472805..1b36ec5a6 100644 --- a/src/addnewtorrentdialog.h +++ b/src/addnewtorrentdialog.h @@ -91,7 +91,6 @@ private: PropListDelegate *m_contentDelegate; bool m_isMagnet; bool m_hasMetadata; - bool m_convertingMagnet; QString m_filePath; QString m_url; QString m_hash; diff --git a/src/qtlibtorrent/qbtsession.cpp b/src/qtlibtorrent/qbtsession.cpp index 5a45c7a63..d9cbef42a 100755 --- a/src/qtlibtorrent/qbtsession.cpp +++ b/src/qtlibtorrent/qbtsession.cpp @@ -83,6 +83,8 @@ //initialize static member variables QHash TorrentTempData::data = QHash(); +QStringList HiddenData::hashes = QStringList(); +unsigned int HiddenData::metadata_counter = 0; using namespace libtorrent; @@ -426,9 +428,9 @@ void QBtSession::configureSession() { #endif // Queueing System if (pref.isQueueingSystemEnabled()) { - sessionSettings.active_downloads = pref.getMaxActiveDownloads(); + sessionSettings.active_downloads = pref.getMaxActiveDownloads() + HiddenData::getDownloadingSize(); sessionSettings.active_seeds = pref.getMaxActiveUploads(); - sessionSettings.active_limit = pref.getMaxActiveTorrents(); + sessionSettings.active_limit = pref.getMaxActiveTorrents() + HiddenData::getDownloadingSize(); sessionSettings.dont_count_slow_torrents = pref.ignoreSlowTorrentsForQueueing(); setQueueingEnabled(true); } else { @@ -808,6 +810,8 @@ void QBtSession::deleteTorrent(const QString &hash, bool delete_local_files) { fsutils::forceRemove(torrentBackup.absoluteFilePath(file)); } TorrentPersistentData::deletePersistentData(hash); + TorrentTempData::deleteTempData(hash); + HiddenData::deleteData(hash); // Remove tracker errors trackersInfos.remove(hash); if (delete_local_files) @@ -983,14 +987,24 @@ QTorrentHandle QBtSession::addMagnetUri(QString magnet_uri, bool resumed, bool f // Load filtered files if (!resumed) { 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 h.resume(); } // Send torrent addition signal 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; } @@ -2385,7 +2399,20 @@ void QBtSession::readAlerts() { } else if (metadata_received_alert* p = dynamic_cast(a.get())) { QTorrentHandle h(p->handle); + Preferences pref; 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())); // Save metadata const QDir torrentBackup(fsutils::BTBackupLocation()); @@ -2398,8 +2425,12 @@ void QBtSession::readAlerts() { if (appendqBExtension) appendqBextensionToTorrent(h, true); - emit metadataReceived(h); - if (h.is_paused()) { + if (!HiddenData::hasData(hash)) + 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 // and the torrent can be paused when metadata is received emit pausedTorrent(h); @@ -2438,9 +2469,11 @@ void QBtSession::readAlerts() { else if (torrent_paused_alert* p = dynamic_cast(a.get())) { if (p->handle.is_valid()) { QTorrentHandle h(p->handle); - if (!h.has_error()) - h.save_resume_data(); - emit pausedTorrent(h); + if (!HiddenData::hasData(h.hash())) { + if (!h.has_error()) + h.save_resume_data(); + emit pausedTorrent(h); + } } } else if (tracker_error_alert* p = dynamic_cast(a.get())) { @@ -2922,3 +2955,42 @@ void QBtSession::backupPersistentData(const QString &hash, boost::shared_ptrsettings()); + 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); +} diff --git a/src/qtlibtorrent/qbtsession.h b/src/qtlibtorrent/qbtsession.h index f7f52142e..019c0c0a1 100755 --- a/src/qtlibtorrent/qbtsession.h +++ b/src/qtlibtorrent/qbtsession.h @@ -175,6 +175,7 @@ public slots: void configureSession(); void banIP(QString ip); void recursiveTorrentDownload(const QTorrentHandle &h); + void unhideMagnet(const QString &hash); private: QString getSavePath(const QString &hash, bool fromScanDir = false, QString filePath = QString::null); @@ -226,6 +227,7 @@ signals: void alternativeSpeedsModeChanged(bool alternative); void recursiveTorrentDownloadPossible(const QTorrentHandle &h); void ipFilterParsed(bool error, int ruleCount); + void metadataReceivedHidden(const QTorrentHandle &h); private: // Bittorrent diff --git a/src/qtlibtorrent/torrentmodel.cpp b/src/qtlibtorrent/torrentmodel.cpp index 6ce65f697..20b5a131b 100644 --- a/src/qtlibtorrent/torrentmodel.cpp +++ b/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(); switch(column) { case TR_NAME: - return m_name.isEmpty()? m_torrent.name() : m_name; - case TR_PRIORITY: - return m_torrent.queue_position(); + return m_name.isEmpty() ? m_torrent.name() : m_name; + case TR_PRIORITY: { + int pos = m_torrent.queue_position(); + if (pos > -1) + return pos - HiddenData::getSize(); + else + return pos; + } case TR_SIZE: return m_torrent.has_metadata() ? static_cast(m_torrent.actual_size()) : -1; case TR_PROGRESS: diff --git a/src/torrentpersistentdata.h b/src/torrentpersistentdata.h index b93d3b9f7..b36a81460 100644 --- a/src/torrentpersistentdata.h +++ b/src/torrentpersistentdata.h @@ -114,6 +114,38 @@ private: static QHash 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 { public: enum RatioLimit {