Skip to content

Commit

Permalink
Keep unwanted files in separate folder
Browse files Browse the repository at this point in the history
  • Loading branch information
glassez committed Oct 31, 2023
1 parent 7bd8f26 commit e9d354e
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 45 deletions.
1 change: 1 addition & 0 deletions src/base/bittorrent/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@
#include "base/global.h"

inline const QString QB_EXT = u".!qB"_s;
inline const QString UNWANTED_FOLDER_NAME = u".unwanted"_s;
104 changes: 61 additions & 43 deletions src/base/bittorrent/torrentimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession

const auto fileIter = m_ltAddTorrentParams.renamed_files.find(nativeIndex);
const Path filePath = ((fileIter != m_ltAddTorrentParams.renamed_files.end())
? Path(fileIter->second).removedExtension(QB_EXT) : m_torrentInfo.filePath(i));
? makeUserPath(Path(fileIter->second)) : m_torrentInfo.filePath(i));
m_filePaths.append(filePath);

const auto priority = LT::fromNative(filePriorities[LT::toUnderlyingType(nativeIndex)]);
Expand All @@ -356,28 +356,6 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession

if (hasMetadata())
applyFirstLastPiecePriority(m_hasFirstLastPiecePriority);

// TODO: Remove the following upgrade code in v4.4
// == BEGIN UPGRADE CODE ==
const Path spath = actualStorageLocation();
for (int i = 0; i < filesCount(); ++i)
{
const Path filepath = filePath(i);
// Move "unwanted" files back to their original folder
const Path parentRelPath = filepath.parentPath();
if (parentRelPath.filename() == u".unwanted")
{
const QString oldName = filepath.filename();
const Path newRelPath = parentRelPath.parentPath();
renameFile(i, (newRelPath / Path(oldName)));

// Remove .unwanted directory if empty
const Path newPath = spath / newRelPath;
qDebug() << "Attempting to remove \".unwanted\" folder at " << (newPath / Path(u".unwanted"_s)).toString();
Utils::Fs::rmdir(newPath / Path(u".unwanted"_s));
}
}
// == END UPGRADE CODE ==
}

TorrentImpl::~TorrentImpl() = default;
Expand Down Expand Up @@ -581,15 +559,39 @@ void TorrentImpl::setAutoManaged(const bool enable)
m_nativeHandle.unset_flags(lt::torrent_flags::auto_managed);
}

Path TorrentImpl::wantedActualPath(int index, const Path &path) const
Path TorrentImpl::makeActualPath(int index, const Path &path) const
{
Path actualPath = path;

if (m_session->isAppendExtensionEnabled()
&& (fileSize(index) > 0) && !m_completedFiles.at(index))
{
return path + QB_EXT;
actualPath += QB_EXT;
}

return path;
if (m_filePriorities[index] == DownloadPriority::Ignored)
{
const Path parentPath = actualPath.parentPath();
const QString fileName = actualPath.filename();
actualPath = parentPath / Path(UNWANTED_FOLDER_NAME) / Path(fileName);
}

return actualPath;
}

Path TorrentImpl::makeUserPath(const Path &path) const
{
Path userPath = path.removedExtension(QB_EXT);

const Path parentRelPath = userPath.parentPath();
if (parentRelPath.filename() == UNWANTED_FOLDER_NAME)
{
const QString fileName = userPath.filename();
const Path relPath = parentRelPath.parentPath();
userPath = relPath / Path(fileName);
}

return userPath;
}

QVector<TrackerEntry> TorrentImpl::trackers() const
Expand Down Expand Up @@ -1889,8 +1891,8 @@ void TorrentImpl::renameFile(const int index, const Path &path)
if ((index < 0) || (index >= filesCount())) [[unlikely]]
return;

const Path wantedPath = wantedActualPath(index, path);
doRenameFile(index, wantedPath);
const Path targetActualPath = makeActualPath(index, path);
doRenameFile(index, targetActualPath);
}

