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:
Gustavo Machado 2023-04-10 15:11:44 +01:00 committed by GitHub
parent d48e94ff33
commit ef75b67b25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 364 additions and 76 deletions

View file

@ -221,6 +221,8 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
"except_language",
"tags",
"except_tags",
"tags_match_logic",
"except_tags_match_logic",
"origins",
"except_origins",
"external_script_enabled",
@ -248,11 +250,11 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*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 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")
}
@ -284,6 +286,8 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
f.ExceptUploaders = exceptUploaders.String
f.Tags = tags.String
f.ExceptTags = exceptTags.String
f.TagsMatchLogic = tagsMatchLogic.String
f.ExceptTagsMatchLogic = exceptTagsMatchLogic.String
f.UseRegex = useRegex.Bool
f.Scene = scene.Bool
f.Freeleech = freeleech.Bool
@ -384,6 +388,8 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
"f.except_language",
"f.tags",
"f.except_tags",
"f.tags_match_logic",
"f.except_tags_match_logic",
"f.origins",
"f.except_origins",
"f.external_script_enabled",
@ -421,11 +427,11 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
for rows.Next() {
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 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")
}
@ -457,6 +463,8 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
f.ExceptUploaders = exceptUploaders.String
f.Tags = tags.String
f.ExceptTags = exceptTags.String
f.TagsMatchLogic = tagsMatchLogic.String
f.ExceptTagsMatchLogic = exceptTagsMatchLogic.String
f.UseRegex = useRegex.Bool
f.Scene = scene.Bool
f.Freeleech = freeleech.Bool
@ -521,6 +529,8 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F
"except_language",
"tags",
"except_tags",
"tags_match_logic",
"except_tags_match_logic",
"artists",
"albums",
"release_types_match",
@ -583,6 +593,8 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F
pq.Array(filter.ExceptLanguage),
filter.Tags,
filter.ExceptTags,
filter.TagsMatchLogic,
filter.ExceptTagsMatchLogic,
filter.Artists,
filter.Albums,
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("tags", filter.Tags).
Set("except_tags", filter.ExceptTags).
Set("tags_match_logic", filter.TagsMatchLogic).
Set("except_tags_match_logic", filter.ExceptTagsMatchLogic).
Set("artists", filter.Artists).
Set("albums", filter.Albums).
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 {
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 {
q = q.Set("artists", filter.Artists)
}

View file

@ -115,6 +115,8 @@ CREATE TABLE filter
except_language TEXT [] DEFAULT '{}',
tags TEXT,
except_tags TEXT,
tags_match_logic TEXT,
except_tags_match_logic TEXT,
origins TEXT [] DEFAULT '{}',
except_origins TEXT [] DEFAULT '{}',
external_script_enabled BOOLEAN DEFAULT FALSE,
@ -655,4 +657,18 @@ ADD COLUMN info_url TEXT;
ALTER TABLE "release"
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;
`,
}

View file

@ -115,6 +115,8 @@ CREATE TABLE filter
except_language TEXT [] DEFAULT '{}',
tags TEXT,
except_tags TEXT,
tags_match_logic TEXT,
except_tags_match_logic TEXT,
origins TEXT [] DEFAULT '{}',
except_origins TEXT [] DEFAULT '{}',
external_script_enabled BOOLEAN DEFAULT FALSE,
@ -1048,4 +1050,18 @@ ADD COLUMN info_url TEXT;
ALTER TABLE "release"
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;
`,
}

View file

