diff --git a/ErsatzTV.Application/Television/Mapper.cs b/ErsatzTV.Application/Television/Mapper.cs index 062b7febe..3cb9745bd 100644 --- a/ErsatzTV.Application/Television/Mapper.cs +++ b/ErsatzTV.Application/Television/Mapper.cs @@ -17,7 +17,8 @@ namespace ErsatzTV.Application.Television show.ShowMetadata.HeadOrNone().Map(GetFanArt).IfNone(string.Empty), show.ShowMetadata.HeadOrNone().Map(m => m.Genres.Map(g => g.Name).ToList()).IfNone(new List()), show.ShowMetadata.HeadOrNone().Map(m => m.Tags.Map(g => g.Name).ToList()).IfNone(new List()), - show.ShowMetadata.HeadOrNone().Map(m => m.Studios.Map(s => s.Name).ToList()).IfNone(new List())); + show.ShowMetadata.HeadOrNone().Map(m => m.Studios.Map(s => s.Name).ToList()) + .IfNone(new List())); internal static TelevisionSeasonViewModel ProjectToViewModel(Season season) => new( diff --git a/ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs b/ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs index b91057218..d4a134092 100644 --- a/ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs +++ b/ErsatzTV.Core.Tests/Metadata/MovieFolderScannerTests.cs @@ -238,6 +238,50 @@ namespace ErsatzTV.Core.Tests.Metadata Times.Once); } + [Test] + public async Task NewMovie_Statistics_And_FallbackMetadata_And_FolderPoster( + [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.VideoFileExtensions))] + string videoExtension, + [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.ImageFileExtensions))] + string imageExtension) + { + string moviePath = Path.Combine( + FakeRoot, + Path.Combine("Movie (2020)", $"Movie (2020){videoExtension}")); + + string posterPath = Path.Combine( + Path.GetDirectoryName(moviePath) ?? string.Empty, + $"folder.{imageExtension}"); + + MovieFolderScanner service = GetService( + new FakeFileEntry(moviePath) { LastWriteTime = DateTime.Now }, + new FakeFileEntry(posterPath) { LastWriteTime = DateTime.Now } + ); + var libraryPath = new LibraryPath { Id = 1, Path = FakeRoot }; + + Either result = await service.ScanFolder(libraryPath, FFprobePath); + + result.IsRight.Should().BeTrue(); + + _movieRepository.Verify(x => x.GetOrAdd(It.IsAny(), It.IsAny()), Times.Once); + _movieRepository.Verify(x => x.GetOrAdd(libraryPath, moviePath), Times.Once); + + _localStatisticsProvider.Verify( + x => x.RefreshStatistics( + FFprobePath, + It.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath)), + Times.Once); + + _localMetadataProvider.Verify( + x => x.RefreshFallbackMetadata( + It.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath)), + Times.Once); + + _imageCache.Verify( + x => x.CopyArtworkToCache(posterPath, ArtworkKind.Poster), + Times.Once); + } + [Test] public async Task NewMovie_Statistics_And_FallbackMetadata_And_MovieNamePoster( [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.VideoFileExtensions))] diff --git a/ErsatzTV.Core/Metadata/MovieFolderScanner.cs b/ErsatzTV.Core/Metadata/MovieFolderScanner.cs index 3058e4792..f3174e00c 100644 --- a/ErsatzTV.Core/Metadata/MovieFolderScanner.cs +++ b/ErsatzTV.Core/Metadata/MovieFolderScanner.cs @@ -210,6 +210,14 @@ namespace ErsatzTV.Core.Metadata ext => new[] { $"{segment}.{ext}", Path.GetFileNameWithoutExtension(path) + $"-{segment}.{ext}" }) .Map(f => Path.Combine(folder, f)); Option result = possibleMoviePosters.Filter(p => _localFileSystem.FileExists(p)).HeadOrNone(); + if (result.IsNone && artworkKind == ArtworkKind.Poster) + { + IEnumerable possibleFolderPosters = ImageFileExtensions.Collect( + ext => new[] { $"folder.{ext}" }) + .Map(f => Path.Combine(folder, f)); + result = possibleFolderPosters.Filter(p => _localFileSystem.FileExists(p)).HeadOrNone(); + } + return result; } } diff --git a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs index dfc32add4..24beabae2 100644 --- a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs +++ b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs @@ -319,15 +319,16 @@ namespace ErsatzTV.Core.Metadata private Option LocateArtworkForShow(string showFolder, ArtworkKind artworkKind) { - string segment = artworkKind switch + string[] segments = artworkKind switch { - ArtworkKind.Poster => "poster", - ArtworkKind.FanArt => "fanart", + ArtworkKind.Poster => new[] { "poster", "folder" }, + ArtworkKind.FanArt => new[] { "fanart" }, _ => throw new ArgumentOutOfRangeException(nameof(artworkKind)) }; return ImageFileExtensions - .Map(ext => $"{segment}.{ext}") + .Map(ext => segments.Map(segment => $"{segment}.{ext}")) + .Flatten() .Map(f => Path.Combine(showFolder, f)) .Filter(s => _localFileSystem.FileExists(s)) .HeadOrNone(); diff --git a/ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs b/ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs index 893871825..200e04547 100644 --- a/ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs +++ b/ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs @@ -131,7 +131,7 @@ namespace ErsatzTV.Core.Plex result.IsUpdated = true; } } - + foreach (Studio studio in existingMetadata.Studios .Filter(s => incomingMetadata.Studios.All(s2 => s2.Name != s.Name)) .ToList()) diff --git a/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs index fe16814f7..c45e215a3 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs @@ -545,7 +545,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories { return BaseError.New("Multi-episode files are not yet supported"); } - + var episode = new Episode { LibraryPathId = libraryPathId, diff --git a/ErsatzTV.Infrastructure/Search/SearchIndex.cs b/ErsatzTV.Infrastructure/Search/SearchIndex.cs index 7cd4a5eb2..3f95e1d0c 100644 --- a/ErsatzTV.Infrastructure/Search/SearchIndex.cs +++ b/ErsatzTV.Infrastructure/Search/SearchIndex.cs @@ -49,7 +49,7 @@ namespace ErsatzTV.Infrastructure.Search private readonly ILogger _logger; private readonly ISearchRepository _searchRepository; - + public SearchIndex( ILocalFileSystem localFileSystem, ISearchRepository searchRepository,