Compare commits

..

381 Commits

Author SHA1 Message Date
sledgehammer999
01519b5e77 Bump to 4.3.9 2021-10-31 12:36:05 +02:00
sledgehammer999
95ad606db1 Update Changelog 2021-10-31 12:35:31 +02:00
sledgehammer999
7a31c4c1fd Sync translations from Transifex and run lupdate 2021-10-31 12:35:07 +02:00
sledgehammer999
74b4c24c8f Sync translations from Transifex and run lupdate 2021-10-31 03:01:46 +03:00
SiderealArt
fac91a29e8 NSIS: Update Traditional Chinese translation
PR #15595.
2021-10-25 00:17:20 +03:00
Faisal Al-Munawar Fathur Rahman
a58cfe3f00 Update Indonesian translation
PR #15436.
2021-10-25 00:17:12 +03:00
Chocobo1
1bae770b2c Fix broken behavior of "priority by shown file order"
Closes #15421.
PR #15423.
2021-10-12 10:42:12 +08:00
Chocobo1
298d63d47c Prevent self-assignment in assignment operator 2021-10-12 10:42:12 +08:00
Chocobo1
c598bdd290 Guard for null pointer 2021-10-12 10:42:12 +08:00
gxcreator
8ba8d69bef Initialize member fields 2021-10-12 10:42:12 +08:00
Jose M. Abuin
57ec71b4d3 Add missing double-click action
Closes #15422.
PR #15509.
2021-10-12 10:42:12 +08:00
Chocobo1
c561c28614 Revert "WebUI: group trackers by hostname"
This functionality wasn't ever correctly implemented and couldn't be
done without considerable effort, so revert it for now.
This reverts commit 4ac25a50ed.
PR #15542.
2021-10-12 10:42:12 +08:00
Vladimir Golovnev
ac5c264e66 Properly handle exceptions when create torrent
Closes #15518.
PR #15532.
2021-10-08 12:47:31 +03:00
Chocobo1
338d9a0848 Remove unnecessary UI properties in "Add new torrent" dialog
Closes #15383.

