feat(actions): qbit rules set ratio and seed time limits (#264)

This commit is contained in:
Ludvig Lundgren 2022-05-03 14:57:47 +02:00 committed by GitHub
parent 43d37fc859
commit 8b1174c65f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 86 additions and 6 deletions

View file

@ -62,6 +62,12 @@ func (s *service) qbittorrent(qbt *qbittorrent.Client, action domain.Action, rel
if action.LimitDownloadSpeed > 0 { if action.LimitDownloadSpeed > 0 {
options["dlLimit"] = strconv.FormatInt(action.LimitDownloadSpeed, 10) options["dlLimit"] = strconv.FormatInt(action.LimitDownloadSpeed, 10)
} }
if action.LimitRatio > 0 {
options["ratioLimit"] = strconv.FormatFloat(action.LimitRatio, 'r', 2, 64)
}
if action.LimitSeedTime > 0 {
options["seedingTimeLimit"] = strconv.FormatInt(action.LimitSeedTime, 10)
}
log.Trace().Msgf("action qBittorrent options: %+v", options) log.Trace().Msgf("action qBittorrent options: %+v", options)

View file

@ -68,6 +68,8 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int) (
"ignore_rules", "ignore_rules",
"limit_download_speed", "limit_download_speed",
"limit_upload_speed", "limit_upload_speed",
"limit_ratio",
"limit_seed_time",
"reannounce_skip", "reannounce_skip",
"reannounce_delete", "reannounce_delete",
"reannounce_interval", "reannounce_interval",
@ -100,12 +102,14 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int) (
var a domain.Action var a domain.Action
var execCmd, execArgs, watchFolder, category, tags, label, savePath, webhookHost, webhookType, webhookMethod, webhookData sql.NullString var execCmd, execArgs, watchFolder, category, tags, label, savePath, webhookHost, webhookType, webhookMethod, webhookData sql.NullString
var limitUl, limitDl sql.NullInt64 var limitUl, limitDl, limitSeedTime sql.NullInt64
var limitRatio sql.NullFloat64
var clientID sql.NullInt32 var clientID sql.NullInt32
// filterID // filterID
var paused, ignoreRules sql.NullBool var paused, ignoreRules sql.NullBool
if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &clientID); err != nil { if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &clientID); err != nil {
log.Error().Stack().Err(err).Msg("action.findByFilterID: error scanning row") log.Error().Stack().Err(err).Msg("action.findByFilterID: error scanning row")
return nil, err return nil, err
} }
@ -122,6 +126,8 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int) (
a.LimitDownloadSpeed = limitDl.Int64 a.LimitDownloadSpeed = limitDl.Int64
a.LimitUploadSpeed = limitUl.Int64 a.LimitUploadSpeed = limitUl.Int64
a.LimitRatio = limitRatio.Float64
a.LimitSeedTime = limitSeedTime.Int64
a.WebhookHost = webhookHost.String a.WebhookHost = webhookHost.String
a.WebhookType = webhookType.String a.WebhookType = webhookType.String
@ -206,6 +212,8 @@ func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) {
"ignore_rules", "ignore_rules",
"limit_download_speed", "limit_download_speed",
"limit_upload_speed", "limit_upload_speed",
"limit_ratio",
"limit_seed_time",
"reannounce_skip", "reannounce_skip",
"reannounce_delete", "reannounce_delete",
"reannounce_interval", "reannounce_interval",
@ -237,11 +245,12 @@ func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) {
var a domain.Action var a domain.Action
var execCmd, execArgs, watchFolder, category, tags, label, savePath, webhookHost, webhookType, webhookMethod, webhookData sql.NullString var execCmd, execArgs, watchFolder, category, tags, label, savePath, webhookHost, webhookType, webhookMethod, webhookData sql.NullString
var limitUl, limitDl sql.NullInt64 var limitUl, limitDl, limitSeedTime sql.NullInt64
var limitRatio sql.NullFloat64
var clientID sql.NullInt32 var clientID sql.NullInt32
var paused, ignoreRules sql.NullBool var paused, ignoreRules sql.NullBool
if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &clientID); err != nil { if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &clientID); err != nil {
log.Error().Stack().Err(err).Msg("action.list: error scanning row") log.Error().Stack().Err(err).Msg("action.list: error scanning row")
return nil, err return nil, err
} }
@ -255,6 +264,8 @@ func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) {
a.LimitDownloadSpeed = limitDl.Int64 a.LimitDownloadSpeed = limitDl.Int64
a.LimitUploadSpeed = limitUl.Int64 a.LimitUploadSpeed = limitUl.Int64
a.LimitRatio = limitRatio.Float64
a.LimitSeedTime = limitSeedTime.Int64
a.WebhookHost = webhookHost.String a.WebhookHost = webhookHost.String
a.WebhookType = webhookType.String a.WebhookType = webhookType.String
@ -332,6 +343,8 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A
limitDL := toNullInt64(action.LimitDownloadSpeed) limitDL := toNullInt64(action.LimitDownloadSpeed)
limitUL := toNullInt64(action.LimitUploadSpeed) limitUL := toNullInt64(action.LimitUploadSpeed)
limitRatio := toNullFloat64(action.LimitRatio)
limitSeedTime := toNullInt64(action.LimitSeedTime)
clientID := toNullInt32(action.ClientID) clientID := toNullInt32(action.ClientID)
filterID := toNullInt32(int32(action.FilterID)) filterID := toNullInt32(int32(action.FilterID))
@ -352,6 +365,8 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A
"ignore_rules", "ignore_rules",
"limit_upload_speed", "limit_upload_speed",
"limit_download_speed", "limit_download_speed",
"limit_ratio",
"limit_seed_time",
"reannounce_skip", "reannounce_skip",
"reannounce_delete", "reannounce_delete",
"reannounce_interval", "reannounce_interval",
@ -378,6 +393,8 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A
action.IgnoreRules, action.IgnoreRules,
limitUL, limitUL,
limitDL, limitDL,
limitRatio,
limitSeedTime,
action.ReAnnounceSkip, action.ReAnnounceSkip,
action.ReAnnounceDelete, action.ReAnnounceDelete,
action.ReAnnounceInterval, action.ReAnnounceInterval,
@ -421,6 +438,9 @@ func (r *ActionRepo) Update(ctx context.Context, action domain.Action) (*domain.
limitDL := toNullInt64(action.LimitDownloadSpeed) limitDL := toNullInt64(action.LimitDownloadSpeed)
limitUL := toNullInt64(action.LimitUploadSpeed) limitUL := toNullInt64(action.LimitUploadSpeed)
limitRatio := toNullFloat64(action.LimitRatio)
limitSeedTime := toNullInt64(action.LimitSeedTime)
clientID := toNullInt32(action.ClientID) clientID := toNullInt32(action.ClientID)
filterID := toNullInt32(int32(action.FilterID)) filterID := toNullInt32(int32(action.FilterID))
@ -442,6 +462,8 @@ func (r *ActionRepo) Update(ctx context.Context, action domain.Action) (*domain.
Set("ignore_rules", action.IgnoreRules). Set("ignore_rules", action.IgnoreRules).
Set("limit_upload_speed", limitUL). Set("limit_upload_speed", limitUL).
Set("limit_download_speed", limitDL). Set("limit_download_speed", limitDL).
Set("limit_ratio", limitRatio).
Set("limit_seed_time", limitSeedTime).
Set("reannounce_skip", action.ReAnnounceSkip). Set("reannounce_skip", action.ReAnnounceSkip).
Set("reannounce_delete", action.ReAnnounceDelete). Set("reannounce_delete", action.ReAnnounceDelete).
Set("reannounce_interval", action.ReAnnounceInterval). Set("reannounce_interval", action.ReAnnounceInterval).
@ -509,6 +531,8 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []*domain.A
limitDL := toNullInt64(action.LimitDownloadSpeed) limitDL := toNullInt64(action.LimitDownloadSpeed)
limitUL := toNullInt64(action.LimitUploadSpeed) limitUL := toNullInt64(action.LimitUploadSpeed)
limitRatio := toNullFloat64(action.LimitRatio)
limitSeedTime := toNullInt64(action.LimitSeedTime)
clientID := toNullInt32(action.ClientID) clientID := toNullInt32(action.ClientID)
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
@ -528,6 +552,8 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []*domain.A
"ignore_rules", "ignore_rules",
"limit_upload_speed", "limit_upload_speed",
"limit_download_speed", "limit_download_speed",
"limit_ratio",
"limit_seed_time",
"reannounce_skip", "reannounce_skip",
"reannounce_delete", "reannounce_delete",
"reannounce_interval", "reannounce_interval",
@ -554,6 +580,8 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []*domain.A
action.IgnoreRules, action.IgnoreRules,
limitUL, limitUL,
limitDL, limitDL,
limitRatio,
limitSeedTime,
action.ReAnnounceSkip, action.ReAnnounceSkip,
action.ReAnnounceDelete, action.ReAnnounceDelete,
action.ReAnnounceInterval, action.ReAnnounceInterval,

View file

@ -147,6 +147,8 @@ CREATE TABLE action
ignore_rules BOOLEAN, ignore_rules BOOLEAN,
limit_upload_speed INT, limit_upload_speed INT,
limit_download_speed INT, limit_download_speed INT,
limit_ratio REAL,
limit_seed_time INT,
reannounce_skip BOOLEAN DEFAULT false, reannounce_skip BOOLEAN DEFAULT false,
reannounce_delete BOOLEAN DEFAULT false, reannounce_delete BOOLEAN DEFAULT false,
reannounce_interval INTEGER DEFAULT 7, reannounce_interval INTEGER DEFAULT 7,
@ -665,6 +667,13 @@ ALTER TABLE release_action_status_dg_tmp
ALTER TABLE "action" ALTER TABLE "action"
ADD COLUMN reannounce_max_attempts INTEGER DEFAULT 50; ADD COLUMN reannounce_max_attempts INTEGER DEFAULT 50;
`, `,
`
ALTER TABLE "action"
ADD COLUMN limit_ratio REAL DEFAULT 0;
ALTER TABLE "action"
ADD COLUMN limit_seed_time INTEGER DEFAULT 0;
`,
} }
const postgresSchema = ` const postgresSchema = `
@ -814,6 +823,8 @@ CREATE TABLE action
ignore_rules BOOLEAN, ignore_rules BOOLEAN,
limit_upload_speed INT, limit_upload_speed INT,
limit_download_speed INT, limit_download_speed INT,
limit_ratio REAL,
limit_seed_time INT,
reannounce_skip BOOLEAN DEFAULT false, reannounce_skip BOOLEAN DEFAULT false,
reannounce_delete BOOLEAN DEFAULT false, reannounce_delete BOOLEAN DEFAULT false,
reannounce_interval INTEGER DEFAULT 7, reannounce_interval INTEGER DEFAULT 7,
@ -1085,4 +1096,11 @@ var postgresMigrations = []string{
ALTER TABLE "action" ALTER TABLE "action"
ADD COLUMN reannounce_max_attempts INTEGER DEFAULT 50; ADD COLUMN reannounce_max_attempts INTEGER DEFAULT 50;
`, `,
`
ALTER TABLE "action"
ADD COLUMN limit_ratio REAL DEFAULT 0;
ALTER TABLE "action"
ADD COLUMN limit_seed_time INTEGER DEFAULT 0;
`,
} }

