Remove empty series folders when create empty folders is false
New: Remove empty series folders after disk scan/deleting last episode file and create emoty series folders is disabled Closes #2395
This commit is contained in:
parent
1c36bc5fee
commit
a9c54a1f01
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -27,7 +27,7 @@ namespace NzbDrone.Core.Extras.Files
|
||||||
|
|
||||||
public abstract class ExtraFileService<TExtraFile> : IExtraFileService<TExtraFile>,
|
public abstract class ExtraFileService<TExtraFile> : IExtraFileService<TExtraFile>,
|
||||||
IHandleAsync<SeriesDeletedEvent>,
|
IHandleAsync<SeriesDeletedEvent>,
|
||||||
IHandleAsync<EpisodeFileDeletedEvent>
|
IHandle<EpisodeFileDeletedEvent>
|
||||||
where TExtraFile : ExtraFile, new()
|
where TExtraFile : ExtraFile, new()
|
||||||
{
|
{
|
||||||
private readonly IExtraFileRepository<TExtraFile> _repository;
|
private readonly IExtraFileRepository<TExtraFile> _repository;
|
||||||
|
@ -103,7 +103,7 @@ namespace NzbDrone.Core.Extras.Files
|
||||||
_repository.DeleteForSeries(message.Series.Id);
|
_repository.DeleteForSeries(message.Series.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleAsync(EpisodeFileDeletedEvent message)
|
public void Handle(EpisodeFileDeletedEvent message)
|
||||||
{
|
{
|
||||||
var episodeFile = message.EpisodeFile;
|
var episodeFile = message.EpisodeFile;
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,10 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
{
|
{
|
||||||
_logger.Debug("Series folder doesn't exist: {0}", series.Path);
|
_logger.Debug("Series folder doesn't exist: {0}", series.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
CleanMediaFiles(series, new List<string>());
|
CleanMediaFiles(series, new List<string>());
|
||||||
CompletedScanning(series);
|
CompletedScanning(series);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +115,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
_logger.Trace("Import decisions complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed);
|
_logger.Trace("Import decisions complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed);
|
||||||
_importApprovedEpisodes.Import(decisions, false);
|
_importApprovedEpisodes.Import(decisions, false);
|
||||||
|
|
||||||
|
RemoveEmptySeriesFolder(series.Path);
|
||||||
CompletedScanning(series);
|
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)
|
public void Handle(SeriesUpdatedEvent message)
|
||||||
{
|
{
|
||||||
Scan(message.Series);
|
Scan(message.Series);
|
||||||
|
|
|
@ -4,7 +4,10 @@ using System.Net;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
|
using NzbDrone.Core.Messaging;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
using NzbDrone.Core.Tv.Events;
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
@ -16,24 +19,29 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
void DeleteEpisodeFile(Series series, EpisodeFile episodeFile);
|
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 IDiskProvider _diskProvider;
|
||||||
private readonly IRecycleBinProvider _recycleBinProvider;
|
private readonly IRecycleBinProvider _recycleBinProvider;
|
||||||
private readonly IMediaFileService _mediaFileService;
|
private readonly IMediaFileService _mediaFileService;
|
||||||
private readonly ISeriesService _seriesService;
|
private readonly ISeriesService _seriesService;
|
||||||
|
private readonly IConfigService _configService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public MediaFileDeletionService(IDiskProvider diskProvider,
|
public MediaFileDeletionService(IDiskProvider diskProvider,
|
||||||
IRecycleBinProvider recycleBinProvider,
|
IRecycleBinProvider recycleBinProvider,
|
||||||
IMediaFileService mediaFileService,
|
IMediaFileService mediaFileService,
|
||||||
ISeriesService seriesService,
|
ISeriesService seriesService,
|
||||||
|
IConfigService configService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_recycleBinProvider = recycleBinProvider;
|
_recycleBinProvider = recycleBinProvider;
|
||||||
_mediaFileService = mediaFileService;
|
_mediaFileService = mediaFileService;
|
||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
|
_configService = configService;
|
||||||
_logger = logger;
|
_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
|
@ -48,7 +49,11 @@ namespace NzbDrone.Core.Messaging.Events
|
||||||
|
|
||||||
|
|
||||||
//call synchronous handlers first.
|
//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
|
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);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -850,6 +850,7 @@
|
||||||
<Compile Include="Messaging\Events\EventAggregator.cs" />
|
<Compile Include="Messaging\Events\EventAggregator.cs" />
|
||||||
<Compile Include="Messaging\Events\IEventAggregator.cs" />
|
<Compile Include="Messaging\Events\IEventAggregator.cs" />
|
||||||
<Compile Include="Messaging\Events\IHandle.cs" />
|
<Compile Include="Messaging\Events\IHandle.cs" />
|
||||||
|
<Compile Include="Messaging\EventHandleOrderAttribute.cs" />
|
||||||
<Compile Include="Messaging\IProcessMessage.cs" />
|
<Compile Include="Messaging\IProcessMessage.cs" />
|
||||||
<Compile Include="MetadataSource\SkyHook\Resource\ActorResource.cs" />
|
<Compile Include="MetadataSource\SkyHook\Resource\ActorResource.cs" />
|
||||||
<Compile Include="MetadataSource\SkyHook\Resource\EpisodeResource.cs" />
|
<Compile Include="MetadataSource\SkyHook\Resource\EpisodeResource.cs" />
|
||||||
|
|
Loading…
Reference in New Issue