mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-12-21 08:09:35 +08:00
Drop ".unwanted folder" feature
This commit is contained in:
parent
17205802ec
commit
6a0a78f3f7
@ -420,34 +420,6 @@ namespace
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QStringList getUnwantedFilePaths(const lt::torrent_handle &torrentHandle)
|
|
||||||
{
|
|
||||||
const TorrentInfo torrentInfo {torrentHandle.torrent_file()};
|
|
||||||
if (!torrentInfo.isValid())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const QString savePath = QString::fromStdString(
|
|
||||||
torrentHandle.status(lt::torrent_handle::query_save_path).save_path);
|
|
||||||
const QDir saveDir {savePath};
|
|
||||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
|
||||||
const std::vector<LTDownloadPriority> fp = torrentHandle.file_priorities();
|
|
||||||
#else
|
|
||||||
const std::vector<LTDownloadPriority> fp = torrentHandle.get_file_priorities();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QStringList res;
|
|
||||||
for (int i = 0; i < static_cast<int>(fp.size()); ++i) {
|
|
||||||
if (fp[i] == LTDownloadPriority {0}) {
|
|
||||||
const QString path = Utils::Fs::expandPathAbs(
|
|
||||||
saveDir.absoluteFilePath(torrentInfo.filePath(i)));
|
|
||||||
if (path.contains(".unwanted"))
|
|
||||||
res << path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session
|
// Session
|
||||||
@ -1877,6 +1849,8 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio
|
|||||||
|
|
||||||
// Remove it from session
|
// Remove it from session
|
||||||
if (deleteOption == Torrent) {
|
if (deleteOption == Torrent) {
|
||||||
|
m_removingTorrents[torrent->hash()] = {torrent->name(), "", deleteOption};
|
||||||
|
|
||||||
const lt::torrent_handle nativeHandle {torrent->nativeHandle()};
|
const lt::torrent_handle nativeHandle {torrent->nativeHandle()};
|
||||||
const auto iter = std::find_if(m_moveStorageQueue.begin(), m_moveStorageQueue.end()
|
const auto iter = std::find_if(m_moveStorageQueue.begin(), m_moveStorageQueue.end()
|
||||||
, [&nativeHandle](const MoveStorageJob &job)
|
, [&nativeHandle](const MoveStorageJob &job)
|
||||||
@ -1892,27 +1866,20 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio
|
|||||||
nativeHandle.unset_flags(lt::torrent_flags::auto_managed);
|
nativeHandle.unset_flags(lt::torrent_flags::auto_managed);
|
||||||
#endif
|
#endif
|
||||||
nativeHandle.pause();
|
nativeHandle.pause();
|
||||||
m_removingTorrents[torrent->hash()] = {torrent->name(), {}, deleteOption};
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_removingTorrents[torrent->hash()] = {torrent->name(), getUnwantedFilePaths(nativeHandle), deleteOption};
|
|
||||||
m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile);
|
m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const QString rootPath = torrent->rootPath(true);
|
QString rootPath = torrent->rootPath(true);
|
||||||
if (!rootPath.isEmpty()) {
|
if (!rootPath.isEmpty() && torrent->useTempPath()) {
|
||||||
// torrent with root folder
|
|
||||||
m_removingTorrents[torrent->hash()] = {torrent->name(), {rootPath}, deleteOption};
|
|
||||||
}
|
|
||||||
else if (torrent->useTempPath()) {
|
|
||||||
// torrent without root folder still has it in its temporary save path
|
// torrent without root folder still has it in its temporary save path
|
||||||
m_removingTorrents[torrent->hash()] = {torrent->name(), {torrent->actualStorageLocation()}, deleteOption};
|
rootPath = torrent->actualStorageLocation();
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_removingTorrents[torrent->hash()] = {torrent->name(), {}, deleteOption};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_removingTorrents[torrent->hash()] = {torrent->name(), rootPath, deleteOption};
|
||||||
|
|
||||||
if (m_moveStorageQueue.size() > 1) {
|
if (m_moveStorageQueue.size() > 1) {
|
||||||
// Delete "move storage job" for the deleted torrent
|
// Delete "move storage job" for the deleted torrent
|
||||||
// (note: we shouldn't delete active job)
|
// (note: we shouldn't delete active job)
|
||||||
@ -4147,14 +4114,12 @@ void Session::handleMoveTorrentStorageJobFinished(const QString &errorMessage)
|
|||||||
else {
|
else {
|
||||||
// Last job is completed for torrent that being removing, so actually remove it
|
// Last job is completed for torrent that being removing, so actually remove it
|
||||||
const lt::torrent_handle nativeHandle {finishedJob.torrentHandle};
|
const lt::torrent_handle nativeHandle {finishedJob.torrentHandle};
|
||||||
RemovingTorrentData &removingTorrentData = m_removingTorrents[nativeHandle.info_hash()];
|
const RemovingTorrentData &removingTorrentData = m_removingTorrents[nativeHandle.info_hash()];
|
||||||
if (removingTorrentData.deleteOption == Torrent) {
|
if (removingTorrentData.deleteOption == Torrent)
|
||||||
removingTorrentData.pathsToRemove = getUnwantedFilePaths(nativeHandle);
|
|
||||||
m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile);
|
m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Session::handleTorrentTrackerWarning(TorrentHandleImpl *const torrent, const QString &trackerUrl)
|
void Session::handleTorrentTrackerWarning(TorrentHandleImpl *const torrent, const QString &trackerUrl)
|
||||||
{
|
{
|
||||||
@ -4662,15 +4627,6 @@ void Session::handleTorrentRemovedAlert(const lt::torrent_removed_alert *p)
|
|||||||
const auto removingTorrentDataIter = m_removingTorrents.find(infoHash);
|
const auto removingTorrentDataIter = m_removingTorrents.find(infoHash);
|
||||||
if (removingTorrentDataIter != m_removingTorrents.end()) {
|
if (removingTorrentDataIter != m_removingTorrents.end()) {
|
||||||
if (removingTorrentDataIter->deleteOption == Torrent) {
|
if (removingTorrentDataIter->deleteOption == Torrent) {
|
||||||
// Remove unwanted and incomplete files
|
|
||||||
for (const QString &unwantedFile : asConst(removingTorrentDataIter->pathsToRemove)) {
|
|
||||||
qDebug("Removing unwanted file: %s", qUtf8Printable(unwantedFile));
|
|
||||||
Utils::Fs::forceRemove(unwantedFile);
|
|
||||||
const QString parentFolder = Utils::Fs::branchPath(unwantedFile);
|
|
||||||
qDebug("Attempt to remove parent folder (if empty): %s", qUtf8Printable(parentFolder));
|
|
||||||
QDir().rmdir(parentFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name));
|
LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name));
|
||||||
m_removingTorrents.erase(removingTorrentDataIter);
|
m_removingTorrents.erase(removingTorrentDataIter);
|
||||||
}
|
}
|
||||||
@ -4685,9 +4641,7 @@ void Session::handleTorrentDeletedAlert(const lt::torrent_deleted_alert *p)
|
|||||||
if (removingTorrentDataIter == m_removingTorrents.end())
|
if (removingTorrentDataIter == m_removingTorrents.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Q_ASSERT(removingTorrentDataIter->pathsToRemove.count() <= 1);
|
Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->pathToRemove);
|
||||||
if (!removingTorrentDataIter->pathsToRemove.isEmpty())
|
|
||||||
Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->pathsToRemove.first());
|
|
||||||
LogMsg(tr("'%1' was removed from the transfer list and hard disk.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name));
|
LogMsg(tr("'%1' was removed from the transfer list and hard disk.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name));
|
||||||
m_removingTorrents.erase(removingTorrentDataIter);
|
m_removingTorrents.erase(removingTorrentDataIter);
|
||||||
}
|
}
|
||||||
@ -4702,9 +4656,7 @@ void Session::handleTorrentDeleteFailedAlert(const lt::torrent_delete_failed_ale
|
|||||||
|
|
||||||
// libtorrent won't delete the directory if it contains files not listed in the torrent,
|
// libtorrent won't delete the directory if it contains files not listed in the torrent,
|
||||||
// so we remove the directory ourselves
|
// so we remove the directory ourselves
|
||||||
Q_ASSERT(removingTorrentDataIter->pathsToRemove.count() <= 1);
|
Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->pathToRemove);
|
||||||
if (!removingTorrentDataIter->pathsToRemove.isEmpty())
|
|
||||||
Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->pathsToRemove.first());
|
|
||||||
|
|
||||||
if (p->error) {
|
if (p->error) {
|
||||||
LogMsg(tr("'%1' was removed from the transfer list but the files couldn't be deleted. Error: %2", "'xxx.avi' was removed...")
|
LogMsg(tr("'%1' was removed from the transfer list but the files couldn't be deleted. Error: %2", "'xxx.avi' was removed...")
|
||||||
|
@ -537,7 +537,7 @@ namespace BitTorrent
|
|||||||
struct RemovingTorrentData
|
struct RemovingTorrentData
|
||||||
{
|
{
|
||||||
QString name;
|
QString name;
|
||||||
QStringList pathsToRemove;
|
QString pathToRemove;
|
||||||
DeleteOption deleteOption;
|
DeleteOption deleteOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -203,6 +203,28 @@ TorrentHandleImpl::TorrentHandleImpl(Session *session, const lt::torrent_handle
|
|||||||
if (filesCount() == 1)
|
if (filesCount() == 1)
|
||||||
m_hasRootFolder = false;
|
m_hasRootFolder = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove the following upgrade code in v.4.4
|
||||||
|
// == BEGIN UPGRADE CODE ==
|
||||||
|
const QString spath = actualStorageLocation();
|
||||||
|
for (int i = 0; i < filesCount(); ++i) {
|
||||||
|
const QString filepath = filePath(i);
|
||||||
|
// Move "unwanted" files back to their original folder
|
||||||
|
const QString parentRelPath = Utils::Fs::branchPath(filepath);
|
||||||
|
if (QDir(parentRelPath).dirName() == ".unwanted") {
|
||||||
|
const QString oldName = Utils::Fs::fileName(filepath);
|
||||||
|
const QString newRelPath = Utils::Fs::branchPath(parentRelPath);
|
||||||
|
if (newRelPath.isEmpty())
|
||||||
|
renameFile(i, oldName);
|
||||||
|
else
|
||||||
|
renameFile(i, QDir(newRelPath).filePath(oldName));
|
||||||
|
|
||||||
|
// Remove .unwanted directory if empty
|
||||||
|
qDebug() << "Attempting to remove \".unwanted\" folder at " << QDir(spath + '/' + newRelPath).absoluteFilePath(".unwanted");
|
||||||
|
QDir(spath + '/' + newRelPath).rmdir(".unwanted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// == END UPGRADE CODE ==
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentHandleImpl::~TorrentHandleImpl() {}
|
TorrentHandleImpl::~TorrentHandleImpl() {}
|
||||||
@ -2049,61 +2071,6 @@ void TorrentHandleImpl::prioritizeFiles(const QVector<DownloadPriority> &priorit
|
|||||||
qDebug() << Q_FUNC_INFO << "Changing files priorities...";
|
qDebug() << Q_FUNC_INFO << "Changing files priorities...";
|
||||||
m_nativeHandle.prioritize_files(toLTDownloadPriorities(priorities));
|
m_nativeHandle.prioritize_files(toLTDownloadPriorities(priorities));
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << "Moving unwanted files to .unwanted folder and conversely...";
|
|
||||||
const QString spath = savePath(true);
|
|
||||||
for (int i = 0; i < priorities.size(); ++i) {
|
|
||||||
const QString filepath = filePath(i);
|
|
||||||
// Move unwanted files to a .unwanted subfolder
|
|
||||||
if (priorities[i] == DownloadPriority::Ignored) {
|
|
||||||
const QString oldAbsPath = QDir(spath).absoluteFilePath(filepath);
|
|
||||||
const QString parentAbsPath = Utils::Fs::branchPath(oldAbsPath);
|
|
||||||
// Make sure the file does not already exists
|
|
||||||
if (QDir(parentAbsPath).dirName() != ".unwanted") {
|
|
||||||
const QString unwantedAbsPath = parentAbsPath + "/.unwanted";
|
|
||||||
const QString newAbsPath = unwantedAbsPath + '/' + Utils::Fs::fileName(filepath);
|
|
||||||
qDebug() << "Unwanted path is" << unwantedAbsPath;
|
|
||||||
if (QFile::exists(newAbsPath)) {
|
|
||||||
qWarning() << "File" << newAbsPath << "already exists at destination.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool created = QDir().mkpath(unwantedAbsPath);
|
|
||||||
qDebug() << "unwanted folder was created:" << created;
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
if (created) {
|
|
||||||
// Hide the folder on Windows
|
|
||||||
qDebug() << "Hiding folder (Windows)";
|
|
||||||
std::wstring winPath = Utils::Fs::toNativePath(unwantedAbsPath).toStdWString();
|
|
||||||
DWORD dwAttrs = ::GetFileAttributesW(winPath.c_str());
|
|
||||||
bool ret = ::SetFileAttributesW(winPath.c_str(), dwAttrs | FILE_ATTRIBUTE_HIDDEN);
|
|
||||||
Q_ASSERT(ret != 0); Q_UNUSED(ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
QString parentPath = Utils::Fs::branchPath(filepath);
|
|
||||||
if (!parentPath.isEmpty() && !parentPath.endsWith('/'))
|
|
||||||
parentPath += '/';
|
|
||||||
renameFile(i, parentPath + ".unwanted/" + Utils::Fs::fileName(filepath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move wanted files back to their original folder
|
|
||||||
if (priorities[i] > DownloadPriority::Ignored) {
|
|
||||||
const QString parentRelPath = Utils::Fs::branchPath(filepath);
|
|
||||||
if (QDir(parentRelPath).dirName() == ".unwanted") {
|
|
||||||
const QString oldName = Utils::Fs::fileName(filepath);
|
|
||||||
const QString newRelPath = Utils::Fs::branchPath(parentRelPath);
|
|
||||||
if (newRelPath.isEmpty())
|
|
||||||
renameFile(i, oldName);
|
|
||||||
else
|
|
||||||
renameFile(i, QDir(newRelPath).filePath(oldName));
|
|
||||||
|
|
||||||
// Remove .unwanted directory if empty
|
|
||||||
qDebug() << "Attempting to remove .unwanted folder at " << QDir(spath + '/' + newRelPath).absoluteFilePath(".unwanted");
|
|
||||||
QDir(spath + '/' + newRelPath).rmdir(".unwanted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore first/last piece first option if necessary
|
// Restore first/last piece first option if necessary
|
||||||
if (firstLastPieceFirst)
|
if (firstLastPieceFirst)
|
||||||
setFirstLastPiecePriorityImpl(true, priorities);
|
setFirstLastPiecePriorityImpl(true, priorities);
|
||||||
|
@ -161,8 +161,3 @@ QString PieceAvailabilityBar::simpleToolTipText() const
|
|||||||
return tr("White: Unavailable pieces") + '\n'
|
return tr("White: Unavailable pieces") + '\n'
|
||||||
+ tr("Blue: Available pieces") + '\n';
|
+ tr("Blue: Available pieces") + '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PieceAvailabilityBar::isFileNameCorrectionNeeded() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
@ -48,7 +48,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool updateImage(QImage &image) override;
|
bool updateImage(QImage &image) override;
|
||||||
QString simpleToolTipText() const override;
|
QString simpleToolTipText() const override;
|
||||||
bool isFileNameCorrectionNeeded() const override;
|
|
||||||
|
|
||||||
// last used int vector, uses to better resize redraw
|
// last used int vector, uses to better resize redraw
|
||||||
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster
|
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster
|
||||||
|
@ -276,12 +276,8 @@ void PiecesBar::showToolTip(const QHelpEvent *e)
|
|||||||
|
|
||||||
DetailedTooltipRenderer renderer(stream, tooltipTitle);
|
DetailedTooltipRenderer renderer(stream, tooltipTitle);
|
||||||
|
|
||||||
const bool isFileNameCorrectionNeeded = this->isFileNameCorrectionNeeded();
|
|
||||||
for (int f : files) {
|
for (int f : files) {
|
||||||
QString filePath {m_torrent->info().filePath(f)};
|
const QString filePath {m_torrent->info().filePath(f)};
|
||||||
if (isFileNameCorrectionNeeded)
|
|
||||||
filePath.replace(QLatin1String("/.unwanted"), QString());
|
|
||||||
|
|
||||||
renderer(Utils::Misc::friendlyUnit(m_torrent->info().fileSize(f)), filePath);
|
renderer(Utils::Misc::friendlyUnit(m_torrent->info().fileSize(f)), filePath);
|
||||||
}
|
}
|
||||||
stream << "</body></html>";
|
stream << "</body></html>";
|
||||||
@ -333,8 +329,3 @@ void PiecesBar::updatePieceColors()
|
|||||||
m_pieceColors[i] = mixTwoColors(backgroundColor().rgb(), m_pieceColor.rgb(), ratio);
|
m_pieceColors[i] = mixTwoColors(backgroundColor().rgb(), m_pieceColor.rgb(), ratio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PiecesBar::isFileNameCorrectionNeeded() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
@ -83,9 +83,6 @@ private:
|
|||||||
|
|
||||||
virtual QString simpleToolTipText() const = 0;
|
virtual QString simpleToolTipText() const = 0;
|
||||||
|
|
||||||
/// whether to perform removing of ".unwanted" directory from paths
|
|
||||||
virtual bool isFileNameCorrectionNeeded() const;
|
|
||||||
|
|
||||||
// draw new image to replace the actual image
|
// draw new image to replace the actual image
|
||||||
// returns true if image was successfully updated
|
// returns true if image was successfully updated
|
||||||
virtual bool updateImage(QImage &image) = 0;
|
virtual bool updateImage(QImage &image) = 0;
|
||||||
|
@ -458,9 +458,6 @@ void TorrentContentModel::setupModelData(const BitTorrent::TorrentInfo &info)
|
|||||||
pathFolders.removeLast();
|
pathFolders.removeLast();
|
||||||
|
|
||||||
for (const QStringRef &pathPartRef : asConst(pathFolders)) {
|
for (const QStringRef &pathPartRef : asConst(pathFolders)) {
|
||||||
if (pathPartRef == QLatin1String(".unwanted"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const QString pathPart = pathPartRef.toString();
|
const QString pathPart = pathPartRef.toString();
|
||||||
TorrentContentModelFolder *newParent = currentParent->childFolderWithName(pathPart);
|
TorrentContentModelFolder *newParent = currentParent->childFolderWithName(pathPart);
|
||||||
if (!newParent) {
|
if (!newParent) {
|
||||||
|
Loading…
Reference in New Issue
Block a user