Compare commits

..

42 Commits

Author SHA1 Message Date
dependabot[bot]
576774bcae GHA CI: Bump actions/upload-artifact in the github-actions group
Bumps the github-actions group with 1 update: [actions/upload-artifact](https://github.com/actions/upload-artifact).


Updates `actions/upload-artifact` from 5 to 6
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 10:03:09 +00:00
sledgehammer999
9d5a8270cf Bump to v5.2.0beta1 2025-12-31 21:54:34 +02:00
sledgehammer999
d55b924190 Sync translations from Transifex and run lupdate 2025-12-31 21:50:08 +02:00
Chocobo1
a5b5ba2065 GHA CI: improve manageability for boost version
Adopted suggestion from: https://github.com/qbittorrent/qBittorrent/pull/23631#discussion_r2637707057

PR #23671.
2025-12-30 21:59:40 +08:00
Chocobo1
14d2db185a WebUI: simplify code for filtering nodes
Now it use object property to store visited information instead of an array.
Also prefix temporary properties with underscore.
There are no user visible changes.

PR #23670.
2025-12-30 21:50:09 +08:00
Chocobo1
351b065553 Migrate away from old libtorrent setting
The setting has been renamed from `peer_tos` to `peer_dscp` and the default value has changed
from `0x04` to `0x01`.
Note that in WebAPI and qbt config, the previous name is retained to avoid disruption to user.

Upstream PR:
https://github.com/arvidn/libtorrent/pull/6822
https://github.com/arvidn/libtorrent/pull/8072

PR #23669.
2025-12-30 21:17:37 +08:00
Vladimir Golovnev
52a6e7229b Refresh announce status if trackers were removed or replaced
PR #23668.
2025-12-29 11:50:58 +03:00
xavier2k6
be12be2b79 GHA CI: Bump pandoc version
https://github.com/jgm/pandoc/releases/

PR #23638.
2025-12-27 23:02:46 +08:00
Vladimir Golovnev
0bba3f342e Fix incorrect save path when torrent is added from watched folder
PR #23656.
Closes #23302.
2025-12-27 09:04:06 +03:00
Chocobo1
ae7cc7445b Enable strict type checking for Pyright
Doc: https://github.com/microsoft/pyright/blob/main/docs/configuration.md#type-check-diagnostics-settings

PR #23634.
2025-12-22 12:14:38 +08:00
Chocobo1
e79be5853e Enforce Python to run in UTF-8 mode
When running Python via QProcess on Windows, the output code page will be set to the system default instead of UTF-8.
This commit enforces that UTF-8 will be used unconditionally.

Supersedes #23629.
PR #23633.
2025-12-22 12:00:27 +08:00
Chocobo1
b718cc52fa GHA CI: separate Boost version for different libtorrent branches
PR #23631.
2025-12-22 11:20:33 +08:00
Vladimir Golovnev
57c99b54c8 Move torrents to parent category when category is removed
PR #23620.
2025-12-21 19:49:29 +03:00
Vladimir Golovnev
25224f6050 Remove indentation if no subcategory exists
PR #23619.
2025-12-21 19:49:02 +03:00
Vladimir Golovnev
b5d16dfeee Allow to set torrent share limits per category
PR #23577.
2025-12-21 19:48:31 +03:00
Tom Piccirello
1c231ce014 WebUI: keep preferences window open after unsuccessful save
This gives the user another opportunity to save their changes.

PR #23549.
2025-12-20 17:21:26 +08:00
Vladimir Golovnev
93470f2080 Use subcategories unconditionally
PR #23585.
2025-12-16 21:56:15 +03:00
Andrei Stepanov
260563d340 NSIS: Update Russian translation
PR #23602.
2025-12-15 16:40:17 +08:00
Burak Yavuz
b792ecede5 NSIS: Update Turkish translation
PR #23434.
2025-12-15 16:34:24 +08:00
John Veness
19ebf67c74 Use consistent text for "Do not download" priority
To match priority setting in menu.

PR #23593.
2025-12-15 16:28:19 +08:00
xavier2k6
56cd98e06e GHA CI: Bump Boost dependency in coverity-scan workflow
* Bumped Boost to `1.90.0`
https://www.boost.org/releases/1.90.0/

PR #23591.
2025-12-15 16:21:34 +08:00
Mark Yu
c25bd6aaea GHA CI: Include all image format plugins in Windows installer
Add support for WebP in the RSS viewer

Closes #23169.
Closes #23573.
PR #23590.
2025-12-15 16:14:49 +08:00
tehcneko
26e42abf32 WebUI: Clean up duplicated codes in dynamic table
Call class super methods.

PR #23576.
2025-12-15 16:07:35 +08:00
Chocobo1
5abf458e69 Calculate torrent pieces asynchronously
So the GUI won't hang when the calculation took a long time.
Note that it is not possible to cancel the calculation so it will always run until finish in the background.

Supersedes #23497.
PR #23584.
2025-12-13 14:22:20 +08:00
dependabot[bot]
7451552e6a GHA CI: Bump actions version
PR #23566.

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-13 14:13:34 +08:00
Vladimir Golovnev
96161627d6 Fix invalid index
PR #23586.
2025-12-10 16:26:39 +03:00
xavier2k6
0f80d3a74a GHA CI: Bump Qt version
* Bump `Qt` version to `6.10.1` for (Windows, macOS, coverity-scan)

PR #23563.
2025-12-07 18:45:10 +08:00
sledgehammer999
73c15e1f00 Revert "NSIS: Create a mutex to ensure only one installer is running" (#23540)
This reverts commit 530c7d1bbd.
The installer uses the `UAC` plugin which creates two instances of the
installer when launched. One runs with admin privileges while the other
with user privileges. Creating a mutex in the first instance stops the
other one from continuing.

PR #23540
2025-12-06 11:08:30 +02:00
Vladimir Golovnev
a59238f4ea Correctly detect whether option is actually changed
PR #23574.
2025-12-06 11:02:31 +03:00
Vladimir Golovnev
d918c43aba Fix Trackerless row is removed when it becomes zero
PR #23571.
2025-12-06 11:01:50 +03:00
Vladimir Golovnev
c45dfb6662 Implement separate (advanced) "Tracker status" filter
PR #23452.
2025-12-03 10:09:35 +03:00
Chocobo1
f68bc3fef9 Raise 'torrent share ratio' maximum limit
The default from Qt was `99.99` which could be too small for some.
The new limit is `INT_MAX` (not `DOUBLE_MAX`) as to hide the rounding/approximation errors from the user.

PR #23559.
2025-11-30 21:00:16 +08:00
Chocobo1
ed9a8687ad NSIS: set appropriate error code on error
PR #23557.
2025-11-30 19:51:17 +08:00
Chocobo1
6a4b1b9727 GHA CI: enable ccache by default on forked repository
This change only affects forked repository.
Previously ccache was only enabled on `master` branch regardless of the owner of the repository.
This is not ideal for forked repository where the owner (mostly) wants to run the GHA CI to
create binary for their own use and ccache couldn't be utilized. This change will enable
ccache by default for all non-official repositories.

PR #23558.
2025-11-30 19:37:26 +08:00
Vasiliy Kostin
f2f4676824 Add reboot option when downloads complete
This commit implements a new "Reboot System" option that allows users to automatically reboot the computer when all downloads are complete, similar to the existing shutdown, suspend, and hibernate options.

Closes #10774.
PR #23525.
2025-11-30 19:16:48 +08:00
Mark Yu
8b9064a33c WebUI: Do not hide context menu if the click target has submenu
Add check if the click event occurs in the menu item and if the menu item has a submenu, do not close the context menu.

Closes #23532.
PR #23534.
2025-11-30 19:15:23 +08:00
tehcneko
296c90d688 WebUI: Fix row selection by Shift key with virtual list enabled
Fixes #23336.
PR #23543.
2025-11-30 19:14:30 +08:00
tehcneko
564afc975f WebUI: Fix row collapsing with virtual list enabled
Fixes https://github.com/qbittorrent/qBittorrent/issues/23241#issuecomment-3295352816.
PR #23542.
2025-11-30 19:13:10 +08:00
Vladimir Golovnev
a77b17e6da Allow to configure style and color scheme on all platforms
PR #23522.
2025-11-24 09:04:28 +03:00
Hanabishi
4a3922d152 Make the active torrents filter reflect actual transfers
PR #23431.
Closes #23121.
2025-11-24 09:03:20 +03:00
Chocobo1
1b96a48266 GHA CI: test built binary
This would ensure the built binary is able to start up and rule out compiler or library linking
issues.

PR #23529.
2025-11-24 02:51:46 +08:00
Chocobo1
1f6e7519a0 Raise connection max limits
And remove a few redundant properties as they are the same as the default value (or they have the same effect as using the default value).

Closes #23465.
PR #23528.
2025-11-24 02:38:21 +08:00
266 changed files with 66167 additions and 65066 deletions

View File

@@ -16,7 +16,7 @@ jobs:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
persist-credentials: false
@@ -31,12 +31,13 @@ jobs:
- name: Check doc
env:
pandoc_path: "${{ github.workspace }}/../pandoc"
pandoc_version: "3.8.3"
run: |
# install pandoc
curl \
-L \
-o "${{ runner.temp }}/pandoc.tar.gz" \
"https://github.com/jgm/pandoc/releases/download/3.7.0.2/pandoc-3.7.0.2-linux-amd64.tar.gz"
"https://github.com/jgm/pandoc/releases/download/${{ env.pandoc_version }}/pandoc-${{ env.pandoc_version }}-linux-amd64.tar.gz"
tar -xf "${{ runner.temp }}/pandoc.tar.gz" -C "${{ github.workspace }}/.."
mv "${{ github.workspace }}/.."/pandoc-* "${{ env.pandoc_path }}"
# run pandoc

View File

@@ -18,9 +18,17 @@ jobs:
strategy:
fail-fast: false
matrix:
libt_version: ["2.0.11", "1.2.20"]
libtorrent:
- version: "2.0.11"
boost_major_version: "1"
boost_minor_version: "90"
boost_patch_version: "0"
- version: "1.2.20"
boost_major_version: "1"
boost_minor_version: "86"
boost_patch_version: "0"
qbt_gui: ["GUI=ON", "GUI=OFF"]
qt_version: ["6.9.1"]
qt_version: ["6.10.1"]
env:
boost_path: "${{ github.workspace }}/../boost"
@@ -28,7 +36,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
persist-credentials: false
@@ -49,19 +57,15 @@ jobs:
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
store_cache: ${{ github.ref == 'refs/heads/master' }}
store_cache: ${{ (github.repository != 'qbittorrent/qBittorrent') || (github.ref == 'refs/heads/master') }}
update_packager_index: false
ccache_options: |
max_size=1G
- name: Install boost
env:
BOOST_MAJOR_VERSION: "1"
BOOST_MINOR_VERSION: "86"
BOOST_PATCH_VERSION: "0"
run: |
boost_url="https://archives.boost.io/release/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/source/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz"
boost_url2="https://sourceforge.net/projects/boost/files/boost/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz"
boost_url="https://archives.boost.io/release/${{ matrix.libtorrent.boost_major_version }}.${{ matrix.libtorrent.boost_minor_version }}.${{ matrix.libtorrent.boost_patch_version }}/source/boost_${{ matrix.libtorrent.boost_major_version }}_${{ matrix.libtorrent.boost_minor_version }}_${{ matrix.libtorrent.boost_patch_version }}.tar.gz"
boost_url2="https://sourceforge.net/projects/boost/files/boost/${{ matrix.libtorrent.boost_major_version }}.${{ matrix.libtorrent.boost_minor_version }}.${{ matrix.libtorrent.boost_patch_version }}/boost_${{ matrix.libtorrent.boost_major_version }}_${{ matrix.libtorrent.boost_minor_version }}_${{ matrix.libtorrent.boost_patch_version }}.tar.gz"
set +e
curl -L -o "${{ runner.temp }}/boost.tar.gz" "$boost_url"
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."; _exitCode="$?"
@@ -79,13 +83,14 @@ jobs:
with:
version: ${{ matrix.qt_version }}
archives: qtbase qtdeclarative qtsvg qttools
modules: qtimageformats
# Not sure why Qt made a hard dependency on qtdeclarative, try removing it when Qt > 6.4.0
cache: true
- name: Install libtorrent
run: |
git clone \
--branch v${{ matrix.libt_version }} \
--branch v${{ matrix.libtorrent.version }} \
--depth 1 \
--recurse-submodules \
https://github.com/arvidn/libtorrent.git \
@@ -119,6 +124,11 @@ jobs:
cmake --build build --target qbt_update_translations
cmake --build build
cmake --build build --target check
if [ "${{ matrix.qbt_gui }}" = "GUI=ON" ]; then
build/qbittorrent.app/Contents/MacOS/qbittorrent -v
else
build/qbittorrent-nox.app/Contents/MacOS/qbittorrent-nox -v
fi
- name: Prepare build artifacts
run: |
@@ -156,7 +166,7 @@ jobs:
cp ${{ env.libtorrent_path }}/build/compile_commands.json upload/cmake/libtorrent
- name: Upload build artifacts
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: qBittorrent-CI_macOS_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libt_version }}_Qt-${{ matrix.qt_version }}
name: qBittorrent-CI_macOS_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libtorrent.version }}_Qt-${{ matrix.qt_version }}
path: upload

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
persist-credentials: false

View File