PR #15387
2021-09-10 09:00:00 +08:00
JungHee Lee
0efd667d7e Update korean.nsi
PR #15380
2021-09-10 09:00:00 +08:00
Chocobo1
5fd6e18390 Fix WebUI crash when tracker URL is invalid
Closes #15391.
PR #15395.
2021-09-10 09:00:00 +08:00
xavier2k6
b5f4afabe0 Remove Windows Vista support from manifest
PR #15394.
2021-09-10 09:00:00 +08:00
sledgehammer999
9392ce436d Bump to 4.3.8 2021-08-29 01:57:25 +03:00
sledgehammer999
8ceb2d8832 Update Changelog 2021-08-29 01:56:30 +03:00
sledgehammer999
40ec873199 Sync translations from Transifex and run lupdate 2021-08-29 01:55:57 +03:00
Chocobo1
f3a5a43a20 Specify Unicode for resource block (#15370)
The StringFileInfo block was using "1252 Multilingual", change it to
"1200 Unicode" for consistency.
https://docs.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block

Closes #15364.
2021-08-29 00:13:09 +03:00
a1346054
72ba22afd1 Fix typo 2021-08-23 22:21:47 +03:00
a1346054
423232b4b9 Use license file verbatim
The GPL part of COPYING file was distributed incomplete, it must be
distributed verbatim.

The file was obtained from:
https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
2021-08-23 22:21:35 +03:00
sledgehammer999
86a6b53f82 Change IRC channel to Libera.Chat
Unfortunately Freenode, after a takeover, decided to purge all their databases, thus
deleting all channel and user registrations, without a warning.
So if we're forced to re-register our stuff why not go where the cool kids are at?
2021-08-23 22:21:34 +03:00
a-raccoon
618afb3609 Update README.md
Removed these two lines because they haven't been true in a very long time, and is no longer even possible.
```
You can also meet me (sledgehammer_999) on IRC:
`#qbittorrent on irc.freenode.net`
```
2021-08-23 22:21:17 +03:00
Chocobo1
fefce03379 GHA CI: Backport latest changes (#15361)
By having unified github workflows, the building cache would be utilized
more efficiently as the total cache size will be smaller (no more vcpkg
caching on macOS CI) and will stop thrashing the build cache (large
vcpkg cache evicts other smaller cache).

Relevant PRs:
#15321
#15340
#15342
#15355
2021-08-23 10:56:03 +08:00
Chocobo1
250cac73b6 Improve "last activity" calculation in WebAPI (#15339)
Co-authored-by: 秦风 <mayli.he@gmail.com>

Co-authored-by: Chocobo1 <Chocobo1@users.noreply.github.com>
2021-08-21 12:59:40 +08:00
Chocobo1
84ec5a6acf Use default values for inconsequential fields
Or when the default value is actually what we want.
2021-08-21 12:59:40 +08:00
Chocobo1
0e2aca7583 Use default upper limits for ddns entries
The default is 32767 which is larger than the previous artificial limit.
2021-08-21 12:59:40 +08:00
Chocobo1
3bded7e71b Use the same icon for selecting folders/files
As stated in Qt doc, the `QStyle::SP_DialogOpenButton` is only for a
button within QDialogButtonBox which means it isn't suitable elsewhere.
2021-08-21 12:59:40 +08:00
Mengyang Li
51ca65eea1 WebUI: group trackers by hostname (#15264)
Closes #13608.
2021-08-21 12:59:40 +08:00
Chocobo1
f21f7b8edc Ignore file heath for 3rd party libraries 2021-08-21 12:59:40 +08:00
Chocobo1
331304159d Work around missing function error
The fix comes from older version of MochaUI.
2021-08-21 12:59:40 +08:00
Chocobo1
2aab675dc4 Update MochaUI to v0.9.7
Upstream: https://github.com/cdotyone/mochaui/blob/develop-0.9.8/Build/mocha.js
2021-08-21 12:59:40 +08:00
Chocobo1
9c8016dc65 Update clipboard.js to v2.0.8 2021-08-21 12:59:40 +08:00
Chocobo1
b99262bc36 Update mootools to v1.6.0 2021-08-21 12:59:40 +08:00
Sylvain Finot
078cfe656a Expose SSRF mitigation (#15247) 2021-08-21 12:59:40 +08:00
Matthaiks
89ac9bf2c9 NSIS: Add Polish translation (#15262) 2021-08-21 12:59:40 +08:00
Vladimir Golovnev
81932b6313 Delay processing of watched folders (#15282)
Fixes regression of #14882.
Closes #15272.
2021-08-21 12:59:40 +08:00
sledgehammer999
4ce5d9d5e2 Update grunt dependency
This fixes CVE-2020-7729
2021-08-21 12:59:40 +08:00
sledgehammer999
0415c0c6f8 Bump to 4.3.7 2021-08-03 23:24:47 +03:00
sledgehammer999
def5765160 Update Changelog 2021-08-03 23:20:32 +03:00
sledgehammer999
9977395c03 Sync translations from Transifex and run lupdate 2021-08-03 23:18:15 +03:00
Daniel Aleksandersen
2b05b2b471 Disconnect comment links fom the WebUI (#15251) 2021-08-03 23:00:47 +03:00
scootergrisen
d1bd426618 Update Danish translation (#15192) 2021-07-26 02:04:23 +03:00
Andrei Stepanov
b84c5edf51 Remove excess space 2021-07-26 02:04:16 +03:00
Vladimir Golovnev (glassez)
3ac8c97e6f Properly create "clean path" for watched folder 2021-07-12 11:45:57 +03:00
Vladimir Golovnev
ede42910da Merge pull request #15150 from glassez/backports
Backport changes to v4.3.x branch
2021-07-05 11:20:38 +03:00
xavier2k6
500d0e717b Update AppVeyor CI image to Visual Studio 2019 (#14983)
Update AppVeyor CI image to Visual Studio 2019
2021-07-03 11:44:43 +03:00
An0n
a3f039ffcb Bump file pool size (#14966) 2021-07-03 11:43:10 +03:00
Kacper Michajłow
81ad324209 Suppress C4267 conversion warnings
- warning C4267: 'initializing': conversion from 'size_t' to 'int',
  possible loss of data

Caused by mismatch between size_type of std and Qt containers. It is
safe to cast to int as all of those containers hold low number of
objects.
2021-07-03 11:16:04 +03:00
Vladimir Golovnev (Glassez)
81de07789a Provide tracker peers count via TrackerEntry
Don't expose additional accessor in Torrent interface.
2021-07-01 14:03:14 +03:00
Vladimir Golovnev (Glassez)
6a8a1f602f Don't overwrite tracker message
Use one of the tracker endpoint messages.
2021-07-01 13:44:48 +03:00
FranciscoPombal
9dfaaa2dd1 Remove TravisCI config 2021-07-01 11:09:35 +03:00
tgregerson
c06d6eaa77 Don't close tags menu when toggling items (#15098)
The issue was resolved by using QAction::toggled signal instead of
QAction::triggered. In QT 5.15+ the latter signal causes a QMenu
to close, whereas the former does not. Closes #13492.
2021-07-01 10:09:17 +03:00
Vladimir Golovnev (Glassez)
d198ee97a5 Don't forget to start "watch timer" 2021-07-01 09:44:46 +03:00
sledgehammer999
ac8105c304 Bump to 4.3.6 2021-06-26 21:24:22 +03:00
sledgehammer999
6cb16cfbb7 Update Changelog 2021-06-26 21:20:58 +03:00
sledgehammer999
2b475c4296 Sync translations from Transifex and run lupdate 2021-06-26 21:13:38 +03:00
sledgehammer999
3a9e4397fd Add new languages
* Mongolian
* Persian
* Thai
2021-06-26 21:12:41 +03:00
sledgehammer999
1ce0bb7cee Add Turkish Qt translation 2021-06-26 21:12:39 +03:00
sledgehammer999
dd4b09f3a9 Update Qt translations
Based on Qt 5.15.2
2021-06-26 21:12:38 +03:00
nonew-star
8c2df049f1 NSIS: Update Swedish translation (#14950)
Remove redundant spaces.
2021-06-26 21:12:38 +03:00
nonew-star
8b66c444ee NSIS: Update Swedish translation (#14933)
Added a word.
2021-06-26 21:12:37 +03:00
xkrstudio
0ccbdbccf4 NSIS: Update Hungarian translation (#14906)
Add hungarian translation.
2021-06-26 21:12:36 +03:00
Burak Yavuz
d08b6c81ba NSIS: Update Turkish translation
Uninstall string added
2021-06-26 21:12:36 +03:00
maboroshin
5f897709cf NSIS: Update Japanese translation 2021-06-26 21:12:30 +03:00
Vladimir Golovnev (Glassez)
e25948e737 Properly add torrent with new tags
First, an attempt is made to add new tags to the Session.
Closes #15105.
2021-06-19 10:52:08 +03:00
Vladimir Golovnev (Glassez)
144956a209 Remove lockfile only when last app instance is destroyed 2021-06-19 10:52:08 +03:00
Dmitry Khlestkov
667d4e4211 Keep sub-sorting order (#15074)
Fixes #15073
2021-06-15 14:19:53 +03:00
Vladimir Golovnev (Glassez)
d957eef331 Improve "Watched folders" feature
Make "file system watcher" an application core component
and separate it from its presentation model.
2021-06-15 14:19:53 +03:00
brvphoenix
baa32a20e0 Remove the lockfile on exit (#14997) 2021-06-15 14:19:53 +03:00
Chocobo1
eff465126e Fix main window turns blank after restoring from tray (#15031)
When restoring from tray icon, although the window manager shows qbt
window but qbt itself didn't handle the event correctly, i.e. the
`show()` was missing and thus qbt did nothing and the window is blank.
Note that at this point the `visible` property is `false`.
After invoking `show()` qbt will start showing the contents and also
fire another showEvent where `visible` property is `true` and here is where
qbt should handle preparations for the window.

Fix #9510.
2021-06-15 14:19:53 +03:00
thalieht
09089b2d33 Make some strings in WebUI translatable
Closes #14920
2021-06-15 14:19:53 +03:00
Vladimir Golovnev (Glassez)
3aa36ad40c Declare AbstractFileStorage destructor virtual 2021-06-15 14:19:53 +03:00
Vladimir Golovnev (Glassez)
24bc5a9875 Unify custom exceptions 2021-06-15 14:19:53 +03:00
Vladimir Golovnev (Glassez)
744a2cb5a3 Allow add torrents with relative save path
The relative save path will be resoloved against the default one.
2021-06-15 14:19:53 +03:00
Vladimir Golovnev (Glassez)
33e090cfcb Provide correct error description in "upload mode" 2021-06-08 08:06:11 +03:00
sledgehammer999
063844ed44 Bump to 4.3.5 2021-05-02 18:59:11 +03:00
sledgehammer999
899f8a3f61 Update Changelog 2021-05-02 18:59:10 +03:00
sledgehammer999
0f72f22096 Sync translations from Transifex and run lupdate 2021-05-02 18:33:49 +03:00
Felipe
ffda0ab0ac Update portugueseBR.nsi
An updated/fixed version of the installer language file.
2021-05-02 17:41:08 +03:00
Долматов Алексей
21f18623db Update russian.nsi
Update uninstall strings.
2021-05-02 17:41:06 +03:00
PriitUring
c4265db0fd Update estonian.nsi
Changing translation of word "Uninstall" to more common local word "Desinstall".
2021-05-02 17:41:04 +03:00
Henry Water
bc8d9656f6 Update german.nsi
Line 32
Changing "zumindest" to "mindestens".
I even would go further to change the line into "[...] Windows 7 oder höher." ("[...] Windows 7 or higher."), as this seems to make more sense and we wouldn't have the hassle of discussing whether "zumindest" or "mindestens" fits better.

If you insist on a comment:
It is quite a cosmetic change, and a personal opinion as well. Imo "mindestens" fits more to the theme of general use - "zumindest" can be used in special places, as it isn't that common in e.g. regular conversations. What comes to my mind is "Best before", which is "Mindestens haltbar bis". It would be unusual to use "Zumindest haltbar bis". 😄

Finally it is up to you what to change.

CC: @schnurlos

Additionally I fixed line 10, where no need of a double-"mit" was.
Plus line 34, as requested!
2021-05-02 17:41:02 +03:00
Chocobo1
bd284facbd Add new translatable string to all available languages
Also provide translation for Traditional Chinese.
Fix up a2ef09466f.
2021-05-02 17:40:59 +03:00
bovirus
7eb77cbcbd Enable translation for uninstaller link (#14660) 2021-05-02 17:40:57 +03:00
sledgehammer999
86e96b819e Clarify that the license is GPLv2+
Regarding this license clarification there are 3 commits of interest
(commits A, B, C). Before commit A the COPYING file contained only the
text of the GPLv2 license, while all source files had a license block
at the top saying that they are under the terms of "GPLv2 or later". With
commit A there was a temporary change to GPLv3. The COPYING file contained
only the text of the GPLv3 license, while all source files had a license
block at the top saying that they are under the terms of "GPLv3 or later".
Then with commit B the COPYING file and the license block of the source
files was reverted to their state before commit A. Afterwards, with
commit C a license summary(or clarification) block was put at the top of
the COPYING file. This block indicated that the license was GPLv2 without
having the "or later" clause and it also included the OpenSSL exception.
However, the license block of each source file continued to contain the
"or later" clause which was not removed. The same license block continues
to exist in all current source files. Thus it is concluded that the ommision
of the "or later" clause with commit C in the COPYING file was accidental.
OR ALTERNATIVELY (OR IN ADDITION)
At the time commit C was made Christophe Dumez was not the sole contributor.
There is no record that the other contributors agreed with the supposed
GPLv2 only change or that there was a Contributor License Agreement,
transfering their rights to him. Thus making his license change decision
invalid/void/illegal.

Commit A: 54f9375b32
Commit B: 8df61db644
Commit C: 9835af4962
2021-05-02 17:40:56 +03:00
Chocobo1
132be7ee9d Move cursor to the next line of end of text
Closes #13908.
2021-05-02 17:40:10 +03:00
Chocobo1
9f8a6e8fb1 Merge pull request #14872 from jagannatharjun/pfix-back
Correctly draw progress background with stylesheet (backport v4_3_x)
2021-04-30 10:09:31 +08:00
jagannatharjun
e6447c8f28 Correctly draw progress background with stylesheet
fixes #14731
2021-04-29 11:28:20 +05:30
Vladimir Golovnev
7dd9e73431 Merge pull request #14865 from Kolcha/cmake_mac_4_3
Improve Info.plist generation with CMake (v4_3_x backport)
2021-04-28 14:18:39 +03:00
Nick Korotysh
ea82962c5d Improve Info.plist generation with CMake
- drop configure_file() and file(GENERATE) calls
- fill missed MACOSX_DEPLOYMENT_TARGET variable
2021-04-27 23:51:13 +03:00
Vladimir Golovnev
b2a43eeffc Merge pull request #14828 from Kolcha/bundle_name_4_3
Don't use executable name as CFBundleName value (v4_3_x backport)
2021-04-25 07:02:41 +03:00
Vladimir Golovnev
681347148d Merge pull request #14832 from glassez/v4.3-upload-mode
Correctly handle "not enough disk space" error (v4_3_x backport)
2021-04-25 07:01:27 +03:00
Vladimir Golovnev (Glassez)
1f63490755 Correctly handle "no enough disk space" error
If torrent failed to write, it stops downloading and goes to
"upload mode" instead of errored state so it just keeps seeding.
Now qBittorrent indicates this state as "errored" and allows
the user to manually bring the torrent out of this state.
2021-04-22 18:53:20 +03:00
Nick Korotysh
0140ed356f Don't use executable name as CFBundleName value 2021-04-21 21:07:25 +03:00
Chocobo1
2c8f322af5 Merge pull request #14801 from Chocobo1/backport
Backport PRs to v4_3_x
2021-04-18 12:42:15 +08:00
Vladimir Golovnev (Glassez)
6f31ebd899 Allow to specify file indexes in torrents/files API 2021-04-17 11:46:41 +08:00
zhuangzi926
014df529c5 Update dyndns register url 2021-04-17 11:46:20 +08:00
Chocobo1
482dad00fd Fix D-Bus Notification desktop-entry field 2021-04-16 14:22:32 +08:00
Chocobo1
7898037006 Merge pull request #14701 from Chocobo1/backport
Backport to v4_3_x
2021-04-09 11:32:36 +08:00
skvenders
5c819ee384 Remove contributor
Remove contributor as requested: https://github.com/qbittorrent/qBittorrent/pull/14637#issuecomment-808894421
2021-04-08 12:06:35 +08:00
brvphoenix
a590e7139b WebUI: Fix magnet url from the browser 2021-04-08 12:05:56 +08:00
Chocobo1
89a8e07217 Revise folder monitoring functions in WebUI
Closes #14241.
2021-04-03 14:52:14 +08:00
Chocobo1
5c05bdaa27 Clean up code 2021-04-03 14:52:14 +08:00
Chocobo1
7006afc611 Remove unnecessary URL encoding
Fix #14635.
2021-04-03 14:51:24 +08:00
Christoph Rackwitz
9cb3a6d29e Fix tabChangesFocus attribute in "Edit trackers" dialog 2021-04-03 14:49:03 +08:00
Chocobo1
2b6baa6099 Merge pull request #14685 from Chocobo1/actions
Enable Github Actions CI for other branches
2021-04-03 13:21:36 +08:00
Chocobo1
8881035b7a Enable Github Actions CI for other branches
Since we need to backport some changes.
2021-04-01 12:50:00 +08:00
sledgehammer999
2be30a50ef Merge pull request #14628 from sledgehammer999/qt_511
Lower Qt requirement to 5.11
2021-03-27 17:56:43 +02:00
Mike Tzou
81a7b0c034 Merge pull request #14625 from Chocobo1/backport
Backport to v4_3_x (#14619, #14590)
2021-03-27 11:14:26 +08:00
sledgehammer999
e7235cc3f8 Revert "Use QRegularExpression instead of deprecated QRegExp"
Related to #14611

This reverts commit 3b748178c2.
2021-03-26 12:43:51 +02:00
sledgehammer999
1570b51f6c Lower Qt requirement to 5.11
Partially reverts 4037143f4e
Closes #14611
2021-03-26 12:42:08 +02:00
Chocobo1
6272c6d95d Apply code formatting 2021-03-26 10:48:34 +08:00
Chocobo1
473ae25fd8 Add WebUI checking to CI 2021-03-26 10:48:34 +08:00
Chocobo1
42d7d9b5f4 Add necessary curly brackets 2021-03-26 10:48:33 +08:00
Chocobo1
0f77b00428 Don't use Object.prototypes builtins directly
See: https://eslint.org/docs/rules/no-prototype-builtins
2021-03-26 10:48:33 +08:00
Chocobo1
060804d3b8 Remove unnecessary escape character 2021-03-26 10:48:33 +08:00
Chocobo1
f8b6cb4879 Remove extra semicolon 2021-03-26 10:48:13 +08:00
Chocobo1
a6d27223db Add tools for js code formatting and linting
Due to eslint couldn't correctly resolve the context for the variables,
two eslint rules are disabled for now.
2021-03-26 10:48:13 +08:00
Chocobo1
bb32b88a62 Sort invalid QDateTime values after valid values
Closes #14607.
2021-03-26 10:47:54 +08:00
sledgehammer999
332b173e08 Bump to 4.3.4.1 2021-03-24 21:21:06 +02:00
sledgehammer999
e921cf677a Update Changelog 2021-03-24 21:19:55 +02:00
Vladimir Golovnev (Glassez)
973b5a4809 Correctly draw progress bar in Qt 6 2021-03-24 21:15:49 +02:00
Chocobo1
688e11a911 Remove wrong parentheses
Fix up 87ad8a1495.
2021-03-24 19:17:30 +02:00
sledgehammer999
f7e6b96493 Bump to 4.3.4 2021-03-23 23:14:15 +02:00
sledgehammer999
88bf6f11c7 Update Changelog 2021-03-23 23:04:12 +02:00
sledgehammer999
90e2236990 Sync translations from Transifex and run lupdate 2021-03-23 23:02:22 +02:00
treysis
6ad7cadc4b Fix bad IPv6 address format for outgoingInterfaces
Fixes https://github.com/qbittorrent/qBittorrent/issues/12892#issuecomment-792292336
2021-03-23 22:26:59 +02:00
brvphoenix
0499111156 WebUI: Avoid decoding strings repeatedly
Fix #14553
2021-03-23 22:26:57 +02:00
Vladimir Golovnev (Glassez)
ae44e59c9a Wrap "resume data" in LoadTorrentParams 2021-03-23 22:26:55 +02:00
Vladimir Golovnev (Glassez)
1de52f9bcf Drop deprecated code 2021-03-23 22:26:54 +02:00
Vladimir Golovnev (Glassez)
448e55031e Save resume data when torrent has done checking 2021-03-23 22:26:52 +02:00
Vladimir Golovnev (Glassez)
3b748178c2 Use QRegularExpression instead of deprecated QRegExp
Now it follows closely the definition of wildcard for glob patterns.
The backslash (\) character is not an escape char in this context.
In order to match one of the special characters, place it in square
brackets (for example, [?]).
2021-03-23 22:26:50 +02:00
thalieht
a4a54ce712 Allow >100 days in WebUI function "friendlyDuration"
Because it's not only used for ETA.
2021-03-23 22:26:48 +02:00
thalieht
d19b524d2d Fix incorrect seeding time string in WebUI General tab 2021-03-23 22:26:47 +02:00
thalieht
1e2bf50e66 Add seeding time to the active time column in WebUI
Closes #14526
2021-03-23 22:26:46 +02:00
Vladimir Golovnev (Glassez)
e7f3409053 Don't use deprecated operators 2021-03-23 22:26:44 +02:00
Vladimir Golovnev (Glassez)
9758633eeb Use correct return statement 2021-03-23 22:26:42 +02:00
Vladimir Golovnev (Glassez)
3def5e40c4 Include missing header 2021-03-23 22:26:41 +02:00
Vladimir Golovnev (Glassez)
ca923ed02c Include QDesktopWidget header only when needed 2021-03-23 22:26:38 +02:00
Chocobo1
e4c3bad93a Fix library requirements 2021-03-23 22:26:37 +02:00
Chocobo1
3b52c5ce97 Draw progress bar in disabled style 2021-03-23 22:26:36 +02:00
Vladimir Golovnev (Glassez)
44b94803a4 Improve "save resume data" handling 2021-03-23 22:26:35 +02:00
jagannatharjun
5d4644c4fc Remember sub sort column of transfer list 2021-03-23 22:26:34 +02:00
Chocobo1
a2ef115c66 Simplify progress bar painting 2021-03-23 22:26:31 +02:00
Vladimir Golovnev (Glassez)
1356f200b8 Don't use deprecated QTextCodec 2021-03-23 22:26:30 +02:00
Vladimir Golovnev
3c68896b1d CI: Don't compile on Ubuntu 18.04 2021-03-23 22:26:29 +02:00
Vladimir Golovnev (Glassez)
265da50791 Don't use deprecated features 2021-03-23 22:26:28 +02:00
Vladimir Golovnev (Glassez)
4037143f4e Raise minimum supported Qt version to 5.12 2021-03-23 22:26:26 +02:00
Chocobo1
8cae8ad5c5 Replace parameters in one step
This would avoid the unwanted effect of replacing parameter coming from
another parameter.
2021-03-23 22:26:22 +02:00
Vladimir Golovnev (Glassez)
50bd845682 Initialize torrent status from add torrent params 2021-03-23 22:26:20 +02:00
Vladimir Golovnev (Glassez)
ed5aa07526 CI: Disable libtorrent2 deprecated functions on Travis 2021-03-23 22:26:19 +02:00
Vladimir Golovnev (Glassez)
437b51b3a5 Improve "info hash" handling
Define "torrent ID" concept, which is either a SHA1 hash for torrents of version 1,
or a SHA256 hash (truncated to SHA1 hash length) for torrents of version 2.
Add support for native libtorrent2 info hashes.
2021-03-23 22:26:18 +02:00
Vladimir Golovnev (Glassez)
c2ccc9dfa4 Properly show tracker status for "paused" torrents 2021-03-23 22:26:16 +02:00
Vladimir Golovnev (Glassez)
b2c7d8211f Improve tracker entries handling 2021-03-23 22:26:14 +02:00
Vladimir Golovnev (Glassez)
726455ac3e Don't allow speed plot buffer to overflow 2021-03-23 22:26:13 +02:00
Vladimir Golovnev (Glassez)
ae2bb4efeb Accept "share limits" when adding torrent using WebAPI 2021-03-23 22:26:12 +02:00
Vladimir Golovnev (Glassez)
9971329121 Look for qbittorrent.pdb in installation directory
Pass application directory as PDB search path in SymInitialize.
Otherwise it searches in application working directory so when you
run qBittorrent with working directory other than its installation
one it can't find qbittorent.pdb file and produces broken stacktrace.
2021-03-23 22:26:10 +02:00
Chocobo1
d0ec1c4a86 Expose ToS setting from libtorrent
Closes #14420.
2021-03-23 22:26:08 +02:00
Chocobo1
9c55600d81 Add missing semicolon 2021-03-23 22:26:01 +02:00
Vladimir Golovnev (Glassez)
b45fb74e01 Define template for classes that represent SHA hashes 2021-03-23 21:05:41 +02:00
Vladimir Golovnev (Glassez)
f16c585a77 Drop implicit conversions between InfoHash and QString 2021-03-23 21:05:40 +02:00
Chocobo1
9c664d04ae Remove unused lambda capture 2021-03-23 21:05:38 +02:00
Chocobo1
3d0ca83474 Specify Qt version in TravisCI build script
In homebrew `qt` package is referring to Qt6 instead of Qt5.
2021-03-23 21:05:37 +02:00
Chocobo1
e713ffb064 Properly stop torrent creation if aborted
Closes #11346.
2021-03-23 21:05:37 +02:00
Chocobo1
cf1e61bcf5 Correctly draw the background of progress bar
Closes #12271.
2021-03-23 21:05:36 +02:00
Vladimir Golovnev (Glassez)
42b22d6645 CI: Use custom vcpkg libtorrent port 2021-03-23 21:05:35 +02:00
Vladimir Golovnev (Glassez)
2d607f8c1a Raise minimum libtorrent version to 1.2.12 2021-03-23 21:05:34 +02:00
jagannatharjun
69256905c2 Support sub-sorting in Transferlist 2021-03-23 21:05:32 +02:00
brvphoenix
305316b1fc WebUI: Properly decode strings 2021-03-23 21:05:32 +02:00
Chocobo1
27e222455b Improve detection of filename extension of audio/video files 2021-03-23 21:05:31 +02:00
Michał Kopeć
2b18318e0c Add an option to disable icons in menus 2021-03-23 21:05:30 +02:00
Chocobo1
49cadce253 Enable sponsor button on Github 2021-03-23 21:05:29 +02:00
Juraj Oršulić
f1b908b95b Systemd: wait for mounting of local filesystems 2021-03-23 21:05:28 +02:00
jagannatharjun
4acfcef8da Add a 3-Hour graph 2021-03-23 21:05:27 +02:00
jagannatharjun
69f2196a22 Make SpeedPlotView averager time aware
Previously SpeedPlotView assumed speed is updated per second but the
default value was 1500ms and that can be further changed by the
user, this caused a lot of duplicate data in the calculation of the
graph points. Now Averager averages based on the target duration, resolution
and also takes into account when actually data has arrived.

Also improved resolution of 6-hour graph, previously it was same as 12-hour graph
2021-03-23 21:05:26 +02:00
Chocobo1
b20a3c5b8e Use std::optional to return results 2021-03-23 21:05:25 +02:00
Chocobo1
2c5271b3b2 Fix potential out-of-bounds access 2021-03-23 21:05:24 +02:00
Si Yong Kim
7696895a88 Refactor apply button logics on options dialog 2021-03-23 21:05:23 +02:00
Si Yong Kim
c1ae5d2572 Add empty name error handling on new category dialog 2021-03-23 21:05:23 +02:00
Si Yong Kim
0e635c7fdd Add category button on AutomatedRSSDownloader on GUI
Closes #7629
2021-03-23 21:05:22 +02:00
Chocobo1
58345e5bbf Revise getter function for torrrent queue position
This addresses https://github.com/qbittorrent/qBittorrent/pull/14335#issuecomment-774667836

The WebAPI is not affected as a workaround is added.
2021-03-23 21:05:21 +02:00
Chocobo1
89382d4ec2 Apply "Hide infinity values" to ETA column 2021-03-23 21:05:20 +02:00
Chocobo1
372f5af36b Apply "Hide infinity values" to "Down/Up Limit" columns 2021-03-23 21:05:19 +02:00
Chocobo1
f38736729d Apply "Hide zero values" to "Time Active" column 2021-03-23 21:05:18 +02:00
Chocobo1
bf67ef21c6 Clean up coding style 2021-03-23 21:05:18 +02:00
Chocobo1
cfd40adcb5 Show proper string when torrent availability is not available 2021-03-23 21:05:16 +02:00
Vladimir Golovnev (Glassez)
8210f9841e Restart "missing files" torrents after changing location 2021-03-23 21:05:16 +02:00
Vladimir Golovnev (Glassez)
ae3d17ec01 Allow "missing files" torrents to save more resume data 2021-03-23 21:05:15 +02:00
Vladimir Golovnev (Glassez)
349e958be3 Allow change-case-only file renaming on Windows 2021-03-23 21:05:14 +02:00
Chocobo1
42acc75394 Use stable sorting in transfer list 2021-03-23 21:05:12 +02:00
Chocobo1
8b91dcedb0 Use built-in function for configuring file contents 2021-03-23 21:05:11 +02:00
dyumin
a454a0303d Treat errored torrents as finished 2021-03-23 21:05:11 +02:00
Chocobo1
789c6de2e8 Simplify CI script directives 2021-03-23 21:05:10 +02:00
Chocobo1
c2fb51159f Don't trigger Github Actions CI builds after editing a PR's opening post
After dropping "edited" keyword, it is the same as the default.
2021-03-23 21:05:09 +02:00
PriitUring
bfb0afe3cf NSIS: Add Estonian translation
This file was previously not translated.
PR #14331.
2021-03-23 21:05:08 +02:00
Chocobo1
26a2d4f24d Reuse existing code for sorting
This makes the behavior of sorting by TR_SEED_DATE consistent.
2021-03-23 21:05:08 +02:00
Si Yong Kim
f6e88c8c55 Add hyperlink to Transifex on translator list
Closes #12609
2021-03-23 21:05:07 +02:00
Si Yong Kim
51033c212a Remove Hungarian translator email 2021-03-23 21:05:06 +02:00
Chocobo1
16c858cf61 Prolong checking interval for program updates 2021-03-23 21:05:05 +02:00
Chocobo1
0496543fce Improve behavior when using ProgramUpdater class
This is mainly to avoid involving of `sender()` function.
2021-03-23 21:05:04 +02:00
Chocobo1
746e8a7be1 Revise version comparison 2021-03-23 21:05:04 +02:00
Chocobo1
6d301ccf55 Clean up coding style 2021-03-23 21:05:03 +02:00
jagannatharjun
d441b18da0 Disable expand on double click in TorrentContentTreeView
We hook our own actions on double click. Fixes #14269
2021-03-23 21:05:01 +02:00
Vladimir Golovnev (Glassez)
13023ba70a Bump WebAPI version 2021-03-23 21:05:01 +02:00
Alex
ecb7c02d4c Update Portuguese BR NSIS translation (#12376) 2021-03-23 21:05:00 +02:00
slrslr
fd1ac43157 Translating new phrases (#12318)
* Update Czech NSIS translation

Co-authored-by: slrslr <czautohits@gmail.com>
2021-03-23 21:04:59 +02:00
Chocobo1
c6d4a1f7d4 Enlarge "speed limit" icon slightly 2021-03-23 21:04:58 +02:00
Chocobo1
01110690da Don't let "program update" dialog steal focus
And also avoid creating an unnecessary event loop.
Closes #14250.
2021-03-23 21:04:57 +02:00
Chocobo1
c998c7d38d Disable translation of program name 2021-03-23 21:04:56 +02:00
an0n666
230f98da4a Validate HTTPS Tracker Certificate by default 2021-03-23 21:04:56 +02:00
xavier2k6
c86db0004f Change qBittorrent Updater window title 2021-03-23 21:04:54 +02:00
Christoph Rackwitz
e645514c8f Allow tab to escape the text box in "Edit trackers" dialog 2021-03-23 21:04:53 +02:00
Chocobo1
f3c9dbd512 Remove redundant variable declarations 2021-03-23 21:04:52 +02:00
Chocobo1
ef650293e3 Add ability to prioritize selected items by shown file order
Closes #2834.
2021-03-23 21:04:51 +02:00
Chocobo1
05e217537c Move menu actions out of .ui files
This is to move related code together.
2021-03-23 21:04:50 +02:00
Vladimir Golovnev (Glassez)
13cb3b5ca1 Drop extension from generated content folder name
Try to detect whether generated content folder name contains extension
and drop it to avoid possible conflicts between file/folder names.
2021-03-23 21:04:38 +02:00
sledgehammer999
da0b276d5f Bump to 4.3.3 2021-01-19 00:47:04 +02:00
sledgehammer999
2d73bc9e7d Update Changelog 2021-01-19 00:46:29 +02:00
Chocobo1
fdd54fe568 Simplify code for checking free disk space
`QStorageInfo::bytesAvailable()` is guaranteed to return `-1` for an
invalid path.
https://doc.qt.io/qt-5/qstorageinfo.html#bytesAvailable
2021-01-19 00:45:13 +02:00
Chocobo1
e5ce24e55e Improve detection of file extension string 2021-01-19 00:45:06 +02:00
sledgehammer999
d90349709b Sync translations from Transifex and run lupdate 2021-01-17 23:24:02 +02:00
Vladimir Golovnev (Glassez)
adb0fe6582 WebUI: Correctly represent torrent content structure 2021-01-17 22:50:40 +02:00
Chocobo1
5ed81580c9 Add README.md to searchengine folder 2021-01-17 22:50:39 +02:00
Chocobo1
86d6fb86d7 Unify "github actions" artifacts naming scheme 2021-01-17 22:50:38 +02:00
Chocobo1
ddec247d4f Migrate away from deprecated Qt functions
`QString QDateTime::toString(Qt::DateFormat format = Qt::TextDate)` will
be removed in Qt6.
2021-01-17 22:50:37 +02:00
Chocobo1
d431ecbe00 Disable clang "range loop analysis" compiler warning
See: https://github.com/qbittorrent/qBittorrent/pull/13915#issuecomment-739449084
2021-01-17 22:50:36 +02:00
Chocobo1
be929ed88c Set source character sets to UTF-8
This suppress warning C4819.
https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-160
2021-01-17 22:50:35 +02:00
Chocobo1
2e1f9bf8be Add script for generating project tarball 2021-01-17 22:50:20 +02:00
lbilli
7fff393b0e On Linux use legacy 'data' directory only as a fallback 2021-01-17 22:47:13 +02:00
sledgehammer999
a669ec49ad Correct copyright attribution
These files were created and edited in their entirety in commit 8db4bde15d
As far as I can tell they were almost entirety rewritten from their original state.
The old copyright attribution is restored and the new author is added too.
2021-01-17 22:47:11 +02:00
Vladimir Golovnev (Glassez)
1880082017 Remove redundant suffix from TorrentHandle class
Originally, it was just a wrapper for libtorrent::torrent_handle class, so it mimicked its name.
It was then transformed into a more complex aggregate, but the name was retained (just by inertia).
Unlike libtorrent::torrent_handle class in whose name "handle" means the pattern used,
it does not matter for qBittorrent classes and just eats up space in the source code.
2021-01-17 22:47:00 +02:00
sledgehammer999
0cbd15890a Merge pull request #14170 from sledgehammer999/use_cxx1z
Use c++1z to enable c++17
2021-01-07 13:40:05 +02:00
sledgehammer999
7fe7c6c277 Use c++1z to enable c++17
It increases compatibility with older qt versions.
2021-01-06 21:54:46 +02:00
jagannatharjun
e4c177fec7 Correctly set items flags in TorrentContentModel
Only set editable flag on item's where editing is handled in the delegate

closes #13515
2021-01-06 21:36:40 +02:00
Chocobo1
77f4e6c2cf Generate version header when configuring project
The basic idea is we create a version header template at
"src/base/version.h.in" and the build systems are expected to replace
strings that are enclosed with @ symbols and generate
"src/base/version.h" for other source files to consume/include.
2021-01-06 21:36:39 +02:00
sledgehammer999
4563b11a2e Bump copyright year 2021-01-06 21:36:37 +02:00
Vladimir Golovnev (Glassez)
cb477f9a29 QMake: Raise minimal macOS target version 2021-01-06 21:36:35 +02:00
Vladimir Golovnev (Glassez)
58ac07667e Use single parameter to accept torrent source 2021-01-06 21:36:34 +02:00
Vladimir Golovnev (Glassez)
74bf3af41c Use std::optional<bool> instead of custom TriStateBool 2021-01-06 21:36:33 +02:00
Vladimir Golovnev (Glassez)
9317071122 Change parseBool() to return optional bool value 2021-01-06 21:36:31 +02:00
Vladimir Golovnev (Glassez)
dab32f2090 Use std::optional instead of boost::optional 2021-01-06 21:36:29 +02:00
Vladimir Golovnev (Glassez)
dc464d4d41 Use nested namespaces definition syntax 2021-01-06 21:36:28 +02:00
Chocobo1
e7e3f6a9db Don't use deprecated locale name 2021-01-06 21:36:27 +02:00
Chocobo1
5a1c4e79b3 Revise store/load state operations of Options Dialog 2021-01-06 21:36:26 +02:00
Chocobo1
c6d9ab6810 Remember dialog sizes
This applies to "About Dialog", "Ban List Options Dialog", "Download From URL Dialog", "IP Subnet
Whitelist Options Dialog", "Search Plugin Select Dialog", "Search Plugin Source Dialog",
"Statistics Dialog", "Speed Limit Dialog" and "Torrent Options Dialog".

Also unifies storing the dialog size under the key "Size".
2021-01-06 21:36:24 +02:00
Chocobo1
d7afad835e Revise SettingsStorage store/load value interface 2021-01-06 21:36:22 +02:00
Chocobo1
8608d7b9da Improve load data behavior of SettingsStorage class
Previously it only handle the case of failed lookup, now it discard
invalid values when deserializing the database from disk.
Also checks whether the data is convertible to the intended type.
2021-01-06 21:36:22 +02:00
Vladimir Golovnev (Glassez)
72970602af Reload "missing files" torrent instead of re-checking 2021-01-06 21:36:20 +02:00
Vladimir Golovnev (Glassez)
86579ca87d Extract torrent reloading logic into separate method 2021-01-06 21:36:19 +02:00
Vladimir Golovnev (Glassez)
e55582124c Drop notification about move storage failed 2021-01-06 21:36:17 +02:00
Vladimir Golovnev (Glassez)
bd8b06c607 Drop notification about move storage finished 2021-01-06 21:36:16 +02:00
Chocobo1
230fedf069 Move parsing of TriStateBool to a static class function 2021-01-06 21:36:14 +02:00
thalieht
7bea10f507 Update "Keep top-level folder" in WebUI options 2021-01-06 21:36:13 +02:00
Chocobo1
7cde969b90 Exclude configure script for "trailing newlines" checking 2021-01-06 21:36:12 +02:00
Chocobo1
a3b8f6880b Migrate away from deprecated AC_OUTPUT macro
The `AC_OUTPUT` has two versions, the deprecated one takes arguments and the other not. Check the
following link for equivalent replacement:
https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.70/html_node/Obsolete-Macros.html#Obsolete-Macros

Also regenerate the configure script with the latest Autoconf 2.70.
2021-01-06 21:35:33 +02:00
Chocobo1
ad79fc8d43 Migrate away from deprecated std::iterator class 2021-01-06 21:31:51 +02:00
Chocobo1
fb4bf94a56 Use function-pointer based signal-slot connection 2021-01-06 21:31:50 +02:00
Chocobo1
1c184944fd Remove unused define 2021-01-06 21:31:49 +02:00
Chocobo1
ec420f6617 Bump project requirement to C++17 2021-01-06 21:31:47 +02:00
Chocobo1
d908227619 Add a thin layer around SettingsStorage class
This new layer would be handy for saving GUI widget states as they don't
need the value cached and they store/load rarely.
2021-01-06 21:31:45 +02:00
sledgehammer999
ac8167410b Add new languages
* Azerbaijani
* Estonian
2021-01-06 21:31:44 +02:00
Vladimir Golovnev (Glassez)
26ce187b30 Don't call non-existent elements
Fixed a regression where the script tries to access elements that no longer
exist on the page, because they were replaced with others by a previous change.
2021-01-06 21:31:43 +02:00
Vladimir Golovnev (Glassez)
2c4e04e537 Don't call non-existent elements
Fixed a regression where the script tries to access elements that no longer
exist on the page, because they were replaced with others by a previous change.
2021-01-06 21:31:42 +02:00
Vladimir Golovnev (Glassez)
b418f65c2f Improve content file/folder names handling
Move files/folders renaming functions to core classes.
Query file/folder for renaming by its current path.
Add ability to rename content folders from WebAPI/WebUI.
2021-01-06 21:31:41 +02:00
Vladimir Golovnev (Glassez)
dd3a8d5d56 Fix folder name extraction functions
It should return empty string if there is no parent folder.
2021-01-06 21:31:39 +02:00
Chocobo1
49e54a55df Capitalize locale names 2021-01-06 21:31:38 +02:00
thalieht
8cd0a7ae85 Group several torrent options into one dialog
Speed limits, share limits and the new options to disable DHT, PeX, LSD per torrent
2021-01-06 21:31:36 +02:00
thalieht
442f0df613 Save fastresume when setting torrent speed limits 2021-01-06 21:31:35 +02:00
thalieht
f9ee5bdb59 Increase maximum global speed limits from ~1 GiB/s to ~2 GiB/s
Closer to the INT_MAX limit of ~2 Billion when multiplied by 1024 for libtorrent
2021-01-06 21:31:33 +02:00
thalieht
b9602cc6ab Convert existing speed dialog to global + alt global limits only 2021-01-06 21:31:25 +02:00
sledgehammer999
abb854a1e6 Bump to 4.3.2 2020-12-27 13:42:41 +02:00
sledgehammer999
4ee17a73d0 Update Changelog 2020-12-27 13:42:40 +02:00
sledgehammer999
faf6e82274 Sync translations from Transifex and run lupdate 2020-12-26 21:18:40 +02:00
Vladimir Golovnev (Glassez)
c08ec1ac5e Allow to add root folder to torrent content 2020-12-26 20:27:34 +02:00
Vladimir Golovnev (Glassez)
cd0b6d9a43 Extract enum serialization/parsing functions 2020-12-26 20:27:33 +02:00
Vladimir Golovnev (Glassez)
b8f1142abe Improve torrent name handling 2020-12-26 20:27:31 +02:00
Chocobo1
78859415d6 Use a helper function to look up stat indexes 2020-12-26 20:27:29 +02:00
Chocobo1
ef92c17192 Don't use removed stat metric in libtorrent 2.0
For now, the metric is not entirely removed due to WebAPI still needs to
access it.
2020-12-26 20:27:28 +02:00
Chocobo1
22f3abc4b5 Initialize stat indices to -1
When the index is initialized it will be set to a number >= 0, so we use
-1 to denote its uninitialized status.
2020-12-26 20:27:27 +02:00
Chocobo1
a56e6294c1 Fix wrong JSON type returned
Fix up 78638a15be.
Closes #14041.
2020-12-26 20:27:26 +02:00
Chocobo1
77909e0093 Don't use default CFLAGS, CXXFLAGS from autotools
Before this commit, autotools will inject `-g -O2` to debug build
(`--enable-debug=yes`) and rendering the result binary useless. This
commit fixes it.
https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.70/html_node/C_002b_002b-Compiler.html

Closes #14032.
2020-12-26 20:27:25 +02:00
Vladimir Golovnev (Glassez)
2c2bb14b2a Fix bug of "move storage job" can be performed multiple times 2020-12-26 20:27:16 +02:00
Chocobo1
73c8b77464 Migrate away from deprecated QVariant comparison operators
Fortunately, serializing to JSON limits the data types to a very small
subset and thus we are able to implement the comparison without much
hassle.

Fix up cba8d83b21.
2020-12-26 20:27:14 +02:00
Alessandro Simonelli
042238db87 NSIS: Fixed italian.nsi after 4.3.0.1 update
Merged my previous fixes (discussed in #13607) with the suggestions by @glassez (#13615).
2020-12-26 20:27:13 +02:00
FranciscoPombal
6e267f8e81 Update coding guidelines policy for include guards 2020-12-26 20:27:11 +02:00
FranciscoPombal
fdc64d9b38 Use #pragma once instead of include guards 2020-12-26 20:27:10 +02:00
Chocobo1
0b42425db5 Add support for allow_idna option
Upstream PR: https://github.com/arvidn/libtorrent/pull/5316
2020-12-26 20:27:08 +02:00
Chocobo1
e5d7738127 Update "HTTPS tracker validation" enablement conditional
https://github.com/arvidn/libtorrent/pull/5313
2020-12-26 20:27:06 +02:00
Chocobo1
422489e2a1 Revise Utils::Version comparison operators 2020-12-26 20:27:04 +02:00
Chocobo1
7de983b4e5 Add operator< for InfoHash class 2020-12-26 20:27:03 +02:00
Chocobo1
e4e55d2a80 Migrate away from deprecated QVariant comparison operators
Another idea would be manually define a custom comparison function for
QVariant. However, having the function would be excessive due to its
limited usage count, also note that we are already casting
various QVariant to its underlying type in existing code.
2020-12-26 20:27:01 +02:00
Vladimir Golovnev (Glassez)
926012ce71 Fix bug of torrents don't save "stopped" state 2020-12-26 20:27:00 +02:00
Chocobo1
487eb554c9 Fix coding style 2020-12-26 20:26:59 +02:00
Chocobo1
5a96e1fc7a Use Qt provided forward declaration header 2020-12-26 20:26:58 +02:00
FranciscoPombal
2fe698ee60 CMake: detect required header for STACKTRACE feature
musl does not provide execinfo.h, so our current stacktrace-related
code cannot be used with it.
2020-12-26 20:26:57 +02:00
Chocobo1
177ac32a5e Use the correct type when referring to info hash 2020-12-26 20:26:55 +02:00
Vladimir Golovnev (Glassez)
5f34d1555b Fix received metadata handling 2020-12-26 20:26:54 +02:00
FranciscoPombal
7cfe68f46c Bump dependency versions in CI
- Bump vcpkg version in GitHub Actions CI
- Bump libtorrent version in Travis CI

Co-authored-by: Vladimir Golovnev <glassez@yandex.ru>
2020-12-26 20:26:53 +02:00
Vladimir Golovnev
f94f4d2391 Drop support for building with libtorrent < 1.2.11
Co-authored-by: Vladimir Golovnev <glassez@yandex.ru>
2020-12-26 20:26:52 +02:00
FranciscoPombal
73b18d7ef3 Update minimum depedency versions 2020-12-26 20:26:51 +02:00
FranciscoPombal
817e9c4747 Fix method invocation on Qt < 5.10
Fixup 0c3fe54b0b
2020-12-26 20:26:48 +02:00
Vladimir Golovnev (Glassez)
28844eff44 Search for existing files in separate thread 2020-12-26 20:26:47 +02:00
Vladimir Golovnev (Glassez)
389664213b Don't rewrite TorrentInfo instance if it's valid 2020-12-26 20:26:46 +02:00
Vladimir Golovnev (Glassez)
953b6fd6f8 Properly handle "Append extension" option changing 2020-12-26 20:26:45 +02:00
Vladimir Golovnev (Glassez)
9b4f3fcbf8 Clean up metadata downloading code 2020-12-26 20:26:43 +02:00
Chocobo1
80743180be Remove unnecessary restriction on input length
Closes #13884.
2020-12-26 20:26:42 +02:00
Chocobo1
b2847b2381 Update URL to libtorrent settings 2020-12-26 20:26:41 +02:00
Chocobo1
eb657ec032 Move "embedded tracker" options to qbt section 2020-12-26 20:26:39 +02:00
Chocobo1
fc2be601df Add links to libtorrent documentation 2020-12-26 20:26:38 +02:00
Chocobo1
5786c7ff11 Lift upper limit of "Max concurrent HTTP announces" option
Closes #13800.
2020-12-26 20:26:37 +02:00
Jesse Chan
4a183dd968 WebAPI: bump version to 2.6.2 2020-12-26 20:26:36 +02:00
Jesse Chan
7c10dba10c WebAPI: allow to attach tags while adding torrents 2020-12-26 20:26:35 +02:00
sledgehammer999
894446d308 Don't try to remove folders for a torrent without metadata 2020-12-26 20:26:34 +02:00
sledgehammer999
47e9c5ac08 Fix status of torrents without metadata 2020-12-26 20:26:33 +02:00
Chocobo1
7f47ac11f1 Add libtorrent 2.0 to TravisCI script
Also bumping to ubuntu focal as libtorrent requires boost >= 1.66.
2020-12-26 20:26:32 +02:00
Chocobo1
67b17891fa Simplify the calculation of speed graph scale 2020-12-26 20:26:31 +02:00
Chocobo1
dd5b7ba05b Avoid potential rounding to integer issues 2020-12-26 20:26:30 +02:00
Chocobo1
61aa4d9f1c Fix coding style 2020-12-26 20:26:29 +02:00
Chocobo1
6e924b668e Fix availability value
Closes #13869.
Fix up 02f19bfbee.
2020-12-26 20:26:27 +02:00
FranciscoPombal
618ce33fa0 Detect .ts file issues with file health workflow
Also adjust newlines to improve output
2020-12-26 20:26:26 +02:00
Chocobo1
ac413c76b9 Update to use latest macOS image for TravisCI
The default version is so outdated that it needs to rebuild many
dependencies. Now we bump it to the latest version so that it can use
prebuilt packages.
2020-12-26 20:26:25 +02:00
Chocobo1
f266184514 Add ability to use 'shift+delete' to delete torrents in WebUI
Closes #13827.
2020-12-26 20:26:24 +02:00
Chocobo1
8c48bf4a70 Fix wrong data used for comparison
In torrent transfer list we should use underlying data for sorting, not
displayed values.

Closes #13818.
2020-12-26 20:26:23 +02:00
Andrei Stepanov
8bee69c9fc NSIS: Update Russian translation 2020-12-26 20:26:14 +02:00
sledgehammer999
5876886345 Bump to 4.3.1 2020-11-25 13:49:50 +02:00
sledgehammer999
0392bfce3c Update Changelog 2020-11-25 13:49:48 +02:00
sledgehammer999
c66cf43d6a Sync translations from Transifex and run lupdate 2020-11-24 17:04:07 +02:00
Chocobo1
7515afc058 Pin github actions scripts to major versions
> Using the specific major action version allows you to receive critical
> fixes and security patches while still maintaining compatibility. It
> also assures that your workflow should still work.
https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsuses
2020-11-24 16:14:16 +02:00
Thomas De Rocker
5fcfcc901e Fix confusion in date format description (#1)
* Update automatedrssdownloader.ui

* Update rssDownloader.html (#2)
2020-11-24 16:14:15 +02:00
Vladimir Golovnev (Glassez)
1728c16580 Improve coding style 2020-11-24 16:14:14 +02:00
Thomas De Rocker
d3f46452a9 Update dutch.nsi
As referenced in https://github.com/qbittorrent/qBittorrent/pull/13615
and suggested by @glassez 
- Use the word qBittorrent when it is mentioned for the first time within a string.
- If the string contains other references to qBittorrent, then use it (rather than repeating qBittorrent).

Line 24 is the updated Dutch translation for the recently updated English source string (may 2020)
2020-11-24 16:14:09 +02:00
sledgehammer999
7092a98c93 Add Latgalian translation
Closes #12415
2020-11-24 16:14:08 +02:00
sledgehammer999
8e19f66b4f Update .desktop file translations 2020-11-24 16:14:06 +02:00
Chocobo1
b6ab2abf3f Don't use deprecated torrent state "allocating"
Closes #13737.
2020-11-24 16:14:05 +02:00
Vladimir Golovnev (Glassez)
3edaaa30c9 Handle torrent "paused" state at application level 2020-11-24 16:14:04 +02:00
FranciscoPombal
38efff461e Add GitHub Actions file health workflow 2020-11-24 16:14:03 +02:00
FranciscoPombal
2179148b8d Make sure there are no empty files 2020-11-24 16:14:02 +02:00
FranciscoPombal
f92c4c0a40 Fix extra/missing trailing new lines in files 2020-11-24 16:14:00 +02:00
FranciscoPombal
1e7f792dbb Fix trailing whitespace in multiple files
Also fix formatting of CODING_GUIDELINES.md
2020-11-24 16:13:59 +02:00
FranciscoPombal
1d4af505c2 Encode files in UTF-8 without BOM 2020-11-24 16:13:57 +02:00
Chocobo1
baa609b713 Remove unused function 2020-11-24 16:13:55 +02:00
Chocobo1
bc20cf9ad7 Remove redundant semicolon 2020-11-24 16:13:53 +02:00
Chocobo1
7d3ecfa9a6 Allow adding torrents using "Paste" key sequence
Closes #13685.
2020-11-24 16:13:52 +02:00
NotTsunami
88a90ed7d4 Fix mingw64 build error
mingw64 defines interface, so revert back to previous naming scheme

Fixes: 87864531ab
Closes #13649
2020-11-24 16:13:51 +02:00
jagannatharjun
3e540b3f51 Align integer data to right in torrent content view 2020-11-24 16:13:50 +02:00
jagannatharjun
87e1661bd5 Rename TR_PROGRESS header in TransferList
Closes #13665
2020-11-24 16:13:49 +02:00
Chocobo1
f82a4051af Remove outdated information 2020-11-24 16:13:47 +02:00
Vladimir Golovnev (Glassez)
5730e917a1 Fix torrent state calculation 2020-11-24 16:13:46 +02:00
Vladimir Golovnev (Glassez)
5e7d7c2ef0 Don't resume "paused" torrents when checking by libtorrent 2020-11-24 16:13:45 +02:00
jagannatharjun
2b6e1953d7 Use ProgressbarDelegate for drawing progressbar in PropListDelegate
Also directly provide display data from model rather then generating it in delegate
2020-11-24 16:13:43 +02:00
jagannatharjun
6fc50f4169 Use ProgressBarDelegate for drawing progressbar in TransferListView 2020-11-24 16:13:42 +02:00
jagannatharjun
40d7a53695 Implement ProgressBarDelegate 2020-11-24 16:13:41 +02:00
Chocobo1
7e89893454 Add support for tracker scrape in libtorrent 2.0 2020-11-24 16:13:39 +02:00
Chocobo1
d83f09e731 Migrate away from deprecated functions in libtorrent 2.0 2020-11-24 16:13:38 +02:00
Chocobo1
36575b225d Improve compatibility with libtorrent 2.0
In libtorrent 2.0, the `connection_type` was changed to a flag type and
hence it cannot be used in a switch statement directly. Also our use of
`connection_type` is limited so that a single equality comparison
would cover all of our use cases.
2020-11-24 16:13:36 +02:00
jagannatharjun
fe0ea843e0 Fix crash when clicked outside the table of torrent content view
Closes #13645
2020-11-24 16:13:35 +02:00
FranciscoPombal
a8911f8136 Clarify protocol choice label 2020-11-24 16:13:34 +02:00
FranciscoPombal
c5ef1a0207 Update "GitHub Actions" CI actions versions 2020-11-24 16:13:32 +02:00
brvphoenix
102d628c0a Fix the issue that IPv6 address can't be banned
The ban action doesn't depend on ipfilter.
2020-11-24 16:13:31 +02:00
FranciscoPombal
6ea3acdaea Expose contentPath in WebAPI torrents/info
Bump WebAPI version to 2.6.1
2020-11-24 16:13:30 +02:00
Chocobo1
621578353d Remove redundant checking before remove 2020-11-24 16:13:29 +02:00
Chocobo1
ca776c3036 Fix class name 2020-11-24 16:13:28 +02:00
Chocobo1
9d27eb3b57 Move qHash helper for libtorrent types to its own file 2020-11-24 16:13:26 +02:00
Vladimir Golovnev (Glassez)
9171dffe97 Prevent resume data to be saved for removed torrent 2020-11-24 16:13:25 +02:00
thalieht
f919d4f5bf Fix toggling advanced option in WebUI
option "Disallow connection to peers on privileged ports"
2020-11-24 16:13:24 +02:00
Chocobo1
59afc7c520 Avoid settings being reset via WebAPI
Closes #13585.
2020-11-24 16:13:23 +02:00
Chocobo1
f02b65b866 Fix typos 2020-11-24 16:13:19 +02:00
Andrei Stepanov
891c471160 Fix typo in connection.cpp
limiation -> limitation
2020-11-24 16:13:17 +02:00
Sepro
f49f5ba9a1 Place WebUI RSS description in sandboxed iframe 2020-11-24 16:10:40 +02:00
NotTsunami
539b3b7c3e Remove branches block from Travis config
This block has no significance because these branches are stale and
builds will not be triggered on these branches.
2020-11-24 16:10:39 +02:00
NotTsunami
83ce285138 Disallow CMake build failures on Travis
Our CMake configuration has matured over time, thus require CMake
builds to require successful builds on Travis CI.
2020-11-24 16:10:30 +02:00
sledgehammer999
260e48b705 Correct the Changelog entry 2020-10-22 14:48:11 +03:00
sledgehammer999
f09ee1b398 Bump to 4.3.0.1 2020-10-22 09:29:00 +03:00
sledgehammer999
e3c2266611 Update Changelog 2020-10-22 09:22:54 +03:00
bovirus
53fb6220c5 NSIS: Update Italian translation 2020-10-22 09:21:00 +03:00
sledgehammer999
34e6b73374 Close parentheses in Changelog entry 2020-10-19 01:48:52 +03:00
sledgehammer999
b925cffddb Bump to 4.3.0 2020-10-18 22:41:04 +03:00
sledgehammer999
3595626eff Update Changelog 2020-10-18 22:41:03 +03:00
402 changed files with 63142 additions and 62269 deletions

View File

@@ -13,8 +13,8 @@ environment:
REPO_DIR: &REPO_DIR c:\qbittorrent
CACHE_DIR: &CACHE_DIR c:\qbt_cache
QBT_VER_URL: https://builds.shiki.hu/appveyor/version_64
QBT_LIB_URL: https://builds.shiki.hu/appveyor/qbt_libraries_64.7z
QBT_VER_URL: https://builds.shiki.hu/appveyor/version
QBT_LIB_URL: https://builds.shiki.hu/appveyor/qbt_libraries.7z
# project directory
clone_folder: *REPO_DIR
@@ -38,12 +38,12 @@ install:
appveyor DownloadFile "%QBT_LIB_URL%" -FileName "c:\qbt_lib.7z" && 7z x "c:\qbt_lib.7z" -o"%CACHE_DIR%" > nul &&
COPY "c:\version_new" "%CACHE_DIR%\version")
# Qt stay compressed in cache
- 7z x "%CACHE_DIR%\qt5_64.7z" -o"c:\qbt" > nul
- 7z x "%CACHE_DIR%\qt5_32.7z" -o"c:\qbt" > nul
before_build:
# setup env
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
- SET PATH=%PATH%;C:\Qt\5.15.2\msvc2019_64\bin;%CACHE_DIR%\jom
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat"
- SET PATH=%PATH%;c:\qbt\qt5_32\bin;%CACHE_DIR%\jom;
# setup project
- COPY /Y "%CACHE_DIR%\conf.pri" "%REPO_DIR%"
# workarounds

19
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,19 @@
**Please provide the following information**
### qBittorrent version and Operating System
(type here)
### If on linux, libtorrent-rasterbar and Qt version
(type here)
### What is the problem
(type here)
### What is the expected behavior
(type here)
### Steps to reproduce
(type here)
### Extra info(if any)
(type here)

View File

@@ -1,89 +0,0 @@
---
name: Bug Report
about: Report a problem with qBittorrent to help us resolve it.
title: ''
labels: ''
assignees: ''
---
# Bug report
<!--
###############################################################################
WARNING!
IGNORING THE INSTRUCTIONS IN THIS TEMPLATE WILL RESULT IN THE ISSUE BEING
CLOSED AS INCOMPLETE/INVALID
###############################################################################
-->
## Checklist
<!--
################################## IMPORTANT ##################################
As you read and fulfill each of the following requirements below,
put an "x" between the square brackets to mark each task as done, like so: [x]
-->
- [ ] I have read the **issue reporting section** in the [contributing guidelines](https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md), so I know how to submit a good bug report with the required information
- [ ] I have verified that the **issue is not fixed and is reproducible** in the **[latest version](https://www.qbittorrent.org/download.php)**
- [ ] (optional but recommended) I have verified that the **issue is not fixed and is reproducible** in the **[latest CI build](https://github.com/qbittorrent/qBittorrent/actions/workflows/ci.yaml?query=branch%3Amaster+event%3Apush)**
- [ ] I have **checked the [frequent/common issues list](https://github.com/qbittorrent/qBittorrent/projects/2)** and **searched** the issue tracker for similar bug reports (including closed ones) **to avoid posting a duplicate**
- [ ] This report is **not a support request or question**, both of which are better suited for either the [discussions section](https://github.com/qbittorrent/qBittorrent/discussions), [forum](https://qbforums.shiki.hu/), or [subreddit](https://www.reddit.com/r/qBittorrent/). The [wiki](https://github.com/qbittorrent/qBittorrent/wiki) did not contain a suitable solution either
- [ ] I have **pasted/attached the settings file and relevant log(s)** in the **Attachments** section at the bottom of the report. Mandatory: the settings file and at least the most recent log. See [this wiki page](https://github.com/qbittorrent/qBittorrent/wiki/Frequently-Asked-Questions#Where_does_qBittorrent_save_its_settings) if you're not sure where to find them.
## Description
<!--
################################## IMPORTANT ##################################
Delete each "(type here)" indicator and type your text in their place in the subsections below.
You MUST fill in ALL subsections marked with "(type here)" with the appropriate information.
Please make sure the description is worded well enough to be understood.
Provide steps to reproduce the issue, any additional relevant information, suggested solution (if applicable) and as much context and examples as possible.
For more information consult the Contributing Guidelines at https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md.
Do not forget about the mandatory attachments!
Use the Preview tab before posting to make sure your report looks like it is formatted properly.
You don't need to delete these comments, they won't show up in the final post.
-->
### qBittorrent info and operating system(s)
<!--
IMPORTANT:
if you did not get the qBittorrent installer from the links in the official website
or if you did not install it from the PPA, please mention that after the version
-->
- qBittorrent version: (type here)
- Operating system(s) where the issue occurs: (type here)
### If on Linux, `libtorrent-rasterbar` and `Qt` versions
- Qt: (type here)
- libtorrent-rasterbar: (type here)
### What is the problem
(type here)
### Detailed steps to reproduce the problem
1. (type here)
2. (type here)
3. (etc.)
### What is the expected behavior
(type here)
### Extra info (if any)
(type here)
## Attachments
<!-- paste file contents here (or attach the files if they are big), do NOT link to external sites -->

View File

@@ -1,20 +0,0 @@
blank_issues_enabled: false
contact_links:
-
about: "Consult the wiki first (especially the FAQ), it might already contain the information you are looking for"
name: Wiki
url: "https://github.com/qbittorrent/qBittorrent/wiki/"
-
about: "Please ask questions related to usage/setup/support/non-issue development discussion in the Discussions section"
name: Question
url: "https://github.com/qbittorrent/qBittorrent/discussions"
-
about: "Alternatively, ask on the official forum"
name: Question
url: "http://forum.qbittorrent.org/"
-
about: "Alternatively, use the subreddit"
name: Question
url: "https://www.reddit.com/r/qBittorrent/"

View File

@@ -1,61 +0,0 @@
---
name: Feature Request
about: Suggest a new feature or enhancement for qBittorrent.
title: ''
labels: 'Feature request'
assignees: ''
---
# Feature request
<!--
###############################################################################
WARNING!
IGNORING THE INSTRUCTIONS IN THIS TEMPLATE WILL RESULT IN THE ISSUE BEING
CLOSED AS INCOMPLETE/INVALID
###############################################################################
-->
## Checklist
<!--
################################## IMPORTANT ##################################
As you read and fulfill each of the following requirements below,
put an "x" between the square brackets to mark each task as done, like so: [x]
-->
- [ ] I have read the **feature request section** in the [contributing guidelines](https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md), so I know how to submit a good feature request with the required information
- [ ] I have verified that the **feature** I am requesting is **not available** in the **[latest version](https://www.qbittorrent.org/download.php)**
- [ ] (optional but recommended) I have verified that the **feature** I am requesting is **not available** in the **[latest CI build](https://github.com/qbittorrent/qBittorrent/actions/workflows/ci.yaml?query=branch%3Amaster+event%3Apush)**
- [ ] I have **checked the [frequent/common issues list](https://github.com/qbittorrent/qBittorrent/projects/2)** and **searched** the issue tracker for similar feature requests (including closed ones) **to avoid posting a duplicate**
- [ ] This request is **not a support request or question**, both of which are better suited for either the [discussions section](https://github.com/qbittorrent/qBittorrent/discussions), [forum](https://qbforums.shiki.hu/), or [subreddit](https://www.reddit.com/r/qBittorrent/). The [wiki](https://github.com/qbittorrent/qBittorrent/wiki) did not contain a suitable solution either
## Description
<!--
################################## IMPORTANT ##################################
Delete each "(type here)" indicator and type your text in their place in the subsections below.
You MUST fill in ALL subsections marked with "(type here)" with the appropriate information.
Please make sure the description is worded well enough to be understood.
Provide a detailed description of the feature and as much context and examples as necessary.
If the feature request has to do with visual elements and the GUI, images/screenshots are always helpful.
For more information consult the Contributing Guidelines at https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md.
Use the Preview tab before posting to make sure your report looks like it is formatted properly.
You don't need to delete these comments, they won't show up in the final post.
-->
### Suggestion
(type here)
### Use case
(type here)
### Extra info/examples/attachments
<!-- optional -->

View File

@@ -1,16 +0,0 @@
# Changes proposed in this pull request
<!--
IMPORTANT: an image is worth a thousand words.
It is often a good idea to post screenshots showing the "before" and "after" your PR's changes,
especially with changes related to the GUI, along with the textual description.
Images makes it immediately clearer for others what your proposed changes are all about.
-->
(type here)
<!--
OPTIONAL: if this PR directly addresses an issue, make sure to include a "Closes #XXXXX" statement at the end.
-->
<!-- You don't need to delete these comments before posting, they won't show up in the post :) -->

18
.github/SUPPORT.md vendored
View File

@@ -1,18 +0,0 @@
# Support Resources
The issue tracker is only for bug reports/feature requests related to the project itself.
Please do not use the issue tracker for questions about general program usage,
how BitTorrent (the protocol) works in general, etc.
For such questions, use one of the following community support resources:
* The [discussions section][discussions-url]
* The official forum [official forum][forum-url]
* The [qBittorrent subreddit][subreddit-url]
[discussions-url]: https://github.com/qbittorrent/qBittorrent/discussions
[forum-url]: http://forum.qbittorrent.org/
[subreddit-url]: https://www.reddit.com/r/qBittorrent/

View File

@@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
libt_version: ["v2.0.4", "v1.2.14"]
libt_version: ["v1.2.12"]
qbt_gui: ["GUI=ON", "GUI=OFF"]
fail-fast: false

View File

@@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
libt_version: ["v2.0.4", "v1.2.14"]
libt_version: ["v1.2.12"]
qbt_gui: ["GUI=ON", "GUI=OFF"]
fail-fast: false

View File

@@ -1,85 +0,0 @@
name: Coverity Scan
on:
schedule:
- cron: '0 0 1 * *' # Monthly (1st day of month at midnight)
workflow_dispatch: # Mainly for testing. Don't forget the Coverity usage limits.
env:
LIBTORRENT_VERSION_TAG: v1.2.14
jobs:
coverity_scan:
name: Scan
runs-on: ubuntu-20.04
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install dependencies
run: |
sudo apt update
sudo apt install \
build-essential cmake git ninja-build pkg-config \
libssl-dev zlib1g-dev libboost-dev libboost-system-dev
# sudo apt install libqt5svg5-dev qtbase5-dev qttools5-dev # the Qt version in the standard repositories is too old...
# this will be installed under /opt/qt515. CMake will still find it automatically without additional hints
# to speed up the process, only the required components are installed rather than the full qt515-meta-full metapackage
- name: Install Qt
run: |
sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-focal
sudo apt install \
qt515base qt515svg qt515tools
- name: Install libtorrent
run: |
git clone https://github.com/arvidn/libtorrent
cd libtorrent
git checkout ${{ env.LIBTORRENT_VERSION_TAG }}
cmake \
-B build \
-G "Ninja" \
-DCMAKE_BUILD_TYPE=Release \
-Ddeprecated-functions=OFF
cmake --build build
sudo cmake --install build --prefix /usr/local
- name: Download Coverity Build Tool
run: |
wget \
-q \
https://scan.coverity.com/download/linux64 \
--post-data "token=$TOKEN&project=qbittorrent%2FqBittorrent" \
-O coverity_tool.tgz
mkdir coverity_tool
tar xzf coverity_tool.tgz --strip 1 -C coverity_tool
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
- name: Configure qBittorrent
run: |
cmake \
-B build \
-G "Ninja" \
-DCMAKE_BUILD_TYPE=Release \
-DGUI=ON \
-DVERBOSE_CONFIGURE=ON
- name: Build qBittorrent
run: |
export PATH="$(pwd)/coverity_tool/bin:$PATH"
cov-build --dir cov-int cmake --build build
- name: Submit the result to Coverity Scan
run: |
tar caf qbittorrent.xz cov-int
curl \
--form token=$TOKEN \
--form email=sledgehammer999@qbittorrent.org \
--form file=@qbittorrent.tgz \
--form version="$(git rev-parse --short HEAD)" \
--form description="master" \
https://scan.coverity.com/builds?project=qbittorrent%2FqBittorrent
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}

View File

@@ -1,22 +0,0 @@
name: Stale bot
on:
schedule:
- cron: '0 0 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- name: Mark and close stale PRs
uses: actions/stale@v4
with:
stale-pr-message: "This PR is stale because it has been 60 days with no activity. This PR will be automatically closed within 7 days if there is no further activity."
close-pr-message: "This PR was closed because it has been stalled for some time with no activity."
days-before-stale: -1 # avoid marking issues
days-before-pr-stale: 60
days-before-close: -1 # avoid closing issues
days-before-pr-close: 7
exempt-all-pr-assignees: true # avoid stale for all PR with assignees
exempt-all-pr-milestones: true # avoid stale for all PR with milestones
operations-per-run: 200

View File

@@ -12,10 +12,9 @@ project(qBittorrent
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
# version requirements - older versions may work, but you are on your own
set(minBoostVersion 1.65)
set(minQtVersion 5.15.2)
set(minQtVersion 5.11)
set(minOpenSSLVersion 1.1.1)
set(minLibtorrent1Version 1.2.14)
set(minLibtorrentVersion 2.0.4)
set(minLibtorrentVersion 1.2.12)
set(minZlibVersion 1.2.11)
# features (some are platform-specific)

168
Changelog
View File

@@ -1,6 +1,168 @@
Unreleased - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.4.0
- FEATURE: Add support for creating v2 torrents(requires libtorrent 2.0.x) (Chocobo1)
- FEATURE: Expose libtorrent hashing_threads settings (Anton Bershanskiy)
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)

14
INSTALL
View File

@@ -5,22 +5,20 @@ qBittorrent - A BitTorrent client in C++ / Qt
- Boost >= 1.65
- libtorrent-rasterbar 1.2.14 - 1.2.x || 2.0.4 - 2.0.x
* By Arvid Norberg, https://www.libtorrent.org/
- libtorrent-rasterbar >= 1.2.12 (by Arvid Norberg)
* https://www.libtorrent.org/
* Be careful: another library (the one used by rTorrent) uses a similar name
- OpenSSL >= 1.1.1
- Qt 5.15.2 - 5.x
- Qt >= 5.12
- zlib >= 1.2.11
- pkg-config *
* Compile-time only on *nix systems
- pkg-config (compile-time only on *nix systems)
- Python >= 3.5.0
* Optional, run-time only
* Used by the bundled search engine
- Python >= 3.5.0 (optional, runtime only)
* Required by the internal search engine
Dependency version numbers are bumped every once in a while to keep the range of properly tested configurations manageable, even if not strictly required to build.
You may be able to build with older versions of (some of) the dependencies other than the minimum versions specified in the build scripts, but support for such builds is not provided - you are on your own.

View File

@@ -17,7 +17,7 @@ macro(qbt_common_config)
)
target_compile_definitions(qbt_common_cfg INTERFACE
QT_DISABLE_DEPRECATED_BEFORE=0x050f02
QT_DEPRECATED_WARNINGS
QT_NO_CAST_TO_ASCII
QT_NO_CAST_FROM_BYTEARRAY
QT_USE_QSTRINGBUILDER
@@ -37,7 +37,7 @@ macro(qbt_common_config)
)
endif()
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
if ((CXX_COMPILER_ID STREQUAL "GNU") OR (CXX_COMPILER_ID STREQUAL "Clang") OR (CXX_COMPILER_ID STREQUAL "AppleClang"))
target_compile_options(qbt_common_cfg INTERFACE
-Wall
-Wextra
@@ -59,7 +59,7 @@ macro(qbt_common_config)
endif()
endif()
if ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
if ((CXX_COMPILER_ID STREQUAL "Clang") OR (CXX_COMPILER_ID STREQUAL "AppleClang"))
target_compile_options(qbt_common_cfg INTERFACE
-Wno-range-loop-analysis
)
@@ -79,8 +79,6 @@ macro(qbt_common_config)
target_compile_options(qbt_common_cfg INTERFACE
/guard:cf
/utf-8
# https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
/Zc:__cplusplus
)
target_link_options(qbt_common_cfg INTERFACE
/guard:cf
@@ -90,7 +88,4 @@ macro(qbt_common_config)
)
endif()
if (LibtorrentRasterbar_VERSION VERSION_GREATER_EQUAL ${minLibtorrentVersion})
target_compile_definitions(qbt_common_cfg INTERFACE QBT_USES_LIBTORRENT2)
endif()
endmacro(qbt_common_config)

View File

@@ -45,9 +45,6 @@ DEFINES += BOOST_SYSTEM_STATIC_LINK
# Enable if linking dynamically against libtorrent
#DEFINES += TORRENT_LINKING_SHARED
# Enable this if compiling with libtorrent 2.x
#DEFINES += QBT_USES_LIBTORRENT2
# Enable stack trace support
CONFIG += stacktrace

822
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
AC_INIT([qbittorrent], [v4.4.0alpha], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
AC_INIT([qbittorrent], [v4.3.9], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
: ${CFLAGS=""}
@@ -142,7 +141,7 @@ AS_IF([test "x$QT_QMAKE" = "x"],
[AC_MSG_ERROR([Could not find qmake])
])
AS_IF([test "x$enable_gui" = "xyes"],
[PKG_CHECK_MODULES(Qt5Svg, [Qt5Svg >= 5.15.2])
[PKG_CHECK_MODULES(Qt5Svg, [Qt5Svg >= 5.11])
])
AC_MSG_CHECKING([whether QtDBus should be enabled])
AS_CASE(["x$enable_qt_dbus"],
@@ -176,12 +175,14 @@ m4_define([DETECT_BOOST_VERSION_PROGRAM],
AC_COMPILE_IFELSE([DETECT_BOOST_VERSION_PROGRAM(106000)], [],
[QBT_ADD_DEFINES="$QBT_ADD_DEFINES BOOST_NO_CXX11_RVALUE_REFERENCES"])
AX_BOOST_SYSTEM()
AC_MSG_NOTICE([Boost.System LIB: "$BOOST_SYSTEM_LIB"])
LIBS="$BOOST_SYSTEM_LIB $LIBS"
PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 2.0.4],
[CXXFLAGS="$libtorrent_CFLAGS $CXXFLAGS" LIBS="$libtorrent_LIBS $LIBS" QBT_ADD_DEFINES="$QBT_ADD_DEFINES QBT_USES_LIBTORRENT2"],
[PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 1.2.14 libtorrent-rasterbar < 2],
[CXXFLAGS="$libtorrent_CFLAGS $CXXFLAGS" LIBS="$libtorrent_LIBS $LIBS"])])
[libtorrent-rasterbar >= 1.2.12],
[CXXFLAGS="$libtorrent_CFLAGS $CXXFLAGS"
LIBS="$libtorrent_LIBS $LIBS"])
PKG_CHECK_MODULES(openssl,
[openssl >= 1.1.1],
@@ -215,7 +216,7 @@ AS_IF([test "x$QBT_CXX17_FOUND" = "xno"],
CXXFLAGS="-std=c++17 $TMP_CXXFLAGS"
AC_COMPILE_IFELSE([DETECT_CPP17_PROGRAM()],
[AC_MSG_RESULT([no])
QBT_ADD_CONFIG="$QBT_ADD_CONFIG c++17"
QBT_ADD_CONFIG="$QBT_ADD_CONFIG c++1z"
AC_MSG_WARN([C++17 mode is now force enabled. The C++ mode should match the mode that other libraries were built with, otherwise you'll likely get linking errors.])],
[AC_MSG_RESULT([yes])
AC_MSG_ERROR([The compiler supports C++17 but the user or a dependency has explicitly enabled a lower mode.])])],

2
dist/mac/Info.plist vendored
View File

@@ -55,7 +55,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>4.4.0</string>
<string>4.3.9</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>

Binary file not shown.

Binary file not shown.

View File

@@ -30,6 +30,12 @@ install(FILES ${MAN_FILES}
)
if (GUI)
install(DIRECTORY menuicons/
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor
COMPONENT data
FILES_MATCHING PATTERN "*.png"
)
install(FILES org.qbittorrent.qBittorrent.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications/
COMPONENT data
@@ -40,11 +46,6 @@ if (GUI)
COMPONENT data
)
install(DIRECTORY menuicons/
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor
COMPONENT data
)
install(FILES
${PROJECT_SOURCE_DIR}/src/icons/qbittorrent-tray.svg
${PROJECT_SOURCE_DIR}/src/icons/qbittorrent-tray-dark.svg

View File

@@ -1,16 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">
<title>
qbittorrent-new-light
</title>
<defs>
<linearGradient x1="34.012%" y1="0%" x2="76.373%" y2="76.805%" id="a">
<stop stop-color="#72B4F5" offset="0%"/>
<stop stop-color="#356EBF" offset="100%"/>
</linearGradient>
</defs>
<g fill="none" fill-rule="evenodd">
<circle stroke="#DAEFFF" stroke-width="32" fill="url(#a)" cx="512" cy="512" r="496"/>
<path d="M712.898 332.399q66.657 0 103.38 45.671 37.03 45.364 37.03 128.684t-37.34 129.61q-37.03 45.98-103.07 45.98-33.02 0-60.484-12.035-27.156-12.344-45.672-37.649h-3.703l-10.8 43.512h-36.724V196h51.227v116.65q0 39.191-2.469 70.359h2.47q35.796-50.61 106.155-50.61zm-7.406 42.894q-52.46 0-75.605 30.242-23.145 29.934-23.145 101.219t23.762 102.145q23.761 30.55 76.222 30.55 47.215 0 70.36-34.254 23.144-34.562 23.144-99.058 0-66.04-23.144-98.442-23.145-32.402-71.594-32.402z" fill="#fff"/>
<path d="M317.273 639.45q51.227 0 74.68-27.466 23.453-27.464 24.996-92.578v-11.418q0-70.976-24.07-102.144-24.07-31.168-76.223-31.168-45.055 0-69.125 35.18-23.762 34.87-23.762 98.75 0 63.879 23.454 97.515 23.761 33.328 70.05 33.328zm-7.715 42.894q-65.421 0-102.144-45.98-36.723-45.981-36.723-128.376 0-83.011 37.032-129.609 37.03-46.598 103.07-46.598 69.433 0 106.773 52.461h2.778l7.406-46.289h40.426V828h-51.227V683.27q0-30.86 3.395-52.461h-4.012q-35.488 51.535-106.774 51.535z" fill="#c8e8ff"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -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.3.9" date="2021-10-31"/>
</releases>
</component>

View File

@@ -49,8 +49,8 @@ Name[da]=qBittorrent
Comment[de]=Über BitTorrent Dateien herunterladen und teilen
GenericName[de]=BitTorrent Client
Name[de]=qBittorrent
Comment[el]=Κάντε λήψη και ανταλλάξτε αρχεία μέσω BitTorrent
GenericName[el]=Πελάτης BitTorrent
Comment[el]=Κάντε λήψη και μοιραστείτε αρχεία μέσω BitTorrent
GenericName[el]=BitTorrent client
Name[el]=qBittorrent
Comment[en_GB]=Download and share files over BitTorrent
GenericName[en_GB]=BitTorrent client
@@ -70,7 +70,7 @@ Name[fa]=کیو بیت تورنت
Comment[fi]=Lataa ja jaa tiedostoja BitTorrentia käyttäen
GenericName[fi]=BitTorrent-asiakasohjelma
Name[fi]=qBittorrent
Comment[fr]=Télécharger et partager des fichiers avec BitTorrent
Comment[fr]=Letölteni és megosztani a dokumentumokat Bittorrenttel
GenericName[fr]=Client BitTorrent
Name[fr]=qBittorrent
Comment[gl]=Descargar e compartir ficheiros co protocolo BitTorrent
@@ -106,8 +106,8 @@ Name[ja]=qBittorrent
Comment[ka]=ჩამოტვირთე და გააზიარე ფაილები Bittorrent-ის საშუალებით
GenericName[ka]=BitTorrent კლიენტი
Name[ka]=qBittorrent
Comment[ko]=비트토렌트를 통해 파일을 받고 공유합니다
GenericName[ko]=비트토렌트 클라이언트
Comment[ko]=BitTorrent를 통해 파일 다운로드 및 공유
GenericName[ko]=BitTorrent 클라이언트
Name[ko]=qBittorrent
Comment[zh]=通过 BitTorrent 下载和分享文件
GenericName[zh]=BitTorrent 客户端
@@ -153,6 +153,7 @@ GenericName[sl]=BitTorrent odjemalec
Name[sl]=qBittorrent
Comment[sr]=Преузимајте и делите фајлове преко BitTorrent протокола
GenericName[sr]=BitTorrent-клијент
Name[sr]=qBittorrent
Comment[sr@latin]=Preuzimanje i deljenje fajlova preko BitTorrent-a
GenericName[sr@latin]=BitTorrent klijent
Name[sr@latin]=qBittorrent
@@ -192,6 +193,9 @@ 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
@@ -213,6 +217,6 @@ Name[te]=క్యు బిట్ టొరెంట్
Comment[pt_PT]=Transferir e partilhar ficheiros por BitTorrent
GenericName[pt_PT]=Cliente BitTorrent
Name[pt_PT]=qBittorrent
Comment[th]=ดาวน์โหลดและแชร์ไฟล์ด้วยบิททอเร้น
GenericName[th]=โปรแกรมบิททอเร้น
Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่าน BitTorrent
GenericName[th]=ไคลเอนต์ BitTorrent
Name[th]=qBittorrent

View File

@@ -1,60 +1,60 @@
;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_INDONESIAN} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_INDONESIAN} "qBittorrent (diperlukan)"
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
LangString inst_dekstop ${LANG_INDONESIAN} "Create Desktop Shortcut"
LangString inst_dekstop ${LANG_INDONESIAN} "Buat Pintasan Desktop"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_INDONESIAN} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_INDONESIAN} "Buat Pintasan Menu"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
LangString inst_startup ${LANG_INDONESIAN} "Start qBittorrent on Windows start up"
LangString inst_startup ${LANG_INDONESIAN} "Jalankan qBittorrent pada start up Windows"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_INDONESIAN} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_INDONESIAN} "Buka file .torrent dengan qBittorrent"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
LangString inst_magnet ${LANG_INDONESIAN} "Open magnet links with qBittorrent"
LangString inst_magnet ${LANG_INDONESIAN} "Buka link magnet dengan qBittorrent"
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_INDONESIAN} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_INDONESIAN} "Tambahkan aturan Windows Firewall"
;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_INDONESIAN} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
LangString inst_pathlimit ${LANG_INDONESIAN} "Matikan batasan panjang path Windows (limitasi MAX_PATH 260 karaker, membutuhkan Windows 10 1607 atau lebih baru)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_INDONESIAN} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_INDONESIAN} "Menambahkan aturan Windows Firewall"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_INDONESIAN} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_INDONESIAN} "qBittorrent berjalan. Mohon tutup aplikasi sebelum memasang."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_INDONESIAN} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_INDONESIAN} "Versi saat ini akan dicopot. Pengaturan pengguna dan torrent akan tetap utuh."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_INDONESIAN} "Uninstalling previous version."
LangString inst_unist ${LANG_INDONESIAN} "Mencopot versi sebelumnya."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
LangString launch_qbt ${LANG_INDONESIAN} "Launch qBittorrent."
LangString launch_qbt ${LANG_INDONESIAN} "Buka qBittorrent."
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_INDONESIAN} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_INDONESIAN} "Aplikasi ini hanya berjalan pada versi Windows 64-bit."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_INDONESIAN} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_INDONESIAN} "Versi qBittorrent ini membutuhkan setidaknya Windows 7."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_INDONESIAN} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_INDONESIAN} "Copot qBittorrent"
;------------------------------------
;Uninstaller strings
;LangString remove_files ${LANG_ENGLISH} "Remove files"
LangString remove_files ${LANG_INDONESIAN} "Remove files"
LangString remove_files ${LANG_INDONESIAN} "Hapus file"
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
LangString remove_shortcuts ${LANG_INDONESIAN} "Remove shortcuts"
LangString remove_shortcuts ${LANG_INDONESIAN} "Hapus pintasan"
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
LangString remove_associations ${LANG_INDONESIAN} "Remove file associations"
LangString remove_associations ${LANG_INDONESIAN} "Hapus asosiasi file"
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
LangString remove_registry ${LANG_INDONESIAN} "Remove registry keys"
LangString remove_registry ${LANG_INDONESIAN} "Hapus key registri"
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
LangString remove_conf ${LANG_INDONESIAN} "Remove configuration files"
LangString remove_conf ${LANG_INDONESIAN} "Hapus file konfigurasi"
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
LangString remove_firewall ${LANG_INDONESIAN} "Remove Windows Firewall rule"
LangString remove_firewall ${LANG_INDONESIAN} "Hapus aturan Windows Firewall"
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
LangString remove_firewallinfo ${LANG_INDONESIAN} "Removing Windows Firewall rule"
LangString remove_firewallinfo ${LANG_INDONESIAN} "Menghapus aturan Windows Firewall"
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
LangString remove_cache ${LANG_INDONESIAN} "Remove torrents and cached data"
LangString remove_cache ${LANG_INDONESIAN} "Hapus torrent dan data ter-cache"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_INDONESIAN} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_INDONESIAN} "qBittorrent berjalan. Mohon tutup aplikasi sebelum mencopot."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_INDONESIAN} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_INDONESIAN} "Tidak menghapus asosiasi .torrent. Terasosiasi dengan:"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
LangString uninst_mag_warn ${LANG_INDONESIAN} "Not removing magnet association. It is associated with:"
LangString uninst_mag_warn ${LANG_INDONESIAN} "Tidak menghapus asosiasi magnet. Terasosiasi dengan:"

View File

@@ -1,60 +1,60 @@
;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_KOREAN} "qBittorrent (required)"
LangString inst_qbt_req ${LANG_KOREAN} "qBittorrent (필요함)"
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
LangString inst_dekstop ${LANG_KOREAN} "Create Desktop Shortcut"
LangString inst_dekstop ${LANG_KOREAN} "바탕화면 바로가기 만들기"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_KOREAN} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_KOREAN} "시작 메뉴 바로가기 만들기"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
LangString inst_startup ${LANG_KOREAN} "Start qBittorrent on Windows start up"
LangString inst_startup ${LANG_KOREAN} "Windows 시작 시 qBittorrent 시작"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_KOREAN} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_KOREAN} "qBittorrent로 .torrent 파일 열기"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
LangString inst_magnet ${LANG_KOREAN} "Open magnet links with qBittorrent"
LangString inst_magnet ${LANG_KOREAN} "qBittorrent로 자석 링크 열기"
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_KOREAN} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_KOREAN} "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_KOREAN} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
LangString inst_pathlimit ${LANG_KOREAN} "Windows 경로 길이 제한 비활성화(260자 MAX_PATH 제한, Windows 10 1607 이상 필요)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_KOREAN} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_KOREAN} "Windows 방화벽 규칙 추가하는 중"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_KOREAN} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_KOREAN} "qBittorrent가 실행 중입니다. 설치하기 전에 응용 프로그램을 닫으십시오."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_KOREAN} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_KOREAN} "현재 버전이 삭제됩니다. 사용자 설정과 토렌트는 그대로 유지됩니다."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_KOREAN} "Uninstalling previous version."
LangString inst_unist ${LANG_KOREAN} "이전 버전을 삭제하는 중입니다."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
LangString launch_qbt ${LANG_KOREAN} "Launch qBittorrent."
LangString launch_qbt ${LANG_KOREAN} "qBittorrent를 실행합니다."
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_KOREAN} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_KOREAN} "이 설치 프로그램은 64비트 윈도우즈 버전에서만 작동합니다."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_KOREAN} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_KOREAN} " qBittorrent 버전에는 Windows 7 이상이 필요합니다."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_KOREAN} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_KOREAN} "qBittorrent 삭제"
;------------------------------------
;Uninstaller strings
;LangString remove_files ${LANG_ENGLISH} "Remove files"
LangString remove_files ${LANG_KOREAN} "Remove files"
LangString remove_files ${LANG_KOREAN} "파일 제거"
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
LangString remove_shortcuts ${LANG_KOREAN} "Remove shortcuts"
LangString remove_shortcuts ${LANG_KOREAN} "바로가기 제거"
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
LangString remove_associations ${LANG_KOREAN} "Remove file associations"
LangString remove_associations ${LANG_KOREAN} "파일 연결 제거"
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
LangString remove_registry ${LANG_KOREAN} "Remove registry keys"
LangString remove_registry ${LANG_KOREAN} "레지스트리 키 제거"
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
LangString remove_conf ${LANG_KOREAN} "Remove configuration files"
LangString remove_conf ${LANG_KOREAN} "구성 파일 제거"
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
LangString remove_firewall ${LANG_KOREAN} "Remove Windows Firewall rule"
LangString remove_firewall ${LANG_KOREAN} "Windows 방화벽 규칙 제거"
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
LangString remove_firewallinfo ${LANG_KOREAN} "Removing Windows Firewall rule"
LangString remove_firewallinfo ${LANG_KOREAN} "Windows 방화벽 규칙 제거하는 중"
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
LangString remove_cache ${LANG_KOREAN} "Remove torrents and cached data"
LangString remove_cache ${LANG_KOREAN} "토렌트 및 캐시된 데이터 제거"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_KOREAN} "qBittorrent is running. Please close the application before uninstalling."
LangString uninst_warning ${LANG_KOREAN} "qBittorrent가 실행 중입니다. 삭제하기 전에 응용 프로그램을 닫으십시오."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_KOREAN} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_KOREAN} ".torrent 연결을 제거하지 않습니다. 관련 항목:"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
LangString uninst_mag_warn ${LANG_KOREAN} "Not removing magnet association. It is associated with:"
LangString uninst_mag_warn ${LANG_KOREAN} "자석 연결을 제거하지 않습니다. 관련 항목:"

View File

@@ -15,21 +15,21 @@ LangString inst_magnet ${LANG_TRADCHINESE} "使用 qBittorrent 開啟 magnet 連
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_TRADCHINESE} "建立 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_TRADCHINESE} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
LangString inst_pathlimit ${LANG_TRADCHINESE} "停用 Windows 路徑長度限制 (MAX_PATH 260 字元限制,需 Windows 10 1607 以上版本)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_TRADCHINESE} "正在建立 Windows 防火牆規則"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
LangString inst_warning ${LANG_TRADCHINESE} "qBittorrent 正在執行中,請先關閉後再進行安裝。"
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_TRADCHINESE} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_TRADCHINESE} "目前版本將被解除安裝。使用者設定及 torrent 將保留。"
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
LangString inst_unist ${LANG_TRADCHINESE} "正在移除先前版本"
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
LangString launch_qbt ${LANG_TRADCHINESE} "啟動 qBittorrent"
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_TRADCHINESE} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_TRADCHINESE} "此安裝程式僅支援 64 位元版本的 Windows。"
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_TRADCHINESE} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_TRADCHINESE} " qBittorrent 版本僅支援 Windows 7 以上的系統。"
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_TRADCHINESE} "移除 qBittorrent"

View File

@@ -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.3.9"
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun

121
m4/ax_boost_system.m4 Normal file
View File

@@ -0,0 +1,121 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_boost_system.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_SYSTEM
#
# DESCRIPTION
#
# Test for System library from the Boost C++ libraries. The macro requires
# a preceding call to AX_BOOST_BASE. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_SYSTEM_LIB)
#
# And sets:
#
# HAVE_BOOST_SYSTEM
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
# Copyright (c) 2008 Michael Tindal
# Copyright (c) 2008 Daniel Casimiro <dan.casimiro@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 20
AC_DEFUN([AX_BOOST_SYSTEM],
[
AC_ARG_WITH([boost-system],
AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@],
[use the System library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-system=boost_system-gcc-mt ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_system_lib=""
else
want_boost="yes"
ax_boost_user_system_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_BUILD])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::System library is available,
ax_cv_boost_system,
[AC_LANG_PUSH([C++])
CXXFLAGS_SAVE=$CXXFLAGS
CXXFLAGS=
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
[[boost::system::error_category *a = 0;]])],
ax_cv_boost_system=yes, ax_cv_boost_system=no)
CXXFLAGS=$CXXFLAGS_SAVE
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_system" = "xyes"; then
AC_SUBST(BOOST_CPPFLAGS)
AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
LDFLAGS_SAVE=$LDFLAGS
if test "x$ax_boost_user_system_lib" = "x"; then
for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
if test "x$link_system" != "xyes"; then
for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
fi
else
for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the Boost::System library!)
fi
if test "x$link_system" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])

215
m4/pkg.m4
View File

@@ -1,60 +1,29 @@
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 12 (pkg-config-0.29.2)
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
#
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
dnl 02111-1307, USA.
dnl
dnl As a special exception to the GNU General Public License, if you
dnl distribute this file as part of a program that contains a
dnl configuration script generated by Autoconf, you may include it under
dnl the same distribution terms that you use for the rest of that
dnl program.
dnl PKG_PREREQ(MIN-VERSION)
dnl -----------------------
dnl Since: 0.29
dnl
dnl Verify that the version of the pkg-config macros are at least
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
dnl installed version of pkg-config, this checks the developer's version
dnl of pkg.m4 when generating configure.
dnl
dnl To ensure that this macro is defined, also add:
dnl m4_ifndef([PKG_PREREQ],
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29.2])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
dnl ----------------------------------
dnl Since: 0.16
dnl
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
dnl first found in the path. Checks that the version of pkg-config found
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
dnl used since that's the first version where most current features of
dnl pkg-config existed.
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
# ----------------------------------
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
@@ -76,19 +45,18 @@ if test -n "$PKG_CONFIG"; then
PKG_CONFIG=""
fi
fi[]dnl
])dnl PKG_PROG_PKG_CONFIG
])# PKG_PROG_PKG_CONFIG
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------------------------------
dnl Since: 0.18
dnl
dnl Check to see whether a particular set of modules exists. Similar to
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
dnl
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
dnl only at the first occurence in configure.ac, so if the first place
dnl it's called might be skipped (such as if it is within an "if", you
dnl have to call PKG_CHECK_EXISTS manually
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# Check to see whether a particular set of modules exists. Similar
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
# only at the first occurence in configure.ac, so if the first place
# it's called might be skipped (such as if it is within an "if", you
# have to call PKG_CHECK_EXISTS manually
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
@@ -98,10 +66,8 @@ m4_ifvaln([$3], [else
$3])dnl
fi])
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
dnl ---------------------------------------------
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
dnl pkg_failed based on the result.
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
# ---------------------------------------------
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
@@ -113,11 +79,10 @@ m4_define([_PKG_CONFIG],
else
pkg_failed=untried
fi[]dnl
])dnl _PKG_CONFIG
])# _PKG_CONFIG
dnl _PKG_SHORT_ERRORS_SUPPORTED
dnl ---------------------------
dnl Internal check to see if pkg-config supports short errors.
# _PKG_SHORT_ERRORS_SUPPORTED
# -----------------------------
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -125,24 +90,26 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
else
_pkg_short_errors_supported=no
fi[]dnl
])dnl _PKG_SHORT_ERRORS_SUPPORTED
])# _PKG_SHORT_ERRORS_SUPPORTED
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl --------------------------------------------------------------
dnl Since: 0.4.0
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
#
#
# Note that if there is a possibility the first call to
# PKG_CHECK_MODULES might not happen, you should be sure to include an
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
#
#
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $2])
AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
@@ -152,7 +119,7 @@ and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
@@ -173,7 +140,7 @@ installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
@@ -189,40 +156,16 @@ else
AC_MSG_RESULT([yes])
$3
fi[]dnl
])dnl PKG_CHECK_MODULES
])# PKG_CHECK_MODULES
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl ---------------------------------------------------------------------
dnl Since: 0.29
dnl
dnl Checks for existence of MODULES and gathers its build flags with
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
dnl and VARIABLE-PREFIX_LIBS from --libs.
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
dnl configure.ac.
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
_save_PKG_CONFIG=$PKG_CONFIG
PKG_CONFIG="$PKG_CONFIG --static"
PKG_CHECK_MODULES($@)
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
])dnl PKG_CHECK_MODULES_STATIC
dnl PKG_INSTALLDIR([DIRECTORY])
dnl -------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable pkgconfigdir as the location where a module
dnl should install pkg-config .pc files. By default the directory is
dnl $libdir/pkgconfig, but the default can be changed by passing
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
dnl parameter.
# PKG_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable pkgconfigdir as the location where a module
# should install pkg-config .pc files. By default the directory is
# $libdir/pkgconfig, but the default can be changed by passing
# DIRECTORY. The user can override through the --with-pkgconfigdir
# parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
@@ -233,18 +176,16 @@ AC_ARG_WITH([pkgconfigdir],
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
])dnl PKG_INSTALLDIR
]) dnl PKG_INSTALLDIR
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
dnl --------------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
dnl module should install arch-independent pkg-config .pc files. By
dnl default the directory is $datadir/pkgconfig, but the default can be
dnl changed by passing DIRECTORY. The user can override through the
dnl --with-noarch-pkgconfigdir parameter.
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable noarch_pkgconfigdir as the location where a
# module should install arch-independent pkg-config .pc files. By
# default the directory is $datadir/pkgconfig, but the default can be
# changed by passing DIRECTORY. The user can override through the
# --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
@@ -255,15 +196,13 @@ AC_ARG_WITH([noarch-pkgconfigdir],
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
])dnl PKG_NOARCH_INSTALLDIR
]) dnl PKG_NOARCH_INSTALLDIR
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------
dnl Since: 0.28
dnl
dnl Retrieves the value of the pkg-config variable for the given module.
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------------------------------------
# Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
@@ -272,4 +211,4 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])dnl PKG_CHECK_VAR
])# PKG_CHECK_VAR

View File

@@ -5,9 +5,9 @@
# Sets the QT_QMAKE variable to the path of Qt5 qmake if found.
# --------------------------------------
AC_DEFUN([FIND_QT5],
[PKG_CHECK_EXISTS([Qt5Core >= 5.15.2],
[PKG_CHECK_EXISTS([Qt5Core >= 5.11],
[PKG_CHECK_VAR(QT_QMAKE,
[Qt5Core >= 5.15.2],
[Qt5Core >= 5.11],
[host_bins])
])
@@ -18,7 +18,7 @@ AS_IF([test -f "$QT_QMAKE/qmake"],
[QT_QMAKE=""])
])
AC_MSG_CHECKING([for Qt5 qmake >= 5.15.2])
AC_MSG_CHECKING([for Qt5 qmake >= 5.11])
AS_IF([test "x$QT_QMAKE" != "x"],
[AC_MSG_RESULT([$QT_QMAKE])],
[AC_MSG_RESULT([not found])]
@@ -29,8 +29,8 @@ AS_IF([test "x$QT_QMAKE" != "x"],
# Sets the HAVE_QTDBUS variable to true or false.
# --------------------------------------
AC_DEFUN([FIND_QTDBUS],
[AC_MSG_CHECKING([for Qt5DBus >= 5.15.2])
PKG_CHECK_EXISTS([Qt5DBus >= 5.15.2],
[AC_MSG_CHECKING([for Qt5DBus >= 5.11])
PKG_CHECK_EXISTS([Qt5DBus >= 5.11],
[AC_MSG_RESULT([found])
HAVE_QTDBUS=[true]],
[AC_MSG_RESULT([not found])

View File

@@ -1,49 +1,41 @@
macro(find_libtorrent version)
if (UNIX AND (NOT APPLE) AND (NOT CYGWIN))
find_package(LibtorrentRasterbar QUIET ${version} COMPONENTS torrent-rasterbar)
if (NOT LibtorrentRasterbar_FOUND)
include(FindPkgConfig)
pkg_check_modules(LibtorrentRasterbar IMPORTED_TARGET GLOBAL "libtorrent-rasterbar>=${version}")
if (NOT LibtorrentRasterbar_FOUND)
message(
FATAL_ERROR
"Package LibtorrentRasterbar >= ${version} not found"
" with CMake or pkg-config.\n- Set LibtorrentRasterbar_DIR to a directory containing"
" a LibtorrentRasterbarConfig.cmake file or add the installation prefix of LibtorrentRasterbar"
" to CMAKE_PREFIX_PATH.\n- Alternatively, make sure there is a valid libtorrent-rasterbar.pc"
" file in your system's pkg-config search paths (use the system environment variable PKG_CONFIG_PATH"
" to specify additional search paths if needed)."
)
endif()
add_library(LibtorrentRasterbar::torrent-rasterbar ALIAS PkgConfig::LibtorrentRasterbar)
# force a fake package to show up in the feature summary
set_property(GLOBAL APPEND PROPERTY
PACKAGES_FOUND
"LibtorrentRasterbar via pkg-config (version >= ${version})"
if (UNIX AND (NOT APPLE) AND (NOT CYGWIN))
find_package(LibtorrentRasterbar QUIET ${minLibtorrentVersion} COMPONENTS torrent-rasterbar)
if (NOT LibtorrentRasterbar_FOUND)
include(FindPkgConfig)
pkg_check_modules(LIBTORRENT_RASTERBAR IMPORTED_TARGET GLOBAL "libtorrent-rasterbar>=${minLibtorrentVersion}")
if (NOT LIBTORRENT_RASTERBAR_FOUND)
message(
FATAL_ERROR
"Package LibtorrentRasterbar >= ${minLibtorrentVersion} not found"
" with CMake or pkg-config.\n- Set LibtorrentRasterbar_DIR to a directory containing"
" a LibtorrentRasterbarConfig.cmake file or add the installation prefix of LibtorrentRasterbar"
" to CMAKE_PREFIX_PATH.\n- Alternatively, make sure there is a valid libtorrent-rasterbar.pc"
" file in your system's pkg-config search paths (use the system environment variable PKG_CONFIG_PATH"
" to specify additional search paths if needed)."
)
set_package_properties("LibtorrentRasterbar via pkg-config (version >= ${version})"
PROPERTIES
TYPE REQUIRED
)
else()
set_package_properties(LibtorrentRasterbar PROPERTIES TYPE REQUIRED)
endif()
add_library(LibtorrentRasterbar::torrent-rasterbar ALIAS PkgConfig::LIBTORRENT_RASTERBAR)
# force a fake package to show up in the feature summary
set_property(GLOBAL APPEND PROPERTY
PACKAGES_FOUND
"LibtorrentRasterbar via pkg-config (version >= ${minLibtorrentVersion})"
)
set_package_properties("LibtorrentRasterbar via pkg-config (version >= ${minLibtorrentVersion})"
PROPERTIES
TYPE REQUIRED
)
else()
find_package(LibtorrentRasterbar ${version} REQUIRED COMPONENTS torrent-rasterbar)
set_package_properties(LibtorrentRasterbar PROPERTIES TYPE REQUIRED)
endif()
endmacro()
find_libtorrent(${minLibtorrent1Version})
if (LibtorrentRasterbar_FOUND AND (LibtorrentRasterbar_VERSION VERSION_GREATER_EQUAL 2.0))
find_libtorrent(${minLibtorrentVersion})
else()
find_package(LibtorrentRasterbar ${minLibtorrentVersion} REQUIRED COMPONENTS torrent-rasterbar)
endif()
# force variable type so that it always shows up in ccmake/cmake-gui frontends
set_property(CACHE LibtorrentRasterbar_DIR PROPERTY TYPE PATH)
find_package(Boost ${minBoostVersion} REQUIRED)
find_package(OpenSSL ${minOpenSSLVersion} REQUIRED)
find_package(ZLIB ${minZlibVersion} REQUIRED)
find_package(Qt5 ${minQtVersion} REQUIRED COMPONENTS Core Network Sql Xml LinguistTools)
find_package(Qt5 ${minQtVersion} REQUIRED COMPONENTS Core Network Xml LinguistTools)
if (DBUS)
find_package(Qt5 ${minQtVersion} REQUIRED COMPONENTS DBus)
set_package_properties(Qt5DBus PROPERTIES
@@ -69,7 +61,9 @@ add_subdirectory(base)
if (GUI)
find_package(Qt5 ${minQtVersion} REQUIRED COMPONENTS Widgets Svg)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
find_package(Qt5 ${minQtVersion} REQUIRED COMPONENTS MacExtras)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
find_package(Qt5 ${minQtVersion} REQUIRED COMPONENTS WinExtras)
endif()
add_subdirectory(gui)

View File

@@ -4,14 +4,22 @@
# Based on https://gist.github.com/giraldeau/546ba5512a74dfe9d8ea0862d66db412
file(GLOB QBT_TS_FILES "${qBittorrent_SOURCE_DIR}/src/lang/*.ts")
set_source_files_properties(${QBT_TS_FILES} PROPERTIES OUTPUT_LOCATION "${qBittorrent_BINARY_DIR}/src/lang")
qt5_add_translation(QBT_QM_FILES ${QBT_TS_FILES} OPTIONS -silent)
if (Qt5_VERSION VERSION_LESS 5.12)
qt5_add_translation(QBT_QM_FILES ${QBT_TS_FILES})
else()
qt5_add_translation(QBT_QM_FILES ${QBT_TS_FILES} OPTIONS -silent)
endif()
configure_file("${qBittorrent_SOURCE_DIR}/src/lang/lang.qrc" "${qBittorrent_BINARY_DIR}/src/lang/lang.qrc" COPYONLY)
if (WEBUI)
file(GLOB QBT_WEBUI_TS_FILES "${qBittorrent_SOURCE_DIR}/src/webui/www/translations/*.ts")
set_source_files_properties(${QBT_WEBUI_TS_FILES}
PROPERTIES OUTPUT_LOCATION "${qBittorrent_BINARY_DIR}/src/webui/www/translations")
qt5_add_translation(QBT_WEBUI_QM_FILES ${QBT_WEBUI_TS_FILES} OPTIONS -silent)
if (Qt5_VERSION VERSION_LESS 5.12)
qt5_add_translation(QBT_WEBUI_QM_FILES ${QBT_WEBUI_TS_FILES})
else()
qt5_add_translation(QBT_WEBUI_QM_FILES ${QBT_WEBUI_TS_FILES} OPTIONS -silent)
endif()
configure_file("${qBittorrent_SOURCE_DIR}/src/webui/www/translations/webui_translations.qrc"
"${qBittorrent_BINARY_DIR}/src/webui/www/translations/webui_translations.qrc" COPYONLY)
endif()
@@ -139,7 +147,11 @@ endif()
if (GUI)
target_link_libraries(qbt_app PRIVATE qbt_gui)
if ((CMAKE_SYSTEM_NAME STREQUAL "Windows") OR (CMAKE_SYSTEM_NAME STREQUAL "Darwin"))
qt_import_plugins(qbt_app INCLUDE Qt5::QSvgIconPlugin Qt5::QSvgPlugin)
if (Qt5_VERSION VERSION_LESS 5.14)
set_property(TARGET qbt_app APPEND PROPERTY QT_PLUGINS Qt5::QSvgIconPlugin Qt5::QSvgPlugin)
else()
qt_import_plugins(qbt_app INCLUDE Qt5::QSvgIconPlugin Qt5::QSvgPlugin)
endif()
endif()
endif()

View File

@@ -78,9 +78,9 @@
#include "base/search/searchpluginmanager.h"
#include "base/settingsstorage.h"
#include "base/torrentfileswatcher.h"
#include "base/utils/compare.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h"
#include "base/version.h"
#include "applicationinstancemanager.h"
#include "filelogger.h"
@@ -302,7 +302,7 @@ void Application::setFileLoggerAgeType(const int value)
void Application::processMessage(const QString &message)
{
const QStringList params = message.split(PARAMS_SEPARATOR, Qt::SkipEmptyParts);
const QStringList params = message.split(PARAMS_SEPARATOR, QString::SkipEmptyParts);
// If Application is not running (i.e., other
// components are not ready) store params
if (m_running)
@@ -350,15 +350,13 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const
#endif
break;
case u'G':
program.replace(i, 2, torrent->tags().join(QLatin1String(",")));
{
QStringList tags = torrent->tags().values();
std::sort(tags.begin(), tags.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
program.replace(i, 2, tags.join(','));
}
break;
case u'I':
program.replace(i, 2, (torrent->infoHash().v1().isValid() ? torrent->infoHash().v1().toString() : QLatin1String("-")));
break;
case u'J':
program.replace(i, 2, (torrent->infoHash().v2().isValid() ? torrent->infoHash().v2().toString() : QLatin1String("-")));
break;
case u'K':
program.replace(i, 2, torrent->id().toString());
break;
case u'L':
@@ -435,12 +433,16 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const
// enable command injection via torrent name and other arguments
// (especially when some automated download mechanism has been setup).
// See: https://github.com/qbittorrent/qBittorrent/issues/10925
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QStringList args = QProcess::splitCommand(program);
if (args.isEmpty())
return;
const QString command = args.takeFirst();
QProcess::startDetached(command, args);
#else
QProcess::startDetached(program);
#endif
#endif
}
@@ -561,7 +563,7 @@ void Application::processParams(const QStringList &params)
if (param.startsWith(QLatin1String("@addPaused=")))
{
torrentParams.addPaused = (QStringView(param).mid(11).toInt() != 0);
torrentParams.addPaused = (param.midRef(11).toInt() != 0);
continue;
}
@@ -591,7 +593,7 @@ void Application::processParams(const QStringList &params)
if (param.startsWith(QLatin1String("@skipDialog=")))
{
skipTorrentDialog = (QStringView(param).mid(12).toInt() != 0);
skipTorrentDialog = (param.midRef(12).toInt() != 0);
continue;
}

View File

@@ -71,7 +71,7 @@ namespace RSS
class Application final : public BaseApplication
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Application)
Q_DISABLE_COPY(Application)
public:
Application(int &argc, char **argv);

View File

@@ -35,7 +35,7 @@ class QtLocalPeer;
class ApplicationInstanceManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(ApplicationInstanceManager)
Q_DISABLE_COPY(ApplicationInstanceManager)
public:
explicit ApplicationInstanceManager(const QString &appId, QObject *parent = nullptr);

View File

@@ -126,9 +126,7 @@ void FileLogger::addLogMessage(const Log::Msg &msg)
if (!m_logFile.isOpen()) return;
QTextStream stream(&m_logFile);
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
stream.setCodec("UTF-8");
#endif
switch (msg.type)
{

View File

@@ -40,7 +40,7 @@ namespace Log
class FileLogger : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(FileLogger)
Q_DISABLE_COPY(FileLogger)
public:
enum FileLogAgeType

View File

@@ -134,7 +134,7 @@ int main(int argc, char *argv[])
// We must save it here because QApplication constructor may change it
bool isOneArg = (argc == 2);
#if !defined(DISABLE_GUI)
#if !defined(DISABLE_GUI) && (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
// Attribute Qt::AA_EnableHighDpiScaling must be set before QCoreApplication is created
if (qgetenv("QT_ENABLE_HIGHDPI_SCALING").isEmpty() && qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR").isEmpty())
Application::setAttribute(Qt::AA_EnableHighDpiScaling, true);
@@ -235,7 +235,7 @@ int main(int argc, char *argv[])
// 3. https://bugreports.qt.io/browse/QTBUG-46015
qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && !defined(DISABLE_GUI)
#if !defined(DISABLE_GUI)
// this is the default in Qt6
app->setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif

View File

@@ -79,7 +79,6 @@
#include <QDir>
#include <QLocalServer>
#include <QLocalSocket>
#include <QRegularExpression>
#include "base/utils/misc.h"
@@ -109,7 +108,7 @@ QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
#endif
prefix = id.section(QLatin1Char('/'), -1);
}
prefix.remove(QRegularExpression("[^a-zA-Z]"));
prefix.remove(QRegExp("[^a-zA-Z]"));
prefix.truncate(6);
QByteArray idc = id.toUtf8();

View File

@@ -89,7 +89,7 @@ Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
Qt::HANDLE mutex;
if (doCreate) {
QT_WA( { mutex = CreateMutexW(NULL, FALSE, reinterpret_cast<const TCHAR *>(mname.utf16())); },
QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
@@ -97,7 +97,7 @@ Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
}
}
else {
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, reinterpret_cast<const TCHAR *>(mname.utf16())); },
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
if (GetLastError() != ERROR_FILE_NOT_FOUND)

View File

@@ -73,7 +73,7 @@ void straceWin::loadHelpStackFrame(IMAGEHLP_STACK_FRAME& ihsf, const STACKFRAME6
BOOL CALLBACK straceWin::EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user)
{
Q_UNUSED(size)
auto params = static_cast<QStringList *>(user);
QStringList* params = (QStringList*)user;
if (symInfo->Flags & SYMFLAG_PARAMETER)
params->append(symInfo->Name);
return TRUE;
@@ -91,7 +91,7 @@ BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVO
{
Q_UNUSED(ModuleName)
IMAGEHLP_MODULE64 mod;
auto context = static_cast<EnumModulesContext *>(UserContext);
EnumModulesContext* context = (EnumModulesContext*)UserContext;
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod))
{
@@ -264,7 +264,7 @@ const QString straceWin::getBacktrace()
ULONG64 buffer[(sizeof(SYMBOL_INFO) +
MAX_SYM_NAME * sizeof(TCHAR) +
sizeof(ULONG64) - 1) / sizeof(ULONG64)];
auto pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;

View File

@@ -39,7 +39,7 @@ namespace Ui
class StacktraceDialog : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(StacktraceDialog)
Q_DISABLE_COPY(StacktraceDialog)
public:
explicit StacktraceDialog(QWidget *parent = nullptr);

View File

@@ -102,28 +102,12 @@ namespace
settingsStorage->storeValue(newKey, Utils::String::fromEnum(torrentContentLayout));
settingsStorage->removeValue(oldKey);
}
void upgradeListenPortSettings()
{
const auto oldKey = QString::fromLatin1("BitTorrent/Session/UseRandomPort");
const auto newKey = QString::fromLatin1("Preferences/Connection/PortRangeMin");
auto *settingsStorage = SettingsStorage::instance();
if (settingsStorage->hasKey(oldKey))
{
if (settingsStorage->loadValue<bool>(oldKey))
settingsStorage->storeValue(newKey, 0);
settingsStorage->removeValue(oldKey);
}
}
}
bool upgrade(const bool /*ask*/)
{
exportWebUIHttpsFiles();
upgradeTorrentContentLayout();
upgradeListenPortSettings();
return true;
}

View File

@@ -5,16 +5,13 @@ add_library(qbt_base STATIC
bittorrent/abstractfilestorage.h
bittorrent/addtorrentparams.h
bittorrent/bandwidthscheduler.h
bittorrent/bencoderesumedatastorage.h
bittorrent/cachestatus.h
bittorrent/common.h
bittorrent/customstorage.h
bittorrent/dbresumedatastorage.h
bittorrent/downloadpriority.h
bittorrent/filesearcher.h
bittorrent/filterparserthread.h
bittorrent/infohash.h
bittorrent/loadtorrentparams.h
bittorrent/ltqhash.h
bittorrent/ltunderlyingtype.h
bittorrent/magneturi.h
@@ -23,7 +20,7 @@ add_library(qbt_base STATIC
bittorrent/peeraddress.h
bittorrent/peerinfo.h
bittorrent/portforwarderimpl.h
bittorrent/resumedatastorage.h
bittorrent/resumedatasavingmanager.h
bittorrent/session.h
bittorrent/sessionstatus.h
bittorrent/speedmonitor.h
@@ -58,7 +55,6 @@ add_library(qbt_base STATIC
net/proxyconfigurationmanager.h
net/reverseresolution.h
net/smtp.h
orderedset.h
preferences.h
profile.h
profile_p.h
@@ -74,14 +70,12 @@ add_library(qbt_base STATIC
search/searchhandler.h
search/searchpluginmanager.h
settingsstorage.h
tagset.h
torrentfileguard.h
torrentfileswatcher.h
torrentfilter.h
types.h
unicodestrings.h
utils/bytearray.h
utils/compare.h
utils/foreignapps.h
utils/fs.h
utils/gzip.h
@@ -98,9 +92,7 @@ add_library(qbt_base STATIC
asyncfilestorage.cpp
bittorrent/abstractfilestorage.cpp
bittorrent/bandwidthscheduler.cpp
bittorrent/bencoderesumedatastorage.cpp
bittorrent/customstorage.cpp
bittorrent/dbresumedatastorage.cpp
bittorrent/downloadpriority.cpp
bittorrent/filesearcher.cpp
bittorrent/filterparserthread.cpp
@@ -111,6 +103,7 @@ add_library(qbt_base STATIC
bittorrent/peeraddress.cpp
bittorrent/peerinfo.cpp
bittorrent/portforwarderimpl.cpp
bittorrent/resumedatasavingmanager.cpp
bittorrent/session.cpp
bittorrent/speedmonitor.cpp
bittorrent/statistics.cpp
@@ -153,12 +146,10 @@ add_library(qbt_base STATIC
search/searchhandler.cpp
search/searchpluginmanager.cpp
settingsstorage.cpp
tagset.cpp
torrentfileguard.cpp
torrentfileswatcher.cpp
torrentfilter.cpp
utils/bytearray.cpp
utils/compare.cpp
utils/foreignapps.cpp
utils/fs.cpp
utils/gzip.cpp
@@ -176,7 +167,7 @@ target_link_libraries(qbt_base
ZLIB::ZLIB
PUBLIC
LibtorrentRasterbar::torrent-rasterbar
Qt5::Core Qt5::Network Qt5::Sql Qt5::Xml
Qt5::Core Qt5::Network Qt5::Xml
qbt_common_cfg
)

View File

@@ -44,7 +44,7 @@ namespace Algorithm
{
};
// To be used with associative array types, such as QMap, QHash and its variants
// To be used with associative array types, such as QMap, QHash and it's variants
template <typename T, typename BinaryPredicate
, typename std::enable_if_t<HasMappedType<T>::value, int> = 0>
void removeIf(T &dict, BinaryPredicate &&p)

View File

@@ -43,7 +43,7 @@ public:
class AsyncFileStorage : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(AsyncFileStorage)
Q_DISABLE_COPY(AsyncFileStorage)
public:
explicit AsyncFileStorage(const QString &storageFolderPath, QObject *parent = nullptr);

View File

@@ -4,16 +4,13 @@ HEADERS += \
$$PWD/bittorrent/abstractfilestorage.h \
$$PWD/bittorrent/addtorrentparams.h \
$$PWD/bittorrent/bandwidthscheduler.h \
$$PWD/bittorrent/bencoderesumedatastorage.h \
$$PWD/bittorrent/cachestatus.h \
$$PWD/bittorrent/common.h \
$$PWD/bittorrent/customstorage.h \
$$PWD/bittorrent/downloadpriority.h \
$$PWD/bittorrent/dbresumedatastorage.h \
$$PWD/bittorrent/filesearcher.h \
$$PWD/bittorrent/filterparserthread.h \
$$PWD/bittorrent/infohash.h \
$$PWD/bittorrent/loadtorrentparams.h \
$$PWD/bittorrent/ltqhash.h \
$$PWD/bittorrent/ltunderlyingtype.h \
$$PWD/bittorrent/magneturi.h \
@@ -22,7 +19,7 @@ HEADERS += \
$$PWD/bittorrent/peeraddress.h \
$$PWD/bittorrent/peerinfo.h \
$$PWD/bittorrent/portforwarderimpl.h \
$$PWD/bittorrent/resumedatastorage.h \
$$PWD/bittorrent/resumedatasavingmanager.h \
$$PWD/bittorrent/session.h \
$$PWD/bittorrent/sessionstatus.h \
$$PWD/bittorrent/speedmonitor.h \
@@ -57,7 +54,6 @@ HEADERS += \
$$PWD/net/proxyconfigurationmanager.h \
$$PWD/net/reverseresolution.h \
$$PWD/net/smtp.h \
$$PWD/orderedset.h \
$$PWD/preferences.h \
$$PWD/profile.h \
$$PWD/profile_p.h \
@@ -74,14 +70,12 @@ HEADERS += \
$$PWD/search/searchpluginmanager.h \
$$PWD/settingsstorage.h \
$$PWD/settingvalue.h \
$$PWD/tagset.h \
$$PWD/torrentfileguard.h \
$$PWD/torrentfileswatcher.h \
$$PWD/torrentfilter.h \
$$PWD/types.h \
$$PWD/unicodestrings.h \
$$PWD/utils/bytearray.h \
$$PWD/utils/compare.h \
$$PWD/utils/foreignapps.h \
$$PWD/utils/fs.h \
$$PWD/utils/gzip.h \
@@ -98,9 +92,7 @@ SOURCES += \
$$PWD/asyncfilestorage.cpp \
$$PWD/bittorrent/abstractfilestorage.cpp \
$$PWD/bittorrent/bandwidthscheduler.cpp \
$$PWD/bittorrent/bencoderesumedatastorage.cpp \
$$PWD/bittorrent/customstorage.cpp \
$$PWD/bittorrent/dbresumedatastorage.cpp \
$$PWD/bittorrent/downloadpriority.cpp \
$$PWD/bittorrent/filesearcher.cpp \
$$PWD/bittorrent/filterparserthread.cpp \
@@ -111,6 +103,7 @@ SOURCES += \
$$PWD/bittorrent/peeraddress.cpp \
$$PWD/bittorrent/peerinfo.cpp \
$$PWD/bittorrent/portforwarderimpl.cpp \
$$PWD/bittorrent/resumedatasavingmanager.cpp \
$$PWD/bittorrent/session.cpp \
$$PWD/bittorrent/speedmonitor.cpp \
$$PWD/bittorrent/statistics.cpp \
@@ -153,12 +146,10 @@ SOURCES += \
$$PWD/search/searchhandler.cpp \
$$PWD/search/searchpluginmanager.cpp \
$$PWD/settingsstorage.cpp \
$$PWD/tagset.cpp \
$$PWD/torrentfileguard.cpp \
$$PWD/torrentfileswatcher.cpp \
$$PWD/torrentfilter.cpp \
$$PWD/utils/bytearray.cpp \
$$PWD/utils/compare.cpp \
$$PWD/utils/foreignapps.cpp \
$$PWD/utils/fs.cpp \
$$PWD/utils/gzip.cpp \

View File

@@ -31,10 +31,10 @@
#include <optional>
#include <QMetaType>
#include <QSet>
#include <QString>
#include <QVector>
#include "base/tagset.h"
#include "torrent.h"
#include "torrentcontentlayout.h"
@@ -46,7 +46,7 @@ namespace BitTorrent
{
QString name;
QString category;
TagSet tags;
QSet<QString> tags;
QString savePath;
bool disableTempPath = false; // e.g. for imported torrents
bool sequential = false;

View File

@@ -35,7 +35,7 @@
class BandwidthScheduler : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(BandwidthScheduler)
Q_DISABLE_COPY(BandwidthScheduler)
public:
explicit BandwidthScheduler(QObject *parent = nullptr);

View File

@@ -1,415 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015, 2018 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 "bencoderesumedatastorage.h"
#include <libtorrent/bdecode.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/read_resume_data.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/write_resume_data.hpp>
#include <QByteArray>
#include <QRegularExpression>
#include <QSaveFile>
#include <QThread>
#include "base/algorithm.h"
#include "base/exceptions.h"
#include "base/global.h"
#include "base/logger.h"
#include "base/profile.h"
#include "base/tagset.h"
#include "base/utils/fs.h"
#include "base/utils/io.h"
#include "base/utils/string.h"
#include "infohash.h"
#include "loadtorrentparams.h"
namespace BitTorrent
{
class BencodeResumeDataStorage::Worker final : public QObject
{
Q_DISABLE_COPY_MOVE(Worker)
public:
explicit Worker(const QDir &resumeDataDir);
void store(const TorrentID &id, const LoadTorrentParams &resumeData) const;
void remove(const TorrentID &id) const;
void storeQueue(const QVector<TorrentID> &queue) const;
private:
const QDir m_resumeDataDir;
};
}
namespace
{
template <typename LTStr>
QString fromLTString(const LTStr &str)
{
return QString::fromUtf8(str.data(), static_cast<int>(str.size()));
}
using ListType = lt::entry::list_type;
ListType setToEntryList(const TagSet &input)
{
ListType entryList;
entryList.reserve(input.size());
for (const QString &setValue : input)
entryList.emplace_back(setValue.toStdString());
return entryList;
}
void writeEntryToFile(const QString &filepath, const lt::entry &data)
{
QSaveFile file {filepath};
if (!file.open(QIODevice::WriteOnly))
throw RuntimeError(file.errorString());
lt::bencode(Utils::IO::FileDeviceOutputIterator {file}, data);
if (file.error() != QFileDevice::NoError || !file.commit())
throw RuntimeError(file.errorString());
}
}
BitTorrent::BencodeResumeDataStorage::BencodeResumeDataStorage(const QString &path, QObject *parent)
: ResumeDataStorage {parent}
, m_resumeDataDir {path}
, m_ioThread {new QThread {this}}
, m_asyncWorker {new Worker {m_resumeDataDir}}
{
if (!m_resumeDataDir.exists() && !m_resumeDataDir.mkpath(m_resumeDataDir.absolutePath()))
{
throw RuntimeError {tr("Cannot create torrent resume folder: \"%1\"")
.arg(Utils::Fs::toNativePath(m_resumeDataDir.absolutePath()))};
}
const QRegularExpression filenamePattern {QLatin1String("^([A-Fa-f0-9]{40})\\.fastresume$")};
const QStringList filenames = m_resumeDataDir.entryList(QStringList(QLatin1String("*.fastresume")), QDir::Files, QDir::Unsorted);
m_registeredTorrents.reserve(filenames.size());
for (const QString &filename : filenames)
{
const QRegularExpressionMatch rxMatch = filenamePattern.match(filename);
if (rxMatch.hasMatch())
m_registeredTorrents.append(TorrentID::fromString(rxMatch.captured(1)));
}
loadQueue(m_resumeDataDir.absoluteFilePath(QLatin1String("queue")));
qDebug("Registered torrents count: %d", m_registeredTorrents.size());
m_asyncWorker->moveToThread(m_ioThread);
connect(m_ioThread, &QThread::finished, m_asyncWorker, &QObject::deleteLater);
m_ioThread->start();
}
BitTorrent::BencodeResumeDataStorage::~BencodeResumeDataStorage()
{
m_ioThread->quit();
m_ioThread->wait();
}
QVector<BitTorrent::TorrentID> BitTorrent::BencodeResumeDataStorage::registeredTorrents() const
{
return m_registeredTorrents;
}
std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorage::load(const TorrentID &id) const
{
const QString idString = id.toString();
const QString fastresumePath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.fastresume").arg(idString));
const QString torrentFilePath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(idString));
QFile resumeDataFile {fastresumePath};
if (!resumeDataFile.open(QIODevice::ReadOnly))
{
LogMsg(tr("Cannot read file %1: %2").arg(fastresumePath, resumeDataFile.errorString()), Log::WARNING);
return std::nullopt;
}
QFile metadataFile {torrentFilePath};
if (metadataFile.exists() && !metadataFile.open(QIODevice::ReadOnly))
{
LogMsg(tr("Cannot read file %1: %2").arg(torrentFilePath, metadataFile.errorString()), Log::WARNING);
return std::nullopt;
}
const QByteArray data = resumeDataFile.readAll();
const QByteArray metadata = (metadataFile.isOpen() ? metadataFile.readAll() : "");
return loadTorrentResumeData(data, metadata);
}
std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorage::loadTorrentResumeData(
const QByteArray &data, const QByteArray &metadata) const
{
const QByteArray allData = ((metadata.isEmpty() || data.isEmpty())
? data : (data.chopped(1) + metadata.mid(1)));
lt::error_code ec;
const lt::bdecode_node root = lt::bdecode(allData, ec);
if (ec || (root.type() != lt::bdecode_node::dict_t))
return std::nullopt;
LoadTorrentParams torrentParams;
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);
// 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");
if (contentLayoutNode.type() == lt::bdecode_node::string_t)
{
const QString contentLayoutStr = fromLTString(contentLayoutNode.string_value());
torrentParams.contentLayout = Utils::String::toEnum(contentLayoutStr, TorrentContentLayout::Original);
}
else
{
const bool hasRootFolder = root.dict_find_int_value("qBt-hasRootFolder");
torrentParams.contentLayout = (hasRootFolder ? TorrentContentLayout::Original : TorrentContentLayout::NoSubfolder);
}
// === END DEPRECATED CODE === //
// === BEGIN REPLACEMENT CODE === //
// torrentParams.contentLayout = Utils::String::parse(
// fromLTString(root.dict_find_string_value("qBt-contentLayout")), TorrentContentLayout::Default);
// === END REPLACEMENT CODE === //
const lt::string_view ratioLimitString = root.dict_find_string_value("qBt-ratioLimit");
if (ratioLimitString.empty())
torrentParams.ratioLimit = root.dict_find_int_value("qBt-ratioLimit", Torrent::USE_GLOBAL_RATIO * 1000) / 1000.0;
else
torrentParams.ratioLimit = fromLTString(ratioLimitString).toDouble();
const lt::bdecode_node tagsNode = root.dict_find("qBt-tags");
if (tagsNode.type() == lt::bdecode_node::list_t)
{
for (int i = 0; i < tagsNode.list_size(); ++i)
{
const QString tag = fromLTString(tagsNode.list_string_value_at(i));
torrentParams.tags.insert(tag);
}
}
lt::add_torrent_params &p = torrentParams.ltAddTorrentParams;
p = lt::read_resume_data(root, ec);
p.save_path = Profile::instance()->fromPortablePath(fromLTString(p.save_path)).toStdString();
if (p.flags & lt::torrent_flags::stop_when_ready)
{
// If torrent has "stop_when_ready" flag set then it is actually "stopped"
torrentParams.stopped = true;
torrentParams.operatingMode = TorrentOperatingMode::AutoManaged;
// ...but temporarily "resumed" to perform some service jobs (e.g. checking)
p.flags &= ~lt::torrent_flags::paused;
p.flags |= lt::torrent_flags::auto_managed;
}
else
{
torrentParams.stopped = (p.flags & lt::torrent_flags::paused) && !(p.flags & lt::torrent_flags::auto_managed);
torrentParams.operatingMode = (p.flags & lt::torrent_flags::paused) || (p.flags & lt::torrent_flags::auto_managed)
? TorrentOperatingMode::AutoManaged : TorrentOperatingMode::Forced;
}
const bool hasMetadata = (p.ti && p.ti->is_valid());
if (!hasMetadata && !root.dict_find("info-hash"))
return std::nullopt;
return torrentParams;
}
void BitTorrent::BencodeResumeDataStorage::store(const TorrentID &id, const LoadTorrentParams &resumeData) const
{
QMetaObject::invokeMethod(m_asyncWorker, [this, id, resumeData]()
{
m_asyncWorker->store(id, resumeData);
});
}
void BitTorrent::BencodeResumeDataStorage::remove(const TorrentID &id) const
{
QMetaObject::invokeMethod(m_asyncWorker, [this, id]()
{
m_asyncWorker->remove(id);
});
}
void BitTorrent::BencodeResumeDataStorage::storeQueue(const QVector<TorrentID> &queue) const
{
QMetaObject::invokeMethod(m_asyncWorker, [this, queue]()
{
m_asyncWorker->storeQueue(queue);
});
}
void BitTorrent::BencodeResumeDataStorage::loadQueue(const QString &queueFilename)
{
QFile queueFile {queueFilename};
if (!queueFile.exists())
return;
if (queueFile.open(QFile::ReadOnly))
{
const QRegularExpression hashPattern {QLatin1String("^([A-Fa-f0-9]{40})$")};
QByteArray line;
int start = 0;
while (!(line = queueFile.readLine().trimmed()).isEmpty())
{
const QRegularExpressionMatch rxMatch = hashPattern.match(line);
if (rxMatch.hasMatch())
{
const auto torrentID = TorrentID::fromString(rxMatch.captured(1));
const int pos = m_registeredTorrents.indexOf(torrentID, start);
if (pos != -1)
{
std::swap(m_registeredTorrents[start], m_registeredTorrents[pos]);
++start;
}
}
}
}
else
{
LogMsg(tr("Couldn't load torrents queue from '%1'. Error: %2")
.arg(queueFile.fileName(), queueFile.errorString()), Log::WARNING);
}
}
BitTorrent::BencodeResumeDataStorage::Worker::Worker(const QDir &resumeDataDir)
: m_resumeDataDir {resumeDataDir}
{
}
void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, const LoadTorrentParams &resumeData) const
{
// We need to adjust native libtorrent resume data
lt::add_torrent_params p = resumeData.ltAddTorrentParams;
p.save_path = Profile::instance()->toPortablePath(QString::fromStdString(p.save_path)).toStdString();
if (resumeData.stopped)
{
p.flags |= lt::torrent_flags::paused;
p.flags &= ~lt::torrent_flags::auto_managed;
}
else
{
// Torrent can be actually "running" but temporarily "paused" to perform some
// service jobs behind the scenes so we need to restore it as "running"
if (resumeData.operatingMode == BitTorrent::TorrentOperatingMode::AutoManaged)
{
p.flags |= lt::torrent_flags::auto_managed;
}
else
{
p.flags &= ~lt::torrent_flags::paused;
p.flags &= ~lt::torrent_flags::auto_managed;
}
}
lt::entry data = lt::write_resume_data(p);
// metadata is stored in separate .torrent file
if (p.ti)
{
lt::entry::dictionary_type &dataDict = data.dict();
lt::entry metadata {lt::entry::dictionary_t};
lt::entry::dictionary_type &metadataDict = metadata.dict();
metadataDict.insert(dataDict.extract("info"));
metadataDict.insert(dataDict.extract("creation date"));
metadataDict.insert(dataDict.extract("created by"));
metadataDict.insert(dataDict.extract("comment"));
const QString torrentFilepath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(id.toString()));
try
{
writeEntryToFile(torrentFilepath, metadata);
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2.")
.arg(torrentFilepath, err.message()), Log::CRITICAL);
return;
}
}
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();
data["qBt-tags"] = setToEntryList(resumeData.tags);
data["qBt-name"] = resumeData.name.toStdString();
data["qBt-seedStatus"] = resumeData.hasSeedStatus;
data["qBt-contentLayout"] = Utils::String::fromEnum(resumeData.contentLayout).toStdString();
data["qBt-firstLastPiecePriority"] = resumeData.firstLastPiecePriority;
const QString resumeFilepath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.fastresume").arg(id.toString()));
try
{
writeEntryToFile(resumeFilepath, data);
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't save torrent resume data to '%1'. Error: %2.")
.arg(resumeFilepath, err.message()), Log::CRITICAL);
}
}
void BitTorrent::BencodeResumeDataStorage::Worker::remove(const TorrentID &id) const
{
const QString resumeFilename = QString::fromLatin1("%1.fastresume").arg(id.toString());
Utils::Fs::forceRemove(m_resumeDataDir.absoluteFilePath(resumeFilename));
const QString torrentFilename = QString::fromLatin1("%1.torrent").arg(id.toString());
Utils::Fs::forceRemove(m_resumeDataDir.absoluteFilePath(torrentFilename));
}
void BitTorrent::BencodeResumeDataStorage::Worker::storeQueue(const QVector<TorrentID> &queue) const
{
QByteArray data;
data.reserve(((BitTorrent::TorrentID::length() * 2) + 1) * queue.size());
for (const BitTorrent::TorrentID &torrentID : queue)
data += (torrentID.toString().toLatin1() + '\n');
const QString filepath = m_resumeDataDir.absoluteFilePath(QLatin1String("queue"));
QSaveFile file {filepath};
if (!file.open(QIODevice::WriteOnly) || (file.write(data) != data.size()) || !file.commit())
{
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
.arg(filepath, file.errorString()), Log::CRITICAL);
}
}

View File

@@ -1,67 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015, 2018 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 <QDir>
#include <QVector>
#include "resumedatastorage.h"
class QByteArray;
class QThread;
namespace BitTorrent
{
class BencodeResumeDataStorage final : public ResumeDataStorage
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(BencodeResumeDataStorage)
public:
explicit BencodeResumeDataStorage(const QString &path, QObject *parent = nullptr);
~BencodeResumeDataStorage() override;
QVector<TorrentID> registeredTorrents() const override;
std::optional<LoadTorrentParams> load(const TorrentID &id) const override;
void store(const TorrentID &id, const LoadTorrentParams &resumeData) const override;
void remove(const TorrentID &id) const override;
void storeQueue(const QVector<TorrentID> &queue) const override;
private:
void loadQueue(const QString &queueFilename);
std::optional<LoadTorrentParams> loadTorrentResumeData(const QByteArray &data, const QByteArray &metadata) const;
const QDir m_resumeDataDir;
QVector<TorrentID> m_registeredTorrents;
QThread *m_ioThread = nullptr;
class Worker;
Worker *m_asyncWorker = nullptr;
};
}

View File

@@ -35,7 +35,7 @@
#include "base/utils/fs.h"
#include "common.h"
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
#include <libtorrent/session.hpp>
std::unique_ptr<lt::disk_interface> customDiskIOConstructor(

View File

@@ -30,10 +30,11 @@
#include <libtorrent/aux_/vector.hpp>
#include <libtorrent/fwd.hpp>
#include <libtorrent/version.hpp>
#include <QString>
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
#include <libtorrent/disk_interface.hpp>
#include <libtorrent/file_storage.hpp>
#include <libtorrent/io_context.hpp>
@@ -45,7 +46,7 @@
#include <libtorrent/storage.hpp>
#endif
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
std::unique_ptr<lt::disk_interface> customDiskIOConstructor(
lt::io_context &ioContext, lt::settings_interface const &settings, lt::counters &counters);

View File

@@ -1,591 +0,0 @@
/*
* 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 "dbresumedatastorage.h"
#include <libtorrent/bdecode.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/read_resume_data.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/write_resume_data.hpp>
#include <QByteArray>
#include <QFile>
#include <QSet>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QThread>
#include <QVector>
#include "base/exceptions.h"
#include "base/global.h"
#include "base/logger.h"
#include "base/profile.h"
#include "base/utils/fs.h"
#include "base/utils/string.h"
#include "infohash.h"
#include "loadtorrentparams.h"
namespace
{
const char DB_CONNECTION_NAME[] = "ResumeDataStorage";
const int DB_VERSION = 1;
const char DB_TABLE_META[] = "meta";
const char DB_TABLE_TORRENTS[] = "torrents";
struct Column
{
QString name;
QString placeholder;
};
Column makeColumn(const char *columnName)
{
return {QLatin1String(columnName), (QLatin1Char(':') + QLatin1String(columnName))};
}
const Column DB_COLUMN_ID = makeColumn("id");
const Column DB_COLUMN_TORRENT_ID = makeColumn("torrent_id");
const Column DB_COLUMN_QUEUE_POSITION = makeColumn("queue_position");
const Column DB_COLUMN_NAME = makeColumn("name");
const Column DB_COLUMN_CATEGORY = makeColumn("category");
const Column DB_COLUMN_TAGS = makeColumn("tags");
const Column DB_COLUMN_TARGET_SAVE_PATH = makeColumn("target_save_path");
const Column DB_COLUMN_CONTENT_LAYOUT = makeColumn("content_layout");
const Column DB_COLUMN_RATIO_LIMIT = makeColumn("ratio_limit");
const Column DB_COLUMN_SEEDING_TIME_LIMIT = makeColumn("seeding_time_limit");
const Column DB_COLUMN_HAS_OUTER_PIECES_PRIORITY = makeColumn("has_outer_pieces_priority");
const Column DB_COLUMN_HAS_SEED_STATUS = makeColumn("has_seed_status");
const Column DB_COLUMN_OPERATING_MODE = makeColumn("operating_mode");
const Column DB_COLUMN_STOPPED = makeColumn("stopped");
const Column DB_COLUMN_RESUMEDATA = makeColumn("libtorrent_resume_data");
const Column DB_COLUMN_METADATA = makeColumn("metadata");
const Column DB_COLUMN_VALUE = makeColumn("value");
template <typename LTStr>
QString fromLTString(const LTStr &str)
{
return QString::fromUtf8(str.data(), static_cast<int>(str.size()));
}
QString quoted(const QString &name)
{
const QLatin1Char quote {'`'};
return (quote + name + quote);
}
QString makeCreateTableStatement(const QString &tableName, const QStringList &items)
{
return QString::fromLatin1("CREATE TABLE %1 (%2)").arg(quoted(tableName), items.join(QLatin1Char(',')));
}
QString makeInsertStatement(const QString &tableName, 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(','));
return QString::fromLatin1("INSERT INTO %1 (%2) VALUES (%3)")
.arg(quoted(tableName), jointNames, jointValues);
}
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(','));
return QString::fromLatin1(" ON CONFLICT (%1) DO UPDATE SET (%2) = (%3)")
.arg(quoted(constraint.name), jointNames, jointValues);
}
QString makeColumnDefinition(const Column &column, const char *definition)
{
return QString::fromLatin1("%1 %2").arg(quoted(column.name), QLatin1String(definition));
}
}
namespace BitTorrent
{
class DBResumeDataStorage::Worker final : public QObject
{
Q_DISABLE_COPY_MOVE(Worker)
public:
Worker(const QString &dbPath, const QString &dbConnectionName);
void openDatabase() const;
void closeDatabase() const;
void store(const TorrentID &id, const LoadTorrentParams &resumeData) const;
void remove(const TorrentID &id) const;
void storeQueue(const QVector<TorrentID> &queue) const;
private:
const QString m_path;
const QString m_connectionName;
};
}
BitTorrent::DBResumeDataStorage::DBResumeDataStorage(const QString &dbPath, QObject *parent)
: ResumeDataStorage {parent}
, m_ioThread {new QThread(this)}
{
const bool needCreateDB = !QFile::exists(dbPath);
auto db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), DB_CONNECTION_NAME);
db.setDatabaseName(dbPath);
if (!db.open())
throw RuntimeError(db.lastError().text());
if (needCreateDB)
createDB();
m_asyncWorker = new Worker(dbPath, QLatin1String("ResumeDataStorageWorker"));
m_asyncWorker->moveToThread(m_ioThread);
connect(m_ioThread, &QThread::finished, m_asyncWorker, &QObject::deleteLater);
m_ioThread->start();
RuntimeError *errPtr = nullptr;
QMetaObject::invokeMethod(m_asyncWorker, [this, &errPtr]()
{
try
{
m_asyncWorker->openDatabase();
}
catch (const RuntimeError &err)
{
errPtr = new RuntimeError(err);
}
}, Qt::BlockingQueuedConnection);
if (errPtr)
throw *errPtr;
}
BitTorrent::DBResumeDataStorage::~DBResumeDataStorage()
{
QMetaObject::invokeMethod(m_asyncWorker, &Worker::closeDatabase);
QSqlDatabase::removeDatabase(DB_CONNECTION_NAME);
m_ioThread->quit();
m_ioThread->wait();
}
QVector<BitTorrent::TorrentID> BitTorrent::DBResumeDataStorage::registeredTorrents() const
{
const auto selectTorrentIDStatement = QString::fromLatin1("SELECT %1 FROM %2 ORDER BY %3;")
.arg(quoted(DB_COLUMN_TORRENT_ID.name), quoted(DB_TABLE_TORRENTS), quoted(DB_COLUMN_QUEUE_POSITION.name));
auto db = QSqlDatabase::database(DB_CONNECTION_NAME);
QSqlQuery query {db};
if (!query.exec(selectTorrentIDStatement))
throw RuntimeError(query.lastError().text());
QVector<TorrentID> registeredTorrents;
registeredTorrents.reserve(query.size());
while (query.next())
registeredTorrents.append(BitTorrent::TorrentID::fromString(query.value(0).toString()));
return registeredTorrents;
}
std::optional<BitTorrent::LoadTorrentParams> BitTorrent::DBResumeDataStorage::load(const TorrentID &id) const
{
const QString selectTorrentStatement =
QString(QLatin1String("SELECT * FROM %1 WHERE %2 = %3;"))
.arg(quoted(DB_TABLE_TORRENTS), quoted(DB_COLUMN_TORRENT_ID.name), DB_COLUMN_TORRENT_ID.placeholder);
auto db = QSqlDatabase::database(DB_CONNECTION_NAME);
QSqlQuery query {db};
try
{
if (!query.prepare(selectTorrentStatement))
throw RuntimeError(query.lastError().text());
query.bindValue(DB_COLUMN_TORRENT_ID.placeholder, id.toString());
if (!query.exec())
throw RuntimeError(query.lastError().text());
if (!query.next())
throw RuntimeError(tr("Not found."));
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't load resume data of torrent '%1'. Error: %2")
.arg(id.toString(), err.message()), Log::CRITICAL);
return std::nullopt;
}
LoadTorrentParams resumeData;
resumeData.restored = true;
resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
if (!tagsData.isEmpty())
{
const QStringList tagList = tagsData.split(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;
resumeData.seedingTimeLimit = query.value(DB_COLUMN_SEEDING_TIME_LIMIT.name).toInt();
resumeData.contentLayout = Utils::String::toEnum<TorrentContentLayout>(
query.value(DB_COLUMN_CONTENT_LAYOUT.name).toString(), TorrentContentLayout::Original);
resumeData.operatingMode = Utils::String::toEnum<TorrentOperatingMode>(
query.value(DB_COLUMN_OPERATING_MODE.name).toString(), TorrentOperatingMode::AutoManaged);
resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray();
const QByteArray allData = ((bencodedMetadata.isEmpty() || bencodedResumeData.isEmpty())
? bencodedResumeData
: (bencodedResumeData.chopped(1) + bencodedMetadata.mid(1)));
lt::error_code ec;
const lt::bdecode_node root = lt::bdecode(allData, ec);
lt::add_torrent_params &p = resumeData.ltAddTorrentParams;
p = lt::read_resume_data(root, ec);
p.save_path = Profile::instance()->fromPortablePath(fromLTString(p.save_path)).toStdString();
return resumeData;
}
void BitTorrent::DBResumeDataStorage::store(const TorrentID &id, const LoadTorrentParams &resumeData) const
{
QMetaObject::invokeMethod(m_asyncWorker, [this, id, resumeData]()
{
m_asyncWorker->store(id, resumeData);
});
}
void BitTorrent::DBResumeDataStorage::remove(const BitTorrent::TorrentID &id) const
{
QMetaObject::invokeMethod(m_asyncWorker, [this, id]()
{
m_asyncWorker->remove(id);
});
}
void BitTorrent::DBResumeDataStorage::storeQueue(const QVector<TorrentID> &queue) const
{
QMetaObject::invokeMethod(m_asyncWorker, [this, queue]()
{
m_asyncWorker->storeQueue(queue);
});
}
void BitTorrent::DBResumeDataStorage::createDB() const
{
auto db = QSqlDatabase::database(DB_CONNECTION_NAME);
if (!db.transaction())
throw RuntimeError(db.lastError().text());
QSqlQuery query {db};
try
{
const QStringList tableMetaItems = {
makeColumnDefinition(DB_COLUMN_ID, "INTEGER PRIMARY KEY"),
makeColumnDefinition(DB_COLUMN_NAME, "TEXT NOT NULL UNIQUE"),
makeColumnDefinition(DB_COLUMN_VALUE, "BLOB")
};
const QString createTableMetaQuery = makeCreateTableStatement(DB_TABLE_META, tableMetaItems);
if (!query.exec(createTableMetaQuery))
throw RuntimeError(query.lastError().text());
const QString insertMetaVersionQuery = makeInsertStatement(DB_TABLE_META, {DB_COLUMN_NAME, DB_COLUMN_VALUE});
if (!query.prepare(insertMetaVersionQuery))
throw RuntimeError(query.lastError().text());
query.bindValue(DB_COLUMN_NAME.placeholder, QString::fromLatin1("version"));
query.bindValue(DB_COLUMN_VALUE.placeholder, DB_VERSION);
if (!query.exec())
throw RuntimeError(query.lastError().text());
const QStringList tableTorrentsItems = {
makeColumnDefinition(DB_COLUMN_ID, "INTEGER PRIMARY KEY"),
makeColumnDefinition(DB_COLUMN_TORRENT_ID, "BLOB NOT NULL UNIQUE"),
makeColumnDefinition(DB_COLUMN_QUEUE_POSITION, "INTEGER NOT NULL DEFAULT -1"),
makeColumnDefinition(DB_COLUMN_NAME, "TEXT"),
makeColumnDefinition(DB_COLUMN_CATEGORY, "TEXT"),
makeColumnDefinition(DB_COLUMN_TAGS, "TEXT"),
makeColumnDefinition(DB_COLUMN_TARGET_SAVE_PATH, "TEXT"),
makeColumnDefinition(DB_COLUMN_CONTENT_LAYOUT, "TEXT NOT NULL"),
makeColumnDefinition(DB_COLUMN_RATIO_LIMIT, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_SEEDING_TIME_LIMIT, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_HAS_SEED_STATUS, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_OPERATING_MODE, "TEXT NOT NULL"),
makeColumnDefinition(DB_COLUMN_STOPPED, "INTEGER NOT NULL"),
makeColumnDefinition(DB_COLUMN_RESUMEDATA, "BLOB NOT NULL"),
makeColumnDefinition(DB_COLUMN_METADATA, "BLOB")
};
const QString createTableTorrentsQuery = makeCreateTableStatement(DB_TABLE_TORRENTS, tableTorrentsItems);
if (!query.exec(createTableTorrentsQuery))
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}
{
}
void BitTorrent::DBResumeDataStorage::Worker::openDatabase() const
{
auto db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_connectionName);
db.setDatabaseName(m_path);
if (!db.open())
throw RuntimeError(db.lastError().text());
}
void BitTorrent::DBResumeDataStorage::Worker::closeDatabase() const
{
QSqlDatabase::removeDatabase(m_connectionName);
}
void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const LoadTorrentParams &resumeData) const
{
// We need to adjust native libtorrent resume data
lt::add_torrent_params p = resumeData.ltAddTorrentParams;
p.save_path = Profile::instance()->toPortablePath(QString::fromStdString(p.save_path)).toStdString();
if (resumeData.stopped)
{
p.flags |= lt::torrent_flags::paused;
p.flags &= ~lt::torrent_flags::auto_managed;
}
else
{
// Torrent can be actually "running" but temporarily "paused" to perform some
// service jobs behind the scenes so we need to restore it as "running"
if (resumeData.operatingMode == BitTorrent::TorrentOperatingMode::AutoManaged)
{
p.flags |= lt::torrent_flags::auto_managed;
}
else
{
p.flags &= ~lt::torrent_flags::paused;
p.flags &= ~lt::torrent_flags::auto_managed;
}
}
QVector<Column> columns {
DB_COLUMN_TORRENT_ID,
DB_COLUMN_NAME,
DB_COLUMN_CATEGORY,
DB_COLUMN_TAGS,
DB_COLUMN_TARGET_SAVE_PATH,
DB_COLUMN_CONTENT_LAYOUT,
DB_COLUMN_RATIO_LIMIT,
DB_COLUMN_SEEDING_TIME_LIMIT,
DB_COLUMN_HAS_OUTER_PIECES_PRIORITY,
DB_COLUMN_HAS_SEED_STATUS,
DB_COLUMN_OPERATING_MODE,
DB_COLUMN_STOPPED,
DB_COLUMN_RESUMEDATA
};
lt::entry data = lt::write_resume_data(p);
// metadata is stored in separate column
QByteArray bencodedMetadata;
if (p.ti)
{
lt::entry::dictionary_type &dataDict = data.dict();
lt::entry metadata {lt::entry::dictionary_t};
lt::entry::dictionary_type &metadataDict = metadata.dict();
metadataDict.insert(dataDict.extract("info"));
metadataDict.insert(dataDict.extract("creation date"));
metadataDict.insert(dataDict.extract("created by"));
metadataDict.insert(dataDict.extract("comment"));
try
{
bencodedMetadata.reserve(512 * 1024);
lt::bencode(std::back_inserter(bencodedMetadata), metadata);
}
catch (const std::exception &err)
{
LogMsg(tr("Couldn't save torrent metadata. Error: %1.")
.arg(QString::fromLocal8Bit(err.what())), Log::CRITICAL);
return;
}
columns.append(DB_COLUMN_METADATA);
}
QByteArray bencodedResumeData;
bencodedResumeData.reserve(256 * 1024);
lt::bencode(std::back_inserter(bencodedResumeData), data);
const QString insertTorrentStatement = makeInsertStatement(DB_TABLE_TORRENTS, columns)
+ makeOnConflictUpdateStatement(DB_COLUMN_TORRENT_ID, columns);
auto db = QSqlDatabase::database(m_connectionName);
QSqlQuery query {db};
try
{
if (!query.prepare(insertTorrentStatement))
throw RuntimeError(query.lastError().text());
query.bindValue(DB_COLUMN_TORRENT_ID.placeholder, id.toString());
query.bindValue(DB_COLUMN_NAME.placeholder, resumeData.name);
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);
query.bindValue(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY.placeholder, resumeData.firstLastPiecePriority);
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);
query.bindValue(DB_COLUMN_RESUMEDATA.placeholder, bencodedResumeData);
if (!bencodedMetadata.isEmpty())
query.bindValue(DB_COLUMN_METADATA.placeholder, bencodedMetadata);
if (!query.exec())
throw RuntimeError(query.lastError().text());
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't store resume data for torrent '%1'. Error: %2")
.arg(id.toString(), err.message()), Log::CRITICAL);
}
}
void BitTorrent::DBResumeDataStorage::Worker::remove(const TorrentID &id) const
{
const auto deleteTorrentStatement = QString::fromLatin1("DELETE FROM %1 WHERE %2 = %3;")
.arg(quoted(DB_TABLE_TORRENTS), quoted(DB_COLUMN_TORRENT_ID.name), DB_COLUMN_TORRENT_ID.placeholder);
auto db = QSqlDatabase::database(m_connectionName);
QSqlQuery query {db};
try
{
if (!query.prepare(deleteTorrentStatement))
throw RuntimeError(query.lastError().text());
query.bindValue(DB_COLUMN_TORRENT_ID.placeholder, id.toString());
if (!query.exec())
throw RuntimeError(query.lastError().text());
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't delete resume data of torrent '%1'. Error: %2")
.arg(id.toString(), err.message()), Log::CRITICAL);
}
}
void BitTorrent::DBResumeDataStorage::Worker::storeQueue(const QVector<TorrentID> &queue) const
{
const auto updateQueuePosStatement = QString::fromLatin1("UPDATE %1 SET %2 = %3 WHERE %4 = %5;")
.arg(quoted(DB_TABLE_TORRENTS), quoted(DB_COLUMN_QUEUE_POSITION.name), DB_COLUMN_QUEUE_POSITION.placeholder
, quoted(DB_COLUMN_TORRENT_ID.name), DB_COLUMN_TORRENT_ID.placeholder);
auto db = QSqlDatabase::database(m_connectionName);
try
{
if (!db.transaction())
throw RuntimeError(db.lastError().text());
QSqlQuery query {db};
try
{
if (!query.prepare(updateQueuePosStatement))
throw RuntimeError(query.lastError().text());
int pos = 0;
for (const TorrentID &torrentID : queue)
{
query.bindValue(DB_COLUMN_TORRENT_ID.placeholder, torrentID.toString());
query.bindValue(DB_COLUMN_QUEUE_POSITION.placeholder, pos++);
if (!query.exec())
throw RuntimeError(query.lastError().text());
}
if (!db.commit())
throw RuntimeError(db.lastError().text());
}
catch (const RuntimeError &)
{
db.rollback();
throw;
}
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't store torrents queue positions. Error: %1")
.arg(err.message()), Log::CRITICAL);
}
}

