diff --git a/frontend/src/Settings/MediaManagement/MediaManagement.js b/frontend/src/Settings/MediaManagement/MediaManagement.js index 11ae6cf24..16a80f031 100644 --- a/frontend/src/Settings/MediaManagement/MediaManagement.js +++ b/frontend/src/Settings/MediaManagement/MediaManagement.js @@ -316,11 +316,27 @@ class MediaManagement extends Component { type={inputTypes.PATH} name="recycleBin" helpText="Episode files will go here when deleted instead of being permanently deleted" - helpTextWarning="Files in the recycle bin older than a week will be cleaned up automatically" onChange={onInputChange} {...settings.recycleBin} /> + + + Recycling Bin Cleanup + + + { diff --git a/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs b/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs index e38908474..5e336420b 100644 --- a/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs +++ b/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs @@ -37,6 +37,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests public void Setup() { Mocker.GetMock().SetupGet(s => s.RecycleBin).Returns(RecycleBin); + Mocker.GetMock().SetupGet(s => s.RecycleBinCleanupDays).Returns(7); Mocker.GetMock().Setup(s => s.GetDirectories(RecycleBin)) .Returns(new [] { @"C:\Test\RecycleBin\Folder1", @"C:\Test\RecycleBin\Folder2", @"C:\Test\RecycleBin\Folder3" }); @@ -55,6 +56,16 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests Mocker.GetMock().Verify(v => v.GetDirectories(It.IsAny()), Times.Never()); } + [Test] + public void should_return_if_recycleBinCleanupDays_is_zero() + { + Mocker.GetMock().SetupGet(s => s.RecycleBinCleanupDays).Returns(0); + + Mocker.Resolve().Cleanup(); + + Mocker.GetMock().Verify(v => v.GetDirectories(It.IsAny()), Times.Never()); + } + [Test] public void should_delete_all_expired_files() { diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index bf6c1ed1d..822ff1b7a 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -94,6 +94,12 @@ namespace NzbDrone.Core.Configuration set { SetValue("RecycleBin", value); } } + public int RecycleBinCleanupDays + { + get { return GetValueInt("RecycleBinCleanupDays", 7); } + set { SetValue("RecycleBinCleanupDays", value); } + } + public int RssSyncInterval { get { return GetValueInt("RssSyncInterval", 15); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index a16b64f76..5374f61be 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -27,6 +27,7 @@ namespace NzbDrone.Core.Configuration //Media Management bool AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; } string RecycleBin { get; set; } + int RecycleBinCleanupDays { get; set; } ProperDownloadTypes DownloadPropersAndRepacks { get; set; } bool CreateEmptySeriesFolders { get; set; } bool DeleteEmptyFolders { get; set; } @@ -39,7 +40,6 @@ namespace NzbDrone.Core.Configuration RescanAfterRefreshType RescanAfterRefresh { get; set; } EpisodeTitleRequiredType EpisodeTitleRequired { get; set; } - //Permissions (Media Management) bool SetPermissionsLinux { get; set; } string FileChmod { get; set; } diff --git a/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs b/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs index 85c628ad1..686e5375e 100644 --- a/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs +++ b/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs @@ -157,11 +157,19 @@ namespace NzbDrone.Core.MediaFiles return; } - _logger.Info("Removing items older than 7 days from the recycling bin"); + var cleanupDays = _configService.RecycleBinCleanupDays; + + if (cleanupDays == 0) + { + _logger.Info("Automatic cleanup of Recycle Bin is disabled"); + return; + } + + _logger.Info("Removing items older than {0} days from the recycling bin", cleanupDays); foreach (var file in _diskProvider.GetFiles(_configService.RecycleBin, SearchOption.AllDirectories)) { - if (_diskProvider.FileGetLastWrite(file).AddDays(7) > DateTime.UtcNow) + if (_diskProvider.FileGetLastWrite(file).AddDays(cleanupDays) > DateTime.UtcNow) { _logger.Debug("File hasn't expired yet, skipping: {0}", file); continue; diff --git a/src/Sonarr.Api.V3/Config/MediaManagementConfigModule.cs b/src/Sonarr.Api.V3/Config/MediaManagementConfigModule.cs index 6d241de86..85dd39c7b 100644 --- a/src/Sonarr.Api.V3/Config/MediaManagementConfigModule.cs +++ b/src/Sonarr.Api.V3/Config/MediaManagementConfigModule.cs @@ -9,6 +9,7 @@ namespace Sonarr.Api.V3.Config public MediaManagementConfigModule(IConfigService configService, PathExistsValidator pathExistsValidator) : base(configService) { + SharedValidator.RuleFor(c => c.RecycleBinCleanupDays).GreaterThanOrEqualTo(0); SharedValidator.RuleFor(c => c.FileChmod).NotEmpty(); SharedValidator.RuleFor(c => c.FolderChmod).NotEmpty(); SharedValidator.RuleFor(c => c.RecycleBin).IsValidPath().SetValidator(pathExistsValidator).When(c => !string.IsNullOrWhiteSpace(c.RecycleBin)); diff --git a/src/Sonarr.Api.V3/Config/MediaManagementConfigResource.cs b/src/Sonarr.Api.V3/Config/MediaManagementConfigResource.cs index 338c9e282..c76d0fa24 100644 --- a/src/Sonarr.Api.V3/Config/MediaManagementConfigResource.cs +++ b/src/Sonarr.Api.V3/Config/MediaManagementConfigResource.cs @@ -10,6 +10,7 @@ namespace Sonarr.Api.V3.Config { public bool AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; } public string RecycleBin { get; set; } + public int RecycleBinCleanupDays { get; set; } public ProperDownloadTypes DownloadPropersAndRepacks { get; set; } public bool CreateEmptySeriesFolders { get; set; } public bool DeleteEmptyFolders { get; set; } @@ -38,6 +39,7 @@ namespace Sonarr.Api.V3.Config { AutoUnmonitorPreviouslyDownloadedEpisodes = model.AutoUnmonitorPreviouslyDownloadedEpisodes, RecycleBin = model.RecycleBin, + RecycleBinCleanupDays = model.RecycleBinCleanupDays, DownloadPropersAndRepacks = model.DownloadPropersAndRepacks, CreateEmptySeriesFolders = model.CreateEmptySeriesFolders, DeleteEmptyFolders = model.DeleteEmptyFolders,