@@ -19,7 +19,15 @@ jobs:
strategy:
fail-fast: false
matrix:
libt_version: ["2.0.11", "1.2.20"]
libtorrent:
- version: "2.0.11"
boost_major_version: "1"
boost_minor_version: "77"
boost_patch_version: "0"
- version: "1.2.20"
boost_major_version: "1"
boost_minor_version: "77"
boost_patch_version: "0"
qbt_gui: ["GUI=ON", "GUI=OFF"]
qt_version: ["6.6.3"]
@@ -30,7 +38,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
persist-credentials: false
@@ -39,24 +47,20 @@ jobs:
sudo apt update
sudo apt install \
build-essential cmake ninja-build \
libssl-dev libxkbcommon-x11-dev libxcb-cursor-dev zlib1g-dev
libssl-dev zlib1g-dev
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
store_cache: ${{ github.ref == 'refs/heads/master' }}
store_cache: ${{ (github.repository != 'qbittorrent/qBittorrent') || (github.ref == 'refs/heads/master') }}
update_packager_index: false
ccache_options: |
max_size=1G
- name: Install boost
env:
BOOST_MAJOR_VERSION: "1"
BOOST_MINOR_VERSION: "77"
BOOST_PATCH_VERSION: "0"
run: |
boost_url="https://archives.boost.io/release/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/source/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz"
boost_url2="https://sourceforge.net/projects/boost/files/boost/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz"
boost_url="https://archives.boost.io/release/${{ matrix.libtorrent.boost_major_version }}.${{ matrix.libtorrent.boost_minor_version }}.${{ matrix.libtorrent.boost_patch_version }}/source/boost_${{ matrix.libtorrent.boost_major_version }}_${{ matrix.libtorrent.boost_minor_version }}_${{ matrix.libtorrent.boost_patch_version }}.tar.gz"
boost_url2="https://sourceforge.net/projects/boost/files/boost/${{ matrix.libtorrent.boost_major_version }}.${{ matrix.libtorrent.boost_minor_version }}.${{ matrix.libtorrent.boost_patch_version }}/boost_${{ matrix.libtorrent.boost_major_version }}_${{ matrix.libtorrent.boost_minor_version }}_${{ matrix.libtorrent.boost_patch_version }}.tar.gz"
set +e
curl -L -o "${{ runner.temp }}/boost.tar.gz" "$boost_url"
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."; _exitCode="$?"
@@ -74,12 +78,13 @@ jobs:
with:
version: ${{ matrix.qt_version }}
archives: icu qtbase qtdeclarative qtsvg qttools
modules: qtimageformats
cache: true
- name: Install libtorrent
run: |
git clone \
--branch v${{ matrix.libt_version }} \
--branch v${{ matrix.libtorrent.version }} \
--depth 1 \
--recurse-submodules \
https://github.com/arvidn/libtorrent.git \
@@ -101,7 +106,7 @@ jobs:
# to avoid scanning 3rdparty codebases, initialize it just before building qbt
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
if: startsWith(matrix.libt_version, 2) && (matrix.qbt_gui == 'GUI=ON')
if: startsWith(matrix.libtorrent.version, 2) && (matrix.qbt_gui == 'GUI=ON')
with:
config-file: ./.github/workflows/helper/codeql/cpp.yaml
languages: cpp
@@ -123,11 +128,16 @@ jobs:
cmake --build build --target qbt_update_translations
cmake --build build
cmake --build build --target check
if [ "${{ matrix.qbt_gui }}" = "GUI=ON" ]; then
QT_QPA_PLATFORM=offscreen build/qbittorrent -v
else
build/qbittorrent-nox -v
fi
DESTDIR="qbittorrent" cmake --install build
- name: Run CodeQL analysis
uses: github/codeql-action/analyze@v4
if: startsWith(matrix.libt_version, 2) && (matrix.qbt_gui == 'GUI=ON')
if: startsWith(matrix.libtorrent.version, 2) && (matrix.qbt_gui == 'GUI=ON')
with:
category: ${{ github.base_ref || github.ref_name }}
@@ -172,7 +182,7 @@ jobs:
./linuxdeploy-x86_64.AppImage --appdir qbittorrent --output appimage
- name: Upload build artifacts
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: qBittorrent-CI_Ubuntu-x64_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libt_version }}_Qt-${{ matrix.qt_version }}
name: qBittorrent-CI_Ubuntu-x64_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libtorrent.version }}_Qt-${{ matrix.qt_version }}
path: upload

View File

@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
persist-credentials: false

View File

@@ -10,7 +10,7 @@ concurrency:
jobs:
ci:
name: Build (${{ matrix.libt_version }}, ${{ matrix.config.arch }})
name: Build (${{ matrix.libtorrent.version }}, ${{ matrix.config.arch }})
runs-on: ${{ matrix.config.os }}
permissions:
actions: write
@@ -18,7 +18,15 @@ jobs:
strategy:
fail-fast: false
matrix:
libt_version: ["2.0.11", "1.2.20"]
libtorrent:
- version: "2.0.11"
boost_major_version: "1"
boost_minor_version: "90"
boost_patch_version: "0"
- version: "1.2.20"
boost_major_version: "1"
boost_minor_version: "86"
boost_patch_version: "0"
config:
- os: windows-latest
arch: x64
@@ -31,7 +39,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
persist-credentials: false
@@ -86,13 +94,9 @@ jobs:
$packages
- name: Install boost
env:
BOOST_MAJOR_VERSION: "1"
BOOST_MINOR_VERSION: "86"
BOOST_PATCH_VERSION: "0"
run: |
$boost_url="https://archives.boost.io/release/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/source/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz"
$boost_url2="https://sourceforge.net/projects/boost/files/boost/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz"
$boost_url="https://archives.boost.io/release/${{ matrix.libtorrent.boost_major_version }}.${{ matrix.libtorrent.boost_minor_version }}.${{ matrix.libtorrent.boost_patch_version }}/source/boost_${{ matrix.libtorrent.boost_major_version }}_${{ matrix.libtorrent.boost_minor_version }}_${{ matrix.libtorrent.boost_patch_version }}.tar.gz"
$boost_url2="https://sourceforge.net/projects/boost/files/boost/${{ matrix.libtorrent.boost_major_version }}.${{ matrix.libtorrent.boost_minor_version }}.${{ matrix.libtorrent.boost_patch_version }}/boost_${{ matrix.libtorrent.boost_major_version }}_${{ matrix.libtorrent.boost_minor_version }}_${{ matrix.libtorrent.boost_patch_version }}.tar.gz"
curl -L -o "${{ runner.temp }}/boost.tar.gz" "$boost_url"
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."
if ($LastExitCode -ne 0)
@@ -112,15 +116,16 @@ jobs:
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
version: "6.9.1"
version: "6.10.1"
arch: ${{ matrix.config.qt_arch }}
archives: qtbase qtsvg qttools
modules: qtimageformats
cache: true
- name: Install libtorrent
run: |
git clone `
--branch v${{ matrix.libt_version }} `
--branch v${{ matrix.libtorrent.version }} `
--depth 1 `
--recurse-submodules `
https://github.com/arvidn/libtorrent.git `
@@ -182,8 +187,16 @@ jobs:
mkdir upload/qBittorrent/plugins/iconengines
copy "${{ env.Qt_ROOT_DIR }}/plugins/iconengines/qsvgicon.dll" upload/qBittorrent/plugins/iconengines
mkdir upload/qBittorrent/plugins/imageformats
# include all imageformats dlls since CI (dev) build links dynamically
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qgif.dll" upload/qBittorrent/plugins/imageformats
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qicns.dll" upload/qBittorrent/plugins/imageformats
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qico.dll" upload/qBittorrent/plugins/imageformats
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qjpeg.dll" upload/qBittorrent/plugins/imageformats
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qsvg.dll" upload/qBittorrent/plugins/imageformats
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qtga.dll" upload/qBittorrent/plugins/imageformats
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qtiff.dll" upload/qBittorrent/plugins/imageformats
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qwbmp.dll" upload/qBittorrent/plugins/imageformats
copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qwebp.dll" upload/qBittorrent/plugins/imageformats
mkdir upload/qBittorrent/plugins/platforms
copy "${{ env.Qt_ROOT_DIR }}/plugins/platforms/qwindows.dll" upload/qBittorrent/plugins/platforms
mkdir upload/qBittorrent/plugins/sqldrivers
@@ -200,9 +213,9 @@ jobs:
copy ${{ env.libtorrent_path }}/build/compile_commands.json upload/cmake/libtorrent
- name: Upload build artifacts
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: qBittorrent-CI_Windows-${{ matrix.config.arch }}_libtorrent-${{ matrix.libt_version }}
name: qBittorrent-CI_Windows-${{ matrix.config.arch }}_libtorrent-${{ matrix.libtorrent.version }}
path: upload
- name: Install NSIS
@@ -216,7 +229,7 @@ jobs:
makensis /DQBT_CPU_ARCH="${{ matrix.config.arch }}" /DQBT_DIST_DIR="../../upload/qBittorrent" /WX dist/windows/qbittorrent.nsi
- name: Upload installer
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: qBittorrent-CI_Windows-${{ matrix.config.arch }}_libtorrent-${{ matrix.libt_version }}-setup
name: qBittorrent-CI_Windows-${{ matrix.config.arch }}_libtorrent-${{ matrix.libtorrent.version }}-setup
path: dist/windows/qbittorrent_*_setup.exe

View File

@@ -14,9 +14,13 @@ jobs:
strategy:
matrix:
libt_version: ["2.0.11"]
libtorrent:
- version: "2.0.11"
boost_major_version: "1"
boost_minor_version: "90"
boost_patch_version: "0"
qbt_gui: ["GUI=ON"]
qt_version: ["6.9.1"]
qt_version: ["6.10.1"]
env:
boost_path: "${{ github.workspace }}/../boost"
@@ -25,7 +29,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
persist-credentials: false
@@ -37,13 +41,9 @@ jobs:
libssl-dev libxkbcommon-x11-dev libxcb-cursor-dev zlib1g-dev
- name: Install boost
env:
BOOST_MAJOR_VERSION: "1"
BOOST_MINOR_VERSION: "88"
BOOST_PATCH_VERSION: "0"
run: |
boost_url="https://archives.boost.io/release/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/source/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz"
boost_url2="https://sourceforge.net/projects/boost/files/boost/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz"
boost_url="https://archives.boost.io/release/${{ matrix.libtorrent.boost_major_version }}.${{ matrix.libtorrent.boost_minor_version }}.${{ matrix.libtorrent.boost_patch_version }}/source/boost_${{ matrix.libtorrent.boost_major_version }}_${{ matrix.libtorrent.boost_minor_version }}_${{ matrix.libtorrent.boost_patch_version }}.tar.gz"
boost_url2="https://sourceforge.net/projects/boost/files/boost/${{ matrix.libtorrent.boost_major_version }}.${{ matrix.libtorrent.boost_minor_version }}.${{ matrix.libtorrent.boost_patch_version }}/boost_${{ matrix.libtorrent.boost_major_version }}_${{ matrix.libtorrent.boost_minor_version }}_${{ matrix.libtorrent.boost_patch_version }}.tar.gz"
set +e
curl -L -o "${{ runner.temp }}/boost.tar.gz" "$boost_url"
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."; _exitCode="$?"
@@ -66,7 +66,7 @@ jobs:
- name: Install libtorrent
run: |
git clone \
--branch v${{ matrix.libt_version }} \
--branch v${{ matrix.libtorrent.version }} \
--depth 1 \
--recurse-submodules \
https://github.com/arvidn/libtorrent.git \

View File

@@ -162,7 +162,7 @@ GenericName[te]=క్యు బిట్ టొరెంట్ క్లయి
Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి
Name[te]=qBittorrent
GenericName[th]=ไคลเอนต์บิตทอร์เรนต์
Comment[th]=ดาวน์โหลดและแบ่งปันไฟล์ผ่านไฟล์บิตทอร์เรนต์
Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่าน BitTorrent
Name[th]=qBittorrent
GenericName[tr]=BitTorrent istemcisi
Comment[tr]=Dosyaları BitTorrent üzerinden indirin ve paylaşın

View File

@@ -62,6 +62,6 @@
<url type="contribute">https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md</url>
<content_rating type="oars-1.1"/>
<releases>
<release version="5.2.0~alpha1" date="2025-02-11"/>
<release version="5.2.0~beta1" date="2025-12-31"/>
</releases>
</component>

View File

@@ -157,16 +157,20 @@ ${Case} 0
${IfThen} $3 <> 0 ${|} ${Break} ${|} ;we are admin, let the show go on
${If} $1 = 3 ;RunAs completed successfully, but with a non-admin user
MessageBox mb_YesNo|mb_IconExclamation|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, try again" /SD IDNO IDYES uac_tryagain IDNO 0
SetErrorLevel 1314 # WinError.h: `ERROR_PRIVILEGE_NOT_HELD`
${EndIf}
;fall-through and die
${Case} 1223
MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, aborting!"
SetErrorLevel 1223 # WinError.h: `ERROR_CANCELLED`
Quit
${Case} 1062
MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Logon service not running, aborting!"
SetErrorLevel 1062 # WinError.h: `ERROR_SERVICE_NOT_ACTIVE`
Quit
${Default}
MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Unable to elevate , error $0"
SetErrorLevel 1603 # WinError.h: `ERROR_INSTALL_FAILURE`
Quit
${EndSwitch}

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_AFRIKAANS} "Uninstall qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_AFRIKAANS} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_AFRIKAANS} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_AFRIKAANS} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -38,8 +38,7 @@ LangString inst_uninstall_link_description ${LANG_ALBANIAN} "Uninstall qBittorre
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ALBANIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ALBANIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_ALBANIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_ARABIC} "Uninstall qBittorrent
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ARABIC} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ARABIC} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_ARABIC} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_BASQUE} "Uninstall qBittorrent
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_BASQUE} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_BASQUE} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_BASQUE} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_BELARUSIAN} "Uninstall qBittor
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_BELARUSIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_BELARUSIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_BELARUSIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_BOSNIAN} "Uninstall qBittorren
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_BOSNIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_BOSNIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_BOSNIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_BRETON} "Uninstall qBittorrent
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_BRETON} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_BRETON} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_BRETON} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_BULGARIAN} "Uninstall qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_BULGARIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_BULGARIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_BULGARIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_CATALAN} "Desinstal·lar qBitt
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_CATALAN} "Aquesta versió x64 de qBittorrent no pot funcionar en sistemes ARM64. Siusplau, descarrega l'instal·lador ARM64."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_CATALAN} "Aquesta versió ARM64 de qBittorrent no pot funcionar en sistemes x64. Siusplau, descarrega l'instal·lador x64."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_CATALAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_CROATIAN} "Uninstall qBittorre
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_CROATIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_CROATIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_CROATIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_CZECH} "Uninstall qBittorrent"
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_CZECH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_CZECH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_CZECH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_DANISH} "Afinstaller qBittorre
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_DANISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_DANISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_DANISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_DUTCH} "qBittorrent verwijdere
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_DUTCH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_DUTCH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_DUTCH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorren
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ENGLISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_ESPERANTO} "Uninstall qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ESPERANTO} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ESPERANTO} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_ESPERANTO} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_ESTONIAN} "Desinstalli qBittor
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ESTONIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ESTONIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_ESTONIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_FARSI} "Uninstall qBittorrent"
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_FARSI} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_FARSI} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_FARSI} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_FINNISH} "Uninstall qBittorren
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_FINNISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_FINNISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_FINNISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_FRENCH} "Désinstaller qBittor
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_FRENCH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_FRENCH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_FRENCH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_GALICIAN} "Uninstall qBittorre
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_GALICIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_GALICIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_GALICIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_GERMAN} "qBittorrent deinstall
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_GERMAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_GERMAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_GERMAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_GREEK} "Uninstall qBittorrent"
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_GREEK} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_GREEK} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_GREEK} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_HEBREW} "הסר את ההתק
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_HEBREW} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_HEBREW} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_HEBREW} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_HUNGARIAN} "qBittorrent eltáv
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_HUNGARIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_HUNGARIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_HUNGARIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_ICELANDIC} "Uninstall qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ICELANDIC} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ICELANDIC} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_ICELANDIC} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_INDONESIAN} "Hapus qBittorrent
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_INDONESIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_INDONESIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_INDONESIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_IRISH} "Uninstall qBittorrent"
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_IRISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_IRISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_IRISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_ITALIAN} "Disinstalla qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ITALIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ITALIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_ITALIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_JAPANESE} "qBittorrent をア
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_JAPANESE} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_JAPANESE} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_JAPANESE} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_KOREAN} "qBittorrent 제거"
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_KOREAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_KOREAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_KOREAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_KURDISH} "کیووبیتتۆر
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_KURDISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_KURDISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_KURDISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_LATVIAN} "Atinstalēt qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_LATVIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_LATVIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_LATVIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_LITHUANIAN} "Pašalinti qBitto
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_LITHUANIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_LITHUANIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_LITHUANIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_LUXEMBOURGISH} "qBittorrent de
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_LUXEMBOURGISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_LUXEMBOURGISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_LUXEMBOURGISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_MACEDONIAN} "Uninstall qBittor
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_MACEDONIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_MACEDONIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_MACEDONIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_MALAY} "Uninstall qBittorrent"
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_MALAY} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_MALAY} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_MALAY} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_MONGOLIAN} "Uninstall qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_MONGOLIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_MONGOLIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_MONGOLIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_NORWEGIAN} "Uninstall qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_NORWEGIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_NORWEGIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_NORWEGIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_NORWEGIANNYNORSK} "Uninstall q
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_NORWEGIANNYNORSK} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_NORWEGIANNYNORSK} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_NORWEGIANNYNORSK} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_POLISH} "Odinstaluj qBittorren
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_POLISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_POLISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_POLISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_PORTUGUESE} "Desinstalar qBitt
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_PORTUGUESE} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_PORTUGUESE} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_PORTUGUESE} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_PORTUGUESEBR} "Desinstalar o q
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_PORTUGUESEBR} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_PORTUGUESEBR} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_PORTUGUESEBR} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_ROMANIAN} "Dezinstalați qBitt
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ROMANIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ROMANIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_ROMANIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -33,11 +33,9 @@ LangString inst_requires_win10 ${LANG_RUSSIAN} "Для работы этого
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_RUSSIAN} "Удалить qBittorrent"
;LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ENGLISH} "Error: This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_RUSSIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_RUSSIAN} "Эта версия qBittorrent для x64 не может работать на системах ARM64. Пожалуйста, скачайте установщик для ARM64."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_RUSSIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_RUSSIAN} "Another instance of the installer is already running."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_RUSSIAN} "Эта версия qBittorrent для ARM64 не может работать на системах x64. Пожалуйста, скачайте установщик для x64."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_SERBIAN} "Uninstall qBittorren
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_SERBIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_SERBIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_SERBIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_SERBIANLATIN} "Uninstall qBitt
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_SERBIANLATIN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_SERBIANLATIN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_SERBIANLATIN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_SIMPCHINESE} "卸载 qBittorre
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_SIMPCHINESE} "X64 版本的 qBittorrent 不能运行在 ARM64 系统上。请下载 ARM64 安装程序。"
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_SIMPCHINESE} "ARM64 版本的 qBittorrent 不能运行在 X64 系统上。请下载 X64 安装程序。"
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_SIMPCHINESE} "另一个安装程序实例正在运行。"
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_SLOVAK} "Odinštalovať qBitto
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_SLOVAK} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_SLOVAK} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_SLOVAK} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_SLOVENIAN} "Uninstall qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_SLOVENIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_SLOVENIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_SLOVENIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_SPANISH} "Desinstalar qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_SPANISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_SPANISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_SPANISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_SPANISHINTERNATIONAL} "Desinst
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_SPANISHINTERNATIONAL} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_SPANISHINTERNATIONAL} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_SPANISHINTERNATIONAL} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_SWEDISH} "Avinstallera qBittor
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_SWEDISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_SWEDISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_SWEDISH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_THAI} "Uninstall qBittorrent"
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_THAI} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_THAI} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_THAI} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_TRADCHINESE} "移除 qBittorre
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_TRADCHINESE} "X64 版本的 qBittorrent 無法在 ARM64 系統上執行。請下載 ARM64 安裝程式。"
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_TRADCHINESE} "ARM64 版本的 qBittorrent 無法在 X64 系統上執行。請下載 X64 安裝程式。"
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_TRADCHINESE} "另一個安裝程式實例正在運行。"
;------------------------------------
;Uninstaller strings

View File

@@ -21,7 +21,7 @@ LangString inst_firewallinfo ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralı
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_TURKISH} "qBittorrent çalışıyor. Lütfen yüklemeden önce uygulamayı kapatın."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_TURKISH} "Şu anki sürüm kaldırılacaktır. Kullanıcı ayarları ve torrent'ler bozulmadan kalacaktır."
LangString inst_uninstall_question ${LANG_TURKISH} "Şu anki sürüm kaldırılacak. Kullanıcı ayarları ve torrent'ler bozulmadan kalacaktır."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_TURKISH} "Önceki sürüm kaldırılıyor."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
@@ -33,11 +33,9 @@ LangString inst_requires_win10 ${LANG_TURKISH} "Bu yükleyici en az Windows 10
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_TURKISH} "qBittorrent'i kaldır"
;LangString inst_arch_mismatch_x64_on_arm64 ${LANG_ENGLISH} "Error: This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_TURKISH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_TURKISH} "qBittorrent'in bu x64 sürümü ARM64 sistemlerde çalışamaz. Lütfen ARM64 yükleyicisini indirin."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_TURKISH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_TURKISH} "Another instance of the installer is already running."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_TURKISH} "qBittorrent'in bu ARM64 sürümü x64 sistemlerde çalışamaz. Lütfen x64 yükleyicisini indirin."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,6 @@ LangString inst_uninstall_link_description ${LANG_UKRAINIAN} "Uninstall qBittorr
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_UKRAINIAN} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_UKRAINIAN} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_UKRAINIAN} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_UZBEK} "qBittorrent oʻchirils
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_UZBEK} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_UZBEK} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_UZBEK} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -36,8 +36,7 @@ LangString inst_uninstall_link_description ${LANG_WELSH} "Uninstall qBittorrent"
LangString inst_arch_mismatch_x64_on_arm64 ${LANG_WELSH} "This x64 version of qBittorrent cannot run on ARM64 systems. Please download the ARM64 installer."
;LangString inst_arch_mismatch_arm64_on_x64 ${LANG_ENGLISH} "Error: This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
LangString inst_arch_mismatch_arm64_on_x64 ${LANG_WELSH} "This ARM64 version of qBittorrent cannot run on x64 systems. Please download the x64 installer."
;LangString inst_already_running ${LANG_ENGLISH} "Another instance of the installer is already running."
LangString inst_already_running ${LANG_WELSH} "Another instance of the installer is already running."
;------------------------------------
;Uninstaller strings

View File

@@ -112,18 +112,6 @@ SectionEnd
;--------------------------------
Function .onInit
; create a mutex to ensure only one installer is running
System::Call 'kernel32::CreateMutex(p 0, b 0, t "qbt_installer") p . r1 ?e'
Var /GLOBAL CreateMutexResult
Pop $CreateMutexResult
IntCmpU $CreateMutexResult 183 isDuplicateInstance isUniqueInstance isUniqueInstance
isDuplicateInstance:
MessageBox MB_OK|MB_ICONEXCLAMATION $(inst_already_running) /SD IDOK
SetErrorLevel 183 # WinError.h: `ERROR_ALREADY_EXISTS`
Abort
isUniqueInstance:
!insertmacro Init "installer"
!insertmacro MUI_LANGDLL_DISPLAY

View File

@@ -776,8 +776,9 @@ void Application::allTorrentsFinished()
bool isShutdown = pref->shutdownWhenDownloadsComplete();
bool isSuspend = pref->suspendWhenDownloadsComplete();
bool isHibernate = pref->hibernateWhenDownloadsComplete();
bool isReboot = pref->rebootWhenDownloadsComplete();
bool haveAction = isExit || isShutdown || isSuspend || isHibernate;
const bool haveAction = isExit || isShutdown || isSuspend || isHibernate || isReboot;
if (!haveAction) return;
ShutdownDialogAction action = ShutdownDialogAction::Exit;
@@ -787,6 +788,8 @@ void Application::allTorrentsFinished()
action = ShutdownDialogAction::Hibernate;
else if (isShutdown)
action = ShutdownDialogAction::Shutdown;
else if (isReboot)
action = ShutdownDialogAction::Reboot;
#ifndef DISABLE_GUI
// ask confirm
@@ -808,6 +811,7 @@ void Application::allTorrentsFinished()
pref->setShutdownWhenDownloadsComplete(false);
pref->setSuspendWhenDownloadsComplete(false);
pref->setHibernateWhenDownloadsComplete(false);
pref->setRebootWhenDownloadsComplete(false);
// Make sure preferences are synced before exiting
m_shutdownAct = action;
}

View File

@@ -32,7 +32,7 @@
#include <QCoreApplication>
#include <QMetaEnum>
#include "base/bittorrent/sharelimitaction.h"
#include "base/bittorrent/sharelimits.h"
#include "base/bittorrent/torrentcontentlayout.h"
#include "base/global.h"
#include "base/logger.h"

View File

