1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-08-18 00:09:37 +02:00

Fixed: Remove Static/Dynamic Settings, Allow Folder Move from Editor

This commit is contained in:
Qstick 2020-01-11 22:13:28 -05:00
parent 1c8f94f1d8
commit e954b01921
23 changed files with 251 additions and 215 deletions

View File

@ -49,6 +49,13 @@ function MoveMovieModal(props) {
`Would you like to move the movie folders to '${destinationRootFolder}'?` :
`Would you like to move the movie files from '${originalPath}' to '${destinationPath}'?`
}
{
destinationRootFolder ?
<div>
This will also rename the movie folder per the movie folder format in settings.
</div> :
null
}
</ModalBody>
<ModalFooter>

View File

@ -39,7 +39,6 @@ public static MediaManagementConfigResource ToResource(IConfigService model)
CreateEmptySeriesFolders = model.CreateEmptyMovieFolders,
FileDate = model.FileDate,
AutoRenameFolders = model.AutoRenameFolders,
PathsDefaultStatic = model.PathsDefaultStatic,
SetPermissionsLinux = model.SetPermissionsLinux,
FileChmod = model.FileChmod,

View File

@ -25,7 +25,7 @@ private object SaveAll()
var movie = resources.Select(movieResource => movieResource.ToModel(_movieService.GetMovie(movieResource.Id))).ToList();
return ResponseWithCode(_movieService.UpdateMovie(movie)
return ResponseWithCode(_movieService.UpdateMovie(movie, true)
.ToResource(),
HttpStatusCode.Accepted);
}

View File

@ -43,7 +43,6 @@ public MovieResource()
//View & Edit
public string Path { get; set; }
public int ProfileId { get; set; }
public MoviePathState PathState { get; set; }
//Editing Only
public bool Monitored { get; set; }
@ -144,7 +143,6 @@ public static MovieResource ToResource(this Core.Movies.Movie model)
Path = model.Path,
ProfileId = model.ProfileId,
PathState = model.PathState,
Monitored = model.Monitored,
MinimumAvailability = model.MinimumAvailability,
@ -209,7 +207,6 @@ public static Core.Movies.Movie ToModel(this MovieResource resource)
Path = resource.Path,
ProfileId = resource.ProfileId,
PathState = resource.PathState,
Monitored = resource.Monitored,
MinimumAvailability = resource.MinimumAvailability,

View File

@ -153,30 +153,30 @@ public void where_in_list_2()
[Test]
public void enum_as_int()
{
_subject = Where(x => x.PathState == MoviePathState.Static);
_subject = Where(x => x.Status == MovieStatusType.Released);
var name = _subject.Parameters.ParameterNames.First();
_subject.ToString().Should().Be($"(\"Movies\".\"PathState\" = @{name})");
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" = @{name})");
}
[Test]
public void enum_in_list()
{
var allowed = new List<MoviePathState> { MoviePathState.Dynamic, MoviePathState.Static };
_subject = Where(x => allowed.Contains(x.PathState));
var allowed = new List<MovieStatusType> { MovieStatusType.InCinemas, MovieStatusType.Released };
_subject = Where(x => allowed.Contains(x.Status));
var name = _subject.Parameters.ParameterNames.First();
_subject.ToString().Should().Be($"(\"Movies\".\"PathState\" IN @{name})");
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" IN @{name})");
}
[Test]
public void enum_in_array()
{
var allowed = new MoviePathState[] { MoviePathState.Dynamic, MoviePathState.Static };
_subject = Where(x => allowed.Contains(x.PathState));
var allowed = new MovieStatusType[] { MovieStatusType.InCinemas, MovieStatusType.Released };
_subject = Where(x => allowed.Contains(x.Status));
var name = _subject.Parameters.ParameterNames.First();
_subject.ToString().Should().Be($"(\"Movies\".\"PathState\" IN @{name})");
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" IN @{name})");
}
}
}

View File

