mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-10-22 18:56:08 +03:00
Merge pull request #18014 from sledgehammer999/maybe_backport
Backports to v4_5_x
This commit is contained in:
commit
bff9189e52
39 changed files with 288 additions and 239 deletions
|
@ -3,7 +3,7 @@ host = https://www.transifex.com
|
|||
|
||||
[qbittorrent.qbittorrent_master]
|
||||
file_filter = src/lang/qbittorrent_<lang>.ts
|
||||
lang_map = pt: pt_PT
|
||||
lang_map = pt: pt_PT, zh: zh_CN
|
||||
source_file = src/lang/qbittorrent_en.ts
|
||||
source_lang = en
|
||||
type = QT
|
||||
|
@ -19,7 +19,7 @@ mode = developer
|
|||
|
||||
[qbittorrent.qbittorrent_webui]
|
||||
file_filter = src/webui/www/translations/webui_<lang>.ts
|
||||
lang_map = pt: pt_PT
|
||||
lang_map = pt: pt_PT, zh: zh_CN
|
||||
source_file = src/webui/www/translations/webui_en.ts
|
||||
source_lang = en
|
||||
type = QT
|
||||
|
|
|
@ -882,7 +882,7 @@ void Application::createStartupProgressDialog()
|
|||
m_startupProgressDialog = new QProgressDialog(tr("Loading torrents..."), tr("Exit"), 0, 100);
|
||||
m_startupProgressDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
m_startupProgressDialog->setWindowFlag(Qt::WindowMinimizeButtonHint);
|
||||
m_startupProgressDialog->setMinimumDuration(0); // Show dialog immediatelly by default
|
||||
m_startupProgressDialog->setMinimumDuration(0); // Show dialog immediately by default
|
||||
m_startupProgressDialog->setAutoReset(false);
|
||||
m_startupProgressDialog->setAutoClose(false);
|
||||
|
||||
|
|
|
@ -210,7 +210,6 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
|
|||
return nonstd::make_unexpected(tr("Cannot parse resume data: invalid format"));
|
||||
|
||||
LoadTorrentParams torrentParams;
|
||||
torrentParams.restored = true;
|
||||
torrentParams.category = fromLTString(resumeDataRoot.dict_find_string_value("qBt-category"));
|
||||
torrentParams.name = fromLTString(resumeDataRoot.dict_find_string_value("qBt-name"));
|
||||
torrentParams.hasSeedStatus = resumeDataRoot.dict_find_int_value("qBt-seedStatus");
|
||||
|
|
|
@ -196,7 +196,6 @@ namespace BitTorrent
|
|||
LoadTorrentParams parseQueryResultRow(const QSqlQuery &query)
|
||||
{
|
||||
LoadTorrentParams resumeData;
|
||||
resumeData.restored = true;
|
||||
resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
|
||||
resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
|
||||
const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
|
||||
|
|
|
@ -58,7 +58,5 @@ namespace BitTorrent
|
|||
|
||||
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
|
||||
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
|
||||
|
||||
bool restored = false; // is existing torrent job?
|
||||
};
|
||||
}
|
||||
|
|
|
@ -181,6 +181,31 @@ QString PeerInfo::client() const
|
|||
return QString::fromStdString(m_nativeInfo.client);
|
||||
}
|
||||
|
||||
QString PeerInfo::peerIdClient() const
|
||||
{
|
||||
// when peer ID is not known yet it contains only zero bytes,
|
||||
// do not create string in such case, return empty string instead
|
||||
if (m_nativeInfo.pid.is_all_zeros())
|
||||
return {};
|
||||
|
||||
QString result;
|
||||
|
||||
// interesting part of a typical peer ID is first 8 chars
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
const std::uint8_t c = m_nativeInfo.pid[i];
|
||||
|
||||
// ensure that the peer ID slice consists only of printable ASCII characters,
|
||||
// this should filter out most of the improper IDs
|
||||
if ((c < 32) || (c > 126))
|
||||
return tr("Unknown");
|
||||
|
||||
result += QChar::fromLatin1(c);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
qreal PeerInfo::progress() const
|
||||
{
|
||||
return m_nativeInfo.progress;
|
||||
|
|
|
@ -78,6 +78,7 @@ namespace BitTorrent
|
|||
|
||||
PeerAddress address() const;
|
||||
QString client() const;
|
||||
QString peerIdClient() const;
|
||||
qreal progress() const;
|
||||
int payloadUpSpeed() const;
|
||||
int payloadDownSpeed() const;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <libtorrent/session.hpp>
|
||||
|
||||
#include "base/algorithm.h"
|
||||
#include "base/logger.h"
|
||||
|
||||
PortForwarderImpl::PortForwarderImpl(lt::session *provider, QObject *parent)
|
||||
|
@ -63,45 +64,64 @@ void PortForwarderImpl::setEnabled(const bool enabled)
|
|||
m_storeActive = enabled;
|
||||
}
|
||||
|
||||
void PortForwarderImpl::addPort(const quint16 port)
|
||||
void PortForwarderImpl::setPorts(const QString &profile, QSet<quint16> ports)
|
||||
{
|
||||
if (m_mappedPorts.contains(port))
|
||||
return;
|
||||
|
||||
if (isEnabled())
|
||||
m_mappedPorts.insert(port, m_provider->add_port_mapping(lt::session::tcp, port, port));
|
||||
else
|
||||
m_mappedPorts.insert(port, {});
|
||||
}
|
||||
|
||||
void PortForwarderImpl::deletePort(const quint16 port)
|
||||
{
|
||||
const auto iter = m_mappedPorts.find(port);
|
||||
if (iter == m_mappedPorts.end())
|
||||
return;
|
||||
|
||||
if (isEnabled())
|
||||
PortMapping &portMapping = m_portProfiles[profile];
|
||||
Algorithm::removeIf(portMapping, [this, &ports](const quint16 port, const std::vector<lt::port_mapping_t> &handles)
|
||||
{
|
||||
for (const lt::port_mapping_t &portMapping : *iter)
|
||||
m_provider->delete_port_mapping(portMapping);
|
||||
// keep existing forwardings
|
||||
const bool isAlreadyMapped = ports.remove(port);
|
||||
if (isAlreadyMapped)
|
||||
return false;
|
||||
|
||||
// remove outdated forwardings
|
||||
for (const lt::port_mapping_t &handle : handles)
|
||||
m_provider->delete_port_mapping(handle);
|
||||
m_forwardedPorts.remove(port);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// add new forwardings
|
||||
for (const quint16 port : ports)
|
||||
{
|
||||
// port already forwarded/taken by other profile, don't do anything
|
||||
if (m_forwardedPorts.contains(port))
|
||||
continue;
|
||||
|
||||
if (isEnabled())
|
||||
portMapping.insert(port, m_provider->add_port_mapping(lt::session::tcp, port, port));
|
||||
else
|
||||
portMapping.insert(port, {});
|
||||
m_forwardedPorts.insert(port);
|
||||
}
|
||||
|
||||
m_mappedPorts.erase(iter);
|
||||
if (portMapping.isEmpty())
|
||||
m_portProfiles.remove(profile);
|
||||
}
|
||||
|
||||
void PortForwarderImpl::removePorts(const QString &profile)
|
||||
{
|
||||
setPorts(profile, {});
|
||||
}
|
||||
|
||||
void PortForwarderImpl::start()
|
||||
{
|
||||
lt::settings_pack settingsPack = m_provider->get_settings();
|
||||
lt::settings_pack settingsPack;
|
||||
settingsPack.set_bool(lt::settings_pack::enable_upnp, true);
|
||||
settingsPack.set_bool(lt::settings_pack::enable_natpmp, true);
|
||||
m_provider->apply_settings(settingsPack);
|
||||
m_provider->apply_settings(std::move(settingsPack));
|
||||
|
||||
for (auto iter = m_mappedPorts.begin(); iter != m_mappedPorts.end(); ++iter)
|
||||
for (auto profileIter = m_portProfiles.begin(); profileIter != m_portProfiles.end(); ++profileIter)
|
||||
{
|
||||
Q_ASSERT(iter.value().empty());
|
||||
PortMapping &portMapping = profileIter.value();
|
||||
for (auto iter = portMapping.begin(); iter != portMapping.end(); ++iter)
|
||||
{
|
||||
Q_ASSERT(iter.value().empty());
|
||||
|
||||
const quint16 port = iter.key();
|
||||
iter.value() = m_provider->add_port_mapping(lt::session::tcp, port, port);
|
||||
const quint16 port = iter.key();
|
||||
iter.value() = m_provider->add_port_mapping(lt::session::tcp, port, port);
|
||||
}
|
||||
}
|
||||
|
||||
LogMsg(tr("UPnP/NAT-PMP support: ON"), Log::INFO);
|
||||
|
@ -109,14 +129,18 @@ void PortForwarderImpl::start()
|
|||
|
||||
void PortForwarderImpl::stop()
|
||||
{
|
||||
lt::settings_pack settingsPack = m_provider->get_settings();
|
||||
lt::settings_pack settingsPack;
|
||||
settingsPack.set_bool(lt::settings_pack::enable_upnp, false);
|
||||
settingsPack.set_bool(lt::settings_pack::enable_natpmp, false);
|
||||
m_provider->apply_settings(settingsPack);
|
||||
m_provider->apply_settings(std::move(settingsPack));
|
||||
|
||||
// don't clear m_mappedPorts so a later `start()` call can restore the port forwarding
|
||||
for (auto iter = m_mappedPorts.begin(); iter != m_mappedPorts.end(); ++iter)
|
||||
iter.value().clear();
|
||||
// don't clear m_portProfiles so a later `start()` call can restore the port forwardings
|
||||
for (auto profileIter = m_portProfiles.begin(); profileIter != m_portProfiles.end(); ++profileIter)
|
||||
{
|
||||
PortMapping &portMapping = profileIter.value();
|
||||
for (auto iter = portMapping.begin(); iter != portMapping.end(); ++iter)
|
||||
iter.value().clear();
|
||||
}
|
||||
|
||||
LogMsg(tr("UPnP/NAT-PMP support: OFF"), Log::INFO);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <libtorrent/portmap.hpp>
|
||||
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
|
||||
#include "base/net/portforwarder.h"
|
||||
#include "base/settingvalue.h"
|
||||
|
@ -50,8 +51,8 @@ public:
|
|||
bool isEnabled() const override;
|
||||
void setEnabled(bool enabled) override;
|
||||
|
||||
void addPort(quint16 port) override;
|
||||
void deletePort(quint16 port) override;
|
||||
void setPorts(const QString &profile, QSet<quint16> ports) override;
|
||||
void removePorts(const QString &profile) override;
|
||||
|
||||
private:
|
||||
void start();
|
||||
|
@ -59,5 +60,8 @@ private:
|
|||
|
||||
CachedSettingValue<bool> m_storeActive;
|
||||
lt::session *const m_provider = nullptr;
|
||||
QHash<quint16, std::vector<lt::port_mapping_t>> m_mappedPorts;
|
||||
|
||||
using PortMapping = QHash<quint16, std::vector<lt::port_mapping_t>>; // <port, handles>
|
||||
QHash<QString, PortMapping> m_portProfiles;
|
||||
QSet<quint16> m_forwardedPorts;
|
||||
};
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
#include "base/logger.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/proxyconfigurationmanager.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/profile.h"
|
||||
#include "base/torrentfileguard.h"
|
||||
#include "base/torrentfilter.h"
|
||||
|
@ -548,8 +549,6 @@ SessionImpl::SessionImpl(QObject *parent)
|
|||
if (isExcludedFileNamesEnabled())
|
||||
populateExcludedFileNamesRegExpList();
|
||||
|
||||
enableTracker(isTrackerEnabled());
|
||||
|
||||
connect(Net::ProxyConfigurationManager::instance()
|
||||
, &Net::ProxyConfigurationManager::proxyConfigurationChanged
|
||||
, this, &SessionImpl::configureDeferred);
|
||||
|
@ -569,11 +568,14 @@ SessionImpl::SessionImpl(QObject *parent)
|
|||
|
||||
m_ioThread->start();
|
||||
|
||||
initMetrics();
|
||||
loadStatistics();
|
||||
|
||||
// initialize PortForwarder instance
|
||||
new PortForwarderImpl(m_nativeSession);
|
||||
|
||||
initMetrics();
|
||||
loadStatistics();
|
||||
// start embedded tracker
|
||||
enableTracker(isTrackerEnabled());
|
||||
|
||||
prepareStartup();
|
||||
}
|
||||
|
@ -1055,25 +1057,25 @@ void SessionImpl::adjustLimits()
|
|||
{
|
||||
if (isQueueingSystemEnabled())
|
||||
{
|
||||
lt::settings_pack settingsPack = m_nativeSession->get_settings();
|
||||
adjustLimits(settingsPack);
|
||||
m_nativeSession->apply_settings(settingsPack);
|
||||
lt::settings_pack settingsPack;
|
||||
// Internally increase the queue limits to ensure that the magnet is started
|
||||
settingsPack.set_int(lt::settings_pack::active_downloads, adjustLimit(maxActiveDownloads()));
|
||||
settingsPack.set_int(lt::settings_pack::active_limit, adjustLimit(maxActiveTorrents()));
|
||||
m_nativeSession->apply_settings(std::move(settingsPack));
|
||||
}
|
||||
}
|
||||
|
||||
void SessionImpl::applyBandwidthLimits()
|
||||
{
|
||||
lt::settings_pack settingsPack = m_nativeSession->get_settings();
|
||||
applyBandwidthLimits(settingsPack);
|
||||
m_nativeSession->apply_settings(settingsPack);
|
||||
lt::settings_pack settingsPack;
|
||||
settingsPack.set_int(lt::settings_pack::download_rate_limit, downloadSpeedLimit());
|
||||
settingsPack.set_int(lt::settings_pack::upload_rate_limit, uploadSpeedLimit());
|
||||
m_nativeSession->apply_settings(std::move(settingsPack));
|
||||
}
|
||||
|
||||
void SessionImpl::configure()
|
||||
{
|
||||
lt::settings_pack settingsPack = m_nativeSession->get_settings();
|
||||
loadLTSettings(settingsPack);
|
||||
m_nativeSession->apply_settings(settingsPack);
|
||||
|
||||
m_nativeSession->apply_settings(loadLTSettings());
|
||||
configureComponents();
|
||||
|
||||
m_deferredConfigureScheduled = false;
|
||||
|
@ -1424,10 +1426,11 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
|
|||
|
||||
void SessionImpl::initializeNativeSession()
|
||||
{
|
||||
const std::string peerId = lt::generate_fingerprint(PEER_ID, QBT_VERSION_MAJOR, QBT_VERSION_MINOR, QBT_VERSION_BUGFIX, QBT_VERSION_BUILD);
|
||||
lt::settings_pack pack = loadLTSettings();
|
||||
|
||||
lt::settings_pack pack;
|
||||
const std::string peerId = lt::generate_fingerprint(PEER_ID, QBT_VERSION_MAJOR, QBT_VERSION_MINOR, QBT_VERSION_BUGFIX, QBT_VERSION_BUILD);
|
||||
pack.set_str(lt::settings_pack::peer_fingerprint, peerId);
|
||||
|
||||
pack.set_bool(lt::settings_pack::listen_system_port_fallback, false);
|
||||
pack.set_str(lt::settings_pack::user_agent, USER_AGENT.toStdString());
|
||||
pack.set_bool(lt::settings_pack::use_dht_as_fallback, false);
|
||||
|
@ -1444,8 +1447,7 @@ void SessionImpl::initializeNativeSession()
|
|||
pack.set_bool(lt::settings_pack::enable_set_file_valid_data, true);
|
||||
#endif
|
||||
|
||||
loadLTSettings(pack);
|
||||
lt::session_params sessionParams {pack, {}};
|
||||
lt::session_params sessionParams {std::move(pack), {}};
|
||||
#ifdef QBT_USES_LIBTORRENT2
|
||||
switch (diskIOType())
|
||||
{
|
||||
|
@ -1503,28 +1505,14 @@ void SessionImpl::processBannedIPs(lt::ip_filter &filter)
|
|||
}
|
||||
}
|
||||
|
||||
void SessionImpl::adjustLimits(lt::settings_pack &settingsPack) const
|
||||
int SessionImpl::adjustLimit(const int limit) const
|
||||
{
|
||||
// Internally increase the queue limits to ensure that the magnet is started
|
||||
const auto adjustLimit = [this](const int limit) -> int
|
||||
{
|
||||
if (limit <= -1)
|
||||
return limit;
|
||||
// check for overflow: (limit + m_extraLimit) < std::numeric_limits<int>::max()
|
||||
return (m_extraLimit < (std::numeric_limits<int>::max() - limit))
|
||||
? (limit + m_extraLimit)
|
||||
: std::numeric_limits<int>::max();
|
||||
};
|
||||
|
||||
settingsPack.set_int(lt::settings_pack::active_downloads, adjustLimit(maxActiveDownloads()));
|
||||
settingsPack.set_int(lt::settings_pack::active_limit, adjustLimit(maxActiveTorrents()));
|
||||
}
|
||||
|
||||
void SessionImpl::applyBandwidthLimits(lt::settings_pack &settingsPack) const
|
||||
{
|
||||
const bool altSpeedLimitEnabled = isAltGlobalSpeedLimitEnabled();
|
||||
settingsPack.set_int(lt::settings_pack::download_rate_limit, altSpeedLimitEnabled ? altGlobalDownloadSpeedLimit() : globalDownloadSpeedLimit());
|
||||
settingsPack.set_int(lt::settings_pack::upload_rate_limit, altSpeedLimitEnabled ? altGlobalUploadSpeedLimit() : globalUploadSpeedLimit());
|
||||
if (limit <= -1)
|
||||
return limit;
|
||||
// check for overflow: (limit + m_extraLimit) < std::numeric_limits<int>::max()
|
||||
return (m_extraLimit < (std::numeric_limits<int>::max() - limit))
|
||||
? (limit + m_extraLimit)
|
||||
: std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
void SessionImpl::initMetrics()
|
||||
|
@ -1569,8 +1557,10 @@ void SessionImpl::initMetrics()
|
|||
m_metricIndices.disk.diskJobTime = findMetricIndex("disk.disk_job_time");
|
||||
}
|
||||
|
||||
void SessionImpl::loadLTSettings(lt::settings_pack &settingsPack)
|
||||
lt::settings_pack SessionImpl::loadLTSettings() const
|
||||
{
|
||||
lt::settings_pack settingsPack;
|
||||
|
||||
const lt::alert_category_t alertMask = lt::alert::error_notification
|
||||
| lt::alert::file_progress_notification
|
||||
| lt::alert::ip_block_notification
|
||||
|
@ -1588,8 +1578,10 @@ void SessionImpl::loadLTSettings(lt::settings_pack &settingsPack)
|
|||
// It will not take affect until the listen_interfaces settings is updated
|
||||
settingsPack.set_int(lt::settings_pack::listen_queue_size, socketBacklogSize());
|
||||
|
||||
configureNetworkInterfaces(settingsPack);
|
||||
applyBandwidthLimits(settingsPack);
|
||||
applyNetworkInterfacesSettings(settingsPack);
|
||||
|
||||
settingsPack.set_int(lt::settings_pack::download_rate_limit, downloadSpeedLimit());
|
||||
settingsPack.set_int(lt::settings_pack::upload_rate_limit, uploadSpeedLimit());
|
||||
|
||||
// The most secure, rc4 only so that all streams are encrypted
|
||||
settingsPack.set_int(lt::settings_pack::allowed_enc_level, lt::settings_pack::pe_rc4);
|
||||
|
@ -1724,7 +1716,9 @@ void SessionImpl::loadLTSettings(lt::settings_pack &settingsPack)
|
|||
// Queueing System
|
||||
if (isQueueingSystemEnabled())
|
||||
{
|
||||
adjustLimits(settingsPack);
|
||||
// Internally increase the queue limits to ensure that the magnet is started
|
||||
settingsPack.set_int(lt::settings_pack::active_downloads, adjustLimit(maxActiveDownloads()));
|
||||
settingsPack.set_int(lt::settings_pack::active_limit, adjustLimit(maxActiveTorrents()));
|
||||
|
||||
settingsPack.set_int(lt::settings_pack::active_seeds, maxActiveUploads());
|
||||
settingsPack.set_bool(lt::settings_pack::dont_count_slow_torrents, ignoreSlowTorrentsForQueueing());
|
||||
|
@ -1840,9 +1834,11 @@ void SessionImpl::loadLTSettings(lt::settings_pack &settingsPack)
|
|||
settingsPack.set_int(lt::settings_pack::seed_choking_algorithm, lt::settings_pack::anti_leech);
|
||||
break;
|
||||
}
|
||||
|
||||
return settingsPack;
|
||||
}
|
||||
|
||||
void SessionImpl::configureNetworkInterfaces(lt::settings_pack &settingsPack)
|
||||
void SessionImpl::applyNetworkInterfacesSettings(lt::settings_pack &settingsPack) const
|
||||
{
|
||||
if (m_listenInterfaceConfigured)
|
||||
return;
|
||||
|
@ -1985,16 +1981,27 @@ void SessionImpl::configurePeerClasses()
|
|||
|
||||
void SessionImpl::enableTracker(const bool enable)
|
||||
{
|
||||
const QString profile = u"embeddedTracker"_qs;
|
||||
auto *portForwarder = Net::PortForwarder::instance();
|
||||
|
||||
if (enable)
|
||||
{
|
||||
if (!m_tracker)
|
||||
m_tracker = new Tracker(this);
|
||||
|
||||
m_tracker->start();
|
||||
|
||||
const auto *pref = Preferences::instance();
|
||||
if (pref->isTrackerPortForwardingEnabled())
|
||||
portForwarder->setPorts(profile, {static_cast<quint16>(pref->getTrackerPort())});
|
||||
else
|
||||
portForwarder->removePorts(profile);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_tracker;
|
||||
|
||||
portForwarder->removePorts(profile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2758,9 +2765,6 @@ bool SessionImpl::addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &so
|
|||
|
||||
p.flags |= lt::torrent_flags::duplicate_is_error;
|
||||
|
||||
// Prevent torrent from saving initial resume data twice
|
||||
p.flags &= ~lt::torrent_flags::need_save_resume;
|
||||
|
||||
p.added_time = std::time(nullptr);
|
||||
|
||||
// Limits
|
||||
|
@ -2903,10 +2907,8 @@ void SessionImpl::saveResumeData()
|
|||
saveTorrentsQueue();
|
||||
|
||||
for (const TorrentImpl *torrent : asConst(m_torrents))
|
||||
{
|
||||
torrent->nativeHandle().save_resume_data(lt::torrent_handle::only_if_modified);
|
||||
++m_numResumeData;
|
||||
}
|
||||
m_numResumeData += m_torrents.size();
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
@ -5212,10 +5214,8 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle,
|
|||
if (const InfoHash infoHash = torrent->infoHash(); infoHash.isHybrid())
|
||||
m_hybridTorrentsByAltID.insert(TorrentID::fromSHA1Hash(infoHash.v1()), torrent);
|
||||
|
||||
if (!params.restored)
|
||||
if (isRestored())
|
||||
{
|
||||
m_resumeDataStorage->store(torrent->id(), params);
|
||||
|
||||
// The following is useless for newly added magnet
|
||||
if (torrent->hasMetadata())
|
||||
{
|
||||
|
@ -5230,7 +5230,7 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle,
|
|||
m_seedingLimitTimer->start();
|
||||
}
|
||||
|
||||
if (params.restored)
|
||||
if (!isRestored())
|
||||
{
|
||||
LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name()));
|
||||
}
|
||||
|
|
|
@ -474,11 +474,10 @@ namespace BitTorrent
|
|||
Q_INVOKABLE void configure();
|
||||
void configureComponents();
|
||||
void initializeNativeSession();
|
||||
void loadLTSettings(lt::settings_pack &settingsPack);
|
||||
void configureNetworkInterfaces(lt::settings_pack &settingsPack);
|
||||
lt::settings_pack loadLTSettings() const;
|
||||
void applyNetworkInterfacesSettings(lt::settings_pack &settingsPack) const;
|
||||
void configurePeerClasses();
|
||||
void adjustLimits(lt::settings_pack &settingsPack) const;
|
||||
void applyBandwidthLimits(lt::settings_pack &settingsPack) const;
|
||||
int adjustLimit(int limit) const;
|
||||
void initMetrics();
|
||||
void adjustLimits();
|
||||
void applyBandwidthLimits();
|
||||
|
@ -553,7 +552,7 @@ namespace BitTorrent
|
|||
|
||||
bool m_deferredConfigureScheduled = false;
|
||||
bool m_IPFilteringConfigured = false;
|
||||
bool m_listenInterfaceConfigured = false;
|
||||
mutable bool m_listenInterfaceConfigured = false;
|
||||
|
||||
CachedSettingValue<bool> m_isDHTEnabled;
|
||||
CachedSettingValue<bool> m_isLSDEnabled;
|
||||
|
|
|
@ -203,12 +203,12 @@ Tracker::Tracker(QObject *parent)
|
|||
|
||||
bool Tracker::start()
|
||||
{
|
||||
const QHostAddress ip = QHostAddress::Any;
|
||||
const int port = Preferences::instance()->getTrackerPort();
|
||||
|
||||
if (m_server->isListening())
|
||||
{
|
||||
if (m_server->serverPort() == port)
|
||||
if (const int oldPort = m_server->serverPort()
|
||||
; oldPort == port)
|
||||
{
|
||||
// Already listening on the right port, just return
|
||||
return true;
|
||||
|
@ -218,9 +218,9 @@ bool Tracker::start()
|
|||
m_server->close();
|
||||
}
|
||||
|
||||
// Listen on the predefined port
|
||||
// Listen on port
|
||||
const QHostAddress ip = QHostAddress::Any;
|
||||
const bool listenSuccess = m_server->listen(ip, port);
|
||||
|
||||
if (listenSuccess)
|
||||
{
|
||||
LogMsg(tr("Embedded Tracker: Now listening on IP: %1, port: %2")
|
||||
|
|
|
@ -124,7 +124,7 @@ namespace
|
|||
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents
|
||||
request.setRawHeader("Referer", request.url().toEncoded().data());
|
||||
#ifdef QT_NO_COMPRESS
|
||||
// The macro "QT_NO_COMPRESS" defined in QT will disable the zlib releated features
|
||||
// The macro "QT_NO_COMPRESS" defined in QT will disable the zlib related features
|
||||
// and reply data auto-decompression in QT will also be disabled. But we can support
|
||||
// gzip encoding and manually decompress the reply data.
|
||||
request.setRawHeader("Accept-Encoding", "gzip");
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
|
||||
class QString;
|
||||
|
||||
namespace Net
|
||||
{
|
||||
|
@ -45,8 +48,8 @@ namespace Net
|
|||
virtual bool isEnabled() const = 0;
|
||||
virtual void setEnabled(bool enabled) = 0;
|
||||
|
||||
virtual void addPort(quint16 port) = 0;
|
||||
virtual void deletePort(quint16 port) = 0;
|
||||
virtual void setPorts(const QString &profile, QSet<quint16> ports) = 0;
|
||||
virtual void removePorts(const QString &profile) = 0;
|
||||
|
||||
private:
|
||||
static PortForwarder *m_instance;
|
||||
|
|
|
@ -1164,6 +1164,16 @@ void Preferences::setTrackerPort(const int port)
|
|||
setValue(u"Preferences/Advanced/trackerPort"_qs, port);
|
||||
}
|
||||
|
||||
bool Preferences::isTrackerPortForwardingEnabled() const
|
||||
{
|
||||
return value(u"Preferences/Advanced/trackerPortForwarding"_qs, false);
|
||||
}
|
||||
|
||||
void Preferences::setTrackerPortForwardingEnabled(const bool enabled)
|
||||
{
|
||||
setValue(u"Preferences/Advanced/trackerPortForwarding"_qs, enabled);
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
||||
bool Preferences::isUpdateCheckEnabled() const
|
||||
{
|
||||
|
|
|
@ -299,6 +299,8 @@ public:
|
|||
#endif
|
||||
int getTrackerPort() const;
|
||||
void setTrackerPort(int port);
|
||||
bool isTrackerPortForwardingEnabled() const;
|
||||
void setTrackerPortForwardingEnabled(bool enabled);
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
||||
bool isUpdateCheckEnabled() const;
|
||||
void setUpdateCheckEnabled(bool enabled);
|
||||
|
|
|
@ -97,6 +97,7 @@ namespace
|
|||
// embedded tracker
|
||||
TRACKER_STATUS,
|
||||
TRACKER_PORT,
|
||||
TRACKER_PORT_FORWARDING,
|
||||
// libtorrent section
|
||||
LIBTORRENT_HEADER,
|
||||
ASYNC_IO_THREADS,
|
||||
|
@ -292,7 +293,9 @@ void AdvancedSettings::saveAdvancedSettings() const
|
|||
|
||||
// Tracker
|
||||
pref->setTrackerPort(m_spinBoxTrackerPort.value());
|
||||
pref->setTrackerPortForwardingEnabled(m_checkBoxTrackerPortForwarding.isChecked());
|
||||
session->setTrackerEnabled(m_checkBoxTrackerStatus.isChecked());
|
||||
|
||||
// Choking algorithm
|
||||
session->setChokingAlgorithm(m_comboBoxChokingAlgorithm.currentData().value<BitTorrent::ChokingAlgorithm>());
|
||||
// Seed choking algorithm
|
||||
|
@ -732,6 +735,9 @@ void AdvancedSettings::loadAdvancedSettings()
|
|||
m_spinBoxTrackerPort.setMaximum(65535);
|
||||
m_spinBoxTrackerPort.setValue(pref->getTrackerPort());
|
||||
addRow(TRACKER_PORT, tr("Embedded tracker port"), &m_spinBoxTrackerPort);
|
||||
// Tracker port forwarding
|
||||
m_checkBoxTrackerPortForwarding.setChecked(pref->isTrackerPortForwardingEnabled());
|
||||
addRow(TRACKER_PORT_FORWARDING, tr("Enable port forwarding for embedded tracker"), &m_checkBoxTrackerPortForwarding);
|
||||
// Choking algorithm
|
||||
m_comboBoxChokingAlgorithm.addItem(tr("Fixed slots"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::FixedSlots));
|
||||
m_comboBoxChokingAlgorithm.addItem(tr("Upload rate based"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::RateBased));
|
||||
|
|
|
@ -68,7 +68,7 @@ private:
|
|||
m_spinBoxSavePathHistoryLength, m_spinBoxPeerTurnover, m_spinBoxPeerTurnoverCutoff, m_spinBoxPeerTurnoverInterval, m_spinBoxRequestQueueSize;
|
||||
QCheckBox m_checkBoxOsCache, m_checkBoxRecheckCompleted, m_checkBoxResolveCountries, m_checkBoxResolveHosts,
|
||||
m_checkBoxProgramNotifications, m_checkBoxTorrentAddedNotifications, m_checkBoxReannounceWhenAddressChanged, m_checkBoxTrackerFavicon, m_checkBoxTrackerStatus,
|
||||
m_checkBoxConfirmTorrentRecheck, m_checkBoxConfirmRemoveAllTags, m_checkBoxAnnounceAllTrackers, m_checkBoxAnnounceAllTiers,
|
||||
m_checkBoxTrackerPortForwarding, m_checkBoxConfirmTorrentRecheck, m_checkBoxConfirmRemoveAllTags, m_checkBoxAnnounceAllTrackers, m_checkBoxAnnounceAllTiers,
|
||||
m_checkBoxMultiConnectionsPerIp, m_checkBoxValidateHTTPSTrackerCertificate, m_checkBoxSSRFMitigation, m_checkBoxBlockPeersOnPrivilegedPorts, m_checkBoxPieceExtentAffinity,
|
||||
m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport;
|
||||
QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxDiskIOReadMode, m_comboBoxDiskIOWriteMode, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm,
|
||||
|
|
|
@ -89,7 +89,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
|||
, m_properties(parent)
|
||||
{
|
||||
// Load settings
|
||||
loadSettings();
|
||||
const bool columnLoaded = loadSettings();
|
||||
// Visual settings
|
||||
setUniformRowHeights(true);
|
||||
setRootIsDecorated(false);
|
||||
|
@ -109,6 +109,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
|||
m_listModel->setHeaderData(PeerListColumns::FLAGS, Qt::Horizontal, tr("Flags"));
|
||||
m_listModel->setHeaderData(PeerListColumns::CONNECTION, Qt::Horizontal, tr("Connection"));
|
||||
m_listModel->setHeaderData(PeerListColumns::CLIENT, Qt::Horizontal, tr("Client", "i.e.: Client application"));
|
||||
m_listModel->setHeaderData(PeerListColumns::PEERID_CLIENT, Qt::Horizontal, tr("Peer ID Client", "i.e.: Client resolved from Peer ID"));
|
||||
m_listModel->setHeaderData(PeerListColumns::PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded"));
|
||||
m_listModel->setHeaderData(PeerListColumns::DOWN_SPEED, Qt::Horizontal, tr("Down Speed", "i.e: Download speed"));
|
||||
m_listModel->setHeaderData(PeerListColumns::UP_SPEED, Qt::Horizontal, tr("Up Speed", "i.e: Upload speed"));
|
||||
|
@ -130,8 +131,16 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
|||
m_proxyModel->setSourceModel(m_listModel);
|
||||
m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
setModel(m_proxyModel);
|
||||
|
||||
hideColumn(PeerListColumns::IP_HIDDEN);
|
||||
hideColumn(PeerListColumns::COL_COUNT);
|
||||
|
||||
// Default hidden columns
|
||||
if (!columnLoaded)
|
||||
{
|
||||
hideColumn(PeerListColumns::PEERID_CLIENT);
|
||||
}
|
||||
|
||||
m_resolveCountries = Preferences::instance()->resolvePeerCountries();
|
||||
if (!m_resolveCountries)
|
||||
hideColumn(PeerListColumns::COUNTRY);
|
||||
|
@ -371,9 +380,9 @@ void PeerListWidget::clear()
|
|||
m_listModel->removeRows(0, nbrows);
|
||||
}
|
||||
|
||||
void PeerListWidget::loadSettings()
|
||||
bool PeerListWidget::loadSettings()
|
||||
{
|
||||
header()->restoreState(Preferences::instance()->getPeerListState());
|
||||
return header()->restoreState(Preferences::instance()->getPeerListState());
|
||||
}
|
||||
|
||||
void PeerListWidget::saveSettings() const
|
||||
|
@ -461,6 +470,8 @@ void PeerListWidget::updatePeer(const BitTorrent::Torrent *torrent, const BitTor
|
|||
setModelData(row, PeerListColumns::FLAGS, peer.flags(), peer.flags(), {}, peer.flagsDescription());
|
||||
const QString client = peer.client().toHtmlEscaped();
|
||||
setModelData(row, PeerListColumns::CLIENT, client, client, {}, client);
|
||||
const QString peerIdClient = peer.peerIdClient().toHtmlEscaped();
|
||||
setModelData(row, PeerListColumns::PEERID_CLIENT, peerIdClient, peerIdClient);
|
||||
setModelData(row, PeerListColumns::PROGRESS, (Utils::String::fromDouble(peer.progress() * 100, 1) + u'%'), peer.progress(), intDataTextAlignment);
|
||||
const QString downSpeed = (hideValues && (peer.payloadDownSpeed() <= 0)) ? QString {} : Utils::Misc::friendlyUnit(peer.payloadDownSpeed(), true);
|
||||
setModelData(row, PeerListColumns::DOWN_SPEED, downSpeed, peer.payloadDownSpeed(), intDataTextAlignment);
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
CONNECTION,
|
||||
FLAGS,
|
||||
CLIENT,
|
||||
PEERID_CLIENT,
|
||||
PROGRESS,
|
||||
DOWN_SPEED,
|
||||
UP_SPEED,
|
||||
|
@ -87,7 +88,7 @@ public:
|
|||
void clear();
|
||||
|
||||
private slots:
|
||||
void loadSettings();
|
||||
bool loadSettings();
|
||||
void saveSettings() const;
|
||||
void displayColumnHeaderMenu();
|
||||
void showPeerListMenu();
|
||||
|
|
|
@ -48,7 +48,7 @@ StatusBar::StatusBar(QWidget *parent)
|
|||
{
|
||||
#ifndef Q_OS_MACOS
|
||||
// Redefining global stylesheet breaks certain elements on mac like tabs.
|
||||
// Qt checks whether the stylesheet class inherts("QMacStyle") and this becomes false.
|
||||
// Qt checks whether the stylesheet class inherits("QMacStyle") and this becomes false.
|
||||
setStyleSheet(u"QStatusBar::item { border-width: 0; }"_qs);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -221,11 +221,7 @@ void TorrentContentModel::updateFilesProgress(const QVector<qreal> &fp)
|
|||
m_rootItem->recalculateProgress();
|
||||
m_rootItem->recalculateAvailability();
|
||||
|
||||
const QVector<ColumnInterval> columns =
|
||||
{
|
||||
{TorrentContentModelItem::COL_PROGRESS, TorrentContentModelItem::COL_PROGRESS}
|
||||
};
|
||||
notifySubtreeUpdated(index(0, 0), columns);
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
void TorrentContentModel::updateFilesPriorities(const QVector<BitTorrent::DownloadPriority> &fprio)
|
||||
|
@ -239,12 +235,7 @@ void TorrentContentModel::updateFilesPriorities(const QVector<BitTorrent::Downlo
|
|||
for (int i = 0; i < fprio.size(); ++i)
|
||||
m_filesIndex[i]->setPriority(static_cast<BitTorrent::DownloadPriority>(fprio[i]));
|
||||
|
||||
const QVector<ColumnInterval> columns =
|
||||
{
|
||||
{TorrentContentModelItem::COL_NAME, TorrentContentModelItem::COL_NAME},
|
||||
{TorrentContentModelItem::COL_PRIO, TorrentContentModelItem::COL_PRIO}
|
||||
};
|
||||
notifySubtreeUpdated(index(0, 0), columns);
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
void TorrentContentModel::updateFilesAvailability(const QVector<qreal> &fa)
|
||||
|
@ -259,11 +250,7 @@ void TorrentContentModel::updateFilesAvailability(const QVector<qreal> &fa)
|
|||
// Update folders progress in the tree
|
||||
m_rootItem->recalculateProgress();
|
||||
|
||||
const QVector<ColumnInterval> columns =
|
||||
{
|
||||
{TorrentContentModelItem::COL_AVAILABILITY, TorrentContentModelItem::COL_AVAILABILITY}
|
||||
};
|
||||
notifySubtreeUpdated(index(0, 0), columns);
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
QVector<BitTorrent::DownloadPriority> TorrentContentModel::getFilePriorities() const
|
||||
|
@ -308,17 +295,13 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu
|
|||
|
||||
if (currentPrio != newPrio)
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
item->setPriority(newPrio);
|
||||
// Update folders progress in the tree
|
||||
m_rootItem->recalculateProgress();
|
||||
m_rootItem->recalculateAvailability();
|
||||
|
||||
const QVector<ColumnInterval> columns =
|
||||
{
|
||||
{TorrentContentModelItem::COL_NAME, TorrentContentModelItem::COL_NAME},
|
||||
{TorrentContentModelItem::COL_PRIO, TorrentContentModelItem::COL_PRIO}
|
||||
};
|
||||
notifySubtreeUpdated(index, columns);
|
||||
emit layoutChanged();
|
||||
emit filteredFilesChanged();
|
||||
|
||||
return true;
|
||||
|
@ -350,14 +333,9 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu
|
|||
const auto newPrio = static_cast<BitTorrent::DownloadPriority>(value.toInt());
|
||||
if (currentPrio != newPrio)
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
item->setPriority(newPrio);
|
||||
|
||||
const QVector<ColumnInterval> columns =
|
||||
{
|
||||
{TorrentContentModelItem::COL_NAME, TorrentContentModelItem::COL_NAME},
|
||||
{TorrentContentModelItem::COL_PRIO, TorrentContentModelItem::COL_PRIO}
|
||||
};
|
||||
notifySubtreeUpdated(index, columns);
|
||||
emit layoutChanged();
|
||||
|
||||
if ((newPrio == BitTorrent::DownloadPriority::Ignored)
|
||||
|| (currentPrio == BitTorrent::DownloadPriority::Ignored))
|
||||
|
@ -541,7 +519,8 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
|
|||
if (filesCount <= 0)
|
||||
return;
|
||||
|
||||
emit layoutAboutToBeChanged();
|
||||
beginResetModel();
|
||||
|
||||
// Initialize files_index array
|
||||
qDebug("Torrent contains %d files", filesCount);
|
||||
m_filesIndex.reserve(filesCount);
|
||||
|
@ -588,56 +567,6 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
|
|||
lastParent->appendChild(fileItem);
|
||||
m_filesIndex.push_back(fileItem);
|
||||
}
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
void TorrentContentModel::notifySubtreeUpdated(const QModelIndex &index, const QVector<ColumnInterval> &columns)
|
||||
{
|
||||
// For best performance, `columns` entries should be arranged from left to right
|
||||
|
||||
Q_ASSERT(index.isValid());
|
||||
|
||||
// emit itself
|
||||
for (const ColumnInterval &column : columns)
|
||||
emit dataChanged(index.siblingAtColumn(column.first()), index.siblingAtColumn(column.last()));
|
||||
|
||||
// propagate up the model
|
||||
QModelIndex parentIndex = parent(index);
|
||||
while (parentIndex.isValid())
|
||||
{
|
||||
for (const ColumnInterval &column : columns)
|
||||
emit dataChanged(parentIndex.siblingAtColumn(column.first()), parentIndex.siblingAtColumn(column.last()));
|
||||
parentIndex = parent(parentIndex);
|
||||
}
|
||||
|
||||
// propagate down the model
|
||||
QVector<QModelIndex> parentIndexes;
|
||||
|
||||
if (hasChildren(index))
|
||||
parentIndexes.push_back(index);
|
||||
|
||||
while (!parentIndexes.isEmpty())
|
||||
{
|
||||
const QModelIndex parent = parentIndexes.takeLast();
|
||||
|
||||
const int childCount = rowCount(parent);
|
||||
const QModelIndex child = this->index(0, 0, parent);
|
||||
|
||||
// emit this generation
|
||||
for (const ColumnInterval &column : columns)
|
||||
{
|
||||
const QModelIndex childTopLeft = child.siblingAtColumn(column.first());
|
||||
const QModelIndex childBottomRight = child.sibling((childCount - 1), column.last());
|
||||
emit dataChanged(childTopLeft, childBottomRight);
|
||||
}
|
||||
|
||||
// check generations further down
|
||||
parentIndexes.reserve(childCount);
|
||||
for (int i = 0; i < childCount; ++i)
|
||||
{
|
||||
const QModelIndex sibling = child.siblingAtRow(i);
|
||||
if (hasChildren(sibling))
|
||||
parentIndexes.push_back(sibling);
|
||||
}
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
|
|
@ -81,10 +81,6 @@ signals:
|
|||
void filteredFilesChanged();
|
||||
|
||||
private:
|
||||
using ColumnInterval = IndexInterval<int>;
|
||||
|
||||
void notifySubtreeUpdated(const QModelIndex &index, const QVector<ColumnInterval> &columns);
|
||||
|
||||
TorrentContentModelFolder *m_rootItem = nullptr;
|
||||
QVector<TorrentContentModelFile *> m_filesIndex;
|
||||
QFileIconProvider *m_fileIconProvider = nullptr;
|
||||
|
|
|
@ -79,25 +79,19 @@ void TorrentContentTreeView::keyPressEvent(QKeyEvent *event)
|
|||
|
||||
event->accept();
|
||||
|
||||
QModelIndex current = currentNameCell();
|
||||
|
||||
QVariant value = current.data(Qt::CheckStateRole);
|
||||
const QVariant value = currentNameCell().data(Qt::CheckStateRole);
|
||||
if (!value.isValid())
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
|
||||
? Qt::Unchecked : Qt::Checked);
|
||||
|
||||
const Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked)
|
||||
? Qt::Unchecked : Qt::Checked;
|
||||
const QModelIndexList selection = selectionModel()->selectedRows(TorrentContentModelItem::COL_NAME);
|
||||
|
||||
for (const QModelIndex &index : selection)
|
||||
{
|
||||
Q_ASSERT(index.column() == TorrentContentModelItem::COL_NAME);
|
||||
model()->setData(index, state, Qt::CheckStateRole);
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentContentTreeView::renameSelectedFile(BitTorrent::AbstractFileStorage &fileStorage)
|
||||
|
@ -142,16 +136,16 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::AbstractFileStorage
|
|||
}
|
||||
}
|
||||
|
||||
QModelIndex TorrentContentTreeView::currentNameCell()
|
||||
QModelIndex TorrentContentTreeView::currentNameCell() const
|
||||
{
|
||||
QModelIndex current = currentIndex();
|
||||
const QModelIndex current = currentIndex();
|
||||
if (!current.isValid())
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
return {};
|
||||
}
|
||||
|
||||
return model()->index(current.row(), TorrentContentModelItem::COL_NAME, current.parent());
|
||||
return current.siblingAtColumn(TorrentContentModelItem::COL_NAME);
|
||||
}
|
||||
|
||||
void TorrentContentTreeView::wheelEvent(QWheelEvent *event)
|
||||
|
|
|
@ -49,6 +49,6 @@ public:
|
|||
void renameSelectedFile(BitTorrent::AbstractFileStorage &fileStorage);
|
||||
|
||||
private:
|
||||
QModelIndex currentNameCell();
|
||||
QModelIndex currentNameCell() const;
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
};
|
||||
|
|
|
@ -632,9 +632,12 @@ bool TransferListModel::setData(const QModelIndex &index, const QVariant &value,
|
|||
|
||||
void TransferListModel::addTorrents(const QVector<BitTorrent::Torrent *> &torrents)
|
||||
{
|
||||
int row = m_torrentList.size();
|
||||
beginInsertRows({}, row, (row + torrents.size()));
|
||||
qsizetype row = m_torrentList.size();
|
||||
const qsizetype total = row + torrents.size();
|
||||
|
||||
beginInsertRows({}, row, total);
|
||||
|
||||
m_torrentList.reserve(total);
|
||||
for (BitTorrent::Torrent *torrent : torrents)
|
||||
{
|
||||
Q_ASSERT(!m_torrentMap.contains(torrent));
|
||||
|
|
|
@ -363,12 +363,30 @@ void TransferListWidget::setSelectedTorrentsLocation()
|
|||
|
||||
void TransferListWidget::pauseAllTorrents()
|
||||
{
|
||||
// Show confirmation if user would really like to Pause All
|
||||
const QMessageBox::StandardButton ret =
|
||||
QMessageBox::question(this, tr("Confirm pause")
|
||||
, tr("Would you like to pause all torrents?")
|
||||
, (QMessageBox::Yes | QMessageBox::No));
|
||||
|
||||
if (ret != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
for (BitTorrent::Torrent *const torrent : asConst(BitTorrent::Session::instance()->torrents()))
|
||||
torrent->pause();
|
||||
}
|
||||
|
||||
void TransferListWidget::resumeAllTorrents()
|
||||
{
|
||||
// Show confirmation if user would really like to Resume All
|
||||
const QMessageBox::StandardButton ret =
|
||||
QMessageBox::question(this, tr("Confirm resume")
|
||||
, tr("Would you like to resume all torrents?")
|
||||
, (QMessageBox::Yes | QMessageBox::No));
|
||||
|
||||
if (ret != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
for (BitTorrent::Torrent *const torrent : asConst(BitTorrent::Session::instance()->torrents()))
|
||||
torrent->resume();
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<file>qbittorrent_uk.qm</file>
|
||||
<file>qbittorrent_uz@Latn.qm</file>
|
||||
<file>qbittorrent_vi.qm</file>
|
||||
<file>qbittorrent_zh.qm</file>
|
||||
<file>qbittorrent_zh_CN.qm</file>
|
||||
<file>qbittorrent_zh_HK.qm</file>
|
||||
<file>qbittorrent_zh_TW.qm</file>
|
||||
</qresource>
|
||||
|
|
|
@ -372,6 +372,7 @@ void AppController::preferencesAction()
|
|||
// Embedded tracker
|
||||
data[u"enable_embedded_tracker"_qs] = session->isTrackerEnabled();
|
||||
data[u"embedded_tracker_port"_qs] = pref->getTrackerPort();
|
||||
data[u"embedded_tracker_port_forwarding"_qs] = pref->isTrackerPortForwardingEnabled();
|
||||
// Choking algorithm
|
||||
data[u"upload_slots_behavior"_qs] = static_cast<int>(session->chokingAlgorithm());
|
||||
// Seed choking algorithm
|
||||
|
@ -899,6 +900,8 @@ void AppController::setPreferencesAction()
|
|||
// Embedded tracker
|
||||
if (hasKey(u"embedded_tracker_port"_qs))
|
||||
pref->setTrackerPort(it.value().toInt());
|
||||
if (hasKey(u"embedded_tracker_port_forwarding"_qs))
|
||||
pref->setTrackerPortForwardingEnabled(it.value().toBool());
|
||||
if (hasKey(u"enable_embedded_tracker"_qs))
|
||||
session->setTrackerEnabled(it.value().toBool());
|
||||
// Choking algorithm
|
||||
|
|
|
@ -66,6 +66,7 @@ namespace
|
|||
|
||||
// Peer keys
|
||||
const QString KEY_PEER_CLIENT = u"client"_qs;
|
||||
const QString KEY_PEER_ID_CLIENT = u"peer_id_client"_qs;
|
||||
const QString KEY_PEER_CONNECTION_TYPE = u"connection"_qs;
|
||||
const QString KEY_PEER_COUNTRY = u"country"_qs;
|
||||
const QString KEY_PEER_COUNTRY_CODE = u"country_code"_qs;
|
||||
|
@ -561,6 +562,7 @@ void SyncController::torrentPeersAction()
|
|||
{KEY_PEER_IP, pi.address().ip.toString()},
|
||||
{KEY_PEER_PORT, pi.address().port},
|
||||
{KEY_PEER_CLIENT, pi.client()},
|
||||
{KEY_PEER_ID_CLIENT, pi.peerIdClient()},
|
||||
{KEY_PEER_PROGRESS, pi.progress()},
|
||||
{KEY_PEER_DOWN_SPEED, pi.payloadDownSpeed()},
|
||||
{KEY_PEER_UP_SPEED, pi.payloadUpSpeed()},
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
#include "base/utils/version.h"
|
||||
#include "api/isessionmanager.h"
|
||||
|
||||
inline const Utils::Version<3, 2> API_VERSION {2, 8, 16};
|
||||
inline const Utils::Version<3, 2> API_VERSION {2, 8, 18};
|
||||
|
||||
class APIController;
|
||||
class AuthController;
|
||||
|
|
|
@ -50,25 +50,21 @@ void WebUI::configure()
|
|||
{
|
||||
m_isErrored = false; // clear previous error state
|
||||
|
||||
Preferences *const pref = Preferences::instance();
|
||||
|
||||
const quint16 oldPort = m_port;
|
||||
m_port = pref->getWebUiPort();
|
||||
const QString portForwardingProfile = u"webui"_qs;
|
||||
const Preferences *pref = Preferences::instance();
|
||||
const quint16 port = pref->getWebUiPort();
|
||||
|
||||
if (pref->isWebUiEnabled())
|
||||
{
|
||||
// UPnP/NAT-PMP
|
||||
// Port forwarding
|
||||
auto *portForwarder = Net::PortForwarder::instance();
|
||||
if (pref->useUPnPForWebUIPort())
|
||||
{
|
||||
if (m_port != oldPort)
|
||||
{
|
||||
Net::PortForwarder::instance()->deletePort(oldPort);
|
||||
Net::PortForwarder::instance()->addPort(m_port);
|
||||
}
|
||||
portForwarder->setPorts(portForwardingProfile, {port});
|
||||
}
|
||||
else
|
||||
{
|
||||
Net::PortForwarder::instance()->deletePort(oldPort);
|
||||
portForwarder->removePorts(portForwardingProfile);
|
||||
}
|
||||
|
||||
// http server
|
||||
|
@ -81,7 +77,7 @@ void WebUI::configure()
|
|||
else
|
||||
{
|
||||
if ((m_httpServer->serverAddress().toString() != serverAddressString)
|
||||
|| (m_httpServer->serverPort() != m_port))
|
||||
|| (m_httpServer->serverPort() != port))
|
||||
m_httpServer->close();
|
||||
}
|
||||
|
||||
|
@ -112,15 +108,15 @@ void WebUI::configure()
|
|||
{
|
||||
const auto address = ((serverAddressString == u"*") || serverAddressString.isEmpty())
|
||||
? QHostAddress::Any : QHostAddress(serverAddressString);
|
||||
bool success = m_httpServer->listen(address, m_port);
|
||||
bool success = m_httpServer->listen(address, port);
|
||||
if (success)
|
||||
{
|
||||
LogMsg(tr("Web UI: Now listening on IP: %1, port: %2").arg(serverAddressString).arg(m_port));
|
||||
LogMsg(tr("Web UI: Now listening on IP: %1, port: %2").arg(serverAddressString).arg(port));
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString errorMsg = tr("Web UI: Unable to bind to IP: %1, port: %2. Reason: %3")
|
||||
.arg(serverAddressString).arg(m_port).arg(m_httpServer->errorString());
|
||||
.arg(serverAddressString).arg(port).arg(m_httpServer->errorString());
|
||||
LogMsg(errorMsg, Log::CRITICAL);
|
||||
qCritical() << errorMsg;
|
||||
|
||||
|
@ -144,7 +140,7 @@ void WebUI::configure()
|
|||
}
|
||||
else
|
||||
{
|
||||
Net::PortForwarder::instance()->deletePort(oldPort);
|
||||
Net::PortForwarder::instance()->removePorts(portForwardingProfile);
|
||||
|
||||
delete m_httpServer;
|
||||
delete m_webapp;
|
||||
|
|
|
@ -66,5 +66,4 @@ private:
|
|||
QPointer<Http::Server> m_httpServer;
|
||||
QPointer<Net::DNSUpdater> m_dnsUpdater;
|
||||
QPointer<WebApplication> m_webapp;
|
||||
quint16 m_port = 0;
|
||||
};
|
||||
|
|
|
@ -1498,6 +1498,7 @@ window.qBittorrent.DynamicTable = (function() {
|
|||
this.newColumn('connection', '', 'QBT_TR(Connection)QBT_TR[CONTEXT=PeerListWidget]', 50, true);
|
||||
this.newColumn('flags', '', 'QBT_TR(Flags)QBT_TR[CONTEXT=PeerListWidget]', 50, true);
|
||||
this.newColumn('client', '', 'QBT_TR(Client)QBT_TR[CONTEXT=PeerListWidget]', 140, true);
|
||||
this.newColumn('peer_id_client', '', 'QBT_TR(Peer ID Client)QBT_TR[CONTEXT=PeerListWidget]', 60, false);
|
||||
this.newColumn('progress', '', 'QBT_TR(Progress)QBT_TR[CONTEXT=PeerListWidget]', 50, true);
|
||||
this.newColumn('dl_speed', '', 'QBT_TR(Down Speed)QBT_TR[CONTEXT=PeerListWidget]', 50, true);
|
||||
this.newColumn('up_speed', '', 'QBT_TR(Up Speed)QBT_TR[CONTEXT=PeerListWidget]', 50, true);
|
||||
|
|
|
@ -979,18 +979,34 @@ const initializeWindows = function() {
|
|||
}
|
||||
};
|
||||
|
||||
['pause', 'resume'].each(function(item) {
|
||||
addClickEvent(item + 'All', function(e) {
|
||||
new Event(e).stop();
|
||||
addClickEvent('pauseAll', (e) => {
|
||||
new Event(e).stop();
|
||||
|
||||
if (confirm('QBT_TR(Would you like to pause all torrents?)QBT_TR[CONTEXT=MainWindow]')) {
|
||||
new Request({
|
||||
url: 'api/v2/torrents/' + item,
|
||||
url: 'api/v2/torrents/pause',
|
||||
method: 'post',
|
||||
data: {
|
||||
hashes: "all"
|
||||
}
|
||||
}).send();
|
||||
updateMainData();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
addClickEvent('resumeAll', (e) => {
|
||||
new Event(e).stop();
|
||||
|
||||
if (confirm('QBT_TR(Would you like to resume all torrents?)QBT_TR[CONTEXT=MainWindow]')) {
|
||||
new Request({
|
||||
url: 'api/v2/torrents/resume',
|
||||
method: 'post',
|
||||
data: {
|
||||
hashes: "all"
|
||||
}
|
||||
}).send();
|
||||
updateMainData();
|
||||
}
|
||||
});
|
||||
|
||||
['pause', 'resume', 'recheck'].each(function(item) {
|
||||
|
|
|
@ -1016,6 +1016,14 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
|||
<input type="text" id="embeddedTrackerPort" style="width: 15em;" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="embeddedTrackerPortForwarding">QBT_TR(Enable port forwarding for embedded tracker:)QBT_TR[CONTEXT=OptionsDialog]</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" id="embeddedTrackerPortForwarding" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<fieldset class="settings">
|
||||
|
@ -2099,6 +2107,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
|||
$('blockPeersOnPrivilegedPorts').setProperty('checked', pref.block_peers_on_privileged_ports);
|
||||
$('enableEmbeddedTracker').setProperty('checked', pref.enable_embedded_tracker);
|
||||
$('embeddedTrackerPort').setProperty('value', pref.embedded_tracker_port);
|
||||
$('embeddedTrackerPortForwarding').setProperty('checked', pref.embedded_tracker_port_forwarding);
|
||||
$('uploadSlotsBehavior').setProperty('value', pref.upload_slots_behavior);
|
||||
$('uploadChokingAlgorithm').setProperty('value', pref.upload_choking_algorithm);
|
||||
$('announceAllTrackers').setProperty('checked', pref.announce_to_all_trackers);
|
||||
|
@ -2526,6 +2535,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
|||
settings.set('block_peers_on_privileged_ports', $('blockPeersOnPrivilegedPorts').getProperty('checked'));
|
||||
settings.set('enable_embedded_tracker', $('enableEmbeddedTracker').getProperty('checked'));
|
||||
settings.set('embedded_tracker_port', $('embeddedTrackerPort').getProperty('value'));
|
||||
settings.set('embedded_tracker_port_forwarding', $('embeddedTrackerPortForwarding').getProperty('checked'));
|
||||
settings.set('upload_slots_behavior', $('uploadSlotsBehavior').getProperty('value'));
|
||||
settings.set('upload_choking_algorithm', $('uploadChokingAlgorithm').getProperty('value'));
|
||||
settings.set('announce_to_all_trackers', $('announceAllTrackers').getProperty('checked'));
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<file>webui_uk.qm</file>
|
||||
<file>webui_uz@Latn.qm</file>
|
||||
<file>webui_vi.qm</file>
|
||||
<file>webui_zh.qm</file>
|
||||
<file>webui_zh_CN.qm</file>
|
||||
<file>webui_zh_HK.qm</file>
|
||||
<file>webui_zh_TW.qm</file>
|
||||
</qresource>
|
||||
|
|
Loading…
Reference in a new issue