mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-12-21 08:09:35 +08:00
Merge pull request #12035 from glassez/move-storage
Move torrent storages one by one
This commit is contained in:
commit
5127156ba4
@ -1815,8 +1815,19 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio
|
||||
for (const QString &file : files)
|
||||
Utils::Fs::forceRemove(resumeDataDir.absoluteFilePath(file));
|
||||
|
||||
if (m_moveStorageQueue.size() > 1) {
|
||||
// Delete "move storage job" for the deleted torrent
|
||||
// (note: we shouldn't delete active job)
|
||||
const auto iter = std::find_if(m_moveStorageQueue.begin() + 1, m_moveStorageQueue.end()
|
||||
, [torrent](const MoveStorageJob &job)
|
||||
{
|
||||
return job.torrent == torrent;
|
||||
});
|
||||
if (iter != m_moveStorageQueue.end())
|
||||
m_moveStorageQueue.erase(iter);
|
||||
}
|
||||
|
||||
delete torrent;
|
||||
qDebug("Torrent deleted.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3938,6 +3949,78 @@ void Session::handleTorrentTrackerError(TorrentHandle *const torrent, const QStr
|
||||
emit trackerError(torrent, trackerUrl);
|
||||
}
|
||||
|
||||
bool Session::addMoveTorrentStorageJob(TorrentHandle *torrent, const QString &newPath, const MoveStorageMode mode)
|
||||
{
|
||||
Q_ASSERT(torrent);
|
||||
|
||||
if (m_moveStorageQueue.size() > 1) {
|
||||
const auto iter = std::find_if(m_moveStorageQueue.begin() + 1, m_moveStorageQueue.end()
|
||||
, [torrent](const MoveStorageJob &job)
|
||||
{
|
||||
return job.torrent == torrent;
|
||||
});
|
||||
|
||||
if (iter != m_moveStorageQueue.end()) {
|
||||
// remove existing inactive job
|
||||
m_moveStorageQueue.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
QString currentLocation = QString::fromStdString(
|
||||
torrent->nativeHandle().status(lt::torrent_handle::query_save_path).save_path);
|
||||
if (!m_moveStorageQueue.isEmpty() && (m_moveStorageQueue.first().torrent == torrent)) {
|
||||
// if there is active job for this torrent consider its target path as current location
|
||||
// of this torrent to prevent creating meaningless job that will do nothing
|
||||
currentLocation = m_moveStorageQueue.first().path;
|
||||
}
|
||||
|
||||
if (QDir {currentLocation} == QDir {newPath})
|
||||
return false;
|
||||
|
||||
const MoveStorageJob moveStorageJob {torrent, newPath, mode};
|
||||
qDebug("Move storage from \"%s\" to \"%s\" is enqueued.", qUtf8Printable(currentLocation), qUtf8Printable(newPath));
|
||||
|
||||
if (m_moveStorageQueue.size() == 1)
|
||||
moveTorrentStorage(moveStorageJob);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Session::moveTorrentStorage(const MoveStorageJob &job) const
|
||||
{
|
||||
lt::torrent_handle handle = job.torrent->nativeHandle();
|
||||
|
||||
qDebug("Moving torrent storage to \"%s\"...", qUtf8Printable(job.path));
|
||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||
handle.move_storage(job.path.toUtf8().constData()
|
||||
, ((job.mode == MoveStorageMode::Overwrite)
|
||||
? lt::always_replace_files : lt::dont_replace));
|
||||
#else
|
||||
handle.move_storage(job.path.toUtf8().constData()
|
||||
, ((job.mode == MoveStorageMode::Overwrite)
|
||||
? lt::move_flags_t::always_replace_files : lt::move_flags_t::dont_replace));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Session::handleMoveTorrentStorageJobFinished(const QString &errorMessage)
|
||||
{
|
||||
Q_ASSERT(!m_moveStorageQueue.isEmpty());
|
||||
|
||||
const MoveStorageJob finishedJob = m_moveStorageQueue.takeFirst();
|
||||
if (!m_moveStorageQueue.isEmpty())
|
||||
moveTorrentStorage(m_moveStorageQueue.first());
|
||||
|
||||
const auto iter = std::find_if(m_moveStorageQueue.cbegin(), m_moveStorageQueue.cend()
|
||||
, [&finishedJob](const MoveStorageJob &job)
|
||||
{
|
||||
return job.torrent == finishedJob.torrent;
|
||||
});
|
||||
if (iter == m_moveStorageQueue.cend()) {
|
||||
// There is no more job for this torrent
|
||||
finishedJob.torrent->handleStorageMoved(finishedJob.path, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl)
|
||||
{
|
||||
emit trackerWarning(torrent, trackerUrl);
|
||||
@ -4254,8 +4337,6 @@ void Session::handleAlert(const lt::alert *a)
|
||||
case lt::torrent_finished_alert::alert_type:
|
||||
case lt::save_resume_data_alert::alert_type:
|
||||
case lt::save_resume_data_failed_alert::alert_type:
|
||||
case lt::storage_moved_alert::alert_type:
|
||||
case lt::storage_moved_failed_alert::alert_type:
|
||||
case lt::torrent_paused_alert::alert_type:
|
||||
case lt::torrent_resumed_alert::alert_type:
|
||||
case lt::tracker_error_alert::alert_type:
|
||||
@ -4319,6 +4400,12 @@ void Session::handleAlert(const lt::alert *a)
|
||||
handleAlertsDroppedAlert(static_cast<const lt::alerts_dropped_alert *>(a));
|
||||
break;
|
||||
#endif
|
||||
case lt::storage_moved_alert::alert_type:
|
||||
handleStorageMovedAlert(static_cast<const lt::storage_moved_alert*>(a));
|
||||
break;
|
||||
case lt::storage_moved_failed_alert::alert_type:
|
||||
handleStorageMovedFailedAlert(static_cast<const lt::storage_moved_failed_alert*>(a));
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &exc) {
|
||||
@ -4813,6 +4900,29 @@ void Session::handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const
|
||||
}
|
||||
#endif
|
||||
|
||||
void Session::handleStorageMovedAlert(const lt::storage_moved_alert *p)
|
||||
{
|
||||
if (m_moveStorageQueue.isEmpty()) return;
|
||||
|
||||
const TorrentHandle *torrent = m_torrents.value(p->handle.info_hash());
|
||||
const MoveStorageJob ¤tJob = m_moveStorageQueue.first();
|
||||
if (currentJob.torrent != torrent) return;
|
||||
|
||||
const QString newPath {p->storage_path()};
|
||||
handleMoveTorrentStorageJobFinished(newPath != currentJob.path ? tr("New path doesn't match a target path.") : QString {});
|
||||
}
|
||||
|
||||
void Session::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p)
|
||||
{
|
||||
if (m_moveStorageQueue.isEmpty()) return;
|
||||
|
||||
const TorrentHandle *torrent = m_torrents.value(p->handle.info_hash());
|
||||
const MoveStorageJob ¤tJob = m_moveStorageQueue.first();
|
||||
if (currentJob.torrent != torrent) return;
|
||||
|
||||
handleMoveTorrentStorageJobFinished(QString::fromStdString(p->message()));
|
||||
}
|
||||
|
||||
void Session::handleStateUpdateAlert(const lt::state_update_alert *p)
|
||||
{
|
||||
QVector<BitTorrent::TorrentHandle *> updatedTorrents;
|
||||
|
@ -96,6 +96,8 @@ namespace BitTorrent
|
||||
class TrackerEntry;
|
||||
struct CreateTorrentParams;
|
||||
|
||||
enum class MoveStorageMode;
|
||||
|
||||
// Using `Q_ENUM_NS()` without a wrapper namespace in our case is not advised
|
||||
// since `Q_NAMESPACE` cannot be used when the same namespace resides at different files.
|
||||
// https://www.kdab.com/new-qt-5-8-meta-object-support-namespaces/#comment-143779
|
||||
@ -461,6 +463,8 @@ namespace BitTorrent
|
||||
void handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentTrackerError(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
|
||||
bool addMoveTorrentStorageJob(TorrentHandle *torrent, const QString &newPath, MoveStorageMode mode);
|
||||
|
||||
signals:
|
||||
void addTorrentFailed(const QString &error);
|
||||
void allTorrentsFinished();
|
||||
@ -514,6 +518,13 @@ namespace BitTorrent
|
||||
void networkConfigurationChange(const QNetworkConfiguration &);
|
||||
|
||||
private:
|
||||
struct MoveStorageJob
|
||||
{
|
||||
TorrentHandle *torrent;
|
||||
QString path;
|
||||
MoveStorageMode mode;
|
||||
};
|
||||
|
||||
struct RemovingTorrentData
|
||||
{
|
||||
QString name;
|
||||
@ -583,6 +594,8 @@ namespace BitTorrent
|
||||
#if (LIBTORRENT_VERSION_NUM >= 10200)
|
||||
void handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const;
|
||||
#endif
|
||||
void handleStorageMovedAlert(const lt::storage_moved_alert *p);
|
||||
void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p);
|
||||
|
||||
void createTorrentHandle(const lt::torrent_handle &nativeHandle);
|
||||
|
||||
@ -592,6 +605,9 @@ namespace BitTorrent
|
||||
|
||||
std::vector<lt::alert *> getPendingAlerts(lt::time_duration time = lt::time_duration::zero()) const;
|
||||
|
||||
void moveTorrentStorage(const MoveStorageJob &job) const;
|
||||
void handleMoveTorrentStorageJobFinished(const QString &errorMessage = {});
|
||||
|
||||
// BitTorrent
|
||||
lt::session *m_nativeSession = nullptr;
|
||||
|
||||
@ -732,6 +748,8 @@ namespace BitTorrent
|
||||
|
||||
QNetworkConfigurationManager *m_networkManager = nullptr;
|
||||
|
||||
QList<MoveStorageJob> m_moveStorageQueue;
|
||||
|
||||
static Session *m_instance;
|
||||
};
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ QString TorrentHandle::currentTracker() const
|
||||
QString TorrentHandle::savePath(bool actual) const
|
||||
{
|
||||
if (actual)
|
||||
return Utils::Fs::toUniformPath(nativeActualSavePath());
|
||||
return Utils::Fs::toUniformPath(actualStorageLocation());
|
||||
else
|
||||
return Utils::Fs::toUniformPath(m_savePath);
|
||||
}
|
||||
@ -369,7 +369,7 @@ void TorrentHandle::setAutoTMMEnabled(bool enabled)
|
||||
m_session->handleTorrentSavingModeChanged(this);
|
||||
|
||||
if (m_useAutoTMM)
|
||||
move_impl(m_session->categorySavePath(m_category), true);
|
||||
move_impl(m_session->categorySavePath(m_category), MoveStorageMode::Overwrite);
|
||||
}
|
||||
|
||||
bool TorrentHandle::hasRootFolder() const
|
||||
@ -377,7 +377,7 @@ bool TorrentHandle::hasRootFolder() const
|
||||
return m_hasRootFolder;
|
||||
}
|
||||
|
||||
QString TorrentHandle::nativeActualSavePath() const
|
||||
QString TorrentHandle::actualStorageLocation() const
|
||||
{
|
||||
return QString::fromStdString(m_nativeStatus.save_path);
|
||||
}
|
||||
@ -898,44 +898,42 @@ void TorrentHandle::updateState()
|
||||
else if (isMoveInProgress()) {
|
||||
m_state = TorrentState::Moving;
|
||||
}
|
||||
else if (hasMissingFiles()) {
|
||||
m_state = TorrentState::MissingFiles;
|
||||
}
|
||||
else if (isPaused()) {
|
||||
if (hasMissingFiles())
|
||||
m_state = TorrentState::MissingFiles;
|
||||
else
|
||||
m_state = isSeed() ? TorrentState::PausedUploading : TorrentState::PausedDownloading;
|
||||
m_state = isSeed() ? TorrentState::PausedUploading : TorrentState::PausedDownloading;
|
||||
}
|
||||
else if (m_session->isQueueingSystemEnabled() && isQueued() && !isChecking()) {
|
||||
m_state = isSeed() ? TorrentState::QueuedUploading : TorrentState::QueuedDownloading;
|
||||
}
|
||||
else {
|
||||
if (m_session->isQueueingSystemEnabled() && isQueued() && !isChecking()) {
|
||||
m_state = isSeed() ? TorrentState::QueuedUploading : TorrentState::QueuedDownloading;
|
||||
}
|
||||
else {
|
||||
switch (m_nativeStatus.state) {
|
||||
case lt::torrent_status::finished:
|
||||
case lt::torrent_status::seeding:
|
||||
if (isForced())
|
||||
m_state = TorrentState::ForcedUploading;
|
||||
else
|
||||
m_state = m_nativeStatus.upload_payload_rate > 0 ? TorrentState::Uploading : TorrentState::StalledUploading;
|
||||
break;
|
||||
case lt::torrent_status::allocating:
|
||||
m_state = TorrentState::Allocating;
|
||||
break;
|
||||
case lt::torrent_status::checking_files:
|
||||
m_state = m_hasSeedStatus ? TorrentState::CheckingUploading : TorrentState::CheckingDownloading;
|
||||
break;
|
||||
case lt::torrent_status::downloading_metadata:
|
||||
m_state = TorrentState::DownloadingMetadata;
|
||||
break;
|
||||
case lt::torrent_status::downloading:
|
||||
if (isForced())
|
||||
m_state = TorrentState::ForcedDownloading;
|
||||
else
|
||||
m_state = m_nativeStatus.download_payload_rate > 0 ? TorrentState::Downloading : TorrentState::StalledDownloading;
|
||||
break;
|
||||
default:
|
||||
qWarning("Unrecognized torrent status, should not happen!!! status was %d", m_nativeStatus.state);
|
||||
m_state = TorrentState::Unknown;
|
||||
}
|
||||
switch (m_nativeStatus.state) {
|
||||
case lt::torrent_status::finished:
|
||||
case lt::torrent_status::seeding:
|
||||
if (isForced())
|
||||
m_state = TorrentState::ForcedUploading;
|
||||
else
|
||||
m_state = m_nativeStatus.upload_payload_rate > 0 ? TorrentState::Uploading : TorrentState::StalledUploading;
|
||||
break;
|
||||
case lt::torrent_status::allocating:
|
||||
m_state = TorrentState::Allocating;
|
||||
break;
|
||||
case lt::torrent_status::checking_files:
|
||||
m_state = m_hasSeedStatus ? TorrentState::CheckingUploading : TorrentState::CheckingDownloading;
|
||||
break;
|
||||
case lt::torrent_status::downloading_metadata:
|
||||
m_state = TorrentState::DownloadingMetadata;
|
||||
break;
|
||||
case lt::torrent_status::downloading:
|
||||
if (isForced())
|
||||
m_state = TorrentState::ForcedDownloading;
|
||||
else
|
||||
m_state = m_nativeStatus.download_payload_rate > 0 ? TorrentState::Downloading : TorrentState::StalledDownloading;
|
||||
break;
|
||||
default:
|
||||
qWarning("Unrecognized torrent status, should not happen!!! status was %d", m_nativeStatus.state);
|
||||
m_state = TorrentState::Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1334,7 +1332,7 @@ bool TorrentHandle::setCategory(const QString &category)
|
||||
|
||||
if (m_useAutoTMM) {
|
||||
if (!m_session->isDisableAutoTMMWhenCategoryChanged())
|
||||
move_impl(m_session->categorySavePath(m_category), true);
|
||||
move_impl(m_session->categorySavePath(m_category), MoveStorageMode::Overwrite);
|
||||
else
|
||||
setAutoTMMEnabled(false);
|
||||
}
|
||||
@ -1354,21 +1352,19 @@ void TorrentHandle::move(QString path)
|
||||
if (!path.endsWith('/'))
|
||||
path += '/';
|
||||
|
||||
move_impl(path, false);
|
||||
move_impl(path, MoveStorageMode::KeepExistingFiles);
|
||||
}
|
||||
|
||||
void TorrentHandle::move_impl(QString path, bool overwrite)
|
||||
void TorrentHandle::move_impl(QString path, const MoveStorageMode mode)
|
||||
{
|
||||
if (path == savePath()) return;
|
||||
path = Utils::Fs::toNativePath(path);
|
||||
|
||||
if (!useTempPath()) {
|
||||
moveStorage(path, overwrite);
|
||||
}
|
||||
else {
|
||||
m_savePath = path;
|
||||
m_session->handleTorrentSavePathChanged(this);
|
||||
}
|
||||
if (!useTempPath())
|
||||
moveStorage(path, mode);
|
||||
|
||||
m_savePath = path;
|
||||
m_session->handleTorrentSavePathChanged(this);
|
||||
}
|
||||
|
||||
void TorrentHandle::forceReannounce(int index)
|
||||
@ -1502,30 +1498,10 @@ void TorrentHandle::resume_impl(bool forced)
|
||||
m_nativeHandle.resume();
|
||||
}
|
||||
|
||||
void TorrentHandle::moveStorage(const QString &newPath, bool overwrite)
|
||||
void TorrentHandle::moveStorage(const QString &newPath, const MoveStorageMode mode)
|
||||
{
|
||||
if (isMoveInProgress()) {
|
||||
qDebug("enqueue move storage to %s", qUtf8Printable(newPath));
|
||||
m_moveStorageInfo.queuedPath = newPath;
|
||||
m_moveStorageInfo.queuedOverwrite = overwrite;
|
||||
}
|
||||
else {
|
||||
const QString oldPath = nativeActualSavePath();
|
||||
if (QDir(oldPath) == QDir(newPath)) return;
|
||||
|
||||
qDebug("move storage: %s to %s", qUtf8Printable(oldPath), qUtf8Printable(newPath));
|
||||
// Actually move the storage
|
||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||
m_nativeHandle.move_storage(newPath.toUtf8().constData()
|
||||
, (overwrite ? lt::always_replace_files : lt::dont_replace));
|
||||
#else
|
||||
m_nativeHandle.move_storage(newPath.toUtf8().constData()
|
||||
, (overwrite ? lt::move_flags_t::always_replace_files : lt::move_flags_t::dont_replace));
|
||||
#endif
|
||||
m_moveStorageInfo.oldPath = oldPath;
|
||||
m_moveStorageInfo.newPath = newPath;
|
||||
updateState();
|
||||
}
|
||||
if (m_session->addMoveTorrentStorageJob(this, newPath, mode))
|
||||
m_storageIsMoving = true;
|
||||
}
|
||||
|
||||
void TorrentHandle::renameFile(const int index, const QString &name)
|
||||
@ -1540,66 +1516,18 @@ void TorrentHandle::handleStateUpdate(const lt::torrent_status &nativeStatus)
|
||||
updateStatus(nativeStatus);
|
||||
}
|
||||
|
||||
void TorrentHandle::handleStorageMovedAlert(const lt::storage_moved_alert *p)
|
||||
void TorrentHandle::handleStorageMoved(const QString &newPath, const QString &errorMessage)
|
||||
{
|
||||
if (!isMoveInProgress()) {
|
||||
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
|
||||
return;
|
||||
}
|
||||
m_storageIsMoving = false;
|
||||
|
||||
const QString newPath(p->storage_path());
|
||||
if (newPath != m_moveStorageInfo.newPath) {
|
||||
qWarning() << Q_FUNC_INFO << ": New path doesn't match a path in a queue.";
|
||||
return;
|
||||
}
|
||||
if (!errorMessage.isEmpty())
|
||||
LogMsg(tr("Could not move torrent: %1. Reason: %2").arg(name(), errorMessage), Log::CRITICAL);
|
||||
else
|
||||
LogMsg(tr("Successfully moved torrent: %1. New path: %2").arg(name(), newPath));
|
||||
|
||||
LogMsg(tr("Successfully moved torrent: %1. New path: %2").arg(name(), m_moveStorageInfo.newPath));
|
||||
|
||||
const QDir oldDir {m_moveStorageInfo.oldPath};
|
||||
if ((oldDir == QDir(m_session->torrentTempPath(info())))
|
||||
&& (oldDir != QDir(m_session->tempPath()))) {
|
||||
// torrent without root folder still has it in its temporary save path
|
||||
// so its temp path isn't equal to temp path root
|
||||
qDebug() << "Removing torrent temp folder:" << m_moveStorageInfo.oldPath;
|
||||
Utils::Fs::smartRemoveEmptyFolderTree(m_moveStorageInfo.oldPath);
|
||||
}
|
||||
|
||||
m_moveStorageInfo.newPath.clear();
|
||||
updateStatus();
|
||||
|
||||
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
|
||||
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
|
||||
m_moveStorageInfo.queuedPath.clear();
|
||||
}
|
||||
|
||||
if (!useTempPath()) {
|
||||
m_savePath = newPath;
|
||||
m_session->handleTorrentSavePathChanged(this);
|
||||
}
|
||||
|
||||
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
|
||||
m_moveFinishedTriggers.takeFirst()();
|
||||
}
|
||||
|
||||
void TorrentHandle::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p)
|
||||
{
|
||||
if (!isMoveInProgress()) {
|
||||
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
|
||||
return;
|
||||
}
|
||||
|
||||
LogMsg(tr("Could not move torrent: '%1'. Reason: %2")
|
||||
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
|
||||
|
||||
m_moveStorageInfo.newPath.clear();
|
||||
updateStatus();
|
||||
|
||||
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
|
||||
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
|
||||
m_moveStorageInfo.queuedPath.clear();
|
||||
}
|
||||
|
||||
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
|
||||
while ((m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
|
||||
m_moveFinishedTriggers.takeFirst()();
|
||||
}
|
||||
|
||||
@ -1922,7 +1850,7 @@ void TorrentHandle::handleTempPathChanged()
|
||||
void TorrentHandle::handleCategorySavePathChanged()
|
||||
{
|
||||
if (m_useAutoTMM)
|
||||
move_impl(m_session->categorySavePath(m_category), true);
|
||||
move_impl(m_session->categorySavePath(m_category), MoveStorageMode::Overwrite);
|
||||
}
|
||||
|
||||
void TorrentHandle::handleAppendExtensionToggled()
|
||||
@ -1953,12 +1881,6 @@ void TorrentHandle::handleAlert(const lt::alert *a)
|
||||
case lt::save_resume_data_failed_alert::alert_type:
|
||||
handleSaveResumeDataFailedAlert(static_cast<const lt::save_resume_data_failed_alert*>(a));
|
||||
break;
|
||||
case lt::storage_moved_alert::alert_type:
|
||||
handleStorageMovedAlert(static_cast<const lt::storage_moved_alert*>(a));
|
||||
break;
|
||||
case lt::storage_moved_failed_alert::alert_type:
|
||||
handleStorageMovedFailedAlert(static_cast<const lt::storage_moved_failed_alert*>(a));
|
||||
break;
|
||||
case lt::torrent_paused_alert::alert_type:
|
||||
handleTorrentPausedAlert(static_cast<const lt::torrent_paused_alert*>(a));
|
||||
break;
|
||||
@ -2028,19 +1950,27 @@ void TorrentHandle::adjustActualSavePath()
|
||||
|
||||
void TorrentHandle::adjustActualSavePath_impl()
|
||||
{
|
||||
QString path;
|
||||
if (!useTempPath()) {
|
||||
// Disabling temp dir
|
||||
// Moving all torrents to their destination folder
|
||||
path = savePath();
|
||||
}
|
||||
else {
|
||||
// Moving all downloading torrents to temporary folder
|
||||
path = m_session->torrentTempPath(info());
|
||||
qDebug() << "Moving torrent to its temporary folder:" << path;
|
||||
const bool needUseTempDir = useTempPath();
|
||||
const QDir tempDir {m_session->torrentTempPath(info())};
|
||||
const QDir currentDir {actualStorageLocation()};
|
||||
const QDir targetDir {needUseTempDir ? tempDir : QDir {savePath()}};
|
||||
|
||||
if (targetDir == currentDir) return;
|
||||
|
||||
if (!needUseTempDir) {
|
||||
if ((currentDir == tempDir) && (currentDir != QDir {m_session->tempPath()})) {
|
||||
// torrent without root folder still has it in its temporary save path
|
||||
// so its temp path isn't equal to temp path root
|
||||
const QString currentDirPath = currentDir.absolutePath();
|
||||
m_moveFinishedTriggers.append([currentDirPath]
|
||||
{
|
||||
qDebug() << "Removing torrent temp folder:" << currentDirPath;
|
||||
Utils::Fs::smartRemoveEmptyFolderTree(currentDirPath);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
moveStorage(Utils::Fs::toNativePath(path), true);
|
||||
moveStorage(Utils::Fs::toNativePath(targetDir.absolutePath()), MoveStorageMode::Overwrite);
|
||||
}
|
||||
|
||||
lt::torrent_handle TorrentHandle::nativeHandle() const
|
||||
@ -2057,7 +1987,7 @@ void TorrentHandle::updateTorrentInfo()
|
||||
|
||||
bool TorrentHandle::isMoveInProgress() const
|
||||
{
|
||||
return !m_moveStorageInfo.newPath.isEmpty();
|
||||
return m_storageIsMoving;
|
||||
}
|
||||
|
||||
bool TorrentHandle::useTempPath() const
|
||||
|
@ -99,6 +99,12 @@ namespace BitTorrent
|
||||
int numPeers = 0;
|
||||
};
|
||||
|
||||
enum class MoveStorageMode
|
||||
{
|
||||
KeepExistingFiles,
|
||||
Overwrite
|
||||
};
|
||||
|
||||
enum class TorrentState
|
||||
{
|
||||
Unknown = -1,
|
||||
@ -345,6 +351,7 @@ namespace BitTorrent
|
||||
void handleCategorySavePathChanged();
|
||||
void handleAppendExtensionToggled();
|
||||
void saveResumeData();
|
||||
void handleStorageMoved(const QString &newPath, const QString &errorMessage);
|
||||
|
||||
/**
|
||||
* @brief fraction of file pieces that are available at least from one peer
|
||||
@ -376,8 +383,6 @@ namespace BitTorrent
|
||||
void handlePerformanceAlert(const lt::performance_alert *p) const;
|
||||
void handleSaveResumeDataAlert(const lt::save_resume_data_alert *p);
|
||||
void handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p);
|
||||
void handleStorageMovedAlert(const lt::storage_moved_alert *p);
|
||||
void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p);
|
||||
void handleTorrentCheckedAlert(const lt::torrent_checked_alert *p);
|
||||
void handleTorrentFinishedAlert(const lt::torrent_finished_alert *p);
|
||||
void handleTorrentPausedAlert(const lt::torrent_paused_alert *p);
|
||||
@ -388,14 +393,14 @@ namespace BitTorrent
|
||||
|
||||
void resume_impl(bool forced);
|
||||
bool isMoveInProgress() const;
|
||||
QString nativeActualSavePath() const;
|
||||
QString actualStorageLocation() const;
|
||||
bool isAutoManaged() const;
|
||||
void setAutoManaged(bool enable);
|
||||
|
||||
void adjustActualSavePath();
|
||||
void adjustActualSavePath_impl();
|
||||
void move_impl(QString path, bool overwrite);
|
||||
void moveStorage(const QString &newPath, bool overwrite);
|
||||
void move_impl(QString path, MoveStorageMode mode);
|
||||
void moveStorage(const QString &newPath, MoveStorageMode mode);
|
||||
void manageIncompleteFiles();
|
||||
void setFirstLastPiecePriorityImpl(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {});
|
||||
|
||||
@ -408,16 +413,7 @@ namespace BitTorrent
|
||||
|
||||
InfoHash m_hash;
|
||||
|
||||
struct
|
||||
{
|
||||
QString oldPath;
|
||||
QString newPath;
|
||||
// queuedPath is where files should be moved to,
|
||||
// when current moving is completed
|
||||
QString queuedPath;
|
||||
bool queuedOverwrite = true;
|
||||
} m_moveStorageInfo;
|
||||
|
||||
bool m_storageIsMoving = false;
|
||||
// m_moveFinishedTriggers is activated only when the following conditions are met:
|
||||
// all file rename jobs complete, all file move jobs complete
|
||||
QQueue<EventTrigger> m_moveFinishedTriggers;
|
||||
|
@ -507,12 +507,9 @@ void TransferListWidget::setSelectedTorrentsLocation()
|
||||
if (torrents.isEmpty()) return;
|
||||
|
||||
const QString oldLocation = torrents[0]->savePath();
|
||||
qDebug("Old location is %s", qUtf8Printable(oldLocation));
|
||||
|
||||
const QString newLocation = QFileDialog::getExistingDirectory(this, tr("Choose save path"), oldLocation,
|
||||
QFileDialog::DontConfirmOverwrite | QFileDialog::ShowDirsOnly | QFileDialog::HideNameFilterDetails);
|
||||
if (newLocation.isEmpty() || !QDir(newLocation).exists()) return;
|
||||
qDebug("New location is %s", qUtf8Printable(newLocation));
|
||||
|
||||
// Actually move storage
|
||||
for (BitTorrent::TorrentHandle *const torrent : torrents) {
|
||||
|
Loading…
Reference in New Issue
Block a user