From 17bfcdd32565328ae38fda28c29bb3e91f80810b Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Tue, 20 Dec 2022 17:17:47 -0800 Subject: [PATCH] New: Portuguese (Brazil) and Spanish (Latino) languages Closes #5302 --- .../Languages/LanguageFixture.cs | 30 ++++++++++-- .../ParserTests/IsoLanguagesFixture.cs | 49 +++++++++++++++++++ .../ParserTests/LanguageParserFixture.cs | 23 ++++++--- src/NzbDrone.Core/Languages/Language.cs | 4 ++ src/NzbDrone.Core/Parser/IsoLanguages.cs | 35 +++++++++---- src/NzbDrone.Core/Parser/LanguageParser.cs | 10 ++++ 6 files changed, 130 insertions(+), 21 deletions(-) create mode 100644 src/NzbDrone.Core.Test/ParserTests/IsoLanguagesFixture.cs diff --git a/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs b/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs index 8a27cba4e..c796653f4 100644 --- a/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs +++ b/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Languages; @@ -33,7 +31,19 @@ namespace NzbDrone.Core.Test.Languages new object[] { 19, Language.Flemish }, new object[] { 20, Language.Greek }, new object[] { 21, Language.Korean }, - new object[] { 22, Language.Hungarian } + new object[] { 22, Language.Hungarian }, + new object[] { 23, Language.Hebrew }, + new object[] { 24, Language.Lithuanian }, + new object[] { 25, Language.Czech }, + new object[] { 26, Language.Arabic }, + new object[] { 27, Language.Hindi }, + new object[] { 28, Language.Bulgarian }, + new object[] { 29, Language.Malayalam }, + new object[] { 30, Language.Ukrainian }, + new object[] { 31, Language.Slovak }, + new object[] { 32, Language.Thai }, + new object[] { 33, Language.PortugueseBrazil }, + new object[] { 34, Language.SpanishLatino } }; public static object[] ToIntCases = @@ -59,7 +69,19 @@ namespace NzbDrone.Core.Test.Languages new object[] { Language.Flemish, 19 }, new object[] { Language.Greek, 20 }, new object[] { Language.Korean, 21 }, - new object[] { Language.Hungarian, 22 } + new object[] { Language.Hungarian, 22 }, + new object[] { Language.Hebrew, 23 }, + new object[] { Language.Lithuanian, 24 }, + new object[] { Language.Czech, 25 }, + new object[] { Language.Arabic, 26 }, + new object[] { Language.Hindi, 27 }, + new object[] { Language.Bulgarian, 28 }, + new object[] { Language.Malayalam, 29 }, + new object[] { Language.Ukrainian, 30 }, + new object[] { Language.Slovak, 31 }, + new object[] { Language.Thai, 32 }, + new object[] { Language.PortugueseBrazil, 33 }, + new object[] { Language.SpanishLatino, 34 } }; [Test] diff --git a/src/NzbDrone.Core.Test/ParserTests/IsoLanguagesFixture.cs b/src/NzbDrone.Core.Test/ParserTests/IsoLanguagesFixture.cs new file mode 100644 index 000000000..6d50e65b4 --- /dev/null +++ b/src/NzbDrone.Core.Test/ParserTests/IsoLanguagesFixture.cs @@ -0,0 +1,49 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Languages; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.ParserTests +{ + [TestFixture] + public class IsoLanguagesFixture : CoreTest + { + [TestCase("en")] + [TestCase("eng")] + [TestCase("en-US")] + [TestCase("en-GB")] + public void should_return_iso_language_for_English(string isoCode) + { + var result = IsoLanguages.Find(isoCode); + result.Language.Should().Be(Language.English); + } + + [TestCase("enus")] + [TestCase("enusa")] + [TestCase("wo")] + [TestCase("ca-IT")] + [TestCase("fr-CA")] + public void unknown_or_invalid_code_should_return_null(string isoCode) + { + var result = IsoLanguages.Find(isoCode); + result.Should().Be(null); + } + + [TestCase("pt")] + [TestCase("por")] + [TestCase("pt-PT")] + public void should_return_portuguese(string isoCode) + { + var result = IsoLanguages.Find(isoCode); + result.Language.Should().Be(Language.Portuguese); + } + + [TestCase("de-AU")] + public void should_not_return_portuguese(string isoCode) + { + var result = IsoLanguages.Find(isoCode); + result.Should().Be(null); + } + } +} diff --git a/src/NzbDrone.Core.Test/ParserTests/LanguageParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/LanguageParserFixture.cs index f2e507919..be7a02b46 100644 --- a/src/NzbDrone.Core.Test/ParserTests/LanguageParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/LanguageParserFixture.cs @@ -321,15 +321,24 @@ namespace NzbDrone.Core.Test.ParserTests result.First().Id.Should().Be(Language.Thai.Id); } - [TestCase("Title.the.Russian.Series.S01E07.Cold.Action.HDTV.XviD-Droned")] - [TestCase("Title.the.Russian.Series.S01E07E08.Cold.Action.HDTV.XviD-Droned")] - [TestCase("Title.the.Russian.Series.S01.1080p.WEBRip.DDP5.1.x264-Drone")] - [TestCase("Title.the.Spanish.Series.S02E08.Peace.1080p.AMZN.WEBRip.DDP5.1.x264-NTb")] - [TestCase("Title The Spanish S02E02 Flodden 720p AMZN WEB-DL DDP5 1 H 264-NTb")] - public void should_not_parse_series_or_episode_title(string postTitle) + [TestCase("Title.the.Series.2009.S01E14.Brazilian.HDTV.XviD-LOL")] + [TestCase("Title.the.Series.2009.S01E14.Dublado.HDTV.XviD-LOL")] + public void should_parse_language_portuguese_brazil(string postTitle) { var result = LanguageParser.ParseLanguages(postTitle); - result.First().Name.Should().Be(Language.Unknown.Name); + result.First().Id.Should().Be(Language.PortugueseBrazil.Id); + } + + [TestCase("Series.Title.S01.2019.720p_Eng-Spa(Latino)_MovieClubMx")] + [TestCase("Series.Title.1.WEB-DL.720p.Complete.Latino.YG")] + [TestCase("Series.Title.S08E01.1080p.WEB.H264.Latino.YG")] + [TestCase("Series Title latino")] + [TestCase("Series Title (Temporada 11 Completa) Audio Dual Ingles/Latino 1920x1080")] + [TestCase("series title 7x4 audio latino")] + public void should_parse_language_spanish_latino(string postTitle) + { + var result = LanguageParser.ParseLanguages(postTitle); + result.First().Id.Should().Be(Language.SpanishLatino.Id); } } } diff --git a/src/NzbDrone.Core/Languages/Language.cs b/src/NzbDrone.Core/Languages/Language.cs index de0e72a3a..fea42f085 100644 --- a/src/NzbDrone.Core/Languages/Language.cs +++ b/src/NzbDrone.Core/Languages/Language.cs @@ -103,6 +103,8 @@ namespace NzbDrone.Core.Languages public static Language Ukrainian => new Language(30, "Ukrainian"); public static Language Slovak => new Language(31, "Slovak"); public static Language Thai => new Language(32, "Thai"); + public static Language PortugueseBrazil => new Language(33, "Portuguese (Brazil)"); + public static Language SpanishLatino => new Language(34, "Spanish (Latino)"); public static Language Original => new Language(-2, "Original"); public static List All @@ -144,6 +146,8 @@ namespace NzbDrone.Core.Languages Ukrainian, Slovak, Thai, + PortugueseBrazil, + SpanishLatino, Original }; } diff --git a/src/NzbDrone.Core/Parser/IsoLanguages.cs b/src/NzbDrone.Core/Parser/IsoLanguages.cs index 0ab756337..5c3b64d7e 100644 --- a/src/NzbDrone.Core/Parser/IsoLanguages.cs +++ b/src/NzbDrone.Core/Parser/IsoLanguages.cs @@ -41,25 +41,40 @@ namespace NzbDrone.Core.Parser new IsoLanguage("bg", "", "bul", Language.Bulgarian), new IsoLanguage("ml", "", "mal", Language.Malayalam), new IsoLanguage("uk", "", "ukr", Language.Ukrainian), - new IsoLanguage("sk", "", "slk", Language.Slovak) + new IsoLanguage("sk", "", "slk", Language.Slovak), + new IsoLanguage("th", "th", "tha", Language.Thai), + new IsoLanguage("pt", "br", "por", Language.PortugueseBrazil), + new IsoLanguage("es", "mx", "spa", Language.SpanishLatino) }; public static IsoLanguage Find(string isoCode) { - if (isoCode.Length == 2) + var isoArray = isoCode.Split('-'); + var langCode = isoArray[0].ToLower(); + + if (langCode.Length == 2) { // Lookup ISO639-1 code - return All.FirstOrDefault(l => l.TwoLetterCode == isoCode); - } - else if (isoCode.Length == 3) - { - // Lookup ISO639-2T code - if (FileNameBuilder.Iso639BTMap.TryGetValue(isoCode, out var mapped)) + var isoLanguages = All.Where(l => l.TwoLetterCode == langCode).ToList(); + + if (isoArray.Length > 1) { - isoCode = mapped; + isoLanguages = isoLanguages.Any(l => l.CountryCode == isoArray[1].ToLower()) ? + isoLanguages.Where(l => l.CountryCode == isoArray[1].ToLower()).ToList() : + isoLanguages.Where(l => string.IsNullOrEmpty(l.CountryCode)).ToList(); } - return All.FirstOrDefault(l => l.ThreeLetterCode == isoCode); + return isoLanguages.FirstOrDefault(); + } + else if (langCode.Length == 3) + { + // Lookup ISO639-2T code + if (FileNameBuilder.Iso639BTMap.TryGetValue(langCode, out var mapped)) + { + langCode = mapped; + } + + return All.FirstOrDefault(l => l.ThreeLetterCode == langCode); } return null; diff --git a/src/NzbDrone.Core/Parser/LanguageParser.cs b/src/NzbDrone.Core/Parser/LanguageParser.cs index 523441d52..adbff6a56 100644 --- a/src/NzbDrone.Core/Parser/LanguageParser.cs +++ b/src/NzbDrone.Core/Parser/LanguageParser.cs @@ -161,6 +161,16 @@ namespace NzbDrone.Core.Parser languages.Add(Language.Slovak); } + if (lowerTitle.Contains("brazilian") || lowerTitle.Contains("dublado")) + { + languages.Add(Language.PortugueseBrazil); + } + + if (lowerTitle.Contains("latino")) + { + languages.Add(Language.SpanishLatino); + } + var regexLanguages = RegexLanguage(title); if (regexLanguages.Any())