View File

@@ -1,60 +0,0 @@
/*
* 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 "resumedatastorage.h"
class QThread;
namespace BitTorrent
{
class DBResumeDataStorage final : public ResumeDataStorage
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(DBResumeDataStorage)
public:
explicit DBResumeDataStorage(const QString &dbPath, QObject *parent = nullptr);
~DBResumeDataStorage() override;
QVector<TorrentID> registeredTorrents() const override;
std::optional<LoadTorrentParams> load(const TorrentID &id) const override;
void store(const TorrentID &id, const LoadTorrentParams &resumeData) const override;
void remove(const TorrentID &id) const override;
void storeQueue(const QVector<TorrentID> &queue) const override;
private:
void createDB() const;
QThread *m_ioThread = nullptr;
class Worker;
Worker *m_asyncWorker = nullptr;
};
}

View File

@@ -38,7 +38,7 @@ namespace BitTorrent
class FileSearcher final : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(FileSearcher)
Q_DISABLE_COPY(FileSearcher)
public:
FileSearcher() = default;

View File

@@ -41,27 +41,9 @@ bool BitTorrent::InfoHash::isValid() const
return m_valid;
}
SHA1Hash BitTorrent::InfoHash::v1() const
{
#ifdef QBT_USES_LIBTORRENT2
return (m_nativeHash.has_v1() ? SHA1Hash(m_nativeHash.v1) : SHA1Hash());
#else
return {m_nativeHash};
#endif
}
SHA256Hash BitTorrent::InfoHash::v2() const
{
#ifdef QBT_USES_LIBTORRENT2
return (m_nativeHash.has_v2() ? SHA256Hash(m_nativeHash.v2) : SHA256Hash());
#else
return {};
#endif
}
BitTorrent::TorrentID BitTorrent::InfoHash::toTorrentID() const
{
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
return m_nativeHash.get_best();
#else
return {m_nativeHash};

View File

@@ -28,7 +28,8 @@
#pragma once
#ifdef QBT_USES_LIBTORRENT2
#include <libtorrent/version.hpp>
#if (LIBTORRENT_VERSION_NUM >= 20000)
#include <libtorrent/info_hash.hpp>
#endif
@@ -57,7 +58,7 @@ namespace BitTorrent
class InfoHash
{
public:
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
using WrappedType = lt::info_hash_t;
#else
using WrappedType = lt::sha1_hash;
@@ -68,8 +69,6 @@ namespace BitTorrent
InfoHash(const WrappedType &nativeHash);
bool isValid() const;
SHA1Hash v1() const;
SHA256Hash v2() const;
TorrentID toTorrentID() const;
operator WrappedType() const;

View File

@@ -1,60 +0,0 @@
/*
* 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 <libtorrent/add_torrent_params.hpp>
#include <QString>
#include "base/tagset.h"
#include "torrent.h"
#include "torrentcontentlayout.h"
namespace BitTorrent
{
struct LoadTorrentParams
{
lt::add_torrent_params ltAddTorrentParams {};
QString name;
QString category;
TagSet tags;
QString savePath;
TorrentContentLayout contentLayout = TorrentContentLayout::Original;
TorrentOperatingMode operatingMode = TorrentOperatingMode::AutoManaged;
bool firstLastPiecePriority = false;
bool hasSeedStatus = false;
bool stopped = false;
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
bool restored = false; // is existing torrent job?
};
}

View File

@@ -28,8 +28,31 @@
#pragma once
template <typename T>
typename T::underlying_type toLTUnderlyingType(const T &t)
#include <type_traits>
template <typename T, typename = void>
struct HasUnderlyingType
: std::false_type
{
return static_cast<typename T::underlying_type>(t);
}
};
template <typename T>
struct HasUnderlyingType<T, std::void_t<typename T::underlying_type>>
: std::true_type
{
};
template <typename T, typename = void>
struct LTUnderlying
{
using type = T;
};
template <typename T>
struct LTUnderlying<T, typename std::enable_if_t<HasUnderlyingType<T>::value>>
{
using type = typename T::underlying_type;
};
template <typename T>
using LTUnderlyingType = typename LTUnderlying<T>::type;

View File

@@ -39,34 +39,21 @@
namespace
{
// BEP9 Extension for Peers to Send Metadata Files
bool isV1Hash(const QString &string)
bool isSHA1Hash(const QString &string)
{
// There are 2 representations for BitTorrent v1 info hash:
// There are 2 representations for BitTorrent info hash:
// 1. 40 chars hex-encoded string
// == 20 (SHA-1 length in bytes) * 2 (each byte maps to 2 hex characters)
// 2. 32 chars Base32 encoded string
// == 20 (SHA-1 length in bytes) * 1.6 (the efficiency of Base32 encoding)
const int V1_HEX_SIZE = SHA1Hash::length() * 2;
const int V1_BASE32_SIZE = SHA1Hash::length() * 1.6;
const int SHA1_HEX_SIZE = SHA1Hash::length() * 2;
const int SHA1_BASE32_SIZE = SHA1Hash::length() * 1.6;
return ((((string.size() == V1_HEX_SIZE))
return ((((string.size() == SHA1_HEX_SIZE))
&& !string.contains(QRegularExpression(QLatin1String("[^0-9A-Fa-f]"))))
|| ((string.size() == V1_BASE32_SIZE)
|| ((string.size() == SHA1_BASE32_SIZE)
&& !string.contains(QRegularExpression(QLatin1String("[^2-7A-Za-z]")))));
}
bool isV2Hash(const QString &string)
{
// There are 1 representation for BitTorrent v2 info hash:
// 1. 64 chars hex-encoded string
// == 32 (SHA-2 256 length in bytes) * 2 (each byte maps to 2 hex characters)
const int V2_HEX_SIZE = SHA256Hash::length() * 2;
return (string.size() == V2_HEX_SIZE)
&& !string.contains(QRegularExpression(QLatin1String("[^0-9A-Fa-f]")));
}
}
using namespace BitTorrent;
@@ -79,10 +66,8 @@ MagnetUri::MagnetUri(const QString &source)
{
if (source.isEmpty()) return;
if (isV2Hash(source))
m_url = QString::fromLatin1("magnet:?xt=urn:btmh:1220") + source; // 0x12 0x20 is the "multihash format" tag for the SHA-256 hashing scheme.
else if (isV1Hash(source))
m_url = QString::fromLatin1("magnet:?xt=urn:btih:") + source;
if (isSHA1Hash(source))
m_url = QLatin1String("magnet:?xt=urn:btih:") + source;
lt::error_code ec;
lt::parse_magnet_uri(m_url.toStdString(), m_addTorrentParams, ec);
@@ -90,7 +75,7 @@ MagnetUri::MagnetUri(const QString &source)
m_valid = true;
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
m_infoHash = m_addTorrentParams.info_hashes;
#else
m_infoHash = m_addTorrentParams.info_hash;

View File

@@ -29,10 +29,11 @@
#pragma once
#include <libtorrent/extensions.hpp>
#include <libtorrent/version.hpp>
class NativeSessionExtension final : public lt::plugin
{
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
using ClientData = lt::client_data_t;
#else
using ClientData = void *;

View File

@@ -32,18 +32,18 @@
using namespace BitTorrent;
PeerAddress PeerAddress::parse(const QStringView address)
PeerAddress PeerAddress::parse(const QString &address)
{
QList<QStringView> ipPort;
QVector<QStringRef> ipPort;
if (address.startsWith(u'[') && address.contains(QLatin1String("]:")))
if (address.startsWith('[') && address.contains("]:"))
{ // IPv6
ipPort = address.split(QString::fromLatin1("]:"));
ipPort = address.splitRef("]:");
ipPort[0] = ipPort[0].mid(1); // chop '['
}
else if (address.contains(u':'))
else if (address.contains(':'))
{ // IPv4
ipPort = address.split(u':');
ipPort = address.splitRef(':');
}
else
{

View File

@@ -39,7 +39,7 @@ namespace BitTorrent
QHostAddress ip;
ushort port = 0;
static PeerAddress parse(QStringView address);
static PeerAddress parse(const QString &address);
QString toString() const;
};

View File

@@ -257,86 +257,123 @@ qreal PeerInfo::relevance() const
void PeerInfo::determineFlags()
{
const auto updateFlags = [this](const QChar specifier, const QString &explanation)
{
m_flags += (specifier + QLatin1Char(' '));
m_flagsDescription += QString::fromLatin1("%1 = %2\n").arg(specifier, explanation);
};
if (isInteresting())
{
// d = Your client wants to download, but peer doesn't want to send (interested and choked)
if (isRemoteChocked())
{
// d = Your client wants to download, but peer doesn't want to send (interested and choked)
updateFlags(QLatin1Char('d'), tr("Interested (local) and choked (peer)"));
m_flags += "d ";
m_flagsDescription += ("d = "
+ tr("Interested(local) and Choked(peer)") + '\n');
}
else
{
// D = Currently downloading (interested and not choked)
updateFlags(QLatin1Char('D'), tr("Interested (local) and unchoked (peer)"));
m_flags += "D ";
m_flagsDescription += ("D = "
+ tr("interested(local) and unchoked(peer)") + '\n');
}
}
if (isRemoteInterested())
{
// u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
if (isChocked())
{
// u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
updateFlags(QLatin1Char('u'), tr("Interested (peer) and choked (local)"));
m_flags += "u ";
m_flagsDescription += ("u = "
+ tr("interested(peer) and choked(local)") + '\n');
}
else
{
// U = Currently uploading (interested and not choked)
updateFlags(QLatin1Char('U'), tr("Interested (peer) and unchoked (local)"));
m_flags += "U ";
m_flagsDescription += ("U = "
+ tr("interested(peer) and unchoked(local)") + '\n');
}
}
// O = Optimistic unchoke
if (optimisticUnchoke())
{
m_flags += "O ";
m_flagsDescription += ("O = " + tr("optimistic unchoke") + '\n');
}
// S = Peer is snubbed
if (isSnubbed())
{
m_flags += "S ";
m_flagsDescription += ("S = " + tr("peer snubbed") + '\n');
}
// I = Peer is an incoming connection
if (!isLocalConnection())
{
m_flags += "I ";
m_flagsDescription += ("I = " + tr("incoming connection") + '\n');
}
// K = Peer is unchoking your client, but your client is not interested
if (!isRemoteChocked() && !isInteresting())
updateFlags(QLatin1Char('K'), tr("Not interested (local) and unchoked (peer)"));
{
m_flags += "K ";
m_flagsDescription += ("K = "
+ tr("not interested(local) and unchoked(peer)") + '\n');
}
// ? = Your client unchoked the peer but the peer is not interested
if (!isChocked() && !isRemoteInterested())
updateFlags(QLatin1Char('?'), tr("Not interested (peer) and unchoked (local)"));
// O = Optimistic unchoke
if (optimisticUnchoke())
updateFlags(QLatin1Char('O'), tr("Optimistic unchoke"));
// S = Peer is snubbed
if (isSnubbed())
updateFlags(QLatin1Char('S'), tr("Peer snubbed"));
// I = Peer is an incoming connection
if (!isLocalConnection())
updateFlags(QLatin1Char('I'), tr("Incoming connection"));
// H = Peer was obtained through DHT
if (fromDHT())
updateFlags(QLatin1Char('H'), tr("Peer from DHT"));
{
m_flags += "? ";
m_flagsDescription += ("? = "
+ tr("not interested(peer) and unchoked(local)") + '\n');
}
// X = Peer was included in peerlists obtained through Peer Exchange (PEX)
if (fromPeX())
updateFlags(QLatin1Char('X'), tr("Peer from PEX"));
{
m_flags += "X ";
m_flagsDescription += ("X = " + tr("peer from PEX") + '\n');
}
// L = Peer is local
if (fromLSD())
updateFlags(QLatin1Char('L'), tr("Peer from LSD"));
// H = Peer was obtained through DHT
if (fromDHT())
{
m_flags += "H ";
m_flagsDescription += ("H = " + tr("peer from DHT") + '\n');
}
// E = Peer is using Protocol Encryption (all traffic)
if (isRC4Encrypted())
updateFlags(QLatin1Char('E'), tr("Encrypted traffic"));
{
m_flags += "E ";
m_flagsDescription += ("E = " + tr("encrypted traffic") + '\n');
}
// e = Peer is using Protocol Encryption (handshake)
if (isPlaintextEncrypted())
updateFlags(QLatin1Char('e'), tr("Encrypted handshake"));
{
m_flags += "e ";
m_flagsDescription += ("e = " + tr("encrypted handshake") + '\n');
}
// P = Peer is using uTorrent uTP
if (useUTPSocket())
updateFlags(QLatin1Char('P'), QString::fromUtf8(C_UTP));
{
m_flags += "P ";
m_flagsDescription += ("P = " + QString::fromUtf8(C_UTP) + '\n');
}
m_flags.chop(1);
m_flagsDescription.chop(1);
// L = Peer is local
if (fromLSD())
{
m_flags += "L ";
m_flagsDescription += ("L = " + tr("peer from LSD") + '\n');
}
m_flags = m_flags.trimmed();
m_flagsDescription = m_flagsDescription.trimmed();
}
QString PeerInfo::flags() const

View File

@@ -40,7 +40,7 @@
class PortForwarderImpl final : public Net::PortForwarder
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(PortForwarderImpl)
Q_DISABLE_COPY(PortForwarderImpl)
public:
explicit PortForwarderImpl(lt::session *provider, QObject *parent = nullptr);

View File

@@ -0,0 +1,83 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015, 2018 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 "resumedatasavingmanager.h"
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#include <QByteArray>
#include <QSaveFile>
#include "base/logger.h"
#include "base/utils/fs.h"
#include "base/utils/io.h"
ResumeDataSavingManager::ResumeDataSavingManager(const QString &resumeFolderPath)
: m_resumeDataDir(resumeFolderPath)
{
}
void ResumeDataSavingManager::save(const QString &filename, const QByteArray &data) const
{
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
QSaveFile file {filepath};
if (!file.open(QIODevice::WriteOnly) || (file.write(data) != data.size()) || !file.commit())
{
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
.arg(filepath, file.errorString()), Log::CRITICAL);
}
}
void ResumeDataSavingManager::save(const QString &filename, const std::shared_ptr<lt::entry> &data) const
{
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
QSaveFile file {filepath};
if (!file.open(QIODevice::WriteOnly))
{
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
.arg(filepath, file.errorString()), Log::CRITICAL);
return;
}
lt::bencode(Utils::IO::FileDeviceOutputIterator {file}, *data);
if ((file.error() != QFileDevice::NoError) || !file.commit())
{
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
.arg(filepath, file.errorString()), Log::CRITICAL);
}
}
void ResumeDataSavingManager::remove(const QString &filename) const
{
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
Utils::Fs::forceRemove(filepath);
}

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2021 Mike Tzou (Chocobo1)
* Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,22 +28,28 @@
#pragma once
#include <QMetaType>
#include <QString>
#include <memory>
#include "base/orderedset.h"
#include "base/utils/compare.h"
#include <libtorrent/fwd.hpp>
class TagLessThan
#include <QDir>
#include <QObject>
class QByteArray;
class ResumeDataSavingManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ResumeDataSavingManager)
public:
bool operator()(const QString &left, const QString &right) const;
explicit ResumeDataSavingManager(const QString &resumeFolderPath);
public slots:
void save(const QString &filename, const QByteArray &data) const;
void save(const QString &filename, const std::shared_ptr<lt::entry> &data) const;
void remove(const QString &filename) const;
private:
Utils::Compare::NaturalCompare<Qt::CaseInsensitive> m_compare;
Utils::Compare::NaturalCompare<Qt::CaseSensitive> m_subCompare;
const QDir m_resumeDataDir;
};
using TagSet = OrderedSet<QString, TagLessThan>;
Q_DECLARE_METATYPE(TagSet)

View File

@@ -1,55 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015, 2018 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 <QtContainerFwd>
#include <QObject>
namespace BitTorrent
{
class TorrentID;
struct LoadTorrentParams;
class ResumeDataStorage : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(ResumeDataStorage)
public:
using QObject::QObject;
virtual QVector<TorrentID> registeredTorrents() const = 0;
virtual std::optional<LoadTorrentParams> load(const TorrentID &id) const = 0;
virtual void store(const TorrentID &id, const LoadTorrentParams &resumeData) const = 0;
virtual void remove(const TorrentID &id) const = 0;
virtual void storeQueue(const QVector<TorrentID> &queue) const = 0;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,7 @@
#include <libtorrent/add_torrent_params.hpp>
#include <libtorrent/fwd.hpp>
#include <libtorrent/torrent_handle.hpp>
#include <libtorrent/version.hpp>
#include <QHash>
#include <QPointer>
@@ -49,12 +50,10 @@
#include "cachestatus.h"
#include "sessionstatus.h"
#include "torrentinfo.h"
#include "trackerentry.h"
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
class QFile;
class QNetworkConfiguration;
class QNetworkConfigurationManager;
#endif
class QString;
class QThread;
class QTimer;
@@ -63,6 +62,7 @@ class QUrl;
class BandwidthScheduler;
class FileSearcher;
class FilterParserThread;
class ResumeDataSavingManager;
class Statistics;
// These values should remain unchanged when adding new items
@@ -81,6 +81,12 @@ enum DeleteOption
DeleteTorrentAndFiles
};
enum TorrentExportFolder
{
Regular,
Finished
};
namespace Net
{
struct DownloadResult;
@@ -90,11 +96,11 @@ namespace BitTorrent
{
class InfoHash;
class MagnetUri;
class ResumeDataStorage;
class Torrent;
class TorrentImpl;
class Tracker;
struct LoadTorrentParams;
struct TrackerEntry;
enum class MoveStorageMode;
@@ -135,13 +141,6 @@ namespace BitTorrent
};
Q_ENUM_NS(SeedChokingAlgorithm)
enum class ResumeDataStorageType
{
Legacy,
SQLite
};
Q_ENUM_NS(ResumeDataStorageType)
#if defined(Q_OS_WIN)
enum class OSMemoryPriority : int
{
@@ -190,7 +189,7 @@ namespace BitTorrent
{
int diskBlocksInUse = -1;
int numBlocksRead = -1;
#ifndef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM < 20000)
int numBlocksCacheHits = -1;
#endif
int writeJobs = -1;
@@ -204,7 +203,7 @@ namespace BitTorrent
class Session : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Session)
Q_DISABLE_COPY(Session)
public:
static void initInstance();
@@ -305,6 +304,8 @@ namespace BitTorrent
void setSaveResumeDataInterval(int value);
int port() const;
void setPort(int port);
bool useRandomPort() const;
void setUseRandomPort(bool value);
QString networkInterface() const;
void setNetworkInterface(const QString &iface);
QString networkInterfaceName() const;
@@ -363,8 +364,6 @@ namespace BitTorrent
void setSendBufferLowWatermark(int value);
int sendBufferWatermarkFactor() const;
void setSendBufferWatermarkFactor(int value);
int connectionSpeed() const;
void setConnectionSpeed(int value);
int socketBacklogSize() const;
void setSocketBacklogSize(int value);
bool isAnonymousModeEnabled() const;
@@ -395,9 +394,6 @@ namespace BitTorrent
void setAnnounceIP(const QString &ip);
int maxConcurrentHTTPAnnounces() const;
void setMaxConcurrentHTTPAnnounces(int value);
bool isReannounceWhenAddressChangedEnabled() const;
void setReannounceWhenAddressChangedEnabled(bool enabled);
void reannounceToAllTrackers() const;
int stopTrackerTimeout() const;
void setStopTrackerTimeout(int value);
int maxConnections() const;
@@ -434,8 +430,6 @@ namespace BitTorrent
void setTrackerFilteringEnabled(bool enabled);
QStringList bannedIPs() const;
void setBannedIPs(const QStringList &newList);
ResumeDataStorageType resumeDataStorageType() const;
void setResumeDataStorageType(ResumeDataStorageType type);
#if defined(Q_OS_WIN)
OSMemoryPriority getOSMemoryPriority() const;
void setOSMemoryPriority(OSMemoryPriority priority);
@@ -550,11 +544,9 @@ namespace BitTorrent
void handleDownloadFinished(const Net::DownloadResult &result);
void fileSearchFinished(const TorrentID &id, const QString &savePath, const QStringList &fileNames);
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
// Session reconfiguration triggers
void networkOnlineStateChanged(bool online);
void networkConfigurationChange(const QNetworkConfiguration &);
#endif
private:
struct MoveStorageJob
@@ -577,6 +569,8 @@ namespace BitTorrent
bool hasPerTorrentRatioLimit() const;
bool hasPerTorrentSeedingTimeLimit() const;
void initResumeFolder();
// Session configuration
Q_INVOKABLE void configure();
void configureComponents();
@@ -601,12 +595,13 @@ namespace BitTorrent
void applyOSMemoryPriority() const;
#endif
bool loadTorrentResumeData(const QByteArray &data, const TorrentInfo &metadata, LoadTorrentParams &torrentParams);
bool loadTorrent(LoadTorrentParams params);
LoadTorrentParams initLoadTorrentParams(const AddTorrentParams &addTorrentParams);
bool addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source, const AddTorrentParams &addTorrentParams);
void updateSeedingLimitTimer();
void exportTorrentFile(const TorrentInfo &torrentInfo, const QString &folderPath, const QString &baseName);
void exportTorrentFile(const Torrent *torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
void handleAlert(const lt::alert *a);
void dispatchTorrentAlert(const lt::alert *a);
@@ -670,7 +665,6 @@ namespace BitTorrent
CachedSettingValue<int> m_sendBufferWatermark;
CachedSettingValue<int> m_sendBufferLowWatermark;
CachedSettingValue<int> m_sendBufferWatermarkFactor;
CachedSettingValue<int> m_connectionSpeed;
CachedSettingValue<int> m_socketBacklogSize;
CachedSettingValue<bool> m_isAnonymousModeEnabled;
CachedSettingValue<bool> m_isQueueingEnabled;
@@ -689,7 +683,6 @@ namespace BitTorrent
CachedSettingValue<bool> m_includeOverheadInLimits;
CachedSettingValue<QString> m_announceIP;
CachedSettingValue<int> m_maxConcurrentHTTPAnnounces;
CachedSettingValue<bool> m_isReannounceWhenAddressChangedEnabled;
CachedSettingValue<int> m_stopTrackerTimeout;
CachedSettingValue<int> m_maxConnections;
CachedSettingValue<int> m_maxUploads;
@@ -722,6 +715,7 @@ namespace BitTorrent
CachedSettingValue<bool> m_isBandwidthSchedulerEnabled;
CachedSettingValue<int> m_saveResumeDataInterval;
CachedSettingValue<int> m_port;
CachedSettingValue<bool> m_useRandomPort;
CachedSettingValue<QString> m_networkInterface;
CachedSettingValue<QString> m_networkInterfaceName;
CachedSettingValue<QString> m_networkInterfaceAddress;
@@ -745,7 +739,6 @@ namespace BitTorrent
CachedSettingValue<int> m_peerTurnoverCutoff;
CachedSettingValue<int> m_peerTurnoverInterval;
CachedSettingValue<QStringList> m_bannedIPs;
CachedSettingValue<ResumeDataStorageType> m_resumeDataStorageType;
#if defined(Q_OS_WIN)
CachedSettingValue<OSMemoryPriority> m_OSMemoryPriority;
#endif
@@ -758,6 +751,8 @@ namespace BitTorrent
int m_numResumeData = 0;
int m_extraLimit = 0;
QVector<TrackerEntry> m_additionalTrackerList;
QString m_resumeFolderPath;
QFile *m_resumeFolderLock = nullptr;
bool m_refreshEnqueued = false;
QTimer *m_seedingLimitTimer = nullptr;
@@ -768,9 +763,9 @@ namespace BitTorrent
QPointer<BandwidthScheduler> m_bwScheduler;
// Tracker
QPointer<Tracker> m_tracker;
// fastresume data writing thread
QThread *m_ioThread = nullptr;
ResumeDataStorage *m_resumeDataStorage = nullptr;
ResumeDataSavingManager *m_resumeDataSavingManager = nullptr;
FileSearcher *m_fileSearcher = nullptr;
QSet<TorrentID> m_downloadedMetadata;
@@ -792,14 +787,11 @@ namespace BitTorrent
SessionStatus m_status;
CacheStatus m_cacheStatus;
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QNetworkConfigurationManager *m_networkManager = nullptr;
#endif
QList<MoveStorageJob> m_moveStorageQueue;
QString m_lastExternalIP;
static Session *m_instance;
};
}

View File

@@ -39,7 +39,7 @@ namespace BitTorrent
class Statistics : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Statistics)
Q_DISABLE_COPY(Statistics)
public:
explicit Statistics(BitTorrent::Session *session);

View File

@@ -33,7 +33,6 @@
#include <QString>
#include <QtContainerFwd>
#include "base/tagset.h"
#include "abstractfilestorage.h"
class QBitArray;
@@ -72,7 +71,6 @@ namespace BitTorrent
ForcedDownloading,
Downloading,
ForcedDownloadingMetadata,
DownloadingMetadata,
StalledDownloading,
@@ -180,7 +178,7 @@ namespace BitTorrent
virtual bool belongsToCategory(const QString &category) const = 0;
virtual bool setCategory(const QString &category) = 0;
virtual TagSet tags() const = 0;
virtual QSet<QString> tags() const = 0;
virtual bool hasTag(const QString &tag) const = 0;
virtual bool addTag(const QString &tag) = 0;
virtual bool removeTag(const QString &tag) = 0;

View File

@@ -42,9 +42,9 @@
#include "base/exceptions.h"
#include "base/global.h"
#include "base/utils/compare.h"
#include "base/utils/fs.h"
#include "base/utils/io.h"
#include "base/utils/string.h"
#include "base/version.h"
#include "ltunderlyingtype.h"
@@ -57,7 +57,7 @@ namespace
return !Utils::Fs::fileName(QString::fromStdString(f)).startsWith('.');
}
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
lt::create_flags_t toNativeTorrentFormatFlag(const BitTorrent::TorrentFormat torrentFormat)
{
switch (torrentFormat)
@@ -98,12 +98,6 @@ void TorrentCreatorThread::sendProgressSignal(int currentPieceIdx, int totalPiec
emit updateProgress(static_cast<int>((currentPieceIdx * 100.) / totalPieces));
}
void TorrentCreatorThread::checkInterruptionRequested() const
{
if (isInterruptionRequested())
throw RuntimeError(tr("Operation aborted"));
}
void TorrentCreatorThread::run()
{
emit updateProgress(0);
@@ -111,7 +105,6 @@ void TorrentCreatorThread::run()
try
{
const QString parentPath = Utils::Fs::branchPath(m_params.inputPath) + '/';
const Utils::Compare::NaturalLessThan<Qt::CaseInsensitive> naturalLessThan {};
// Adding files to the torrent
lt::file_storage fs;
@@ -124,13 +117,13 @@ void TorrentCreatorThread::run()
// need to sort the file names by natural sort order
QStringList dirs = {m_params.inputPath};
QDirIterator dirIter {m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories};
QDirIterator dirIter(m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories);
while (dirIter.hasNext())
{
dirIter.next();
dirs += dirIter.filePath();
}
std::sort(dirs.begin(), dirs.end(), naturalLessThan);
std::sort(dirs.begin(), dirs.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
QStringList fileNames;
QHash<QString, qint64> fileSizeMap;
@@ -149,7 +142,7 @@ void TorrentCreatorThread::run()
fileSizeMap[relFilePath] = fileIter.fileInfo().size();
}
std::sort(tmpNames.begin(), tmpNames.end(), naturalLessThan);
std::sort(tmpNames.begin(), tmpNames.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
fileNames += tmpNames;
}
@@ -157,9 +150,9 @@ void TorrentCreatorThread::run()
fs.add_file(fileName.toStdString(), fileSizeMap[fileName]);
}
checkInterruptionRequested();
if (isInterruptionRequested()) return;
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
lt::create_torrent newTorrent {fs, m_params.pieceSize, toNativeTorrentFormatFlag(m_params.torrentFormat)};
#else
lt::create_torrent newTorrent(fs, m_params.pieceSize, m_params.paddedFileSizeLimit
@@ -187,8 +180,10 @@ void TorrentCreatorThread::run()
lt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
, [this, &newTorrent](const lt::piece_index_t n)
{
checkInterruptionRequested();
sendProgressSignal(toLTUnderlyingType(n), newTorrent.num_pieces());
if (isInterruptionRequested())
throw RuntimeError {tr("Create new torrent aborted.")};
sendProgressSignal(static_cast<LTUnderlyingType<lt::piece_index_t>>(n), newTorrent.num_pieces());
});
// Set qBittorrent as creator and add user comment to
@@ -198,7 +193,7 @@ void TorrentCreatorThread::run()
// Is private ?
newTorrent.set_priv(m_params.isPrivate);
checkInterruptionRequested();
if (isInterruptionRequested()) return;
lt::entry entry = newTorrent.generate();
@@ -206,18 +201,24 @@ void TorrentCreatorThread::run()
if (!m_params.source.isEmpty())
entry["info"]["source"] = m_params.source.toStdString();
checkInterruptionRequested();
if (isInterruptionRequested()) return;
// create the torrent
QFile outfile {m_params.savePath};
if (!outfile.open(QIODevice::WriteOnly))
throw RuntimeError(outfile.errorString());
{
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
.arg(outfile.errorString())};
}
checkInterruptionRequested();
if (isInterruptionRequested()) return;
lt::bencode(Utils::IO::FileDeviceOutputIterator {outfile}, entry);
if (outfile.error() != QFileDevice::NoError)
throw RuntimeError(outfile.errorString());
{
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
.arg(outfile.errorString())};
}
outfile.close();
emit updateProgress(100);
@@ -233,7 +234,7 @@ void TorrentCreatorThread::run()
}
}
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
int TorrentCreatorThread::calculateTotalPieces(const QString &inputPath, const int pieceSize, const TorrentFormat torrentFormat)
#else
int TorrentCreatorThread::calculateTotalPieces(const QString &inputPath, const int pieceSize, const bool isAlignmentOptimized, const int paddedFileSizeLimit)
@@ -245,7 +246,7 @@ int TorrentCreatorThread::calculateTotalPieces(const QString &inputPath, const i
lt::file_storage fs;
lt::add_files(fs, Utils::Fs::toNativePath(inputPath).toStdString(), fileFilter);
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
return lt::create_torrent {fs, pieceSize, toNativeTorrentFormatFlag(torrentFormat)}.num_pieces();
#else
return lt::create_torrent(fs, pieceSize, paddedFileSizeLimit

View File

@@ -28,12 +28,14 @@
#pragma once
#include <libtorrent/version.hpp>
#include <QStringList>
#include <QThread>
namespace BitTorrent
{
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
enum class TorrentFormat
{
V1,
@@ -45,7 +47,7 @@ namespace BitTorrent
struct TorrentCreatorParams
{
bool isPrivate;
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
TorrentFormat torrentFormat;
#else
bool isAlignmentOptimized;
@@ -63,30 +65,30 @@ namespace BitTorrent
class TorrentCreatorThread final : public QThread
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(TorrentCreatorThread)
public:
explicit TorrentCreatorThread(QObject *parent = nullptr);
~TorrentCreatorThread() override;
TorrentCreatorThread(QObject *parent = nullptr);
~TorrentCreatorThread();
void create(const TorrentCreatorParams &params);
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
static int calculateTotalPieces(const QString &inputPath, const int pieceSize, const TorrentFormat torrentFormat);
#else
static int calculateTotalPieces(const QString &inputPath
, const int pieceSize, const bool isAlignmentOptimized, int paddedFileSizeLimit);
#endif
protected:
void run() override;
signals:
void creationFailure(const QString &msg);
void creationSuccess(const QString &path, const QString &branchPath);
void updateProgress(int progress);
private:
void run() override;
void sendProgressSignal(int currentPieceIdx, int totalPieces);
void checkInterruptionRequested() const;
TorrentCreatorParams m_params;
};

View File

@@ -43,8 +43,9 @@
#include <libtorrent/session.hpp>
#include <libtorrent/storage_defs.hpp>
#include <libtorrent/time.hpp>
#include <libtorrent/version.hpp>
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
#include <libtorrent/info_hash.hpp>
#endif
@@ -62,7 +63,6 @@
#include "base/utils/string.h"
#include "common.h"
#include "downloadpriority.h"
#include "loadtorrentparams.h"
#include "ltqhash.h"
#include "ltunderlyingtype.h"
#include "peeraddress.h"
@@ -83,7 +83,7 @@ namespace
, std::back_inserter(out), [](const DownloadPriority priority)
{
return static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(priority));
static_cast<LTUnderlyingType<lt::download_priority_t>>(priority));
});
return out;
}
@@ -95,7 +95,7 @@ namespace
return entry;
}
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry
, const lt::info_hash_t &hashes, const QMap<lt::tcp::endpoint, int> &trackerPeerCounts)
#else
@@ -110,8 +110,8 @@ namespace
int numNotWorking = 0;
QString firstTrackerMessage;
QString firstErrorMessage;
#ifdef QBT_USES_LIBTORRENT2
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1));
#if (LIBTORRENT_VERSION_NUM >= 20000)
const size_t numEndpoints = nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
trackerEntry.endpoints.reserve(static_cast<decltype(trackerEntry.endpoints)::size_type>(numEndpoints));
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
@@ -166,8 +166,8 @@ namespace
}
}
#else
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size());
trackerEntry.endpoints.reserve(static_cast<decltype(trackerEntry.endpoints)::size_type>(numEndpoints));
const int numEndpoints = nativeEntry.endpoints.size();
trackerEntry.endpoints.reserve(numEndpoints);
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
TrackerEntry::EndpointStats trackerEndpoint;
@@ -264,7 +264,7 @@ TorrentImpl::TorrentImpl(Session *session, lt::session *nativeSession
, m_session(session)
, m_nativeSession(nativeSession)
, m_nativeHandle(nativeHandle)
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
, m_infoHash(m_nativeHandle.info_hashes())
#else
, m_infoHash(m_nativeHandle.info_hash())
@@ -275,12 +275,12 @@ TorrentImpl::TorrentImpl(Session *session, lt::session *nativeSession
, m_tags(params.tags)
, m_ratioLimit(params.ratioLimit)
, m_seedingTimeLimit(params.seedingTimeLimit)
, m_operatingMode(params.operatingMode)
, m_operatingMode(params.forced ? TorrentOperatingMode::Forced : TorrentOperatingMode::AutoManaged)
, m_contentLayout(params.contentLayout)
, m_hasSeedStatus(params.hasSeedStatus)
, m_hasFirstLastPiecePriority(params.firstLastPiecePriority)
, m_useAutoTMM(params.savePath.isEmpty())
, m_isStopped(params.stopped)
, m_isStopped(params.paused)
, m_ltAddTorrentParams(params.ltAddTorrentParams)
{
if (m_useAutoTMM)
@@ -477,7 +477,7 @@ QVector<TrackerEntry> TorrentImpl::trackers() const
for (const lt::announce_entry &tracker : nativeTrackers)
{
const QString trackerURL = QString::fromStdString(tracker.url);
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
entries << fromNativeAnnouncerEntry(tracker, m_nativeHandle.info_hashes(), m_trackerPeerCounts[trackerURL]);
#else
entries << fromNativeAnnouncerEntry(tracker, m_trackerPeerCounts[trackerURL]);
@@ -702,7 +702,7 @@ bool TorrentImpl::belongsToCategory(const QString &category) const
return false;
}
TagSet TorrentImpl::tags() const
QSet<QString> TorrentImpl::tags() const
{
return m_tags;
}
@@ -716,18 +716,18 @@ bool TorrentImpl::addTag(const QString &tag)
{
if (!Session::isValidTag(tag))
return false;
if (hasTag(tag))
return false;
if (!m_session->hasTag(tag))
if (!hasTag(tag))
{
if (!m_session->addTag(tag))
return false;
if (!m_session->hasTag(tag))
if (!m_session->addTag(tag))
return false;
m_tags.insert(tag);
m_session->handleTorrentNeedSaveResumeData(this);
m_session->handleTorrentTagAdded(this, tag);
return true;
}
m_tags.insert(tag);
m_session->handleTorrentNeedSaveResumeData(this);
m_session->handleTorrentTagAdded(this, tag);
return true;
return false;
}
bool TorrentImpl::removeTag(const QString &tag)
@@ -796,10 +796,9 @@ QVector<DownloadPriority> TorrentImpl::filePriorities() const
const std::vector<lt::download_priority_t> fp = m_nativeHandle.get_file_priorities();
QVector<DownloadPriority> ret;
ret.reserve(static_cast<decltype(ret)::size_type>(fp.size()));
std::transform(fp.cbegin(), fp.cend(), std::back_inserter(ret), [](const lt::download_priority_t priority)
std::transform(fp.cbegin(), fp.cend(), std::back_inserter(ret), [](lt::download_priority_t priority)
{
return static_cast<DownloadPriority>(toLTUnderlyingType(priority));
return static_cast<DownloadPriority>(static_cast<LTUnderlyingType<lt::download_priority_t>>(priority));
});
return ret;
}
@@ -832,7 +831,6 @@ bool TorrentImpl::isDownloading() const
{
return m_state == TorrentState::Downloading
|| m_state == TorrentState::DownloadingMetadata
|| m_state == TorrentState::ForcedDownloadingMetadata
|| m_state == TorrentState::StalledDownloading
|| m_state == TorrentState::CheckingDownloading
|| m_state == TorrentState::PausedDownloading
@@ -865,7 +863,6 @@ bool TorrentImpl::isActive() const
return (uploadPayloadRate() > 0);
return m_state == TorrentState::DownloadingMetadata
|| m_state == TorrentState::ForcedDownloadingMetadata
|| m_state == TorrentState::Downloading
|| m_state == TorrentState::ForcedDownloading
|| m_state == TorrentState::Uploading
@@ -935,7 +932,7 @@ void TorrentImpl::updateState()
else if (m_session->isQueueingSystemEnabled() && isQueued())
m_state = TorrentState::QueuedDownloading;
else
m_state = isForced() ? TorrentState::ForcedDownloadingMetadata : TorrentState::DownloadingMetadata;
m_state = TorrentState::DownloadingMetadata;
}
else if ((m_nativeStatus.state == lt::torrent_status::checking_files)
&& (!isPaused() || (m_nativeStatus.flags & lt::torrent_flags::auto_managed)
@@ -1252,7 +1249,7 @@ QBitArray TorrentImpl::downloadingPieces() const
m_nativeHandle.get_download_queue(queue);
for (const lt::partial_piece_info &info : queue)
result.setBit(toLTUnderlyingType(info.piece_index));
result.setBit(static_cast<LTUnderlyingType<lt::piece_index_t>>(info.piece_index));
return result;
}
@@ -1262,7 +1259,7 @@ QVector<int> TorrentImpl::pieceAvailability() const
std::vector<int> avail;
m_nativeHandle.piece_availability(avail);
return {avail.cbegin(), avail.cend()};
return Vector::fromStdVector(avail);
}
qreal TorrentImpl::distributedCopies() const
@@ -1511,10 +1508,6 @@ void TorrentImpl::endReceivedMetadataHandling(const QString &savePath, const QSt
p.renamed_files[lt::file_index_t {i}] = fileNames[i].toStdString();
p.save_path = Utils::Fs::toNativePath(savePath).toStdString();
// Use qBittorrent default priority rather than libtorrent's (4)
p.file_priorities = std::vector(fileNames.size(), static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
reload();
// If first/last piece priority was specified when adding this torrent,
@@ -1524,7 +1517,6 @@ void TorrentImpl::endReceivedMetadataHandling(const QString &savePath, const QSt
m_maintenanceJob = MaintenanceJob::None;
updateStatus();
prepareResumeData(p);
m_session->handleTorrentMetadataReceived(this);
}
@@ -1628,10 +1620,8 @@ void TorrentImpl::moveStorage(const QString &newPath, const MoveStorageMode mode
void TorrentImpl::renameFile(const int index, const QString &path)
{
#ifndef QBT_USES_LIBTORRENT2
const QString oldPath = filePath(index);
m_oldPath[lt::file_index_t {index}].push_back(oldPath);
#endif
++m_renameCount;
m_nativeHandle.rename_file(lt::file_index_t {index}, Utils::Fs::toNativePath(path).toStdString());
}
@@ -1779,10 +1769,31 @@ void TorrentImpl::handleTorrentResumedAlert(const lt::torrent_resumed_alert *p)
void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p)
{
if (m_hasMissingFiles)
{
const auto havePieces = m_ltAddTorrentParams.have_pieces;
const auto unfinishedPieces = m_ltAddTorrentParams.unfinished_pieces;
const auto verifiedPieces = m_ltAddTorrentParams.verified_pieces;
// Update recent resume data but preserve existing progress
m_ltAddTorrentParams = p->params;
m_ltAddTorrentParams.have_pieces = havePieces;
m_ltAddTorrentParams.unfinished_pieces = unfinishedPieces;
m_ltAddTorrentParams.verified_pieces = verifiedPieces;
}
else
{
// Update recent resume data
m_ltAddTorrentParams = p->params;
}
m_ltAddTorrentParams.added_time = addedTime().toSecsSinceEpoch();
// We shouldn't save upload_mode flag to allow torrent operate normally on next run
m_ltAddTorrentParams.flags &= ~lt::torrent_flags::upload_mode;
if (m_maintenanceJob == MaintenanceJob::HandleMetadata)
{
m_ltAddTorrentParams = p->params;
m_ltAddTorrentParams.have_pieces.clear();
m_ltAddTorrentParams.verified_pieces.clear();
@@ -1791,36 +1802,6 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p)
m_session->findIncompleteFiles(metadata, m_savePath);
}
else
{
prepareResumeData(p->params);
}
}
void TorrentImpl::prepareResumeData(const lt::add_torrent_params &params)
{
if (m_hasMissingFiles)
{
const auto havePieces = m_ltAddTorrentParams.have_pieces;
const auto unfinishedPieces = m_ltAddTorrentParams.unfinished_pieces;
const auto verifiedPieces = m_ltAddTorrentParams.verified_pieces;
// Update recent resume data but preserve existing progress
m_ltAddTorrentParams = params;
m_ltAddTorrentParams.have_pieces = havePieces;
m_ltAddTorrentParams.unfinished_pieces = unfinishedPieces;
m_ltAddTorrentParams.verified_pieces = verifiedPieces;
}
else
{
// Update recent resume data
m_ltAddTorrentParams = params;
}
m_ltAddTorrentParams.added_time = addedTime().toSecsSinceEpoch();
// We shouldn't save upload_mode flag to allow torrent operate normally on next run
m_ltAddTorrentParams.flags &= ~lt::torrent_flags::upload_mode;
LoadTorrentParams resumeData;
resumeData.name = m_name;
@@ -1832,8 +1813,8 @@ void TorrentImpl::prepareResumeData(const lt::add_torrent_params &params)
resumeData.seedingTimeLimit = m_seedingTimeLimit;
resumeData.firstLastPiecePriority = m_hasFirstLastPiecePriority;
resumeData.hasSeedStatus = m_hasSeedStatus;
resumeData.stopped = m_isStopped;
resumeData.operatingMode = m_operatingMode;
resumeData.paused = m_isStopped;
resumeData.forced = (m_operatingMode == TorrentOperatingMode::Forced);
resumeData.ltAddTorrentParams = m_ltAddTorrentParams;
m_session->handleTorrentResumeDataReady(this, resumeData);
@@ -1867,18 +1848,15 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
// Remove empty leftover folders
// For example renaming "a/b/c" to "d/b/c", then folders "a/b" and "a" will
// be removed if they are empty
#ifndef QBT_USES_LIBTORRENT2
const QString oldFilePath = m_oldPath[p->index].takeFirst();
if (m_oldPath[p->index].isEmpty())
m_oldPath.remove(p->index);
#else
const QString oldFilePath = Utils::Fs::toUniformPath(p->old_name());
#endif
const QString newFilePath = Utils::Fs::toUniformPath(p->new_name());
QList<QStringView> oldPathParts = QStringView(oldFilePath).split('/', Qt::SkipEmptyParts);
if (m_oldPath[p->index].isEmpty())
m_oldPath.remove(p->index);
QVector<QStringRef> oldPathParts = oldFilePath.splitRef('/', QString::SkipEmptyParts);
oldPathParts.removeLast(); // drop file name part
QList<QStringView> newPathParts = QStringView(newFilePath).split('/', Qt::SkipEmptyParts);
QVector<QStringRef> newPathParts = newFilePath.splitRef('/', QString::SkipEmptyParts);
newPathParts.removeLast(); // drop file name part
#if defined(Q_OS_WIN)
@@ -1897,7 +1875,7 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
for (int i = (oldPathParts.size() - 1); i >= pathIdx; --i)
{
QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QString::fromLatin1("/")));
QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QLatin1String("/")));
oldPathParts.removeLast();
}
@@ -1911,14 +1889,12 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
void TorrentImpl::handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p)
{
LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"")
.arg(name(), filePath(toLTUnderlyingType(p->index))
.arg(name(), filePath(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index))
, QString::fromLocal8Bit(p->error.message().c_str())), Log::WARNING);
#ifndef QBT_USES_LIBTORRENT2
m_oldPath[p->index].removeFirst();
if (m_oldPath[p->index].isEmpty())
m_oldPath.remove(p->index);
#endif
--m_renameCount;
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
@@ -1932,13 +1908,13 @@ void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p)
qDebug("A file completed download in torrent \"%s\"", qUtf8Printable(name()));
if (m_session->isAppendExtensionEnabled())
{
QString name = filePath(toLTUnderlyingType(p->index));
QString name = filePath(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index));
if (name.endsWith(QB_EXT))
{
const QString oldName = name;
name.chop(QB_EXT.size());
qDebug("Renaming %s to %s", qUtf8Printable(oldName), qUtf8Printable(name));
renameFile(toLTUnderlyingType(p->index), name);
renameFile(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index), name);
}
}
}
@@ -1948,14 +1924,6 @@ void TorrentImpl::handleFileErrorAlert(const lt::file_error_alert *p)
m_lastFileError = {p->error, p->op};
}
#ifdef QBT_USES_LIBTORRENT2
void TorrentImpl::handleFilePrioAlert(const lt::file_prio_alert *)
{
if (m_nativeHandle.need_save_resume_data())
m_session->handleTorrentNeedSaveResumeData(this);
}
#endif
void TorrentImpl::handleMetadataReceivedAlert(const lt::metadata_received_alert *p)
{
Q_UNUSED(p);
@@ -1993,11 +1961,6 @@ void TorrentImpl::handleAlert(const lt::alert *a)
{
switch (a->type())
{
#ifdef QBT_USES_LIBTORRENT2
case lt::file_prio_alert::alert_type:
handleFilePrioAlert(static_cast<const lt::file_prio_alert*>(a));
break;
#endif
case lt::file_renamed_alert::alert_type:
handleFileRenamedAlert(static_cast<const lt::file_renamed_alert*>(a));
break;

View File

@@ -42,10 +42,10 @@
#include <QMap>
#include <QObject>
#include <QQueue>
#include <QSet>
#include <QString>
#include <QVector>
#include "base/tagset.h"
#include "infohash.h"
#include "speedmonitor.h"
#include "torrent.h"
@@ -54,7 +54,27 @@
namespace BitTorrent
{
class Session;
struct LoadTorrentParams;
struct AddTorrentParams;
struct LoadTorrentParams
{
lt::add_torrent_params ltAddTorrentParams {};
QString name;
QString category;
QSet<QString> tags;
QString savePath;
TorrentContentLayout contentLayout = TorrentContentLayout::Original;
bool firstLastPiecePriority = false;
bool hasSeedStatus = false;
bool forced = false;
bool paused = false;
qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
bool restored = false; // is existing torrent job?
};
enum class MoveStorageMode
{
@@ -76,7 +96,7 @@ namespace BitTorrent
class TorrentImpl final : public QObject, public Torrent
{
Q_DISABLE_COPY_MOVE(TorrentImpl)
Q_DISABLE_COPY(TorrentImpl)
Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentImpl)
public:
@@ -111,7 +131,7 @@ namespace BitTorrent
bool belongsToCategory(const QString &category) const override;
bool setCategory(const QString &category) override;
TagSet tags() const override;
QSet<QString> tags() const override;
bool hasTag(const QString &tag) const override;
bool addTag(const QString &tag) override;
bool removeTag(const QString &tag) override;
@@ -243,7 +263,7 @@ namespace BitTorrent
QString actualStorageLocation() const;
private:
using EventTrigger = std::function<void ()>;
typedef std::function<void ()> EventTrigger;
void updateStatus();
void updateStatus(const lt::torrent_status &nativeStatus);
@@ -252,9 +272,6 @@ namespace BitTorrent
void handleFastResumeRejectedAlert(const lt::fastresume_rejected_alert *p);
void handleFileCompletedAlert(const lt::file_completed_alert *p);
void handleFileErrorAlert(const lt::file_error_alert *p);
#ifdef QBT_USES_LIBTORRENT2
void handleFilePrioAlert(const lt::file_prio_alert *p);
#endif
void handleFileRenamedAlert(const lt::file_renamed_alert *p);
void handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p);
void handleMetadataReceivedAlert(const lt::metadata_received_alert *p);
@@ -280,7 +297,6 @@ namespace BitTorrent
void manageIncompleteFiles();
void applyFirstLastPiecePriority(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {});
void prepareResumeData(const lt::add_torrent_params &params);
void endReceivedMetadataHandling(const QString &savePath, const QStringList &fileNames);
void reload();
@@ -302,20 +318,18 @@ namespace BitTorrent
MaintenanceJob m_maintenanceJob = MaintenanceJob::None;
#ifndef QBT_USES_LIBTORRENT2
// Until libtorrent provided an "old_name" field in `file_renamed_alert`
// we relied on this workaround to remove empty leftover folders
// Until libtorrent provide an "old_name" field in `file_renamed_alert`
// we will rely on this workaround to remove empty leftover folders
QHash<lt::file_index_t, QVector<QString>> m_oldPath;
#endif
QHash<QString, QMap<lt::tcp::endpoint, int>> m_trackerPeerCounts;
FileErrorInfo m_lastFileError;
QHash<QString, QMap<lt::tcp::endpoint, int>> m_trackerPeerCounts;
// Persistent data
QString m_name;
QString m_savePath;
QString m_category;
TagSet m_tags;
QSet<QString> m_tags;
qreal m_ratioLimit;
int m_seedingTimeLimit;
TorrentOperatingMode m_operatingMode;

View File

@@ -31,6 +31,7 @@
#include <libtorrent/bencode.hpp>
#include <libtorrent/create_torrent.hpp>
#include <libtorrent/error_code.hpp>
#include <libtorrent/version.hpp>
#include <QByteArray>
#include <QDateTime>
@@ -60,7 +61,7 @@ namespace
{
if (QDir::isAbsolutePath(filePath)) continue;
const auto filePathElements = QStringView(filePath).split(u'/');
const auto filePathElements = filePath.splitRef('/');
// if at least one file has no root folder, no common root folder exists
if (filePathElements.count() <= 1) return {};
@@ -88,7 +89,10 @@ TorrentInfo::TorrentInfo(const TorrentInfo &other)
TorrentInfo &TorrentInfo::operator=(const TorrentInfo &other)
{
m_nativeInfo = other.m_nativeInfo;
if (this != &other)
{
m_nativeInfo = other.m_nativeInfo;
}
return *this;
}
@@ -166,25 +170,18 @@ TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexc
void TorrentInfo::saveToFile(const QString &path) const
{
if (!isValid())
throw RuntimeError {tr("Invalid metadata")};
throw RuntimeError {tr("Invalid metadata.")};
try
{
const auto torrentCreator = lt::create_torrent(*nativeInfo());
const lt::entry torrentEntry = torrentCreator.generate();
const lt::create_torrent torrentCreator = lt::create_torrent(*(nativeInfo()));
const lt::entry torrentEntry = torrentCreator.generate();
QFile torrentFile {path};
if (!torrentFile.open(QIODevice::WriteOnly))
throw RuntimeError(torrentFile.errorString());
QFile torrentFile {path};
if (!torrentFile.open(QIODevice::WriteOnly))
throw RuntimeError {torrentFile.errorString()};
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
if (torrentFile.error() != QFileDevice::NoError)
throw RuntimeError(torrentFile.errorString());
}
catch (const lt::system_error &err)
{
throw RuntimeError(QString::fromLocal8Bit(err.what()));
}
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
if (torrentFile.error() != QFileDevice::NoError)
throw RuntimeError {torrentFile.errorString()};
}
bool TorrentInfo::isValid() const
@@ -196,7 +193,7 @@ InfoHash TorrentInfo::infoHash() const
{
if (!isValid()) return {};
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
return m_nativeInfo->info_hashes();
#else
return m_nativeInfo->info_hash();
@@ -341,7 +338,7 @@ QVector<QUrl> TorrentInfo::urlSeeds() const
QByteArray TorrentInfo::metadata() const
{
if (!isValid()) return {};
#ifdef QBT_USES_LIBTORRENT2
#if (LIBTORRENT_VERSION_NUM >= 20000)
const lt::span<const char> infoSection {m_nativeInfo->info_section()};
return {infoSection.data(), static_cast<int>(infoSection.size())};
#else

View File

@@ -72,7 +72,7 @@ namespace BitTorrent
class Tracker final : public QObject, public Http::IRequestHandler, private Http::ResponseBuilder
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Tracker)
Q_DISABLE_COPY(Tracker)
struct TrackerAnnounceRequest;

View File

@@ -53,10 +53,10 @@ namespace BitTorrent
int numSeeds = -1;
int numLeeches = -1;
int numDownloaded = -1;
QString message {};
QString message;
};
QString url {};
QString url;
int tier = 0;
QVector<EndpointStats> endpoints {};
@@ -67,7 +67,7 @@ namespace BitTorrent
int numSeeds = -1;
int numLeeches = -1;
int numDownloaded = -1;
QString message {};
QString message;
};
bool operator==(const TrackerEntry &left, const TrackerEntry &right);

View File

@@ -35,16 +35,44 @@
#define QBT_APP_64BIT
#endif
inline const char C_TORRENT_FILE_EXTENSION[] = ".torrent";
inline const int MAX_TORRENT_SIZE = 100 * 1024 * 1024; // 100 MiB
const char C_TORRENT_FILE_EXTENSION[] = ".torrent";
const int MAX_TORRENT_SIZE = 100 * 1024 * 1024; // 100 MiB
template <typename T>
constexpr typename std::add_const_t<T> &asConst(T &t) noexcept { return t; }
constexpr typename std::add_const<T>::type &asConst(T &t) noexcept { return t; }
// Forward rvalue as const
template <typename T>
constexpr typename std::add_const_t<T> asConst(T &&t) noexcept { return std::move(t); }
constexpr typename std::add_const<T>::type asConst(T &&t) noexcept { return std::move(t); }
// Prevent const rvalue arguments
template <typename T>
void asConst(const T &&) = delete;
namespace List
{
// Replacement for the deprecated`QSet<T> QSet::fromList(const QList<T> &list)`
template <typename T>
QSet<T> toSet(const QList<T> &list)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return {list.cbegin(), list.cend()};
#else
return QSet<T>::fromList(list);
#endif
}
}
namespace Vector
{
// Replacement for the deprecated `QVector<T> QVector::fromStdVector(const std::vector<T> &vector)`
template <typename T>
QVector<T> fromStdVector(const std::vector<T> &vector)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return {vector.cbegin(), vector.cend()};
#else
return QVector<T>::fromStdVector(vector);
#endif
}
}

View File

@@ -137,9 +137,9 @@ bool Connection::acceptsGzipEncoding(QString codings)
{
// [rfc7231] 5.3.4. Accept-Encoding
const auto isCodingAvailable = [](const QList<QStringView> &list, const QStringView encoding) -> bool
const auto isCodingAvailable = [](const QVector<QStringRef> &list, const QString &encoding) -> bool
{
for (const QStringView &str : list)
for (const QStringRef &str : list)
{
if (!str.startsWith(encoding))
continue;
@@ -149,7 +149,7 @@ bool Connection::acceptsGzipEncoding(QString codings)
return true;
// [rfc7231] 5.3.1. Quality Values
const QStringView substr = str.mid(encoding.size() + 3); // ex. skip over "gzip;q="
const QStringRef substr = str.mid(encoding.size() + 3); // ex. skip over "gzip;q="
bool ok = false;
const double qvalue = substr.toDouble(&ok);
@@ -161,15 +161,15 @@ bool Connection::acceptsGzipEncoding(QString codings)
return false;
};
const QList<QStringView> list = QStringView(codings.remove(' ').remove('\t')).split(u',', Qt::SkipEmptyParts);
const QVector<QStringRef> list = codings.remove(' ').remove('\t').splitRef(',', QString::SkipEmptyParts);
if (list.isEmpty())
return false;
const bool canGzip = isCodingAvailable(list, QString::fromLatin1("gzip"));
const bool canGzip = isCodingAvailable(list, QLatin1String("gzip"));
if (canGzip)
return true;
const bool canAny = isCodingAvailable(list, QString::fromLatin1("*"));
const bool canAny = isCodingAvailable(list, QLatin1String("*"));
if (canAny)
return true;

View File

@@ -43,7 +43,7 @@ namespace Http
class Connection : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Connection)
Q_DISABLE_COPY(Connection)
public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);

View File

@@ -57,7 +57,7 @@ namespace
return in;
}
bool parseHeaderLine(const QStringView line, HeaderMap &out)
bool parseHeaderLine(const QString &line, HeaderMap &out)
{
// [rfc7230] 3.2. Header Fields
const int i = line.indexOf(':');
@@ -67,8 +67,8 @@ namespace
return false;
}
const QString name = line.left(i).trimmed().toString().toLower();
const QString value = line.mid(i + 1).trimmed().toString();
const QString name = line.leftRef(i).trimmed().toString().toLower();
const QString value = line.midRef(i + 1).trimmed().toString();
out[name] = value;
return true;
@@ -145,10 +145,10 @@ RequestParser::ParseResult RequestParser::doParse(const QByteArray &data)
return {ParseStatus::BadRequest, Request(), 0}; // TODO: SHOULD respond "501 Not Implemented"
}
bool RequestParser::parseStartLines(const QStringView data)
bool RequestParser::parseStartLines(const QString &data)
{
// we don't handle malformed request which uses `LF` for newline
const QList<QStringView> lines = data.split(QString::fromLatin1(CRLF), Qt::SkipEmptyParts);
const QVector<QStringRef> lines = data.splitRef(CRLF, QString::SkipEmptyParts);
// [rfc7230] 3.2.2. Field Order
QStringList requestLines;
@@ -267,7 +267,7 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
return false;
}
const QByteArray delimiter = Utils::String::unquote(QStringView(contentType).mid(idx + boundaryFieldName.size())).toLatin1();
const QByteArray delimiter = Utils::String::unquote(contentType.midRef(idx + boundaryFieldName.size())).toLatin1();
if (delimiter.isEmpty())
{
qWarning() << Q_FUNC_INFO << "boundary delimiter field empty!";
@@ -276,7 +276,7 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
// split data by "dash-boundary"
const QByteArray dashDelimiter = QByteArray("--") + delimiter + CRLF;
QVector<QByteArray> multipart = splitToViews(data, dashDelimiter, Qt::SkipEmptyParts);
QVector<QByteArray> multipart = splitToViews(data, dashDelimiter, QString::SkipEmptyParts);
if (multipart.isEmpty())
{
qWarning() << Q_FUNC_INFO << "multipart empty";
@@ -299,7 +299,7 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
bool RequestParser::parseFormData(const QByteArray &data)
{
const QVector<QByteArray> list = splitToViews(data, EOH, Qt::KeepEmptyParts);
const QVector<QByteArray> list = splitToViews(data, EOH, QString::KeepEmptyParts);
if (list.size() != 2)
{
@@ -311,13 +311,13 @@ bool RequestParser::parseFormData(const QByteArray &data)
const QByteArray payload = viewWithoutEndingWith(list[1], CRLF);
HeaderMap headersMap;
const QList<QStringView> headerLines = QStringView(headers).split(QString::fromLatin1(CRLF), Qt::SkipEmptyParts);
const QVector<QStringRef> headerLines = headers.splitRef(CRLF, QString::SkipEmptyParts);
for (const auto &line : headerLines)
{
if (line.trimmed().startsWith(QString::fromLatin1(HEADER_CONTENT_DISPOSITION), Qt::CaseInsensitive))
if (line.trimmed().startsWith(HEADER_CONTENT_DISPOSITION, Qt::CaseInsensitive))
{
// extract out filename & name
const QList<QStringView> directives = line.split(u';', Qt::SkipEmptyParts);
const QVector<QStringRef> directives = line.split(';', QString::SkipEmptyParts);
for (const auto &directive : directives)
{

View File

@@ -60,7 +60,7 @@ namespace Http
RequestParser();
ParseResult doParse(const QByteArray &data);
bool parseStartLines(QStringView data);
bool parseStartLines(const QString &data);
bool parseRequestLine(const QString &line);
bool parsePostMessage(const QByteArray &data);

View File

@@ -43,7 +43,7 @@ namespace Http
class Server final : public QTcpServer
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Server)
Q_DISABLE_COPY(Server)
public:
explicit Server(IRequestHandler *requestHandler, QObject *parent = nullptr);

View File

@@ -35,44 +35,43 @@
namespace Http
{
inline const char METHOD_GET[] = "GET";
inline const char METHOD_POST[] = "POST";
const char METHOD_GET[] = "GET";
const char METHOD_POST[] = "POST";
inline const char HEADER_CACHE_CONTROL[] = "cache-control";
inline const char HEADER_CONNECTION[] = "connection";
inline const char HEADER_CONTENT_DISPOSITION[] = "content-disposition";
inline const char HEADER_CONTENT_ENCODING[] = "content-encoding";
inline const char HEADER_CONTENT_LENGTH[] = "content-length";
inline const char HEADER_CONTENT_SECURITY_POLICY[] = "content-security-policy";
inline const char HEADER_CONTENT_TYPE[] = "content-type";
inline const char HEADER_DATE[] = "date";
inline const char HEADER_HOST[] = "host";
inline const char HEADER_ORIGIN[] = "origin";
inline const char HEADER_REFERER[] = "referer";
inline const char HEADER_REFERRER_POLICY[] = "referrer-policy";
inline const char HEADER_SET_COOKIE[] = "set-cookie";
inline const char HEADER_X_CONTENT_TYPE_OPTIONS[] = "x-content-type-options";
inline const char HEADER_X_FORWARDED_FOR[] = "x-forwarded-for";
inline const char HEADER_X_FORWARDED_HOST[] = "x-forwarded-host";
inline const char HEADER_X_FRAME_OPTIONS[] = "x-frame-options";
inline const char HEADER_X_XSS_PROTECTION[] = "x-xss-protection";
const char HEADER_CACHE_CONTROL[] = "cache-control";
const char HEADER_CONNECTION[] = "connection";
const char HEADER_CONTENT_DISPOSITION[] = "content-disposition";
const char HEADER_CONTENT_ENCODING[] = "content-encoding";
const char HEADER_CONTENT_LENGTH[] = "content-length";
const char HEADER_CONTENT_SECURITY_POLICY[] = "content-security-policy";
const char HEADER_CONTENT_TYPE[] = "content-type";
const char HEADER_DATE[] = "date";
const char HEADER_HOST[] = "host";
const char HEADER_ORIGIN[] = "origin";
const char HEADER_REFERER[] = "referer";
const char HEADER_REFERRER_POLICY[] = "referrer-policy";
const char HEADER_SET_COOKIE[] = "set-cookie";
const char HEADER_X_CONTENT_TYPE_OPTIONS[] = "x-content-type-options";
const char HEADER_X_FORWARDED_HOST[] = "x-forwarded-host";
const char HEADER_X_FRAME_OPTIONS[] = "x-frame-options";
const char HEADER_X_XSS_PROTECTION[] = "x-xss-protection";
inline const char HEADER_REQUEST_METHOD_GET[] = "GET";
inline const char HEADER_REQUEST_METHOD_HEAD[] = "HEAD";
inline const char HEADER_REQUEST_METHOD_POST[] = "POST";
const char HEADER_REQUEST_METHOD_GET[] = "GET";
const char HEADER_REQUEST_METHOD_HEAD[] = "HEAD";
const char HEADER_REQUEST_METHOD_POST[] = "POST";
inline const char CONTENT_TYPE_HTML[] = "text/html";
inline const char CONTENT_TYPE_CSS[] = "text/css";
inline const char CONTENT_TYPE_TXT[] = "text/plain; charset=UTF-8";
inline const char CONTENT_TYPE_JS[] = "application/javascript";
inline const char CONTENT_TYPE_JSON[] = "application/json";
inline const char CONTENT_TYPE_GIF[] = "image/gif";
inline const char CONTENT_TYPE_PNG[] = "image/png";
inline const char CONTENT_TYPE_FORM_ENCODED[] = "application/x-www-form-urlencoded";
inline const char CONTENT_TYPE_FORM_DATA[] = "multipart/form-data";
const char CONTENT_TYPE_HTML[] = "text/html";
const char CONTENT_TYPE_CSS[] = "text/css";
const char CONTENT_TYPE_TXT[] = "text/plain; charset=UTF-8";
const char CONTENT_TYPE_JS[] = "application/javascript";
const char CONTENT_TYPE_JSON[] = "application/json";
const char CONTENT_TYPE_GIF[] = "image/gif";
const char CONTENT_TYPE_PNG[] = "image/png";
const char CONTENT_TYPE_FORM_ENCODED[] = "application/x-www-form-urlencoded";
const char CONTENT_TYPE_FORM_DATA[] = "multipart/form-data";
// portability: "\r\n" doesn't guarantee mapping to the correct symbol
inline const char CRLF[] = {0x0D, 0x0A, '\0'};
const char CRLF[] = {0x0D, 0x0A, '\0'};
struct Environment
{
@@ -121,7 +120,7 @@ namespace Http
HeaderMap headers;
QByteArray content;
Response(uint code = 200, const QString &text = QLatin1String("OK"))
Response(uint code = 200, const QString &text = "OK")
: status {code, text}
{
}

View File

@@ -35,7 +35,7 @@ class QString;
class IconProvider : public QObject
{
Q_DISABLE_COPY_MOVE(IconProvider)
Q_DISABLE_COPY(IconProvider)
public:
static void initInstance();

View File

@@ -72,7 +72,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Log::MsgTypes)
class Logger : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Logger)
Q_DISABLE_COPY(Logger)
public:
static void initInstance();

View File

@@ -39,7 +39,7 @@ class QUrl;
class DownloadHandlerImpl final : public Net::DownloadHandler
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(DownloadHandlerImpl)
Q_DISABLE_COPY(DownloadHandlerImpl)
public:
DownloadHandlerImpl(Net::DownloadManager *manager, const Net::DownloadRequest &downloadRequest);

View File

@@ -98,7 +98,7 @@ namespace Net
class DownloadHandler : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(DownloadHandler)
Q_DISABLE_COPY(DownloadHandler)
public:
using QObject::QObject;
@@ -112,7 +112,7 @@ namespace Net
class DownloadManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(DownloadManager)
Q_DISABLE_COPY(DownloadManager)
public:
static void initInstance();

View File

@@ -43,7 +43,7 @@ namespace Net
class GeoIPManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(GeoIPManager)
Q_DISABLE_COPY(GeoIPManager)
public:
static void initInstance();

View File

@@ -34,7 +34,7 @@ namespace Net
{
class PortForwarder : public QObject
{
Q_DISABLE_COPY_MOVE(PortForwarder)
Q_DISABLE_COPY(PortForwarder)
public:
explicit PortForwarder(QObject *parent = nullptr);

View File

@@ -56,7 +56,7 @@ namespace Net
class ProxyConfigurationManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(ProxyConfigurationManager)
Q_DISABLE_COPY(ProxyConfigurationManager)
explicit ProxyConfigurationManager(QObject *parent = nullptr);
~ProxyConfigurationManager() = default;

View File

@@ -28,6 +28,7 @@
#include "reverseresolution.h"
#include <QHostAddress>
#include <QHostInfo>
#include <QString>

View File

@@ -29,9 +29,9 @@
#pragma once
#include <QCache>
#include <QHostAddress>
#include <QObject>
class QHostAddress;
class QHostInfo;
class QString;
@@ -40,7 +40,7 @@ namespace Net
class ReverseResolution : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(ReverseResolution)
Q_DISABLE_COPY(ReverseResolution)
public:
explicit ReverseResolution(QObject *parent = nullptr);

View File

@@ -122,7 +122,12 @@ Smtp::Smtp(QObject *parent)
connect(m_socket, &QIODevice::readyRead, this, &Smtp::readyRead);
connect(m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
connect(m_socket, &QAbstractSocket::errorOccurred, this, &Smtp::error);
#else
connect(m_socket, qOverload<QAbstractSocket::SocketError>(&QAbstractSocket::error)
, this, &Smtp::error);
#endif
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
@@ -451,7 +456,7 @@ void Smtp::authenticate()
// AUTH extension is supported, check which
// authentication modes are supported by
// the server
const QStringList auth = m_extensions["AUTH"].toUpper().split(' ', Qt::SkipEmptyParts);
const QStringList auth = m_extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts);
if (auth.contains("CRAM-MD5"))
{
qDebug() << "Using CRAM-MD5 authentication...";

View File

@@ -1,108 +0,0 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2021 Mike Tzou (Chocobo1)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#pragma once
#include <functional>
#include <set>
#include <type_traits>
#include "algorithm.h"
template <typename T, typename Compare = std::less<T>>
class OrderedSet : public std::set<T, Compare>
{
using ThisType = OrderedSet<T, Compare>;
public:
using BaseType = std::set<T, Compare>;
using key_type = typename BaseType::key_type;
using value_type = typename BaseType::value_type;
using BaseType::BaseType;
using BaseType::operator=;
// The following are custom functions that are in line with Qt API interface, such as `QSet`
#if __cplusplus < 202002L
bool contains(const key_type &value) const
{
return (BaseType::find(value) != BaseType::cend());
}
#endif
int count() const
{
return static_cast<int>(BaseType::size());
}
ThisType &intersect(const ThisType &other)
{
Algorithm::removeIf(*this, [&other](const value_type &value) -> bool
{
return !other.contains(value);
});
return *this;
}
bool isEmpty() const
{
return BaseType::empty();
}
template <typename std::enable_if_t<std::is_same_v<value_type, QString>, int> = 0>
QString join(const QString &separator) const
{
auto iter = BaseType::cbegin();
if (iter == BaseType::cend())
return {};
QString ret = *iter;
++iter;
while (iter != BaseType::cend())
{
ret.push_back(separator + *iter);
++iter;
}
return ret;
}
bool remove(const key_type &value)
{
return (BaseType::erase(value) > 0);
}
ThisType &unite(const ThisType &other)
{
BaseType::insert(other.cbegin(), other.cend());
return *this;
}
};

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