mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-23 13:04:23 +00:00
Fix torrent checking issues
Start all torrents auto-managed to prevent simultaneous checking of multiple torrents. Handle checking state of paused torrent to prevent it from being resumed when qBittorrent is closed until checking isn't complete.
This commit is contained in:
parent
91742d4a53
commit
9399b876eb
@ -1861,29 +1861,22 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
|||||||
hash = magnetUri.hash();
|
hash = magnetUri.hash();
|
||||||
|
|
||||||
if (m_loadedMetadata.contains(hash)) {
|
if (m_loadedMetadata.contains(hash)) {
|
||||||
// Adding preloaded torrent
|
// Adding preloaded torrent...
|
||||||
m_loadedMetadata.remove(hash);
|
m_addingTorrents.insert(hash, params);
|
||||||
lt::torrent_handle handle = m_nativeSession->find_torrent(hash);
|
|
||||||
--m_extraLimit;
|
|
||||||
|
|
||||||
|
lt::torrent_handle handle = m_nativeSession->find_torrent(hash);
|
||||||
|
// We need to pause it first to create TorrentHandle within the same
|
||||||
|
// underlying state as in other cases.
|
||||||
try {
|
try {
|
||||||
// Preloaded torrent is in "Upload mode" so we need to disable it
|
|
||||||
// otherwise the torrent never be downloaded (until application restart)
|
|
||||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||||
handle.auto_managed(false);
|
handle.auto_managed(false);
|
||||||
handle.set_upload_mode(false);
|
|
||||||
#else
|
#else
|
||||||
handle.unset_flags(lt::torrent_flags::auto_managed | lt::torrent_flags::upload_mode);
|
handle.unset_flags(lt::torrent_flags::auto_managed);
|
||||||
#endif
|
#endif
|
||||||
handle.pause();
|
handle.pause();
|
||||||
}
|
}
|
||||||
catch (const std::exception &) {}
|
catch (const std::exception &) {}
|
||||||
|
|
||||||
adjustLimits();
|
|
||||||
|
|
||||||
// use common 2nd step of torrent addition
|
|
||||||
m_addingTorrents.insert(hash, params);
|
|
||||||
createTorrentHandle(handle);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1923,8 +1916,15 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
|||||||
if (!fromMagnetUri) {
|
if (!fromMagnetUri) {
|
||||||
if (params.restored) { // load from existing fastresume
|
if (params.restored) { // load from existing fastresume
|
||||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||||
p.resume_data = std::vector<char> {fastresumeData.constData()
|
// Make sure the torrent will be initially checked and then paused
|
||||||
, (fastresumeData.constData() + fastresumeData.size())};
|
// to perform some service jobs on it. We will start it if needed.
|
||||||
|
// (Workaround to easily support libtorrent-1.1
|
||||||
|
QByteArray patchedFastresumeData = fastresumeData;
|
||||||
|
patchedFastresumeData.replace("6:pausedi0e", "6:pausedi1e");
|
||||||
|
patchedFastresumeData.replace("12:auto_managedi0e", "12:auto_managedi1e");
|
||||||
|
|
||||||
|
p.resume_data = std::vector<char> {patchedFastresumeData.constData()
|
||||||
|
, (patchedFastresumeData.constData() + patchedFastresumeData.size())};
|
||||||
p.flags |= lt::add_torrent_params::flag_use_resume_save_path;
|
p.flags |= lt::add_torrent_params::flag_use_resume_save_path;
|
||||||
|
|
||||||
// Still setup the default parameters and let libtorrent handle
|
// Still setup the default parameters and let libtorrent handle
|
||||||
@ -1975,18 +1975,25 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
|||||||
p.ti = torrentInfo.nativeInfo();
|
p.ti = torrentInfo.nativeInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasCompleteFastresume) {
|
// Common
|
||||||
// Common
|
|
||||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||||
p.flags |= lt::add_torrent_params::flag_paused; // Start in pause
|
p.flags &= ~lt::add_torrent_params::flag_duplicate_is_error; // Already checked
|
||||||
p.flags &= ~lt::add_torrent_params::flag_auto_managed; // Because it is added in paused state
|
|
||||||
p.flags &= ~lt::add_torrent_params::flag_duplicate_is_error; // Already checked
|
|
||||||
#else
|
#else
|
||||||
p.flags |= lt::torrent_flags::paused; // Start in pause
|
p.flags &= ~lt::torrent_flags::duplicate_is_error; // Already checked
|
||||||
p.flags &= ~lt::torrent_flags::auto_managed; // Because it is added in paused state
|
#endif
|
||||||
p.flags &= ~lt::torrent_flags::duplicate_is_error; // Already checked
|
// Make sure the torrent will be initially checked and then paused
|
||||||
|
// to perform some service jobs on it. We will start it if needed.
|
||||||
|
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||||
|
p.flags |= lt::add_torrent_params::flag_paused;
|
||||||
|
p.flags |= lt::add_torrent_params::flag_auto_managed;
|
||||||
|
p.flags |= lt::add_torrent_params::flag_stop_when_ready;
|
||||||
|
#else
|
||||||
|
p.flags |= lt::torrent_flags::paused;
|
||||||
|
p.flags |= lt::torrent_flags::auto_managed;
|
||||||
|
p.flags |= lt::torrent_flags::stop_when_ready;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!hasCompleteFastresume) {
|
||||||
// Limits
|
// Limits
|
||||||
p.max_connections = maxConnectionsPerTorrent();
|
p.max_connections = maxConnectionsPerTorrent();
|
||||||
p.max_uploads = maxUploadsPerTorrent();
|
p.max_uploads = maxUploadsPerTorrent();
|
||||||
@ -2012,16 +2019,6 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
|||||||
p.flags &= ~lt::add_torrent_params::flag_seed_mode;
|
p.flags &= ~lt::add_torrent_params::flag_seed_mode;
|
||||||
#else
|
#else
|
||||||
p.flags &= ~lt::torrent_flags::seed_mode;
|
p.flags &= ~lt::torrent_flags::seed_mode;
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.restored && !params.paused) {
|
|
||||||
// Make sure the torrent will restored in "paused" state
|
|
||||||
// Then we will start it if needed
|
|
||||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
|
||||||
p.flags |= lt::add_torrent_params::flag_stop_when_ready;
|
|
||||||
#else
|
|
||||||
p.flags |= lt::torrent_flags::stop_when_ready;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2105,6 +2102,7 @@ bool Session::loadMetadata(const MagnetUri &magnetUri)
|
|||||||
p.flags &= ~lt::torrent_flags::paused;
|
p.flags &= ~lt::torrent_flags::paused;
|
||||||
p.flags &= ~lt::torrent_flags::auto_managed;
|
p.flags &= ~lt::torrent_flags::auto_managed;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Solution to avoid accidental file writes
|
// Solution to avoid accidental file writes
|
||||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||||
p.flags |= lt::add_torrent_params::flag_upload_mode;
|
p.flags |= lt::add_torrent_params::flag_upload_mode;
|
||||||
@ -3872,10 +3870,7 @@ void Session::handleAlert(const lt::alert *a)
|
|||||||
case lt::tracker_warning_alert::alert_type:
|
case lt::tracker_warning_alert::alert_type:
|
||||||
case lt::fastresume_rejected_alert::alert_type:
|
case lt::fastresume_rejected_alert::alert_type:
|
||||||
case lt::torrent_checked_alert::alert_type:
|
case lt::torrent_checked_alert::alert_type:
|
||||||
dispatchTorrentAlert(a);
|
|
||||||
break;
|
|
||||||
case lt::metadata_received_alert::alert_type:
|
case lt::metadata_received_alert::alert_type:
|
||||||
handleMetadataReceivedAlert(static_cast<const lt::metadata_received_alert*>(a));
|
|
||||||
dispatchTorrentAlert(a);
|
dispatchTorrentAlert(a);
|
||||||
break;
|
break;
|
||||||
case lt::state_update_alert::alert_type:
|
case lt::state_update_alert::alert_type:
|
||||||
@ -3933,8 +3928,19 @@ void Session::handleAlert(const lt::alert *a)
|
|||||||
void Session::dispatchTorrentAlert(const lt::alert *a)
|
void Session::dispatchTorrentAlert(const lt::alert *a)
|
||||||
{
|
{
|
||||||
TorrentHandle *const torrent = m_torrents.value(static_cast<const lt::torrent_alert*>(a)->handle.info_hash());
|
TorrentHandle *const torrent = m_torrents.value(static_cast<const lt::torrent_alert*>(a)->handle.info_hash());
|
||||||
if (torrent)
|
if (torrent) {
|
||||||
torrent->handleAlert(a);
|
torrent->handleAlert(a);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (a->type()) {
|
||||||
|
case lt::torrent_paused_alert::alert_type:
|
||||||
|
handleTorrentPausedAlert(static_cast<const lt::torrent_paused_alert*>(a));
|
||||||
|
break;
|
||||||
|
case lt::metadata_received_alert::alert_type:
|
||||||
|
handleMetadataReceivedAlert(static_cast<const lt::metadata_received_alert*>(a));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::createTorrentHandle(const lt::torrent_handle &nativeHandle)
|
void Session::createTorrentHandle(const lt::torrent_handle &nativeHandle)
|
||||||
@ -4064,6 +4070,32 @@ void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p)
|
||||||
|
{
|
||||||
|
const InfoHash hash {p->handle.info_hash()};
|
||||||
|
|
||||||
|
if (m_loadedMetadata.contains(hash)) {
|
||||||
|
// Adding preloaded torrent
|
||||||
|
m_loadedMetadata.remove(hash);
|
||||||
|
lt::torrent_handle handle = p->handle;
|
||||||
|
--m_extraLimit;
|
||||||
|
|
||||||
|
// Preloaded torrent is in "Upload mode" so we need to disable it
|
||||||
|
// otherwise the torrent never be downloaded (until application restart)
|
||||||
|
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||||
|
handle.set_upload_mode(false);
|
||||||
|
handle.auto_managed(true);
|
||||||
|
#else
|
||||||
|
handle.unset_flags(lt::torrent_flags::upload_mode);
|
||||||
|
handle.set_flags(lt::torrent_flags::auto_managed);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
adjustLimits();
|
||||||
|
// use common 2nd step of torrent addition
|
||||||
|
createTorrentHandle(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Session::handleFileErrorAlert(const lt::file_error_alert *p)
|
void Session::handleFileErrorAlert(const lt::file_error_alert *p)
|
||||||
{
|
{
|
||||||
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());
|
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());
|
||||||
|
@ -551,6 +551,7 @@ namespace BitTorrent
|
|||||||
void handleAddTorrentAlert(const lt::add_torrent_alert *p);
|
void handleAddTorrentAlert(const lt::add_torrent_alert *p);
|
||||||
void handleStateUpdateAlert(const lt::state_update_alert *p);
|
void handleStateUpdateAlert(const lt::state_update_alert *p);
|
||||||
void handleMetadataReceivedAlert(const lt::metadata_received_alert *p);
|
void handleMetadataReceivedAlert(const lt::metadata_received_alert *p);
|
||||||
|
void handleTorrentPausedAlert(const lt::torrent_paused_alert *p);
|
||||||
void handleFileErrorAlert(const lt::file_error_alert *p);
|
void handleFileErrorAlert(const lt::file_error_alert *p);
|
||||||
void handleTorrentRemovedAlert(const lt::torrent_removed_alert *p);
|
void handleTorrentRemovedAlert(const lt::torrent_removed_alert *p);
|
||||||
void handleTorrentDeletedAlert(const lt::torrent_deleted_alert *p);
|
void handleTorrentDeletedAlert(const lt::torrent_deleted_alert *p);
|
||||||
|
@ -191,6 +191,7 @@ TorrentHandle::TorrentHandle(Session *session, const lt::torrent_handle &nativeH
|
|||||||
, m_hasRootFolder(params.hasRootFolder)
|
, m_hasRootFolder(params.hasRootFolder)
|
||||||
, m_needsToSetFirstLastPiecePriority(false)
|
, m_needsToSetFirstLastPiecePriority(false)
|
||||||
, m_needsToStartForced(params.forced)
|
, m_needsToStartForced(params.forced)
|
||||||
|
, m_pauseWhenReady(params.paused)
|
||||||
{
|
{
|
||||||
if (m_useAutoTMM)
|
if (m_useAutoTMM)
|
||||||
m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category));
|
m_savePath = Utils::Fs::toNativePath(m_session->categorySavePath(m_category));
|
||||||
@ -216,18 +217,18 @@ TorrentHandle::TorrentHandle(Session *session, const lt::torrent_handle &nativeH
|
|||||||
m_hasRootFolder = false;
|
m_hasRootFolder = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "started" means "all initialization has completed and torrent has started regular processing".
|
if (!hasMetadata()) {
|
||||||
// When torrent added/restored in "paused" state it become "started" immediately after construction.
|
// There is nothing to prepare
|
||||||
// When it is added/restored in "resumed" state, it become "started" after it is really resumed
|
if (!m_pauseWhenReady) {
|
||||||
// (i.e. after receiving "torrent resumed" alert).
|
// Resume torrent because it was added in "resumed" state
|
||||||
if (params.paused) {
|
// but it's actually paused during initialization.
|
||||||
m_startupState = Started;
|
m_startupState = Starting;
|
||||||
}
|
resume(m_needsToStartForced);
|
||||||
else if (!params.restored || !hasMetadata()) {
|
}
|
||||||
// Resume torrent because it was added in "resumed" state
|
else {
|
||||||
// but it's actually paused during initialization
|
m_startupState = Started;
|
||||||
m_startupState = Starting;
|
m_pauseWhenReady = false;
|
||||||
resume(params.forced);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1346,7 +1347,8 @@ void TorrentHandle::forceRecheck()
|
|||||||
#else
|
#else
|
||||||
m_nativeHandle.set_flags(lt::torrent_flags::stop_when_ready);
|
m_nativeHandle.set_flags(lt::torrent_flags::stop_when_ready);
|
||||||
#endif
|
#endif
|
||||||
resume_impl(false);
|
setAutoManaged(true);
|
||||||
|
m_pauseWhenReady = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1618,17 +1620,22 @@ void TorrentHandle::handleTorrentCheckedAlert(const lt::torrent_checked_alert *p
|
|||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
qDebug("\"%s\" have just finished checking", qUtf8Printable(name()));
|
qDebug("\"%s\" have just finished checking", qUtf8Printable(name()));
|
||||||
|
|
||||||
if (m_startupState == NotStarted) {
|
if (m_startupState == Preparing) {
|
||||||
if (!m_hasMissingFiles) {
|
if (!m_pauseWhenReady) {
|
||||||
// Resume torrent because it was added in "resumed" state
|
if (!m_hasMissingFiles) {
|
||||||
// but it's actually paused during initialization.
|
// Resume torrent because it was added in "resumed" state
|
||||||
m_startupState = Starting;
|
// but it's actually paused during initialization.
|
||||||
resume(m_needsToStartForced);
|
m_startupState = Starting;
|
||||||
|
resume(m_needsToStartForced);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Torrent that has missing files is paused.
|
||||||
|
m_startupState = Started;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Torrent that has missing files is marked as "started"
|
|
||||||
// but it remains paused.
|
|
||||||
m_startupState = Started;
|
m_startupState = Started;
|
||||||
|
m_pauseWhenReady = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1652,10 +1659,10 @@ void TorrentHandle::handleTorrentFinishedAlert(const lt::torrent_finished_alert
|
|||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
qDebug("Got a torrent finished alert for \"%s\"", qUtf8Printable(name()));
|
qDebug("Got a torrent finished alert for \"%s\"", qUtf8Printable(name()));
|
||||||
qDebug("Torrent has seed status: %s", m_hasSeedStatus ? "yes" : "no");
|
qDebug("Torrent has seed status: %s", m_hasSeedStatus ? "yes" : "no");
|
||||||
|
m_hasMissingFiles = false;
|
||||||
if (m_hasSeedStatus) return;
|
if (m_hasSeedStatus) return;
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
m_hasMissingFiles = false;
|
|
||||||
m_hasSeedStatus = true;
|
m_hasSeedStatus = true;
|
||||||
|
|
||||||
adjustActualSavePath();
|
adjustActualSavePath();
|
||||||
@ -1679,9 +1686,14 @@ void TorrentHandle::handleTorrentPausedAlert(const lt::torrent_paused_alert *p)
|
|||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
|
|
||||||
if (m_startupState == Started) {
|
if (m_startupState == Started) {
|
||||||
updateStatus();
|
if (!m_pauseWhenReady) {
|
||||||
m_speedMonitor.reset();
|
updateStatus();
|
||||||
m_session->handleTorrentPaused(this);
|
m_speedMonitor.reset();
|
||||||
|
m_session->handleTorrentPaused(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_pauseWhenReady = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1710,8 +1722,8 @@ void TorrentHandle::handleSaveResumeDataAlert(const lt::save_resume_data_alert *
|
|||||||
|
|
||||||
if (useDummyResumeData) {
|
if (useDummyResumeData) {
|
||||||
resumeData["qBt-magnetUri"] = toMagnetUri().toStdString();
|
resumeData["qBt-magnetUri"] = toMagnetUri().toStdString();
|
||||||
resumeData["qBt-paused"] = isPaused();
|
resumeData["paused"] = isPaused();
|
||||||
resumeData["qBt-forced"] = isForced();
|
resumeData["auto_managed"] = isAutoManaged();
|
||||||
// Both firstLastPiecePriority and sequential need to be stored in the
|
// Both firstLastPiecePriority and sequential need to be stored in the
|
||||||
// resume data if there is no metadata, otherwise they won't be
|
// resume data if there is no metadata, otherwise they won't be
|
||||||
// restored if qBittorrent quits before the metadata are retrieved:
|
// restored if qBittorrent quits before the metadata are retrieved:
|
||||||
@ -1733,6 +1745,14 @@ void TorrentHandle::handleSaveResumeDataAlert(const lt::save_resume_data_alert *
|
|||||||
resumeData["qBt-queuePosition"] = (static_cast<int>(nativeHandle().queue_position()) + 1); // qBt starts queue at 1
|
resumeData["qBt-queuePosition"] = (static_cast<int>(nativeHandle().queue_position()) + 1); // qBt starts queue at 1
|
||||||
resumeData["qBt-hasRootFolder"] = m_hasRootFolder;
|
resumeData["qBt-hasRootFolder"] = m_hasRootFolder;
|
||||||
|
|
||||||
|
if (m_pauseWhenReady) {
|
||||||
|
// We need to redefine these values when torrent starting/rechecking
|
||||||
|
// in "paused" state since native values can be logically wrong
|
||||||
|
// (torrent can be not paused and auto_managed when it is checking).
|
||||||
|
resumeData["paused"] = true;
|
||||||
|
resumeData["auto_managed"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
m_session->handleTorrentResumeDataReady(this, resumeData);
|
m_session->handleTorrentResumeDataReady(this, resumeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,12 +447,15 @@ namespace BitTorrent
|
|||||||
|
|
||||||
enum StartupState
|
enum StartupState
|
||||||
{
|
{
|
||||||
NotStarted,
|
Preparing, // torrent is preparing to start regular processing
|
||||||
Starting,
|
Starting, // torrent is prepared and starting to perform regular processing
|
||||||
Started
|
Started // torrent is performing regular processing
|
||||||
};
|
};
|
||||||
|
StartupState m_startupState = Preparing;
|
||||||
|
// Handle torrent state when it starts performing some service job
|
||||||
|
// being in Paused state so it might be unpaused internally and then paused again
|
||||||
|
bool m_pauseWhenReady;
|
||||||
|
|
||||||
StartupState m_startupState = NotStarted;
|
|
||||||
bool m_unchecked = false;
|
bool m_unchecked = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user