feat(filters): implement AnnounceType (#1837)

* feat(filters): implement AnnounceType

* fix: rss tests
This commit is contained in:
ze0s 2024-12-08 21:08:24 +01:00 committed by GitHub
parent ec85d53d8f
commit f644b3a4d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 155 additions and 17 deletions

View file

@ -175,6 +175,7 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
"f.max_size", "f.max_size",
"f.delay", "f.delay",
"f.priority", "f.priority",
"f.announce_types",
"f.max_downloads", "f.max_downloads",
"f.max_downloads_unit", "f.max_downloads_unit",
"f.match_releases", "f.match_releases",
@ -267,6 +268,7 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
&maxSize, &maxSize,
&delay, &delay,
&f.Priority, &f.Priority,
pq.Array(&f.AnnounceTypes),
&maxDownloads, &maxDownloads,
&maxDownloadsUnit, &maxDownloadsUnit,
&matchReleases, &matchReleases,
@ -391,6 +393,7 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, indexer string
"f.max_size", "f.max_size",
"f.delay", "f.delay",
"f.priority", "f.priority",
"f.announce_types",
"f.max_downloads", "f.max_downloads",
"f.max_downloads_unit", "f.max_downloads_unit",
"f.match_releases", "f.match_releases",
@ -488,6 +491,7 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, indexer string
&maxSize, &maxSize,
&delay, &delay,
&f.Priority, &f.Priority,
pq.Array(&f.AnnounceTypes),
&maxDownloads, &maxDownloads,
&maxDownloadsUnit, &maxDownloadsUnit,
&matchReleases, &matchReleases,
@ -693,6 +697,7 @@ func (r *FilterRepo) Store(ctx context.Context, filter *domain.Filter) error {
"max_size", "max_size",
"delay", "delay",
"priority", "priority",
"announce_types",
"max_downloads", "max_downloads",
"max_downloads_unit", "max_downloads_unit",
"match_releases", "match_releases",
@ -758,6 +763,7 @@ func (r *FilterRepo) Store(ctx context.Context, filter *domain.Filter) error {
filter.MaxSize, filter.MaxSize,
filter.Delay, filter.Delay,
filter.Priority, filter.Priority,
pq.Array(filter.AnnounceTypes),
filter.MaxDownloads, filter.MaxDownloads,
filter.MaxDownloadsUnit, filter.MaxDownloadsUnit,
filter.MatchReleases, filter.MatchReleases,
@ -841,6 +847,7 @@ func (r *FilterRepo) Update(ctx context.Context, filter *domain.Filter) error {
Set("max_size", filter.MaxSize). Set("max_size", filter.MaxSize).
Set("delay", filter.Delay). Set("delay", filter.Delay).
Set("priority", filter.Priority). Set("priority", filter.Priority).
Set("announce_types", pq.Array(filter.AnnounceTypes)).
Set("max_downloads", filter.MaxDownloads). Set("max_downloads", filter.MaxDownloads).
Set("max_downloads_unit", filter.MaxDownloadsUnit). Set("max_downloads_unit", filter.MaxDownloadsUnit).
Set("use_regex", filter.UseRegex). Set("use_regex", filter.UseRegex).
@ -943,6 +950,9 @@ func (r *FilterRepo) UpdatePartial(ctx context.Context, filter domain.FilterUpda
if filter.Priority != nil { if filter.Priority != nil {
q = q.Set("priority", filter.Priority) q = q.Set("priority", filter.Priority)
} }
if filter.AnnounceTypes != nil {
q = q.Set("announce_types", pq.Array(filter.AnnounceTypes))
}
if filter.MaxDownloads != nil { if filter.MaxDownloads != nil {
q = q.Set("max_downloads", filter.MaxDownloads) q = q.Set("max_downloads", filter.MaxDownloads)
} }

View file

@ -99,6 +99,7 @@ CREATE TABLE filter
priority INTEGER DEFAULT 0 NOT NULL, priority INTEGER DEFAULT 0 NOT NULL,
max_downloads INTEGER DEFAULT 0, max_downloads INTEGER DEFAULT 0,
max_downloads_unit TEXT, max_downloads_unit TEXT,
announce_types TEXT [] DEFAULT '{}',
match_releases TEXT, match_releases TEXT,
except_releases TEXT, except_releases TEXT,
use_regex BOOLEAN, use_regex BOOLEAN,
@ -261,6 +262,7 @@ CREATE TABLE "release"
protocol TEXT, protocol TEXT,
implementation TEXT, implementation TEXT,
timestamp TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, timestamp TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
announce_type TEXT DEFAULT 'NEW',
info_url TEXT, info_url TEXT,
download_url TEXT, download_url TEXT,
group_id TEXT, group_id TEXT,
@ -994,5 +996,11 @@ UPDATE irc_network
`UPDATE irc_network `UPDATE irc_network
SET port = '6697', tls = true SET port = '6697', tls = true
WHERE server = 'irc.seedpool.org'; WHERE server = 'irc.seedpool.org';
`,
`ALTER TABLE "release"
ADD COLUMN announce_type TEXT DEFAULT 'NEW';
ALTER TABLE filter
ADD COLUMN announce_types TEXT [] DEFAULT '{}';
`, `,
} }

View file

@ -38,8 +38,8 @@ func (repo *ReleaseRepo) Store(ctx context.Context, r *domain.Release) error {
queryBuilder := repo.db.squirrel. queryBuilder := repo.db.squirrel.
Insert("release"). Insert("release").
Columns("filter_status", "rejections", "indexer", "filter", "protocol", "implementation", "timestamp", "group_id", "torrent_id", "info_url", "download_url", "torrent_name", "size", "title", "category", "season", "episode", "year", "month", "day", "resolution", "source", "codec", "container", "hdr", "release_group", "proper", "repack", "website", "type", "origin", "tags", "uploader", "pre_time", "filter_id"). Columns("filter_status", "rejections", "indexer", "filter", "protocol", "implementation", "timestamp", "announce_type", "group_id", "torrent_id", "info_url", "download_url", "torrent_name", "size", "title", "category", "season", "episode", "year", "month", "day", "resolution", "source", "codec", "container", "hdr", "release_group", "proper", "repack", "website", "type", "origin", "tags", "uploader", "pre_time", "filter_id").
Values(r.FilterStatus, pq.Array(r.Rejections), r.Indexer.Identifier, r.FilterName, r.Protocol, r.Implementation, r.Timestamp.Format(time.RFC3339), r.GroupID, r.TorrentID, r.InfoURL, r.DownloadURL, r.TorrentName, r.Size, r.Title, r.Category, r.Season, r.Episode, r.Year, r.Month, r.Day, r.Resolution, r.Source, codecStr, r.Container, hdrStr, r.Group, r.Proper, r.Repack, r.Website, r.Type, r.Origin, pq.Array(r.Tags), r.Uploader, r.PreTime, r.FilterID). Values(r.FilterStatus, pq.Array(r.Rejections), r.Indexer.Identifier, r.FilterName, r.Protocol, r.Implementation, r.Timestamp.Format(time.RFC3339), r.AnnounceType, r.GroupID, r.TorrentID, r.InfoURL, r.DownloadURL, r.TorrentName, r.Size, r.Title, r.Category, r.Season, r.Episode, r.Year, r.Month, r.Day, r.Resolution, r.Source, codecStr, r.Container, hdrStr, r.Group, r.Proper, r.Repack, r.Website, r.Type, r.Origin, pq.Array(r.Tags), r.Uploader, r.PreTime, r.FilterID).
Suffix("RETURNING id").RunWith(repo.db.handler) Suffix("RETURNING id").RunWith(repo.db.handler)
// return values // return values
@ -230,7 +230,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
} }
queryBuilder := repo.db.squirrel. queryBuilder := repo.db.squirrel.
Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "i.id", "i.name", "i.identifier_external", "r.filter", "r.protocol", "r.info_url", "r.download_url", "r.title", "r.torrent_name", "r.size", "r.category", "r.season", "r.episode", "r.year", "r.resolution", "r.source", "r.codec", "r.container", "r.release_group", "r.timestamp", Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "i.id", "i.name", "i.identifier_external", "r.filter", "r.protocol", "r.announce_type", "r.info_url", "r.download_url", "r.title", "r.torrent_name", "r.size", "r.category", "r.season", "r.episode", "r.year", "r.resolution", "r.source", "r.codec", "r.container", "r.release_group", "r.timestamp",
"ras.id", "ras.status", "ras.action", "ras.action_id", "ras.type", "ras.client", "ras.filter", "ras.filter_id", "ras.release_id", "ras.rejections", "ras.timestamp"). "ras.id", "ras.status", "ras.action", "ras.action_id", "ras.type", "ras.client", "ras.filter", "ras.filter_id", "ras.release_id", "ras.rejections", "ras.timestamp").
Column(sq.Alias(countQuery, "page_total")). Column(sq.Alias(countQuery, "page_total")).
From("release r"). From("release r").
@ -267,7 +267,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
var rls domain.Release var rls domain.Release
var ras domain.ReleaseActionStatus var ras domain.ReleaseActionStatus
var rlsIndexer, rlsIndexerName, rlsIndexerExternalName, rlsFilter, infoUrl, downloadUrl, codec sql.NullString var rlsIndexer, rlsIndexerName, rlsIndexerExternalName, rlsFilter, rlsAnnounceType, infoUrl, downloadUrl, codec sql.NullString
var rlsIndexerID sql.NullInt64 var rlsIndexerID sql.NullInt64
var rasId, rasFilterId, rasReleaseId, rasActionId sql.NullInt64 var rasId, rasFilterId, rasReleaseId, rasActionId sql.NullInt64
@ -275,7 +275,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
var rasRejections []sql.NullString var rasRejections []sql.NullString
var rasTimestamp sql.NullTime var rasTimestamp sql.NullTime
if err := rows.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &rlsIndexer, &rlsIndexerID, &rlsIndexerName, &rlsIndexerExternalName, &rlsFilter, &rls.Protocol, &infoUrl, &downloadUrl, &rls.Title, &rls.TorrentName, &rls.Size, &rls.Category, &rls.Season, &rls.Episode, &rls.Year, &rls.Resolution, &rls.Source, &codec, &rls.Container, &rls.Group, &rls.Timestamp, &rasId, &rasStatus, &rasAction, &rasActionId, &rasType, &rasClient, &rasFilter, &rasFilterId, &rasReleaseId, pq.Array(&rasRejections), &rasTimestamp, &resp.TotalCount); err != nil { if err := rows.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &rlsIndexer, &rlsIndexerID, &rlsIndexerName, &rlsIndexerExternalName, &rlsFilter, &rls.Protocol, &rlsAnnounceType, &infoUrl, &downloadUrl, &rls.Title, &rls.TorrentName, &rls.Size, &rls.Category, &rls.Season, &rls.Episode, &rls.Year, &rls.Resolution, &rls.Source, &codec, &rls.Container, &rls.Group, &rls.Timestamp, &rasId, &rasStatus, &rasAction, &rasActionId, &rasType, &rasClient, &rasFilter, &rasFilterId, &rasReleaseId, pq.Array(&rasRejections), &rasTimestamp, &resp.TotalCount); err != nil {
return resp, errors.Wrap(err, "error scanning row") return resp, errors.Wrap(err, "error scanning row")
} }
@ -320,6 +320,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
rls.Indexer.IdentifierExternal = rlsIndexerExternalName.String rls.Indexer.IdentifierExternal = rlsIndexerExternalName.String
rls.FilterName = rlsFilter.String rls.FilterName = rlsFilter.String
rls.AnnounceType = domain.AnnounceType(rlsAnnounceType.String)
rls.ActionStatus = make([]domain.ReleaseActionStatus, 0) rls.ActionStatus = make([]domain.ReleaseActionStatus, 0)
rls.InfoURL = infoUrl.String rls.InfoURL = infoUrl.String
rls.DownloadURL = downloadUrl.String rls.DownloadURL = downloadUrl.String
@ -419,7 +420,7 @@ func (repo *ReleaseRepo) GetActionStatusByReleaseID(ctx context.Context, release
func (repo *ReleaseRepo) Get(ctx context.Context, req *domain.GetReleaseRequest) (*domain.Release, error) { func (repo *ReleaseRepo) Get(ctx context.Context, req *domain.GetReleaseRequest) (*domain.Release, error) {
queryBuilder := repo.db.squirrel. queryBuilder := repo.db.squirrel.
Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "r.filter", "r.filter_id", "r.protocol", "r.implementation", "r.info_url", "r.download_url", "r.title", "r.torrent_name", "r.category", "r.size", "r.group_id", "r.torrent_id", "r.uploader", "r.timestamp"). Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "r.filter", "r.filter_id", "r.protocol", "r.implementation", "r.announce_type", "r.info_url", "r.download_url", "r.title", "r.torrent_name", "r.category", "r.size", "r.group_id", "r.torrent_id", "r.uploader", "r.timestamp").
From("release r"). From("release r").
OrderBy("r.id DESC"). OrderBy("r.id DESC").
Where(sq.Eq{"r.id": req.Id}) Where(sq.Eq{"r.id": req.Id})
@ -438,10 +439,10 @@ func (repo *ReleaseRepo) Get(ctx context.Context, req *domain.GetReleaseRequest)
var rls domain.Release var rls domain.Release
var indexerName, filterName, infoUrl, downloadUrl, groupId, torrentId, category, uploader sql.NullString var indexerName, filterName, announceType, infoUrl, downloadUrl, groupId, torrentId, category, uploader sql.NullString
var filterId sql.NullInt64 var filterId sql.NullInt64
if err := row.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &indexerName, &filterName, &filterId, &rls.Protocol, &rls.Implementation, &infoUrl, &downloadUrl, &rls.Title, &rls.TorrentName, &category, &rls.Size, &groupId, &torrentId, &uploader, &rls.Timestamp); err != nil { if err := row.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &indexerName, &filterName, &filterId, &rls.Protocol, &rls.Implementation, &announceType, &infoUrl, &downloadUrl, &rls.Title, &rls.TorrentName, &category, &rls.Size, &groupId, &torrentId, &uploader, &rls.Timestamp); err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
return nil, domain.ErrRecordNotFound return nil, domain.ErrRecordNotFound
} }
@ -453,6 +454,7 @@ func (repo *ReleaseRepo) Get(ctx context.Context, req *domain.GetReleaseRequest)
rls.FilterName = filterName.String rls.FilterName = filterName.String
rls.FilterID = int(filterId.Int64) rls.FilterID = int(filterId.Int64)
rls.ActionStatus = make([]domain.ReleaseActionStatus, 0) rls.ActionStatus = make([]domain.ReleaseActionStatus, 0)
rls.AnnounceType = domain.AnnounceType(announceType.String)
rls.InfoURL = infoUrl.String rls.InfoURL = infoUrl.String
rls.DownloadURL = downloadUrl.String rls.DownloadURL = downloadUrl.String
rls.Category = category.String rls.Category = category.String

