Browse Source

Merge pull request #5465 from glassez/strip_root_folder_v2

Allow to strip root folder. Closes #588, closes #5433
adaptive-webui-19844
sledgehammer999 8 years ago committed by GitHub
parent
commit
d702b32e53
  1. 19
      src/base/bittorrent/session.cpp
  2. 4
      src/base/bittorrent/session.h
  3. 29
      src/base/bittorrent/torrenthandle.cpp
  4. 10
      src/base/bittorrent/torrenthandle.h
  5. 20
      src/base/bittorrent/torrentinfo.cpp
  6. 1
      src/base/bittorrent/torrentinfo.h
  7. 8
      src/gui/addnewtorrentdialog.cpp
  8. 28
      src/gui/addnewtorrentdialog.ui
  9. 3
      src/gui/optionsdlg.cpp
  10. 10
      src/gui/optionsdlg.ui
  11. 3
      src/gui/properties/propertieswidget.cpp

19
src/base/bittorrent/session.cpp

@ -244,6 +244,7 @@ Session::Session(QObject *parent) @@ -244,6 +244,7 @@ Session::Session(QObject *parent)
, m_additionalTrackers(BITTORRENT_SESSION_KEY("AdditionalTrackers"))
, m_globalMaxRatio(BITTORRENT_SESSION_KEY("GlobalMaxRatio"), -1, [](qreal r) { return r < 0 ? -1. : r;})
, m_isAddTorrentPaused(BITTORRENT_SESSION_KEY("AddTorrentPaused"), false)
, m_isCreateTorrentSubfolder(BITTORRENT_SESSION_KEY("CreateTorrentSubfolder"), true)
, m_isAppendExtensionEnabled(BITTORRENT_SESSION_KEY("AddExtensionToIncompleteFiles"), false)
, m_refreshInterval(BITTORRENT_SESSION_KEY("RefreshInterval"), 1500)
, m_isPreallocationEnabled(BITTORRENT_SESSION_KEY("Preallocation"), false)
@ -1405,7 +1406,9 @@ bool Session::deleteTorrent(const QString &hash, bool deleteLocalFiles) @@ -1405,7 +1406,9 @@ bool Session::deleteTorrent(const QString &hash, bool deleteLocalFiles)
// Remove it from session
if (deleteLocalFiles) {
m_savePathsToRemove[torrent->hash()] = torrent->rootPath(true);
QString rootPath = torrent->rootPath(true);
if (!rootPath.isEmpty())
m_savePathsToRemove[torrent->hash()] = rootPath;
m_nativeSession->remove_torrent(torrent->nativeHandle(), libt::session::delete_files);
}
else {
@ -1652,6 +1655,9 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri @@ -1652,6 +1655,9 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
p = magnetUri.addTorrentParams();
}
else if (torrentInfo.isValid()) {
if (!addData.resumed && !addData.hasRootFolder)
torrentInfo.stripRootFolder();
// Metadata
if (!addData.resumed && !addData.hasSeedStatus)
findIncompleteFiles(torrentInfo, savePath);
@ -3248,6 +3254,16 @@ void Session::getPendingAlerts(std::vector<libt::alert *> &out, ulong time) @@ -3248,6 +3254,16 @@ void Session::getPendingAlerts(std::vector<libt::alert *> &out, ulong time)
#endif
}
bool Session::isCreateTorrentSubfolder() const
{
return m_isCreateTorrentSubfolder;
}
void Session::setCreateTorrentSubfolder(bool value)
{
m_isCreateTorrentSubfolder = value;
}
// Read alerts sent by the BitTorrent session
void Session::readAlerts()
{
@ -3646,6 +3662,7 @@ namespace @@ -3646,6 +3662,7 @@ namespace
torrentData.name = QString::fromStdString(fast.dict_find_string_value("qBt-name"));
torrentData.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus");
torrentData.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled");
torrentData.hasRootFolder = fast.dict_find_int_value("qBt-hasRootFolder");
magnetUri = MagnetUri(QString::fromStdString(fast.dict_find_string_value("qBt-magnetUri")));
torrentData.addPaused = fast.dict_find_int_value("qBt-paused");

4
src/base/bittorrent/session.h

@ -147,6 +147,7 @@ namespace BitTorrent @@ -147,6 +147,7 @@ namespace BitTorrent
QVector<int> filePriorities; // used if TorrentInfo is set
bool ignoreShareRatio = false;
bool skipChecking = false;
bool createSubfolder = true;
};
struct TorrentStatusReport
@ -221,6 +222,8 @@ namespace BitTorrent @@ -221,6 +222,8 @@ namespace BitTorrent
void setPeXEnabled(bool enabled);
bool isAddTorrentPaused() const;
void setAddTorrentPaused(bool value);
bool isCreateTorrentSubfolder() const;
void setCreateTorrentSubfolder(bool value);
bool isTrackerEnabled() const;
void setTrackerEnabled(bool enabled);
bool isAppendExtensionEnabled() const;
@ -538,6 +541,7 @@ namespace BitTorrent @@ -538,6 +541,7 @@ namespace BitTorrent
CachedSettingValue<QString> m_additionalTrackers;
CachedSettingValue<qreal> m_globalMaxRatio;
CachedSettingValue<bool> m_isAddTorrentPaused;
CachedSettingValue<bool> m_isCreateTorrentSubfolder;
CachedSettingValue<bool> m_isAppendExtensionEnabled;
CachedSettingValue<uint> m_refreshInterval;
CachedSettingValue<bool> m_isPreallocationEnabled;

