From 8a21a81756a392ad03cbc4e66bd90fea30e042a3 Mon Sep 17 00:00:00 2001 From: Farid Date: Thu, 1 Jan 2026 08:09:59 +0400 Subject: [PATCH 1/2] Improve series/episode parsing and CLI support Enhanced regex patterns to support multi-digit series/episode numbers and explicit episode zero detection. Updated parsing logic to better classify series and episode tags, including edge cases for episode zero. Added a standalone CLI in cmd/rls/main.go for JSON output, improved test coverage, and updated documentation. Also added new collection tag (WOWP) and refined group extraction from unused series tags. --- README.md | 9 +++++++ cmd/rls/main.go | 66 +++++++++++++++++++++++++++++++++++++++++++++ lex.go | 16 +++++------ parse.go | 59 ++++++++++++++++++++++++++++++++++------ reutil/reutil.go | 1 + rls.go | 18 ++++++++++--- taginfo/taginfo.csv | 1 + tests.yaml | 40 ++++++++++++++++++++++++++- 8 files changed, 189 insertions(+), 21 deletions(-) create mode 100644 cmd/rls/main.go diff --git a/README.md b/README.md index 20e833d..a06f63a 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,12 @@ func main() { // group: NOiR } ``` +## Build standalone cli +``` +go build -o rls ./cmd/rls +``` + +## Run tests +``` +go test ./... +``` diff --git a/cmd/rls/main.go b/cmd/rls/main.go new file mode 100644 index 0000000..6452a0f --- /dev/null +++ b/cmd/rls/main.go @@ -0,0 +1,66 @@ +package main + +import ( + "bufio" + "encoding/json" + "flag" + "fmt" + "os" + "strings" + + "github.com/moistari/rls" +) + +var pretty = flag.Bool("pretty", false, "pretty-print JSON output") + +func processLine(line string) error { + line = strings.TrimSpace(line) + if line == "" { + return nil + } + + // Just parse the release directly + r := rls.ParseString(line) + + var b []byte + var err error + + if *pretty { + b, err = json.MarshalIndent(r, "", " ") + } else { + b, err = json.Marshal(r) + } + + if err != nil { + return err + } + fmt.Print(string(b)) + return nil +} + +func main() { + flag.Parse() + args := flag.Args() + if len(args) == 0 { + // read lines from stdin + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + if err := processLine(scanner.Text()); err != nil { + fmt.Fprintln(os.Stderr, "error:", err) + os.Exit(1) + } + } + if err := scanner.Err(); err != nil { + fmt.Fprintln(os.Stderr, "error reading stdin:", err) + os.Exit(1) + } + return + } + // treat each arg as a separate release name + for _, a := range args { + if err := processLine(a); err != nil { + fmt.Fprintln(os.Stderr, "error:", err) + os.Exit(1) + } + } +} diff --git a/lex.go b/lex.go index 2601117..5e54f10 100644 --- a/lex.go +++ b/lex.go @@ -70,17 +70,17 @@ func DefaultLexers() []Lexer { NewRegexpSourceLexer(TagTypeCollection, true), NewSeriesLexer( // s02, S01E01 - `(?i)^s(?P[0-8]?\d)[\-\._ ]?(?:e(?P\d{1,5}))?\b`, + `(?i)^s(?P\d{1,4})[\-\._ ]?(?:e(?P\d{1,5}))?\b`, // S01E02E03, S01E02-E03, S01E03.E04.E05 - `(?i)^s(?P[0-8]?\d)(?P(?:[\-\._ ]?e\d{1,5}){1,5})\b`, + `(?i)^s(?P\d{1,4})(?P(?:[\-\._ ]?e\d{1,5}){1,5})\b`, // S01S02S03 - `(?i)^(?P(?:s[0-8]?\d){2,4})\b`, + `(?i)^(?P(?:s\d{1,4}){2,4})\b`, // 2x1, 1x01 - `(?i)^(?P[0-8]?\d)x(?P\d{1,3})\b`, + `(?i)^(?P\d{1,4})x(?P\d{1,5})\b`, // S01 - 02v3, S07-06, s03-5v.9 - `(?i)^s(?P[0-8]?\d)[\-\._ ]{1,3}(?P\d{1,5})(?:[\-\._ ]{1,3}(?Pv\d+(?:\.\d+){0,2}))?\b`, + `(?i)^s(?P\d{1,4})[\-\._ ]{1,3}(?P\d{1,5})(?:[\-\._ ]{1,3}(?Pv\d+(?:\.\d+){0,2}))?\b`, // Season.01.Episode.02, Series.01.Ep.02, Series.01, Season.01 - `(?i)^(?:series|season|s)[\-\._ ]?(?P[0-8]?\d)(?:[\-\._ ]?(?:episode|ep)(?P\d{1,5}))?\b`, + `(?i)^(?:series|season|s)[\-\._ ]?(?P\d{1,4})(?:[\-\._ ]?(?:episode|ep)(?P\d{1,5}))?\b`, // Vol.1.No.2, vol1no2 `(?i)^vol(?:ume)?[\-\._ ]?(?P\d{1,3})(?:[\-\._ ]?(?:number|no)[\-\._ ]?(?P\d{1,5}))\b`, // Episode 15, E009, Ep. 007, Ep.05-07 @@ -88,7 +88,7 @@ func DefaultLexers() []Lexer { // 10v1.7, 13v2 `(?i)^(?P\d{1,5})(?Pv[\-\._ ]?\d+(?:\.\d){0,2})\b`, // S01.Disc02, s01D3, Series.01.Disc.02, S02DVD3 - `(?i)^(?:series|season|s)[\-\._ ]?(?P[0-8]?\d)[\-\._ ]?(?P(?:disc|disk|dvd|d)[\-\._ ]?(?:\d{1,3}))\b`, + `(?i)^(?:series|season|s)[\-\._ ]?(?P\d{1,4})[\-\._ ]?(?P(?:disc|disk|dvd|d)[\-\._ ]?(?:\d{1,3}))\b`, // s1957e01 `(?i)^s(?P19\d\d)e(?P\d{2,4})\b`, ), @@ -231,7 +231,7 @@ func NewDateLexer(strs ...string) Lexer { func NewSeriesLexer(strs ...string) Lexer { var sourcef taginfo.FindFunc lexer := NamedCaptureLexer(strs...) - mlt := regexp.MustCompile(`(?i)s(\d?\d)`) + mlt := regexp.MustCompile(`(?i)s(\d{1,4})`) mny := regexp.MustCompile(`(?i)[\-\._ ]?e(\d{1,5})`) dsc := regexp.MustCompile(`(?i)^disc|disk|dvd|d`) return TagLexer{ diff --git a/parse.go b/parse.go index 0a046af..a285f1e 100644 --- a/parse.go +++ b/parse.go @@ -507,6 +507,17 @@ func (b *TagBuilder) fixMusic(r *Release) { // collect collects tags into the release. func (b *TagBuilder) collect(r *Release) { + // determine pivot and the text end prior to pivot — only consider series + // tags that occur before this 'end' (the first text prior to the pivot). + // Note: do not include TagTypeSeries when computing the pivot here — + // including it causes the pivot to point to series tags themselves and + // leads to misclassification when series tags appear early in the name. + // compute pivot based on source/resolution/version so that series tags + // following a title or year (TagTypeDate) are still accepted. Excluding + // TagTypeDate prevents dates from moving the pivot before legitimate + // series tokens. + _, seriesTextEnd := b.pivots(r, TagTypeSource, TagTypeResolution, TagTypeVersion) + for i := 0; i < len(r.tags); i++ { switch r.tags[i].typ { case TagTypeText: @@ -534,12 +545,26 @@ func (b *TagBuilder) collect(r *Release) { case TagTypeDate: r.Year, r.Month, r.Day = r.tags[i].Date() case TagTypeSeries: - series, episode := r.tags[i].Series() + // only accept series tags from the initial part of the release + // name (typically after the title or year). series tokens found + // after the pivot (eg. in codec/version sections) are ignored. + if i >= seriesTextEnd { + // treat as text (leave for unused/group heuristics) + r.tags[i] = r.tags[i].As(TagTypeText, nil) + break + } + // inspect raw tag captures so we can detect explicit episode captures + tag := r.tags[i] + series, episode := tag.Series() if r.Series == 0 { r.Series = series } - if r.Episode == 0 { - r.Episode = episode + // if the tag actually captured an episode (even "0"), set episode + if len(tag.v) > 2 && tag.v[2] != "" { + // prefer first explicit episode capture + if r.Episode == 0 && (episode != 0 || tag.v[2] == "0") { + r.Episode = episode + } } case TagTypeVersion: if r.Version == "" { @@ -627,6 +652,14 @@ func (b *TagBuilder) inspect(r *Release, initial bool) Type { return r.Type } n := len(r.tags) + // detect explicit episode captures in tags (including "0") + episodePresent := false + for _, t := range r.tags { + if t.Is(TagTypeSeries) && len(t.v) > 2 && t.v[2] != "" { + episodePresent = true + break + } + } // inspect types var app, series, movie bool for i := n; i > 0; i-- { @@ -642,12 +675,12 @@ func (b *TagBuilder) inspect(r *Release, initial bool) Type { } return typ case Series, Episode: - if r.Episode != 0 || (r.Series == 0 && r.Episode == 0) && !contains(r.Other, "BOXSET") { + if episodePresent || (r.Series == 0 && !episodePresent) && !contains(r.Other, "BOXSET") { return Episode } return Series case Education: - if r.Series == 0 && r.Episode == 0 { + if r.Series == 0 && !episodePresent { return Education } case Music: @@ -664,7 +697,7 @@ func (b *TagBuilder) inspect(r *Release, initial bool) Type { // exclusive tag not superseded by version/episode/date if r.tags[i-1].InfoExcl() && r.Version == "" && - r.Series == 0 && r.Episode == 0 && + r.Series == 0 && !episodePresent && r.Day == 0 && r.Month == 0 { return typ } @@ -690,7 +723,7 @@ func (b *TagBuilder) inspect(r *Release, initial bool) Type { } // defaults switch { - case r.Episode != 0 || (r.Year != 0 && r.Month != 0 && r.Day != 0): + case episodePresent || (r.Year != 0 && r.Month != 0 && r.Day != 0): return Episode case r.Series != 0 || series: return Series @@ -1180,7 +1213,17 @@ func (b *TagBuilder) unused(r *Release, i int) { case r.Sum == "" && b.sum.MatchString(s) && strings.ContainsAny(s, "0123456789"): r.Sum, r.unused = s, r.unused[:n-1] case r.Group == "" && !b.digits.MatchString(s): - r.Group, r.unused = s, r.unused[:n-1] + // if the unused tag was originally a series token, reconstruct + // a normalized series-like group (eg. "S97") using the numeric + // capture rather than the raw captured text (which may include + // punctuation such as a trailing dot). + if r.tags[r.unused[n-1]].Was(TagTypeSeries) { + series, _ := r.tags[r.unused[n-1]].Series() + r.Group = fmt.Sprintf("S%v", series) + } else { + r.Group = s + } + r.unused = r.unused[:n-1] } } } diff --git a/reutil/reutil.go b/reutil/reutil.go index b9ec69d..644e818 100644 --- a/reutil/reutil.go +++ b/reutil/reutil.go @@ -25,6 +25,7 @@ func Join(quote bool, strs ...string) string { // Build builds a regexp for strings. // // Config options: +// // i - ignore case // ^ - add ^ start anchor // a - add \b start anchor diff --git a/rls.go b/rls.go index 0a7f2a5..9fee48b 100644 --- a/rls.go +++ b/rls.go @@ -3,6 +3,7 @@ package rls import ( "bytes" + "encoding/json" "fmt" "math" "regexp" @@ -261,8 +262,8 @@ func (tag Tag) Info() *taginfo.Taginfo { // SingleEp returns true when the func (tag Tag) SingleEp() bool { if tag.typ.Is(TagTypeSeries) { - s, e := tag.Series() - return s == 0 && e != 0 && tag.v[1] == "" && tag.v[0] == tag.v[2] + s, _ := tag.Series() + return s == 0 && len(tag.v) > 2 && tag.v[2] != "" && tag.v[1] == "" && tag.v[0] == tag.v[2] } return false } @@ -346,7 +347,7 @@ func (tag Tag) Normalize() string { return strconv.Itoa(year) case TagTypeSeries: series, episode := tag.Series() - if episode != 0 { + if len(tag.v) > 2 && tag.v[2] != "" { return fmt.Sprintf("S%02dE%02d", series, episode) } return fmt.Sprintf("S%02d", series) @@ -521,7 +522,10 @@ func (tag Tag) Series() (int, int) { func (tag Tag) Episodes() []int { var v []int for _, b := range tag.v[2:] { - if episode, _ := strconv.Atoi(b); episode != 0 { + if b == "" { + continue + } + if episode, err := strconv.Atoi(b); err == nil { v = append(v, episode) } } @@ -703,6 +707,12 @@ const ( Series ) +// MarshalJSON ensures that when this type is converted to JSON, +// it uses its string representation instead of the integer value. +func (t Type) MarshalJSON() ([]byte, error) { + return json.Marshal(t.String()) +} + // ParseType parses a type from s. func ParseType(s string) Type { switch s { diff --git a/taginfo/taginfo.csv b/taginfo/taginfo.csv index 69fc152..af0312b 100644 --- a/taginfo/taginfo.csv +++ b/taginfo/taginfo.csv @@ -179,6 +179,7 @@ collection,VTC,,,,education,1 collection,WAKA,Wakanim,(?-i:WAKA),,, collection,WiiWare,WiiWare Shop,,,game,1 collection,Wiley,,wiley(?:[\-\._ ]?com)?,,education,1 +collection,WOWP,WOW Presents Plus,(?-i:WOWP)|WOW Presents Plus,,, collection,XBLA,Xbox Live Arcade,,,game,1 collection,XXX,Adult,(?-i:XXX),,, collection,YOUTUBE,YouTube,(?-i:YOUTUBE)|(?-i:YT),,, diff --git a/tests.yaml b/tests.yaml index 99b442e..607f8f0 100644 --- a/tests.yaml +++ b/tests.yaml @@ -1973,12 +1973,13 @@ site: "SubsPlease" sum: "C00D6C68" "Hold.The.Sunset.S01E00.Christmas.Special.720p.HDTV.X264-MTB": - type: "series" + type: "episode" title: "Hold The Sunset" subtitle: "Christmas Special" source: "HDTV" resolution: "720p" series: 1 + episode: 0 codec: "x264" group: "MTB" "HollyRandall.15.03.09.Black.Angelika.and.Nick.Lang.Take.Me.Home.Tonight.XXX.1080p.x264-GAGViD": @@ -3693,3 +3694,40 @@ type: "game" title: "Oddsparks An Automation Adventure Coaster Rush" group: "RUNE" +"Big Fat Quiz S2025E02 1080p ALL4 WEB-DL AAC 2.0 H.264-RAWR": + type: "episode" + title: "Big Fat Quiz" + source: "WEB-DL" + resolution: "1080p" + codec: "H.264" + audio: "AAC" + channels: "2.0" + series: 2025 + Episode: 2 + collection: "ALL4" + group: "RAWR" +"Robotech The Macross Saga E00 Extended Pilot 1080p BluRay x264-PRESENT": + type: "episode" + title: "Robotech The Macross Saga" + subtitle: "Pilot" + source: "BluRay" + resolution: "1080p" + series: 0 + Episode: 0 + cut: "Extended.Cut" + codec: "x264" + group: "PRESENT" +# to do: fix subtitle as "Meet the Queens of Season 1" +"Drag Race Philippines: Slaysian Royale S01E00 Meet the Queens of Season 1 1080p WOWP WEB-DL AAC 2.0 H.264-Kitsune": + type: "episode" + title: "Drag Race Philippines: Slaysian Royale" + subtitle: "Meet the Queens of" + source: "WEB-DL" + resolution: "1080p" + codec: "H.264" + audio: "AAC" + channels: "2.0" + series: 1 + Episode: 0 + group: "Kitsune" + collection: "WOWP" \ No newline at end of file From 98593fb0d9f02dcedefd1722328fd534fc19b5e7 Mon Sep 17 00:00:00 2001 From: Farid Date: Sat, 3 Jan 2026 06:18:22 +0400 Subject: [PATCH 2/2] Expand language tags and fix regex for season parsing Updated taginfo.csv to include a comprehensive list of language tags with improved regex patterns and standardization. Adjusted the season/series regex in lex.go to limit season numbers to two digits. Fixed various test cases in tests.yaml to use standardized language tag casing and names. Updated README.md to simplify the build command. --- README.md | 2 +- lex.go | 2 +- taginfo/taginfo.csv | 125 +++++++++++++++++++++++++++++--------------- tests.yaml | 38 +++++++------- 4 files changed, 105 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index a06f63a..4956f77 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ func main() { ``` ## Build standalone cli ``` -go build -o rls ./cmd/rls +go build ./cmd/rls ``` ## Run tests diff --git a/lex.go b/lex.go index 5e54f10..2fdedab 100644 --- a/lex.go +++ b/lex.go @@ -80,7 +80,7 @@ func DefaultLexers() []Lexer { // S01 - 02v3, S07-06, s03-5v.9 `(?i)^s(?P\d{1,4})[\-\._ ]{1,3}(?P\d{1,5})(?:[\-\._ ]{1,3}(?Pv\d+(?:\.\d+){0,2}))?\b`, // Season.01.Episode.02, Series.01.Ep.02, Series.01, Season.01 - `(?i)^(?:series|season|s)[\-\._ ]?(?P\d{1,4})(?:[\-\._ ]?(?:episode|ep)(?P\d{1,5}))?\b`, + `(?i)^(?:series|season|s)[\-\._ ]?(?P\d{1,2})(?:[\-\._ ]?(?:episode|ep)(?P\d{1,5}))?\b`, // Vol.1.No.2, vol1no2 `(?i)^vol(?:ume)?[\-\._ ]?(?P\d{1,3})(?:[\-\._ ]?(?:number|no)[\-\._ ]?(?P\d{1,5}))\b`, // Episode 15, E009, Ep. 007, Ep.05-07 diff --git a/taginfo/taginfo.csv b/taginfo/taginfo.csv index af0312b..c436ffd 100644 --- a/taginfo/taginfo.csv +++ b/taginfo/taginfo.csv @@ -332,53 +332,96 @@ hdr,HLG,Hybrid Log-Gamma,,,movie, hdr,SDR,Standard Dynamic Range,,,movie, hdr,DV,Dolby Vision,dolby[\-\._ ]vision|dovi|dv,,movie, language,AUDiO.ADDON,Audio Addon,audio[\-\._ ]?addon,,, -language,BALTIC,Baltic,,,, -language,BRAZiLiAN,Brazilian,BRAZiLiAN|BR,,, -language,BULGARiAN,Bulgarian,(?i:bulgarian)|BG,,, -language,CHiNESE,Chinese,CH[iI]N[eE]S[eE]|CN,,, +language,DL,Dual Language,(?i:dual[\-\._ ]?(?:audio|line|language))|DL,,, +language,DUBBED,Dubbed,(?i:(?:line[\-\._ ]?)?dubbed),,, +language,HARDSUB,Subs (hard),(?i:hard[\-\._ ]?sub(?:s|bed)?),,, +language,HC,Hardcoded,(?i:hard[\-\._ ]?coded)|HC,,, +language,MULTILANG,Multi (lang),,,, +language,MULTISUB,Subs (multi),(?i:multiple[\-\._ ]subtitles?|multi[\-\._ ]?subs?),,, +language,MULTI,Multi,(?i:multi(?:[\-\._ ]?(?:lingual|language))?)|MULT[iI],,, +language,SUBBED,Subbed,(?i:subbed),,, +language,SUBFORCED,Subbed (forced),(?i:sub(?:[\-\._ ]?forced)?|forced(?:[\-\._ ]?sub)?),,, +language,SUBPACK,Subs (pack),(?i:subs?[\-\._ ]?pack),,, +language,SYNCED,Synced,(?i:synced),,, +language,AFRIKAANS,Afrikaans,(?i:afrikaans)|AF,,, +language,ALBANIAN,Albanian,(?i:albanian)|SQ,,, +language,AMHARIC,Amharic,(?i:amharic)|AM,,, +language,ARABIC,Arabic,(?i:ara(?:bic)?)|AR,,, +language,ARMENIAN,Armenian,(?i:armenian)|HY,,, +language,AZERBAIJANI,Azerbaijani,(?i:azerbaijani)|AZ,,, +language,BALTIC,Baltic,(?i:baltic),,, +language,BASQUE,Basque,(?i:basque)|EU,,, +language,BELARUSIAN,Belarusian,(?i:belarusian)|BE,,, +language,BENGALI,Bengali,(?i:bengali)|BN,,, +language,BOSNIAN,Bosnian,(?i:bosnian)|BS,,, +language,BRAZILIAN,Brazilian,(?i:brazilian)|BR,,, +language,BULGARIAN,Bulgarian,(?i:bulgarian)|BG,,, +language,BURMESE,Burmese,(?i:burmese)|MY,,, +language,CATALAN,Catalan,(?i:catalan)|CA,,, +language,CHINESE,Chinese,(?i:chinese)|ZH|CN,,, language,CHS,Chinese (simplified),(?i:chinese[\-\._ ]?simplified)|CHS,,, language,CHT,Chinese (traditional),(?i:chinese[\-\._ ]?traditional)|CHT,,, -language,CZECH,Czech,CZECH|CZ,,, -language,DANiSH,Danish,(?i:danish)|DK,,, -language,DL,Dual Language,(?i:dual[\-\._ ]?language)|DL,,, -language,DUBBED,Dubbed,(?i:(?:line[\-\._ ]?)?dubbed),,, +language,CROATIAN,Croatian,(?i:croatian)|HR,,, +language,CZECH,Czech,(?i:czech)|CZ,,, +language,DANISH,Danish,(?i:danish)|DK,,, language,DUTCH,Dutch,(?i:dutch|flemish)|NL,,, -language,ENGLiSH,English,(?i:eng(?:lish)?)|EN,,, -language,ESTONiAN,Estonian,(?i:estonian)|EE,,, -language,FiNNiSH,Finnish,(?i:finnish)|FI,,, -language,FRENCH,French,(?i:french)|FRE|FR,,, +language,ENGLISH,English,(?i:eng(?:lish)?)|EN,,, +language,ESTONIAN,Estonian,(?i:estonian)|EE,,, +language,FINNISH,Finnish,(?i:finnish)|FI,,, +language,FRENCH,French,(?i:french)|FR,,, +language,GEORGIAN,Georgian,(?i:georgian)|KA,,, language,GERMAN,German,(?i:german)|DE,,, -language,GREEK,Greek,GREEK|(?i:gr),,, -language,HAiTiAN,Hatian,(?i:haitian)|HT,,, -language,HARDSUB,Subs (hard),(?:hardsub),,, -language,HC,Hardcoded,(?i:hard[\-\._ ]?coded|hc),,, -language,HiNDI,Hindi,(?i:hindi)|HI,,, -language,HUNGARiAN,Hungarian,(?i:hun(?:garian)?)|HU,,, -language,iCELANDiC,Icelandic,(?i:icelandic),,, -language,iTALiAN,Italian,(?i:ita(?:lian)?),,, +language,GREEK,Greek,(?i:greek)|GR,,, +language,HAITIAN,Haitian,(?i:haitian)|HT,,, +language,HEBREW,Hebrew,(?i:hebrew)|HE,,, +language,HINDI,Hindi,(?i:hindi)|HI,,, +language,HUNGARIAN,Hungarian,(?i:hun(?:garian)?)|HU,,, +language,ICELANDIC,Icelandic,(?i:icelandic)|IS,,, +language,INDONESIAN,Indonesian,(?i:indonesian)|ID,,, +language,IRISH,Irish,(?i:irish)|GA,,, +language,ITALIAN,Italian,(?i:ita(?:lian)?)|IT,,, language,JAPANESE,Japanese,(?i:japanese),,, -language,KOREAN,Korean,K[oO]R[eE][aA]N|KR,,, -language,LATiN,Latin,,,, -language,MANDARiN,Mandarin,,,, -language,MULTILANG,Multi (lang),,,, -language,MULTiSUB,Subs (multi),(?i:multiple[\-\._ ]subtitles?|multi[\-\._ ]?subs?),,, -language,MULTi,Multi,(?i:multi(?:[\-\._ ]?(?:lingual|language)))|MULT[iI],,, -language,NORDiC,Nordic,N[oO]RD[iI]C,,, -language,NORWEGiAN,Norwegian,(?i:nor(?:wegian)?)|NO,,, -language,POLiSH,Polish,(?i:polish)|PL,,, +language,JAVANESE,Javanese,(?i:javanese)|JV,,, +language,KAZAKH,Kazakh,(?i:kazakh)|KK,,, +language,KHMER,Khmer,(?i:khmer)|KM,,, +language,KOREAN,Korean,(?i:kor(?:ean)?)|KR,,, +language,LAOTIAN,Laotian,(?i:lao(?:tian)?)|LO,,, +language,LATIN,Latin,(?i:latin)|LA,,, +language,LATVIAN,Latvian,(?i:latvian)|LV,,, +language,LITHUANIAN,Lithuanian,(?i:lithuanian)|LT,,, +language,MACEDONIAN,Macedonian,(?i:macedonian)|MK,,, +language,MALAY,Malay,(?i:malay)|MS,,, +language,MALAYALAM,Malayalam,(?i:malayalam)|ML,,, +language,MANDARIN,Mandarin,(?i:mandarin),,, +language,MARATHI,Marathi,(?i:marathi)|MR,,, +language,MONGOLIAN,Mongolian,(?i:mongolian)|MN,,, +language,NEPALI,Nepali,(?i:nepali)|NE,,, +language,NORDIC,Nordic,(?i:nordic),,, +language,NORWEGIAN,Norwegian,(?i:nor(?:wegian)?)|NO,,, +language,PERSIAN,Persian,(?i:persian|farsi)|FA,,, +language,POLISH,Polish,(?i:polish)|PL,,, language,PORTUGUESE,Portuguese,(?i:portuguese)|PT,,, -language,ROMANiAN,Romanian,(?i:romanian)|RO,,, -language,RUSSiAN,Russian,(?i:rus(?:sian)?)|RU,,, -language,SLOVAK,Slovak,SLOVAK|SK,,, -language,SPANiSH,Spanish,(?i:spanish)|SPA|ES,,, -language,SUBBED,Subbed,(?i:subbed),,, -language,SUBFORCED,Subbed (forced),(?i:subforced|forcedsub),,, -language,SUBPACK,Subs (pack),(?i:subs?[\-\._ ]?pack),,, -language,SWEDiSH,Swedish,(?i:swe(?:dish)?)|SE,,, -language,SYNCED,Synced,(?i:synced),,, -language,TURKiSH,Turkish,(?i:turkish)|TR,,, -language,UKRAiNiAN,Ukrainian,(?i:ukrainian)|UA,,, -language,UNSUBBED,Unsubbed,(?i:unsubbed),,, +language,PUNJABI,Punjabi,(?i:punjabi)|PA,,, +language,ROMANIAN,Romanian,(?i:romanian)|RO,,, +language,RUSSIAN,Russian,(?i:rus(?:sian)?)|RU,,, +language,SERBIAN,Serbian,(?i:serbian)|SR,,, +language,SLOVAK,Slovak,(?i:slovak)|SK,,, +language,SLOVENIAN,Slovenian,(?i:slovenian)|SL,,, +language,SOMALI,Somali,(?i:somali)|SO,,, +language,SPANISH,Spanish,(?i:spanish)|SPA|ES,,, +language,SWAHILI,Swahili,(?i:swahili)|SW,,, +language,SWEDISH,Swedish,(?i:swe(?:dish)?)|SE,,, +language,TAGALOG,Tagalog,(?i:tagalog)|TL,,, +language,TAMIL,Tamil,(?i:tamil)|TA,,, +language,TELUGU,Telugu,(?i:telugu)|TE,,, +language,THAI,Thai,(?i:thai)|TH,,, +language,TURKISH,Turkish,(?i:turkish)|TR,,, +language,UKRAINIAN,Ukrainian,(?i:ukrainian)|UA,,, +language,URDU,Urdu,(?i:urdu)|UR,,, +language,UZBEK,Uzbek,(?i:uzbek)|UZ,,, +language,VIETNAMESE,Vietnamese,(?i:vietnamese)|VI,,, +language,WELSH,Welsh,(?i:welsh)|CY,,, +language,ZULU,Zulu,(?i:zulu)|ZU,,, language,VF2,VFF et VFQ,(?i:vf2|fr2),,, language,VFB,Version Francophone Belge,(?i:vfb),,, language,VFF,Version Francophone Français,(?i:vf?f|truefrench),,, diff --git a/tests.yaml b/tests.yaml index 607f8f0..286894b 100644 --- a/tests.yaml +++ b/tests.yaml @@ -94,7 +94,7 @@ source: "BluRay" year: 1992 other: "INTERNAL" - language: "SWEDiSH SUBPACK" + language: "SWEDISH SUBPACK" group: "SiN" "(2001)A Space Odyssey(1961).mkv": type: "movie" @@ -127,7 +127,7 @@ codec: "x264" audio: "DUAL.AUDIO" channels: "6.0" - language: "ENGLiSH HiNDI" + language: "ENGLISH HINDI" group: "GOPISAHI" unused: "Esub" "2012(2009).1080p.Dual Audio(Hindi+English) 5.1 Audios": @@ -137,7 +137,7 @@ year: 2009 audio: "DUAL.AUDIO" channels: "5.1" - language: "HiNDI ENGLiSH" + language: "HINDI ENGLISH" "2012 (2009) 1080p BrRip x264 - 1.7GB - YIFY": type: "movie" title: "2012" @@ -227,7 +227,7 @@ year: 2011 codec: "x264.HQ" other: "3D Half-SBS" - language: "FRENCH MULTiSUB" + language: "FRENCH MULTISUB" group: "TUSAHD" "Adam.Carolla.Not.Taco.Bell.Material.2019.WEB-DL": type: "movie" @@ -252,7 +252,7 @@ audio: "DD" channels: "5.1" other: "UPSCALED" - language: "HiNDI" + language: "HINDI" group: "M2Tv" unused: "DesiSCR Rip Mafiaking" "Akte.X.Jenseits.der.Wahrheit.R5.Line.Dubbed.German.READ.NFO.XviD-VCF": @@ -485,7 +485,7 @@ year: 2006 other: "DIRFIX COMPLETE" cut: "Extended.Cut" - language: "MULTi" + language: "MULTI" group: "MONUMENT" "(Comedy) Netflix Originals - Dave Chappelle - Deep in the Heart of Texas (2017) 1080p WEBRip DD5.1 x264-TrollHD.mkv": type: "movie" @@ -671,7 +671,7 @@ source: "BluRay" resolution: "720p" year: 1965 - language: "VOSTFR RUSSiAN" + language: "VOSTFR RUSSIAN" group: "Popo" unused: "Russ Meyer Liosaa" "FAT.A.Documentary.2019.1080p.AMZN.WEB-DL.DDP5.1.H.264-NTG.mkv": @@ -713,7 +713,7 @@ source: "DVDSCR" resolution: "576p" codec: "H.264" - language: "ENGLiSH HARDSUB" + language: "ENGLISH HARDSUB" site: "ValdikSS" ext: "mkv" "\t foo\nbar\n\f\r1080p \t\nbluray\n\t": @@ -771,7 +771,7 @@ source: "HDTV" resolution: "720p" codec: "x264" - language: "DANiSH" + language: "DANISH" group: "SKANK" "(horror)Heart-.Burn+.-.h-264.D-Z0N3 {{ secret }}": type: "movie" @@ -834,7 +834,7 @@ year: 2014 codec: "x264" audio: "AAC" - language: "ENGLiSH" + language: "ENGLISH" group: "CPG" "Jack.And.The.Cuckoo-Clock.Heart.2013.BRRip XViD": type: "movie" @@ -1119,7 +1119,7 @@ audio: "DDP Atmos" channels: "5.1" other: "HYBRiD" - language: "ENGLiSH" + language: "ENGLISH" group: "HONE" ext: "mkv" "South.Park.Bigger.Longer.and.Uncut.1999.1080p.Blu-ray.AVC.TrueHD.5.1.REMUX-FraMeSToR": @@ -1350,7 +1350,7 @@ disc: "1x" codec: "x264" audio: "AAC" - language: "HiNDI" + language: "HINDI" group: "Hon3y" site: "DDR" "The.Treasure.of.the.Sierra.Madre.1948.BluRay.1080p.FLAC.1.0.VC-1.REMUX-FraMeSToR": @@ -1588,7 +1588,7 @@ series: 1 episode: 1 codec: "XViD" - language: "SWEDiSH" + language: "SWEDISH" group: "HDR" "1899.S01.PROPER.1080p.NF.WEB-DL.DDP5.1.Atmos.H.264-FLUX": type: "series" @@ -1759,7 +1759,7 @@ resolution: "720p" series: 2 episode: 20 - language: "RUSSiAN ENGLiSH" + language: "RUSSIAN ENGLISH" "Core.Kyoto.S05E16.Tatami.The.Flooring.Underlying.Japanese.Culture.HDTV.x264-DARKFLiX": type: "episode" title: "Core Kyoto" @@ -1912,7 +1912,7 @@ audio: "DD" channels: "2.0" other: "BOXSET" - language: "NORDiC" + language: "NORDIC" group: "TWASERiES" "Game of Thrones - 4x03 - Breaker of Chains": type: "episode" @@ -2685,7 +2685,7 @@ episode: 8 audio: "AAC" channels: "2.0" - language: "ENGLiSH SUBBED" + language: "ENGLISH SUBBED" group: "ZR" ext: "mkv" unused: "Shuumatsu no Harem" @@ -3335,7 +3335,7 @@ arch: "x64" year: 2019 version: "v21.0.12" - language: "MULTi" + language: "MULTI" group: "WEBiSO" "Atlassian.Fisheye.and.Crucible.v4.7.0.MultiOS.Incl.KeyMaker.and.Patch.15TH.BIRTHDAY-DVT": type: "app" @@ -3495,7 +3495,7 @@ platform: "NSW" version: "v1.90" other: "UPDATE" - language: "MULTi" + language: "MULTI" group: "SUXXORS" "Super_Mario_3D_World_plus_Bowsers_Fury_Update_v1.1.0_NSW-VENOM": type: "game" @@ -3599,7 +3599,7 @@ source: "AUDiOBOOK" year: 2021 other: "INTERNAL" - language: "SWEDiSH" + language: "SWEDISH" group: "OLDSWE" "PLURALSIGHT.3DS.MAX.RIGGING.FUNDAMENTALS-JGTiSO": type: "education"