@ -0,0 +1,94 @@
using System.IO;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.MovieTests
{
[TestFixture]
public class MovieFolderPathBuilderFixture : CoreTest<MoviePathBuilder>
{
private Movie _movie;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
.With(s => s.Title = "Movie Title")
.With(s => s.Path = @"C:\Test\Movies\Movie.Title".AsOsAgnostic())
.With(s => s.RootFolderPath = null)
.Build();
}
public void GivenMovieFolderName(string name)
{
Mocker.GetMock<IBuildFileNames>()
.Setup(s => s.GetMovieFolder(_movie, null))
.Returns(name);
}
public void GivenExistingRootFolder(string rootFolder)
{
Mocker.GetMock<IRootFolderService>()
.Setup(s => s.GetBestRootFolderPath(It.IsAny<string>()))
.Returns(rootFolder);
}
[Test]
public void should_create_new_movie_path()
{
var rootFolder = @"C:\Test\Movies2".AsOsAgnostic();
GivenMovieFolderName(_movie.Title);
_movie.RootFolderPath = rootFolder;
Subject.BuildPath(_movie, false).Should().Be(Path.Combine(rootFolder, _movie.Title));
}
[Test]
public void should_reuse_existing_relative_folder_name()
{
var folderName = Path.GetFileName(_movie.Path);
var rootFolder = @"C:\Test\Movies2".AsOsAgnostic();
GivenExistingRootFolder(Path.GetDirectoryName(_movie.Path));
GivenMovieFolderName(_movie.Title);
_movie.RootFolderPath = rootFolder;
Subject.BuildPath(_movie, true).Should().Be(Path.Combine(rootFolder, folderName));
}
[Test]
public void should_reuse_existing_relative_folder_structure()
{
var existingRootFolder = @"C:\Test\Movies".AsOsAgnostic();
var existingRelativePath = @"M\Movie.Title";
var rootFolder = @"C:\Test\Movies2".AsOsAgnostic();
GivenExistingRootFolder(existingRootFolder);
GivenMovieFolderName(_movie.Title);
_movie.RootFolderPath = rootFolder;
_movie.Path = Path.Combine(existingRootFolder, existingRelativePath);
Subject.BuildPath(_movie, true).Should().Be(Path.Combine(rootFolder, existingRelativePath));
}
[Test]
public void should_use_built_path_for_new_movie()
{
var rootFolder = @"C:\Test\Movies2".AsOsAgnostic();
GivenMovieFolderName(_movie.Title);
_movie.RootFolderPath = rootFolder;
_movie.Path = null;
Subject.BuildPath(_movie, true).Should().Be(Path.Combine(rootFolder, _movie.Title));
}
}
}

View File

@ -1,10 +1,12 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
@ -30,7 +32,7 @@ public void Setup()
[Test]
public void should_call_repo_updateMany()
{
Subject.UpdateMovie(_movies);
Subject.UpdateMovie(_movies, false);
Mocker.GetMock<IMovieRepository>().Verify(v => v.UpdateMany(_movies), Times.Once());
}
@ -41,13 +43,17 @@ public void should_update_path_when_rootFolderPath_is_supplied()
var newRoot = @"C:\Test\TV2".AsOsAgnostic();
_movies.ForEach(s => s.RootFolderPath = newRoot);
Subject.UpdateMovie(_movies).ForEach(s => s.Path.Should().StartWith(newRoot));
Mocker.GetMock<IBuildMoviePaths>()
.Setup(s => s.BuildPath(It.IsAny<Movie>(), false))
.Returns<Movie, bool>((s, u) => Path.Combine(s.RootFolderPath, s.Title));
Subject.UpdateMovie(_movies, false).ForEach(s => s.Path.Should().StartWith(newRoot));
}
[Test]
public void should_not_update_path_when_rootFolderPath_is_empty()
{
Subject.UpdateMovie(_movies).ForEach(s =>
Subject.UpdateMovie(_movies, false).ForEach(s =>
{
var expectedPath = _movies.Single(ser => ser.Id == s.Id).Path;
s.Path.Should().Be(expectedPath);
@ -66,7 +72,11 @@ public void should_be_able_to_update_many_movies()
var newRoot = @"C:\Test\Movies2".AsOsAgnostic();
movies.ForEach(s => s.RootFolderPath = newRoot);
Subject.UpdateMovie(movies);
Mocker.GetMock<IBuildFileNames>()
.Setup(s => s.GetMovieFolder(It.IsAny<Movie>(), (NamingConfig)null))
.Returns<Movie, NamingConfig>((s, n) => s.Title);
Subject.UpdateMovie(movies, false);
}
}
}

View File

@ -116,7 +116,7 @@ public void should_not_clean_library_if_config_value_disable()
.Verify(v => v.GetAllMovies(), Times.Never());
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(new List<Movie>()), Times.Once());
.Verify(v => v.UpdateMovie(new List<Movie>(), true), Times.Once());
}
[Test]
@ -139,7 +139,7 @@ public void should_log_only_on_clean_library_if_config_value_logonly()
.Verify(v => v.DeleteMovie(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Never());
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(new List<Movie>()), Times.Once());
.Verify(v => v.UpdateMovie(new List<Movie>(), true), Times.Once());
}
[Test]
@ -162,7 +162,7 @@ public void should_unmonitor_on_clean_library_if_config_value_keepAndUnmonitor()
.Verify(v => v.DeleteMovie(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Never());
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(It.Is<List<Movie>>(s => s.Count == 3 && s.All(m => !m.Monitored))), Times.Once());
.Verify(v => v.UpdateMovie(It.Is<List<Movie>>(s => s.Count == 3 && s.All(m => !m.Monitored)), true), Times.Once());
}
[Test]
@ -181,7 +181,7 @@ public void should_not_clean_on_clean_library_if_tmdb_match()
Subject.Execute(_command);
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(It.Is<List<Movie>>(s => s.Count == 2 && s.All(m => !m.Monitored))), Times.Once());
.Verify(v => v.UpdateMovie(It.Is<List<Movie>>(s => s.Count == 2 && s.All(m => !m.Monitored)), true), Times.Once());
}
[Test]
@ -201,7 +201,7 @@ public void should_fallback_to_imdbid_on_clean_library_if_tmdb_not_found()
Subject.Execute(_command);
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(It.Is<List<Movie>>(s => s.Count == 2 && s.All(m => !m.Monitored))), Times.Once());
.Verify(v => v.UpdateMovie(It.Is<List<Movie>>(s => s.Count == 2 && s.All(m => !m.Monitored)), true), Times.Once());
}
[Test]
@ -227,7 +227,7 @@ public void should_delete_movies_not_files_on_clean_library_if_config_value_logo
.Verify(v => v.DeleteMovie(It.IsAny<int>(), true, It.IsAny<bool>()), Times.Never());
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(new List<Movie>()), Times.Once());
.Verify(v => v.UpdateMovie(new List<Movie>(), true), Times.Once());
}
[Test]
@ -253,7 +253,7 @@ public void should_delete_movies_and_files_on_clean_library_if_config_value_logo
.Verify(v => v.DeleteMovie(It.IsAny<int>(), true, It.IsAny<bool>()), Times.Exactly(3));
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(new List<Movie>()), Times.Once());
.Verify(v => v.UpdateMovie(new List<Movie>(), true), Times.Once());
}
[Test]
@ -267,7 +267,7 @@ public void should_not_clean_if_list_failures()
Subject.Execute(_command);
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(new List<Movie>()), Times.Never());
.Verify(v => v.UpdateMovie(new List<Movie>(), true), Times.Never());
}
[Test]

View File

@ -299,13 +299,6 @@ public bool AutoRenameFolders
set { SetValue("AutoRenameFolders", value); }
}
public bool PathsDefaultStatic
{
get { return GetValueBoolean("PathsDefaultStatic", true); }
set { SetValue("PathsDefaultStatic", value); }
}
public RescanAfterRefreshType RescanAfterRefresh
{
get { return GetValueEnum("RescanAfterRefresh", RescanAfterRefreshType.Always); }

View File

@ -40,7 +40,6 @@ public interface IConfigService
string ExtraFileExtensions { get; set; }
RescanAfterRefreshType RescanAfterRefresh { get; set; }
bool AutoRenameFolders { get; set; }
bool PathsDefaultStatic { get; set; }
//Permissions (Media Management)
bool SetPermissionsLinux { get; set; }

View File

@ -0,0 +1,21 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(167)]
public class remove_movie_pathstate : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Delete.Column("PathState").FromTable("Movies");
Execute.Sql("DELETE FROM Config WHERE [KEY] IN ('pathsdefaultstatic')");
Alter.Table("MovieFiles").AddColumn("OriginalFilePath").AsString().Nullable();
//This is Ignored in mapping, should not be in DB
Delete.Column("Path").FromTable("MovieFiles");
}
}
}

View File

@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Commands;
@ -20,22 +18,18 @@ namespace NzbDrone.Core.MediaFiles
public interface IRenameMovieFileService
{
List<RenameMovieFilePreview> GetRenamePreviews(int movieId);
void RenameMoviePath(Movie movie, bool shouldRenameFiles);
}
public class RenameMovieFileService : IRenameMovieFileService,
IExecute<RenameFilesCommand>,
IExecute<RenameMovieCommand>,
IExecute<RenameMovieFolderCommand>
IExecute<RenameMovieCommand>
{
private readonly IMovieService _movieService;
private readonly IMediaFileService _mediaFileService;
private readonly IMoveMovieFiles _movieFileMover;
private readonly IEventAggregator _eventAggregator;
private readonly IBuildFileNames _filenameBuilder;
private readonly IConfigService _configService;
private readonly IDiskProvider _diskProvider;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly Logger _logger;
public RenameMovieFileService(IMovieService movieService,
@ -43,8 +37,6 @@ public RenameMovieFileService(IMovieService movieService,
IMoveMovieFiles movieFileMover,
IEventAggregator eventAggregator,
IBuildFileNames filenameBuilder,
IConfigService configService,
IRecycleBinProvider recycleBinProvider,
IDiskProvider diskProvider,
Logger logger)
{
@ -53,8 +45,6 @@ public RenameMovieFileService(IMovieService movieService,
_movieFileMover = movieFileMover;
_eventAggregator = eventAggregator;
_filenameBuilder = filenameBuilder;
_configService = configService;
_recycleBinProvider = recycleBinProvider;
_diskProvider = diskProvider;
_logger = logger;
}
@ -82,28 +72,21 @@ private IEnumerable<RenameMovieFilePreview> GetPreviews(Movie movie, List<MovieF
{
MovieId = movie.Id,
MovieFileId = file.Id,
ExistingPath = movieFilePath,
ExistingPath = file.RelativePath,
//NewPath = movie.Path.GetRelativePath(newPath)
NewPath = newPath
NewPath = movie.Path.GetRelativePath(newPath)
};
}
}
}
private void RenameFiles(List<MovieFile> movieFiles, Movie movie, string oldMoviePath = null)
private void RenameFiles(List<MovieFile> movieFiles, Movie movie)
{
var renamed = new List<MovieFile>();
if (oldMoviePath == null)
{
oldMoviePath = movie.Path;
}
foreach (var movieFile in movieFiles)
{
var oldMovieFilePath = Path.Combine(oldMoviePath, movieFile.RelativePath);
movieFile.Path = oldMovieFilePath;
var movieFilePath = Path.Combine(movie.Path, movieFile.RelativePath);
try
{
@ -116,7 +99,7 @@ private void RenameFiles(List<MovieFile> movieFiles, Movie movie, string oldMovi
_logger.Debug("Renamed movie file: {0}", movieFile);
_eventAggregator.PublishEvent(new MovieFileRenamedEvent(movie, movieFile, oldMovieFilePath));
_eventAggregator.PublishEvent(new MovieFileRenamedEvent(movie, movieFile, movieFilePath));
}
catch (SameFilenameException ex)
{
@ -124,55 +107,18 @@ private void RenameFiles(List<MovieFile> movieFiles, Movie movie, string oldMovi
}
catch (Exception ex)
{
_logger.Error(ex, "Failed to rename file: {0}", oldMovieFilePath);
_logger.Error(ex, "Failed to rename file: {0}", movieFilePath);
}
}
if (renamed.Any())
{
_diskProvider.RemoveEmptySubfolders(movie.Path);
_eventAggregator.PublishEvent(new MovieRenamedEvent(movie));
}
}
public void RenameMoviePath(Movie movie, bool shouldRenameFiles = true)
{
var newFolder = _filenameBuilder.BuildMoviePath(movie);
if (newFolder != movie.Path && movie.PathState == MoviePathState.Dynamic)
{
if (!_configService.AutoRenameFolders)
{
_logger.Info("{0}'s movie should be {1} according to your naming config.", movie, newFolder);
return;
}
_logger.Info("{0}'s movie folder changed to: {1}", movie, newFolder);
var oldFolder = movie.Path;
movie.Path = newFolder;
_diskProvider.MoveFolder(oldFolder, movie.Path);
// if (false)
// {
// var movieFiles = _mediaFileService.GetFilesByMovie(movie.Id);
// _logger.ProgressInfo("Renaming movie files for {0}", movie.Title);
// RenameFiles(movieFiles, movie, oldFolder);
// _logger.ProgressInfo("All movie files renamed for {0}", movie.Title);
// }
_movieService.UpdateMovie(movie);
if (_diskProvider.GetFiles(oldFolder, SearchOption.AllDirectories).Count() == 0)
{
_recycleBinProvider.DeleteFolder(oldFolder);
}
}
if (movie.PathState == MoviePathState.StaticOnce)
{
movie.PathState = MoviePathState.Dynamic;
_movieService.UpdateMovie(movie);
}
}
public void Execute(RenameFilesCommand message)
{
var movie = _movieService.GetMovie(message.MovieId);
@ -196,25 +142,5 @@ public void Execute(RenameMovieCommand message)
_logger.ProgressInfo("All movie files renamed for {0}", movie.Title);
}
}
public void Execute(RenameMovieFolderCommand message)
{
try
{
_logger.Debug("Renaming movie folder for selected movie if necessary");
var moviesToRename = _movieService.GetMovies(message.MovieIds);
foreach (var movie in moviesToRename)
{
var movieFiles = _mediaFileService.GetFilesByMovie(movie.Id);
//_logger.ProgressInfo("Renaming movie folder for {0}", movie.Title);
RenameMoviePath(movie);
}
}
catch (SQLiteException ex)
{
_logger.Warn(ex, "wtf: {0}, {1}", ex.ResultCode, ex.Data);
}
}
}
}

View File

@ -9,6 +9,7 @@ public class MoveMovieCommand : Command
public string DestinationPath { get; set; }
public string DestinationRootFolder { get; set; }
public override bool SendUpdatesToClient => true;
public override bool RequiresDiskAccess => true;
}
}

View File

@ -42,7 +42,6 @@ public Movie()
public string Certification { get; set; }
public string RootFolderPath { get; set; }
public MoviePathState PathState { get; set; }
public DateTime Added { get; set; }
public DateTime? InCinemas { get; set; }
public DateTime? PhysicalRelease { get; set; }
@ -154,7 +153,6 @@ public void ApplyChanges(Movie otherMovie)
Path = otherMovie.Path;
ProfileId = otherMovie.ProfileId;
PathState = otherMovie.PathState;
Monitored = otherMovie.Monitored;
MinimumAvailability = otherMovie.MinimumAvailability;
@ -164,11 +162,4 @@ public void ApplyChanges(Movie otherMovie)
AddOptions = otherMovie.AddOptions;
}
}
public enum MoviePathState
{
Dynamic,
StaticOnce,
Static,
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.IO;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.RootFolders;
namespace NzbDrone.Core.Movies
{
public interface IBuildMoviePaths
{
string BuildPath(Movie movie, bool useExistingRelativeFolder);
}
public class MoviePathBuilder : IBuildMoviePaths
{
private readonly IBuildFileNames _fileNameBuilder;
private readonly IRootFolderService _rootFolderService;
public MoviePathBuilder(IBuildFileNames fileNameBuilder, IRootFolderService rootFolderService)
{
_fileNameBuilder = fileNameBuilder;
_rootFolderService = rootFolderService;
}
public string BuildPath(Movie movie, bool useExistingRelativeFolder)
{
if (movie.RootFolderPath.IsNullOrWhiteSpace())
{
throw new ArgumentException("Root folder was not provided", nameof(movie));
}
if (useExistingRelativeFolder && movie.Path.IsNotNullOrWhiteSpace())
{
var relativePath = GetExistingRelativePath(movie);
return Path.Combine(movie.RootFolderPath, relativePath);
}
return Path.Combine(movie.RootFolderPath, _fileNameBuilder.GetMovieFolder(movie));
}
private string GetExistingRelativePath(Movie movie)
{
var rootFolderPath = _rootFolderService.GetBestRootFolderPath(movie.Path);
return rootFolderPath.GetRelativePath(movie.Path);
}
}
}

View File

@ -43,7 +43,7 @@ public interface IMovieService
List<Movie> GetAllMovies();
List<Movie> AllForTag(int tagId);
Movie UpdateMovie(Movie movie);
List<Movie> UpdateMovie(List<Movie> movie);
List<Movie> UpdateMovie(List<Movie> movie, bool useExistingRelativeFolder);
List<Movie> FilterExistingMovies(List<Movie> movies);
bool MoviePathExists(string folder);
void RemoveAddOptions(Movie movie);
@ -57,6 +57,7 @@ public class MovieService : IMovieService, IHandle<MovieFileAddedEvent>,
private readonly IEventAggregator _eventAggregator;
private readonly IBuildFileNames _fileNameBuilder;
private readonly IImportExclusionsService _exclusionService;
private readonly IBuildMoviePaths _moviePathBuilder;
private readonly Logger _logger;
public MovieService(IMovieRepository movieRepository,
@ -64,6 +65,7 @@ public MovieService(IMovieRepository movieRepository,
IBuildFileNames fileNameBuilder,
IConfigService configService,
IImportExclusionsService exclusionService,
IBuildMoviePaths moviePathBuilder,
Logger logger)
{
_movieRepository = movieRepository;
@ -71,6 +73,7 @@ public MovieService(IMovieRepository movieRepository,
_fileNameBuilder = fileNameBuilder;
_configService = configService;
_exclusionService = exclusionService;
_moviePathBuilder = moviePathBuilder;
_logger = logger;
}
@ -93,21 +96,10 @@ public Movie AddMovie(Movie newMovie)
{
Ensure.That(newMovie, () => newMovie).IsNotNull();
MoviePathState defaultState = MoviePathState.Static;
if (!_configService.PathsDefaultStatic)
{
defaultState = MoviePathState.Dynamic;
}
if (string.IsNullOrWhiteSpace(newMovie.Path))
{
var folderName = _fileNameBuilder.GetMovieFolder(newMovie);
newMovie.Path = Path.Combine(newMovie.RootFolderPath, folderName);
newMovie.PathState = defaultState;
}
else
{
newMovie.PathState = defaultState == MoviePathState.Dynamic ? MoviePathState.StaticOnce : MoviePathState.Static;
}
_logger.Info("Adding Movie {0} Path: [{1}]", newMovie, newMovie.Path);
@ -128,21 +120,10 @@ public List<Movie> AddMovies(List<Movie> newMovies)
newMovies.ForEach(m =>
{
MoviePathState defaultState = MoviePathState.Static;
if (!_configService.PathsDefaultStatic)
{
defaultState = MoviePathState.Dynamic;
}
if (string.IsNullOrWhiteSpace(m.Path))
{
var folderName = _fileNameBuilder.GetMovieFolder(m);
m.Path = Path.Combine(m.RootFolderPath, folderName);
m.PathState = defaultState;
}
else
{
m.PathState = defaultState == MoviePathState.Dynamic ? MoviePathState.StaticOnce : MoviePathState.Static;
}
m.CleanTitle = m.Title.CleanSeriesTitle();
@ -324,21 +305,22 @@ public Movie UpdateMovie(Movie movie)
return updatedMovie;
}
public List<Movie> UpdateMovie(List<Movie> movie)
public List<Movie> UpdateMovie(List<Movie> movie, bool useExistingRelativeFolder)
{
_logger.Debug("Updating {0} movie", movie.Count);
foreach (var s in movie)
foreach (var m in movie)
{
_logger.Trace("Updating: {0}", s.Title);
if (!s.RootFolderPath.IsNullOrWhiteSpace())
_logger.Trace("Updating: {0}", m.Title);
if (!m.RootFolderPath.IsNullOrWhiteSpace())
{
var folderName = new DirectoryInfo(s.Path).Name;
s.Path = Path.Combine(s.RootFolderPath, folderName);
_logger.Trace("Changing path for {0} to {1}", s.Title, s.Path);
m.Path = _moviePathBuilder.BuildPath(m, useExistingRelativeFolder);
_logger.Trace("Changing path for {0} to {1}", m.Title, m.Path);
}
else
{
_logger.Trace("Not changing path for: {0}", s.Title);
_logger.Trace("Not changing path for: {0}", m.Title);
}
}

View File

@ -138,7 +138,7 @@ private void RefreshMovieInfo(Movie movie)
_logger.Info(ex, "Unable to communicate with Mappings Server.");
}
_movieService.UpdateMovie(new List<Movie> { movie });
_movieService.UpdateMovie(new List<Movie> { movie }, true);
_creditService.UpdateCredits(tuple.Item2, movie);
try

View File

@ -194,7 +194,7 @@ private void CleanLibrary(List<Movie> movies)
}
}
_movieService.UpdateMovie(moviesToUpdate);
_movieService.UpdateMovie(moviesToUpdate, true);
}
}
}

