You've already forked qBittorrent
mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-10-14 11:52:15 +02:00
Compare commits
29 Commits
release-5.
...
release-4.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
480e3f02ca | ||
![]() |
6b05c716a8 | ||
![]() |
c697829b1b | ||
![]() |
9a2ec6912b | ||
![]() |
7601163d32 | ||
![]() |
8e2bda2b7a | ||
![]() |
1761f6c58e | ||
![]() |
419cdde4e1 | ||
![]() |
6ec46a90d1 | ||
![]() |
f4051034d7 | ||
![]() |
1a8ba00f2c | ||
![]() |
de4c1c9265 | ||
![]() |
bff9189e52 | ||
![]() |
076b3628b1 | ||
![]() |
75ccce705e | ||
![]() |
964bf31775 | ||
![]() |
507ced2fa2 | ||
![]() |
e62f9ef56a | ||
![]() |
a5a242377b | ||
![]() |
0758109d15 | ||
![]() |
3970d91d19 | ||
![]() |
4e98b7f0cf | ||
![]() |
27a69d9cca | ||
![]() |
d884ec1731 | ||
![]() |
62b2959cb4 | ||
![]() |
2bdc91c53f | ||
![]() |
d829df99aa | ||
![]() |
4f2ac34440 | ||
![]() |
94e9e9fdb2 |
@@ -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
|
||||
|
82
Changelog
82
Changelog
@@ -1,4 +1,84 @@
|
||||
Unreleased - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.5.0
|
||||
Sat Nov 26 2022 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.5.0
|
||||
- FEATURE: Add `Auto resize columns` functionality (Chocobo1)
|
||||
- FEATURE: Allow to use Category paths in `Manual` mode (glassez)
|
||||
- FEATURE: Allow to disable Automatic mode when default "temp" path changed (glassez)
|
||||
- FEATURE: Add tuning options related to performance warnings (Chocobo1)
|
||||
- FEATURE: Add right click menu for status filters (An0n)
|
||||
- FEATURE: Allow setting the number of maximum active checking torrents (An0n)
|
||||
- FEATURE: Add option to toggle filters sidebar (AbeniMatteo)
|
||||
- FEATURE: Allow to set `working set limit` on non-Windows OS (Chocobo1)
|
||||
- FEATURE: Add `Export .torrent` action (Chocobo1)
|
||||
- FEATURE: Add keyboard navigation keys (itlezy)
|
||||
- FEATURE: Allow to use POSIX-compliant disk IO type (Coda)
|
||||
- FEATURE: Add `Filter files` field in new torrent dialog (thalieht)
|
||||
- FEATURE: Implement new icon/color theme (now-im, xavier2k6)
|
||||
- FEATURE: Add file name filter/blacklist (mxtsdev, thalieht)
|
||||
- FEATURE: Add support for custom SMTP ports (Emil M George)
|
||||
- FEATURE: Split the OS cache settings into Disk IO read/write modes (summer)
|
||||
- FEATURE: When duplicate torrent is added set metadata to existing one (glassez)
|
||||
- FEATURE: Greatly improve startup time with many torrents (glassez, jagannatharjun)
|
||||
- FEATURE: Add keyboard shortcut to Download URL dialog (Chocobo1)
|
||||
- FEATURE: Add ability to run external program on torrent added (glassez)
|
||||
- FEATURE: Add infohash and download path columns (tristanleboss)
|
||||
- FEATURE: Allow to set torrent stop condition (glassez, thalieht)
|
||||
- FEATURE: Add a `Moving` status filter (tristanleboss)
|
||||
- FEATURE: Change color palettes for both dark, light themes (Chocobo1)
|
||||
- FEATURE: Add a `Use proxy for hostname lookup` option (Nathan Lewis)
|
||||
- FEATURE: Introduce a `change listen port` cmd option (BallsOfSpaghetti)
|
||||
- FEATURE: Implement `Peer ID Client` column for `Peers` tab (Hanabishi)
|
||||
- FEATURE: Add port forwarding option for embedded tracker (Chocobo1)
|
||||
- BUGFIX: Store hybrid torrents using `torrent ID` as basename (glassez)
|
||||
- BUGFIX: Enable Combobox editor for the `Mixed` file download priority (Aleksandr Cupacenko)
|
||||
- BUGFIX: Allow shortcut folders for the Open and Save directory dialogs (Aleksandr Cupacenko)
|
||||
- BUGFIX: Rename content tab `Size` column to `Total Size` (Aleksandr Cupacenko)
|
||||
- BUGFIX: Fix scrolling to the lowermost visible torrent (Aleksandr Cupacenko)
|
||||
- BUGFIX: Allow changing file priorities for finished torrents (An0n)
|
||||
- BUGFIX: Focus save path when Manual mode is selected initially (Aleksandr Cupacenko)
|
||||
- BUGFIX: Disable force reannounce when it is not possible (An0n)
|
||||
- BUGFIX: Add horizontal scrolling for tracker list and torrent content (NotTsunami)
|
||||
- BUGFIX: Enlarge "speed limits" icons (Chocobo1)
|
||||
- BUGFIX: Change Downloaded to Times Downloaded in trackers tab (An0n)
|
||||
- BUGFIX: Remove artificial max limits from `Torrent Queueing` related options (Chocobo1)
|
||||
- BUGFIX: Preserve `skip hash check` when there is no metadata (glassez)
|
||||
- BUGFIX: Fix DHT/PeX/LSD status when it is globally disabled (Kacper Michajłow)
|
||||
- BUGFIX: Fix rate calculation when interval is too low (glassez)
|
||||
- BUGFIX: Add tooltip message when system tray icon isn't available (Chocobo1)
|
||||
- BUGFIX: Improve sender field in mail notifications (Dmitry Vodopyanov)
|
||||
- BUGFIX: Fix "Add torrent dialog" spill-over on smaller screens (Chocobo1)
|
||||
- BUGFIX: Fix peer count issue when tracker responds with zero figure (summer)
|
||||
- BUGFIX: Don't merge trackers by default (glassez)
|
||||
- BUGFIX: Don't inhibit system sleep/auto shutdown for torrents stuck at downloading metadata (summer)
|
||||
- BUGFIX: Allow to pause a checking torrent from context menu (summer)
|
||||
- BUGFIX: Allow to use subnet notation in reverse proxy list (Chocobo1)
|
||||
- BUGFIX: Fine tune translations loading for Chinese locales (sledgehammer999)
|
||||
- BUGFIX: Fix torrent content checkboxes not updated properly (Chocobo1)
|
||||
- BUGFIX: Correctly load state of `Use another path for incomplete torrents` in Watched folders (glassez)
|
||||
- BUGFIX: Add confirmation to resume/pause all (BallsOfSpaghetti)
|
||||
- BUGFIX: Fix wrong count of errored trackers (Chocobo1)
|
||||
- WEBUI: Allow blank lines in multipart form-data input (Aleksandr Cupacenko)
|
||||
- WEBUI: Make various dialogs resizable (Chocobo1)
|
||||
- WEBUI: Fix wrong v2 hash string displayed (Chocobo1)
|
||||
- WEBUI: WebAPI: return correct status (Requi)
|
||||
- WEBUI: Fix empty selection in language combobox (Chocobo1)
|
||||
- WEBUI: Store WebUI port setting in human readable number (Chocobo1)
|
||||
- WEBUI: Add support for exporting .torrent (Tom Piccirello)
|
||||
- WEBUI: WebAPI: Add endpoint to set speed limit mode (glassez)
|
||||
- WEBUI: Improve progress bar rendering (Mike Lei)
|
||||
- WEBUI: Add transfer list refresh interval settings (summer)
|
||||
- WEBUI: Use natural sort (Chocobo1)
|
||||
- WEBUI: Apply i18n translation only to built-in WebUI (Chocobo1)
|
||||
- WEBUI: Alert when HTTPS settings are incomplete (Chocobo1)
|
||||
- WEBUI: Handle drag and drop events (Chocobo1)
|
||||
- WEBUI: Fix wrong behavior for shutdown action (Chocobo1)
|
||||
- WEBUI: Don't disable combobox for file priority (Chocobo1)
|
||||
- RSS: Increase limit of maximum number of articles per feed (summer)
|
||||
- WINDOWS: Fix `Open destination folder` delay on Windows (Andrew)
|
||||
- WINDOWS: NSIS: Update Russian, Estonian, Japanese, Dutch, Portuguese BR, German and Indonesian translations (Andrei Stepanov, Priit Uring, maboroshin, Thomas De Rocker, Ícaro, schnurlos, Faisal A. F. Rahman)
|
||||
- LINUX: Mark as single window app in .desktop file (Nicolas Fella)
|
||||
- LINUX: Add Dockerfile (Amanuense-del-diavolo, Tom Piccirello, Chocobo1)
|
||||
- LINUX: Remove option of using icons from system theme (now-im)
|
||||
- MACOS: Fix wrong background color in properties widget (NotTsunami)
|
||||
- OTHER: Binary distributions of qbittorrent are GPLv3+ licensed (sledgehammer999)
|
||||
|
||||
Thu Jan 06 2022 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.4.0
|
||||
- FEATURE: Support for v2 torrents along with libtorrent 2.0.x support (glassez, Chocobo1)
|
||||
|
20
configure
vendored
20
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for qbittorrent v4.5.0beta1.
|
||||
# Generated by GNU Autoconf 2.71 for qbittorrent v4.5.0.
|
||||
#
|
||||
# Report bugs to <bugs.qbittorrent.org>.
|
||||
#
|
||||
@@ -611,8 +611,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='qbittorrent'
|
||||
PACKAGE_TARNAME='qbittorrent'
|
||||
PACKAGE_VERSION='v4.5.0beta1'
|
||||
PACKAGE_STRING='qbittorrent v4.5.0beta1'
|
||||
PACKAGE_VERSION='v4.5.0'
|
||||
PACKAGE_STRING='qbittorrent v4.5.0'
|
||||
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
|
||||
PACKAGE_URL='https://www.qbittorrent.org/'
|
||||
|
||||
@@ -1329,7 +1329,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures qbittorrent v4.5.0beta1 to adapt to many kinds of systems.
|
||||
\`configure' configures qbittorrent v4.5.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1400,7 +1400,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of qbittorrent v4.5.0beta1:";;
|
||||
short | recursive ) echo "Configuration of qbittorrent v4.5.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1533,7 +1533,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
qbittorrent configure v4.5.0beta1
|
||||
qbittorrent configure v4.5.0
|
||||
generated by GNU Autoconf 2.71
|
||||
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
@@ -1648,7 +1648,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by qbittorrent $as_me v4.5.0beta1, which was
|
||||
It was created by qbittorrent $as_me v4.5.0, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@@ -4779,7 +4779,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='qbittorrent'
|
||||
VERSION='v4.5.0beta1'
|
||||
VERSION='v4.5.0'
|
||||
|
||||
|
||||
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
|
||||
@@ -7237,7 +7237,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by qbittorrent $as_me v4.5.0beta1, which was
|
||||
This file was extended by qbittorrent $as_me v4.5.0, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -7297,7 +7297,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config='$ac_cs_config_escaped'
|
||||
ac_cs_version="\\
|
||||
qbittorrent config.status v4.5.0beta1
|
||||
qbittorrent config.status v4.5.0
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
AC_INIT([qbittorrent], [v4.5.0beta1], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||
AC_INIT([qbittorrent], [v4.5.0], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
: ${CFLAGS=""}
|
||||
|
@@ -74,6 +74,6 @@
|
||||
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="4.5.0" date="2022-01-06"/>
|
||||
<release version="4.5.0" date="2022-11-26"/>
|
||||
</releases>
|
||||
</component>
|
||||
|
@@ -98,7 +98,7 @@ Name[is]=qBittorrent
|
||||
Comment[it]=Scarica e condividi file tramite BitTorrent
|
||||
GenericName[it]=Client BitTorrent
|
||||
Name[it]=qBittorrent
|
||||
Comment[ja]=BitTorrent でファイルをダウンロードおよび共有します
|
||||
Comment[ja]=BitTorrent でファイルをダウンロードおよび共有
|
||||
GenericName[ja]=BitTorrent クライアント
|
||||
Name[ja]=qBittorrent
|
||||
Comment[ka]=გადმოტვირთეთ და გააზიარეთ ფაილები BitTorrent-ის საშუალებით
|
||||
|
@@ -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;
|
||||
@@ -1390,7 +1392,12 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
|
||||
context->startupStorage->deleteLater();
|
||||
|
||||
if (context->currentStorageType == ResumeDataStorageType::Legacy)
|
||||
Utils::Fs::removeFile(dbPath);
|
||||
{
|
||||
connect(context->startupStorage, &QObject::destroyed, [dbPath]
|
||||
{
|
||||
Utils::Fs::removeFile(dbPath);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
context->deleteLater();
|
||||
@@ -1419,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);
|
||||
@@ -1439,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())
|
||||
{
|
||||
@@ -1498,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()
|
||||
@@ -1564,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
|
||||
@@ -1583,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);
|
||||
@@ -1719,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());
|
||||
@@ -1835,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;
|
||||
@@ -1980,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2753,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
|
||||
@@ -2898,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();
|
||||
@@ -5207,9 +5214,9 @@ 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);
|
||||
torrent->saveResumeData(lt::torrent_handle::save_info_dict);
|
||||
|
||||
// The following is useless for newly added magnet
|
||||
if (torrent->hasMetadata())
|
||||
@@ -5225,7 +5232,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;
|
||||
|
@@ -690,9 +690,9 @@ bool TorrentImpl::needSaveResumeData() const
|
||||
return m_nativeStatus.need_save_resume;
|
||||
}
|
||||
|
||||
void TorrentImpl::saveResumeData()
|
||||
void TorrentImpl::saveResumeData(lt::resume_data_flags_t flags)
|
||||
{
|
||||
m_nativeHandle.save_resume_data();
|
||||
m_nativeHandle.save_resume_data(flags);
|
||||
m_session->handleTorrentSaveResumeDataRequested(this);
|
||||
}
|
||||
|
||||
|
@@ -245,7 +245,7 @@ namespace BitTorrent
|
||||
void handleStateUpdate(const lt::torrent_status &nativeStatus);
|
||||
void handleCategoryOptionsChanged();
|
||||
void handleAppendExtensionToggled();
|
||||
void saveResumeData();
|
||||
void saveResumeData(lt::resume_data_flags_t flags = {});
|
||||
void handleMoveStorageJobFinished(const Path &path, bool hasOutstandingJob);
|
||||
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
|
||||
void updatePeerCount(const QString &trackerURL, const TrackerEntry::Endpoint &endpoint, int count);
|
||||
|
@@ -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);
|
||||
|
@@ -277,9 +277,11 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result)
|
||||
|
||||
void Feed::load()
|
||||
{
|
||||
QMetaObject::invokeMethod(m_serializer, [this]()
|
||||
QMetaObject::invokeMethod(m_serializer
|
||||
, [serializer = m_serializer, url = m_url
|
||||
, path = (m_session->dataFileStorage()->storageDir() / m_dataFileName)]
|
||||
{
|
||||
m_serializer->load((m_session->dataFileStorage()->storageDir() / m_dataFileName), m_url);
|
||||
serializer->load(path, url);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -297,9 +299,11 @@ void Feed::store()
|
||||
for (Article *article :asConst(m_articles))
|
||||
articlesData.push_back(article->data());
|
||||
|
||||
QMetaObject::invokeMethod(m_serializer, [this, articlesData]()
|
||||
QMetaObject::invokeMethod(m_serializer
|
||||
, [articlesData, serializer = m_serializer
|
||||
, path = (m_session->dataFileStorage()->storageDir() / m_dataFileName)]
|
||||
{
|
||||
m_serializer->store((m_session->dataFileStorage()->storageDir() / m_dataFileName), articlesData);
|
||||
serializer->store(path, articlesData);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -32,7 +32,7 @@
|
||||
#define QBT_VERSION_MINOR 5
|
||||
#define QBT_VERSION_BUGFIX 0
|
||||
#define QBT_VERSION_BUILD 0
|
||||
#define QBT_VERSION_STATUS "beta1" // Should be empty for stable releases!
|
||||
#define QBT_VERSION_STATUS "" // Should be empty for stable releases!
|
||||
|
||||
#define QBT__STRINGIFY(x) #x
|
||||
#define QBT_STRINGIFY(x) QBT__STRINGIFY(x)
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -541,7 +541,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,7 +589,8 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
|
||||
lastParent->appendChild(fileItem);
|
||||
m_filesIndex.push_back(fileItem);
|
||||
}
|
||||
emit layoutChanged();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void TorrentContentModel::notifySubtreeUpdated(const QModelIndex &index, const QVector<ColumnInterval> &columns)
|
||||
|
@@ -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)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user