View file

@ -99,6 +99,7 @@ CREATE TABLE filter
priority INTEGER DEFAULT 0 NOT NULL, priority INTEGER DEFAULT 0 NOT NULL,
max_downloads INTEGER DEFAULT 0, max_downloads INTEGER DEFAULT 0,
max_downloads_unit TEXT, max_downloads_unit TEXT,
announce_types TEXT [] DEFAULT '{}',
match_releases TEXT, match_releases TEXT,
except_releases TEXT, except_releases TEXT,
use_regex BOOLEAN, use_regex BOOLEAN,
@ -264,6 +265,7 @@ CREATE TABLE "release"
protocol TEXT, protocol TEXT,
implementation TEXT, implementation TEXT,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
announce_type TEXT DEFAULT 'NEW',
info_url TEXT, info_url TEXT,
download_url TEXT, download_url TEXT,
group_id TEXT, group_id TEXT,
@ -1636,5 +1638,11 @@ UPDATE irc_network
`UPDATE irc_network `UPDATE irc_network
SET port = '6697', tls = true SET port = '6697', tls = true
WHERE server = 'irc.seedpool.org'; WHERE server = 'irc.seedpool.org';
`,
`ALTER TABLE "release"
ADD COLUMN announce_type TEXT DEFAULT 'NEW';
ALTER TABLE filter
ADD COLUMN announce_types TEXT [] DEFAULT '{}';
`, `,
} }

