New: Use MediaInfo to Augment Languages

This commit is contained in:
Qstick 2020-07-06 15:17:03 -04:00
parent 10322a1867
commit 88bda6bcb6
11 changed files with 259 additions and 76 deletions

View File

@ -1,9 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using FluentAssertions.Common;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Languages;
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators;
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
@ -13,17 +18,47 @@ namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Aggregation.Aggregators
public class AggregateLanguageFixture : CoreTest<AggregateLanguage>
{
private LocalMovie _localMovie;
private Movie _movie;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
.With(m => m.OriginalLanguage = Language.English)
.Build();
_localMovie = Builder<LocalMovie>.CreateNew()
.With(l => l.DownloadClientMovieInfo = null)
.With(l => l.FolderMovieInfo = null)
.With(l => l.FileMovieInfo = null)
.With(l => l.Movie = _movie)
.Build();
}
private void GivenAugmenters(List<Language> fileNameLanguages, List<Language> folderNameLanguages, List<Language> clientLanguages, List<Language> mediaInfoLanguages)
{
var fileNameAugmenter = new Mock<IAugmentLanguage>();
var folderNameAugmenter = new Mock<IAugmentLanguage>();
var clientInfoAugmenter = new Mock<IAugmentLanguage>();
var mediaInfoAugmenter = new Mock<IAugmentLanguage>();
fileNameAugmenter.Setup(s => s.AugmentLanguage(It.IsAny<LocalMovie>()))
.Returns(new AugmentLanguageResult(fileNameLanguages, Confidence.Filename));
folderNameAugmenter.Setup(s => s.AugmentLanguage(It.IsAny<LocalMovie>()))
.Returns(new AugmentLanguageResult(folderNameLanguages, Confidence.Foldername));
clientInfoAugmenter.Setup(s => s.AugmentLanguage(It.IsAny<LocalMovie>()))
.Returns(new AugmentLanguageResult(clientLanguages, Confidence.DownloadClientItem));
mediaInfoAugmenter.Setup(s => s.AugmentLanguage(It.IsAny<LocalMovie>()))
.Returns(new AugmentLanguageResult(mediaInfoLanguages, Confidence.MediaInfo));
var mocks = new List<Mock<IAugmentLanguage>> { fileNameAugmenter, folderNameAugmenter, clientInfoAugmenter, mediaInfoAugmenter };
Mocker.SetConstant<IEnumerable<IAugmentLanguage>>(mocks.Select(c => c.Object));
}
private ParsedMovieInfo GetParsedMovieInfo(List<Language> languages)
{
return new ParsedMovieInfo
@ -35,56 +70,77 @@ namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Aggregation.Aggregators
[Test]
public void should_return_default_if_no_info_is_known()
{
Subject.Aggregate(_localMovie, false).Languages.Should().Contain(Language.Unknown);
var result = Subject.Aggregate(_localMovie, false);
result.Languages.Should().Contain(_movie.OriginalLanguage);
}
[Test]
public void should_return_file_language_when_only_file_info_is_known()
{
_localMovie.FileMovieInfo = GetParsedMovieInfo(new List<Language> { Language.English });
GivenAugmenters(new List<Language> { Language.French },
null,
null,
null);
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(_localMovie.FileMovieInfo.Languages);
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List<Language> { Language.French });
}
[Test]
public void should_return_folder_language_when_folder_info_is_known()
{
_localMovie.FolderMovieInfo = GetParsedMovieInfo(new List<Language> { Language.English });
_localMovie.FileMovieInfo = GetParsedMovieInfo(new List<Language> { Language.English });
GivenAugmenters(new List<Language> { Language.French },
new List<Language> { Language.German },
null,
null);
var aggregation = Subject.Aggregate(_localMovie, false);
aggregation.Languages.Should().Equal(_localMovie.FolderMovieInfo.Languages);
aggregation.Languages.Should().Equal(new List<Language> { Language.German });
}
[Test]
public void should_return_download_client_item_language_when_download_client_item_info_is_known()
{
_localMovie.DownloadClientMovieInfo = GetParsedMovieInfo(new List<Language> { Language.English });
_localMovie.FolderMovieInfo = GetParsedMovieInfo(new List<Language> { Language.English });
_localMovie.FileMovieInfo = GetParsedMovieInfo(new List<Language> { Language.English });
GivenAugmenters(new List<Language> { Language.French },
new List<Language> { Language.German },
new List<Language> { Language.Spanish },
null);
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(_localMovie.DownloadClientMovieInfo.Languages);
}
[Test]
public void should_return_file_language_when_file_language_is_higher_than_others()
{
_localMovie.DownloadClientMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Unknown });
_localMovie.FolderMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Unknown });
_localMovie.FileMovieInfo = GetParsedMovieInfo(new List<Language> { Language.French });
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(_localMovie.FileMovieInfo.Languages);
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List<Language> { Language.Spanish });
}
[Test]
public void should_return_multi_language()
{
_localMovie.DownloadClientMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Unknown });
_localMovie.FolderMovieInfo = GetParsedMovieInfo(new List<Language> { Language.English, Language.German });
_localMovie.FileMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Unknown });
GivenAugmenters(new List<Language> { Language.Unknown },
new List<Language> { Language.French, Language.German },
new List<Language> { Language.Unknown },
null);
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(_localMovie.FolderMovieInfo.Languages);
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List<Language> { Language.French, Language.German });
}
[Test]
public void should_use_mediainfo_over_others()
{
GivenAugmenters(new List<Language> { Language.Unknown },
new List<Language> { Language.French, Language.German },
new List<Language> { Language.Unknown },
new List<Language> { Language.Japanese, Language.English });
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List<Language> { Language.Japanese, Language.English });
}
[Test]
public void should_not_use_mediainfo_if_unknown()
{
GivenAugmenters(new List<Language> { Language.Unknown },
new List<Language> { Language.French, Language.German },
new List<Language> { Language.Unknown },
new List<Language> { Language.Unknown });
Subject.Aggregate(_localMovie, false).Languages.Should().Equal(new List<Language> { Language.French, Language.German });
}
}
}

