From e538eae726e89e3782f8412c2dc38d26f5b69004 Mon Sep 17 00:00:00 2001 From: toster Date: Sat, 14 Apr 2018 03:24:08 +0300 Subject: [PATCH 1/3] Make alignment optimization optional Disabling alignment optimization allows preserving file order in torrent files and closes #5652 --- src/base/bittorrent/torrentcreatorthread.cpp | 3 ++- src/base/bittorrent/torrentcreatorthread.h | 1 + src/gui/torrentcreatordlg.cpp | 6 +++++- src/gui/torrentcreatordlg.h | 1 + src/gui/torrentcreatordlg.ui | 11 +++++++++++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/base/bittorrent/torrentcreatorthread.cpp b/src/base/bittorrent/torrentcreatorthread.cpp index aaec19324..e5f92a7c2 100644 --- a/src/base/bittorrent/torrentcreatorthread.cpp +++ b/src/base/bittorrent/torrentcreatorthread.cpp @@ -92,7 +92,8 @@ void TorrentCreatorThread::run() if (isInterruptionRequested()) return; - libt::create_torrent newTorrent(fs, m_params.pieceSize); + libt::create_torrent newTorrent(fs, m_params.pieceSize, -1 + , (m_params.isAlignmentOptimized ? libt::create_torrent::optimize_alignment : 0)); // Add url seeds foreach (QString seed, m_params.urlSeeds) { diff --git a/src/base/bittorrent/torrentcreatorthread.h b/src/base/bittorrent/torrentcreatorthread.h index 58785cfa2..2f32db4d4 100644 --- a/src/base/bittorrent/torrentcreatorthread.h +++ b/src/base/bittorrent/torrentcreatorthread.h @@ -39,6 +39,7 @@ namespace BitTorrent struct TorrentCreatorParams { bool isPrivate; + bool isAlignmentOptimized; int pieceSize; QString inputPath; QString savePath; diff --git a/src/gui/torrentcreatordlg.cpp b/src/gui/torrentcreatordlg.cpp index 793f31f66..3c3b5bd1c 100644 --- a/src/gui/torrentcreatordlg.cpp +++ b/src/gui/torrentcreatordlg.cpp @@ -55,6 +55,7 @@ TorrentCreatorDlg::TorrentCreatorDlg(QWidget *parent, const QString &defaultPath , m_storePrivateTorrent(SETTINGS_KEY("PrivateTorrent")) , m_storeStartSeeding(SETTINGS_KEY("StartSeeding")) , m_storeIgnoreRatio(SETTINGS_KEY("IgnoreRatio")) + , m_storeOptimizeAlignment(SETTINGS_KEY("OptimizeAlignment"), true) , m_storeLastAddPath(SETTINGS_KEY("LastAddPath"), QDir::homePath()) , m_storeTrackerList(SETTINGS_KEY("TrackerList")) , m_storeWebSeedList(SETTINGS_KEY("WebSeedList")) @@ -169,7 +170,8 @@ void TorrentCreatorDlg::onCreateButtonClicked() const QString source = m_ui->lineEditSource->text(); // run the creator thread - m_creatorThread->create({ m_ui->checkPrivate->isChecked(), getPieceSize() + m_creatorThread->create({ m_ui->checkPrivate->isChecked() + , m_ui->checkOptimizeAlignment->isChecked(), getPieceSize() , input, destination, comment, source, trackers, urlSeeds }); } @@ -241,6 +243,7 @@ void TorrentCreatorDlg::saveSettings() m_storePrivateTorrent = m_ui->checkPrivate->isChecked(); m_storeStartSeeding = m_ui->checkStartSeeding->isChecked(); m_storeIgnoreRatio = m_ui->checkIgnoreShareLimits->isChecked(); + m_storeOptimizeAlignment = m_ui->checkOptimizeAlignment->isChecked(); m_storeTrackerList = m_ui->trackersList->toPlainText(); m_storeWebSeedList = m_ui->URLSeedsList->toPlainText(); @@ -258,6 +261,7 @@ void TorrentCreatorDlg::loadSettings() m_ui->checkPrivate->setChecked(m_storePrivateTorrent); m_ui->checkStartSeeding->setChecked(m_storeStartSeeding); m_ui->checkIgnoreShareLimits->setChecked(m_storeIgnoreRatio); + m_ui->checkOptimizeAlignment->setChecked(m_storeOptimizeAlignment); m_ui->checkIgnoreShareLimits->setEnabled(m_ui->checkStartSeeding->isChecked()); m_ui->trackersList->setPlainText(m_storeTrackerList); diff --git a/src/gui/torrentcreatordlg.h b/src/gui/torrentcreatordlg.h index 514dedf0c..48c9eacc3 100644 --- a/src/gui/torrentcreatordlg.h +++ b/src/gui/torrentcreatordlg.h @@ -80,6 +80,7 @@ private: CachedSettingValue m_storePrivateTorrent; CachedSettingValue m_storeStartSeeding; CachedSettingValue m_storeIgnoreRatio; + CachedSettingValue m_storeOptimizeAlignment; CachedSettingValue m_storeLastAddPath; CachedSettingValue m_storeTrackerList; CachedSettingValue m_storeWebSeedList; diff --git a/src/gui/torrentcreatordlg.ui b/src/gui/torrentcreatordlg.ui index 7ac6cbf59..b4238661d 100644 --- a/src/gui/torrentcreatordlg.ui +++ b/src/gui/torrentcreatordlg.ui @@ -224,6 +224,16 @@ + + + + Optimize alignment + + + true + + + @@ -329,6 +339,7 @@ checkPrivate checkStartSeeding checkIgnoreShareLimits + checkOptimizeAlignment trackersList URLSeedsList txtComment From c4625f50a8e34fede444ab27dd8987101c3bba43 Mon Sep 17 00:00:00 2001 From: toster Date: Sat, 14 Apr 2018 20:00:08 +0300 Subject: [PATCH 2/3] Pass isAlignmentOptimized flag to piece size calculation --- src/base/bittorrent/torrentcreatorthread.cpp | 5 +++-- src/base/bittorrent/torrentcreatorthread.h | 2 +- src/gui/torrentcreatordlg.cpp | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/base/bittorrent/torrentcreatorthread.cpp b/src/base/bittorrent/torrentcreatorthread.cpp index e5f92a7c2..d59feefd7 100644 --- a/src/base/bittorrent/torrentcreatorthread.cpp +++ b/src/base/bittorrent/torrentcreatorthread.cpp @@ -157,12 +157,13 @@ void TorrentCreatorThread::run() } } -int TorrentCreatorThread::calculateTotalPieces(const QString &inputPath, const int pieceSize) +int TorrentCreatorThread::calculateTotalPieces(const QString &inputPath, const int pieceSize, const bool isAlignmentOptimized) { if (inputPath.isEmpty()) return 0; libt::file_storage fs; libt::add_files(fs, Utils::Fs::toNativePath(inputPath).toStdString(), fileFilter); - return libt::create_torrent(fs, pieceSize).num_pieces(); + return libt::create_torrent(fs, pieceSize, -1 + , (isAlignmentOptimized ? libt::create_torrent::optimize_alignment : 0)).num_pieces(); } diff --git a/src/base/bittorrent/torrentcreatorthread.h b/src/base/bittorrent/torrentcreatorthread.h index 2f32db4d4..5704315be 100644 --- a/src/base/bittorrent/torrentcreatorthread.h +++ b/src/base/bittorrent/torrentcreatorthread.h @@ -59,7 +59,7 @@ namespace BitTorrent void create(const TorrentCreatorParams ¶ms); - static int calculateTotalPieces(const QString &inputPath, const int pieceSize); + static int calculateTotalPieces(const QString &inputPath, const int pieceSize, const bool isAlignmentOptimized); protected: void run(); diff --git a/src/gui/torrentcreatordlg.cpp b/src/gui/torrentcreatordlg.cpp index 3c3b5bd1c..fa1e8b2e2 100644 --- a/src/gui/torrentcreatordlg.cpp +++ b/src/gui/torrentcreatordlg.cpp @@ -215,8 +215,9 @@ void TorrentCreatorDlg::updateProgressBar(int progress) void TorrentCreatorDlg::updatePiecesCount() { const QString path = m_ui->textInputPath->text().trimmed(); + const bool isAlignmentOptimized = m_ui->checkOptimizeAlignment->isChecked(); - const int count = BitTorrent::TorrentCreatorThread::calculateTotalPieces(path, getPieceSize()); + const int count = BitTorrent::TorrentCreatorThread::calculateTotalPieces(path, getPieceSize(), isAlignmentOptimized); m_ui->labelTotalPieces->setText(QString::number(count)); } From 970ad7cf284894b7bd6e7c8b98729baee419536c Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 14 Apr 2018 14:50:28 +0800 Subject: [PATCH 3/3] Sort filenames when creating torrent First all dir paths are retrieved, then filenames in each path are retrieved and sorted, then concatenate the sorted filenames together. --- src/base/bittorrent/torrentcreatorthread.cpp | 46 ++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/base/bittorrent/torrentcreatorthread.cpp b/src/base/bittorrent/torrentcreatorthread.cpp index d59feefd7..bb2dfecab 100644 --- a/src/base/bittorrent/torrentcreatorthread.cpp +++ b/src/base/bittorrent/torrentcreatorthread.cpp @@ -38,8 +38,12 @@ #include #include +#include #include +#include +#include +#include "base/global.h" #include "base/utils/fs.h" #include "base/utils/misc.h" #include "base/utils/string.h" @@ -86,9 +90,46 @@ void TorrentCreatorThread::run() emit updateProgress(0); try { - libt::file_storage fs; + const QString parentPath = Utils::Fs::branchPath(m_params.inputPath) + "/"; + // Adding files to the torrent - libt::add_files(fs, Utils::Fs::toNativePath(m_params.inputPath).toStdString(), fileFilter); + libt::file_storage fs; + if (QFileInfo(m_params.inputPath).isFile()) { + libt::add_files(fs, Utils::Fs::toNativePath(m_params.inputPath).toStdString(), fileFilter); + } + else { + // need to sort the file names by natural sort order + QStringList dirs = {m_params.inputPath}; + + QDirIterator dirIter(m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories); + while (dirIter.hasNext()) { + dirIter.next(); + dirs += dirIter.filePath(); + } + std::sort(dirs.begin(), dirs.end(), Utils::String::naturalLessThan); + + QStringList fileNames; + QHash fileSizeMap; + + for (const auto &dir : qAsConst(dirs)) { + QStringList tmpNames; // natural sort files within each dir + + QDirIterator fileIter(dir, QDir::Files); + while (fileIter.hasNext()) { + fileIter.next(); + + const QString relFilePath = fileIter.filePath().mid(parentPath.length()); + tmpNames += relFilePath; + fileSizeMap[relFilePath] = fileIter.fileInfo().size(); + } + + std::sort(tmpNames.begin(), tmpNames.end(), Utils::String::naturalLessThan); + fileNames += tmpNames; + } + + for (const auto &fileName : qAsConst(fileNames)) + fs.add_file(fileName.toStdString(), fileSizeMap[fileName]); + } if (isInterruptionRequested()) return; @@ -113,7 +154,6 @@ void TorrentCreatorThread::run() if (isInterruptionRequested()) return; // calculate the hash for all pieces - const QString parentPath = Utils::Fs::branchPath(m_params.inputPath) + "/"; libt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString() , [this, &newTorrent](const int n) { sendProgressSignal(n, newTorrent.num_pieces()); }); // Set qBittorrent as creator and add user comment to