diff --git a/NzbDrone.Core.Test/DiskScanProviderTest_ImportFile.cs b/NzbDrone.Core.Test/DiskScanProviderTest_ImportFile.cs index 3ea583061..848d02ffd 100644 --- a/NzbDrone.Core.Test/DiskScanProviderTest_ImportFile.cs +++ b/NzbDrone.Core.Test/DiskScanProviderTest_ImportFile.cs @@ -80,9 +80,6 @@ namespace NzbDrone.Core.Test VerifyFileImport(result, mocker, fakeEpisode, size); } - - - [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] [TestCase("WEEDS.S03E01.DUAL.SDTV.XviD.AC3.-HELLYWOOD.avi")] public void import_new_file_episode_has_same_or_better_quality_should_skip(string fileName) @@ -116,7 +113,6 @@ namespace NzbDrone.Core.Test VerifySkipImport(result, mocker); } - [Test] public void import_unparsable_file_should_skip() { @@ -215,6 +211,186 @@ namespace NzbDrone.Core.Test VerifySkipImport(result, mocker); } + [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] + [TestCase("WEEDS.S03E01.DUAL.bluray.x264.AC3.-HELLYWOOD.mkv")] + public void import_new_file_episode_has_better_quality_than_existing(string fileName) + { + + //Fakes + var fakeSeries = Builder.CreateNew().Build(); + var fakeEpisode = Builder.CreateNew() + .With(c => c.EpisodeFile = Builder.CreateNew() + .With(e => e.Quality = QualityTypes.SDTV).Build() + ) + .Build(); + + //Mocks + var mocker = new AutoMoqer(); + + mocker.GetMock() + .Setup(e => e.GetSize(fileName)).Returns(12345).Verifiable(); + + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); + + mocker.GetMock() + .Setup(e => e.GetEpisodesByParseResult(It.IsAny(), false)).Returns(new List { fakeEpisode }); + + //Act + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + + //Assert + VerifyFileImport(result, mocker, fakeEpisode, 12345); + mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Once()); + } + + [TestCase("WEEDS.S03E01.DUAL.hdtv.XviD.AC3.-HELLYWOOD.avi")] + [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] + [TestCase("WEEDS.S03E01.DUAL.bluray.x264.AC3.-HELLYWOOD.mkv")] + public void import_new_multi_part_file_episode_has_equal_or_better_quality_than_existing(string fileName) + { + //Fakes + var fakeSeries = Builder.CreateNew().Build(); + + var fakeEpisodes = Builder.CreateListOfSize(2) + .WhereAll() + .Have(e => e.EpisodeFile = Builder.CreateNew() + .With(f => f.Quality = QualityTypes.SDTV) + .Build()) + .Build(); + + //Mocks + var mocker = new AutoMoqer(); + + mocker.GetMock() + .Setup(e => e.GetSize(fileName)).Returns(12345).Verifiable(); + + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); + + mocker.GetMock() + .Setup(e => e.GetEpisodesByParseResult(It.IsAny(), false)).Returns(fakeEpisodes); + + //Act + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + + //Assert + VerifyFileImport(result, mocker, fakeEpisodes[0], 12345); + mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Once()); + } + + [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] + [TestCase("WEEDS.S03E01.DUAL.HDTV.XviD.AC3.-HELLYWOOD.avi")] + public void skip_import_new_multi_part_file_episode_existing_has_better_quality(string fileName) + { + //Fakes + var fakeSeries = Builder.CreateNew().Build(); + + var fakeEpisodes = Builder.CreateListOfSize(2) + .WhereAll() + .Have(e => e.EpisodeFile = Builder.CreateNew() + .With(f => f.Quality = QualityTypes.Bluray720p) + .Build()) + .Build(); + + //Mocks + var mocker = new AutoMoqer(); + + mocker.GetMock() + .Setup(e => e.GetSize(fileName)).Returns(12345).Verifiable(); + + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); + + mocker.GetMock() + .Setup(e => e.GetEpisodesByParseResult(It.IsAny(), false)).Returns(fakeEpisodes); + + //Act + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + + //Assert + VerifySkipImport(result, mocker); + } + + [Test] + public void import_new_multi_part_file_episode_replace_two_files() + { + const string fileName = "WEEDS.S03E01E02.DUAL.bluray.x264.AC3.-HELLYWOOD.mkv"; + + //Fakes + var fakeSeries = Builder.CreateNew().Build(); + + var fakeEpisodeFiles = Builder.CreateListOfSize(2) + .WhereAll() + .Have(e => e.Quality = QualityTypes.SDTV) + .Build(); + + var fakeEpisode1 = Builder.CreateNew() + .With(c => c.EpisodeFile = fakeEpisodeFiles[0]) + .Build(); + + var fakeEpisode2 = Builder.CreateNew() + .With(c => c.EpisodeFile = fakeEpisodeFiles[1]) + .Build(); + + //Mocks + var mocker = new AutoMoqer(); + + mocker.GetMock() + .Setup(e => e.GetSize(fileName)).Returns(12345).Verifiable(); + + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); + + mocker.GetMock() + .Setup(e => e.GetEpisodesByParseResult(It.IsAny(), false)).Returns(new List { fakeEpisode1, fakeEpisode2 }); + + //Act + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + + //Assert + VerifyFileImport(result, mocker, fakeEpisode1, 12345); + mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Exactly(2)); + } + + [Test] + public void import_new_episode_no_existing_episode_file() + { + const string fileName = "WEEDS.S03E01E02.DUAL.bluray.x264.AC3.-HELLYWOOD.mkv"; + + //Fakes + var fakeSeries = Builder.CreateNew().Build(); + + var fakeEpisode = Builder.CreateNew() + .With(e => e.EpisodeFileId = 0) + .With(e => e.EpisodeFile = null) + .Build(); + + //Mocks + var mocker = new AutoMoqer(); + + mocker.GetMock() + .Setup(e => e.GetSize(fileName)).Returns(12345).Verifiable(); + + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); + + mocker.GetMock() + .Setup(e => e.GetEpisodesByParseResult(It.IsAny(), false)).Returns(new List { fakeEpisode}); + + //Act + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + + //Assert + VerifyFileImport(result, mocker, fakeEpisode, 12345); + mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Never()); + } + private static void VerifyFileImport(EpisodeFile result, AutoMoqer mocker, Episode fakeEpisode, int size) { mocker.VerifyAllMocks(); @@ -236,6 +412,7 @@ namespace NzbDrone.Core.Test result.Should().BeNull(); mocker.GetMock().Verify(p => p.Add(It.IsAny()), Times.Never()); mocker.GetMock().Verify(p => p.UpdateEpisode(It.IsAny()), Times.Never()); + mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Never()); } } } diff --git a/NzbDrone.Core/Providers/DiskScanProvider.cs b/NzbDrone.Core/Providers/DiskScanProvider.cs index 49dd9bc8f..31737d3da 100644 --- a/NzbDrone.Core/Providers/DiskScanProvider.cs +++ b/NzbDrone.Core/Providers/DiskScanProvider.cs @@ -82,7 +82,6 @@ namespace NzbDrone.Core.Providers return importedFiles; } - public virtual EpisodeFile ImportFile(Series series, string filePath) { Logger.Trace("Importing file to database [{0}]", filePath); @@ -114,13 +113,22 @@ namespace NzbDrone.Core.Providers if (episodes.Count <= 0) { - Logger.Debug("Can't find any matching episodes in the database. skipping. {0}", filePath); + Logger.Debug("Can't find any matching episodes in the database. Skipping {0}", filePath); return null; } - if (episodes.Any(e => e.EpisodeFile != null && e.EpisodeFile.QualityWrapper > parseResult.Quality)) + //Make sure this file is an upgrade for ALL episodes already on disk + if (episodes.All(e => e.EpisodeFile == null || e.EpisodeFile.QualityWrapper <= parseResult.Quality)) + { + Logger.Debug("Deleting the existing file(s) on disk to upgrade to: {0}", filePath); + //Do the delete for files where there is already an episode on disk + episodes.Where(e => e.EpisodeFile != null).Select(e => e.EpisodeFile.Path).Distinct().ToList().ForEach(p => _diskProvider.DeleteFile(p)); + } + + else { - Logger.Trace("File with better quality is already attached. skipping {0}", filePath); + //Skip this file because its not an upgrade + Logger.Trace("This file isn't an upgrade for all episodes. Skipping {0}", filePath); return null; } diff --git a/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs b/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs index f57e7d2b7..0e10a3bea 100644 --- a/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs +++ b/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs @@ -73,6 +73,12 @@ namespace NzbDrone.Core.Providers.Jobs continue; } + if (subfolderInfo.Name.StartsWith("_NzbDrone_", StringComparison.CurrentCultureIgnoreCase)) + { + Logger.Debug("Folder [{0}] is marked as already processedby NzbDrone. skipping.", subfolder); + continue; + } + //Parse the Folder name var seriesName = Parser.ParseSeriesName(subfolderInfo.Name); var series = _seriesProvider.FindSeries(seriesName); @@ -88,10 +94,13 @@ namespace NzbDrone.Core.Providers.Jobs //Delete the folder only if folder is small enough if (_diskProvider.GetDirectorySize(subfolder) < 10.Megabytes()) - { _diskProvider.DeleteFolder(subfolder, true); - } + + //Otherwise rename the folder to say it was already processed once by NzbDrone so it will not be continually processed + else + _diskProvider.MoveDirectory(subfolderInfo.FullName, Path.Combine(subfolderInfo.Parent.FullName, "_NzbDrone_" + subfolderInfo.Name)); } + catch (Exception e) { Logger.ErrorException("An error has occurred while importing " + subfolder, e); @@ -99,4 +108,4 @@ namespace NzbDrone.Core.Providers.Jobs } } } -} +} \ No newline at end of file