From f644b3a4d648c5680cc86c80b7aeed91e34d2bc7 Mon Sep 17 00:00:00 2001 From: ze0s <43699394+zze0s@users.noreply.github.com> Date: Sun, 8 Dec 2024 21:08:24 +0100 Subject: [PATCH] feat(filters): implement `AnnounceType` (#1837) * feat(filters): implement AnnounceType * fix: rss tests --- internal/database/filter.go | 10 ++++ internal/database/postgres_migrate.go | 8 +++ internal/database/release.go | 18 +++--- internal/database/sqlite_migrate.go | 8 +++ internal/domain/filter.go | 6 ++ internal/domain/release.go | 60 +++++++++++++++++++- internal/feed/rss_test.go | 8 +-- web/src/domain/constants.ts | 23 ++++++++ web/src/screens/filters/Details.tsx | 1 + web/src/screens/filters/sections/General.tsx | 28 +++++++-- web/src/types/Filter.d.ts | 1 + web/src/types/Release.d.ts | 1 + 12 files changed, 155 insertions(+), 17 deletions(-) diff --git a/internal/database/filter.go b/internal/database/filter.go index cd2c293..3dcb844 100644 --- a/internal/database/filter.go +++ b/internal/database/filter.go @@ -175,6 +175,7 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter "f.max_size", "f.delay", "f.priority", + "f.announce_types", "f.max_downloads", "f.max_downloads_unit", "f.match_releases", @@ -267,6 +268,7 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter &maxSize, &delay, &f.Priority, + pq.Array(&f.AnnounceTypes), &maxDownloads, &maxDownloadsUnit, &matchReleases, @@ -391,6 +393,7 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, indexer string "f.max_size", "f.delay", "f.priority", + "f.announce_types", "f.max_downloads", "f.max_downloads_unit", "f.match_releases", @@ -488,6 +491,7 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, indexer string &maxSize, &delay, &f.Priority, + pq.Array(&f.AnnounceTypes), &maxDownloads, &maxDownloadsUnit, &matchReleases, @@ -693,6 +697,7 @@ func (r *FilterRepo) Store(ctx context.Context, filter *domain.Filter) error { "max_size", "delay", "priority", + "announce_types", "max_downloads", "max_downloads_unit", "match_releases", @@ -758,6 +763,7 @@ func (r *FilterRepo) Store(ctx context.Context, filter *domain.Filter) error { filter.MaxSize, filter.Delay, filter.Priority, + pq.Array(filter.AnnounceTypes), filter.MaxDownloads, filter.MaxDownloadsUnit, filter.MatchReleases, @@ -841,6 +847,7 @@ func (r *FilterRepo) Update(ctx context.Context, filter *domain.Filter) error { Set("max_size", filter.MaxSize). Set("delay", filter.Delay). Set("priority", filter.Priority). + Set("announce_types", pq.Array(filter.AnnounceTypes)). Set("max_downloads", filter.MaxDownloads). Set("max_downloads_unit", filter.MaxDownloadsUnit). Set("use_regex", filter.UseRegex). @@ -943,6 +950,9 @@ func (r *FilterRepo) UpdatePartial(ctx context.Context, filter domain.FilterUpda if filter.Priority != nil { q = q.Set("priority", filter.Priority) } + if filter.AnnounceTypes != nil { + q = q.Set("announce_types", pq.Array(filter.AnnounceTypes)) + } if filter.MaxDownloads != nil { q = q.Set("max_downloads", filter.MaxDownloads) } diff --git a/internal/database/postgres_migrate.go b/internal/database/postgres_migrate.go index 366c4f3..aacae1f 100644 --- a/internal/database/postgres_migrate.go +++ b/internal/database/postgres_migrate.go @@ -99,6 +99,7 @@ CREATE TABLE filter priority INTEGER DEFAULT 0 NOT NULL, max_downloads INTEGER DEFAULT 0, max_downloads_unit TEXT, + announce_types TEXT [] DEFAULT '{}', match_releases TEXT, except_releases TEXT, use_regex BOOLEAN, @@ -261,6 +262,7 @@ CREATE TABLE "release" protocol TEXT, implementation TEXT, timestamp TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + announce_type TEXT DEFAULT 'NEW', info_url TEXT, download_url TEXT, group_id TEXT, @@ -994,5 +996,11 @@ UPDATE irc_network `UPDATE irc_network SET port = '6697', tls = true WHERE server = 'irc.seedpool.org'; +`, + `ALTER TABLE "release" + ADD COLUMN announce_type TEXT DEFAULT 'NEW'; + + ALTER TABLE filter + ADD COLUMN announce_types TEXT [] DEFAULT '{}'; `, } diff --git a/internal/database/release.go b/internal/database/release.go index 7b87b9b..6d7e749 100644 --- a/internal/database/release.go +++ b/internal/database/release.go @@ -38,8 +38,8 @@ func (repo *ReleaseRepo) Store(ctx context.Context, r *domain.Release) error { queryBuilder := repo.db.squirrel. 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"). - 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). + 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.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) // return values @@ -230,7 +230,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain } 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"). Column(sq.Alias(countQuery, "page_total")). From("release r"). @@ -267,7 +267,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain var rls domain.Release 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 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 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") } @@ -320,6 +320,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain rls.Indexer.IdentifierExternal = rlsIndexerExternalName.String rls.FilterName = rlsFilter.String + rls.AnnounceType = domain.AnnounceType(rlsAnnounceType.String) rls.ActionStatus = make([]domain.ReleaseActionStatus, 0) rls.InfoURL = infoUrl.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) { 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"). OrderBy("r.id DESC"). 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 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 - 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) { return nil, domain.ErrRecordNotFound } @@ -453,6 +454,7 @@ func (repo *ReleaseRepo) Get(ctx context.Context, req *domain.GetReleaseRequest) rls.FilterName = filterName.String rls.FilterID = int(filterId.Int64) rls.ActionStatus = make([]domain.ReleaseActionStatus, 0) + rls.AnnounceType = domain.AnnounceType(announceType.String) rls.InfoURL = infoUrl.String rls.DownloadURL = downloadUrl.String rls.Category = category.String diff --git a/internal/database/sqlite_migrate.go b/internal/database/sqlite_migrate.go index 6877834..ce00e4f 100644 --- a/internal/database/sqlite_migrate.go +++ b/internal/database/sqlite_migrate.go @@ -99,6 +99,7 @@ CREATE TABLE filter priority INTEGER DEFAULT 0 NOT NULL, max_downloads INTEGER DEFAULT 0, max_downloads_unit TEXT, + announce_types TEXT [] DEFAULT '{}', match_releases TEXT, except_releases TEXT, use_regex BOOLEAN, @@ -264,6 +265,7 @@ CREATE TABLE "release" protocol TEXT, implementation TEXT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + announce_type TEXT DEFAULT 'NEW', info_url TEXT, download_url TEXT, group_id TEXT, @@ -1636,5 +1638,11 @@ UPDATE irc_network `UPDATE irc_network SET port = '6697', tls = true WHERE server = 'irc.seedpool.org'; +`, + `ALTER TABLE "release" + ADD COLUMN announce_type TEXT DEFAULT 'NEW'; + + ALTER TABLE filter + ADD COLUMN announce_types TEXT [] DEFAULT '{}'; `, } diff --git a/internal/domain/filter.go b/internal/domain/filter.go index 3366879..36b87af 100644 --- a/internal/domain/filter.go +++ b/internal/domain/filter.go @@ -107,6 +107,7 @@ type Filter struct { UseRegex bool `json:"use_regex,omitempty"` MatchReleaseGroups string `json:"match_release_groups,omitempty"` ExceptReleaseGroups string `json:"except_release_groups,omitempty"` + AnnounceTypes []string `json:"announce_types,omitempty"` Scene bool `json:"scene,omitempty"` Origins []string `json:"origins,omitempty"` ExceptOrigins []string `json:"except_origins,omitempty"` @@ -222,6 +223,7 @@ type FilterUpdate struct { MaxSize *string `json:"max_size,omitempty"` Delay *int `json:"delay,omitempty"` Priority *int32 `json:"priority,omitempty"` + AnnounceTypes *[]string `json:"announce_types,omitempty"` MaxDownloads *int `json:"max_downloads,omitempty"` MaxDownloadsUnit *FilterMaxDownloadsUnit `json:"max_downloads_unit,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) } + 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) { f.RejectReasons.Add("match origin", r.Origin, f.Origins) } diff --git a/internal/domain/release.go b/internal/domain/release.go index d5a6cb7..42e83e1 100644 --- a/internal/domain/release.go +++ b/internal/domain/release.go @@ -53,6 +53,7 @@ type Release struct { Protocol ReleaseProtocol `json:"protocol"` Implementation ReleaseImplementation `json:"implementation"` // irc, rss, api Timestamp time.Time `json:"timestamp"` + AnnounceType AnnounceType `json:"announce_type"` InfoURL string `json:"info_url"` DownloadURL string `json:"download_url"` MagnetURI string `json:"-"` @@ -114,6 +115,56 @@ func (r *Release) Raw(s string) rls.Release { 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 { ID int64 `json:"id"` Status ReleasePushStatus `json:"status"` @@ -307,6 +358,7 @@ func NewRelease(indexer IndexerMinimal) *Release { Timestamp: time.Now(), Tags: []string{}, Size: 0, + AnnounceType: AnnounceTypeNew, } return r @@ -667,7 +719,6 @@ const MagnetURIPrefix = "magnet:?" // MapVars map vars from regex captures to fields on release func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) error { - if torrentName, err := getStringMapValue(varMap, "torrentName"); err != nil { return errors.Wrap(err, "failed parsing required field") } else { @@ -682,6 +733,13 @@ func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) erro 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 { fl := StringEqualFoldMulti(freeleech, "1", "free", "freeleech", "freeleech!", "yes", "VIP", "★") if fl { diff --git a/internal/feed/rss_test.go b/internal/feed/rss_test.go index 45cac16..a8bdc60 100644 --- a/internal/feed/rss_test.go +++ b/internal/feed/rss_test.go @@ -73,7 +73,7 @@ func TestRSSJob_processItem(t *testing.T) { Link: "/details.php?id=00000&hit=1", 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", @@ -107,7 +107,7 @@ func TestRSSJob_processItem(t *testing.T) { Link: "https://fake-feed.com/details.php?id=00000&hit=1", 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", @@ -142,7 +142,7 @@ func TestRSSJob_processItem(t *testing.T) { GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", //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", @@ -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 { diff --git a/web/src/domain/constants.ts b/web/src/domain/constants.ts index 75413f0..4adba58 100644 --- a/web/src/domain/constants.ts +++ b/web/src/domain/constants.ts @@ -5,6 +5,29 @@ 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 = [ "2160p", "1080p", diff --git a/web/src/screens/filters/Details.tsx b/web/src/screens/filters/Details.tsx index 3527c95..e656cbf 100644 --- a/web/src/screens/filters/Details.tsx +++ b/web/src/screens/filters/Details.tsx @@ -392,6 +392,7 @@ export const FilterDetails = () => { enabled: filter.enabled, min_size: filter.min_size, max_size: filter.max_size, + announce_types: filter.announce_types || [], delay: filter.delay, priority: filter.priority, max_downloads: filter.max_downloads, diff --git a/web/src/screens/filters/sections/General.tsx b/web/src/screens/filters/sections/General.tsx index 0ec0a7f..e42c1de 100644 --- a/web/src/screens/filters/sections/General.tsx +++ b/web/src/screens/filters/sections/General.tsx @@ -10,7 +10,16 @@ import { IndexersOptionsQueryOptions } from "@api/queries"; import { DocsLink } from "@components/ExternalLink"; 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) => ( @@ -29,9 +38,20 @@ export const General = () => { - {/*{!isLoading && (*/} - - {/*)}*/} + +

NEW! Match releases which contain any of the selected announce types.

+ + + } + /> + +
diff --git a/web/src/types/Filter.d.ts b/web/src/types/Filter.d.ts index a4ce0fe..5a7262c 100644 --- a/web/src/types/Filter.d.ts +++ b/web/src/types/Filter.d.ts @@ -13,6 +13,7 @@ interface Filter { max_size: string; delay: number; priority: number; + announce_types: string[]; max_downloads: number; max_downloads_unit: string; match_releases: string; diff --git a/web/src/types/Release.d.ts b/web/src/types/Release.d.ts index 369551a..ade3c84 100644 --- a/web/src/types/Release.d.ts +++ b/web/src/types/Release.d.ts @@ -11,6 +11,7 @@ interface Release { filter: string; protocol: string; implementation: string; + announce_type: string; name: string; title: string; size: number;