diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 59808a89f..5fd81dc09 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1 +1 @@
-custom: "https://www.qbittorrent.org/donate"
+custom: "https://www.qbittorrent.org/donate.php"
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 1302695fb..c77cc888e 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -7,17 +7,19 @@ body:
#### ADVISORY
"We do not support any versions older than the current release series"
- "We do not support any 3rd party/forked versions e.g. `portableapps`/`Enhanced Edition` etc."
+ "We do not support any 3rd party/forked versions e.g. `portableapps`/`Enhanced Edition`etc."
"Please post all details in **English**."
#### Prerequisites before submitting an issue!
- Read the issue reporting section in the **[contributing guidelines](https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md)**, to know how to submit a good bug report with the required information.
- Verify that the issue is not fixed and is reproducible in the **[latest official qBittorrent version](https://www.qbittorrent.org/download.php).**
- - (Optional, but recommended) Verify that the issue is not fixed and is reproducible in the latest CI (**[macOS](https://github.com/qbittorrent/qBittorrent/actions/workflows/ci_macos.yaml?query=branch%3Amaster+event%3Apush)** / **[Ubuntu](https://github.com/qbittorrent/qBittorrent/actions/workflows/ci_ubuntu.yaml?query=branch%3Amaster+event%3Apush)** / **[Windows](https://github.com/qbittorrent/qBittorrent/actions/workflows/ci_windows.yaml?query=branch%3Amaster+event%3Apush)**) builds.
- - Perform a **[search of the issue tracker (including closed ones)](https://github.com/qbittorrent/qBittorrent/issues?q=is%3Aissue+is%3Aopen+-label%3A%22Feature+request%22)** to avoid posting a duplicate.
+ - (Optional, but recommended) Verify that the issue is not fixed and is reproducible in the latest CI (currently only on **[Windows](https://github.com/qbittorrent/qBittorrent/actions/workflows/ci_windows.yaml?query=branch%3Amaster+event%3Apush)**) builds.
+ - Check the **[frequent/common issues list](https://github.com/qbittorrent/qBittorrent/projects/2)** and perform a **[search of the issue tracker (including closed ones)](https://github.com/qbittorrent/qBittorrent/issues)** to avoid posting a duplicate.
- Make sure this is not a support request or question, both of which are better suited for either the **[discussions section](https://github.com/qbittorrent/qBittorrent/discussions)**, **[forum](https://qbforums.shiki.hu/)**, or **[subreddit](https://www.reddit.com/r/qBittorrent/)**.
- Verify that the **[wiki](https://github.com/qbittorrent/qBittorrent/wiki)** did not contain a suitable solution either.
+ - If relevant to issue/when asked, the qBittorrent preferences file, qBittorrent.log & watched_folders.json (if using "Watched Folders" feature) must be provided.
+ See **[Where does qBittorrent save its settings?](https://github.com/qbittorrent/qBittorrent/wiki/Frequently-Asked-Questions#Where_does_qBittorrent_save_its_settings)**
- type: textarea
attributes:
@@ -26,10 +28,10 @@ body:
Qt and libtorrent-rasterbar versions are required when: 1. You are using linux. 2. You are not using an official build downloaded from our website.
Example of preferred formatting:
- qBittorrent: 4.6.6 x64
- Operating system: Windows 10 Pro x64 (22H2) 10.0.19045
- Qt: 6.4.3
- libtorrent-rasterbar: 1.2.19
+ qBittorrent: 4.3.7 x64
+ Operating system: Windows 10 Pro 21H1/2009 x64
+ Qt: 5.15.2
+ libtorrent-rasterbar: 1.2.14
placeholder: |
qBittorrent:
Operating system:
@@ -71,4 +73,4 @@ body:
See **[Where does qBittorrent save its settings?](https://github.com/qbittorrent/qBittorrent/wiki/Frequently-Asked-Questions#Where_does_qBittorrent_save_its_settings)**
#### Note: It's the user's responsibility to redact any sensitive information
validations:
- required: true
+ required: false
diff --git a/.github/workflows/ci_file_health.yaml b/.github/workflows/ci_file_health.yaml
index 54c87a104..76b358263 100644
--- a/.github/workflows/ci_file_health.yaml
+++ b/.github/workflows/ci_file_health.yaml
@@ -12,15 +12,11 @@ jobs:
ci:
name: Check
runs-on: ubuntu-latest
- permissions:
- security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- with:
- persist-credentials: false
- - name: Setup python
+ - name: Install tools
uses: actions/setup-python@v5
with:
python-version: "*"
@@ -36,7 +32,7 @@ jobs:
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/3.1.7/pandoc-3.1.7-linux-amd64.tar.gz"
tar -xf "${{ runner.temp }}/pandoc.tar.gz" -C "${{ github.workspace }}/.."
mv "${{ github.workspace }}/.."/pandoc-* "${{ env.pandoc_path }}"
# run pandoc
@@ -46,26 +42,3 @@ jobs:
done
# check diff, ignore "Automatically generated by ..." part
git diff -I '\.\\".*' --exit-code
-
- - name: Check GitHub Actions workflow
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: |
- pip install zizmor
- IGNORE_RULEID='(.ruleId != "zizmor/template-injection")
- and (.ruleId != "zizmor/unpinned-uses")'
- IGNORE_ID='(.id != "zizmor/template-injection")
- and (.id != "zizmor/unpinned-uses")'
- zizmor \
- --format sarif \
- --persona auditor \
- ./ \
- | jq "(.runs[].results |= map(select($IGNORE_RULEID)))
- | (.runs[].tool.driver.rules |= map(select($IGNORE_ID)))" \
- > "${{ runner.temp }}/zizmor_results.sarif"
-
- - name: Upload zizmor results
- uses: github/codeql-action/upload-sarif@v3
- with:
- category: zizmor
- sarif_file: "${{ runner.temp }}/zizmor_results.sarif"
diff --git a/.github/workflows/ci_macos.yaml b/.github/workflows/ci_macos.yaml
index abc6c9f7d..a73663501 100644
--- a/.github/workflows/ci_macos.yaml
+++ b/.github/workflows/ci_macos.yaml
@@ -2,7 +2,8 @@ name: CI - macOS
on: [pull_request, push]
-permissions: {}
+permissions:
+ actions: write
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
@@ -12,28 +13,25 @@ jobs:
ci:
name: Build
runs-on: macos-latest
- permissions:
- actions: write
strategy:
fail-fast: false
matrix:
- libt_version: ["2.0.11", "1.2.20"]
+ libt_version: ["2.0.10", "1.2.19"]
qbt_gui: ["GUI=ON", "GUI=OFF"]
- qt_version: ["6.9.1"]
+ qt_version: ["6.5.2"]
env:
boost_path: "${{ github.workspace }}/../boost"
+ openssl_root: /usr/local/opt/openssl@3
libtorrent_path: "${{ github.workspace }}/../libtorrent"
steps:
- name: Checkout repository
uses: actions/checkout@v4
- with:
- persist-credentials: false
- name: Install dependencies
- uses: Wandalen/wretry.action@v3
+ uses: Wandalen/wretry.action@v1
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
@@ -49,18 +47,16 @@ jobs:
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
- store_cache: ${{ github.ref == 'refs/heads/master' }}
+ store_cache: ${{ startsWith(github.ref, 'refs/heads/') }}
update_packager_index: false
- ccache_options: |
- max_size=1G
- name: Install boost
env:
BOOST_MAJOR_VERSION: "1"
- BOOST_MINOR_VERSION: "86"
+ BOOST_MINOR_VERSION: "84"
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_url="https://boostorg.jfrog.io/artifactory/main/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"
set +e
curl -L -o "${{ runner.temp }}/boost.tar.gz" "$boost_url"
@@ -70,12 +66,9 @@ jobs:
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."; _exitCode="$?"
fi
mv "${{ github.workspace }}/.."/boost_* "${{ env.boost_path }}"
- cd "${{ env.boost_path }}"
- ./bootstrap.sh
- ./b2 stage --stagedir=./ --with-headers
- name: Install Qt
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@v3
with:
version: ${{ matrix.qt_version }}
archives: qtbase qtdeclarative qtsvg qttools
@@ -96,23 +89,25 @@ jobs:
-G "Ninja" \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
- -DCMAKE_CXX_STANDARD=20 \
+ -DCMAKE_CXX_STANDARD=17 \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
- -DBOOST_ROOT="${{ env.boost_path }}/lib/cmake" \
- -Ddeprecated-functions=OFF
+ -DBOOST_ROOT="${{ env.boost_path }}" \
+ -Ddeprecated-functions=OFF \
+ -DOPENSSL_ROOT_DIR="${{ env.openssl_root }}"
cmake --build build
sudo cmake --install build
- name: Build qBittorrent
run: |
- CXXFLAGS="$CXXFLAGS -DQT_FORCE_ASSERTS -Werror -Wno-error=deprecated-declarations" \
+ CXXFLAGS="$CXXFLAGS -Werror -Wno-error=deprecated-declarations" \
LDFLAGS="$LDFLAGS -gz" \
cmake \
-B build \
-G "Ninja" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
- -DBOOST_ROOT="${{ env.boost_path }}/lib/cmake" \
+ -DBOOST_ROOT="${{ env.boost_path }}" \
+ -DOPENSSL_ROOT_DIR="${{ env.openssl_root }}" \
-DTESTING=ON \
-DVERBOSE_CONFIGURE=ON \
-D${{ matrix.qbt_gui }}
@@ -122,30 +117,13 @@ jobs:
- name: Prepare build artifacts
run: |
+ # create .dmg
appName="qbittorrent"
if [ "${{ matrix.qbt_gui }}" = "GUI=OFF" ]; then
appName="qbittorrent-nox"
fi
pushd build
- # packaging
- macdeployqt "$appName.app" -no-strip
- # code signing
- xattr -cr "$appName.app"
- codesign --force --sign - \
- "$appName.app" \
- "$appName.app/Contents/Frameworks"/* \
- "$appName.app/Contents/MacOS/$appName"
- codesign --verify --deep --strict -v "$appName.app"
- # create .dmg
- PACKAGE_RETRY=0
- while [ "$PACKAGE_RETRY" -lt "3" ]; do
- if hdiutil create -fs HFS+ -srcfolder "$appName.app" -volname "$appName" "$appName.dmg"; then
- break
- fi
- sleep 5
- PACKAGE_RETRY=$((PACKAGE_RETRY + 1))
- echo "Retry $PACKAGE_RETRY..."
- done
+ macdeployqt "$appName.app" -dmg -no-strip
popd
# prepare upload folder
mkdir upload
diff --git a/.github/workflows/ci_python.yaml b/.github/workflows/ci_python.yaml
deleted file mode 100644
index ef8a73598..000000000
--- a/.github/workflows/ci_python.yaml
+++ /dev/null
@@ -1,99 +0,0 @@
-name: CI - Python
-
-on: [pull_request, push]
-
-permissions: {}
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
- cancel-in-progress: ${{ github.head_ref != '' }}
-
-jobs:
- ci:
- name: Check
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
- with:
- persist-credentials: false
-
- - name: Setup python (auxiliary scripts)
- uses: actions/setup-python@v5
- with:
- python-version: '3' # use default version
-
- - name: Install tools (auxiliary scripts)
- run: pip install bandit isort pycodestyle pyflakes
-
- - name: Gather files (auxiliary scripts)
- run: |
- export "PY_FILES=$(find . -type f -name '*.py' ! -path '*searchengine*' -printf '%p ')"
- echo $PY_FILES
- echo "PY_FILES=$PY_FILES" >> "$GITHUB_ENV"
-
- - name: Lint code (auxiliary scripts)
- run: |
- pyflakes $PY_FILES
- bandit --skip B101,B314,B405 $PY_FILES
-
- - name: Format code (auxiliary scripts)
- run: |
- pycodestyle \
- --max-line-length=1000 \
- --statistics \
- $PY_FILES
- isort \
- --check \
- --diff \
- $PY_FILES
-
- - name: Build code (auxiliary scripts)
- run: |
- python -m compileall $PY_FILES
-
- - name: Setup python (search engine)
- uses: actions/setup-python@v5
- with:
- python-version: '3.9'
-
- - name: Install tools (search engine)
- run: pip install bandit isort mypy pycodestyle pyflakes pyright
-
- - name: Gather files (search engine)
- run: |
- export "PY_FILES=$(find . -type f -name '*.py' -path '*searchengine*' ! -name 'socks.py' -printf '%p ')"
- echo $PY_FILES
- echo "PY_FILES=$PY_FILES" >> "$GITHUB_ENV"
-
- - name: Check typings (search engine)
- run: |
- MYPYPATH="src/searchengine/nova3" \
- mypy \
- --follow-imports skip \
- --strict \
- $PY_FILES
- pyright \
- $PY_FILES
-
- - name: Lint code (search engine)
- run: |
- pyflakes $PY_FILES
- bandit --skip B110,B310,B314,B405 $PY_FILES
-
- - name: Format code (search engine)
- run: |
- pycodestyle \
- --ignore=E265,E402 \
- --max-line-length=1000 \
- --statistics \
- $PY_FILES
- isort \
- --check \
- --diff \
- $PY_FILES
-
- - name: Build code (search engine)
- run: |
- python -m compileall $PY_FILES
diff --git a/.github/workflows/ci_ubuntu.yaml b/.github/workflows/ci_ubuntu.yaml
index 807eef19f..f4c5f5d6d 100644
--- a/.github/workflows/ci_ubuntu.yaml
+++ b/.github/workflows/ci_ubuntu.yaml
@@ -2,7 +2,9 @@ name: CI - Ubuntu
on: [pull_request, push]
-permissions: {}
+permissions:
+ actions: write
+ security-events: write
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
@@ -12,27 +14,22 @@ jobs:
ci:
name: Build
runs-on: ubuntu-latest
- permissions:
- actions: write
- security-events: write
strategy:
fail-fast: false
matrix:
- libt_version: ["2.0.11", "1.2.20"]
+ libt_version: ["2.0.10", "1.2.19"]
qbt_gui: ["GUI=ON", "GUI=OFF"]
- qt_version: ["6.6.3"]
+ qt_version: ["6.5.2"]
env:
boost_path: "${{ github.workspace }}/../boost"
- harden_flags: "-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS"
+ harden_flags: "-D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS"
libtorrent_path: "${{ github.workspace }}/../libtorrent"
steps:
- name: Checkout repository
uses: actions/checkout@v4
- with:
- persist-credentials: false
- name: Install dependencies
run: |
@@ -44,18 +41,18 @@ jobs:
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
- store_cache: ${{ github.ref == 'refs/heads/master' }}
+ store_cache: ${{ startsWith(github.ref, 'refs/heads/') }}
update_packager_index: false
ccache_options: |
- max_size=1G
+ max_size=2G
- name: Install boost
env:
BOOST_MAJOR_VERSION: "1"
- BOOST_MINOR_VERSION: "77"
+ BOOST_MINOR_VERSION: "76"
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_url="https://boostorg.jfrog.io/artifactory/main/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"
set +e
curl -L -o "${{ runner.temp }}/boost.tar.gz" "$boost_url"
@@ -65,12 +62,9 @@ jobs:
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."; _exitCode="$?"
fi
mv "${{ github.workspace }}/.."/boost_* "${{ env.boost_path }}"
- cd "${{ env.boost_path }}"
- ./bootstrap.sh
- ./b2 stage --stagedir=./ --with-headers
- name: Install Qt
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@v3
with:
version: ${{ matrix.qt_version }}
archives: icu qtbase qtdeclarative qtsvg qttools
@@ -91,9 +85,8 @@ jobs:
-G "Ninja" \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
- -DCMAKE_CXX_STANDARD=20 \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
- -DBOOST_ROOT="${{ env.boost_path }}/lib/cmake" \
+ -DBOOST_ROOT="${{ env.boost_path }}" \
-Ddeprecated-functions=OFF
cmake --build build
sudo cmake --install build
@@ -108,14 +101,14 @@ jobs:
- name: Build qBittorrent
run: |
- CXXFLAGS="$CXXFLAGS ${{ env.harden_flags }} -DQT_FORCE_ASSERTS -Werror" \
+ CXXFLAGS="$CXXFLAGS ${{ env.harden_flags }} -Werror" \
LDFLAGS="$LDFLAGS -gz" \
cmake \
-B build \
-G "Ninja" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
- -DBOOST_ROOT="${{ env.boost_path }}/lib/cmake" \
+ -DBOOST_ROOT="${{ env.boost_path }}" \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DTESTING=ON \
-DVERBOSE_CONFIGURE=ON \
@@ -141,6 +134,7 @@ jobs:
- name: Install AppImage
run: |
+ sudo apt install libfuse2
curl \
-L \
-Z \
@@ -162,7 +156,6 @@ jobs:
- name: Package AppImage
run: |
- rm -f "${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/sqldrivers/libqsqlmimer.so"
./linuxdeploy-x86_64.AppImage --appdir qbittorrent --plugin qt
rm qbittorrent/apprun-hooks/*
cp .github/workflows/helper/appimage/export_vars.sh qbittorrent/apprun-hooks/export_vars.sh
diff --git a/.github/workflows/ci_webui.yaml b/.github/workflows/ci_webui.yaml
index a46e003ca..01b4e67c6 100644
--- a/.github/workflows/ci_webui.yaml
+++ b/.github/workflows/ci_webui.yaml
@@ -2,7 +2,8 @@ name: CI - WebUI
on: [pull_request, push]
-permissions: {}
+permissions:
+ security-events: write
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
@@ -12,8 +13,6 @@ jobs:
ci:
name: Check
runs-on: ubuntu-latest
- permissions:
- security-events: write
defaults:
run:
@@ -22,8 +21,6 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- with:
- persist-credentials: false
- name: Setup nodejs
uses: actions/setup-node@v4
@@ -31,15 +28,7 @@ jobs:
node-version: 'lts/*'
- name: Install tools
- run: |
- npm install
- npm ls
- echo "::group::npm ls --all"
- npm ls --all
- echo "::endgroup::"
-
- - name: Run tests
- run: npm test
+ run: npm install
- name: Lint code
run: npm run lint
@@ -52,7 +41,7 @@ jobs:
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
- config-file: .github/workflows/helper/codeql/js.yaml
+ config-file: ./.github/workflows/helper/codeql/js.yaml
languages: javascript
- name: Run CodeQL analysis
diff --git a/.github/workflows/ci_windows.yaml b/.github/workflows/ci_windows.yaml
index a5e06b1a2..f07613dcd 100644
--- a/.github/workflows/ci_windows.yaml
+++ b/.github/workflows/ci_windows.yaml
@@ -2,7 +2,8 @@ name: CI - Windows
on: [pull_request, push]
-permissions: {}
+permissions:
+ actions: write
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
@@ -12,13 +13,11 @@ jobs:
ci:
name: Build
runs-on: windows-latest
- permissions:
- actions: write
strategy:
fail-fast: false
matrix:
- libt_version: ["2.0.11", "1.2.20"]
+ libt_version: ["2.0.10", "1.2.19"]
env:
boost_path: "${{ github.workspace }}/../boost"
@@ -28,8 +27,6 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- with:
- persist-credentials: false
- name: Setup devcmd
uses: ilammy/msvc-dev-cmd@v1
@@ -67,7 +64,6 @@ jobs:
"set(VCPKG_BUILD_TYPE release)")
# clear buildtrees after each package installation to reduce disk space requirements
$packages = `
- "boost-build:x64-windows-static-md-release",
"openssl:x64-windows-static-md-release",
"zlib:x64-windows-static-md-release"
${{ env.vcpkg_path }}/vcpkg.exe upgrade `
@@ -82,10 +78,10 @@ jobs:
- name: Install boost
env:
BOOST_MAJOR_VERSION: "1"
- BOOST_MINOR_VERSION: "86"
+ BOOST_MINOR_VERSION: "84"
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_url="https://boostorg.jfrog.io/artifactory/main/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"
curl -L -o "${{ runner.temp }}/boost.tar.gz" "$boost_url"
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."
@@ -95,19 +91,11 @@ jobs:
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."
}
move "${{ github.workspace }}/../boost_*" "${{ env.boost_path }}"
- cd "${{ env.boost_path }}"
- #.\bootstrap.bat
- ${{ env.vcpkg_path }}/installed/x64-windows-static-md-release/tools/boost-build/b2.exe `
- stage `
- toolset=msvc `
- --stagedir=.\ `
- --with-headers
- name: Install Qt
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@v3
with:
- version: "6.9.1"
- arch: win64_msvc2022_64
+ version: "6.5.2"
archives: qtbase qtsvg qttools
cache: true
@@ -121,16 +109,15 @@ jobs:
${{ env.libtorrent_path }}
cd ${{ env.libtorrent_path }}
$env:CXXFLAGS+=" /guard:cf"
- $env:LDFLAGS+=" /GUARD:CF"
+ $env:LDFLAGS+=" /guard:cf"
cmake `
-B build `
-G "Ninja" `
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
- -DCMAKE_CXX_STANDARD=20 `
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON `
-DCMAKE_INSTALL_PREFIX="${{ env.libtorrent_path }}/install" `
-DCMAKE_TOOLCHAIN_FILE="${{ env.vcpkg_path }}/scripts/buildsystems/vcpkg.cmake" `
- -DBOOST_ROOT="${{ env.boost_path }}/lib/cmake" `
+ -DBOOST_ROOT="${{ env.boost_path }}" `
-DBUILD_SHARED_LIBS=OFF `
-Ddeprecated-functions=OFF `
-Dstatic_runtime=OFF `
@@ -140,14 +127,14 @@ jobs:
- name: Build qBittorrent
run: |
- $env:CXXFLAGS+="/DQT_FORCE_ASSERTS /WX"
+ $env:CXXFLAGS+=" /WX"
cmake `
-B build `
-G "Ninja" `
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON `
-DCMAKE_TOOLCHAIN_FILE="${{ env.vcpkg_path }}/scripts/buildsystems/vcpkg.cmake" `
- -DBOOST_ROOT="${{ env.boost_path }}/lib/cmake" `
+ -DBOOST_ROOT="${{ env.boost_path }}" `
-DLibtorrentRasterbar_DIR="${{ env.libtorrent_path }}/install/lib/cmake/LibtorrentRasterbar" `
-DMSVC_RUNTIME_DYNAMIC=ON `
-DTESTING=ON `
@@ -166,26 +153,26 @@ jobs:
copy build/qbittorrent.pdb upload/qBittorrent
copy dist/windows/qt.conf upload/qBittorrent
# runtimes
- copy "${{ env.Qt_ROOT_DIR }}/bin/Qt6Core.dll" upload/qBittorrent
- copy "${{ env.Qt_ROOT_DIR }}/bin/Qt6Gui.dll" upload/qBittorrent
- copy "${{ env.Qt_ROOT_DIR }}/bin/Qt6Network.dll" upload/qBittorrent
- copy "${{ env.Qt_ROOT_DIR }}/bin/Qt6Sql.dll" upload/qBittorrent
- copy "${{ env.Qt_ROOT_DIR }}/bin/Qt6Svg.dll" upload/qBittorrent
- copy "${{ env.Qt_ROOT_DIR }}/bin/Qt6Widgets.dll" upload/qBittorrent
- copy "${{ env.Qt_ROOT_DIR }}/bin/Qt6Xml.dll" upload/qBittorrent
+ copy "${{ env.Qt6_DIR }}/bin/Qt6Core.dll" upload/qBittorrent
+ copy "${{ env.Qt6_DIR }}/bin/Qt6Gui.dll" upload/qBittorrent
+ copy "${{ env.Qt6_DIR }}/bin/Qt6Network.dll" upload/qBittorrent
+ copy "${{ env.Qt6_DIR }}/bin/Qt6Sql.dll" upload/qBittorrent
+ copy "${{ env.Qt6_DIR }}/bin/Qt6Svg.dll" upload/qBittorrent
+ copy "${{ env.Qt6_DIR }}/bin/Qt6Widgets.dll" upload/qBittorrent
+ copy "${{ env.Qt6_DIR }}/bin/Qt6Xml.dll" upload/qBittorrent
mkdir upload/qBittorrent/plugins/iconengines
- copy "${{ env.Qt_ROOT_DIR }}/plugins/iconengines/qsvgicon.dll" upload/qBittorrent/plugins/iconengines
+ copy "${{ env.Qt6_DIR }}/plugins/iconengines/qsvgicon.dll" upload/qBittorrent/plugins/iconengines
mkdir upload/qBittorrent/plugins/imageformats
- copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qico.dll" upload/qBittorrent/plugins/imageformats
- copy "${{ env.Qt_ROOT_DIR }}/plugins/imageformats/qsvg.dll" upload/qBittorrent/plugins/imageformats
+ copy "${{ env.Qt6_DIR }}/plugins/imageformats/qico.dll" upload/qBittorrent/plugins/imageformats
+ copy "${{ env.Qt6_DIR }}/plugins/imageformats/qsvg.dll" upload/qBittorrent/plugins/imageformats
mkdir upload/qBittorrent/plugins/platforms
- copy "${{ env.Qt_ROOT_DIR }}/plugins/platforms/qwindows.dll" upload/qBittorrent/plugins/platforms
+ copy "${{ env.Qt6_DIR }}/plugins/platforms/qwindows.dll" upload/qBittorrent/plugins/platforms
mkdir upload/qBittorrent/plugins/sqldrivers
- copy "${{ env.Qt_ROOT_DIR }}/plugins/sqldrivers/qsqlite.dll" upload/qBittorrent/plugins/sqldrivers
+ copy "${{ env.Qt6_DIR }}/plugins/sqldrivers/qsqlite.dll" upload/qBittorrent/plugins/sqldrivers
mkdir upload/qBittorrent/plugins/styles
- copy "${{ env.Qt_ROOT_DIR }}/plugins/styles/qmodernwindowsstyle.dll" upload/qBittorrent/plugins/styles
+ copy "${{ env.Qt6_DIR }}/plugins/styles/qwindowsvistastyle.dll" upload/qBittorrent/plugins/styles
mkdir upload/qBittorrent/plugins/tls
- copy "${{ env.Qt_ROOT_DIR }}/plugins/tls/qschannelbackend.dll" upload/qBittorrent/plugins/tls
+ copy "${{ env.Qt6_DIR }}/plugins/tls/qschannelbackend.dll" upload/qBittorrent/plugins/tls
# cmake additionals
mkdir upload/cmake
copy build/compile_commands.json upload/cmake
diff --git a/.github/workflows/coverity-scan.yaml b/.github/workflows/coverity-scan.yaml
index dc561ac4a..93c8b89e5 100644
--- a/.github/workflows/coverity-scan.yaml
+++ b/.github/workflows/coverity-scan.yaml
@@ -14,9 +14,9 @@ jobs:
strategy:
matrix:
- libt_version: ["2.0.11"]
+ libt_version: ["2.0.10"]
qbt_gui: ["GUI=ON"]
- qt_version: ["6.9.1"]
+ qt_version: ["6.5.2"]
env:
boost_path: "${{ github.workspace }}/../boost"
@@ -26,8 +26,6 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- with:
- persist-credentials: false
- name: Install dependencies
run: |
@@ -39,10 +37,10 @@ jobs:
- name: Install boost
env:
BOOST_MAJOR_VERSION: "1"
- BOOST_MINOR_VERSION: "88"
+ BOOST_MINOR_VERSION: "84"
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_url="https://boostorg.jfrog.io/artifactory/main/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"
set +e
curl -L -o "${{ runner.temp }}/boost.tar.gz" "$boost_url"
@@ -52,12 +50,9 @@ jobs:
tar -xf "${{ runner.temp }}/boost.tar.gz" -C "${{ github.workspace }}/.."; _exitCode="$?"
fi
mv "${{ github.workspace }}/.."/boost_* "${{ env.boost_path }}"
- cd "${{ env.boost_path }}"
- ./bootstrap.sh
- ./b2 stage --stagedir=./ --with-headers
- name: Install Qt
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@v3
with:
version: ${{ matrix.qt_version }}
archives: icu qtbase qtdeclarative qtsvg qttools
@@ -76,8 +71,7 @@ jobs:
-B build \
-G "Ninja" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
- -DCMAKE_CXX_STANDARD=20 \
- -DBOOST_ROOT="${{ env.boost_path }}/lib/cmake" \
+ -DBOOST_ROOT="${{ env.boost_path }}" \
-Ddeprecated-functions=OFF
cmake --build build
sudo cmake --install build
@@ -101,7 +95,7 @@ jobs:
-B build \
-G "Ninja" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
- -DBOOST_ROOT="${{ env.boost_path }}/lib/cmake" \
+ -DBOOST_ROOT="${{ env.boost_path }}" \
-DVERBOSE_CONFIGURE=ON \
-D${{ matrix.qbt_gui }}
PATH="${{ env.coverity_path }}/bin:$PATH" \
diff --git a/.github/workflows/helper/pre-commit/.typos.toml b/.github/workflows/helper/pre-commit/.typos.toml
index 90d6e1746..0f33373ad 100644
--- a/.github/workflows/helper/pre-commit/.typos.toml
+++ b/.github/workflows/helper/pre-commit/.typos.toml
@@ -16,5 +16,3 @@ ths = "ths"
[default.extend-words]
BA = "BA"
helo = "helo"
-Pn = "Pn"
-UIU = "UIU"
diff --git a/.github/workflows/helper/pre-commit/check_grid_items_order.py b/.github/workflows/helper/pre-commit/check_grid_items_order.py
deleted file mode 100755
index dfd1bba68..000000000
--- a/.github/workflows/helper/pre-commit/check_grid_items_order.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env python3
-
-# A pre-commit hook for checking items order in grid layouts
-# Copyright (C) 2024 Mike Tzou (Chocobo1)
-#
-# 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.
-
-import argparse
-import re
-import sys
-import xml.etree.ElementTree as ElementTree
-from collections.abc import Callable, Sequence
-from typing import Optional
-
-
-def traversePostOrder(root: ElementTree.Element, visitFunc: Callable[[ElementTree.Element], None]) -> None:
- stack = [(root, False)]
-
- while len(stack) > 0:
- (element, visit) = stack.pop()
- if visit:
- visitFunc(element)
- else:
- stack.append((element, True))
- stack.extend((child, False) for child in reversed(element))
-
-
-def modifyElement(element: ElementTree.Element) -> None:
- def getSortKey(e: ElementTree.Element) -> tuple[int, int]:
- if e.tag == 'item':
- return (int(e.attrib['row']), int(e.attrib['column']))
- return (-1, -1) # don't care
-
- if element.tag == 'layout' and element.attrib['class'] == 'QGridLayout' and len(element) > 0:
- element[:] = sorted(element, key=getSortKey)
-
- # workaround_2a: ElementTree will unescape `"` and we need to escape it back
- if element.tag == 'string' and element.text is not None:
- element.text = element.text.replace('"', '"')
-
-
-def main(argv: Optional[Sequence[str]] = None) -> int:
- parser = argparse.ArgumentParser()
- parser.add_argument('filenames', nargs='*', help='Filenames to check')
- args = parser.parse_args(argv)
-
- for filename in args.filenames:
- with open(filename, 'r+') as f:
- orig = f.read()
- root = ElementTree.fromstring(orig)
- traversePostOrder(root, modifyElement)
- ElementTree.indent(root, ' ')
-
- # workaround_1: cannot use `xml_declaration=True` since it uses single quotes instead of Qt preferred double quotes
- ret = f'\n{ElementTree.tostring(root, 'unicode')}\n'
-
- # workaround_2b: ElementTree will turn `"` into `"`, so revert it back
- ret = ret.replace('"', '"')
-
- # workaround_3: Qt prefers no whitespaces in self-closing tags
- ret = re.sub('<(.+) +/>', r'<\1/>', ret)
-
- if ret != orig:
- print(f'Tip: run this script to apply the fix: `python {__file__} {filename}`', file=sys.stderr)
-
- f.seek(0)
- f.write(ret)
- f.truncate()
-
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/.github/workflows/helper/pre-commit/check_translation_tag.py b/.github/workflows/helper/pre-commit/check_translation_tag.py
index 547a2a992..34705f74d 100755
--- a/.github/workflows/helper/pre-commit/check_translation_tag.py
+++ b/.github/workflows/helper/pre-commit/check_translation_tag.py
@@ -26,12 +26,9 @@
# but you are not obligated to do so. If you do not wish to do so, delete this
# exception statement from your version.
+from typing import Optional, Sequence
import argparse
import re
-import sys
-from collections.abc import Sequence
-from typing import Optional
-
def main(argv: Optional[Sequence[str]] = None) -> int:
parser = argparse.ArgumentParser()
@@ -50,12 +47,12 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
for line in file:
if (match := regex.match(line)) is not None:
error_buffer += str(f"Defect file: \"{filename}\"\n"
- f"Line: {line_counter}\n"
- f"Column span: {match.span()}\n"
- f"Part: \"{match.group()}\"\n\n")
+ f"Line: {line_counter}\n"
+ f"Column span: {match.span()}\n"
+ f"Part: \"{match.group()}\"\n\n")
line_counter += 1
- except UnicodeDecodeError:
+ except UnicodeDecodeError as error:
# not a text file, skip
continue
@@ -67,6 +64,5 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
return 0
-
if __name__ == '__main__':
- sys.exit(main())
+ exit(main())
diff --git a/.github/workflows/stale_bot.yaml b/.github/workflows/stale_bot.yaml
index 705f6a5c9..6cd727855 100644
--- a/.github/workflows/stale_bot.yaml
+++ b/.github/workflows/stale_bot.yaml
@@ -4,13 +4,12 @@ on:
schedule:
- cron: '0 0 * * *'
-permissions: {}
+permissions:
+ pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
- permissions:
- pull-requests: write
steps:
- name: Mark and close stale PRs
uses: actions/stale@v9
diff --git a/.gitignore b/.gitignore
index 17b925842..c928583ee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,7 @@ src/icons/skin/build-icons/icons/*.png
# CMake build directory
build/
+
+# Web UI tools
+node_modules
+package-lock.json
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 90beea365..a910f1c77 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,12 +1,6 @@
repos:
- repo: local
hooks:
- - id: check-grid-order
- name: Check items order in grid layouts
- entry: .github/workflows/helper/pre-commit/check_grid_items_order.py
- language: script
- files: \.ui$
-
- id: check-translation-tag
name: Check newline characters in tag
entry: .github/workflows/helper/pre-commit/check_translation_tag.py
@@ -19,7 +13,7 @@ repos:
- ts
- repo: https://github.com/pre-commit/pre-commit-hooks.git
- rev: v6.0.0
+ rev: v4.5.0
hooks:
- id: check-json
name: Check JSON files
@@ -69,26 +63,32 @@ repos:
- ts
- repo: https://github.com/codespell-project/codespell.git
- rev: v2.4.1
+ rev: v2.2.6
hooks:
- id: codespell
name: Check spelling (codespell)
- args: ["--ignore-words-list", "additionals,categor,curren,fo,indexIn,ist,ket,notin,searchin,sectionin,superseeding,te,ths"]
+ args: ["--ignore-words-list", "additionals,curren,fo,ist,ket,superseeding,te,ths"]
exclude: |
(?x)^(
.*\.desktop |
.*\.qrc |
+ build-aux/.* |
Changelog |
dist/windows/installer-translations/.* |
+ m4/.* |
src/base/3rdparty/.* |
src/searchengine/nova3/socks.py |
- src/webui/www/private/scripts/lib/.*
+ src/webui/www/private/lang/.* |
+ src/webui/www/private/scripts/lib/.* |
+ src/webui/www/public/lang/.* |
+ src/webui/www/public/scripts/lib/.* |
+ src/webui/www/transifex/.*
)$
exclude_types:
- ts
- repo: https://github.com/crate-ci/typos.git
- rev: v1.35.3
+ rev: v1.16.18
hooks:
- id: typos
name: Check spelling (typos)
@@ -99,11 +99,18 @@ repos:
.*\.desktop |
.*\.qrc |
\.pre-commit-config\.yaml |
+ build-aux/.* |
Changelog |
+ configure.* |
dist/windows/installer-translations/.* |
+ m4/.* |
src/base/3rdparty/.* |
src/searchengine/nova3/socks.py |
- src/webui/www/private/scripts/lib/.*
+ src/webui/www/private/lang/.* |
+ src/webui/www/private/scripts/lib/.* |
+ src/webui/www/public/lang/.* |
+ src/webui/www/public/scripts/lib/.* |
+ src/webui/www/transifex/.*
)$
exclude_types:
- svg
diff --git a/.tx/config b/.tx/config
index 95d5b1afa..593cf8675 100644
--- a/.tx/config
+++ b/.tx/config
@@ -17,6 +17,14 @@ type = QT
minimum_perc = 23
lang_map = pt: pt_PT, zh: zh_CN
+[o:sledgehammer999:p:qbittorrent:r:qbittorrent_webui_json]
+file_filter = src/webui/www/transifex/.json
+source_file = src/webui/www/transifex/en.json
+source_lang = en
+type = KEYVALUEJSON
+minimum_perc = 23
+lang_map = pt: pt_PT, zh: zh_CN
+
[o:sledgehammer999:p:qbittorrent:r:qbittorrentdesktop_master]
source_file = dist/unix/org.qbittorrent.qBittorrent.desktop
source_lang = en
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97ecb3684..06032cba5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,10 +8,10 @@ project(qBittorrent
# version requirements - older versions may work, but you are on your own
set(minBoostVersion 1.76)
-set(minQt6Version 6.6.0)
+set(minQt6Version 6.5.0)
set(minOpenSSLVersion 3.0.2)
set(minLibtorrent1Version 1.2.19)
-set(minLibtorrentVersion 2.0.10)
+set(minLibtorrentVersion 2.0.9)
set(minZlibVersion 1.2.11)
include(GNUInstallDirs)
diff --git a/COPYING.GPLv2 b/COPYING.GPLv2
index 9efa6fbc9..d159169d1 100644
--- a/COPYING.GPLv2
+++ b/COPYING.GPLv2
@@ -2,7 +2,7 @@
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
-
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -304,7 +304,8 @@ the "copyright" line and a pointer to where the full notice is found.
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, see .
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
@@ -328,8 +329,8 @@ necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
- , 1 April 1989
- Moe Ghoul, President of Vice
+ , 1 April 1989
+ Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
diff --git a/Changelog b/Changelog
index 453c4bcdc..8d702641d 100644
--- a/Changelog
+++ b/Changelog
@@ -1,26 +1,4 @@
-Unreleased - sledgehammer999 - v5.1.0
-
-Mon Oct 28th 2024 - sledgehammer999 - v5.0.1
- - FEATURE: Add "Simple pread/pwrite" disk IO type (Hanabishi)
- - BUGFIX: Don't ignore SSL errors (sledgehammer999)
- - BUGFIX: Don't try to apply Mark-of-the-Web to nonexistent files (glassez)
- - BUGFIX: Disable "Move to trash" option by default (glassez)
- - BUGFIX: Disable the ability to create torrents with a piece size of 256MiB (stalkerok)
- - BUGFIX: Allow to choose Qt style (glassez)
- - BUGFIX: Always notify user about duplicate torrent (glassez)
- - BUGFIX: Correctly handle "torrent finished after move" event (glassez)
- - BUGFIX: Correctly apply filename filter when `!qB` extension is enabled (glassez)
- - BUGFIX: Improve color scheme change detection (glassez)
- - BUGFIX: Fix button state for SSL certificate check (Chocobo1)
- - WEBUI: Fix CSS that results in hidden torrent list in some browsers (skomerko)
- - WEBUI: Use proper text color to highlight items in all filter lists (skomerko)
- - WEBUI: Fix 'rename files' dialog cannot be opened more than once (Chocobo1)
- - WEBUI: Fix UI of Advanced Settings to show all settings (glassez)
- - WEBUI: Free resources allocated by web session once it is destructed (dyseg)
- - SEARCH: Import correct libraries (Chocobo1)
- - OTHER: Sync flag icons with upstream (xavier2k6)
-
-Sun Sep 29th 2024 - sledgehammer999 - v5.0.0
+Unreleased - sledgehammer999 - v5.0.0
- FEATURE: Support creating .torrent with larger piece size (Chocobo1)
- FEATURE: Improve tracker entries handling (glassez)
- FEATURE: Add separate filter item for tracker errors (glassez)
@@ -34,30 +12,14 @@ Sun Sep 29th 2024 - sledgehammer999 - v5.0.0
- FEATURE: Enable Ctrl+F hotkey for more inputs (thalieht)
- FEATURE: Add seeding limits to RSS and Watched folders options UI (glassez)
- FEATURE: Subcategories implicitly follow the parent category options (glassez)
+ - FEATURE: Add support for SSL torrents (Chocobo1, Radu Carpa)
- FEATURE: Add option to name each qbittorrent instance (Chocobo1)
- FEATURE: Add button for sending test email (Thomas Piccirello)
- FEATURE: Allow torrents to override default share limit action (glassez)
- - FEATURE: Use Start/Stop instead of Resume/Pause (thalieht)
- - FEATURE: Add the Popularity metric (Aliaksei Urbanski)
- - FEATURE: Focus on Download button if torrent link retrieved from the clipboard (glassez)
- - FEATURE: Add ability to pause/resume entire BitTorrent session (glassez)
- - FEATURE: Add an option to set BitTorrent session shutdown timeout (glassez)
- - FEATURE: Apply "Excluded file names" to folder names as well (glassez)
- - FEATURE: Allow to use regular expression to filter torrent content (glassez)
- - FEATURE: Allow to move content files to Trash instead of deleting them (glassez)
- - FEATURE: Add ability to display torrent "privateness" in UI (ManiMatter)
- - FEATURE: Add a flag in `Peers` tab denoting a connection using NAT hole punching (stalkerok)
- BUGFIX: Display error message when unrecoverable error occurred (glassez)
- BUGFIX: Update size of selected files when selection is changed (glassez)
- BUGFIX: Normalize tags by trimming leading/trailing whitespace (glassez)
- BUGFIX: Correctly handle share limits in torrent options dialog (glassez)
- - BUGFIX: Adjust tracker tier when adding additional trackers (Chocobo1)
- - BUGFIX: Fix inconsistent naming between `Done/Progress` column (luzpaz)
- - BUGFIX: Sanitize peer client names (Hanabishi)
- - BUGFIX: Apply share limits immediately when torrent downloading is finished (glassez)
- - BUGFIX: Show download progress for folders with zero byte size as 100 instead of 0 (vikas_c)
- - BUGFIX: Fix highlighted piece color (Prince Gupta)
- - BUGFIX: Apply "merge trackers" logic regardless of way the torrent is added (glassez)
- WEBUI: Improve WebUI responsiveness (Chocobo1)
- WEBUI: Do not exit the app when WebUI has failed to start (Hanabishi)
- WEBUI: Add `Moving` filter to side panel (xavier2k6)
@@ -66,37 +28,14 @@ Sun Sep 29th 2024 - sledgehammer999 - v5.0.0
- WEBUI: Leave the fields empty when value is invalid (Chocobo1)
- WEBUI: Use natural sorting (Chocobo1)
- WEBUI: Improve WebUI login behavior (JayRet)
- - WEBUI: Conditionally show filters sidebar (Thomas Piccirello)
- - WEBUI: Add support for running concurrent searches (Thomas Piccirello)
- - WEBUI: Improve accuracy of trackers list (Thomas Piccirello)
- - WEBUI: Fix error when category doesn't exist (Thomas Piccirello)
- - WEBUI: Improve table scrolling and selection on mobile (Thomas Piccirello)
- - WEBUI: Restore search tabs on load (Thomas Piccirello)
- - WEBUI: Restore previously used tab on load (Thomas Piccirello)
- - WEBUI: Increase default height of `Share ratio limit` dialog (thalieht)
- - WEBUI: Use enabled search plugins by default (Thomas Piccirello)
- - WEBUI: Add columns `Incomplete Save Path`, `Info Hash v1`, `Info Hash v2` (thalieht)
- - WEBUI: Always create generic filter items (skomerko)
- - WEBUI: Provide `Use Category paths in Manual Mode` option (skomerko)
- - WEBUI: Provide `Merge trackers to existing torrent` option (skomerko)
- WEBAPI: Fix wrong timestamp values (Chocobo1)
- WEBAPI: Send binary data with filename and mime type specified (glassez)
- WEBAPI: Expose API for the torrent creator (glassez, Radu Carpa)
- - WEBAPI: Add support for SSL torrents (Chocobo1, Radu Carpa)
- - WEBAPI: Provide endpoint for listing directory content (Paweł Kotiuk)
- - WEBAPI: Provide "private" flag via "torrents/info" endpoint (ManiMatter)
- - WEBAPI: Add a way to download .torrent file using search plugin (glassez)
- - WEBAPI: Add "private" filter for "torrents/info" endpoint (ManiMatter)
- - WEBAPI: Add root_path to "torrents/info" result (David Newhall)
- RSS: Show RSS feed title in HTML browser (Jay)
- RSS: Allow to set delay between requests to the same host (jNullj)
- SEARCH: Allow users to specify Python executable path (Chocobo1)
- - SEARCH: Lazy load search plugins (milahu)
- - SEARCH: Add date column to the built-in search engine (ducalex)
- - SEARCH: Allow to rearrange search tabs (glassez)
- WINDOWS: Use Fusion style on Windows 10+. It has better compatibility with dark mode (glassez)
- WINDOWS: Allow to set qBittorrent as default program (glassez)
- - WINDOWS: Don't access "Favorites" folder unexpectedly (glassez)
- LINUX: Add support for systemd power management (Chocobo1)
- LINUX: Add support for localized man pages (Victor Chernyakin)
- LINUX: Specify a locale if none is set (Chocobo1)
@@ -106,42 +45,6 @@ Sun Sep 29th 2024 - sledgehammer999 - v5.0.0
- OTHER: Minimum supported versions: Qt: 6.5, Boost: 1.76, OpenSSL: 3.0.2
- OTHER: Switch to C++20
-Mon Sep 16th 2024 - sledgehammer999 - v4.6.7
- - BUGFIX: The updater will launch the link to the build variant you're currently using (sledgehammer999)
- - BUGFIX: Focus on Download button if torrent link retrieved from the clipboard (glassez)
- - WEBUI: RSS: The list of feeds wouldn't load for Apply Rule (glassez)
-
-Sun Aug 18th 2024 - sledgehammer999 - v4.6.6
- - BUGFIX: Fix handling of tags containing '&' character (glassez)
- - BUGFIX: Show scroll bar in Torrent Tags dialog (glassez)
- - BUGFIX: Apply bulk changes to correct content widget items (glassez)
- - BUGFIX: Hide zero status filters when torrents are removed (glassez)
- - BUGFIX: Fix `Incomplete Save Path` cannot be changed for torrents without metadata (glassez)
- - WEBUI: Correctly apply changed "save path" of RSS rules (glassez)
- - WEBUI: Clear tracker list on full update (skomerko)
- - OTHER: Update User-Agent string for internal downloader and search engines (cayenne17)
-
-Sun May 26th 2024 - sledgehammer999 - v4.6.5
- - BUGFIX: Prevent app from being closed when disabling system tray icon (glassez)
- - BUGFIX: Fix Enter key behavior in Add new torrent dialog (glassez)
- - BUGFIX: Prevent invalid status filter index from being used (glassez)
- - BUGFIX: Add extra offset for dialog frame (glassez)
- - BUGFIX: Don't overwrite stored layout of main window with incorrect one (glassez)
- - BUGFIX: Don't forget to resume "missing files" torrent when rechecking (glassez)
- - WEBUI: Restore ability to use server-side translation by custom WebUI (glassez)
- - WEBUI: Fix wrong peer number (Chocobo1)
- - LINUX: Improve AppStream metadata (Chocobo1)
-
-Sun Mar 24th 2024 - sledgehammer999 - v4.6.4
- - BUGFIX: Correctly adjust "Add New torrent" dialog position in all the cases (glassez)
- - BUGFIX: Change "metadata received" stop condition behavior (glassez)
- - BUGFIX: Add a small delay before processing the key input of search boxes (Chocobo1)
- - BUGFIX: Ensure the profile path is pointing to a directory (Chocobo1)
- - RSS: Use better icons for RSS articles (glassez)
- - WINDOWS: NSIS: Update French, Hungarian translations (MarcDrieu, foxi69)
- - LINUX: Fix sorting when ICU isn't used (Chocobo1)
- - LINUX: Fix invisible tray icon on Plasma 6 (tehcneko)
-
Mon Jan 15th 2024 - sledgehammer999 - v4.6.3
- BUGFIX: Correctly update number of filtered items (glassez)
- BUGFIX: Don't forget to store Stop condition value (glassez)
diff --git a/INSTALL b/INSTALL
index b17e323fb..8d43301ed 100644
--- a/INSTALL
+++ b/INSTALL
@@ -5,20 +5,20 @@ qBittorrent - A BitTorrent client in C++ / Qt
- Boost >= 1.76
- - libtorrent-rasterbar 1.2.19 - 1.2.x || 2.0.10 - 2.0.x
+ - libtorrent-rasterbar 1.2.19 - 1.2.x || 2.0.9 - 2.0.x
* By Arvid Norberg, https://www.libtorrent.org/
* Be careful: another library (the one used by rTorrent) uses a similar name
- OpenSSL >= 3.0.2
- - Qt 6.6.0 - 6.x
+ - Qt 6.5.0 - 6.x
- zlib >= 1.2.11
- CMake >= 3.16
* Compile-time only
- - Python >= 3.9.0
+ - Python >= 3.7.0
* Optional, run-time only
* Used by the bundled search engine
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index 6c931a30c..000000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Security Policy
-
-qBittorrent takes the security of our software seriously, including all source code repositories managed through our GitHub organisation.
-If you believe you have found a security vulnerability in qBittorrent, please report it to us as described below.
-
-## Reporting Security Issues
-
-Please do not report security vulnerabilities through public GitHub issues. Instead, please use GitHubs private vulnerability reporting functionality associated to this repository. Additionally, you may email us with all security-related inquiries and notifications at `security@qbittorrent.org`.
-
-Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
-1. Type of issue
-2. Step-by-step instructions to reproduce the issue
-3. Proof-of-concept or exploit code (if possible)
-4. Potential impact of the issue, including how an attacker might exploit the issue
-
-This information will help us triage your report more quickly. Any and all CVEs will be requested and issued through GitHubs private vulnerability reporting functionality, which will be published alongside the disclosure.
-
-This security policy only applies to the most recent stable branch of qBittorrent. Flaws in old versions that are not present in the current stable branch will not be fixed.
diff --git a/WebAPI_Changelog.md b/WebAPI_Changelog.md
deleted file mode 100644
index 2cb5fe033..000000000
--- a/WebAPI_Changelog.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# WebAPI Changelog
-
-## 2.13.0
-* [#23045](https://github.com/qbittorrent/qBittorrent/pull/23045)
- * `torrents/trackers` returns three new fields: `next_announce`, `min_announce` and `endpoints`
- * `endpoints` is an array of tracker endpoints, each with `name`, `updating`, `status`, `msg`, `bt_version`, `num_peers`, `num_peers`, `num_leeches`, `num_downloaded`, `next_announce` and `min_announce` fields
- * `torrents/trackers` now returns `5` and `6` in `status` field as possible values
- * `5` for `Tracker error` and `6` for `Unreachable`
-* [#22963](https://github.com/qbittorrent/qBittorrent/pull/22963)
- * `torrents/editTracker` endpoint now supports setting a tracker's tier via `tier` parameter
- * `torrents/editTracker` endpoint always responds with a 204 when successful
- * `torrents/editTracker` endpoint `origUrl` parameter renamed to `url`
-
-## 2.12.1
-* [#23031](https://github.com/qbittorrent/qBittorrent/pull/23031)
- * Add `torrents/setComment` endpoint with parameters `hashes` and `comment` for setting a new torrent comment
-
-## 2.12.0
-
-* [#22989](https://github.com/qbittorrent/qBittorrent/pull/22989)
- * `sync/maindata` returns one new field: `share_limit_action`
- * `torrents/setShareLimits` now requires a new `shareLimitAction` param that sets a torrent's shareLimitAction property
- * possible values `Default`, `Stop`, `Remove`, `RemoveWithContent` and `EnableSuperSeeding`
-
-## 2.11.10
-
-* [#22958](https://github.com/qbittorrent/qBittorrent/pull/22958)
- * `torrents/categories` and `sync/maindata` now serialize categories' `downloadPath` to `null`, rather than `undefined`
-* [#22954](https://github.com/qbittorrent/qBittorrent/pull/22954)
- * `torrents/reannounce` supports specifying individual trackers via `trackers` field
-
-## 2.11.9
-
-* [#21015](https://github.com/qbittorrent/qBittorrent/pull/21015)
- * Add `torrents/fetchMetadata` endpoint for retrieving torrent metadata associated with a URL
- * Add `torrents/parseMetadata` endpoint for retrieving torrent metadata associated with a .torrent file
- * Add `torrents/saveMetadata` endpoint for saving retrieved torrent metadata to a .torrent file
- * `torrents/add` allows adding a torrent with metadata previously retrieved via `torrents/fetchMetadata` or `torrents/parseMetadata`
- * `torrents/add` allows specifying a torrent's file priorities
-* [#22698](https://github.com/qbittorrent/qBittorrent/pull/22698)
- * `torrents/addTrackers` and `torrents/removeTrackers` now accept `hash=all` and adds/removes the tracker to/from *all* torrents
- * For compatibility, `torrents/removeTrackers` still accepts `hash=*` internally we transform it into `all`
- * Allow passing a pipe (`|`) separated list of hashes in `hash` for `torrents/addTrackers` and `torrents/removeTrackers`
-
-## 2.11.8
-
-* [#21349](https://github.com/qbittorrent/qBittorrent/pull/21349)
- * Handle sending `204 No Content` status code when response contains no data
- * Some endpoints still return `200 OK` to ensure smooth transition
-* [#22750](https://github.com/qbittorrent/qBittorrent/pull/22750)
- * `torrents/info` allows an optional parameter `includeFiles` that defaults to `false`
- * Each torrent will contain a new key `files` which will list all files similar to the `torrents/files` endpoint
-* [#22813](https://github.com/qbittorrent/qBittorrent/pull/22813)
- * `app/getDirectoryContent` allows an optional parameter `withMetadata` to send file metadata
- * Fields are `name`, `type`, `size`, `creation_date`, `last_access_date`, `last_modification_date`
- * See PR for TypeScript types
-
-## 2.11.7
-
-* [#22166](https://github.com/qbittorrent/qBittorrent/pull/22166)
- * `sync/maindata` returns 3 new torrent fields: `has_tracker_warning`, `has_tracker_error`, `has_other_announce_error`
-
-## 2.11.6
-
-* [#22460](https://github.com/qbittorrent/qBittorrent/pull/22460)
- * `app/setPreferences` allows only one of `max_ratio_enabled`, `max_ratio` to be present
- * `app/setPreferences` allows only one of `max_seeding_time_enabled`, `max_seeding_time` to be present
- * `app/setPreferences` allows only one of `max_inactive_seeding_time_enabled`, `max_inactive_seeding_time` to be present
diff --git a/cmake/Modules/CheckPackages.cmake b/cmake/Modules/CheckPackages.cmake
index 6b082ea11..6c85b8d11 100644
--- a/cmake/Modules/CheckPackages.cmake
+++ b/cmake/Modules/CheckPackages.cmake
@@ -47,9 +47,6 @@ find_package(Boost ${minBoostVersion} REQUIRED)
find_package(OpenSSL ${minOpenSSLVersion} REQUIRED)
find_package(ZLIB ${minZlibVersion} REQUIRED)
find_package(Qt6 ${minQt6Version} REQUIRED COMPONENTS Core Network Sql Xml LinguistTools)
-if (Qt6_FOUND AND (Qt6_VERSION VERSION_GREATER_EQUAL 6.10))
- find_package(Qt6 ${minQt6Version} REQUIRED COMPONENTS CorePrivate)
-endif()
if (DBUS)
find_package(Qt6 ${minQt6Version} REQUIRED COMPONENTS DBus)
set_package_properties(Qt6DBus PROPERTIES
diff --git a/cmake/Modules/CommonConfig.cmake b/cmake/Modules/CommonConfig.cmake
index b66019fd6..b57dc4bcf 100644
--- a/cmake/Modules/CommonConfig.cmake
+++ b/cmake/Modules/CommonConfig.cmake
@@ -20,11 +20,10 @@ target_compile_features(qbt_common_cfg INTERFACE
)
target_compile_definitions(qbt_common_cfg INTERFACE
- QT_DISABLE_DEPRECATED_UP_TO=0x060600
+ QT_DISABLE_DEPRECATED_UP_TO=0x060500
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
QT_NO_CAST_FROM_BYTEARRAY
- QT_NO_CONTEXTLESS_CONNECT
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
QT_USE_QSTRINGBUILDER
QT_STRICT_ITERATORS
@@ -90,7 +89,7 @@ if (MSVC)
/Zc:__cplusplus
)
target_link_options(qbt_common_cfg INTERFACE
- /GUARD:CF
+ /guard:cf
$<$>:/OPT:REF /OPT:ICF>
# suppress linking warning due to /INCREMENTAL and /OPT:ICF being both ON
$<$:/INCREMENTAL:NO>
diff --git a/dist/mac/Info.plist b/dist/mac/Info.plist
index bebe2f1fb..50f6ccbd4 100644
--- a/dist/mac/Info.plist
+++ b/dist/mac/Info.plist
@@ -55,7 +55,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 5.2.0
+ 5.0.0
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
@@ -67,7 +67,7 @@
NSAppleScriptEnabled
YES
NSHumanReadableCopyright
- Copyright © 2006-2025 The qBittorrent project
+ Copyright © 2006-2024 The qBittorrent project
UTExportedTypeDeclarations
diff --git a/dist/mac/qBitTorrentDocument.icns b/dist/mac/qBitTorrentDocument.icns
index d257dc2d9..efd7fc1e5 100644
Binary files a/dist/mac/qBitTorrentDocument.icns and b/dist/mac/qBitTorrentDocument.icns differ
diff --git a/dist/mac/qbittorrent_mac.icns b/dist/mac/qbittorrent_mac.icns
index a618a87a4..58684a09e 100644
Binary files a/dist/mac/qbittorrent_mac.icns and b/dist/mac/qbittorrent_mac.icns differ
diff --git a/dist/unix/CMakeLists.txt b/dist/unix/CMakeLists.txt
index c731ebbaf..19fb16fbb 100644
--- a/dist/unix/CMakeLists.txt
+++ b/dist/unix/CMakeLists.txt
@@ -34,12 +34,12 @@ endforeach()
if (GUI)
install(FILES org.qbittorrent.qBittorrent.desktop
- DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications/
COMPONENT data
)
- install(FILES org.qbittorrent.qBittorrent.metainfo.xml
- DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo
+ install(FILES org.qbittorrent.qBittorrent.appdata.xml
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo/
COMPONENT data
)
@@ -55,9 +55,4 @@ if (GUI)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status
COMPONENT data
)
-else()
- install(FILES org.qbittorrent.qBittorrent-nox.metainfo.xml
- DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo
- COMPONENT data
- )
endif()
diff --git a/dist/unix/menuicons/16x16/apps/qbittorrent.png b/dist/unix/menuicons/16x16/apps/qbittorrent.png
index 3dcb87856..bf74dc0e6 100644
Binary files a/dist/unix/menuicons/16x16/apps/qbittorrent.png and b/dist/unix/menuicons/16x16/apps/qbittorrent.png differ
diff --git a/dist/unix/menuicons/16x16/status/qbittorrent-tray.png b/dist/unix/menuicons/16x16/status/qbittorrent-tray.png
index 3dcb87856..bf74dc0e6 100644
Binary files a/dist/unix/menuicons/16x16/status/qbittorrent-tray.png and b/dist/unix/menuicons/16x16/status/qbittorrent-tray.png differ
diff --git a/dist/unix/menuicons/192x192/apps/qbittorrent.png b/dist/unix/menuicons/192x192/apps/qbittorrent.png
index af1c69a74..799b5c2c0 100644
Binary files a/dist/unix/menuicons/192x192/apps/qbittorrent.png and b/dist/unix/menuicons/192x192/apps/qbittorrent.png differ
diff --git a/dist/unix/menuicons/192x192/status/qbittorrent-tray.png b/dist/unix/menuicons/192x192/status/qbittorrent-tray.png
index af1c69a74..799b5c2c0 100644
Binary files a/dist/unix/menuicons/192x192/status/qbittorrent-tray.png and b/dist/unix/menuicons/192x192/status/qbittorrent-tray.png differ
diff --git a/dist/unix/menuicons/24x24/apps/qbittorrent.png b/dist/unix/menuicons/24x24/apps/qbittorrent.png
index 1c9c69451..a17e0398a 100644
Binary files a/dist/unix/menuicons/24x24/apps/qbittorrent.png and b/dist/unix/menuicons/24x24/apps/qbittorrent.png differ
diff --git a/dist/unix/menuicons/24x24/status/qbittorrent-tray.png b/dist/unix/menuicons/24x24/status/qbittorrent-tray.png
index 1c9c69451..a17e0398a 100644
Binary files a/dist/unix/menuicons/24x24/status/qbittorrent-tray.png and b/dist/unix/menuicons/24x24/status/qbittorrent-tray.png differ
diff --git a/dist/unix/menuicons/32x32/apps/qbittorrent.png b/dist/unix/menuicons/32x32/apps/qbittorrent.png
index 59cdb93f9..a1c56efd2 100644
Binary files a/dist/unix/menuicons/32x32/apps/qbittorrent.png and b/dist/unix/menuicons/32x32/apps/qbittorrent.png differ
diff --git a/dist/unix/menuicons/32x32/status/qbittorrent-tray.png b/dist/unix/menuicons/32x32/status/qbittorrent-tray.png
index 59cdb93f9..a1c56efd2 100644
Binary files a/dist/unix/menuicons/32x32/status/qbittorrent-tray.png and b/dist/unix/menuicons/32x32/status/qbittorrent-tray.png differ
diff --git a/dist/unix/menuicons/36x36/apps/qbittorrent.png b/dist/unix/menuicons/36x36/apps/qbittorrent.png
index b7e65a6a2..11c7278e5 100644
Binary files a/dist/unix/menuicons/36x36/apps/qbittorrent.png and b/dist/unix/menuicons/36x36/apps/qbittorrent.png differ
diff --git a/dist/unix/menuicons/36x36/status/qbittorrent-tray.png b/dist/unix/menuicons/36x36/status/qbittorrent-tray.png
index b7e65a6a2..11c7278e5 100644
Binary files a/dist/unix/menuicons/36x36/status/qbittorrent-tray.png and b/dist/unix/menuicons/36x36/status/qbittorrent-tray.png differ
diff --git a/dist/unix/menuicons/64x64/apps/qbittorrent.png b/dist/unix/menuicons/64x64/apps/qbittorrent.png
index fdd8df4ea..243f82cc6 100644
Binary files a/dist/unix/menuicons/64x64/apps/qbittorrent.png and b/dist/unix/menuicons/64x64/apps/qbittorrent.png differ
diff --git a/dist/unix/menuicons/64x64/status/qbittorrent-tray.png b/dist/unix/menuicons/64x64/status/qbittorrent-tray.png
index fdd8df4ea..243f82cc6 100644
Binary files a/dist/unix/menuicons/64x64/status/qbittorrent-tray.png and b/dist/unix/menuicons/64x64/status/qbittorrent-tray.png differ
diff --git a/dist/unix/menuicons/72x72/apps/qbittorrent.png b/dist/unix/menuicons/72x72/apps/qbittorrent.png
index 5d4162322..017e4fe18 100644
Binary files a/dist/unix/menuicons/72x72/apps/qbittorrent.png and b/dist/unix/menuicons/72x72/apps/qbittorrent.png differ
diff --git a/dist/unix/menuicons/72x72/status/qbittorrent-tray.png b/dist/unix/menuicons/72x72/status/qbittorrent-tray.png
index 5d4162322..017e4fe18 100644
Binary files a/dist/unix/menuicons/72x72/status/qbittorrent-tray.png and b/dist/unix/menuicons/72x72/status/qbittorrent-tray.png differ
diff --git a/dist/unix/menuicons/96x96/apps/qbittorrent.png b/dist/unix/menuicons/96x96/apps/qbittorrent.png
index 996aa6fc0..e87302310 100644
Binary files a/dist/unix/menuicons/96x96/apps/qbittorrent.png and b/dist/unix/menuicons/96x96/apps/qbittorrent.png differ
diff --git a/dist/unix/menuicons/96x96/status/qbittorrent-tray.png b/dist/unix/menuicons/96x96/status/qbittorrent-tray.png
index 996aa6fc0..e87302310 100644
Binary files a/dist/unix/menuicons/96x96/status/qbittorrent-tray.png and b/dist/unix/menuicons/96x96/status/qbittorrent-tray.png differ
diff --git a/dist/unix/org.qbittorrent.qBittorrent-nox.metainfo.xml b/dist/unix/org.qbittorrent.qBittorrent-nox.metainfo.xml
deleted file mode 100644
index c0aebf988..000000000
--- a/dist/unix/org.qbittorrent.qBittorrent-nox.metainfo.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
- org.qbittorrent.qBittorrent-nox
- CC0-1.0
- GPL-3.0-or-later and OpenSSL
- qBittorrent-nox
- An open-source Bittorrent client (nox version)
-
-
- The qBittorrent project aims to provide an open-source software alternative to µTorrent.
- Additionally, qBittorrent runs and provides the same features on all major platforms (FreeBSD, Linux, macOS, OS/2, Windows).
- qBittorrent is based on the Qt toolkit and libtorrent-rasterbar library.
-
-
- - Polished µTorrent-like User Interface
- - Well-integrated and extensible Search Engine
- - RSS feed support with advanced download filters (incl. regex)
- - Many Bittorrent extensions supported
- - Remote control through Web user interface, written with AJAX
- - Sequential downloading (Download in order)
- - Advanced control over torrents, trackers and peers
- - Bandwidth scheduler
- - Torrent creation tool
- - IP Filtering (eMule & PeerGuardian format compatible)
- - IPv6 compliant
- - UPnP / NAT-PMP port forwarding support
- - Available on all platforms: Windows, Linux, macOS, FreeBSD, OS/2
- - Available in ~70 languages
-
-
-
- qbittorrent-nox
-
-
-
- Running headless (nox) version
- https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/43fcf4550f567c38fb879b984922b659e90982cc/src/img/screenshots/linux/5.webp
-
-
- sledgehammer999@qbittorrent.org
-
- The qBittorrent Project
-
- https://www.qbittorrent.org/
- https://bugs.qbittorrent.org/
- https://wiki.qbittorrent.org/Frequently-Asked-Questions
- https://forum.qbittorrent.org/
- https://www.qbittorrent.org/donate
- https://wiki.qbittorrent.org/How-to-translate-qBittorrent
- https://github.com/qbittorrent/qBittorrent
- https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md
-
-
-
-
-
diff --git a/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml b/dist/unix/org.qbittorrent.qBittorrent.appdata.xml
similarity index 55%
rename from dist/unix/org.qbittorrent.qBittorrent.metainfo.xml
rename to dist/unix/org.qbittorrent.qBittorrent.appdata.xml
index 4aacf15ce..a24f47a6f 100644
--- a/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml
+++ b/dist/unix/org.qbittorrent.qBittorrent.appdata.xml
@@ -1,6 +1,6 @@
-
+
org.qbittorrent.qBittorrent
CC0-1.0
GPL-3.0-or-later and OpenSSL
@@ -14,12 +14,33 @@
- Polished µTorrent-like User Interface
- - Well-integrated and extensible Search Engine
+ -
+ Well-integrated and extensible Search Engine
+
+ - Simultaneous search in many Torrent search sites
+ - Category-specific search requests (e.g. Books, Music, Software)
+
+
- RSS feed support with advanced download filters (incl. regex)
- - Many Bittorrent extensions supported
+ -
+ Many Bittorrent extensions supported:
+
+ - Magnet links
+ - Distributed hash table (DHT), peer exchange protocol (PEX), local peer discovery (LSD)
+ - Private torrents
+ - Encrypted connections
+ - and many more...
+
+
- Remote control through Web user interface, written with AJAX
- Sequential downloading (Download in order)
- - Advanced control over torrents, trackers and peers
+ -
+ Advanced control over torrents, trackers and peers
+
+ - Torrents queueing and prioritizing
+ - Torrent content selection and prioritizing
+
+
- Bandwidth scheduler
- Torrent creation tool
- IP Filtering (eMule & PeerGuardian format compatible)
@@ -32,36 +53,27 @@
org.qbittorrent.qBittorrent.desktop
- Main window (General tab collapsed)
- https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/1.webp
+ https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_01.png
- Main window (General tab expanded)
- https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/2.webp
+ https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_02.png
- Options dialog
- https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/3.webp
+ https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_03.png
- Search engine
- https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/4.webp
+ https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_04.png
sledgehammer999@qbittorrent.org
-
- The qBittorrent Project
-
+ The qBittorrent Project
https://www.qbittorrent.org/
https://bugs.qbittorrent.org/
- https://wiki.qbittorrent.org/Frequently-Asked-Questions
- https://forum.qbittorrent.org/
https://www.qbittorrent.org/donate
- https://wiki.qbittorrent.org/How-to-translate-qBittorrent
- https://github.com/qbittorrent/qBittorrent
- https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md
+ https://forum.qbittorrent.org/
+ https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent
-
+
diff --git a/dist/unix/org.qbittorrent.qBittorrent.desktop b/dist/unix/org.qbittorrent.qBittorrent.desktop
index 1b71eb024..cb9e814cb 100644
--- a/dist/unix/org.qbittorrent.qBittorrent.desktop
+++ b/dist/unix/org.qbittorrent.qBittorrent.desktop
@@ -14,220 +14,216 @@ Keywords=bittorrent;torrent;magnet;download;p2p;
SingleMainWindow=true
# Translations
-GenericName[af]=BitTorrent kliënt
Comment[af]=Aflaai en deel lêers oor BitTorrent
+GenericName[af]=BitTorrent kliënt
Name[af]=qBittorrent
-GenericName[ar]=عميل بتتورنت
Comment[ar]=نزّل وشارك الملفات عبر كيوبتتورنت
+GenericName[ar]=عميل بتتورنت
Name[ar]=qBittorrent
-GenericName[be]=Кліент BitTorrent
Comment[be]=Спампоўванне і раздача файлаў праз пратакол BitTorrent
+GenericName[be]=Кліент BitTorrent
Name[be]=qBittorrent
-GenericName[bg]=BitTorrent клиент
Comment[bg]=Сваляне и споделяне на файлове чрез BitTorrent
+GenericName[bg]=BitTorrent клиент
Name[bg]=qBittorrent
-GenericName[bn]=বিটটরেন্ট ক্লায়েন্ট
Comment[bn]=বিটটরেন্টে ফাইল ডাউনলোড এবং শেয়ার করুন
+GenericName[bn]=বিটটরেন্ট ক্লায়েন্ট
Name[bn]=qBittorrent
-GenericName[zh]=BitTorrent 客户端
Comment[zh]=通过 BitTorrent 下载和分享文件
+GenericName[zh]=BitTorrent 客户端
Name[zh]=qBittorrent
-GenericName[bs]=BitTorrent klijent
Comment[bs]=Preuzmi i dijeli datoteke preko BitTorrent-a
+GenericName[bs]=BitTorrent klijent
Name[bs]=qBittorrent
-GenericName[ca]=Client de BitTorrent
Comment[ca]=Baixeu i compartiu fitxers amb el BitTorrent
+GenericName[ca]=Client de BitTorrent
Name[ca]=qBittorrent
-GenericName[cs]=BitTorrent klient
Comment[cs]=Stahování a sdílení souborů přes síť BitTorrent
+GenericName[cs]=BitTorrent klient
Name[cs]=qBittorrent
-GenericName[da]=BitTorrent-klient
Comment[da]=Download og del filer over BitTorrent
+GenericName[da]=BitTorrent-klient
Name[da]=qBittorrent
-GenericName[de]=BitTorrent Client
Comment[de]=Über BitTorrent Dateien herunterladen und teilen
+GenericName[de]=BitTorrent Client
Name[de]=qBittorrent
-GenericName[el]=BitTorrent client
Comment[el]=Κάντε λήψη και μοιραστείτε αρχεία μέσω BitTorrent
+GenericName[el]=BitTorrent client
Name[el]=qBittorrent
-GenericName[en_GB]=BitTorrent client
Comment[en_GB]=Download and share files over BitTorrent
+GenericName[en_GB]=BitTorrent client
Name[en_GB]=qBittorrent
-GenericName[es]=Cliente BitTorrent
Comment[es]=Descargue y comparta archivos por BitTorrent
+GenericName[es]=Cliente BitTorrent
Name[es]=qBittorrent
-GenericName[et]=BitTorrent klient
Comment[et]=Lae alla ja jaga faile üle BitTorrenti
+GenericName[et]=BitTorrent klient
Name[et]=qBittorrent
-GenericName[eu]=BitTorrent bezeroa
Comment[eu]=Jeitsi eta elkarbanatu agiriak BitTorrent bidez
+GenericName[eu]=BitTorrent bezeroa
Name[eu]=qBittorrent
-GenericName[fa]=بیت تورنت نسخه کلاینت
Comment[fa]=دانلود و به اشتراک گذاری فایل های بوسیله بیت تورنت
+GenericName[fa]=بیت تورنت نسخه کلاینت
Name[fa]=qBittorrent
-GenericName[fi]=BitTorrent-asiakasohjelma
Comment[fi]=Lataa ja jaa tiedostoja BitTorrentia käyttäen
+GenericName[fi]=BitTorrent-asiakasohjelma
Name[fi]=qBittorrent
-GenericName[fr]=Client BitTorrent
Comment[fr]=Télécharger et partager des fichiers sur BitTorrent
+GenericName[fr]=Client BitTorrent
Name[fr]=qBittorrent
-GenericName[gl]=Cliente BitTorrent
Comment[gl]=Descargar e compartir ficheiros co protocolo BitTorrent
+GenericName[gl]=Cliente BitTorrent
Name[gl]=qBittorrent
-GenericName[gu]=બિટ્ટોરેંટ ક્લાયન્ટ
Comment[gu]=બિટ્ટોરેંટ પર ફાઈલો ડાઉનલોડ અને શેર કરો
+GenericName[gu]=બિટ્ટોરેંટ ક્લાયન્ટ
Name[gu]=qBittorrent
-GenericName[he]=לקוח ביטורנט
Comment[he]=הורד ושתף קבצים על גבי ביטורנט
+GenericName[he]=לקוח ביטורנט
Name[he]=qBittorrent
-GenericName[hr]=BitTorrent klijent
Comment[hr]=Preuzmite i dijelite datoteke putem BitTorrenta
+GenericName[hr]=BitTorrent klijent
Name[hr]=qBittorrent
-GenericName[hu]=BitTorrent kliens
Comment[hu]=Fájlok letöltése és megosztása a BitTorrent hálózaton keresztül
+GenericName[hu]=BitTorrent kliens
Name[hu]=qBittorrent
-GenericName[hy]=BitTorrent սպասառու
Comment[hy]=Նիշքերի փոխանցում BitTorrent-ի միջոցով
+GenericName[hy]=BitTorrent սպասառու
Name[hy]=qBittorrent
-GenericName[id]=Klien BitTorrent
Comment[id]=Unduh dan berbagi berkas melalui BitTorrent
+GenericName[id]=Klien BitTorrent
Name[id]=qBittorrent
-GenericName[is]=BitTorrent biðlarar
Comment[is]=Sækja og deila skrám yfir BitTorrent
+GenericName[is]=BitTorrent biðlarar
Name[is]=qBittorrent
-GenericName[it]=Client BitTorrent
Comment[it]=Scarica e condividi file tramite BitTorrent
+GenericName[it]=Client BitTorrent
Name[it]=qBittorrent
-GenericName[ja]=BitTorrentクライアント
Comment[ja]=BitTorrentでファイルのダウンロードと共有
+GenericName[ja]=BitTorrentクライアント
Name[ja]=qBittorrent
-GenericName[ka]=BitTorrent კლიენტი
Comment[ka]=გადმოტვირთეთ და გააზიარეთ ფაილები BitTorrent-ის საშუალებით
+GenericName[ka]=BitTorrent კლიენტი
Name[ka]=qBittorrent
+Comment[ko]=BitTorrent를 통한 파일 내려받기 및 공유
GenericName[ko]=BitTorrent 클라이언트
-Comment[ko]=BitTorrent를 통해 파일 다운로드 및 공유
Name[ko]=qBittorrent
-GenericName[lt]=BitTorrent klientas
Comment[lt]=Atsisiųskite bei dalinkitės failais BitTorrent tinkle
+GenericName[lt]=BitTorrent klientas
Name[lt]=qBittorrent
-GenericName[mk]=BitTorrent клиент
Comment[mk]=Превземајте и споделувајте фајлови преку BitTorrent
+GenericName[mk]=BitTorrent клиент
Name[mk]=qBittorrent
-GenericName[my]=တောရန့်စီမံခန့်ခွဲသည့်အရာ
Comment[my]=တောရန့်ဖြင့်ဖိုင်များဒေါင်းလုဒ်ဆွဲရန်နှင့်မျှဝေရန်
+GenericName[my]=တောရန့်စီမံခန့်ခွဲသည့်အရာ
Name[my]=qBittorrent
-GenericName[nb]=BitTorrent-klient
Comment[nb]=Last ned og del filer over BitTorrent
+GenericName[nb]=BitTorrent-klient
Name[nb]=qBittorrent
-GenericName[nl]=BitTorrent-client
Comment[nl]=Bestanden downloaden en delen via BitTorrent
+GenericName[nl]=BitTorrent-client
Name[nl]=qBittorrent
-GenericName[pl]=Klient BitTorrent
Comment[pl]=Pobieraj i dziel się plikami przez BitTorrent
+GenericName[pl]=Klient BitTorrent
Name[pl]=qBittorrent
-GenericName[pt]=Cliente BitTorrent
Comment[pt]=Transferir e partilhar ficheiros por BitTorrent
+GenericName[pt]=Cliente BitTorrent
Name[pt]=qBittorrent
-GenericName[pt_BR]=Cliente BitTorrent
Comment[pt_BR]=Baixe e compartilhe arquivos pelo BitTorrent
+GenericName[pt_BR]=Cliente BitTorrent
Name[pt_BR]=qBittorrent
-GenericName[ro]=Client BitTorrent
Comment[ro]=Descărcați și partajați fișiere prin BitTorrent
+GenericName[ro]=Client BitTorrent
Name[ro]=qBittorrent
-GenericName[ru]=Клиент сети БитТоррент
Comment[ru]=Обмен файлами по сети БитТоррент
+GenericName[ru]=Клиент сети БитТоррент
Name[ru]=qBittorrent
-GenericName[sk]=Klient siete BitTorrent
Comment[sk]=Sťahovanie a zdieľanie súborov prostredníctvom siete BitTorrent
+GenericName[sk]=Klient siete BitTorrent
Name[sk]=qBittorrent
-GenericName[sl]=BitTorrent odjemalec
Comment[sl]=Prenesite in delite datoteke preko BitTorrenta
+GenericName[sl]=BitTorrent odjemalec
Name[sl]=qBittorrent
-GenericName[sq]=Klienti BitTorrent
-Comment[sq]=Shkarko dhe shpërndaj skedarë në BitTorrent
Name[sq]=qBittorrent
-GenericName[sr]=BitTorrent клијент
-Comment[sr]=Преузимајте и делите фајлове преко BitTorrent-а
+Comment[sr]=Преузимајте и делите фајлове преко BitTorrent протокола
+GenericName[sr]=BitTorrent-клијент
Name[sr]=qBittorrent
-GenericName[sr@latin]=BitTorrent klijent
Comment[sr@latin]=Preuzimanje i deljenje fajlova preko BitTorrent-a
+GenericName[sr@latin]=BitTorrent klijent
Name[sr@latin]=qBittorrent
-GenericName[sv]=BitTorrent-klient
Comment[sv]=Hämta och dela filer över BitTorrent
+GenericName[sv]=BitTorrent-klient
Name[sv]=qBittorrent
-GenericName[ta]=BitTorrent வாடிக்கையாளர்
Comment[ta]=BitTorrent வழியாக கோப்புகளை பதிவிறக்க மற்றும் பகிர
+GenericName[ta]=BitTorrent வாடிக்கையாளர்
Name[ta]=qBittorrent
-GenericName[te]=క్యు బిట్ టొరెంట్ క్లయింట్
Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి
+GenericName[te]=క్యు బిట్ టొరెంట్ క్లయింట్
Name[te]=qBittorrent
-GenericName[th]=ไคลเอนต์บิททอร์เรนต์
-Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่านบิตทอร์เรนต์
+Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่าน BitTorrent
+GenericName[th]=โปรแกรมบิททอเร้นท์
Name[th]=qBittorrent
-GenericName[tr]=BitTorrent istemcisi
Comment[tr]=Dosyaları BitTorrent üzerinden indirin ve paylaşın
+GenericName[tr]=BitTorrent istemcisi
Name[tr]=qBittorrent
-GenericName[ur]=قیو بٹ ٹورنٹ کلائنٹ
Comment[ur]=BitTorrent پر فائلوں کو ڈاؤن لوڈ کریں اور اشتراک کریں
+GenericName[ur]=قیو بٹ ٹورنٹ کلائنٹ
Name[ur]=qBittorrent
-GenericName[uk]=BitTorrent-клієнт
Comment[uk]=Завантажуйте та поширюйте файли через BitTorrent
+GenericName[uk]=BitTorrent-клієнт
Name[uk]=qBittorrent
-GenericName[vi]=Máy khách BitTorrent
Comment[vi]=Tải xuống và chia sẻ tệp qua BitTorrent
+GenericName[vi]=Máy khách BitTorrent
Name[vi]=qBittorrent
-GenericName[zh_HK]=BitTorrent用戶端
Comment[zh_HK]=經由BitTorrent下載並分享檔案
+GenericName[zh_HK]=BitTorrent用戶端
Name[zh_HK]=qBittorrent
+Comment[zh_TW]=經由 BitTorrent 下載並分享檔案
GenericName[zh_TW]=BitTorrent 用戶端
-Comment[zh_TW]=使用 BitTorrent 下載並分享檔案
Name[zh_TW]=qBittorrent
-GenericName[eo]=BitTorrent-kliento
Comment[eo]=Elŝutu kaj kunhavigu dosierojn per BitTorrent
+GenericName[eo]=BitTorrent-kliento
Name[eo]=qBittorrent
-GenericName[kk]=BitTorrent клиенті
Comment[kk]=BitTorrent арқылы файл жүктеу және бөлісу
+GenericName[kk]=BitTorrent клиенті
Name[kk]=qBittorrent
-GenericName[en_AU]=BitTorrent client
Comment[en_AU]=Download and share files over BitTorrent
+GenericName[en_AU]=BitTorrent client
Name[en_AU]=qBittorrent
Name[rm]=qBittorrent
Name[jv]=qBittorrent
-GenericName[oc]=Client BitTorrent
Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent
+GenericName[oc]=Client BitTorrent
Name[oc]=qBittorrent
Name[ug]=qBittorrent
Name[yi]=qBittorrent
-GenericName[nqo]=ߓߌߙߏߙߍ߲ߕ ߕߣߐ߬ߓߐ߬ߟߊ
Comment[nqo]=ߞߐߕߐ߯ߘߐ ߟߎ߬ ߟߊߖߌ߰ ߞߊ߬ ߓߊ߲߫ ߞߵߊ߬ߟߎ߬ ߘߐߕߟߊ߫ ߓߌߙߏߙߍ߲ߕ ߞߊ߲߬
+GenericName[nqo]=ߓߌߙߏߙߍ߲ߕ ߕߣߐ߬ߓߐ߬ߟߊ
Name[nqo]=qBittorrent
-GenericName[uz@Latn]=BitTorrent mijozi
Comment[uz@Latn]=BitTorrent orqali fayllarni yuklab olish va baham ko‘rish
+GenericName[uz@Latn]=BitTorrent mijozi
Name[uz@Latn]=qBittorrent
-GenericName[ltg]=BitTorrent klients
Comment[ltg]=Atsasyuteit i daleit failus ar BitTorrent
+GenericName[ltg]=BitTorrent klients
Name[ltg]=qBittorrent
-GenericName[hi_IN]=Bittorrent साधन
Comment[hi_IN]=BitTorrent द्वारा फाइल डाउनलोड व सहभाजन
+GenericName[hi_IN]=Bittorrent साधन
Name[hi_IN]=qBittorrent
-GenericName[az@latin]=BitTorrent client
Comment[az@latin]=Faylları BitTorrent vasitəsilə endirin və paylaşın
+GenericName[az@latin]=BitTorrent client
Name[az@latin]=qBittorrent
-GenericName[lv_LV]=BitTorrent klients
Comment[lv_LV]=Lejupielādēt un koplietot failus ar BitTorrent
+GenericName[lv_LV]=BitTorrent klients
Name[lv_LV]=qBittorrent
-GenericName[ms_MY]=Klien BitTorrent
Comment[ms_MY]=Muat turun dan kongsi fail melalui BitTorrent
+GenericName[ms_MY]=Klien BitTorrent
Name[ms_MY]=qBittorrent
-GenericName[mn_MN]=BitTorrent татагч
Comment[mn_MN]=BitTorrent-оор файлуудаа тат, түгээ
+GenericName[mn_MN]=BitTorrent татагч
Name[mn_MN]=qBittorrent
-GenericName[ne_NP]=BitTorrent क्लाइन्ट
Comment[ne_NP]=फाइलहरू डाउनलोड गर्नुहोस् र BitTorrent मा साझा गर्नुहोस्
+GenericName[ne_NP]=BitTorrent क्लाइन्ट
Name[ne_NP]=qBittorrent
-GenericName[pt_PT]=Cliente BitTorrent
Comment[pt_PT]=Transferir e partilhar ficheiros por BitTorrent
+GenericName[pt_PT]=Cliente BitTorrent
Name[pt_PT]=qBittorrent
-GenericName[si_LK]=BitTorrent සේවාදායකයා
-Comment[si_LK]=BitTorrent හරහා ගොනු බාගත කර බෙදාගන්න.
Name[si_LK]=qBittorrent
diff --git a/dist/windows/config.nsh b/dist/windows/config.nsh
index 19558c1d6..658262782 100644
--- a/dist/windows/config.nsh
+++ b/dist/windows/config.nsh
@@ -14,7 +14,7 @@
; 4.5.1.3 -> good
; 4.5.1.3.2 -> bad
; 4.5.0beta -> bad
-!define /ifndef QBT_VERSION "5.2.0"
+!define /ifndef QBT_VERSION "5.0.0"
; Option that controls the installer's window name
; If set, its value will be used like this:
@@ -86,7 +86,7 @@ OutFile "qbittorrent_${QBT_INSTALLER_FILENAME}_setup.exe"
;Installer Version Information
VIAddVersionKey "ProductName" "qBittorrent"
VIAddVersionKey "CompanyName" "The qBittorrent project"
-VIAddVersionKey "LegalCopyright" "Copyright ©2006-2025 The qBittorrent project"
+VIAddVersionKey "LegalCopyright" "Copyright ©2006-2024 The qBittorrent project"
VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client"
VIAddVersionKey "FileVersion" "${QBT_VERSION}"
@@ -111,8 +111,7 @@ RequestExecutionLevel user
!define MUI_HEADERIMAGE
!define MUI_COMPONENTSPAGE_NODESC
;!define MUI_ICON "qbittorrent.ico"
-!define MUI_LICENSEPAGE_BUTTON $(^NextBtn)
-!define MUI_LICENSEPAGE_TEXT_BOTTOM "$_CLICK"
+!define MUI_LICENSEPAGE_CHECKBOX
!define MUI_LANGDLL_ALLLANGUAGES
;--------------------------------
diff --git a/dist/windows/gather_qt_translations.py b/dist/windows/gather_qt_translations.py
index cfa212c8c..d1ff44499 100644
--- a/dist/windows/gather_qt_translations.py
+++ b/dist/windows/gather_qt_translations.py
@@ -7,11 +7,9 @@ import shutil
import sys
from typing import List
-
def isNotStub(path: str) -> bool:
return (os.path.getsize(path) >= (10 * 1024))
-
def main() -> int:
parser = argparse.ArgumentParser(description='Gather valid Qt translations for NSIS packaging.')
parser.add_argument("qt_translations_folder", help="Qt's translations folder")
@@ -29,6 +27,5 @@ def main() -> int:
return 0
-
if __name__ == '__main__':
sys.exit(main())
diff --git a/dist/windows/installer-translations/italian.nsh b/dist/windows/installer-translations/italian.nsh
index 2668dc5ca..a63024b01 100644
--- a/dist/windows/installer-translations/italian.nsh
+++ b/dist/windows/installer-translations/italian.nsh
@@ -29,7 +29,7 @@ LangString launch_qbt ${LANG_ITALIAN} "Esegui qBittorrent."
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_ITALIAN} "Questo installer funziona solo con versioni di Windows a 64bit."
;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
-LangString inst_requires_win10 ${LANG_ITALIAN} "Questo installer richiede almeno Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ITALIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_ITALIAN} "Disinstalla qBittorrent"
diff --git a/dist/windows/installer-translations/luxembourgish.nsh b/dist/windows/installer-translations/luxembourgish.nsh
index 4a30e954a..b866e3c93 100644
--- a/dist/windows/installer-translations/luxembourgish.nsh
+++ b/dist/windows/installer-translations/luxembourgish.nsh
@@ -15,7 +15,7 @@ LangString inst_magnet ${LANG_LUXEMBOURGISH} "Magnet-Linken mat qBittorrent opma
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_LUXEMBOURGISH} "Reegel an der Windows Firewall dobäisetzen"
;LangString inst_pathlimit ${LANG_ENGLISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
-LangString inst_pathlimit ${LANG_LUXEMBOURGISH} "D'Windows path length (Padlängtbeschränkung) desaktivéieren (260 Zeechen MAX_PATH Beschränkung, erfuerdert min. Windows 10 1607)"
+LangString inst_pathlimit ${LANG_LUXEMBOURGISH} "D'Windows path lenght (Padlängtbeschränkung) desaktivéieren (260 Zeechen MAX_PATH Beschränkung, erfuerdert min. Windows 10 1607)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_LUXEMBOURGISH} "Reegel an der Windows Firewall dobäisetzen"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
diff --git a/dist/windows/installer-translations/portuguese.nsh b/dist/windows/installer-translations/portuguese.nsh
index c149119f4..b067b00da 100644
--- a/dist/windows/installer-translations/portuguese.nsh
+++ b/dist/windows/installer-translations/portuguese.nsh
@@ -7,7 +7,7 @@ LangString inst_desktop ${LANG_PORTUGUESE} "Criar atalho no ambiente de trabalho
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_PORTUGUESE} "Criar atalho no menu Iniciar"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
-LangString inst_startup ${LANG_PORTUGUESE} "Iniciar o qBittorrent no arranque do Windows"
+LangString inst_startup ${LANG_PORTUGUESE} "Iniciar o qBittorrent na inicialização do Windows"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_PORTUGUESE} "Abrir ficheiros .torrent com o qBittorrent"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
@@ -29,7 +29,7 @@ LangString launch_qbt ${LANG_PORTUGUESE} "Iniciar qBittorrent."
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_PORTUGUESE} "Este instalador funciona apenas em versões Windows de 64 bits."
;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
-LangString inst_requires_win10 ${LANG_PORTUGUESE} "Este instalador requer, pelo menos, o Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_PORTUGUESE} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_PORTUGUESE} "Desinstalar qBittorrent"
diff --git a/dist/windows/installer-translations/simpchinese.nsh b/dist/windows/installer-translations/simpchinese.nsh
index f0256e046..42744b0d0 100644
--- a/dist/windows/installer-translations/simpchinese.nsh
+++ b/dist/windows/installer-translations/simpchinese.nsh
@@ -23,13 +23,13 @@ LangString inst_warning ${LANG_SIMPCHINESE} "qBittorrent 正在运行。 安装
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_SIMPCHINESE} "当前版本会被卸载。 用户设置和种子会被完整保留。"
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
-LangString inst_unist ${LANG_SIMPCHINESE} "正在卸载以前的版本。"
+LangString inst_unist ${LANG_SIMPCHINESE} "卸载以前的版本。"
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
LangString launch_qbt ${LANG_SIMPCHINESE} "启动 qBittorrent。"
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_SIMPCHINESE} "此安装程序仅支持 64 位 Windows 系统。"
;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
-LangString inst_requires_win10 ${LANG_SIMPCHINESE} "此安装程序仅支持 Windows 10 (1809) / Windows Server 2019 或更新的系统。"
+LangString inst_requires_win10 ${LANG_SIMPCHINESE} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SIMPCHINESE} "卸载 qBittorrent"
diff --git a/dist/windows/installer-translations/swedish.nsh b/dist/windows/installer-translations/swedish.nsh
index 51912d112..77db60683 100644
--- a/dist/windows/installer-translations/swedish.nsh
+++ b/dist/windows/installer-translations/swedish.nsh
@@ -7,21 +7,21 @@ LangString inst_desktop ${LANG_SWEDISH} "Skapa skrivbordsgenväg"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_SWEDISH} "Skapa startmenygenväg"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
-LangString inst_startup ${LANG_SWEDISH} "Starta qBittorrent vid Windows-uppstart"
+LangString inst_startup ${LANG_SWEDISH} "Starta qBittorrent vid Windows start"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_SWEDISH} "Öppna .torrent-filer med qBittorrent"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
LangString inst_magnet ${LANG_SWEDISH} "Öppna magnetlänkar med qBittorrent"
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
-LangString inst_firewall ${LANG_SWEDISH} "Lägg till Windows-brandväggsregel"
+LangString inst_firewall ${LANG_SWEDISH} "Lägg till Windows-brandväggregel"
;LangString inst_pathlimit ${LANG_ENGLISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
LangString inst_pathlimit ${LANG_SWEDISH} "Inaktivera gränsen för Windows-sökvägslängd (260 tecken MAX_PATH-begränsning, kräver Windows 10 1607 eller senare)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
-LangString inst_firewallinfo ${LANG_SWEDISH} "Lägger till Windows-brandväggsregel"
+LangString inst_firewallinfo ${LANG_SWEDISH} "Lägger till Windows-brandväggregel"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
-LangString inst_warning ${LANG_SWEDISH} "qBittorrent körs. Stäng programmet innan du installerar."
+LangString inst_warning ${LANG_SWEDISH} "qBittorrent körs. Vänligen stäng programmet innan du installerar."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
-LangString inst_uninstall_question ${LANG_SWEDISH} "Aktuell version avinstalleras. Användarinställningar och torrenter kommer att förbli intakta."
+LangString inst_uninstall_question ${LANG_SWEDISH} "Nuvarande version avinstalleras. Användarinställningar och torrenter kommer att förbli intakta."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_SWEDISH} "Avinstallerar tidigare version."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
@@ -53,7 +53,7 @@ LangString remove_firewallinfo ${LANG_SWEDISH} "Tar bort Windows-brandväggsrege
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
LangString remove_cache ${LANG_SWEDISH} "Ta bort torrenter och cachade data"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
-LangString uninst_warning ${LANG_SWEDISH} "qBittorrent körs. Stäng programmet innan du avinstallerar."
+LangString uninst_warning ${LANG_SWEDISH} "qBittorrent körs. Vänligen stäng programmet innan du avinstallerar."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_SWEDISH} "Tar inte bort .torrent-association. Den är associerad med:"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
diff --git a/dist/windows/installer-translations/tradchinese.nsh b/dist/windows/installer-translations/tradchinese.nsh
index 49bcff874..cfacc6d92 100644
--- a/dist/windows/installer-translations/tradchinese.nsh
+++ b/dist/windows/installer-translations/tradchinese.nsh
@@ -29,7 +29,7 @@ LangString launch_qbt ${LANG_TRADCHINESE} "啟動 qBittorrent"
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_TRADCHINESE} "此安裝程式僅支援 64 位元版本的 Windows。"
;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
-LangString inst_requires_win10 ${LANG_TRADCHINESE} "此安裝程式僅支援 Windows 10 (1809) / Windows Server 2019 以上的系統。"
+LangString inst_requires_win10 ${LANG_TRADCHINESE} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_TRADCHINESE} "移除 qBittorrent"
diff --git a/doc/en/qbittorrent-nox.1 b/doc/en/qbittorrent-nox.1
index 3b9830fc1..7d1ee0dd1 100644
--- a/doc/en/qbittorrent-nox.1
+++ b/doc/en/qbittorrent-nox.1
@@ -1,44 +1,41 @@
-.\" Automatically generated by Pandoc 3.7.0.2
+.\" Automatically generated by Pandoc 3.1.7
.\"
-.TH "QBITTORRENT\-NOX" "1" "January 16th 2010" "Command line Bittorrent client written in C++ / Qt"
+.TH "QBITTORRENT-NOX" "1" "January 16th 2010" "Command line Bittorrent client written in C++ / Qt" ""
.SH NAME
-qBittorrent\-nox \- a command line Bittorrent client written in C++ / Qt
+qBittorrent-nox - a command line Bittorrent client written in C++ / Qt
.SH SYNOPSIS
-\f[B]qbittorrent\-nox\f[R]
-\f[CR][\-\-d|\-\-daemon] [\-\-webui\-port=x] [TORRENT_FILE | URL]...\f[R]
+\f[B]qbittorrent-nox\f[R]
+\f[CR][--d|--daemon] [--webui-port=x] [TORRENT_FILE | URL]...\f[R]
.PP
-\f[B]qbittorrent\-nox\f[R] \f[CR]\-\-help\f[R]
+\f[B]qbittorrent-nox\f[R] \f[CR]--help\f[R]
.PP
-\f[B]qbittorrent\-nox\f[R] \f[CR]\-\-version\f[R]
+\f[B]qbittorrent-nox\f[R] \f[CR]--version\f[R]
.SH DESCRIPTION
-\f[B]qBittorrent\-nox\f[R] is an advanced command\-line Bittorrent
-client written in C++ / Qt using the \f[B]libtorrent\-rasterbar\f[R]
-library by Arvid Norberg.
-qBittorrent\-nox aims to be a good alternative to other command line
+\f[B]qBittorrent-nox\f[R] is an advanced command-line Bittorrent client
+written in C++ / Qt using the \f[B]libtorrent-rasterbar\f[R] library by
+Arvid Norberg.
+qBittorrent-nox aims to be a good alternative to other command line
bittorrent clients and provides features similar to popular graphical
clients.
.PP
-qBittorrent\-nox is fast, stable, light and it supports unicode.
-It also comes with UPnP port forwarding / NAT\-PMP, encryption (Vuze
+qBittorrent-nox is fast, stable, light and it supports unicode.
+It also comes with UPnP port forwarding / NAT-PMP, encryption (Vuze
compatible), FAST extension (mainline) and PeX support (utorrent
compatible).
.PP
-qBittorrent\-nox is meant to be controlled via its feature\-rich Web UI
+qBittorrent-nox is meant to be controlled via its feature-rich Web UI
which is accessible as a default on http://localhost:8080.
The Web UI access is secured and the default account user name is
-\(lqadmin\(rq with \(lqadminadmin\(rq as a password.
+\[lq]admin\[rq] with \[lq]adminadmin\[rq] as a password.
.SH OPTIONS
-\f[B]\f[CB]\-\-help\f[B]\f[R] Prints the command line options.
+\f[B]\f[CB]--help\f[B]\f[R] Prints the command line options.
.PP
-\f[B]\f[CB]\-\-version\f[B]\f[R] Prints qbittorrent program version
+\f[B]\f[CB]--version\f[B]\f[R] Prints qbittorrent program version
number.
.PP
-\f[B]\f[CB]\-\-webui\-port=x\f[B]\f[R] Changes Web UI port to x
-(default: 8080).
+\f[B]\f[CB]--webui-port=x\f[B]\f[R] Changes Web UI port to x (default:
+8080).
.SH BUGS
If you find a bug, please report it at https://bugs.qbittorrent.org
.SH AUTHORS
-Christophe Dumez \c
-.MT chris@qbittorrent.org
-.ME \c
-\&.
+Christophe Dumez .
diff --git a/doc/en/qbittorrent.1 b/doc/en/qbittorrent.1
index 7c304be93..4efca9e0d 100644
--- a/doc/en/qbittorrent.1
+++ b/doc/en/qbittorrent.1
@@ -1,38 +1,35 @@
-.\" Automatically generated by Pandoc 3.7.0.2
+.\" Automatically generated by Pandoc 3.1.7
.\"
-.TH "QBITTORRENT" "1" "January 16th 2010" "Bittorrent client written in C++ / Qt"
+.TH "QBITTORRENT" "1" "January 16th 2010" "Bittorrent client written in C++ / Qt" ""
.SH NAME
-qBittorrent \- a Bittorrent client written in C++ / Qt
+qBittorrent - a Bittorrent client written in C++ / Qt
.SH SYNOPSIS
\f[B]qbittorrent\f[R]
-\f[CR][\-\-no\-splash] [\-\-webui\-port=x] [TORRENT_FILE | URL]...\f[R]
+\f[CR][--no-splash] [--webui-port=x] [TORRENT_FILE | URL]...\f[R]
.PP
-\f[B]qbittorrent\f[R] \f[CR]\-\-help\f[R]
+\f[B]qbittorrent\f[R] \f[CR]--help\f[R]
.PP
-\f[B]qbittorrent\f[R] \f[CR]\-\-version\f[R]
+\f[B]qbittorrent\f[R] \f[CR]--version\f[R]
.SH DESCRIPTION
\f[B]qBittorrent\f[R] is an advanced Bittorrent client written in C++ /
-Qt, using the \f[B]libtorrent\-rasterbar\f[R] library by Arvid Norberg.
+Qt, using the \f[B]libtorrent-rasterbar\f[R] library by Arvid Norberg.
qBittorrent is similar to uTorrent.
qBittorrent is fast, stable, light, it supports unicode and it provides
a good integrated search engine.
-It also comes with UPnP port forwarding / NAT\-PMP, encryption (Vuze
+It also comes with UPnP port forwarding / NAT-PMP, encryption (Vuze
compatible), FAST extension (mainline) and PeX support (utorrent
compatible).
.SH OPTIONS
-\f[B]\f[CB]\-\-help\f[B]\f[R] Prints the command line options.
+\f[B]\f[CB]--help\f[B]\f[R] Prints the command line options.
.PP
-\f[B]\f[CB]\-\-version\f[B]\f[R] Prints qbittorrent program version
+\f[B]\f[CB]--version\f[B]\f[R] Prints qbittorrent program version
number.
.PP
-\f[B]\f[CB]\-\-no\-splash\f[B]\f[R] Disables splash screen on startup.
+\f[B]\f[CB]--no-splash\f[B]\f[R] Disables splash screen on startup.
.PP
-\f[B]\f[CB]\-\-webui\-port=x\f[B]\f[R] Changes Web UI port to x
-(default: 8080).
+\f[B]\f[CB]--webui-port=x\f[B]\f[R] Changes Web UI port to x (default:
+8080).
.SH BUGS
If you find a bug, please report it at https://bugs.qbittorrent.org
.SH AUTHORS
-Christophe Dumez \c
-.MT chris@qbittorrent.org
-.ME \c
-\&.
+Christophe Dumez .
diff --git a/doc/ru/qbittorrent-nox.1 b/doc/ru/qbittorrent-nox.1
index 122716e44..ba8713bae 100644
--- a/doc/ru/qbittorrent-nox.1
+++ b/doc/ru/qbittorrent-nox.1
@@ -1,10 +1,7 @@
-.\" Automatically generated by Pandoc 3.7.0.2
+.\" Automatically generated by Pandoc 3.1.7
.\"
-.TH "QBITTORRENT\-NOX" "1" "16 января 2010" "Клиент сети БитТоррент для командной строки"
+.TH "QBITTORRENT-NOX" "1" "16 января 2010" "Клиент сети БитТоррент для командной строки" ""
.SH НАЗВАНИЕ
-qBittorrent\-nox \(em клиент сети БитТоррент для командной строки.
+qBittorrent-nox \[em] клиент сети БитТоррент для командной строки.
.SH АВТОРЫ
-Christophe Dumez \c
-.MT chris@qbittorrent.org
-.ME \c
-\&.
+Christophe Dumez .
diff --git a/doc/ru/qbittorrent.1 b/doc/ru/qbittorrent.1
index 1d4f54a2c..2fc395ddd 100644
--- a/doc/ru/qbittorrent.1
+++ b/doc/ru/qbittorrent.1
@@ -1,10 +1,7 @@
-.\" Automatically generated by Pandoc 3.7.0.2
+.\" Automatically generated by Pandoc 3.1.7
.\"
-.TH "QBITTORRENT" "1" "16 января 2010" "Клиент сети БитТоррент"
+.TH "QBITTORRENT" "1" "16 января 2010" "Клиент сети БитТоррент" ""
.SH НАЗВАНИЕ
-qBittorrent \(em клиент сети БитТоррент.
+qBittorrent \[em] клиент сети БитТоррент.
.SH АВТОРЫ
-Christophe Dumez \c
-.MT chris@qbittorrent.org
-.ME \c
-\&.
+Christophe Dumez .
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 4c007ce1e..b5174aa45 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -86,19 +86,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
PROPERTIES
MACOSX_PACKAGE_LOCATION Resources
)
- # Generate lproj folders for the translations
- foreach(TS_FILE IN LISTS QBT_TS_FILES)
- string(FIND "${TS_FILE}" "_" POS)
- math(EXPR START "${POS} + 1")
- string(SUBSTRING "${TS_FILE}" ${START} -1 LPROJ_FOLDER)
- string(REPLACE ".ts" ".lproj" LPROJ_FOLDER "${LPROJ_FOLDER}")
- # @ is not valid as a language code for a lproj folder on MacOS
- string(REPLACE "@" "-" LPROJ_FOLDER "${LPROJ_FOLDER}")
- add_custom_command(TARGET qbt_app POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory
- "$/../Resources/${LPROJ_FOLDER}"
- )
- endforeach()
# provide variables for substitution in dist/mac/Info.plist
get_target_property(EXECUTABLE_NAME qbt_app OUTPUT_NAME)
# This variable name should be changed once qmake is no longer used. Refer to the discussion in PR #14813
diff --git a/src/app/application.cpp b/src/app/application.cpp
index da09211bd..bfb925915 100644
--- a/src/app/application.cpp
+++ b/src/app/application.cpp
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
- * Copyright (C) 2015-2025 Vladimir Golovnev
+ * Copyright (C) 2015 Vladimir Golovnev
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -124,28 +124,6 @@ namespace
const int PIXMAP_CACHE_SIZE = 64 * 1024 * 1024; // 64MiB
#endif
- const QString PARAM_ADDSTOPPED = u"@addStopped"_s;
- const QString PARAM_CATEGORY = u"@category"_s;
- const QString PARAM_FIRSTLASTPIECEPRIORITY = u"@firstLastPiecePriority"_s;
- const QString PARAM_SAVEPATH = u"@savePath"_s;
- const QString PARAM_SEQUENTIAL = u"@sequential"_s;
- const QString PARAM_SKIPCHECKING = u"@skipChecking"_s;
- const QString PARAM_SKIPDIALOG = u"@skipDialog"_s;
-
- QString bindParamValue(const QStringView paramName, const QStringView paramValue)
- {
- return paramName + u'=' + paramValue;
- }
-
- std::pair parseParam(const QStringView param)
- {
- const qsizetype sepIndex = param.indexOf(u'=');
- if (sepIndex >= 0)
- return {param.first(sepIndex), param.sliced(sepIndex + 1)};
-
- return {param, {}};
- }
-
QString serializeParams(const QBtCommandLineParameters ¶ms)
{
QStringList result;
@@ -160,86 +138,85 @@ namespace
const BitTorrent::AddTorrentParams &addTorrentParams = params.addTorrentParams;
if (!addTorrentParams.savePath.isEmpty())
- result.append(bindParamValue(PARAM_SAVEPATH, addTorrentParams.savePath.data()));
+ result.append(u"@savePath=" + addTorrentParams.savePath.data());
- if (addTorrentParams.addStopped.has_value())
- result.append(bindParamValue(PARAM_ADDSTOPPED, (*addTorrentParams.addStopped ? u"1" : u"0")));
+ if (addTorrentParams.addPaused.has_value())
+ result.append(*addTorrentParams.addPaused ? u"@addPaused=1"_s : u"@addPaused=0"_s);
if (addTorrentParams.skipChecking)
- result.append(PARAM_SKIPCHECKING);
+ result.append(u"@skipChecking"_s);
if (!addTorrentParams.category.isEmpty())
- result.append(bindParamValue(PARAM_CATEGORY, addTorrentParams.category));
+ result.append(u"@category=" + addTorrentParams.category);
if (addTorrentParams.sequential)
- result.append(PARAM_SEQUENTIAL);
+ result.append(u"@sequential"_s);
if (addTorrentParams.firstLastPiecePriority)
- result.append(PARAM_FIRSTLASTPIECEPRIORITY);
+ result.append(u"@firstLastPiecePriority"_s);
if (params.skipDialog.has_value())
- result.append(bindParamValue(PARAM_SKIPDIALOG, (*params.skipDialog ? u"1" : u"0")));
+ result.append(*params.skipDialog ? u"@skipDialog=1"_s : u"@skipDialog=0"_s);
result += params.torrentSources;
return result.join(PARAMS_SEPARATOR);
}
- QBtCommandLineParameters parseParams(const QStringView str)
+ QBtCommandLineParameters parseParams(const QString &str)
{
QBtCommandLineParameters parsedParams;
BitTorrent::AddTorrentParams &addTorrentParams = parsedParams.addTorrentParams;
- for (QStringView param : asConst(str.split(PARAMS_SEPARATOR, Qt::SkipEmptyParts)))
+ for (QString param : asConst(str.split(PARAMS_SEPARATOR, Qt::SkipEmptyParts)))
{
param = param.trimmed();
- const auto [paramName, paramValue] = parseParam(param);
// Process strings indicating options specified by the user.
- if (paramName == PARAM_SAVEPATH)
+ if (param.startsWith(u"@savePath="))
{
- addTorrentParams.savePath = Path(paramValue.toString());
+ addTorrentParams.savePath = Path(param.mid(10));
continue;
}
- if (paramName == PARAM_ADDSTOPPED)
+ if (param.startsWith(u"@addPaused="))
{
- addTorrentParams.addStopped = (paramValue.toInt() != 0);
+ addTorrentParams.addPaused = (QStringView(param).mid(11).toInt() != 0);
continue;
}
- if (paramName == PARAM_SKIPCHECKING)
+ if (param == u"@skipChecking")
{
addTorrentParams.skipChecking = true;
continue;
}
- if (paramName == PARAM_CATEGORY)
+ if (param.startsWith(u"@category="))
{
- addTorrentParams.category = paramValue.toString();
+ addTorrentParams.category = param.mid(10);
continue;
}
- if (paramName == PARAM_SEQUENTIAL)
+ if (param == u"@sequential")
{
addTorrentParams.sequential = true;
continue;
}
- if (paramName == PARAM_FIRSTLASTPIECEPRIORITY)
+ if (param == u"@firstLastPiecePriority")
{
addTorrentParams.firstLastPiecePriority = true;
continue;
}
- if (paramName == PARAM_SKIPDIALOG)
+ if (param.startsWith(u"@skipDialog="))
{
- parsedParams.skipDialog = (paramValue.toInt() != 0);
+ parsedParams.skipDialog = (QStringView(param).mid(12).toInt() != 0);
continue;
}
- parsedParams.torrentSources.append(param.toString());
+ parsedParams.torrentSources.append(param);
}
return parsedParams;
@@ -274,7 +251,6 @@ Application::Application(int &argc, char **argv)
#if !defined(DISABLE_GUI)
setDesktopFileName(u"org.qbittorrent.qBittorrent"_s);
setQuitOnLastWindowClosed(false);
- setQuitLockEnabled(false);
QPixmapCache::setCacheLimit(PIXMAP_CACHE_SIZE);
#endif
@@ -410,7 +386,7 @@ void Application::setMemoryWorkingSetLimit(const int size)
return;
m_storeMemoryWorkingSetLimit = size;
-#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_LINUX) && !defined(Q_OS_MACOS)
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
applyMemoryWorkingSetLimit();
#endif
}
@@ -575,9 +551,6 @@ void Application::runExternalProgram(const QString &programTemplate, const BitTo
case u'L':
str.replace(i, 2, torrent->category());
break;
- case u'M':
- str.replace(i, 2, torrent->comment());
- break;
case u'N':
str.replace(i, 2, torrent->name());
break;
@@ -605,7 +578,7 @@ void Application::runExternalProgram(const QString &programTemplate, const BitTo
const QString logMsg = tr("Running external program. Torrent: \"%1\". Command: `%2`");
const QString logMsgError = tr("Failed to run external program. Torrent: \"%1\". Command: `%2`");
- // The processing sequence is different for Windows and other OS, this is intentional
+ // The processing sequenece is different for Windows and other OS, this is intentional
#if defined(Q_OS_WIN)
const QString program = replaceVariables(programTemplate);
const std::wstring programWStr = program.toStdWString();
@@ -662,13 +635,7 @@ void Application::runExternalProgram(const QString &programTemplate, const BitTo
{
// strip redundant quotes
if (arg.startsWith(u'"') && arg.endsWith(u'"'))
- {
-#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
- arg.slice(1, (arg.size() - 2));
-#else
- arg.removeLast().removeFirst();
-#endif
- }
+ arg = arg.mid(1, (arg.size() - 2));
arg = replaceVariables(arg);
}
@@ -677,7 +644,6 @@ void Application::runExternalProgram(const QString &programTemplate, const BitTo
QProcess proc;
proc.setProgram(command);
proc.setArguments(args);
- proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
if (proc.startDetached())
{
@@ -847,7 +813,7 @@ int Application::exec()
printf("%s\n", qUtf8Printable(loadingStr));
#endif
-#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_LINUX) && !defined(Q_OS_MACOS)
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
applyMemoryWorkingSetLimit();
#endif
@@ -866,7 +832,7 @@ int Application::exec()
m_desktopIntegration = new DesktopIntegration;
m_desktopIntegration->setToolTip(tr("Loading torrents..."));
#ifndef Q_OS_MACOS
- auto *desktopIntegrationMenu = m_desktopIntegration->menu();
+ auto *desktopIntegrationMenu = new QMenu;
auto *actionExit = new QAction(tr("E&xit"), desktopIntegrationMenu);
actionExit->setIcon(UIThemeManager::instance()->getIcon(u"application-exit"_s));
actionExit->setMenuRole(QAction::QuitRole);
@@ -877,6 +843,8 @@ int Application::exec()
});
desktopIntegrationMenu->addAction(actionExit);
+ m_desktopIntegration->setMenu(desktopIntegrationMenu);
+
const bool isHidden = m_desktopIntegration->isActive() && (startUpWindowState() == WindowState::Hidden);
#else
const bool isHidden = false;
@@ -930,10 +898,10 @@ int Application::exec()
m_desktopIntegration->showNotification(tr("Torrent added"), tr("'%1' was added.", "e.g: xxx.avi was added.").arg(torrent->name()));
});
connect(m_addTorrentManager, &AddTorrentManager::addTorrentFailed, this
- , [this](const QString &source, const BitTorrent::AddTorrentError &reason)
+ , [this](const QString &source, const QString &reason)
{
m_desktopIntegration->showNotification(tr("Add torrent failed")
- , tr("Couldn't add torrent '%1', reason: %2.").arg(source, reason.message));
+ , tr("Couldn't add torrent '%1', reason: %2.").arg(source, reason));
});
disconnect(m_desktopIntegration, &DesktopIntegration::activationRequested, this, &Application::createStartupProgressDialog);
@@ -1205,7 +1173,7 @@ void Application::shutdownCleanup([[maybe_unused]] QSessionManager &manager)
}
#endif
-#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_LINUX) && !defined(Q_OS_MACOS)
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
void Application::applyMemoryWorkingSetLimit() const
{
const size_t MiB = 1024 * 1024;
diff --git a/src/app/cmdoptions.cpp b/src/app/cmdoptions.cpp
index 5ed6e4865..582426044 100644
--- a/src/app/cmdoptions.cpp
+++ b/src/app/cmdoptions.cpp
@@ -36,7 +36,6 @@
#include
#include
#include
-#include
#if defined(Q_OS_WIN) && !defined(DISABLE_GUI)
#include
@@ -61,7 +60,7 @@ namespace
class Option
{
protected:
- explicit constexpr Option(const QStringView name, const QChar shortcut = QChar::Null)
+ explicit constexpr Option(const char *name, char shortcut = 0)
: m_name {name}
, m_shortcut {shortcut}
{
@@ -69,23 +68,23 @@ namespace
QString fullParameter() const
{
- return u"--" + m_name.toString();
+ return u"--" + QString::fromLatin1(m_name);
}
QString shortcutParameter() const
{
- return u"-" + m_shortcut;
+ return u"-" + QChar::fromLatin1(m_shortcut);
}
bool hasShortcut() const
{
- return !m_shortcut.isNull();
+ return m_shortcut != 0;
}
QString envVarName() const
{
return u"QBT_"
- + m_name.toString().toUpper().replace(u'-', u'_');
+ + QString::fromLatin1(m_name).toUpper().replace(u'-', u'_');
}
public:
@@ -100,15 +99,15 @@ namespace
}
private:
- const QStringView m_name;
- const QChar m_shortcut;
+ const char *m_name = nullptr;
+ const char m_shortcut;
};
// Boolean option.
class BoolOption : protected Option
{
public:
- explicit constexpr BoolOption(const QStringView name, const QChar shortcut = QChar::Null)
+ explicit constexpr BoolOption(const char *name, char shortcut = 0)
: Option {name, shortcut}
{
}
@@ -140,8 +139,8 @@ namespace
struct StringOption : protected Option
{
public:
- explicit constexpr StringOption(const QStringView name)
- : Option {name, QChar::Null}
+ explicit constexpr StringOption(const char *name)
+ : Option {name, 0}
{
}
@@ -182,7 +181,7 @@ namespace
class IntOption : protected StringOption
{
public:
- explicit constexpr IntOption(const QStringView name)
+ explicit constexpr IntOption(const char *name)
: StringOption {name}
{
}
@@ -230,8 +229,8 @@ namespace
class TriStateBoolOption : protected Option
{
public:
- constexpr TriStateBoolOption(const QStringView name, const bool defaultValue)
- : Option {name, QChar::Null}
+ constexpr TriStateBoolOption(const char *name, bool defaultValue)
+ : Option {name, 0}
, m_defaultValue(defaultValue)
{
}
@@ -264,8 +263,8 @@ namespace
}
throw CommandLineParameterError(QCoreApplication::translate("CMD Options", "Parameter '%1' must follow syntax '%1=%2'",
- "e.g. Parameter '--add-stopped' must follow syntax "
- "'--add-stopped='")
+ "e.g. Parameter '--add-paused' must follow syntax "
+ "'--add-paused='")
.arg(fullParameter(), u""_s));
}
@@ -300,32 +299,31 @@ namespace
return arg.section(u'=', 0, 0) == option.fullParameter();
}
- private:
- bool m_defaultValue = false;
+ bool m_defaultValue;
};
- constexpr const BoolOption SHOW_HELP_OPTION {u"help", u'h'};
+ constexpr const BoolOption SHOW_HELP_OPTION {"help", 'h'};
#if !defined(Q_OS_WIN) || defined(DISABLE_GUI)
- constexpr const BoolOption SHOW_VERSION_OPTION {u"version", u'v'};
+ constexpr const BoolOption SHOW_VERSION_OPTION {"version", 'v'};
#endif
- constexpr const BoolOption CONFIRM_LEGAL_NOTICE {u"confirm-legal-notice"};
+ constexpr const BoolOption CONFIRM_LEGAL_NOTICE {"confirm-legal-notice"};
#if defined(DISABLE_GUI) && !defined(Q_OS_WIN)
- constexpr const BoolOption DAEMON_OPTION {u"daemon", u'd'};
+ constexpr const BoolOption DAEMON_OPTION {"daemon", 'd'};
#else
- constexpr const BoolOption NO_SPLASH_OPTION {u"no-splash"};
+ constexpr const BoolOption NO_SPLASH_OPTION {"no-splash"};
#endif
- constexpr const IntOption WEBUI_PORT_OPTION {u"webui-port"};
- constexpr const IntOption TORRENTING_PORT_OPTION {u"torrenting-port"};
- constexpr const StringOption PROFILE_OPTION {u"profile"};
- constexpr const StringOption CONFIGURATION_OPTION {u"configuration"};
- constexpr const BoolOption RELATIVE_FASTRESUME {u"relative-fastresume"};
- constexpr const StringOption SAVE_PATH_OPTION {u"save-path"};
- constexpr const TriStateBoolOption STOPPED_OPTION {u"add-stopped", true};
- constexpr const BoolOption SKIP_HASH_CHECK_OPTION {u"skip-hash-check"};
- constexpr const StringOption CATEGORY_OPTION {u"category"};
- constexpr const BoolOption SEQUENTIAL_OPTION {u"sequential"};
- constexpr const BoolOption FIRST_AND_LAST_OPTION {u"first-and-last"};
- constexpr const TriStateBoolOption SKIP_DIALOG_OPTION {u"skip-dialog", true};
+ constexpr const IntOption WEBUI_PORT_OPTION {"webui-port"};
+ constexpr const IntOption TORRENTING_PORT_OPTION {"torrenting-port"};
+ constexpr const StringOption PROFILE_OPTION {"profile"};
+ constexpr const StringOption CONFIGURATION_OPTION {"configuration"};
+ constexpr const BoolOption RELATIVE_FASTRESUME {"relative-fastresume"};
+ constexpr const StringOption SAVE_PATH_OPTION {"save-path"};
+ constexpr const TriStateBoolOption PAUSED_OPTION {"add-paused", true};
+ constexpr const BoolOption SKIP_HASH_CHECK_OPTION {"skip-hash-check"};
+ constexpr const StringOption CATEGORY_OPTION {"category"};
+ constexpr const BoolOption SEQUENTIAL_OPTION {"sequential"};
+ constexpr const BoolOption FIRST_AND_LAST_OPTION {"first-and-last"};
+ constexpr const TriStateBoolOption SKIP_DIALOG_OPTION {"skip-dialog", true};
}
QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &env)
@@ -347,7 +345,7 @@ QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &en
addTorrentParams.skipChecking = SKIP_HASH_CHECK_OPTION.value(env);
addTorrentParams.sequential = SEQUENTIAL_OPTION.value(env);
addTorrentParams.firstLastPiecePriority = FIRST_AND_LAST_OPTION.value(env);
- addTorrentParams.addStopped = STOPPED_OPTION.value(env);
+ addTorrentParams.addPaused = PAUSED_OPTION.value(env);
}
QBtCommandLineParameters parseCommandLine(const QStringList &args)
@@ -419,9 +417,9 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
{
result.addTorrentParams.savePath = Path(SAVE_PATH_OPTION.value(arg));
}
- else if (arg == STOPPED_OPTION)
+ else if (arg == PAUSED_OPTION)
{
- result.addTorrentParams.addStopped = STOPPED_OPTION.value(arg);
+ result.addTorrentParams.addPaused = PAUSED_OPTION.value(arg);
}
else if (arg == SKIP_HASH_CHECK_OPTION)
{
@@ -465,13 +463,13 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
return result;
}
-QString wrapText(const QString &text, const int initialIndentation = USAGE_TEXT_COLUMN, const int wrapAtColumn = WRAP_AT_COLUMN)
+QString wrapText(const QString &text, int initialIndentation = USAGE_TEXT_COLUMN, int wrapAtColumn = WRAP_AT_COLUMN)
{
- const QStringList words = text.split(u' ');
+ QStringList words = text.split(u' ');
QStringList lines = {words.first()};
int currentLineMaxLength = wrapAtColumn - initialIndentation;
- for (const QString &word : asConst(words.sliced(1)))
+ for (const QString &word : asConst(words.mid(1)))
{
if (lines.last().length() + word.length() + 1 < currentLineMaxLength)
{
@@ -491,12 +489,6 @@ QString makeUsage(const QString &prgName)
{
const QString indentation {USAGE_INDENTATION, u' '};
-#if defined(Q_OS_WIN)
- const QString noSplashCommand = u"set QBT_NO_SPLASH=1 && " + prgName;
-#else
- const QString noSplashCommand = u"QBT_NO_SPLASH=1 " + prgName;
-#endif
-
const QString text = QCoreApplication::translate("CMD Options", "Usage:") + u'\n'
+ indentation + prgName + u' ' + QCoreApplication::translate("CMD Options", "[options] [( | )...]") + u'\n'
@@ -531,7 +523,7 @@ QString makeUsage(const QString &prgName)
+ wrapText(QCoreApplication::translate("CMD Options", "Options when adding new torrents:"), 0) + u'\n'
+ SAVE_PATH_OPTION.usage(QCoreApplication::translate("CMD Options", "path")) + wrapText(QCoreApplication::translate("CMD Options", "Torrent save path")) + u'\n'
- + STOPPED_OPTION.usage() + wrapText(QCoreApplication::translate("CMD Options", "Add torrents as running or stopped")) + u'\n'
+ + PAUSED_OPTION.usage() + wrapText(QCoreApplication::translate("CMD Options", "Add torrents as started or paused")) + u'\n'
+ SKIP_HASH_CHECK_OPTION.usage() + wrapText(QCoreApplication::translate("CMD Options", "Skip hash check")) + u'\n'
+ CATEGORY_OPTION.usage(QCoreApplication::translate("CMD Options", "name"))
+ wrapText(QCoreApplication::translate("CMD Options", "Assign torrents to category. If the category doesn't exist, it will be "
@@ -548,7 +540,7 @@ QString makeUsage(const QString &prgName)
"'parameter-name', environment variable name is 'QBT_PARAMETER_NAME' (in upper "
"case, '-' replaced with '_'). To pass flag values, set the variable to '1' or "
"'TRUE'. For example, to disable the splash screen: "), 0) + u'\n'
- + noSplashCommand + u'\n'
+ + u"QBT_NO_SPLASH=1 " + prgName + u'\n'
+ wrapText(QCoreApplication::translate("CMD Options", "Command line parameters take precedence over environment variables"), 0) + u'\n';
return text;
diff --git a/src/app/filelogger.cpp b/src/app/filelogger.cpp
index 4c83c16a1..e0cafbb7e 100644
--- a/src/app/filelogger.cpp
+++ b/src/app/filelogger.cpp
@@ -32,8 +32,8 @@
#include
#include
-#include
#include
+#include
#include "base/global.h"
#include "base/logger.h"
@@ -175,15 +175,12 @@ void FileLogger::flushLog()
void FileLogger::openLogFile()
{
- if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
+ if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)
+ || !m_logFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner))
{
- LogMsg(tr("An error occurred while trying to open the log file. Logging to file is disabled. File: \"%1\". Error: \"%2\".")
- .arg(m_logFile.fileName(), m_logFile.errorString()), Log::CRITICAL);
- return;
+ m_logFile.close();
+ LogMsg(tr("An error occurred while trying to open the log file. Logging to file is disabled."), Log::CRITICAL);
}
-
- // best effort, don't report error
- m_logFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
}
void FileLogger::closeLogFile()
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 21730827f..53455f99b 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
- * Copyright (C) 2014-2024 Vladimir Golovnev
+ * Copyright (C) 2014-2023 Vladimir Golovnev
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -58,6 +58,10 @@
#include
#include
+#ifdef Q_OS_WIN
+#include
+#endif
+
#ifdef QBT_STATIC_QT
#include
Q_IMPORT_PLUGIN(QICOPlugin)
@@ -182,6 +186,14 @@ int main(int argc, char *argv[])
adjustFileDescriptorLimit();
#endif
+ // We must save it here because QApplication constructor may change it
+ const bool isOneArg = (argc == 2);
+
+#if !defined(DISABLE_GUI) && defined(Q_OS_WIN)
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10)
+ QApplication::setStyle(u"Fusion"_s);
+#endif
+
// `app` must be declared out of try block to allow display message box in case of exception
std::unique_ptr app;
try
@@ -201,27 +213,34 @@ int main(int argc, char *argv[])
#endif
const QBtCommandLineParameters params = app->commandLineArgs();
-
- // "show help/version" takes priority over other flags
- if (params.showHelp)
- {
- displayUsage(QString::fromLocal8Bit(argv[0]));
- return EXIT_SUCCESS;
- }
-#if !defined(Q_OS_WIN) || defined(DISABLE_GUI)
- if (params.showVersion)
- {
- displayVersion();
- return EXIT_SUCCESS;
- }
-#endif
-
if (!params.unknownParameter.isEmpty())
{
throw CommandLineParameterError(QCoreApplication::translate("Main", "%1 is an unknown command line parameter.",
"--random-parameter is an unknown command line parameter.")
.arg(params.unknownParameter));
}
+#if !defined(Q_OS_WIN) || defined(DISABLE_GUI)
+ if (params.showVersion)
+ {
+ if (isOneArg)
+ {
+ displayVersion();
+ return EXIT_SUCCESS;
+ }
+ throw CommandLineParameterError(QCoreApplication::translate("Main", "%1 must be the single command line parameter.")
+ .arg(u"-v (or --version)"_s));
+ }
+#endif
+ if (params.showHelp)
+ {
+ if (isOneArg)
+ {
+ displayUsage(QString::fromLocal8Bit(argv[0]));
+ return EXIT_SUCCESS;
+ }
+ throw CommandLineParameterError(QCoreApplication::translate("Main", "%1 must be the single command line parameter.")
+ .arg(u"-h (or --help)"_s));
+ }
// Check if qBittorrent is already running
if (app->hasAnotherInstance())
diff --git a/src/app/qtlocalpeer/qtlocalpeer.cpp b/src/app/qtlocalpeer/qtlocalpeer.cpp
index cc97eb464..2ad65f31a 100644
--- a/src/app/qtlocalpeer/qtlocalpeer.cpp
+++ b/src/app/qtlocalpeer/qtlocalpeer.cpp
@@ -74,7 +74,6 @@
#include
#endif
-#include
#include
#include
#include
@@ -91,7 +90,7 @@ namespace QtLP_Private
#endif
}
-const QByteArray ACK = QByteArrayLiteral("ack");
+const char ACK[] = "ack";
QtLocalPeer::QtLocalPeer(const QString &path, QObject *parent)
: QObject(parent)
@@ -170,7 +169,7 @@ bool QtLocalPeer::sendMessage(const QString &message, const int timeout)
{
res &= socket.waitForReadyRead(timeout); // wait for ack
if (res)
- res &= (socket.read(ACK.size()) == ACK);
+ res &= (socket.read(qstrlen(ACK)) == ACK);
}
return res;
}
@@ -221,7 +220,7 @@ void QtLocalPeer::receiveConnection()
return;
}
QString message(QString::fromUtf8(uMsg));
- socket->write(ACK);
+ socket->write(ACK, qstrlen(ACK));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
diff --git a/src/app/qtlocalpeer/qtlockedfile.h b/src/app/qtlocalpeer/qtlockedfile.h
index 3ea32c61a..63d78aaec 100644
--- a/src/app/qtlocalpeer/qtlockedfile.h
+++ b/src/app/qtlocalpeer/qtlockedfile.h
@@ -71,8 +71,8 @@
#include
#ifdef Q_OS_WIN
-#include
#include
+#include
#endif
namespace QtLP_Private
@@ -105,7 +105,7 @@ namespace QtLP_Private
Qt::HANDLE m_writeMutex = nullptr;
Qt::HANDLE m_readMutex = nullptr;
- QList m_readMutexes;
+ QVector m_readMutexes;
QString m_mutexName;
#endif
diff --git a/src/app/upgrade.cpp b/src/app/upgrade.cpp
index 5a9d9b896..45d129dcf 100644
--- a/src/app/upgrade.cpp
+++ b/src/app/upgrade.cpp
@@ -46,7 +46,7 @@
namespace
{
- const int MIGRATION_VERSION = 8;
+ const int MIGRATION_VERSION = 7;
const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_s;
void exportWebUIHttpsFiles()
@@ -468,16 +468,6 @@ namespace
settingsStorage->removeValue(oldKey);
}
-
- void migrateAddPausedSetting()
- {
- auto *settingsStorage = SettingsStorage::instance();
- const auto oldKey = u"BitTorrent/Session/AddTorrentPaused"_s;
- const auto newKey = u"BitTorrent/Session/AddTorrentStopped"_s;
-
- settingsStorage->storeValue(newKey, settingsStorage->loadValue(oldKey));
- settingsStorage->removeValue(oldKey);
- }
}
bool upgrade()
@@ -519,9 +509,6 @@ bool upgrade()
if (version < 7)
migrateShareLimitActionSettings();
- if (version < 8)
- migrateAddPausedSetting();
-
version = MIGRATION_VERSION;
}
diff --git a/src/base/3rdparty/expected.hpp b/src/base/3rdparty/expected.hpp
index 305f3abad..a1ddc6f0e 100644
--- a/src/base/3rdparty/expected.hpp
+++ b/src/base/3rdparty/expected.hpp
@@ -13,8 +13,8 @@
#define NONSTD_EXPECTED_LITE_HPP
#define expected_lite_MAJOR 0
-#define expected_lite_MINOR 8
-#define expected_lite_PATCH 0
+#define expected_lite_MINOR 6
+#define expected_lite_PATCH 3
#define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH)
@@ -66,21 +66,6 @@
# define nsel_P0323R 7
#endif
-// Monadic operations proposal revisions:
-//
-// P2505R0: 0 (2021-12-12)
-// P2505R1: 1 (2022-02-10)
-// P2505R2: 2 (2022-04-15)
-// P2505R3: 3 (2022-06-05)
-// P2505R4: 4 (2022-06-15)
-// P2505R5: 5 (2022-09-20) *
-//
-// expected-lite uses 5
-
-#ifndef nsel_P2505R
-# define nsel_P2505R 5
-#endif
-
// Control presence of C++ exception handling (try and auto discover):
#ifndef nsel_CONFIG_NO_EXCEPTIONS
@@ -231,24 +216,8 @@ inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_pla
namespace nonstd {
using std::expected;
- using std::unexpected;
- using std::bad_expected_access;
- using std::unexpect_t;
- using std::unexpect;
-
- //[[deprecated("replace unexpected_type with unexpected")]]
-
- template< typename E >
- using unexpected_type = unexpected;
-
- // Unconditionally provide make_unexpected():
-
- template< typename E>
- constexpr auto make_unexpected( E && value ) -> unexpected< typename std::decay::type >
- {
- return unexpected< typename std::decay::type >( std::forward(value) );
- }
-} // namespace nonstd
+// ...
+}
#else // nsel_USES_STD_EXPECTED
@@ -347,6 +316,16 @@ namespace nonstd {
#define nsel_REQUIRES_A(...) \
, typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr
+// Presence of language and library features:
+
+#ifdef _HAS_CPP0X
+# define nsel_HAS_CPP0X _HAS_CPP0X
+#else
+# define nsel_HAS_CPP0X 0
+#endif
+
+//#define nsel_CPP11_140 (nsel_CPP11_OR_GREATER || nsel_COMPILER_MSVC_VER >= 1900)
+
// Clang, GNUC, MSVC warning suppression macros:
#ifdef __clang__
@@ -356,23 +335,20 @@ namespace nonstd {
#endif // __clang__
#if nsel_COMPILER_MSVC_VERSION >= 140
-# define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(push) ) __pragma( warning(disable: codes) )
+# pragma warning( push )
+# define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(disable: codes) )
#else
# define nsel_DISABLE_MSVC_WARNINGS(codes)
#endif
#ifdef __clang__
-# define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")
-# define nsel_RESTORE_MSVC_WARNINGS()
+# define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")
#elif defined __GNUC__
-# define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
-# define nsel_RESTORE_MSVC_WARNINGS()
+# define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
#elif nsel_COMPILER_MSVC_VERSION >= 140
-# define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) )
-# define nsel_RESTORE_MSVC_WARNINGS() nsel_RESTORE_WARNINGS()
+# define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) )
#else
# define nsel_RESTORE_WARNINGS()
-# define nsel_RESTORE_MSVC_WARNINGS()
#endif
// Suppress the following MSVC (GSL) warnings:
@@ -380,30 +356,6 @@ namespace nonstd {
nsel_DISABLE_MSVC_WARNINGS( 26409 )
-// Presence of language and library features:
-
-#ifdef _HAS_CPP0X
-# define nsel_HAS_CPP0X _HAS_CPP0X
-#else
-# define nsel_HAS_CPP0X 0
-#endif
-
-// Presence of language and library features:
-
-#define nsel_CPP17_000 (nsel_CPP17_OR_GREATER)
-
-// Presence of C++17 language features:
-
-#define nsel_HAVE_DEPRECATED nsel_CPP17_000
-
-// C++ feature usage:
-
-#if nsel_HAVE_DEPRECATED
-# define nsel_deprecated(msg) [[deprecated(msg)]]
-#else
-# define nsel_deprecated(msg) /*[[deprecated]]*/
-#endif
-
//
// expected:
//
@@ -500,162 +452,8 @@ class expected;
namespace detail {
-#if nsel_P2505R >= 3
-template< typename T >
-struct is_expected : std::false_type {};
-
-template< typename T, typename E >
-struct is_expected< expected< T, E > > : std::true_type {};
-#endif // nsel_P2505R >= 3
-
/// discriminated union to hold value or 'error'.
-template< typename T, typename E >
-class storage_t_noncopy_nonmove_impl
-{
- template< typename, typename > friend class nonstd::expected_lite::expected;
-
-public:
- using value_type = T;
- using error_type = E;
-
- // no-op construction
- storage_t_noncopy_nonmove_impl() {}
- ~storage_t_noncopy_nonmove_impl() {}
-
- explicit storage_t_noncopy_nonmove_impl( bool has_value )
- : m_has_value( has_value )
- {}
-
- void construct_value()
- {
- new( &m_value ) value_type();
- }
-
- // void construct_value( value_type const & e )
- // {
- // new( &m_value ) value_type( e );
- // }
-
- // void construct_value( value_type && e )
- // {
- // new( &m_value ) value_type( std::move( e ) );
- // }
-
- template< class... Args >
- void emplace_value( Args&&... args )
- {
- new( &m_value ) value_type( std::forward(args)...);
- }
-
- template< class U, class... Args >
- void emplace_value( std::initializer_list il, Args&&... args )
- {
- new( &m_value ) value_type( il, std::forward(args)... );
- }
-
- void destruct_value()
- {
- m_value.~value_type();
- }
-
- // void construct_error( error_type const & e )
- // {
- // // new( &m_error ) error_type( e );
- // }
-
- // void construct_error( error_type && e )
- // {
- // // new( &m_error ) error_type( std::move( e ) );
- // }
-
- template< class... Args >
- void emplace_error( Args&&... args )
- {
- new( &m_error ) error_type( std::forward(args)...);
- }
-
- template< class U, class... Args >
- void emplace_error( std::initializer_list il, Args&&... args )
- {
- new( &m_error ) error_type( il, std::forward(args)... );
- }
-
- void destruct_error()
- {
- m_error.~error_type();
- }
-
- constexpr value_type const & value() const &
- {
- return m_value;
- }
-
- value_type & value() &
- {
- return m_value;
- }
-
- constexpr value_type const && value() const &&
- {
- return std::move( m_value );
- }
-
- nsel_constexpr14 value_type && value() &&
- {
- return std::move( m_value );
- }
-
- value_type const * value_ptr() const
- {
- return &m_value;
- }
-
- value_type * value_ptr()
- {
- return &m_value;
- }
-
- error_type const & error() const &
- {
- return m_error;
- }
-
- error_type & error() &
- {
- return m_error;
- }
-
- constexpr error_type const && error() const &&
- {
- return std::move( m_error );
- }
-
- nsel_constexpr14 error_type && error() &&
- {
- return std::move( m_error );
- }
-
- bool has_value() const
- {
- return m_has_value;
- }
-
- void set_has_value( bool v )
- {
- m_has_value = v;
- }
-
-private:
- union
- {
- value_type m_value;
- error_type m_error;
- };
-
- bool m_has_value = false;
-};
-
template< typename T, typename E >
class storage_t_impl
{
@@ -673,11 +471,6 @@ public:
: m_has_value( has_value )
{}
- void construct_value()
- {
- new( &m_value ) value_type();
- }
-
void construct_value( value_type const & e )
{
new( &m_value ) value_type( e );
@@ -891,23 +684,16 @@ private:
template< typename T, typename E, bool isConstructable, bool isMoveable >
class storage_t
{
-public:
-};
-
-template< typename T, typename E >
-class storage_t : public storage_t_noncopy_nonmove_impl
-{
public:
storage_t() = default;
~storage_t() = default;
explicit storage_t( bool has_value )
- : storage_t_noncopy_nonmove_impl( has_value )
+ : storage_t_impl( has_value )
{}
storage_t( storage_t const & other ) = delete;
storage_t( storage_t && other ) = delete;
-
};
template< typename T, typename E >
@@ -1046,146 +832,6 @@ public:
}
};
-#if nsel_P2505R >= 3
-// C++11 invoke implementation
-template< typename >
-struct is_reference_wrapper : std::false_type {};
-template< typename T >
-struct is_reference_wrapper< std::reference_wrapper< T > > : std::true_type {};
-
-template< typename FnT, typename ClassT, typename ObjectT, typename... Args
- nsel_REQUIRES_T(
- std::is_function::value
- && ( std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
- || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value )
- )
->
-nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args )
- noexcept( noexcept( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ) ) )
- -> decltype( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )...) )
-{
- return (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... );
-}
-
-template< typename FnT, typename ClassT, typename ObjectT, typename... Args
- nsel_REQUIRES_T(
- std::is_function::value
- && is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value
- )
->
-nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args )
- noexcept( noexcept( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) )
- -> decltype( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) )
-{
- return (obj.get().*memfnptr)( std::forward< Args >( args ) ... );
-}
-
-template< typename FnT, typename ClassT, typename ObjectT, typename... Args
- nsel_REQUIRES_T(
- std::is_function::value
- && !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
- && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
- && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value
- )
->
-nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args )
- noexcept( noexcept( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) )
- -> decltype( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) )
-{
- return ((*std::forward(obj)).*memfnptr)( std::forward< Args >( args ) ... );
-}
-
-template< typename MemberT, typename ClassT, typename ObjectT
- nsel_REQUIRES_T(
- std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
- || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
- )
->
-nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj )
- noexcept( noexcept( std::forward< ObjectT >( obj ).*memobjptr ) )
- -> decltype( std::forward< ObjectT >( obj ).*memobjptr )
-{
- return std::forward< ObjectT >( obj ).*memobjptr;
-}
-
-template< typename MemberT, typename ClassT, typename ObjectT
- nsel_REQUIRES_T(
- is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value
- )
->
-nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj )
- noexcept( noexcept( obj.get().*memobjptr ) )
- -> decltype( obj.get().*memobjptr )
-{
- return obj.get().*memobjptr;
-}
-
-template< typename MemberT, typename ClassT, typename ObjectT
- nsel_REQUIRES_T(
- !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
- && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
- && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value
- )
->
-nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj )
- noexcept( noexcept( (*std::forward< ObjectT >( obj )).*memobjptr ) )
- -> decltype( (*std::forward< ObjectT >( obj )).*memobjptr )
-{
- return (*std::forward< ObjectT >( obj )).*memobjptr;
-}
-
-template< typename F, typename... Args
- nsel_REQUIRES_T(
- std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value
- )
->
-nsel_constexpr auto invoke( F && f, Args && ... args )
- noexcept( noexcept( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) )
- -> decltype( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) )
-{
- return invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... );
-}
-
-template< typename F, typename... Args
- nsel_REQUIRES_T(
- std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value
- )
->
-nsel_constexpr auto invoke( F && f, Args && ... args )
- noexcept( noexcept( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) )
- -> decltype( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) )
-{
- return invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... );
-}
-
-template< typename F, typename... Args
- nsel_REQUIRES_T(
- !std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value
- && !std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value
- )
->
-nsel_constexpr auto invoke( F && f, Args && ... args )
- noexcept( noexcept( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) )
- -> decltype( std::forward< F >( f )( std::forward< Args >( args ) ... ) )
-{
- return std::forward< F >( f )( std::forward< Args >( args ) ... );
-}
-
-template< typename F, typename ... Args >
-using invoke_result_nocvref_t = typename std20::remove_cvref< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type;
-
-#if nsel_P2505R >= 5
-template< typename F, typename ... Args >
-using transform_invoke_result_t = typename std::remove_cv< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type;
-#else
-template< typename F, typename ... Args >
-using transform_invoke_result_t = invoke_result_nocvref_t
-#endif // nsel_P2505R >= 5
-
-template< typename T >
-struct valid_expected_value_type : std::integral_constant< bool, std::is_destructible< T >::value && !std::is_reference< T >::value && !std::is_array< T >::value > {};
-
-#endif // nsel_P2505R >= 3
} // namespace detail
/// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected.
@@ -1252,7 +898,7 @@ public:
)
>
constexpr explicit unexpected_type( unexpected_type const & error )
- : m_error( E{ error.error() } )
+ : m_error( E{ error.value() } )
{}
template< typename E2
@@ -1270,7 +916,7 @@ public:
)
>
constexpr /*non-explicit*/ unexpected_type( unexpected_type const & error )
- : m_error( error.error() )
+ : m_error( error.value() )
{}
template< typename E2
@@ -1288,7 +934,7 @@ public:
)
>
constexpr explicit unexpected_type( unexpected_type && error )
- : m_error( E{ std::move( error.error() ) } )
+ : m_error( E{ std::move( error.value() ) } )
{}
template< typename E2
@@ -1306,7 +952,7 @@ public:
)
>
constexpr /*non-explicit*/ unexpected_type( unexpected_type && error )
- : m_error( std::move( error.error() ) )
+ : m_error( std::move( error.value() ) )
{}
// x.x.5.2.2 Assignment
@@ -1317,54 +963,24 @@ public:
template< typename E2 = E >
nsel_constexpr14 unexpected_type & operator=( unexpected_type const & other )
{
- unexpected_type{ other.error() }.swap( *this );
+ unexpected_type{ other.value() }.swap( *this );
return *this;
}
template< typename E2 = E >
nsel_constexpr14 unexpected_type & operator=( unexpected_type && other )
{
- unexpected_type{ std::move( other.error() ) }.swap( *this );
+ unexpected_type{ std::move( other.value() ) }.swap( *this );
return *this;
}
// x.x.5.2.3 Observers
- nsel_constexpr14 E & error() & noexcept
- {
- return m_error;
- }
-
- constexpr E const & error() const & noexcept
- {
- return m_error;
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
-
- nsel_constexpr14 E && error() && noexcept
- {
- return std::move( m_error );
- }
-
- constexpr E const && error() const && noexcept
- {
- return std::move( m_error );
- }
-
-#endif
-
- // x.x.5.2.3 Observers - deprecated
-
- nsel_deprecated("replace value() with error()")
-
nsel_constexpr14 E & value() & noexcept
{
return m_error;
}
- nsel_deprecated("replace value() with error()")
-
constexpr E const & value() const & noexcept
{
return m_error;
@@ -1372,15 +988,11 @@ public:
#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- nsel_deprecated("replace value() with error()")
-
nsel_constexpr14 E && value() && noexcept
{
return std::move( m_error );
}
- nsel_deprecated("replace value() with error()")
-
constexpr E const && value() const && noexcept
{
return std::move( m_error );
@@ -1469,7 +1081,7 @@ private:
template< typename E1, typename E2 >
constexpr bool operator==( unexpected_type const & x, unexpected_type const & y )
{
- return x.error() == y.error();
+ return x.value() == y.value();
}
template< typename E1, typename E2 >
@@ -1483,7 +1095,7 @@ constexpr bool operator!=( unexpected_type const & x, unexpected_type co
template< typename E >
constexpr bool operator<( unexpected_type const & x, unexpected_type const & y )
{
- return x.error() < y.error();
+ return x.value() < y.value();
}
template< typename E >
@@ -1728,24 +1340,6 @@ struct error_traits< std::error_code >
#endif // nsel_CONFIG_NO_EXCEPTIONS
-#if nsel_P2505R >= 3
-namespace detail {
-
-// from https://en.cppreference.com/w/cpp/utility/expected/unexpected:
-// "the type of the unexpected value. The type must not be an array type, a non-object type, a specialization of std::unexpected, or a cv-qualified type."
-template< typename T >
-struct valid_unexpected_type : std::integral_constant< bool,
- std::is_same< T, typename std20::remove_cvref< T >::type >::value
- && std::is_object< T >::value
- && !std::is_array< T >::value
-> {};
-
-template< typename T >
-struct valid_unexpected_type< unexpected_type< T > > : std::false_type {};
-
-} // namespace detail
-#endif // nsel_P2505R >= 3
-
} // namespace expected_lite
// provide nonstd::unexpected_type:
@@ -1786,7 +1380,7 @@ public:
nsel_constexpr14 expected()
: contained( true )
{
- contained.construct_value();
+ contained.construct_value( value_type() );
}
nsel_constexpr14 expected( expected const & ) = default;
@@ -1940,7 +1534,7 @@ public:
nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error )
: contained( false )
{
- contained.construct_error( E{ error.error() } );
+ contained.construct_error( E{ error.value() } );
}
template< typename G = E
@@ -1952,7 +1546,7 @@ public:
nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error )
: contained( false )
{
- contained.construct_error( error.error() );
+ contained.construct_error( error.value() );
}
template< typename G = E
@@ -1964,7 +1558,7 @@ public:
nsel_constexpr14 explicit expected( nonstd::unexpected_type && error )
: contained( false )
{
- contained.construct_error( E{ std::move( error.error() ) } );
+ contained.construct_error( E{ std::move( error.value() ) } );
}
template< typename G = E
@@ -1976,7 +1570,7 @@ public:
nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error )
: contained( false )
{
- contained.construct_error( std::move( error.error() ) );
+ contained.construct_error( std::move( error.value() ) );
}
// in-place construction, value
@@ -2081,7 +1675,7 @@ public:
>
expected & operator=( nonstd::unexpected_type const & error )
{
- expected( unexpect, error.error() ).swap( *this );
+ expected( unexpect, error.value() ).swap( *this );
return *this;
}
@@ -2094,7 +1688,7 @@ public:
>
expected & operator=( nonstd::unexpected_type && error )
{
- expected( unexpect, std::move( error.error() ) ).swap( *this );
+ expected( unexpect, std::move( error.value() ) ).swap( *this );
return *this;
}
@@ -2197,8 +1791,6 @@ public:
return contained.has_value();
}
- nsel_DISABLE_MSVC_WARNINGS( 4702 ) // warning C4702: unreachable code, see issue 65.
-
constexpr value_type const & value() const &
{
return has_value()
@@ -2212,7 +1804,6 @@ public:
? ( contained.value() )
: ( error_traits::rethrow( contained.error() ), contained.value() );
}
- nsel_RESTORE_MSVC_WARNINGS()
#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
@@ -2294,316 +1885,6 @@ public:
: static_cast( std::forward( v ) );
}
-#if nsel_P2505R >= 4
- template< typename G = E
- nsel_REQUIRES_T(
- std::is_copy_constructible< E >::value
- && std::is_convertible< G, E >::value
- )
- >
- nsel_constexpr error_type error_or( G && e ) const &
- {
- return has_value()
- ? static_cast< E >( std::forward< G >( e ) )
- : contained.error();
- }
-
- template< typename G = E
- nsel_REQUIRES_T(
- std::is_move_constructible< E >::value
- && std::is_convertible< G, E >::value
- )
- >
- nsel_constexpr14 error_type error_or( G && e ) &&
- {
- return has_value()
- ? static_cast< E >( std::forward< G >( e ) )
- : std::move( contained.error() );
- }
-#endif // nsel_P2505R >= 4
-
-#if nsel_P2505R >= 3
- // Monadic operations (P2505)
- template< typename F
- nsel_REQUIRES_T(
- detail::is_expected < detail::invoke_result_nocvref_t< F, value_type & > > ::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type & >::error_type, error_type >::value
- && std::is_constructible< error_type, error_type & >::value
- )
- >
- nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type & > and_then( F && f ) &
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, value_type & >( detail::invoke( std::forward< F >( f ), value() ) )
- : detail::invoke_result_nocvref_t< F, value_type & >( unexpect, error() );
- }
-
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value
- && std::is_constructible< error_type, const error_type & >::value
- )
- >
- nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type & > and_then( F && f ) const &
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, const value_type & >( detail::invoke( std::forward< F >( f ), value() ) )
- : detail::invoke_result_nocvref_t< F, const value_type & >( unexpect, error() );
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type && >::error_type, error_type >::value
- && std::is_constructible< error_type, error_type && >::value
- )
- >
- nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type && > and_then( F && f ) &&
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) )
- : detail::invoke_result_nocvref_t< F, value_type && >( unexpect, std::move( error() ) );
- }
-
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value
- && std::is_constructible< error_type, const error_type && >::value
- )
- >
- nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type && > and_then( F && f ) const &&
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, const value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) )
- : detail::invoke_result_nocvref_t< F, const value_type && >( unexpect, std::move( error() ) );
- }
-#endif
-
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type, value_type >::value
- && std::is_constructible< value_type, value_type & >::value
- )
- >
- nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) &
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, error_type & >( value() )
- : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) );
- }
-
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type, value_type >::value
- && std::is_constructible< value_type, const value_type & >::value
- )
- >
- nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const &
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, const error_type & >( value() )
- : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) );
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type, value_type >::value
- && std::is_constructible< value_type, value_type && >::value
- )
- >
- nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) &&
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, error_type && >( std::move( value() ) )
- : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
- }
-
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type, value_type >::value
- && std::is_constructible< value_type, const value_type && >::value
- )
- >
- nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const &&
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, const error_type && >( std::move( value() ) )
- : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
- }
-#endif
-
- template::value
- && !std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value
- && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type & > >::value
- )
- >
- nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type & >, error_type > transform( F && f ) &
- {
- return has_value()
- ? expected< detail::transform_invoke_result_t< F, value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) )
- : make_unexpected( error() );
- }
-
- template::value
- && std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value
- )
- >
- nsel_constexpr14 expected< void, error_type > transform( F && f ) &
- {
- return has_value()
- ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() )
- : make_unexpected( error() );
- }
-
- template::value
- && !std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value
- && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type & > >::value
- )
- >
- nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type & >, error_type > transform( F && f ) const &
- {
- return has_value()
- ? expected< detail::transform_invoke_result_t< F, const value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) )
- : make_unexpected( error() );
- }
-
- template::value
- && std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value
- )
- >
- nsel_constexpr expected< void, error_type > transform( F && f ) const &
- {
- return has_value()
- ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() )
- : make_unexpected( error() );
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- template::value
- && !std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value
- && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type && > >::value
- )
- >
- nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type && >, error_type > transform( F && f ) &&
- {
- return has_value()
- ? expected< detail::transform_invoke_result_t< F, value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) )
- : make_unexpected( std::move( error() ) );
- }
-
- template::value
- && std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value
- )
- >
- nsel_constexpr14 expected< void, error_type > transform( F && f ) &&
- {
- return has_value()
- ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() )
- : make_unexpected( std::move( error() ) );
- }
-
- template::value
- && !std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value
- && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type && > >::value
- )
- >
- nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type && >, error_type > transform( F && f ) const &&
- {
- return has_value()
- ? expected< detail::transform_invoke_result_t< F, const value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) )
- : make_unexpected( std::move( error() ) );
- }
-
- template::value
- && std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value
- )
- >
- nsel_constexpr expected< void, error_type > transform( F && f ) const &&
- {
- return has_value()
- ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() )
- : make_unexpected( std::move( error() ) );
- }
-#endif
-
- template >::value
- && std::is_constructible< value_type, value_type & >::value
- )
- >
- nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) &
- {
- return has_value()
- ? expected< value_type, detail::transform_invoke_result_t< F, error_type & > >( in_place, **this )
- : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) );
- }
-
- template >::value
- && std::is_constructible< value_type, const value_type & >::value
- )
- >
- nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const &
- {
- return has_value()
- ? expected< value_type, detail::transform_invoke_result_t< F, const error_type & > >( in_place, **this )
- : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) );
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- template >::value
- && std::is_constructible< value_type, value_type && >::value
- )
- >
- nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) &&
- {
- return has_value()
- ? expected< value_type, detail::transform_invoke_result_t< F, error_type && > >( in_place, std::move( **this ) )
- : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
- }
-
- template >::value
- && std::is_constructible< value_type, const value_type && >::value
- )
- >
- nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const &&
- {
- return has_value()
- ? expected< value_type, detail::transform_invoke_result_t< F, const error_type && > >( in_place, std::move( **this ) )
- : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
- }
-#endif
-#endif // nsel_P2505R >= 3
// unwrap()
// template
@@ -2680,7 +1961,7 @@ public:
nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error )
: contained( false )
{
- contained.construct_error( E{ error.error() } );
+ contained.construct_error( E{ error.value() } );
}
template< typename G = E
@@ -2691,7 +1972,7 @@ public:
nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error )
: contained( false )
{
- contained.construct_error( error.error() );
+ contained.construct_error( error.value() );
}
template< typename G = E
@@ -2702,7 +1983,7 @@ public:
nsel_constexpr14 explicit expected( nonstd::unexpected_type && error )
: contained( false )
{
- contained.construct_error( E{ std::move( error.error() ) } );
+ contained.construct_error( E{ std::move( error.value() ) } );
}
template< typename G = E
@@ -2713,7 +1994,7 @@ public:
nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error )
: contained( false )
{
- contained.construct_error( std::move( error.error() ) );
+ contained.construct_error( std::move( error.value() ) );
}
template< typename... Args
@@ -2850,305 +2131,6 @@ public:
return ! has_value() && std::is_base_of< Ex, ContainedEx>::value;
}
-#if nsel_P2505R >= 4
- template< typename G = E
- nsel_REQUIRES_T(
- std::is_copy_constructible< E >::value
- && std::is_convertible< G, E >::value
- )
- >
- nsel_constexpr error_type error_or( G && e ) const &
- {
- return has_value()
- ? static_cast< E >( std::forward< G >( e ) )
- : contained.error();
- }
-
- template< typename G = E
- nsel_REQUIRES_T(
- std::is_move_constructible< E >::value
- && std::is_convertible< G, E >::value
- )
- >
- nsel_constexpr14 error_type error_or( G && e ) &&
- {
- return has_value()
- ? static_cast< E >( std::forward< G >( e ) )
- : std::move( contained.error() );
- }
-#endif // nsel_P2505R >= 4
-
-#if nsel_P2505R >= 3
- // Monadic operations (P2505)
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value
- && std::is_constructible< error_type, error_type & >::value
- )
- >
- nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) &
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) )
- : detail::invoke_result_nocvref_t< F >( unexpect, error() );
- }
-
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value
- && std::is_constructible< error_type, const error_type & >::value
- )
- >
- nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const &
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) )
- : detail::invoke_result_nocvref_t< F >( unexpect, error() );
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value
- && std::is_constructible< error_type, error_type && >::value
- )
- >
- nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) &&
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) )
- : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) );
- }
-
- template >::value
- && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value
- && std::is_constructible< error_type, const error_type && >::value
- )
- >
- nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const &&
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) )
- : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) );
- }
-#endif
-
- template >::value
- && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type >::value
- )
- >
- nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) &
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, error_type & >()
- : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) );
- }
-
- template >::value
- && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type >::value
- )
- >
- nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const &
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, const error_type & >()
- : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) );
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- template >::value
- && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type >::value
- )
- >
- nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) &&
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, error_type && >()
- : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
- }
-
- template >::value
- && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type >::value
- )
- >
- nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const &&
- {
- return has_value()
- ? detail::invoke_result_nocvref_t< F, const error_type && >()
- : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
- }
-#endif
-
- template::value
- && !std::is_void< detail::transform_invoke_result_t< F > >::value
- )
- >
- nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) &
- {
- return has_value()
- ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) )
- : make_unexpected( error() );
- }
-
- template::value
- && std::is_void< detail::transform_invoke_result_t< F > >::value
- )
- >
- nsel_constexpr14 expected< void, error_type > transform( F && f ) &
- {
- return has_value()
- ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() )
- : make_unexpected( error() );
- }
-
- template::value
- && !std::is_void< detail::transform_invoke_result_t< F > >::value
- )
- >
- nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const &
- {
- return has_value()
- ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) )
- : make_unexpected( error() );
- }
-
- template::value
- && std::is_void< detail::transform_invoke_result_t< F > >::value
- )
- >
- nsel_constexpr expected< void, error_type > transform( F && f ) const &
- {
- return has_value()
- ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() )
- : make_unexpected( error() );
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- template::value
- && !std::is_void< detail::transform_invoke_result_t< F > >::value
- )
- >
- nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) &&
- {
- return has_value()
- ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) )
- : make_unexpected( error() );
- }
-
- template::value
- && std::is_void< detail::transform_invoke_result_t< F > >::value
- )
- >
- nsel_constexpr14 expected< void, error_type > transform( F && f ) &&
- {
- return has_value()
- ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() )
- : make_unexpected( error() );
- }
-
- template::value
- && !std::is_void< detail::transform_invoke_result_t< F > >::value
- )
- >
- nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const &&
- {
- return has_value()
- ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) )
- : make_unexpected( error() );
- }
-
- template::value
- && std::is_void< detail::transform_invoke_result_t< F > >::value
- )
- >
- nsel_constexpr expected< void, error_type > transform( F && f ) const &&
- {
- return has_value()
- ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() )
- : make_unexpected( error() );
- }
-#endif
-
- template >::value
- )
- >
- nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) &
- {
- return has_value()
- ? expected< void, detail::transform_invoke_result_t< F, error_type & > >()
- : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) );
- }
-
- template >::value
- )
- >
- nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const &
- {
- return has_value()
- ? expected< void, detail::transform_invoke_result_t< F, const error_type & > >()
- : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) );
- }
-
-#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
- template >::value
- )
- >
- nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) &&
- {
- return has_value()
- ? expected< void, detail::transform_invoke_result_t< F, error_type && > >()
- : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
- }
-
- template >::value
- )
- >
- nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const &&
- {
- return has_value()
- ? expected< void, detail::transform_invoke_result_t< F, const error_type && > >()
- : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
- }
-#endif
-#endif // nsel_P2505R >= 3
-
// template constexpr 'see below' unwrap() const&;
//
// template 'see below' unwrap() &&;
diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt
index fa4123251..3120422d6 100644
--- a/src/base/CMakeLists.txt
+++ b/src/base/CMakeLists.txt
@@ -6,9 +6,7 @@ add_library(qbt_base STATIC
applicationcomponent.h
asyncfilestorage.h
bittorrent/abstractfilestorage.h
- bittorrent/addtorrenterror.h
bittorrent/addtorrentparams.h
- bittorrent/announcetimepoint.h
bittorrent/bandwidthscheduler.h
bittorrent/bencoderesumedatastorage.h
bittorrent/cachestatus.h
@@ -40,8 +38,6 @@ add_library(qbt_base STATIC
bittorrent/torrent.h
bittorrent/torrentcontenthandler.h
bittorrent/torrentcontentlayout.h
- bittorrent/torrentcontentremoveoption.h
- bittorrent/torrentcontentremover.h
bittorrent/torrentcreationmanager.h
bittorrent/torrentcreationtask.h
bittorrent/torrentcreator.h
@@ -50,12 +46,10 @@ add_library(qbt_base STATIC
bittorrent/torrentinfo.h
bittorrent/tracker.h
bittorrent/trackerentry.h
- bittorrent/trackerentrystatus.h
concepts/explicitlyconvertibleto.h
concepts/stringable.h
digest32.h
exceptions.h
- freediskspacechecker.h
global.h
http/connection.h
http/httperror.h
@@ -112,7 +106,6 @@ add_library(qbt_base STATIC
utils/io.h
utils/misc.h
utils/net.h
- utils/number.h
utils/os.h
utils/password.h
utils/random.h
@@ -150,7 +143,6 @@ add_library(qbt_base STATIC
bittorrent/sslparameters.cpp
bittorrent/torrent.cpp
bittorrent/torrentcontenthandler.cpp
- bittorrent/torrentcontentremover.cpp
bittorrent/torrentcreationmanager.cpp
bittorrent/torrentcreationtask.cpp
bittorrent/torrentcreator.cpp
@@ -159,9 +151,7 @@ add_library(qbt_base STATIC
bittorrent/torrentinfo.cpp
bittorrent/tracker.cpp
bittorrent/trackerentry.cpp
- bittorrent/trackerentrystatus.cpp
exceptions.cpp
- freediskspacechecker.cpp
http/connection.cpp
http/httperror.cpp
http/requestparser.cpp
@@ -209,7 +199,6 @@ add_library(qbt_base STATIC
utils/io.cpp
utils/misc.cpp
utils/net.cpp
- utils/number.cpp
utils/os.cpp
utils/password.cpp
utils/random.cpp
diff --git a/src/base/addtorrentmanager.cpp b/src/base/addtorrentmanager.cpp
index bce47d6ab..a094dbd85 100644
--- a/src/base/addtorrentmanager.cpp
+++ b/src/base/addtorrentmanager.cpp
@@ -29,7 +29,6 @@
#include "addtorrentmanager.h"
-#include "base/bittorrent/addtorrenterror.h"
#include "base/bittorrent/infohash.h"
#include "base/bittorrent/session.h"
#include "base/bittorrent/torrentdescriptor.h"
@@ -141,7 +140,7 @@ void AddTorrentManager::onSessionTorrentAdded(BitTorrent::Torrent *torrent)
}
}
-void AddTorrentManager::onSessionAddTorrentFailed(const BitTorrent::InfoHash &infoHash, const BitTorrent::AddTorrentError &reason)
+void AddTorrentManager::onSessionAddTorrentFailed(const BitTorrent::InfoHash &infoHash, const QString &reason)
{
if (const QString source = m_sourcesByInfoHash.take(infoHash); !source.isEmpty())
{
@@ -155,40 +154,14 @@ void AddTorrentManager::onSessionAddTorrentFailed(const BitTorrent::InfoHash &in
void AddTorrentManager::handleAddTorrentFailed(const QString &source, const QString &reason)
{
LogMsg(tr("Failed to add torrent. Source: \"%1\". Reason: \"%2\"").arg(source, reason), Log::WARNING);
- emit addTorrentFailed(source, {BitTorrent::AddTorrentError::Other, reason});
+ emit addTorrentFailed(source, reason);
}
-void AddTorrentManager::handleDuplicateTorrent(const QString &source
- , const BitTorrent::TorrentDescriptor &torrentDescr, BitTorrent::Torrent *existingTorrent)
+void AddTorrentManager::handleDuplicateTorrent(const QString &source, BitTorrent::Torrent *torrent, const QString &message)
{
- const bool hasMetadata = torrentDescr.info().has_value();
- if (hasMetadata)
- {
- // Trying to set metadata to existing torrent in case if it has none
- existingTorrent->setMetadata(*torrentDescr.info());
- }
-
- const bool isPrivate = existingTorrent->isPrivate() || (hasMetadata && torrentDescr.info()->isPrivate());
- QString message;
- if (!btSession()->isMergeTrackersEnabled())
- {
- message = tr("Merging of trackers is disabled");
- }
- else if (isPrivate)
- {
- message = tr("Trackers cannot be merged because it is a private torrent");
- }
- else
- {
- // merge trackers and web seeds
- existingTorrent->addTrackers(torrentDescr.trackers());
- existingTorrent->addUrlSeeds(torrentDescr.urlSeeds());
- message = tr("Trackers are merged from new source");
- }
-
- LogMsg(tr("Detected an attempt to add a duplicate torrent. Source: %1. Existing torrent: \"%2\". Torrent infohash: %3. Result: %4")
- .arg(source, existingTorrent->name(), existingTorrent->infoHash().toString(), message));
- emit addTorrentFailed(source, {BitTorrent::AddTorrentError::DuplicateTorrent, message});
+ LogMsg(tr("Detected an attempt to add a duplicate torrent. Source: %1. Existing torrent: %2. Result: %3")
+ .arg(source, torrent->name(), message));
+ emit addTorrentFailed(source, message);
}
void AddTorrentManager::setTorrentFileGuard(const QString &source, std::shared_ptr torrentFileGuard)
@@ -196,9 +169,11 @@ void AddTorrentManager::setTorrentFileGuard(const QString &source, std::shared_p
m_guardedTorrentFiles.emplace(source, std::move(torrentFileGuard));
}
-std::shared_ptr AddTorrentManager::releaseTorrentFileGuard(const QString &source)
+void AddTorrentManager::releaseTorrentFileGuard(const QString &source)
{
- return m_guardedTorrentFiles.take(source);
+ auto torrentFileGuard = m_guardedTorrentFiles.take(source);
+ if (torrentFileGuard)
+ torrentFileGuard->setAutoRemove(false);
}
bool AddTorrentManager::processTorrent(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr
@@ -209,7 +184,32 @@ bool AddTorrentManager::processTorrent(const QString &source, const BitTorrent::
if (BitTorrent::Torrent *torrent = btSession()->findTorrent(infoHash))
{
// a duplicate torrent is being added
- handleDuplicateTorrent(source, torrentDescr, torrent);
+
+ const bool hasMetadata = torrentDescr.info().has_value();
+ if (hasMetadata)
+ {
+ // Trying to set metadata to existing torrent in case if it has none
+ torrent->setMetadata(*torrentDescr.info());
+ }
+
+ if (!btSession()->isMergeTrackersEnabled())
+ {
+ handleDuplicateTorrent(source, torrent, tr("Merging of trackers is disabled"));
+ return false;
+ }
+
+ const bool isPrivate = torrent->isPrivate() || (hasMetadata && torrentDescr.info()->isPrivate());
+ if (isPrivate)
+ {
+ handleDuplicateTorrent(source, torrent, tr("Trackers cannot be merged because it is a private torrent"));
+ return false;
+ }
+
+ // merge trackers and web seeds
+ torrent->addTrackers(torrentDescr.trackers());
+ torrent->addUrlSeeds(torrentDescr.urlSeeds());
+
+ handleDuplicateTorrent(source, torrent, tr("Trackers are merged from new source"));
return false;
}
diff --git a/src/base/addtorrentmanager.h b/src/base/addtorrentmanager.h
index c0044be65..ef31ae4da 100644
--- a/src/base/addtorrentmanager.h
+++ b/src/base/addtorrentmanager.h
@@ -44,7 +44,6 @@ namespace BitTorrent
class Session;
class Torrent;
class TorrentDescriptor;
- struct AddTorrentError;
}
namespace Net
@@ -67,20 +66,20 @@ public:
signals:
void torrentAdded(const QString &source, BitTorrent::Torrent *torrent);
- void addTorrentFailed(const QString &source, const BitTorrent::AddTorrentError &reason);
+ void addTorrentFailed(const QString &source, const QString &reason);
protected:
bool addTorrentToSession(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr
, const BitTorrent::AddTorrentParams &addTorrentParams);
void handleAddTorrentFailed(const QString &source, const QString &reason);
- void handleDuplicateTorrent(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr, BitTorrent::Torrent *existingTorrent);
+ void handleDuplicateTorrent(const QString &source, BitTorrent::Torrent *torrent, const QString &message);
void setTorrentFileGuard(const QString &source, std::shared_ptr torrentFileGuard);
- std::shared_ptr releaseTorrentFileGuard(const QString &source);
+ void releaseTorrentFileGuard(const QString &source);
private:
void onDownloadFinished(const Net::DownloadResult &result);
void onSessionTorrentAdded(BitTorrent::Torrent *torrent);
- void onSessionAddTorrentFailed(const BitTorrent::InfoHash &infoHash, const BitTorrent::AddTorrentError &reason);
+ void onSessionAddTorrentFailed(const BitTorrent::InfoHash &infoHash, const QString &reason);
bool processTorrent(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr
, const BitTorrent::AddTorrentParams &addTorrentParams);
diff --git a/src/base/bittorrent/abstractfilestorage.cpp b/src/base/bittorrent/abstractfilestorage.cpp
index ccd501c5b..c55ef8e52 100644
--- a/src/base/bittorrent/abstractfilestorage.cpp
+++ b/src/base/bittorrent/abstractfilestorage.cpp
@@ -30,7 +30,7 @@
#include
#include
-#include
+#include
#include "base/exceptions.h"
#include "base/path.h"
@@ -71,7 +71,7 @@ void BitTorrent::AbstractFileStorage::renameFolder(const Path &oldFolderPath, co
if (newFolderPath.isAbsolute())
throw RuntimeError(tr("Absolute path isn't allowed: '%1'.").arg(newFolderPath.toString()));
- QList renamingFileIndexes;
+ QVector renamingFileIndexes;
renamingFileIndexes.reserve(filesCount());
for (int i = 0; i < filesCount(); ++i)
diff --git a/src/base/bittorrent/addtorrenterror.h b/src/base/bittorrent/addtorrenterror.h
deleted file mode 100644
index a0afb4705..000000000
--- a/src/base/bittorrent/addtorrenterror.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Bittorrent Client using Qt and libtorrent.
- * Copyright (C) 2025 Vladimir Golovnev
- *
- * 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
-#include
-
-namespace BitTorrent
-{
- struct AddTorrentError
- {
- enum Kind
- {
- DuplicateTorrent,
- Other
- };
-
- Kind kind = Other;
- QString message;
- };
-}
-
-Q_DECLARE_METATYPE(BitTorrent::AddTorrentError)
diff --git a/src/base/bittorrent/addtorrentparams.cpp b/src/base/bittorrent/addtorrentparams.cpp
index d284b36d3..8784c047e 100644
--- a/src/base/bittorrent/addtorrentparams.cpp
+++ b/src/base/bittorrent/addtorrentparams.cpp
@@ -116,7 +116,7 @@ BitTorrent::AddTorrentParams BitTorrent::parseAddTorrentParams(const QJsonObject
.downloadPath = Path(jsonObj.value(PARAM_DOWNLOADPATH).toString()),
.addForced = (getEnum(jsonObj, PARAM_OPERATINGMODE) == TorrentOperatingMode::Forced),
.addToQueueTop = getOptionalBool(jsonObj, PARAM_QUEUETOP),
- .addStopped = getOptionalBool(jsonObj, PARAM_STOPPED),
+ .addPaused = getOptionalBool(jsonObj, PARAM_STOPPED),
.stopCondition = getOptionalEnum(jsonObj, PARAM_STOPCONDITION),
.filePaths = {},
.filePriorities = {},
@@ -163,8 +163,8 @@ QJsonObject BitTorrent::serializeAddTorrentParams(const AddTorrentParams ¶ms
if (params.addToQueueTop)
jsonObj[PARAM_QUEUETOP] = *params.addToQueueTop;
- if (params.addStopped)
- jsonObj[PARAM_STOPPED] = *params.addStopped;
+ if (params.addPaused)
+ jsonObj[PARAM_STOPPED] = *params.addPaused;
if (params.stopCondition)
jsonObj[PARAM_STOPCONDITION] = Utils::String::fromEnum(*params.stopCondition);
if (params.contentLayout)
diff --git a/src/base/bittorrent/addtorrentparams.h b/src/base/bittorrent/addtorrentparams.h
index a2de0b725..60107d122 100644
--- a/src/base/bittorrent/addtorrentparams.h
+++ b/src/base/bittorrent/addtorrentparams.h
@@ -30,9 +30,9 @@
#include
-#include
#include
#include
+#include
#include "base/path.h"
#include "base/tagset.h"
@@ -59,10 +59,10 @@ namespace BitTorrent
bool firstLastPiecePriority = false;
bool addForced = false;
std::optional addToQueueTop;
- std::optional addStopped;
+ std::optional addPaused;
std::optional stopCondition;
PathList filePaths; // used if TorrentInfo is set
- QList filePriorities; // used if TorrentInfo is set
+ QVector filePriorities; // used if TorrentInfo is set
bool skipChecking = false;
std::optional contentLayout;
std::optional useAutoTMM;
diff --git a/src/base/bittorrent/announcetimepoint.h b/src/base/bittorrent/announcetimepoint.h
deleted file mode 100644
index 1dd65eea7..000000000
--- a/src/base/bittorrent/announcetimepoint.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Bittorrent Client using Qt and libtorrent.
- * Copyright (C) 2024 Vladimir Golovnev
- *
- * 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
-
-namespace BitTorrent
-{
- using AnnounceTimePoint = std::chrono::high_resolution_clock::time_point;
-}
diff --git a/src/base/bittorrent/bandwidthscheduler.cpp b/src/base/bittorrent/bandwidthscheduler.cpp
index 5463cc36e..bb8d1d0a8 100644
--- a/src/base/bittorrent/bandwidthscheduler.cpp
+++ b/src/base/bittorrent/bandwidthscheduler.cpp
@@ -102,7 +102,7 @@ bool BandwidthScheduler::isTimeForAlternative() const
alternative = !alternative;
break;
default:
- Q_UNREACHABLE();
+ Q_ASSERT(false);
break;
}
}
diff --git a/src/base/bittorrent/bencoderesumedatastorage.cpp b/src/base/bittorrent/bencoderesumedatastorage.cpp
index ee87b5601..4107c5aa9 100644
--- a/src/base/bittorrent/bencoderesumedatastorage.cpp
+++ b/src/base/bittorrent/bencoderesumedatastorage.cpp
@@ -40,6 +40,7 @@
#include
#include
+#include "base/algorithm.h"
#include "base/exceptions.h"
#include "base/global.h"
#include "base/logger.h"
@@ -64,7 +65,7 @@ namespace BitTorrent
void store(const TorrentID &id, const LoadTorrentParams &resumeData) const;
void remove(const TorrentID &id) const;
- void storeQueue(const QList &queue) const;
+ void storeQueue(const QVector &queue) const;
private:
const Path m_resumeDataDir;
@@ -131,11 +132,10 @@ BitTorrent::BencodeResumeDataStorage::BencodeResumeDataStorage(const Path &path,
m_asyncWorker->moveToThread(m_ioThread.get());
connect(m_ioThread.get(), &QThread::finished, m_asyncWorker, &QObject::deleteLater);
- m_ioThread->setObjectName("BencodeResumeDataStorage m_ioThread");
m_ioThread->start();
}
-QList BitTorrent::BencodeResumeDataStorage::registeredTorrents() const
+QVector BitTorrent::BencodeResumeDataStorage::registeredTorrents() const
{
return m_registeredTorrents;
}
@@ -147,7 +147,7 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::load(cons
const Path torrentFilePath = path() / Path(idString + u".torrent");
const qint64 torrentSizeLimit = Preferences::instance()->getTorrentFileSizeLimit();
- const auto resumeDataReadResult = Utils::IO::readFile(fastresumePath, -1);
+ const auto resumeDataReadResult = Utils::IO::readFile(fastresumePath, torrentSizeLimit);
if (!resumeDataReadResult)
return nonstd::make_unexpected(resumeDataReadResult.error().message);
@@ -189,13 +189,8 @@ void BitTorrent::BencodeResumeDataStorage::loadQueue(const Path &queueFilename)
return;
}
- QHash registeredTorrentsIndexes;
- registeredTorrentsIndexes.reserve(m_registeredTorrents.length());
- for (qsizetype i = 0; i < m_registeredTorrents.length(); ++i)
- registeredTorrentsIndexes.insert(m_registeredTorrents.at(i), i);
-
const QRegularExpression hashPattern {u"^([A-Fa-f0-9]{40})$"_s};
- qsizetype queuePos = 0;
+ int start = 0;
while (true)
{
const auto line = QString::fromLatin1(queueFile.readLine(lineMaxLength).trimmed());
@@ -206,15 +201,11 @@ void BitTorrent::BencodeResumeDataStorage::loadQueue(const Path &queueFilename)
if (rxMatch.hasMatch())
{
const auto torrentID = BitTorrent::TorrentID::fromString(rxMatch.captured(1));
- const qsizetype pos = registeredTorrentsIndexes.value(torrentID, -1);
+ const int pos = m_registeredTorrents.indexOf(torrentID, start);
if (pos != -1)
{
- if (pos != queuePos)
- {
- m_registeredTorrents.swapItemsAt(pos, queuePos);
- registeredTorrentsIndexes.insert(m_registeredTorrents.at(pos), pos);
- }
- ++queuePos;
+ std::swap(m_registeredTorrents[start], m_registeredTorrents[pos]);
+ ++start;
}
}
}
@@ -236,7 +227,6 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
LoadTorrentParams torrentParams;
torrentParams.category = fromLTString(resumeDataRoot.dict_find_string_value("qBt-category"));
torrentParams.name = fromLTString(resumeDataRoot.dict_find_string_value("qBt-name"));
- 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);
@@ -300,11 +290,10 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
lt::add_torrent_params &p = torrentParams.ltAddTorrentParams;
p = lt::read_resume_data(resumeDataRoot, ec);
- if (ec)
- return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message())));
if (!metadata.isEmpty())
{
+ const auto *pref = Preferences::instance();
const lt::bdecode_node torentInfoRoot = lt::bdecode(metadata, ec
, nullptr, pref->getBdecodeDepthLimit(), pref->getBdecodeTokenLimit());
if (ec)
@@ -332,8 +321,6 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
p.save_path = Profile::instance()->fromPortablePath(
Path(fromLTString(p.save_path))).toString().toStdString();
- if (p.save_path.empty())
- return nonstd::make_unexpected(tr("Corrupted resume data: %1").arg(tr("save_path is invalid")));
torrentParams.stopped = (p.flags & lt::torrent_flags::paused) && !(p.flags & lt::torrent_flags::auto_managed);
torrentParams.operatingMode = (p.flags & lt::torrent_flags::paused) || (p.flags & lt::torrent_flags::auto_managed)
@@ -352,9 +339,9 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
return torrentParams;
}
-void BitTorrent::BencodeResumeDataStorage::store(const TorrentID &id, LoadTorrentParams resumeData) const
+void BitTorrent::BencodeResumeDataStorage::store(const TorrentID &id, const LoadTorrentParams &resumeData) const
{
- QMetaObject::invokeMethod(m_asyncWorker, [this, id, resumeData = std::move(resumeData)]
+ QMetaObject::invokeMethod(m_asyncWorker, [this, id, resumeData]()
{
m_asyncWorker->store(id, resumeData);
});
@@ -368,7 +355,7 @@ void BitTorrent::BencodeResumeDataStorage::remove(const TorrentID &id) const
});
}
-void BitTorrent::BencodeResumeDataStorage::storeQueue(const QList &queue) const
+void BitTorrent::BencodeResumeDataStorage::storeQueue(const QVector &queue) const
{
QMetaObject::invokeMethod(m_asyncWorker, [this, queue]()
{
@@ -438,7 +425,6 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
data["qBt-category"] = resumeData.category.toStdString();
data["qBt-tags"] = setToEntryList(resumeData.tags);
data["qBt-name"] = resumeData.name.toStdString();
- data["qBt-comment"] = resumeData.comment.toStdString();
data["qBt-seedStatus"] = resumeData.hasFinishedStatus;
data["qBt-contentLayout"] = Utils::String::fromEnum(resumeData.contentLayout).toStdString();
data["qBt-firstLastPiecePriority"] = resumeData.firstLastPiecePriority;
@@ -475,7 +461,7 @@ void BitTorrent::BencodeResumeDataStorage::Worker::remove(const TorrentID &id) c
Utils::Fs::removeFile(m_resumeDataDir / torrentFilename);
}
-void BitTorrent::BencodeResumeDataStorage::Worker::storeQueue(const QList &queue) const
+void BitTorrent::BencodeResumeDataStorage::Worker::storeQueue(const QVector &queue) const
{
QByteArray data;
data.reserve(((BitTorrent::TorrentID::length() * 2) + 1) * queue.size());
diff --git a/src/base/bittorrent/bencoderesumedatastorage.h b/src/base/bittorrent/bencoderesumedatastorage.h
index 3e1f96943..9e7820e99 100644
--- a/src/base/bittorrent/bencoderesumedatastorage.h
+++ b/src/base/bittorrent/bencoderesumedatastorage.h
@@ -29,7 +29,7 @@
#pragma once
#include
-#include
+#include
#include "base/pathfwd.h"
#include "base/utils/thread.h"
@@ -37,6 +37,7 @@
#include "resumedatastorage.h"
class QByteArray;
+class QThread;
namespace BitTorrent
{
@@ -48,18 +49,18 @@ namespace BitTorrent
public:
explicit BencodeResumeDataStorage(const Path &path, QObject *parent = nullptr);
- QList registeredTorrents() const override;
+ QVector registeredTorrents() const override;
LoadResumeDataResult load(const TorrentID &id) const override;
- void store(const TorrentID &id, LoadTorrentParams resumeData) const override;
+ void store(const TorrentID &id, const LoadTorrentParams &resumeData) const override;
void remove(const TorrentID &id) const override;
- void storeQueue(const QList &queue) const override;
+ void storeQueue(const QVector &queue) const override;
private:
void doLoadAll() const override;
void loadQueue(const Path &queueFilename);
LoadResumeDataResult loadTorrentResumeData(const QByteArray &data, const QByteArray &metadata) const;
- QList m_registeredTorrents;
+ QVector m_registeredTorrents;
Utils::Thread::UniquePtr m_ioThread;
class Worker;
diff --git a/src/base/bittorrent/categoryoptions.cpp b/src/base/bittorrent/categoryoptions.cpp
index c839670c6..fec609ff7 100644
--- a/src/base/bittorrent/categoryoptions.cpp
+++ b/src/base/bittorrent/categoryoptions.cpp
@@ -52,7 +52,7 @@ BitTorrent::CategoryOptions BitTorrent::CategoryOptions::fromJSON(const QJsonObj
QJsonObject BitTorrent::CategoryOptions::toJSON() const
{
- QJsonValue downloadPathValue = QJsonValue::Null;
+ QJsonValue downloadPathValue = QJsonValue::Undefined;
if (downloadPath)
{
if (downloadPath->enabled)
diff --git a/src/base/bittorrent/customstorage.cpp b/src/base/bittorrent/customstorage.cpp
index 9134b1507..c4957ef07 100644
--- a/src/base/bittorrent/customstorage.cpp
+++ b/src/base/bittorrent/customstorage.cpp
@@ -240,11 +240,11 @@ void CustomDiskIOThread::handleCompleteFiles(lt::storage_index_t storage, const
lt::storage_interface *customStorageConstructor(const lt::storage_params ¶ms, lt::file_pool &pool)
{
- return new CustomStorage(params, pool);
+ return new CustomStorage {params, pool};
}
CustomStorage::CustomStorage(const lt::storage_params ¶ms, lt::file_pool &filePool)
- : lt::default_storage(params, filePool)
+ : lt::default_storage {params, filePool}
, m_savePath {params.path}
{
}
diff --git a/src/base/bittorrent/dbresumedatastorage.cpp b/src/base/bittorrent/dbresumedatastorage.cpp
index 4c6a3576c..bb0efbdaf 100644
--- a/src/base/bittorrent/dbresumedatastorage.cpp
+++ b/src/base/bittorrent/dbresumedatastorage.cpp
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
- * Copyright (C) 2021-2025 Vladimir Golovnev
+ * Copyright (C) 2021-2023 Vladimir Golovnev
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -41,7 +41,6 @@
#include
#include
-#include
#include
#include
#include
@@ -49,6 +48,7 @@
#include
#include
#include
+#include
#include
#include "base/exceptions.h"
@@ -67,7 +67,7 @@ namespace
{
const QString DB_CONNECTION_NAME = u"ResumeDataStorage"_s;
- const int DB_VERSION = 9;
+ const int DB_VERSION = 7;
const QString DB_TABLE_META = u"meta"_s;
const QString DB_TABLE_TORRENTS = u"torrents"_s;
@@ -86,7 +86,7 @@ namespace
class StoreJob final : public Job
{
public:
- StoreJob(const TorrentID &torrentID, LoadTorrentParams resumeData);
+ StoreJob(const TorrentID &torrentID, const LoadTorrentParams &resumeData);
void perform(QSqlDatabase db) override;
private:
@@ -107,11 +107,11 @@ namespace
class StoreQueueJob final : public Job
{
public:
- explicit StoreQueueJob(const QList &queue);
+ explicit StoreQueueJob(const QVector &queue);
void perform(QSqlDatabase db) override;
private:
- const QList m_queue;
+ const QVector m_queue;
};
struct Column
@@ -120,36 +120,36 @@ namespace
QString placeholder;
};
- Column makeColumn(const QString &columnName)
+ Column makeColumn(const char *columnName)
{
- return {.name = columnName, .placeholder = (u':' + columnName)};
+ const QString name = QString::fromLatin1(columnName);
+ return {.name = name, .placeholder = (u':' + name)};
}
- const Column DB_COLUMN_ID = makeColumn(u"id"_s);
- const Column DB_COLUMN_TORRENT_ID = makeColumn(u"torrent_id"_s);
- const Column DB_COLUMN_QUEUE_POSITION = makeColumn(u"queue_position"_s);
- const Column DB_COLUMN_NAME = makeColumn(u"name"_s);
- const Column DB_COLUMN_CATEGORY = makeColumn(u"category"_s);
- const Column DB_COLUMN_TAGS = makeColumn(u"tags"_s);
- const Column DB_COLUMN_COMMENT = makeColumn(u"comment"_s);
- const Column DB_COLUMN_TARGET_SAVE_PATH = makeColumn(u"target_save_path"_s);
- const Column DB_COLUMN_DOWNLOAD_PATH = makeColumn(u"download_path"_s);
- const Column DB_COLUMN_CONTENT_LAYOUT = makeColumn(u"content_layout"_s);
- const Column DB_COLUMN_RATIO_LIMIT = makeColumn(u"ratio_limit"_s);
- const Column DB_COLUMN_SEEDING_TIME_LIMIT = makeColumn(u"seeding_time_limit"_s);
- const Column DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT = makeColumn(u"inactive_seeding_time_limit"_s);
- const Column DB_COLUMN_SHARE_LIMIT_ACTION = makeColumn(u"share_limit_action"_s);
- const Column DB_COLUMN_HAS_OUTER_PIECES_PRIORITY = makeColumn(u"has_outer_pieces_priority"_s);
- const Column DB_COLUMN_HAS_SEED_STATUS = makeColumn(u"has_seed_status"_s);
- const Column DB_COLUMN_OPERATING_MODE = makeColumn(u"operating_mode"_s);
- const Column DB_COLUMN_STOPPED = makeColumn(u"stopped"_s);
- const Column DB_COLUMN_STOP_CONDITION = makeColumn(u"stop_condition"_s);
- const Column DB_COLUMN_SSL_CERTIFICATE = makeColumn(u"ssl_certificate"_s);
- const Column DB_COLUMN_SSL_PRIVATE_KEY = makeColumn(u"ssl_private_key"_s);
- const Column DB_COLUMN_SSL_DH_PARAMS = makeColumn(u"ssl_dh_params"_s);
- const Column DB_COLUMN_RESUMEDATA = makeColumn(u"libtorrent_resume_data"_s);
- const Column DB_COLUMN_METADATA = makeColumn(u"metadata"_s);
- const Column DB_COLUMN_VALUE = makeColumn(u"value"_s);
+ const Column DB_COLUMN_ID = makeColumn("id");
+ const Column DB_COLUMN_TORRENT_ID = makeColumn("torrent_id");
+ const Column DB_COLUMN_QUEUE_POSITION = makeColumn("queue_position");
+ const Column DB_COLUMN_NAME = makeColumn("name");
+ const Column DB_COLUMN_CATEGORY = makeColumn("category");
+ const Column DB_COLUMN_TAGS = makeColumn("tags");
+ const Column DB_COLUMN_TARGET_SAVE_PATH = makeColumn("target_save_path");
+ const Column DB_COLUMN_DOWNLOAD_PATH = makeColumn("download_path");
+ const Column DB_COLUMN_CONTENT_LAYOUT = makeColumn("content_layout");
+ const Column DB_COLUMN_RATIO_LIMIT = makeColumn("ratio_limit");
+ const Column DB_COLUMN_SEEDING_TIME_LIMIT = makeColumn("seeding_time_limit");
+ const Column DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT = makeColumn("inactive_seeding_time_limit");
+ const Column DB_COLUMN_SHARE_LIMIT_ACTION = makeColumn("share_limit_action");
+ const Column DB_COLUMN_HAS_OUTER_PIECES_PRIORITY = makeColumn("has_outer_pieces_priority");
+ const Column DB_COLUMN_HAS_SEED_STATUS = makeColumn("has_seed_status");
+ const Column DB_COLUMN_OPERATING_MODE = makeColumn("operating_mode");
+ const Column DB_COLUMN_STOPPED = makeColumn("stopped");
+ const Column DB_COLUMN_STOP_CONDITION = makeColumn("stop_condition");
+ const Column DB_COLUMN_SSL_CERTIFICATE = makeColumn("ssl_certificate");
+ const Column DB_COLUMN_SSL_PRIVATE_KEY = makeColumn("ssl_private_key");
+ const Column DB_COLUMN_SSL_DH_PARAMS = makeColumn("ssl_dh_params");
+ const Column DB_COLUMN_RESUMEDATA = makeColumn("libtorrent_resume_data");
+ const Column DB_COLUMN_METADATA = makeColumn("metadata");
+ const Column DB_COLUMN_VALUE = makeColumn("value");
template
QString fromLTString(const LTStr &str)
@@ -168,7 +168,7 @@ namespace
return u"CREATE TABLE %1 (%2)"_s.arg(quoted(tableName), items.join(u','));
}
- std::pair joinColumns(const QList &columns)
+ std::pair joinColumns(const QVector &columns)
{
int namesSize = columns.size();
int valuesSize = columns.size();
@@ -193,30 +193,104 @@ namespace
return std::make_pair(names, values);
}
- QString makeInsertStatement(const QString &tableName, const QList &columns)
+ QString makeInsertStatement(const QString &tableName, const QVector &columns)
{
const auto [names, values] = joinColumns(columns);
return u"INSERT INTO %1 (%2) VALUES (%3)"_s
.arg(quoted(tableName), names, values);
}
- QString makeUpdateStatement(const QString &tableName, const QList &columns)
+ QString makeUpdateStatement(const QString &tableName, const QVector &columns)
{
const auto [names, values] = joinColumns(columns);
return u"UPDATE %1 SET (%2) = (%3)"_s
.arg(quoted(tableName), names, values);
}
- QString makeOnConflictUpdateStatement(const Column &constraint, const QList &columns)
+ QString makeOnConflictUpdateStatement(const Column &constraint, const QVector &columns)
{
const auto [names, values] = joinColumns(columns);
return u" ON CONFLICT (%1) DO UPDATE SET (%2) = (%3)"_s
.arg(quoted(constraint.name), names, values);
}
- QString makeColumnDefinition(const Column &column, const QString &definition)
+ QString makeColumnDefinition(const Column &column, const char *definition)
{
- return u"%1 %2"_s.arg(quoted(column.name), definition);
+ return u"%1 %2"_s.arg(quoted(column.name), QString::fromLatin1(definition));
+ }
+
+ LoadTorrentParams parseQueryResultRow(const QSqlQuery &query)
+ {
+ LoadTorrentParams resumeData;
+ resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
+ resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
+ const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
+ if (!tagsData.isEmpty())
+ {
+ const QStringList tagList = tagsData.split(u',');
+ resumeData.tags.insert(tagList.cbegin(), tagList.cend());
+ }
+ resumeData.hasFinishedStatus = query.value(DB_COLUMN_HAS_SEED_STATUS.name).toBool();
+ resumeData.firstLastPiecePriority = query.value(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY.name).toBool();
+ resumeData.ratioLimit = query.value(DB_COLUMN_RATIO_LIMIT.name).toInt() / 1000.0;
+ resumeData.seedingTimeLimit = query.value(DB_COLUMN_SEEDING_TIME_LIMIT.name).toInt();
+ resumeData.inactiveSeedingTimeLimit = query.value(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT.name).toInt();
+ resumeData.shareLimitAction = Utils::String::toEnum(
+ query.value(DB_COLUMN_SHARE_LIMIT_ACTION.name).toString(), ShareLimitAction::Default);
+ resumeData.contentLayout = Utils::String::toEnum(
+ query.value(DB_COLUMN_CONTENT_LAYOUT.name).toString(), TorrentContentLayout::Original);
+ resumeData.operatingMode = Utils::String::toEnum(
+ query.value(DB_COLUMN_OPERATING_MODE.name).toString(), TorrentOperatingMode::AutoManaged);
+ resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
+ resumeData.stopCondition = Utils::String::toEnum(
+ query.value(DB_COLUMN_STOP_CONDITION.name).toString(), Torrent::StopCondition::None);
+ resumeData.sslParameters =
+ {
+ .certificate = QSslCertificate(query.value(DB_COLUMN_SSL_CERTIFICATE.name).toByteArray()),
+ .privateKey = Utils::SSLKey::load(query.value(DB_COLUMN_SSL_PRIVATE_KEY.name).toByteArray()),
+ .dhParams = query.value(DB_COLUMN_SSL_DH_PARAMS.name).toByteArray()
+ };
+
+ resumeData.savePath = Profile::instance()->fromPortablePath(
+ Path(query.value(DB_COLUMN_TARGET_SAVE_PATH.name).toString()));
+ resumeData.useAutoTMM = resumeData.savePath.isEmpty();
+ if (!resumeData.useAutoTMM)
+ {
+ resumeData.downloadPath = Profile::instance()->fromPortablePath(
+ Path(query.value(DB_COLUMN_DOWNLOAD_PATH.name).toString()));
+ }
+
+ const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
+ const auto *pref = Preferences::instance();
+ const int bdecodeDepthLimit = pref->getBdecodeDepthLimit();
+ const int bdecodeTokenLimit = pref->getBdecodeTokenLimit();
+
+ lt::error_code ec;
+ const lt::bdecode_node resumeDataRoot = lt::bdecode(bencodedResumeData, ec
+ , nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
+
+ lt::add_torrent_params &p = resumeData.ltAddTorrentParams;
+
+ p = lt::read_resume_data(resumeDataRoot, ec);
+
+ if (const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray()
+ ; !bencodedMetadata.isEmpty())
+ {
+ const lt::bdecode_node torentInfoRoot = lt::bdecode(bencodedMetadata, ec
+ , nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
+ p.ti = std::make_shared(torentInfoRoot, ec);
+ }
+
+ p.save_path = Profile::instance()->fromPortablePath(Path(fromLTString(p.save_path)))
+ .toString().toStdString();
+
+ if (p.flags & lt::torrent_flags::stop_when_ready)
+ {
+ p.flags &= ~lt::torrent_flags::stop_when_ready;
+ resumeData.stopCondition = Torrent::StopCondition::FilesChecked;
+ }
+
+ return resumeData;
}
}
@@ -232,9 +306,9 @@ namespace BitTorrent
void run() override;
void requestInterruption();
- void store(const TorrentID &id, LoadTorrentParams resumeData);
+ void store(const TorrentID &id, const LoadTorrentParams &resumeData);
void remove(const TorrentID &id);
- void storeQueue(const QList &queue);
+ void storeQueue(const QVector &queue);
private:
void addJob(std::unique_ptr job);
@@ -251,6 +325,7 @@ namespace BitTorrent
BitTorrent::DBResumeDataStorage::DBResumeDataStorage(const Path &dbPath, QObject *parent)
: ResumeDataStorage(dbPath, parent)
+ , m_ioThread {new QThread}
{
const bool needCreateDB = !dbPath.exists();
@@ -281,7 +356,7 @@ BitTorrent::DBResumeDataStorage::~DBResumeDataStorage()
QSqlDatabase::removeDatabase(DB_CONNECTION_NAME);
}
-QList BitTorrent::DBResumeDataStorage::registeredTorrents() const
+QVector BitTorrent::DBResumeDataStorage::registeredTorrents() const
{
const auto selectTorrentIDStatement = u"SELECT %1 FROM %2 ORDER BY %3;"_s
.arg(quoted(DB_COLUMN_TORRENT_ID.name), quoted(DB_TABLE_TORRENTS), quoted(DB_COLUMN_QUEUE_POSITION.name));
@@ -292,7 +367,7 @@ QList BitTorrent::DBResumeDataStorage::registeredTorrents
if (!query.exec(selectTorrentIDStatement))
throw RuntimeError(query.lastError().text());
- QList registeredTorrents;
+ QVector registeredTorrents;
registeredTorrents.reserve(query.size());
while (query.next())
registeredTorrents.append(BitTorrent::TorrentID::fromString(query.value(0).toString()));
@@ -328,9 +403,9 @@ BitTorrent::LoadResumeDataResult BitTorrent::DBResumeDataStorage::load(const Tor
return parseQueryResultRow(query);
}
-void BitTorrent::DBResumeDataStorage::store(const TorrentID &id, LoadTorrentParams resumeData) const
+void BitTorrent::DBResumeDataStorage::store(const TorrentID &id, const LoadTorrentParams &resumeData) const
{
- m_asyncWorker->store(id, std::move(resumeData));
+ m_asyncWorker->store(id, resumeData);
}
void BitTorrent::DBResumeDataStorage::remove(const BitTorrent::TorrentID &id) const
@@ -338,7 +413,7 @@ void BitTorrent::DBResumeDataStorage::remove(const BitTorrent::TorrentID &id) co
m_asyncWorker->remove(id);
}
-void BitTorrent::DBResumeDataStorage::storeQueue(const QList &queue) const
+void BitTorrent::DBResumeDataStorage::storeQueue(const QVector &queue) const
{
m_asyncWorker->storeQueue(queue);
}
@@ -363,7 +438,7 @@ void BitTorrent::DBResumeDataStorage::doLoadAll() const
if (!query.exec(selectTorrentIDStatement))
throw RuntimeError(query.lastError().text());
- QList registeredTorrents;
+ QVector registeredTorrents;
registeredTorrents.reserve(query.size());
while (query.next())
registeredTorrents.append(TorrentID::fromString(query.value(0).toString()));
@@ -437,9 +512,9 @@ void BitTorrent::DBResumeDataStorage::createDB() const
try
{
const QStringList tableMetaItems = {
- makeColumnDefinition(DB_COLUMN_ID, u"INTEGER PRIMARY KEY"_s),
- makeColumnDefinition(DB_COLUMN_NAME, u"TEXT NOT NULL UNIQUE"_s),
- makeColumnDefinition(DB_COLUMN_VALUE, u"BLOB"_s)
+ makeColumnDefinition(DB_COLUMN_ID, "INTEGER PRIMARY KEY"),
+ makeColumnDefinition(DB_COLUMN_NAME, "TEXT NOT NULL UNIQUE"),
+ makeColumnDefinition(DB_COLUMN_VALUE, "BLOB")
};
const QString createTableMetaQuery = makeCreateTableStatement(DB_TABLE_META, tableMetaItems);
if (!query.exec(createTableMetaQuery))
@@ -456,30 +531,29 @@ void BitTorrent::DBResumeDataStorage::createDB() const
throw RuntimeError(query.lastError().text());
const QStringList tableTorrentsItems = {
- makeColumnDefinition(DB_COLUMN_ID, u"INTEGER PRIMARY KEY"_s),
- makeColumnDefinition(DB_COLUMN_TORRENT_ID, u"BLOB NOT NULL UNIQUE"_s),
- makeColumnDefinition(DB_COLUMN_QUEUE_POSITION, u"INTEGER NOT NULL DEFAULT -1"_s),
- makeColumnDefinition(DB_COLUMN_NAME, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_CATEGORY, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_TAGS, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_COMMENT, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_TARGET_SAVE_PATH, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_DOWNLOAD_PATH, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_CONTENT_LAYOUT, u"TEXT NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_RATIO_LIMIT, u"INTEGER NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_SEEDING_TIME_LIMIT, u"INTEGER NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT, u"INTEGER NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_SHARE_LIMIT_ACTION, u"TEXT NOT NULL DEFAULT `Default`"_s),
- makeColumnDefinition(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY, u"INTEGER NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_HAS_SEED_STATUS, u"INTEGER NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_OPERATING_MODE, u"TEXT NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_STOPPED, u"INTEGER NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_STOP_CONDITION, u"TEXT NOT NULL DEFAULT `None`"_s),
- makeColumnDefinition(DB_COLUMN_SSL_CERTIFICATE, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_SSL_PRIVATE_KEY, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_SSL_DH_PARAMS, u"TEXT"_s),
- makeColumnDefinition(DB_COLUMN_RESUMEDATA, u"BLOB NOT NULL"_s),
- makeColumnDefinition(DB_COLUMN_METADATA, u"BLOB"_s)
+ makeColumnDefinition(DB_COLUMN_ID, "INTEGER PRIMARY KEY"),
+ makeColumnDefinition(DB_COLUMN_TORRENT_ID, "BLOB NOT NULL UNIQUE"),
+ makeColumnDefinition(DB_COLUMN_QUEUE_POSITION, "INTEGER NOT NULL DEFAULT -1"),
+ makeColumnDefinition(DB_COLUMN_NAME, "TEXT"),
+ makeColumnDefinition(DB_COLUMN_CATEGORY, "TEXT"),
+ makeColumnDefinition(DB_COLUMN_TAGS, "TEXT"),
+ makeColumnDefinition(DB_COLUMN_TARGET_SAVE_PATH, "TEXT"),
+ makeColumnDefinition(DB_COLUMN_DOWNLOAD_PATH, "TEXT"),
+ makeColumnDefinition(DB_COLUMN_CONTENT_LAYOUT, "TEXT NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_RATIO_LIMIT, "INTEGER NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_SEEDING_TIME_LIMIT, "INTEGER NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT, "INTEGER NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_SHARE_LIMIT_ACTION, "TEXT NOT NULL DEFAULT `Default`"),
+ makeColumnDefinition(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY, "INTEGER NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_HAS_SEED_STATUS, "INTEGER NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_OPERATING_MODE, "TEXT NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_STOPPED, "INTEGER NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_STOP_CONDITION, "TEXT NOT NULL DEFAULT `None`"),
+ makeColumnDefinition(DB_COLUMN_SSL_CERTIFICATE, "TEXT"),
+ makeColumnDefinition(DB_COLUMN_SSL_PRIVATE_KEY, "TEXT"),
+ makeColumnDefinition(DB_COLUMN_SSL_DH_PARAMS, "TEXT"),
+ makeColumnDefinition(DB_COLUMN_RESUMEDATA, "BLOB NOT NULL"),
+ makeColumnDefinition(DB_COLUMN_METADATA, "BLOB")
};
const QString createTableTorrentsQuery = makeCreateTableStatement(DB_TABLE_TORRENTS, tableTorrentsItems);
if (!query.exec(createTableTorrentsQuery))
@@ -517,7 +591,7 @@ void BitTorrent::DBResumeDataStorage::updateDB(const int fromVersion) const
try
{
- const auto addColumn = [&query](const QString &table, const Column &column, const QString &definition)
+ const auto addColumn = [&query](const QString &table, const Column &column, const char *definition)
{
const auto testQuery = u"SELECT COUNT(%1) FROM %2;"_s.arg(quoted(column.name), quoted(table));
if (query.exec(testQuery))
@@ -529,10 +603,10 @@ void BitTorrent::DBResumeDataStorage::updateDB(const int fromVersion) const
};
if (fromVersion <= 1)
- addColumn(DB_TABLE_TORRENTS, DB_COLUMN_DOWNLOAD_PATH, u"TEXT"_s);
+ addColumn(DB_TABLE_TORRENTS, DB_COLUMN_DOWNLOAD_PATH, "TEXT");
if (fromVersion <= 2)
- addColumn(DB_TABLE_TORRENTS, DB_COLUMN_STOP_CONDITION, u"TEXT NOT NULL DEFAULT `None`"_s);
+ addColumn(DB_TABLE_TORRENTS, DB_COLUMN_STOP_CONDITION, "TEXT NOT NULL DEFAULT `None`");
if (fromVersion <= 3)
{
@@ -544,44 +618,17 @@ void BitTorrent::DBResumeDataStorage::updateDB(const int fromVersion) const
}
if (fromVersion <= 4)
- addColumn(DB_TABLE_TORRENTS, DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT, u"INTEGER NOT NULL DEFAULT -2"_s);
+ addColumn(DB_TABLE_TORRENTS, DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT, "INTEGER NOT NULL DEFAULT -2");
if (fromVersion <= 5)
{
- addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SSL_CERTIFICATE, u"TEXT"_s);
- addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SSL_PRIVATE_KEY, u"TEXT"_s);
- addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SSL_DH_PARAMS, u"TEXT"_s);
+ addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SSL_CERTIFICATE, "TEXT");
+ addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SSL_PRIVATE_KEY, "TEXT");
+ addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SSL_DH_PARAMS, "TEXT");
}
if (fromVersion <= 6)
- addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SHARE_LIMIT_ACTION, u"TEXT NOT NULL DEFAULT `Default`"_s);
-
- if (fromVersion == 7)
- {
- const QString TEMP_COLUMN_NAME = DB_COLUMN_SHARE_LIMIT_ACTION.name + u"_temp";
-
- auto queryStr = u"ALTER TABLE %1 ADD %2 %3"_s
- .arg(quoted(DB_TABLE_TORRENTS), TEMP_COLUMN_NAME, u"TEXT NOT NULL DEFAULT `Default`");
- if (!query.exec(queryStr))
- throw RuntimeError(query.lastError().text());
-
- queryStr = u"UPDATE %1 SET %2 = %3"_s
- .arg(quoted(DB_TABLE_TORRENTS), quoted(TEMP_COLUMN_NAME), quoted(DB_COLUMN_SHARE_LIMIT_ACTION.name));
- if (!query.exec(queryStr))
- throw RuntimeError(query.lastError().text());
-
- queryStr = u"ALTER TABLE %1 DROP %2"_s.arg(quoted(DB_TABLE_TORRENTS), quoted(DB_COLUMN_SHARE_LIMIT_ACTION.name));
- if (!query.exec(queryStr))
- throw RuntimeError(query.lastError().text());
-
- queryStr = u"ALTER TABLE %1 RENAME %2 TO %3"_s
- .arg(quoted(DB_TABLE_TORRENTS), quoted(TEMP_COLUMN_NAME), quoted(DB_COLUMN_SHARE_LIMIT_ACTION.name));
- if (!query.exec(queryStr))
- throw RuntimeError(query.lastError().text());
- }
-
- if (fromVersion <= 8)
- addColumn(DB_TABLE_TORRENTS, DB_COLUMN_COMMENT, u"TEXT"_s);
+ addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SHARE_LIMIT_ACTION, "TEXTNOT NULL DEFAULT `Default`");
const QString updateMetaVersionQuery = makeUpdateStatement(DB_TABLE_META, {DB_COLUMN_NAME, DB_COLUMN_VALUE});
if (!query.prepare(updateMetaVersionQuery))
@@ -619,91 +666,6 @@ void BitTorrent::DBResumeDataStorage::enableWALMode() const
throw RuntimeError(tr("WAL mode is probably unsupported due to filesystem limitations."));
}
-LoadResumeDataResult DBResumeDataStorage::parseQueryResultRow(const QSqlQuery &query) const
-{
- LoadTorrentParams resumeData;
- resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
- resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
- resumeData.comment = query.value(DB_COLUMN_COMMENT.name).toString();
- const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
- if (!tagsData.isEmpty())
- {
- const QStringList tagList = tagsData.split(u',');
- resumeData.tags.insert(tagList.cbegin(), tagList.cend());
- }
- resumeData.hasFinishedStatus = query.value(DB_COLUMN_HAS_SEED_STATUS.name).toBool();
- resumeData.firstLastPiecePriority = query.value(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY.name).toBool();
- resumeData.ratioLimit = query.value(DB_COLUMN_RATIO_LIMIT.name).toInt() / 1000.0;
- resumeData.seedingTimeLimit = query.value(DB_COLUMN_SEEDING_TIME_LIMIT.name).toInt();
- resumeData.inactiveSeedingTimeLimit = query.value(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT.name).toInt();
- resumeData.shareLimitAction = Utils::String::toEnum(
- query.value(DB_COLUMN_SHARE_LIMIT_ACTION.name).toString(), ShareLimitAction::Default);
- resumeData.contentLayout = Utils::String::toEnum(
- query.value(DB_COLUMN_CONTENT_LAYOUT.name).toString(), TorrentContentLayout::Original);
- resumeData.operatingMode = Utils::String::toEnum(
- query.value(DB_COLUMN_OPERATING_MODE.name).toString(), TorrentOperatingMode::AutoManaged);
- resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
- resumeData.stopCondition = Utils::String::toEnum(
- query.value(DB_COLUMN_STOP_CONDITION.name).toString(), Torrent::StopCondition::None);
- resumeData.sslParameters =
- {
- .certificate = QSslCertificate(query.value(DB_COLUMN_SSL_CERTIFICATE.name).toByteArray()),
- .privateKey = Utils::SSLKey::load(query.value(DB_COLUMN_SSL_PRIVATE_KEY.name).toByteArray()),
- .dhParams = query.value(DB_COLUMN_SSL_DH_PARAMS.name).toByteArray()
- };
-
- resumeData.savePath = Profile::instance()->fromPortablePath(
- Path(query.value(DB_COLUMN_TARGET_SAVE_PATH.name).toString()));
- resumeData.useAutoTMM = resumeData.savePath.isEmpty();
- if (!resumeData.useAutoTMM)
- {
- resumeData.downloadPath = Profile::instance()->fromPortablePath(
- Path(query.value(DB_COLUMN_DOWNLOAD_PATH.name).toString()));
- }
-
- const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
- const auto *pref = Preferences::instance();
- const int bdecodeDepthLimit = pref->getBdecodeDepthLimit();
- const int bdecodeTokenLimit = pref->getBdecodeTokenLimit();
-
- lt::error_code ec;
- const lt::bdecode_node resumeDataRoot = lt::bdecode(bencodedResumeData, ec, nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
- if (ec)
- return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message())));
-
- lt::add_torrent_params &p = resumeData.ltAddTorrentParams;
-
- p = lt::read_resume_data(resumeDataRoot, ec);
- if (ec)
- return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message())));
-
- if (const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray()
- ; !bencodedMetadata.isEmpty())
- {
- const lt::bdecode_node torentInfoRoot = lt::bdecode(bencodedMetadata, ec
- , nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
- if (ec)
- return nonstd::make_unexpected(tr("Cannot parse torrent info: %1").arg(QString::fromStdString(ec.message())));
-
- p.ti = std::make_shared(torentInfoRoot, ec);
- if (ec)
- return nonstd::make_unexpected(tr("Cannot parse torrent info: %1").arg(QString::fromStdString(ec.message())));
- }
-
- p.save_path = Profile::instance()->fromPortablePath(Path(fromLTString(p.save_path)))
- .toString().toStdString();
- if (p.save_path.empty())
- return nonstd::make_unexpected(tr("Corrupted resume data: %1").arg(tr("save_path is invalid")));
-
- if (p.flags & lt::torrent_flags::stop_when_ready)
- {
- p.flags &= ~lt::torrent_flags::stop_when_ready;
- resumeData.stopCondition = Torrent::StopCondition::FilesChecked;
- }
-
- return resumeData;
-}
-
BitTorrent::DBResumeDataStorage::Worker::Worker(const Path &dbPath, QReadWriteLock &dbLock, QObject *parent)
: QThread(parent)
, m_path {dbPath}
@@ -775,9 +737,9 @@ void DBResumeDataStorage::Worker::requestInterruption()
m_waitCondition.wakeAll();
}
-void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, LoadTorrentParams resumeData)
+void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const LoadTorrentParams &resumeData)
{
- addJob(std::make_unique(id, std::move(resumeData)));
+ addJob(std::make_unique(id, resumeData));
}
void BitTorrent::DBResumeDataStorage::Worker::remove(const TorrentID &id)
@@ -785,7 +747,7 @@ void BitTorrent::DBResumeDataStorage::Worker::remove(const TorrentID &id)
addJob(std::make_unique(id));
}
-void BitTorrent::DBResumeDataStorage::Worker::storeQueue(const QList &queue)
+void BitTorrent::DBResumeDataStorage::Worker::storeQueue(const QVector &queue)
{
addJob(std::make_unique(queue));
}
@@ -803,9 +765,9 @@ namespace
{
using namespace BitTorrent;
-StoreJob::StoreJob(const TorrentID &torrentID, LoadTorrentParams resumeData)
+ StoreJob::StoreJob(const TorrentID &torrentID, const LoadTorrentParams &resumeData)
: m_torrentID {torrentID}
- , m_resumeData {std::move(resumeData)}
+ , m_resumeData {resumeData}
{
}
@@ -835,12 +797,11 @@ StoreJob::StoreJob(const TorrentID &torrentID, LoadTorrentParams resumeData)
}
}
- QList columns {
+ QVector columns {
DB_COLUMN_TORRENT_ID,
DB_COLUMN_NAME,
DB_COLUMN_CATEGORY,
DB_COLUMN_TAGS,
- DB_COLUMN_COMMENT,
DB_COLUMN_TARGET_SAVE_PATH,
DB_COLUMN_DOWNLOAD_PATH,
DB_COLUMN_CONTENT_LAYOUT,
@@ -906,7 +867,6 @@ StoreJob::StoreJob(const TorrentID &torrentID, LoadTorrentParams resumeData)
query.bindValue(DB_COLUMN_CATEGORY.placeholder, m_resumeData.category);
query.bindValue(DB_COLUMN_TAGS.placeholder, (m_resumeData.tags.isEmpty()
? QString() : Utils::String::joinIntoString(m_resumeData.tags, u","_s)));
- query.bindValue(DB_COLUMN_COMMENT.placeholder, m_resumeData.comment);
query.bindValue(DB_COLUMN_CONTENT_LAYOUT.placeholder, Utils::String::fromEnum(m_resumeData.contentLayout));
query.bindValue(DB_COLUMN_RATIO_LIMIT.placeholder, static_cast(m_resumeData.ratioLimit * 1000));
query.bindValue(DB_COLUMN_SEEDING_TIME_LIMIT.placeholder, m_resumeData.seedingTimeLimit);
@@ -969,7 +929,7 @@ StoreJob::StoreJob(const TorrentID &torrentID, LoadTorrentParams resumeData)
}
}
- StoreQueueJob::StoreQueueJob(const QList &queue)
+ StoreQueueJob::StoreQueueJob(const QVector &queue)
: m_queue {queue}
{
}
diff --git a/src/base/bittorrent/dbresumedatastorage.h b/src/base/bittorrent/dbresumedatastorage.h
index a98148cd7..97485f298 100644
--- a/src/base/bittorrent/dbresumedatastorage.h
+++ b/src/base/bittorrent/dbresumedatastorage.h
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
- * Copyright (C) 2021-2025 Vladimir Golovnev
+ * Copyright (C) 2021-2022 Vladimir Golovnev
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,9 +31,10 @@
#include
#include "base/pathfwd.h"
+#include "base/utils/thread.h"
#include "resumedatastorage.h"
-class QSqlQuery;
+class QThread;
namespace BitTorrent
{
@@ -46,12 +47,12 @@ namespace BitTorrent
explicit DBResumeDataStorage(const Path &dbPath, QObject *parent = nullptr);
~DBResumeDataStorage() override;
- QList registeredTorrents() const override;
+ QVector registeredTorrents() const override;
LoadResumeDataResult load(const TorrentID &id) const override;
- void store(const TorrentID &id, LoadTorrentParams resumeData) const override;
+ void store(const TorrentID &id, const LoadTorrentParams &resumeData) const override;
void remove(const TorrentID &id) const override;
- void storeQueue(const QList &queue) const override;
+ void storeQueue(const QVector &queue) const override;
private:
void doLoadAll() const override;
@@ -59,7 +60,8 @@ namespace BitTorrent
void createDB() const;
void updateDB(int fromVersion) const;
void enableWALMode() const;
- LoadResumeDataResult parseQueryResultRow(const QSqlQuery &query) const;
+
+ Utils::Thread::UniquePtr m_ioThread;
class Worker;
Worker *m_asyncWorker = nullptr;
diff --git a/src/base/bittorrent/filesearcher.cpp b/src/base/bittorrent/filesearcher.cpp
index e7241b889..2fcd31f8f 100644
--- a/src/base/bittorrent/filesearcher.cpp
+++ b/src/base/bittorrent/filesearcher.cpp
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
- * Copyright (C) 2020-2025 Vladimir Golovnev
+ * Copyright (C) 2020 Vladimir Golovnev
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -27,14 +27,13 @@
*/
#include "filesearcher.h"
-
-#include
-
#include "base/bittorrent/common.h"
+#include "base/bittorrent/infohash.h"
-namespace
+void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &originalFileNames
+ , const Path &savePath, const Path &downloadPath, const bool forceAppendExt)
{
- bool findInDir(const Path &dirPath, PathList &fileNames, const bool forceAppendExt)
+ const auto findInDir = [](const Path &dirPath, PathList &fileNames, const bool forceAppendExt) -> bool
{
bool found = false;
for (Path &fileName : fileNames)
@@ -59,12 +58,8 @@ namespace
}
return found;
- }
-}
+ };
-void FileSearcher::search(const PathList &originalFileNames, const Path &savePath
- , const Path &downloadPath, const bool forceAppendExt, QPromise &promise)
-{
Path usedPath = savePath;
PathList adjustedFileNames = originalFileNames;
const bool found = findInDir(usedPath, adjustedFileNames, (forceAppendExt && downloadPath.isEmpty()));
@@ -74,5 +69,5 @@ void FileSearcher::search(const PathList &originalFileNames, const Path &savePat
findInDir(usedPath, adjustedFileNames, forceAppendExt);
}
- promise.addResult(FileSearchResult {.savePath = usedPath, .fileNames = adjustedFileNames});
+ emit searchFinished(id, usedPath, adjustedFileNames);
}
diff --git a/src/base/bittorrent/filesearcher.h b/src/base/bittorrent/filesearcher.h
index f225b95dc..04495bd76 100644
--- a/src/base/bittorrent/filesearcher.h
+++ b/src/base/bittorrent/filesearcher.h
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
- * Copyright (C) 2020-2025 Vladimir Golovnev
+ * Copyright (C) 2020 Vladimir Golovnev
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -32,13 +32,10 @@
#include "base/path.h"
-template class QPromise;
-
-struct FileSearchResult
+namespace BitTorrent
{
- Path savePath;
- PathList fileNames;
-};
+ class TorrentID;
+}
class FileSearcher final : public QObject
{
@@ -46,8 +43,12 @@ class FileSearcher final : public QObject
Q_DISABLE_COPY_MOVE(FileSearcher)
public:
- using QObject::QObject;
+ FileSearcher() = default;
- void search(const PathList &originalFileNames, const Path &savePath
- , const Path &downloadPath, bool forceAppendExt, QPromise &promise);
+public slots:
+ void search(const BitTorrent::TorrentID &id, const PathList &originalFileNames
+ , const Path &savePath, const Path &downloadPath, bool forceAppendExt);
+
+signals:
+ void searchFinished(const BitTorrent::TorrentID &id, const Path &savePath, const PathList &fileNames);
};
diff --git a/src/base/bittorrent/filterparserthread.cpp b/src/base/bittorrent/filterparserthread.cpp
index 5b5c0659c..56d650ed7 100644
--- a/src/base/bittorrent/filterparserthread.cpp
+++ b/src/base/bittorrent/filterparserthread.cpp
@@ -133,7 +133,7 @@ int FilterParserThread::parseDATFilterFile()
return ruleCount;
}
- std::vector buffer(BUFFER_SIZE, 0); // seems a bit faster than QList
+ std::vector