From ab7bb610a65806a48f48a929c5c1e48fa66a125a Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 27 Aug 2020 22:33:54 -0400 Subject: [PATCH] Fixed: Fix Instances where DB MovieFileId Relationship is Screwy --- ...CleanupOrphanedMovieMovieFileIdsFixture.cs | 55 +++++++++++++++++++ .../DeleteFileFixture.cs | 30 +++++++--- .../Extras/Files/ExtraFileService.cs | 4 +- .../CleanupOrphanedMovieMovieFileIds.cs | 29 ++++++++++ .../MediaFiles/UpgradeMediaFileService.cs | 14 ++--- 5 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedMovieMovieFileIdsFixture.cs create mode 100644 src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMovieMovieFileIds.cs diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedMovieMovieFileIdsFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedMovieMovieFileIdsFixture.cs new file mode 100644 index 000000000..333a451f2 --- /dev/null +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedMovieMovieFileIdsFixture.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Housekeeping.Housekeepers; +using NzbDrone.Core.Languages; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Movies; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Housekeeping.Housekeepers +{ + public class CleanupOrphanedMovieMovieFileIdsFixture : DbTest + { + [Test] + public void should_remove_moviefileid_from_movie_referencing_deleted_moviefile() + { + var removedId = 2; + + var movie = Builder.CreateNew() + .With(e => e.MovieFileId = removedId) + .BuildNew(); + + Db.Insert(movie); + + Subject.Clean(); + AllStoredModels.Should().HaveCount(1); + Db.All().Should().Contain(e => e.MovieFileId == 0); + } + + [Test] + public void should_not_remove_moviefileid_from_movie_referencing_valid_moviefile() + { + var movieFiles = Builder.CreateListOfSize(2) + .All() + .With(h => h.Quality = new QualityModel()) + .With(h => h.Languages = new List { Language.English }) + .BuildListOfNew(); + + Db.InsertMany(movieFiles); + + var movie = Builder.CreateNew() + .With(e => e.MovieFileId = movieFiles.First().Id) + .BuildNew(); + + Db.Insert(movie); + + Subject.Clean(); + AllStoredModels.Should().HaveCount(1); + Db.All().Should().Contain(e => e.MovieFileId == movieFiles.First().Id); + } + } +} diff --git a/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/DeleteFileFixture.cs b/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/DeleteFileFixture.cs index bd4b8c4b0..af41f9ed3 100644 --- a/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/DeleteFileFixture.cs +++ b/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/DeleteFileFixture.cs @@ -1,4 +1,4 @@ -using System; +using System; using Moq; using NUnit.Framework; using NzbDrone.Common.Disk; @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests { WithoutRecycleBin(); - var path = @"C:\Test\TV\30 Rock\S01E01.avi".AsOsAgnostic(); + var path = @"C:\Test\Movie\The Mask (1994)\The Mask.avi".AsOsAgnostic(); Mocker.Resolve().DeleteFile(path); @@ -40,11 +40,11 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests { WithRecycleBin(); - var path = @"C:\Test\TV\30 Rock\S01E01.avi".AsOsAgnostic(); + var path = @"C:\Test\Movie\The Mask (1994)\The Mask.avi".AsOsAgnostic(); Mocker.Resolve().DeleteFile(path); - Mocker.GetMock().Verify(v => v.TransferFile(path, @"C:\Test\Recycle Bin\S01E01.avi".AsOsAgnostic(), TransferMode.Move, false, true), Times.Once()); + Mocker.GetMock().Verify(v => v.TransferFile(path, @"C:\Test\Recycle Bin\The Mask.avi".AsOsAgnostic(), TransferMode.Move, false, true), Times.Once()); } [Test] @@ -52,15 +52,15 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests { WithRecycleBin(); - var path = @"C:\Test\TV\30 Rock\S01E01.avi".AsOsAgnostic(); + var path = @"C:\Test\Movie\The Mask (1994)\The Mask.avi".AsOsAgnostic(); Mocker.GetMock() - .Setup(v => v.FileExists(@"C:\Test\Recycle Bin\S01E01.avi".AsOsAgnostic())) + .Setup(v => v.FileExists(@"C:\Test\Recycle Bin\The Mask.avi".AsOsAgnostic())) .Returns(true); Mocker.Resolve().DeleteFile(path); - Mocker.GetMock().Verify(v => v.TransferFile(path, @"C:\Test\Recycle Bin\S01E01_2.avi".AsOsAgnostic(), TransferMode.Move, false, true), Times.Once()); + Mocker.GetMock().Verify(v => v.TransferFile(path, @"C:\Test\Recycle Bin\The Mask_2.avi".AsOsAgnostic(), TransferMode.Move, false, true), Times.Once()); } [Test] @@ -68,11 +68,23 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests { WindowsOnly(); WithRecycleBin(); - var path = @"C:\Test\TV\30 Rock\S01E01.avi".AsOsAgnostic(); + var path = @"C:\Test\Movie\The Mask (1994)\The Mask.avi".AsOsAgnostic(); Mocker.Resolve().DeleteFile(path); - Mocker.GetMock().Verify(v => v.FileSetLastWriteTime(@"C:\Test\Recycle Bin\S01E01.avi".AsOsAgnostic(), It.IsAny()), Times.Once()); + Mocker.GetMock().Verify(v => v.FileSetLastWriteTime(@"C:\Test\Recycle Bin\The Mask.avi".AsOsAgnostic(), It.IsAny()), Times.Once()); + } + + [Test] + public void should_use_subfolder_when_passed_in() + { + WithRecycleBin(); + + var path = @"C:\Test\Movie\The Mask (1994)\The Mask.avi".AsOsAgnostic(); + + Mocker.Resolve().DeleteFile(path, "The Mask (1994)"); + + Mocker.GetMock().Verify(v => v.TransferFile(path, @"C:\Test\Recycle Bin\The Mask (1994)\The Mask.avi".AsOsAgnostic(), TransferMode.Move, false, true), Times.Once()); } } } diff --git a/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs b/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs index 63ce48e26..8768f1322 100644 --- a/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs +++ b/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using NLog; using NzbDrone.Common.Disk; +using NzbDrone.Common.Extensions; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Messaging.Events; @@ -112,7 +113,8 @@ namespace NzbDrone.Core.Extras.Files if (_diskProvider.FileExists(path)) { // Send to the recycling bin so they can be recovered if necessary - _recycleBinProvider.DeleteFile(path); + var subfolder = _diskProvider.GetParentFolder(movie.Path).GetRelativePath(_diskProvider.GetParentFolder(path)); + _recycleBinProvider.DeleteFile(path, subfolder); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMovieMovieFileIds.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMovieMovieFileIds.cs new file mode 100644 index 000000000..9bded13b1 --- /dev/null +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMovieMovieFileIds.cs @@ -0,0 +1,29 @@ +using Dapper; +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Core.Housekeeping.Housekeepers +{ + public class CleanupOrphanedMovieMovieFileIds : IHousekeepingTask + { + private readonly IMainDatabase _database; + + public CleanupOrphanedMovieMovieFileIds(IMainDatabase database) + { + _database = database; + } + + public void Clean() + { + using (var mapper = _database.OpenConnection()) + { + mapper.Execute(@"UPDATE Movies + SET MovieFileId = 0 + WHERE Id IN ( + SELECT Movies.Id FROM Movies + LEFT OUTER JOIN MovieFiles + ON Movies.MovieFileId = MovieFiles.Id + WHERE MovieFiles.Id IS NULL)"); + } + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs b/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs index e6a18ccec..6a8b01f28 100644 --- a/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs @@ -1,6 +1,7 @@ using System.IO; using NLog; using NzbDrone.Common.Disk; +using NzbDrone.Common.Extensions; using NzbDrone.Core.MediaFiles.MovieImport; using NzbDrone.Core.Parser.Model; @@ -40,7 +41,7 @@ namespace NzbDrone.Core.MediaFiles _logger.Trace("Upgrading existing movie file."); var moveFileResult = new MovieFileMoveResult(); - var existingFile = localMovie.Movie.MovieFile; + var existingFile = localMovie.Movie.MovieFileId > 0 ? localMovie.Movie.MovieFile : null; var rootFolder = _diskProvider.GetParentFolder(localMovie.Movie.Path); @@ -53,21 +54,18 @@ namespace NzbDrone.Core.MediaFiles if (existingFile != null) { var movieFilePath = Path.Combine(localMovie.Movie.Path, existingFile.RelativePath); + var subfolder = rootFolder.GetRelativePath(_diskProvider.GetParentFolder(movieFilePath)); if (_diskProvider.FileExists(movieFilePath)) { _logger.Debug("Removing existing movie file: {0}", existingFile); - _recycleBinProvider.DeleteFile(movieFilePath); + _recycleBinProvider.DeleteFile(movieFilePath, subfolder); } moveFileResult.OldFiles.Add(existingFile); _mediaFileService.Delete(existingFile, DeleteMediaFileReason.Upgrade); } - //Temporary for correctly getting path - localMovie.Movie.MovieFileId = 1; - localMovie.Movie.MovieFile = movieFile; - if (copyOnly) { moveFileResult.MovieFile = _movieFileMover.CopyMovieFile(movieFile, localMovie); @@ -77,10 +75,6 @@ namespace NzbDrone.Core.MediaFiles moveFileResult.MovieFile = _movieFileMover.MoveMovieFile(movieFile, localMovie); } - localMovie.Movie.MovieFileId = existingFile?.Id ?? 0; - localMovie.Movie.MovieFile = existingFile; - - //_movieFileRenamer.RenameMoviePath(localMovie.Movie, false); return moveFileResult; } }