From 5c402b6d6ce6a812b9b77e65634ab5372e5c6bb5 Mon Sep 17 00:00:00 2001 From: ze0s <43699394+zze0s@users.noreply.github.com> Date: Mon, 9 Jan 2023 00:33:08 +0100 Subject: [PATCH] feat(filters): support Language filtering (#632) * feat(filters): add support for language * feat(filters): add db migrations and repo * feat(filters): fix failing tests * feat(filters): fix failing tests --- internal/database/filter.go | 20 +++++++++- internal/database/postgres_migrate.go | 8 ++++ internal/database/sqlite_migrate.go | 8 ++++ internal/domain/filter.go | 12 ++++++ internal/domain/release.go | 3 +- internal/domain/release_test.go | 3 +- internal/feed/rss_test.go | 6 +-- pkg/torznab/torznab_test.go | 3 +- web/src/domain/constants.ts | 55 +++++++++++++++++++++++++++ web/src/screens/filters/details.tsx | 8 ++++ web/src/types/Filter.d.ts | 2 + 11 files changed, 120 insertions(+), 8 deletions(-) diff --git a/internal/database/filter.go b/internal/database/filter.go index b56999a..9b62bf1 100644 --- a/internal/database/filter.go +++ b/internal/database/filter.go @@ -217,6 +217,8 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter "except_categories", "match_uploaders", "except_uploaders", + "match_language", + "except_language", "tags", "except_tags", "origins", @@ -250,7 +252,7 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter 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, &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, 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") } @@ -378,6 +380,8 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe "f.except_categories", "f.match_uploaders", "f.except_uploaders", + "f.match_language", + "f.except_language", "f.tags", "f.except_tags", "f.origins", @@ -421,7 +425,7 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe 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, &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, 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") } @@ -513,6 +517,8 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F "except_categories", "match_uploaders", "except_uploaders", + "match_language", + "except_language", "tags", "except_tags", "artists", @@ -573,6 +579,8 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F filter.ExceptCategories, filter.MatchUploaders, filter.ExceptUploaders, + pq.Array(filter.MatchLanguage), + pq.Array(filter.ExceptLanguage), filter.Tags, filter.ExceptTags, filter.Artists, @@ -652,6 +660,8 @@ func (r *FilterRepo) Update(ctx context.Context, filter domain.Filter) (*domain. Set("except_categories", filter.ExceptCategories). Set("match_uploaders", filter.MatchUploaders). Set("except_uploaders", filter.ExceptUploaders). + Set("match_language", pq.Array(filter.MatchLanguage)). + Set("except_language", pq.Array(filter.ExceptLanguage)). Set("tags", filter.Tags). Set("except_tags", filter.ExceptTags). Set("artists", filter.Artists). @@ -803,6 +813,12 @@ func (r *FilterRepo) UpdatePartial(ctx context.Context, filter domain.FilterUpda if filter.ExceptUploaders != nil { q = q.Set("except_uploaders", filter.ExceptUploaders) } + if filter.MatchLanguage != nil { + q = q.Set("match_language", pq.Array(filter.MatchLanguage)) + } + if filter.ExceptLanguage != nil { + q = q.Set("except_language", pq.Array(filter.ExceptLanguage)) + } if filter.Tags != nil { q = q.Set("tags", filter.Tags) } diff --git a/internal/database/postgres_migrate.go b/internal/database/postgres_migrate.go index 407082f..c2cf4f5 100644 --- a/internal/database/postgres_migrate.go +++ b/internal/database/postgres_migrate.go @@ -111,6 +111,8 @@ CREATE TABLE filter except_categories TEXT, match_uploaders TEXT, except_uploaders TEXT, + match_language TEXT [] DEFAULT '{}', + except_language TEXT [] DEFAULT '{}', tags TEXT, except_tags TEXT, origins TEXT [] DEFAULT '{}', @@ -623,4 +625,10 @@ CREATE INDEX indexer_identifier_index `ALTER TABLE "filter" ADD COLUMN smart_episode BOOLEAN DEFAULT false; `, + `ALTER TABLE "filter" + ADD COLUMN match_language TEXT [] DEFAULT '{}'; + + ALTER TABLE "filter" + ADD COLUMN except_language TEXT [] DEFAULT '{}'; + `, } diff --git a/internal/database/sqlite_migrate.go b/internal/database/sqlite_migrate.go index 7850c08..b856836 100644 --- a/internal/database/sqlite_migrate.go +++ b/internal/database/sqlite_migrate.go @@ -111,6 +111,8 @@ CREATE TABLE filter except_categories TEXT, match_uploaders TEXT, except_uploaders TEXT, + match_language TEXT [] DEFAULT '{}', + except_language TEXT [] DEFAULT '{}', tags TEXT, except_tags TEXT, origins TEXT [] DEFAULT '{}', @@ -967,4 +969,10 @@ ALTER TABLE irc_network_dg_tmp `ALTER TABLE "filter" ADD COLUMN smart_episode BOOLEAN DEFAULT false; `, + `ALTER TABLE "filter" + ADD COLUMN match_language TEXT [] DEFAULT '{}'; + + ALTER TABLE "filter" + ADD COLUMN except_language TEXT [] DEFAULT '{}'; + `, } diff --git a/internal/domain/filter.go b/internal/domain/filter.go index 38d86a3..b295d7a 100644 --- a/internal/domain/filter.go +++ b/internal/domain/filter.go @@ -109,6 +109,8 @@ type Filter struct { ExceptCategories string `json:"except_categories,omitempty"` MatchUploaders string `json:"match_uploaders,omitempty"` ExceptUploaders string `json:"except_uploaders,omitempty"` + MatchLanguage []string `json:"match_language,omitempty"` + ExceptLanguage []string `json:"except_language,omitempty"` Tags string `json:"tags,omitempty"` ExceptTags string `json:"except_tags,omitempty"` TagsAny string `json:"tags_any,omitempty"` @@ -182,6 +184,8 @@ type FilterUpdate struct { ExceptCategories *string `json:"except_categories,omitempty"` MatchUploaders *string `json:"match_uploaders,omitempty"` ExceptUploaders *string `json:"except_uploaders,omitempty"` + MatchLanguage *[]string `json:"match_language,omitempty"` + ExceptLanguage *[]string `json:"except_language,omitempty"` Tags *string `json:"tags,omitempty"` ExceptTags *string `json:"except_tags,omitempty"` TagsAny *string `json:"tags_any,omitempty"` @@ -297,6 +301,14 @@ func (f Filter) CheckFilter(r *Release) ([]string, bool) { r.addRejectionF("unwanted uploaders. got: %v unwanted: %v", r.Uploader, f.ExceptUploaders) } + if len(f.MatchLanguage) > 0 && !sliceContainsSlice(r.Language, f.MatchLanguage) { + r.addRejectionF("language not matching. got: %v want: %v", r.Language, f.MatchLanguage) + } + + if len(f.ExceptLanguage) > 0 && sliceContainsSlice(r.Language, f.ExceptLanguage) { + r.addRejectionF("language unwanted. got: %v want: %v", r.Language, f.ExceptLanguage) + } + if len(f.Resolutions) > 0 && !containsSlice(r.Resolution, f.Resolutions) { r.addRejectionF("resolution not matching. got: %v want: %v", r.Resolution, f.Resolutions) } diff --git a/internal/domain/release.go b/internal/domain/release.go index ae71445..7b88c30 100644 --- a/internal/domain/release.go +++ b/internal/domain/release.go @@ -67,7 +67,7 @@ type Release struct { AudioChannels string `json:"-"` Group string `json:"group"` Region string `json:"-"` - Language string `json:"-"` + Language []string `json:"-"` Proper bool `json:"proper"` Repack bool `json:"repack"` Website string `json:"website"` @@ -203,6 +203,7 @@ func (r *Release) ParseString(title string) { r.HDR = rel.HDR r.Other = rel.Other r.Artists = rel.Artist + r.Language = rel.Language if r.Season == 0 { r.Season = rel.Series diff --git a/internal/domain/release_test.go b/internal/domain/release_test.go index 38e7d1e..251b61b 100644 --- a/internal/domain/release_test.go +++ b/internal/domain/release_test.go @@ -260,6 +260,7 @@ func TestRelease_Parse(t *testing.T) { Year: 2022, Group: "GROUP1", Season: 1, + Language: []string{"ENGLiSH"}, }, }, } @@ -733,7 +734,7 @@ func TestRelease_DownloadTorrentFile(t *testing.T) { AudioChannels string Group string Region string - Language string + Language []string Proper bool Repack bool Website string diff --git a/internal/feed/rss_test.go b/internal/feed/rss_test.go index 4e83234..13e9014 100644 --- a/internal/feed/rss_test.go +++ b/internal/feed/rss_test.go @@ -64,7 +64,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: "mock-feed", FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", TorrentURL: "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: 0x0, Title: "Some Release Title", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: "", Proper: false, Repack: false, Website: "", Artists: "", Type: "", LogScore: 0, IsScene: false, 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: "mock-feed", FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", TorrentURL: "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: 0x0, Title: "Some Release Title", Category: "", Season: 0, Episode: 0, Year: 2022, 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: "", LogScore: 0, IsScene: false, 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", @@ -93,7 +93,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: "mock-feed", FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", TorrentURL: "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: 0x0, Title: "Some Release Title", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: "", Proper: false, Repack: false, Website: "", Artists: "", Type: "", LogScore: 0, IsScene: false, 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: "mock-feed", FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", TorrentURL: "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: 0x0, Title: "Some Release Title", Category: "", Season: 0, Episode: 0, Year: 2022, 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: "", LogScore: 0, IsScene: false, 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", @@ -123,7 +123,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: "mock-feed", FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", TorrentURL: "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: 0x0, Title: "Some Release Title", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: "", Proper: false, Repack: false, Website: "", Artists: "", Type: "", LogScore: 0, IsScene: false, 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: "mock-feed", FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", TorrentURL: "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: 0x0, Title: "Some Release Title", Category: "", Season: 0, Episode: 0, Year: 2022, 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: "", LogScore: 0, IsScene: false, 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", diff --git a/pkg/torznab/torznab_test.go b/pkg/torznab/torznab_test.go index 8dbe8af..f3c8d86 100644 --- a/pkg/torznab/torznab_test.go +++ b/pkg/torznab/torznab_test.go @@ -1,6 +1,7 @@ package torznab import ( + "context" "encoding/xml" "net/http" "net/http/httptest" @@ -232,7 +233,7 @@ func TestClient_GetCaps(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewClient(Config{Host: tt.fields.Host, ApiKey: tt.fields.ApiKey}) - got, err := c.FetchCaps() + got, err := c.FetchCaps(context.TODO()) if tt.wantErr && assert.Error(t, err) { assert.EqualErrorf(t, err, tt.expectedErr, "Error should be: %v, got: %v", tt.wantErr, err) } diff --git a/web/src/domain/constants.ts b/web/src/domain/constants.ts index efab677..16a43f2 100644 --- a/web/src/domain/constants.ts +++ b/web/src/domain/constants.ts @@ -154,6 +154,61 @@ export const originOptions = [ export const ORIGIN_OPTIONS = originOptions.map(v => ({ value: v, label: v, key: v })); +export const languageOptions = [ + "BALTIC", + "BRAZiLiAN", + "BULGARiAN", + "CHiNESE", + "CHS", + "CHT", + "CZECH", + "DANiSH", + "DUBBED", + "DKSUBS", + "DUTCH", + "ENGLiSH", + "ESTONiAN", + "FLEMiSH", + "FiNNiSH", + "FRENCH", + "GERMAN", + "GREEK", + "HAiTiAN", + "HARDSUB", + "Hardcoded", + "HEBREW", + "HebSub", + "HiNDi", + "HUNGARiAN", + "iCELANDiC", + "iTALiAN", + "JAPANESE", + "KOREAN", + "LATiN", + "MANDARiN", + "MULTi", + "MULTILANG", + "MULTiSUB", + "MULTiSUBS", + "NORDiC", + "NORWEGiAN", + "POLiSH", + "PORTUGUESE", + "ROMANiAN", + "RUSSiAN", + "SPANiSH", + "SUBBED", + "SUBFORCED", + "SUBPACK", + "SWEDiSH", + "SYNCED", + "TURKiSH", + "UKRAiNiAN", + "UNSUBBED" +]; + +export const LANGUAGE_OPTIONS = languageOptions.map(v => ({ value: v, label: v, key: v })); + export interface RadioFieldsetOption { label: string; description: string; diff --git a/web/src/screens/filters/details.tsx b/web/src/screens/filters/details.tsx index b151755..69752ba 100644 --- a/web/src/screens/filters/details.tsx +++ b/web/src/screens/filters/details.tsx @@ -11,6 +11,7 @@ import { downloadsPerUnitOptions, FORMATS_OPTIONS, HDR_OPTIONS, + LANGUAGE_OPTIONS, ORIGIN_OPTIONS, OTHER_OPTIONS, QUALITY_MUSIC_OPTIONS, @@ -265,6 +266,8 @@ export default function FilterDetails() { except_tags: filter.except_tags, match_uploaders: filter.match_uploaders, except_uploaders: filter.except_uploaders, + match_language: filter.match_language || [], + except_language: filter.except_language || [], freeleech: filter.freeleech, freeleech_percent: filter.freeleech_percent, formats: filter.formats || [], @@ -516,6 +519,11 @@ export function Advanced({ values }: AdvancedProps) { + + + + + diff --git a/web/src/types/Filter.d.ts b/web/src/types/Filter.d.ts index fbb3c92..5559d3b 100644 --- a/web/src/types/Filter.d.ts +++ b/web/src/types/Filter.d.ts @@ -51,6 +51,8 @@ interface Filter { except_categories: string; match_uploaders: string; except_uploaders: string; + match_language: string[]; + except_language: string[]; tags: string; except_tags: string; tags_any: string;