Compare commits
171 Commits
release-4.
...
release-4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ed9ffcaf2 | ||
|
|
bf986fcf4c | ||
|
|
0036a02a72 | ||
|
|
6e268b007b | ||
|
|
2be2ee6fc2 | ||
|
|
be4fa061ee | ||
|
|
665bbc2421 | ||
|
|
8d408ffc8b | ||
|
|
aa39c7aae5 | ||
|
|
7ad667e8d2 | ||
|
|
0c8220c9fd | ||
|
|
e9364b72f9 | ||
|
|
a004f0afc5 | ||
|
|
d7f172060c | ||
|
|
9eae2b8ea9 | ||
|
|
26e220e003 | ||
|
|
d7e9533e8c | ||
|
|
8306a41d11 | ||
|
|
169c4991d5 | ||
|
|
78344a10fa | ||
|
|
f8d9f70e7f | ||
|
|
011ac90a52 | ||
|
|
c1b38221d2 | ||
|
|
c621cae43b | ||
|
|
ede7c8acbb | ||
|
|
9195df5179 | ||
|
|
a3d5ea829b | ||
|
|
c062f86bac | ||
|
|
e5894831ec | ||
|
|
f40e92f186 | ||
|
|
0ab10ef2b3 | ||
|
|
049e376953 | ||
|
|
6dab4615aa | ||
|
|
0b9a1dfd9d | ||
|
|
11c45db2ec | ||
|
|
ba147d72b9 | ||
|
|
97ead6d7c9 | ||
|
|
51cb3ca0c8 | ||
|
|
c514c2b7a8 | ||
|
|
d26e582cc1 | ||
|
|
5d161d2477 | ||
|
|
b9ea6a5dc5 | ||
|
|
7b0b64a04e | ||
|
|
4cb386af35 | ||
|
|
14ab1b015c | ||
|
|
0a4971c994 | ||
|
|
a75ae21434 | ||
|
|
01eed5dae9 | ||
|
|
e73397c750 | ||
|
|
869d079507 | ||
|
|
71174edf72 | ||
|
|
b3d46ecb78 | ||
|
|
80035a2520 | ||
|
|
6790335239 | ||
|
|
48ff494dca | ||
|
|
c5b361ce74 | ||
|
|
397b7b9407 | ||
|
|
6e0c1e2147 | ||
|
|
e93c360db6 | ||
|
|
270e2023cd | ||
|
|
5ac858213b | ||
|
|
f0ee6aba29 | ||
|
|
fa418087c4 | ||
|
|
8493e1ad64 | ||
|
|
fe90fcef5b | ||
|
|
210fd80167 | ||
|
|
0a1e864f74 | ||
|
|
7adccab687 | ||
|
|
67e536d869 | ||
|
|
86e8d848f6 | ||
|
|
88114b4588 | ||
|
|
e468f004f4 | ||
|
|
4cfccc54ea | ||
|
|
5ffa7e4752 | ||
|
|
d7fd576293 | ||
|
|
83b34053a1 | ||
|
|
b9164adb7a | ||
|
|
8397b118b7 | ||
|
|
74dc000ac1 | ||
|
|
9b61991523 | ||
|
|
702c79a92f | ||
|
|
a27822b557 | ||
|
|
bdcb00a3b2 | ||
|
|
ac5a485651 | ||
|
|
e8c65388eb | ||
|
|
f2cbb61d49 | ||
|
|
0a1c61d9d3 | ||
|
|
01a0fff4c2 | ||
|
|
bf9516d164 | ||
|
|
fdbf8cb0ee | ||
|
|
7e8a176751 | ||
|
|
61504ae3b1 | ||
|
|
dd76525372 | ||
|
|
1c0f8b4289 | ||
|
|
63043b4927 | ||
|
|
3ea4c66d41 | ||
|
|
781d7fbf1a | ||
|
|
e7ebbffbfd | ||
|
|
39f054eef6 | ||
|
|
7a620c794d | ||
|
|
cc13f3e10d | ||
|
|
b0e41abf5a | ||
|
|
5347897b7d | ||
|
|
6f8fae9a7b | ||
|
|
62b50d1475 | ||
|
|
2fb0c86f1e | ||
|
|
aedd997604 | ||
|
|
aa3da942cb | ||
|
|
87e1a14a4b | ||
|
|
00f6bb7c82 | ||
|
|
cca93c2be2 | ||
|
|
ad9d0608d4 | ||
|
|
3c5688c6f6 | ||
|
|
ece92a886a | ||
|
|
85777ea491 | ||
|
|
b8a84dbd83 | ||
|
|
35c31906b7 | ||
|
|
1fa940876f | ||
|
|
c652123145 | ||
|
|
1c52fff1cc | ||
|
|
261f08b90e | ||
|
|
2d48581570 | ||
|
|
b8a7ecfe69 | ||
|
|
cbc2de6b85 | ||
|
|
9d2bb67834 | ||
|
|
3d7ff9765a | ||
|
|
28f2def21f | ||
|
|
0ee303789a | ||
|
|
6ccc92020c | ||
|
|
e3fe66d3ec | ||
|
|
ab5605d54b | ||
|
|
a7a90613c2 | ||
|
|
19d95ebd10 | ||
|
|
0e1849346b | ||
|
|
0f34e3bed9 | ||
|
|
c8b66b25e8 | ||
|
|
e6f07a6fe4 | ||
|
|
51469f8fa2 | ||
|
|
d78b2a569f | ||
|
|
ec6c970775 | ||
|
|
67c45efff7 | ||
|
|
a54772bf35 | ||
|
|
166be2a94d | ||
|
|
7150d05399 | ||
|
|
36a6e22f27 | ||
|
|
dc13eaed1f | ||
|
|
001bd60d36 | ||
|
|
b063042988 | ||
|
|
fa1d49add5 | ||
|
|
b45248bf99 | ||
|
|
dfe862dcd5 | ||
|
|
d4ddeaa917 | ||
|
|
13a49866a7 | ||
|
|
7e2aea92b0 | ||
|
|
7db51b2f8d | ||
|
|
ae1b963e0f | ||
|
|
b29b7e0185 | ||
|
|
71270260bf | ||
|
|
22abbc1d41 | ||
|
|
32698fe0be | ||
|
|
16f8d6a936 | ||
|
|
046d6f3bc1 | ||
|
|
e33c4086b9 | ||
|
|
51d754a53e | ||
|
|
49976bcd83 | ||
|
|
f991d2bdb4 | ||
|
|
e6ff23885e | ||
|
|
7aa859a442 | ||
|
|
180deb867a | ||
|
|
a5c531f0a4 | ||
|
|
5dd70b88d3 |
@@ -3,7 +3,7 @@ version: '{branch}-{build}'
|
||||
# Do not build on tags (GitHub only)
|
||||
skip_tags: true
|
||||
|
||||
image: Visual Studio 2019
|
||||
image: Visual Studio 2022
|
||||
|
||||
branches:
|
||||
except: # blacklist
|
||||
@@ -42,7 +42,7 @@ install:
|
||||
|
||||
before_build:
|
||||
# setup env
|
||||
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
- CALL "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
- SET PATH=%PATH%;C:\Qt\5.15.2\msvc2019_64\bin;%CACHE_DIR%\jom
|
||||
# setup project
|
||||
- COPY /Y "%CACHE_DIR%\conf.pri" "%REPO_DIR%"
|
||||
@@ -56,4 +56,38 @@ build_script:
|
||||
- qmake qbittorrent.pro && cd src && qmake src.pro
|
||||
- jom -j2 -f Makefile.Release
|
||||
|
||||
after_build:
|
||||
- cd "%REPO_DIR%"
|
||||
- MKDIR upload
|
||||
- COPY dist\windows\qt.conf upload
|
||||
- COPY src\release\qbittorrent.exe upload
|
||||
- COPY src\release\qbittorrent.pdb upload
|
||||
- COPY "%CACHE_DIR%\base\bin\libcrypto-1_1-x64.dll" upload
|
||||
- COPY "%CACHE_DIR%\base\bin\libssl-1_1-x64.dll" upload
|
||||
- COPY "%CACHE_DIR%\base\lib\torrent-rasterbar.dll" upload
|
||||
- COPY "%CACHE_DIR%\base\lib\zlib1.dll" upload
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\bin\Qt5Core.dll upload
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\bin\Qt5Gui.dll upload
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\bin\Qt5Network.dll upload
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\bin\Qt5Sql.dll upload
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\bin\Qt5Svg.dll upload
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\bin\Qt5Widgets.dll upload
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\bin\Qt5WinExtras.dll upload
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\bin\Qt5Xml.dll upload
|
||||
- MKDIR upload\plugins\iconengines
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\plugins\iconengines\qsvgicon.dll upload\plugins\iconengines
|
||||
- MKDIR upload\plugins\imageformats
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\plugins\imageformats\qico.dll upload\plugins\imageformats
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\plugins\imageformats\qsvg.dll upload\plugins\imageformats
|
||||
- MKDIR upload\plugins\platforms
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\plugins\platforms\qwindows.dll upload\plugins\platforms
|
||||
- MKDIR upload\plugins\sqldrivers
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\plugins\sqldrivers\qsqlite.dll upload\plugins\sqldrivers
|
||||
- MKDIR upload\plugins\styles
|
||||
- COPY C:\Qt\5.15.2\msvc2019_64\plugins\styles\qwindowsvistastyle.dll upload\plugins\styles
|
||||
|
||||
test: off
|
||||
|
||||
artifacts:
|
||||
- path: upload
|
||||
name: qBittorrent-Appveyor_Windows-x64
|
||||
|
||||
48
.github/workflows/ci_macos.yaml
vendored
@@ -9,14 +9,15 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
libt_version: ["2.0.4", "1.2.14"]
|
||||
libt_version: ["2.0.5", "1.2.15"]
|
||||
qbt_gui: ["GUI=ON", "GUI=OFF"]
|
||||
qt_version: ["5.15.2", "6.2.0"]
|
||||
exclude:
|
||||
- libt_version: "1.2.14"
|
||||
- libt_version: "1.2.15"
|
||||
qt_version: "6.2.0"
|
||||
|
||||
env:
|
||||
boost_path: "${{ github.workspace }}/../boost"
|
||||
openssl_root: /usr/local/opt/openssl@1.1
|
||||
|
||||
steps:
|
||||
@@ -28,28 +29,43 @@ jobs:
|
||||
brew update > /dev/null
|
||||
brew install \
|
||||
cmake ninja \
|
||||
boost openssl@1.1 zlib
|
||||
openssl@1.1 zlib
|
||||
|
||||
- name: Setup ccache
|
||||
uses: Chocobo1/setup-ccache-action@v1
|
||||
with:
|
||||
update_packager_index: false
|
||||
|
||||
- name: Install boost
|
||||
run: |
|
||||
curl \
|
||||
-L \
|
||||
-o "${{ runner.temp }}/boost.tar.bz2" \
|
||||
"https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.bz2"
|
||||
tar -xf "${{ runner.temp }}/boost.tar.bz2" -C "${{ github.workspace }}/.."
|
||||
mv "${{ github.workspace }}/.."/boost_* "${{ env.boost_path }}"
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
setup-python: false
|
||||
version: ${{ matrix.qt_version }}
|
||||
|
||||
- name: Install libtorrent
|
||||
run: |
|
||||
git clone --branch v${{ matrix.libt_version }} --depth 1 https://github.com/arvidn/libtorrent.git
|
||||
git clone \
|
||||
--branch v${{ matrix.libt_version }} \
|
||||
--depth 1 \
|
||||
--recurse-submodules \
|
||||
https://github.com/arvidn/libtorrent.git
|
||||
cd libtorrent
|
||||
git submodule update --init --recursive
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_CXX_STANDARD=17 \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DBOOST_ROOT="${{ env.boost_path }}" \
|
||||
-Ddeprecated-functions=OFF \
|
||||
-DOPENSSL_ROOT_DIR="${{ env.openssl_root }}"
|
||||
cmake --build build
|
||||
@@ -58,12 +74,14 @@ jobs:
|
||||
- name: Build qBittorrent (Qt5)
|
||||
if: ${{ startsWith(matrix.qt_version, 5) }}
|
||||
run: |
|
||||
lupdate -extensions c,cpp,h,hpp,ui ./
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DBOOST_ROOT="${{ env.boost_path }}" \
|
||||
-DOPENSSL_ROOT_DIR="${{ env.openssl_root }}" \
|
||||
-DQt5_DIR="$Qt5_DIR" \
|
||||
-DVERBOSE_CONFIGURE=ON \
|
||||
-D${{ matrix.qbt_gui }}
|
||||
cmake --build build
|
||||
@@ -71,21 +89,29 @@ jobs:
|
||||
- name: Build qBittorrent (Qt6)
|
||||
if: ${{ startsWith(matrix.qt_version, 6) }}
|
||||
run: |
|
||||
lupdate -extensions c,cpp,h,hpp,ui ./
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DBOOST_ROOT="${{ env.boost_path }}" \
|
||||
-DOPENSSL_ROOT_DIR="${{ env.openssl_root }}" \
|
||||
-DQT6=ON \
|
||||
-DQt6_DIR="$Qt6_DIR" \
|
||||
-DVERBOSE_CONFIGURE=ON \
|
||||
-D${{ matrix.qbt_gui }}
|
||||
cmake --build build
|
||||
|
||||
- name: Prepare build artifacts
|
||||
run: |
|
||||
mkdir upload
|
||||
mkdir upload/cmake
|
||||
cp build/compile_commands.json upload/cmake
|
||||
mkdir upload/cmake/libtorrent
|
||||
cp libtorrent/build/compile_commands.json upload/cmake/libtorrent
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: qBittorrent-CI_macOS_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libt_version }}_Qt-${{ matrix.qt_version }}
|
||||
path: |
|
||||
build/qbittorrent.app
|
||||
build/qbittorrent-nox.app
|
||||
name: build-info_macOS_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libt_version }}_Qt-${{ matrix.qt_version }}
|
||||
path: upload
|
||||
|
||||
49
.github/workflows/ci_ubuntu.yaml
vendored
@@ -9,11 +9,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
libt_version: ["2.0.4", "1.2.14"]
|
||||
libt_version: ["2.0.5", "1.2.15"]
|
||||
qbt_gui: ["GUI=ON", "GUI=OFF"]
|
||||
qt_version: ["5.15.2", "6.2.0"]
|
||||
exclude:
|
||||
- libt_version: "1.2.14"
|
||||
- libt_version: "1.2.15"
|
||||
qt_version: "6.2.0"
|
||||
|
||||
steps:
|
||||
@@ -41,59 +41,62 @@ jobs:
|
||||
|
||||
- name: Install libtorrent
|
||||
run: |
|
||||
git clone --branch v${{ matrix.libt_version }} --depth 1 https://github.com/arvidn/libtorrent.git
|
||||
git clone \
|
||||
--branch v${{ matrix.libt_version }} \
|
||||
--depth 1 \
|
||||
--recurse-submodules \
|
||||
https://github.com/arvidn/libtorrent.git
|
||||
cd libtorrent
|
||||
git submodule update --init --recursive
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-Ddeprecated-functions=OFF \
|
||||
--graphviz=cmake-build-dir/target_graph.dot
|
||||
-Ddeprecated-functions=OFF
|
||||
cmake --build build
|
||||
sudo cmake --install build
|
||||
|
||||
- name: Build qBittorrent (Qt5)
|
||||
if: ${{ startsWith(matrix.qt_version, 5) }}
|
||||
run: |
|
||||
lupdate -extensions c,cpp,h,hpp,ui ./
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DQt5_DIR="$Qt5_DIR" \
|
||||
-D${{ matrix.qbt_gui }} \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DVERBOSE_CONFIGURE=ON \
|
||||
--graphviz=build/target_graph.dot
|
||||
-D${{ matrix.qbt_gui }}
|
||||
cmake --build build
|
||||
sudo cmake --install build
|
||||
DESTDIR="qbittorrent" cmake --install build
|
||||
|
||||
- name: Build qBittorrent (Qt6)
|
||||
if: ${{ startsWith(matrix.qt_version, 6) }}
|
||||
run: |
|
||||
lupdate -extensions c,cpp,h,hpp,ui ./
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DQt6_DIR="$Qt6_DIR" \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DQT6=ON \
|
||||
-D${{ matrix.qbt_gui }} \
|
||||
-DVERBOSE_CONFIGURE=ON \
|
||||
--graphviz=build/target_graph.dot
|
||||
-D${{ matrix.qbt_gui }}
|
||||
cmake --build build
|
||||
sudo cmake --install build
|
||||
DESTDIR="qbittorrent" cmake --install build
|
||||
|
||||
- name: Prepare build artifacts
|
||||
run: |
|
||||
mkdir upload
|
||||
mkdir upload/cmake
|
||||
cp build/compile_commands.json upload/cmake
|
||||
mkdir upload/cmake/libtorrent
|
||||
cp libtorrent/build/compile_commands.json upload/cmake/libtorrent
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: qBittorrent-CI_ubuntu-20.04-x64_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libt_version }}_Qt-${{ matrix.qt_version }}
|
||||
path: |
|
||||
build/compile_commands.json
|
||||
build/install_manifest.txt
|
||||
build/target_graph.dot
|
||||
build/qbittorrent
|
||||
build/qbittorrent-nox
|
||||
libtorrent/cmake-build-dir/compile_commands.json
|
||||
libtorrent/cmake-build-dir/target_graph.dot
|
||||
name: build-info_ubuntu-20.04-x64_${{ matrix.qbt_gui }}_libtorrent-${{ matrix.libt_version }}_Qt-${{ matrix.qt_version }}
|
||||
path: upload
|
||||
|
||||
56
.github/workflows/ci_windows.yaml
vendored
@@ -7,12 +7,12 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
libt_version: ["v2.0.4", "v1.2.14"]
|
||||
fail-fast: false
|
||||
matrix:
|
||||
libt_version: ["2.0.5", "1.2.15"]
|
||||
|
||||
env:
|
||||
boost_path: "${{ github.workspace }}/boost"
|
||||
boost_path: "${{ github.workspace }}/../boost"
|
||||
libtorrent_path: "${{ github.workspace }}/libtorrent"
|
||||
|
||||
steps:
|
||||
@@ -35,9 +35,9 @@ jobs:
|
||||
doNotUpdateVcpkg: true # the preinstalled vcpkg is updated regularly
|
||||
setupOnly: true
|
||||
|
||||
# tell vcpkg to only build Release variants of the dependencies
|
||||
- name: Configure vcpkg triplet overlay
|
||||
- name: Install dependencies from vcpkg
|
||||
run: |
|
||||
# tell vcpkg to only build Release variants of the dependencies
|
||||
New-Item `
|
||||
-Path "${{ github.workspace }}" `
|
||||
-Name "triplets_overlay" `
|
||||
@@ -48,16 +48,9 @@ jobs:
|
||||
Add-Content `
|
||||
"${{ github.workspace }}/triplets_overlay/x64-windows-static-release.cmake" `
|
||||
-Value "set(VCPKG_BUILD_TYPE release)"
|
||||
|
||||
# clear buildtrees after each package installation to reduce disk space requirements
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# clear buildtrees after each package installation to reduce disk space requirements
|
||||
$packages = `
|
||||
"openssl:x64-windows-static-release",
|
||||
"qt5-base:x64-windows-static-release",
|
||||
"qt5-svg:x64-windows-static-release",
|
||||
"qt5-tools:x64-windows-static-release",
|
||||
"qt5-winextras:x64-windows-static-release",
|
||||
"zlib:x64-windows-static-release"
|
||||
${{ env.RUNVCPKG_VCPKG_ROOT }}/vcpkg.exe upgrade `
|
||||
--overlay-triplets="${{ github.workspace }}/triplets_overlay" `
|
||||
@@ -76,15 +69,24 @@ jobs:
|
||||
7z x "${{ runner.temp }}/boost.7z" -o"${{ github.workspace }}/.."
|
||||
move "${{ github.workspace }}/../boost_*" "${{ env.boost_path }}"
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: "5.15.2"
|
||||
|
||||
- name: Install libtorrent
|
||||
run: |
|
||||
git clone --branch ${{ matrix.libt_version }} --depth 1 https://github.com/arvidn/libtorrent.git
|
||||
git clone `
|
||||
--branch v${{ matrix.libt_version }} `
|
||||
--depth 1 `
|
||||
--recurse-submodules `
|
||||
https://github.com/arvidn/libtorrent.git
|
||||
cd libtorrent
|
||||
git submodule update --init --recursive
|
||||
cmake `
|
||||
-B build `
|
||||
-G "Ninja" `
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON `
|
||||
-DCMAKE_INSTALL_PREFIX="${{ env.libtorrent_path }}" `
|
||||
-DCMAKE_TOOLCHAIN_FILE="${{ env.RUNVCPKG_VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake" `
|
||||
-DBOOST_ROOT="${{ env.boost_path }}" `
|
||||
@@ -97,6 +99,7 @@ jobs:
|
||||
|
||||
- name: Build qBittorrent
|
||||
run: |
|
||||
lupdate -extensions c,cpp,h,hpp,ui .
|
||||
cmake `
|
||||
-B build `
|
||||
-G "Ninja" `
|
||||
@@ -117,9 +120,32 @@ jobs:
|
||||
copy build/qbittorrent.exe upload
|
||||
copy build/qbittorrent.pdb upload
|
||||
copy dist/windows/qt.conf upload
|
||||
# runtimes
|
||||
copy "${{ env.Qt5_DIR }}/bin/Qt5Core.dll" upload
|
||||
copy "${{ env.Qt5_DIR }}/bin/Qt5Gui.dll" upload
|
||||
copy "${{ env.Qt5_DIR }}/bin/Qt5Network.dll" upload
|
||||
copy "${{ env.Qt5_DIR }}/bin/Qt5Sql.dll" upload
|
||||
copy "${{ env.Qt5_DIR }}/bin/Qt5Svg.dll" upload
|
||||
copy "${{ env.Qt5_DIR }}/bin/Qt5Widgets.dll" upload
|
||||
copy "${{ env.Qt5_DIR }}/bin/Qt5WinExtras.dll" upload
|
||||
copy "${{ env.Qt5_DIR }}/bin/Qt5Xml.dll" upload
|
||||
mkdir upload/plugins/iconengines
|
||||
copy "${{ env.Qt5_DIR }}/plugins/iconengines/qsvgicon.dll" upload/plugins/iconengines
|
||||
mkdir upload/plugins/imageformats
|
||||
copy "${{ env.Qt5_DIR }}/plugins/imageformats/qico.dll" upload/plugins/imageformats
|
||||
copy "${{ env.Qt5_DIR }}/plugins/imageformats/qsvg.dll" upload/plugins/imageformats
|
||||
mkdir upload/plugins/platforms
|
||||
copy "${{ env.Qt5_DIR }}/plugins/platforms/qwindows.dll" upload/plugins/platforms
|
||||
mkdir upload/plugins/sqldrivers
|
||||
copy "${{ env.Qt5_DIR }}/plugins/sqldrivers/qsqlite.dll" upload/plugins/sqldrivers
|
||||
mkdir upload/plugins/styles
|
||||
copy "${{ env.Qt5_DIR }}/plugins/styles/qwindowsvistastyle.dll" upload/plugins/styles
|
||||
# cmake additionals
|
||||
mkdir upload/cmake
|
||||
copy build/compile_commands.json upload/cmake
|
||||
copy build/target_graph.dot upload/cmake
|
||||
mkdir upload/cmake/libtorrent
|
||||
copy libtorrent/build/compile_commands.json upload/cmake/libtorrent
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
|
||||
19
.github/workflows/coverity-scan.yml
vendored
@@ -15,21 +15,28 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-focal
|
||||
sudo apt update
|
||||
sudo apt install \
|
||||
build-essential cmake ninja-build pkg-config \
|
||||
libboost-dev libssl-dev qt515base qt515svg qt515tools zlib1g-dev
|
||||
libboost-dev libssl-dev zlib1g-dev
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: "5.15.2"
|
||||
|
||||
- name: Install libtorrent
|
||||
run: |
|
||||
git clone --branch v2.0.4 --depth 1 https://github.com/arvidn/libtorrent.git
|
||||
git clone \
|
||||
--branch "v2.0.5" \
|
||||
--depth 1 \
|
||||
--recurse-submodules \
|
||||
https://github.com/arvidn/libtorrent.git
|
||||
cd libtorrent
|
||||
git submodule update --init --recursive
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-Ddeprecated-functions=OFF
|
||||
cmake --build build
|
||||
sudo cmake --install build
|
||||
@@ -49,7 +56,7 @@ jobs:
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DGUI=ON \
|
||||
-DVERBOSE_CONFIGURE=ON
|
||||
export PATH="$(pwd)/coverity_tool/bin:$PATH"
|
||||
|
||||
388
Changelog
@@ -1,6 +1,269 @@
|
||||
Unreleased - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.4.0
|
||||
- FEATURE: Add support for creating v2 torrents(requires libtorrent 2.0.x) (Chocobo1)
|
||||
Sun May 22 2022 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.4.3
|
||||
- BUGFIX: Correctly handle changing of temp save path (glassez)
|
||||
- BUGFIX: Fix storage in SQLite (glassez)
|
||||
- BUGFIX: Correctly apply content layout when "Skip hash check" is enabled (glassez)
|
||||
- BUGFIX: Don't corrupt IDs of v2 torrents (glassez)
|
||||
- BUGFIX: Reduce the number of hashing threads by default (improves hashing speed on HDDs) (summer)
|
||||
- BUGFIX: Prevent the "update dialog" from blocking input on other windows (summer)
|
||||
- BUGFIX: Add trackers in exported .torrent files (glassez)
|
||||
- BUGFIX: Fix wrong GUI behavior in "Optional IP address to bind to" setting (Chocobo1)
|
||||
- WEBUI: Fix WebUI crash due to missing tags from config (An0n)
|
||||
- WEBUI: Show correct location path (Chocobo1)
|
||||
- MACOS: Fix main window freezing after opening a files dialog (glassez)
|
||||
|
||||
Tue Mar 22 2022 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.4.2
|
||||
- FEATURE: Allow to limit max memory working set size (glassez)
|
||||
- BUGFIX: Fix UI crash when torrent is in a non-existent category (Kevin Cox)
|
||||
- BUGFIX: Correctly handle changing of global save paths (glassez)
|
||||
- BUGFIX: Disable performance alert (Chocobo1)
|
||||
- BUGFIX: Prevent loading resume data with inconsistent ID (glassez)
|
||||
- BUGFIX: Properly handle metadata download for an existing torrent (glassez)
|
||||
- BUGFIX: Prevent crash when open torrent destination folder (glassez)
|
||||
- WINDOWS: NSIS: Update Spanish, Spanish International and French translations(Juanjo Jiménez, RqndomHax)
|
||||
|
||||
Tue Feb 15 2022 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.4.1
|
||||
- FEATURE: Restore all torrent settings to the torrent's main context menu (thalieht)
|
||||
- FEATURE: Add confirmation for enabling Auto TMM from context menu (thalieht)
|
||||
- FEATURE: Add tooltip to Automatic Torrent Management context menu action (thalieht)
|
||||
- FEATURE: Add Select All/None buttons in new torrent dialog (thalieht)
|
||||
- BUGFIX: Keep "torrent info" alive while generate .torrent file (glassez)
|
||||
- BUGFIX: Correctly handle Auto TMM in Torrent Files Watcher (glassez)
|
||||
- BUGFIX: Correctly track the root folder name change (glassez)
|
||||
- BUGFIX: Various fixes to the moving torrent code (glassez)
|
||||
- BUGFIX: Update the torrent's download path field when changing category (thalieht)
|
||||
- BUGFIX: Correctly handle received metadata (glassez)
|
||||
- BUGFIX: Store hybrid torrents using legacy filenames (glassez)
|
||||
- BUGFIX: Open correct directory when clicked on Browse button (glassez)
|
||||
- BUGFIX: Fix crash when shutting down and clicing on system tray icon (Chocobo1)
|
||||
- BUGFIX: Fix "Free space on disk" in new torrent dialog (thalieht)
|
||||
- BUGFIX: Optimize completed files handling (Prince Gupta)
|
||||
- BUGFIX: Migrate proxy settings (sledgehammer999)
|
||||
- BUGFIX: Try to recover missing categories (glassez)
|
||||
- WEBUI: WebAPI: fix wrong key used for categories (Chocobo1)
|
||||
- WEBUI: Remove hack for outdated IE 6 browser (Chocobo1)
|
||||
- RSS: Correctly handle XML parsing errors (glassez)
|
||||
|
||||
Thu Jan 06 2022 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.4.0
|
||||
- FEATURE: Support for v2 torrents along with libtorrent 2.0.x support (glassez, Chocobo1)
|
||||
- FEATURE: Support for Qt6 (glassez)
|
||||
- FEATURE: Expose libtorrent hashing_threads settings (Anton Bershanskiy)
|
||||
- FEATURE: Add "Notification timeout" option (kevtechxx)
|
||||
- FEATURE: Add `connection_speed` to advanced settings (Chocobo1)
|
||||
- FEATURE: Announce to all trackers if IP changed (#15001) (zhuangzi926)
|
||||
- FEATURE: Add tooltip for various columns (Chocobo1)
|
||||
- FEATURE: Add context menu to toggle content tab columns (#15164) (AbeniMatteo)
|
||||
- FEATURE: Add filter "Checking" to side panel (#15166) (AbeniMatteo)
|
||||
- FEATURE: Add "Forced metadata downloading" state (#15185) (AbeniMatteo)
|
||||
- FEATURE: Remember last viewed page in Options dialog (#15230) (Chocobo1)
|
||||
- FEATURE: Add tooltip to listening port spinbox (Chocobo1)
|
||||
- FEATURE: Add "Skip hash check" option for watched folders (glassez)
|
||||
- FEATURE: Add "Show torrent options" double-click action (glassez)
|
||||
- FEATURE: Allow setting temp folder per torrent/catergory (glassez)
|
||||
- FEATURE: Support folder based UI Themes (Prince Gupta)
|
||||
- BUGFIX: Save "resume data" once file priority is changed (glassez)
|
||||
- BUGFIX: Show priority menu at top level if there is no other in Add New Torrent dialog (FozzeY)
|
||||
- BUGFIX: Capitalize "peer flags" descriptions (Chocobo1)
|
||||
- BUGFIX: Reorder peer flags (Chocobo1)
|
||||
- BUGFIX: Show "last activity" value under all circumstances (Chocobo1)
|
||||
- BUGFIX: Elide text from the right for all columns' header (smigii)
|
||||
- BUGFIX: Fix startup with different profiles (jagannatharjun)
|
||||
- BUGFIX: Move a few torrent context menu actions into "Torrent options" dialog (thalieht)
|
||||
- BUGFIX: Allow deselecting radio buttons in "Torrent options" for mixed torrents (thalieht)
|
||||
- BUGFIX: Apply file priority changes correctly (a-sum-duma, Chocobo1)
|
||||
- BUGFIX: Use proper string for Korean language (OctopusET)
|
||||
- BUGFIX: Disable "add peers" menu items instead of hiding it (Chocobo1)
|
||||
- BUGFIX: Disable system tray icon menu when app is exiting (Chocobo1)
|
||||
- BUGFIX: Show GUI lock icon after system tray icon is initialized (Chocobo1)
|
||||
- BUGFIX: Apply selected layout to displayed torrent content in "Add New Torrent" dialog (glassez)
|
||||
- WEBUI: Add reverse proxy source IP resolution (#15047) (HiFiPhile)
|
||||
- WEBUI: Support navigating UI tables with arrow keys (Thomas Piccirello)
|
||||
- WEBUI: Support expanding/collapsing UI folders with arrow keys (Thomas Piccirello)
|
||||
- WEBUI: Support sorting UI tables via touch (#15205) (Tom Piccirello)
|
||||
- WEBUI: Add pieces progress bar to General tab (Jesse Smick)
|
||||
- WEBUI: Update authors page (Chocobo1)
|
||||
- WEBUI: Set icon sizes attribute (Daniel Aleksandersen)
|
||||
- WEBUI: Add meta application name (Daniel Aleksandersen)
|
||||
- WEBUI: Sort WebUI language selection values (Chocobo1)
|
||||
- WEBUI: Use correct URL scheme in user prompt when HTTPS is enabled (Chocobo1)
|
||||
- RSS: Stick Unread row to top in RSS feed list (Prince Gupta)
|
||||
- RSS: Correctly use fallback icons for RSS feed in GUI (jagannatharjun)
|
||||
- SEARCH: Add context menu for tabs in search widget (#14926) (Anton)
|
||||
- SEARCH: Add more download options to torrent search result right-click menu (a-sum-duma)
|
||||
- WINDOWS: Add windows-clang support (#15115) (Biswapriyo Nath)
|
||||
- WINDOWS: Update python installer URL for Windows (xavier2k6)
|
||||
- WINDOWS: NSIS: Update Simplified Chinese translation (Losiki)
|
||||
- LINUX: Prolong wait time for shutdown for qbittorrent-nox (Chocobo1)
|
||||
- LINUX: Install vector program icon (Chocobo1)
|
||||
- LINUX: Add detection for OpenBSD, Haiku in configure script (Chocobo1)
|
||||
- MACOS: Update Mac icons for Big Sur (17jiangz1)
|
||||
- EXPERIMENTAL: Setting to store/load fastresume/torrent files in an SQLite database (glassez)
|
||||
- OTHER: Many internal code refactorings and bug fixing by many people
|
||||
|
||||
Sun Oct 31 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.9
|
||||
- BUGFIX: Fix "no action" option on torrent double click (Jose M. Abuin)
|
||||
- BUGFIX: Fix broken behavior of "priority by shown file order" (Chocobo1)
|
||||
- WEBUI: Fix WebUI crash when tracker URL is invalid (Chocobo1)
|
||||
- WEBUI: Revert "WebUI: group trackers by hostname" (Chocobo1)
|
||||
- WINDOWS: Remove Windows Vista support from manifest (xavier2k6)
|
||||
- WINDOWS: NSIS: Update Korean, Indonesian and Traditional Chinese translation (JungHee Lee, Faisal Al-Munawar Fathur Rahman, SiderealArt)
|
||||
|
||||
Sun Aug 29 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.8
|
||||
- BUGFIX: Delay processing of watched folders (#15282) (glassez)
|
||||
- BUGFIX: Use the same icon for selecting folders/files (Chocobo1)
|
||||
- BUGFIX: Use default upper limits for ddns entries (Chocobo1)
|
||||
- WEBUI: Expose SSRF mitigation (#15247) (Sylvain Finot)
|
||||
- WEBUI: Update webui libraries (Chocobo1)
|
||||
- WEBUI: Group trackers by hostname (#15264) (Mengyang Li)
|
||||
- WEBUI: Improve "last activity" calculation in WebAPI (#15339) (Chocobo1)
|
||||
- WINDOWS: NSIS: Add Polish translation (#15262) (Matthaiks)
|
||||
|
||||
Tue Aug 03 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.7
|
||||
- BUGFIX: Don't forget to start Watched folders timer (glassez)
|
||||
- BUGFIX: Don't close tags menu when toggling items (tgregerson)
|
||||
- BUGFIX: Don't overwrite tracker message (glassez)
|
||||
- BUGFIX: Bump file pool size (#14966) (An0n)
|
||||
- BUGFIX: Properly create "clean path" for watched folder (glassez)
|
||||
- WEBUI: Disconnect comment links (Daniel Aleksandersen)
|
||||
- WINDOWS: NSIS: Update Danish translation (scootergrisen)
|
||||
|
||||
Sat Jun 26 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.6
|
||||
- FEATURE: New languages: Mongolian, Persian, Thai
|
||||
- BUGFIX: Provide correct error description in "upload mode" (glassez)
|
||||
- BUGFIX: Allow adding torrents with relative save path (glassez)
|
||||
- BUGFIX: Fix main window turns blank after restoring from tray (#15031) (Chocobo1)
|
||||
- BUGFIX: Remove the lockfile on exit (#14997) (brvphoenix)
|
||||
- BUGFIX: Improve "Watched folders" feature (glassez)
|
||||
- BUGFIX: Keep sub-sorting order (#15074) (Dmitry Khlestkov)
|
||||
- BUGFIX: Properly add torrent with new tags (glassez)
|
||||
- WINDOWS: NSIS: Update Japanese, Turkish, Hungarian, Swedish translation (maboroshin, Burak Yavuz, xkrstudio, nonew-star)
|
||||
|
||||
Sun May 02 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.5
|
||||
- BUGFIX: Move cursor to the end when autofilling URL/hash in "Download from URLs" dialog (Chocobo1)
|
||||
- BUGFIX: Sort invalid QDateTime values after valid values (Chocobo1)
|
||||
- BUGFIX: Fix tabChangesFocus attribute in "Edit trackers" dialog (Christoph Rackwitz)
|
||||
- BUGFIX: Update DynDNS register url (zhuangzi926)
|
||||
- BUGFIX: Handle "not enough disk space" error more graciously (glassez)
|
||||
- BUGFIX: Correctly draw progress background with stylesheet (jagannatharjun)
|
||||
- WEBUI: Fix magnet url from the search facility (Chocobo1)
|
||||
- WEBUI: Revise folder monitoring functions (Chocobo1)
|
||||
- WEBUI: Fix magnet url from the browser (brvphoenix)
|
||||
- WEBUI: Allow to specify file indexes in torrents/files API (glassez)
|
||||
- WINDOWS: NSIS: Allow more strings to translated (bovirus, Chocobo1)
|
||||
- WINDOWS: NSIS: Update Italian, German, Estonian, Russian, PortugueseBR translations (bovirus, Henry Water, PriitUring, Долматов Алексей, Felipe)
|
||||
- LINUX: Fix D-Bus Notification `desktop-entry` field (Chocobo1)
|
||||
- MACOS: Don't use executable name as CFBundleName value (Nick Korotysh)
|
||||
- OTHER: Lower Qt requirement to 5.11 (sledgehammer999)
|
||||
- OTHER: Clarify that the license is GPLv2+ (sledgehammer999)
|
||||
|
||||
Wed Mar 24 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.4.1
|
||||
- BUGFIX: Correctly draw progress bar (glassez)
|
||||
- WEBUI: Fix javascript code which broke the UI (Chocobo1)
|
||||
|
||||
Tue Mar 23 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.4
|
||||
- FEATURE: Add ability to prioritize selected items by shown file order (Chocobo1)
|
||||
- FEATURE: Allow tab to escape the text box in "Edit trackers" dialog (Christoph Rackwitz)
|
||||
- FEATURE: Support sub-sorting in Transferlist (jagannatharjun)
|
||||
- FEATURE: Expose ToS setting from libtorrent (Chocobo1)
|
||||
- FEATURE: Improve tracker entries handling (glassez)
|
||||
- BUGFIX: Drop extension from generated content folder name (glassez)
|
||||
- BUGFIX: Change qBittorrent Updater window title (xavier2k6)
|
||||
- BUGFIX: Validate HTTPS Tracker Certificate by default (an0n666)
|
||||
- BUGFIX: Don't let "program update" dialog steal focus (Chocobo1)
|
||||
- BUGFIX: Disable expand on double click in TorrentContentTreeView (jagannatharjun)
|
||||
- BUGFIX: Add hyperlink to Transifex on translator list (Si Yong Kim)
|
||||
- BUGFIX: Enlarge "speed limit" icon slightly (Chocobo1)
|
||||
- BUGFIX: Don't prevent system sleep due to errored torrents (dyumin)
|
||||
- BUGFIX: Use stable sorting in transfer list (Chocobo1)
|
||||
- BUGFIX: Allow "missing files" torrents to save more resume data (glassez)
|
||||
- BUGFIX: Restart "missing files" torrents after changing location (glassez)
|
||||
- BUGFIX: Show proper string when torrent availability is not available (Chocobo1)
|
||||
- BUGFIX: Apply "Hide zero/infinity values" to "Time Active", "Down/Up Limit" and ETA columns (Chocobo1)
|
||||
- BUGFIX: Fix potential out-of-bounds access (Chocobo1)
|
||||
- BUGFIX: Make SpeedPlotView averager time aware (jagannatharjun)
|
||||
- BUGFIX: Add a 3-Hour graph (jagannatharjun)
|
||||
- BUGFIX: Add an option to disable icons in menus (always disabled on MacOS) (Michał Kopeć)
|
||||
- BUGFIX: Improve detection of filename extension of audio/video files (Chocobo1)
|
||||
- BUGFIX: Various drawing improvements of progress bar (Chocobo1)
|
||||
- BUGFIX: Properly stop torrent creation if aborted (Chocobo1)
|
||||
- BUGFIX: Replace external program parameters in one step (Chocobo1)
|
||||
- BUGFIX: Improve "save resume data" handling (glassez)
|
||||
- BUGFIX: Fix bad IPv6 address format for outgoingInterfaces (treysis)
|
||||
- WEBUI: Properly decode strings (brvphoenix)
|
||||
- WEBUI: Accept "share limits" when adding torrent using WebAPI (glassez)
|
||||
- WEBUI: Add seeding time to the active time column (thalieht)
|
||||
- WEBUI: Fix incorrect seeding time string in General tab (thalieht)
|
||||
- WEBUI: Allow >100 days in WebUI function "friendlyDuration" (thalieht)
|
||||
- WEBUI: Avoid decoding strings repeatedly (brvphoenix)
|
||||
- RSS: Add category button on AutomatedRSSDownloader on GUI (Si Yong Kim)
|
||||
- WINDOWS: NSIS: Update Czech translation (slrslr)
|
||||
- WINDOWS: NSIS: Update Portuguese BR translation (Alex)
|
||||
- WINDOWS: NSIS: Add Estonian translation (PriitUring)
|
||||
- WINDOWS: Allow change-case-only file renaming (glassez)
|
||||
- LINUX: Systemd: wait for mounting of local filesystems (Juraj Oršulić)
|
||||
- OTHER: Raise minimum libtorrent version to 1.2.12 (glassez)
|
||||
- OTHER: Raise minimum Qt version to 5.12 (glassez)
|
||||
|
||||
Tue Jan 19 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.3
|
||||
- FEATURE: New languages: Azerbaijani, Estonian
|
||||
- BUGFIX: Unify global speed dialogs for normal/alternative speeds (thalieht)
|
||||
- BUGFIX: Increase maximum global speed limits ~2 GiB/s (thalieht)
|
||||
- BUGFIX: Save fastresume when setting torrent speed limits (thalieht)
|
||||
- BUGFIX: Group several torrent options into one dialog (thalieht)
|
||||
- BUGFIX: Capitalize locale names (Chocobo1)
|
||||
- BUGFIX: Improve content file/folder names handling (glassez)
|
||||
- BUGFIX: Drop notification about move storage finished or failed (glassez)
|
||||
- BUGFIX: Reload "missing files" torrent instead of re-checking (glassez)
|
||||
- BUGFIX: Remember dialog sizes (Chocobo1)
|
||||
- BUGFIX: Improve detection of file extension string (Chocobo1)
|
||||
- WEBUI: Don't call non-existent elements (glassez)
|
||||
- WEBUI: Update "Keep top-level folder" in WebUI options (thalieht)
|
||||
- MACOS: QMake: Raise minimal macOS target version to 10.14 (glassez)
|
||||
- LINUX: Use legacy 'data' directory only as a fallback (lbilli)
|
||||
- OTHER: Bump project requirement to C++17 (Chocobo1)
|
||||
|
||||
Sun Dec 27 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.2
|
||||
- FEATURE: Allow to add root folder to torrent content (glassez)
|
||||
- FEATURE: "HTTPS tracker validation" option is available on all platforms with latest libtorrent (Chocobo1)
|
||||
- FEATURE: Option for supporting internationalized domain names (IDNs) (Chocobo1)
|
||||
- BUGFIX: Fix broken sorting on some columns (Chocobo1)
|
||||
- BUGFIX: Fix availability per file value (Chocobo1)
|
||||
- BUGFIX: Fix status of torrents without metadata (sledgehammer999)
|
||||
- BUGFIX: Don't try to remove folders for a torrent without metadata (sledgehammer999)
|
||||
- BUGFIX: Lift upper limit of "Max concurrent HTTP announces" option (Chocobo1)
|
||||
- BUGFIX: Add links to libtorrent documentation (Chocobo1)
|
||||
- BUGFIX: Move "embedded tracker" options to qbt section (Chocobo1)
|
||||
- BUGFIX: Properly handle "Append extension" option changing (glassez)
|
||||
- BUGFIX: Correctly save paused torrent state (glassez)
|
||||
- BUGFIX: Fix bug of "move storage job" can be performed multiple times (glassez)
|
||||
- WEBUI: Add ability to use 'shift+delete' to delete torrents (Chocobo1)
|
||||
- WEBUI: Allow to attach tags while adding torrents (Jesse Chan)
|
||||
- WEBUI: Bump version to 2.6.2 (Jesse Chan)
|
||||
- WEBUI: Remove unnecessary restriction on input length (Chocobo1)
|
||||
- WINDOWS: NSIS: Update Russian translation (Andrei Stepanov)
|
||||
- WINDOWS: NSIS: Update Italian translation (Alessandro Simonelli)
|
||||
- OTHER: Drop support for building with libtorrent < 1.2.11 (Vladimir Golovnev)
|
||||
|
||||
Wed Nov 25 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.1
|
||||
- FEATURE: Allow progress bar styling from custom themes (jagannatharjun)
|
||||
- FEATURE: Allow adding torrents using "Paste" key sequence (Chocobo1)
|
||||
- FEATURE: Add Latgalian translation (sledgehammer999)
|
||||
- BUGFIX: Prevent resume data to be saved for removed torrent (glassez)
|
||||
- BUGFIX: Clarify connection protocol choice label (FranciscoPombal)
|
||||
- BUGFIX: Fix crash when clicked outside the table of torrent content view (jagannatharjun)
|
||||
- BUGFIX: Don't resume "paused" torrents when put into "checking" state by libtorrent (glassez)
|
||||
- BUGFIX: Fix torrent state calculation (glassez)
|
||||
- BUGFIX: Align integer data to right in torrent content view (jagannatharjun)
|
||||
- WEBUI: Place WebUI RSS description in sandboxed iframe (Sepro)
|
||||
- WEBUI: Avoid settings being reset via WebAPI (Chocobo1)
|
||||
- WEBUI: Fix toggling advanced option in WebUI (thalieht)
|
||||
- WEBUI: Expose contentPath in WebAPI torrents/info (FranciscoPombal)
|
||||
- WEBUI: Fix the issue that IPv6 address can't be banned (brvphoenix)
|
||||
- RSS: Fix confusion in date format description (Thomas De Rocker)
|
||||
- WINDOWS: Update dutch.nsi (Thomas De Rocker)
|
||||
- LINUX: Update .desktop file translations (sledgehammer999)
|
||||
|
||||
Thu Oct 22 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.0.1
|
||||
- WINDOWS: NSIS: Update Italian translation (bovirus)
|
||||
|
||||
Sun Oct 18 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.0
|
||||
- FEATURE: Many UI elements colors are themeable now (jagannatharjun)
|
||||
@@ -55,6 +318,127 @@ Sun Oct 18 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.0
|
||||
- OTHER: Support for libtorrent 1.1.x is dropped (Chocobo1)
|
||||
- OTHER: Many code cleanups and improvements (FranciscoPombal, Chocobo1, glassez)
|
||||
|
||||
Sat Apr 25 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.5
|
||||
- BUGFIX: Fix crash when torrent is deleted on limit reached (glassez)
|
||||
- BUGFIX: Register datatype properly (Chocobo1)
|
||||
- WEBUI: Add ability to send custom HTTP headers (Chocobo1)
|
||||
- WEBUI: Expand RSS related API (Sepro)
|
||||
- WINDOWS: Installer: Update german translation (schnurlos)
|
||||
|
||||
Wed Apr 22 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.4
|
||||
- BUGFIX: Fix sub-sorting of Transfer list (glassez)
|
||||
- BUGFIX: Fix wrong logic that disables "prevent sleeping" timer (Chocobo1)
|
||||
- BUGFIX: Set disk cache size for older libtorrent versions (NotTsunami)
|
||||
- BUGFIX: Sort locale language list (Chocobo1)
|
||||
- BUGFIX: Remove white outline around mascot.png (adem)
|
||||
- BUGFIX: Various fixes in configuring the chosen network interface and not leaking the IP (Raif Atef, an0n666)
|
||||
- BUGFIX: Save "resume data" when torrent storage is moved (glassez)
|
||||
- BUGFIX: Avoid holding encoded resume data in memory (Chocobo1)
|
||||
- BUGFIX: Fix date format for "Last seen complete" (Chocobo1)
|
||||
- BUGFIX: Remove deprecated strict super seeding mode from advanced settings (an0n666)
|
||||
- BUGFIX: Change default stop_tracker_timeout settings (an0n666)
|
||||
- BUGFIX: Convert the Log widget to use custom View/Model (jagannatharjun)
|
||||
- BUGFIX: Change default upload slot choking limits (an0n666)
|
||||
- BUGFIX: Don't uncheck Authentication checkbox when changing proxy type (thalieht)
|
||||
- BUGFIX: Reduce ambiguity for selecting tray icons (Chocobo1)
|
||||
- WEBUI: Fix unable to add multiple peers in WebUI (Sepro)
|
||||
- WEBUI: Fix UPnP lease duration get/set (NotTsunami)
|
||||
- SEARCH: Detect python3 executable on Windows (József Sallai)
|
||||
|
||||
Wed Apr 01 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.3
|
||||
- FEATURE: Add logging for SOCKS5 proxy errors (Chocobo1)
|
||||
- FEATURE: Add UPnP lease duration advanced option (NotTsunami)
|
||||
- BUGFIX: Allow to translate error messages (Chocobo1)
|
||||
- BUGFIX: Don't round scaling factor (Nick Korotysh)
|
||||
- BUGFIX: Save log file in UTF-8 encoding (Chocobo1)
|
||||
- BUGFIX: Avoid log file excessive flushing (Chocobo1)
|
||||
- BUGFIX: Fix regression when fastresume contains network path (Tester798)
|
||||
- BUGFIX: Fix broken UNC paths in fastresumes on Windows (sledgehammer999)
|
||||
- BUGFIX: Prevent multiple instances for the same app config (glassez)
|
||||
- BUGFIX: Fix unexpected torrent resume after app restart with libtorrent 1.1.x (glassez)
|
||||
- WEBUI: Add alt and title tags for WebUI footer (LameLemon)
|
||||
- WINDOWS: Installer: Update Finnish translation (Roope Jukkara)
|
||||
- WINDOWS: Installer: Update Japanese translation (maboroshin)
|
||||
- WINDOWS: Installer: Update Turkish translation (Burak Yavuz)
|
||||
- WINDOWS: Installer: Update Russian translation (Andrei Stepanov)
|
||||
|
||||
Tue Mar 24 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.2
|
||||
- FEATURE: Allow transfer list text color changes through QSS (Prince Gupta)
|
||||
- FEATURE: Option to show console when external program is run (sledgehammer999)
|
||||
- FEATURE: Rename Country column to "Country / Region" (Thomas Piccirello)
|
||||
- FEATURE: Change the defaults of some settings (FranciscoPombal)
|
||||
- FEATURE: Refactored Transfer List code to allow theming. As a sideffect the row height has more padding. (glassez)
|
||||
- FEATURE: Allow double-click in preview dialog (thalieht)
|
||||
- FEATURE: Expose stop_tracker_timeout in advanced settings (an0n666)
|
||||
- FEATURE: Add piece_extent_affinity to AdvancedSettings (FranciscoPombal)
|
||||
- FEATURE: Reorganize UI theme selection (Prince Gupta)
|
||||
- FEATURE: Show any multiple connections from the same IP in peer list (thalieht)
|
||||
- FEATURE: Add stalled filters to GUI and Web API/UI (FranciscoPombal)
|
||||
- FEATURE: Use IP geolocation database by DB-IP instead of MaxMind (sledgehammer999)
|
||||
- FEATURE: Allow to save downloaded metadata as torrent file (glassez)
|
||||
- FEATURE: Allow single app instance per configuration (glassez)
|
||||
- PERFORMANCE: Move multiple torrents one by one (glassez)
|
||||
- BUGFIX: Disable Torrent Queue by default for new users (an0n666)
|
||||
- BUGFIX: Update free disk space label on Category change in Auto Mode (Medvedishce)
|
||||
- BUGFIX: Save resume data after recheck (glassez)
|
||||
- BUGFIX: Tracker is errored only if all local endpoints fail (sledgehammer999)
|
||||
- BUGFIX: Change placement of stop tracker timeout setting (An0n)
|
||||
- BUGFIX: Redesign torrent startup handling (glassez)
|
||||
- BUGFIX: Show "∞" instead of " -1" in Preferences (Sakib-Abrar)
|
||||
- BUGFIX: Improve code efficiency for reverse resolution of peers (Chocobo1)
|
||||
- BUGFIX: Handle HTTP redirection to magnet URI (glassez)
|
||||
- BUGFIX: Various fixes for portable mode (Tester798)
|
||||
- BUGFIX: Include resume folder path in exception message (Chocobo1)
|
||||
- BUGFIX: Change placeholder text in torrent list's filter (djt3)
|
||||
- BUGFIX: Improvements in the embedded tracker to be more spec compliant (FranciscoPombal)
|
||||
- BUGFIX: Improve the options tooltips (NotTsunami)
|
||||
- BUGFIX: Check if file exists in seed mode (an0n666)
|
||||
- BUGFIX: Delegate GUI scaling work to Qt (Nick Korotysh)
|
||||
- BUGFIX: Fix crash when renaming torrent contents (Chocobo1)
|
||||
- BUGFIX: Fix total connected peers count calculation (FranciscoPombal)
|
||||
- BUGFIX: Allow other keypresses in LogListWidget (NotTsunami)
|
||||
- BUGFIX: Disable Auto TMM when not using default savepath from monitored folder (thalieht)
|
||||
- WEBUI: Fix first row renaming in files tab (Denis)
|
||||
- WEBUI: Use SVG image for WebUI favicon (Nick Korotysh)
|
||||
- WEBUI: Inherit text color for filter list elements (Nick Korotysh)
|
||||
- WEBUI: Expose WebUI ban counter to users (Chocobo1)
|
||||
- WEBUI: Expose WebUI ban duration to users (Chocobo1)
|
||||
- WEBUI: Implement "Secure" flag for session cookie (FranciscoPombal)
|
||||
- WEBUI: Remove unused/deprecated option (FranciscoPombal)
|
||||
- WEBUI: Prevent excessive sync requests (FranciscoPombal)
|
||||
- WEBUI: Fix populating statistics window (FranciscoPombal)
|
||||
- WEBUI: Fix matching uncategorized torrents (FranciscoPombal)
|
||||
- WEBUI: Always allow whitespace in category names (FranciscoPombal)
|
||||
- SEARCH: Bump python version for new installation (Chocobo1)
|
||||
- SEARCH: Fix missing string (Chocobo1)
|
||||
- SEARCH: Drop python2 support (Chocobo1)
|
||||
- WINDOWS: Installer: Option to start qBittorrent on Windows start up (An0n)
|
||||
- WINDOWS: Installer: Improve Czech translation (slrslr)
|
||||
- WINDOWS: Installer: Update French translation (zywo)
|
||||
- WINDOWS: Installer: Update German translation (schnurlos)
|
||||
- WINDOWS: Installer: Update Japanese translation (maboroshin)
|
||||
- WINDOWS: Path length limitation is removed on Windows 10 1607 onwards (an0n666)
|
||||
|
||||
Wed Dec 18 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.1
|
||||
- FEATURE: Enable portable mode if "profile" directory exists (Tester798)
|
||||
- FEATURE: Enable "Apply rate limit to peers on LAN" option by default (Chocobo1)
|
||||
- BUGFIX: Sync translations from Transifex and run lupdate (sledgehammer999)
|
||||
- BUGFIX: Don't unnecessarily delete OS files in folders (sledgehammer999)
|
||||
- BUGFIX: Use the incomplete folder where appropriate (sledgehammer999)
|
||||
- BUGFIX: Align Properties tab bar correctly on window resize (Prince Gupta)
|
||||
- BUGFIX: Rework the listening IP/interface selection code (sledgehammer999)
|
||||
- BUGFIX: Fix inconsistent icon for deleting torrent (Chocobo1)
|
||||
- BUGFIX: Show torrent error message in transfer list (Chocobo1)
|
||||
- BUGFIX: Fix stuck in wrong torrent state (Chocobo1)
|
||||
- BUGFIX: Expand single-item folders in torrent content (warren)
|
||||
- WEBUI: Bump Web API version (sledgehammer999)
|
||||
- WEBUI: Add ability to rename torrent files from the WebUI (Thomas Piccirello)
|
||||
- WEBUI: Mention lack of HTTPS in WebUI magnet link warning (nl6720)
|
||||
- WEBUI: Fix HTML elements size in search tab (Chocobo1)
|
||||
- SEARCH: Fix incorrect translation displayed after language change (Chocobo1)
|
||||
- SEARCH: Fix missing translations in search plugins dialog (Chocobo1)
|
||||
- WINDOWS: Update russian translation of the installer (Andrei Stepanov)
|
||||
|
||||
Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0
|
||||
- FEATURE: Libtorrent 1.2.x series are supported now (glassez)
|
||||
- FEATURE: Add OpenSSL version to GUI and stackdump (Chocobo1)
|
||||
|
||||
2
INSTALL
@@ -11,7 +11,7 @@ qBittorrent - A BitTorrent client in C++ / Qt
|
||||
|
||||
- OpenSSL >= 1.1.1
|
||||
|
||||
- Qt 5.15.2 - 5.x
|
||||
- Qt 5.15.2 - 5.x || 6.2.0 - 6.x
|
||||
|
||||
- zlib >= 1.2.11
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ Please report any bug (or feature request) to:
|
||||
http://bugs.qbittorrent.org
|
||||
|
||||
Official IRC channel:
|
||||
`#qbittorrent on irc.libera.chat`
|
||||
[#qbittorrent on irc.libera.chat](ircs://irc.libera.chat:6697/qbittorrent)
|
||||
|
||||
------------------------------------------
|
||||
sledgehammer999 <sledgehammer999@qbittorrent.org>
|
||||
sledgehammer999 \<sledgehammer999@qbittorrent.org\>
|
||||
|
||||
25
cmake/Modules/FindQtTranslations.cmake
Normal file
@@ -0,0 +1,25 @@
|
||||
# Return Qt translations files as list of paths
|
||||
# It will return .qm files of qt/qtbase that aren't stub files.
|
||||
# Requires that Qt has been found first because it depends on qmake being available
|
||||
|
||||
function(qbt_get_qt_translations qt_translations)
|
||||
get_target_property(QT_QMAKE_EXECUTABLE Qt::qmake IMPORTED_LOCATION)
|
||||
execute_process(COMMAND "${QT_QMAKE_EXECUTABLE}" -query QT_INSTALL_TRANSLATIONS
|
||||
OUTPUT_VARIABLE QT_TRANSLATIONS_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
FILE(GLOB QT_TEMP_TRANSLATIONS CONFIGURE_DEPENDS
|
||||
"${QT_TRANSLATIONS_DIR}/qt_??.qm"
|
||||
"${QT_TRANSLATIONS_DIR}/qt_??_??.qm"
|
||||
"${QT_TRANSLATIONS_DIR}/qtbase_??.qm"
|
||||
"${QT_TRANSLATIONS_DIR}/qtbase_??_??.qm")
|
||||
|
||||
foreach(TRANSLATION ${QT_TEMP_TRANSLATIONS})
|
||||
FILE(SIZE "${TRANSLATION}" translation_size)
|
||||
# Consider files less than 10KB as stub translations
|
||||
if (translation_size GREATER_EQUAL 10240)
|
||||
list(APPEND QT_FINAL_TRANSLATIONS "${TRANSLATION}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
SET(${qt_translations} ${QT_FINAL_TRANSLATIONS} PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -25,6 +25,12 @@ macro(qbt_common_config)
|
||||
$<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG_OUTPUT>
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
target_compile_definitions(qbt_common_cfg INTERFACE
|
||||
_DARWIN_FEATURE_64_BIT_INODE
|
||||
)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
target_compile_definitions(qbt_common_cfg INTERFACE
|
||||
NTDDI_VERSION=0x06010000
|
||||
|
||||
20
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for qbittorrent v4.4.0alpha.
|
||||
# Generated by GNU Autoconf 2.71 for qbittorrent v4.4.3.
|
||||
#
|
||||
# Report bugs to <bugs.qbittorrent.org>.
|
||||
#
|
||||
@@ -611,8 +611,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='qbittorrent'
|
||||
PACKAGE_TARNAME='qbittorrent'
|
||||
PACKAGE_VERSION='v4.4.0alpha'
|
||||
PACKAGE_STRING='qbittorrent v4.4.0alpha'
|
||||
PACKAGE_VERSION='v4.4.3'
|
||||
PACKAGE_STRING='qbittorrent v4.4.3'
|
||||
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
|
||||
PACKAGE_URL='https://www.qbittorrent.org/'
|
||||
|
||||
@@ -1329,7 +1329,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures qbittorrent v4.4.0alpha to adapt to many kinds of systems.
|
||||
\`configure' configures qbittorrent v4.4.3 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1400,7 +1400,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of qbittorrent v4.4.0alpha:";;
|
||||
short | recursive ) echo "Configuration of qbittorrent v4.4.3:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1533,7 +1533,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
qbittorrent configure v4.4.0alpha
|
||||
qbittorrent configure v4.4.3
|
||||
generated by GNU Autoconf 2.71
|
||||
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
@@ -1648,7 +1648,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by qbittorrent $as_me v4.4.0alpha, which was
|
||||
It was created by qbittorrent $as_me v4.4.3, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@@ -4779,7 +4779,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='qbittorrent'
|
||||
VERSION='v4.4.0alpha'
|
||||
VERSION='v4.4.3'
|
||||
|
||||
|
||||
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
|
||||
@@ -7254,7 +7254,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by qbittorrent $as_me v4.4.0alpha, which was
|
||||
This file was extended by qbittorrent $as_me v4.4.3, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -7314,7 +7314,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config='$ac_cs_config_escaped'
|
||||
ac_cs_version="\\
|
||||
qbittorrent config.status v4.4.0alpha
|
||||
qbittorrent config.status v4.4.3
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
AC_INIT([qbittorrent], [v4.4.0alpha], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||
AC_INIT([qbittorrent], [v4.4.3], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
: ${CFLAGS=""}
|
||||
|
||||
4
dist/mac/Info.plist
vendored
@@ -55,7 +55,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.4.0</string>
|
||||
<string>4.4.3</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -67,7 +67,7 @@
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<string>YES</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2006-2021 The qBittorrent project</string>
|
||||
<string>Copyright © 2006-2022 The qBittorrent project</string>
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
||||
BIN
dist/qt-translations/qt_fa.qm
vendored
BIN
dist/qt-translations/qt_gl.qm
vendored
BIN
dist/qt-translations/qt_lt.qm
vendored
BIN
dist/qt-translations/qt_pt.qm
vendored
BIN
dist/qt-translations/qt_sl.qm
vendored
BIN
dist/qt-translations/qt_sv.qm
vendored
BIN
dist/qt-translations/qt_zh_CN.qm
vendored
BIN
dist/qt-translations/qtbase_ar.qm
vendored
BIN
dist/qt-translations/qtbase_bg.qm
vendored
BIN
dist/qt-translations/qtbase_ca.qm
vendored
BIN
dist/qt-translations/qtbase_cs.qm
vendored
BIN
dist/qt-translations/qtbase_da.qm
vendored
BIN
dist/qt-translations/qtbase_de.qm
vendored
BIN
dist/qt-translations/qtbase_es.qm
vendored
BIN
dist/qt-translations/qtbase_fi.qm
vendored
BIN
dist/qt-translations/qtbase_fr.qm
vendored
BIN
dist/qt-translations/qtbase_gd.qm
vendored
BIN
dist/qt-translations/qtbase_he.qm
vendored
BIN
dist/qt-translations/qtbase_hu.qm
vendored
BIN
dist/qt-translations/qtbase_it.qm
vendored
BIN
dist/qt-translations/qtbase_ja.qm
vendored
BIN
dist/qt-translations/qtbase_ko.qm
vendored
BIN
dist/qt-translations/qtbase_lv.qm
vendored
BIN
dist/qt-translations/qtbase_pl.qm
vendored
BIN
dist/qt-translations/qtbase_ru.qm
vendored
BIN
dist/qt-translations/qtbase_sk.qm
vendored
BIN
dist/qt-translations/qtbase_tr.qm
vendored
BIN
dist/qt-translations/qtbase_uk.qm
vendored
BIN
dist/qt-translations/qtbase_zh_TW.qm
vendored
BIN
dist/unix/menuicons/128x128/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.3 KiB |
BIN
dist/unix/menuicons/16x16/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 775 B After Width: | Height: | Size: 750 B |
|
Before Width: | Height: | Size: 775 B After Width: | Height: | Size: 750 B |
BIN
dist/unix/menuicons/192x192/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
BIN
dist/unix/menuicons/22x22/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
dist/unix/menuicons/24x24/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
BIN
dist/unix/menuicons/32x32/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
dist/unix/menuicons/36x36/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
dist/unix/menuicons/48x48/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
dist/unix/menuicons/64x64/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.7 KiB |
BIN
dist/unix/menuicons/72x72/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
BIN
dist/unix/menuicons/96x96/apps/qbittorrent.png
vendored
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.4 KiB |
@@ -74,6 +74,6 @@
|
||||
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="4.4.0" date="2020-10-18"/>
|
||||
<release version="4.4.3" date="2022-05-22"/>
|
||||
</releases>
|
||||
</component>
|
||||
|
||||
113
dist/unix/org.qbittorrent.qBittorrent.desktop
vendored
@@ -16,15 +16,12 @@ Keywords=bittorrent;torrent;magnet;download;p2p;
|
||||
|
||||
|
||||
# Translations
|
||||
Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent
|
||||
GenericName[oc]=Client BitTorrent
|
||||
Name[oc]=qBittorrent
|
||||
Comment[af]=Aflaai en deel lêers oor BitTorrent
|
||||
GenericName[af]=BitTorrent kliënt
|
||||
Name[af]=qBittorrent
|
||||
Comment[ar]=نزّل وشارك الملفات عبر كيوبتتورنت
|
||||
GenericName[ar]=عميل بتتورنت
|
||||
Name[ar]=كيوبتتورنت
|
||||
Name[ar]=qBittorrent
|
||||
Comment[be]=Спампоўванне і раздача файлаў праз пратакол BitTorrent
|
||||
GenericName[be]=Кліент BitTorrent
|
||||
Name[be]=qBittorrent
|
||||
@@ -33,7 +30,10 @@ GenericName[bg]=BitTorrent клиент
|
||||
Name[bg]=qBittorrent
|
||||
Comment[bn]=বিটটরেন্টে ফাইল ডাউনলোড এবং শেয়ার করুন
|
||||
GenericName[bn]=বিটটরেন্ট ক্লায়েন্ট
|
||||
Name[bn]=কিউবি্টটরেন্ট
|
||||
Name[bn]=qBittorrent
|
||||
Comment[zh]=通过 BitTorrent 下载和分享文件
|
||||
GenericName[zh]=BitTorrent 客户端
|
||||
Name[zh]=qBittorrent
|
||||
Comment[bs]=Preuzmi i dijeli datoteke preko BitTorrent-a
|
||||
GenericName[bs]=BitTorrent klijent
|
||||
Name[bs]=qBittorrent
|
||||
@@ -66,11 +66,11 @@ GenericName[eu]=BitTorrent bezeroa
|
||||
Name[eu]=qBittorrent
|
||||
Comment[fa]=دانلود و به اشتراک گذاری فایل های بوسیله بیت تورنت
|
||||
GenericName[fa]=بیت تورنت نسخه کلاینت
|
||||
Name[fa]=کیو بیت تورنت
|
||||
Name[fa]=qBittorrent
|
||||
Comment[fi]=Lataa ja jaa tiedostoja BitTorrentia käyttäen
|
||||
GenericName[fi]=BitTorrent-asiakasohjelma
|
||||
Name[fi]=qBittorrent
|
||||
Comment[fr]=Letölteni és megosztani a dokumentumokat Bittorrenttel
|
||||
Comment[fr]=Télécharger et partager des fichiers sur BitTorrent
|
||||
GenericName[fr]=Client BitTorrent
|
||||
Name[fr]=qBittorrent
|
||||
Comment[gl]=Descargar e compartir ficheiros co protocolo BitTorrent
|
||||
@@ -78,7 +78,7 @@ GenericName[gl]=Cliente BitTorrent
|
||||
Name[gl]=qBittorrent
|
||||
Comment[gu]=બિટ્ટોરેંટ પર ફાઈલો ડાઉનલોડ અને શેર કરો
|
||||
GenericName[gu]=બિટ્ટોરેંટ ક્લાયન્ટ
|
||||
Name[gu]=ક્યૂ-બિટ્ટોરેંટ
|
||||
Name[gu]=qBittorrent
|
||||
Comment[he]=הורד ושתף קבצים על גבי ביטורנט
|
||||
GenericName[he]=לקוח ביטורנט
|
||||
Name[he]=qBittorrent
|
||||
@@ -106,27 +106,21 @@ Name[ja]=qBittorrent
|
||||
Comment[ka]=ჩამოტვირთე და გააზიარე ფაილები Bittorrent-ის საშუალებით
|
||||
GenericName[ka]=BitTorrent კლიენტი
|
||||
Name[ka]=qBittorrent
|
||||
Comment[ko]=BitTorrent를 통해 파일 다운로드 및 공유
|
||||
Comment[ko]=BitTorrent를 통한 파일 다운로드 및 공유
|
||||
GenericName[ko]=BitTorrent 클라이언트
|
||||
Name[ko]=qBittorrent
|
||||
Comment[zh]=通过 BitTorrent 下载和分享文件
|
||||
GenericName[zh]=BitTorrent 客户端
|
||||
Name[zh]=qBittorrent
|
||||
Comment[lt]=Atsisiųskite bei dalinkitės failais BitTorrent tinkle
|
||||
GenericName[lt]=BitTorrent klientas
|
||||
Name[lt]=qBittorrent
|
||||
Comment[mk]=Превземајте и споделувајте фајлови преку BitTorrent
|
||||
GenericName[mk]=BitTorrent клиент
|
||||
Name[mk]=qBittorrent
|
||||
Comment[en_AU]=Download and share files over BitTorrent
|
||||
GenericName[en_AU]=BitTorrent client
|
||||
Name[en_AU]=qBittorrent
|
||||
Comment[my]=တောရန့်ဖြင့်ဖိုင်များဒေါင်းလုဒ်ဆွဲရန်နှင့်မျှဝေရန်
|
||||
GenericName[my]=တောရန့်စီမံခန့်ခွဲသည့်အရာ
|
||||
Name[my]=qBittorrent
|
||||
Comment[nb]=Last ned og del filer over BitTorrent
|
||||
GenericName[nb]=BitTorrent-klient
|
||||
Name[nb]=qBittorrent
|
||||
Comment[nqo]=ߞߐߕߐ߯ߘߐ ߟߎ߬ ߟߊߖߌ߰ ߞߊ߬ ߓߊ߲߫ ߞߵߊ߬ߟߎ߬ ߘߐߕߟߊ߫ ߓߌߙߏߙߍ߲ߕ ߞߊ߲߬
|
||||
GenericName[nqo]=ߓߌߙߏߙߍ߲ߕ ߕߣߐ߬ߓߐ߬ߟߊ
|
||||
Name[nqo]=ߞߎ߳ߓߌߕߏߙߍ߲ߕ
|
||||
Comment[nl]=Bestanden downloaden en delen via BitTorrent
|
||||
GenericName[nl]=BitTorrent-client
|
||||
Name[nl]=qBittorrent
|
||||
@@ -151,6 +145,7 @@ Name[sk]=qBittorrent
|
||||
Comment[sl]=Prenesite in delite datoteke preko BitTorrenta
|
||||
GenericName[sl]=BitTorrent odjemalec
|
||||
Name[sl]=qBittorrent
|
||||
Name[sq]=qBittorrent
|
||||
Comment[sr]=Преузимајте и делите фајлове преко BitTorrent протокола
|
||||
GenericName[sr]=BitTorrent-клијент
|
||||
Name[sr]=qBittorrent
|
||||
@@ -160,6 +155,52 @@ Name[sr@latin]=qBittorrent
|
||||
Comment[sv]=Hämta och dela filer över BitTorrent
|
||||
GenericName[sv]=BitTorrent-klient
|
||||
Name[sv]=qBittorrent
|
||||
Comment[ta]=BitTorrent வழியாக கோப்புகளை பதிவிறக்க மற்றும் பகிர
|
||||
GenericName[ta]=BitTorrent வாடிக்கையாளர்
|
||||
Name[ta]=qBittorrent
|
||||
Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి
|
||||
GenericName[te]=క్యు బిట్ టొరెంట్ క్లయింట్
|
||||
Name[te]=qBittorrent
|
||||
Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่าน BitTorrent
|
||||
GenericName[th]=ไคลเอนต์ BitTorrent
|
||||
Name[th]=qBittorrent
|
||||
Comment[tr]=Dosyaları BitTorrent üzerinden indirin ve paylaşın
|
||||
GenericName[tr]=BitTorrent istemcisi
|
||||
Name[tr]=qBittorrent
|
||||
Comment[ur]=BitTorrent پر فائلوں کو ڈاؤن لوڈ کریں اور اشتراک کریں
|
||||
GenericName[ur]=قیو بٹ ٹورنٹ کلائنٹ
|
||||
Name[ur]=qBittorrent
|
||||
Comment[uk]=Завантажуйте та поширюйте файли через BitTorrent
|
||||
GenericName[uk]=BitTorrent-клієнт
|
||||
Name[uk]=qBittorrent
|
||||
Comment[vi]=Tải về và chia sẻ tệp qua BitTorrent
|
||||
GenericName[vi]=Máy khách BitTorrent
|
||||
Name[vi]=qBittorrent
|
||||
Comment[zh_HK]=經由BitTorrent下載並分享檔案
|
||||
GenericName[zh_HK]=BitTorrent用戶端
|
||||
Name[zh_HK]=qBittorrent
|
||||
Comment[zh_TW]=經由 BitTorrent 下載並分享檔案
|
||||
GenericName[zh_TW]=BitTorrent 客戶端
|
||||
Name[zh_TW]=qBittorrent
|
||||
Comment[eo]=Elŝutu kaj kunhavigu dosierojn per BitTorrent
|
||||
GenericName[eo]=BitTorrent-kliento
|
||||
Name[eo]=qBittorrent
|
||||
Comment[kk]=BitTorrent арқылы файл жүктеу және бөлісу
|
||||
GenericName[kk]=BitTorrent клиенті
|
||||
Name[kk]=qBittorrent
|
||||
Comment[en_AU]=Download and share files over BitTorrent
|
||||
GenericName[en_AU]=BitTorrent client
|
||||
Name[en_AU]=qBittorrent
|
||||
Name[rm]=qBittorrent
|
||||
Name[jv]=qBittorrent
|
||||
Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent
|
||||
GenericName[oc]=Client BitTorrent
|
||||
Name[oc]=qBittorrent
|
||||
Name[ug]=qBittorrent
|
||||
Name[yi]=qBittorrent
|
||||
Comment[nqo]=ߞߐߕߐ߯ߘߐ ߟߎ߬ ߟߊߖߌ߰ ߞߊ߬ ߓߊ߲߫ ߞߵߊ߬ߟߎ߬ ߘߐߕߟߊ߫ ߓߌߙߏߙߍ߲ߕ ߞߊ߲߬
|
||||
GenericName[nqo]=ߓߌߙߏߙߍ߲ߕ ߕߣߐ߬ߓߐ߬ߟߊ
|
||||
Name[nqo]=qBittorrent
|
||||
Comment[uz@Latn]=BitTorrent orqali fayllarni yuklab olish va baham ko‘rish
|
||||
GenericName[uz@Latn]=BitTorrent mijozi
|
||||
Name[uz@Latn]=qBittorrent
|
||||
@@ -168,55 +209,23 @@ GenericName[ltg]=BitTorrent klients
|
||||
Name[ltg]=qBittorrent
|
||||
Comment[hi_IN]=BitTorrent द्वारा फाइल डाउनलोड व सहभाजन
|
||||
GenericName[hi_IN]=Bittorrent साधन
|
||||
Name[hi_IN]=क्यूबिटटाॅरेंट
|
||||
Comment[tr]=Dosyaları BitTorrent üzerinden indirin ve paylaşın
|
||||
GenericName[tr]=BitTorrent istemcisi
|
||||
Name[tr]=qBittorrent
|
||||
Comment[ur]=BitTorrent پر فائلوں کو ڈاؤن لوڈ کریں اور اشتراک کریں
|
||||
GenericName[ur]=قیو بٹ ٹورنٹ کلائنٹ
|
||||
Name[ur]=قیو بٹ ٹورنٹ
|
||||
Comment[uk]=Завантажуйте та поширюйте файли через BitTorrent
|
||||
GenericName[uk]=BitTorrent-клієнт
|
||||
Name[uk]=qBittorrent
|
||||
Comment[vi]=Tải về và chia sẻ tệp qua BitTorrent
|
||||
GenericName[vi]=Máy khách BitTorrent
|
||||
Name[vi]=qBittorrent
|
||||
Name[hi_IN]=qBittorrent
|
||||
Comment[az@latin]=Faylları BitTorrent vasitəsilə göndərin və paylaşın
|
||||
GenericName[az@latin]=BitTorrent client
|
||||
Name[az@latin]=qBittorrent
|
||||
Comment[zh_HK]=經由BitTorrent下載並分享檔案
|
||||
GenericName[zh_HK]=BitTorrent用戶端
|
||||
Name[zh_HK]=qBittorrent
|
||||
Comment[zh_TW]=經由 BitTorrent 下載並分享檔案
|
||||
GenericName[zh_TW]=BitTorrent 客戶端
|
||||
Name[zh_TW]=qBittorrent
|
||||
Comment[lv_LV]=Lejupielādēt un koplietot failus ar BitTorrent
|
||||
GenericName[lv_LV]=BitTorrent klients
|
||||
Name[lv_LV]=qBittorrent
|
||||
Comment[kk]=BitTorrent арқылы файл жүктеу және бөлісу
|
||||
GenericName[kk]=BitTorrent клиенті
|
||||
Name[kk]=qBittorrent
|
||||
Comment[ms_MY]=Muat turun dan kongsi fail melalui BitTorrent
|
||||
GenericName[ms_MY]=Klien BitTorrent
|
||||
Name[ms_MY]=qBittorrent
|
||||
Comment[eo]=Elŝutu kaj kunhavigu dosierojn per BitTorrent
|
||||
GenericName[eo]=BitTorrent-kliento
|
||||
Name[eo]=qBittorrent
|
||||
Comment[mn_MN]=BitTorrent-оор файлуудаа тат, түгээ
|
||||
GenericName[mn_MN]=BitTorrent татагч
|
||||
Name[mn_MN]=qBittorrent
|
||||
Comment[ta]=BitTorrent வழியாக கோப்புகளை பதிவிறக்க மற்றும் பகிர
|
||||
GenericName[ta]=BitTorrent வாடிக்கையாளர்
|
||||
Name[ta]=qBittorrent
|
||||
Comment[ne_NP]=फाइलहरू डाउनलोड गर्नुहोस् र BitTorrent मा साझा गर्नुहोस्
|
||||
GenericName[ne_NP]=BitTorrent क्लाइन्ट
|
||||
Name[ne_NP]=qBittorrent
|
||||
Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి
|
||||
GenericName[te]=క్యు బిట్ టొరెంట్ క్లయింట్
|
||||
Name[te]=క్యు బిట్ టొరెంట్
|
||||
Comment[pt_PT]=Transferir e partilhar ficheiros por BitTorrent
|
||||
GenericName[pt_PT]=Cliente BitTorrent
|
||||
Name[pt_PT]=qBittorrent
|
||||
Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่าน BitTorrent
|
||||
GenericName[th]=ไคลเอนต์ BitTorrent
|
||||
Name[th]=qBittorrent
|
||||
Name[si_LK]=qBittorrent
|
||||
|
||||
10
dist/windows/README.txt
vendored
@@ -38,10 +38,12 @@ installer-translations
|
||||
translations
|
||||
qt_ar.qm
|
||||
...
|
||||
(all the .qm files found in the 'translations' folder of your Qt install. Those files differ between Qt4 and Qt5.
|
||||
If you want to distribute Qt4 translations it is better to use the ones found in this repo under the path "dist/qt-translations".
|
||||
They contain extra languages not distributed via the official qt4 sources.
|
||||
Don't forget to edit the filelist in installer.nsi + uninstaller.nsi to include all your .qm files.)
|
||||
(All the .qm files found in the 'translations' folder of your Qt install. Those files differ between Qt5 and Qt6.
|
||||
You will need the files that conform to this globbing expression 'qt_??.qm qt_??_??.qm qtbase_??.qm qtbase_??_??.qm'.
|
||||
Some of those files will be stubs. Filter any file that is smaller than 10KB in size.
|
||||
Alternatively you can use the 'gather_qt_translations.py' script found in the same folder as this file.
|
||||
Run it with '--help' to see its usage.
|
||||
**YOU MUST** edit the list of .qm files in the 'installer.nsi' to match whatever files are in the 'translations' subfolder.)
|
||||
qt_zh_TW.qm
|
||||
installer.nsi
|
||||
license.txt
|
||||
|
||||
31
dist/windows/gather_qt_translations.py
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import os
|
||||
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")
|
||||
parser.add_argument("nsis_packaging_folder", help="NSIS packaging translations folder")
|
||||
args = parser.parse_args()
|
||||
|
||||
tmp_translations: List[str] = glob.glob(f'{args.qt_translations_folder}/qt_??.qm')
|
||||
tmp_translations += glob.glob(f'{args.qt_translations_folder}/qt_??_??.qm')
|
||||
tmp_translations += glob.glob(f'{args.qt_translations_folder}/qtbase_??.qm')
|
||||
tmp_translations += glob.glob(f'{args.qt_translations_folder}qtbase_??_??.qm')
|
||||
|
||||
filtered = filter(isNotStub, tmp_translations)
|
||||
for file in filtered:
|
||||
shutil.copy2(file, args.nsis_packaging_folder)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
36
dist/windows/installer-translations/french.nsi
vendored
@@ -3,27 +3,27 @@
|
||||
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_FRENCH} "qBittorrent (requis)"
|
||||
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_FRENCH} "Créer Raccourci Bureau"
|
||||
LangString inst_dekstop ${LANG_FRENCH} "Créer un Raccourci sur le Bureau"
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_FRENCH} "Créer Raccourci dans le Menu Démarrer"
|
||||
LangString inst_startmenu ${LANG_FRENCH} "Créer un Raccourci dans le Menu Démarrer"
|
||||
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
|
||||
LangString inst_startup ${LANG_FRENCH} "Démarrez qBittorrent au démarrage de Windows"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_FRENCH} "Ouvrir fichiers .torrent avec qBittorrent"
|
||||
LangString inst_torrent ${LANG_FRENCH} "Ouvrir les fichiers .torrent avec qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_FRENCH} "Ouvrir liens magnet avec qBittorrent"
|
||||
LangString inst_magnet ${LANG_FRENCH} "Ouvrir les liens magnet avec qBittorrent"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_FRENCH} "Ajouter règle Pare-Feu Windows"
|
||||
LangString inst_firewall ${LANG_FRENCH} "Ajouter une règle au Pare-Feu de Windows"
|
||||
;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_FRENCH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
|
||||
LangString inst_pathlimit ${LANG_FRENCH} "Désactiver la limite de taille du chemin de Windows (limitation de MAX_PATH 260 caractères, nécessite Windows 10 1607 ou plus)"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_FRENCH} "Ajout règle Pare-Feu Windows"
|
||||
LangString inst_firewallinfo ${LANG_FRENCH} "Ajout d'une règle au Pare-Feu de Windows"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_FRENCH} "qBittorrent est en cours d'exécution. Veuillez fermer l'application avant l'installation."
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
|
||||
LangString inst_uninstall_question ${LANG_FRENCH} "Une installation précédente a été détectée. Elle sera désinstallée sans supprimer les réglages utilisateur."
|
||||
LangString inst_uninstall_question ${LANG_FRENCH} "Une installation précédente a été détectée. Elle sera désinstallée en conservant les réglages utilisateur."
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_FRENCH} "Désinstallation de la version précédente."
|
||||
LangString inst_unist ${LANG_FRENCH} "Désinstallation de la version antérieure."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_FRENCH} "Lancer qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
@@ -31,27 +31,27 @@ LangString inst_requires_64bit ${LANG_FRENCH} "Cet installateur ne fonctionne qu
|
||||
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_FRENCH} "Cette version de qBittorrent nécessite au moins Windows 7."
|
||||
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_FRENCH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_FRENCH} "Désinstaller qBittorrent"
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
|
||||
;LangString remove_files ${LANG_ENGLISH} "Remove files"
|
||||
LangString remove_files ${LANG_FRENCH} "Supprimer fichiers"
|
||||
LangString remove_files ${LANG_FRENCH} "Supprimer les fichiers"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_FRENCH} "Supprimer raccourcis"
|
||||
LangString remove_shortcuts ${LANG_FRENCH} "Supprimer les raccourcis"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_FRENCH} "Supprimer associations de fichiers"
|
||||
LangString remove_associations ${LANG_FRENCH} "Supprimer les associations de fichiers"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_FRENCH} "Supprimer clés de registre"
|
||||
LangString remove_registry ${LANG_FRENCH} "Supprimer les clés de registre"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_FRENCH} "Supprimer fichiers de configuration"
|
||||
LangString remove_conf ${LANG_FRENCH} "Supprimer les fichiers de configuration"
|
||||
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_FRENCH} "Supprimer règle Pare-Feu Windows"
|
||||
LangString remove_firewall ${LANG_FRENCH} "Supprimer la règle du Pare-Feu de Windows"
|
||||
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_FRENCH} "Suppression règle Pare-Feu Windows"
|
||||
LangString remove_firewallinfo ${LANG_FRENCH} "Suppression de la règle du Pare-Feu de Windows"
|
||||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_FRENCH} "Supprimer torrents et données cachées"
|
||||
LangString remove_cache ${LANG_FRENCH} "Supprimer les torrents et données cachées"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_FRENCH} "qBittorrent est en cours d'exécution. Veuillez fermer l'application avant la désinstallation."
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
;Installer strings
|
||||
|
||||
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_SIMPCHINESE} "qBittorrent (必要)"
|
||||
LangString inst_qbt_req ${LANG_SIMPCHINESE} "qBittorrent 主程序 (必要)"
|
||||
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_SIMPCHINESE} "创建桌面快捷方式"
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_SIMPCHINESE} "创建开始菜单快捷方式"
|
||||
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
|
||||
LangString inst_startup ${LANG_SIMPCHINESE} "在Windows上启动qBittorrent进行启动"
|
||||
LangString inst_startup ${LANG_SIMPCHINESE} "qBittorrent 开机自启动"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_SIMPCHINESE} "用 qBittorrent 打开.torrent文件"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_SIMPCHINESE} "用 qBittorrent 打开磁力链接"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_SIMPCHINESE} "添加Windows防火墙规则"
|
||||
LangString inst_firewall ${LANG_SIMPCHINESE} "添加 Windows 防火墙规则"
|
||||
;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_SIMPCHINESE} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
|
||||
LangString inst_pathlimit ${LANG_SIMPCHINESE} "解除 Windows 的 PATH 长度限制 (解除 MAX_PATH 为 260 的限制, 需要 Windows 10 1607 或更新版本)"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_SIMPCHINESE} "正在添加Windows防火墙规则"
|
||||
LangString inst_firewallinfo ${LANG_SIMPCHINESE} "正在添加 Windows 防火墙规则"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_SIMPCHINESE} "qBittorrent 正在运行。 安装前请关闭应用程序。"
|
||||
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_uninstall_question ${LANG_SIMPCHINESE} "当前版本会被卸载。 用户设置和种子会被完整保留。"
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_SIMPCHINESE} "卸载以前的版本。"
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_SIMPCHINESE} "启动 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_64bit ${LANG_SIMPCHINESE} "此安装程序仅支持 64 位 Windows 系统。"
|
||||
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_SIMPCHINESE} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_SIMPCHINESE} "这个版本的 qBittorrent 仅支持 Windows 7 及更新的系统。"
|
||||
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_SIMPCHINESE} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_SIMPCHINESE} "卸载 qBittorrent"
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
@@ -41,20 +41,20 @@ LangString remove_files ${LANG_SIMPCHINESE} "删除文件"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_SIMPCHINESE} "删除快捷方式"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_SIMPCHINESE} "删除文件关联"
|
||||
LangString remove_associations ${LANG_SIMPCHINESE} "解除文件关联"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_SIMPCHINESE} "删除注册表键"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_SIMPCHINESE} "删除配置文件"
|
||||
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_SIMPCHINESE} "删除Windows防火墙规则"
|
||||
LangString remove_firewall ${LANG_SIMPCHINESE} "删除 Windows 防火墙规则"
|
||||
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_SIMPCHINESE} "正在删除Windows防火墙规则"
|
||||
LangString remove_firewallinfo ${LANG_SIMPCHINESE} "正在删除 Windows 防火墙规则"
|
||||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_SIMPCHINESE} "删除种子和缓存数据"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_SIMPCHINESE} "qBittorrent 正在运行。 卸载前请关闭程序。"
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_SIMPCHINESE} "不删除 .torrent 关联。 关联的是:"
|
||||
LangString uninst_tor_warn ${LANG_SIMPCHINESE} "未解除与 .torrent 的关联。 它已与另一程序关联:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_SIMPCHINESE} "不删除磁力关联。 关联的是:"
|
||||
LangString uninst_mag_warn ${LANG_SIMPCHINESE} "未解除与 磁力链接 的关联。 它已与另一程序关联:"
|
||||
|
||||
10
dist/windows/installer-translations/spanish.nsi
vendored
@@ -7,7 +7,7 @@ LangString inst_dekstop ${LANG_SPANISH} "Crear un acceso directo en el escritori
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_SPANISH} "Crear un acceso directo en el menú inicio"
|
||||
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
|
||||
LangString inst_startup ${LANG_SPANISH} "Inicie qBittorrent en el inicio de Windows"
|
||||
LangString inst_startup ${LANG_SPANISH} "Iniciar qBittorrent en el inicio de Windows"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_SPANISH} "Abrir archivos .torrent con qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
@@ -15,7 +15,7 @@ LangString inst_magnet ${LANG_SPANISH} "Abrir enlaces magnet con qBittorrent"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_SPANISH} "Añadir regla al Firewall de Windows"
|
||||
;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_SPANISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
|
||||
LangString inst_pathlimit ${LANG_SPANISH} "Deshabilitar límite de caracteres del PATH de Windows (limitación MAX_PATH de 260 caracteres, requiere Windows 10 1607 o superior)"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_SPANISH} "Añadiendo regla al Firewall de Windows"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
@@ -29,9 +29,9 @@ LangString launch_qbt ${LANG_SPANISH} "Iniciar qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_SPANISH} "Este instalador solo funciona en versiones de 64-bit de Windows."
|
||||
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_SPANISH} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_SPANISH} "Esta versión de qBittorrent requiere Windows 7 o superior."
|
||||
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_SPANISH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_SPANISH} "Desinstalar qBittorrent"
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
@@ -41,7 +41,7 @@ LangString remove_files ${LANG_SPANISH} "Quitar archivos"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_SPANISH} "Quitar accesos directos"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_SPANISH} "Deshacer asociaciones"
|
||||
LangString remove_associations ${LANG_SPANISH} "Deshacer asociaciones de archivos"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_SPANISH} "Eliminar claves del registro"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
|
||||
@@ -7,7 +7,7 @@ LangString inst_dekstop ${LANG_SPANISHINTERNATIONAL} "Crear un acceso directo en
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_SPANISHINTERNATIONAL} "Crear un acceso directo en el menú inicio"
|
||||
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
|
||||
LangString inst_startup ${LANG_SPANISHINTERNATIONAL} "Inicie qBittorrent en el inicio de Windows"
|
||||
LangString inst_startup ${LANG_SPANISHINTERNATIONAL} "Iniciar qBittorrent en el inicio de Windows"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_SPANISHINTERNATIONAL} "Abrir archivos .torrent con qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
@@ -15,7 +15,7 @@ LangString inst_magnet ${LANG_SPANISHINTERNATIONAL} "Abrir enlaces magnet con qB
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_SPANISHINTERNATIONAL} "Añadir regla al Firewall de Windows"
|
||||
;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_SPANISHINTERNATIONAL} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
|
||||
LangString inst_pathlimit ${LANG_SPANISHINTERNATIONAL} "Deshabilitar límite de caracteres del PATH de Windows (limitación MAX_PATH de 260 caracteres, requiere Windows 10 1607 o superior)"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_SPANISHINTERNATIONAL} "Añadiendo regla al Firewall de Windows"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
@@ -29,9 +29,9 @@ LangString launch_qbt ${LANG_SPANISHINTERNATIONAL} "Iniciar qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_SPANISHINTERNATIONAL} "Este instalador solo funciona en versiones de 64-bit de Windows."
|
||||
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_SPANISHINTERNATIONAL} "This qBittorrent version requires at least Windows 7."
|
||||
LangString inst_requires_win7 ${LANG_SPANISHINTERNATIONAL} "Esta versión de qBittorrent requiere Windows 7 o superior."
|
||||
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_SPANISHINTERNATIONAL} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_SPANISHINTERNATIONAL} "Desinstalar qBittorrent"
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
@@ -41,7 +41,7 @@ LangString remove_files ${LANG_SPANISHINTERNATIONAL} "Quitar archivos"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_SPANISHINTERNATIONAL} "Quitar accesos directos"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_SPANISHINTERNATIONAL} "Deshacer asociaciones"
|
||||
LangString remove_associations ${LANG_SPANISHINTERNATIONAL} "Deshacer asociaciones de archivos"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_SPANISHINTERNATIONAL} "Eliminar claves del registro"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
|
||||
4
dist/windows/options.nsi
vendored
@@ -28,7 +28,7 @@ XPStyle on
|
||||
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
|
||||
|
||||
; Program specific
|
||||
!define PROG_VERSION "4.4.0"
|
||||
!define PROG_VERSION "4.4.3"
|
||||
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
||||
@@ -51,7 +51,7 @@ XPStyle on
|
||||
;Installer Version Information
|
||||
VIAddVersionKey "ProductName" "qBittorrent"
|
||||
VIAddVersionKey "CompanyName" "The qBittorrent project"
|
||||
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2021 The qBittorrent project"
|
||||
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2022 The qBittorrent project"
|
||||
VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client"
|
||||
VIAddVersionKey "FileVersion" "${PROG_VERSION}"
|
||||
|
||||
|
||||
32
macxconf.pri
@@ -7,11 +7,31 @@ else {
|
||||
include(conf.pri)
|
||||
}
|
||||
|
||||
# Custom function
|
||||
# Return Qt translations files as list of paths
|
||||
# It will return .qm files of qt/qtbase that aren't stub files.
|
||||
defineReplace(qbt_get_qt_translations) {
|
||||
# The $$[] syntax queries qmake properties
|
||||
TMP_TRANSLATIONS = $$files($$[QT_INSTALL_TRANSLATIONS]/qt_??.qm)
|
||||
TMP_TRANSLATIONS += $$files($$[QT_INSTALL_TRANSLATIONS]/qt_??_??.qm)
|
||||
TMP_TRANSLATIONS += $$files($$[QT_INSTALL_TRANSLATIONS]/qtbase_??.qm)
|
||||
TMP_TRANSLATIONS += $$files($$[QT_INSTALL_TRANSLATIONS]/qtbase_??_??.qm)
|
||||
|
||||
# Consider files less than 10KB as stub translations
|
||||
for (TRANSLATION, TMP_TRANSLATIONS) {
|
||||
TRANSLATION_SIZE = $$system("stat -f%z $${TRANSLATION}", true, EXIT_STATUS)
|
||||
equals(EXIT_STATUS, 0):!lessThan(TRANSLATION_SIZE, 10240): FINAL_TRANSLATIONS += $${TRANSLATION}
|
||||
}
|
||||
|
||||
return($$FINAL_TRANSLATIONS)
|
||||
}
|
||||
|
||||
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.14
|
||||
|
||||
DEFINES += _DARWIN_FEATURE_64_BIT_INODE
|
||||
|
||||
LIBS += -framework Carbon -framework IOKit -framework AppKit
|
||||
|
||||
QT_LANG_PATH = ../dist/qt-translations
|
||||
DIST_PATH = ../dist/mac
|
||||
|
||||
document_icon.path = Contents/Resources
|
||||
@@ -23,15 +43,7 @@ qt_conf.files = $$DIST_PATH/qt.conf
|
||||
QMAKE_BUNDLE_DATA += qt_conf
|
||||
|
||||
qt_translations.path = Contents/translations
|
||||
qt_translations.files = $$files($$QT_LANG_PATH/qtbase_*.qm)
|
||||
qt_translations.files += \
|
||||
$$QT_LANG_PATH/qt_fa.qm \
|
||||
$$QT_LANG_PATH/qt_gl.qm \
|
||||
$$QT_LANG_PATH/qt_lt.qm \
|
||||
$$QT_LANG_PATH/qt_pt.qm \
|
||||
$$QT_LANG_PATH/qt_sl.qm \
|
||||
$$QT_LANG_PATH/qt_sv.qm \
|
||||
$$QT_LANG_PATH/qt_zh_CN.qm
|
||||
qt_translations.files = $$qbt_get_qt_translations()
|
||||
QMAKE_BUNDLE_DATA += qt_translations
|
||||
|
||||
ICON = $$DIST_PATH/qbittorrent_mac.icns
|
||||
|
||||
@@ -16,11 +16,6 @@ if (WEBUI)
|
||||
"${qBittorrent_BINARY_DIR}/src/webui/www/translations/webui_translations.qrc" COPYONLY)
|
||||
endif()
|
||||
|
||||
FILE(GLOB QT_TRANSLATIONS "${qBittorrent_SOURCE_DIR}/dist/qt-translations/qtbase_*.qm")
|
||||
foreach(EXTRA_TRANSLATION IN ITEMS "fa" "gl" "lt" "pt" "sl" "sv" "zh_CN")
|
||||
list(APPEND QT_TRANSLATIONS "${qBittorrent_SOURCE_DIR}/dist/qt-translations/qt_${EXTRA_TRANSLATION}.qm")
|
||||
endforeach()
|
||||
|
||||
# Executable target configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -65,16 +60,17 @@ endif()
|
||||
# Additional platform specific configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
set_source_files_properties(${QT_TRANSLATIONS} PROPERTIES MACOSX_PACKAGE_LOCATION translations)
|
||||
set_source_files_properties(
|
||||
"${qBittorrent_SOURCE_DIR}/dist/mac/qt.conf"
|
||||
"${qBittorrent_SOURCE_DIR}/dist/mac/qBitTorrentDocument.icns"
|
||||
"${qBittorrent_SOURCE_DIR}/dist/mac/qbittorrent_mac.icns"
|
||||
PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
include(FindQtTranslations)
|
||||
qbt_get_qt_translations(QT_TRANSLATIONS)
|
||||
set_source_files_properties(${QT_TRANSLATIONS} PROPERTIES MACOSX_PACKAGE_LOCATION translations)
|
||||
set_source_files_properties(
|
||||
"${qBittorrent_SOURCE_DIR}/dist/mac/qt.conf"
|
||||
"${qBittorrent_SOURCE_DIR}/dist/mac/qBitTorrentDocument.icns"
|
||||
"${qBittorrent_SOURCE_DIR}/dist/mac/qbittorrent_mac.icns"
|
||||
PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources
|
||||
)
|
||||
# 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
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/torrent.h"
|
||||
#include "base/exceptions.h"
|
||||
#include "base/global.h"
|
||||
#include "base/iconprovider.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
@@ -100,22 +101,10 @@
|
||||
namespace
|
||||
{
|
||||
#define SETTINGS_KEY(name) "Application/" name
|
||||
|
||||
// FileLogger properties keys
|
||||
#define FILELOGGER_SETTINGS_KEY(name) QStringLiteral(SETTINGS_KEY("FileLogger/") name)
|
||||
const QString KEY_FILELOGGER_ENABLED = FILELOGGER_SETTINGS_KEY("Enabled");
|
||||
const QString KEY_FILELOGGER_PATH = FILELOGGER_SETTINGS_KEY("Path");
|
||||
const QString KEY_FILELOGGER_BACKUP = FILELOGGER_SETTINGS_KEY("Backup");
|
||||
const QString KEY_FILELOGGER_DELETEOLD = FILELOGGER_SETTINGS_KEY("DeleteOld");
|
||||
const QString KEY_FILELOGGER_MAXSIZEBYTES = FILELOGGER_SETTINGS_KEY("MaxSizeBytes");
|
||||
const QString KEY_FILELOGGER_AGE = FILELOGGER_SETTINGS_KEY("Age");
|
||||
const QString KEY_FILELOGGER_AGETYPE = FILELOGGER_SETTINGS_KEY("AgeType");
|
||||
|
||||
// just a shortcut
|
||||
inline SettingsStorage *settings() { return SettingsStorage::instance(); }
|
||||
#define FILELOGGER_SETTINGS_KEY(name) (SETTINGS_KEY("FileLogger/") name)
|
||||
|
||||
const QString LOG_FOLDER = QStringLiteral("logs");
|
||||
const QChar PARAMS_SEPARATOR = '|';
|
||||
const QChar PARAMS_SEPARATOR = QLatin1Char('|');
|
||||
|
||||
const QString DEFAULT_PORTABLE_MODE_PROFILE_DIR = QStringLiteral("profile");
|
||||
|
||||
@@ -133,6 +122,16 @@ Application::Application(int &argc, char **argv)
|
||||
, m_running(false)
|
||||
, m_shutdownAct(ShutdownDialogAction::Exit)
|
||||
, m_commandLineArgs(parseCommandLine(this->arguments()))
|
||||
#ifdef Q_OS_WIN
|
||||
, m_storeMemoryWorkingSetLimit(SETTINGS_KEY("MemoryWorkingSetLimit"))
|
||||
#endif
|
||||
, m_storeFileLoggerEnabled(FILELOGGER_SETTINGS_KEY("Enabled"))
|
||||
, m_storeFileLoggerBackup(FILELOGGER_SETTINGS_KEY("Backup"))
|
||||
, m_storeFileLoggerDeleteOld(FILELOGGER_SETTINGS_KEY("DeleteOld"))
|
||||
, m_storeFileLoggerMaxSize(FILELOGGER_SETTINGS_KEY("MaxSizeBytes"))
|
||||
, m_storeFileLoggerAge(FILELOGGER_SETTINGS_KEY("Age"))
|
||||
, m_storeFileLoggerAgeType(FILELOGGER_SETTINGS_KEY("AgeType"))
|
||||
, m_storeFileLoggerPath(FILELOGGER_SETTINGS_KEY("Path"))
|
||||
{
|
||||
qRegisterMetaType<Log::Msg>("Log::Msg");
|
||||
qRegisterMetaType<Log::Peer>("Log::Peer");
|
||||
@@ -154,17 +153,11 @@ Application::Application(int &argc, char **argv)
|
||||
const QString profileDir = portableModeEnabled
|
||||
? QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(DEFAULT_PORTABLE_MODE_PROFILE_DIR)
|
||||
: m_commandLineArgs.profileDir;
|
||||
#ifdef Q_OS_WIN
|
||||
const QString instanceId = (profileDir + (m_commandLineArgs.configurationName.isEmpty() ? QString {} : ('/' + m_commandLineArgs.configurationName))).toLower();
|
||||
#else
|
||||
const QString instanceId = profileDir + (m_commandLineArgs.configurationName.isEmpty() ? QString {} : ('/' + m_commandLineArgs.configurationName));
|
||||
#endif
|
||||
const QString appId = QLatin1String("qBittorrent-") + Utils::Misc::getUserIDString() + '@' + instanceId;
|
||||
m_instanceManager = new ApplicationInstanceManager {appId, this};
|
||||
|
||||
Profile::initInstance(profileDir, m_commandLineArgs.configurationName,
|
||||
(m_commandLineArgs.relativeFastresumePaths || portableModeEnabled));
|
||||
|
||||
m_instanceManager = new ApplicationInstanceManager {Profile::instance()->location(SpecialFolder::Config), this};
|
||||
|
||||
Logger::initInstance();
|
||||
SettingsStorage::initInstance();
|
||||
Preferences::initInstance();
|
||||
@@ -215,9 +208,25 @@ const QBtCommandLineParameters &Application::commandLineArgs() const
|
||||
return m_commandLineArgs;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
int Application::memoryWorkingSetLimit() const
|
||||
{
|
||||
return m_storeMemoryWorkingSetLimit.get(512);
|
||||
}
|
||||
|
||||
void Application::setMemoryWorkingSetLimit(const int size)
|
||||
{
|
||||
if (size == memoryWorkingSetLimit())
|
||||
return;
|
||||
|
||||
m_storeMemoryWorkingSetLimit = size;
|
||||
applyMemoryWorkingSetLimit();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Application::isFileLoggerEnabled() const
|
||||
{
|
||||
return settings()->loadValue(KEY_FILELOGGER_ENABLED, true);
|
||||
return m_storeFileLoggerEnabled.get(true);
|
||||
}
|
||||
|
||||
void Application::setFileLoggerEnabled(const bool value)
|
||||
@@ -226,49 +235,48 @@ void Application::setFileLoggerEnabled(const bool value)
|
||||
m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType()));
|
||||
else if (!value)
|
||||
delete m_fileLogger;
|
||||
settings()->storeValue(KEY_FILELOGGER_ENABLED, value);
|
||||
m_storeFileLoggerEnabled = value;
|
||||
}
|
||||
|
||||
QString Application::fileLoggerPath() const
|
||||
{
|
||||
return settings()->loadValue(KEY_FILELOGGER_PATH
|
||||
, QString {specialFolderLocation(SpecialFolder::Data) + LOG_FOLDER});
|
||||
return m_storeFileLoggerPath.get(QDir(specialFolderLocation(SpecialFolder::Data)).absoluteFilePath(LOG_FOLDER));
|
||||
}
|
||||
|
||||
void Application::setFileLoggerPath(const QString &path)
|
||||
{
|
||||
if (m_fileLogger)
|
||||
m_fileLogger->changePath(path);
|
||||
settings()->storeValue(KEY_FILELOGGER_PATH, path);
|
||||
m_storeFileLoggerPath = path;
|
||||
}
|
||||
|
||||
bool Application::isFileLoggerBackup() const
|
||||
{
|
||||
return settings()->loadValue(KEY_FILELOGGER_BACKUP, true);
|
||||
return m_storeFileLoggerBackup.get(true);
|
||||
}
|
||||
|
||||
void Application::setFileLoggerBackup(const bool value)
|
||||
{
|
||||
if (m_fileLogger)
|
||||
m_fileLogger->setBackup(value);
|
||||
settings()->storeValue(KEY_FILELOGGER_BACKUP, value);
|
||||
m_storeFileLoggerBackup = value;
|
||||
}
|
||||
|
||||
bool Application::isFileLoggerDeleteOld() const
|
||||
{
|
||||
return settings()->loadValue(KEY_FILELOGGER_DELETEOLD, true);
|
||||
return m_storeFileLoggerDeleteOld.get(true);
|
||||
}
|
||||
|
||||
void Application::setFileLoggerDeleteOld(const bool value)
|
||||
{
|
||||
if (value && m_fileLogger)
|
||||
m_fileLogger->deleteOld(fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType()));
|
||||
settings()->storeValue(KEY_FILELOGGER_DELETEOLD, value);
|
||||
m_storeFileLoggerDeleteOld = value;
|
||||
}
|
||||
|
||||
int Application::fileLoggerMaxSize() const
|
||||
{
|
||||
const int val = settings()->loadValue(KEY_FILELOGGER_MAXSIZEBYTES, DEFAULT_FILELOG_SIZE);
|
||||
const int val = m_storeFileLoggerMaxSize.get(DEFAULT_FILELOG_SIZE);
|
||||
return std::min(std::max(val, MIN_FILELOG_SIZE), MAX_FILELOG_SIZE);
|
||||
}
|
||||
|
||||
@@ -277,29 +285,29 @@ void Application::setFileLoggerMaxSize(const int bytes)
|
||||
const int clampedValue = std::min(std::max(bytes, MIN_FILELOG_SIZE), MAX_FILELOG_SIZE);
|
||||
if (m_fileLogger)
|
||||
m_fileLogger->setMaxSize(clampedValue);
|
||||
settings()->storeValue(KEY_FILELOGGER_MAXSIZEBYTES, clampedValue);
|
||||
m_storeFileLoggerMaxSize = clampedValue;
|
||||
}
|
||||
|
||||
int Application::fileLoggerAge() const
|
||||
{
|
||||
const int val = settings()->loadValue(KEY_FILELOGGER_AGE, 1);
|
||||
const int val = m_storeFileLoggerAge.get(1);
|
||||
return std::min(std::max(val, 1), 365);
|
||||
}
|
||||
|
||||
void Application::setFileLoggerAge(const int value)
|
||||
{
|
||||
settings()->storeValue(KEY_FILELOGGER_AGE, std::min(std::max(value, 1), 365));
|
||||
m_storeFileLoggerAge = std::min(std::max(value, 1), 365);
|
||||
}
|
||||
|
||||
int Application::fileLoggerAgeType() const
|
||||
{
|
||||
const int val = settings()->loadValue(KEY_FILELOGGER_AGETYPE, 1);
|
||||
const int val = m_storeFileLoggerAgeType.get(1);
|
||||
return ((val < 0) || (val > 2)) ? 1 : val;
|
||||
}
|
||||
|
||||
void Application::setFileLoggerAgeType(const int value)
|
||||
{
|
||||
settings()->storeValue(KEY_FILELOGGER_AGETYPE, ((value < 0) || (value > 2)) ? 1 : value);
|
||||
m_storeFileLoggerAgeType = ((value < 0) || (value > 2)) ? 1 : value;
|
||||
}
|
||||
|
||||
void Application::processMessage(const QString &message)
|
||||
@@ -394,14 +402,13 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const
|
||||
LogMsg(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program));
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
auto programWchar = std::make_unique<wchar_t[]>(program.length() + 1);
|
||||
program.toWCharArray(programWchar.get());
|
||||
const std::wstring programWStr = program.toStdWString();
|
||||
|
||||
// Need to split arguments manually because QProcess::startDetached(QString)
|
||||
// will strip off empty parameters.
|
||||
// E.g. `python.exe "1" "" "3"` will become `python.exe "1" "3"`
|
||||
int argCount = 0;
|
||||
std::unique_ptr<LPWSTR[], decltype(&::LocalFree)> args {::CommandLineToArgvW(programWchar.get(), &argCount), ::LocalFree};
|
||||
std::unique_ptr<LPWSTR[], decltype(&::LocalFree)> args {::CommandLineToArgvW(programWStr.c_str(), &argCount), ::LocalFree};
|
||||
|
||||
QStringList argList;
|
||||
for (int i = 1; i < argCount; ++i)
|
||||
@@ -614,6 +621,10 @@ void Application::processParams(const QStringList ¶ms)
|
||||
|
||||
int Application::exec(const QStringList ¶ms)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
applyMemoryWorkingSetLimit();
|
||||
#endif
|
||||
|
||||
Net::ProxyConfigurationManager::initInstance();
|
||||
Net::DownloadManager::initInstance();
|
||||
IconProvider::initInstance();
|
||||
@@ -657,12 +668,13 @@ int Application::exec(const QStringList ¶ms)
|
||||
|
||||
#ifdef DISABLE_GUI
|
||||
#ifndef DISABLE_WEBUI
|
||||
Preferences *const pref = Preferences::instance();
|
||||
// Display some information to the user
|
||||
const Preferences *pref = Preferences::instance();
|
||||
|
||||
const auto scheme = QString::fromLatin1(pref->isWebUiHttpsEnabled() ? "https" : "http");
|
||||
const auto url = QString::fromLatin1("%1://localhost:%2\n").arg(scheme, QString::number(pref->getWebUiPort()));
|
||||
const QString mesg = QString::fromLatin1("\n******** %1 ********\n").arg(tr("Information"))
|
||||
+ tr("To control qBittorrent, access the Web UI at %1")
|
||||
.arg(QString("http://localhost:") + QString::number(pref->getWebUiPort())) + '\n';
|
||||
printf("%s", qUtf8Printable(mesg));
|
||||
+ tr("To control qBittorrent, access the WebUI at: %1").arg(url);
|
||||
printf("%s\n", qUtf8Printable(mesg));
|
||||
|
||||
if (pref->getWebUIPassword() == "ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==")
|
||||
{
|
||||
@@ -782,6 +794,29 @@ void Application::shutdownCleanup(QSessionManager &manager)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void Application::applyMemoryWorkingSetLimit()
|
||||
{
|
||||
const SIZE_T UNIT_SIZE = 1024 * 1024; // MiB
|
||||
const SIZE_T maxSize = memoryWorkingSetLimit() * UNIT_SIZE;
|
||||
const SIZE_T minSize = std::min<SIZE_T>((64 * UNIT_SIZE), (maxSize / 2));
|
||||
if (!::SetProcessWorkingSetSizeEx(::GetCurrentProcess(), minSize, maxSize, QUOTA_LIMITS_HARDWS_MAX_ENABLE))
|
||||
{
|
||||
const DWORD errorCode = ::GetLastError();
|
||||
QString message;
|
||||
LPVOID lpMsgBuf = nullptr;
|
||||
if (::FormatMessageW((FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS)
|
||||
, nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&lpMsgBuf), 0, nullptr))
|
||||
{
|
||||
message = QString::fromWCharArray(reinterpret_cast<LPWSTR>(lpMsgBuf)).trimmed();
|
||||
::LocalFree(lpMsgBuf);
|
||||
}
|
||||
LogMsg(tr("Failed to set physical memory (RAM) usage limit. Error code: %1. Error message: \"%2\"")
|
||||
.arg(QString::number(errorCode), message), Log::WARNING);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Application::cleanup()
|
||||
{
|
||||
// cleanup() can be called multiple times during shutdown. We only need it once.
|
||||
@@ -799,8 +834,9 @@ void Application::cleanup()
|
||||
m_window->hide();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
const std::wstring msg = tr("Saving torrent progress...").toStdWString();
|
||||
::ShutdownBlockReasonCreate(reinterpret_cast<HWND>(m_window->effectiveWinId())
|
||||
, tr("Saving torrent progress...").toStdWString().c_str());
|
||||
, msg.c_str());
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
// Do manual cleanup in MainWindow to force widgets
|
||||
|
||||
@@ -47,6 +47,7 @@ class QSessionManager;
|
||||
using BaseApplication = QCoreApplication;
|
||||
#endif // DISABLE_GUI
|
||||
|
||||
#include "base/settingvalue.h"
|
||||
#include "base/types.h"
|
||||
#include "cmdoptions.h"
|
||||
|
||||
@@ -87,6 +88,11 @@ public:
|
||||
|
||||
const QBtCommandLineParameters &commandLineArgs() const;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
int memoryWorkingSetLimit() const;
|
||||
void setMemoryWorkingSetLimit(int size);
|
||||
#endif
|
||||
|
||||
// FileLogger properties
|
||||
bool isFileLoggerEnabled() const;
|
||||
void setFileLoggerEnabled(bool value);
|
||||
@@ -120,6 +126,14 @@ private slots:
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef Q_OS_WIN
|
||||
void applyMemoryWorkingSetLimit();
|
||||
#endif
|
||||
void initializeTranslation();
|
||||
void processParams(const QStringList ¶ms);
|
||||
void runExternalProgram(const BitTorrent::Torrent *torrent) const;
|
||||
void sendNotificationEmail(const BitTorrent::Torrent *torrent);
|
||||
|
||||
ApplicationInstanceManager *m_instanceManager = nullptr;
|
||||
bool m_running;
|
||||
ShutdownDialogAction m_shutdownAct;
|
||||
@@ -140,8 +154,14 @@ private:
|
||||
QTranslator m_translator;
|
||||
QStringList m_paramsQueue;
|
||||
|
||||
void initializeTranslation();
|
||||
void processParams(const QStringList ¶ms);
|
||||
void runExternalProgram(const BitTorrent::Torrent *torrent) const;
|
||||
void sendNotificationEmail(const BitTorrent::Torrent *torrent);
|
||||
#ifdef Q_OS_WIN
|
||||
SettingValue<int> m_storeMemoryWorkingSetLimit;
|
||||
#endif
|
||||
SettingValue<bool> m_storeFileLoggerEnabled;
|
||||
SettingValue<bool> m_storeFileLoggerBackup;
|
||||
SettingValue<bool> m_storeFileLoggerDeleteOld;
|
||||
SettingValue<int> m_storeFileLoggerMaxSize;
|
||||
SettingValue<int> m_storeFileLoggerAge;
|
||||
SettingValue<int> m_storeFileLoggerAgeType;
|
||||
SettingValue<QString> m_storeFileLoggerPath;
|
||||
};
|
||||
|
||||
@@ -28,24 +28,27 @@
|
||||
|
||||
#include "applicationinstancemanager.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QSharedMemory>
|
||||
#endif
|
||||
|
||||
#include "qtlocalpeer/qtlocalpeer.h"
|
||||
|
||||
ApplicationInstanceManager::ApplicationInstanceManager(const QString &appId, QObject *parent)
|
||||
ApplicationInstanceManager::ApplicationInstanceManager(const QString &instancePath, QObject *parent)
|
||||
: QObject {parent}
|
||||
, m_peer {new QtLocalPeer {this, appId}}
|
||||
, m_peer {new QtLocalPeer {instancePath, this}}
|
||||
, m_isFirstInstance {!m_peer->isClient()}
|
||||
{
|
||||
connect(m_peer, &QtLocalPeer::messageReceived, this, &ApplicationInstanceManager::messageReceived);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
auto sharedMem = new QSharedMemory {appId + QLatin1String {"-shared-memory-key"}, this};
|
||||
const QString sharedMemoryKey = instancePath + QLatin1String {"/shared-memory"};
|
||||
auto sharedMem = new QSharedMemory {sharedMemoryKey, this};
|
||||
if (m_isFirstInstance)
|
||||
{
|
||||
// First instance creates shared memory and store PID
|
||||
@@ -79,8 +82,3 @@ bool ApplicationInstanceManager::sendMessage(const QString &message, const int t
|
||||
{
|
||||
return m_peer->sendMessage(message, timeout);
|
||||
}
|
||||
|
||||
QString ApplicationInstanceManager::appId() const
|
||||
{
|
||||
return m_peer->applicationId();
|
||||
}
|
||||
|
||||
@@ -32,16 +32,15 @@
|
||||
|
||||
class QtLocalPeer;
|
||||
|
||||
class ApplicationInstanceManager : public QObject
|
||||
class ApplicationInstanceManager final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(ApplicationInstanceManager)
|
||||
|
||||
public:
|
||||
explicit ApplicationInstanceManager(const QString &appId, QObject *parent = nullptr);
|
||||
explicit ApplicationInstanceManager(const QString &instancePath, QObject *parent = nullptr);
|
||||
|
||||
bool isFirstInstance() const;
|
||||
QString appId() const;
|
||||
|
||||
public slots:
|
||||
bool sendMessage(const QString &message, int timeout = 5000);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
#include <sys/resource.h>
|
||||
@@ -188,7 +189,6 @@ int main(int argc, char *argv[])
|
||||
#ifndef DISABLE_GUI
|
||||
if (!userAgreesWithLegalNotice())
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
#elif defined(Q_OS_WIN)
|
||||
if (_isatty(_fileno(stdin))
|
||||
&& _isatty(_fileno(stdout))
|
||||
@@ -201,6 +201,8 @@ int main(int argc, char *argv[])
|
||||
&& !userAgreesWithLegalNotice())
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
|
||||
setCurrentMigrationVersion();
|
||||
}
|
||||
|
||||
// Check if qBittorrent is already running for this user
|
||||
@@ -320,17 +322,13 @@ int main(int argc, char *argv[])
|
||||
void reportToUser(const char *str)
|
||||
{
|
||||
const size_t strLen = strlen(str);
|
||||
#ifndef Q_OS_WIN
|
||||
if (write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen))
|
||||
{
|
||||
const auto dummy = write(STDOUT_FILENO, str, strLen);
|
||||
#ifdef Q_OS_WIN
|
||||
if (_write(_fileno(stderr), str, strLen) < static_cast<int>(strLen))
|
||||
std::ignore = _write(_fileno(stdout), str, strLen);
|
||||
#else
|
||||
if (_write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen))
|
||||
{
|
||||
const auto dummy = _write(STDOUT_FILENO, str, strLen);
|
||||
if (write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen))
|
||||
std::ignore = write(STDOUT_FILENO, str, strLen);
|
||||
#endif
|
||||
Q_UNUSED(dummy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -359,8 +357,10 @@ void sigAbnormalHandler(int signum)
|
||||
reportToUser(msg);
|
||||
reportToUser(sigName);
|
||||
reportToUser("\n");
|
||||
#if !defined Q_OS_WIN
|
||||
print_stacktrace(); // unsafe
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_WIN && !defined DISABLE_GUI
|
||||
StacktraceDialog dlg; // unsafe
|
||||
|
||||
@@ -68,20 +68,16 @@
|
||||
|
||||
#include "qtlocalpeer.h"
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDataStream>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "base/utils/misc.h"
|
||||
|
||||
namespace QtLP_Private
|
||||
{
|
||||
@@ -94,75 +90,49 @@ namespace QtLP_Private
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* QtLocalPeer::ack = "ack";
|
||||
const char ACK[] = "ack";
|
||||
|
||||
QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
|
||||
QtLocalPeer::QtLocalPeer(const QString &path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, id(appId)
|
||||
, m_socketName(path + QLatin1String("/ipc-socket"))
|
||||
, m_server(new QLocalServer(this))
|
||||
{
|
||||
QString prefix = id;
|
||||
if (id.isEmpty())
|
||||
{
|
||||
id = QCoreApplication::applicationFilePath();
|
||||
#if defined(Q_OS_WIN)
|
||||
id = id.toLower();
|
||||
#endif
|
||||
prefix = id.section(QLatin1Char('/'), -1);
|
||||
}
|
||||
prefix.remove(QRegularExpression("[^a-zA-Z]"));
|
||||
prefix.truncate(6);
|
||||
m_server->setSocketOptions(QLocalServer::UserAccessOption);
|
||||
|
||||
QByteArray idc = id.toUtf8();
|
||||
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
||||
socketName = QLatin1String("qtsingleapp-") + prefix
|
||||
+ QLatin1Char('-') + QString::number(idNum, 16);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
DWORD sessionId = 0;
|
||||
::ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
socketName += (QLatin1Char('-') + QString::number(sessionId, 16));
|
||||
#else
|
||||
socketName += (QLatin1Char('-') + QString::number(::getuid(), 16));
|
||||
#endif
|
||||
|
||||
server = new QLocalServer(this);
|
||||
server->setSocketOptions(QLocalServer::UserAccessOption);
|
||||
QString lockName = QDir(QDir::tempPath()).absolutePath()
|
||||
+ QLatin1Char('/') + socketName
|
||||
+ QLatin1String("-lockfile");
|
||||
lockFile.setFileName(lockName);
|
||||
lockFile.open(QIODevice::ReadWrite);
|
||||
m_lockFile.setFileName(path + QLatin1String("/lockfile"));
|
||||
m_lockFile.open(QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
QtLocalPeer::~QtLocalPeer()
|
||||
{
|
||||
if (!isClient())
|
||||
{
|
||||
lockFile.unlock();
|
||||
lockFile.remove();
|
||||
m_lockFile.unlock();
|
||||
m_lockFile.remove();
|
||||
}
|
||||
}
|
||||
|
||||
bool QtLocalPeer::isClient()
|
||||
{
|
||||
if (lockFile.isLocked())
|
||||
if (m_lockFile.isLocked())
|
||||
return false;
|
||||
|
||||
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
|
||||
if (!m_lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
|
||||
return true;
|
||||
|
||||
bool res = server->listen(socketName);
|
||||
bool res = m_server->listen(m_socketName);
|
||||
#if defined(Q_OS_UNIX)
|
||||
// ### Workaround
|
||||
if (!res && server->serverError() == QAbstractSocket::AddressInUseError)
|
||||
if (!res && m_server->serverError() == QAbstractSocket::AddressInUseError)
|
||||
{
|
||||
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
|
||||
res = server->listen(socketName);
|
||||
QFile::remove(m_socketName);
|
||||
res = m_server->listen(m_socketName);
|
||||
}
|
||||
#endif
|
||||
if (!res)
|
||||
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
|
||||
connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection);
|
||||
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qUtf8Printable(m_server->errorString()));
|
||||
|
||||
connect(m_server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -176,7 +146,7 @@ bool QtLocalPeer::sendMessage(const QString &message, const int timeout)
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
// Try twice, in case the other instance is just starting up
|
||||
socket.connectToServer(socketName);
|
||||
socket.connectToServer(m_socketName);
|
||||
connOk = socket.waitForConnected(timeout/2);
|
||||
if (connOk || i)
|
||||
break;
|
||||
@@ -199,19 +169,14 @@ bool QtLocalPeer::sendMessage(const QString &message, const int timeout)
|
||||
{
|
||||
res &= socket.waitForReadyRead(timeout); // wait for ack
|
||||
if (res)
|
||||
res &= (socket.read(qstrlen(ack)) == ack);
|
||||
res &= (socket.read(qstrlen(ACK)) == ACK);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
QString QtLocalPeer::applicationId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
void QtLocalPeer::receiveConnection()
|
||||
{
|
||||
QLocalSocket* socket = server->nextPendingConnection();
|
||||
QLocalSocket *socket = m_server->nextPendingConnection();
|
||||
if (!socket)
|
||||
return;
|
||||
|
||||
@@ -255,7 +220,7 @@ void QtLocalPeer::receiveConnection()
|
||||
return;
|
||||
}
|
||||
QString message(QString::fromUtf8(uMsg));
|
||||
socket->write(ack, qstrlen(ack));
|
||||
socket->write(ACK, qstrlen(ACK));
|
||||
socket->waitForBytesWritten(1000);
|
||||
socket->waitForDisconnected(1000); // make sure client reads ack
|
||||
delete socket;
|
||||
|
||||
@@ -68,34 +68,32 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
|
||||
class QLocalServer;
|
||||
|
||||
class QtLocalPeer : public QObject
|
||||
class QtLocalPeer final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(QtLocalPeer)
|
||||
|
||||
public:
|
||||
QtLocalPeer(QObject *parent = nullptr, const QString &appId = QString());
|
||||
QtLocalPeer(const QString &path, QObject *parent = nullptr);
|
||||
~QtLocalPeer() override;
|
||||
|
||||
bool isClient();
|
||||
bool sendMessage(const QString &message, int timeout);
|
||||
QString applicationId() const;
|
||||
|
||||
signals:
|
||||
void messageReceived(const QString &message);
|
||||
|
||||
protected slots:
|
||||
private slots:
|
||||
void receiveConnection();
|
||||
|
||||
protected:
|
||||
QString id;
|
||||
QString socketName;
|
||||
QLocalServer *server = nullptr;
|
||||
QtLP_Private::QtLockedFile lockFile;
|
||||
|
||||
private:
|
||||
static const char* ack;
|
||||
QString m_socketName;
|
||||
QLocalServer *m_server = nullptr;
|
||||
QtLP_Private::QtLockedFile m_lockFile;
|
||||
};
|
||||
|
||||
@@ -108,11 +108,7 @@
|
||||
|
||||
\sa QFile::QFile()
|
||||
*/
|
||||
QtLockedFile::QtLockedFile()
|
||||
: QFile()
|
||||
{
|
||||
m_lock_mode = NoLock;
|
||||
}
|
||||
QtLockedFile::QtLockedFile() = default;
|
||||
|
||||
/*!
|
||||
Constructs an unlocked QtLockedFile object with file \a name. This
|
||||
@@ -124,7 +120,6 @@ QtLockedFile::QtLockedFile()
|
||||
QtLockedFile::QtLockedFile(const QString &name)
|
||||
: QFile(name)
|
||||
{
|
||||
m_lock_mode = NoLock;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -142,7 +137,8 @@ QtLockedFile::QtLockedFile(const QString &name)
|
||||
*/
|
||||
bool QtLockedFile::open(const OpenMode mode)
|
||||
{
|
||||
if (mode & QIODevice::Truncate) {
|
||||
if (mode & QIODevice::Truncate)
|
||||
{
|
||||
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
|
||||
return false;
|
||||
}
|
||||
@@ -157,7 +153,7 @@ bool QtLockedFile::open(const OpenMode mode)
|
||||
*/
|
||||
bool QtLockedFile::isLocked() const
|
||||
{
|
||||
return m_lock_mode != NoLock;
|
||||
return m_lockMode != NoLock;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -168,7 +164,7 @@ bool QtLockedFile::isLocked() const
|
||||
*/
|
||||
QtLockedFile::LockMode QtLockedFile::lockMode() const
|
||||
{
|
||||
return m_lock_mode;
|
||||
return m_lockMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
#include <QFile>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#endif
|
||||
|
||||
@@ -100,14 +101,14 @@ namespace QtLP_Private
|
||||
private:
|
||||
#ifdef Q_OS_WIN
|
||||
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
|
||||
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
|
||||
bool waitMutex(Qt::HANDLE mutex, bool doBlock) const;
|
||||
|
||||
Qt::HANDLE wmutex = nullptr;
|
||||
Qt::HANDLE rmutex = nullptr;
|
||||
QVector<Qt::HANDLE> rmutexes;
|
||||
QString mutexname;
|
||||
Qt::HANDLE m_writeMutex = nullptr;
|
||||
Qt::HANDLE m_readMutex = nullptr;
|
||||
QVector<Qt::HANDLE> m_readMutexes;
|
||||
QString m_mutexName;
|
||||
#endif
|
||||
|
||||
LockMode m_lock_mode;
|
||||
LockMode m_lockMode = NoLock;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -73,9 +73,10 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
bool QtLockedFile::lock(LockMode mode, bool block)
|
||||
bool QtLockedFile::lock(const LockMode mode, const bool block)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
if (!isOpen())
|
||||
{
|
||||
qWarning("QtLockedFile::lock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
@@ -83,10 +84,10 @@ bool QtLockedFile::lock(LockMode mode, bool block)
|
||||
if (mode == NoLock)
|
||||
return unlock();
|
||||
|
||||
if (mode == m_lock_mode)
|
||||
if (mode == m_lockMode)
|
||||
return true;
|
||||
|
||||
if (m_lock_mode != NoLock)
|
||||
if (m_lockMode != NoLock)
|
||||
unlock();
|
||||
|
||||
struct flock fl;
|
||||
@@ -97,19 +98,21 @@ bool QtLockedFile::lock(LockMode mode, bool block)
|
||||
int cmd = block ? F_SETLKW : F_SETLK;
|
||||
int ret = fcntl(handle(), cmd, &fl);
|
||||
|
||||
if (ret == -1) {
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lock_mode = mode;
|
||||
m_lockMode = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QtLockedFile::unlock()
|
||||
{
|
||||
if (!isOpen()) {
|
||||
if (!isOpen())
|
||||
{
|
||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
@@ -124,12 +127,13 @@ bool QtLockedFile::unlock()
|
||||
fl.l_type = F_UNLCK;
|
||||
int ret = fcntl(handle(), F_SETLKW, &fl);
|
||||
|
||||
if (ret == -1) {
|
||||
if (ret == -1)
|
||||
{
|
||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lock_mode = NoLock;
|
||||
m_lockMode = NoLock;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,64 +70,75 @@
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#define MUTEX_PREFIX "QtLockedFile mutex "
|
||||
#include "base/global.h"
|
||||
|
||||
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
|
||||
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
|
||||
const int MAX_READERS = MAXIMUM_WAIT_OBJECTS;
|
||||
|
||||
#define QT_WA(unicode, ansi) unicode
|
||||
|
||||
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
|
||||
Qt::HANDLE QtLockedFile::getMutexHandle(const int idx, const bool doCreate)
|
||||
{
|
||||
if (mutexname.isEmpty()) {
|
||||
if (m_mutexName.isEmpty())
|
||||
{
|
||||
QFileInfo fi(*this);
|
||||
mutexname = QString::fromLatin1(MUTEX_PREFIX)
|
||||
+ fi.absoluteFilePath().toLower();
|
||||
m_mutexName = QString::fromLatin1("QtLockedFile mutex ") + fi.absoluteFilePath().toLower();
|
||||
}
|
||||
QString mname(mutexname);
|
||||
|
||||
QString mname = m_mutexName;
|
||||
if (idx >= 0)
|
||||
mname += QString::number(idx);
|
||||
|
||||
Qt::HANDLE mutex;
|
||||
if (doCreate) {
|
||||
QT_WA( { mutex = CreateMutexW(NULL, FALSE, reinterpret_cast<const TCHAR *>(mname.utf16())); },
|
||||
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
|
||||
if (!mutex) {
|
||||
const std::wstring mnameWStr = mname.toStdWString();
|
||||
|
||||
if (doCreate)
|
||||
{
|
||||
const Qt::HANDLE mutex = ::CreateMutexW(NULL, FALSE, mnameWStr.c_str());
|
||||
if (!mutex)
|
||||
{
|
||||
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mutex;
|
||||
}
|
||||
else {
|
||||
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, reinterpret_cast<const TCHAR *>(mname.utf16())); },
|
||||
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
|
||||
if (!mutex) {
|
||||
else
|
||||
{
|
||||
const Qt::HANDLE mutex = ::OpenMutexW((SYNCHRONIZE | MUTEX_MODIFY_STATE), FALSE, mnameWStr.c_str());
|
||||
if (!mutex)
|
||||
{
|
||||
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mutex;
|
||||
}
|
||||
return mutex;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
|
||||
bool QtLockedFile::waitMutex(const Qt::HANDLE mutex, const bool doBlock) const
|
||||
{
|
||||
Q_ASSERT(mutex);
|
||||
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
|
||||
switch (res) {
|
||||
|
||||
const DWORD res = ::WaitForSingleObject(mutex, (doBlock ? INFINITE : 0));
|
||||
switch (res)
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
case WAIT_ABANDONED:
|
||||
return true;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
break;
|
||||
return false;
|
||||
default:
|
||||
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QtLockedFile::lock(LockMode mode, bool block)
|
||||
bool QtLockedFile::lock(const LockMode mode, const bool block)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
if (!isOpen())
|
||||
{
|
||||
qWarning("QtLockedFile::lock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
@@ -135,72 +146,85 @@ bool QtLockedFile::lock(LockMode mode, bool block)
|
||||
if (mode == NoLock)
|
||||
return unlock();
|
||||
|
||||
if (mode == m_lock_mode)
|
||||
if (mode == m_lockMode)
|
||||
return true;
|
||||
|
||||
if (m_lock_mode != NoLock)
|
||||
if (m_lockMode != NoLock)
|
||||
unlock();
|
||||
|
||||
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
|
||||
if (!m_writeMutex && !(m_writeMutex = getMutexHandle(-1, true)))
|
||||
return false;
|
||||
|
||||
if (!waitMutex(wmutex, block))
|
||||
if (!waitMutex(m_writeMutex, block))
|
||||
return false;
|
||||
|
||||
if (mode == ReadLock) {
|
||||
if (mode == ReadLock)
|
||||
{
|
||||
int idx = 0;
|
||||
for (; idx < MAX_READERS; idx++) {
|
||||
rmutex = getMutexHandle(idx, false);
|
||||
if (!rmutex || waitMutex(rmutex, false))
|
||||
for (; idx < MAX_READERS; ++idx)
|
||||
{
|
||||
m_readMutex = getMutexHandle(idx, false);
|
||||
if (!m_readMutex || waitMutex(m_readMutex, false))
|
||||
break;
|
||||
CloseHandle(rmutex);
|
||||
::CloseHandle(m_readMutex);
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
if (idx >= MAX_READERS) {
|
||||
if (idx >= MAX_READERS)
|
||||
{
|
||||
qWarning("QtLockedFile::lock(): too many readers");
|
||||
rmutex = 0;
|
||||
m_readMutex = nullptr;
|
||||
ok = false;
|
||||
}
|
||||
else if (!rmutex) {
|
||||
rmutex = getMutexHandle(idx, true);
|
||||
if (!rmutex || !waitMutex(rmutex, false))
|
||||
else if (!m_readMutex)
|
||||
{
|
||||
m_readMutex = getMutexHandle(idx, true);
|
||||
if (!m_readMutex || !waitMutex(m_readMutex, false))
|
||||
ok = false;
|
||||
}
|
||||
if (!ok && rmutex) {
|
||||
CloseHandle(rmutex);
|
||||
rmutex = 0;
|
||||
|
||||
if (!ok && m_readMutex)
|
||||
{
|
||||
::CloseHandle(m_readMutex);
|
||||
m_readMutex = nullptr;
|
||||
}
|
||||
ReleaseMutex(wmutex);
|
||||
|
||||
::ReleaseMutex(m_writeMutex);
|
||||
if (!ok)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Q_ASSERT(rmutexes.isEmpty());
|
||||
for (int i = 0; i < MAX_READERS; i++) {
|
||||
Qt::HANDLE mutex = getMutexHandle(i, false);
|
||||
else
|
||||
{
|
||||
Q_ASSERT(m_readMutexes.isEmpty());
|
||||
for (int i = 0; i < MAX_READERS; ++i)
|
||||
{
|
||||
const Qt::HANDLE mutex = getMutexHandle(i, false);
|
||||
if (mutex)
|
||||
rmutexes.append(mutex);
|
||||
m_readMutexes.append(mutex);
|
||||
}
|
||||
if (rmutexes.size()) {
|
||||
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
|
||||
TRUE, block ? INFINITE : 0);
|
||||
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
|
||||
if (m_readMutexes.size())
|
||||
{
|
||||
const DWORD res = ::WaitForMultipleObjects(m_readMutexes.size(), m_readMutexes.constData(),
|
||||
TRUE, (block ? INFINITE : 0));
|
||||
if ((res != WAIT_OBJECT_0) && (res != WAIT_ABANDONED))
|
||||
{
|
||||
if (res != WAIT_TIMEOUT)
|
||||
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
|
||||
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
|
||||
m_lockMode = WriteLock; // trick unlock() to clean up - semiyucky
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_lock_mode = mode;
|
||||
m_lockMode = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QtLockedFile::unlock()
|
||||
{
|
||||
if (!isOpen()) {
|
||||
if (!isOpen())
|
||||
{
|
||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
@@ -208,21 +232,24 @@ bool QtLockedFile::unlock()
|
||||
if (!isLocked())
|
||||
return true;
|
||||
|
||||
if (m_lock_mode == ReadLock) {
|
||||
ReleaseMutex(rmutex);
|
||||
CloseHandle(rmutex);
|
||||
rmutex = 0;
|
||||
if (m_lockMode == ReadLock)
|
||||
{
|
||||
::ReleaseMutex(m_readMutex);
|
||||
::CloseHandle(m_readMutex);
|
||||
m_readMutex = nullptr;
|
||||
}
|
||||
else {
|
||||
foreach(Qt::HANDLE mutex, rmutexes) {
|
||||
ReleaseMutex(mutex);
|
||||
CloseHandle(mutex);
|
||||
else
|
||||
{
|
||||
for (const Qt::HANDLE &mutex : asConst(m_readMutexes))
|
||||
{
|
||||
::ReleaseMutex(mutex);
|
||||
::CloseHandle(mutex);
|
||||
}
|
||||
rmutexes.clear();
|
||||
ReleaseMutex(wmutex);
|
||||
m_readMutexes.clear();
|
||||
::ReleaseMutex(m_writeMutex);
|
||||
}
|
||||
|
||||
m_lock_mode = QtLockedFile::NoLock;
|
||||
m_lockMode = QtLockedFile::NoLock;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -230,6 +257,6 @@ QtLockedFile::~QtLockedFile()
|
||||
{
|
||||
if (isOpen())
|
||||
unlock();
|
||||
if (wmutex)
|
||||
CloseHandle(wmutex);
|
||||
if (m_writeMutex)
|
||||
::CloseHandle(m_writeMutex);
|
||||
}
|
||||
|
||||
@@ -255,9 +255,10 @@ const QString straceWin::getBacktrace()
|
||||
QTextStream logStream(&log);
|
||||
logStream << "```\n";
|
||||
|
||||
const std::wstring appPath = QCoreApplication::applicationDirPath().toStdWString();
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
HANDLE hThread = GetCurrentThread();
|
||||
SymInitializeW(hProcess, QCoreApplication::applicationDirPath().toStdWString().c_str(), TRUE);
|
||||
SymInitializeW(hProcess, appPath.c_str(), TRUE);
|
||||
|
||||
DWORD64 dwDisplacement;
|
||||
|
||||
|
||||
@@ -29,18 +29,23 @@
|
||||
#include "upgrade.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
#include <QVector>
|
||||
|
||||
#include "base/bittorrent/torrentcontentlayout.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/net/proxyconfigurationmanager.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/profile.h"
|
||||
#include "base/settingsstorage.h"
|
||||
#include "base/settingvalue.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/io.h"
|
||||
#include "base/utils/string.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const int MIGRATION_VERSION = 3;
|
||||
const char MIGRATION_VERSION_KEY[] = "Meta/MigrationVersion";
|
||||
|
||||
void exportWebUIHttpsFiles()
|
||||
{
|
||||
const auto migrate = [](const QString &oldKey, const QString &newKey, const QString &savePath)
|
||||
@@ -70,10 +75,10 @@ namespace
|
||||
const QString configPath {specialFolderLocation(SpecialFolder::Config)};
|
||||
migrate(QLatin1String("Preferences/WebUI/HTTPS/Certificate")
|
||||
, QLatin1String("Preferences/WebUI/HTTPS/CertificatePath")
|
||||
, Utils::Fs::toNativePath(configPath + QLatin1String("WebUICertificate.crt")));
|
||||
, Utils::Fs::toNativePath(configPath + QLatin1String("/WebUICertificate.crt")));
|
||||
migrate(QLatin1String("Preferences/WebUI/HTTPS/Key")
|
||||
, QLatin1String("Preferences/WebUI/HTTPS/KeyPath")
|
||||
, Utils::Fs::toNativePath(configPath + QLatin1String("WebUIPrivateKey.pem")));
|
||||
, Utils::Fs::toNativePath(configPath + QLatin1String("/WebUIPrivateKey.pem")));
|
||||
}
|
||||
|
||||
void upgradeTorrentContentLayout()
|
||||
@@ -110,16 +115,293 @@ namespace
|
||||
settingsStorage->removeValue(oldKey);
|
||||
}
|
||||
}
|
||||
|
||||
void upgradeSchedulerDaysSettings()
|
||||
{
|
||||
auto *settingsStorage = SettingsStorage::instance();
|
||||
const auto key = QString::fromLatin1("Preferences/Scheduler/days");
|
||||
const auto value = settingsStorage->loadValue<QString>(key);
|
||||
|
||||
bool ok = false;
|
||||
const auto number = value.toInt(&ok);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
switch (number)
|
||||
{
|
||||
case 0:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::EveryDay);
|
||||
break;
|
||||
case 1:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Weekday);
|
||||
break;
|
||||
case 2:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Weekend);
|
||||
break;
|
||||
case 3:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Monday);
|
||||
break;
|
||||
case 4:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Tuesday);
|
||||
break;
|
||||
case 5:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Wednesday);
|
||||
break;
|
||||
case 6:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Thursday);
|
||||
break;
|
||||
case 7:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Friday);
|
||||
break;
|
||||
case 8:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Saturday);
|
||||
break;
|
||||
case 9:
|
||||
settingsStorage->storeValue(key, Scheduler::Days::Sunday);
|
||||
break;
|
||||
default:
|
||||
LogMsg(QObject::tr("Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
|
||||
.arg(key, QString::number(number)), Log::WARNING);
|
||||
settingsStorage->removeValue(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void upgradeDNSServiceSettings()
|
||||
{
|
||||
auto *settingsStorage = SettingsStorage::instance();
|
||||
const auto key = QString::fromLatin1("Preferences/DynDNS/Service");
|
||||
const auto value = settingsStorage->loadValue<QString>(key);
|
||||
|
||||
bool ok = false;
|
||||
const auto number = value.toInt(&ok);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
switch (number)
|
||||
{
|
||||
case -1:
|
||||
settingsStorage->storeValue(key, DNS::Service::None);
|
||||
break;
|
||||
case 0:
|
||||
settingsStorage->storeValue(key, DNS::Service::DynDNS);
|
||||
break;
|
||||
case 1:
|
||||
settingsStorage->storeValue(key, DNS::Service::NoIP);
|
||||
break;
|
||||
default:
|
||||
LogMsg(QObject::tr("Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
|
||||
.arg(key, QString::number(number)), Log::WARNING);
|
||||
settingsStorage->removeValue(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void upgradeTrayIconStyleSettings()
|
||||
{
|
||||
auto *settingsStorage = SettingsStorage::instance();
|
||||
const auto key = QString::fromLatin1("Preferences/Advanced/TrayIconStyle");
|
||||
const auto value = settingsStorage->loadValue<QString>(key);
|
||||
|
||||
bool ok = false;
|
||||
const auto number = value.toInt(&ok);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
switch (number)
|
||||
{
|
||||
case 0:
|
||||
settingsStorage->storeValue(key, TrayIcon::Style::Normal);
|
||||
break;
|
||||
case 1:
|
||||
settingsStorage->storeValue(key, TrayIcon::Style::MonoDark);
|
||||
break;
|
||||
case 2:
|
||||
settingsStorage->storeValue(key, TrayIcon::Style::MonoLight);
|
||||
break;
|
||||
default:
|
||||
LogMsg(QObject::tr("Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
|
||||
.arg(key, QString::number(number)), Log::WARNING);
|
||||
settingsStorage->removeValue(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void migrateSettingKeys()
|
||||
{
|
||||
struct KeyMapping
|
||||
{
|
||||
QString newKey;
|
||||
QString oldKey;
|
||||
};
|
||||
|
||||
const KeyMapping mappings[] =
|
||||
{
|
||||
{"AddNewTorrentDialog/Enabled", "Preferences/Downloads/NewAdditionDialog"},
|
||||
{"AddNewTorrentDialog/Expanded", "AddNewTorrentDialog/expanded"},
|
||||
{"AddNewTorrentDialog/Position", "AddNewTorrentDialog/y"},
|
||||
{"AddNewTorrentDialog/SavePathHistory", "TorrentAdditionDlg/save_path_history"},
|
||||
{"AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront"},
|
||||
{"AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/qt5/treeHeaderState"},
|
||||
{"AddNewTorrentDialog/Width", "AddNewTorrentDialog/width"},
|
||||
{"BitTorrent/Session/AddExtensionToIncompleteFiles", "Preferences/Downloads/UseIncompleteExtension"},
|
||||
{"BitTorrent/Session/AdditionalTrackers", "Preferences/Bittorrent/TrackersList"},
|
||||
{"BitTorrent/Session/AddTorrentPaused", "Preferences/Downloads/StartInPause"},
|
||||
{"BitTorrent/Session/AddTrackersEnabled", "Preferences/Bittorrent/AddTrackers"},
|
||||
{"BitTorrent/Session/AlternativeGlobalDLSpeedLimit", "Preferences/Connection/GlobalDLLimitAlt"},
|
||||
{"BitTorrent/Session/AlternativeGlobalUPSpeedLimit", "Preferences/Connection/GlobalUPLimitAlt"},
|
||||
{"BitTorrent/Session/AnnounceIP", "Preferences/Connection/InetAddress"},
|
||||
{"BitTorrent/Session/AnnounceToAllTrackers", "Preferences/Advanced/AnnounceToAllTrackers"},
|
||||
{"BitTorrent/Session/AnonymousModeEnabled", "Preferences/Advanced/AnonymousMode"},
|
||||
{"BitTorrent/Session/BandwidthSchedulerEnabled", "Preferences/Scheduler/Enabled"},
|
||||
{"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"},
|
||||
{"BitTorrent/Session/DHTEnabled", "Preferences/Bittorrent/DHT"},
|
||||
{"BitTorrent/Session/DiskCacheSize", "Preferences/Downloads/DiskWriteCacheSize"},
|
||||
{"BitTorrent/Session/DiskCacheTTL", "Preferences/Downloads/DiskWriteCacheTTL"},
|
||||
{"BitTorrent/Session/Encryption", "Preferences/Bittorrent/Encryption"},
|
||||
{"BitTorrent/Session/FinishedTorrentExportDirectory", "Preferences/Downloads/FinishedTorrentExportDir"},
|
||||
{"BitTorrent/Session/ForceProxy", "Preferences/Connection/ProxyForce"},
|
||||
{"BitTorrent/Session/GlobalDLSpeedLimit", "Preferences/Connection/GlobalDLLimit"},
|
||||
{"BitTorrent/Session/GlobalMaxRatio", "Preferences/Bittorrent/MaxRatio"},
|
||||
{"BitTorrent/Session/GlobalUPSpeedLimit", "Preferences/Connection/GlobalUPLimit"},
|
||||
{"BitTorrent/Session/IgnoreLimitsOnLAN", "Preferences/Advanced/IgnoreLimitsLAN"},
|
||||
{"BitTorrent/Session/IgnoreSlowTorrentsForQueueing", "Preferences/Queueing/IgnoreSlowTorrents"},
|
||||
{"BitTorrent/Session/IncludeOverheadInLimits", "Preferences/Advanced/IncludeOverhead"},
|
||||
{"BitTorrent/Session/Interface", "Preferences/Connection/Interface"},
|
||||
{"BitTorrent/Session/InterfaceAddress", "Preferences/Connection/InterfaceAddress"},
|
||||
{"BitTorrent/Session/InterfaceName", "Preferences/Connection/InterfaceName"},
|
||||
{"BitTorrent/Session/IPFilter", "Preferences/IPFilter/File"},
|
||||
{"BitTorrent/Session/IPFilteringEnabled", "Preferences/IPFilter/Enabled"},
|
||||
{"BitTorrent/Session/LSDEnabled", "Preferences/Bittorrent/LSD"},
|
||||
{"BitTorrent/Session/MaxActiveDownloads", "Preferences/Queueing/MaxActiveDownloads"},
|
||||
{"BitTorrent/Session/MaxActiveTorrents", "Preferences/Queueing/MaxActiveTorrents"},
|
||||
{"BitTorrent/Session/MaxActiveUploads", "Preferences/Queueing/MaxActiveUploads"},
|
||||
{"BitTorrent/Session/MaxConnections", "Preferences/Bittorrent/MaxConnecs"},
|
||||
{"BitTorrent/Session/MaxConnectionsPerTorrent", "Preferences/Bittorrent/MaxConnecsPerTorrent"},
|
||||
{"BitTorrent/Session/MaxHalfOpenConnections", "Preferences/Connection/MaxHalfOpenConnec"},
|
||||
{"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"},
|
||||
{"BitTorrent/Session/MaxUploads", "Preferences/Bittorrent/MaxUploads"},
|
||||
{"BitTorrent/Session/MaxUploadsPerTorrent", "Preferences/Bittorrent/MaxUploadsPerTorrent"},
|
||||
{"BitTorrent/Session/OutgoingPortsMax", "Preferences/Advanced/OutgoingPortsMax"},
|
||||
{"BitTorrent/Session/OutgoingPortsMin", "Preferences/Advanced/OutgoingPortsMin"},
|
||||
{"BitTorrent/Session/PeXEnabled", "Preferences/Bittorrent/PeX"},
|
||||
{"BitTorrent/Session/Port", "Preferences/Connection/PortRangeMin"},
|
||||
{"BitTorrent/Session/Preallocation", "Preferences/Downloads/PreAllocation"},
|
||||
{"BitTorrent/Session/ProxyPeerConnections", "Preferences/Connection/ProxyPeerConnections"},
|
||||
{"BitTorrent/Session/QueueingSystemEnabled", "Preferences/Queueing/QueueingEnabled"},
|
||||
{"BitTorrent/Session/RefreshInterval", "Preferences/General/RefreshInterval"},
|
||||
{"BitTorrent/Session/SaveResumeDataInterval", "Preferences/Downloads/SaveResumeDataInterval"},
|
||||
{"BitTorrent/Session/SuperSeedingEnabled", "Preferences/Advanced/SuperSeeding"},
|
||||
{"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"},
|
||||
{"BitTorrent/Session/TempPathEnabled", "Preferences/Downloads/TempPathEnabled"},
|
||||
{"BitTorrent/Session/TorrentExportDirectory", "Preferences/Downloads/TorrentExportDir"},
|
||||
{"BitTorrent/Session/TrackerFilteringEnabled", "Preferences/IPFilter/FilterTracker"},
|
||||
{"BitTorrent/Session/UseAlternativeGlobalSpeedLimit", "Preferences/Connection/alt_speeds_on"},
|
||||
{"BitTorrent/Session/UseOSCache", "Preferences/Advanced/osCache"},
|
||||
{"BitTorrent/Session/UseRandomPort", "Preferences/General/UseRandomPort"},
|
||||
{"BitTorrent/Session/uTPEnabled", "Preferences/Bittorrent/uTP"},
|
||||
{"BitTorrent/Session/uTPRateLimited", "Preferences/Bittorrent/uTP_rate_limited"},
|
||||
{"BitTorrent/TrackerEnabled", "Preferences/Advanced/trackerEnabled"},
|
||||
{"Network/PortForwardingEnabled", "Preferences/Connection/UPnP"},
|
||||
{"Network/Proxy/Authentication", "Preferences/Connection/Proxy/Authentication"},
|
||||
{"Network/Proxy/IP", "Preferences/Connection/Proxy/IP"},
|
||||
{"Network/Proxy/OnlyForTorrents", "Preferences/Connection/ProxyOnlyForTorrents"},
|
||||
{"Network/Proxy/Password", "Preferences/Connection/Proxy/Password"},
|
||||
{"Network/Proxy/Port", "Preferences/Connection/Proxy/Port"},
|
||||
{"Network/Proxy/Type", "Preferences/Connection/ProxyType"},
|
||||
{"Network/Proxy/Username", "Preferences/Connection/Proxy/Username"},
|
||||
{"State/BannedIPs", "Preferences/IPFilter/BannedIPs"}
|
||||
};
|
||||
|
||||
auto *settingsStorage = SettingsStorage::instance();
|
||||
for (const KeyMapping &mapping : mappings)
|
||||
{
|
||||
if (settingsStorage->hasKey(mapping.oldKey))
|
||||
{
|
||||
const auto value = settingsStorage->loadValue<QVariant>(mapping.oldKey);
|
||||
settingsStorage->storeValue(mapping.newKey, value);
|
||||
// TODO: Remove oldKey after ~v4.4.3 and bump migration version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void migrateProxySettingsEnum()
|
||||
{
|
||||
auto *settingsStorage = SettingsStorage::instance();
|
||||
const auto key = QString::fromLatin1("Network/Proxy/Type");
|
||||
const auto value = settingsStorage->loadValue<QString>(key);
|
||||
|
||||
bool ok = false;
|
||||
const auto number = value.toInt(&ok);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
switch (number)
|
||||
{
|
||||
case 0:
|
||||
settingsStorage->storeValue(key, Net::ProxyType::None);
|
||||
break;
|
||||
case 1:
|
||||
settingsStorage->storeValue(key, Net::ProxyType::HTTP);
|
||||
break;
|
||||
case 2:
|
||||
settingsStorage->storeValue(key, Net::ProxyType::SOCKS5);
|
||||
break;
|
||||
case 3:
|
||||
settingsStorage->storeValue(key, Net::ProxyType::HTTP_PW);
|
||||
break;
|
||||
case 4:
|
||||
settingsStorage->storeValue(key, Net::ProxyType::SOCKS5_PW);
|
||||
break;
|
||||
case 5:
|
||||
settingsStorage->storeValue(key, Net::ProxyType::SOCKS4);
|
||||
break;
|
||||
default:
|
||||
LogMsg(QObject::tr("Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
|
||||
.arg(key, QString::number(number)), Log::WARNING);
|
||||
settingsStorage->removeValue(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool upgrade(const bool /*ask*/)
|
||||
{
|
||||
exportWebUIHttpsFiles();
|
||||
upgradeTorrentContentLayout();
|
||||
upgradeListenPortSettings();
|
||||
CachedSettingValue<int> version {MIGRATION_VERSION_KEY, 0};
|
||||
|
||||
if (version != MIGRATION_VERSION)
|
||||
{
|
||||
if (version < 1)
|
||||
{
|
||||
exportWebUIHttpsFiles();
|
||||
upgradeTorrentContentLayout();
|
||||
upgradeListenPortSettings();
|
||||
upgradeSchedulerDaysSettings();
|
||||
upgradeDNSServiceSettings();
|
||||
upgradeTrayIconStyleSettings();
|
||||
}
|
||||
|
||||
if (version < 2)
|
||||
migrateSettingKeys();
|
||||
|
||||
if (version < 3)
|
||||
migrateProxySettingsEnum();
|
||||
|
||||
version = MIGRATION_VERSION;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setCurrentMigrationVersion()
|
||||
{
|
||||
SettingsStorage::instance()->storeValue(QLatin1String(MIGRATION_VERSION_KEY), MIGRATION_VERSION);
|
||||
}
|
||||
|
||||
void handleChangedDefaults(const DefaultPreferencesMode mode)
|
||||
{
|
||||
struct DefaultValue
|
||||
@@ -129,15 +411,18 @@ void handleChangedDefaults(const DefaultPreferencesMode mode)
|
||||
QVariant current;
|
||||
};
|
||||
|
||||
const QVector<DefaultValue> changedDefaults
|
||||
const DefaultValue changedDefaults[] =
|
||||
{
|
||||
{QLatin1String {"BitTorrent/Session/QueueingSystemEnabled"}, true, false}
|
||||
};
|
||||
|
||||
SettingsStorage *settingsStorage {SettingsStorage::instance()};
|
||||
for (auto it = changedDefaults.cbegin(); it != changedDefaults.cend(); ++it)
|
||||
auto *settingsStorage = SettingsStorage::instance();
|
||||
for (const DefaultValue &value : changedDefaults)
|
||||
{
|
||||
if (settingsStorage->loadValue<QVariant>(it->name).isNull())
|
||||
settingsStorage->storeValue(it->name, (mode == DefaultPreferencesMode::Legacy ? it->legacy : it->current));
|
||||
if (!settingsStorage->hasKey(value.name))
|
||||
{
|
||||
settingsStorage->storeValue(value.name
|
||||
, (mode == DefaultPreferencesMode::Legacy ? value.legacy : value.current));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,3 +36,4 @@ enum class DefaultPreferencesMode
|
||||
|
||||
void handleChangedDefaults(DefaultPreferencesMode mode);
|
||||
bool upgrade(bool ask = true);
|
||||
void setCurrentMigrationVersion();
|
||||
|
||||
@@ -8,6 +8,7 @@ add_library(qbt_base STATIC
|
||||
bittorrent/bandwidthscheduler.h
|
||||
bittorrent/bencoderesumedatastorage.h
|
||||
bittorrent/cachestatus.h
|
||||
bittorrent/categoryoptions.h
|
||||
bittorrent/common.h
|
||||
bittorrent/customstorage.h
|
||||
bittorrent/dbresumedatastorage.h
|
||||
@@ -100,6 +101,7 @@ add_library(qbt_base STATIC
|
||||
bittorrent/abstractfilestorage.cpp
|
||||
bittorrent/bandwidthscheduler.cpp
|
||||
bittorrent/bencoderesumedatastorage.cpp
|
||||
bittorrent/categoryoptions.cpp
|
||||
bittorrent/customstorage.cpp
|
||||
bittorrent/dbresumedatastorage.cpp
|
||||
bittorrent/downloadpriority.cpp
|
||||
@@ -116,6 +118,7 @@ add_library(qbt_base STATIC
|
||||
bittorrent/speedmonitor.cpp
|
||||
bittorrent/statistics.cpp
|
||||
bittorrent/torrent.cpp
|
||||
bittorrent/torrentcontentlayout.cpp
|
||||
bittorrent/torrentcreatorthread.cpp
|
||||
bittorrent/torrentimpl.cpp
|
||||
bittorrent/torrentinfo.cpp
|
||||
|
||||
@@ -7,6 +7,7 @@ HEADERS += \
|
||||
$$PWD/bittorrent/bandwidthscheduler.h \
|
||||
$$PWD/bittorrent/bencoderesumedatastorage.h \
|
||||
$$PWD/bittorrent/cachestatus.h \
|
||||
$$PWD/bittorrent/categoryoptions.h \
|
||||
$$PWD/bittorrent/common.h \
|
||||
$$PWD/bittorrent/customstorage.h \
|
||||
$$PWD/bittorrent/downloadpriority.h \
|
||||
@@ -100,6 +101,7 @@ SOURCES += \
|
||||
$$PWD/bittorrent/abstractfilestorage.cpp \
|
||||
$$PWD/bittorrent/bandwidthscheduler.cpp \
|
||||
$$PWD/bittorrent/bencoderesumedatastorage.cpp \
|
||||
$$PWD/bittorrent/categoryoptions.cpp \
|
||||
$$PWD/bittorrent/customstorage.cpp \
|
||||
$$PWD/bittorrent/dbresumedatastorage.cpp \
|
||||
$$PWD/bittorrent/downloadpriority.cpp \
|
||||
@@ -116,6 +118,7 @@ SOURCES += \
|
||||
$$PWD/bittorrent/speedmonitor.cpp \
|
||||
$$PWD/bittorrent/statistics.cpp \
|
||||
$$PWD/bittorrent/torrent.cpp \
|
||||
$$PWD/bittorrent/torrentcontentlayout.cpp \
|
||||
$$PWD/bittorrent/torrentcreatorthread.cpp \
|
||||
$$PWD/bittorrent/torrentimpl.cpp \
|
||||
$$PWD/bittorrent/torrentinfo.cpp \
|
||||
|
||||
@@ -48,11 +48,13 @@ namespace BitTorrent
|
||||
QString category;
|
||||
TagSet tags;
|
||||
QString savePath;
|
||||
bool disableTempPath = false; // e.g. for imported torrents
|
||||
std::optional<bool> useDownloadPath;
|
||||
QString downloadPath;
|
||||
bool sequential = false;
|
||||
bool firstLastPiecePriority = false;
|
||||
bool addForced = false;
|
||||
std::optional<bool> addPaused;
|
||||
QStringList filePaths; // used if TorrentInfo is set
|
||||
QVector<DownloadPriority> filePriorities; // used if TorrentInfo is set
|
||||
bool skipChecking = false;
|
||||
std::optional<BitTorrent::TorrentContentLayout> contentLayout;
|
||||
|
||||
@@ -61,7 +61,7 @@ bool BandwidthScheduler::isTimeForAlternative() const
|
||||
QTime start = pref->getSchedulerStartTime();
|
||||
QTime end = pref->getSchedulerEndTime();
|
||||
const QTime now = QTime::currentTime();
|
||||
const int schedulerDays = pref->getSchedulerDays();
|
||||
const Scheduler::Days schedulerDays = pref->getSchedulerDays();
|
||||
const int day = QDate::currentDate().dayOfWeek();
|
||||
bool alternative = false;
|
||||
|
||||
@@ -75,20 +75,34 @@ bool BandwidthScheduler::isTimeForAlternative() const
|
||||
{
|
||||
switch (schedulerDays)
|
||||
{
|
||||
case EVERY_DAY:
|
||||
case Scheduler::Days::EveryDay:
|
||||
alternative = !alternative;
|
||||
break;
|
||||
case WEEK_ENDS:
|
||||
case Scheduler::Days::Monday:
|
||||
case Scheduler::Days::Tuesday:
|
||||
case Scheduler::Days::Wednesday:
|
||||
case Scheduler::Days::Thursday:
|
||||
case Scheduler::Days::Friday:
|
||||
case Scheduler::Days::Saturday:
|
||||
case Scheduler::Days::Sunday:
|
||||
{
|
||||
const int offset = static_cast<int>(Scheduler::Days::Monday) - 1;
|
||||
const int dayOfWeek = static_cast<int>(schedulerDays) - offset;
|
||||
if (day == dayOfWeek)
|
||||
alternative = !alternative;
|
||||
}
|
||||
break;
|
||||
case Scheduler::Days::Weekday:
|
||||
if ((day >= 1) && (day <= 5))
|
||||
alternative = !alternative;
|
||||
break;
|
||||
case Scheduler::Days::Weekend:
|
||||
if ((day == 6) || (day == 7))
|
||||
alternative = !alternative;
|
||||
break;
|
||||
case WEEK_DAYS:
|
||||
if ((day != 6) && (day != 7))
|
||||
alternative = !alternative;
|
||||
break;
|
||||
default:
|
||||
if (day == (schedulerDays - 2))
|
||||
alternative = !alternative;
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -173,12 +173,19 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorag
|
||||
torrentParams.restored = true;
|
||||
torrentParams.category = fromLTString(root.dict_find_string_value("qBt-category"));
|
||||
torrentParams.name = fromLTString(root.dict_find_string_value("qBt-name"));
|
||||
torrentParams.savePath = Profile::instance()->fromPortablePath(
|
||||
Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-savePath"))));
|
||||
torrentParams.hasSeedStatus = root.dict_find_int_value("qBt-seedStatus");
|
||||
torrentParams.firstLastPiecePriority = root.dict_find_int_value("qBt-firstLastPiecePriority");
|
||||
torrentParams.seedingTimeLimit = root.dict_find_int_value("qBt-seedingTimeLimit", Torrent::USE_GLOBAL_SEEDING_TIME);
|
||||
|
||||
torrentParams.savePath = Profile::instance()->fromPortablePath(
|
||||
Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-savePath"))));
|
||||
torrentParams.useAutoTMM = torrentParams.savePath.isEmpty();
|
||||
if (!torrentParams.useAutoTMM)
|
||||
{
|
||||
torrentParams.downloadPath = Profile::instance()->fromPortablePath(
|
||||
Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-downloadPath"))));
|
||||
}
|
||||
|
||||
// TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x.
|
||||
// === BEGIN DEPRECATED CODE === //
|
||||
const lt::bdecode_node contentLayoutNode = root.dict_find("qBt-contentLayout");
|
||||
@@ -352,7 +359,6 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
|
||||
}
|
||||
}
|
||||
|
||||
data["qBt-savePath"] = Profile::instance()->toPortablePath(resumeData.savePath).toStdString();
|
||||
data["qBt-ratioLimit"] = static_cast<int>(resumeData.ratioLimit * 1000);
|
||||
data["qBt-seedingTimeLimit"] = resumeData.seedingTimeLimit;
|
||||
data["qBt-category"] = resumeData.category.toStdString();
|
||||
@@ -362,6 +368,12 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
|
||||
data["qBt-contentLayout"] = Utils::String::fromEnum(resumeData.contentLayout).toStdString();
|
||||
data["qBt-firstLastPiecePriority"] = resumeData.firstLastPiecePriority;
|
||||
|
||||
if (!resumeData.useAutoTMM)
|
||||
{
|
||||
data["qBt-savePath"] = Profile::instance()->toPortablePath(resumeData.savePath).toStdString();
|
||||
data["qBt-downloadPath"] = Profile::instance()->toPortablePath(resumeData.downloadPath).toStdString();
|
||||
}
|
||||
|
||||
const QString resumeFilepath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.fastresume").arg(id.toString()));
|
||||
const nonstd::expected<void, QString> result = Utils::IO::saveToFile(resumeFilepath, data);
|
||||
if (!result)
|
||||
|
||||
78
src/base/bittorrent/categoryoptions.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2021 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "categoryoptions.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
const QString OPTION_SAVEPATH {QStringLiteral("save_path")};
|
||||
const QString OPTION_DOWNLOADPATH {QStringLiteral("download_path")};
|
||||
|
||||
BitTorrent::CategoryOptions BitTorrent::CategoryOptions::fromJSON(const QJsonObject &jsonObj)
|
||||
{
|
||||
CategoryOptions options;
|
||||
options.savePath = jsonObj.value(OPTION_SAVEPATH).toString();
|
||||
|
||||
const QJsonValue downloadPathValue = jsonObj.value(OPTION_DOWNLOADPATH);
|
||||
if (downloadPathValue.isBool())
|
||||
options.downloadPath = {downloadPathValue.toBool(), {}};
|
||||
else if (downloadPathValue.isString())
|
||||
options.downloadPath = {true, downloadPathValue.toString()};
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
QJsonObject BitTorrent::CategoryOptions::toJSON() const
|
||||
{
|
||||
QJsonValue downloadPathValue = QJsonValue::Undefined;
|
||||
if (downloadPath)
|
||||
{
|
||||
if (downloadPath->enabled)
|
||||
downloadPathValue = downloadPath->path;
|
||||
else
|
||||
downloadPathValue = false;
|
||||
}
|
||||
|
||||
return {
|
||||
{OPTION_SAVEPATH, savePath},
|
||||
{OPTION_DOWNLOADPATH, downloadPathValue}
|
||||
};
|
||||
}
|
||||
|
||||
bool BitTorrent::operator==(const BitTorrent::CategoryOptions::DownloadPathOption &left, const BitTorrent::CategoryOptions::DownloadPathOption &right)
|
||||
{
|
||||
return ((left.enabled == right.enabled)
|
||||
&& (left.path == right.path));
|
||||
}
|
||||
|
||||
bool BitTorrent::operator==(const BitTorrent::CategoryOptions &left, const BitTorrent::CategoryOptions &right)
|
||||
{
|
||||
return ((left.savePath == right.savePath)
|
||||
&& (left.downloadPath == right.downloadPath));
|
||||
}
|
||||
56
src/base/bittorrent/categoryoptions.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2021 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <QString>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
struct CategoryOptions
|
||||
{
|
||||
struct DownloadPathOption
|
||||
{
|
||||
bool enabled;
|
||||
QString path;
|
||||
};
|
||||
|
||||
QString savePath;
|
||||
std::optional<DownloadPathOption> downloadPath;
|
||||
|
||||
static CategoryOptions fromJSON(const QJsonObject &jsonObj);
|
||||
QJsonObject toJSON() const;
|
||||
};
|
||||
|
||||
bool operator==(const CategoryOptions::DownloadPathOption &left, const CategoryOptions::DownloadPathOption &right);
|
||||
bool operator==(const CategoryOptions &left, const CategoryOptions &right);
|
||||
}
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "dbresumedatastorage.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <libtorrent/bdecode.hpp>
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
@@ -41,6 +43,7 @@
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlRecord>
|
||||
#include <QThread>
|
||||
#include <QVector>
|
||||
|
||||
@@ -57,11 +60,13 @@ namespace
|
||||
{
|
||||
const char DB_CONNECTION_NAME[] = "ResumeDataStorage";
|
||||
|
||||
const int DB_VERSION = 1;
|
||||
const int DB_VERSION = 2;
|
||||
|
||||
const char DB_TABLE_META[] = "meta";
|
||||
const char DB_TABLE_TORRENTS[] = "torrents";
|
||||
|
||||
const char META_VERSION[] = "version";
|
||||
|
||||
struct Column
|
||||
{
|
||||
QString name;
|
||||
@@ -80,6 +85,7 @@ namespace
|
||||
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");
|
||||
@@ -109,42 +115,50 @@ namespace
|
||||
return QString::fromLatin1("CREATE TABLE %1 (%2)").arg(quoted(tableName), items.join(QLatin1Char(',')));
|
||||
}
|
||||
|
||||
QString makeInsertStatement(const QString &tableName, const QVector<Column> &columns)
|
||||
std::pair<QString, QString> joinColumns(const QVector<Column> &columns)
|
||||
{
|
||||
QStringList names;
|
||||
names.reserve(columns.size());
|
||||
QStringList values;
|
||||
values.reserve(columns.size());
|
||||
int namesSize = columns.size();
|
||||
int valuesSize = columns.size();
|
||||
for (const Column &column : columns)
|
||||
{
|
||||
names.append(quoted(column.name));
|
||||
values.append(column.placeholder);
|
||||
namesSize += column.name.size() + 2;
|
||||
valuesSize += column.placeholder.size();
|
||||
}
|
||||
|
||||
const QString jointNames = names.join(QLatin1Char(','));
|
||||
const QString jointValues = values.join(QLatin1Char(','));
|
||||
QString names;
|
||||
names.reserve(namesSize);
|
||||
QString values;
|
||||
values.reserve(valuesSize);
|
||||
for (const Column &column : columns)
|
||||
{
|
||||
names.append(quoted(column.name) + QLatin1Char(','));
|
||||
values.append(column.placeholder + QLatin1Char(','));
|
||||
}
|
||||
names.chop(1);
|
||||
values.chop(1);
|
||||
|
||||
return std::make_pair(names, values);
|
||||
}
|
||||
|
||||
QString makeInsertStatement(const QString &tableName, const QVector<Column> &columns)
|
||||
{
|
||||
const auto [names, values] = joinColumns(columns);
|
||||
return QString::fromLatin1("INSERT INTO %1 (%2) VALUES (%3)")
|
||||
.arg(quoted(tableName), jointNames, jointValues);
|
||||
.arg(quoted(tableName), names, values);
|
||||
}
|
||||
|
||||
QString makeUpdateStatement(const QString &tableName, const QVector<Column> &columns)
|
||||
{
|
||||
const auto [names, values] = joinColumns(columns);
|
||||
return QString::fromLatin1("UPDATE %1 SET (%2) = (%3)")
|
||||
.arg(quoted(tableName), names, values);
|
||||
}
|
||||
|
||||
QString makeOnConflictUpdateStatement(const Column &constraint, const QVector<Column> &columns)
|
||||
{
|
||||
QStringList names;
|
||||
names.reserve(columns.size());
|
||||
QStringList values;
|
||||
values.reserve(columns.size());
|
||||
for (const Column &column : columns)
|
||||
{
|
||||
names.append(quoted(column.name));
|
||||
values.append(column.placeholder);
|
||||
}
|
||||
|
||||
const QString jointNames = names.join(QLatin1Char(','));
|
||||
const QString jointValues = values.join(QLatin1Char(','));
|
||||
|
||||
const auto [names, values] = joinColumns(columns);
|
||||
return QString::fromLatin1(" ON CONFLICT (%1) DO UPDATE SET (%2) = (%3)")
|
||||
.arg(quoted(constraint.name), jointNames, jointValues);
|
||||
.arg(quoted(constraint.name), names, values);
|
||||
}
|
||||
|
||||
QString makeColumnDefinition(const Column &column, const char *definition)
|
||||
@@ -187,7 +201,15 @@ BitTorrent::DBResumeDataStorage::DBResumeDataStorage(const QString &dbPath, QObj
|
||||
throw RuntimeError(db.lastError().text());
|
||||
|
||||
if (needCreateDB)
|
||||
{
|
||||
createDB();
|
||||
}
|
||||
else
|
||||
{
|
||||
const int dbVersion = currentDBVersion();
|
||||
if ((dbVersion == 1) || !db.record(DB_TABLE_TORRENTS).contains(DB_COLUMN_DOWNLOAD_PATH.name))
|
||||
updateDBFromVersion1();
|
||||
}
|
||||
|
||||
m_asyncWorker = new Worker(dbPath, QLatin1String("ResumeDataStorageWorker"));
|
||||
m_asyncWorker->moveToThread(m_ioThread);
|
||||
@@ -276,8 +298,6 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::DBResumeDataStorage::lo
|
||||
const QStringList tagList = tagsData.split(QLatin1Char(','));
|
||||
resumeData.tags.insert(tagList.cbegin(), tagList.cend());
|
||||
}
|
||||
resumeData.savePath = Profile::instance()->fromPortablePath(
|
||||
Utils::Fs::toUniformPath(query.value(DB_COLUMN_TARGET_SAVE_PATH.name).toString()));
|
||||
resumeData.hasSeedStatus = 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;
|
||||
@@ -288,6 +308,15 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::DBResumeDataStorage::lo
|
||||
query.value(DB_COLUMN_OPERATING_MODE.name).toString(), TorrentOperatingMode::AutoManaged);
|
||||
resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
|
||||
|
||||
resumeData.savePath = Profile::instance()->fromPortablePath(
|
||||
Utils::Fs::toUniformPath(query.value(DB_COLUMN_TARGET_SAVE_PATH.name).toString()));
|
||||
resumeData.useAutoTMM = resumeData.savePath.isEmpty();
|
||||
if (!resumeData.useAutoTMM)
|
||||
{
|
||||
resumeData.downloadPath = Profile::instance()->fromPortablePath(
|
||||
Utils::Fs::toUniformPath(query.value(DB_COLUMN_DOWNLOAD_PATH.name).toString()));
|
||||
}
|
||||
|
||||
const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
|
||||
const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray();
|
||||
const QByteArray allData = ((bencodedMetadata.isEmpty() || bencodedResumeData.isEmpty())
|
||||
@@ -329,6 +358,33 @@ void BitTorrent::DBResumeDataStorage::storeQueue(const QVector<TorrentID> &queue
|
||||
});
|
||||
}
|
||||
|
||||
int BitTorrent::DBResumeDataStorage::currentDBVersion() const
|
||||
{
|
||||
const auto selectDBVersionStatement = QString::fromLatin1("SELECT %1 FROM %2 WHERE %3 = %4;")
|
||||
.arg(quoted(DB_COLUMN_VALUE.name), quoted(DB_TABLE_META), quoted(DB_COLUMN_NAME.name), DB_COLUMN_NAME.placeholder);
|
||||
|
||||
auto db = QSqlDatabase::database(DB_CONNECTION_NAME);
|
||||
QSqlQuery query {db};
|
||||
|
||||
if (!query.prepare(selectDBVersionStatement))
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
query.bindValue(DB_COLUMN_NAME.placeholder, QString::fromLatin1(META_VERSION));
|
||||
|
||||
if (!query.exec())
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
if (!query.next())
|
||||
throw RuntimeError(tr("Database is corrupted."));
|
||||
|
||||
bool ok;
|
||||
const int dbVersion = query.value(0).toInt(&ok);
|
||||
if (!ok)
|
||||
throw RuntimeError(tr("Database is corrupted."));
|
||||
|
||||
return dbVersion;
|
||||
}
|
||||
|
||||
void BitTorrent::DBResumeDataStorage::createDB() const
|
||||
{
|
||||
auto db = QSqlDatabase::database(DB_CONNECTION_NAME);
|
||||
@@ -353,7 +409,7 @@ void BitTorrent::DBResumeDataStorage::createDB() const
|
||||
if (!query.prepare(insertMetaVersionQuery))
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
query.bindValue(DB_COLUMN_NAME.placeholder, QString::fromLatin1("version"));
|
||||
query.bindValue(DB_COLUMN_NAME.placeholder, QString::fromLatin1(META_VERSION));
|
||||
query.bindValue(DB_COLUMN_VALUE.placeholder, DB_VERSION);
|
||||
|
||||
if (!query.exec())
|
||||
@@ -367,6 +423,7 @@ void BitTorrent::DBResumeDataStorage::createDB() const
|
||||
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"),
|
||||
@@ -391,6 +448,42 @@ void BitTorrent::DBResumeDataStorage::createDB() const
|
||||
}
|
||||
}
|
||||
|
||||
void BitTorrent::DBResumeDataStorage::updateDBFromVersion1() const
|
||||
{
|
||||
auto db = QSqlDatabase::database(DB_CONNECTION_NAME);
|
||||
|
||||
if (!db.transaction())
|
||||
throw RuntimeError(db.lastError().text());
|
||||
|
||||
QSqlQuery query {db};
|
||||
|
||||
try
|
||||
{
|
||||
const auto alterTableTorrentsQuery = QString::fromLatin1("ALTER TABLE %1 ADD %2")
|
||||
.arg(quoted(DB_TABLE_TORRENTS), makeColumnDefinition(DB_COLUMN_DOWNLOAD_PATH, "TEXT"));
|
||||
if (!query.exec(alterTableTorrentsQuery))
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
const QString updateMetaVersionQuery = makeUpdateStatement(DB_TABLE_META, {DB_COLUMN_NAME, DB_COLUMN_VALUE});
|
||||
if (!query.prepare(updateMetaVersionQuery))
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
query.bindValue(DB_COLUMN_NAME.placeholder, QString::fromLatin1(META_VERSION));
|
||||
query.bindValue(DB_COLUMN_VALUE.placeholder, DB_VERSION);
|
||||
|
||||
if (!query.exec())
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
if (!db.commit())
|
||||
throw RuntimeError(db.lastError().text());
|
||||
}
|
||||
catch (const RuntimeError &)
|
||||
{
|
||||
db.rollback();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BitTorrent::DBResumeDataStorage::Worker::Worker(const QString &dbPath, const QString &dbConnectionName)
|
||||
: m_path {dbPath}
|
||||
, m_connectionName {dbConnectionName}
|
||||
@@ -499,7 +592,6 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
|
||||
query.bindValue(DB_COLUMN_CATEGORY.placeholder, resumeData.category);
|
||||
query.bindValue(DB_COLUMN_TAGS.placeholder, (resumeData.tags.isEmpty()
|
||||
? QVariant(QVariant::String) : resumeData.tags.join(QLatin1String(","))));
|
||||
query.bindValue(DB_COLUMN_TARGET_SAVE_PATH.placeholder, Profile::instance()->toPortablePath(resumeData.savePath));
|
||||
query.bindValue(DB_COLUMN_CONTENT_LAYOUT.placeholder, Utils::String::fromEnum(resumeData.contentLayout));
|
||||
query.bindValue(DB_COLUMN_RATIO_LIMIT.placeholder, static_cast<int>(resumeData.ratioLimit * 1000));
|
||||
query.bindValue(DB_COLUMN_SEEDING_TIME_LIMIT.placeholder, resumeData.seedingTimeLimit);
|
||||
@@ -507,6 +599,13 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
|
||||
query.bindValue(DB_COLUMN_HAS_SEED_STATUS.placeholder, resumeData.hasSeedStatus);
|
||||
query.bindValue(DB_COLUMN_OPERATING_MODE.placeholder, Utils::String::fromEnum(resumeData.operatingMode));
|
||||
query.bindValue(DB_COLUMN_STOPPED.placeholder, resumeData.stopped);
|
||||
|
||||
if (!resumeData.useAutoTMM)
|
||||
{
|
||||
query.bindValue(DB_COLUMN_TARGET_SAVE_PATH.placeholder, Profile::instance()->toPortablePath(resumeData.savePath));
|
||||
query.bindValue(DB_COLUMN_DOWNLOAD_PATH.placeholder, Profile::instance()->toPortablePath(resumeData.downloadPath));
|
||||
}
|
||||
|
||||
query.bindValue(DB_COLUMN_RESUMEDATA.placeholder, bencodedResumeData);
|
||||
if (!bencodedMetadata.isEmpty())
|
||||
query.bindValue(DB_COLUMN_METADATA.placeholder, bencodedMetadata);
|
||||
|
||||
@@ -50,7 +50,9 @@ namespace BitTorrent
|
||||
void storeQueue(const QVector<TorrentID> &queue) const override;
|
||||
|
||||
private:
|
||||
int currentDBVersion() const;
|
||||
void createDB() const;
|
||||
void updateDBFromVersion1() const;
|
||||
|
||||
QThread *m_ioThread = nullptr;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "base/bittorrent/infohash.h"
|
||||
|
||||
void FileSearcher::search(const BitTorrent::TorrentID &id, const QStringList &originalFileNames
|
||||
, const QString &completeSavePath, const QString &incompleteSavePath)
|
||||
, const QString &savePath, const QString &downloadPath)
|
||||
{
|
||||
const auto findInDir = [](const QString &dirPath, QStringList &fileNames) -> bool
|
||||
{
|
||||
@@ -56,14 +56,14 @@ void FileSearcher::search(const BitTorrent::TorrentID &id, const QStringList &or
|
||||
return found;
|
||||
};
|
||||
|
||||
QString savePath = completeSavePath;
|
||||
QString usedPath = savePath;
|
||||
QStringList adjustedFileNames = originalFileNames;
|
||||
const bool found = findInDir(savePath, adjustedFileNames);
|
||||
if (!found && !incompleteSavePath.isEmpty())
|
||||
const bool found = findInDir(usedPath, adjustedFileNames);
|
||||
if (!found && !downloadPath.isEmpty())
|
||||
{
|
||||
savePath = incompleteSavePath;
|
||||
findInDir(savePath, adjustedFileNames);
|
||||
usedPath = downloadPath;
|
||||
findInDir(usedPath, adjustedFileNames);
|
||||
}
|
||||
|
||||
emit searchFinished(id, savePath, adjustedFileNames);
|
||||
emit searchFinished(id, usedPath, adjustedFileNames);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void search(const BitTorrent::TorrentID &id, const QStringList &originalFileNames
|
||||
, const QString &completeSavePath, const QString &incompleteSavePath);
|
||||
, const QString &savePath, const QString &downloadPath);
|
||||
|
||||
signals:
|
||||
void searchFinished(const BitTorrent::TorrentID &id, const QString &savePath, const QStringList &fileNames);
|
||||
|
||||