View File

@ -1,53 +1,43 @@
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Languages;
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators
{
public class AggregateLanguage : IAggregateLocalMovie
{
private readonly IEnumerable<IAugmentLanguage> _augmentQualities;
private readonly Logger _logger;
public AggregateLanguage(Logger logger)
public AggregateLanguage(IEnumerable<IAugmentLanguage> augmentQualities,
Logger logger)
{
_augmentQualities = augmentQualities;
_logger = logger;
}
public LocalMovie Aggregate(LocalMovie localMovie, bool otherFiles)
{
// Get languages in preferred order, download client item, folder and finally file.
// Non-English languages will be preferred later, in the event there is a conflict
// between parsed languages the more preferred item will be used.
var languages = new List<Language>();
var augmentedLanguages = _augmentQualities.Select(a => a.AugmentLanguage(localMovie))
.Where(a => a != null)
.OrderBy(a => a.Confidence);
languages.AddRange(localMovie.DownloadClientMovieInfo?.Languages ?? new List<Language>());
var languages = new List<Language> { localMovie.Movie.OriginalLanguage ?? Language.Unknown };
var languagesConfidence = Confidence.Default;
if (!languages.Any(l => l != Language.Unknown))
foreach (var augmentedLanguage in augmentedLanguages)
{
languages = localMovie.FolderMovieInfo?.Languages ?? new List<Language>();
if (augmentedLanguage?.Languages != null && augmentedLanguage.Languages.Count > 0 && !(augmentedLanguage.Languages.Count == 1 && augmentedLanguage.Languages.Contains(Language.Unknown)))
{
languages = augmentedLanguage.Languages;
languagesConfidence = augmentedLanguage.Confidence;
}
}
if (!languages.Any(l => l != Language.Unknown))
{
languages = localMovie.FileMovieInfo?.Languages ?? new List<Language>();
}
if (!languages.Any())
{
languages.Add(Language.Unknown);
}
languages = languages.Distinct().ToList();
if (languages.Count == 1 && languages.Contains(Language.Unknown))
{
languages = new List<Language> { localMovie.Movie.OriginalLanguage };
}
_logger.Debug("Using languages: {0}", languages.Select(l => l.Name).ToList().Join(","));
_logger.Debug("Using languages: {0}", languages);
localMovie.Languages = languages;

View File

@ -0,0 +1,19 @@
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language
{
public class AugmentLanguageFromDownloadClientItem : IAugmentLanguage
{
public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie)
{
var languages = localMovie.DownloadClientMovieInfo?.Languages;
if (languages == null)
{
return null;
}
return new AugmentLanguageResult(languages, Confidence.DownloadClientItem);
}
}
}

View File

@ -0,0 +1,19 @@
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language
{
public class AugmentLanguageFromFileName : IAugmentLanguage
{
public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie)
{
var languages = localMovie.FileMovieInfo?.Languages;
if (languages == null)
{
return null;
}
return new AugmentLanguageResult(languages, Confidence.Filename);
}
}
}

View File

@ -0,0 +1,19 @@
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language
{
public class AugmentLanguageFromFolder : IAugmentLanguage
{
public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie)
{
var languages = localMovie.FolderMovieInfo?.Languages;
if (languages == null)
{
return null;
}
return new AugmentLanguageResult(languages, Confidence.Foldername);
}
}
}