void TorrentImpl::handleStateUpdate(const lt::torrent_status &nativeStatus)
Expand Down Expand Up @@ -1953,7 +1955,7 @@ void TorrentImpl::handleTorrentCheckedAlert([[maybe_unused]] const lt::torrent_c
m_hasFinishedStatus = true;

adjustStorageLocation();
manageIncompleteFiles();
manageActualFilePaths();

if (!isPaused())
{
Expand Down Expand Up @@ -1981,7 +1983,7 @@ void TorrentImpl::handleTorrentFinishedAlert([[maybe_unused]] const lt::torrent_
m_statusUpdatedTriggers.enqueue([this]()
{
adjustStorageLocation();
manageIncompleteFiles();
manageActualFilePaths();

m_session->handleTorrentNeedSaveResumeData(this);

Expand Down Expand Up @@ -2144,19 +2146,33 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
const int fileIndex = m_indexMap.value(p->index, -1);
Q_ASSERT(fileIndex >= 0);

// Remove empty leftover folders
// For example renaming "a/b/c" to "d/b/c", then folders "a/b" and "a" will
// be removed if they are empty
const auto newActualFilePath = Path(QString::fromUtf8(p->new_name()));

const Path oldFilePath = m_filePaths.at(fileIndex);
const Path newFilePath = Path(QString::fromUtf8(p->new_name())).removedExtension(QB_EXT);
const Path newFilePath = makeUserPath(newActualFilePath);

// Check if ".!qB" extension was just added or removed
// Check if ".!qB" extension or ".unwanted" folder was just added or removed
// We should compare path in a case sensitive manner even on case insensitive
// platforms since it can be renamed by only changing case of some character(s)
if (oldFilePath.data() != newFilePath.data())
if (oldFilePath.data() == newFilePath.data())
{
// Remove empty ".unwanted" folders
const auto oldActualFilePath = Path(QString::fromUtf8(p->old_name()));
const Path oldActualParentPath = oldActualFilePath.parentPath();
if (oldActualParentPath.filename() == UNWANTED_FOLDER_NAME)
{
Q_ASSERT(newActualFilePath.parentPath().filename() != UNWANTED_FOLDER_NAME);

Utils::Fs::rmdir(actualStorageLocation() / oldActualParentPath);
}
}
else
{
m_filePaths[fileIndex] = newFilePath;

// Remove empty leftover folders
// For example renaming "a/b/c" to "d/b/c", then folders "a/b" and "a" will
// be removed if they are empty
Path oldParentPath = oldFilePath.parentPath();
const Path commonBasePath = Path::commonPath(oldParentPath, newFilePath.parentPath());
while (oldParentPath != commonBasePath)
Expand Down Expand Up @@ -2263,7 +2279,7 @@ void TorrentImpl::handleAppendExtensionToggled()
{
if (!hasMetadata()) return;

manageIncompleteFiles();
manageActualFilePaths();
}

void TorrentImpl::handleAlert(const lt::alert *a)
Expand Down Expand Up @@ -2317,7 +2333,7 @@ void TorrentImpl::handleAlert(const lt::alert *a)
}
}

void TorrentImpl::manageIncompleteFiles()
void TorrentImpl::manageActualFilePaths()
{
const std::shared_ptr<const lt::torrent_info> nativeInfo = nativeTorrentInfo();
const lt::file_storage &nativeFiles = nativeInfo->files();
Expand All @@ -2328,11 +2344,11 @@ void TorrentImpl::manageIncompleteFiles()

const auto nativeIndex = m_torrentInfo.nativeIndexes().at(i);
const Path actualPath {nativeFiles.file_path(nativeIndex)};
const Path wantedPath = wantedActualPath(i, path);
if (actualPath != wantedPath)
const Path targetActualPath = makeActualPath(i, path);
if (actualPath != targetActualPath)
{
qDebug() << "Renaming" << actualPath.toString() << "to" << wantedPath.toString();
doRenameFile(i, wantedPath);
qDebug() << "Renaming" << actualPath.toString() << "to" << targetActualPath.toString();
doRenameFile(i, targetActualPath);
}
}
}
Expand Down Expand Up @@ -2814,7 +2830,8 @@ void TorrentImpl::fetchAvailableFileFractions(std::function<void (QVector<qreal>

void TorrentImpl::prioritizeFiles(const QVector<DownloadPriority> &priorities)
{
if (!hasMetadata()) return;
if (!hasMetadata())
return;

Q_ASSERT(priorities.size() == filesCount());

Expand Down Expand Up @@ -2845,6 +2862,7 @@ void TorrentImpl::prioritizeFiles(const QVector<DownloadPriority> &priorities)
// Restore first/last piece first option if necessary
if (m_hasFirstLastPiecePriority)
applyFirstLastPiecePriority(true);
manageActualFilePaths();
}

QVector<qreal> TorrentImpl::availableFileFractions() const
Expand Down
5 changes: 3 additions & 2 deletions src/base/bittorrent/torrentimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,11 +299,12 @@ namespace BitTorrent

void setAutoManaged(bool enable);

Path wantedActualPath(int index, const Path &path) const;
Path makeActualPath(int index, const Path &path) const;
Path makeUserPath(const Path &path) const;
void adjustStorageLocation();
void doRenameFile(int index, const Path &path);
void moveStorage(const Path &newPath, MoveStorageContext context);
void manageIncompleteFiles();
void manageActualFilePaths();
void applyFirstLastPiecePriority(bool enabled);

void prepareResumeData(const lt::add_torrent_params &params);
Expand Down

0 comments on commit e9d354e

Please sign in to comment.