@@ -34,10 +34,11 @@ add_library(qbt_base STATIC
bittorrent/session.h
bittorrent/sessionimpl.h
bittorrent/sessionstatus.h
bittorrent/sharelimitaction.h
bittorrent/sharelimits.h
bittorrent/speedmonitor.h
bittorrent/sslparameters.h
bittorrent/torrent.h
bittorrent/torrentannouncestatus.h
bittorrent/torrentcontenthandler.h
bittorrent/torrentcontentlayout.h
bittorrent/torrentcontentremoveoption.h

View File

@@ -125,9 +125,9 @@ BitTorrent::AddTorrentParams BitTorrent::parseAddTorrentParams(const QJsonObject
.useAutoTMM = getOptionalBool(jsonObj, PARAM_AUTOTMM),
.uploadLimit = jsonObj.value(PARAM_UPLOADLIMIT).toInt(-1),
.downloadLimit = jsonObj.value(PARAM_DOWNLOADLIMIT).toInt(-1),
.seedingTimeLimit = jsonObj.value(PARAM_SEEDINGTIMELIMIT).toInt(Torrent::USE_GLOBAL_SEEDING_TIME),
.inactiveSeedingTimeLimit = jsonObj.value(PARAM_INACTIVESEEDINGTIMELIMIT).toInt(Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME),
.ratioLimit = jsonObj.value(PARAM_RATIOLIMIT).toDouble(Torrent::USE_GLOBAL_RATIO),
.seedingTimeLimit = jsonObj.value(PARAM_SEEDINGTIMELIMIT).toInt(DEFAULT_SEEDING_TIME_LIMIT),
.inactiveSeedingTimeLimit = jsonObj.value(PARAM_INACTIVESEEDINGTIMELIMIT).toInt(DEFAULT_SEEDING_TIME_LIMIT),
.ratioLimit = jsonObj.value(PARAM_RATIOLIMIT).toDouble(DEFAULT_RATIO_LIMIT),
.shareLimitAction = getEnum<ShareLimitAction>(jsonObj, PARAM_SHARELIMITACTION, ShareLimitAction::Default),
.sslParameters =
{

View File

@@ -36,7 +36,7 @@
#include "base/path.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "sharelimits.h"
#include "sslparameters.h"
#include "torrent.h"
#include "torrentcontentlayout.h"
@@ -68,9 +68,9 @@ namespace BitTorrent
std::optional<bool> useAutoTMM;
int uploadLimit = -1;
int downloadLimit = -1;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
int inactiveSeedingTimeLimit = Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME;
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
int inactiveSeedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
qreal ratioLimit = DEFAULT_RATIO_LIMIT;
ShareLimitAction shareLimitAction = ShareLimitAction::Default;
SSLParameters sslParameters;

View File

@@ -239,8 +239,8 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
torrentParams.comment = fromLTString(resumeDataRoot.dict_find_string_value("qBt-comment"));
torrentParams.hasFinishedStatus = resumeDataRoot.dict_find_int_value("qBt-seedStatus");
torrentParams.firstLastPiecePriority = resumeDataRoot.dict_find_int_value("qBt-firstLastPiecePriority");
torrentParams.seedingTimeLimit = resumeDataRoot.dict_find_int_value("qBt-seedingTimeLimit", Torrent::USE_GLOBAL_SEEDING_TIME);
torrentParams.inactiveSeedingTimeLimit = resumeDataRoot.dict_find_int_value("qBt-inactiveSeedingTimeLimit", Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME);
torrentParams.seedingTimeLimit = resumeDataRoot.dict_find_int_value("qBt-seedingTimeLimit", DEFAULT_SEEDING_TIME_LIMIT);
torrentParams.inactiveSeedingTimeLimit = resumeDataRoot.dict_find_int_value("qBt-inactiveSeedingTimeLimit", DEFAULT_SEEDING_TIME_LIMIT);
torrentParams.shareLimitAction = Utils::String::toEnum(
fromLTString(resumeDataRoot.dict_find_string_value("qBt-shareLimitAction")), ShareLimitAction::Default);
@@ -283,7 +283,7 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
const lt::string_view ratioLimitString = resumeDataRoot.dict_find_string_value("qBt-ratioLimit");
if (ratioLimitString.empty())
torrentParams.ratioLimit = resumeDataRoot.dict_find_int_value("qBt-ratioLimit", Torrent::USE_GLOBAL_RATIO * 1000) / 1000.0;
torrentParams.ratioLimit = resumeDataRoot.dict_find_int_value("qBt-ratioLimit", DEFAULT_RATIO_LIMIT * 1000) / 1000.0;
else
torrentParams.ratioLimit = fromLTString(ratioLimitString).toDouble();

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2021-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2021-2025 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -32,10 +32,16 @@
#include <QJsonValue>
#include "base/global.h"
#include "base/utils/string.h"
const QString OPTION_SAVEPATH = u"save_path"_s;
const QString OPTION_DOWNLOADPATH = u"download_path"_s;
const QString OPTION_RATIOLIMIT = u"ratio_limit"_s;
const QString OPTION_SEEDINGTIMELIMIT = u"seeding_time_limit"_s;
const QString OPTION_INACTIVESEEDINGTIMELIMIT = u"inactive_seeding_time_limit"_s;
const QString OPTION_SHARELIMITACTION = u"share_limit_action"_s;
BitTorrent::CategoryOptions BitTorrent::CategoryOptions::fromJSON(const QJsonObject &jsonObj)
{
CategoryOptions options;
@@ -47,6 +53,11 @@ BitTorrent::CategoryOptions BitTorrent::CategoryOptions::fromJSON(const QJsonObj
else if (downloadPathValue.isString())
options.downloadPath = {true, Path(downloadPathValue.toString())};
options.ratioLimit = jsonObj.value(OPTION_RATIOLIMIT).toDouble(DEFAULT_RATIO_LIMIT);
options.seedingTimeLimit = jsonObj.value(OPTION_SEEDINGTIMELIMIT).toInt(DEFAULT_SEEDING_TIME_LIMIT);
options.inactiveSeedingTimeLimit = jsonObj.value(OPTION_INACTIVESEEDINGTIMELIMIT).toInt(DEFAULT_SEEDING_TIME_LIMIT);
options.shareLimitAction = Utils::String::toEnum<ShareLimitAction>(jsonObj.value(OPTION_SHARELIMITACTION).toString(), ShareLimitAction::Default);
return options;
}
@@ -63,12 +74,10 @@ QJsonObject BitTorrent::CategoryOptions::toJSON() const
return {
{OPTION_SAVEPATH, savePath.data()},
{OPTION_DOWNLOADPATH, downloadPathValue}
{OPTION_DOWNLOADPATH, downloadPathValue},
{OPTION_RATIOLIMIT, ratioLimit},
{OPTION_SEEDINGTIMELIMIT, seedingTimeLimit},
{OPTION_INACTIVESEEDINGTIMELIMIT, inactiveSeedingTimeLimit},
{OPTION_SHARELIMITACTION, Utils::String::fromEnum(shareLimitAction)}
};
}
bool BitTorrent::operator==(const BitTorrent::CategoryOptions &left, const BitTorrent::CategoryOptions &right)
{
return ((left.savePath == right.savePath)
&& (left.downloadPath == right.downloadPath));
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2021-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2021-2025 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@
#include "base/path.h"
#include "downloadpathoption.h"
#include "sharelimits.h"
class QJsonObject;
@@ -44,9 +45,14 @@ namespace BitTorrent
Path savePath;
std::optional<DownloadPathOption> downloadPath;
qreal ratioLimit = DEFAULT_RATIO_LIMIT;
int seedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
int inactiveSeedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
ShareLimitAction shareLimitAction = ShareLimitAction::Default;
static CategoryOptions fromJSON(const QJsonObject &jsonObj);
QJsonObject toJSON() const;
};
bool operator==(const CategoryOptions &left, const CategoryOptions &right);
friend bool operator==(const CategoryOptions &, const CategoryOptions &) = default;
};
}

View File

@@ -34,7 +34,7 @@
#include "base/path.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "sharelimits.h"
#include "sslparameters.h"
#include "torrent.h"
#include "torrentcontentlayout.h"
@@ -61,9 +61,9 @@ namespace BitTorrent
bool addToQueueTop = false; // only for new torrents
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
int inactiveSeedingTimeLimit = Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME;
qreal ratioLimit = DEFAULT_RATIO_LIMIT;
int seedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
int inactiveSeedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
ShareLimitAction shareLimitAction = ShareLimitAction::Default;
SSLParameters sslParameters;

View File

@@ -37,7 +37,7 @@
#include "addtorrenterror.h"
#include "addtorrentparams.h"
#include "categoryoptions.h"
#include "sharelimitaction.h"
#include "sharelimits.h"
#include "torrentcontentremoveoption.h"
#include "trackerentry.h"
#include "trackerentrystatus.h"
@@ -158,15 +158,17 @@ namespace BitTorrent
virtual QStringList categories() const = 0;
virtual CategoryOptions categoryOptions(const QString &categoryName) const = 0;
virtual bool setCategoryOptions(const QString &categoryName, const CategoryOptions &options) = 0;
virtual Path categorySavePath(const QString &categoryName) const = 0;
virtual Path categorySavePath(const QString &categoryName, const CategoryOptions &options) const = 0;
virtual Path categoryDownloadPath(const QString &categoryName) const = 0;
virtual Path categoryDownloadPath(const QString &categoryName, const CategoryOptions &options) const = 0;
virtual qreal categoryRatioLimit(const QString &categoryName) const = 0;
virtual int categorySeedingTimeLimit(const QString &categoryName) const = 0;
virtual int categoryInactiveSeedingTimeLimit(const QString &categoryName) const = 0;
virtual ShareLimitAction categoryShareLimitAction(const QString &categoryName) const = 0;
virtual bool addCategory(const QString &name, const CategoryOptions &options = {}) = 0;
virtual bool editCategory(const QString &name, const CategoryOptions &options) = 0;
virtual bool removeCategory(const QString &name) = 0;
virtual bool isSubcategoriesEnabled() const = 0;
virtual void setSubcategoriesEnabled(bool value) = 0;
virtual bool useCategoryPathsInManualMode() const = 0;
virtual void setUseCategoryPathsInManualMode(bool value) = 0;
@@ -385,8 +387,8 @@ namespace BitTorrent
virtual void setOutgoingPortsMax(int max) = 0;
virtual int UPnPLeaseDuration() const = 0;
virtual void setUPnPLeaseDuration(int duration) = 0;
virtual int peerToS() const = 0;
virtual void setPeerToS(int value) = 0;
virtual int peerDSCP() const = 0;
virtual void setPeerDSCP(int value) = 0;
virtual bool ignoreLimitsOnLAN() const = 0;
virtual void setIgnoreLimitsOnLAN(bool ignore) = 0;
virtual bool includeOverheadInLimits() const = 0;
@@ -518,7 +520,7 @@ namespace BitTorrent
void torrentTagRemoved(Torrent *torrent, const Tag &tag);
void trackerError(Torrent *torrent, const QString &tracker);
void trackersAdded(Torrent *torrent, const QList<TrackerEntry> &trackers);
void trackersChanged(Torrent *torrent);
void trackersReset(Torrent *torrent, const QList<TrackerEntryStatus> &oldEntries, const QList<TrackerEntry> &newEntries);
void trackersRemoved(Torrent *torrent, const QStringList &trackers);
void trackerSuccess(Torrent *torrent, const QString &tracker);
void trackerWarning(Torrent *torrent, const QString &tracker);

View File

@@ -484,7 +484,7 @@ SessionImpl::SessionImpl(QObject *parent)
, m_outgoingPortsMin(BITTORRENT_SESSION_KEY(u"OutgoingPortsMin"_s), 0)
, m_outgoingPortsMax(BITTORRENT_SESSION_KEY(u"OutgoingPortsMax"_s), 0)
, m_UPnPLeaseDuration(BITTORRENT_SESSION_KEY(u"UPnPLeaseDuration"_s), 0)
, m_peerToS(BITTORRENT_SESSION_KEY(u"PeerToS"_s), 0x04)
, m_peerDSCP(BITTORRENT_SESSION_KEY(u"PeerToS"_s), 0x01)
, m_ignoreLimitsOnLAN(BITTORRENT_SESSION_KEY(u"IgnoreLimitsOnLAN"_s), false)
, m_includeOverheadInLimits(BITTORRENT_SESSION_KEY(u"IncludeOverheadInLimits"_s), false)
, m_announceIP(BITTORRENT_SESSION_KEY(u"AnnounceIP"_s))
@@ -513,9 +513,9 @@ SessionImpl::SessionImpl(QObject *parent)
, m_additionalTrackersURL(BITTORRENT_SESSION_KEY(u"AdditionalTrackersURL"_s))
, m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r; })
, m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s)
, Torrent::NO_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_SEEDING_TIME_LIMIT))
, NO_SEEDING_TIME_LIMIT, lowerLimited(NO_SEEDING_TIME_LIMIT))
, m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s)
, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT))
, NO_SEEDING_TIME_LIMIT, lowerLimited(NO_SEEDING_TIME_LIMIT))
, m_isAddTorrentToQueueTop(BITTORRENT_SESSION_KEY(u"AddTorrentToTopOfQueue"_s), false)
, m_isAddTorrentStopped(BITTORRENT_SESSION_KEY(u"AddTorrentStopped"_s), false)
, m_torrentStopCondition(BITTORRENT_SESSION_KEY(u"TorrentStopCondition"_s), Torrent::StopCondition::None)
@@ -555,7 +555,6 @@ SessionImpl::SessionImpl(QObject *parent)
, m_savePath(BITTORRENT_SESSION_KEY(u"DefaultSavePath"_s), specialFolderLocation(SpecialFolder::Downloads))
, m_downloadPath(BITTORRENT_SESSION_KEY(u"TempPath"_s), (savePath() / Path(u"temp"_s)))
, m_isDownloadPathEnabled(BITTORRENT_SESSION_KEY(u"TempPathEnabled"_s), false)
, m_isSubcategoriesEnabled(BITTORRENT_SESSION_KEY(u"SubcategoriesEnabled"_s), false)
, m_useCategoryPathsInManualMode(BITTORRENT_SESSION_KEY(u"UseCategoryPathsInManualMode"_s), false)
, m_isAutoTMMDisabledByDefault(BITTORRENT_SESSION_KEY(u"DisableAutoTMMByDefault"_s), true)
, m_isDisableAutoTMMWhenCategoryChanged(BITTORRENT_SESSION_KEY(u"DisableAutoTMMTriggers/CategoryChanged"_s), false)
@@ -626,11 +625,6 @@ SessionImpl::SessionImpl(QObject *parent)
enableBandwidthScheduler();
loadCategories();
if (isSubcategoriesEnabled())
{
// if subcategories support changed manually
m_categories = expandCategories(m_categories);
}
const QStringList storedTags = m_storedTags.get();
for (const QString &tagStr : storedTags)
@@ -938,15 +932,8 @@ Path SessionImpl::categorySavePath(const QString &categoryName, const CategoryOp
if (path.isEmpty())
{
// use implicit save path
if (isSubcategoriesEnabled())
{
path = Utils::Fs::toValidPath(subcategoryName(categoryName));
basePath = categorySavePath(parentCategoryName(categoryName));
}
else
{
path = Utils::Fs::toValidPath(categoryName);
}
path = Utils::Fs::toValidPath(subcategoryName(categoryName));
basePath = categorySavePath(parentCategoryName(categoryName));
}
return (path.isAbsolute() ? path : (basePath / path));
@@ -966,8 +953,7 @@ Path SessionImpl::categoryDownloadPath(const QString &categoryName, const Catego
if (categoryName.isEmpty())
return downloadPath();
const bool useSubcategories = isSubcategoriesEnabled();
const QString name = useSubcategories ? subcategoryName(categoryName) : categoryName;
const QString name = subcategoryName(categoryName);
const Path path = !downloadPathOption.path.isEmpty()
? downloadPathOption.path
: Utils::Fs::toValidPath(name); // use implicit download path
@@ -975,7 +961,7 @@ Path SessionImpl::categoryDownloadPath(const QString &categoryName, const Catego
if (path.isAbsolute())
return path;
const QString parentName = useSubcategories ? parentCategoryName(categoryName) : QString();
const QString parentName = parentCategoryName(categoryName);
CategoryOptions parentOptions = categoryOptions(parentName);
// Even if download path of parent category is disabled (directly or by inheritance)
// we need to construct the one as if it would be enabled.
@@ -986,6 +972,62 @@ Path SessionImpl::categoryDownloadPath(const QString &categoryName, const Catego
return (basePath / path);
}
qreal SessionImpl::categoryRatioLimit(const QString &categoryName) const
{
if (categoryName.isEmpty())
return globalMaxRatio();
if (const auto ratioLimit = categoryOptions(categoryName).ratioLimit;
ratioLimit != DEFAULT_RATIO_LIMIT)
{
return ratioLimit;
}
return categoryRatioLimit(parentCategoryName(categoryName));
}
int SessionImpl::categorySeedingTimeLimit(const QString &categoryName) const
{
if (categoryName.isEmpty())
return globalMaxSeedingMinutes();
if (const auto seedingTimeLimit = categoryOptions(categoryName).seedingTimeLimit;
seedingTimeLimit != DEFAULT_SEEDING_TIME_LIMIT)
{
return seedingTimeLimit;
}
return categorySeedingTimeLimit(parentCategoryName(categoryName));
}
int SessionImpl::categoryInactiveSeedingTimeLimit(const QString &categoryName) const
{
if (categoryName.isEmpty())
return globalMaxInactiveSeedingMinutes();
if (const auto inactiveSeedingTimeLimit = categoryOptions(categoryName).inactiveSeedingTimeLimit;
inactiveSeedingTimeLimit != DEFAULT_SEEDING_TIME_LIMIT)
{
return inactiveSeedingTimeLimit;
}
return categoryInactiveSeedingTimeLimit(parentCategoryName(categoryName));
}
ShareLimitAction SessionImpl::categoryShareLimitAction(const QString &categoryName) const
{
if (categoryName.isEmpty())
return shareLimitAction();
if (const auto shareLimitAction = categoryOptions(categoryName).shareLimitAction;
shareLimitAction != ShareLimitAction::Default)
{
return shareLimitAction;
}
return categoryShareLimitAction(parentCategoryName(categoryName));
}
DownloadPathOption SessionImpl::resolveCategoryDownloadPathOption(const QString &categoryName, const std::optional<DownloadPathOption> &option) const
{
if (categoryName.isEmpty())
@@ -994,7 +1036,7 @@ DownloadPathOption SessionImpl::resolveCategoryDownloadPathOption(const QString
if (option.has_value())
return *option;
const QString parentName = isSubcategoriesEnabled() ? parentCategoryName(categoryName) : QString();
const QString parentName = parentCategoryName(categoryName);
return resolveCategoryDownloadPathOption(parentName, categoryOptions(parentName).downloadPath);
}
@@ -1006,15 +1048,12 @@ bool SessionImpl::addCategory(const QString &name, const CategoryOptions &option
if (!isValidCategoryName(name) || m_categories.contains(name))
return false;
if (isSubcategoriesEnabled())
for (const QString &parent : asConst(expandCategory(name)))
{
for (const QString &parent : asConst(expandCategory(name)))
if ((parent != name) && !m_categories.contains(parent))
{
if ((parent != name) && !m_categories.contains(parent))
{
m_categories[parent] = {};
emit categoryAdded(parent);
}
m_categories[parent] = {};
emit categoryAdded(parent);
}
}
@@ -1025,9 +1064,9 @@ bool SessionImpl::addCategory(const QString &name, const CategoryOptions &option
return true;
}
bool SessionImpl::editCategory(const QString &name, const CategoryOptions &options)
bool SessionImpl::setCategoryOptions(const QString &categoryName, const CategoryOptions &options)
{
const auto it = m_categories.find(name);
const auto it = m_categories.find(categoryName);
if (it == m_categories.end())
return false;
@@ -1035,14 +1074,15 @@ bool SessionImpl::editCategory(const QString &name, const CategoryOptions &optio
if (options == currentOptions)
return false;
if (isDisableAutoTMMWhenCategorySavePathChanged())
if (isDisableAutoTMMWhenCategorySavePathChanged()
&& ((options.savePath != currentOptions.savePath) || (options.downloadPath != currentOptions.downloadPath)))
{
// This should be done before changing the category options
// to prevent the torrent from being moved at the new save path.
for (TorrentImpl *const torrent : asConst(m_torrents))
{
if (torrent->category() == name)
if (torrent->category() == categoryName)
torrent->setAutoTMMEnabled(false);
}
}
@@ -1052,39 +1092,37 @@ bool SessionImpl::editCategory(const QString &name, const CategoryOptions &optio
for (TorrentImpl *const torrent : asConst(m_torrents))
{
if (torrent->category() == name)
if (torrent->category() == categoryName)
torrent->handleCategoryOptionsChanged();
}
emit categoryOptionsChanged(name);
emit categoryOptionsChanged(categoryName);
return true;
}
bool SessionImpl::removeCategory(const QString &name)
{
const QString parentCategory = parentCategoryName(name);
for (TorrentImpl *const torrent : asConst(m_torrents))
{
if (torrent->belongsToCategory(name))
torrent->setCategory(u""_s);
torrent->setCategory(parentCategory);
}
// remove stored category and its subcategories if exist
bool result = false;
if (isSubcategoriesEnabled())
// remove subcategories
const QString test = name + u'/';
Algorithm::removeIf(m_categories, [this, &test, &result](const QString &category, const CategoryOptions &)
{
// remove subcategories
const QString test = name + u'/';
Algorithm::removeIf(m_categories, [this, &test, &result](const QString &category, const CategoryOptions &)
if (category.startsWith(test))
{
if (category.startsWith(test))
{
result = true;
emit categoryRemoved(category);
return true;
}
return false;
});
}
result = true;
emit categoryRemoved(category);
return true;
}
return false;
});
result = (m_categories.remove(name) > 0) || result;
@@ -1098,32 +1136,6 @@ bool SessionImpl::removeCategory(const QString &name)
return result;
}
bool SessionImpl::isSubcategoriesEnabled() const
{
return m_isSubcategoriesEnabled;
}
void SessionImpl::setSubcategoriesEnabled(const bool value)
{
if (isSubcategoriesEnabled() == value) return;
if (value)
{
// expand categories to include all parent categories
m_categories = expandCategories(m_categories);
// update stored categories
storeCategories();
}
else
{
// reload categories
loadCategories();
}
m_isSubcategoriesEnabled = value;
emit subcategoriesSupportChanged();
}
bool SessionImpl::useCategoryPathsInManualMode() const
{
return m_useCategoryPathsInManualMode;
@@ -1281,7 +1293,7 @@ qreal SessionImpl::globalMaxRatio() const
void SessionImpl::setGlobalMaxRatio(qreal ratio)
{
if (ratio < 0)
ratio = Torrent::NO_RATIO_LIMIT;
ratio = NO_RATIO_LIMIT;
if (ratio != globalMaxRatio())
{
@@ -1297,7 +1309,7 @@ int SessionImpl::globalMaxSeedingMinutes() const
void SessionImpl::setGlobalMaxSeedingMinutes(int minutes)
{
minutes = std::max(minutes, Torrent::NO_SEEDING_TIME_LIMIT);
minutes = std::max(minutes, NO_SEEDING_TIME_LIMIT);
if (minutes != globalMaxSeedingMinutes())
{
@@ -1313,7 +1325,7 @@ int SessionImpl::globalMaxInactiveSeedingMinutes() const
void SessionImpl::setGlobalMaxInactiveSeedingMinutes(int minutes)
{
minutes = std::max(minutes, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT);
minutes = std::max(minutes, NO_SEEDING_TIME_LIMIT);
if (minutes != globalMaxInactiveSeedingMinutes())
{
@@ -2057,7 +2069,7 @@ lt::settings_pack SessionImpl::loadLTSettings() const
// UPnP lease duration
settingsPack.set_int(lt::settings_pack::upnp_lease_duration, UPnPLeaseDuration());
// Type of service
settingsPack.set_int(lt::settings_pack::peer_tos, peerToS());
settingsPack.set_int(lt::settings_pack::peer_dscp, peerDSCP());
// Include overhead in transfer limits
settingsPack.set_bool(lt::settings_pack::rate_limit_ip_overhead, includeOverheadInLimits());
// IP address to announce to trackers
@@ -2356,14 +2368,9 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent)
if (!torrent->isFinished() || torrent->isForced())
return;
const auto effectiveLimit = []<typename T>(const T limit, const T useGlobalLimit, const T globalLimit) -> T
{
return (limit == useGlobalLimit) ? globalLimit : limit;
};
const qreal ratioLimit = effectiveLimit(torrent->ratioLimit(), Torrent::USE_GLOBAL_RATIO, globalMaxRatio());
const int seedingTimeLimit = effectiveLimit(torrent->seedingTimeLimit(), Torrent::USE_GLOBAL_SEEDING_TIME, globalMaxSeedingMinutes());
const int inactiveSeedingTimeLimit = effectiveLimit(torrent->inactiveSeedingTimeLimit(), Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME, globalMaxInactiveSeedingMinutes());
const qreal ratioLimit = torrent->effectiveRatioLimit();
const int seedingTimeLimit = torrent->effectiveSeedingTimeLimit();
const int inactiveSeedingTimeLimit = torrent->effectiveInactiveSeedingTimeLimit();
bool reached = false;
QString description;
@@ -2390,7 +2397,7 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent)
if (reached)
{
const QString torrentName = tr("Torrent: \"%1\".").arg(torrent->name());
const ShareLimitAction shareLimitAction = (torrent->shareLimitAction() == ShareLimitAction::Default) ? m_shareLimitAction : torrent->shareLimitAction();
const ShareLimitAction shareLimitAction = torrent->effectiveShareLimitAction();
if (shareLimitAction == ShareLimitAction::Remove)
{
@@ -4882,17 +4889,17 @@ void SessionImpl::setUPnPLeaseDuration(const int duration)
}
}
int SessionImpl::peerToS() const
int SessionImpl::peerDSCP() const
{
return m_peerToS;
return m_peerDSCP;
}
void SessionImpl::setPeerToS(const int value)
void SessionImpl::setPeerDSCP(const int value)
{
if (value == m_peerToS)
if (value == m_peerDSCP)
return;
m_peerToS = value;
m_peerDSCP = value;
configureDeferred();
}
@@ -5218,9 +5225,9 @@ bool SessionImpl::isKnownTorrent(const InfoHash &infoHash) const
void SessionImpl::updateSeedingLimitTimer()
{
if ((globalMaxRatio() == Torrent::NO_RATIO_LIMIT) && !hasPerTorrentRatioLimit()
&& (globalMaxSeedingMinutes() == Torrent::NO_SEEDING_TIME_LIMIT) && !hasPerTorrentSeedingTimeLimit()
&& (globalMaxInactiveSeedingMinutes() == Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT) && !hasPerTorrentInactiveSeedingTimeLimit())
if ((globalMaxRatio() == NO_RATIO_LIMIT) && !hasPerTorrentRatioLimit()
&& (globalMaxSeedingMinutes() == NO_SEEDING_TIME_LIMIT) && !hasPerTorrentSeedingTimeLimit()
&& (globalMaxInactiveSeedingMinutes() == NO_SEEDING_TIME_LIMIT) && !hasPerTorrentInactiveSeedingTimeLimit())
{
if (m_seedingLimitTimer->isActive())
m_seedingLimitTimer->stop();
@@ -5279,9 +5286,9 @@ void SessionImpl::handleTorrentTrackersRemoved(TorrentImpl *const torrent, const
emit trackersRemoved(torrent, deletedTrackers);
}
void SessionImpl::handleTorrentTrackersChanged(TorrentImpl *const torrent)
void SessionImpl::handleTorrentTrackersReset(TorrentImpl *const torrent, const QList<TrackerEntryStatus> &oldEntries, const QList<TrackerEntry> &newEntries)
{
emit trackersChanged(torrent);
emit trackersReset(torrent, oldEntries, newEntries);
}
void SessionImpl::handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QList<QUrl> &newUrlSeeds)
@@ -5584,6 +5591,8 @@ void SessionImpl::loadCategories()
const auto categoryOptions = CategoryOptions::fromJSON(it.value().toObject());
m_categories[categoryName] = categoryOptions;
}
m_categories = expandCategories(m_categories);
}
bool SessionImpl::hasPerTorrentRatioLimit() const

View File

@@ -149,15 +149,17 @@ namespace BitTorrent
QStringList categories() const override;
CategoryOptions categoryOptions(const QString &categoryName) const override;
bool setCategoryOptions(const QString &categoryName, const CategoryOptions &options) override;
Path categorySavePath(const QString &categoryName) const override;
Path categorySavePath(const QString &categoryName, const CategoryOptions &options) const override;
Path categoryDownloadPath(const QString &categoryName) const override;
Path categoryDownloadPath(const QString &categoryName, const CategoryOptions &options) const override;
qreal categoryRatioLimit(const QString &categoryName) const override;
int categorySeedingTimeLimit(const QString &categoryName) const override;
int categoryInactiveSeedingTimeLimit(const QString &categoryName) const override;
ShareLimitAction categoryShareLimitAction(const QString &categoryName) const override;
bool addCategory(const QString &name, const CategoryOptions &options = {}) override;
bool editCategory(const QString &name, const CategoryOptions &options) override;
bool removeCategory(const QString &name) override;
bool isSubcategoriesEnabled() const override;
void setSubcategoriesEnabled(bool value) override;
bool useCategoryPathsInManualMode() const override;
void setUseCategoryPathsInManualMode(bool value) override;
@@ -359,8 +361,8 @@ namespace BitTorrent
void setOutgoingPortsMax(int max) override;
int UPnPLeaseDuration() const override;
void setUPnPLeaseDuration(int duration) override;
int peerToS() const override;
void setPeerToS(int value) override;
int peerDSCP() const override;
void setPeerDSCP(int value) override;
bool ignoreLimitsOnLAN() const override;
void setIgnoreLimitsOnLAN(bool ignore) override;
bool includeOverheadInLimits() const override;
@@ -474,7 +476,7 @@ namespace BitTorrent
void handleTorrentFinished(TorrentImpl *torrent);
void handleTorrentTrackersAdded(TorrentImpl *torrent, const QList<TrackerEntry> &newTrackers);
void handleTorrentTrackersRemoved(TorrentImpl *torrent, const QStringList &deletedTrackers);
void handleTorrentTrackersChanged(TorrentImpl *torrent);
void handleTorrentTrackersReset(TorrentImpl *torrent, const QList<TrackerEntryStatus> &oldEntries, const QList<TrackerEntry> &newEntries);
void handleTorrentUrlSeedsAdded(TorrentImpl *torrent, const QList<QUrl> &newUrlSeeds);
void handleTorrentUrlSeedsRemoved(TorrentImpl *torrent, const QList<QUrl> &urlSeeds);
void handleTorrentResumeDataReady(TorrentImpl *torrent, LoadTorrentParams data);
@@ -690,7 +692,7 @@ namespace BitTorrent
CachedSettingValue<int> m_outgoingPortsMin;
CachedSettingValue<int> m_outgoingPortsMax;
CachedSettingValue<int> m_UPnPLeaseDuration;
CachedSettingValue<int> m_peerToS;
CachedSettingValue<int> m_peerDSCP;
CachedSettingValue<bool> m_ignoreLimitsOnLAN;
CachedSettingValue<bool> m_includeOverheadInLimits;
CachedSettingValue<QString> m_announceIP;
@@ -754,7 +756,6 @@ namespace BitTorrent
CachedSettingValue<Path> m_savePath;
CachedSettingValue<Path> m_downloadPath;
CachedSettingValue<bool> m_isDownloadPathEnabled;
CachedSettingValue<bool> m_isSubcategoriesEnabled;
CachedSettingValue<bool> m_useCategoryPathsInManualMode;
CachedSettingValue<bool> m_isAutoTMMDisabledByDefault;
CachedSettingValue<bool> m_isDisableAutoTMMWhenCategoryChanged;

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -33,6 +33,12 @@
namespace BitTorrent
{
inline const qreal DEFAULT_RATIO_LIMIT = -2;
inline const qreal NO_RATIO_LIMIT = -1;
inline const int DEFAULT_SEEDING_TIME_LIMIT = -2;
inline const int NO_SEEDING_TIME_LIMIT = -1;
// Using `Q_ENUM_NS()` without a wrapper namespace in our case is not advised
// since `Q_NAMESPACE` cannot be used when the same namespace resides at different files.
// https://www.kdab.com/new-qt-5-8-meta-object-support-namespaces/#comment-143779

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -44,15 +44,6 @@ namespace BitTorrent
// Torrent
const qreal Torrent::USE_GLOBAL_RATIO = -2;
const qreal Torrent::NO_RATIO_LIMIT = -1;
const int Torrent::USE_GLOBAL_SEEDING_TIME = -2;
const int Torrent::NO_SEEDING_TIME_LIMIT = -1;
const int Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME = -2;
const int Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT = -1;
const qreal Torrent::MAX_RATIO = std::numeric_limits<qreal>::infinity();
TorrentID Torrent::id() const

View File

@@ -37,7 +37,8 @@
#include "base/3rdparty/expected.hpp"
#include "base/pathfwd.h"
#include "base/tagset.h"
#include "sharelimitaction.h"
#include "sharelimits.h"
#include "torrentannouncestatus.h"
#include "torrentcontenthandler.h"
class QBitArray;
@@ -124,15 +125,6 @@ namespace BitTorrent
};
Q_ENUM(StopCondition)
static const qreal USE_GLOBAL_RATIO;
static const qreal NO_RATIO_LIMIT;
static const int USE_GLOBAL_SEEDING_TIME;
static const int NO_SEEDING_TIME_LIMIT;
static const int USE_GLOBAL_INACTIVE_SEEDING_TIME;
static const int NO_INACTIVE_SEEDING_TIME_LIMIT;
static const qreal MAX_RATIO;
using TorrentContentHandler::TorrentContentHandler;
@@ -235,6 +227,10 @@ namespace BitTorrent
virtual void setInactiveSeedingTimeLimit(int limit) = 0;
virtual ShareLimitAction shareLimitAction() const = 0;
virtual void setShareLimitAction(ShareLimitAction action) = 0;
virtual qreal effectiveRatioLimit() const = 0;
virtual int effectiveSeedingTimeLimit() const = 0;
virtual int effectiveInactiveSeedingTimeLimit() const = 0;
virtual ShareLimitAction effectiveShareLimitAction() const = 0;
virtual PathList filePaths() const = 0;
virtual PathList actualFilePaths() const = 0;
@@ -278,9 +274,6 @@ namespace BitTorrent
virtual bool isLSDDisabled() const = 0;
virtual QBitArray pieces() const = 0;
virtual qreal distributedCopies() const = 0;
virtual qreal maxRatio() const = 0;
virtual int maxSeedingTime() const = 0;
virtual int maxInactiveSeedingTime() const = 0;
virtual qreal realRatio() const = 0;
virtual qreal popularity() const = 0;
virtual int uploadPayloadRate() const = 0;
@@ -290,6 +283,7 @@ namespace BitTorrent
virtual int connectionsCount() const = 0;
virtual int connectionsLimit() const = 0;
virtual qlonglong nextAnnounce() const = 0;
virtual TorrentAnnounceStatus announceStatus() const = 0;
virtual void setName(const QString &name) = 0;
virtual void setSequentialDownload(bool enable) = 0;

View File

@@ -0,0 +1,47 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#pragma once
#include <QFlags>
namespace BitTorrent
{
enum class TorrentAnnounceStatusFlag
{
HasNoProblem = 0,
HasWarning = 1,
HasTrackerError = 2,
HasOtherError = 4
};
Q_DECLARE_FLAGS(TorrentAnnounceStatus, TorrentAnnounceStatusFlag);
}
Q_DECLARE_OPERATORS_FOR_FLAGS(BitTorrent::TorrentAnnounceStatus);

View File

@@ -700,6 +700,7 @@ void TorrentImpl::removeTrackers(const QStringList &trackers)
if (!removedTrackers.isEmpty())
{
m_nativeHandle.replace_trackers(nativeTrackers);
m_announceStatus.reset();
deferredRequestResumeData();
m_session->handleTorrentTrackersRemoved(this, removedTrackers);
@@ -718,15 +719,16 @@ void TorrentImpl::replaceTrackers(QList<TrackerEntry> trackers)
std::vector<lt::announce_entry> nativeTrackers;
nativeTrackers.reserve(trackers.size());
m_trackerEntryStatuses.clear();
const auto oldEntries = std::exchange(m_trackerEntryStatuses, {});
for (const TrackerEntry &tracker : trackers)
for (const TrackerEntry &tracker : asConst(trackers))
{
nativeTrackers.emplace_back(makeNativeAnnounceEntry(tracker.url, tracker.tier));
m_trackerEntryStatuses.append({tracker.url, tracker.tier});
}
m_nativeHandle.replace_trackers(nativeTrackers);
m_announceStatus.reset();
// Clear the peer list if it's a private torrent since
// we do not want to keep connecting with peers from old tracker.
@@ -734,7 +736,7 @@ void TorrentImpl::replaceTrackers(QList<TrackerEntry> trackers)
clearPeers();
deferredRequestResumeData();
m_session->handleTorrentTrackersChanged(this);
m_session->handleTorrentTrackersReset(this, oldEntries, trackers);
}
QList<QUrl> TorrentImpl::urlSeeds() const
@@ -934,7 +936,7 @@ bool TorrentImpl::belongsToCategory(const QString &category) const
if (m_category == category)
return true;
return (m_session->isSubcategoriesEnabled() && m_category.startsWith(category + u'/'));
return m_category.startsWith(category + u'/');
}
TagSet TorrentImpl::tags() const
@@ -1186,25 +1188,7 @@ bool TorrentImpl::isCompleted() const
bool TorrentImpl::isActive() const
{
switch (m_state)
{
case TorrentState::StalledDownloading:
return (uploadPayloadRate() > 0);
case TorrentState::DownloadingMetadata:
case TorrentState::ForcedDownloadingMetadata:
case TorrentState::Downloading:
case TorrentState::ForcedDownloading:
case TorrentState::Uploading:
case TorrentState::ForcedUploading:
case TorrentState::Moving:
return true;
default:
break;
};
return false;
return ((uploadPayloadRate() > 0) || (downloadPayloadRate() > 0));
}
bool TorrentImpl::isInactive() const
@@ -1356,16 +1340,16 @@ qlonglong TorrentImpl::eta() const
if (isFinished())
{
const qreal maxRatioValue = maxRatio();
const int maxSeedingTimeValue = maxSeedingTime();
const int maxInactiveSeedingTimeValue = maxInactiveSeedingTime();
if ((maxRatioValue < 0) && (maxSeedingTimeValue < 0) && (maxInactiveSeedingTimeValue < 0)) return MAX_ETA;
const qreal maxRatioValue = effectiveRatioLimit();
const int maxSeedingTimeValue = effectiveSeedingTimeLimit();
const int maxInactiveSeedingTimeValue = effectiveInactiveSeedingTimeLimit();
if ((maxRatioValue < 0) && (maxSeedingTimeValue < 0) && (maxInactiveSeedingTimeValue < 0))
return MAX_ETA;
qlonglong ratioEta = MAX_ETA;
if ((speedAverage.upload > 0) && (maxRatioValue >= 0))
{
qlonglong realDL = totalDownload();
if (realDL <= 0)
realDL = wantedSize();
@@ -1497,30 +1481,38 @@ qreal TorrentImpl::distributedCopies() const
return m_nativeStatus.distributed_copies;
}
qreal TorrentImpl::maxRatio() const
qreal TorrentImpl::effectiveRatioLimit() const
{
if (m_ratioLimit == USE_GLOBAL_RATIO)
return m_session->globalMaxRatio();
if (m_ratioLimit == DEFAULT_RATIO_LIMIT)
return m_session->categoryRatioLimit(category());
return m_ratioLimit;
}
int TorrentImpl::maxSeedingTime() const
int TorrentImpl::effectiveSeedingTimeLimit() const
{
if (m_seedingTimeLimit == USE_GLOBAL_SEEDING_TIME)
return m_session->globalMaxSeedingMinutes();
if (m_seedingTimeLimit == DEFAULT_SEEDING_TIME_LIMIT)
return m_session->categorySeedingTimeLimit(category());
return m_seedingTimeLimit;
}
int TorrentImpl::maxInactiveSeedingTime() const
int TorrentImpl::effectiveInactiveSeedingTimeLimit() const
{
if (m_inactiveSeedingTimeLimit == USE_GLOBAL_INACTIVE_SEEDING_TIME)
return m_session->globalMaxInactiveSeedingMinutes();
if (m_inactiveSeedingTimeLimit == DEFAULT_SEEDING_TIME_LIMIT)
return m_session->categoryInactiveSeedingTimeLimit(category());
return m_inactiveSeedingTimeLimit;
}
ShareLimitAction TorrentImpl::effectiveShareLimitAction() const
{
if (m_shareLimitAction == ShareLimitAction::Default)
return m_session->categoryShareLimitAction(category());
return m_shareLimitAction;
}
qreal TorrentImpl::realRatio() const
{
const int64_t upload = m_nativeStatus.all_time_upload;
@@ -1575,6 +1567,46 @@ qlonglong TorrentImpl::nextAnnounce() const
return lt::total_seconds(m_nativeStatus.next_announce);
}
TorrentAnnounceStatus TorrentImpl::announceStatus() const
{
if (m_announceStatus)
return *m_announceStatus;
TorrentAnnounceStatus announceStatus = TorrentAnnounceStatusFlag::HasNoProblem;
for (const TrackerEntryStatus &trackerEntryStatus : asConst(m_trackerEntryStatuses))
{
switch (trackerEntryStatus.state)
{
case BitTorrent::TrackerEndpointState::Working:
if (!announceStatus.testFlag(TorrentAnnounceStatusFlag::HasWarning))
{
const bool hasWarningMessage = std::ranges::any_of(trackerEntryStatus.endpoints
, [](const TrackerEndpointStatus &endpointEntry)
{
return !endpointEntry.message.isEmpty() && (endpointEntry.state == BitTorrent::TrackerEndpointState::Working);
});
announceStatus.setFlag(TorrentAnnounceStatusFlag::HasWarning, hasWarningMessage);
}
break;
case BitTorrent::TrackerEndpointState::NotWorking:
case BitTorrent::TrackerEndpointState::Unreachable:
announceStatus.setFlag(TorrentAnnounceStatusFlag::HasOtherError);
break;
case BitTorrent::TrackerEndpointState::TrackerError:
announceStatus.setFlag(TorrentAnnounceStatusFlag::HasTrackerError);
break;
case BitTorrent::TrackerEndpointState::NotContacted:
break;
};
}
m_announceStatus = announceStatus;
return *m_announceStatus;
}
qreal TorrentImpl::popularity() const
{
// in order to produce floating-point numbers using `std::chrono::duration_cast`,
@@ -1761,6 +1793,7 @@ TrackerEntryStatus TorrentImpl::updateTrackerEntryStatus(const lt::announce_entr
#endif
::updateTrackerEntryStatus(*it, announceEntry, btProtocols, updateInfo);
m_announceStatus.reset();
return *it;
}
@@ -1776,6 +1809,8 @@ void TorrentImpl::resetTrackerEntryStatuses()
status.url = tempUrl;
status.tier = tempTier;
}
m_announceStatus = TorrentAnnounceStatusFlag::HasNoProblem;
}
std::shared_ptr<const libtorrent::torrent_info> TorrentImpl::nativeTorrentInfo() const
@@ -2598,7 +2633,7 @@ void TorrentImpl::updateProgress()
void TorrentImpl::setRatioLimit(qreal limit)
{
if (limit < USE_GLOBAL_RATIO)
if (limit < DEFAULT_RATIO_LIMIT)
limit = NO_RATIO_LIMIT;
if (m_ratioLimit != limit)
@@ -2611,7 +2646,7 @@ void TorrentImpl::setRatioLimit(qreal limit)
void TorrentImpl::setSeedingTimeLimit(int limit)
{
if (limit < USE_GLOBAL_SEEDING_TIME)
if (limit < DEFAULT_SEEDING_TIME_LIMIT)
limit = NO_SEEDING_TIME_LIMIT;
if (m_seedingTimeLimit != limit)
@@ -2624,8 +2659,8 @@ void TorrentImpl::setSeedingTimeLimit(int limit)
void TorrentImpl::setInactiveSeedingTimeLimit(int limit)
{
if (limit < USE_GLOBAL_INACTIVE_SEEDING_TIME)
limit = NO_INACTIVE_SEEDING_TIME_LIMIT;
if (limit < DEFAULT_SEEDING_TIME_LIMIT)
limit = NO_SEEDING_TIME_LIMIT;
if (m_inactiveSeedingTimeLimit != limit)
{

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@@ -156,6 +156,10 @@ namespace BitTorrent
void setInactiveSeedingTimeLimit(int limit) override;
ShareLimitAction shareLimitAction() const override;
void setShareLimitAction(ShareLimitAction action) override;
qreal effectiveRatioLimit() const override;
int effectiveSeedingTimeLimit() const override;
int effectiveInactiveSeedingTimeLimit() const override;
ShareLimitAction effectiveShareLimitAction() const override;
Path filePath(int index) const override;
Path actualFilePath(int index) const override;
@@ -205,9 +209,6 @@ namespace BitTorrent
bool isLSDDisabled() const override;
QBitArray pieces() const override;
qreal distributedCopies() const override;
qreal maxRatio() const override;
int maxSeedingTime() const override;
int maxInactiveSeedingTime() const override;
qreal realRatio() const override;
qreal popularity() const override;
int uploadPayloadRate() const override;
@@ -217,6 +218,7 @@ namespace BitTorrent
int connectionsCount() const override;
int connectionsLimit() const override;
qlonglong nextAnnounce() const override;
TorrentAnnounceStatus announceStatus() const override;
void setName(const QString &name) override;
void setSequentialDownload(bool enable) override;
@@ -349,6 +351,7 @@ namespace BitTorrent
MaintenanceJob m_maintenanceJob = MaintenanceJob::None;
QList<TrackerEntryStatus> m_trackerEntryStatuses;
mutable std::optional<TorrentAnnounceStatus> m_announceStatus;
QList<QUrl> m_urlSeeds;
FileErrorInfo m_lastFileError;

View File

@@ -494,10 +494,17 @@ void Preferences::setWinStartup(const bool b)
settings.remove(profileID);
}
}
#endif // Q_OS_WIN
QString Preferences::getStyle() const
{
return value<QString>(u"Appearance/Style"_s);
#ifdef Q_OS_WIN
const QString defaultStyleName = u"Fusion"_s;
#else
const QString defaultStyleName = u"system"_s;
#endif
const auto styleName = value<QString>(u"Appearance/Style"_s);
return styleName.isEmpty() ? defaultStyleName : styleName;
}
void Preferences::setStyle(const QString &styleName)
@@ -507,7 +514,6 @@ void Preferences::setStyle(const QString &styleName)
setValue(u"Appearance/Style"_s, styleName);
}
#endif // Q_OS_WIN
// Downloads
Path Preferences::getScanDirsLastPath() const
@@ -1291,6 +1297,19 @@ void Preferences::setShutdownWhenDownloadsComplete(const bool shutdown)
setValue(u"Preferences/Downloads/AutoShutDownOnCompletion"_s, shutdown);
}
bool Preferences::rebootWhenDownloadsComplete() const
{
return value(u"Preferences/Downloads/AutoRebootOnCompletion"_s, false);
}
void Preferences::setRebootWhenDownloadsComplete(const bool reboot)
{
if (reboot == rebootWhenDownloadsComplete())
return;
setValue(u"Preferences/Downloads/AutoRebootOnCompletion"_s, reboot);
}
bool Preferences::suspendWhenDownloadsComplete() const
{
return value(u"Preferences/Downloads/AutoSuspendOnCompletion"_s, false);
@@ -1885,6 +1904,32 @@ void Preferences::setTrackerFilterState(const bool checked)
setValue(u"TransferListFilters/trackerFilterState"_s, checked);
}
bool Preferences::getTrackerStatusFilterState() const
{
return value(u"TransferListFilters/TrackerStatusFilterState"_s, true);
}
void Preferences::setTrackerStatusFilterState(const bool checked)
{
if (checked == getTrackerStatusFilterState())
return;
setValue(u"TransferListFilters/TrackerStatusFilterState"_s, checked);
}
bool Preferences::useSeparateTrackerStatusFilter() const
{
return value(u"TransferListFilters/SeparateTrackerStatusFilter"_s, false);
}
void Preferences::setUseSeparateTrackerStatusFilter(const bool value)
{
if (value == useSeparateTrackerStatusFilter())
return;
setValue(u"TransferListFilters/SeparateTrackerStatusFilter"_s, value);
}
int Preferences::getTransSelFilter() const
{
return value<int>(u"TransferListFilters/selectedFilterIndex"_s, 0);

View File

@@ -137,11 +137,11 @@ public:
void setPreventFromSuspendWhenDownloading(bool b);
bool preventFromSuspendWhenSeeding() const;
void setPreventFromSuspendWhenSeeding(bool b);
QString getStyle() const;
void setStyle(const QString &styleName);
#ifdef Q_OS_WIN
bool WinStartup() const;
void setWinStartup(bool b);
QString getStyle() const;
void setStyle(const QString &styleName);
#endif
// Downloads
@@ -287,6 +287,8 @@ public:
bool shutdownWhenDownloadsComplete() const;
void setShutdownWhenDownloadsComplete(bool shutdown);
bool rebootWhenDownloadsComplete() const;
void setRebootWhenDownloadsComplete(bool reboot);
bool suspendWhenDownloadsComplete() const;
void setSuspendWhenDownloadsComplete(bool suspend);
bool hibernateWhenDownloadsComplete() const;
@@ -400,6 +402,9 @@ public:
bool getCategoryFilterState() const;
bool getTagFilterState() const;
bool getTrackerFilterState() const;
bool getTrackerStatusFilterState() const;
bool useSeparateTrackerStatusFilter() const;
void setUseSeparateTrackerStatusFilter(bool value);
int getTransSelFilter() const;
void setTransSelFilter(int index);
bool getHideZeroStatusFilters() const;
@@ -449,6 +454,7 @@ public slots:
void setCategoryFilterState(bool checked);
void setTagFilterState(bool checked);
void setTrackerFilterState(bool checked);
void setTrackerStatusFilterState(bool checked);
void apply();

View File

@@ -54,6 +54,7 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QS
const QStringList params
{
Utils::ForeignApps::PYTHON_ISOLATE_MODE_FLAG,
Utils::ForeignApps::PYTHON_UTF8_MODE_FLAG,
(SearchPluginManager::engineLocation() / Path(u"nova2dl.py"_s)).toString(),
pluginName,
url

View File

@@ -102,6 +102,7 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co
const QStringList params
{
Utils::ForeignApps::PYTHON_ISOLATE_MODE_FLAG,
Utils::ForeignApps::PYTHON_UTF8_MODE_FLAG,
(SearchPluginManager::engineLocation() / Path(u"nova2.py"_s)).toString(),
m_usedPlugins.join(u','),
m_category

View File

@@ -554,6 +554,7 @@ void SearchPluginManager::update()
const QStringList params
{
Utils::ForeignApps::PYTHON_ISOLATE_MODE_FLAG,
Utils::ForeignApps::PYTHON_UTF8_MODE_FLAG,
(engineLocation() / Path(u"/nova2.py"_s)).toString(),
u"--capabilities"_s
};

View File

@@ -434,9 +434,9 @@ void TorrentFilesWatcher::Worker::processFolder(const Path &path, const Path &wa
}
else
{
if (!m_failedTorrents.value(path).contains(filePath))
if (!m_failedTorrents.value(watchedFolderPath).contains(filePath))
{
m_failedTorrents[path][filePath] = 0;
m_failedTorrents[watchedFolderPath][filePath] = 0;
}
}
}
@@ -471,7 +471,7 @@ void TorrentFilesWatcher::Worker::processFailedTorrents()
BitTorrent::AddTorrentParams addTorrentParams = options.addTorrentParams;
if (torrentPath != watchedFolderPath)
{
const Path subdirPath = watchedFolderPath.relativePathOf(torrentPath);
const Path subdirPath = watchedFolderPath.relativePathOf(torrentPath).parentPath();
const bool useAutoTMM = addTorrentParams.useAutoTMM.value_or(!BitTorrent::Session::instance()->isAutoTMMDisabledByDefault());
if (useAutoTMM)
{

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2014-2025 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,94 +28,57 @@
#include "torrentfilter.h"
#include "bittorrent/infohash.h"
#include "bittorrent/torrent.h"
#include <algorithm>
#include <QUrl>
#include "base/bittorrent/infohash.h"
#include "base/bittorrent/torrent.h"
#include "base/bittorrent/trackerentrystatus.h"
#include "base/global.h"
using namespace BitTorrent;
const std::optional<QString> TorrentFilter::AnyCategory;
const std::optional<TorrentIDSet> TorrentFilter::AnyID;
const std::optional<QString> TorrentFilter::AnyCategory;
const std::optional<Tag> TorrentFilter::AnyTag;
const std::optional<QString> TorrentFilter::AnyTrackerHost;
const std::optional<TorrentAnnounceStatus> TorrentFilter::AnyAnnounceStatus;
const TorrentFilter TorrentFilter::DownloadingTorrent(TorrentFilter::Downloading);
const TorrentFilter TorrentFilter::SeedingTorrent(TorrentFilter::Seeding);
const TorrentFilter TorrentFilter::CompletedTorrent(TorrentFilter::Completed);
const TorrentFilter TorrentFilter::StoppedTorrent(TorrentFilter::Stopped);
const TorrentFilter TorrentFilter::RunningTorrent(TorrentFilter::Running);
const TorrentFilter TorrentFilter::ActiveTorrent(TorrentFilter::Active);
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::MovingTorrent(TorrentFilter::Moving);
const TorrentFilter TorrentFilter::ErroredTorrent(TorrentFilter::Errored);
QString getTrackerHost(const QString &url)
{
// We want the hostname.
if (const QString host = QUrl(url).host(); !host.isEmpty())
return host;
using BitTorrent::Torrent;
// If failed to parse the domain, original input should be returned
return url;
}
TorrentFilter::TorrentFilter(const Type type, const std::optional<TorrentIDSet> &idSet
, const std::optional<QString> &category, const std::optional<Tag> &tag, const std::optional<bool> isPrivate)
: m_type {type}
TorrentFilter::TorrentFilter(const Status status, const std::optional<TorrentIDSet> &idSet, const std::optional<QString> &category
, const std::optional<Tag> &tag, const std::optional<bool> &isPrivate, const std::optional<QString> &trackerHost
, const std::optional<TorrentAnnounceStatus> &announceStatus)
: m_status {status}
, m_category {category}
, m_tag {tag}
, m_idSet {idSet}
, m_private {isPrivate}
, m_trackerHost {trackerHost}
, m_announceStatus {announceStatus}
{
}
TorrentFilter::TorrentFilter(const QString &filter, const std::optional<TorrentIDSet> &idSet
, const std::optional<QString> &category, const std::optional<Tag> &tag, const std::optional<bool> isPrivate)
: m_category {category}
, m_tag {tag}
, m_idSet {idSet}
, m_private {isPrivate}
bool TorrentFilter::setStatus(const Status status)
{
setTypeByName(filter);
}
bool TorrentFilter::setType(Type type)
{
if (m_type != type)
if (m_status != status)
{
m_type = type;
m_status = status;
return true;
}
return false;
}
bool TorrentFilter::setTypeByName(const QString &filter)
{
Type type = All;
if (filter == u"downloading")
type = Downloading;
else if (filter == u"seeding")
type = Seeding;
else if (filter == u"completed")
type = Completed;
else if (filter == u"stopped")
type = Stopped;
else if (filter == u"running")
type = Running;
else if (filter == u"active")
type = Active;
else if (filter == u"inactive")
type = Inactive;
else if (filter == u"stalled")
type = Stalled;
else if (filter == u"stalled_uploading")
type = StalledUploading;
else if (filter == u"stalled_downloading")
type = StalledDownloading;
else if (filter == u"checking")
type = Checking;
else if (filter == u"moving")
type = Moving;
else if (filter == u"errored")
type = Errored;
return setType(type);
}
bool TorrentFilter::setTorrentIDSet(const std::optional<TorrentIDSet> &idSet)
{
if (m_idSet != idSet)
@@ -160,18 +123,43 @@ bool TorrentFilter::setPrivate(const std::optional<bool> isPrivate)
return false;
}
bool TorrentFilter::match(const Torrent *const torrent) const
bool TorrentFilter::setTrackerHost(const std::optional<QString> &trackerHost)
{
if (!torrent) return false;
if (m_trackerHost != trackerHost)
{
m_trackerHost = trackerHost;
return true;
}
return (matchState(torrent) && matchHash(torrent) && matchCategory(torrent) && matchTag(torrent) && matchPrivate(torrent));
return false;
}
bool TorrentFilter::matchState(const BitTorrent::Torrent *const torrent) const
bool TorrentFilter::setAnnounceStatus(const std::optional<TorrentAnnounceStatus> &announceStatus)
{
const BitTorrent::TorrentState state = torrent->state();
if (m_announceStatus != announceStatus)
{
m_announceStatus = announceStatus;
return true;
}
switch (m_type)
return false;
}
bool TorrentFilter::match(const Torrent *const torrent) const
{
Q_ASSERT(torrent);
if (!torrent) [[unlikely]]
return false;
return (matchStatus(torrent) && matchHash(torrent) && matchCategory(torrent)
&& matchTag(torrent) && matchPrivate(torrent) && matchTracker(torrent));
}
bool TorrentFilter::matchStatus(const Torrent *const torrent) const
{
const TorrentState state = torrent->state();
switch (m_status)
{
case All:
return true;
@@ -190,16 +178,16 @@ bool TorrentFilter::matchState(const BitTorrent::Torrent *const torrent) const
case Inactive:
return torrent->isInactive();
case Stalled:
return (state == BitTorrent::TorrentState::StalledUploading)
|| (state == BitTorrent::TorrentState::StalledDownloading);
return (state == TorrentState::StalledUploading)
|| (state == TorrentState::StalledDownloading);
case StalledUploading:
return state == BitTorrent::TorrentState::StalledUploading;
return state == TorrentState::StalledUploading;
case StalledDownloading:
return state == BitTorrent::TorrentState::StalledDownloading;
return state == TorrentState::StalledDownloading;
case Checking:
return (state == BitTorrent::TorrentState::CheckingUploading)
|| (state == BitTorrent::TorrentState::CheckingDownloading)
|| (state == BitTorrent::TorrentState::CheckingResumeData);
return (state == TorrentState::CheckingUploading)
|| (state == TorrentState::CheckingDownloading)
|| (state == TorrentState::CheckingResumeData);
case Moving:
return torrent->isMoving();
case Errored:
@@ -212,7 +200,7 @@ bool TorrentFilter::matchState(const BitTorrent::Torrent *const torrent) const
return false;
}
bool TorrentFilter::matchHash(const BitTorrent::Torrent *const torrent) const
bool TorrentFilter::matchHash(const Torrent *const torrent) const
{
if (!m_idSet)
return true;
@@ -220,7 +208,7 @@ bool TorrentFilter::matchHash(const BitTorrent::Torrent *const torrent) const
return m_idSet->contains(torrent->id());
}
bool TorrentFilter::matchCategory(const BitTorrent::Torrent *const torrent) const
bool TorrentFilter::matchCategory(const Torrent *const torrent) const
{
if (!m_category)
return true;
@@ -228,7 +216,7 @@ bool TorrentFilter::matchCategory(const BitTorrent::Torrent *const torrent) cons
return (torrent->belongsToCategory(*m_category));
}
bool TorrentFilter::matchTag(const BitTorrent::Torrent *const torrent) const
bool TorrentFilter::matchTag(const Torrent *const torrent) const
{
if (!m_tag)
return true;
@@ -240,10 +228,65 @@ bool TorrentFilter::matchTag(const BitTorrent::Torrent *const torrent) const
return torrent->hasTag(*m_tag);
}
bool TorrentFilter::matchPrivate(const BitTorrent::Torrent *const torrent) const
bool TorrentFilter::matchPrivate(const Torrent *const torrent) const
{
if (!m_private)
return true;
return m_private == torrent->isPrivate();
}
bool TorrentFilter::matchTracker(const Torrent *torrent) const
{
if (!m_trackerHost)
{
if (!m_announceStatus)
return true;
const TorrentAnnounceStatus announceStatus = torrent->announceStatus();
const TorrentAnnounceStatus &testAnnounceStatus = *m_announceStatus;
if (!testAnnounceStatus)
return !announceStatus;
return announceStatus.testAnyFlags(testAnnounceStatus);
}
// Trackerless torrent
if (m_trackerHost->isEmpty())
return torrent->trackers().isEmpty() && !m_announceStatus;
return std::ranges::any_of(asConst(torrent->trackers())
, [trackerHost = m_trackerHost, announceStatus = m_announceStatus](const TrackerEntryStatus &trackerEntryStatus)
{
if (getTrackerHost(trackerEntryStatus.url) != trackerHost)
return false;
if (!announceStatus)
return true;
switch (trackerEntryStatus.state)
{
case TrackerEndpointState::Working:
{
const bool hasWarningMessage = std::ranges::any_of(trackerEntryStatus.endpoints
, [](const TrackerEndpointStatus &endpointEntry)
{
return !endpointEntry.message.isEmpty() && (endpointEntry.state == TrackerEndpointState::Working);
});
return hasWarningMessage ? announceStatus->testFlag(TorrentAnnounceStatusFlag::HasWarning) : !*announceStatus;
}
case TrackerEndpointState::NotWorking:
case TrackerEndpointState::Unreachable:
return announceStatus->testFlag(TorrentAnnounceStatusFlag::HasOtherError);
case TrackerEndpointState::TrackerError:
return announceStatus->testFlag(TorrentAnnounceStatusFlag::HasTrackerError);
case TrackerEndpointState::NotContacted:
return false;
};
return false;
});
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2014-2025 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@
#include <QString>
#include "base/bittorrent/infohash.h"
#include "base/bittorrent/torrentannouncestatus.h"
#include "base/tag.h"
namespace BitTorrent
@@ -46,7 +47,7 @@ using TorrentIDSet = QSet<BitTorrent::TorrentID>;
class TorrentFilter
{
public:
enum Type
enum Status
{
All,
Downloading,
@@ -67,57 +68,47 @@ public:
};
// These mean any permutation, including no category / tag.
static const std::optional<QString> AnyCategory;
static const std::optional<TorrentIDSet> AnyID;
static const std::optional<QString> AnyCategory;
static const std::optional<Tag> AnyTag;
static const TorrentFilter DownloadingTorrent;
static const TorrentFilter SeedingTorrent;
static const TorrentFilter CompletedTorrent;
static const TorrentFilter StoppedTorrent;
static const TorrentFilter RunningTorrent;
static const TorrentFilter ActiveTorrent;
static const TorrentFilter InactiveTorrent;
static const TorrentFilter StalledTorrent;
static const TorrentFilter StalledUploadingTorrent;
static const TorrentFilter StalledDownloadingTorrent;
static const TorrentFilter CheckingTorrent;
static const TorrentFilter MovingTorrent;
static const TorrentFilter ErroredTorrent;
static const std::optional<QString> AnyTrackerHost;
static const std::optional<BitTorrent::TorrentAnnounceStatus> AnyAnnounceStatus;
TorrentFilter() = default;
// category & tags: pass empty string for uncategorized / untagged torrents.
TorrentFilter(Type type
TorrentFilter(Status status
, const std::optional<TorrentIDSet> &idSet = AnyID
, const std::optional<QString> &category = AnyCategory
, const std::optional<Tag> &tag = AnyTag
, std::optional<bool> isPrivate = {});
TorrentFilter(const QString &filter
, const std::optional<TorrentIDSet> &idSet = AnyID
, const std::optional<QString> &category = AnyCategory
, const std::optional<Tag> &tags = AnyTag
, std::optional<bool> isPrivate = {});
, const std::optional<bool> &isPrivate = {}
, const std::optional<QString> &trackerHost = AnyTrackerHost
, const std::optional<BitTorrent::TorrentAnnounceStatus> &announceStatus = AnyAnnounceStatus);
bool setType(Type type);
bool setTypeByName(const QString &filter);
bool setStatus(Status status);
bool setTorrentIDSet(const std::optional<TorrentIDSet> &idSet);
bool setCategory(const std::optional<QString> &category);
bool setTag(const std::optional<Tag> &tag);
bool setPrivate(std::optional<bool> isPrivate);
bool setTrackerHost(const std::optional<QString> &trackerHost);
bool setAnnounceStatus(const std::optional<BitTorrent::TorrentAnnounceStatus> &announceStatus);
bool match(const BitTorrent::Torrent *torrent) const;
private:
bool matchState(const BitTorrent::Torrent *torrent) const;
bool matchStatus(const BitTorrent::Torrent *torrent) const;
bool matchHash(const BitTorrent::Torrent *torrent) const;
bool matchCategory(const BitTorrent::Torrent *torrent) const;
bool matchTag(const BitTorrent::Torrent *torrent) const;
bool matchPrivate(const BitTorrent::Torrent *torrent) const;
bool matchTracker(const BitTorrent::Torrent *torrent) const;
Type m_type {All};
Status m_status {All};
std::optional<QString> m_category;
std::optional<Tag> m_tag;
std::optional<TorrentIDSet> m_idSet;
std::optional<bool> m_private;
std::optional<QString> m_trackerHost;
std::optional<BitTorrent::TorrentAnnounceStatus> m_announceStatus;
};
QString getTrackerHost(const QString &url);

View File

@@ -37,7 +37,8 @@ enum class ShutdownDialogAction
Exit,
Shutdown,
Suspend,
Hibernate
Hibernate,
Reboot
};
using QStringMap = QMap<QString, QString>;

View File

@@ -38,6 +38,7 @@
namespace Utils::ForeignApps
{
inline const QString PYTHON_ISOLATE_MODE_FLAG = u"-I"_s;
inline const QString PYTHON_UTF8_MODE_FLAG = u"-Xutf8=1"_s;
struct PythonInfo
{

View File

@@ -87,22 +87,30 @@ void Utils::OS::shutdownComputer([[maybe_unused]] const ShutdownDialogAction &ac
{
::SetSuspendState(TRUE, FALSE, FALSE);
}
else
else if (action == ShutdownDialogAction::Shutdown)
{
std::wstring msg = QCoreApplication::translate("misc"
, "qBittorrent will shutdown the computer now because all downloads are complete.").toStdWString();
::InitiateSystemShutdownW(nullptr, msg.data(), 10, TRUE, FALSE);
}
else if (action == ShutdownDialogAction::Reboot)
{
std::wstring msg = QCoreApplication::translate("misc"
, "qBittorrent will reboot the computer now because all downloads are complete.").toStdWString();
::InitiateSystemShutdownW(nullptr, msg.data(), 10, TRUE, TRUE);
}
// Disable shutdown privilege.
tkp.Privileges[0].Attributes = 0;
::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0);
#elif defined(Q_OS_MACOS)
AEEventID EventToSend;
if (action != ShutdownDialogAction::Shutdown)
AEEventID EventToSend {};
if (action == ShutdownDialogAction::Suspend)
EventToSend = kAESleep;
else
else if (action == ShutdownDialogAction::Reboot)
EventToSend = kAERestart;
else if (action == ShutdownDialogAction::Shutdown)
EventToSend = kAEShutDown;
AEAddressDesc targetDesc;
const ProcessSerialNumber kPSNOfSystemProcess = {0, kSystemProcess};
@@ -133,7 +141,7 @@ void Utils::OS::shutdownComputer([[maybe_unused]] const ShutdownDialogAction &ac
#elif defined(QBT_USES_DBUS)
// Use dbus to power off / suspend the system
if (action != ShutdownDialogAction::Shutdown)
if ((action == ShutdownDialogAction::Suspend) || (action == ShutdownDialogAction::Hibernate))
{
// Some recent systems use systemd's logind
QDBusInterface login1Iface(u"org.freedesktop.login1"_s, u"/org/freedesktop/login1"_s,
@@ -166,7 +174,7 @@ void Utils::OS::shutdownComputer([[maybe_unused]] const ShutdownDialogAction &ac
else
halIface.call(u"Hibernate"_s);
}
else
else if (action == ShutdownDialogAction::Shutdown)
{
// Some recent systems use systemd's logind
QDBusInterface login1Iface(u"org.freedesktop.login1"_s, u"/org/freedesktop/login1"_s,
@@ -190,6 +198,30 @@ void Utils::OS::shutdownComputer([[maybe_unused]] const ShutdownDialogAction &ac
QDBusConnection::systemBus());
halIface.call(u"Shutdown"_s);
}
else if (action == ShutdownDialogAction::Reboot)
{
// Some recent systems use systemd's logind
QDBusInterface login1Iface(u"org.freedesktop.login1"_s, u"/org/freedesktop/login1"_s,
u"org.freedesktop.login1.Manager"_s, QDBusConnection::systemBus());
if (login1Iface.isValid())
{
login1Iface.call(u"Reboot"_s, false);
return;
}
// Else, other recent systems use ConsoleKit
QDBusInterface consolekitIface(u"org.freedesktop.ConsoleKit"_s, u"/org/freedesktop/ConsoleKit/Manager"_s,
u"org.freedesktop.ConsoleKit.Manager"_s, QDBusConnection::systemBus());
if (consolekitIface.isValid())
{
consolekitIface.call(u"Restart"_s);
return;
}
// HAL (older systems)
QDBusInterface halIface(u"org.freedesktop.Hal"_s, u"/org/freedesktop/Hal/devices/computer"_s,
u"org.freedesktop.Hal.Device.SystemPowerManagement"_s,
QDBusConnection::systemBus());
halIface.call(u"Reboot"_s);
}
#endif
}

View File

@@ -32,7 +32,7 @@
#define QBT_VERSION_MINOR 2
#define QBT_VERSION_BUGFIX 0
#define QBT_VERSION_BUILD 0
#define QBT_VERSION_STATUS "alpha1" // Should be empty for stable releases!
#define QBT_VERSION_STATUS "beta1" // Should be empty for stable releases!
#define QBT__STRINGIFY(x) #x
#define QBT_STRINGIFY(x) QBT__STRINGIFY(x)

View File

@@ -129,7 +129,9 @@ add_library(qbt_gui STATIC
transferlistfilters/tagfilterproxymodel.h
transferlistfilters/tagfilterwidget.h
transferlistfilters/trackersfilterwidget.h
transferlistfilters/trackerstatusfilterwidget.h
transferlistfilterswidget.h
transferlistfilterswidgetitem.h
transferlistmodel.h
transferlistsortmodel.h
transferlistwidget.h
@@ -230,7 +232,9 @@ add_library(qbt_gui STATIC
transferlistfilters/tagfilterproxymodel.cpp
transferlistfilters/tagfilterwidget.cpp
transferlistfilters/trackersfilterwidget.cpp
transferlistfilters/trackerstatusfilterwidget.cpp
transferlistfilterswidget.cpp
transferlistfilterswidgetitem.cpp
transferlistmodel.cpp
transferlistsortmodel.cpp
transferlistwidget.cpp

Some files were not shown because too many files have changed in this diff Show More