diff --git a/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs b/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs index de478235e..e4fdef50f 100644 --- a/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs +++ b/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs @@ -12,13 +12,13 @@ namespace NzbDrone.Api.Config MappedNetworkDriveValidator mappedNetworkDriveValidator) : base(configService) { - SharedValidator.RuleFor(c => c.DownloadedEpisodesFolder) + SharedValidator.RuleFor(c => c.DownloadedMoviesFolder) .Cascade(CascadeMode.StopOnFirstFailure) .IsValidPath() .SetValidator(rootFolderValidator) .SetValidator(mappedNetworkDriveValidator) .SetValidator(pathExistsValidator) - .When(c => !string.IsNullOrWhiteSpace(c.DownloadedEpisodesFolder)); + .When(c => !string.IsNullOrWhiteSpace(c.DownloadedMoviesFolder)); } protected override DownloadClientConfigResource ToResource(IConfigService model) diff --git a/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs b/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs index 8309c9f4d..b34febd7b 100644 --- a/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs +++ b/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs @@ -5,9 +5,9 @@ namespace NzbDrone.Api.Config { public class DownloadClientConfigResource : RestResource { - public string DownloadedEpisodesFolder { get; set; } + public string DownloadedMoviesFolder { get; set; } public string DownloadClientWorkingFolders { get; set; } - public int DownloadedEpisodesScanInterval { get; set; } + public int DownloadedMoviesScanInterval { get; set; } public bool EnableCompletedDownloadHandling { get; set; } public bool RemoveCompletedDownloads { get; set; } @@ -22,9 +22,9 @@ namespace NzbDrone.Api.Config { return new DownloadClientConfigResource { - DownloadedEpisodesFolder = model.DownloadedEpisodesFolder, + DownloadedMoviesFolder = model.DownloadedMoviesFolder, DownloadClientWorkingFolders = model.DownloadClientWorkingFolders, - DownloadedEpisodesScanInterval = model.DownloadedEpisodesScanInterval, + DownloadedMoviesScanInterval = model.DownloadedMoviesScanInterval, EnableCompletedDownloadHandling = model.EnableCompletedDownloadHandling, RemoveCompletedDownloads = model.RemoveCompletedDownloads, diff --git a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs index 8d39e68b3..618f276de 100644 --- a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs @@ -154,7 +154,7 @@ namespace NzbDrone.Core.Test.Download public void should_not_process_if_storage_directory_in_drone_factory() { Mocker.GetMock() - .SetupGet(v => v.DownloadedEpisodesFolder) + .SetupGet(v => v.DownloadedMoviesFolder) .Returns(@"C:\DropFolder".AsOsAgnostic()); _trackedDownload.DownloadItem.OutputPath = new OsPath(@"C:\DropFolder\SomeOtherFolder".AsOsAgnostic()); @@ -372,8 +372,8 @@ namespace NzbDrone.Core.Test.Download private void AssertNoAttemptedImport() { - Mocker.GetMock() - .Verify(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); + Mocker.GetMock() + .Verify(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); AssertNoCompletedDownload(); } diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/PneumaticProviderFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/PneumaticProviderFixture.cs index a10c88ee3..158116e36 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/PneumaticProviderFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/PneumaticProviderFixture.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Net; using Moq; @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests _nzbPath = Path.Combine(_pneumaticFolder, _title + ".nzb").AsOsAgnostic(); _sabDrop = @"d:\unsorted tv\".AsOsAgnostic(); - Mocker.GetMock().SetupGet(c => c.DownloadedEpisodesFolder).Returns(_sabDrop); + Mocker.GetMock().SetupGet(c => c.DownloadedMoviesFolder).Returns(_sabDrop); _remoteMovie = new RemoteMovie(); _remoteMovie.Release = new ReleaseInfo(); diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/DroneFactoryCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/DroneFactoryCheckFixture.cs index fbde84eb4..23781a09e 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/DroneFactoryCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/DroneFactoryCheckFixture.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks private void GivenDroneFactoryFolder(bool exists = false, bool writable = true) { Mocker.GetMock() - .SetupGet(s => s.DownloadedEpisodesFolder) + .SetupGet(s => s.DownloadedMoviesFolder) .Returns(DRONE_FACTORY_FOLDER); Mocker.GetMock() diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/ImportMechanismCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/ImportMechanismCheckFixture.cs index 5f0f3d9a0..7030d1096 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/ImportMechanismCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/ImportMechanismCheckFixture.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks private void GivenDroneFactoryFolder(bool exists = false) { Mocker.GetMock() - .SetupGet(s => s.DownloadedEpisodesFolder) + .SetupGet(s => s.DownloadedMoviesFolder) .Returns(DRONE_FACTORY_FOLDER.AsOsAgnostic()); Mocker.GetMock() diff --git a/src/NzbDrone.Core.Test/MediaFiles/DownloadedMoviesCommandServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DownloadedMoviesCommandServiceFixture.cs new file mode 100644 index 000000000..21919839c --- /dev/null +++ b/src/NzbDrone.Core.Test/MediaFiles/DownloadedMoviesCommandServiceFixture.cs @@ -0,0 +1,172 @@ +using System.Collections.Generic; +using System.IO; +using FizzWare.NBuilder; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Download; +using NzbDrone.Core.Download.TrackedDownloads; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.MediaFiles.Commands; +using NzbDrone.Core.MediaFiles.EpisodeImport; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.MediaFiles +{ + [TestFixture] + public class DownloadedMoviesCommandServiceFixture : CoreTest + { + private string _droneFactory = "c:\\drop\\".AsOsAgnostic(); + private string _downloadFolder = "c:\\drop_other\\Show.S01E01\\".AsOsAgnostic(); + private string _downloadFile = "c:\\drop_other\\Show.S01E01.mkv".AsOsAgnostic(); + + private TrackedDownload _trackedDownload; + + [SetUp] + public void Setup() + { + Mocker.GetMock().SetupGet(c => c.DownloadedMoviesFolder) + .Returns(_droneFactory); + + Mocker.GetMock() + .Setup(v => v.ProcessRootFolder(It.IsAny())) + .Returns(new List()); + + Mocker.GetMock() + .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(new List()); + + var downloadItem = Builder.CreateNew() + .With(v => v.DownloadId = "sab1") + .With(v => v.Status = DownloadItemStatus.Downloading) + .Build(); + + var remoteMovie = Builder.CreateNew() + .With(v => v.Movie = new Movie()) + .Build(); + + _trackedDownload = new TrackedDownload + { + DownloadItem = downloadItem, + RemoteMovie = remoteMovie, + State = TrackedDownloadStage.Downloading + }; + } + + private void GivenExistingFolder(string path) + { + Mocker.GetMock().Setup(c => c.FolderExists(It.IsAny())) + .Returns(true); + } + + private void GivenExistingFile(string path) + { + Mocker.GetMock().Setup(c => c.FileExists(It.IsAny())) + .Returns(true); + } + + private void GivenValidQueueItem() + { + Mocker.GetMock() + .Setup(s => s.Find("sab1")) + .Returns(_trackedDownload); + } + + [Test] + public void should_process_dronefactory_if_path_is_not_specified() + { + GivenExistingFolder(_droneFactory); + + Subject.Execute(new DownloadedMoviesScanCommand()); + + Mocker.GetMock().Verify(c => c.ProcessRootFolder(It.IsAny()), Times.Once()); + } + + [Test] + public void should_skip_import_if_dronefactory_doesnt_exist() + { + Subject.Execute(new DownloadedMoviesScanCommand()); + + Mocker.GetMock().Verify(c => c.ProcessRootFolder(It.IsAny()), Times.Never()); + + ExceptionVerification.ExpectedWarns(1); + } + + [Test] + public void should_ignore_downloadclientid_if_path_is_not_specified() + { + GivenExistingFolder(_droneFactory); + + Subject.Execute(new DownloadedMoviesScanCommand() { DownloadClientId = "sab1" }); + + Mocker.GetMock().Verify(c => c.ProcessRootFolder(It.IsAny()), Times.Once()); + } + + [Test] + public void should_process_folder_if_downloadclientid_is_not_specified() + { + GivenExistingFolder(_downloadFolder); + + Subject.Execute(new DownloadedMoviesScanCommand() { Path = _downloadFolder }); + + Mocker.GetMock().Verify(c => c.ProcessPath(It.IsAny(), ImportMode.Auto, null, null), Times.Once()); + } + + [Test] + public void should_process_file_if_downloadclientid_is_not_specified() + { + GivenExistingFile(_downloadFile); + + Subject.Execute(new DownloadedMoviesScanCommand() { Path = _downloadFile }); + + Mocker.GetMock().Verify(c => c.ProcessPath(It.IsAny(), ImportMode.Auto, null, null), Times.Once()); + } + + [Test] + public void should_process_folder_with_downloadclientitem_if_available() + { + GivenExistingFolder(_downloadFolder); + GivenValidQueueItem(); + + Subject.Execute(new DownloadedMoviesScanCommand() { Path = _downloadFolder, DownloadClientId = "sab1" }); + + Mocker.GetMock().Verify(c => c.ProcessPath(_downloadFolder, ImportMode.Auto, _trackedDownload.RemoteMovie.Movie, _trackedDownload.DownloadItem), Times.Once()); + } + + [Test] + public void should_process_folder_without_downloadclientitem_if_not_available() + { + GivenExistingFolder(_downloadFolder); + + Subject.Execute(new DownloadedMoviesScanCommand() { Path = _downloadFolder, DownloadClientId = "sab1" }); + + Mocker.GetMock().Verify(c => c.ProcessPath(_downloadFolder, ImportMode.Auto, null, null), Times.Once()); + + ExceptionVerification.ExpectedWarns(1); + } + + [Test] + public void should_warn_if_neither_folder_or_file_exists() + { + Subject.Execute(new DownloadedMoviesScanCommand() { Path = _downloadFolder }); + + Mocker.GetMock().Verify(c => c.ProcessPath(It.IsAny(), ImportMode.Auto, null, null), Times.Never()); + + ExceptionVerification.ExpectedWarns(1); + } + + [Test] + public void should_override_import_mode() + { + GivenExistingFile(_downloadFile); + + Subject.Execute(new DownloadedMoviesScanCommand() { Path = _downloadFile, ImportMode = ImportMode.Copy }); + + Mocker.GetMock().Verify(c => c.ProcessPath(It.IsAny(), ImportMode.Copy, null, null), Times.Once()); + } + } +} diff --git a/src/NzbDrone.Core.Test/MediaFiles/DownloadedMoviesImportServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DownloadedMoviesImportServiceFixture.cs new file mode 100644 index 000000000..75c3a641b --- /dev/null +++ b/src/NzbDrone.Core.Test/MediaFiles/DownloadedMoviesImportServiceFixture.cs @@ -0,0 +1,377 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using FizzWare.NBuilder; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.MediaFiles.EpisodeImport; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; +using NzbDrone.Test.Common; +using FluentAssertions; + +namespace NzbDrone.Core.Test.MediaFiles +{ + [TestFixture] + public class DownloadedMoviesImportServiceFixture : CoreTest + { + private string _droneFactory = "c:\\drop\\".AsOsAgnostic(); + private string[] _subFolders = new[] { "c:\\root\\foldername".AsOsAgnostic() }; + private string[] _videoFiles = new[] { "c:\\root\\foldername\\47.ronin.2013.ext".AsOsAgnostic() }; + + [SetUp] + public void Setup() + { + Mocker.GetMock().Setup(c => c.GetVideoFiles(It.IsAny(), It.IsAny())) + .Returns(_videoFiles); + + Mocker.GetMock().Setup(c => c.GetDirectories(It.IsAny())) + .Returns(_subFolders); + + Mocker.GetMock().Setup(c => c.FolderExists(It.IsAny())) + .Returns(true); + + Mocker.GetMock() + .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto)) + .Returns(new List()); + } + + private void GivenValidMovie() + { + Mocker.GetMock() + .Setup(s => s.GetMovie(It.IsAny())) + .Returns(Builder.CreateNew().Build()); + } + + [Test] + public void should_search_for_series_using_folder_name() + { + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock().Verify(c => c.GetMovie("foldername"), Times.Once()); + } + + [Test] + public void should_skip_if_file_is_in_use_by_another_process() + { + GivenValidMovie(); + + Mocker.GetMock().Setup(c => c.IsFileLocked(It.IsAny())) + .Returns(true); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + VerifyNoImport(); + } + + [Test] + public void should_skip_if_no_series_found() + { + Mocker.GetMock().Setup(c => c.GetMovie("foldername")).Returns((Movie)null); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock() + .Verify(c => c.GetImportDecisions(It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny()), + Times.Never()); + + VerifyNoImport(); + } + + [Test] + public void should_not_import_if_folder_is_a_series_path() + { + GivenValidMovie(); + + Mocker.GetMock() + .Setup(s => s.MoviePathExists(It.IsAny())) + .Returns(true); + + Mocker.GetMock() + .Setup(c => c.GetVideoFiles(It.IsAny(), It.IsAny())) + .Returns(new string[0]); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock() + .Verify(v => v.GetVideoFiles(It.IsAny(), true), Times.Never()); + + ExceptionVerification.ExpectedWarns(1); + } + + [Test] + public void should_not_delete_folder_if_no_files_were_imported() + { + Mocker.GetMock() + .Setup(s => s.Import(It.IsAny>(), false, null, ImportMode.Auto)) + .Returns(new List()); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock() + .Verify(v => v.GetFolderSize(It.IsAny()), Times.Never()); + } + + [Test] + public void should_not_delete_folder_if_files_were_imported_and_video_files_remain() + { + GivenValidMovie(); + + var localMovie = new LocalMovie(); + + var imported = new List(); + imported.Add(new ImportDecision(localMovie)); + + Mocker.GetMock() + .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true)) + .Returns(imported); + + Mocker.GetMock() + .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto)) + .Returns(imported.Select(i => new ImportResult(i)).ToList()); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock() + .Verify(v => v.DeleteFolder(It.IsAny(), true), Times.Never()); + + ExceptionVerification.ExpectedWarns(1); + } + + [Test] + public void should_delete_folder_if_files_were_imported_and_only_sample_files_remain() + { + GivenValidMovie(); + + var localMovie = new LocalMovie(); + + var imported = new List(); + imported.Add(new ImportDecision(localMovie)); + + Mocker.GetMock() + .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true)) + .Returns(imported); + + Mocker.GetMock() + .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto)) + .Returns(imported.Select(i => new ImportResult(i)).ToList()); + + Mocker.GetMock() + .Setup(s => s.IsSample(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(true); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock() + .Verify(v => v.DeleteFolder(It.IsAny(), true), Times.Once()); + } + + [TestCase("_UNPACK_")] + [TestCase("_FAILED_")] + public void should_remove_unpack_from_folder_name(string prefix) + { + var folderName = "47.ronin.2013.hdtv-lol"; + var folders = new[] { string.Format(@"C:\Test\Unsorted\{0}{1}", prefix, folderName).AsOsAgnostic() }; + + Mocker.GetMock() + .Setup(c => c.GetDirectories(It.IsAny())) + .Returns(folders); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock() + .Verify(v => v.GetMovie(folderName), Times.Once()); + + Mocker.GetMock() + .Verify(v => v.GetMovie(It.Is(s => s.StartsWith(prefix))), Times.Never()); + } + + [Test] + public void should_return_importresult_on_unknown_movie() + { + Mocker.GetMock().Setup(c => c.FolderExists(It.IsAny())) + .Returns(false); + + Mocker.GetMock().Setup(c => c.FileExists(It.IsAny())) + .Returns(true); + + var fileName = @"C:\folder\file.mkv".AsOsAgnostic(); + + var result = Subject.ProcessPath(fileName); + + result.Should().HaveCount(1); + result.First().ImportDecision.Should().NotBeNull(); + result.First().ImportDecision.LocalMovie.Should().NotBeNull(); + result.First().ImportDecision.LocalMovie.Path.Should().Be(fileName); + result.First().Result.Should().Be(ImportResultType.Rejected); + } + + [Test] + public void should_not_delete_if_there_is_large_rar_file() + { + GivenValidMovie(); + + var localMovie = new LocalMovie(); + + var imported = new List(); + imported.Add(new ImportDecision(localMovie)); + + Mocker.GetMock() + .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true)) + .Returns(imported); + + Mocker.GetMock() + .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto)) + .Returns(imported.Select(i => new ImportResult(i)).ToList()); + + Mocker.GetMock() + .Setup(s => s.IsSample(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(true); + + Mocker.GetMock() + .Setup(s => s.GetFiles(It.IsAny(), SearchOption.AllDirectories)) + .Returns(new[] { _videoFiles.First().Replace(".ext", ".rar") }); + + Mocker.GetMock() + .Setup(s => s.GetFileSize(It.IsAny())) + .Returns(15.Megabytes()); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock() + .Verify(v => v.DeleteFolder(It.IsAny(), true), Times.Never()); + + ExceptionVerification.ExpectedWarns(1); + } + + [Test] + public void should_use_folder_if_folder_import() + { + GivenValidMovie(); + + var folderName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] American Psycho (2000) [720p]".AsOsAgnostic(); + var fileName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] American Psycho (2000) [720p]\[HorribleSubs] American Psycho (2000) [720p].mkv".AsOsAgnostic(); + + Mocker.GetMock().Setup(c => c.FolderExists(folderName)) + .Returns(true); + + Mocker.GetMock().Setup(c => c.GetFiles(folderName, SearchOption.TopDirectoryOnly)) + .Returns(new[] { fileName }); + + var localMovie = new LocalMovie(); + + var imported = new List(); + imported.Add(new ImportDecision(localMovie)); + + + Subject.ProcessPath(fileName); + + Mocker.GetMock() + .Verify(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), It.IsAny(), true, false), Times.Once()); + } + + [Test] + public void should_not_use_folder_if_file_import() + { + GivenValidMovie(); + + var fileName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\Torrents\[HorribleSubs] 47 Ronin (2013) [720p].mkv".AsOsAgnostic(); + + Mocker.GetMock().Setup(c => c.FolderExists(fileName)) + .Returns(false); + + Mocker.GetMock().Setup(c => c.FileExists(fileName)) + .Returns(true); + + var localMovie = new LocalMovie(); + + var imported = new List(); + imported.Add(new ImportDecision(localMovie)); + + var result = Subject.ProcessPath(fileName); + + Mocker.GetMock() + .Verify(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true, false), Times.Once()); + } + + [Test] + public void should_not_process_if_file_and_folder_do_not_exist() + { + var folderName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] 47 Ronin (2013) [720p]".AsOsAgnostic(); + + Mocker.GetMock().Setup(c => c.FolderExists(folderName)) + .Returns(false); + + Mocker.GetMock().Setup(c => c.FileExists(folderName)) + .Returns(false); + + Subject.ProcessPath(folderName).Should().BeEmpty(); + + Mocker.GetMock() + .Verify(v => v.GetMovie(It.IsAny()), Times.Never()); + + ExceptionVerification.ExpectedErrors(1); + } + + [Test] + public void should_not_delete_if_no_files_were_imported() + { + GivenValidMovie(); + + var localMovie = new LocalMovie(); + + var imported = new List(); + imported.Add(new ImportDecision(localMovie)); + + Mocker.GetMock() + .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true)) + .Returns(imported); + + Mocker.GetMock() + .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto)) + .Returns(new List()); + + Mocker.GetMock() + .Setup(s => s.IsSample(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(true); + + Mocker.GetMock() + .Setup(s => s.GetFileSize(It.IsAny())) + .Returns(15.Megabytes()); + + Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory)); + + Mocker.GetMock() + .Verify(v => v.DeleteFolder(It.IsAny(), true), Times.Never()); + } + + private void VerifyNoImport() + { + Mocker.GetMock().Verify(c => c.Import(It.IsAny>(), true, null, ImportMode.Auto), + Times.Never()); + } + + private void VerifyImport() + { + Mocker.GetMock().Verify(c => c.Import(It.IsAny>(), true, null, ImportMode.Auto), + Times.Once()); + } + } +} diff --git a/src/NzbDrone.Core.Test/Messaging/Commands/CommandEqualityComparerFixture.cs b/src/NzbDrone.Core.Test/Messaging/Commands/CommandEqualityComparerFixture.cs index 8154c7a24..c15e2cfd4 100644 --- a/src/NzbDrone.Core.Test/Messaging/Commands/CommandEqualityComparerFixture.cs +++ b/src/NzbDrone.Core.Test/Messaging/Commands/CommandEqualityComparerFixture.cs @@ -15,8 +15,8 @@ namespace NzbDrone.Core.Test.Messaging.Commands [Test] public void should_return_true_when_there_are_no_properties() { - var command1 = new DownloadedEpisodesScanCommand(); - var command2 = new DownloadedEpisodesScanCommand(); + var command1 = new DownloadedMoviesScanCommand(); + var command2 = new DownloadedMoviesScanCommand(); CommandEqualityComparer.Instance.Equals(command1, command2).Should().BeTrue(); } diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 54cc53118..2f50a8cf2 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -272,8 +272,8 @@ - - + + @@ -590,4 +590,4 @@ --> - + \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/RootFolderTests/RootFolderServiceFixture.cs b/src/NzbDrone.Core.Test/RootFolderTests/RootFolderServiceFixture.cs index bbce4f287..b559e02a6 100644 --- a/src/NzbDrone.Core.Test/RootFolderTests/RootFolderServiceFixture.cs +++ b/src/NzbDrone.Core.Test/RootFolderTests/RootFolderServiceFixture.cs @@ -103,7 +103,7 @@ namespace NzbDrone.Core.Test.RootFolderTests var path = @"C:\TV".AsOsAgnostic(); Mocker.GetMock() - .SetupGet(s => s.DownloadedEpisodesFolder) + .SetupGet(s => s.DownloadedMoviesFolder) .Returns(path); Assert.Throws(() => Subject.Add(new RootFolder { Path = path })); diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 5d7911e06..094a0fbc3 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Configuration { public enum ConfigKey { - DownloadedEpisodesFolder + DownloadedMoviesFolder } public class ConfigService : IConfigService @@ -73,11 +73,11 @@ namespace NzbDrone.Core.Configuration return _repository.Get(key.ToLower()) != null; } - public string DownloadedEpisodesFolder + public string DownloadedMoviesFolder { - get { return GetValue(ConfigKey.DownloadedEpisodesFolder.ToString()); } + get { return GetValue(ConfigKey.DownloadedMoviesFolder.ToString()); } - set { SetValue(ConfigKey.DownloadedEpisodesFolder.ToString(), value); } + set { SetValue(ConfigKey.DownloadedMoviesFolder.ToString(), value); } } public bool AutoUnmonitorPreviouslyDownloadedEpisodes @@ -231,11 +231,11 @@ namespace NzbDrone.Core.Configuration set { SetValue("DownloadClientWorkingFolders", value); } } - public int DownloadedEpisodesScanInterval + public int DownloadedMoviesScanInterval { - get { return GetValueInt("DownloadedEpisodesScanInterval", 0); } + get { return GetValueInt("DownloadedMoviesScanInterval", 0); } - set { SetValue("DownloadedEpisodesScanInterval", value); } + set { SetValue("DownloadedMoviesScanInterval", value); } } public int DownloadClientHistoryLimit diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index f0f5e54f7..7707e5a01 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Core.MediaFiles; using NzbDrone.Common.Http.Proxy; @@ -11,9 +11,9 @@ namespace NzbDrone.Core.Configuration bool IsDefined(string key); //Download Client - string DownloadedEpisodesFolder { get; set; } + string DownloadedMoviesFolder { get; set; } string DownloadClientWorkingFolders { get; set; } - int DownloadedEpisodesScanInterval { get; set; } + int DownloadedMoviesScanInterval { get; set; } int DownloadClientHistoryLimit { get; set; } //Completed/Failed Download Handling (Download client) diff --git a/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs b/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs index 69e8af676..32b318085 100644 --- a/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs +++ b/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs @@ -49,9 +49,9 @@ namespace NzbDrone.Core.DiskSpace private IEnumerable GetDroneFactoryFreeSpace() { - if (!string.IsNullOrWhiteSpace(_configService.DownloadedEpisodesFolder)) + if (!string.IsNullOrWhiteSpace(_configService.DownloadedMoviesFolder)) { - return GetDiskSpace(new[] { _diskProvider.GetPathRoot(_configService.DownloadedEpisodesFolder) }); + return GetDiskSpace(new[] { _diskProvider.GetPathRoot(_configService.DownloadedMoviesFolder) }); } return new List(); diff --git a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs index bd1fd661d..3cb100862 100644 --- a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs +++ b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs @@ -127,7 +127,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic if (Settings.StrmFolder.IsNullOrWhiteSpace()) { - folder = _configService.DownloadedEpisodesFolder; + folder = _configService.DownloadedMoviesFolder; if (folder.IsNullOrWhiteSpace()) { diff --git a/src/NzbDrone.Core/Download/CompletedDownloadService.cs b/src/NzbDrone.Core/Download/CompletedDownloadService.cs index c55b98e84..955816c64 100644 --- a/src/NzbDrone.Core/Download/CompletedDownloadService.cs +++ b/src/NzbDrone.Core/Download/CompletedDownloadService.cs @@ -26,7 +26,6 @@ namespace NzbDrone.Core.Download private readonly IConfigService _configService; private readonly IEventAggregator _eventAggregator; private readonly IHistoryService _historyService; - private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService; private readonly IDownloadedMovieImportService _downloadedMovieImportService; private readonly IParsingService _parsingService; private readonly IMovieService _movieService; @@ -36,7 +35,6 @@ namespace NzbDrone.Core.Download public CompletedDownloadService(IConfigService configService, IEventAggregator eventAggregator, IHistoryService historyService, - IDownloadedEpisodesImportService downloadedEpisodesImportService, IDownloadedMovieImportService downloadedMovieImportService, IParsingService parsingService, ISeriesService seriesService, @@ -46,7 +44,6 @@ namespace NzbDrone.Core.Download _configService = configService; _eventAggregator = eventAggregator; _historyService = historyService; - _downloadedEpisodesImportService = downloadedEpisodesImportService; _downloadedMovieImportService = downloadedMovieImportService; _parsingService = parsingService; _movieService = movieService; @@ -86,9 +83,9 @@ namespace NzbDrone.Core.Download return; } - var downloadedEpisodesFolder = new OsPath(_configService.DownloadedEpisodesFolder); + var downloadedMoviesFolder = new OsPath(_configService.DownloadedMoviesFolder); - if (downloadedEpisodesFolder.Contains(downloadItemOutputPath)) + if (downloadedMoviesFolder.Contains(downloadItemOutputPath)) { trackedDownload.Warn("Intermediate Download path inside drone factory, Skipping."); return; diff --git a/src/NzbDrone.Core/HealthCheck/Checks/DroneFactoryCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/DroneFactoryCheck.cs index ffae0b4f6..338f8f921 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/DroneFactoryCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/DroneFactoryCheck.cs @@ -17,7 +17,7 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { - var droneFactoryFolder = _configService.DownloadedEpisodesFolder; + var droneFactoryFolder = _configService.DownloadedMoviesFolder; if (droneFactoryFolder.IsNullOrWhiteSpace()) { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/ImportMechanismCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/ImportMechanismCheck.cs index ec35653c7..559202399 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/ImportMechanismCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/ImportMechanismCheck.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { - var droneFactoryFolder = new OsPath(_configService.DownloadedEpisodesFolder); + var droneFactoryFolder = new OsPath(_configService.DownloadedMoviesFolder); List downloadClients; try diff --git a/src/NzbDrone.Core/Jobs/TaskManager.cs b/src/NzbDrone.Core/Jobs/TaskManager.cs index c2739b506..0663874eb 100644 --- a/src/NzbDrone.Core/Jobs/TaskManager.cs +++ b/src/NzbDrone.Core/Jobs/TaskManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using NLog; @@ -94,9 +94,9 @@ namespace NzbDrone.Core.Jobs new ScheduledTask { - Interval = _configService.DownloadedEpisodesScanInterval, - TypeName = typeof(DownloadedEpisodesScanCommand).FullName - //TypeName = typeof(DownloadedMovieScanCommand).FullName + Interval = _configService.DownloadedMoviesScanInterval, + //TypeName = typeof(DownloadedEpisodesScanCommand).FullName + TypeName = typeof(DownloadedMoviesScanCommand).FullName }, }; @@ -178,13 +178,13 @@ namespace NzbDrone.Core.Jobs var rss = _scheduledTaskRepository.GetDefinition(typeof(RssSyncCommand)); rss.Interval = _configService.RssSyncInterval; - var downloadedEpisodes = _scheduledTaskRepository.GetDefinition(typeof(DownloadedEpisodesScanCommand)); - downloadedEpisodes.Interval = _configService.DownloadedEpisodesScanInterval; + var downloadedMovies = _scheduledTaskRepository.GetDefinition(typeof(DownloadedMoviesScanCommand)); + downloadedMovies.Interval = _configService.DownloadedMoviesScanInterval; var netImport = _scheduledTaskRepository.GetDefinition(typeof(NetImportSyncCommand)); netImport.Interval = _configService.NetImportSyncInterval; - _scheduledTaskRepository.UpdateMany(new List { rss, downloadedEpisodes, netImport }); + _scheduledTaskRepository.UpdateMany(new List { rss, downloadedMovies, netImport }); } } } diff --git a/src/NzbDrone.Core/MediaFiles/Commands/DownloadedMovieScanCommand.cs b/src/NzbDrone.Core/MediaFiles/Commands/DownloadedMovieScanCommand.cs index 69e1bb34d..7f46f0430 100644 --- a/src/NzbDrone.Core/MediaFiles/Commands/DownloadedMovieScanCommand.cs +++ b/src/NzbDrone.Core/MediaFiles/Commands/DownloadedMovieScanCommand.cs @@ -3,7 +3,7 @@ using NzbDrone.Core.Messaging.Commands; namespace NzbDrone.Core.MediaFiles.Commands { - public class DownloadedMovieScanCommand : Command + public class DownloadedMoviesScanCommand : Command { public override bool SendUpdatesToClient => SendUpdates; diff --git a/src/NzbDrone.Core/MediaFiles/DownloadedMovieCommandService.cs b/src/NzbDrone.Core/MediaFiles/DownloadedMovieCommandService.cs index 5f9c5362f..383c5e0eb 100644 --- a/src/NzbDrone.Core/MediaFiles/DownloadedMovieCommandService.cs +++ b/src/NzbDrone.Core/MediaFiles/DownloadedMovieCommandService.cs @@ -14,7 +14,7 @@ using System.Text; namespace NzbDrone.Core.MediaFiles { - public class DownloadedMovieCommandService : IExecute + public class DownloadedMovieCommandService : IExecute { private readonly IDownloadedMovieImportService _downloadedMovieImportService; private readonly ITrackedDownloadService _trackedDownloadService; @@ -37,24 +37,24 @@ namespace NzbDrone.Core.MediaFiles private List ProcessDroneFactoryFolder() { - var downloadedEpisodesFolder = _configService.DownloadedEpisodesFolder; + var downloadedMoviesFolder = _configService.DownloadedMoviesFolder; - if (string.IsNullOrEmpty(downloadedEpisodesFolder)) + if (string.IsNullOrEmpty(downloadedMoviesFolder)) { _logger.Trace("Drone Factory folder is not configured"); return new List(); } - if (!_diskProvider.FolderExists(downloadedEpisodesFolder)) + if (!_diskProvider.FolderExists(downloadedMoviesFolder)) { - _logger.Warn("Drone Factory folder [{0}] doesn't exist.", downloadedEpisodesFolder); + _logger.Warn("Drone Factory folder [{0}] doesn't exist.", downloadedMoviesFolder); return new List(); } - return _downloadedMovieImportService.ProcessRootFolder(new DirectoryInfo(downloadedEpisodesFolder)); + return _downloadedMovieImportService.ProcessRootFolder(new DirectoryInfo(downloadedMoviesFolder)); } - private List ProcessPath(DownloadedMovieScanCommand message) + private List ProcessPath(DownloadedMoviesScanCommand message) { if (!_diskProvider.FolderExists(message.Path) && !_diskProvider.FileExists(message.Path)) { @@ -83,7 +83,7 @@ namespace NzbDrone.Core.MediaFiles return _downloadedMovieImportService.ProcessPath(message.Path, message.ImportMode); } - public void Execute(DownloadedMovieScanCommand message) + public void Execute(DownloadedMoviesScanCommand message) { List importResults; diff --git a/src/NzbDrone.Core/MediaFiles/DownloadedMovieImportService.cs b/src/NzbDrone.Core/MediaFiles/DownloadedMovieImportService.cs index 1843bdf72..0367dbe19 100644 --- a/src/NzbDrone.Core/MediaFiles/DownloadedMovieImportService.cs +++ b/src/NzbDrone.Core/MediaFiles/DownloadedMovieImportService.cs @@ -258,7 +258,7 @@ namespace NzbDrone.Core.MediaFiles private ImportResult UnknownMovieResult(string message, string videoFile = null) { - var localEpisode = videoFile == null ? null : new LocalEpisode { Path = videoFile }; + var localEpisode = videoFile == null ? null : new LocalMovie { Path = videoFile }; return new ImportResult(new ImportDecision(localEpisode, new Rejection("Unknown Movie")), message); } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs index 5a8a69279..88cf586d7 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs @@ -20,7 +20,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport List GetImportDecisions(List videoFiles, Series series); List GetImportDecisions(List videoFiles, Movie movie); List GetImportDecisions(List videoFiles, Movie movie, bool shouldCheckQuality); - List GetImportDecisions(List videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality); //TODO: Needs changing to ParsedMovieInfo!! + List GetImportDecisions(List videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality); + List GetImportDecisions(List videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource); List GetImportDecisions(List videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource); } @@ -86,6 +87,23 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport return decisions; } + public List GetImportDecisions(List videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource) + { + var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), movie); + + _logger.Debug("Analyzing {0}/{1} files.", newFiles.Count, videoFiles.Count()); + + var shouldUseFolderName = ShouldUseFolderName(videoFiles, movie, folderInfo); + var decisions = new List(); + + foreach (var file in newFiles) + { + decisions.AddIfNotNull(GetDecision(file, movie, folderInfo, sceneSource, shouldUseFolderName)); + } + + return decisions; + } + public List GetImportDecisions(List videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality = false) { var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), movie); diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs index 58df3dfb8..671d3139a 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs @@ -36,7 +36,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual private readonly IImportApprovedEpisodes _importApprovedEpisodes; private readonly IImportApprovedMovie _importApprovedMovie; private readonly ITrackedDownloadService _trackedDownloadService; - private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService; private readonly IDownloadedMovieImportService _downloadedMovieImportService; private readonly IEventAggregator _eventAggregator; private readonly Logger _logger; @@ -52,7 +51,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual IImportApprovedEpisodes importApprovedEpisodes, IImportApprovedMovie importApprovedMovie, ITrackedDownloadService trackedDownloadService, - IDownloadedEpisodesImportService downloadedEpisodesImportService, IDownloadedMovieImportService downloadedMovieImportService, IEventAggregator eventAggregator, Logger logger) @@ -68,7 +66,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual _importApprovedEpisodes = importApprovedEpisodes; _importApprovedMovie = importApprovedMovie; _trackedDownloadService = trackedDownloadService; - _downloadedEpisodesImportService = downloadedEpisodesImportService; _downloadedMovieImportService = downloadedMovieImportService; _eventAggregator = eventAggregator; _logger = logger; diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index fe287ab33..3054e5cd2 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -787,7 +787,6 @@ - @@ -812,10 +811,6 @@ Code - - Code - - diff --git a/src/NzbDrone.Core/RootFolders/RootFolderService.cs b/src/NzbDrone.Core/RootFolders/RootFolderService.cs index 977ebfab4..87db99517 100644 --- a/src/NzbDrone.Core/RootFolders/RootFolderService.cs +++ b/src/NzbDrone.Core/RootFolders/RootFolderService.cs @@ -110,7 +110,7 @@ namespace NzbDrone.Core.RootFolders throw new InvalidOperationException("Recent directory already exists."); } - if (_configService.DownloadedEpisodesFolder.IsNotNullOrWhiteSpace() && _configService.DownloadedEpisodesFolder.PathEquals(rootFolder.Path)) + if (_configService.DownloadedMoviesFolder.IsNotNullOrWhiteSpace() && _configService.DownloadedMoviesFolder.PathEquals(rootFolder.Path)) { throw new InvalidOperationException("Drone Factory folder cannot be used."); } diff --git a/src/NzbDrone.Core/Validation/Paths/DroneFactoryValidator.cs b/src/NzbDrone.Core/Validation/Paths/DroneFactoryValidator.cs index cc2aec19c..63ed8db77 100644 --- a/src/NzbDrone.Core/Validation/Paths/DroneFactoryValidator.cs +++ b/src/NzbDrone.Core/Validation/Paths/DroneFactoryValidator.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Validation.Paths { if (context.PropertyValue == null) return false; - var droneFactory = _configService.DownloadedEpisodesFolder; + var droneFactory = _configService.DownloadedMoviesFolder; if (string.IsNullOrWhiteSpace(droneFactory)) return true; diff --git a/src/UI/Settings/DownloadClient/DroneFactory/DroneFactoryViewTemplate.hbs b/src/UI/Settings/DownloadClient/DroneFactory/DroneFactoryViewTemplate.hbs index fb5074290..e174fac62 100644 --- a/src/UI/Settings/DownloadClient/DroneFactory/DroneFactoryViewTemplate.hbs +++ b/src/UI/Settings/DownloadClient/DroneFactory/DroneFactoryViewTemplate.hbs @@ -10,7 +10,7 @@
- +
@@ -23,7 +23,7 @@
- +
\ No newline at end of file