View File

@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language
{
public class AugmentLanguageFromMediaInfo : IAugmentLanguage
{
public AugmentLanguageResult AugmentLanguage(LocalMovie localMovie)
{
if (localMovie.MediaInfo == null)
{
return null;
}
var audioLanguages = localMovie.MediaInfo.AudioLanguages.Split('/').Distinct().ToList();
var languages = new List<Languages.Language>();
foreach (var audioLanguage in audioLanguages)
{
var language = IsoLanguages.FindByName(audioLanguage)?.Language;
languages.AddIfNotNull(language);
}
if (languages.Count == 0)
{
return null;
}
return new AugmentLanguageResult(languages, Confidence.MediaInfo);
}
}
}

View File

@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language
{
public class AugmentLanguageResult
{
public List<Languages.Language> Languages { get; set; }
public Confidence Confidence { get; set; }
public AugmentLanguageResult(List<Languages.Language> languages,
Confidence confidence)
{
Languages = languages;
Confidence = confidence;
}
}
}

View File

@ -0,0 +1,11 @@
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language
{
public enum Confidence
{
Default,
Filename,
Foldername,
DownloadClientItem,
MediaInfo
}
}

View File

@ -0,0 +1,9 @@
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Language
{
public interface IAugmentLanguage
{
AugmentLanguageResult AugmentLanguage(LocalMovie localMovie);
}
}

View File

@ -7,13 +7,15 @@ namespace NzbDrone.Core.Parser
public string TwoLetterCode { get; set; }
public string ThreeLetterCode { get; set; }
public string CountryCode { get; set; }
public string EnglishName { get; set; }
public Language Language { get; set; }
public IsoLanguage(string twoLetterCode, string countryCode, string threeLetterCode, Language language)
public IsoLanguage(string twoLetterCode, string countryCode, string threeLetterCode, string englishName, Language language)
{
TwoLetterCode = twoLetterCode;
ThreeLetterCode = threeLetterCode;
CountryCode = countryCode;
EnglishName = englishName;
Language = language;
}
}

View File