View file

@ -107,6 +107,7 @@ type Filter struct {
UseRegex bool `json:"use_regex,omitempty"` UseRegex bool `json:"use_regex,omitempty"`
MatchReleaseGroups string `json:"match_release_groups,omitempty"` MatchReleaseGroups string `json:"match_release_groups,omitempty"`
ExceptReleaseGroups string `json:"except_release_groups,omitempty"` ExceptReleaseGroups string `json:"except_release_groups,omitempty"`
AnnounceTypes []string `json:"announce_types,omitempty"`
Scene bool `json:"scene,omitempty"` Scene bool `json:"scene,omitempty"`
Origins []string `json:"origins,omitempty"` Origins []string `json:"origins,omitempty"`
ExceptOrigins []string `json:"except_origins,omitempty"` ExceptOrigins []string `json:"except_origins,omitempty"`
@ -222,6 +223,7 @@ type FilterUpdate struct {
MaxSize *string `json:"max_size,omitempty"` MaxSize *string `json:"max_size,omitempty"`
Delay *int `json:"delay,omitempty"` Delay *int `json:"delay,omitempty"`
Priority *int32 `json:"priority,omitempty"` Priority *int32 `json:"priority,omitempty"`
AnnounceTypes *[]string `json:"announce_types,omitempty"`
MaxDownloads *int `json:"max_downloads,omitempty"` MaxDownloads *int `json:"max_downloads,omitempty"`
MaxDownloadsUnit *FilterMaxDownloadsUnit `json:"max_downloads_unit,omitempty"` MaxDownloadsUnit *FilterMaxDownloadsUnit `json:"max_downloads_unit,omitempty"`
MatchReleases *string `json:"match_releases,omitempty"` MatchReleases *string `json:"match_releases,omitempty"`
@ -385,6 +387,10 @@ func (f *Filter) CheckFilter(r *Release) (*RejectionReasons, bool) {
f.RejectReasons.Add("freeleech percent", r.FreeleechPercent, f.FreeleechPercent) f.RejectReasons.Add("freeleech percent", r.FreeleechPercent, f.FreeleechPercent)
} }
if len(f.AnnounceTypes) > 0 && !basicContainsSlice(string(r.AnnounceType), f.AnnounceTypes) {
f.RejectReasons.Add("match announce type", r.AnnounceType, f.AnnounceTypes)
}
if len(f.Origins) > 0 && !containsSlice(r.Origin, f.Origins) { if len(f.Origins) > 0 && !containsSlice(r.Origin, f.Origins) {
f.RejectReasons.Add("match origin", r.Origin, f.Origins) f.RejectReasons.Add("match origin", r.Origin, f.Origins)
} }

View file

@ -53,6 +53,7 @@ type Release struct {
Protocol ReleaseProtocol `json:"protocol"` Protocol ReleaseProtocol `json:"protocol"`
Implementation ReleaseImplementation `json:"implementation"` // irc, rss, api Implementation ReleaseImplementation `json:"implementation"` // irc, rss, api
Timestamp time.Time `json:"timestamp"` Timestamp time.Time `json:"timestamp"`
AnnounceType AnnounceType `json:"announce_type"`
InfoURL string `json:"info_url"` InfoURL string `json:"info_url"`
DownloadURL string `json:"download_url"` DownloadURL string `json:"download_url"`
MagnetURI string `json:"-"` MagnetURI string `json:"-"`
@ -114,6 +115,56 @@ func (r *Release) Raw(s string) rls.Release {
return rls.ParseString(s) return rls.ParseString(s)
} }
type AnnounceType string
const (
// AnnounceTypeNew Default announce type
AnnounceTypeNew AnnounceType = "NEW"
// AnnounceTypeChecked Checked release
AnnounceTypeChecked AnnounceType = "CHECKED"
// AnnounceTypePromo Marked as promotion (neutral/half/feeeleech etc.)
AnnounceTypePromo AnnounceType = "PROMO"
// AnnounceTypePromoGP Marked Golden Popcorn, PTP specific
AnnounceTypePromoGP AnnounceType = "PROMO_GP"
// AnnounceTypeResurrect Reseeded/revived from dead
AnnounceTypeResurrect AnnounceType = "RESURRECTED"
)
func (a AnnounceType) String() string {
switch a {
case AnnounceTypeNew:
return "NEW"
case AnnounceTypeChecked:
return "CHECKED"
case AnnounceTypePromo:
return "PROMO"
case AnnounceTypePromoGP:
return "PROMO_GP"
case AnnounceTypeResurrect:
return "RESURRECTED"
}
return ""
}
// ParseAnnounceType parse AnnounceType from string
func ParseAnnounceType(s string) (AnnounceType, error) {
switch s {
case string(AnnounceTypeNew):
return AnnounceTypeNew, nil
case string(AnnounceTypeChecked):
return AnnounceTypeChecked, nil
case string(AnnounceTypePromo):
return AnnounceTypePromo, nil
case string(AnnounceTypePromoGP):
return AnnounceTypePromoGP, nil
case string(AnnounceTypeResurrect):
return AnnounceTypeResurrect, nil
default:
return "", fmt.Errorf("invalid AnnounceType: %s", s)
}
}
type ReleaseActionStatus struct { type ReleaseActionStatus struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Status ReleasePushStatus `json:"status"` Status ReleasePushStatus `json:"status"`
@ -307,6 +358,7 @@ func NewRelease(indexer IndexerMinimal) *Release {
Timestamp: time.Now(), Timestamp: time.Now(),
Tags: []string{}, Tags: []string{},
Size: 0, Size: 0,
AnnounceType: AnnounceTypeNew,
} }
return r return r
@ -667,7 +719,6 @@ const MagnetURIPrefix = "magnet:?"
// MapVars map vars from regex captures to fields on release // MapVars map vars from regex captures to fields on release
func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) error { func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) error {
if torrentName, err := getStringMapValue(varMap, "torrentName"); err != nil { if torrentName, err := getStringMapValue(varMap, "torrentName"); err != nil {
return errors.Wrap(err, "failed parsing required field") return errors.Wrap(err, "failed parsing required field")
} else { } else {
@ -682,6 +733,13 @@ func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) erro
r.Category = category r.Category = category
} }
if announceType, err := getStringMapValue(varMap, "announceTypeEnum"); err == nil {
annType, parseErr := ParseAnnounceType(announceType)
if parseErr == nil {
r.AnnounceType = annType
}
}
if freeleech, err := getStringMapValue(varMap, "freeleech"); err == nil { if freeleech, err := getStringMapValue(varMap, "freeleech"); err == nil {
fl := StringEqualFoldMulti(freeleech, "1", "free", "freeleech", "freeleech!", "yes", "VIP", "★") fl := StringEqualFoldMulti(freeleech, "1", "free", "freeleech", "freeleech!", "yes", "VIP", "★")
if fl { if fl {

View file

@ -73,7 +73,7 @@ func TestRSSJob_processItem(t *testing.T) {
Link: "/details.php?id=00000&hit=1", Link: "/details.php?id=00000&hit=1",
GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP",
}}, }},
want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Month: 9, Day: 22, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)}, want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", AnnounceType: domain.AnnounceTypeNew, Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Month: 9, Day: 22, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)},
}, },
{ {
name: "with_baseurl", name: "with_baseurl",
@ -107,7 +107,7 @@ func TestRSSJob_processItem(t *testing.T) {
Link: "https://fake-feed.com/details.php?id=00000&hit=1", Link: "https://fake-feed.com/details.php?id=00000&hit=1",
GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP",
}}, }},
want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Month: 9, Day: 22, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)}, want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", AnnounceType: domain.AnnounceTypeNew, Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Month: 9, Day: 22, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)},
}, },
{ {
name: "time_parse", name: "time_parse",
@ -142,7 +142,7 @@ func TestRSSJob_processItem(t *testing.T) {
GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP",
//PublishedParsed: &nowMinusTime, //PublishedParsed: &nowMinusTime,
}}, }},
want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Month: 9, Day: 22, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)}, want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", AnnounceType: domain.AnnounceTypeNew, Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Month: 9, Day: 22, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)},
}, },
{ {
name: "time_parse", name: "time_parse",
@ -208,7 +208,7 @@ func TestRSSJob_processItem(t *testing.T) {
}, },
}, },
}}, }},
want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, MagnetURI: "magnet:?xt=this-not-a-valid-magnet", GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 0, Title: "Some Release Title", Description: "Category: Example", Category: "", Season: 0, Episode: 0, Year: 2022, Month: 9, Day: 22, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)}, want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", AnnounceType: domain.AnnounceTypeNew, Timestamp: now, MagnetURI: "magnet:?xt=this-not-a-valid-magnet", GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 0, Title: "Some Release Title", Description: "Category: Example", Category: "", Season: 0, Episode: 0, Year: 2022, Month: 9, Day: 22, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)},
}, },
} }
for _, tt := range tests { for _, tt := range tests {

View file

@ -5,6 +5,29 @@
import { MultiSelectOption } from "@components/inputs/select"; import { MultiSelectOption } from "@components/inputs/select";
export const AnnounceTypeOptions: MultiSelectOption[] = [
{
label: "New",
value: "NEW"
},
{
label: "Checked",
value: "CHECKED"
},
{
label: "Promo",
value: "PROMO"
},
{
label: "Promo GP",
value: "PROMO_GP"
},
{
label: "Resurrected",
value: "RESURRECTED"
}
];
export const resolutions = [ export const resolutions = [
"2160p", "2160p",
"1080p", "1080p",

View file

@ -392,6 +392,7 @@ export const FilterDetails = () => {
enabled: filter.enabled, enabled: filter.enabled,
min_size: filter.min_size, min_size: filter.min_size,
max_size: filter.max_size, max_size: filter.max_size,
announce_types: filter.announce_types || [],
delay: filter.delay, delay: filter.delay,
priority: filter.priority, priority: filter.priority,
max_downloads: filter.max_downloads, max_downloads: filter.max_downloads,

View file

@ -10,7 +10,16 @@ import { IndexersOptionsQueryOptions } from "@api/queries";
import { DocsLink } from "@components/ExternalLink"; import { DocsLink } from "@components/ExternalLink";
import { FilterLayout, FilterPage, FilterSection } from "./_components"; import { FilterLayout, FilterPage, FilterSection } from "./_components";
import { IndexerMultiSelect, MultiSelectOption, NumberField, Select, SwitchGroup, TextField } from "@components/inputs"; import {
IndexerMultiSelect,
MultiSelect,
MultiSelectOption,
NumberField,
Select,
SwitchGroup,
TextField
} from "@components/inputs";
import * as CONSTS from "@domain/constants.ts";
const MapIndexer = (indexer: Indexer) => ( const MapIndexer = (indexer: Indexer) => (
@ -29,9 +38,20 @@ export const General = () => {
<FilterLayout> <FilterLayout>
<TextField name="name" label="Filter name" columns={6} placeholder="eg. Filter 1" /> <TextField name="name" label="Filter name" columns={6} placeholder="eg. Filter 1" />
{/*{!isLoading && (*/} <MultiSelect
<IndexerMultiSelect name="indexers" options={indexerOptions} label="Indexers" columns={6} /> name="announce_types"
{/*)}*/} options={CONSTS.AnnounceTypeOptions}
label="announce types"
columns={3}
tooltip={
<div>
<p>NEW! Match releases which contain any of the selected announce types.</p>
<DocsLink href="https://autobrr.com/filters#announce-type" />
</div>
}
/>
<IndexerMultiSelect name="indexers" options={indexerOptions} label="Indexers" columns={3} />
</FilterLayout> </FilterLayout>
</FilterSection> </FilterSection>

View file

@ -13,6 +13,7 @@ interface Filter {
max_size: string; max_size: string;
delay: number; delay: number;
priority: number; priority: number;
announce_types: string[];
max_downloads: number; max_downloads: number;
max_downloads_unit: string; max_downloads_unit: string;
match_releases: string; match_releases: string;

View file

@ -11,6 +11,7 @@ interface Release {
filter: string; filter: string;
protocol: string; protocol: string;
implementation: string; implementation: string;
announce_type: string;
name: string; name: string;
title: string; title: string;
size: number; size: number;