feat(filters): filtering for raw releaseTags (#506)

feat(filters): add releaseTags filtering
This commit is contained in:
ze0s 2022-10-18 23:52:36 +02:00 committed by GitHub
parent dbabb26b83
commit 5183f7683a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 166 additions and 18 deletions

View file

@ -184,6 +184,9 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
"use_regex",
"match_release_groups",
"except_release_groups",
"match_release_tags",
"except_release_tags",
"use_regex_release_tags",
"scene",
"freeleech",
"freeleech_percent",
@ -242,11 +245,11 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
}
var f domain.Filter
var minSize, maxSize, maxDownloadsUnit, matchReleases, exceptReleases, matchReleaseGroups, exceptReleaseGroups, 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, 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, &scene, &freeleech, &freeleechPercent, &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, &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, &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, &tags, &exceptTags, 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")
}
@ -259,6 +262,8 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
f.ExceptReleases = exceptReleases.String
f.MatchReleaseGroups = matchReleaseGroups.String
f.ExceptReleaseGroups = exceptReleaseGroups.String
f.MatchReleaseTags = matchReleaseTags.String
f.ExceptReleaseTags = exceptReleaseTags.String
f.FreeleechPercent = freeleechPercent.String
f.Shows = shows.String
f.Seasons = seasons.String
@ -335,6 +340,9 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
"f.use_regex",
"f.match_release_groups",
"f.except_release_groups",
"f.match_release_tags",
"f.except_release_tags",
"f.use_regex_release_tags",
"f.scene",
"f.freeleech",
"f.freeleech_percent",
@ -403,11 +411,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, 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, 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, &scene, &freeleech, &freeleechPercent, &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, &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, &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, &tags, &exceptTags, 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")
}
@ -420,6 +428,8 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
f.ExceptReleases = exceptReleases.String
f.MatchReleaseGroups = matchReleaseGroups.String
f.ExceptReleaseGroups = exceptReleaseGroups.String
f.MatchReleaseTags = matchReleaseTags.String
f.ExceptReleaseTags = exceptReleaseTags.String
f.FreeleechPercent = freeleechPercent.String
f.Shows = shows.String
f.Seasons = seasons.String
@ -474,6 +484,9 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F
"use_regex",
"match_release_groups",
"except_release_groups",
"match_release_tags",
"except_release_tags",
"use_regex_release_tags",
"scene",
"freeleech",
"freeleech_percent",
@ -530,6 +543,9 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F
filter.UseRegex,
filter.MatchReleaseGroups,
filter.ExceptReleaseGroups,
filter.MatchReleaseTags,
filter.ExceptReleaseTags,
filter.UseRegexReleaseTags,
filter.Scene,
filter.Freeleech,
filter.FreeleechPercent,
@ -605,6 +621,9 @@ func (r *FilterRepo) Update(ctx context.Context, filter domain.Filter) (*domain.
Set("except_releases", filter.ExceptReleases).
Set("match_release_groups", filter.MatchReleaseGroups).
Set("except_release_groups", filter.ExceptReleaseGroups).
Set("match_release_tags", filter.MatchReleaseTags).
Set("except_release_tags", filter.ExceptReleaseTags).
Set("use_regex_release_tags", filter.UseRegexReleaseTags).
Set("scene", filter.Scene).
Set("freeleech", filter.Freeleech).
Set("freeleech_percent", filter.FreeleechPercent).
@ -706,6 +725,15 @@ func (r *FilterRepo) UpdatePartial(ctx context.Context, filter domain.FilterUpda
if filter.ExceptReleaseGroups != nil {
q = q.Set("except_release_groups", filter.ExceptReleaseGroups)
}
if filter.MatchReleaseTags != nil {
q = q.Set("match_release_tags", filter.MatchReleaseTags)
}
if filter.ExceptReleaseTags != nil {
q = q.Set("except_release_tags", filter.ExceptReleaseTags)
}
if filter.UseRegexReleaseTags != nil {
q = q.Set("use_regex_release_tags", filter.UseRegexReleaseTags)
}
if filter.Scene != nil {
q = q.Set("scene", filter.Scene)
}

View file

@ -74,6 +74,9 @@ CREATE TABLE filter
use_regex BOOLEAN,
match_release_groups TEXT,
except_release_groups TEXT,
match_release_tags TEXT,
except_release_tags TEXT,
use_regex_release_tags BOOLEAN DEFAULT FALSE,
scene BOOLEAN,
freeleech BOOLEAN,
freeleech_percent TEXT,
@ -577,4 +580,13 @@ CREATE INDEX indexer_identifier_index
ALTER TABLE feed
ADD COLUMN cookie TEXT;
`,
`ALTER TABLE filter
ADD COLUMN match_release_tags TEXT;
ALTER TABLE filter
ADD COLUMN except_release_tags TEXT;
ALTER TABLE filter
ADD COLUMN use_regex_release_tags BOOLEAN DEFAULT FALSE;
`,
}

View file

@ -74,6 +74,9 @@ CREATE TABLE filter
use_regex BOOLEAN,
match_release_groups TEXT,
except_release_groups TEXT,
match_release_tags TEXT,
except_release_tags TEXT,
use_regex_release_tags BOOLEAN DEFAULT FALSE,
scene BOOLEAN,
freeleech BOOLEAN,
freeleech_percent TEXT,
@ -897,4 +900,13 @@ CREATE INDEX indexer_identifier_index
ALTER TABLE feed
ADD COLUMN cookie TEXT;
`,
`ALTER TABLE filter
ADD COLUMN match_release_tags TEXT;
ALTER TABLE filter
ADD COLUMN except_release_tags TEXT;
ALTER TABLE filter
ADD COLUMN use_regex_release_tags BOOLEAN DEFAULT FALSE;
`,
}

View file

@ -112,6 +112,9 @@ type Filter struct {
ExceptTags string `json:"except_tags,omitempty"`
TagsAny string `json:"tags_any,omitempty"`
ExceptTagsAny string `json:"except_tags_any,omitempty"`
MatchReleaseTags string `json:"match_release_tags,omitempty"`
ExceptReleaseTags string `json:"except_release_tags,omitempty"`
UseRegexReleaseTags bool `json:"use_regex_release_tags,omitempty"`
ExternalScriptEnabled bool `json:"external_script_enabled,omitempty"`
ExternalScriptCmd string `json:"external_script_cmd,omitempty"`
ExternalScriptArgs string `json:"external_script_args,omitempty"`
@ -141,6 +144,9 @@ type FilterUpdate struct {
UseRegex *bool `json:"use_regex,omitempty"`
MatchReleaseGroups *string `json:"match_release_groups,omitempty"`
ExceptReleaseGroups *string `json:"except_release_groups,omitempty"`
MatchReleaseTags *string `json:"match_release_tags,omitempty"`
ExceptReleaseTags *string `json:"except_release_tags,omitempty"`
UseRegexReleaseTags *bool `json:"use_regex_release_tags,omitempty"`
Scene *bool `json:"scene,omitempty"`
Origins *[]string `json:"origins,omitempty"`
ExceptOrigins *[]string `json:"except_origins,omitempty"`
@ -261,6 +267,26 @@ func (f Filter) CheckFilter(r *Release) ([]string, bool) {
r.addRejectionF("unwanted release group. got: %v unwanted: %v", r.Group, f.ExceptReleaseGroups)
}
// check raw releaseTags string
if f.UseRegexReleaseTags {
if f.MatchReleaseTags != "" && !matchRegex(r.ReleaseTags, f.MatchReleaseTags) {
r.addRejectionF("match release tags regex not matching. got: %v want: %v", r.ReleaseTags, f.MatchReleaseTags)
}
if f.ExceptReleaseTags != "" && matchRegex(r.ReleaseTags, f.ExceptReleaseTags) {
r.addRejectionF("except release tags regex: unwanted release. got: %v want: %v", r.ReleaseTags, f.ExceptReleaseTags)
}
} else {
if f.MatchReleaseTags != "" && !containsFuzzy(r.ReleaseTags, f.MatchReleaseTags) {
r.addRejectionF("match release tags not matching. got: %v want: %v", r.ReleaseTags, f.MatchReleaseTags)
}
if f.ExceptReleaseTags != "" && containsFuzzy(r.ReleaseTags, f.ExceptReleaseTags) {
r.addRejectionF("except release tags: unwanted release. got: %v want: %v", r.ReleaseTags, f.ExceptReleaseTags)
}
}
if f.MatchUploaders != "" && !contains(r.Uploader, f.MatchUploaders) {
r.addRejectionF("uploaders not matching. got: %v want: %v", r.Uploader, f.MatchUploaders)
}

View file

@ -1581,6 +1581,45 @@ func TestFilter_CheckFilter1(t *testing.T) {
wantRejections: nil,
wantMatch: true,
},
{
name: "test_39",
fields: fields{
UseRegexReleaseTags: true,
MatchReleaseTags: ".*1080p.+(group1|group3)",
},
args: args{&Release{TorrentName: "Show.Name.S01.DV.2160p.ATVP.WEB-DL.DDPA5.1.x265-GROUP2", ReleaseTags: "MKV | x264 | WEB | P2P"}},
wantRejections: []string{"match release tags regex not matching. got: MKV | x264 | WEB | P2P want: .*1080p.+(group1|group3)"},
wantMatch: false,
},
{
name: "test_40",
fields: fields{
UseRegexReleaseTags: true,
MatchReleaseTags: "foreign - 16",
},
args: args{&Release{TorrentName: "Show.Name.S01.DV.2160p.ATVP.WEB-DL.DDPA5.1.x265-GROUP2", ReleaseTags: "MKV | x264 | WEB | P2P | Foreign - 17"}},
wantRejections: []string{"match release tags regex not matching. got: MKV | x264 | WEB | P2P | Foreign - 17 want: foreign - 16"},
wantMatch: false,
},
{
name: "test_41",
fields: fields{
UseRegexReleaseTags: true,
MatchReleaseTags: "foreign - 17",
},
args: args{&Release{TorrentName: "Show.Name.S01.DV.2160p.ATVP.WEB-DL.DDPA5.1.x265-GROUP2", ReleaseTags: "MKV | x264 | WEB | P2P | Foreign - 17"}},
wantMatch: true,
},
{
name: "test_42",
fields: fields{
UseRegexReleaseTags: true,
MatchReleaseTags: "foreign - 17",
},
args: args{&Release{TorrentName: "Show.Name.S01.DV.2160p.ATVP.WEB-DL.DDPA5.1.x265-GROUP2", ReleaseTags: ""}},
wantRejections: []string{"match release tags regex not matching. got: want: foreign - 17"},
wantMatch: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -1601,6 +1640,9 @@ func TestFilter_CheckFilter1(t *testing.T) {
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,

View file

@ -250,6 +250,9 @@ export default function FilterDetails() {
except_releases: filter.except_releases,
match_release_groups: filter.match_release_groups,
except_release_groups: filter.except_release_groups,
match_release_tags: filter.match_release_tags,
except_release_tags: filter.except_release_tags,
use_regex_release_tags: filter.use_regex_release_tags,
match_categories: filter.match_categories,
except_categories: filter.except_categories,
tags: filter.tags,
@ -454,20 +457,7 @@ export function Advanced() {
<div>
<CollapsableSection defaultOpen={true} title="Releases" subtitle="Match only certain release names and/or ignore other release names">
<div className="grid col-span-12 gap-6">
<div
className="col-span-12 flex p-4 text-sm text-yellow-700 bg-yellow-100 rounded-lg dark:bg-yellow-200 dark:text-yellow-800"
role="alert">
<svg aria-hidden="true" className="flex-shrink-0 inline w-5 h-5 mr-3" fill="currentColor"
viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
clipRule="evenodd"></path>
</svg>
<span className="sr-only">Info</span>
<div>
<span className="font-bold">Warning!</span> autobrr has extensive filtering built-in - only use this if nothing else works. If you need help please ask.
</div>
</div>
<WarningAlert text="autobrr has extensive filtering built-in - only use this if nothing else works. If you need help please ask." />
<TextField name="match_releases" label="Match releases" columns={6} placeholder="eg. *some?movie*,*some?show*s01*" />
<TextField name="except_releases" label="Except releases" columns={6} placeholder="" />
@ -500,6 +490,18 @@ export function Advanced() {
<MultiSelect name="except_origins" options={ORIGIN_OPTIONS} label="Except Origins" columns={6} creatable={true} />
</CollapsableSection>
<CollapsableSection defaultOpen={true} title="Release Tags" subtitle="This is the non-parsed releaseTags string from the announce">
<div className="grid col-span-12 gap-6">
<WarningAlert text="These might not be what you think they are. For advanced users who know how things are parsed." />
<TextField name="match_release_tags" label="Match release tags" columns={6} placeholder="eg. *mkv*,*foreign*" />
<TextField name="except_release_tags" label="Except release tags" columns={6} placeholder="" />
<div className="col-span-6">
<SwitchGroup name="use_regex_release_tags" label="Use Regex" />
</div>
</div>
</CollapsableSection>
<CollapsableSection defaultOpen={true} title="Freeleech" subtitle="Match only freeleech and freeleech percent">
<div className="col-span-6">
<SwitchGroup name="freeleech" label="Freeleech" />
@ -511,6 +513,29 @@ export function Advanced() {
);
}
interface WarningAlertProps {
text: string;
}
function WarningAlert({ text }: WarningAlertProps) {
return (
<div
className="col-span-12 flex p-4 text-sm text-yellow-700 bg-yellow-100 rounded-lg dark:bg-yellow-200 dark:text-yellow-800"
role="alert">
<svg aria-hidden="true" className="flex-shrink-0 inline w-5 h-5 mr-3" fill="currentColor"
viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
clipRule="evenodd"></path>
</svg>
<span className="sr-only">Info</span>
<div>
<span className="font-bold">Warning!</span> {text}
</div>
</div>
);
}
interface CollapsableSectionProps {
title: string;
subtitle: string;

View file

@ -15,6 +15,9 @@ interface Filter {
use_regex: boolean;
match_release_groups: string;
except_release_groups: string;
match_release_tags: string;
except_release_tags: string;
use_regex_release_tags: boolean;
scene: boolean;
origins: string[];
except_origins: string[];