diff --git a/ErsatzTV.Core.Tests/Metadata/TestMediaScannerTests.cs b/ErsatzTV.Core.Tests/Metadata/TestMediaScannerTests.cs index f66992448..f2e05fa58 100644 --- a/ErsatzTV.Core.Tests/Metadata/TestMediaScannerTests.cs +++ b/ErsatzTV.Core.Tests/Metadata/TestMediaScannerTests.cs @@ -12,6 +12,12 @@ namespace ErsatzTV.Core.Tests.Metadata [TestFixture] public class TestMediaScannerTests { + private static readonly List VideoFileExtensions = new() + { + "mpg", "mp2", "mpeg", "mpe", "mpv", "ogg", "mp4", + "m4p", "m4v", "avi", "wmv", "mov", "mkv", "ts" + }; + private static TestMediaScanner ScannerForFiles(IEnumerable fileNames) { var localFileSystem = new FakeLocalFileSystem(fileNames); @@ -30,9 +36,11 @@ namespace ErsatzTV.Core.Tests.Metadata public class NewMovieTests { [Test] - public void WithoutNfo_WithoutPoster() + public void WithoutNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) { - var movieFileName = "/movies/test (2021)/test (2021).mkv"; + var movieFileName = $"/movies/test (2021)/test (2021).{extension}"; string[] fileNames = { movieFileName }; Seq result = ScannerForFiles(fileNames).DetermineActions( @@ -52,10 +60,12 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("test (2021).nfo", "movie.nfo")] string nfoFile) { - var movieFileName = "/movies/test (2021)/test (2021).mkv"; + var movieFileName = $"/movies/test (2021)/test (2021).{extension}"; var nfoFileName = $"/movies/test (2021)/{nfoFile}"; string[] fileNames = { movieFileName, nfoFileName }; @@ -76,12 +86,14 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithoutNfo_WithPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("", "test (2021)-")] string basePosterName, [Values("jpg", "jpeg", "png", "gif", "tbn")] string posterExtension) { - var movieFileName = "/movies/test (2021)/test (2021).mkv"; + var movieFileName = $"/movies/test (2021)/test (2021).{extension}"; var posterFileName = $"/movies/test (2021)/{basePosterName}poster.{posterExtension}"; string[] fileNames = { movieFileName, posterFileName }; @@ -104,6 +116,8 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithNfo_WithPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("test (2021).nfo", "movie.nfo")] string nfoFile, [Values("", "test (2021)-")] @@ -111,7 +125,7 @@ namespace ErsatzTV.Core.Tests.Metadata [Values("jpg", "jpeg", "png", "gif", "tbn")] string posterExtension) { - var movieFileName = "/movies/test (2021)/test (2021).mkv"; + var movieFileName = $"/movies/test (2021)/test (2021).{extension}"; var nfoFileName = $"/movies/test (2021)/{nfoFile}"; var posterFileName = $"/movies/test (2021)/{basePosterName}poster.{posterExtension}"; @@ -139,13 +153,15 @@ namespace ErsatzTV.Core.Tests.Metadata { [Test] public void Fallback_WithNewNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("test (2021).nfo", "movie.nfo")] string nfoFile) { var movieMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/movies/test (2021)/test (2021).mkv" + Path = $"/movies/test (2021)/test (2021).{extension}" }; var nfoFileName = $"/movies/test (2021)/{nfoFile}"; @@ -167,13 +183,15 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void Sidecar_WithOldNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("test (2021).nfo", "movie.nfo")] string nfoFile) { var movieMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Sidecar }, - Path = "/movies/test (2021)/test (2021).mkv" + Path = $"/movies/test (2021)/test (2021).{extension}" }; var nfoFileName = $"/movies/test (2021)/{nfoFile}"; @@ -186,16 +204,18 @@ namespace ErsatzTV.Core.Tests.Metadata result.Count.Should().Be(0); } - + [Test] public void Sidecar_WithUpdatedNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("test (2021).nfo", "movie.nfo")] string nfoFile) { var movieMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Sidecar }, - Path = "/movies/test (2021)/test (2021).mkv" + Path = $"/movies/test (2021)/test (2021).{extension}" }; var nfoFileName = $"/movies/test (2021)/{nfoFile}"; @@ -217,6 +237,8 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithoutNfo_WithNewPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("", "test (2021)-")] string basePosterName, [Values("jpg", "jpeg", "png", "gif", "tbn")] @@ -225,7 +247,7 @@ namespace ErsatzTV.Core.Tests.Metadata var movieMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/movies/test (2021)/test (2021).mkv" + Path = $"/movies/test (2021)/test (2021).{extension}" }; var posterFileName = $"/movies/test (2021)/{basePosterName}poster.{posterExtension}"; @@ -243,9 +265,11 @@ namespace ErsatzTV.Core.Tests.Metadata itemScanningPlans.Should() .BeEquivalentTo(new ItemScanningPlan(posterFileName, ScanningAction.Poster)); } - + [Test] public void WithoutNfo_WithOldPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("", "test (2021)-")] string basePosterName, [Values("jpg", "jpeg", "png", "gif", "tbn")] @@ -254,7 +278,7 @@ namespace ErsatzTV.Core.Tests.Metadata var movieMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/movies/test (2021)/test (2021).mkv", + Path = $"/movies/test (2021)/test (2021).{extension}", Poster = "anything", PosterLastWriteTime = DateTime.UtcNow }; @@ -269,9 +293,11 @@ namespace ErsatzTV.Core.Tests.Metadata result.Count.Should().Be(0); } - + [Test] public void WithoutNfo_WithUpdatedPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("", "test (2021)-")] string basePosterName, [Values("jpg", "jpeg", "png", "gif", "tbn")] @@ -280,7 +306,7 @@ namespace ErsatzTV.Core.Tests.Metadata var movieMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/movies/test (2021)/test (2021).mkv", + Path = $"/movies/test (2021)/test (2021).{extension}", Poster = "anything", PosterLastWriteTime = DateTime.UtcNow }; @@ -303,6 +329,8 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithNewNfo_WithNewPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("test (2021).nfo", "movie.nfo")] string nfoFile, [Values("", "test (2021)-")] @@ -313,7 +341,7 @@ namespace ErsatzTV.Core.Tests.Metadata var movieMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/movies/test (2021)/test (2021).mkv" + Path = $"/movies/test (2021)/test (2021).{extension}" }; var nfoFileName = $"/movies/test (2021)/{nfoFile}"; @@ -340,9 +368,11 @@ namespace ErsatzTV.Core.Tests.Metadata public class NewEpisodeTests { [Test] - public void WithoutNfo_WithoutPoster() + public void WithoutNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) { - var episodeFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv"; + var episodeFileName = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}"; string[] fileNames = { episodeFileName }; Seq result = ScannerForFiles(fileNames).DetermineActions( @@ -361,9 +391,11 @@ namespace ErsatzTV.Core.Tests.Metadata } [Test] - public void WithNfo_WithoutPoster() + public void WithNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) { - var episodeFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv"; + var episodeFileName = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}"; var nfoFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.nfo"; string[] fileNames = { episodeFileName, nfoFileName }; @@ -384,10 +416,12 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithoutNfo_WithPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("jpg", "jpeg", "png", "gif", "tbn")] string posterExtension) { - var episodeFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv"; + var episodeFileName = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}"; var posterFileName = $"/tv/test (2021)/poster.{posterExtension}"; string[] fileNames = { episodeFileName, posterFileName }; @@ -410,10 +444,12 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithNfo_WithPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("jpg", "jpeg", "png", "gif", "tbn")] string posterExtension) { - var episodeFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv"; + var episodeFileName = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}"; var nfoFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.nfo"; var posterFileName = $"/tv/test (2021)/poster.{posterExtension}"; @@ -440,12 +476,14 @@ namespace ErsatzTV.Core.Tests.Metadata public class ExistingEpisodeTests { [Test] - public void Fallback_WithNewNfo_WithoutPoster() + public void Fallback_WithNewNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) { var episodeMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv" + Path = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}" }; var nfoFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.nfo"; @@ -464,14 +502,16 @@ namespace ErsatzTV.Core.Tests.Metadata new ItemScanningPlan(nfoFileName, ScanningAction.SidecarMetadata), new ItemScanningPlan(episodeMediaItem.Path, ScanningAction.Collections)); } - + [Test] - public void Sidecar_WithOldNfo_WithoutPoster() + public void Sidecar_WithOldNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) { var episodeMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Sidecar }, - Path = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv" + Path = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}" }; var nfoFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.nfo"; @@ -484,14 +524,16 @@ namespace ErsatzTV.Core.Tests.Metadata result.Count.Should().Be(0); } - + [Test] - public void Sidecar_WithUpdatedNfo_WithoutPoster() + public void Sidecar_WithUpdatedNfo_WithoutPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) { var episodeMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Sidecar }, - Path = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv" + Path = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}" }; var nfoFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.nfo"; @@ -513,13 +555,15 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithoutNfo_WithNewPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("jpg", "jpeg", "png", "gif", "tbn")] string posterExtension) { var episodeMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv" + Path = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}" }; var posterFileName = $"/tv/test (2021)/poster.{posterExtension}"; @@ -537,16 +581,18 @@ namespace ErsatzTV.Core.Tests.Metadata itemScanningPlans.Should() .BeEquivalentTo(new ItemScanningPlan(posterFileName, ScanningAction.Poster)); } - + [Test] public void WithoutNfo_WithOldPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("jpg", "jpeg", "png", "gif", "tbn")] string posterExtension) { var episodeMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv", + Path = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}", Poster = "anything", PosterLastWriteTime = DateTime.UtcNow }; @@ -561,16 +607,18 @@ namespace ErsatzTV.Core.Tests.Metadata result.Count.Should().Be(0); } - + [Test] public void WithoutNfo_WithUpdatedPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("jpg", "jpeg", "png", "gif", "tbn")] string posterExtension) { var episodeMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv", + Path = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}", Poster = "anything", PosterLastWriteTime = DateTime.UtcNow }; @@ -593,13 +641,15 @@ namespace ErsatzTV.Core.Tests.Metadata [Test] public void WithNewNfo_WithNewPoster( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension, [Values("jpg", "jpeg", "png", "gif", "tbn")] string posterExtension) { var episodeMediaItem = new MediaItem { Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, - Path = "/tv/test (2021)/season 01/test (2021) - s01e03.mkv" + Path = $"/tv/test (2021)/season 01/test (2021) - s01e03.{extension}" }; var nfoFileName = "/tv/test (2021)/season 01/test (2021) - s01e03.nfo"; @@ -623,17 +673,21 @@ namespace ErsatzTV.Core.Tests.Metadata } [Test] - [TestCase("/movies/test (2021)/Behind The Scenes/test (2021).mkv")] - [TestCase("/movies/test (2021)/Deleted Scenes/test (2021).mkv")] - [TestCase("/movies/test (2021)/Featurettes/test (2021).mkv")] - [TestCase("/movies/test (2021)/Interviews/test (2021).mkv")] - [TestCase("/movies/test (2021)/Scenes/test (2021).mkv")] - [TestCase("/movies/test (2021)/Shorts/test (2021).mkv")] - [TestCase("/movies/test (2021)/Trailers/test (2021).mkv")] - [TestCase("/movies/test (2021)/Other/test (2021).mkv")] - public void Movies_Should_Ignore_ExtraFolders(string fileName) + + public void Movies_Should_Ignore_ExtraFolders( + [Values("/movies/test (2021)/Behind The Scenes/test (2021)", + "/movies/test (2021)/Deleted Scenes/test (2021)", + "/movies/test (2021)/Featurettes/test (2021)", + "/movies/test (2021)/Interviews/test (2021)", + "/movies/test (2021)/Scenes/test (2021)", + "/movies/test (2021)/Shorts/test (2021)", + "/movies/test (2021)/Trailers/test (2021)", + "/movies/test (2021)/Other/test (2021)")] + string baseFileName, + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) { - string[] fileNames = { fileName }; + string[] fileNames = { $"{baseFileName}.{extension}" }; Seq result = ScannerForFiles(fileNames).DetermineActions( MediaType.Movie, @@ -642,19 +696,23 @@ namespace ErsatzTV.Core.Tests.Metadata result.Count.Should().Be(0); } - + [Test] - [TestCase("/movies/test (2021)/test (2021)-behindthescenes.mkv")] - [TestCase("/movies/test (2021)/test (2021)-deleted.mkv")] - [TestCase("/movies/test (2021)/test (2021)-featurette.mkv")] - [TestCase("/movies/test (2021)/test (2021)-interview.mkv")] - [TestCase("/movies/test (2021)/test (2021)-scene.mkv")] - [TestCase("/movies/test (2021)/test (2021)-short.mkv")] - [TestCase("/movies/test (2021)/test (2021)-trailer.mkv")] - [TestCase("/movies/test (2021)/test (2021)-other.mkv")] - public void Movies_Should_Ignore_ExtraFiles(string fileName) + public void Movies_Should_Ignore_ExtraFiles( + [Values( + "/movies/test (2021)/test (2021)-behindthescenes", + "/movies/test (2021)/test (2021)-deleted", + "/movies/test (2021)/test (2021)-featurette", + "/movies/test (2021)/test (2021)-interview", + "/movies/test (2021)/test (2021)-scene", + "/movies/test (2021)/test (2021)-short", + "/movies/test (2021)/test (2021)-trailer", + "/movies/test (2021)/test (2021)-other")] + string baseFileName, + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) { - string[] fileNames = { fileName }; + string[] fileNames = { $"{baseFileName}.{extension}" }; Seq result = ScannerForFiles(fileNames).DetermineActions( MediaType.Movie, @@ -664,6 +722,88 @@ namespace ErsatzTV.Core.Tests.Metadata result.Count.Should().Be(0); } + [Test] + // [TestCase( + // "/tv/test (2022)/season 03/test (2022) - s03e01.mkv", + // "/tv/test (2022)/season 03/test (2022) - s03e02.mkv", + // MediaType.TvShow)] + public void Movies_Should_Remove_Missing_MediaItems( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) + { + var movieMediaItem = new MediaItem + { + Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, + Path = $"/movies/test (2021)/test (2021).{extension}" + }; + + var movieMediaItem2 = new MediaItem + { + Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, + Path = $"/movies/test (2022)/test (2022).{extension}" + }; + + string[] fileNames = { "anything" }; + + Seq result = ScannerForFiles(fileNames).DetermineActions( + MediaType.Movie, + Seq.create(movieMediaItem, movieMediaItem2), + fileNames.ToSeq()); + + result.Count.Should().Be(2); + + (Either source1, List itemScanningPlans1) = result.Head(); + source1.IsRight.Should().BeTrue(); + source1.RightToSeq().Should().BeEquivalentTo(movieMediaItem); + itemScanningPlans1.Should().BeEquivalentTo( + new ItemScanningPlan(movieMediaItem.Path, ScanningAction.Remove)); + + (Either source2, List itemScanningPlans2) = result.Last(); + source2.IsRight.Should().BeTrue(); + source2.RightToSeq().Should().BeEquivalentTo(movieMediaItem2); + itemScanningPlans2.Should().BeEquivalentTo( + new ItemScanningPlan(movieMediaItem2.Path, ScanningAction.Remove)); + } + + [Test] + public void Episodes_Should_Remove_Missing_MediaItems( + [ValueSource(typeof(TestMediaScannerTests), nameof(VideoFileExtensions))] + string extension) + { + var movieMediaItem = new MediaItem + { + Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, + Path = $"/tv/test (2022)/season 03/test (2022) - s03e01.{extension}" + }; + + var movieMediaItem2 = new MediaItem + { + Metadata = new MediaMetadata { Source = MetadataSource.Fallback }, + Path = $"/tv/test (2022)/season 03/test (2022) - s03e02.{extension}" + }; + + string[] fileNames = { "anything" }; + + Seq result = ScannerForFiles(fileNames).DetermineActions( + MediaType.TvShow, + Seq.create(movieMediaItem, movieMediaItem2), + fileNames.ToSeq()); + + result.Count.Should().Be(2); + + (Either source1, List itemScanningPlans1) = result.Head(); + source1.IsRight.Should().BeTrue(); + source1.RightToSeq().Should().BeEquivalentTo(movieMediaItem); + itemScanningPlans1.Should().BeEquivalentTo( + new ItemScanningPlan(movieMediaItem.Path, ScanningAction.Remove)); + + (Either source2, List itemScanningPlans2) = result.Last(); + source2.IsRight.Should().BeTrue(); + source2.RightToSeq().Should().BeEquivalentTo(movieMediaItem2); + itemScanningPlans2.Should().BeEquivalentTo( + new ItemScanningPlan(movieMediaItem2.Path, ScanningAction.Remove)); + } + private class FakeLocalFileSystem : ILocalFileSystem { private readonly Dictionary _files = new(); diff --git a/ErsatzTV.Core/Metadata/ScanningAction.cs b/ErsatzTV.Core/Metadata/ScanningAction.cs index cbb297a06..cbfca37b1 100644 --- a/ErsatzTV.Core/Metadata/ScanningAction.cs +++ b/ErsatzTV.Core/Metadata/ScanningAction.cs @@ -7,6 +7,7 @@ SidecarMetadata = 2, FallbackMetadata = 3, Collections = 4, - Poster = 5 + Poster = 5, + Remove = 6 } } diff --git a/ErsatzTV.Core/Metadata/TestMediaScanner.cs b/ErsatzTV.Core/Metadata/TestMediaScanner.cs index 3e6521613..98246a543 100644 --- a/ErsatzTV.Core/Metadata/TestMediaScanner.cs +++ b/ErsatzTV.Core/Metadata/TestMediaScanner.cs @@ -73,7 +73,13 @@ namespace ErsatzTV.Core.Metadata } }); } - + + // missing media items + foreach (MediaItem mediaItem in mediaItems.Where(i => !files.Contains(i.Path))) + { + results.Add(mediaItem, new ItemScanningPlan(mediaItem.Path, ScanningAction.Remove)); + } + return results.Summarize(); }