diff --git a/go.mod b/go.mod index 3401c7a..dffdf64 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/anacrolix/torrent v1.55.0 github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef github.com/autobrr/go-deluge v1.2.0 - github.com/autobrr/go-qbittorrent v1.8.1 + github.com/autobrr/go-qbittorrent v1.9.0 github.com/autobrr/go-rtorrent v1.10.0 github.com/avast/retry-go v3.0.0+incompatible github.com/avast/retry-go/v4 v4.5.1 diff --git a/go.sum b/go.sum index 23a9a97..8841a62 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef h1:2JGTg6JapxP github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII= github.com/autobrr/go-deluge v1.2.0 h1:psqHrH3nhriRAuxEiN8HpjH/2IW4DsNUxVavoqfi2xI= github.com/autobrr/go-deluge v1.2.0/go.mod h1:ndiXT1eHWv/ATNk9TpE8GHIs8OSSUnsImt4Syk+y5LM= -github.com/autobrr/go-qbittorrent v1.8.1 h1:QQxuEaCKThTmV0LhU6tHZQvYv+eCrKmiCRY0G1RiJG4= -github.com/autobrr/go-qbittorrent v1.8.1/go.mod h1:z88B3+O/1/3doQABErvIOOxE4hjpmIpulu6XzDG/q78= +github.com/autobrr/go-qbittorrent v1.9.0 h1:HaLueJ99D3G1cQ2r5ADVbtfwyEhekt2eQoEZ7yhAwYs= +github.com/autobrr/go-qbittorrent v1.9.0/go.mod h1:z88B3+O/1/3doQABErvIOOxE4hjpmIpulu6XzDG/q78= github.com/autobrr/go-rtorrent v1.10.0 h1:SCs7Rdi1BZ3MxNoVIdWK0qTUHQyhSj9rEU8KUTRi4Ug= github.com/autobrr/go-rtorrent v1.10.0/go.mod h1:1CyQ2tcLOGP+p9drOqFiVPb/+QvfExMPCHnEGQd0BmM= github.com/autobrr/sse/v2 v2.0.0-20230520125637-530e06346d7d h1:9EGCYgeugAVWLBAtjHC7AFnXSwUdYfCB98WaOgdDREE= diff --git a/internal/action/qbittorrent.go b/internal/action/qbittorrent.go index 77ab061..9e26806 100644 --- a/internal/action/qbittorrent.go +++ b/internal/action/qbittorrent.go @@ -135,6 +135,9 @@ func (s *service) prepareQbitOptions(action *domain.Action) (map[string]string, if action.SkipHashCheck { opts.SkipHashCheck = true } + if action.FirstLastPiecePrio { + opts.FirstLastPiecePrio = true + } if action.ContentLayout != "" { if action.ContentLayout == domain.ActionContentLayoutSubfolderCreate { opts.ContentLayout = qbittorrent.ContentLayoutSubfolderCreate diff --git a/internal/database/action.go b/internal/database/action.go index 6e4c896..cac27c3 100644 --- a/internal/database/action.go +++ b/internal/database/action.go @@ -75,6 +75,7 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int, a "save_path", "paused", "ignore_rules", + "first_last_piece_prio", "skip_hash_check", "content_layout", "priority", @@ -124,7 +125,7 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int, a var externalClientID, 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, &a.SkipHashCheck, &contentLayout, &priorityLayout, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &externalClientID, &externalClient, &clientID); err != nil { + if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &a.FirstLastPiecePrio, &a.SkipHashCheck, &contentLayout, &priorityLayout, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &externalClientID, &externalClient, &clientID); err != nil { return nil, errors.Wrap(err, "error scanning row") } @@ -229,6 +230,7 @@ func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) { "save_path", "paused", "ignore_rules", + "first_last_piece_prio", "skip_hash_check", "content_layout", "priority", @@ -272,7 +274,7 @@ func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) { var externalClientID, 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, &a.SkipHashCheck, &contentLayout, &priorityLayout, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &externalClientID, &externalClient, &clientID); err != nil { + if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &a.FirstLastPiecePrio, &a.SkipHashCheck, &contentLayout, &priorityLayout, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &externalClientID, &externalClient, &clientID); err != nil { return nil, errors.Wrap(err, "error scanning row") } @@ -325,6 +327,7 @@ func (r *ActionRepo) Get(ctx context.Context, req *domain.GetActionRequest) (*do "save_path", "paused", "ignore_rules", + "first_last_piece_prio", "skip_hash_check", "content_layout", "priority", @@ -370,7 +373,7 @@ func (r *ActionRepo) Get(ctx context.Context, req *domain.GetActionRequest) (*do var externalClientID, clientID, filterID sql.NullInt32 var paused, ignoreRules sql.NullBool - if err := row.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &a.SkipHashCheck, &contentLayout, &priorityLayout, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &externalClientID, &externalClient, &clientID, &filterID); err != nil { + if err := row.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &a.FirstLastPiecePrio, &a.SkipHashCheck, &contentLayout, &priorityLayout, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &externalClientID, &externalClient, &clientID, &filterID); err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, domain.ErrRecordNotFound } @@ -464,6 +467,7 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A "save_path", "paused", "ignore_rules", + "first_last_piece_prio", "skip_hash_check", "content_layout", "priority", @@ -497,6 +501,7 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A toNullString(action.SavePath), action.Paused, action.IgnoreRules, + action.FirstLastPiecePrio, action.SkipHashCheck, toNullString(string(action.ContentLayout)), toNullString(string(action.PriorityLayout)), @@ -548,6 +553,7 @@ func (r *ActionRepo) Update(ctx context.Context, action domain.Action) (*domain. Set("save_path", toNullString(action.SavePath)). Set("paused", action.Paused). Set("ignore_rules", action.IgnoreRules). + Set("first_last_piece_prio", action.FirstLastPiecePrio). Set("skip_hash_check", action.SkipHashCheck). Set("content_layout", toNullString(string(action.ContentLayout))). Set("priority", toNullString(string(action.PriorityLayout))). @@ -609,6 +615,7 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, filterID int64, act Set("save_path", toNullString(action.SavePath)). Set("paused", action.Paused). Set("ignore_rules", action.IgnoreRules). + Set("first_last_piece_prio", action.FirstLastPiecePrio). Set("skip_hash_check", action.SkipHashCheck). Set("content_layout", toNullString(string(action.ContentLayout))). Set("priority", toNullString(string(action.PriorityLayout))). @@ -657,6 +664,7 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, filterID int64, act "save_path", "paused", "ignore_rules", + "first_last_piece_prio", "skip_hash_check", "content_layout", "priority", @@ -690,6 +698,7 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, filterID int64, act toNullString(action.SavePath), action.Paused, action.IgnoreRules, + action.FirstLastPiecePrio, action.SkipHashCheck, toNullString(string(action.ContentLayout)), toNullString(string(action.PriorityLayout)), diff --git a/internal/database/action_test.go b/internal/database/action_test.go index 89d9edf..76c2806 100644 --- a/internal/database/action_test.go +++ b/internal/database/action_test.go @@ -31,6 +31,7 @@ func getMockAction() domain.Action { Paused: false, IgnoreRules: false, SkipHashCheck: false, + FirstLastPiecePrio: false, ContentLayout: domain.ActionContentLayoutOriginal, LimitUploadSpeed: 0, LimitDownloadSpeed: 0, diff --git a/internal/database/postgres_migrate.go b/internal/database/postgres_migrate.go index 1463dc7..d6746c6 100644 --- a/internal/database/postgres_migrate.go +++ b/internal/database/postgres_migrate.go @@ -197,6 +197,7 @@ CREATE TABLE action save_path TEXT, paused BOOLEAN, ignore_rules BOOLEAN, + first_last_piece_prio BOOLEAN DEFAULT false, skip_hash_check BOOLEAN DEFAULT false, content_layout TEXT, limit_upload_speed INT, @@ -873,5 +874,8 @@ ALTER TABLE filter ELSE name END WHERE server = 'irc.animebytes.tv'; +`, + `ALTER TABLE action +ADD COLUMN first_last_piece_prio BOOLEAN DEFAULT false; `, } diff --git a/internal/database/sqlite_migrate.go b/internal/database/sqlite_migrate.go index 9612291..79c0549 100644 --- a/internal/database/sqlite_migrate.go +++ b/internal/database/sqlite_migrate.go @@ -197,6 +197,7 @@ CREATE TABLE action save_path TEXT, paused BOOLEAN, ignore_rules BOOLEAN, + first_last_piece_prio BOOLEAN DEFAULT false, skip_hash_check BOOLEAN DEFAULT false, content_layout TEXT, limit_upload_speed INT, @@ -1511,5 +1512,8 @@ ALTER TABLE filter ELSE name END WHERE server = 'irc.animebytes.tv'; +`, + `ALTER TABLE action + ADD COLUMN first_last_piece_prio BOOLEAN DEFAULT false; `, } diff --git a/internal/domain/action.go b/internal/domain/action.go index 81397bb..173ef50 100644 --- a/internal/domain/action.go +++ b/internal/domain/action.go @@ -36,6 +36,7 @@ type Action struct { SavePath string `json:"save_path,omitempty"` Paused bool `json:"paused,omitempty"` IgnoreRules bool `json:"ignore_rules,omitempty"` + FirstLastPiecePrio bool `json:"first_last_piece_prio,omitempty"` SkipHashCheck bool `json:"skip_hash_check,omitempty"` ContentLayout ActionContentLayout `json:"content_layout,omitempty"` LimitUploadSpeed int64 `json:"limit_upload_speed,omitempty"` diff --git a/web/src/screens/filters/sections/Actions.tsx b/web/src/screens/filters/sections/Actions.tsx index 78cd6f3..ca09ca5 100644 --- a/web/src/screens/filters/sections/Actions.tsx +++ b/web/src/screens/filters/sections/Actions.tsx @@ -51,6 +51,7 @@ export function Actions() { save_path: "", paused: false, ignore_rules: false, + first_last_piece_prio: false, skip_hash_check: false, content_layout: "" || undefined, priority: "" || undefined, diff --git a/web/src/screens/filters/sections/action_components/ActionQBittorrent.tsx b/web/src/screens/filters/sections/action_components/ActionQBittorrent.tsx index f645035..6f9b982 100644 --- a/web/src/screens/filters/sections/action_components/ActionQBittorrent.tsx +++ b/web/src/screens/filters/sections/action_components/ActionQBittorrent.tsx @@ -109,6 +109,11 @@ export const QBittorrent = ({ idx, action, clients }: ClientActionProps) => ( label="Skip hash check" description="Add torrent and skip hash check" /> +