@ -115,6 +115,8 @@ type Filter struct {
ExceptTags string `json:"except_tags,omitempty"`
TagsAny string `json:"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"`
ExceptReleaseTags string `json:"except_release_tags,omitempty"`
UseRegexReleaseTags bool `json:"use_regex_release_tags,omitempty"`
@ -190,6 +192,8 @@ type FilterUpdate struct {
ExceptTags *string `json:"except_tags,omitempty"`
TagsAny *string `json:"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"`
ExternalScriptCmd *string `json:"external_script_cmd,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)
}
if f.Tags != "" && !containsAny(r.Tags, f.Tags) {
r.addRejectionF("tags not matching. got: %v want: %v", r.Tags, f.Tags)
if 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) {
r.addRejectionF("tags unwanted. got: %v want: %v", r.Tags, f.ExceptTags)
if 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) {
@ -620,6 +632,10 @@ func containsAny(tags []string, filter string) bool {
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 {
return containsMatch(tags, strings.Split(filter, ","))
}
@ -686,6 +702,39 @@ func containsMatch(tags []string, filters []string) bool {
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 {
for _, tag := range tags {
if tag == "" {

View file

@ -520,7 +520,7 @@ func TestFilter_CheckFilter(t *testing.T) {
want: true,
},
{
name: "match_tags",
name: "match_tags_any",
fields: &Release{
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
Category: "TV",
@ -535,12 +535,34 @@ func TestFilter_CheckFilter(t *testing.T) {
ExceptUploaders: "Anonymous",
Shows: "Good show",
Tags: "tv",
TagsMatchLogic: "ANY",
},
},
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{
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
Category: "TV",
@ -555,13 +577,36 @@ func TestFilter_CheckFilter(t *testing.T) {
ExceptUploaders: "Anonymous",
Shows: "Good show",
Tags: "tv",
TagsMatchLogic: "ANY",
},
rejections: []string{"tags not matching. got: [foreign] want: tv"},
},
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{
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
Category: "TV",
@ -576,12 +621,13 @@ func TestFilter_CheckFilter(t *testing.T) {
ExceptUploaders: "Anonymous",
Shows: "Good show",
ExceptTags: "tv",
TagsMatchLogic: "ANY",
},
},
want: true,
},
{
name: "match_except_tags_2",
name: "match_except_tags_all",
fields: &Release{
TorrentName: "Good show S02 2160p ATVP WEB-DL DDP 5.1 Atmos DV HEVC-GROUP2",
Category: "TV",
@ -595,12 +641,56 @@ func TestFilter_CheckFilter(t *testing.T) {
MatchUploaders: "Uploader1,Uploader2",
ExceptUploaders: "Anonymous",
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"},
},
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",
fields: &Release{
@ -1717,64 +1807,64 @@ func TestFilter_CheckFilter1(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := Filter{
ID: tt.fields.ID,
Name: tt.fields.Name,
Enabled: tt.fields.Enabled,
CreatedAt: tt.fields.CreatedAt,
UpdatedAt: tt.fields.UpdatedAt,
MinSize: tt.fields.MinSize,
MaxSize: tt.fields.MaxSize,
Delay: tt.fields.Delay,
Priority: tt.fields.Priority,
MaxDownloads: tt.fields.MaxDownloads,
MaxDownloadsUnit: tt.fields.MaxDownloadsUnit,
MatchReleases: tt.fields.MatchReleases,
ExceptReleases: tt.fields.ExceptReleases,
UseRegex: tt.fields.UseRegex,
MatchReleaseGroups: tt.fields.MatchReleaseGroups,
ExceptReleaseGroups: tt.fields.ExceptReleaseGroups,
MatchReleaseTags: tt.fields.MatchReleaseTags,
ExceptReleaseTags: tt.fields.ExceptReleaseTags,
UseRegexReleaseTags: tt.fields.UseRegexReleaseTags,
Scene: tt.fields.Scene,
Origins: tt.fields.Origins,
ExceptOrigins: tt.fields.ExceptOrigins,
Freeleech: tt.fields.Freeleech,
FreeleechPercent: tt.fields.FreeleechPercent,
Shows: tt.fields.Shows,
Seasons: tt.fields.Seasons,
Episodes: tt.fields.Episodes,
Resolutions: tt.fields.Resolutions,
Codecs: tt.fields.Codecs,
Sources: tt.fields.Sources,
Containers: tt.fields.Containers,
MatchHDR: tt.fields.MatchHDR,
ExceptHDR: tt.fields.ExceptHDR,
Years: tt.fields.Years,
Artists: tt.fields.Artists,
Albums: tt.fields.Albums,
MatchReleaseTypes: tt.fields.MatchReleaseTypes,
ExceptReleaseTypes: tt.fields.ExceptReleaseTypes,
Formats: tt.fields.Formats,
Quality: tt.fields.Quality,
Media: tt.fields.Media,
PerfectFlac: tt.fields.PerfectFlac,
Cue: tt.fields.Cue,
Log: tt.fields.Log,
LogScore: tt.fields.LogScore,
MatchOther: tt.fields.MatchOther,
ExceptOther: tt.fields.ExceptOther,
MatchCategories: tt.fields.MatchCategories,
ExceptCategories: tt.fields.ExceptCategories,
MatchUploaders: tt.fields.MatchUploaders,
ExceptUploaders: tt.fields.ExceptUploaders,
Tags: tt.fields.Tags,
ExceptTags: tt.fields.ExceptTags,
TagsAny: tt.fields.TagsAny,
ExceptTagsAny: tt.fields.ExceptTagsAny,
Actions: tt.fields.Actions,
Indexers: tt.fields.Indexers,
Downloads: tt.fields.Downloads,
ID: tt.fields.ID,
Name: tt.fields.Name,
Enabled: tt.fields.Enabled,
CreatedAt: tt.fields.CreatedAt,
UpdatedAt: tt.fields.UpdatedAt,
MinSize: tt.fields.MinSize,
MaxSize: tt.fields.MaxSize,
Delay: tt.fields.Delay,
Priority: tt.fields.Priority,
MaxDownloads: tt.fields.MaxDownloads,
MaxDownloadsUnit: tt.fields.MaxDownloadsUnit,
MatchReleases: tt.fields.MatchReleases,
ExceptReleases: tt.fields.ExceptReleases,
UseRegex: tt.fields.UseRegex,
MatchReleaseGroups: tt.fields.MatchReleaseGroups,
ExceptReleaseGroups: tt.fields.ExceptReleaseGroups,
MatchReleaseTags: tt.fields.MatchReleaseTags,
ExceptReleaseTags: tt.fields.ExceptReleaseTags,
UseRegexReleaseTags: tt.fields.UseRegexReleaseTags,
Scene: tt.fields.Scene,
Origins: tt.fields.Origins,
ExceptOrigins: tt.fields.ExceptOrigins,
Freeleech: tt.fields.Freeleech,
FreeleechPercent: tt.fields.FreeleechPercent,
Shows: tt.fields.Shows,
Seasons: tt.fields.Seasons,
Episodes: tt.fields.Episodes,
Resolutions: tt.fields.Resolutions,
Codecs: tt.fields.Codecs,
Sources: tt.fields.Sources,
Containers: tt.fields.Containers,
MatchHDR: tt.fields.MatchHDR,
ExceptHDR: tt.fields.ExceptHDR,
Years: tt.fields.Years,
Artists: tt.fields.Artists,
Albums: tt.fields.Albums,
MatchReleaseTypes: tt.fields.MatchReleaseTypes,
ExceptReleaseTypes: tt.fields.ExceptReleaseTypes,
Formats: tt.fields.Formats,
Quality: tt.fields.Quality,
Media: tt.fields.Media,
PerfectFlac: tt.fields.PerfectFlac,
Cue: tt.fields.Cue,
Log: tt.fields.Log,
LogScore: tt.fields.LogScore,
MatchOther: tt.fields.MatchOther,
ExceptOther: tt.fields.ExceptOther,
MatchCategories: tt.fields.MatchCategories,
ExceptCategories: tt.fields.ExceptCategories,
MatchUploaders: tt.fields.MatchUploaders,
ExceptUploaders: tt.fields.ExceptUploaders,
Tags: tt.fields.Tags,
ExceptTags: tt.fields.ExceptTags,
TagsMatchLogic: tt.fields.TagsMatchLogic,
ExceptTagsMatchLogic: tt.fields.ExceptTagsMatchLogic,
Actions: tt.fields.Actions,
Indexers: tt.fields.Indexers,
Downloads: tt.fields.Downloads,
}
tt.args.r.ParseString(tt.args.r.TorrentName)
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) {
type args struct {
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) {
type args struct {
tags []string