From a6c1944df86d45630afc49573b7fb0355cfe7412 Mon Sep 17 00:00:00 2001
From: ze0s <43699394+zze0s@users.noreply.github.com>
Date: Tue, 17 Jan 2023 23:34:03 +0100
Subject: [PATCH] feat(downloadclients): qBit rules add speed threshold
condition (#652)
* fix: qbit add rules min check
* feat(downloadclients): add check condition
* feat(downloadclient): return on rejection
---
internal/action/qbittorrent.go | 86 +++++++++++-----
internal/domain/client.go | 18 +++-
web/src/components/inputs/input_wide.tsx | 99 +++++++++++++++++++
web/src/components/inputs/select.tsx | 4 +-
web/src/domain/constants.ts | 12 +++
.../forms/settings/DownloadClientForms.tsx | 9 +-
6 files changed, 194 insertions(+), 34 deletions(-)
diff --git a/internal/action/qbittorrent.go b/internal/action/qbittorrent.go
index 667019e..0d1aa0a 100644
--- a/internal/action/qbittorrent.go
+++ b/internal/action/qbittorrent.go
@@ -104,6 +104,8 @@ func (s *service) prepareQbitOptions(action *domain.Action) (map[string]string,
func (s *service) qbittorrentCheckRulesCanDownload(ctx context.Context, action *domain.Action, client *domain.DownloadClient, qbt *qbittorrent.Client) ([]string, error) {
s.log.Trace().Msgf("action qBittorrent: %v check rules", action.Name)
+ checked := false
+
// check for active downloads and other rules
if client.Settings.Rules.Enabled && !action.IgnoreRules {
activeDownloads, err := qbt.GetTorrentsActiveDownloadsCtx(ctx)
@@ -117,33 +119,16 @@ func (s *service) qbittorrentCheckRulesCanDownload(ctx context.Context, action *
// if max active downloads reached, check speed and if lower than threshold add anyway
if len(activeDownloads) >= client.Settings.Rules.MaxActiveDownloads {
if client.Settings.Rules.IgnoreSlowTorrents {
- // check speeds of downloads
- info, err := qbt.GetTransferInfoCtx(ctx)
- if err != nil {
- return nil, errors.Wrap(err, "could not get transfer info")
+ if client.Settings.Rules.IgnoreSlowTorrentsCondition == domain.IgnoreSlowTorrentsModeMaxReached {
+ rejections, err := s.qbittorrentCheckIgnoreSlow(ctx, client, qbt)
+ if err != nil {
+ return rejections, err
+ }
+
+ s.log.Debug().Msg("active downloads are slower than set limit, lets add it")
+
+ checked = true
}
-
- // if current transfer speed is more than threshold return out and skip
- // DlInfoSpeed is in bytes so lets convert to KB to match DownloadSpeedThreshold
- if info.DlInfoSpeed/1024 >= client.Settings.Rules.DownloadSpeedThreshold {
- rejection := fmt.Sprintf("max active downloads reached and total download speed above threshold: %d, skipping", client.Settings.Rules.DownloadSpeedThreshold)
-
- s.log.Debug().Msg(rejection)
-
- return []string{rejection}, nil
- }
-
- // if current transfer speed is more than threshold return out and skip
- // UpInfoSpeed is in bytes so lets convert to KB to match UploadSpeedThreshold
- if info.UpInfoSpeed/1024 >= client.Settings.Rules.UploadSpeedThreshold {
- rejection := fmt.Sprintf("max active downloads reached and total upload speed above threshold: %d, skipping", client.Settings.Rules.UploadSpeedThreshold)
-
- s.log.Debug().Msg(rejection)
-
- return []string{rejection}, nil
- }
-
- s.log.Debug().Msg("active downloads are slower than set limit, lets add it")
} else {
rejection := "max active downloads reached, skipping"
@@ -153,7 +138,56 @@ func (s *service) qbittorrentCheckRulesCanDownload(ctx context.Context, action *
}
}
}
+
+ if !checked && client.Settings.Rules.IgnoreSlowTorrentsCondition == domain.IgnoreSlowTorrentsModeAlways {
+ rejections, err := s.qbittorrentCheckIgnoreSlow(ctx, client, qbt)
+ if err != nil {
+ return rejections, err
+ }
+
+ if len(rejections) > 0 {
+ return rejections, nil
+ }
+ }
}
return nil, nil
}
+
+func (s *service) qbittorrentCheckIgnoreSlow(ctx context.Context, client *domain.DownloadClient, qbt *qbittorrent.Client) ([]string, error) {
+ // get transfer info
+ info, err := qbt.GetTransferInfoCtx(ctx)
+ if err != nil {
+ return nil, errors.Wrap(err, "could not get transfer info")
+ }
+
+ s.log.Debug().Msgf("checking client ignore slow torrent rules: %+v", info)
+
+ if client.Settings.Rules.DownloadSpeedThreshold > 0 {
+ // if current transfer speed is more than threshold return out and skip
+ // DlInfoSpeed is in bytes so lets convert to KB to match DownloadSpeedThreshold
+ if info.DlInfoSpeed/1024 >= client.Settings.Rules.DownloadSpeedThreshold {
+ rejection := fmt.Sprintf("max active downloads reached and total download speed (%d) above threshold: (%d), skipping", info.DlInfoSpeed/1024, client.Settings.Rules.DownloadSpeedThreshold)
+
+ s.log.Debug().Msg(rejection)
+
+ return []string{rejection}, nil
+ }
+ }
+
+ if client.Settings.Rules.UploadSpeedThreshold > 0 {
+ // if current transfer speed is more than threshold return out and skip
+ // UpInfoSpeed is in bytes so lets convert to KB to match UploadSpeedThreshold
+ if info.UpInfoSpeed/1024 >= client.Settings.Rules.UploadSpeedThreshold {
+ rejection := fmt.Sprintf("max active downloads reached and total upload speed (%d) above threshold: (%d), skipping", info.UpInfoSpeed/1024, client.Settings.Rules.UploadSpeedThreshold)
+
+ s.log.Debug().Msg(rejection)
+
+ return []string{rejection}, nil
+ }
+ }
+
+ s.log.Debug().Msg("active downloads are slower than set limit, lets add it")
+
+ return nil, nil
+}
diff --git a/internal/domain/client.go b/internal/domain/client.go
index 60f809f..cf8b973 100644
--- a/internal/domain/client.go
+++ b/internal/domain/client.go
@@ -44,11 +44,12 @@ type DownloadClientSettings struct {
}
type DownloadClientRules struct {
- Enabled bool `json:"enabled"`
- MaxActiveDownloads int `json:"max_active_downloads"`
- IgnoreSlowTorrents bool `json:"ignore_slow_torrents"`
- DownloadSpeedThreshold int64 `json:"download_speed_threshold"`
- UploadSpeedThreshold int64 `json:"upload_speed_threshold"`
+ Enabled bool `json:"enabled"`
+ MaxActiveDownloads int `json:"max_active_downloads"`
+ IgnoreSlowTorrents bool `json:"ignore_slow_torrents"`
+ IgnoreSlowTorrentsCondition IgnoreSlowTorrentsCondition `json:"ignore_slow_torrents_condition,omitempty"`
+ DownloadSpeedThreshold int64 `json:"download_speed_threshold"`
+ UploadSpeedThreshold int64 `json:"upload_speed_threshold"`
}
type BasicAuth struct {
@@ -57,6 +58,13 @@ type BasicAuth struct {
Password string `json:"password,omitempty"`
}
+type IgnoreSlowTorrentsCondition string
+
+const (
+ IgnoreSlowTorrentsModeAlways IgnoreSlowTorrentsCondition = "ALWAYS"
+ IgnoreSlowTorrentsModeMaxReached IgnoreSlowTorrentsCondition = "MAX_DOWNLOADS_REACHED"
+)
+
type DownloadClientType string
const (
diff --git a/web/src/components/inputs/input_wide.tsx b/web/src/components/inputs/input_wide.tsx
index 2d3254b..ee6b07a 100644
--- a/web/src/components/inputs/input_wide.tsx
+++ b/web/src/components/inputs/input_wide.tsx
@@ -5,6 +5,8 @@ import { useToggle } from "../../hooks/hooks";
import { EyeIcon, EyeSlashIcon } from "@heroicons/react/24/solid";
import { Switch } from "@headlessui/react";
import { ErrorField } from "./common";
+import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
+import { SelectFieldProps } from "./select";
interface TextFieldWideProps {
name: string;
@@ -303,3 +305,100 @@ export const SwitchGroupWideRed = ({
);
+const Input = (props: InputProps) => {
+ return (
+