diff --git a/frontend/src/InteractiveImport/Language/SelectLanguageModalContentConnector.js b/frontend/src/InteractiveImport/Language/SelectLanguageModalContentConnector.js index d638e91e4..e1b30f9ea 100644 --- a/frontend/src/InteractiveImport/Language/SelectLanguageModalContentConnector.js +++ b/frontend/src/InteractiveImport/Language/SelectLanguageModalContentConnector.js @@ -18,11 +18,14 @@ function createMapStateToProps() { items } = languages; + const filterItems = ['Any', 'Original']; + const filteredLanguages = items.filter((lang) => !filterItems.includes(lang.name)); + return { isFetching, isPopulated, error, - items + items: filteredLanguages }; } ); @@ -54,7 +57,9 @@ class SelectLanguageModalContentConnector extends Component { const language = _.find(this.props.items, (item) => item.id === parseInt(languageId)); - languages.push(language); + if (language !== undefined) { + languages.push(language); + } }); this.props.dispatchUpdateInteractiveImportItems({ diff --git a/frontend/src/MovieFile/Language/SelectLanguageModalContentConnector.js b/frontend/src/MovieFile/Language/SelectLanguageModalContentConnector.js index 65adc999e..1eacde068 100644 --- a/frontend/src/MovieFile/Language/SelectLanguageModalContentConnector.js +++ b/frontend/src/MovieFile/Language/SelectLanguageModalContentConnector.js @@ -18,7 +18,7 @@ function createMapStateToProps() { items } = languages; - const filterItems = ['Any']; + const filterItems = ['Any', 'Original']; const filteredLanguages = items.filter((lang) => !filterItems.includes(lang.name)); return { @@ -57,7 +57,9 @@ class SelectLanguageModalContentConnector extends Component { const language = _.find(this.props.items, (item) => item.id === parseInt(languageId)); - languages.push(language); + if (language !== undefined) { + languages.push(language); + } }); this.props.dispatchupdateMovieFiles({ diff --git a/frontend/src/Settings/UI/UISettings.js b/frontend/src/Settings/UI/UISettings.js index 465028423..1b253b43c 100644 --- a/frontend/src/Settings/UI/UISettings.js +++ b/frontend/src/Settings/UI/UISettings.js @@ -65,6 +65,8 @@ class UISettings extends Component { ...otherProps } = this.props; + const uiLanguages = languages.filter((item) => item.value !== 'Original'); + return ( { Language.German }; } + private void WithFrenchRelease() + { + _remoteMovie.ParsedMovieInfo.Languages = new List { Language.French }; + } + [Test] public void should_return_true_if_language_is_english() { @@ -61,6 +67,26 @@ public void should_return_false_if_language_is_german() Mocker.Resolve().IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); } + [Test] + public void should_return_false_if_release_is_german_and_profile_original() + { + _remoteMovie.Movie.Profile.Language = Language.Original; + + WithGermanRelease(); + + Mocker.Resolve().IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); + } + + [Test] + public void should_return_true_if_release_is_french_and_profile_original() + { + _remoteMovie.Movie.Profile.Language = Language.Original; + + WithFrenchRelease(); + + Mocker.Resolve().IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); + } + [Test] public void should_return_true_if_allowed_language_any() { diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs index ca0af52b2..dfeb080ad 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs @@ -27,6 +27,19 @@ public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase se return Decision.Accept(); } + var originalLanguage = subject.Movie.OriginalLanguage; + + if (wantedLanguage == Language.Original) + { + if (!subject.ParsedMovieInfo.Languages.Contains(originalLanguage)) + { + _logger.Debug("Original Language({0}) is wanted, but found {1}", originalLanguage, subject.ParsedMovieInfo.Languages.ToExtendedString()); + return Decision.Reject("Original Language ({0}) is wanted, but found {1}", originalLanguage, subject.ParsedMovieInfo.Languages.ToExtendedString()); + } + + return Decision.Accept(); + } + _logger.Debug("Checking if report meets language requirements. {0}", subject.ParsedMovieInfo.Languages.ToExtendedString()); if (!subject.ParsedMovieInfo.Languages.Contains(wantedLanguage)) diff --git a/src/NzbDrone.Core/Languages/Language.cs b/src/NzbDrone.Core/Languages/Language.cs index 149073337..b06f0dcd3 100644 --- a/src/NzbDrone.Core/Languages/Language.cs +++ b/src/NzbDrone.Core/Languages/Language.cs @@ -97,6 +97,7 @@ public override bool Equals(object obj) public static Language Lithuanian => new Language(24, "Lithuanian"); public static Language Czech => new Language(25, "Czech"); public static Language Any => new Language(-1, "Any"); + public static Language Original => new Language(-2, "Original"); public static List All { @@ -130,7 +131,8 @@ public static List All Hebrew, Lithuanian, Czech, - Any + Any, + Original }; } } diff --git a/src/Radarr.Api.V3/Calendar/CalendarModule.cs b/src/Radarr.Api.V3/Calendar/CalendarModule.cs index b8021a6cb..9ea911f51 100644 --- a/src/Radarr.Api.V3/Calendar/CalendarModule.cs +++ b/src/Radarr.Api.V3/Calendar/CalendarModule.cs @@ -72,10 +72,25 @@ protected MovieResource MapToResource(Movie movie) return null; } - var translation = _movieTranslationService.GetAllTranslationsForMovie(movie.Id).FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage); + var translations = _movieTranslationService.GetAllTranslationsForMovie(movie.Id); + var translation = GetMovieTranslation(translations, movie); var resource = movie.ToResource(_qualityUpgradableSpecification, translation); return resource; } + + private MovieTranslation GetMovieTranslation(List translations, Movie movie) + { + if ((Language)_configService.MovieInfoLanguage == Language.Original) + { + return new MovieTranslation + { + Title = movie.OriginalTitle, + Overview = movie.Overview + }; + } + + return translations.FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage && t.MovieId == movie.Id); + } } } diff --git a/src/Radarr.Api.V3/MovieFiles/MovieFileModule.cs b/src/Radarr.Api.V3/MovieFiles/MovieFileModule.cs index e9c8463c6..4acd740ab 100644 --- a/src/Radarr.Api.V3/MovieFiles/MovieFileModule.cs +++ b/src/Radarr.Api.V3/MovieFiles/MovieFileModule.cs @@ -6,6 +6,7 @@ using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.Exceptions; +using NzbDrone.Core.Languages; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Messaging.Events; @@ -129,7 +130,8 @@ private object SetMovieFile() if (resource.Languages != null) { - movieFile.Languages = resource.Languages; + // Don't allow user to set movieFile with 'Any' or 'Original' language + movieFile.Languages = resource.Languages.Where(l => l != Language.Any || l != Language.Original || l != null).ToList(); } } diff --git a/src/Radarr.Api.V3/Movies/MovieModule.cs b/src/Radarr.Api.V3/Movies/MovieModule.cs index 125e95edb..906b6c83c 100644 --- a/src/Radarr.Api.V3/Movies/MovieModule.cs +++ b/src/Radarr.Api.V3/Movies/MovieModule.cs @@ -109,7 +109,8 @@ private List AllMovie() if (movie != null) { - var translation = _movieTranslationService.GetAllTranslationsForMovie(movie.Id).Where(t => t.Language == (Language)_configService.MovieInfoLanguage).FirstOrDefault(); + var translations = _movieTranslationService.GetAllTranslationsForMovie(movie.Id); + var translation = GetMovieTranslation(translations, movie); moviesResources.AddIfNotNull(movie.ToResource(_qualityUpgradableSpecification, translation)); } } @@ -120,7 +121,7 @@ private List AllMovie() foreach (var movie in movies) { - var translation = translations.FirstOrDefault(t => t.MovieId == movie.Id); + var translation = GetMovieTranslation(translations, movie); moviesResources.Add(movie.ToResource(_qualityUpgradableSpecification, translation)); } } @@ -143,7 +144,8 @@ protected MovieResource MapToResource(Movie movie) return null; } - var translation = _movieTranslationService.GetAllTranslationsForMovie(movie.Id).FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage); + var translations = _movieTranslationService.GetAllTranslationsForMovie(movie.Id); + var translation = GetMovieTranslation(translations, movie); var resource = movie.ToResource(_qualityUpgradableSpecification, translation); MapCoversToLocal(resource); @@ -151,6 +153,20 @@ protected MovieResource MapToResource(Movie movie) return resource; } + private MovieTranslation GetMovieTranslation(List translations, Movie movie) + { + if ((Language)_configService.MovieInfoLanguage == Language.Original) + { + return new MovieTranslation + { + Title = movie.OriginalTitle, + Overview = movie.Overview + }; + } + + return translations.FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage && t.MovieId == movie.Id); + } + private int AddMovie(MovieResource moviesResource) { var movie = _addMovieService.AddMovie(moviesResource.ToModel()); @@ -180,7 +196,8 @@ private void UpdateMovie(MovieResource moviesResource) var model = moviesResource.ToModel(movie); var updatedMovie = _moviesService.UpdateMovie(model); - var translation = _movieTranslationService.GetAllTranslationsForMovie(updatedMovie.Id).FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage); + var translations = _movieTranslationService.GetAllTranslationsForMovie(movie.Id); + var translation = GetMovieTranslation(translations, movie); BroadcastResourceChange(ModelAction.Updated, updatedMovie.ToResource(_qualityUpgradableSpecification, translation)); } @@ -203,7 +220,8 @@ private void MapCoversToLocal(params MovieResource[] movies) public void Handle(MovieImportedEvent message) { - var translation = _movieTranslationService.GetAllTranslationsForMovie(message.ImportedMovie.MovieId).FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage); + var translations = _movieTranslationService.GetAllTranslationsForMovie(message.ImportedMovie.Movie.Id); + var translation = GetMovieTranslation(translations, message.ImportedMovie.Movie); BroadcastResourceChange(ModelAction.Updated, message.ImportedMovie.Movie.ToResource(_qualityUpgradableSpecification, translation)); } @@ -219,13 +237,15 @@ public void Handle(MovieFileDeletedEvent message) public void Handle(MovieUpdatedEvent message) { - var translation = _movieTranslationService.GetAllTranslationsForMovie(message.Movie.Id).FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage); + var translations = _movieTranslationService.GetAllTranslationsForMovie(message.Movie.Id); + var translation = GetMovieTranslation(translations, message.Movie); BroadcastResourceChange(ModelAction.Updated, message.Movie.ToResource(_qualityUpgradableSpecification, translation)); } public void Handle(MovieEditedEvent message) { - var translation = _movieTranslationService.GetAllTranslationsForMovie(message.Movie.Id).FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage); + var translations = _movieTranslationService.GetAllTranslationsForMovie(message.Movie.Id); + var translation = GetMovieTranslation(translations, message.Movie); BroadcastResourceChange(ModelAction.Updated, message.Movie.ToResource(_qualityUpgradableSpecification, translation)); } @@ -239,7 +259,8 @@ public void Handle(MoviesDeletedEvent message) public void Handle(MovieRenamedEvent message) { - var translation = _movieTranslationService.GetAllTranslationsForMovie(message.Movie.Id).FirstOrDefault(t => t.Language == (Language)_configService.MovieInfoLanguage); + var translations = _movieTranslationService.GetAllTranslationsForMovie(message.Movie.Id); + var translation = GetMovieTranslation(translations, message.Movie); BroadcastResourceChange(ModelAction.Updated, message.Movie.ToResource(_qualityUpgradableSpecification, translation)); }