29
src/base/bittorrent/torrenthandle.cpp

@ -89,6 +89,7 @@ AddTorrentData::AddTorrentData(const AddTorrentParams &params) @@ -89,6 +89,7 @@ AddTorrentData::AddTorrentData(const AddTorrentParams &params)
, sequential(params.sequential)
, hasSeedStatus(params.skipChecking) // do not react on 'torrent_finished_alert' when skipping
, skipChecking(params.skipChecking)
, hasRootFolder(params.createSubfolder)
, addForced(params.addForced)
, addPaused(params.addPaused)
, filePriorities(params.filePriorities)
@ -199,6 +200,7 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle @@ -199,6 +200,7 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
, m_ratioLimit(data.ratioLimit)
, m_tempPathDisabled(data.disableTempPath)
, m_hasMissingFiles(false)
, m_hasRootFolder(data.hasRootFolder)
, m_pauseAfterRecheck(false)
, m_needSaveResumeData(false)
{
@ -208,8 +210,13 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle @@ -208,8 +210,13 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
updateStatus();
m_hash = InfoHash(m_nativeStatus.info_hash);
if (!data.resumed)
if (!data.resumed) {
setSequentialDownload(data.sequential);
if (hasMetadata()) {
if (filesCount() == 1)
m_hasRootFolder = false;
}
}
}
TorrentHandle::~TorrentHandle() {}
@ -230,6 +237,9 @@ QString TorrentHandle::name() const @@ -230,6 +237,9 @@ QString TorrentHandle::name() const
if (name.isEmpty())
name = QString::fromStdString(m_nativeStatus.name);
if (name.isEmpty() && hasMetadata())
name = QString::fromStdString(m_torrentInfo.nativeInfo()->orig_files().name());
if (name.isEmpty())
name = m_hash;
@ -302,6 +312,9 @@ QString TorrentHandle::savePath(bool actual) const @@ -302,6 +312,9 @@ QString TorrentHandle::savePath(bool actual) const
QString TorrentHandle::rootPath(bool actual) const
{
if ((filesCount() > 1) && !hasRootFolder())
return QString();
QString firstFilePath = filePath(0);
const int slashIndex = firstFilePath.indexOf("/");
if (slashIndex >= 0)
@ -314,8 +327,10 @@ QString TorrentHandle::contentPath(bool actual) const @@ -314,8 +327,10 @@ QString TorrentHandle::contentPath(bool actual) const
{
if (filesCount() == 1)
return QDir(savePath(actual)).absoluteFilePath(filePath(0));
else
else if (hasRootFolder())
return rootPath(actual);
else
return savePath(actual);
}
bool TorrentHandle::isAutoTMMEnabled() const
@ -334,6 +349,11 @@ void TorrentHandle::setAutoTMMEnabled(bool enabled) @@ -334,6 +349,11 @@ void TorrentHandle::setAutoTMMEnabled(bool enabled)
move_impl(m_session->categorySavePath(m_category));
}
bool TorrentHandle::hasRootFolder() const
{
return m_hasRootFolder;
}
QString TorrentHandle::nativeActualSavePath() const
{
return QString::fromStdString(m_nativeStatus.save_path);
@ -1489,6 +1509,7 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert @@ -1489,6 +1509,7 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert
resumeData["qBt-seedStatus"] = m_hasSeedStatus;
resumeData["qBt-tempPathDisabled"] = m_tempPathDisabled;
resumeData["qBt-queuePosition"] = queuePosition();
resumeData["qBt-hasRootFolder"] = m_hasRootFolder;
m_session->handleTorrentResumeDataReady(this, resumeData);
}
@ -1590,6 +1611,10 @@ void TorrentHandle::handleMetadataReceivedAlert(libt::metadata_received_alert *p @@ -1590,6 +1611,10 @@ void TorrentHandle::handleMetadataReceivedAlert(libt::metadata_received_alert *p
updateStatus();
if (m_session->isAppendExtensionEnabled())
manageIncompleteFiles();
if (!m_hasRootFolder)
m_torrentInfo.stripRootFolder();
if (filesCount() == 1)
m_hasRootFolder = false;
m_session->handleTorrentMetadataReceived(this);
if (isPaused()) {

10
src/base/bittorrent/torrenthandle.h

@ -98,6 +98,7 @@ namespace BitTorrent @@ -98,6 +98,7 @@ namespace BitTorrent
bool sequential;
bool hasSeedStatus;
bool skipChecking;
bool hasRootFolder;
TriStateBool addForced;
TriStateBool addPaused;
// for new torrents
@ -206,6 +207,9 @@ namespace BitTorrent @@ -206,6 +207,9 @@ namespace BitTorrent
// file4
//
//
// Torrent A* (Torrent A in "strip root folder" mode)
//
//
// Torrent B (singlefile)
//
// torrentB/
@ -222,6 +226,7 @@ namespace BitTorrent @@ -222,6 +226,7 @@ namespace BitTorrent
// | | rootPath | contentPath |
// |---|------------------------------|--------------------------------------------|
// | A | /home/user/torrents/torrentA | /home/user/torrents/torrentA |
// | A*| <empty> | /home/user/torrents |
// | B | /home/user/torrents/torrentB | /home/user/torrents/torrentB/subdir1/file1 |
// | C | /home/user/torrents/file1 | /home/user/torrents/file1 |
@ -235,6 +240,8 @@ namespace BitTorrent @@ -235,6 +240,8 @@ namespace BitTorrent
bool belongsToCategory(const QString &category) const;
bool setCategory(const QString &category);
bool hasRootFolder() const;
int filesCount() const;
int piecesCount() const;
int piecesHave() const;
@ -395,7 +402,7 @@ namespace BitTorrent @@ -395,7 +402,7 @@ namespace BitTorrent
Session *const m_session;
libtorrent::torrent_handle m_nativeHandle;
libtorrent::torrent_status m_nativeStatus;
TorrentState m_state;
TorrentState m_state;
TorrentInfo m_torrentInfo;
SpeedMonitor m_speedMonitor;
@ -421,6 +428,7 @@ namespace BitTorrent @@ -421,6 +428,7 @@ namespace BitTorrent
qreal m_ratioLimit;
bool m_tempPathDisabled;
bool m_hasMissingFiles;
bool m_hasRootFolder;
bool m_pauseAfterRecheck;
bool m_needSaveResumeData;

20
src/base/bittorrent/torrentinfo.cpp

@ -279,7 +279,7 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(int fileIndex) const @@ -279,7 +279,7 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(int fileIndex) const
void TorrentInfo::renameFile(uint index, const QString &newPath)
{
if (!isValid()) return;
nativeInfo()->rename_file(index, newPath.toStdString());
nativeInfo()->rename_file(index, Utils::Fs::toNativePath(newPath).toStdString());
}
int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
@ -293,6 +293,24 @@ int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const @@ -293,6 +293,24 @@ int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
return -1;
}
void TorrentInfo::stripRootFolder()
{
if (filesCount() <= 1) return;
libtorrent::file_storage files = m_nativeInfo->files();
// Solution for case of renamed root folder
std::string testName = filePath(0).split('/').value(0).toStdString();
if (files.name() != testName) {
files.set_name(testName);
for (int i = 0; i < files.num_files(); ++i)
files.rename_file(i, files.file_path(i));
}
files.set_name("");
m_nativeInfo->remap_files(files);
}
TorrentInfo::NativePtr TorrentInfo::nativeInfo() const
{
return m_nativeInfo;

1
src/base/bittorrent/torrentinfo.h

@ -99,6 +99,7 @@ namespace BitTorrent @@ -99,6 +99,7 @@ namespace BitTorrent
PieceRange filePieces(int fileIndex) const;
void renameFile(uint index, const QString &newPath);
void stripRootFolder();
NativePtr nativeInfo() const;

8
src/gui/addnewtorrentdialog.cpp

@ -35,6 +35,7 @@ @@ -35,6 +35,7 @@
#include <QMenu>
#include <QFileDialog>
#include "base/preferences.h"
#include "base/settingsstorage.h"
#include "base/net/downloadmanager.h"
#include "base/net/downloadhandler.h"
@ -95,6 +96,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent) @@ -95,6 +96,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
connect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onSavePathChanged(int)));
connect(ui->browseButton, SIGNAL(clicked()), SLOT(browseButton_clicked()));
ui->defaultSavePathCheckBox->setVisible(false); // Default path is selected by default
ui->createSubfolderCheckBox->setChecked(session->isCreateTorrentSubfolder());
ui->doNotDeleteTorrentCheckBox->setVisible(TorrentFileGuard::autoDeleteMode() != TorrentFileGuard::Never);
@ -624,9 +626,8 @@ void AddNewTorrentDialog::accept() @@ -624,9 +626,8 @@ void AddNewTorrentDialog::accept()
BitTorrent::AddTorrentParams params;
if (ui->skip_check_cb->isChecked())
// TODO: Check if destination actually exists
params.skipChecking = true;
// TODO: Check if destination actually exists
params.skipChecking = ui->skipCheckingCheckBox->isChecked();
// Category
params.category = ui->categoryComboBox->currentText();
@ -639,6 +640,7 @@ void AddNewTorrentDialog::accept() @@ -639,6 +640,7 @@ void AddNewTorrentDialog::accept()
params.filePriorities = m_contentModel->model()->getFilePriorities();
params.addPaused = !ui->startTorrentCheckBox->isChecked();
params.createSubfolder = ui->createSubfolderCheckBox->isChecked();
QString savePath = ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString();
if (ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.

28
src/gui/addnewtorrentdialog.ui

@ -170,7 +170,7 @@ @@ -170,7 +170,7 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="skip_check_cb">
<widget class="QCheckBox" name="skipCheckingCheckBox">
<property name="text">
<string>Skip hash check</string>
</property>
@ -192,6 +192,26 @@ @@ -192,6 +192,26 @@
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="startTorrentCheckBox_2">
<property name="text">
<string>Start torrent</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="createSubfolderCheckBox">
<property name="text">
<string>Create subfolder</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -285,8 +305,8 @@ @@ -285,8 +305,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>308</width>
<height>74</height>
<width>321</width>
<height>69</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -403,7 +423,7 @@ @@ -403,7 +423,7 @@
<tabstop>never_show_cb</tabstop>
<tabstop>adv_button</tabstop>
<tabstop>startTorrentCheckBox</tabstop>
<tabstop>skip_check_cb</tabstop>
<tabstop>skipCheckingCheckBox</tabstop>
<tabstop>categoryComboBox</tabstop>
<tabstop>defaultCategoryCheckbox</tabstop>
<tabstop>scrollArea</tabstop>

3
src/gui/optionsdlg.cpp

@ -214,6 +214,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) @@ -214,6 +214,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
connect(m_ui->checkAdditionDialog, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(m_ui->checkAdditionDialogFront, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(m_ui->checkStartPaused, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(m_ui->checkCreateSubfolder, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(m_ui->deleteTorrentBox, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(m_ui->deleteCancelledTorrentBox, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
connect(m_ui->checkExportDir, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
@ -515,6 +516,7 @@ void OptionsDialog::saveOptions() @@ -515,6 +516,7 @@ void OptionsDialog::saveOptions()
AddNewTorrentDialog::setEnabled(useAdditionDialog());
AddNewTorrentDialog::setTopLevel(m_ui->checkAdditionDialogFront->isChecked());
session->setAddTorrentPaused(addTorrentsInPause());
session->setCreateTorrentSubfolder(m_ui->checkCreateSubfolder->isChecked());
ScanFoldersModel::instance()->removeFromFSWatcher(removedScanDirs);
ScanFoldersModel::instance()->addToFSWatcher(addedScanDirs);
ScanFoldersModel::instance()->makePersistent();
@ -716,6 +718,7 @@ void OptionsDialog::loadOptions() @@ -716,6 +718,7 @@ void OptionsDialog::loadOptions()
m_ui->checkAdditionDialog->setChecked(AddNewTorrentDialog::isEnabled());
m_ui->checkAdditionDialogFront->setChecked(AddNewTorrentDialog::isTopLevel());
m_ui->checkStartPaused->setChecked(session->isAddTorrentPaused());
m_ui->checkCreateSubfolder->setChecked(session->isCreateTorrentSubfolder());
const TorrentFileGuard::AutoDeleteMode autoDeleteMode = TorrentFileGuard::autoDeleteMode();
m_ui->deleteTorrentBox->setChecked(autoDeleteMode != TorrentFileGuard::Never);
m_ui->deleteCancelledTorrentBox->setChecked(autoDeleteMode == TorrentFileGuard::Always);

10
src/gui/optionsdlg.ui

@ -709,6 +709,16 @@ @@ -709,6 +709,16 @@
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkCreateSubfolder">
<property name="text">
<string>Create subfolder for torrents with multiple files</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkStartPaused">
<property name="text">

3
src/gui/properties/propertieswidget.cpp

@ -316,7 +316,8 @@ void PropertiesWidget::loadTorrentInfos(BitTorrent::TorrentHandle *const torrent @@ -316,7 +316,8 @@ void PropertiesWidget::loadTorrentInfos(BitTorrent::TorrentHandle *const torrent
// List files in torrent
PropListModel->model()->setupModelData(m_torrent->info());
filesList->setExpanded(PropListModel->index(0, 0), true);
if ((m_torrent->filesCount() > 1) && (PropListModel->model()->rowCount() == 1))
filesList->setExpanded(PropListModel->index(0, 0), true);
// Load file priorities
PropListModel->model()->updateFilesPriorities(m_torrent->filePriorities());

Loading…
Cancel
Save