From a71d40edba1388d67e4deefd8bfc354a7a83c6b1 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 20 Jan 2024 19:22:07 -0800 Subject: [PATCH] New: Add recycle bin path for deleted episodes to webhook/custom script Closes #6114 --- .../Checks/RemotePathMappingCheckFixture.cs | 2 +- .../HistoryTests/HistoryServiceFixture.cs | 2 +- .../NotificationTests/SynologyIndexerFixture.cs | 12 ++++++------ .../NotificationTests/Xbmc/OnDownloadFixture.cs | 13 ++++++++----- src/NzbDrone.Core/MediaFiles/DeletedEpisodeFile.cs | 14 ++++++++++++++ .../MediaFiles/EpisodeFileMoveResult.cs | 6 +++--- .../EpisodeImport/ImportApprovedEpisodes.cs | 2 +- .../MediaFiles/Events/EpisodeImportedEvent.cs | 4 ++-- src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs | 8 ++++++-- .../MediaFiles/ScriptImportDecider.cs | 7 ++++--- .../MediaFiles/UpgradeMediaFileService.cs | 5 +++-- .../Notifications/CustomScript/CustomScript.cs | 7 ++++--- src/NzbDrone.Core/Notifications/DownloadMessage.cs | 2 +- .../Notifications/Synology/SynologyIndexer.cs | 2 +- .../Notifications/Webhook/WebhookBase.cs | 5 +++-- .../Notifications/Webhook/WebhookEpisodeFile.cs | 1 + src/NzbDrone.Core/Parser/Model/LocalEpisode.cs | 2 +- 17 files changed, 60 insertions(+), 34 deletions(-) create mode 100644 src/NzbDrone.Core/MediaFiles/DeletedEpisodeFile.cs diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/RemotePathMappingCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/RemotePathMappingCheckFixture.cs index 65ad530ae..fd4d721c1 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/RemotePathMappingCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/RemotePathMappingCheckFixture.cs @@ -176,7 +176,7 @@ public void should_return_docker_path_mapping_error_if_on_docker_and_root_missin public void should_return_ok_on_episode_imported_event() { GivenFolderExists(_downloadRootPath); - var importEvent = new EpisodeImportedEvent(new LocalEpisode(), new EpisodeFile(), new List(), true, new DownloadClientItem()); + var importEvent = new EpisodeImportedEvent(new LocalEpisode(), new EpisodeFile(), new List(), true, new DownloadClientItem()); Subject.Check(importEvent).ShouldBeOk(); } diff --git a/src/NzbDrone.Core.Test/HistoryTests/HistoryServiceFixture.cs b/src/NzbDrone.Core.Test/HistoryTests/HistoryServiceFixture.cs index 66595f760..96ab16a0d 100644 --- a/src/NzbDrone.Core.Test/HistoryTests/HistoryServiceFixture.cs +++ b/src/NzbDrone.Core.Test/HistoryTests/HistoryServiceFixture.cs @@ -66,7 +66,7 @@ public void should_use_file_name_for_source_title_if_scene_name_is_null() DownloadId = "abcd" }; - Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, new List(), true, downloadClientItem)); + Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, new List(), true, downloadClientItem)); Mocker.GetMock() .Verify(v => v.Insert(It.Is(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localEpisode.Path)))); diff --git a/src/NzbDrone.Core.Test/NotificationTests/SynologyIndexerFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/SynologyIndexerFixture.cs index b2bb853e1..fbdd02ffc 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/SynologyIndexerFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/SynologyIndexerFixture.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Moq; using NUnit.Framework; using NzbDrone.Core.MediaFiles; @@ -33,16 +33,16 @@ public void SetUp() RelativePath = "file1.S01E01E02.mkv" }, - OldFiles = new List + OldFiles = new List { - new EpisodeFile + new DeletedEpisodeFile(new EpisodeFile { RelativePath = "file1.S01E01.mkv" - }, - new EpisodeFile + }, null), + new DeletedEpisodeFile(new EpisodeFile { RelativePath = "file1.S01E02.mkv" - } + }, null) } }; diff --git a/src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnDownloadFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnDownloadFixture.cs index 53052ea88..09063bc4d 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnDownloadFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnDownloadFixture.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using FizzWare.NBuilder; using Moq; @@ -28,7 +28,7 @@ public void Setup() _downloadMessage = Builder.CreateNew() .With(d => d.Series = series) .With(d => d.EpisodeFile = episodeFile) - .With(d => d.OldFiles = new List()) + .With(d => d.OldFiles = new List()) .Build(); Subject.Definition = new NotificationDefinition(); @@ -40,9 +40,12 @@ public void Setup() private void GivenOldFiles() { - _downloadMessage.OldFiles = Builder.CreateListOfSize(1) - .Build() - .ToList(); + _downloadMessage.OldFiles = Builder + .CreateListOfSize(1) + .All() + .WithFactory(() => new DeletedEpisodeFile(Builder.CreateNew().Build(), null)) + .Build() + .ToList(); Subject.Definition.Settings = new XbmcSettings { diff --git a/src/NzbDrone.Core/MediaFiles/DeletedEpisodeFile.cs b/src/NzbDrone.Core/MediaFiles/DeletedEpisodeFile.cs new file mode 100644 index 000000000..1383128c2 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/DeletedEpisodeFile.cs @@ -0,0 +1,14 @@ +namespace NzbDrone.Core.MediaFiles +{ + public class DeletedEpisodeFile + { + public string RecycleBinPath { get; set; } + public EpisodeFile EpisodeFile { get; set; } + + public DeletedEpisodeFile(EpisodeFile episodeFile, string recycleBinPath) + { + EpisodeFile = episodeFile; + RecycleBinPath = recycleBinPath; + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeFileMoveResult.cs b/src/NzbDrone.Core/MediaFiles/EpisodeFileMoveResult.cs index e88a10d29..428bf1762 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeFileMoveResult.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeFileMoveResult.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace NzbDrone.Core.MediaFiles { @@ -6,10 +6,10 @@ public class EpisodeFileMoveResult { public EpisodeFileMoveResult() { - OldFiles = new List(); + OldFiles = new List(); } public EpisodeFile EpisodeFile { get; set; } - public List OldFiles { get; set; } + public List OldFiles { get; set; } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs index 5d4bb77f6..308a210df 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs @@ -67,7 +67,7 @@ public List Import(List decisions, bool newDownloa .ThenByDescending(e => e.LocalEpisode.Size)) { var localEpisode = importDecision.LocalEpisode; - var oldFiles = new List(); + var oldFiles = new List(); try { diff --git a/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportedEvent.cs b/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportedEvent.cs index 35a1fc800..e8a2400f7 100644 --- a/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportedEvent.cs +++ b/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportedEvent.cs @@ -9,12 +9,12 @@ public class EpisodeImportedEvent : IEvent { public LocalEpisode EpisodeInfo { get; private set; } public EpisodeFile ImportedEpisode { get; private set; } - public List OldFiles { get; private set; } + public List OldFiles { get; private set; } public bool NewDownload { get; private set; } public DownloadClientItemClientInfo DownloadClientInfo { get; set; } public string DownloadId { get; private set; } - public EpisodeImportedEvent(LocalEpisode episodeInfo, EpisodeFile importedEpisode, List oldFiles, bool newDownload, DownloadClientItem downloadClientItem) + public EpisodeImportedEvent(LocalEpisode episodeInfo, EpisodeFile importedEpisode, List oldFiles, bool newDownload, DownloadClientItem downloadClientItem) { EpisodeInfo = episodeInfo; ImportedEpisode = importedEpisode; diff --git a/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs b/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs index faf11e2a3..89d9c2340 100644 --- a/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs +++ b/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.MediaFiles public interface IRecycleBinProvider { void DeleteFolder(string path); - void DeleteFile(string path, string subfolder = ""); + string DeleteFile(string path, string subfolder = ""); void Empty(); void Cleanup(); } @@ -66,7 +66,7 @@ public void DeleteFolder(string path) } } - public void DeleteFile(string path, string subfolder = "") + public string DeleteFile(string path, string subfolder = "") { _logger.Debug("Attempting to send '{0}' to recycling bin", path); var recyclingBin = _configService.RecycleBin; @@ -82,6 +82,8 @@ public void DeleteFile(string path, string subfolder = "") _diskProvider.DeleteFile(path); _logger.Debug("File has been permanently deleted: {0}", path); + + return null; } else { @@ -128,6 +130,8 @@ public void DeleteFile(string path, string subfolder = "") SetLastWriteTime(destination, DateTime.UtcNow); _logger.Debug("File has been moved to the recycling bin: {0}", destination); + + return destination; } } diff --git a/src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs b/src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs index 45ab383d7..6e4b77048 100644 --- a/src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs +++ b/src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs @@ -174,9 +174,10 @@ public ScriptImportDecision TryImport(string sourcePath, string destinationFileP if (oldFiles.Any()) { - environmentVariables.Add("Sonarr_DeletedRelativePaths", string.Join("|", oldFiles.Select(e => e.RelativePath))); - environmentVariables.Add("Sonarr_DeletedPaths", string.Join("|", oldFiles.Select(e => Path.Combine(series.Path, e.RelativePath)))); - environmentVariables.Add("Sonarr_DeletedDateAdded", string.Join("|", oldFiles.Select(e => e.DateAdded))); + environmentVariables.Add("Sonarr_DeletedRelativePaths", string.Join("|", oldFiles.Select(e => e.EpisodeFile.RelativePath))); + environmentVariables.Add("Sonarr_DeletedPaths", string.Join("|", oldFiles.Select(e => Path.Combine(series.Path, e.EpisodeFile.RelativePath)))); + environmentVariables.Add("Sonarr_DeletedDateAdded", string.Join("|", oldFiles.Select(e => e.EpisodeFile.DateAdded))); + environmentVariables.Add("Sonarr_DeletedRecycleBinPaths", string.Join("|", oldFiles.Select(e => e.RecycleBinPath ?? string.Empty))); } _logger.Debug("Executing external script: {0}", _configService.ScriptImportPath); diff --git a/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs b/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs index 908271c6d..4910a1e57 100644 --- a/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs @@ -57,14 +57,15 @@ public EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEp var file = existingFile.First(); var episodeFilePath = Path.Combine(localEpisode.Series.Path, file.RelativePath); var subfolder = rootFolder.GetRelativePath(_diskProvider.GetParentFolder(episodeFilePath)); + string recycleBinPath = null; if (_diskProvider.FileExists(episodeFilePath)) { _logger.Debug("Removing existing episode file: {0}", file); - _recycleBinProvider.DeleteFile(episodeFilePath, subfolder); + recycleBinPath = _recycleBinProvider.DeleteFile(episodeFilePath, subfolder); } - moveFileResult.OldFiles.Add(file); + moveFileResult.OldFiles.Add(new DeletedEpisodeFile(file, recycleBinPath)); _mediaFileService.Delete(file, DeleteMediaFileReason.Upgrade); } diff --git a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs index 2a6483e18..d72f668e3 100644 --- a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs +++ b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs @@ -158,9 +158,10 @@ public override void OnDownload(DownloadMessage message) if (message.OldFiles.Any()) { - environmentVariables.Add("Sonarr_DeletedRelativePaths", string.Join("|", message.OldFiles.Select(e => e.RelativePath))); - environmentVariables.Add("Sonarr_DeletedPaths", string.Join("|", message.OldFiles.Select(e => Path.Combine(series.Path, e.RelativePath)))); - environmentVariables.Add("Sonarr_DeletedDateAdded", string.Join("|", message.OldFiles.Select(e => e.DateAdded))); + environmentVariables.Add("Sonarr_DeletedRelativePaths", string.Join("|", message.OldFiles.Select(e => e.EpisodeFile.RelativePath))); + environmentVariables.Add("Sonarr_DeletedPaths", string.Join("|", message.OldFiles.Select(e => Path.Combine(series.Path, e.EpisodeFile.RelativePath)))); + environmentVariables.Add("Sonarr_DeletedDateAdded", string.Join("|", message.OldFiles.Select(e => e.EpisodeFile.DateAdded))); + environmentVariables.Add("Sonarr_DeletedRecycleBinPaths", string.Join("|", message.OldFiles.Select(e => e.RecycleBinPath ?? string.Empty))); } ExecuteScript(environmentVariables); diff --git a/src/NzbDrone.Core/Notifications/DownloadMessage.cs b/src/NzbDrone.Core/Notifications/DownloadMessage.cs index 62f8143d0..bd3e1188f 100644 --- a/src/NzbDrone.Core/Notifications/DownloadMessage.cs +++ b/src/NzbDrone.Core/Notifications/DownloadMessage.cs @@ -12,7 +12,7 @@ public class DownloadMessage public Series Series { get; set; } public LocalEpisode EpisodeInfo { get; set; } public EpisodeFile EpisodeFile { get; set; } - public List OldFiles { get; set; } + public List OldFiles { get; set; } public string SourcePath { get; set; } public DownloadClientItemClientInfo DownloadClientInfo { get; set; } public string DownloadId { get; set; } diff --git a/src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs b/src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs index 23e576b47..733eaa5e4 100644 --- a/src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs +++ b/src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs @@ -29,7 +29,7 @@ public override void OnDownload(DownloadMessage message) { foreach (var oldFile in message.OldFiles) { - var fullPath = Path.Combine(message.Series.Path, oldFile.RelativePath); + var fullPath = Path.Combine(message.Series.Path, oldFile.EpisodeFile.RelativePath); _indexerProxy.DeleteFile(fullPath); } diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs index 22375baa7..2214a1f03 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs @@ -65,9 +65,10 @@ protected WebhookImportPayload BuildOnDownloadPayload(DownloadMessage message) if (message.OldFiles.Any()) { - payload.DeletedFiles = message.OldFiles.ConvertAll(x => new WebhookEpisodeFile(x) + payload.DeletedFiles = message.OldFiles.ConvertAll(x => new WebhookEpisodeFile(x.EpisodeFile) { - Path = Path.Combine(message.Series.Path, x.RelativePath) + Path = Path.Combine(message.Series.Path, x.EpisodeFile.RelativePath), + RecycleBinPath = x.RecycleBinPath }); } diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookEpisodeFile.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookEpisodeFile.cs index 9f392a33b..deeb9db95 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookEpisodeFile.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookEpisodeFile.cs @@ -37,5 +37,6 @@ public WebhookEpisodeFile(EpisodeFile episodeFile) public long Size { get; set; } public DateTime DateAdded { get; set; } public WebhookEpisodeFileMediaInfo MediaInfo { get; set; } + public string RecycleBinPath { get; set; } } } diff --git a/src/NzbDrone.Core/Parser/Model/LocalEpisode.cs b/src/NzbDrone.Core/Parser/Model/LocalEpisode.cs index 060a14e6e..0c4212d61 100644 --- a/src/NzbDrone.Core/Parser/Model/LocalEpisode.cs +++ b/src/NzbDrone.Core/Parser/Model/LocalEpisode.cs @@ -28,7 +28,7 @@ public LocalEpisode() public ParsedEpisodeInfo FolderEpisodeInfo { get; set; } public Series Series { get; set; } public List Episodes { get; set; } - public List OldFiles { get; set; } + public List OldFiles { get; set; } public QualityModel Quality { get; set; } public List Languages { get; set; } public MediaInfoModel MediaInfo { get; set; }