New: Do not automatically unmonitor episodes renamed outside of Sonarr
Closes #6584
This commit is contained in:
parent
653963a247
commit
fa4c11a943
|
@ -1,9 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
@ -14,14 +16,20 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||
[TestFixture]
|
||||
public class HandleEpisodeFileDeletedFixture : CoreTest<EpisodeService>
|
||||
{
|
||||
private Series _series;
|
||||
private EpisodeFile _episodeFile;
|
||||
private List<Episode> _episodes;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = Builder<Series>
|
||||
.CreateNew()
|
||||
.Build();
|
||||
|
||||
_episodeFile = Builder<EpisodeFile>
|
||||
.CreateNew()
|
||||
.With(e => e.SeriesId = _series.Id)
|
||||
.Build();
|
||||
}
|
||||
|
||||
|
@ -30,6 +38,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||
_episodes = Builder<Episode>
|
||||
.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.SeriesId = _series.Id)
|
||||
.With(e => e.Monitored = true)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
@ -44,6 +53,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||
_episodes = Builder<Episode>
|
||||
.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(e => e.SeriesId = _series.Id)
|
||||
.With(e => e.Monitored = true)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
@ -85,9 +95,31 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||
.Returns(true);
|
||||
|
||||
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
||||
Subject.HandleAsync(new SeriesScannedEvent(_series, new List<string>()));
|
||||
|
||||
Mocker.GetMock<IEpisodeRepository>()
|
||||
.Verify(v => v.ClearFileId(It.IsAny<Episode>(), true), Times.Once());
|
||||
.Verify(v => v.SetMonitored(It.IsAny<IEnumerable<int>>(), false), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_leave_monitored_if_autoUnmonitor_is_true_and_missing_episode_is_replaced()
|
||||
{
|
||||
GivenSingleEpisodeFile();
|
||||
|
||||
var newEpisodeFile = _episodeFile.JsonClone();
|
||||
newEpisodeFile.Id = 123;
|
||||
newEpisodeFile.Episodes = new LazyLoaded<List<Episode>>(_episodes);
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.AutoUnmonitorPreviouslyDownloadedEpisodes)
|
||||
.Returns(true);
|
||||
|
||||
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
||||
Subject.Handle(new EpisodeFileAddedEvent(newEpisodeFile));
|
||||
Subject.HandleAsync(new SeriesScannedEvent(_series, new List<string>()));
|
||||
|
||||
Mocker.GetMock<IEpisodeRepository>()
|
||||
.Verify(v => v.SetMonitored(It.IsAny<IEnumerable<int>>(), false), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
@ -42,16 +43,19 @@ namespace NzbDrone.Core.Tv
|
|||
public class EpisodeService : IEpisodeService,
|
||||
IHandle<EpisodeFileDeletedEvent>,
|
||||
IHandle<EpisodeFileAddedEvent>,
|
||||
IHandleAsync<SeriesDeletedEvent>
|
||||
IHandleAsync<SeriesDeletedEvent>,
|
||||
IHandleAsync<SeriesScannedEvent>
|
||||
{
|
||||
private readonly IEpisodeRepository _episodeRepository;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly ICached<HashSet<int>> _cache;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeService(IEpisodeRepository episodeRepository, IConfigService configService, Logger logger)
|
||||
public EpisodeService(IEpisodeRepository episodeRepository, IConfigService configService, ICacheManager cacheManager, Logger logger)
|
||||
{
|
||||
_episodeRepository = episodeRepository;
|
||||
_configService = configService;
|
||||
_cache = cacheManager.GetCache<HashSet<int>>(GetType());
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -215,34 +219,6 @@ namespace NzbDrone.Core.Tv
|
|||
_episodeRepository.DeleteMany(episodes);
|
||||
}
|
||||
|
||||
public void HandleAsync(SeriesDeletedEvent message)
|
||||
{
|
||||
var episodes = _episodeRepository.GetEpisodesBySeriesIds(message.Series.Select(s => s.Id).ToList());
|
||||
_episodeRepository.DeleteMany(episodes);
|
||||
}
|
||||
|
||||
public void Handle(EpisodeFileDeletedEvent message)
|
||||
{
|
||||
foreach (var episode in GetEpisodesByFileId(message.EpisodeFile.Id))
|
||||
{
|
||||
_logger.Debug("Detaching episode {0} from file.", episode.Id);
|
||||
|
||||
var unmonitorForReason = message.Reason != DeleteMediaFileReason.Upgrade &&
|
||||
message.Reason != DeleteMediaFileReason.ManualOverride;
|
||||
|
||||
_episodeRepository.ClearFileId(episode, unmonitorForReason && _configService.AutoUnmonitorPreviouslyDownloadedEpisodes);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(EpisodeFileAddedEvent message)
|
||||
{
|
||||
foreach (var episode in message.EpisodeFile.Episodes.Value)
|
||||
{
|
||||
_episodeRepository.SetFileId(episode, message.EpisodeFile.Id);
|
||||
_logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.RelativePath, episode);
|
||||
}
|
||||
}
|
||||
|
||||
private Episode FindOneByAirDate(int seriesId, string date, int? part)
|
||||
{
|
||||
var episodes = _episodeRepository.Find(seriesId, date);
|
||||
|
@ -277,5 +253,73 @@ namespace NzbDrone.Core.Tv
|
|||
|
||||
throw new InvalidOperationException($"Multiple episodes with the same air date found. Date: {date}");
|
||||
}
|
||||
|
||||
public void Handle(EpisodeFileDeletedEvent message)
|
||||
{
|
||||
foreach (var episode in GetEpisodesByFileId(message.EpisodeFile.Id))
|
||||
{
|
||||
_logger.Debug("Detaching episode {0} from file.", episode.Id);
|
||||
|
||||
var unmonitorEpisodes = _configService.AutoUnmonitorPreviouslyDownloadedEpisodes;
|
||||
|
||||
var unmonitorForReason = message.Reason != DeleteMediaFileReason.Upgrade &&
|
||||
message.Reason != DeleteMediaFileReason.ManualOverride &&
|
||||
message.Reason != DeleteMediaFileReason.MissingFromDisk;
|
||||
|
||||
// If episode is being unlinked because it's missing from disk store it for
|
||||
if (message.Reason == DeleteMediaFileReason.MissingFromDisk && unmonitorEpisodes)
|
||||
{
|
||||
lock (_cache)
|
||||
{
|
||||
var ids = _cache.Get(episode.SeriesId.ToString(), () => new HashSet<int>());
|
||||
|
||||
ids.Add(episode.Id);
|
||||
}
|
||||
}
|
||||
|
||||
_episodeRepository.ClearFileId(episode, unmonitorForReason && unmonitorEpisodes);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(EpisodeFileAddedEvent message)
|
||||
{
|
||||
foreach (var episode in message.EpisodeFile.Episodes.Value)
|
||||
{
|
||||
_episodeRepository.SetFileId(episode, message.EpisodeFile.Id);
|
||||
|
||||
lock (_cache)
|
||||
{
|
||||
var ids = _cache.Find(episode.SeriesId.ToString());
|
||||
|
||||
if (ids?.Contains(episode.Id) == true)
|
||||
{
|
||||
ids.Remove(episode.Id);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.RelativePath, episode);
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleAsync(SeriesDeletedEvent message)
|
||||
{
|
||||
var episodes = _episodeRepository.GetEpisodesBySeriesIds(message.Series.Select(s => s.Id).ToList());
|
||||
_episodeRepository.DeleteMany(episodes);
|
||||
}
|
||||
|
||||
public void HandleAsync(SeriesScannedEvent message)
|
||||
{
|
||||
lock (_cache)
|
||||
{
|
||||
var ids = _cache.Find(message.Series.Id.ToString());
|
||||
|
||||
if (ids?.Any() == true)
|
||||
{
|
||||
_episodeRepository.SetMonitored(ids, false);
|
||||
}
|
||||
|
||||
_cache.Remove(message.Series.Id.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue