diff --git a/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs b/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs index ac30f6536..dc13ba41c 100644 --- a/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs +++ b/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Extras.Files public abstract class ExtraFileService<TExtraFile> : IExtraFileService<TExtraFile>, IHandleAsync<SeriesDeletedEvent>, - IHandleAsync<EpisodeFileDeletedEvent> + IHandle<EpisodeFileDeletedEvent> where TExtraFile : ExtraFile, new() { private readonly IExtraFileRepository<TExtraFile> _repository; @@ -103,7 +103,7 @@ namespace NzbDrone.Core.Extras.Files _repository.DeleteForSeries(message.Series.Id); } - public void HandleAsync(EpisodeFileDeletedEvent message) + public void Handle(EpisodeFileDeletedEvent message) { var episodeFile = message.EpisodeFile; diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs index 8cb10d2c7..38eee0547 100644 --- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -95,8 +95,10 @@ namespace NzbDrone.Core.MediaFiles { _logger.Debug("Series folder doesn't exist: {0}", series.Path); } + CleanMediaFiles(series, new List<string>()); CompletedScanning(series); + return; } @@ -113,6 +115,7 @@ namespace NzbDrone.Core.MediaFiles _logger.Trace("Import decisions complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed); _importApprovedEpisodes.Import(decisions, false); + RemoveEmptySeriesFolder(series.Path); CompletedScanning(series); } @@ -186,6 +189,15 @@ namespace NzbDrone.Core.MediaFiles } } + private void RemoveEmptySeriesFolder(string path) + { + if (_diskProvider.GetFiles(path, SearchOption.AllDirectories).Empty() && + !_configService.CreateEmptySeriesFolders) + { + _diskProvider.DeleteFolder(path, true); + } + } + public void Handle(SeriesUpdatedEvent message) { Scan(message.Series); diff --git a/src/NzbDrone.Core/MediaFiles/MediaFileDeletionService.cs b/src/NzbDrone.Core/MediaFiles/MediaFileDeletionService.cs index 70c9a5a75..e875a97d2 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaFileDeletionService.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaFileDeletionService.cs @@ -4,7 +4,10 @@ using System.Net; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Exceptions; +using NzbDrone.Core.MediaFiles.Events; +using NzbDrone.Core.Messaging; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Tv; using NzbDrone.Core.Tv.Events; @@ -16,24 +19,29 @@ namespace NzbDrone.Core.MediaFiles void DeleteEpisodeFile(Series series, EpisodeFile episodeFile); } - public class MediaFileDeletionService : IDeleteMediaFiles, IHandleAsync<SeriesDeletedEvent> + public class MediaFileDeletionService : IDeleteMediaFiles, + IHandleAsync<SeriesDeletedEvent>, + IHandle<EpisodeFileDeletedEvent> { private readonly IDiskProvider _diskProvider; private readonly IRecycleBinProvider _recycleBinProvider; private readonly IMediaFileService _mediaFileService; private readonly ISeriesService _seriesService; + private readonly IConfigService _configService; private readonly Logger _logger; public MediaFileDeletionService(IDiskProvider diskProvider, IRecycleBinProvider recycleBinProvider, IMediaFileService mediaFileService, ISeriesService seriesService, + IConfigService configService, Logger logger) { _diskProvider = diskProvider; _recycleBinProvider = recycleBinProvider; _mediaFileService = mediaFileService; _seriesService = seriesService; + _configService = configService; _logger = logger; } @@ -105,5 +113,18 @@ namespace NzbDrone.Core.MediaFiles } } } + + [EventHandleOrder(EventHandleOrder.Last)] + public void Handle(EpisodeFileDeletedEvent message) + { + var series = message.EpisodeFile.Series.Value; + var path = series.Path; + + if (_diskProvider.GetFiles(path, SearchOption.AllDirectories).Empty() && + !_configService.CreateEmptySeriesFolders) + { + _diskProvider.DeleteFolder(path, true); + } + } } } diff --git a/src/NzbDrone.Core/Messaging/EventHandleOrderAttribute.cs b/src/NzbDrone.Core/Messaging/EventHandleOrderAttribute.cs new file mode 100644 index 000000000..6af307ecd --- /dev/null +++ b/src/NzbDrone.Core/Messaging/EventHandleOrderAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace NzbDrone.Core.Messaging +{ + [AttributeUsage(AttributeTargets.Method)] + public class EventHandleOrderAttribute : Attribute + { + public EventHandleOrder EventHandleOrder { get; set; } + + public EventHandleOrderAttribute(EventHandleOrder eventHandleOrder) + { + EventHandleOrder = eventHandleOrder; + } + } + + public enum EventHandleOrder + { + First, + Any, + Last + } +} diff --git a/src/NzbDrone.Core/Messaging/Events/EventAggregator.cs b/src/NzbDrone.Core/Messaging/Events/EventAggregator.cs index 0111a7342..f447cf237 100644 --- a/src/NzbDrone.Core/Messaging/Events/EventAggregator.cs +++ b/src/NzbDrone.Core/Messaging/Events/EventAggregator.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using NLog; using NzbDrone.Common; @@ -48,7 +49,11 @@ namespace NzbDrone.Core.Messaging.Events //call synchronous handlers first. - foreach (var handler in _serviceFactory.BuildAll<IHandle<TEvent>>()) + var handlers = _serviceFactory.BuildAll<IHandle<TEvent>>() + .OrderBy(GetEventHandleOrder) + .ToList(); + + foreach (var handler in handlers) { try { @@ -96,5 +101,25 @@ namespace NzbDrone.Core.Messaging.Events return string.Format("{0}<{1}>", eventType.Name.Remove(eventType.Name.IndexOf('`')), eventType.GetGenericArguments()[0].Name); } + + private int GetEventHandleOrder<TEvent>(IHandle<TEvent> eventHandler) where TEvent : class, IEvent + { + // TODO: Convert "Handle" to nameof(eventHandler.Handle) after .net 4.5 + var method = eventHandler.GetType().GetMethod("Handle", new Type[] {typeof(TEvent)}); + + if (method == null) + { + return (int) EventHandleOrder.Any; + } + + var attribute = method.GetCustomAttributes(typeof(EventHandleOrderAttribute), true).FirstOrDefault() as EventHandleOrderAttribute; + + if (attribute == null) + { + return (int) EventHandleOrder.Any; + } + + return (int)attribute.EventHandleOrder; + } } } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 6fa51c9d9..a1169a505 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -850,6 +850,7 @@ <Compile Include="Messaging\Events\EventAggregator.cs" /> <Compile Include="Messaging\Events\IEventAggregator.cs" /> <Compile Include="Messaging\Events\IHandle.cs" /> + <Compile Include="Messaging\EventHandleOrderAttribute.cs" /> <Compile Include="Messaging\IProcessMessage.cs" /> <Compile Include="MetadataSource\SkyHook\Resource\ActorResource.cs" /> <Compile Include="MetadataSource\SkyHook\Resource\EpisodeResource.cs" />