mirror of
https://github.com/idanoo/autobrr
synced 2025-07-22 16:29:12 +00:00
feat(actions): qbit rules set ratio and seed time limits (#264)
This commit is contained in:
parent
43d37fc859
commit
8b1174c65f
8 changed files with 86 additions and 6 deletions
|
@ -62,6 +62,12 @@ func (s *service) qbittorrent(qbt *qbittorrent.Client, action domain.Action, rel
|
|||
if action.LimitDownloadSpeed > 0 {
|
||||
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)
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int) (
|
|||
"ignore_rules",
|
||||
"limit_download_speed",
|
||||
"limit_upload_speed",
|
||||
"limit_ratio",
|
||||
"limit_seed_time",
|
||||
"reannounce_skip",
|
||||
"reannounce_delete",
|
||||
"reannounce_interval",
|
||||
|
@ -100,12 +102,14 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int) (
|
|||
var a domain.Action
|
||||
|
||||
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
|
||||
// filterID
|
||||
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")
|
||||
return nil, err
|
||||
}
|
||||
|
@ -122,6 +126,8 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int) (
|
|||
|
||||
a.LimitDownloadSpeed = limitDl.Int64
|
||||
a.LimitUploadSpeed = limitUl.Int64
|
||||
a.LimitRatio = limitRatio.Float64
|
||||
a.LimitSeedTime = limitSeedTime.Int64
|
||||
|
||||
a.WebhookHost = webhookHost.String
|
||||
a.WebhookType = webhookType.String
|
||||
|
@ -206,6 +212,8 @@ func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) {
|
|||
"ignore_rules",
|
||||
"limit_download_speed",
|
||||
"limit_upload_speed",
|
||||
"limit_ratio",
|
||||
"limit_seed_time",
|
||||
"reannounce_skip",
|
||||
"reannounce_delete",
|
||||
"reannounce_interval",
|
||||
|
@ -237,11 +245,12 @@ func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) {
|
|||
var a domain.Action
|
||||
|
||||
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 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")
|
||||
return nil, err
|
||||
}
|
||||
|
@ -255,6 +264,8 @@ func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) {
|
|||
|
||||
a.LimitDownloadSpeed = limitDl.Int64
|
||||
a.LimitUploadSpeed = limitUl.Int64
|
||||
a.LimitRatio = limitRatio.Float64
|
||||
a.LimitSeedTime = limitSeedTime.Int64
|
||||
|
||||
a.WebhookHost = webhookHost.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)
|
||||
limitUL := toNullInt64(action.LimitUploadSpeed)
|
||||
limitRatio := toNullFloat64(action.LimitRatio)
|
||||
limitSeedTime := toNullInt64(action.LimitSeedTime)
|
||||
clientID := toNullInt32(action.ClientID)
|
||||
filterID := toNullInt32(int32(action.FilterID))
|
||||
|
||||
|
@ -352,6 +365,8 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A
|
|||
"ignore_rules",
|
||||
"limit_upload_speed",
|
||||
"limit_download_speed",
|
||||
"limit_ratio",
|
||||
"limit_seed_time",
|
||||
"reannounce_skip",
|
||||
"reannounce_delete",
|
||||
"reannounce_interval",
|
||||
|
@ -378,6 +393,8 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A
|
|||
action.IgnoreRules,
|
||||
limitUL,
|
||||
limitDL,
|
||||
limitRatio,
|
||||
limitSeedTime,
|
||||
action.ReAnnounceSkip,
|
||||
action.ReAnnounceDelete,
|
||||
action.ReAnnounceInterval,
|
||||
|
@ -421,6 +438,9 @@ func (r *ActionRepo) Update(ctx context.Context, action domain.Action) (*domain.
|
|||
|
||||
limitDL := toNullInt64(action.LimitDownloadSpeed)
|
||||
limitUL := toNullInt64(action.LimitUploadSpeed)
|
||||
limitRatio := toNullFloat64(action.LimitRatio)
|
||||
limitSeedTime := toNullInt64(action.LimitSeedTime)
|
||||
|
||||
clientID := toNullInt32(action.ClientID)
|
||||
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("limit_upload_speed", limitUL).
|
||||
Set("limit_download_speed", limitDL).
|
||||
Set("limit_ratio", limitRatio).
|
||||
Set("limit_seed_time", limitSeedTime).
|
||||
Set("reannounce_skip", action.ReAnnounceSkip).
|
||||
Set("reannounce_delete", action.ReAnnounceDelete).
|
||||
Set("reannounce_interval", action.ReAnnounceInterval).
|
||||
|
@ -509,6 +531,8 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []*domain.A
|
|||
|
||||
limitDL := toNullInt64(action.LimitDownloadSpeed)
|
||||
limitUL := toNullInt64(action.LimitUploadSpeed)
|
||||
limitRatio := toNullFloat64(action.LimitRatio)
|
||||
limitSeedTime := toNullInt64(action.LimitSeedTime)
|
||||
clientID := toNullInt32(action.ClientID)
|
||||
|
||||
queryBuilder := r.db.squirrel.
|
||||
|
@ -528,6 +552,8 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []*domain.A
|
|||
"ignore_rules",
|
||||
"limit_upload_speed",
|
||||
"limit_download_speed",
|
||||
"limit_ratio",
|
||||
"limit_seed_time",
|
||||
"reannounce_skip",
|
||||
"reannounce_delete",
|
||||
"reannounce_interval",
|
||||
|
@ -554,6 +580,8 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []*domain.A
|
|||
action.IgnoreRules,
|
||||
limitUL,
|
||||
limitDL,
|
||||
limitRatio,
|
||||
limitSeedTime,
|
||||
action.ReAnnounceSkip,
|
||||
action.ReAnnounceDelete,
|
||||
action.ReAnnounceInterval,
|
||||
|
|
|
@ -147,6 +147,8 @@ CREATE TABLE action
|
|||
ignore_rules BOOLEAN,
|
||||
limit_upload_speed INT,
|
||||
limit_download_speed INT,
|
||||
limit_ratio REAL,
|
||||
limit_seed_time INT,
|
||||
reannounce_skip BOOLEAN DEFAULT false,
|
||||
reannounce_delete BOOLEAN DEFAULT false,
|
||||
reannounce_interval INTEGER DEFAULT 7,
|
||||
|
@ -665,6 +667,13 @@ ALTER TABLE release_action_status_dg_tmp
|
|||
ALTER TABLE "action"
|
||||
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 = `
|
||||
|
@ -814,6 +823,8 @@ CREATE TABLE action
|
|||
ignore_rules BOOLEAN,
|
||||
limit_upload_speed INT,
|
||||
limit_download_speed INT,
|
||||
limit_ratio REAL,
|
||||
limit_seed_time INT,
|
||||
reannounce_skip BOOLEAN DEFAULT false,
|
||||
reannounce_delete BOOLEAN DEFAULT false,
|
||||
reannounce_interval INTEGER DEFAULT 7,
|
||||
|
@ -1085,4 +1096,11 @@ var postgresMigrations = []string{
|
|||
ALTER TABLE "action"
|
||||
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;
|
||||
`,
|
||||
}
|
||||
|
|
|
@ -32,3 +32,10 @@ func toNullInt64(s int64) sql.NullInt64 {
|
|||
Valid: s != 0,
|
||||
}
|
||||
}
|
||||
|
||||
func toNullFloat64(s float64) sql.NullFloat64 {
|
||||
return sql.NullFloat64{
|
||||
Float64: s,
|
||||
Valid: s != 0,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ type Action struct {
|
|||
IgnoreRules bool `json:"ignore_rules,omitempty"`
|
||||
LimitUploadSpeed int64 `json:"limit_upload_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"`
|
||||
ReAnnounceDelete bool `json:"reannounce_delete,omitempty"`
|
||||
ReAnnounceInterval int64 `json:"reannounce_interval,omitempty"`
|
||||
|
|
|
@ -131,12 +131,14 @@ interface NumberFieldProps {
|
|||
name: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
step?: number;
|
||||
}
|
||||
|
||||
export const NumberField = ({
|
||||
name,
|
||||
label,
|
||||
placeholder
|
||||
placeholder,
|
||||
step,
|
||||
}: NumberFieldProps) => (
|
||||
<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">
|
||||
|
@ -151,6 +153,7 @@ export const NumberField = ({
|
|||
<div className="sm:col-span-2">
|
||||
<input
|
||||
type="number"
|
||||
step={step}
|
||||
{...field}
|
||||
className={classNames(
|
||||
meta.touched && meta.error
|
||||
|
|
|
@ -587,6 +587,8 @@ function FilterActions({ filter, values }: FilterActionsProps) {
|
|||
ignore_rules: false,
|
||||
limit_upload_speed: 0,
|
||||
limit_download_speed: 0,
|
||||
limit_ratio: 0,
|
||||
limit_seed_time: 0,
|
||||
reannounce_skip: false,
|
||||
reannounce_delete: false,
|
||||
reannounce_interval: 7,
|
||||
|
@ -746,7 +748,19 @@ function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemPr
|
|||
label="Limit upload speed (KB/s)"
|
||||
/>
|
||||
</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">
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.paused`}
|
||||
|
|
2
web/src/types/Filter.d.ts
vendored
2
web/src/types/Filter.d.ts
vendored
|
@ -68,6 +68,8 @@ interface Action {
|
|||
ignore_rules?: boolean;
|
||||
limit_upload_speed?: number;
|
||||
limit_download_speed?: number;
|
||||
limit_ratio?: number;
|
||||
limit_seed_time?: number;
|
||||
reannounce_skip: boolean;
|
||||
reannounce_delete: boolean;
|
||||
reannounce_interval: number;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue