diff --git a/src/NzbDrone.Core/MediaCover/MediaCoverService.cs b/src/NzbDrone.Core/MediaCover/MediaCoverService.cs index 04389e97ab..44453eb36a 100644 --- a/src/NzbDrone.Core/MediaCover/MediaCoverService.cs +++ b/src/NzbDrone.Core/MediaCover/MediaCoverService.cs @@ -21,6 +21,7 @@ public interface IMapCoversToLocal { Dictionary GetCoverFileInfos(); void ConvertToLocalUrls(int movieId, IEnumerable covers, Dictionary fileInfos = null); + void ConvertToLocalUrls(IEnumerable>> items, Dictionary coverFileInfos); string GetCoverPath(int movieId, MediaCoverTypes mediaCoverTypes, int? height = null); } @@ -126,6 +127,14 @@ public void ConvertToLocalUrls(int movieId, IEnumerable covers, Dict } } + public void ConvertToLocalUrls(IEnumerable>> items, Dictionary coverFileInfos) + { + foreach (var movie in items) + { + ConvertToLocalUrls(movie.Item1, movie.Item2, coverFileInfos); + } + } + private string GetMovieCoverPath(int movieId) { return Path.Combine(_coverRootFolder, movieId.ToString()); diff --git a/src/NzbDrone.Core/Movies/MovieRepository.cs b/src/NzbDrone.Core/Movies/MovieRepository.cs index 3e6f4b7eb4..fb55ec8800 100644 --- a/src/NzbDrone.Core/Movies/MovieRepository.cs +++ b/src/NzbDrone.Core/Movies/MovieRepository.cs @@ -37,12 +37,16 @@ public interface IMovieRepository : IBasicRepository public class MovieRepository : BasicRepository, IMovieRepository { private readonly IProfileRepository _profileRepository; + private readonly IAlternativeTitleRepository _alternativeTitleRepository; + public MovieRepository(IMainDatabase database, IProfileRepository profileRepository, + IAlternativeTitleRepository alternativeTitleRepository, IEventAggregator eventAggregator) : base(database, eventAggregator) { _profileRepository = profileRepository; + _alternativeTitleRepository = alternativeTitleRepository; } protected override SqlBuilder Builder() => new SqlBuilder() @@ -88,20 +92,30 @@ protected override List Query(SqlBuilder builder) public override IEnumerable All() { - // the skips the join on profile and populates manually - // to avoid repeatedly deserializing the same profile + // the skips the join on profile and alternative title and populates manually + // to avoid repeatedly deserializing the same profile / movie var builder = new SqlBuilder() - .LeftJoin((m, t) => m.Id == t.MovieId) .LeftJoin((m, f) => m.Id == f.MovieId); - var movieDictionary = new Dictionary(); var profiles = _profileRepository.All().ToDictionary(x => x.Id); + var titles = _alternativeTitleRepository.All() + .GroupBy(x => x.MovieId) + .ToDictionary(x => x.Key, y => y.ToList()); - _ = _database.QueryJoined( + return _database.QueryJoined( builder, - (movie, altTitle, file) => Map(movieDictionary, movie, profiles[movie.ProfileId], altTitle, file)); + (movie, file) => + { + movie.MovieFile = file; + movie.Profile = profiles[movie.ProfileId]; - return movieDictionary.Values.ToList(); + if (titles.TryGetValue(movie.Id, out var altTitles)) + { + movie.AlternativeTitles = altTitles; + } + + return movie; + }); } public bool MoviePathExists(string path) diff --git a/src/Radarr.Api.V3/Movies/MovieModule.cs b/src/Radarr.Api.V3/Movies/MovieModule.cs index 23efbc8752..d8f83b61b5 100644 --- a/src/Radarr.Api.V3/Movies/MovieModule.cs +++ b/src/Radarr.Api.V3/Movies/MovieModule.cs @@ -1,9 +1,11 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using FluentValidation; using Nancy; +using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore.Events; @@ -42,6 +44,7 @@ public class MovieModule : RadarrRestModuleWithSignalR, private readonly IManageCommandQueue _commandQueueManager; private readonly IUpgradableSpecification _qualityUpgradableSpecification; private readonly IConfigService _configService; + private readonly Logger _logger; public MovieModule(IBroadcastSignalRMessage signalRBroadcaster, IMovieService moviesService, @@ -59,7 +62,8 @@ public MovieModule(IBroadcastSignalRMessage signalRBroadcaster, RecycleBinValidator recycleBinValidator, SystemFolderValidator systemFolderValidator, ProfileExistsValidator profileExistsValidator, - MovieFolderAsRootFolderValidator movieFolderAsRootFolderValidator) + MovieFolderAsRootFolderValidator movieFolderAsRootFolderValidator, + Logger logger) : base(signalRBroadcaster) { _moviesService = moviesService; @@ -69,6 +73,7 @@ public MovieModule(IBroadcastSignalRMessage signalRBroadcaster, _configService = configService; _coverMapper = coverMapper; _commandQueueManager = commandQueueManager; + _logger = logger; GetResourceAll = AllMovie; GetResourceById = GetMovie; @@ -122,11 +127,13 @@ private List AllMovie() { var configLanguage = (Language)_configService.MovieInfoLanguage; var availDelay = _configService.AvailabilityDelay; + var movieTask = Task.Run(() => _moviesService.GetAllMovies()); var translations = _movieTranslationService - .GetAllTranslationsForLanguage(configLanguage) - .ToDictionary(x => x.MovieId); + .GetAllTranslationsForLanguage(configLanguage); + + var tdict = translations.ToDictionary(x => x.MovieId); coverFileInfos = _coverMapper.GetCoverFileInfos(); @@ -136,13 +143,13 @@ private List AllMovie() foreach (var movie in movies) { - var translation = GetTranslationFromDict(translations, movie, configLanguage); - var resource = movie.ToResource(availDelay, translation, _qualityUpgradableSpecification); - _coverMapper.ConvertToLocalUrls(resource.Id, resource.Images, coverFileInfos); - moviesResources.Add(resource); + var translation = GetTranslationFromDict(tdict, movie, configLanguage); + moviesResources.Add(movie.ToResource(availDelay, translation, _qualityUpgradableSpecification)); } } + MapCoversToLocal(moviesResources, coverFileInfos); + return moviesResources; } @@ -249,6 +256,11 @@ private void MapCoversToLocal(MovieResource movie) _coverMapper.ConvertToLocalUrls(movie.Id, movie.Images); } + private void MapCoversToLocal(IEnumerable movies, Dictionary coverFileInfos) + { + _coverMapper.ConvertToLocalUrls(movies.Select(x => Tuple.Create(x.Id, x.Images.AsEnumerable())), coverFileInfos); + } + public void Handle(MovieImportedEvent message) { var availDelay = _configService.AvailabilityDelay;