@ -8,30 +8,30 @@ namespace NzbDrone.Core.Parser
{
private static readonly HashSet<IsoLanguage> All = new HashSet<IsoLanguage>
{
new IsoLanguage("en", "", "eng", Language.English),
new IsoLanguage("fr", "", "fra", Language.French),
new IsoLanguage("es", "", "spa", Language.Spanish),
new IsoLanguage("de", "", "deu", Language.German),
new IsoLanguage("it", "", "ita", Language.Italian),
new IsoLanguage("da", "", "dan", Language.Danish),
new IsoLanguage("nl", "", "nld", Language.Dutch),
new IsoLanguage("ja", "", "jpn", Language.Japanese),
new IsoLanguage("is", "", "isl", Language.Icelandic),
new IsoLanguage("zh", "", "zho", Language.Chinese),
new IsoLanguage("ru", "", "rus", Language.Russian),
new IsoLanguage("pl", "", "pol", Language.Polish),
new IsoLanguage("vi", "", "vie", Language.Vietnamese),
new IsoLanguage("sv", "", "swe", Language.Swedish),
new IsoLanguage("no", "", "nor", Language.Norwegian),
new IsoLanguage("nb", "", "nob", Language.Norwegian),
new IsoLanguage("fi", "", "fin", Language.Finnish),
new IsoLanguage("tr", "", "tur", Language.Turkish),
new IsoLanguage("pt", "", "por", Language.Portuguese),
new IsoLanguage("el", "", "ell", Language.Greek),
new IsoLanguage("ko", "", "kor", Language.Korean),
new IsoLanguage("hu", "", "hun", Language.Hungarian),
new IsoLanguage("he", "", "heb", Language.Hebrew),
new IsoLanguage("cs", "", "ces", Language.Czech)
new IsoLanguage("en", "", "eng", "English", Language.English),
new IsoLanguage("fr", "", "fra", "French", Language.French),
new IsoLanguage("es", "", "spa", "Spanish", Language.Spanish),
new IsoLanguage("de", "", "deu", "German", Language.German),
new IsoLanguage("it", "", "ita", "Italian", Language.Italian),
new IsoLanguage("da", "", "dan", "Danish", Language.Danish),
new IsoLanguage("nl", "", "nld", "Dutch", Language.Dutch),
new IsoLanguage("ja", "", "jpn", "Japanese", Language.Japanese),
new IsoLanguage("is", "", "isl", "Icelandic", Language.Icelandic),
new IsoLanguage("zh", "", "zho", "Chinese", Language.Chinese),
new IsoLanguage("ru", "", "rus", "Russian", Language.Russian),
new IsoLanguage("pl", "", "pol", "Polish", Language.Polish),
new IsoLanguage("vi", "", "vie", "Vietnamese", Language.Vietnamese),
new IsoLanguage("sv", "", "swe", "Swedish", Language.Swedish),
new IsoLanguage("no", "", "nor", "Norwegian", Language.Norwegian),
new IsoLanguage("nb", "", "nob", "Norwegian Bokmal", Language.Norwegian),
new IsoLanguage("fi", "", "fin", "Finnish", Language.Finnish),
new IsoLanguage("tr", "", "tur", "Turkish", Language.Turkish),
new IsoLanguage("pt", "", "por", "Portuguese", Language.Portuguese),
new IsoLanguage("el", "", "ell", "Greek", Language.Greek),
new IsoLanguage("ko", "", "kor", "Korean", Language.Korean),
new IsoLanguage("hu", "", "hun", "Hungarian", Language.Hungarian),
new IsoLanguage("he", "", "heb", "Hebrew", Language.Hebrew),
new IsoLanguage("cs", "", "ces", "Czech", Language.Czech)
};
public static IsoLanguage Find(string isoCode)
@ -62,6 +62,11 @@ namespace NzbDrone.Core.Parser
return null;
}
public static IsoLanguage FindByName(string name)
{
return All.FirstOrDefault(l => l.EnglishName == name.Trim());
}
public static IsoLanguage Get(Language language)
{
return All.FirstOrDefault(l => l.Language == language);