You've already forked qBittorrent
mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-10-26 06:12:17 +01: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]
|
[qbittorrent.qbittorrent_master]
|
||||||
file_filter = src/lang/qbittorrent_<lang>.ts
|
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_file = src/lang/qbittorrent_en.ts
|
||||||
source_lang = en
|
source_lang = en
|
||||||
type = QT
|
type = QT
|
||||||
@@ -19,7 +19,7 @@ mode = developer
|
|||||||
|
|
||||||
[qbittorrent.qbittorrent_webui]
|
[qbittorrent.qbittorrent_webui]
|
||||||
file_filter = src/webui/www/translations/webui_<lang>.ts
|
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_file = src/webui/www/translations/webui_en.ts
|
||||||
source_lang = en
|
source_lang = en
|
||||||
type = QT
|
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
|
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)
|
- 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
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# 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>.
|
# Report bugs to <bugs.qbittorrent.org>.
|
||||||
#
|
#
|
||||||
@@ -611,8 +611,8 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='qbittorrent'
|
PACKAGE_NAME='qbittorrent'
|
||||||
PACKAGE_TARNAME='qbittorrent'
|
PACKAGE_TARNAME='qbittorrent'
|
||||||
PACKAGE_VERSION='v4.5.0beta1'
|
PACKAGE_VERSION='v4.5.0'
|
||||||
PACKAGE_STRING='qbittorrent v4.5.0beta1'
|
PACKAGE_STRING='qbittorrent v4.5.0'
|
||||||
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
|
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
|
||||||
PACKAGE_URL='https://www.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.
|
# 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.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
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]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1400,7 +1400,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of qbittorrent v4.5.0beta1:";;
|
short | recursive ) echo "Configuration of qbittorrent v4.5.0:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@@ -1533,7 +1533,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
qbittorrent configure v4.5.0beta1
|
qbittorrent configure v4.5.0
|
||||||
generated by GNU Autoconf 2.71
|
generated by GNU Autoconf 2.71
|
||||||
|
|
||||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||||
@@ -1648,7 +1648,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
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
|
generated by GNU Autoconf 2.71. Invocation command line was
|
||||||
|
|
||||||
$ $0$ac_configure_args_raw
|
$ $0$ac_configure_args_raw
|
||||||
@@ -4779,7 +4779,7 @@ fi
|
|||||||
|
|
||||||
# Define the identity of the package.
|
# Define the identity of the package.
|
||||||
PACKAGE='qbittorrent'
|
PACKAGE='qbittorrent'
|
||||||
VERSION='v4.5.0beta1'
|
VERSION='v4.5.0'
|
||||||
|
|
||||||
|
|
||||||
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
|
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
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
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
|
generated by GNU Autoconf 2.71. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
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
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config='$ac_cs_config_escaped'
|
ac_cs_config='$ac_cs_config_escaped'
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
qbittorrent config.status v4.5.0beta1
|
qbittorrent config.status v4.5.0
|
||||||
configured by $0, generated by GNU Autoconf 2.71,
|
configured by $0, generated by GNU Autoconf 2.71,
|
||||||
with options \\"\$ac_cs_config\\"
|
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_AUX_DIR([build-aux])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
: ${CFLAGS=""}
|
: ${CFLAGS=""}
|
||||||
|
|||||||
@@ -74,6 +74,6 @@
|
|||||||
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
|
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
|
||||||
<content_rating type="oars-1.1"/>
|
<content_rating type="oars-1.1"/>
|
||||||
<releases>
|
<releases>
|
||||||
<release version="4.5.0" date="2022-01-06"/>
|
<release version="4.5.0" date="2022-11-26"/>
|
||||||
</releases>
|
</releases>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ Name[is]=qBittorrent
|
|||||||
Comment[it]=Scarica e condividi file tramite BitTorrent
|
Comment[it]=Scarica e condividi file tramite BitTorrent
|
||||||
GenericName[it]=Client BitTorrent
|
GenericName[it]=Client BitTorrent
|
||||||
Name[it]=qBittorrent
|
Name[it]=qBittorrent
|
||||||
Comment[ja]=BitTorrent でファイルをダウンロードおよび共有します
|
Comment[ja]=BitTorrent でファイルをダウンロードおよび共有
|
||||||
GenericName[ja]=BitTorrent クライアント
|
GenericName[ja]=BitTorrent クライアント
|
||||||
Name[ja]=qBittorrent
|
Name[ja]=qBittorrent
|
||||||
Comment[ka]=გადმოტვირთეთ და გააზიარეთ ფაილები BitTorrent-ის საშუალებით
|
Comment[ka]=გადმოტვირთეთ და გააზიარეთ ფაილები BitTorrent-ის საშუალებით
|
||||||
|
|||||||
@@ -882,7 +882,7 @@ void Application::createStartupProgressDialog()
|
|||||||
m_startupProgressDialog = new QProgressDialog(tr("Loading torrents..."), tr("Exit"), 0, 100);
|
m_startupProgressDialog = new QProgressDialog(tr("Loading torrents..."), tr("Exit"), 0, 100);
|
||||||
m_startupProgressDialog->setAttribute(Qt::WA_DeleteOnClose);
|
m_startupProgressDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
m_startupProgressDialog->setWindowFlag(Qt::WindowMinimizeButtonHint);
|
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->setAutoReset(false);
|
||||||
m_startupProgressDialog->setAutoClose(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"));
|
return nonstd::make_unexpected(tr("Cannot parse resume data: invalid format"));
|
||||||
|
|
||||||
LoadTorrentParams torrentParams;
|
LoadTorrentParams torrentParams;
|
||||||
torrentParams.restored = true;
|
|
||||||
torrentParams.category = fromLTString(resumeDataRoot.dict_find_string_value("qBt-category"));
|
torrentParams.category = fromLTString(resumeDataRoot.dict_find_string_value("qBt-category"));
|
||||||
torrentParams.name = fromLTString(resumeDataRoot.dict_find_string_value("qBt-name"));
|
torrentParams.name = fromLTString(resumeDataRoot.dict_find_string_value("qBt-name"));
|
||||||
torrentParams.hasSeedStatus = resumeDataRoot.dict_find_int_value("qBt-seedStatus");
|
torrentParams.hasSeedStatus = resumeDataRoot.dict_find_int_value("qBt-seedStatus");
|
||||||
|
|||||||
@@ -196,7 +196,6 @@ namespace BitTorrent
|
|||||||
LoadTorrentParams parseQueryResultRow(const QSqlQuery &query)
|
LoadTorrentParams parseQueryResultRow(const QSqlQuery &query)
|
||||||
{
|
{
|
||||||
LoadTorrentParams resumeData;
|
LoadTorrentParams resumeData;
|
||||||
resumeData.restored = true;
|
|
||||||
resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
|
resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
|
||||||
resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
|
resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
|
||||||
const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
|
const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
|
||||||
|
|||||||
@@ -58,7 +58,5 @@ namespace BitTorrent
|
|||||||
|
|
||||||
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
|
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
|
||||||
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
|
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);
|
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
|
qreal PeerInfo::progress() const
|
||||||
{
|
{
|
||||||
return m_nativeInfo.progress;
|
return m_nativeInfo.progress;
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ namespace BitTorrent
|
|||||||
|
|
||||||
PeerAddress address() const;
|
PeerAddress address() const;
|
||||||
QString client() const;
|
QString client() const;
|
||||||
|
QString peerIdClient() const;
|
||||||
qreal progress() const;
|
qreal progress() const;
|
||||||
int payloadUpSpeed() const;
|
int payloadUpSpeed() const;
|
||||||
int payloadDownSpeed() const;
|
int payloadDownSpeed() const;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include <libtorrent/session.hpp>
|
#include <libtorrent/session.hpp>
|
||||||
|
|
||||||
|
#include "base/algorithm.h"
|
||||||
#include "base/logger.h"
|
#include "base/logger.h"
|
||||||
|
|
||||||
PortForwarderImpl::PortForwarderImpl(lt::session *provider, QObject *parent)
|
PortForwarderImpl::PortForwarderImpl(lt::session *provider, QObject *parent)
|
||||||
@@ -63,45 +64,64 @@ void PortForwarderImpl::setEnabled(const bool enabled)
|
|||||||
m_storeActive = enabled;
|
m_storeActive = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortForwarderImpl::addPort(const quint16 port)
|
void PortForwarderImpl::setPorts(const QString &profile, QSet<quint16> ports)
|
||||||
{
|
{
|
||||||
if (m_mappedPorts.contains(port))
|
PortMapping &portMapping = m_portProfiles[profile];
|
||||||
return;
|
Algorithm::removeIf(portMapping, [this, &ports](const quint16 port, const std::vector<lt::port_mapping_t> &handles)
|
||||||
|
|
||||||
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())
|
|
||||||
{
|
{
|
||||||
for (const lt::port_mapping_t &portMapping : *iter)
|
// keep existing forwardings
|
||||||
m_provider->delete_port_mapping(portMapping);
|
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()
|
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_upnp, true);
|
||||||
settingsPack.set_bool(lt::settings_pack::enable_natpmp, 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();
|
const quint16 port = iter.key();
|
||||||
iter.value() = m_provider->add_port_mapping(lt::session::tcp, port, port);
|
iter.value() = m_provider->add_port_mapping(lt::session::tcp, port, port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogMsg(tr("UPnP/NAT-PMP support: ON"), Log::INFO);
|
LogMsg(tr("UPnP/NAT-PMP support: ON"), Log::INFO);
|
||||||
@@ -109,14 +129,18 @@ void PortForwarderImpl::start()
|
|||||||
|
|
||||||
void PortForwarderImpl::stop()
|
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_upnp, false);
|
||||||
settingsPack.set_bool(lt::settings_pack::enable_natpmp, 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
|
// don't clear m_portProfiles so a later `start()` call can restore the port forwardings
|
||||||
for (auto iter = m_mappedPorts.begin(); iter != m_mappedPorts.end(); ++iter)
|
for (auto profileIter = m_portProfiles.begin(); profileIter != m_portProfiles.end(); ++profileIter)
|
||||||
iter.value().clear();
|
{
|
||||||
|
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);
|
LogMsg(tr("UPnP/NAT-PMP support: OFF"), Log::INFO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <libtorrent/portmap.hpp>
|
#include <libtorrent/portmap.hpp>
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
#include "base/net/portforwarder.h"
|
#include "base/net/portforwarder.h"
|
||||||
#include "base/settingvalue.h"
|
#include "base/settingvalue.h"
|
||||||
@@ -50,8 +51,8 @@ public:
|
|||||||
bool isEnabled() const override;
|
bool isEnabled() const override;
|
||||||
void setEnabled(bool enabled) override;
|
void setEnabled(bool enabled) override;
|
||||||
|
|
||||||
void addPort(quint16 port) override;
|
void setPorts(const QString &profile, QSet<quint16> ports) override;
|
||||||
void deletePort(quint16 port) override;
|
void removePorts(const QString &profile) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void start();
|
void start();
|
||||||
@@ -59,5 +60,8 @@ private:
|
|||||||
|
|
||||||
CachedSettingValue<bool> m_storeActive;
|
CachedSettingValue<bool> m_storeActive;
|
||||||
lt::session *const m_provider = nullptr;
|
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/logger.h"
|
||||||
#include "base/net/downloadmanager.h"
|
#include "base/net/downloadmanager.h"
|
||||||
#include "base/net/proxyconfigurationmanager.h"
|
#include "base/net/proxyconfigurationmanager.h"
|
||||||
|
#include "base/preferences.h"
|
||||||
#include "base/profile.h"
|
#include "base/profile.h"
|
||||||
#include "base/torrentfileguard.h"
|
#include "base/torrentfileguard.h"
|
||||||
#include "base/torrentfilter.h"
|
#include "base/torrentfilter.h"
|
||||||
@@ -548,8 +549,6 @@ SessionImpl::SessionImpl(QObject *parent)
|
|||||||
if (isExcludedFileNamesEnabled())
|
if (isExcludedFileNamesEnabled())
|
||||||
populateExcludedFileNamesRegExpList();
|
populateExcludedFileNamesRegExpList();
|
||||||
|
|
||||||
enableTracker(isTrackerEnabled());
|
|
||||||
|
|
||||||
connect(Net::ProxyConfigurationManager::instance()
|
connect(Net::ProxyConfigurationManager::instance()
|
||||||
, &Net::ProxyConfigurationManager::proxyConfigurationChanged
|
, &Net::ProxyConfigurationManager::proxyConfigurationChanged
|
||||||
, this, &SessionImpl::configureDeferred);
|
, this, &SessionImpl::configureDeferred);
|
||||||
@@ -569,11 +568,14 @@ SessionImpl::SessionImpl(QObject *parent)
|
|||||||
|
|
||||||
m_ioThread->start();
|
m_ioThread->start();
|
||||||
|
|
||||||
|
initMetrics();
|
||||||
|
loadStatistics();
|
||||||
|
|
||||||
// initialize PortForwarder instance
|
// initialize PortForwarder instance
|
||||||
new PortForwarderImpl(m_nativeSession);
|
new PortForwarderImpl(m_nativeSession);
|
||||||
|
|
||||||
initMetrics();
|
// start embedded tracker
|
||||||
loadStatistics();
|
enableTracker(isTrackerEnabled());
|
||||||
|
|
||||||
prepareStartup();
|
prepareStartup();
|
||||||
}
|
}
|
||||||
@@ -1055,25 +1057,25 @@ void SessionImpl::adjustLimits()
|
|||||||
{
|
{
|
||||||
if (isQueueingSystemEnabled())
|
if (isQueueingSystemEnabled())
|
||||||
{
|
{
|
||||||
lt::settings_pack settingsPack = m_nativeSession->get_settings();
|
lt::settings_pack settingsPack;
|
||||||
adjustLimits(settingsPack);
|
// Internally increase the queue limits to ensure that the magnet is started
|
||||||
m_nativeSession->apply_settings(settingsPack);
|
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()
|
void SessionImpl::applyBandwidthLimits()
|
||||||
{
|
{
|
||||||
lt::settings_pack settingsPack = m_nativeSession->get_settings();
|
lt::settings_pack settingsPack;
|
||||||
applyBandwidthLimits(settingsPack);
|
settingsPack.set_int(lt::settings_pack::download_rate_limit, downloadSpeedLimit());
|
||||||
m_nativeSession->apply_settings(settingsPack);
|
settingsPack.set_int(lt::settings_pack::upload_rate_limit, uploadSpeedLimit());
|
||||||
|
m_nativeSession->apply_settings(std::move(settingsPack));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionImpl::configure()
|
void SessionImpl::configure()
|
||||||
{
|
{
|
||||||
lt::settings_pack settingsPack = m_nativeSession->get_settings();
|
m_nativeSession->apply_settings(loadLTSettings());
|
||||||
loadLTSettings(settingsPack);
|
|
||||||
m_nativeSession->apply_settings(settingsPack);
|
|
||||||
|
|
||||||
configureComponents();
|
configureComponents();
|
||||||
|
|
||||||
m_deferredConfigureScheduled = false;
|
m_deferredConfigureScheduled = false;
|
||||||
@@ -1390,7 +1392,12 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
|
|||||||
context->startupStorage->deleteLater();
|
context->startupStorage->deleteLater();
|
||||||
|
|
||||||
if (context->currentStorageType == ResumeDataStorageType::Legacy)
|
if (context->currentStorageType == ResumeDataStorageType::Legacy)
|
||||||
Utils::Fs::removeFile(dbPath);
|
{
|
||||||
|
connect(context->startupStorage, &QObject::destroyed, [dbPath]
|
||||||
|
{
|
||||||
|
Utils::Fs::removeFile(dbPath);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context->deleteLater();
|
context->deleteLater();
|
||||||
@@ -1419,10 +1426,11 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
|
|||||||
|
|
||||||
void SessionImpl::initializeNativeSession()
|
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_str(lt::settings_pack::peer_fingerprint, peerId);
|
||||||
|
|
||||||
pack.set_bool(lt::settings_pack::listen_system_port_fallback, false);
|
pack.set_bool(lt::settings_pack::listen_system_port_fallback, false);
|
||||||
pack.set_str(lt::settings_pack::user_agent, USER_AGENT.toStdString());
|
pack.set_str(lt::settings_pack::user_agent, USER_AGENT.toStdString());
|
||||||
pack.set_bool(lt::settings_pack::use_dht_as_fallback, false);
|
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);
|
pack.set_bool(lt::settings_pack::enable_set_file_valid_data, true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
loadLTSettings(pack);
|
lt::session_params sessionParams {std::move(pack), {}};
|
||||||
lt::session_params sessionParams {pack, {}};
|
|
||||||
#ifdef QBT_USES_LIBTORRENT2
|
#ifdef QBT_USES_LIBTORRENT2
|
||||||
switch (diskIOType())
|
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
|
if (limit <= -1)
|
||||||
const auto adjustLimit = [this](const int limit) -> int
|
return limit;
|
||||||
{
|
// check for overflow: (limit + m_extraLimit) < std::numeric_limits<int>::max()
|
||||||
if (limit <= -1)
|
return (m_extraLimit < (std::numeric_limits<int>::max() - limit))
|
||||||
return limit;
|
? (limit + m_extraLimit)
|
||||||
// check for overflow: (limit + m_extraLimit) < std::numeric_limits<int>::max()
|
: 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionImpl::initMetrics()
|
void SessionImpl::initMetrics()
|
||||||
@@ -1564,8 +1557,10 @@ void SessionImpl::initMetrics()
|
|||||||
m_metricIndices.disk.diskJobTime = findMetricIndex("disk.disk_job_time");
|
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
|
const lt::alert_category_t alertMask = lt::alert::error_notification
|
||||||
| lt::alert::file_progress_notification
|
| lt::alert::file_progress_notification
|
||||||
| lt::alert::ip_block_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
|
// It will not take affect until the listen_interfaces settings is updated
|
||||||
settingsPack.set_int(lt::settings_pack::listen_queue_size, socketBacklogSize());
|
settingsPack.set_int(lt::settings_pack::listen_queue_size, socketBacklogSize());
|
||||||
|
|
||||||
configureNetworkInterfaces(settingsPack);
|
applyNetworkInterfacesSettings(settingsPack);
|
||||||
applyBandwidthLimits(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
|
// 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);
|
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
|
// Queueing System
|
||||||
if (isQueueingSystemEnabled())
|
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_int(lt::settings_pack::active_seeds, maxActiveUploads());
|
||||||
settingsPack.set_bool(lt::settings_pack::dont_count_slow_torrents, ignoreSlowTorrentsForQueueing());
|
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);
|
settingsPack.set_int(lt::settings_pack::seed_choking_algorithm, lt::settings_pack::anti_leech);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return settingsPack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionImpl::configureNetworkInterfaces(lt::settings_pack &settingsPack)
|
void SessionImpl::applyNetworkInterfacesSettings(lt::settings_pack &settingsPack) const
|
||||||
{
|
{
|
||||||
if (m_listenInterfaceConfigured)
|
if (m_listenInterfaceConfigured)
|
||||||
return;
|
return;
|
||||||
@@ -1980,16 +1981,27 @@ void SessionImpl::configurePeerClasses()
|
|||||||
|
|
||||||
void SessionImpl::enableTracker(const bool enable)
|
void SessionImpl::enableTracker(const bool enable)
|
||||||
{
|
{
|
||||||
|
const QString profile = u"embeddedTracker"_qs;
|
||||||
|
auto *portForwarder = Net::PortForwarder::instance();
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
if (!m_tracker)
|
if (!m_tracker)
|
||||||
m_tracker = new Tracker(this);
|
m_tracker = new Tracker(this);
|
||||||
|
|
||||||
m_tracker->start();
|
m_tracker->start();
|
||||||
|
|
||||||
|
const auto *pref = Preferences::instance();
|
||||||
|
if (pref->isTrackerPortForwardingEnabled())
|
||||||
|
portForwarder->setPorts(profile, {static_cast<quint16>(pref->getTrackerPort())});
|
||||||
|
else
|
||||||
|
portForwarder->removePorts(profile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
delete m_tracker;
|
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;
|
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);
|
p.added_time = std::time(nullptr);
|
||||||
|
|
||||||
// Limits
|
// Limits
|
||||||
@@ -2898,10 +2907,8 @@ void SessionImpl::saveResumeData()
|
|||||||
saveTorrentsQueue();
|
saveTorrentsQueue();
|
||||||
|
|
||||||
for (const TorrentImpl *torrent : asConst(m_torrents))
|
for (const TorrentImpl *torrent : asConst(m_torrents))
|
||||||
{
|
|
||||||
torrent->nativeHandle().save_resume_data(lt::torrent_handle::only_if_modified);
|
torrent->nativeHandle().save_resume_data(lt::torrent_handle::only_if_modified);
|
||||||
++m_numResumeData;
|
m_numResumeData += m_torrents.size();
|
||||||
}
|
|
||||||
|
|
||||||
QElapsedTimer timer;
|
QElapsedTimer timer;
|
||||||
timer.start();
|
timer.start();
|
||||||
@@ -5207,9 +5214,9 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle,
|
|||||||
if (const InfoHash infoHash = torrent->infoHash(); infoHash.isHybrid())
|
if (const InfoHash infoHash = torrent->infoHash(); infoHash.isHybrid())
|
||||||
m_hybridTorrentsByAltID.insert(TorrentID::fromSHA1Hash(infoHash.v1()), torrent);
|
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
|
// The following is useless for newly added magnet
|
||||||
if (torrent->hasMetadata())
|
if (torrent->hasMetadata())
|
||||||
@@ -5225,7 +5232,7 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle,
|
|||||||
m_seedingLimitTimer->start();
|
m_seedingLimitTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.restored)
|
if (!isRestored())
|
||||||
{
|
{
|
||||||
LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name()));
|
LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -474,11 +474,10 @@ namespace BitTorrent
|
|||||||
Q_INVOKABLE void configure();
|
Q_INVOKABLE void configure();
|
||||||
void configureComponents();
|
void configureComponents();
|
||||||
void initializeNativeSession();
|
void initializeNativeSession();
|
||||||
void loadLTSettings(lt::settings_pack &settingsPack);
|
lt::settings_pack loadLTSettings() const;
|
||||||
void configureNetworkInterfaces(lt::settings_pack &settingsPack);
|
void applyNetworkInterfacesSettings(lt::settings_pack &settingsPack) const;
|
||||||
void configurePeerClasses();
|
void configurePeerClasses();
|
||||||
void adjustLimits(lt::settings_pack &settingsPack) const;
|
int adjustLimit(int limit) const;
|
||||||
void applyBandwidthLimits(lt::settings_pack &settingsPack) const;
|
|
||||||
void initMetrics();
|
void initMetrics();
|
||||||
void adjustLimits();
|
void adjustLimits();
|
||||||
void applyBandwidthLimits();
|
void applyBandwidthLimits();
|
||||||
@@ -553,7 +552,7 @@ namespace BitTorrent
|
|||||||
|
|
||||||
bool m_deferredConfigureScheduled = false;
|
bool m_deferredConfigureScheduled = false;
|
||||||
bool m_IPFilteringConfigured = false;
|
bool m_IPFilteringConfigured = false;
|
||||||
bool m_listenInterfaceConfigured = false;
|
mutable bool m_listenInterfaceConfigured = false;
|
||||||
|
|
||||||
CachedSettingValue<bool> m_isDHTEnabled;
|
CachedSettingValue<bool> m_isDHTEnabled;
|
||||||
CachedSettingValue<bool> m_isLSDEnabled;
|
CachedSettingValue<bool> m_isLSDEnabled;
|
||||||
|
|||||||
@@ -690,9 +690,9 @@ bool TorrentImpl::needSaveResumeData() const
|
|||||||
return m_nativeStatus.need_save_resume;
|
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);
|
m_session->handleTorrentSaveResumeDataRequested(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ namespace BitTorrent
|
|||||||
void handleStateUpdate(const lt::torrent_status &nativeStatus);
|
void handleStateUpdate(const lt::torrent_status &nativeStatus);
|
||||||
void handleCategoryOptionsChanged();
|
void handleCategoryOptionsChanged();
|
||||||
void handleAppendExtensionToggled();
|
void handleAppendExtensionToggled();
|
||||||
void saveResumeData();
|
void saveResumeData(lt::resume_data_flags_t flags = {});
|
||||||
void handleMoveStorageJobFinished(const Path &path, bool hasOutstandingJob);
|
void handleMoveStorageJobFinished(const Path &path, bool hasOutstandingJob);
|
||||||
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
|
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
|
||||||
void updatePeerCount(const QString &trackerURL, const TrackerEntry::Endpoint &endpoint, int count);
|
void updatePeerCount(const QString &trackerURL, const TrackerEntry::Endpoint &endpoint, int count);
|
||||||
|
|||||||
@@ -203,12 +203,12 @@ Tracker::Tracker(QObject *parent)
|
|||||||
|
|
||||||
bool Tracker::start()
|
bool Tracker::start()
|
||||||
{
|
{
|
||||||
const QHostAddress ip = QHostAddress::Any;
|
|
||||||
const int port = Preferences::instance()->getTrackerPort();
|
const int port = Preferences::instance()->getTrackerPort();
|
||||||
|
|
||||||
if (m_server->isListening())
|
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
|
// Already listening on the right port, just return
|
||||||
return true;
|
return true;
|
||||||
@@ -218,9 +218,9 @@ bool Tracker::start()
|
|||||||
m_server->close();
|
m_server->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen on the predefined port
|
// Listen on port
|
||||||
|
const QHostAddress ip = QHostAddress::Any;
|
||||||
const bool listenSuccess = m_server->listen(ip, port);
|
const bool listenSuccess = m_server->listen(ip, port);
|
||||||
|
|
||||||
if (listenSuccess)
|
if (listenSuccess)
|
||||||
{
|
{
|
||||||
LogMsg(tr("Embedded Tracker: Now listening on IP: %1, port: %2")
|
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
|
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents
|
||||||
request.setRawHeader("Referer", request.url().toEncoded().data());
|
request.setRawHeader("Referer", request.url().toEncoded().data());
|
||||||
#ifdef QT_NO_COMPRESS
|
#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
|
// and reply data auto-decompression in QT will also be disabled. But we can support
|
||||||
// gzip encoding and manually decompress the reply data.
|
// gzip encoding and manually decompress the reply data.
|
||||||
request.setRawHeader("Accept-Encoding", "gzip");
|
request.setRawHeader("Accept-Encoding", "gzip");
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
|
class QString;
|
||||||
|
|
||||||
namespace Net
|
namespace Net
|
||||||
{
|
{
|
||||||
@@ -45,8 +48,8 @@ namespace Net
|
|||||||
virtual bool isEnabled() const = 0;
|
virtual bool isEnabled() const = 0;
|
||||||
virtual void setEnabled(bool enabled) = 0;
|
virtual void setEnabled(bool enabled) = 0;
|
||||||
|
|
||||||
virtual void addPort(quint16 port) = 0;
|
virtual void setPorts(const QString &profile, QSet<quint16> ports) = 0;
|
||||||
virtual void deletePort(quint16 port) = 0;
|
virtual void removePorts(const QString &profile) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static PortForwarder *m_instance;
|
static PortForwarder *m_instance;
|
||||||
|
|||||||
@@ -1164,6 +1164,16 @@ void Preferences::setTrackerPort(const int port)
|
|||||||
setValue(u"Preferences/Advanced/trackerPort"_qs, 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)
|
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
||||||
bool Preferences::isUpdateCheckEnabled() const
|
bool Preferences::isUpdateCheckEnabled() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -299,6 +299,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
int getTrackerPort() const;
|
int getTrackerPort() const;
|
||||||
void setTrackerPort(int port);
|
void setTrackerPort(int port);
|
||||||
|
bool isTrackerPortForwardingEnabled() const;
|
||||||
|
void setTrackerPortForwardingEnabled(bool enabled);
|
||||||
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
||||||
bool isUpdateCheckEnabled() const;
|
bool isUpdateCheckEnabled() const;
|
||||||
void setUpdateCheckEnabled(bool enabled);
|
void setUpdateCheckEnabled(bool enabled);
|
||||||
|
|||||||
@@ -277,9 +277,11 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result)
|
|||||||
|
|
||||||
void Feed::load()
|
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))
|
for (Article *article :asConst(m_articles))
|
||||||
articlesData.push_back(article->data());
|
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_MINOR 5
|
||||||
#define QBT_VERSION_BUGFIX 0
|
#define QBT_VERSION_BUGFIX 0
|
||||||
#define QBT_VERSION_BUILD 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) #x
|
||||||
#define QBT_STRINGIFY(x) QBT__STRINGIFY(x)
|
#define QBT_STRINGIFY(x) QBT__STRINGIFY(x)
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ namespace
|
|||||||
// embedded tracker
|
// embedded tracker
|
||||||
TRACKER_STATUS,
|
TRACKER_STATUS,
|
||||||
TRACKER_PORT,
|
TRACKER_PORT,
|
||||||
|
TRACKER_PORT_FORWARDING,
|
||||||
// libtorrent section
|
// libtorrent section
|
||||||
LIBTORRENT_HEADER,
|
LIBTORRENT_HEADER,
|
||||||
ASYNC_IO_THREADS,
|
ASYNC_IO_THREADS,
|
||||||
@@ -292,7 +293,9 @@ void AdvancedSettings::saveAdvancedSettings() const
|
|||||||
|
|
||||||
// Tracker
|
// Tracker
|
||||||
pref->setTrackerPort(m_spinBoxTrackerPort.value());
|
pref->setTrackerPort(m_spinBoxTrackerPort.value());
|
||||||
|
pref->setTrackerPortForwardingEnabled(m_checkBoxTrackerPortForwarding.isChecked());
|
||||||
session->setTrackerEnabled(m_checkBoxTrackerStatus.isChecked());
|
session->setTrackerEnabled(m_checkBoxTrackerStatus.isChecked());
|
||||||
|
|
||||||
// Choking algorithm
|
// Choking algorithm
|
||||||
session->setChokingAlgorithm(m_comboBoxChokingAlgorithm.currentData().value<BitTorrent::ChokingAlgorithm>());
|
session->setChokingAlgorithm(m_comboBoxChokingAlgorithm.currentData().value<BitTorrent::ChokingAlgorithm>());
|
||||||
// Seed choking algorithm
|
// Seed choking algorithm
|
||||||
@@ -732,6 +735,9 @@ void AdvancedSettings::loadAdvancedSettings()
|
|||||||
m_spinBoxTrackerPort.setMaximum(65535);
|
m_spinBoxTrackerPort.setMaximum(65535);
|
||||||
m_spinBoxTrackerPort.setValue(pref->getTrackerPort());
|
m_spinBoxTrackerPort.setValue(pref->getTrackerPort());
|
||||||
addRow(TRACKER_PORT, tr("Embedded tracker port"), &m_spinBoxTrackerPort);
|
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
|
// Choking algorithm
|
||||||
m_comboBoxChokingAlgorithm.addItem(tr("Fixed slots"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::FixedSlots));
|
m_comboBoxChokingAlgorithm.addItem(tr("Fixed slots"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::FixedSlots));
|
||||||
m_comboBoxChokingAlgorithm.addItem(tr("Upload rate based"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::RateBased));
|
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;
|
m_spinBoxSavePathHistoryLength, m_spinBoxPeerTurnover, m_spinBoxPeerTurnoverCutoff, m_spinBoxPeerTurnoverInterval, m_spinBoxRequestQueueSize;
|
||||||
QCheckBox m_checkBoxOsCache, m_checkBoxRecheckCompleted, m_checkBoxResolveCountries, m_checkBoxResolveHosts,
|
QCheckBox m_checkBoxOsCache, m_checkBoxRecheckCompleted, m_checkBoxResolveCountries, m_checkBoxResolveHosts,
|
||||||
m_checkBoxProgramNotifications, m_checkBoxTorrentAddedNotifications, m_checkBoxReannounceWhenAddressChanged, m_checkBoxTrackerFavicon, m_checkBoxTrackerStatus,
|
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_checkBoxMultiConnectionsPerIp, m_checkBoxValidateHTTPSTrackerCertificate, m_checkBoxSSRFMitigation, m_checkBoxBlockPeersOnPrivilegedPorts, m_checkBoxPieceExtentAffinity,
|
||||||
m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport;
|
m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport;
|
||||||
QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxDiskIOReadMode, m_comboBoxDiskIOWriteMode, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm,
|
QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxDiskIOReadMode, m_comboBoxDiskIOWriteMode, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm,
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
|||||||
, m_properties(parent)
|
, m_properties(parent)
|
||||||
{
|
{
|
||||||
// Load settings
|
// Load settings
|
||||||
loadSettings();
|
const bool columnLoaded = loadSettings();
|
||||||
// Visual settings
|
// Visual settings
|
||||||
setUniformRowHeights(true);
|
setUniformRowHeights(true);
|
||||||
setRootIsDecorated(false);
|
setRootIsDecorated(false);
|
||||||
@@ -109,6 +109,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
|||||||
m_listModel->setHeaderData(PeerListColumns::FLAGS, Qt::Horizontal, tr("Flags"));
|
m_listModel->setHeaderData(PeerListColumns::FLAGS, Qt::Horizontal, tr("Flags"));
|
||||||
m_listModel->setHeaderData(PeerListColumns::CONNECTION, Qt::Horizontal, tr("Connection"));
|
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::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::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::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"));
|
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->setSourceModel(m_listModel);
|
||||||
m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
setModel(m_proxyModel);
|
setModel(m_proxyModel);
|
||||||
|
|
||||||
hideColumn(PeerListColumns::IP_HIDDEN);
|
hideColumn(PeerListColumns::IP_HIDDEN);
|
||||||
hideColumn(PeerListColumns::COL_COUNT);
|
hideColumn(PeerListColumns::COL_COUNT);
|
||||||
|
|
||||||
|
// Default hidden columns
|
||||||
|
if (!columnLoaded)
|
||||||
|
{
|
||||||
|
hideColumn(PeerListColumns::PEERID_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
m_resolveCountries = Preferences::instance()->resolvePeerCountries();
|
m_resolveCountries = Preferences::instance()->resolvePeerCountries();
|
||||||
if (!m_resolveCountries)
|
if (!m_resolveCountries)
|
||||||
hideColumn(PeerListColumns::COUNTRY);
|
hideColumn(PeerListColumns::COUNTRY);
|
||||||
@@ -371,9 +380,9 @@ void PeerListWidget::clear()
|
|||||||
m_listModel->removeRows(0, nbrows);
|
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
|
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());
|
setModelData(row, PeerListColumns::FLAGS, peer.flags(), peer.flags(), {}, peer.flagsDescription());
|
||||||
const QString client = peer.client().toHtmlEscaped();
|
const QString client = peer.client().toHtmlEscaped();
|
||||||
setModelData(row, PeerListColumns::CLIENT, client, client, {}, client);
|
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);
|
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);
|
const QString downSpeed = (hideValues && (peer.payloadDownSpeed() <= 0)) ? QString {} : Utils::Misc::friendlyUnit(peer.payloadDownSpeed(), true);
|
||||||
setModelData(row, PeerListColumns::DOWN_SPEED, downSpeed, peer.payloadDownSpeed(), intDataTextAlignment);
|
setModelData(row, PeerListColumns::DOWN_SPEED, downSpeed, peer.payloadDownSpeed(), intDataTextAlignment);
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public:
|
|||||||
CONNECTION,
|
CONNECTION,
|
||||||
FLAGS,
|
FLAGS,
|
||||||
CLIENT,
|
CLIENT,
|
||||||
|
PEERID_CLIENT,
|
||||||
PROGRESS,
|
PROGRESS,
|
||||||
DOWN_SPEED,
|
DOWN_SPEED,
|
||||||
UP_SPEED,
|
UP_SPEED,
|
||||||
@@ -87,7 +88,7 @@ public:
|
|||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void loadSettings();
|
bool loadSettings();
|
||||||
void saveSettings() const;
|
void saveSettings() const;
|
||||||
void displayColumnHeaderMenu();
|
void displayColumnHeaderMenu();
|
||||||
void showPeerListMenu();
|
void showPeerListMenu();
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ StatusBar::StatusBar(QWidget *parent)
|
|||||||
{
|
{
|
||||||
#ifndef Q_OS_MACOS
|
#ifndef Q_OS_MACOS
|
||||||
// Redefining global stylesheet breaks certain elements on mac like tabs.
|
// 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);
|
setStyleSheet(u"QStatusBar::item { border-width: 0; }"_qs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -541,7 +541,8 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
|
|||||||
if (filesCount <= 0)
|
if (filesCount <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
emit layoutAboutToBeChanged();
|
beginResetModel();
|
||||||
|
|
||||||
// Initialize files_index array
|
// Initialize files_index array
|
||||||
qDebug("Torrent contains %d files", filesCount);
|
qDebug("Torrent contains %d files", filesCount);
|
||||||
m_filesIndex.reserve(filesCount);
|
m_filesIndex.reserve(filesCount);
|
||||||
@@ -588,7 +589,8 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
|
|||||||
lastParent->appendChild(fileItem);
|
lastParent->appendChild(fileItem);
|
||||||
m_filesIndex.push_back(fileItem);
|
m_filesIndex.push_back(fileItem);
|
||||||
}
|
}
|
||||||
emit layoutChanged();
|
|
||||||
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModel::notifySubtreeUpdated(const QModelIndex &index, const QVector<ColumnInterval> &columns)
|
void TorrentContentModel::notifySubtreeUpdated(const QModelIndex &index, const QVector<ColumnInterval> &columns)
|
||||||
|
|||||||
@@ -79,25 +79,19 @@ void TorrentContentTreeView::keyPressEvent(QKeyEvent *event)
|
|||||||
|
|
||||||
event->accept();
|
event->accept();
|
||||||
|
|
||||||
QModelIndex current = currentNameCell();
|
const QVariant value = currentNameCell().data(Qt::CheckStateRole);
|
||||||
|
|
||||||
QVariant value = current.data(Qt::CheckStateRole);
|
|
||||||
if (!value.isValid())
|
if (!value.isValid())
|
||||||
{
|
{
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
|
const Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked)
|
||||||
? Qt::Unchecked : Qt::Checked);
|
? Qt::Unchecked : Qt::Checked;
|
||||||
|
|
||||||
const QModelIndexList selection = selectionModel()->selectedRows(TorrentContentModelItem::COL_NAME);
|
const QModelIndexList selection = selectionModel()->selectedRows(TorrentContentModelItem::COL_NAME);
|
||||||
|
|
||||||
for (const QModelIndex &index : selection)
|
for (const QModelIndex &index : selection)
|
||||||
{
|
|
||||||
Q_ASSERT(index.column() == TorrentContentModelItem::COL_NAME);
|
|
||||||
model()->setData(index, state, Qt::CheckStateRole);
|
model()->setData(index, state, Qt::CheckStateRole);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentTreeView::renameSelectedFile(BitTorrent::AbstractFileStorage &fileStorage)
|
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())
|
if (!current.isValid())
|
||||||
{
|
{
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return model()->index(current.row(), TorrentContentModelItem::COL_NAME, current.parent());
|
return current.siblingAtColumn(TorrentContentModelItem::COL_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentTreeView::wheelEvent(QWheelEvent *event)
|
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