View File

@ -18,7 +18,6 @@ public interface IBuildFileNames
{
string BuildFileName(Movie movie, MovieFile movieFile, NamingConfig namingConfig = null);
string BuildFilePath(Movie movie, string fileName, string extension);
string BuildMoviePath(Movie movie, NamingConfig namingConfig = null);
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
string GetMovieFolder(Movie movie, NamingConfig namingConfig = null);
}
@ -110,59 +109,11 @@ public string BuildFilePath(Movie movie, string fileName, string extension)
{
Ensure.That(extension, () => extension).IsNotNullOrWhiteSpace();
var path = "";
if (movie.PathState > 0)
{
path = movie.Path;
}
else
{
path = BuildMoviePath(movie);
}
var path = movie.Path;
return Path.Combine(path, fileName + extension);
}
public string BuildMoviePath(Movie movie, NamingConfig namingConfig = null)
{
if (namingConfig == null)
{
namingConfig = _namingConfigService.GetConfig();
}
var path = movie.Path;
var directory = new DirectoryInfo(path).Name;
var parentDirectoryPath = new DirectoryInfo(path).Parent.FullName;
var movieFile = movie.MovieFile;
var pattern = namingConfig.MovieFolderFormat;
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
AddMovieTokens(tokenHandlers, movie);
AddReleaseDateTokens(tokenHandlers, movie.Year);
AddIdTokens(tokenHandlers, movie);
if (movie.MovieFile != null)
{
AddQualityTokens(tokenHandlers, movie, movieFile);
AddMediaInfoTokens(tokenHandlers, movieFile);
AddMovieFileTokens(tokenHandlers, movieFile);
AddTagsTokens(tokenHandlers, movieFile);
}
else
{
AddMovieFileTokens(tokenHandlers, new MovieFile { SceneName = $"{movie.Title} {movie.Year}", RelativePath = $"{movie.Title} {movie.Year}" });
}
var directoryName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
directoryName = FileNameCleanupRegex.Replace(directoryName, match => match.Captures[0].Value[0].ToString());
directoryName = TrimSeparatorsRegex.Replace(directoryName, string.Empty);
return Path.Combine(parentDirectoryPath, directoryName);
}
public BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec)
{
return new BasicNamingConfig(); //For now let's be lazy

View File

@ -46,7 +46,6 @@ public static MediaManagementConfigResource ToResource(IConfigService model)
FileDate = model.FileDate,
RescanAfterRefresh = model.RescanAfterRefresh,
AutoRenameFolders = model.AutoRenameFolders,
PathsDefaultStatic = model.PathsDefaultStatic,
SetPermissionsLinux = model.SetPermissionsLinux,
FileChmod = model.FileChmod,

View File

@ -85,7 +85,7 @@ private object SaveAll()
});
}
return ResponseWithCode(_movieService.UpdateMovie(moviesToUpdate)
return ResponseWithCode(_movieService.UpdateMovie(moviesToUpdate, !resource.MoveFiles)
.ToResource(),
HttpStatusCode.Accepted);
}

