mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
feat(filters): add match logic for tags and except tags (#810)
* feat(filters): add fields for tag and except tag matching logic * refactor(filters): rearrange and simplify logic for containsAllMatch --------- Co-authored-by: Gustavo Machado <me@gstv.dev>
This commit is contained in:
parent
d48e94ff33
commit
ef75b67b25
9 changed files with 364 additions and 76 deletions
|
@ -221,6 +221,8 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
|
||||||
"except_language",
|
"except_language",
|
||||||
"tags",
|
"tags",
|
||||||
"except_tags",
|
"except_tags",
|
||||||
|
"tags_match_logic",
|
||||||
|
"except_tags_match_logic",
|
||||||
"origins",
|
"origins",
|
||||||
"except_origins",
|
"except_origins",
|
||||||
"external_script_enabled",
|
"external_script_enabled",
|
||||||
|
@ -248,11 +250,11 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
var f domain.Filter
|
var f domain.Filter
|
||||||
var minSize, maxSize, maxDownloadsUnit, matchReleases, exceptReleases, matchReleaseGroups, exceptReleaseGroups, matchReleaseTags, exceptReleaseTags, freeleechPercent, shows, seasons, episodes, years, artists, albums, matchCategories, exceptCategories, matchUploaders, exceptUploaders, tags, exceptTags, extScriptCmd, extScriptArgs, extWebhookHost, extWebhookData sql.NullString
|
var minSize, maxSize, maxDownloadsUnit, matchReleases, exceptReleases, matchReleaseGroups, exceptReleaseGroups, matchReleaseTags, exceptReleaseTags, freeleechPercent, shows, seasons, episodes, years, artists, albums, matchCategories, exceptCategories, matchUploaders, exceptUploaders, tags, exceptTags, tagsMatchLogic, exceptTagsMatchLogic, extScriptCmd, extScriptArgs, extWebhookHost, extWebhookData sql.NullString
|
||||||
var useRegex, scene, freeleech, hasLog, hasCue, perfectFlac, extScriptEnabled, extWebhookEnabled sql.NullBool
|
var useRegex, scene, freeleech, hasLog, hasCue, perfectFlac, extScriptEnabled, extWebhookEnabled sql.NullBool
|
||||||
var delay, maxDownloads, logScore, extWebhookStatus, extScriptStatus sql.NullInt32
|
var delay, maxDownloads, logScore, extWebhookStatus, extScriptStatus sql.NullInt32
|
||||||
|
|
||||||
if err := row.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &f.Priority, &maxDownloads, &maxDownloadsUnit, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &matchReleaseTags, &exceptReleaseTags, &f.UseRegexReleaseTags, &scene, &freeleech, &freeleechPercent, &f.SmartEpisode, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), pq.Array(&f.MatchHDR), pq.Array(&f.ExceptHDR), pq.Array(&f.MatchOther), pq.Array(&f.ExceptOther), &years, &artists, &albums, pq.Array(&f.MatchReleaseTypes), pq.Array(&f.Formats), pq.Array(&f.Quality), pq.Array(&f.Media), &logScore, &hasLog, &hasCue, &perfectFlac, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, pq.Array(&f.MatchLanguage), pq.Array(&f.ExceptLanguage), &tags, &exceptTags, pq.Array(&f.Origins), pq.Array(&f.ExceptOrigins), &extScriptEnabled, &extScriptCmd, &extScriptArgs, &extScriptStatus, &extWebhookEnabled, &extWebhookHost, &extWebhookData, &extWebhookStatus, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
if err := row.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &f.Priority, &maxDownloads, &maxDownloadsUnit, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &matchReleaseTags, &exceptReleaseTags, &f.UseRegexReleaseTags, &scene, &freeleech, &freeleechPercent, &f.SmartEpisode, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), pq.Array(&f.MatchHDR), pq.Array(&f.ExceptHDR), pq.Array(&f.MatchOther), pq.Array(&f.ExceptOther), &years, &artists, &albums, pq.Array(&f.MatchReleaseTypes), pq.Array(&f.Formats), pq.Array(&f.Quality), pq.Array(&f.Media), &logScore, &hasLog, &hasCue, &perfectFlac, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, pq.Array(&f.MatchLanguage), pq.Array(&f.ExceptLanguage), &tags, &exceptTags, &tagsMatchLogic, &exceptTagsMatchLogic, pq.Array(&f.Origins), pq.Array(&f.ExceptOrigins), &extScriptEnabled, &extScriptCmd, &extScriptArgs, &extScriptStatus, &extWebhookEnabled, &extWebhookHost, &extWebhookData, &extWebhookStatus, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||||
return nil, errors.Wrap(err, "error scanning row")
|
return nil, errors.Wrap(err, "error scanning row")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +286,8 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
|
||||||
f.ExceptUploaders = exceptUploaders.String
|
f.ExceptUploaders = exceptUploaders.String
|
||||||
f.Tags = tags.String
|
f.Tags = tags.String
|
||||||
f.ExceptTags = exceptTags.String
|
f.ExceptTags = exceptTags.String
|
||||||
|
f.TagsMatchLogic = tagsMatchLogic.String
|
||||||
|
f.ExceptTagsMatchLogic = exceptTagsMatchLogic.String
|
||||||
f.UseRegex = useRegex.Bool
|
f.UseRegex = useRegex.Bool
|
||||||
f.Scene = scene.Bool
|
f.Scene = scene.Bool
|
||||||
f.Freeleech = freeleech.Bool
|
f.Freeleech = freeleech.Bool
|
||||||
|
@ -384,6 +388,8 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
|
||||||
"f.except_language",
|
"f.except_language",
|
||||||
"f.tags",
|
"f.tags",
|
||||||
"f.except_tags",
|
"f.except_tags",
|
||||||
|
"f.tags_match_logic",
|
||||||
|
"f.except_tags_match_logic",
|
||||||
"f.origins",
|
"f.origins",
|
||||||
"f.except_origins",
|
"f.except_origins",
|
||||||
"f.external_script_enabled",
|
"f.external_script_enabled",
|
||||||
|
@ -421,11 +427,11 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var f domain.Filter
|
var f domain.Filter
|
||||||
|
|
||||||
var minSize, maxSize, maxDownloadsUnit, matchReleases, exceptReleases, matchReleaseGroups, exceptReleaseGroups, matchReleaseTags, exceptReleaseTags, freeleechPercent, shows, seasons, episodes, years, artists, albums, matchCategories, exceptCategories, matchUploaders, exceptUploaders, tags, exceptTags, extScriptCmd, extScriptArgs, extWebhookHost, extWebhookData sql.NullString
|
var minSize, maxSize, maxDownloadsUnit, matchReleases, exceptReleases, matchReleaseGroups, exceptReleaseGroups, matchReleaseTags, exceptReleaseTags, freeleechPercent, shows, seasons, episodes, years, artists, albums, matchCategories, exceptCategories, matchUploaders, exceptUploaders, tags, exceptTags, tagsMatchLogic, exceptTagsMatchLogic, extScriptCmd, extScriptArgs, extWebhookHost, extWebhookData sql.NullString
|
||||||
var useRegex, scene, freeleech, hasLog, hasCue, perfectFlac, extScriptEnabled, extWebhookEnabled sql.NullBool
|
var useRegex, scene, freeleech, hasLog, hasCue, perfectFlac, extScriptEnabled, extWebhookEnabled sql.NullBool
|
||||||
var delay, maxDownloads, logScore, extWebhookStatus, extScriptStatus sql.NullInt32
|
var delay, maxDownloads, logScore, extWebhookStatus, extScriptStatus sql.NullInt32
|
||||||
|
|
||||||
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &f.Priority, &maxDownloads, &maxDownloadsUnit, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &matchReleaseTags, &exceptReleaseTags, &f.UseRegexReleaseTags, &scene, &freeleech, &freeleechPercent, &f.SmartEpisode, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), pq.Array(&f.MatchHDR), pq.Array(&f.ExceptHDR), pq.Array(&f.MatchOther), pq.Array(&f.ExceptOther), &years, &artists, &albums, pq.Array(&f.MatchReleaseTypes), pq.Array(&f.Formats), pq.Array(&f.Quality), pq.Array(&f.Media), &logScore, &hasLog, &hasCue, &perfectFlac, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, pq.Array(&f.MatchLanguage), pq.Array(&f.ExceptLanguage), &tags, &exceptTags, pq.Array(&f.Origins), pq.Array(&f.ExceptOrigins), &extScriptEnabled, &extScriptCmd, &extScriptArgs, &extScriptStatus, &extWebhookEnabled, &extWebhookHost, &extWebhookData, &extWebhookStatus, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &f.Priority, &maxDownloads, &maxDownloadsUnit, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &matchReleaseTags, &exceptReleaseTags, &f.UseRegexReleaseTags, &scene, &freeleech, &freeleechPercent, &f.SmartEpisode, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), pq.Array(&f.MatchHDR), pq.Array(&f.ExceptHDR), pq.Array(&f.MatchOther), pq.Array(&f.ExceptOther), &years, &artists, &albums, pq.Array(&f.MatchReleaseTypes), pq.Array(&f.Formats), pq.Array(&f.Quality), pq.Array(&f.Media), &logScore, &hasLog, &hasCue, &perfectFlac, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, pq.Array(&f.MatchLanguage), pq.Array(&f.ExceptLanguage), &tags, &exceptTags, &tagsMatchLogic, &exceptTagsMatchLogic, pq.Array(&f.Origins), pq.Array(&f.ExceptOrigins), &extScriptEnabled, &extScriptCmd, &extScriptArgs, &extScriptStatus, &extWebhookEnabled, &extWebhookHost, &extWebhookData, &extWebhookStatus, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||||
return nil, errors.Wrap(err, "error scanning row")
|
return nil, errors.Wrap(err, "error scanning row")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,6 +463,8 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
|
||||||
f.ExceptUploaders = exceptUploaders.String
|
f.ExceptUploaders = exceptUploaders.String
|
||||||
f.Tags = tags.String
|
f.Tags = tags.String
|
||||||
f.ExceptTags = exceptTags.String
|
f.ExceptTags = exceptTags.String
|
||||||
|
f.TagsMatchLogic = tagsMatchLogic.String
|
||||||
|
f.ExceptTagsMatchLogic = exceptTagsMatchLogic.String
|
||||||
f.UseRegex = useRegex.Bool
|
f.UseRegex = useRegex.Bool
|
||||||
f.Scene = scene.Bool
|
f.Scene = scene.Bool
|
||||||
f.Freeleech = freeleech.Bool
|
f.Freeleech = freeleech.Bool
|
||||||
|
@ -521,6 +529,8 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F
|
||||||
"except_language",
|
"except_language",
|
||||||
"tags",
|
"tags",
|
||||||
"except_tags",
|
"except_tags",
|
||||||
|
"tags_match_logic",
|
||||||
|
"except_tags_match_logic",
|
||||||
"artists",
|
"artists",
|
||||||
"albums",
|
"albums",
|
||||||
"release_types_match",
|
"release_types_match",
|
||||||
|
@ -583,6 +593,8 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F
|
||||||
pq.Array(filter.ExceptLanguage),
|
pq.Array(filter.ExceptLanguage),
|
||||||
filter.Tags,
|
filter.Tags,
|
||||||
filter.ExceptTags,
|
filter.ExceptTags,
|
||||||
|
filter.TagsMatchLogic,
|
||||||
|
filter.ExceptTagsMatchLogic,
|
||||||
filter.Artists,
|
filter.Artists,
|
||||||
filter.Albums,
|
filter.Albums,
|
||||||
pq.Array(filter.MatchReleaseTypes),
|
pq.Array(filter.MatchReleaseTypes),
|
||||||
|
@ -664,6 +676,8 @@ func (r *FilterRepo) Update(ctx context.Context, filter domain.Filter) (*domain.
|
||||||
Set("except_language", pq.Array(filter.ExceptLanguage)).
|
Set("except_language", pq.Array(filter.ExceptLanguage)).
|
||||||
Set("tags", filter.Tags).
|
Set("tags", filter.Tags).
|
||||||
Set("except_tags", filter.ExceptTags).
|
Set("except_tags", filter.ExceptTags).
|
||||||
|
Set("tags_match_logic", filter.TagsMatchLogic).
|
||||||
|
Set("except_tags_match_logic", filter.ExceptTagsMatchLogic).
|
||||||
Set("artists", filter.Artists).
|
Set("artists", filter.Artists).
|
||||||
Set("albums", filter.Albums).
|
Set("albums", filter.Albums).
|
||||||
Set("release_types_match", pq.Array(filter.MatchReleaseTypes)).
|
Set("release_types_match", pq.Array(filter.MatchReleaseTypes)).
|
||||||
|
@ -825,6 +839,12 @@ func (r *FilterRepo) UpdatePartial(ctx context.Context, filter domain.FilterUpda
|
||||||
if filter.ExceptTags != nil {
|
if filter.ExceptTags != nil {
|
||||||
q = q.Set("except_tags", filter.ExceptTags)
|
q = q.Set("except_tags", filter.ExceptTags)
|
||||||
}
|
}
|
||||||
|
if filter.TagsMatchLogic != nil {
|
||||||
|
q = q.Set("tags_match_logic", filter.TagsMatchLogic)
|
||||||
|
}
|
||||||
|
if filter.ExceptTagsMatchLogic != nil {
|
||||||
|
q = q.Set("except_tags_match_logic", filter.ExceptTagsMatchLogic)
|
||||||
|
}
|
||||||
if filter.Artists != nil {
|
if filter.Artists != nil {
|
||||||
q = q.Set("artists", filter.Artists)
|
q = q.Set("artists", filter.Artists)
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,8 @@ CREATE TABLE filter
|
||||||
except_language TEXT [] DEFAULT '{}',
|
except_language TEXT [] DEFAULT '{}',
|
||||||
tags TEXT,
|
tags TEXT,
|
||||||
except_tags TEXT,
|
except_tags TEXT,
|
||||||
|
tags_match_logic TEXT,
|
||||||
|
except_tags_match_logic TEXT,
|
||||||
origins TEXT [] DEFAULT '{}',
|
origins TEXT [] DEFAULT '{}',
|
||||||
except_origins TEXT [] DEFAULT '{}',
|
except_origins TEXT [] DEFAULT '{}',
|
||||||
external_script_enabled BOOLEAN DEFAULT FALSE,
|
external_script_enabled BOOLEAN DEFAULT FALSE,
|
||||||
|
@ -655,4 +657,18 @@ ADD COLUMN info_url TEXT;
|
||||||
ALTER TABLE "release"
|
ALTER TABLE "release"
|
||||||
ADD COLUMN download_url TEXT;
|
ADD COLUMN download_url TEXT;
|
||||||
`,
|
`,
|
||||||
|
`ALTER TABLE filter
|
||||||
|
ADD COLUMN tags_match_logic TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE filter
|
||||||
|
ADD COLUMN except_tags_match_logic TEXT;
|
||||||
|
|
||||||
|
UPDATE filter
|
||||||
|
SET tags_match_logic = 'ANY'
|
||||||
|
WHERE tags IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE filter
|
||||||
|
SET except_tags_match_logic = 'ANY'
|
||||||
|
WHERE except_tags IS NOT NULL;
|
||||||
|
`,
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,8 @@ CREATE TABLE filter
|
||||||
except_language TEXT [] DEFAULT '{}',
|
except_language TEXT [] DEFAULT '{}',
|
||||||
tags TEXT,
|
tags TEXT,
|
||||||
except_tags TEXT,
|
except_tags TEXT,
|
||||||
|
tags_match_logic TEXT,
|
||||||
|
except_tags_match_logic TEXT,
|
||||||
origins TEXT [] DEFAULT '{}',
|
origins TEXT [] DEFAULT '{}',
|
||||||
except_origins TEXT [] DEFAULT '{}',
|
except_origins TEXT [] DEFAULT '{}',
|
||||||
external_script_enabled BOOLEAN DEFAULT FALSE,
|
external_script_enabled BOOLEAN DEFAULT FALSE,
|
||||||
|
@ -1048,4 +1050,18 @@ ADD COLUMN info_url TEXT;
|
||||||
ALTER TABLE "release"
|
ALTER TABLE "release"
|
||||||
ADD COLUMN download_url TEXT;
|
ADD COLUMN download_url TEXT;
|
||||||
`,
|
`,
|
||||||
|
`ALTER TABLE filter
|
||||||
|
ADD COLUMN tags_match_logic TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE filter
|
||||||
|
ADD COLUMN except_tags_match_logic TEXT;
|
||||||
|
|
||||||
|
UPDATE filter
|
||||||
|
SET tags_match_logic = 'ANY'
|
||||||
|
WHERE tags IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE filter
|
||||||
|
SET except_tags_match_logic = 'ANY'
|
||||||
|
WHERE except_tags IS NOT NULL;
|
||||||
|
`,
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,8 @@ type Filter struct {
|
||||||
ExceptTags string `json:"except_tags,omitempty"`
|
ExceptTags string `json:"except_tags,omitempty"`
|
||||||
TagsAny string `json:"tags_any,omitempty"`
|
TagsAny string `json:"tags_any,omitempty"`
|
||||||
ExceptTagsAny string `json:"except_tags_any,omitempty"`
|
ExceptTagsAny string `json:"except_tags_any,omitempty"`
|
||||||
|
TagsMatchLogic string `json:"tags_match_logic,omitempty"`
|
||||||
|
ExceptTagsMatchLogic string `json:"except_tags_match_logic,omitempty"`
|
||||||
MatchReleaseTags string `json:"match_release_tags,omitempty"`
|
MatchReleaseTags string `json:"match_release_tags,omitempty"`
|
||||||
ExceptReleaseTags string `json:"except_release_tags,omitempty"`
|
ExceptReleaseTags string `json:"except_release_tags,omitempty"`
|
||||||
UseRegexReleaseTags bool `json:"use_regex_release_tags,omitempty"`
|
UseRegexReleaseTags bool `json:"use_regex_release_tags,omitempty"`
|
||||||
|
@ -190,6 +192,8 @@ type FilterUpdate struct {
|
||||||
ExceptTags *string `json:"except_tags,omitempty"`
|
ExceptTags *string `json:"except_tags,omitempty"`
|
||||||
TagsAny *string `json:"tags_any,omitempty"`
|
TagsAny *string `json:"tags_any,omitempty"`
|
||||||
ExceptTagsAny *string `json:"except_tags_any,omitempty"`
|
ExceptTagsAny *string `json:"except_tags_any,omitempty"`
|
||||||
|
TagsMatchLogic *string `json:"tags_match_logic,omitempty"`
|
||||||
|
ExceptTagsMatchLogic *string `json:"except_tags_match_logic,omitempty"`
|
||||||
ExternalScriptEnabled *bool `json:"external_script_enabled,omitempty"`
|
ExternalScriptEnabled *bool `json:"external_script_enabled,omitempty"`
|
||||||
ExternalScriptCmd *string `json:"external_script_cmd,omitempty"`
|
ExternalScriptCmd *string `json:"external_script_cmd,omitempty"`
|
||||||
ExternalScriptArgs *string `json:"external_script_args,omitempty"`
|
ExternalScriptArgs *string `json:"external_script_args,omitempty"`
|
||||||
|
@ -379,12 +383,20 @@ func (f Filter) CheckFilter(r *Release) ([]string, bool) {
|
||||||
r.addRejectionF("size not matching. got: %v want min: %v max: %v", r.Size, f.MinSize, f.MaxSize)
|
r.addRejectionF("size not matching. got: %v want min: %v max: %v", r.Size, f.MinSize, f.MaxSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Tags != "" && !containsAny(r.Tags, f.Tags) {
|
if f.Tags != "" {
|
||||||
r.addRejectionF("tags not matching. got: %v want: %v", r.Tags, f.Tags)
|
if f.TagsMatchLogic == "ANY" && !containsAny(r.Tags, f.Tags) {
|
||||||
|
r.addRejectionF("tags not matching. got: %v want: %v", r.Tags, f.Tags)
|
||||||
|
} else if f.TagsMatchLogic == "ALL" && !containsAll(r.Tags, f.Tags) {
|
||||||
|
r.addRejectionF("tags not matching. got: %v want(all): %v", r.Tags, f.Tags)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.ExceptTags != "" && containsAny(r.Tags, f.ExceptTags) {
|
if f.ExceptTags != "" {
|
||||||
r.addRejectionF("tags unwanted. got: %v want: %v", r.Tags, f.ExceptTags)
|
if f.ExceptTagsMatchLogic == "ANY" && containsAny(r.Tags, f.ExceptTags) {
|
||||||
|
r.addRejectionF("tags unwanted. got: %v want: %v", r.Tags, f.ExceptTags)
|
||||||
|
} else if f.ExceptTagsMatchLogic == "ALL" && containsAll(r.Tags, f.ExceptTags) {
|
||||||
|
r.addRejectionF("tags unwanted. got: %v want(all): %v", r.Tags, f.ExceptTags)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(f.Artists) > 0 && !contains(r.Artists, f.Artists) {
|
if len(f.Artists) > 0 && !contains(r.Artists, f.Artists) {
|
||||||
|
@ -620,6 +632,10 @@ func containsAny(tags []string, filter string) bool {
|
||||||
return containsMatch(tags, strings.Split(filter, ","))
|
return containsMatch(tags, strings.Split(filter, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsAll(tags []string, filter string) bool {
|
||||||
|
return containsAllMatch(tags, strings.Split(filter, ","))
|
||||||
|
}
|
||||||
|
|
||||||
func containsAnyOther(filter string, tags ...string) bool {
|
func containsAnyOther(filter string, tags ...string) bool {
|
||||||
return containsMatch(tags, strings.Split(filter, ","))
|
return containsMatch(tags, strings.Split(filter, ","))
|
||||||
}
|
}
|
||||||
|
@ -686,6 +702,39 @@ func containsMatch(tags []string, filters []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsAllMatch(tags []string, filters []string) bool {
|
||||||
|
for _, filter := range filters {
|
||||||
|
if filter == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filter = strings.ToLower(filter)
|
||||||
|
filter = strings.Trim(filter, " ")
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, tag := range tags {
|
||||||
|
if tag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tag = strings.ToLower(tag)
|
||||||
|
|
||||||
|
if tag == filter {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
} else if strings.ContainsAny(filter, "?|*") {
|
||||||
|
if wildcard.Match(filter, tag) {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func containsMatchBasic(tags []string, filters []string) bool {
|
func containsMatchBasic(tags []string, filters []string) bool {
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
|
|
|
@ -520,7 +520,7 @@ func TestFilter_CheckFilter(t *testing.T) {
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "match_tags",
|
name: "match_tags_any",
|
||||||
fields: &Release{
|
fields: &Release{
|
||||||
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
||||||
Category: "TV",
|
Category: "TV",
|
||||||
|
@ -535,12 +535,34 @@ func TestFilter_CheckFilter(t *testing.T) {
|
||||||
ExceptUploaders: "Anonymous",
|
ExceptUploaders: "Anonymous",
|
||||||
Shows: "Good show",
|
Shows: "Good show",
|
||||||
Tags: "tv",
|
Tags: "tv",
|
||||||
|
TagsMatchLogic: "ANY",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "match_tags_bad",
|
name: "match_tags_all",
|
||||||
|
fields: &Release{
|
||||||
|
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
||||||
|
Category: "TV",
|
||||||
|
Uploader: "Uploader1",
|
||||||
|
Tags: []string{"tv", "foreign"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
filter: Filter{
|
||||||
|
Enabled: true,
|
||||||
|
MatchCategories: "*tv*",
|
||||||
|
MatchUploaders: "Uploader1,Uploader2",
|
||||||
|
ExceptUploaders: "Anonymous",
|
||||||
|
Shows: "Good show",
|
||||||
|
Tags: "tv,foreign",
|
||||||
|
TagsMatchLogic: "ALL",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "match_tags_any_bad",
|
||||||
fields: &Release{
|
fields: &Release{
|
||||||
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
||||||
Category: "TV",
|
Category: "TV",
|
||||||
|
@ -555,13 +577,36 @@ func TestFilter_CheckFilter(t *testing.T) {
|
||||||
ExceptUploaders: "Anonymous",
|
ExceptUploaders: "Anonymous",
|
||||||
Shows: "Good show",
|
Shows: "Good show",
|
||||||
Tags: "tv",
|
Tags: "tv",
|
||||||
|
TagsMatchLogic: "ANY",
|
||||||
},
|
},
|
||||||
rejections: []string{"tags not matching. got: [foreign] want: tv"},
|
rejections: []string{"tags not matching. got: [foreign] want: tv"},
|
||||||
},
|
},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "match_except_tags",
|
name: "match_tags_all_bad",
|
||||||
|
fields: &Release{
|
||||||
|
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
||||||
|
Category: "TV",
|
||||||
|
Uploader: "Uploader1",
|
||||||
|
Tags: []string{"foreign"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
filter: Filter{
|
||||||
|
Enabled: true,
|
||||||
|
MatchCategories: "*tv*",
|
||||||
|
MatchUploaders: "Uploader1,Uploader2",
|
||||||
|
ExceptUploaders: "Anonymous",
|
||||||
|
Shows: "Good show",
|
||||||
|
Tags: "tv,foreign",
|
||||||
|
TagsMatchLogic: "ALL",
|
||||||
|
},
|
||||||
|
rejections: []string{"tags not matching. got: [foreign] want(all): tv,foreign"},
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "match_except_tags_any",
|
||||||
fields: &Release{
|
fields: &Release{
|
||||||
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
||||||
Category: "TV",
|
Category: "TV",
|
||||||
|
@ -576,12 +621,13 @@ func TestFilter_CheckFilter(t *testing.T) {
|
||||||
ExceptUploaders: "Anonymous",
|
ExceptUploaders: "Anonymous",
|
||||||
Shows: "Good show",
|
Shows: "Good show",
|
||||||
ExceptTags: "tv",
|
ExceptTags: "tv",
|
||||||
|
TagsMatchLogic: "ANY",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "match_except_tags_2",
|
name: "match_except_tags_all",
|
||||||
fields: &Release{
|
fields: &Release{
|
||||||
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
||||||
Category: "TV",
|
Category: "TV",
|
||||||
|
@ -595,12 +641,56 @@ func TestFilter_CheckFilter(t *testing.T) {
|
||||||
MatchUploaders: "Uploader1,Uploader2",
|
MatchUploaders: "Uploader1,Uploader2",
|
||||||
ExceptUploaders: "Anonymous",
|
ExceptUploaders: "Anonymous",
|
||||||
Shows: "Good show",
|
Shows: "Good show",
|
||||||
ExceptTags: "foreign",
|
ExceptTags: "tv,foreign",
|
||||||
|
TagsMatchLogic: "ALL",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "match_except_tags_any_2",
|
||||||
|
fields: &Release{
|
||||||
|
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
||||||
|
Category: "TV",
|
||||||
|
Uploader: "Uploader1",
|
||||||
|
Tags: []string{"foreign"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
filter: Filter{
|
||||||
|
Enabled: true,
|
||||||
|
MatchCategories: "*tv*",
|
||||||
|
MatchUploaders: "Uploader1,Uploader2",
|
||||||
|
ExceptUploaders: "Anonymous",
|
||||||
|
Shows: "Good show",
|
||||||
|
ExceptTags: "foreign",
|
||||||
|
ExceptTagsMatchLogic: "ANY",
|
||||||
},
|
},
|
||||||
rejections: []string{"tags unwanted. got: [foreign] want: foreign"},
|
rejections: []string{"tags unwanted. got: [foreign] want: foreign"},
|
||||||
},
|
},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "match_except_tags_all_2",
|
||||||
|
fields: &Release{
|
||||||
|
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
|
||||||
|
Category: "TV",
|
||||||
|
Uploader: "Uploader1",
|
||||||
|
Tags: []string{"tv", "foreign"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
filter: Filter{
|
||||||
|
Enabled: true,
|
||||||
|
MatchCategories: "*tv*",
|
||||||
|
MatchUploaders: "Uploader1,Uploader2",
|
||||||
|
ExceptUploaders: "Anonymous",
|
||||||
|
Shows: "Good show",
|
||||||
|
ExceptTags: "foreign,tv",
|
||||||
|
ExceptTagsMatchLogic: "ALL",
|
||||||
|
},
|
||||||
|
rejections: []string{"tags unwanted. got: [tv foreign] want(all): foreign,tv"},
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "match_group_1",
|
name: "match_group_1",
|
||||||
fields: &Release{
|
fields: &Release{
|
||||||
|
@ -1717,64 +1807,64 @@ func TestFilter_CheckFilter1(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
f := Filter{
|
f := Filter{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
Name: tt.fields.Name,
|
Name: tt.fields.Name,
|
||||||
Enabled: tt.fields.Enabled,
|
Enabled: tt.fields.Enabled,
|
||||||
CreatedAt: tt.fields.CreatedAt,
|
CreatedAt: tt.fields.CreatedAt,
|
||||||
UpdatedAt: tt.fields.UpdatedAt,
|
UpdatedAt: tt.fields.UpdatedAt,
|
||||||
MinSize: tt.fields.MinSize,
|
MinSize: tt.fields.MinSize,
|
||||||
MaxSize: tt.fields.MaxSize,
|
MaxSize: tt.fields.MaxSize,
|
||||||
Delay: tt.fields.Delay,
|
Delay: tt.fields.Delay,
|
||||||
Priority: tt.fields.Priority,
|
Priority: tt.fields.Priority,
|
||||||
MaxDownloads: tt.fields.MaxDownloads,
|
MaxDownloads: tt.fields.MaxDownloads,
|
||||||
MaxDownloadsUnit: tt.fields.MaxDownloadsUnit,
|
MaxDownloadsUnit: tt.fields.MaxDownloadsUnit,
|
||||||
MatchReleases: tt.fields.MatchReleases,
|
MatchReleases: tt.fields.MatchReleases,
|
||||||
ExceptReleases: tt.fields.ExceptReleases,
|
ExceptReleases: tt.fields.ExceptReleases,
|
||||||
UseRegex: tt.fields.UseRegex,
|
UseRegex: tt.fields.UseRegex,
|
||||||
MatchReleaseGroups: tt.fields.MatchReleaseGroups,
|
MatchReleaseGroups: tt.fields.MatchReleaseGroups,
|
||||||
ExceptReleaseGroups: tt.fields.ExceptReleaseGroups,
|
ExceptReleaseGroups: tt.fields.ExceptReleaseGroups,
|
||||||
MatchReleaseTags: tt.fields.MatchReleaseTags,
|
MatchReleaseTags: tt.fields.MatchReleaseTags,
|
||||||
ExceptReleaseTags: tt.fields.ExceptReleaseTags,
|
ExceptReleaseTags: tt.fields.ExceptReleaseTags,
|
||||||
UseRegexReleaseTags: tt.fields.UseRegexReleaseTags,
|
UseRegexReleaseTags: tt.fields.UseRegexReleaseTags,
|
||||||
Scene: tt.fields.Scene,
|
Scene: tt.fields.Scene,
|
||||||
Origins: tt.fields.Origins,
|
Origins: tt.fields.Origins,
|
||||||
ExceptOrigins: tt.fields.ExceptOrigins,
|
ExceptOrigins: tt.fields.ExceptOrigins,
|
||||||
Freeleech: tt.fields.Freeleech,
|
Freeleech: tt.fields.Freeleech,
|
||||||
FreeleechPercent: tt.fields.FreeleechPercent,
|
FreeleechPercent: tt.fields.FreeleechPercent,
|
||||||
Shows: tt.fields.Shows,
|
Shows: tt.fields.Shows,
|
||||||
Seasons: tt.fields.Seasons,
|
Seasons: tt.fields.Seasons,
|
||||||
Episodes: tt.fields.Episodes,
|
Episodes: tt.fields.Episodes,
|
||||||
Resolutions: tt.fields.Resolutions,
|
Resolutions: tt.fields.Resolutions,
|
||||||
Codecs: tt.fields.Codecs,
|
Codecs: tt.fields.Codecs,
|
||||||
Sources: tt.fields.Sources,
|
Sources: tt.fields.Sources,
|
||||||
Containers: tt.fields.Containers,
|
Containers: tt.fields.Containers,
|
||||||
MatchHDR: tt.fields.MatchHDR,
|
MatchHDR: tt.fields.MatchHDR,
|
||||||
ExceptHDR: tt.fields.ExceptHDR,
|
ExceptHDR: tt.fields.ExceptHDR,
|
||||||
Years: tt.fields.Years,
|
Years: tt.fields.Years,
|
||||||
Artists: tt.fields.Artists,
|
Artists: tt.fields.Artists,
|
||||||
Albums: tt.fields.Albums,
|
Albums: tt.fields.Albums,
|
||||||
MatchReleaseTypes: tt.fields.MatchReleaseTypes,
|
MatchReleaseTypes: tt.fields.MatchReleaseTypes,
|
||||||
ExceptReleaseTypes: tt.fields.ExceptReleaseTypes,
|
ExceptReleaseTypes: tt.fields.ExceptReleaseTypes,
|
||||||
Formats: tt.fields.Formats,
|
Formats: tt.fields.Formats,
|
||||||
Quality: tt.fields.Quality,
|
Quality: tt.fields.Quality,
|
||||||
Media: tt.fields.Media,
|
Media: tt.fields.Media,
|
||||||
PerfectFlac: tt.fields.PerfectFlac,
|
PerfectFlac: tt.fields.PerfectFlac,
|
||||||
Cue: tt.fields.Cue,
|
Cue: tt.fields.Cue,
|
||||||
Log: tt.fields.Log,
|
Log: tt.fields.Log,
|
||||||
LogScore: tt.fields.LogScore,
|
LogScore: tt.fields.LogScore,
|
||||||
MatchOther: tt.fields.MatchOther,
|
MatchOther: tt.fields.MatchOther,
|
||||||
ExceptOther: tt.fields.ExceptOther,
|
ExceptOther: tt.fields.ExceptOther,
|
||||||
MatchCategories: tt.fields.MatchCategories,
|
MatchCategories: tt.fields.MatchCategories,
|
||||||
ExceptCategories: tt.fields.ExceptCategories,
|
ExceptCategories: tt.fields.ExceptCategories,
|
||||||
MatchUploaders: tt.fields.MatchUploaders,
|
MatchUploaders: tt.fields.MatchUploaders,
|
||||||
ExceptUploaders: tt.fields.ExceptUploaders,
|
ExceptUploaders: tt.fields.ExceptUploaders,
|
||||||
Tags: tt.fields.Tags,
|
Tags: tt.fields.Tags,
|
||||||
ExceptTags: tt.fields.ExceptTags,
|
ExceptTags: tt.fields.ExceptTags,
|
||||||
TagsAny: tt.fields.TagsAny,
|
TagsMatchLogic: tt.fields.TagsMatchLogic,
|
||||||
ExceptTagsAny: tt.fields.ExceptTagsAny,
|
ExceptTagsMatchLogic: tt.fields.ExceptTagsMatchLogic,
|
||||||
Actions: tt.fields.Actions,
|
Actions: tt.fields.Actions,
|
||||||
Indexers: tt.fields.Indexers,
|
Indexers: tt.fields.Indexers,
|
||||||
Downloads: tt.fields.Downloads,
|
Downloads: tt.fields.Downloads,
|
||||||
}
|
}
|
||||||
tt.args.r.ParseString(tt.args.r.TorrentName)
|
tt.args.r.ParseString(tt.args.r.TorrentName)
|
||||||
rejections, match := f.CheckFilter(tt.args.r)
|
rejections, match := f.CheckFilter(tt.args.r)
|
||||||
|
@ -1784,6 +1874,54 @@ func TestFilter_CheckFilter1(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_containsMatch(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
tags []string
|
||||||
|
filters []string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "test_1", args: args{tags: []string{"HDR", "DV"}, filters: []string{"DV"}}, want: true},
|
||||||
|
{name: "test_2", args: args{tags: []string{"HDR", "DV"}, filters: []string{"HD*", "D*"}}, want: true},
|
||||||
|
{name: "test_3", args: args{tags: []string{"HDR"}, filters: []string{"DV"}}, want: false},
|
||||||
|
{name: "test_4", args: args{tags: []string{"HDR"}, filters: []string{"TEST*"}}, want: false},
|
||||||
|
{name: "test_5", args: args{tags: []string{""}, filters: []string{"test,"}}, want: false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equalf(t, tt.want, containsMatch(tt.args.tags, tt.args.filters), "containsMatch(%v, %v)", tt.args.tags, tt.args.filters)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_containsAllMatch(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
tags []string
|
||||||
|
filters []string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "test_1", args: args{tags: []string{"HDR", "DV"}, filters: []string{"DV"}}, want: true},
|
||||||
|
{name: "test_2", args: args{tags: []string{"HDR", "DV"}, filters: []string{"DV", "DoVI"}}, want: false},
|
||||||
|
{name: "test_3", args: args{tags: []string{"HDR", "DV", "DoVI"}, filters: []string{"DV", "DoVI"}}, want: true},
|
||||||
|
{name: "test_4", args: args{tags: []string{"HDR", "DV"}, filters: []string{"HD*", "D*"}}, want: true},
|
||||||
|
{name: "test_5", args: args{tags: []string{"HDR", "DV"}, filters: []string{"HD*", "TEST*"}}, want: false},
|
||||||
|
{name: "test_6", args: args{tags: []string{"HDR"}, filters: []string{"DV"}}, want: false},
|
||||||
|
{name: "test_7", args: args{tags: []string{""}, filters: []string{"test,"}}, want: false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equalf(t, tt.want, containsAllMatch(tt.args.tags, tt.args.filters), "containsAllMatch(%v, %v)", tt.args.tags, tt.args.filters)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_contains(t *testing.T) {
|
func Test_contains(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
tag string
|
tag string
|
||||||
|
@ -1854,6 +1992,31 @@ func Test_containsAny(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_containsAll(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
tags []string
|
||||||
|
filter string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "test_1", args: args{tags: []string{"HDR", "DV"}, filter: "DV"}, want: true},
|
||||||
|
{name: "test_2", args: args{tags: []string{"HDR", "DV"}, filter: "HDR,DV"}, want: true},
|
||||||
|
{name: "test_2", args: args{tags: []string{"HDR", "DV"}, filter: "HD*,D*"}, want: true},
|
||||||
|
{name: "test_3", args: args{tags: []string{"HDR", "DoVI"}, filter: "HDR,DV"}, want: false},
|
||||||
|
{name: "test_4", args: args{tags: []string{"HDR", "DV", "HDR10+"}, filter: "HDR,DV"}, want: true},
|
||||||
|
{name: "test_5", args: args{tags: []string{"HDR"}, filter: "DV"}, want: false},
|
||||||
|
{name: "test_6", args: args{tags: []string{""}, filter: "test,"}, want: false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equalf(t, tt.want, containsAll(tt.args.tags, tt.args.filter), "containsAll(%v, %v)", tt.args.tags, tt.args.filter)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_sliceContainsSlice(t *testing.T) {
|
func Test_sliceContainsSlice(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
tags []string
|
tags []string
|
||||||
|
|
|
@ -251,6 +251,7 @@ export interface SelectFieldProps {
|
||||||
label: string;
|
label: string;
|
||||||
optionDefaultText: string;
|
optionDefaultText: string;
|
||||||
options: SelectFieldOption[];
|
options: SelectFieldOption[];
|
||||||
|
columns?: COL_WIDTHS;
|
||||||
tooltip?: JSX.Element;
|
tooltip?: JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,10 +260,15 @@ export const Select = ({
|
||||||
label,
|
label,
|
||||||
tooltip,
|
tooltip,
|
||||||
optionDefaultText,
|
optionDefaultText,
|
||||||
options
|
options,
|
||||||
|
columns
|
||||||
}: SelectFieldProps) => {
|
}: SelectFieldProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="col-span-6">
|
<div
|
||||||
|
className={classNames(
|
||||||
|
columns ? `col-span-${columns}` : "col-span-6"
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Field name={name} type="select">
|
<Field name={name} type="select">
|
||||||
{({
|
{({
|
||||||
field,
|
field,
|
||||||
|
|
|
@ -500,3 +500,14 @@ export const FeedDownloadTypeOptions: OptionBasicTyped<FeedDownloadType>[] = [
|
||||||
value: "TORRENT"
|
value: "TORRENT"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const tagsMatchLogicOptions: OptionBasic[] = [
|
||||||
|
{
|
||||||
|
label: "any",
|
||||||
|
value: "ANY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "all",
|
||||||
|
value: "ALL"
|
||||||
|
}
|
||||||
|
];
|
|
@ -18,7 +18,8 @@ import {
|
||||||
RELEASE_TYPE_MUSIC_OPTIONS,
|
RELEASE_TYPE_MUSIC_OPTIONS,
|
||||||
RESOLUTION_OPTIONS,
|
RESOLUTION_OPTIONS,
|
||||||
SOURCES_MUSIC_OPTIONS,
|
SOURCES_MUSIC_OPTIONS,
|
||||||
SOURCES_OPTIONS
|
SOURCES_OPTIONS,
|
||||||
|
tagsMatchLogicOptions
|
||||||
} from "../../domain/constants";
|
} from "../../domain/constants";
|
||||||
import { queryClient } from "../../App";
|
import { queryClient } from "../../App";
|
||||||
import { APIClient } from "../../api/APIClient";
|
import { APIClient } from "../../api/APIClient";
|
||||||
|
@ -265,6 +266,8 @@ export default function FilterDetails() {
|
||||||
except_categories: filter.except_categories,
|
except_categories: filter.except_categories,
|
||||||
tags: filter.tags,
|
tags: filter.tags,
|
||||||
except_tags: filter.except_tags,
|
except_tags: filter.except_tags,
|
||||||
|
tags_match_logic: filter.tags_match_logic,
|
||||||
|
except_tags_match_logic: filter.except_tags_match_logic,
|
||||||
match_uploaders: filter.match_uploaders,
|
match_uploaders: filter.match_uploaders,
|
||||||
except_uploaders: filter.except_uploaders,
|
except_uploaders: filter.except_uploaders,
|
||||||
match_language: filter.match_language || [],
|
match_language: filter.match_language || [],
|
||||||
|
@ -509,8 +512,10 @@ export function Advanced({ values }: AdvancedProps) {
|
||||||
<TextField name="match_categories" label="Match categories" columns={6} placeholder="eg. *category*,category1" tooltip={<div><p>Comma separated list of categories to match.</p><a href='https://autobrr.com/filters/categories' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/categories</a></div>} />
|
<TextField name="match_categories" label="Match categories" columns={6} placeholder="eg. *category*,category1" tooltip={<div><p>Comma separated list of categories to match.</p><a href='https://autobrr.com/filters/categories' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/categories</a></div>} />
|
||||||
<TextField name="except_categories" label="Except categories" columns={6} placeholder="eg. *category*" tooltip={<div><p>Comma separated list of categories to ignore (takes priority over Match releases).</p><a href='https://autobrr.com/filters/categories' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/categories</a></div>} />
|
<TextField name="except_categories" label="Except categories" columns={6} placeholder="eg. *category*" tooltip={<div><p>Comma separated list of categories to ignore (takes priority over Match releases).</p><a href='https://autobrr.com/filters/categories' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/categories</a></div>} />
|
||||||
|
|
||||||
<TextField name="tags" label="Match tags" columns={6} placeholder="eg. tag1,tag2" tooltip={<div><p>Comma separated list of tags to match.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
<TextField name="tags" label="Match tags" columns={4} placeholder="eg. tag1,tag2" tooltip={<div><p>Comma separated list of tags to match.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||||
<TextField name="except_tags" label="Except tags" columns={6} placeholder="eg. tag1,tag2" tooltip={<div><p>Comma separated list of tags to ignore (takes priority over Match releases).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>hhttps://autobrr.com/filters#advanced</a></div>} />
|
<Select name="tags_match_logic" label="Tags logic" columns={2} options={tagsMatchLogicOptions} optionDefaultText="any" tooltip={<div><p>Logic used to match filter tags.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||||
|
<TextField name="except_tags" label="Except tags" columns={4} placeholder="eg. tag1,tag2" tooltip={<div><p>Comma separated list of tags to ignore (takes priority over Match releases).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>hhttps://autobrr.com/filters#advanced</a></div>} />
|
||||||
|
<Select name="except_tags_match_logic" label="Except tags logic" columns={2} options={tagsMatchLogicOptions} optionDefaultText="any" tooltip={<div><p>Logic used to match except tags.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||||
</CollapsableSection>
|
</CollapsableSection>
|
||||||
|
|
||||||
<CollapsableSection defaultOpen={true} title="Uploaders" subtitle="Match or ignore uploaders.">
|
<CollapsableSection defaultOpen={true} title="Uploaders" subtitle="Match or ignore uploaders.">
|
||||||
|
|
2
web/src/types/Filter.d.ts
vendored
2
web/src/types/Filter.d.ts
vendored
|
@ -57,6 +57,8 @@ interface Filter {
|
||||||
except_tags: string;
|
except_tags: string;
|
||||||
tags_any: string;
|
tags_any: string;
|
||||||
except_tags_any: string;
|
except_tags_any: string;
|
||||||
|
tags_match_logic: string;
|
||||||
|
except_tags_match_logic: string;
|
||||||
actions_count: number;
|
actions_count: number;
|
||||||
actions: Action[];
|
actions: Action[];
|
||||||
indexers: Indexer[];
|
indexers: Indexer[];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue