qBittorrent
qBittorrent copied to clipboard
Advanced scheduler
This will close #8804 but there is no fancy UI.
- Reworked the existing BandwidthScheduler. Introduced new data classes ScheduleDay and ScheduleEntry.
- Global/alt/scheduled limit prioritization: Alternative limits first, scheduled limits (capped at global limits) second, fallback to global limits.
- Schedule has a Pause option that pauses/resumes the native lt::session. This is (at the time of writing) prioritized more than the alternative limits.
- The schedule is stored in a JSON file. The file is updated when user presses Apply/OK in settings.
- Both JSON data and user input is validated.
- The old scheduler settings are imported in the new scheduler and the old settings are removed.
- Schedule tables are editable in-line and have copy-paste, 'clear all', and 'copy to other days' functionality.
- WebUI is on par with native UI except for editing entries. (User can remove an entry and add a new one to do the same thing.)
- Status bar displays session paused state.
Current UI
Native UI | WebUI |
---|---|
![]() |
![]() |
![]() |
![]() |
Fancy grid GUI
Take a look at #8804 for the concept art by @Liggliluff Not implemented in this PR.
~~Uh-oh, GitHub is struggling~~ edit: (about 5 minutes?) after submitting a support request explaining the issue, it's fixed. nice
Draft design idea
Example UI
/ START - END / DL UL
1 / |00:00| - |08:30| / |100| | 50| |X|
2 / |12:45| - |16:20| / |200| |150| |X|
3 / |00:00| - |00:00| / | 0| | 0|
The 3rd index is an empty list item. When user edits one of the boxes, the item (TimeRange
) gets added to the list (QList<TimeRange>
of Day
). Then the edits are the same as editing the others. Instead of displaying all empty boxes, we can instead put an Add
button there. The button would create an empty TimeRange
instead of getting an initial value for one of the fields. This is a design choice.
UI Functions
The user will be able to add
, edit
and remove
items. When adding and editing, the time range can be anything: even earlier than the first item on the list. So, inserting/moving will be possible.
Conflicting times
Now, when adding/editing a TimeRange
, it's not going to be possible to input a time range that conflicts with any of the other ones. To check those, I'll probably add a conflicts()
function.
Currently, only the time range data type is implemented. There's the UI, the model for the UI, and the file handler (to read from json).
I played around with Qt Creator for a little bit and I have some idea of how it can be done. I'm thinking QAbstractListModel
or QAbstractItemModel
for the model. As for the View, the basic one (not the fancy grid one), it's going to be QTabWidget
and inside each, a QVBoxLayout
with a button and probably a QListView
.
Any ideas are welcome :smile:
@sledgehammer999 Can you create a feature branch for this? I just realized it's not just reading the JSON and populating a list of TimeRanges, but there also needs to be a timed event that sets the DL and UL rates according to the schedule. And then there are the two UIs. I think this needs more people.
Unless I am mistaken github allows other people to push to your branch once you have opened a PR based on it. So your branch can be the feature branch you're asking for.
@sledgehammer999 yeah I guess that works
Current GUI:
-
The old system where there was only one alternative rate limit is gone since this feature replaces that, so I deleted some methods and method calls for that. I hardcoded one to return
false
to not mess with other code. If needed, they will be messed with. -
Currently, the tab labels (days of week) are also hardcoded. They should probably be populated in runtime just after reading the JSON file.
-
The add button may be replaced with an empty entry in the list views; when user edits one field, the item gets added to the list.
-
Also, since I am removing the old scheduler feature, and the grid UI will need more than one speed limits, I think we can make it so that user can change between those limits on demand. As in, right click to system tray will have "Alternative rates" submenu, and user can select one or the same from the status bar of the main window.
Unrelated fun fact: the last commit was the first one that I actually successfully built and used; before I was just editing code and running static checks.
@FurkanKambay I quickly skimmed your posts. I didn't read any of the code. Here are my thoughts and suggestions. If something is interfering with what you have already decided/implemented disregard it.
I have given thought to this issue a long time ago, but I lack the time and motivation to actually code it.
Personally I like the way the scheduler is implemented in the program foobar2000. IMO, it is simpler in terms of UI design but as powerful(or even more) as other implementations.
In case you aren't familiar with it, I post 2 screenshots AND explain it.
Screenshots:
Basically we let the user define a specific Date-Time(timestamp) and what happens(action) when that Date-Time comes. So the UI just represents a list of timestamps and their associated actions. In the 1st iteration of the implementation of the scheduler the only allowed action is to enable/disable alternative speed limits.
The next iterations can broaden the available actions and even allow groups of actions per timestamp. Ideas for actions: pause/start session, specific DL, UL limits (making alternative limits useless), running external program
Also the timestamp should be flexible like it is on foobar2000
: Either a specific timestamp or something like "On Tuesdays and Mondays at 12:00 PM do this action". aka per day actions.
In this type of scheduler the user is responsible to set a new timestamp that reverses the action of a previous timestamp. This type of scheduler doesn't deal in timestamp ranges.
A few words on how to approach this PR. There are 3 distinct places where coding is done.
- The core
- The GUI
- The WebUI
The core
IMO, no matter what UI representation of the scheduler you choose the core should care about one thing: "At timestamp X do this". BandwidthScheduler
should be reworked to do the following:
- Hold the list of timestamp,actions
- Interpret the list in such a way that it knows what's the next/earliest event based on currrent time
- Run a timer regularly. On timeout check current time and compare to the next in line event. If it is time for the event, instruct the
Session
(and related classes) on the actions required (eg set X DL speed). Drop the event from the list if it isn't recurring. Also don't forget to sanitize the list in case the user has changed the clock between 2 timeouts and some events have gone stale.
GUI and WebUI Once core is implemented the interface implementation is almost trivial.
The above is just in abstract. When actually coding it you might need to make modifications.
I hope I didn't give you headaches.
Does it read which weekday should be first, and the time and date formats from the system?
Does it read which weekday should be first, and the time and date formats from the system?
Why does this matter?
Because you are supposed to support the user's format.
I, as a European, don't want to use the American format just like how an American doesn't want to use the European format. (If they want to use a different format, they can change it in the regional settings).
The UI representation is independent of the internal one. The UI should display the formats in the current locale anyway.
@sledgehammer999
I actually like that idea but have you seen the grid UI? (GUI 2) Since that's only related to bandwidth limiting, it won't be able to show other actions. And I think the grid UI should be preserved even if there's a more advanced UI because it's more user-friendly. (or you could say easier to visualize)
How about we still do the grid UI inside the "Speed" section and create a new section like "Scheduler" for the one you proposed? (which will replace the current list UI - also, it needs a separate section anyway)
The grid UI would only show the set DL rate
and set UL rate
actions (and the user will be able to modify them), and the new section will show all of the actions or the actions other than "set DL-UL speed" if there are enough of those other actions. I'm not sure what's the best option but I'm sure the grid UI should be there.
Also, about time ranges vs time stamps: we could just convert to time stamps.
The grid might look nicer, but IMO it will be a lot harder to implement.
How about we still do the grid UI inside the "Speed" section and create a new section like "Scheduler" for the one you proposed? (which will replace the current list UI - also, it needs a separate section anyway)
IMO it doesn't make sense to essentially have duplicate schedulers.
This type of scheduler doesn't deal in timestamp ranges.
On 2nd thought, I might be wrong. Users might want to apply certain limits when they start the application during specific periods of a day. eg "Mondays between 12 A.M and 3:00 P.M give unlimited DL speed".
@sledgehammer999 I mean, I was going to do the grid UI after the rest was finished, so there is no reason to worry about that right now anyway; let's focus on the feature.
I have a question. In foobar2000, the date can be set alongside the time of day. Do you think that should be the case here, too? And foobar2000 also has seconds in the time of day; I think minute-accuracy is enough. What do you think about using crontab-like expressions in JSON? e.g. 16:20-18:30 1-3,5
would mean "from 16:20 to 18:30 on Monday through Wednesday and Friday every week". (obviously not the same as crontab but similar)
Also, do we keep the time ranges for bandwidth limit actions and use time stamps for instant actions like "pause all" or "execute command x"?
Personally I don't code the WebUI and I don't care for it. IIRC @Chocobo1 and @glassez do. So they are more suitable to comment on the format of the JSON.
But, IMO that is the 2nd step. The first is to implement it solidly in the core and how it is going to interact with the Session class.
I think minute-accuracy is enough.
Sure. I think QDateTimeEdit/QTimeEdit can be made to hide the seconds.
In any case here is how the foobar2000 dialog looks for the other 2 settings of the dropdown menu:
Also, do we keep the time ranges for bandwidth limit actions and use time stamps for instant actions like "pause all" or "execute command x"?
For time ranges you just need a start
and end
timestamp. I use the term "timestamp" loosely. In the case of selecting days (Monday, Wednesday) of the week it mainly refers to the time of the day.
If you're talking about your specific TimeRange class, I have no comment about it, since I haven't read the code.
@sledgehammer999
I just realized that there aren't many "actions" available. I mean, pausing the session is just the same as setting the rate limits to 0. "Execute command" might work, but how is that related to qBittorrent? The user can just use another program for that.
I tried to find an action other than setting the DL/UL rate limits but couldn't find any. Is there an action that I can't think of or should I just continue with the original idea? (plus the recurrence feature)
Replying to your last comment:
I didn't say anything about the WebUI. The JSON would be for storing the schedule on disk.
OK, so it'll be minute accuracy and a weekly schedule which was already what I've been doing, so that's great. (apart from recurrence about which I have an idea)
edit: just to clarify, the weekly
events in foobar2000 where you pick days in a week. The once
won't be there and daily
is just weekly
where all days are selected. So this is an example crontab-like expression of everyday between 16:20-18:30: 16:20-18:30 *
or 0,1,2,3,4,5,6
instead of *
. And the same but only Mondays and Fridays: 16:2-18:30 1,5
(and no I wasn't talking about the class, just time-ranges vs points-in-time aka stamps)
Hi, I have qbittorent installed on an headless server so I will manage it only from the WebUI. Will this feature avaible from WebUI too? If not, there is some way to configure the scheduler (ex. from CLI)?
@Ansem93 Well, they depends. If anyone wants to implement the WebUI, or if I decide that I'll take a shot at it, then sure. Otherwise, probably at a later time as a separate feature. As for the command line, the schedule will be in a JSON file and since you can edit a file in command line, yes.
Also, please note that this feature might take long to be released, there is no guarantee.
Yes, please!!!! :-)
@FurkanKambay sorry for not following through. I don't have much to contribute at this point. If you want, continue as you see it best. Start with minimal set of actions/possibilities and if need be it will get extended in the future. I am not sure, if I'll be able to review code in the future for this.
@sledgehammer999 No worries. I'll continue working on this when I have the time.
If anyone is wondering, I'm delaying working on this because I couldn't get Qt Creator (also make/qmake) to work because I have very little experience with C++ and its tools, lol. I had it working in a KDE neon setup, then I had to format the drive; I couldn't get it to work since then.
I'm not gonna forget this, it's just gonna be a while until I can work on it.
@FurkanKambay any update on this PR?
@xavier2k6
Hey, sorry about this. I haven't been able to work on this partly because I still can't get the environment to work again. I try for a day, some things don't want to work, then I give up for another few months and here we are. I still don't know what I'm doing differently than I did the first time I set up the environment. I still wish I didn't format that drive.
Also, you can tell most of my work on this have been in just plain text and the code part is really small. Wish I was more familiar with C++ and Qt so I could just put those words into proper code. Someone more experienced in C++ (and familiar with the codebase) could probably take over if they desired to do so, but if nobody wants, I think I will take a stab at it again soon.
I'm sorry if anyone is waiting for this feature and seeing no update from me. Guess it has been 2 years huh.
@FurkanKambay What kind of difficulties are you having with setting up the environment? If you are on Debian or Ubuntu or a derivative of those, you should be able to build easily with this guide: https://github.com/qbittorrent/qBittorrent/wiki/Compilation:-Debian-and-Ubuntu.
To improve the debugging experience with gdb
, you can follow this guide: https://github.com/qbittorrent/qBittorrent/wiki/Setup-GDB-with-Qt-pretty-printers, which then integrates nicely with this: https://github.com/qbittorrent/qBittorrent/wiki/Using-VSCode-for-qBittorrent-development (although I have to update it, as I'm now using clangd and the corresponding extension for language intelligence features).
You don't have to use QtCreator at all (although it is convenient for certain specific tasks). You can chain together many standalone tools in standard ways.
@FranciscoPombal well I don't remember what error I had gotten before but I did follow those pages. Now I got it to work by the way. Just one thing: in the compilation guide, I still get an error on the make
step after configuring: /usr/bin/ld: cannot find -lvals-NOTFOUND
after it enters the src
directory (I looked it up but I have no idea what lvals
is supposed to be). But this time I tried just starting debugging only via VS Code and it worked just fine. I think I was trying to compile manually before as well.
Anyway, TLDR: I got it working now so I'm gonna first solve conflicts, then try to go from there! Thank you!
Current status
- the add button brings up a time range dialog. only DL rate limit right now; will add UL at a later time when json storage is implemented
- also need to check if the time range conflicts with another in the same day schedule - again, needs json storage
- the add button doesn't add anything to the scheduler view - need json as well
TODOs
- implement json storage in user settings directory
- the scheduler view on optionsdialog will show the time range, DL and UL limits for each entry, maybe editable in-place or with an edit button to bring up the same dialog used for adding a new entry
- background service (don't know too much about the codebase but I'm sure there is a scheduler type thing already, I could use that; otherwise I'm sure I'll figure it out when the time comes)
SIDE QUESTION: do we have a method for only compiling files that have changed?