diff --git a/src/NzbDrone.Core.Test/MovieTests/MoveMovieServiceFixture.cs b/src/NzbDrone.Core.Test/MovieTests/MoveMovieServiceFixture.cs index 80532d61e..016bb1597 100644 --- a/src/NzbDrone.Core.Test/MovieTests/MoveMovieServiceFixture.cs +++ b/src/NzbDrone.Core.Test/MovieTests/MoveMovieServiceFixture.cs @@ -1,4 +1,6 @@ +using System.Collections.Generic; using System.IO; +using System.Linq; using FizzWare.NBuilder; using Moq; using NUnit.Framework; @@ -16,6 +18,7 @@ public class MoveMovieServiceFixture : CoreTest { private Movie _movie; private MoveMovieCommand _command; + private BulkMoveMovieCommand _bulkCommand; [SetUp] public void Setup() @@ -25,15 +28,32 @@ public void Setup() .Build(); _command = new MoveMovieCommand - { - MovieId = 1, - SourcePath = @"C:\Test\Movies\Movie".AsOsAgnostic(), - DestinationPath = @"C:\Test\Movies2\Movie".AsOsAgnostic() - }; + { + MovieId = 1, + SourcePath = @"C:\Test\Movies\Movie".AsOsAgnostic(), + DestinationPath = @"C:\Test\Movies2\Movie".AsOsAgnostic() + }; + + _bulkCommand = new BulkMoveMovieCommand + { + Movies = new List + { + new BulkMoveMovie + { + MovieId = 1, + SourcePath = @"C:\Test\Movies\Movie".AsOsAgnostic() + } + }, + DestinationRootFolder = @"C:\Test\Movies2".AsOsAgnostic() + }; Mocker.GetMock() .Setup(s => s.GetMovie(It.IsAny())) .Returns(_movie); + + Mocker.GetMock() + .Setup(s => s.FolderExists(It.IsAny())) + .Returns(true); } private void GivenFailedMove() @@ -48,52 +68,67 @@ public void should_log_error_when_move_throws_an_exception() { GivenFailedMove(); - Assert.Throws(() => Subject.Execute(_command)); + Subject.Execute(_command); ExceptionVerification.ExpectedErrors(1); } [Test] - public void should_no_update_movie_path_on_error() + public void should_revert_movie_path_on_error() { GivenFailedMove(); - Assert.Throws(() => Subject.Execute(_command)); + Subject.Execute(_command); ExceptionVerification.ExpectedErrors(1); Mocker.GetMock() - .Verify(v => v.UpdateMovie(It.IsAny()), Times.Never()); + .Verify(v => v.UpdateMovie(It.IsAny()), Times.Once()); + } + + [Test] + public void should_use_destination_path() + { + Subject.Execute(_command); + + Mocker.GetMock() + .Verify(v => v.TransferFolder(_command.SourcePath, _command.DestinationPath, TransferMode.Move, It.IsAny()), Times.Once()); + + Mocker.GetMock() + .Verify(v => v.GetMovieFolder(It.IsAny(), null), Times.Never()); } [Test] public void should_build_new_path_when_root_folder_is_provided() { - _command.DestinationPath = null; - _command.DestinationRootFolder = @"C:\Test\Movie3".AsOsAgnostic(); - - var expectedPath = @"C:\Test\Movie3\Movie".AsOsAgnostic(); + var movieFolder = "Movie"; + var expectedPath = Path.Combine(_bulkCommand.DestinationRootFolder, movieFolder); Mocker.GetMock() - .Setup(s => s.GetMovieFolder(It.IsAny(), null)) - .Returns("Movie"); + .Setup(s => s.GetMovieFolder(It.IsAny(), null)) + .Returns(movieFolder); - Subject.Execute(_command); + Subject.Execute(_bulkCommand); - Mocker.GetMock() - .Verify(v => v.UpdateMovie(It.Is(s => s.Path == expectedPath)), Times.Once()); + Mocker.GetMock() + .Verify(v => v.TransferFolder(_bulkCommand.Movies.First().SourcePath, expectedPath, TransferMode.Move, It.IsAny()), Times.Once()); } [Test] - public void should_use_destination_path_if_destination_root_folder_is_blank() + public void should_skip_movie_folder_if_it_does_not_exist() { + Mocker.GetMock() + .Setup(s => s.FolderExists(It.IsAny())) + .Returns(false); + + Subject.Execute(_command); - Mocker.GetMock() - .Verify(v => v.UpdateMovie(It.Is(s => s.Path == _command.DestinationPath)), Times.Once()); + Mocker.GetMock() + .Verify(v => v.TransferFolder(_command.SourcePath, _command.DestinationPath, TransferMode.Move, It.IsAny()), Times.Never()); Mocker.GetMock() .Verify(v => v.GetMovieFolder(It.IsAny(), null), Times.Never()); } } -} +} \ No newline at end of file diff --git a/src/NzbDrone.Core/Movies/MoveMovieService.cs b/src/NzbDrone.Core/Movies/MoveMovieService.cs index 731907dc1..071b04d00 100644 --- a/src/NzbDrone.Core/Movies/MoveMovieService.cs +++ b/src/NzbDrone.Core/Movies/MoveMovieService.cs @@ -1,7 +1,6 @@ using System.IO; using NLog; using NzbDrone.Common.Disk; -using NzbDrone.Common.Extensions; using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; @@ -11,61 +10,94 @@ namespace NzbDrone.Core.Movies { - public class MoveMovieService : IExecute + public class MoveMovieService : IExecute, IExecute { private readonly IMovieService _movieService; private readonly IBuildFileNames _filenameBuilder; + private readonly IDiskProvider _diskProvider; private readonly IDiskTransferService _diskTransferService; private readonly IEventAggregator _eventAggregator; private readonly Logger _logger; public MoveMovieService(IMovieService movieService, IBuildFileNames filenameBuilder, + IDiskProvider diskProvider, IDiskTransferService diskTransferService, IEventAggregator eventAggregator, Logger logger) { _movieService = movieService; _filenameBuilder = filenameBuilder; + _diskProvider = diskProvider; _diskTransferService = diskTransferService; _eventAggregator = eventAggregator; _logger = logger; } - public void Execute(MoveMovieCommand message) + private void MoveSingleMovie(Movie movie, string sourcePath, string destinationPath, int? index = null, int? total = null) { - var movie = _movieService.GetMovie(message.MovieId); - var source = message.SourcePath; - var destination = message.DestinationPath; - - if (!message.DestinationRootFolder.IsNullOrWhiteSpace()) + if (!_diskProvider.FolderExists(sourcePath)) { - _logger.Debug("Buiding destination path using root folder: {0} and the movie title", message.DestinationRootFolder); - destination = Path.Combine(message.DestinationRootFolder, _filenameBuilder.GetMovieFolder(movie)); + _logger.Debug("Folder '{0}' for '{1}' does not exist, not moving.", sourcePath, movie.Title); + return; } - _logger.ProgressInfo("Moving {0} from '{1}' to '{2}'", movie.Title, source, destination); + if (index != null && total != null) + { + _logger.ProgressInfo("Moving {0} from '{1}' to '{2}' ({3}/{4})", movie.Title, sourcePath, destinationPath, index + 1, total); + } + else + { + _logger.ProgressInfo("Moving {0} from '{1}' to '{2}'", movie.Title, sourcePath, destinationPath); + } - //TODO: Move to transactional disk operations try { - _diskTransferService.TransferFolder(source, destination, TransferMode.Move); + _diskTransferService.TransferFolder(sourcePath, destinationPath, TransferMode.Move); + + _logger.ProgressInfo("{0} moved successfully to {1}", movie.Title, movie.Path); + + _eventAggregator.PublishEvent(new MovieMovedEvent(movie, sourcePath, destinationPath)); } catch (IOException ex) { - var errorMessage = string.Format("Unable to move movie from '{0}' to '{1}'", source, destination); + _logger.Error(ex, "Unable to move movie from '{0}' to '{1}'. Try moving files manually", sourcePath, destinationPath); - _logger.Error(ex, errorMessage); - throw; + RevertPath(movie.Id, sourcePath); + } + } + + private void RevertPath(int movieId, string path) + { + var movie = _movieService.GetMovie(movieId); + + movie.Path = path; + _movieService.UpdateMovie(movie); + } + + public void Execute(MoveMovieCommand message) + { + var movie = _movieService.GetMovie(message.MovieId); + MoveSingleMovie(movie, message.SourcePath, message.DestinationPath); + } + + public void Execute(BulkMoveMovieCommand message) + { + var moviesToMove = message.Movies; + var destinationRootFolder = message.DestinationRootFolder; + + _logger.ProgressInfo("Moving {0} movies to '{1}'", moviesToMove.Count, destinationRootFolder); + + for (var index = 0; index < moviesToMove.Count; index++) + { + var s = moviesToMove[index]; + var movie = _movieService.GetMovie(s.MovieId); + var destinationPath = Path.Combine(destinationRootFolder, _filenameBuilder.GetMovieFolder(movie)); + + MoveSingleMovie(movie, s.SourcePath, destinationPath, index, moviesToMove.Count); } - _logger.ProgressInfo("{0} moved successfully to {1}", movie.Title, movie.Path); - - //Update the movie path to the new path - movie.Path = destination; - movie = _movieService.UpdateMovie(movie); - - _eventAggregator.PublishEvent(new MovieMovedEvent(movie, source, destination)); + _logger.ProgressInfo("Finished moving {0} movies to '{1}'", moviesToMove.Count, destinationRootFolder); } } }