diff --git a/NzbDrone.Core.Test/MediaFileProviderTests.cs b/NzbDrone.Core.Test/MediaFileProviderTests.cs index cc0c63562..95877762b 100644 --- a/NzbDrone.Core.Test/MediaFileProviderTests.cs +++ b/NzbDrone.Core.Test/MediaFileProviderTests.cs @@ -359,5 +359,47 @@ namespace NzbDrone.Core.Test //Assert Assert.AreEqual(expectedName, result); } + + [Test] + public void CleanEpisodesWithNonExistantFiles() + { + //Setup + var episodes = Builder.CreateListOfSize(10).Build(); + + var mocker = new AutoMoqer(); + var database = MockLib.GetEmptyDatabase(true); + mocker.SetConstant(database); + database.InsertMany(episodes); + + //Act + mocker.Resolve().CleanEpisodesWithNonExistantFiles(); + var result = database.Fetch(); + + //Assert + result.Should().HaveSameCount(episodes); + result.Should().OnlyContain(e => e.EpisodeFileId == 0); + } + + [Test] + public void DeleteOrphanedEpisodeFiles() + { + //Setup + var episodeFiles = Builder.CreateListOfSize(10).Build(); + var episodes = Builder.CreateListOfSize(5).Build(); + + var mocker = new AutoMoqer(); + var database = MockLib.GetEmptyDatabase(true); + mocker.SetConstant(database); + database.InsertMany(episodes); + database.InsertMany(episodeFiles); + + //Act + mocker.Resolve().DeleteOrphanedEpisodeFiles(); + var result = database.Fetch(); + + //Assert + result.Should().HaveCount(5); + result.Should().OnlyContain(e => e.EpisodeFileId > 0); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/DiskScanProvider.cs b/NzbDrone.Core/Providers/DiskScanProvider.cs index 7db6809b5..4db01ffd9 100644 --- a/NzbDrone.Core/Providers/DiskScanProvider.cs +++ b/NzbDrone.Core/Providers/DiskScanProvider.cs @@ -196,7 +196,9 @@ namespace NzbDrone.Core.Providers /// list of files to verify public virtual void CleanUp(List files) { - //TODO: remove orphaned files. in files table but not linked to from episode table. + _mediaFileProvider.CleanEpisodesWithNonExistantFiles(); + _mediaFileProvider.DeleteOrphanedEpisodeFiles(); + foreach (var episodeFile in files) { if (!_diskProvider.FileExists(episodeFile.Path)) diff --git a/NzbDrone.Core/Providers/MediaFileProvider.cs b/NzbDrone.Core/Providers/MediaFileProvider.cs index d1dc1586a..9d56da9fe 100644 --- a/NzbDrone.Core/Providers/MediaFileProvider.cs +++ b/NzbDrone.Core/Providers/MediaFileProvider.cs @@ -74,6 +74,26 @@ namespace NzbDrone.Core.Providers return new FileInfo(path); } + public virtual void CleanEpisodesWithNonExistantFiles() + { + _database.Execute(@"UPDATE Episodes SET EpisodeFileId = 0 + WHERE EpisodeFileId IN + (SELECT Episodes.EpisodeFileId FROM Episodes + LEFT OUTER JOIN EpisodeFiles + ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId + WHERE Episodes.EpisodeFileId > 0 AND EpisodeFiles.EpisodeFileId IS null)"); + } + + public virtual void DeleteOrphanedEpisodeFiles() + { + _database.Execute(@"DELETE FROM EpisodeFiles + WHERE EpisodeFileId IN + (SELECT EpisodeFiles.EpisodeFileId FROM EpisodeFiles + LEFT OUTER JOIN Episodes + ON EpisodeFiles.EpisodeFileId = Episodes.EpisodeFileId + WHERE Episodes.EpisodeFileId IS null)"); + } + public virtual string GetNewFilename(IList episodes, string seriesTitle, QualityTypes quality) { var separatorStyle = EpisodeSortingHelper.GetSeparatorStyle(_configProvider.SeparatorStyle);