View file

@ -32,3 +32,10 @@ func toNullInt64(s int64) sql.NullInt64 {
Valid: s != 0, Valid: s != 0,
} }
} }
func toNullFloat64(s float64) sql.NullFloat64 {
return sql.NullFloat64{
Float64: s,
Valid: s != 0,
}
}

View file

@ -28,6 +28,8 @@ type Action struct {
IgnoreRules bool `json:"ignore_rules,omitempty"` IgnoreRules bool `json:"ignore_rules,omitempty"`
LimitUploadSpeed int64 `json:"limit_upload_speed,omitempty"` LimitUploadSpeed int64 `json:"limit_upload_speed,omitempty"`
LimitDownloadSpeed int64 `json:"limit_download_speed,omitempty"` LimitDownloadSpeed int64 `json:"limit_download_speed,omitempty"`
LimitRatio float64 `json:"limit_ratio,omitempty"`
LimitSeedTime int64 `json:"limit_seed_time,omitempty"`
ReAnnounceSkip bool `json:"reannounce_skip,omitempty"` ReAnnounceSkip bool `json:"reannounce_skip,omitempty"`
ReAnnounceDelete bool `json:"reannounce_delete,omitempty"` ReAnnounceDelete bool `json:"reannounce_delete,omitempty"`
ReAnnounceInterval int64 `json:"reannounce_interval,omitempty"` ReAnnounceInterval int64 `json:"reannounce_interval,omitempty"`

View file

@ -131,12 +131,14 @@ interface NumberFieldProps {
name: string; name: string;
label?: string; label?: string;
placeholder?: string; placeholder?: string;
step?: number;
} }
export const NumberField = ({ export const NumberField = ({
name, name,
label, label,
placeholder placeholder,
step,
}: NumberFieldProps) => ( }: NumberFieldProps) => (
<div className="col-span-12 sm:col-span-6"> <div className="col-span-12 sm:col-span-6">
<label htmlFor={name} className="block text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide"> <label htmlFor={name} className="block text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
@ -151,6 +153,7 @@ export const NumberField = ({
<div className="sm:col-span-2"> <div className="sm:col-span-2">
<input <input
type="number" type="number"
step={step}
{...field} {...field}
className={classNames( className={classNames(
meta.touched && meta.error meta.touched && meta.error

View file

@ -587,6 +587,8 @@ function FilterActions({ filter, values }: FilterActionsProps) {
ignore_rules: false, ignore_rules: false,
limit_upload_speed: 0, limit_upload_speed: 0,
limit_download_speed: 0, limit_download_speed: 0,
limit_ratio: 0,
limit_seed_time: 0,
reannounce_skip: false, reannounce_skip: false,
reannounce_delete: false, reannounce_delete: false,
reannounce_interval: 7, reannounce_interval: 7,
@ -746,7 +748,19 @@ function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemPr
label="Limit upload speed (KB/s)" label="Limit upload speed (KB/s)"
/> />
</div> </div>
</div>
<div className="mt-6 grid grid-cols-12 gap-6">
<NumberField
name={`actions.${idx}.limit_ratio`}
label="Ratio limit"
step={0.5}
/>
<NumberField
name={`actions.${idx}.limit_seed_time`}
label="Seed time limit (seconds)"
/>
</div>
</div>
<div className="col-span-6"> <div className="col-span-6">
<SwitchGroup <SwitchGroup
name={`actions.${idx}.paused`} name={`actions.${idx}.paused`}

View file

@ -68,6 +68,8 @@ interface Action {
ignore_rules?: boolean; ignore_rules?: boolean;
limit_upload_speed?: number; limit_upload_speed?: number;
limit_download_speed?: number; limit_download_speed?: number;
limit_ratio?: number;
limit_seed_time?: number;
reannounce_skip: boolean; reannounce_skip: boolean;
reannounce_delete: boolean; reannounce_delete: boolean;
reannounce_interval: number; reannounce_interval: number;