View File

@ -7,8 +7,10 @@
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Movies.Commands;
using NzbDrone.Core.Movies.Events;
using NzbDrone.Core.Validation;
using NzbDrone.Core.Validation.Paths;
@ -29,11 +31,13 @@ public class MovieModule : RadarrRestModuleWithSignalR<MovieResource, Movie>,
{
protected readonly IMovieService _moviesService;
private readonly IMapCoversToLocal _coverMapper;
private readonly IManageCommandQueue _commandQueueManager;
private readonly IUpgradableSpecification _qualityUpgradableSpecification;
public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
IMovieService moviesService,
IMapCoversToLocal coverMapper,
IManageCommandQueue commandQueueManager,
IUpgradableSpecification qualityUpgradableSpecification,
RootFolderValidator rootFolderValidator,
MoviePathValidator moviesPathValidator,
@ -46,6 +50,7 @@ public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
_moviesService = moviesService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
_coverMapper = coverMapper;
_commandQueueManager = commandQueueManager;
GetResourceAll = AllMovie;
GetResourceById = GetMovie;
@ -114,7 +119,24 @@ private int AddMovie(MovieResource moviesResource)
private void UpdateMovie(MovieResource moviesResource)
{
var model = moviesResource.ToModel(_moviesService.GetMovie(moviesResource.Id));
var moveFiles = Request.GetBooleanQueryParameter("moveFiles");
var movie = _moviesService.GetMovie(moviesResource.Id);
if (moveFiles)
{
var sourcePath = movie.Path;
var destinationPath = moviesResource.Path;
_commandQueueManager.Push(new MoveMovieCommand
{
MovieId = movie.Id,
SourcePath = sourcePath,
DestinationPath = destinationPath,
Trigger = CommandTrigger.Manual
});
}
var model = moviesResource.ToModel(movie);
_moviesService.UpdateMovie(model);

View File

@ -45,7 +45,6 @@ public MovieResource()
//View & Edit
public string Path { get; set; }
public int QualityProfileId { get; set; }
public MoviePathState PathState { get; set; }
//Editing Only
public bool Monitored { get; set; }
@ -105,7 +104,6 @@ public static MovieResource ToResource(this Movie model)
Path = model.Path,
QualityProfileId = model.ProfileId,
PathState = model.PathState,
Monitored = model.Monitored,
MinimumAvailability = model.MinimumAvailability,
@ -166,7 +164,6 @@ public static MovieResource ToResource(this Movie model, IUpgradableSpecificatio
Path = model.Path,
QualityProfileId = model.ProfileId,
PathState = model.PathState,
Monitored = model.Monitored,
MinimumAvailability = model.MinimumAvailability,
@ -221,7 +218,6 @@ public static Movie ToModel(this MovieResource resource)
Path = resource.Path,
ProfileId = resource.QualityProfileId,
PathState = resource.PathState,
Monitored = resource.Monitored,
MinimumAvailability = resource.MinimumAvailability,