mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-24 17:28:04 -06:00
Compare commits
53 Commits
release-4.
...
release-4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d26f4c5f7 | ||
|
|
8a09558ed8 | ||
|
|
60b1e692b9 | ||
|
|
ce554e6c77 | ||
|
|
5d151cca9d | ||
|
|
e4730191db | ||
|
|
49aab492e0 | ||
|
|
2d4d246268 | ||
|
|
09e558ae0b | ||
|
|
a3fd6633c4 | ||
|
|
1eb246c98b | ||
|
|
96e0c0df20 | ||
|
|
aa8f420681 | ||
|
|
7974b5a95c | ||
|
|
ed4570cb4d | ||
|
|
01d851440b | ||
|
|
e5943b64c1 | ||
|
|
933e56494c | ||
|
|
140e73be4e | ||
|
|
960b9b855f | ||
|
|
1e1d55b26d | ||
|
|
925bf7715c | ||
|
|
399d3ad85a | ||
|
|
d923c03d52 | ||
|
|
699b91ab8d | ||
|
|
abd6eb2ff3 | ||
|
|
32f29e72c6 | ||
|
|
e76bac4131 | ||
|
|
8b94642ab1 | ||
|
|
d3497148c5 | ||
|
|
27baa55443 | ||
|
|
fd3d4d479a | ||
|
|
4b0a2d050a | ||
|
|
d85c14864b | ||
|
|
ee696e6f36 | ||
|
|
6ccbd8472c | ||
|
|
8ec26e9ea9 | ||
|
|
45e31a153c | ||
|
|
7c23d800e6 | ||
|
|
4dbf6af733 | ||
|
|
bdc03b1c75 | ||
|
|
9bfc74a1bc | ||
|
|
5d03917877 | ||
|
|
d2f975a0f3 | ||
|
|
eedd47860a | ||
|
|
6e59248ea6 | ||
|
|
365554d064 | ||
|
|
70d1cb86fd | ||
|
|
ccb7c0d579 | ||
|
|
fd9941e2d8 | ||
|
|
2f89563fca | ||
|
|
261f601bd5 | ||
|
|
5157e4965a |
@@ -43,7 +43,7 @@ install:
|
||||
before_build:
|
||||
# setup env
|
||||
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
- SET PATH=%PATH%;c:\qbt\qt5_64\bin;%CACHE_DIR%\jom;
|
||||
- SET PATH=%PATH%;C:\Qt\5.15.2\msvc2019_64\bin;%CACHE_DIR%\jom
|
||||
# setup project
|
||||
- COPY /Y "%CACHE_DIR%\conf.pri" "%REPO_DIR%"
|
||||
# workarounds
|
||||
|
||||
14
.github/workflows/ci.yaml
vendored
14
.github/workflows/ci.yaml
vendored
@@ -7,10 +7,10 @@ name: GitHub Actions CI
|
||||
on: [pull_request, push]
|
||||
|
||||
env:
|
||||
VCPKG_COMMIT: 8f03e2264da6b95fa5b01dd89cdd5b499458d428
|
||||
VCPKG_COMMIT: 8dddc6c899ce6fdbeab38b525a31e7f23cb2d5bb
|
||||
VCPKG_DEST_MACOS: /Users/runner/qbt_tools/vcpkg
|
||||
VCPKG_DEST_WIN: C:\qbt_tools\vcpkg
|
||||
LIBTORRENT_VERSION_TAG: v1.2.13
|
||||
LIBTORRENT_VERSION_TAG: v1.2.14
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -42,12 +42,12 @@ jobs:
|
||||
libboost-dev libboost-chrono-dev libboost-random-dev libboost-system-dev
|
||||
# sudo apt install libqt5svg5-dev qtbase5-dev qttools5-dev # the Qt version in the standard repositories is too old...
|
||||
|
||||
# this will be installed under /opt/qt514. CMake will still find it automatically without additional hints
|
||||
# to speed up the process, only the required components are installed rather than the full qt514-meta-full metapackage
|
||||
- name: install Qt 5.14.2 from an external PPA
|
||||
# this will be installed under /opt/qt515. CMake will still find it automatically without additional hints
|
||||
# to speed up the process, only the required components are installed rather than the full qt515-meta-full metapackage
|
||||
- name: install Qt 5.15.2 from an external PPA
|
||||
run: |
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.14.2-focal
|
||||
sudo apt install qt514base qt514svg qt514tools
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-focal
|
||||
sudo apt install qt515base qt515svg qt515tools
|
||||
|
||||
- name: install libtorrent from source
|
||||
run: |
|
||||
|
||||
194
.travis.yml
194
.travis.yml
@@ -1,194 +0,0 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
dist: focal
|
||||
osx_image: xcode12.2
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- libt_branch=RC_1_2 gui=true build_system=qmake
|
||||
- libt_branch=RC_1_2 gui=false build_system=qmake
|
||||
- libt_branch=RC_1_2 gui=true build_system=cmake
|
||||
- libt_branch=RC_1_2 gui=false build_system=cmake
|
||||
global:
|
||||
- secure: "OI9CUjj4lTb0HwwIZU5PbECU3hLlAL6KC8KsbwohG8/O3j5fLcnmDsK4Ad9us5cC39sS11Jcd1kDP2qRcCuST/glVNhLkcjKkiQerOfd5nQ/qL4JYfz/1mfP5mdpz9jHKzpLUIG+TXkbSTjP6VVmsb5KPT+3pKEdRFZB+Pu9+J8="
|
||||
- coverity_branch: coverity_scan
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- env: libt_branch=RC_2_0 gui=true build_system=qmake
|
||||
os: linux
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: change
|
||||
|
||||
cache:
|
||||
ccache: true
|
||||
directories:
|
||||
- $HOME/travis/deb
|
||||
- $HOME/travis/brew
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "qbittorrent/qBittorrent"
|
||||
description: "Build submitted via Travis CI"
|
||||
build_command_prepend: "./bootstrap.sh && ./configure $qmake_conf"
|
||||
build_command: "make -j2"
|
||||
branch_pattern: $coverity_branch
|
||||
notification_email: sledgehammer999@qbittorrent.org
|
||||
apt:
|
||||
sources:
|
||||
# sources list: https://github.com/travis-ci/apt-source-safelist/blob/master/ubuntu.json
|
||||
- sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main'
|
||||
key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc'
|
||||
- sourceline: 'ppa:beineri/opt-qt-5.14.2-focal'
|
||||
packages:
|
||||
# packages list: https://github.com/travis-ci/apt-package-safelist/blob/master/ubuntu-trusty
|
||||
- [autoconf, automake, cmake, colormake]
|
||||
- [libboost-dev, libboost-system-dev]
|
||||
- libssl-dev
|
||||
- [qt514base, qt514svg, qt514tools]
|
||||
- zlib1g-dev
|
||||
|
||||
before_install:
|
||||
# only allow specific build for coverity scan, others will stop
|
||||
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ] && ! [ "$TRAVIS_OS_NAME" = "linux" -a "$libt_branch" = "RC_1_2" -a "$gui" = "true" -a "$build_system" = "qmake" ]; then exit ; fi
|
||||
|
||||
- shopt -s expand_aliases
|
||||
- alias make="colormake -j2" # Using nprocs/2 sometimes may fail (gcc is killed by system)
|
||||
- qbt_path="$HOME/qbt_install"
|
||||
- qmake_conf="$qmake_conf --prefix=$qbt_path"
|
||||
- cmake_conf="$cmake_conf -DCMAKE_INSTALL_PREFIX=$qbt_path"
|
||||
|
||||
# options for specific branches
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
# setup virtual display for after_success target
|
||||
if [ "$gui" = "true" ]; then export "DISPLAY=:99.0" && /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 ; fi ;
|
||||
# CMake from Kitware is installed in /usr/bin
|
||||
# TravisCI installs its own cmake to another location which ovverides other installations
|
||||
# if they don't call the new binary directly
|
||||
alias cmake="/usr/bin/cmake"
|
||||
|
||||
# Qt 5.14.2
|
||||
PATH="/opt/qt514/bin:$PATH"
|
||||
qmake_conf="$qmake_conf PKG_CONFIG_PATH=/opt/qt514/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
cmake_conf="$cmake_conf PKG_CONFIG_PATH=/opt/qt514/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
|
||||
fi
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedefs"
|
||||
|
||||
openssl_root_path="/usr/local/opt/openssl"
|
||||
qmake_conf="$qmake_conf PKG_CONFIG_PATH=$openssl_root_path/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
cmake_conf="$cmake_conf -DOPENSSL_ROOT_DIR=$openssl_root_path"
|
||||
fi
|
||||
- |
|
||||
if [ "$gui" = "false" ]; then
|
||||
qmake_conf="$qmake_conf --disable-gui"
|
||||
cmake_conf="$cmake_conf -DGUI=OFF"
|
||||
fi
|
||||
|
||||
# print settings
|
||||
- echo $libt_branch
|
||||
- echo $gui
|
||||
- echo $build_system
|
||||
- echo $qmake_conf
|
||||
- echo $cmake_conf
|
||||
|
||||
install:
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
# dependencies
|
||||
PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
|
||||
brew update > /dev/null
|
||||
brew upgrade cmake
|
||||
brew install ccache colormake boost openssl qt@5 zlib
|
||||
brew link --force qt@5 zlib
|
||||
|
||||
if [ "$build_system" = "cmake" ]; then
|
||||
sudo ln -s /usr/local/opt/qt/mkspecs /usr/local/mkspecs
|
||||
sudo ln -s /usr/local/opt/qt/plugins /usr/local/plugins
|
||||
fi
|
||||
fi
|
||||
- |
|
||||
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then
|
||||
export use_ccache=true
|
||||
ccache -M 512M
|
||||
ccache -V && ccache --show-stats && ccache --zero-stats
|
||||
fi
|
||||
- |
|
||||
if [ "$libt_branch" = "RC_1_2" ]; then
|
||||
pushd "$HOME"
|
||||
git clone --single-branch --branch RC_1_2 https://github.com/arvidn/libtorrent.git
|
||||
cd libtorrent
|
||||
git checkout tags/v1.2.13
|
||||
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_STANDARD=17 \
|
||||
-Ddeprecated-functions=OFF \
|
||||
-DOPENSSL_ROOT_DIR="$openssl_root_path" \
|
||||
./
|
||||
make
|
||||
sudo make install
|
||||
popd
|
||||
elif [ "$libt_branch" = "RC_2_0" ]; then
|
||||
pushd "$HOME"
|
||||
git clone --single-branch --branch RC_2_0 https://github.com/arvidn/libtorrent.git
|
||||
cd libtorrent
|
||||
git checkout tags/v2.0.3
|
||||
git submodule update --init --recursive
|
||||
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_STANDARD=17 \
|
||||
-Ddeprecated-functions=OFF \
|
||||
-DOPENSSL_ROOT_DIR="$openssl_root_path" \
|
||||
./
|
||||
make
|
||||
sudo make install
|
||||
popd
|
||||
fi
|
||||
|
||||
script:
|
||||
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ]; then exit ; fi # skip usual build when running coverity scan
|
||||
- |
|
||||
cd "$TRAVIS_BUILD_DIR"
|
||||
if [ "$build_system" = "qmake" ]; then
|
||||
# scan only as lupdate is prone to hang
|
||||
lupdate -extensions c,cpp,h,hpp,ui ./
|
||||
./bootstrap.sh
|
||||
./configure $qmake_conf CXXFLAGS="$CXXFLAGS"
|
||||
else
|
||||
mkdir build && cd build
|
||||
cmake $cmake_conf ../
|
||||
fi
|
||||
- make
|
||||
- make install
|
||||
|
||||
after_success:
|
||||
- if [ "$gui" = "true" ]; then qbt_exe="qbittorrent" ; else qbt_exe="qbittorrent-nox" ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd "$qbt_path/bin" ; fi
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
if [ "$build_system" = "qmake" ]; then
|
||||
macdeployqt "$TRAVIS_BUILD_DIR/src/$qbt_exe.app"
|
||||
cd "$TRAVIS_BUILD_DIR/src/$qbt_exe.app/Contents/MacOS"
|
||||
else
|
||||
cd "$qbt_path/$qbt_exe.app/Contents/MacOS"
|
||||
fi
|
||||
fi
|
||||
- ./$qbt_exe --version
|
||||
|
||||
after_script:
|
||||
- if [ "$use_ccache" = true ]; then ccache --show-stats ; fi
|
||||
@@ -12,9 +12,9 @@ project(qBittorrent
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
|
||||
# version requirements - older vesions may work, but you are on your own
|
||||
set(minBoostVersion 1.65)
|
||||
set(minQtVersion 5.14)
|
||||
set(minQtVersion 5.15.2)
|
||||
set(minOpenSSLVersion 1.1.1)
|
||||
set(minLibtorrentVersion 1.2.13)
|
||||
set(minLibtorrentVersion 1.2.14)
|
||||
set(minZlibVersion 1.2.11)
|
||||
|
||||
# features (some are platform-specific)
|
||||
|
||||
4
INSTALL
4
INSTALL
@@ -5,13 +5,13 @@ qBittorrent - A BitTorrent client in C++ / Qt
|
||||
|
||||
- Boost >= 1.65
|
||||
|
||||
- libtorrent-rasterbar >= 1.2.13 (by Arvid Norberg)
|
||||
- libtorrent-rasterbar >= 1.2.14 (by Arvid Norberg)
|
||||
* https://www.libtorrent.org/
|
||||
* Be careful: another library (the one used by rTorrent) uses a similar name
|
||||
|
||||
- OpenSSL >= 1.1.1
|
||||
|
||||
- Qt >= 5.14
|
||||
- Qt >= 5.15.2
|
||||
|
||||
- zlib >= 1.2.11
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
qBittorrent - A BitTorrent client in Qt
|
||||
------------------------------------------
|
||||
|
||||
[](https://travis-ci.org/qbittorrent/qBittorrent)
|
||||
[](https://ci.appveyor.com/project/qbittorrent/qBittorrent)
|
||||
[](https://github.com/qbittorrent/qBittorrent/actions)
|
||||
[](https://scan.coverity.com/projects/5494)
|
||||
|
||||
@@ -17,7 +17,7 @@ macro(qbt_common_config)
|
||||
)
|
||||
|
||||
target_compile_definitions(qbt_common_cfg INTERFACE
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x050e00
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x050f02
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_CAST_FROM_BYTEARRAY
|
||||
QT_USE_QSTRINGBUILDER
|
||||
|
||||
61
configure
vendored
61
configure
vendored
@@ -1450,7 +1450,7 @@ Some influential environment variables:
|
||||
directories to add to pkg-config's search path
|
||||
PKG_CONFIG_LIBDIR
|
||||
path overriding pkg-config's built-in search path
|
||||
QT_QMAKE value of host_bins for Qt5Core >= 5.14, overriding pkg-config
|
||||
QT_QMAKE value of host_bins for Qt5Core >= 5.15.2, overriding pkg-config
|
||||
Qt5Svg_CFLAGS
|
||||
C compiler flags for Qt5Svg, overriding pkg-config
|
||||
Qt5Svg_LIBS linker flags for Qt5Svg, overriding pkg-config
|
||||
@@ -5456,8 +5456,8 @@ printf "%s\n" "$enable_webui" >&6; }
|
||||
esac
|
||||
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.14\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.14") 2>&5
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.15.2\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.15.2") 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
@@ -5466,12 +5466,12 @@ if test -n "$QT_QMAKE"; then
|
||||
pkg_cv_QT_QMAKE="$QT_QMAKE"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.14\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.14") 2>&5
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.15.2\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.15.2") 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_QT_QMAKE=`$PKG_CONFIG --variable="host_bins" "Qt5Core >= 5.14" 2>/dev/null`
|
||||
pkg_cv_QT_QMAKE=`$PKG_CONFIG --variable="host_bins" "Qt5Core >= 5.15.2" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
@@ -5501,8 +5501,8 @@ fi
|
||||
|
||||
fi
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Qt5 qmake >= 5.14" >&5
|
||||
printf %s "checking for Qt5 qmake >= 5.14... " >&6; }
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Qt5 qmake >= 5.15.2" >&5
|
||||
printf %s "checking for Qt5 qmake >= 5.15.2... " >&6; }
|
||||
if test "x$QT_QMAKE" != "x"
|
||||
then :
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $QT_QMAKE" >&5
|
||||
@@ -5529,12 +5529,12 @@ if test -n "$Qt5Svg_CFLAGS"; then
|
||||
pkg_cv_Qt5Svg_CFLAGS="$Qt5Svg_CFLAGS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Svg >= 5.14\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5Svg >= 5.14") 2>&5
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Svg >= 5.15.2\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5Svg >= 5.15.2") 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_Qt5Svg_CFLAGS=`$PKG_CONFIG --cflags "Qt5Svg >= 5.14" 2>/dev/null`
|
||||
pkg_cv_Qt5Svg_CFLAGS=`$PKG_CONFIG --cflags "Qt5Svg >= 5.15.2" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
@@ -5546,12 +5546,12 @@ if test -n "$Qt5Svg_LIBS"; then
|
||||
pkg_cv_Qt5Svg_LIBS="$Qt5Svg_LIBS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Svg >= 5.14\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5Svg >= 5.14") 2>&5
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Svg >= 5.15.2\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5Svg >= 5.15.2") 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_Qt5Svg_LIBS=`$PKG_CONFIG --libs "Qt5Svg >= 5.14" 2>/dev/null`
|
||||
pkg_cv_Qt5Svg_LIBS=`$PKG_CONFIG --libs "Qt5Svg >= 5.15.2" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
@@ -5572,14 +5572,14 @@ else
|
||||
_pkg_short_errors_supported=no
|
||||
fi
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
Qt5Svg_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "Qt5Svg >= 5.14" 2>&1`
|
||||
Qt5Svg_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "Qt5Svg >= 5.15.2" 2>&1`
|
||||
else
|
||||
Qt5Svg_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "Qt5Svg >= 5.14" 2>&1`
|
||||
Qt5Svg_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "Qt5Svg >= 5.15.2" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$Qt5Svg_PKG_ERRORS" >&5
|
||||
|
||||
as_fn_error $? "Package requirements (Qt5Svg >= 5.14) were not met:
|
||||
as_fn_error $? "Package requirements (Qt5Svg >= 5.15.2) were not met:
|
||||
|
||||
$Qt5Svg_PKG_ERRORS
|
||||
|
||||
@@ -5619,11 +5619,11 @@ case "x$enable_qt_dbus" in #(
|
||||
"xyes") :
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Qt5DBus >= 5.14" >&5
|
||||
printf %s "checking for Qt5DBus >= 5.14... " >&6; }
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Qt5DBus >= 5.15.2" >&5
|
||||
printf %s "checking for Qt5DBus >= 5.15.2... " >&6; }
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5DBus >= 5.14\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5DBus >= 5.14") 2>&5
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5DBus >= 5.15.2\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "Qt5DBus >= 5.15.2") 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
@@ -6039,12 +6039,12 @@ if test -n "$libtorrent_CFLAGS"; then
|
||||
pkg_cv_libtorrent_CFLAGS="$libtorrent_CFLAGS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.2.13\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.2.13") 2>&5
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.2.14\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.2.14") 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_libtorrent_CFLAGS=`$PKG_CONFIG --cflags "libtorrent-rasterbar >= 1.2.13" 2>/dev/null`
|
||||
pkg_cv_libtorrent_CFLAGS=`$PKG_CONFIG --cflags "libtorrent-rasterbar >= 1.2.14" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
@@ -6056,12 +6056,12 @@ if test -n "$libtorrent_LIBS"; then
|
||||
pkg_cv_libtorrent_LIBS="$libtorrent_LIBS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.2.13\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.2.13") 2>&5
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.2.14\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.2.14") 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_libtorrent_LIBS=`$PKG_CONFIG --libs "libtorrent-rasterbar >= 1.2.13" 2>/dev/null`
|
||||
pkg_cv_libtorrent_LIBS=`$PKG_CONFIG --libs "libtorrent-rasterbar >= 1.2.14" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
@@ -6082,14 +6082,14 @@ else
|
||||
_pkg_short_errors_supported=no
|
||||
fi
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
libtorrent_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent-rasterbar >= 1.2.13" 2>&1`
|
||||
libtorrent_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent-rasterbar >= 1.2.14" 2>&1`
|
||||
else
|
||||
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 1.2.13" 2>&1`
|
||||
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 1.2.14" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$libtorrent_PKG_ERRORS" >&5
|
||||
|
||||
as_fn_error $? "Package requirements (libtorrent-rasterbar >= 1.2.13) were not met:
|
||||
as_fn_error $? "Package requirements (libtorrent-rasterbar >= 1.2.14) were not met:
|
||||
|
||||
$libtorrent_PKG_ERRORS
|
||||
|
||||
@@ -7845,4 +7845,3 @@ fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Good, the configure finished." >&5
|
||||
printf "%s\n" "$as_me: Good, the configure finished." >&6;}
|
||||
printf "%s\n"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
AC_INIT([qbittorrent], [v4.4.0alpha], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
@@ -141,7 +142,7 @@ AS_IF([test "x$QT_QMAKE" = "x"],
|
||||
[AC_MSG_ERROR([Could not find qmake])
|
||||
])
|
||||
AS_IF([test "x$enable_gui" = "xyes"],
|
||||
[PKG_CHECK_MODULES(Qt5Svg, [Qt5Svg >= 5.14])
|
||||
[PKG_CHECK_MODULES(Qt5Svg, [Qt5Svg >= 5.15.2])
|
||||
])
|
||||
AC_MSG_CHECKING([whether QtDBus should be enabled])
|
||||
AS_CASE(["x$enable_qt_dbus"],
|
||||
@@ -176,7 +177,7 @@ AC_COMPILE_IFELSE([DETECT_BOOST_VERSION_PROGRAM(106000)], [],
|
||||
[QBT_ADD_DEFINES="$QBT_ADD_DEFINES BOOST_NO_CXX11_RVALUE_REFERENCES"])
|
||||
|
||||
PKG_CHECK_MODULES(libtorrent,
|
||||
[libtorrent-rasterbar >= 1.2.13],
|
||||
[libtorrent-rasterbar >= 1.2.14],
|
||||
[CXXFLAGS="$libtorrent_CFLAGS $CXXFLAGS"
|
||||
LIBS="$libtorrent_LIBS $LIBS"])
|
||||
|
||||
|
||||
@@ -177,8 +177,8 @@ Name[ur]=قیو بٹ ٹورنٹ
|
||||
Comment[uk]=Завантажуйте та поширюйте файли через BitTorrent
|
||||
GenericName[uk]=BitTorrent-клієнт
|
||||
Name[uk]=qBittorrent
|
||||
Comment[vi]=Tải xuống và chia sẻ tệp qua BitTorrent
|
||||
GenericName[vi]=Client BitTorrent
|
||||
Comment[vi]=Tải về và chia sẻ tệp qua BitTorrent
|
||||
GenericName[vi]=Máy khách BitTorrent
|
||||
Name[vi]=qBittorrent
|
||||
Comment[az@latin]=Faylları BitTorrent vasitəsilə göndərin və paylaşın
|
||||
GenericName[az@latin]=BitTorrent client
|
||||
|
||||
10
dist/windows/installer-translations/danish.nsi
vendored
10
dist/windows/installer-translations/danish.nsi
vendored
@@ -7,7 +7,7 @@ LangString inst_dekstop ${LANG_DANISH} "Opret skrivebordsgenvej"
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_DANISH} "Opret genvej i menuen Start"
|
||||
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
|
||||
LangString inst_startup ${LANG_DANISH} "Start qBittorrent i Windows opstart"
|
||||
LangString inst_startup ${LANG_DANISH} "Start qBittorrent når Windows starter"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_DANISH} "Åbn .torrent-filer med qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
@@ -15,7 +15,7 @@ LangString inst_magnet ${LANG_DANISH} "Åbn magnet-links med qBittorrent"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_DANISH} "Tilføj Windows Firewall-regel"
|
||||
;LangString inst_pathlimit ${LANG_ENGLISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
|
||||
LangString inst_pathlimit ${LANG_DANISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
|
||||
LangString inst_pathlimit ${LANG_DANISH} "Deaktivér grænse for for lang Windows-stien kan være (MAX_PATH-begrænsning på 260 tegn, kræver Windows 10 1607 eller senere)"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_DANISH} "Tilføjer Windows Firewall-regel"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
@@ -27,11 +27,11 @@ LangString inst_unist ${LANG_DANISH} "Afinstallerer tidligere version."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_DANISH} "Start qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_DANISH} "Dette installationsprogram virker kun i 64-bit Windows versioner."
|
||||
LangString inst_requires_64bit ${LANG_DANISH} "Installationsprogrammet virker kun i Windows-versioner som er 64-bit."
|
||||
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_DANISH} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_DANISH} "qBittorrent-versionen kræver mindst Windows 7."
|
||||
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_DANISH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_DANISH} "Afinstaller qBittorrent"
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
# Sets the QT_QMAKE variable to the path of Qt5 qmake if found.
|
||||
# --------------------------------------
|
||||
AC_DEFUN([FIND_QT5],
|
||||
[PKG_CHECK_EXISTS([Qt5Core >= 5.14],
|
||||
[PKG_CHECK_EXISTS([Qt5Core >= 5.15.2],
|
||||
[PKG_CHECK_VAR(QT_QMAKE,
|
||||
[Qt5Core >= 5.14],
|
||||
[Qt5Core >= 5.15.2],
|
||||
[host_bins])
|
||||
])
|
||||
|
||||
@@ -18,7 +18,7 @@ AS_IF([test -f "$QT_QMAKE/qmake"],
|
||||
[QT_QMAKE=""])
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([for Qt5 qmake >= 5.14])
|
||||
AC_MSG_CHECKING([for Qt5 qmake >= 5.15.2])
|
||||
AS_IF([test "x$QT_QMAKE" != "x"],
|
||||
[AC_MSG_RESULT([$QT_QMAKE])],
|
||||
[AC_MSG_RESULT([not found])]
|
||||
@@ -29,8 +29,8 @@ AS_IF([test "x$QT_QMAKE" != "x"],
|
||||
# Sets the HAVE_QTDBUS variable to true or false.
|
||||
# --------------------------------------
|
||||
AC_DEFUN([FIND_QTDBUS],
|
||||
[AC_MSG_CHECKING([for Qt5DBus >= 5.14])
|
||||
PKG_CHECK_EXISTS([Qt5DBus >= 5.14],
|
||||
[AC_MSG_CHECKING([for Qt5DBus >= 5.15.2])
|
||||
PKG_CHECK_EXISTS([Qt5DBus >= 5.15.2],
|
||||
[AC_MSG_RESULT([found])
|
||||
HAVE_QTDBUS=[true]],
|
||||
[AC_MSG_RESULT([not found])
|
||||
|
||||
@@ -435,16 +435,12 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const
|
||||
// enable command injection via torrent name and other arguments
|
||||
// (especially when some automated download mechanism has been setup).
|
||||
// See: https://github.com/qbittorrent/qBittorrent/issues/10925
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
QStringList args = QProcess::splitCommand(program);
|
||||
if (args.isEmpty())
|
||||
return;
|
||||
|
||||
const QString command = args.takeFirst();
|
||||
QProcess::startDetached(command, args);
|
||||
#else
|
||||
QProcess::startDetached(program);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -565,7 +561,7 @@ void Application::processParams(const QStringList ¶ms)
|
||||
|
||||
if (param.startsWith(QLatin1String("@addPaused=")))
|
||||
{
|
||||
torrentParams.addPaused = (param.midRef(11).toInt() != 0);
|
||||
torrentParams.addPaused = (QStringView(param).mid(11).toInt() != 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -595,7 +591,7 @@ void Application::processParams(const QStringList ¶ms)
|
||||
|
||||
if (param.startsWith(QLatin1String("@skipDialog=")))
|
||||
{
|
||||
skipTorrentDialog = (param.midRef(12).toInt() != 0);
|
||||
skipTorrentDialog = (QStringView(param).mid(12).toInt() != 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace RSS
|
||||
class Application final : public BaseApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Application)
|
||||
Q_DISABLE_COPY_MOVE(Application)
|
||||
|
||||
public:
|
||||
Application(int &argc, char **argv);
|
||||
|
||||
@@ -35,7 +35,7 @@ class QtLocalPeer;
|
||||
class ApplicationInstanceManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ApplicationInstanceManager)
|
||||
Q_DISABLE_COPY_MOVE(ApplicationInstanceManager)
|
||||
|
||||
public:
|
||||
explicit ApplicationInstanceManager(const QString &appId, QObject *parent = nullptr);
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Log
|
||||
class FileLogger : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(FileLogger)
|
||||
Q_DISABLE_COPY_MOVE(FileLogger)
|
||||
|
||||
public:
|
||||
enum FileLogAgeType
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Ui
|
||||
class StacktraceDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(StacktraceDialog)
|
||||
Q_DISABLE_COPY_MOVE(StacktraceDialog)
|
||||
|
||||
public:
|
||||
explicit StacktraceDialog(QWidget *parent = nullptr);
|
||||
|
||||
@@ -102,12 +102,28 @@ namespace
|
||||
settingsStorage->storeValue(newKey, Utils::String::fromEnum(torrentContentLayout));
|
||||
settingsStorage->removeValue(oldKey);
|
||||
}
|
||||
|
||||
void upgradeListenPortSettings()
|
||||
{
|
||||
const auto oldKey = QString::fromLatin1("BitTorrent/Session/UseRandomPort");
|
||||
const auto newKey = QString::fromLatin1("Preferences/Connection/PortRangeMin");
|
||||
auto *settingsStorage = SettingsStorage::instance();
|
||||
|
||||
if (settingsStorage->hasKey(oldKey))
|
||||
{
|
||||
if (settingsStorage->loadValue<bool>(oldKey))
|
||||
settingsStorage->storeValue(newKey, 0);
|
||||
|
||||
settingsStorage->removeValue(oldKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool upgrade(const bool /*ask*/)
|
||||
{
|
||||
exportWebUIHttpsFiles();
|
||||
upgradeTorrentContentLayout();
|
||||
upgradeListenPortSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
class AsyncFileStorage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(AsyncFileStorage)
|
||||
Q_DISABLE_COPY_MOVE(AsyncFileStorage)
|
||||
|
||||
public:
|
||||
explicit AsyncFileStorage(const QString &storageFolderPath, QObject *parent = nullptr);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
class BandwidthScheduler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(BandwidthScheduler)
|
||||
Q_DISABLE_COPY_MOVE(BandwidthScheduler)
|
||||
|
||||
public:
|
||||
explicit BandwidthScheduler(QObject *parent = nullptr);
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
|
||||
#include <libtorrent/bdecode.hpp>
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/create_torrent.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
#include <libtorrent/read_resume_data.hpp>
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
#include <libtorrent/write_resume_data.hpp>
|
||||
|
||||
#include <QByteArray>
|
||||
@@ -51,13 +51,12 @@
|
||||
#include "base/utils/string.h"
|
||||
#include "infohash.h"
|
||||
#include "loadtorrentparams.h"
|
||||
#include "torrentinfo.h"
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class BencodeResumeDataStorage::Worker final : public QObject
|
||||
{
|
||||
Q_DISABLE_COPY(Worker)
|
||||
Q_DISABLE_COPY_MOVE(Worker)
|
||||
|
||||
public:
|
||||
explicit Worker(const QDir &resumeDataDir);
|
||||
@@ -151,25 +150,36 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorag
|
||||
const QString fastresumePath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.fastresume").arg(idString));
|
||||
const QString torrentFilePath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(idString));
|
||||
|
||||
QFile file {fastresumePath};
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
QFile resumeDataFile {fastresumePath};
|
||||
if (!resumeDataFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
LogMsg(tr("Cannot read file %1: %2").arg(fastresumePath, file.errorString()), Log::WARNING);
|
||||
LogMsg(tr("Cannot read file %1: %2").arg(fastresumePath, resumeDataFile.errorString()), Log::WARNING);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const QByteArray data = file.readAll();
|
||||
const TorrentInfo metadata = TorrentInfo::loadFromFile(torrentFilePath);
|
||||
QFile metadataFile {torrentFilePath};
|
||||
if (metadataFile.exists() && !metadataFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
LogMsg(tr("Cannot read file %1: %2").arg(torrentFilePath, metadataFile.errorString()), Log::WARNING);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const QByteArray data = resumeDataFile.readAll();
|
||||
const QByteArray metadata = (metadataFile.isOpen() ? metadataFile.readAll() : "");
|
||||
|
||||
return loadTorrentResumeData(data, metadata);
|
||||
}
|
||||
|
||||
std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorage::loadTorrentResumeData(
|
||||
const QByteArray &data, const TorrentInfo &metadata) const
|
||||
const QByteArray &data, const QByteArray &metadata) const
|
||||
{
|
||||
const QByteArray allData = ((metadata.isEmpty() || data.isEmpty())
|
||||
? data : (data.chopped(1) + metadata.mid(1)));
|
||||
|
||||
lt::error_code ec;
|
||||
const lt::bdecode_node root = lt::bdecode(data, ec);
|
||||
if (ec || (root.type() != lt::bdecode_node::dict_t)) return std::nullopt;
|
||||
const lt::bdecode_node root = lt::bdecode(allData, ec);
|
||||
if (ec || (root.type() != lt::bdecode_node::dict_t))
|
||||
return std::nullopt;
|
||||
|
||||
LoadTorrentParams torrentParams;
|
||||
torrentParams.restored = true;
|
||||
@@ -220,8 +230,6 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorag
|
||||
|
||||
p = lt::read_resume_data(root, ec);
|
||||
p.save_path = Profile::instance()->fromPortablePath(fromLTString(p.save_path)).toStdString();
|
||||
if (metadata.isValid())
|
||||
p.ti = metadata.nativeInfo();
|
||||
|
||||
if (p.flags & lt::torrent_flags::stop_when_ready)
|
||||
{
|
||||
@@ -333,15 +341,22 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
|
||||
}
|
||||
}
|
||||
|
||||
lt::entry data = lt::write_resume_data(p);
|
||||
|
||||
// metadata is stored in separate .torrent file
|
||||
const std::shared_ptr<lt::torrent_info> torrentInfo = std::move(p.ti);
|
||||
if (torrentInfo)
|
||||
if (p.ti)
|
||||
{
|
||||
lt::entry::dictionary_type &dataDict = data.dict();
|
||||
lt::entry metadata {lt::entry::dictionary_t};
|
||||
lt::entry::dictionary_type &metadataDict = metadata.dict();
|
||||
metadataDict.insert(dataDict.extract("info"));
|
||||
metadataDict.insert(dataDict.extract("creation date"));
|
||||
metadataDict.insert(dataDict.extract("created by"));
|
||||
metadataDict.insert(dataDict.extract("comment"));
|
||||
|
||||
const QString torrentFilepath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(id.toString()));
|
||||
try
|
||||
{
|
||||
const auto torrentCreator = lt::create_torrent(*torrentInfo);
|
||||
const lt::entry metadata = torrentCreator.generate();
|
||||
writeEntryToFile(torrentFilepath, metadata);
|
||||
}
|
||||
catch (const RuntimeError &err)
|
||||
@@ -350,16 +365,8 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
|
||||
.arg(torrentFilepath, err.message()), Log::CRITICAL);
|
||||
return;
|
||||
}
|
||||
catch (const std::exception &err)
|
||||
{
|
||||
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2.")
|
||||
.arg(torrentFilepath, QString::fromLocal8Bit(err.what())), Log::CRITICAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lt::entry data = lt::write_resume_data(p);
|
||||
|
||||
data["qBt-savePath"] = Profile::instance()->toPortablePath(resumeData.savePath).toStdString();
|
||||
data["qBt-ratioLimit"] = static_cast<int>(resumeData.ratioLimit * 1000);
|
||||
data["qBt-seedingTimeLimit"] = resumeData.seedingTimeLimit;
|
||||
|
||||
@@ -38,12 +38,10 @@ class QThread;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TorrentInfo;
|
||||
|
||||
class BencodeResumeDataStorage final : public ResumeDataStorage
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(BencodeResumeDataStorage)
|
||||
Q_DISABLE_COPY_MOVE(BencodeResumeDataStorage)
|
||||
|
||||
public:
|
||||
explicit BencodeResumeDataStorage(const QString &path, QObject *parent = nullptr);
|
||||
@@ -57,7 +55,7 @@ namespace BitTorrent
|
||||
|
||||
private:
|
||||
void loadQueue(const QString &queueFilename);
|
||||
std::optional<LoadTorrentParams> loadTorrentResumeData(const QByteArray &data, const TorrentInfo &metadata) const;
|
||||
std::optional<LoadTorrentParams> loadTorrentResumeData(const QByteArray &data, const QByteArray &metadata) const;
|
||||
|
||||
const QDir m_resumeDataDir;
|
||||
QVector<TorrentID> m_registeredTorrents;
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
|
||||
#include <libtorrent/bdecode.hpp>
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/create_torrent.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
#include <libtorrent/read_resume_data.hpp>
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
#include <libtorrent/write_resume_data.hpp>
|
||||
|
||||
#include <QByteArray>
|
||||
@@ -52,7 +52,6 @@
|
||||
#include "base/utils/string.h"
|
||||
#include "infohash.h"
|
||||
#include "loadtorrentparams.h"
|
||||
#include "torrentinfo.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -158,7 +157,7 @@ namespace BitTorrent
|
||||
{
|
||||
class DBResumeDataStorage::Worker final : public QObject
|
||||
{
|
||||
Q_DISABLE_COPY(Worker)
|
||||
Q_DISABLE_COPY_MOVE(Worker)
|
||||
|
||||
public:
|
||||
Worker(const QString &dbPath, const QString &dbConnectionName);
|
||||
@@ -290,20 +289,19 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::DBResumeDataStorage::lo
|
||||
resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
|
||||
|
||||
const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
|
||||
const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray();
|
||||
const QByteArray allData = ((bencodedMetadata.isEmpty() || bencodedResumeData.isEmpty())
|
||||
? bencodedResumeData
|
||||
: (bencodedResumeData.chopped(1) + bencodedMetadata.mid(1)));
|
||||
|
||||
lt::error_code ec;
|
||||
const lt::bdecode_node root = lt::bdecode(bencodedResumeData, ec);
|
||||
const lt::bdecode_node root = lt::bdecode(allData, ec);
|
||||
|
||||
lt::add_torrent_params &p = resumeData.ltAddTorrentParams;
|
||||
|
||||
p = lt::read_resume_data(root, ec);
|
||||
p.save_path = Profile::instance()->fromPortablePath(fromLTString(p.save_path)).toStdString();
|
||||
|
||||
const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray();
|
||||
auto metadata = TorrentInfo::load(bencodedMetadata);
|
||||
if (metadata.isValid())
|
||||
p.ti = metadata.nativeInfo();
|
||||
|
||||
return resumeData;
|
||||
}
|
||||
|
||||
@@ -453,16 +451,23 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
|
||||
DB_COLUMN_RESUMEDATA
|
||||
};
|
||||
|
||||
lt::entry data = lt::write_resume_data(p);
|
||||
|
||||
// metadata is stored in separate column
|
||||
QByteArray bencodedMetadata;
|
||||
bencodedMetadata.reserve(512 * 1024);
|
||||
const std::shared_ptr<lt::torrent_info> torrentInfo = std::move(p.ti);
|
||||
if (torrentInfo)
|
||||
if (p.ti)
|
||||
{
|
||||
lt::entry::dictionary_type &dataDict = data.dict();
|
||||
lt::entry metadata {lt::entry::dictionary_t};
|
||||
lt::entry::dictionary_type &metadataDict = metadata.dict();
|
||||
metadataDict.insert(dataDict.extract("info"));
|
||||
metadataDict.insert(dataDict.extract("creation date"));
|
||||
metadataDict.insert(dataDict.extract("created by"));
|
||||
metadataDict.insert(dataDict.extract("comment"));
|
||||
|
||||
try
|
||||
{
|
||||
const auto torrentCreator = lt::create_torrent(*torrentInfo);
|
||||
const lt::entry metadata = torrentCreator.generate();
|
||||
bencodedMetadata.reserve(512 * 1024);
|
||||
lt::bencode(std::back_inserter(bencodedMetadata), metadata);
|
||||
}
|
||||
catch (const std::exception &err)
|
||||
@@ -477,7 +482,7 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
|
||||
|
||||
QByteArray bencodedResumeData;
|
||||
bencodedResumeData.reserve(256 * 1024);
|
||||
lt::bencode(std::back_inserter(bencodedResumeData), lt::write_resume_data(p));
|
||||
lt::bencode(std::back_inserter(bencodedResumeData), data);
|
||||
|
||||
const QString insertTorrentStatement = makeInsertStatement(DB_TABLE_TORRENTS, columns)
|
||||
+ makeOnConflictUpdateStatement(DB_COLUMN_TORRENT_ID, columns);
|
||||
@@ -503,7 +508,7 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
|
||||
query.bindValue(DB_COLUMN_OPERATING_MODE.placeholder, Utils::String::fromEnum(resumeData.operatingMode));
|
||||
query.bindValue(DB_COLUMN_STOPPED.placeholder, resumeData.stopped);
|
||||
query.bindValue(DB_COLUMN_RESUMEDATA.placeholder, bencodedResumeData);
|
||||
if (torrentInfo)
|
||||
if (!bencodedMetadata.isEmpty())
|
||||
query.bindValue(DB_COLUMN_METADATA.placeholder, bencodedMetadata);
|
||||
|
||||
if (!query.exec())
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace BitTorrent
|
||||
class DBResumeDataStorage final : public ResumeDataStorage
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(DBResumeDataStorage)
|
||||
Q_DISABLE_COPY_MOVE(DBResumeDataStorage)
|
||||
|
||||
public:
|
||||
explicit DBResumeDataStorage(const QString &dbPath, QObject *parent = nullptr);
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace BitTorrent
|
||||
class FileSearcher final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(FileSearcher)
|
||||
Q_DISABLE_COPY_MOVE(FileSearcher)
|
||||
|
||||
public:
|
||||
FileSearcher() = default;
|
||||
|
||||
@@ -28,31 +28,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct HasUnderlyingType
|
||||
: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct HasUnderlyingType<T, std::void_t<typename T::underlying_type>>
|
||||
: std::true_type
|
||||
typename T::underlying_type toLTUnderlyingType(const T &t)
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct LTUnderlying
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct LTUnderlying<T, typename std::enable_if_t<HasUnderlyingType<T>::value>>
|
||||
{
|
||||
using type = typename T::underlying_type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using LTUnderlyingType = typename LTUnderlying<T>::type;
|
||||
return static_cast<typename T::underlying_type>(t);
|
||||
}
|
||||
|
||||
@@ -39,21 +39,34 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
bool isSHA1Hash(const QString &string)
|
||||
// BEP9 Extension for Peers to Send Metadata Files
|
||||
|
||||
bool isV1Hash(const QString &string)
|
||||
{
|
||||
// There are 2 representations for BitTorrent info hash:
|
||||
// There are 2 representations for BitTorrent v1 info hash:
|
||||
// 1. 40 chars hex-encoded string
|
||||
// == 20 (SHA-1 length in bytes) * 2 (each byte maps to 2 hex characters)
|
||||
// 2. 32 chars Base32 encoded string
|
||||
// == 20 (SHA-1 length in bytes) * 1.6 (the efficiency of Base32 encoding)
|
||||
const int SHA1_HEX_SIZE = SHA1Hash::length() * 2;
|
||||
const int SHA1_BASE32_SIZE = SHA1Hash::length() * 1.6;
|
||||
const int V1_HEX_SIZE = SHA1Hash::length() * 2;
|
||||
const int V1_BASE32_SIZE = SHA1Hash::length() * 1.6;
|
||||
|
||||
return ((((string.size() == SHA1_HEX_SIZE))
|
||||
return ((((string.size() == V1_HEX_SIZE))
|
||||
&& !string.contains(QRegularExpression(QLatin1String("[^0-9A-Fa-f]"))))
|
||||
|| ((string.size() == SHA1_BASE32_SIZE)
|
||||
|| ((string.size() == V1_BASE32_SIZE)
|
||||
&& !string.contains(QRegularExpression(QLatin1String("[^2-7A-Za-z]")))));
|
||||
}
|
||||
|
||||
bool isV2Hash(const QString &string)
|
||||
{
|
||||
// There are 1 representation for BitTorrent v2 info hash:
|
||||
// 1. 64 chars hex-encoded string
|
||||
// == 32 (SHA-2 256 length in bytes) * 2 (each byte maps to 2 hex characters)
|
||||
const int V2_HEX_SIZE = SHA256Hash::length() * 2;
|
||||
|
||||
return (string.size() == V2_HEX_SIZE)
|
||||
&& !string.contains(QRegularExpression(QLatin1String("[^0-9A-Fa-f]")));
|
||||
}
|
||||
}
|
||||
|
||||
using namespace BitTorrent;
|
||||
@@ -66,8 +79,10 @@ MagnetUri::MagnetUri(const QString &source)
|
||||
{
|
||||
if (source.isEmpty()) return;
|
||||
|
||||
if (isSHA1Hash(source))
|
||||
m_url = QLatin1String("magnet:?xt=urn:btih:") + source;
|
||||
if (isV2Hash(source))
|
||||
m_url = QString::fromLatin1("magnet:?xt=urn:btmh:") + source;
|
||||
else if (isV1Hash(source))
|
||||
m_url = QString::fromLatin1("magnet:?xt=urn:btih:") + source;
|
||||
|
||||
lt::error_code ec;
|
||||
lt::parse_magnet_uri(m_url.toStdString(), m_addTorrentParams, ec);
|
||||
|
||||
@@ -32,18 +32,18 @@
|
||||
|
||||
using namespace BitTorrent;
|
||||
|
||||
PeerAddress PeerAddress::parse(const QString &address)
|
||||
PeerAddress PeerAddress::parse(const QStringView address)
|
||||
{
|
||||
QVector<QStringRef> ipPort;
|
||||
QList<QStringView> ipPort;
|
||||
|
||||
if (address.startsWith('[') && address.contains("]:"))
|
||||
if (address.startsWith(u'[') && address.contains(QLatin1String("]:")))
|
||||
{ // IPv6
|
||||
ipPort = address.splitRef("]:");
|
||||
ipPort = address.split(QString::fromLatin1("]:"));
|
||||
ipPort[0] = ipPort[0].mid(1); // chop '['
|
||||
}
|
||||
else if (address.contains(':'))
|
||||
else if (address.contains(u':'))
|
||||
{ // IPv4
|
||||
ipPort = address.splitRef(':');
|
||||
ipPort = address.split(u':');
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace BitTorrent
|
||||
QHostAddress ip;
|
||||
ushort port = 0;
|
||||
|
||||
static PeerAddress parse(const QString &address);
|
||||
static PeerAddress parse(QStringView address);
|
||||
QString toString() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
class PortForwarderImpl final : public Net::PortForwarder
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PortForwarderImpl)
|
||||
Q_DISABLE_COPY_MOVE(PortForwarderImpl)
|
||||
|
||||
public:
|
||||
explicit PortForwarderImpl(lt::session *provider, QObject *parent = nullptr);
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace BitTorrent
|
||||
class ResumeDataStorage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ResumeDataStorage)
|
||||
Q_DISABLE_COPY_MOVE(ResumeDataStorage)
|
||||
|
||||
public:
|
||||
using QObject::QObject;
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
#include "common.h"
|
||||
#include "customstorage.h"
|
||||
#include "dbresumedatastorage.h"
|
||||
#include "downloadpriority.h"
|
||||
#include "filesearcher.h"
|
||||
#include "filterparserthread.h"
|
||||
#include "loadtorrentparams.h"
|
||||
@@ -407,7 +408,6 @@ Session::Session(QObject *parent)
|
||||
, m_isBandwidthSchedulerEnabled(BITTORRENT_SESSION_KEY("BandwidthSchedulerEnabled"), false)
|
||||
, m_saveResumeDataInterval(BITTORRENT_SESSION_KEY("SaveResumeDataInterval"), 60)
|
||||
, m_port(BITTORRENT_SESSION_KEY("Port"), -1)
|
||||
, m_useRandomPort(BITTORRENT_SESSION_KEY("UseRandomPort"), false)
|
||||
, m_networkInterface(BITTORRENT_SESSION_KEY("Interface"))
|
||||
, m_networkInterfaceName(BITTORRENT_SESSION_KEY("InterfaceName"))
|
||||
, m_networkInterfaceAddress(BITTORRENT_SESSION_KEY("InterfaceAddress"))
|
||||
@@ -1421,13 +1421,12 @@ void Session::configureNetworkInterfaces(lt::settings_pack &settingsPack)
|
||||
if (m_listenInterfaceConfigured)
|
||||
return;
|
||||
|
||||
const int port = useRandomPort() ? 0 : this->port();
|
||||
if (port > 0) // user specified port
|
||||
if (port() > 0) // user has specified port number
|
||||
settingsPack.set_int(lt::settings_pack::max_retry_port_bind, 0);
|
||||
|
||||
QStringList endpoints;
|
||||
QStringList outgoingInterfaces;
|
||||
const QString portString = ':' + QString::number(port);
|
||||
const QString portString = ':' + QString::number(port());
|
||||
|
||||
for (const QString &ip : asConst(getListeningIPs()))
|
||||
{
|
||||
@@ -1489,7 +1488,7 @@ void Session::configurePeerClasses()
|
||||
// Proactively do the same for 0.0.0.0 and address_v4::any()
|
||||
f.add_rule(lt::address_v4::any()
|
||||
, lt::address_v4::broadcast()
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::global_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::global_peer_class_id));
|
||||
|
||||
// IPv6 may not be available on OS and the parsing
|
||||
// would result in an exception -> abnormal program termination
|
||||
@@ -1498,7 +1497,7 @@ void Session::configurePeerClasses()
|
||||
{
|
||||
f.add_rule(lt::address_v6::any()
|
||||
, lt::make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::global_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::global_peer_class_id));
|
||||
}
|
||||
catch (const std::exception &) {}
|
||||
|
||||
@@ -1507,21 +1506,21 @@ void Session::configurePeerClasses()
|
||||
// local networks
|
||||
f.add_rule(lt::make_address("10.0.0.0")
|
||||
, lt::make_address("10.255.255.255")
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
|
||||
f.add_rule(lt::make_address("172.16.0.0")
|
||||
, lt::make_address("172.31.255.255")
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
|
||||
f.add_rule(lt::make_address("192.168.0.0")
|
||||
, lt::make_address("192.168.255.255")
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
|
||||
// link local
|
||||
f.add_rule(lt::make_address("169.254.0.0")
|
||||
, lt::make_address("169.254.255.255")
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
|
||||
// loopback
|
||||
f.add_rule(lt::make_address("127.0.0.0")
|
||||
, lt::make_address("127.255.255.255")
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
|
||||
|
||||
// IPv6 may not be available on OS and the parsing
|
||||
// would result in an exception -> abnormal program termination
|
||||
@@ -1531,15 +1530,15 @@ void Session::configurePeerClasses()
|
||||
// link local
|
||||
f.add_rule(lt::make_address("fe80::")
|
||||
, lt::make_address("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
|
||||
// unique local addresses
|
||||
f.add_rule(lt::make_address("fc00::")
|
||||
, lt::make_address("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
|
||||
// loopback
|
||||
f.add_rule(lt::address_v6::loopback()
|
||||
, lt::address_v6::loopback()
|
||||
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
|
||||
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
|
||||
}
|
||||
catch (const std::exception &) {}
|
||||
}
|
||||
@@ -1590,7 +1589,7 @@ void Session::populateAdditionalTrackers()
|
||||
m_additionalTrackerList.clear();
|
||||
|
||||
const QString trackers = additionalTrackers();
|
||||
for (QStringRef tracker : asConst(trackers.splitRef('\n')))
|
||||
for (QStringView tracker : asConst(QStringView(trackers).split(u'\n')))
|
||||
{
|
||||
tracker = tracker.trimmed();
|
||||
if (!tracker.isEmpty())
|
||||
@@ -2146,12 +2145,21 @@ bool Session::addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source
|
||||
}
|
||||
|
||||
Q_ASSERT(p.file_priorities.empty());
|
||||
std::transform(addTorrentParams.filePriorities.cbegin(), addTorrentParams.filePriorities.cend()
|
||||
, std::back_inserter(p.file_priorities), [](const DownloadPriority priority)
|
||||
if (addTorrentParams.filePriorities.empty())
|
||||
{
|
||||
return static_cast<lt::download_priority_t>(
|
||||
// Use qBittorrent default priority rather than libtorrent's (4)
|
||||
p.file_priorities = std::vector(metadata.filesCount(), static_cast<lt::download_priority_t>(
|
||||
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::transform(addTorrentParams.filePriorities.cbegin(), addTorrentParams.filePriorities.cend()
|
||||
, std::back_inserter(p.file_priorities), [](const DownloadPriority priority)
|
||||
{
|
||||
return static_cast<lt::download_priority_t>(
|
||||
static_cast<lt::download_priority_t::underlying_type>(priority));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
p.ti = metadata.nativeInfo();
|
||||
}
|
||||
@@ -2296,28 +2304,25 @@ bool Session::downloadMetadata(const MagnetUri &magnetUri)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Session::exportTorrentFile(const Torrent *torrent, TorrentExportFolder folder)
|
||||
void Session::exportTorrentFile(const TorrentInfo &torrentInfo, const QString &folderPath, const QString &baseName)
|
||||
{
|
||||
Q_ASSERT(((folder == TorrentExportFolder::Regular) && !torrentExportDirectory().isEmpty()) ||
|
||||
((folder == TorrentExportFolder::Finished) && !finishedTorrentExportDirectory().isEmpty()));
|
||||
|
||||
const QString validName = Utils::Fs::toValidFileSystemName(torrent->name());
|
||||
const QString validName = Utils::Fs::toValidFileSystemName(baseName);
|
||||
QString torrentExportFilename = QString::fromLatin1("%1.torrent").arg(validName);
|
||||
const QDir exportPath(folder == TorrentExportFolder::Regular ? torrentExportDirectory() : finishedTorrentExportDirectory());
|
||||
if (exportPath.exists() || exportPath.mkpath(exportPath.absolutePath()))
|
||||
const QDir exportDir {folderPath};
|
||||
if (exportDir.exists() || exportDir.mkpath(exportDir.absolutePath()))
|
||||
{
|
||||
QString newTorrentPath = exportPath.absoluteFilePath(torrentExportFilename);
|
||||
QString newTorrentPath = exportDir.absoluteFilePath(torrentExportFilename);
|
||||
int counter = 0;
|
||||
while (QFile::exists(newTorrentPath))
|
||||
{
|
||||
// Append number to torrent name to make it unique
|
||||
torrentExportFilename = QString::fromLatin1("%1 %2.torrent").arg(validName).arg(++counter);
|
||||
newTorrentPath = exportPath.absoluteFilePath(torrentExportFilename);
|
||||
newTorrentPath = exportDir.absoluteFilePath(torrentExportFilename);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
torrent->info().saveToFile(newTorrentPath);
|
||||
torrentInfo.saveToFile(newTorrentPath);
|
||||
}
|
||||
catch (const RuntimeError &err)
|
||||
{
|
||||
@@ -2380,7 +2385,7 @@ void Session::saveTorrentsQueue() const
|
||||
for (const TorrentImpl *torrent : asConst(m_torrents))
|
||||
{
|
||||
// We require actual (non-cached) queue position here!
|
||||
const int queuePos = static_cast<LTUnderlyingType<lt::queue_position_t>>(torrent->nativeHandle().queue_position());
|
||||
const int queuePos = toLTUnderlyingType(torrent->nativeHandle().queue_position());
|
||||
if (queuePos >= 0)
|
||||
{
|
||||
if (queuePos >= queue.size())
|
||||
@@ -2754,16 +2759,6 @@ void Session::setPort(const int port)
|
||||
}
|
||||
}
|
||||
|
||||
bool Session::useRandomPort() const
|
||||
{
|
||||
return m_useRandomPort;
|
||||
}
|
||||
|
||||
void Session::setUseRandomPort(const bool value)
|
||||
{
|
||||
m_useRandomPort = value;
|
||||
}
|
||||
|
||||
QString Session::networkInterface() const
|
||||
{
|
||||
return m_networkInterface;
|
||||
@@ -3893,7 +3888,14 @@ void Session::handleTorrentMetadataReceived(TorrentImpl *const torrent)
|
||||
{
|
||||
// Copy the torrent file to the export folder
|
||||
if (!torrentExportDirectory().isEmpty())
|
||||
exportTorrentFile(torrent);
|
||||
{
|
||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||
const TorrentInfo torrentInfo {torrent->nativeHandle().torrent_file_with_hashes()};
|
||||
#else
|
||||
const TorrentInfo torrentInfo {torrent->nativeHandle().torrent_file()};
|
||||
#endif
|
||||
exportTorrentFile(torrentInfo, torrentExportDirectory(), torrent->name());
|
||||
}
|
||||
|
||||
emit torrentMetadataReceived(torrent);
|
||||
}
|
||||
@@ -3944,7 +3946,14 @@ void Session::handleTorrentFinished(TorrentImpl *const torrent)
|
||||
|
||||
// Move .torrent file to another folder
|
||||
if (!finishedTorrentExportDirectory().isEmpty())
|
||||
exportTorrentFile(torrent, TorrentExportFolder::Finished);
|
||||
{
|
||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||
const TorrentInfo torrentInfo {torrent->nativeHandle().torrent_file_with_hashes()};
|
||||
#else
|
||||
const TorrentInfo torrentInfo {torrent->nativeHandle().torrent_file()};
|
||||
#endif
|
||||
exportTorrentFile(torrentInfo, finishedTorrentExportDirectory(), torrent->name());
|
||||
}
|
||||
|
||||
if (!hasUnfinishedTorrents())
|
||||
emit allTorrentsFinished();
|
||||
@@ -4452,7 +4461,10 @@ void Session::createTorrent(const lt::torrent_handle &nativeHandle)
|
||||
{
|
||||
// Copy the torrent file to the export folder
|
||||
if (!torrentExportDirectory().isEmpty())
|
||||
exportTorrentFile(torrent);
|
||||
{
|
||||
const TorrentInfo torrentInfo {params.ltAddTorrentParams.ti};
|
||||
exportTorrentFile(torrentInfo, torrentExportDirectory(), torrent->name());
|
||||
}
|
||||
}
|
||||
|
||||
if (isAddTrackersEnabled() && !torrent->isPrivate())
|
||||
@@ -4579,7 +4591,7 @@ void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p)
|
||||
|
||||
if (downloadedMetadataIter != m_downloadedMetadata.end())
|
||||
{
|
||||
TorrentInfo metadata {p->handle.torrent_file()};
|
||||
const TorrentInfo metadata {p->handle.torrent_file()};
|
||||
|
||||
m_downloadedMetadata.erase(downloadedMetadataIter);
|
||||
--m_extraLimit;
|
||||
|
||||
@@ -82,12 +82,6 @@ enum DeleteOption
|
||||
DeleteTorrentAndFiles
|
||||
};
|
||||
|
||||
enum TorrentExportFolder
|
||||
{
|
||||
Regular,
|
||||
Finished
|
||||
};
|
||||
|
||||
namespace Net
|
||||
{
|
||||
struct DownloadResult;
|
||||
@@ -211,7 +205,7 @@ namespace BitTorrent
|
||||
class Session : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Session)
|
||||
Q_DISABLE_COPY_MOVE(Session)
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
@@ -312,8 +306,6 @@ namespace BitTorrent
|
||||
void setSaveResumeDataInterval(int value);
|
||||
int port() const;
|
||||
void setPort(int port);
|
||||
bool useRandomPort() const;
|
||||
void setUseRandomPort(bool value);
|
||||
QString networkInterface() const;
|
||||
void setNetworkInterface(const QString &iface);
|
||||
QString networkInterfaceName() const;
|
||||
@@ -613,7 +605,7 @@ namespace BitTorrent
|
||||
bool addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source, const AddTorrentParams &addTorrentParams);
|
||||
|
||||
void updateSeedingLimitTimer();
|
||||
void exportTorrentFile(const Torrent *torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
|
||||
void exportTorrentFile(const TorrentInfo &torrentInfo, const QString &folderPath, const QString &baseName);
|
||||
|
||||
void handleAlert(const lt::alert *a);
|
||||
void dispatchTorrentAlert(const lt::alert *a);
|
||||
@@ -728,7 +720,6 @@ namespace BitTorrent
|
||||
CachedSettingValue<bool> m_isBandwidthSchedulerEnabled;
|
||||
CachedSettingValue<int> m_saveResumeDataInterval;
|
||||
CachedSettingValue<int> m_port;
|
||||
CachedSettingValue<bool> m_useRandomPort;
|
||||
CachedSettingValue<QString> m_networkInterface;
|
||||
CachedSettingValue<QString> m_networkInterfaceName;
|
||||
CachedSettingValue<QString> m_networkInterfaceAddress;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace BitTorrent
|
||||
class Statistics : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Statistics)
|
||||
Q_DISABLE_COPY_MOVE(Statistics)
|
||||
|
||||
public:
|
||||
explicit Statistics(BitTorrent::Session *session);
|
||||
|
||||
@@ -72,6 +72,7 @@ namespace BitTorrent
|
||||
|
||||
ForcedDownloading,
|
||||
Downloading,
|
||||
ForcedDownloadingMetadata,
|
||||
DownloadingMetadata,
|
||||
StalledDownloading,
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ void TorrentCreatorThread::run()
|
||||
, [this, &newTorrent](const lt::piece_index_t n)
|
||||
{
|
||||
checkInterruptionRequested();
|
||||
sendProgressSignal(static_cast<LTUnderlyingType<lt::piece_index_t>>(n), newTorrent.num_pieces());
|
||||
sendProgressSignal(toLTUnderlyingType(n), newTorrent.num_pieces());
|
||||
});
|
||||
|
||||
// Set qBittorrent as creator and add user comment to
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace
|
||||
, std::back_inserter(out), [](const DownloadPriority priority)
|
||||
{
|
||||
return static_cast<lt::download_priority_t>(
|
||||
static_cast<LTUnderlyingType<lt::download_priority_t>>(priority));
|
||||
static_cast<lt::download_priority_t::underlying_type>(priority));
|
||||
});
|
||||
return out;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ namespace
|
||||
QString firstTrackerMessage;
|
||||
QString firstErrorMessage;
|
||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||
const size_t numEndpoints = nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
|
||||
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1));
|
||||
trackerEntry.endpoints.reserve(static_cast<decltype(trackerEntry.endpoints)::size_type>(numEndpoints));
|
||||
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
||||
{
|
||||
@@ -167,8 +167,8 @@ namespace
|
||||
}
|
||||
}
|
||||
#else
|
||||
const int numEndpoints = nativeEntry.endpoints.size();
|
||||
trackerEntry.endpoints.reserve(numEndpoints);
|
||||
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size());
|
||||
trackerEntry.endpoints.reserve(static_cast<decltype(trackerEntry.endpoints)::size_type>(numEndpoints));
|
||||
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
||||
{
|
||||
TrackerEntry::EndpointStats trackerEndpoint;
|
||||
@@ -797,9 +797,10 @@ QVector<DownloadPriority> TorrentImpl::filePriorities() const
|
||||
const std::vector<lt::download_priority_t> fp = m_nativeHandle.get_file_priorities();
|
||||
|
||||
QVector<DownloadPriority> ret;
|
||||
std::transform(fp.cbegin(), fp.cend(), std::back_inserter(ret), [](lt::download_priority_t priority)
|
||||
ret.reserve(static_cast<decltype(ret)::size_type>(fp.size()));
|
||||
std::transform(fp.cbegin(), fp.cend(), std::back_inserter(ret), [](const lt::download_priority_t priority)
|
||||
{
|
||||
return static_cast<DownloadPriority>(static_cast<LTUnderlyingType<lt::download_priority_t>>(priority));
|
||||
return static_cast<DownloadPriority>(toLTUnderlyingType(priority));
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
@@ -832,6 +833,7 @@ bool TorrentImpl::isDownloading() const
|
||||
{
|
||||
return m_state == TorrentState::Downloading
|
||||
|| m_state == TorrentState::DownloadingMetadata
|
||||
|| m_state == TorrentState::ForcedDownloadingMetadata
|
||||
|| m_state == TorrentState::StalledDownloading
|
||||
|| m_state == TorrentState::CheckingDownloading
|
||||
|| m_state == TorrentState::PausedDownloading
|
||||
@@ -864,6 +866,7 @@ bool TorrentImpl::isActive() const
|
||||
return (uploadPayloadRate() > 0);
|
||||
|
||||
return m_state == TorrentState::DownloadingMetadata
|
||||
|| m_state == TorrentState::ForcedDownloadingMetadata
|
||||
|| m_state == TorrentState::Downloading
|
||||
|| m_state == TorrentState::ForcedDownloading
|
||||
|| m_state == TorrentState::Uploading
|
||||
@@ -933,7 +936,7 @@ void TorrentImpl::updateState()
|
||||
else if (m_session->isQueueingSystemEnabled() && isQueued())
|
||||
m_state = TorrentState::QueuedDownloading;
|
||||
else
|
||||
m_state = TorrentState::DownloadingMetadata;
|
||||
m_state = isForced() ? TorrentState::ForcedDownloadingMetadata : TorrentState::DownloadingMetadata;
|
||||
}
|
||||
else if ((m_nativeStatus.state == lt::torrent_status::checking_files)
|
||||
&& (!isPaused() || (m_nativeStatus.flags & lt::torrent_flags::auto_managed)
|
||||
@@ -1250,7 +1253,7 @@ QBitArray TorrentImpl::downloadingPieces() const
|
||||
m_nativeHandle.get_download_queue(queue);
|
||||
|
||||
for (const lt::partial_piece_info &info : queue)
|
||||
result.setBit(static_cast<LTUnderlyingType<lt::piece_index_t>>(info.piece_index));
|
||||
result.setBit(toLTUnderlyingType(info.piece_index));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1509,6 +1512,10 @@ void TorrentImpl::endReceivedMetadataHandling(const QString &savePath, const QSt
|
||||
p.renamed_files[lt::file_index_t {i}] = fileNames[i].toStdString();
|
||||
p.save_path = Utils::Fs::toNativePath(savePath).toStdString();
|
||||
|
||||
// Use qBittorrent default priority rather than libtorrent's (4)
|
||||
p.file_priorities = std::vector(fileNames.size(), static_cast<lt::download_priority_t>(
|
||||
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
|
||||
|
||||
reload();
|
||||
|
||||
// If first/last piece priority was specified when adding this torrent,
|
||||
@@ -1865,9 +1872,9 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
|
||||
if (m_oldPath[p->index].isEmpty())
|
||||
m_oldPath.remove(p->index);
|
||||
|
||||
QVector<QStringRef> oldPathParts = oldFilePath.splitRef('/', Qt::SkipEmptyParts);
|
||||
QList<QStringView> oldPathParts = QStringView(oldFilePath).split('/', Qt::SkipEmptyParts);
|
||||
oldPathParts.removeLast(); // drop file name part
|
||||
QVector<QStringRef> newPathParts = newFilePath.splitRef('/', Qt::SkipEmptyParts);
|
||||
QList<QStringView> newPathParts = QStringView(newFilePath).split('/', Qt::SkipEmptyParts);
|
||||
newPathParts.removeLast(); // drop file name part
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
@@ -1886,7 +1893,7 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
|
||||
|
||||
for (int i = (oldPathParts.size() - 1); i >= pathIdx; --i)
|
||||
{
|
||||
QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QLatin1String("/")));
|
||||
QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QString::fromLatin1("/")));
|
||||
oldPathParts.removeLast();
|
||||
}
|
||||
|
||||
@@ -1900,7 +1907,7 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
|
||||
void TorrentImpl::handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p)
|
||||
{
|
||||
LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"")
|
||||
.arg(name(), filePath(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index))
|
||||
.arg(name(), filePath(toLTUnderlyingType(p->index))
|
||||
, QString::fromLocal8Bit(p->error.message().c_str())), Log::WARNING);
|
||||
|
||||
m_oldPath[p->index].removeFirst();
|
||||
@@ -1919,13 +1926,13 @@ void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p)
|
||||
qDebug("A file completed download in torrent \"%s\"", qUtf8Printable(name()));
|
||||
if (m_session->isAppendExtensionEnabled())
|
||||
{
|
||||
QString name = filePath(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index));
|
||||
QString name = filePath(toLTUnderlyingType(p->index));
|
||||
if (name.endsWith(QB_EXT))
|
||||
{
|
||||
const QString oldName = name;
|
||||
name.chop(QB_EXT.size());
|
||||
qDebug("Renaming %s to %s", qUtf8Printable(oldName), qUtf8Printable(name));
|
||||
renameFile(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index), name);
|
||||
renameFile(toLTUnderlyingType(p->index), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,16 +51,6 @@
|
||||
#include "torrent.h"
|
||||
#include "torrentinfo.h"
|
||||
|
||||
#if (LIBTORRENT_VERSION_NUM == 20003)
|
||||
// file_prio_alert is missing to be forward declared in "libtorrent/fwd.hpp"
|
||||
namespace libtorrent
|
||||
{
|
||||
TORRENT_VERSION_NAMESPACE_3
|
||||
struct file_prio_alert;
|
||||
TORRENT_VERSION_NAMESPACE_3_END
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class Session;
|
||||
@@ -86,7 +76,7 @@ namespace BitTorrent
|
||||
|
||||
class TorrentImpl final : public QObject, public Torrent
|
||||
{
|
||||
Q_DISABLE_COPY(TorrentImpl)
|
||||
Q_DISABLE_COPY_MOVE(TorrentImpl)
|
||||
Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentImpl)
|
||||
|
||||
public:
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace
|
||||
{
|
||||
if (QDir::isAbsolutePath(filePath)) continue;
|
||||
|
||||
const auto filePathElements = filePath.splitRef('/');
|
||||
const auto filePathElements = QStringView(filePath).split(u'/');
|
||||
// if at least one file has no root folder, no common root folder exists
|
||||
if (filePathElements.count() <= 1) return {};
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace BitTorrent
|
||||
class Tracker final : public QObject, public Http::IRequestHandler, private Http::ResponseBuilder
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Tracker)
|
||||
Q_DISABLE_COPY_MOVE(Tracker)
|
||||
|
||||
struct TrackerAnnounceRequest;
|
||||
|
||||
|
||||
@@ -137,9 +137,9 @@ bool Connection::acceptsGzipEncoding(QString codings)
|
||||
{
|
||||
// [rfc7231] 5.3.4. Accept-Encoding
|
||||
|
||||
const auto isCodingAvailable = [](const QVector<QStringRef> &list, const QString &encoding) -> bool
|
||||
const auto isCodingAvailable = [](const QList<QStringView> &list, const QStringView encoding) -> bool
|
||||
{
|
||||
for (const QStringRef &str : list)
|
||||
for (const QStringView &str : list)
|
||||
{
|
||||
if (!str.startsWith(encoding))
|
||||
continue;
|
||||
@@ -149,7 +149,7 @@ bool Connection::acceptsGzipEncoding(QString codings)
|
||||
return true;
|
||||
|
||||
// [rfc7231] 5.3.1. Quality Values
|
||||
const QStringRef substr = str.mid(encoding.size() + 3); // ex. skip over "gzip;q="
|
||||
const QStringView substr = str.mid(encoding.size() + 3); // ex. skip over "gzip;q="
|
||||
|
||||
bool ok = false;
|
||||
const double qvalue = substr.toDouble(&ok);
|
||||
@@ -161,15 +161,15 @@ bool Connection::acceptsGzipEncoding(QString codings)
|
||||
return false;
|
||||
};
|
||||
|
||||
const QVector<QStringRef> list = codings.remove(' ').remove('\t').splitRef(',', Qt::SkipEmptyParts);
|
||||
const QList<QStringView> list = QStringView(codings.remove(' ').remove('\t')).split(u',', Qt::SkipEmptyParts);
|
||||
if (list.isEmpty())
|
||||
return false;
|
||||
|
||||
const bool canGzip = isCodingAvailable(list, QLatin1String("gzip"));
|
||||
const bool canGzip = isCodingAvailable(list, QString::fromLatin1("gzip"));
|
||||
if (canGzip)
|
||||
return true;
|
||||
|
||||
const bool canAny = isCodingAvailable(list, QLatin1String("*"));
|
||||
const bool canAny = isCodingAvailable(list, QString::fromLatin1("*"));
|
||||
if (canAny)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Http
|
||||
class Connection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Connection)
|
||||
Q_DISABLE_COPY_MOVE(Connection)
|
||||
|
||||
public:
|
||||
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace
|
||||
return in;
|
||||
}
|
||||
|
||||
bool parseHeaderLine(const QString &line, HeaderMap &out)
|
||||
bool parseHeaderLine(const QStringView line, HeaderMap &out)
|
||||
{
|
||||
// [rfc7230] 3.2. Header Fields
|
||||
const int i = line.indexOf(':');
|
||||
@@ -67,8 +67,8 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString name = line.leftRef(i).trimmed().toString().toLower();
|
||||
const QString value = line.midRef(i + 1).trimmed().toString();
|
||||
const QString name = line.left(i).trimmed().toString().toLower();
|
||||
const QString value = line.mid(i + 1).trimmed().toString();
|
||||
out[name] = value;
|
||||
|
||||
return true;
|
||||
@@ -145,10 +145,10 @@ RequestParser::ParseResult RequestParser::doParse(const QByteArray &data)
|
||||
return {ParseStatus::BadRequest, Request(), 0}; // TODO: SHOULD respond "501 Not Implemented"
|
||||
}
|
||||
|
||||
bool RequestParser::parseStartLines(const QString &data)
|
||||
bool RequestParser::parseStartLines(const QStringView data)
|
||||
{
|
||||
// we don't handle malformed request which uses `LF` for newline
|
||||
const QVector<QStringRef> lines = data.splitRef(CRLF, Qt::SkipEmptyParts);
|
||||
const QList<QStringView> lines = data.split(QString::fromLatin1(CRLF), Qt::SkipEmptyParts);
|
||||
|
||||
// [rfc7230] 3.2.2. Field Order
|
||||
QStringList requestLines;
|
||||
@@ -267,7 +267,7 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
|
||||
return false;
|
||||
}
|
||||
|
||||
const QByteArray delimiter = Utils::String::unquote(contentType.midRef(idx + boundaryFieldName.size())).toLatin1();
|
||||
const QByteArray delimiter = Utils::String::unquote(QStringView(contentType).mid(idx + boundaryFieldName.size())).toLatin1();
|
||||
if (delimiter.isEmpty())
|
||||
{
|
||||
qWarning() << Q_FUNC_INFO << "boundary delimiter field empty!";
|
||||
@@ -311,13 +311,13 @@ bool RequestParser::parseFormData(const QByteArray &data)
|
||||
const QByteArray payload = viewWithoutEndingWith(list[1], CRLF);
|
||||
|
||||
HeaderMap headersMap;
|
||||
const QVector<QStringRef> headerLines = headers.splitRef(CRLF, Qt::SkipEmptyParts);
|
||||
const QList<QStringView> headerLines = QStringView(headers).split(QString::fromLatin1(CRLF), Qt::SkipEmptyParts);
|
||||
for (const auto &line : headerLines)
|
||||
{
|
||||
if (line.trimmed().startsWith(HEADER_CONTENT_DISPOSITION, Qt::CaseInsensitive))
|
||||
if (line.trimmed().startsWith(QString::fromLatin1(HEADER_CONTENT_DISPOSITION), Qt::CaseInsensitive))
|
||||
{
|
||||
// extract out filename & name
|
||||
const QVector<QStringRef> directives = line.split(';', Qt::SkipEmptyParts);
|
||||
const QList<QStringView> directives = line.split(u';', Qt::SkipEmptyParts);
|
||||
|
||||
for (const auto &directive : directives)
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Http
|
||||
RequestParser();
|
||||
|
||||
ParseResult doParse(const QByteArray &data);
|
||||
bool parseStartLines(const QString &data);
|
||||
bool parseStartLines(QStringView data);
|
||||
bool parseRequestLine(const QString &line);
|
||||
|
||||
bool parsePostMessage(const QByteArray &data);
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Http
|
||||
class Server final : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Server)
|
||||
Q_DISABLE_COPY_MOVE(Server)
|
||||
|
||||
public:
|
||||
explicit Server(IRequestHandler *requestHandler, QObject *parent = nullptr);
|
||||
|
||||
@@ -35,7 +35,7 @@ class QString;
|
||||
|
||||
class IconProvider : public QObject
|
||||
{
|
||||
Q_DISABLE_COPY(IconProvider)
|
||||
Q_DISABLE_COPY_MOVE(IconProvider)
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
|
||||
@@ -72,7 +72,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Log::MsgTypes)
|
||||
class Logger : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Logger)
|
||||
Q_DISABLE_COPY_MOVE(Logger)
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
|
||||
@@ -39,7 +39,7 @@ class QUrl;
|
||||
class DownloadHandlerImpl final : public Net::DownloadHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(DownloadHandlerImpl)
|
||||
Q_DISABLE_COPY_MOVE(DownloadHandlerImpl)
|
||||
|
||||
public:
|
||||
DownloadHandlerImpl(Net::DownloadManager *manager, const Net::DownloadRequest &downloadRequest);
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Net
|
||||
class DownloadHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(DownloadHandler)
|
||||
Q_DISABLE_COPY_MOVE(DownloadHandler)
|
||||
|
||||
public:
|
||||
using QObject::QObject;
|
||||
@@ -112,7 +112,7 @@ namespace Net
|
||||
class DownloadManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(DownloadManager)
|
||||
Q_DISABLE_COPY_MOVE(DownloadManager)
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Net
|
||||
class GeoIPManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(GeoIPManager)
|
||||
Q_DISABLE_COPY_MOVE(GeoIPManager)
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Net
|
||||
{
|
||||
class PortForwarder : public QObject
|
||||
{
|
||||
Q_DISABLE_COPY(PortForwarder)
|
||||
Q_DISABLE_COPY_MOVE(PortForwarder)
|
||||
|
||||
public:
|
||||
explicit PortForwarder(QObject *parent = nullptr);
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Net
|
||||
class ProxyConfigurationManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ProxyConfigurationManager)
|
||||
Q_DISABLE_COPY_MOVE(ProxyConfigurationManager)
|
||||
|
||||
explicit ProxyConfigurationManager(QObject *parent = nullptr);
|
||||
~ProxyConfigurationManager() = default;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Net
|
||||
class ReverseResolution : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ReverseResolution)
|
||||
Q_DISABLE_COPY_MOVE(ReverseResolution)
|
||||
|
||||
public:
|
||||
explicit ReverseResolution(QObject *parent = nullptr);
|
||||
|
||||
@@ -122,12 +122,7 @@ Smtp::Smtp(QObject *parent)
|
||||
|
||||
connect(m_socket, &QIODevice::readyRead, this, &Smtp::readyRead);
|
||||
connect(m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
connect(m_socket, &QAbstractSocket::errorOccurred, this, &Smtp::error);
|
||||
#else
|
||||
connect(m_socket, qOverload<QAbstractSocket::SocketError>(&QAbstractSocket::error)
|
||||
, this, &Smtp::error);
|
||||
#endif
|
||||
|
||||
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
|
||||
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace DNS
|
||||
class Preferences : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Preferences)
|
||||
Q_DISABLE_COPY_MOVE(Preferences)
|
||||
|
||||
Preferences();
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace RSS
|
||||
class Article : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Article)
|
||||
Q_DISABLE_COPY_MOVE(Article)
|
||||
|
||||
friend class Feed;
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace RSS
|
||||
class AutoDownloader final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(AutoDownloader)
|
||||
Q_DISABLE_COPY_MOVE(AutoDownloader)
|
||||
|
||||
friend class ::Application;
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ bool AutoDownloadRule::matchesEpisodeFilterExpression(const QString &articleTitl
|
||||
|
||||
if (episode.endsWith('-'))
|
||||
{ // Infinite range
|
||||
const int episodeOurs {episode.leftRef(episode.size() - 1).toInt()};
|
||||
const int episodeOurs {QStringView(episode).left(episode.size() - 1).toInt()};
|
||||
if (((seasonTheirs == seasonOurs) && (episodeTheirs >= episodeOurs)) || (seasonTheirs > seasonOurs))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace RSS
|
||||
class Feed final : public Item
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Feed)
|
||||
Q_DISABLE_COPY_MOVE(Feed)
|
||||
|
||||
friend class Session;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace RSS
|
||||
class Folder final : public Item
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Folder)
|
||||
Q_DISABLE_COPY_MOVE(Folder)
|
||||
|
||||
friend class Session;
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace RSS
|
||||
class Item : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Item)
|
||||
Q_DISABLE_COPY_MOVE(Item)
|
||||
|
||||
friend class Folder;
|
||||
friend class Session;
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace RSS
|
||||
class Session : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Session)
|
||||
Q_DISABLE_COPY_MOVE(Session)
|
||||
|
||||
friend class ::Application;
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ void SearchDownloadHandler::downloadProcessFinished(int exitcode)
|
||||
if ((exitcode == 0) && (m_downloadProcess->exitStatus() == QProcess::NormalExit))
|
||||
{
|
||||
const QString line = QString::fromUtf8(m_downloadProcess->readAllStandardOutput()).trimmed();
|
||||
const QVector<QStringRef> parts = line.splitRef(' ');
|
||||
const QList<QStringView> parts = QStringView(line).split(u' ');
|
||||
if (parts.size() == 2)
|
||||
path = parts[0].toString();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class SearchPluginManager;
|
||||
class SearchDownloadHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(SearchDownloadHandler)
|
||||
Q_DISABLE_COPY_MOVE(SearchDownloadHandler)
|
||||
|
||||
friend class SearchPluginManager;
|
||||
|
||||
|
||||
@@ -163,9 +163,9 @@ void SearchHandler::processFailed()
|
||||
// Parse one line of search results list
|
||||
// Line is in the following form:
|
||||
// file url | file name | file size | nb seeds | nb leechers | Search engine url
|
||||
bool SearchHandler::parseSearchResult(const QString &line, SearchResult &searchResult)
|
||||
bool SearchHandler::parseSearchResult(const QStringView line, SearchResult &searchResult)
|
||||
{
|
||||
const QVector<QStringRef> parts = line.splitRef('|');
|
||||
const QList<QStringView> parts = line.split(u'|');
|
||||
const int nbFields = parts.size();
|
||||
|
||||
if (nbFields < (NB_PLUGIN_COLUMNS - 1)) return false; // -1 because desc_link is optional
|
||||
|
||||
@@ -54,7 +54,7 @@ class SearchPluginManager;
|
||||
class SearchHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(SearchHandler)
|
||||
Q_DISABLE_COPY_MOVE(SearchHandler)
|
||||
|
||||
friend class SearchPluginManager;
|
||||
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
void readSearchOutput();
|
||||
void processFailed();
|
||||
void processFinished(int exitcode);
|
||||
bool parseSearchResult(const QString &line, SearchResult &searchResult);
|
||||
bool parseSearchResult(QStringView line, SearchResult &searchResult);
|
||||
|
||||
const QString m_pattern;
|
||||
const QString m_category;
|
||||
|
||||
@@ -60,7 +60,7 @@ class SearchHandler;
|
||||
class SearchPluginManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(SearchPluginManager)
|
||||
Q_DISABLE_COPY_MOVE(SearchPluginManager)
|
||||
|
||||
public:
|
||||
SearchPluginManager();
|
||||
|
||||
@@ -234,6 +234,13 @@ void SettingsStorage::removeValue(const QString &key)
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsStorage::hasKey(const QString &key) const
|
||||
{
|
||||
const QString realKey = mapKey(key);
|
||||
const QReadLocker locker {&m_lock};
|
||||
return m_data.contains(realKey);
|
||||
}
|
||||
|
||||
QVariantHash TransactionalSettings::read() const
|
||||
{
|
||||
QVariantHash res;
|
||||
|
||||
@@ -79,6 +79,7 @@ public:
|
||||
}
|
||||
|
||||
void removeValue(const QString &key);
|
||||
bool hasKey(const QString &key) const;
|
||||
|
||||
public slots:
|
||||
bool save();
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace
|
||||
class TorrentFilesWatcher::Worker final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Worker)
|
||||
Q_DISABLE_COPY_MOVE(Worker)
|
||||
|
||||
public:
|
||||
Worker();
|
||||
@@ -268,11 +268,10 @@ QString TorrentFilesWatcher::makeCleanPath(const QString &path)
|
||||
if (path.isEmpty())
|
||||
throw InvalidArgument(tr("Watched folder path cannot be empty."));
|
||||
|
||||
const QDir dir {path};
|
||||
if (dir.isRelative())
|
||||
if (QDir::isRelativePath(path))
|
||||
throw InvalidArgument(tr("Watched folder path cannot be relative."));
|
||||
|
||||
return dir.canonicalPath();
|
||||
return QDir::cleanPath(path);
|
||||
}
|
||||
|
||||
void TorrentFilesWatcher::load()
|
||||
@@ -295,7 +294,7 @@ void TorrentFilesWatcher::load()
|
||||
const QJsonDocument jsonDoc = QJsonDocument::fromJson(confFile.readAll(), &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError)
|
||||
{
|
||||
LogMsg(tr("Couldn't parse Watched Folders configuration from %1. Error: %2")
|
||||
LogMsg(tr("Couldn't parse Watched Folders configuration from %1. Error: %2")
|
||||
.arg(confFile.fileName(), jsonError.errorString()), Log::WARNING);
|
||||
return;
|
||||
}
|
||||
@@ -601,13 +600,10 @@ void TorrentFilesWatcher::Worker::addWatchedFolder(const QString &path, const To
|
||||
{
|
||||
#if !defined Q_OS_HAIKU
|
||||
// Check if the path points to a network file system or not
|
||||
if (Utils::Fs::isNetworkFileSystem(path))
|
||||
{
|
||||
m_watchedByTimeoutFolders.insert(path);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (Utils::Fs::isNetworkFileSystem(path) || options.recursive)
|
||||
#else
|
||||
if (options.recursive)
|
||||
#endif
|
||||
{
|
||||
m_watchedByTimeoutFolders.insert(path);
|
||||
if (!m_watchTimer->isActive())
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace BitTorrent
|
||||
class TorrentFilesWatcher final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(TorrentFilesWatcher)
|
||||
Q_DISABLE_COPY_MOVE(TorrentFilesWatcher)
|
||||
|
||||
public:
|
||||
struct WatchedFolderOptions
|
||||
|
||||
@@ -45,6 +45,7 @@ const TorrentFilter TorrentFilter::InactiveTorrent(TorrentFilter::Inactive);
|
||||
const TorrentFilter TorrentFilter::StalledTorrent(TorrentFilter::Stalled);
|
||||
const TorrentFilter TorrentFilter::StalledUploadingTorrent(TorrentFilter::StalledUploading);
|
||||
const TorrentFilter TorrentFilter::StalledDownloadingTorrent(TorrentFilter::StalledDownloading);
|
||||
const TorrentFilter TorrentFilter::CheckingTorrent(TorrentFilter::Checking);
|
||||
const TorrentFilter TorrentFilter::ErroredTorrent(TorrentFilter::Errored);
|
||||
|
||||
using BitTorrent::Torrent;
|
||||
@@ -101,6 +102,8 @@ bool TorrentFilter::setTypeByName(const QString &filter)
|
||||
type = StalledUploading;
|
||||
else if (filter == "stalled_downloading")
|
||||
type = StalledDownloading;
|
||||
else if (filter == "checking")
|
||||
type = Checking;
|
||||
else if (filter == "errored")
|
||||
type = Errored;
|
||||
|
||||
@@ -180,6 +183,10 @@ bool TorrentFilter::matchState(const BitTorrent::Torrent *const torrent) const
|
||||
return torrent->state() == BitTorrent::TorrentState::StalledUploading;
|
||||
case StalledDownloading:
|
||||
return torrent->state() == BitTorrent::TorrentState::StalledDownloading;
|
||||
case Checking:
|
||||
return (torrent->state() == BitTorrent::TorrentState::CheckingUploading)
|
||||
|| (torrent->state() == BitTorrent::TorrentState::CheckingDownloading)
|
||||
|| (torrent->state() == BitTorrent::TorrentState::CheckingResumeData);
|
||||
case Errored:
|
||||
return torrent->isErrored();
|
||||
default: // All
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
Stalled,
|
||||
StalledUploading,
|
||||
StalledDownloading,
|
||||
Checking,
|
||||
Errored
|
||||
};
|
||||
|
||||
@@ -74,6 +75,7 @@ public:
|
||||
static const TorrentFilter StalledTorrent;
|
||||
static const TorrentFilter StalledUploadingTorrent;
|
||||
static const TorrentFilter StalledDownloadingTorrent;
|
||||
static const TorrentFilter CheckingTorrent;
|
||||
static const TorrentFilter ErroredTorrent;
|
||||
|
||||
TorrentFilter() = default;
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <Qt>
|
||||
#include <QtContainerFwd>
|
||||
|
||||
class QByteArray;
|
||||
|
||||
namespace Utils::ByteArray
|
||||
{
|
||||
// Mimic QString::splitRef(sep, behavior)
|
||||
// Mimic QStringView(in).split(sep, behavior)
|
||||
QVector<QByteArray> splitToViews(const QByteArray &in, const QByteArray &sep, const Qt::SplitBehavior behavior = Qt::KeepEmptyParts);
|
||||
|
||||
// Mimic QByteArray::mid(pos, len) but instead of returning a full-copy,
|
||||
|
||||
@@ -60,16 +60,16 @@ int Utils::Compare::naturalCompare(const QString &left, const QString &right, co
|
||||
{
|
||||
// Both are digits, compare the numbers
|
||||
|
||||
const auto numberView = [](const QString &str, int &pos) -> QStringRef
|
||||
const auto numberView = [](const QStringView str, int &pos) -> QStringView
|
||||
{
|
||||
const int start = pos;
|
||||
while ((pos < str.size()) && str[pos].isDigit())
|
||||
++pos;
|
||||
return str.midRef(start, (pos - start));
|
||||
return str.mid(start, (pos - start));
|
||||
};
|
||||
|
||||
const QStringRef numViewL = numberView(left, posL);
|
||||
const QStringRef numViewR = numberView(right, posR);
|
||||
const QStringView numViewL = numberView(left, posL);
|
||||
const QStringView numViewR = numberView(right, posR);
|
||||
|
||||
if (numViewL.length() != numViewR.length())
|
||||
return (numViewL.length() - numViewR.length());
|
||||
|
||||
@@ -498,7 +498,7 @@ QString Utils::Misc::opensslVersionString()
|
||||
#else
|
||||
static const auto version {QString::fromLatin1(SSLeay_version(SSLEAY_VERSION))};
|
||||
#endif
|
||||
return version.splitRef(' ', Qt::SkipEmptyParts)[1].toString();
|
||||
return QStringView(version).split(u' ', Qt::SkipEmptyParts)[1].toString();
|
||||
}
|
||||
|
||||
QString Utils::Misc::zlibVersionString()
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
// to send numbers instead of strings with suffixes
|
||||
QString Utils::String::fromDouble(const double n, const int precision)
|
||||
{
|
||||
/* HACK because QString rounds up. Eg QString::number(0.999*100.0, 'f' ,1) == 99.9
|
||||
/* HACK because QString rounds up. Eg QString::number(0.999*100.0, 'f', 1) == 99.9
|
||||
** but QString::number(0.9999*100.0, 'f' ,1) == 100.0 The problem manifests when
|
||||
** the number has more digits after the decimal than we want AND the digit after
|
||||
** our 'wanted' is >= 5. In this case our last digit gets rounded up. So for each
|
||||
@@ -99,7 +99,7 @@ std::optional<double> Utils::String::parseDouble(const QString &string)
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QString Utils::String::join(const QVector<QStringRef> &strings, const QString &separator)
|
||||
QString Utils::String::join(const QList<QStringView> &strings, const QStringView separator)
|
||||
{
|
||||
if (strings.empty())
|
||||
return {};
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
#include <Qt>
|
||||
#include <QtContainerFwd>
|
||||
|
||||
class QStringRef;
|
||||
|
||||
namespace Utils::String
|
||||
{
|
||||
QString wildcardToRegexPattern(const QString &pattern);
|
||||
@@ -61,7 +59,7 @@ namespace Utils::String
|
||||
std::optional<int> parseInt(const QString &string);
|
||||
std::optional<double> parseDouble(const QString &string);
|
||||
|
||||
QString join(const QVector<QStringRef> &strings, const QString &separator);
|
||||
QString join(const QList<QStringView> &strings, QStringView separator);
|
||||
|
||||
QString fromDouble(double n, int precision);
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#define QBT_VERSION_MINOR 4
|
||||
#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 "beta2" // Should be empty for stable releases!
|
||||
|
||||
#define QBT__STRINGIFY(x) #x
|
||||
#define QBT_STRINGIFY(x) QBT__STRINGIFY(x)
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Ui
|
||||
class AboutDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(AboutDialog)
|
||||
Q_DISABLE_COPY_MOVE(AboutDialog)
|
||||
|
||||
public:
|
||||
explicit AboutDialog(QWidget *parent);
|
||||
|
||||
@@ -460,7 +460,7 @@ void AddNewTorrentDialog::saveTorrentFile()
|
||||
Q_ASSERT(m_hasMetadata);
|
||||
|
||||
const QString torrentFileExtension {C_TORRENT_FILE_EXTENSION};
|
||||
const QString filter {QString{"Torrent file (*%1)"}.arg(torrentFileExtension)};
|
||||
const QString filter {tr("Torrent file (*%1)").arg(torrentFileExtension)};
|
||||
|
||||
QString path = QFileDialog::getSaveFileName(
|
||||
this, tr("Save as torrent file")
|
||||
@@ -679,6 +679,13 @@ void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &metadata
|
||||
// Update UI
|
||||
setupTreeview();
|
||||
setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
|
||||
|
||||
m_ui->buttonSave->setVisible(true);
|
||||
if (m_torrentInfo.infoHash().v2().isValid())
|
||||
{
|
||||
m_ui->buttonSave->setEnabled(false);
|
||||
m_ui->buttonSave->setToolTip(tr("Cannot create v2 torrent until its data is fully downloaded."));
|
||||
}
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText)
|
||||
@@ -687,7 +694,6 @@ void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, co
|
||||
m_ui->lblMetaLoading->setVisible(true);
|
||||
m_ui->lblMetaLoading->setText(labelText);
|
||||
m_ui->progMetaLoading->setVisible(visibleIndicator);
|
||||
m_ui->buttonSave->setVisible(!visibleIndicator);
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::setupTreeview()
|
||||
|
||||
@@ -59,7 +59,7 @@ class TorrentFileGuard;
|
||||
class AddNewTorrentDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(AddNewTorrentDialog)
|
||||
Q_DISABLE_COPY_MOVE(AddNewTorrentDialog)
|
||||
|
||||
public:
|
||||
static const int minPathHistoryLength = 0;
|
||||
|
||||
@@ -355,7 +355,7 @@
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="labelInfohash2">
|
||||
<property name="text">
|
||||
<string>Info hash v2</string>
|
||||
<string>Info hash v2:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Ui
|
||||
class BanListOptionsDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(BanListOptionsDialog)
|
||||
Q_DISABLE_COPY_MOVE(BanListOptionsDialog)
|
||||
|
||||
public:
|
||||
explicit BanListOptionsDialog(QWidget *parent = nullptr);
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
class CategoryFilterWidget final : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(CategoryFilterWidget)
|
||||
Q_DISABLE_COPY_MOVE(CategoryFilterWidget)
|
||||
|
||||
public:
|
||||
explicit CategoryFilterWidget(QWidget *parent = nullptr);
|
||||
|
||||
@@ -49,8 +49,12 @@ namespace
|
||||
|| str.startsWith("https://", Qt::CaseInsensitive)
|
||||
|| str.startsWith("ftp://", Qt::CaseInsensitive)
|
||||
|| str.startsWith("magnet:", Qt::CaseInsensitive)
|
||||
|| ((str.size() == 40) && !str.contains(QRegularExpression("[^0-9A-Fa-f]")))
|
||||
|| ((str.size() == 32) && !str.contains(QRegularExpression("[^2-7A-Za-z]"))));
|
||||
|| ((str.size() == 40) && !str.contains(QRegularExpression("[^0-9A-Fa-f]"))) // v1 hex-encoded SHA-1 info-hash
|
||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||
|| ((str.size() == 64) && !str.contains(QRegularExpression("[^0-9A-Fa-f]"))) // v2 hex-encoded SHA-256 info-hash
|
||||
#endif
|
||||
|| ((str.size() == 32) && !str.contains(QRegularExpression("[^2-7A-Za-z]")))); // v1 Base32 encoded SHA-1 info-hash
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +75,10 @@ DownloadFromURLDialog::DownloadFromURLDialog(QWidget *parent)
|
||||
|
||||
// Paste clipboard if there is an URL in it
|
||||
const QString clipboardText = qApp->clipboard()->text();
|
||||
const QVector<QStringRef> clipboardList = clipboardText.splitRef('\n');
|
||||
const QList<QStringView> clipboardList = QStringView(clipboardText).split(u'\n');
|
||||
|
||||
QSet<QString> uniqueURLs;
|
||||
for (QStringRef strRef : clipboardList)
|
||||
for (QStringView strRef : clipboardList)
|
||||
{
|
||||
strRef = strRef.trimmed();
|
||||
if (strRef.isEmpty()) continue;
|
||||
@@ -103,10 +107,10 @@ DownloadFromURLDialog::~DownloadFromURLDialog()
|
||||
void DownloadFromURLDialog::downloadButtonClicked()
|
||||
{
|
||||
const QString plainText = m_ui->textUrls->toPlainText();
|
||||
const QVector<QStringRef> urls = plainText.splitRef('\n');
|
||||
const QList<QStringView> urls = QStringView(plainText).split(u'\n');
|
||||
|
||||
QSet<QString> uniqueURLs;
|
||||
for (QStringRef url : urls)
|
||||
for (QStringView url : urls)
|
||||
{
|
||||
url = url.trimmed();
|
||||
if (url.isEmpty()) continue;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Ui
|
||||
class DownloadFromURLDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(DownloadFromURLDialog)
|
||||
Q_DISABLE_COPY_MOVE(DownloadFromURLDialog)
|
||||
|
||||
public:
|
||||
explicit DownloadFromURLDialog(QWidget *parent);
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace
|
||||
class FileSystemPathEdit::FileSystemPathEditPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(FileSystemPathEdit)
|
||||
Q_DISABLE_COPY(FileSystemPathEditPrivate)
|
||||
Q_DISABLE_COPY_MOVE(FileSystemPathEditPrivate)
|
||||
|
||||
FileSystemPathEditPrivate(FileSystemPathEdit *q, Private::FileEditorWithCompletion *editor);
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
virtual void setEditWidgetText(const QString &text) = 0;
|
||||
|
||||
QWidget *editWidgetImpl() const;
|
||||
Q_DISABLE_COPY(FileSystemPathEdit)
|
||||
Q_DISABLE_COPY_MOVE(FileSystemPathEdit)
|
||||
class FileSystemPathEditPrivate;
|
||||
Q_DECLARE_PRIVATE(FileSystemPathEdit)
|
||||
FileSystemPathEditPrivate *d_ptr;
|
||||
|
||||
@@ -107,30 +107,32 @@ QValidator::State Private::FileSystemPathValidator::validate(QString &input, int
|
||||
|
||||
// we test path components from beginning to the one with cursor location in strict mode
|
||||
// and the one with cursor and beyond in non-strict mode
|
||||
QVector<QStringRef> components = input.splitRef(QDir::separator(), Qt::KeepEmptyParts);
|
||||
QList<QStringView> components = QStringView(input).split(QDir::separator(), Qt::KeepEmptyParts);
|
||||
// find index of the component that contains pos
|
||||
int componentWithCursorIndex = 0;
|
||||
int componentWithCursorPosition = 0;
|
||||
int pathLength = 0;
|
||||
|
||||
// components.size() - 1 because when path ends with QDir::separator(), we will not see the last
|
||||
// character in the components array, yet everything past the one before the last delimiter
|
||||
// belongs to the last component
|
||||
for (; (componentWithCursorIndex < components.size() - 1) && (pathLength < pos); ++componentWithCursorIndex)
|
||||
for (; (componentWithCursorIndex < (components.size() - 1)) && (pathLength < pos); ++componentWithCursorIndex)
|
||||
{
|
||||
pathLength = components[componentWithCursorIndex].position() + components[componentWithCursorIndex].size();
|
||||
pathLength = componentWithCursorPosition + components[componentWithCursorIndex].size();
|
||||
componentWithCursorPosition += components[componentWithCursorIndex].size() + 1;
|
||||
}
|
||||
|
||||
Q_ASSERT(componentWithCursorIndex < components.size());
|
||||
|
||||
m_lastValidationState = QValidator::Acceptable;
|
||||
if (componentWithCursorIndex > 0)
|
||||
m_lastValidationState = validate(input, components, m_strictMode, 0, componentWithCursorIndex - 1);
|
||||
m_lastValidationState = validate(components, m_strictMode, 0, componentWithCursorIndex - 1);
|
||||
if ((m_lastValidationState == QValidator::Acceptable) && (componentWithCursorIndex < components.size()))
|
||||
m_lastValidationState = validate(input, components, false, componentWithCursorIndex, components.size() - 1);
|
||||
m_lastValidationState = validate(components, false, componentWithCursorIndex, components.size() - 1);
|
||||
return m_lastValidationState;
|
||||
}
|
||||
|
||||
QValidator::State Private::FileSystemPathValidator::validate(const QString &path, const QVector<QStringRef> &pathComponents, bool strict,
|
||||
QValidator::State Private::FileSystemPathValidator::validate(const QList<QStringView> &pathComponents, bool strict,
|
||||
int firstComponentToTest, int lastComponentToTest) const
|
||||
{
|
||||
Q_ASSERT(firstComponentToTest >= 0);
|
||||
@@ -141,12 +143,13 @@ QValidator::State Private::FileSystemPathValidator::validate(const QString &path
|
||||
if (pathComponents.empty())
|
||||
return strict ? QValidator::Invalid : QValidator::Intermediate;
|
||||
|
||||
for (int i = firstComponentToTest; i < lastComponentToTest; ++i)
|
||||
for (int i = firstComponentToTest; i <= lastComponentToTest; ++i)
|
||||
{
|
||||
if (pathComponents[i].isEmpty()) continue;
|
||||
const bool isFinalPath = (i == (pathComponents.size() - 1));
|
||||
const QStringView componentPath = pathComponents[i];
|
||||
if (componentPath.isEmpty()) continue;
|
||||
|
||||
QStringRef componentPath(&path, 0, pathComponents[i].position() + pathComponents[i].size());
|
||||
m_lastTestResult = testPath(componentPath, false);
|
||||
m_lastTestResult = testPath(pathComponents[i], isFinalPath);
|
||||
if (m_lastTestResult != TestResult::OK)
|
||||
{
|
||||
m_lastTestedPath = componentPath.toString();
|
||||
@@ -154,20 +157,11 @@ QValidator::State Private::FileSystemPathValidator::validate(const QString &path
|
||||
}
|
||||
}
|
||||
|
||||
const bool finalPath = (lastComponentToTest == (pathComponents.size() - 1));
|
||||
QStringRef componentPath(&path, 0, pathComponents[lastComponentToTest].position()
|
||||
+ pathComponents[lastComponentToTest].size());
|
||||
m_lastTestResult = testPath(componentPath, finalPath);
|
||||
if (m_lastTestResult != TestResult::OK)
|
||||
{
|
||||
m_lastTestedPath = componentPath.toString();
|
||||
return strict ? QValidator::Invalid : QValidator::Intermediate;
|
||||
}
|
||||
return QValidator::Acceptable;
|
||||
}
|
||||
|
||||
Private::FileSystemPathValidator::TestResult
|
||||
Private::FileSystemPathValidator::testPath(const QStringRef &path, bool pathIsComplete) const
|
||||
Private::FileSystemPathValidator::testPath(const QStringView path, bool pathIsComplete) const
|
||||
{
|
||||
QFileInfo fi(path.toString());
|
||||
if (m_existingOnly && !fi.exists())
|
||||
|
||||
@@ -39,7 +39,6 @@ class QCompleter;
|
||||
class QContextMenuEvent;
|
||||
class QFileSystemModel;
|
||||
class QKeyEvent;
|
||||
class QStringRef;
|
||||
|
||||
namespace Private
|
||||
{
|
||||
@@ -82,10 +81,10 @@ namespace Private
|
||||
QString lastTestedPath() const;
|
||||
|
||||
private:
|
||||
QValidator::State validate(const QString &path, const QVector<QStringRef> &pathComponents, bool strict,
|
||||
QValidator::State validate(const QList<QStringView> &pathComponents, bool strict,
|
||||
int firstComponentToTest, int lastComponentToTest) const;
|
||||
|
||||
TestResult testPath(const QStringRef &path, bool pathIsComplete) const;
|
||||
TestResult testPath(QStringView path, bool pathIsComplete) const;
|
||||
|
||||
bool m_strictMode;
|
||||
bool m_existingOnly;
|
||||
@@ -112,7 +111,7 @@ namespace Private
|
||||
class FileLineEdit final : public QLineEdit, public FileEditorWithCompletion
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(FileLineEdit)
|
||||
Q_DISABLE_COPY_MOVE(FileLineEdit)
|
||||
|
||||
public:
|
||||
FileLineEdit(QWidget *parent = nullptr);
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Ui
|
||||
class IPSubnetWhitelistOptionsDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(IPSubnetWhitelistOptionsDialog)
|
||||
Q_DISABLE_COPY_MOVE(IPSubnetWhitelistOptionsDialog)
|
||||
|
||||
public:
|
||||
explicit IPSubnetWhitelistOptionsDialog(QWidget *parent = nullptr);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
class LogFilterModel final : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LogFilterModel)
|
||||
Q_DISABLE_COPY_MOVE(LogFilterModel)
|
||||
|
||||
public:
|
||||
explicit LogFilterModel(Log::MsgTypes types = Log::ALL, QObject *parent = nullptr);
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
class LogListView final : public QListView
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LogListView)
|
||||
Q_DISABLE_COPY_MOVE(LogListView)
|
||||
|
||||
public:
|
||||
explicit LogListView(QWidget *parent = nullptr);
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
class BaseLogModel : public QAbstractListModel
|
||||
{
|
||||
Q_DISABLE_COPY(BaseLogModel)
|
||||
Q_DISABLE_COPY_MOVE(BaseLogModel)
|
||||
|
||||
public:
|
||||
enum MessageTypeRole
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
class LogMessageModel : public BaseLogModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LogMessageModel)
|
||||
Q_DISABLE_COPY_MOVE(LogMessageModel)
|
||||
|
||||
public:
|
||||
explicit LogMessageModel(QObject *parent = nullptr);
|
||||
@@ -101,7 +101,7 @@ private:
|
||||
class LogPeerModel : public BaseLogModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LogPeerModel)
|
||||
Q_DISABLE_COPY_MOVE(LogPeerModel)
|
||||
|
||||
public:
|
||||
explicit LogPeerModel(QObject *parent = nullptr);
|
||||
|
||||
@@ -68,14 +68,14 @@ namespace MacUtils
|
||||
|
||||
if (class_getInstanceMethod(delClass, shouldHandle))
|
||||
{
|
||||
if (class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
|
||||
if (class_replaceMethod(delClass, shouldHandle, reinterpret_cast<IMP>(dockClickHandler), "B@:"))
|
||||
qDebug("Registered dock click handler (replaced original method)");
|
||||
else
|
||||
qWarning("Failed to replace method for dock click handler");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
|
||||
if (class_addMethod(delClass, shouldHandle, reinterpret_cast<IMP>(dockClickHandler), "B@:"))
|
||||
qDebug("Registered dock click handler");
|
||||
else
|
||||
qWarning("Failed to register dock click handler");
|
||||
|
||||
@@ -2184,8 +2184,9 @@ void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result)
|
||||
QProcess installer;
|
||||
qDebug("Launching Python installer in passive mode...");
|
||||
|
||||
QFile::rename(result.filePath, result.filePath + ".exe");
|
||||
installer.start('"' + Utils::Fs::toNativePath(result.filePath) + ".exe\" /passive");
|
||||
const QString exePath = result.filePath + QLatin1String(".exe");
|
||||
QFile::rename(result.filePath, exePath);
|
||||
installer.start(Utils::Fs::toNativePath(exePath), {"/passive"});
|
||||
|
||||
// Wait for setup to complete
|
||||
installer.waitForFinished(10 * 60 * 1000);
|
||||
@@ -2195,7 +2196,7 @@ void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result)
|
||||
qDebug("Setup should be complete!");
|
||||
|
||||
// Delete temp file
|
||||
Utils::Fs::forceRemove(result.filePath + ".exe");
|
||||
Utils::Fs::forceRemove(exePath);
|
||||
|
||||
// Reload search engine
|
||||
if (Utils::ForeignApps::pythonInfo().isSupportedVersion())
|
||||
|
||||
@@ -180,6 +180,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
, m_ui {new Ui::OptionsDialog}
|
||||
, m_storeDialogSize {SETTINGS_KEY("Size")}
|
||||
, m_storeHSplitterSize {SETTINGS_KEY("HorizontalSplitterSizes")}
|
||||
, m_storeLastViewedPage {SETTINGS_KEY("LastViewedPage")}
|
||||
{
|
||||
qDebug("-> Constructing Options");
|
||||
m_ui->setupUi(this);
|
||||
@@ -300,7 +301,6 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
void (QSpinBox::*qSpinBoxValueChanged)(int) = &QSpinBox::valueChanged;
|
||||
|
||||
connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableProxy);
|
||||
connect(m_ui->checkRandomPort, &QAbstractButton::toggled, m_ui->spinPort, &ThisType::setDisabled);
|
||||
|
||||
// Apply button is activated when a value is changed
|
||||
// Behavior tab
|
||||
@@ -408,7 +408,6 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
// Connection tab
|
||||
connect(m_ui->comboProtocol, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->spinPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->checkRandomPort, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->checkUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->spinUploadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->spinDownloadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
|
||||
@@ -570,6 +569,8 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
for (QSpinBox *widget : asConst(findChildren<QSpinBox *>()))
|
||||
widget->installEventFilter(wheelEventEater);
|
||||
|
||||
m_ui->tabSelection->setCurrentRow(m_storeLastViewedPage);
|
||||
|
||||
Utils::Gui::resize(this, m_storeDialogSize);
|
||||
show();
|
||||
// Have to be called after show(), because splitter width needed
|
||||
@@ -619,6 +620,8 @@ OptionsDialog::~OptionsDialog()
|
||||
hSplitterSizes.append(QString::number(size));
|
||||
m_storeHSplitterSize = hSplitterSizes;
|
||||
|
||||
m_storeLastViewedPage = m_ui->tabSelection->currentRow();
|
||||
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
@@ -770,7 +773,6 @@ void OptionsDialog::saveOptions()
|
||||
// Connection preferences
|
||||
session->setBTProtocol(static_cast<BitTorrent::BTProtocol>(m_ui->comboProtocol->currentIndex()));
|
||||
session->setPort(getPort());
|
||||
session->setUseRandomPort(m_ui->checkRandomPort->isChecked());
|
||||
Net::PortForwarder::instance()->setEnabled(isUPnPEnabled());
|
||||
session->setGlobalDownloadSpeedLimit(m_ui->spinDownloadLimit->value() * 1024);
|
||||
session->setGlobalUploadSpeedLimit(m_ui->spinUploadLimit->value() * 1024);
|
||||
@@ -1067,10 +1069,8 @@ void OptionsDialog::loadOptions()
|
||||
|
||||
// Connection preferences
|
||||
m_ui->comboProtocol->setCurrentIndex(static_cast<int>(session->btProtocol()));
|
||||
m_ui->checkUPnP->setChecked(Net::PortForwarder::instance()->isEnabled());
|
||||
m_ui->checkRandomPort->setChecked(session->useRandomPort());
|
||||
m_ui->spinPort->setValue(session->port());
|
||||
m_ui->spinPort->setDisabled(m_ui->checkRandomPort->isChecked());
|
||||
m_ui->checkUPnP->setChecked(Net::PortForwarder::instance()->isEnabled());
|
||||
|
||||
intValue = session->maxConnections();
|
||||
if (intValue > 0)
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Ui
|
||||
class OptionsDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(OptionsDialog)
|
||||
Q_DISABLE_COPY_MOVE(OptionsDialog)
|
||||
|
||||
using ThisType = OptionsDialog;
|
||||
|
||||
@@ -181,6 +181,7 @@ private:
|
||||
Ui::OptionsDialog *m_ui;
|
||||
SettingValue<QSize> m_storeDialogSize;
|
||||
SettingValue<QStringList> m_storeHSplitterSize;
|
||||
SettingValue<int> m_storeLastViewedPage;
|
||||
|
||||
QPushButton *m_applyButton;
|
||||
|
||||
|
||||
@@ -1457,15 +1457,12 @@ Manual: Various torrent properties (e.g. save path) must be assigned manually</s
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinPort">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
<property name="specialValueText">
|
||||
<string>Any</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -1500,13 +1497,6 @@ Manual: Various torrent properties (e.g. save path) must be assigned manually</s
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkRandomPort">
|
||||
<property name="text">
|
||||
<string>Use different port on each startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -2673,14 +2663,7 @@ Disable encryption: Only connect to peers without protocol encryption</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_16">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPlainTextEdit" name="textTrackers">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPlainTextEdit" name="textTrackers"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -3288,7 +3271,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupEnableReverseProxySupport">
|
||||
<property name="title">
|
||||
<string>Enable reverse proxy support</string>
|
||||
@@ -3527,7 +3510,6 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
|
||||
<tabstop>lineEditAutoRun</tabstop>
|
||||
<tabstop>scrollArea_3</tabstop>
|
||||
<tabstop>randomButton</tabstop>
|
||||
<tabstop>checkRandomPort</tabstop>
|
||||
<tabstop>checkMaxConnecs</tabstop>
|
||||
<tabstop>spinMaxConnec</tabstop>
|
||||
<tabstop>checkMaxConnecsPerTorrent</tabstop>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user