Browse Source

support "backdrop" files as local movie fanart fallback

pull/2804/head
Jason Dove 6 months ago
parent
commit
548b384447
No known key found for this signature in database
  1. 1
      CHANGELOG.md
  2. 54
      ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs
  3. 30
      ErsatzTV.Scanner/Core/Metadata/MovieFolderScanner.cs

1
CHANGELOG.md

@ -32,6 +32,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add chapter `title` to filler expression - Add chapter `title` to filler expression
- This can be used to include or exclude chapters with specific (case-insensitive) titles - This can be used to include or exclude chapters with specific (case-insensitive) titles
- E.g. `title == 'here'`, `title != 'not here'`, `title like '%here%'` - E.g. `title == 'here'`, `title != 'not here'`, `title like '%here%'`
- Local movie libraries: load fanart from `backdrop` files (created by Jellyfin)
### Changed ### Changed
- Disable automatic artwork database cleanup - Disable automatic artwork database cleanup

54
ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs

@ -511,6 +511,60 @@ public class MovieFolderScannerTests
await _imageCache.Received(1).CopyArtworkToCache(fanArtPath, ArtworkKind.FanArt); await _imageCache.Received(1).CopyArtworkToCache(fanArtPath, ArtworkKind.FanArt);
} }
[Test]
public async Task NewMovie_Statistics_And_FallbackMetadata_And_FanArt_Backdrop(
[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 fanArtPath = Path.Combine(
Path.GetDirectoryName(moviePath) ?? string.Empty,
$"backdrop.{imageExtension}");
MovieFolderScanner service = GetService(
new FakeFileEntry(moviePath) { LastWriteTime = DateTime.Now },
new FakeFileEntry(fanArtPath) { LastWriteTime = DateTime.Now }
);
var libraryPath = new LibraryPath
{ Id = 1, Path = FakeRoot, LibraryFolders = new List<LibraryFolder>() };
Either<BaseError, Unit> result = await service.ScanFolder(
libraryPath,
FFmpegPath,
FFprobePath,
0,
1,
CancellationToken.None);
result.IsRight.ShouldBeTrue();
await _movieRepository.Received(1).GetOrAdd(
Arg.Any<LibraryPath>(),
Arg.Any<LibraryFolder>(),
Arg.Any<string>(),
Arg.Any<CancellationToken>());
await _movieRepository.Received(1).GetOrAdd(
libraryPath,
Arg.Any<LibraryFolder>(),
moviePath,
Arg.Any<CancellationToken>());
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
Arg.Is<Movie>(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
Arg.Is<Movie>(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _imageCache.Received(1).CopyArtworkToCache(fanArtPath, ArtworkKind.FanArt);
}
[Test] [Test]
public async Task NewMovie_Statistics_And_FallbackMetadata_And_MovieNameFanArt( public async Task NewMovie_Statistics_And_FallbackMetadata_And_MovieNameFanArt(
[ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.VideoFileExtensions))] [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.VideoFileExtensions))]

30
ErsatzTV.Scanner/Core/Metadata/MovieFolderScanner.cs

@ -381,26 +381,22 @@ public class MovieFolderScanner : LocalFolderScanner, IMovieFolderScanner
private Option<string> LocateArtwork(Movie movie, ArtworkKind artworkKind) private Option<string> LocateArtwork(Movie movie, ArtworkKind artworkKind)
{ {
string segment = artworkKind switch
{
ArtworkKind.Poster => "poster",
ArtworkKind.FanArt => "fanart",
_ => throw new ArgumentOutOfRangeException(nameof(artworkKind))
};
string path = movie.MediaVersions.Head().MediaFiles.Head().Path; string path = movie.MediaVersions.Head().MediaFiles.Head().Path;
string fileName = Path.GetFileNameWithoutExtension(path);
string folder = Path.GetDirectoryName(path) ?? string.Empty; string folder = Path.GetDirectoryName(path) ?? string.Empty;
IEnumerable<string> possibleMoviePosters = ImageFileExtensions.Collect(ext =>
new[] { $"{segment}.{ext}", Path.GetFileNameWithoutExtension(path) + $"-{segment}.{ext}" }) string[] segments = artworkKind switch
.Map(f => Path.Combine(folder, f));
Option<string> result = possibleMoviePosters.Filter(p => _fileSystem.File.Exists(p)).HeadOrNone();
if (result.IsNone && artworkKind == ArtworkKind.Poster)
{ {
IEnumerable<string> possibleFolderPosters = ImageFileExtensions.Collect(ext => new[] { $"folder.{ext}" }) ArtworkKind.Poster => ["poster", $"{fileName}-poster", "folder"],
.Map(f => Path.Combine(folder, f)); ArtworkKind.FanArt => ["fanart", $"{fileName}-fanart", "backdrop"],
result = possibleFolderPosters.Filter(p => _fileSystem.File.Exists(p)).HeadOrNone(); _ => throw new ArgumentOutOfRangeException(nameof(artworkKind))
} };
return result; return ImageFileExtensions
.Map(ext => segments.Map(segment => $"{segment}.{ext}"))
.Flatten()
.Map(f => Path.Combine(folder, f))
.Filter(s => _fileSystem.File.Exists(s))
.HeadOrNone();
} }
} }

Loading…
Cancel
Save