Fixed: Series being unmonitored when still in Import List

Closes #7555
import-list-removal-ids
Mark McDowall 1 month ago
parent 035c474f10
commit 1379166c07
No known key found for this signature in database

@ -14,7 +14,7 @@ namespace NzbDrone.Core.Test.ImportListTests
{
private void GivenExisting(List<ImportListItemInfo> existing)
{
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Setup(v => v.GetAllForLists(It.IsAny<List<int>>()))
.Returns(existing);
}
@ -58,13 +58,13 @@ namespace NzbDrone.Core.Test.ImportListTests
numDeleted.Should().Be(1);
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == newItem.TvdbId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == updatedItem.TvdbId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId != newItem.TvdbId && s[0].TvdbId != updatedItem.TvdbId)), Times.Once());
}
@ -107,13 +107,13 @@ namespace NzbDrone.Core.Test.ImportListTests
numDeleted.Should().Be(1);
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId == newItem.ImdbId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId == updatedItem.ImdbId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId != newItem.ImdbId && s[0].ImdbId != updatedItem.ImdbId)), Times.Once());
}
@ -156,13 +156,13 @@ namespace NzbDrone.Core.Test.ImportListTests
numDeleted.Should().Be(1);
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId == newItem.TmdbId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId == updatedItem.TmdbId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId != newItem.TmdbId && s[0].TmdbId != updatedItem.TmdbId)), Times.Once());
}
@ -205,13 +205,13 @@ namespace NzbDrone.Core.Test.ImportListTests
numDeleted.Should().Be(1);
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId == newItem.MalId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId == updatedItem.MalId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId != newItem.MalId && s[0].MalId != updatedItem.MalId)), Times.Once());
}
@ -254,13 +254,13 @@ namespace NzbDrone.Core.Test.ImportListTests
numDeleted.Should().Be(1);
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId == newItem.AniListId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId == updatedItem.AniListId)), Times.Once());
Mocker.GetMock<IImportListItemInfoRepository>()
Mocker.GetMock<IImportListItemRepository>()
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId != newItem.AniListId && s[0].AniListId != updatedItem.AniListId)), Times.Once());
}
}

@ -42,24 +42,45 @@ namespace NzbDrone.Core.Test.ImportListTests
.TheFirst(1)
.With(s => s.TvdbId = 6)
.With(s => s.ImdbId = "6")
.With(s => s.TmdbId = 6)
.With(s => s.MalIds = new HashSet<int> { 6 })
.With(s => s.AniListIds = new HashSet<int> { 6 })
.With(s => s.Monitored = true)
.TheNext(1)
.With(s => s.TvdbId = 7)
.With(s => s.ImdbId = "7")
.With(s => s.TmdbId = 7)
.With(s => s.MalIds = new HashSet<int> { 7 })
.With(s => s.AniListIds = new HashSet<int> { 7 })
.With(s => s.Monitored = true)
.TheNext(1)
.With(s => s.TvdbId = 8)
.With(s => s.ImdbId = "8")
.With(s => s.TmdbId = 8)
.With(s => s.MalIds = new HashSet<int> { 8 })
.With(s => s.AniListIds = new HashSet<int> { 8 })
.With(s => s.Monitored = true)
.Build().ToList();
_list2Series = Builder<ImportListItemInfo>.CreateListOfSize(3)
.TheFirst(1)
.With(s => s.TvdbId = 6)
.With(s => s.ImdbId = "6")
.With(s => s.TmdbId = 6)
.With(s => s.MalId = 6)
.With(s => s.AniListId = 6)
.TheNext(1)
.With(s => s.TvdbId = 7)
.With(s => s.ImdbId = "7")
.With(s => s.TmdbId = 7)
.With(s => s.MalId = 7)
.With(s => s.AniListId = 7)
.TheNext(1)
.With(s => s.TvdbId = 8)
.With(s => s.ImdbId = "8")
.With(s => s.TmdbId = 8)
.With(s => s.MalId = 8)
.With(s => s.AniListId = 8)
.Build().ToList();
_importListFetch = new ImportListFetchResult(_list1Series, false);
@ -110,6 +131,10 @@ namespace NzbDrone.Core.Test.ImportListTests
Mocker.GetMock<IImportListExclusionService>()
.Setup(v => v.All())
.Returns(new List<ImportListExclusion>());
Mocker.GetMock<IImportListItemService>()
.Setup(s => s.All())
.Returns(new List<ImportListItemInfo>());
}
private void WithTvdbId()
@ -153,6 +178,19 @@ namespace NzbDrone.Core.Test.ImportListTests
});
}
private List<ImportListItemInfo> WithImportListItems(int count)
{
var importListItems = Builder<ImportListItemInfo>.CreateListOfSize(count)
.Build()
.ToList();
Mocker.GetMock<IImportListItemService>()
.Setup(s => s.All())
.Returns(importListItems);
return importListItems;
}
private void WithMonitorType(MonitorTypes monitor)
{
_importLists.ForEach(li => (li.Definition as ImportListDefinition).ShouldMonitor = monitor);
@ -285,16 +323,18 @@ namespace NzbDrone.Core.Test.ImportListTests
{
WithList(1, true);
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
var importListItems = WithImportListItems(_existingSeries.Count - 1);
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
Mocker.GetMock<IImportListItemService>()
.Setup(v => v.Exists(6, It.IsAny<string>()))
.Returns(true);
for (var i = 0; i < importListItems.Count; i++)
{
importListItems[i].TvdbId = _existingSeries[i].TvdbId;
}
Subject.Execute(_commandAll);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count > 0 && s.All(m => !m.Monitored)), true), Times.Once());
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
}
[Test]
@ -302,18 +342,75 @@ namespace NzbDrone.Core.Test.ImportListTests
{
WithList(1, true);
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
var importListItems = WithImportListItems(_existingSeries.Count - 1);
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
var x = _importLists;
for (var i = 0; i < importListItems.Count; i++)
{
importListItems[i].ImdbId = _existingSeries[i].ImdbId;
}
Mocker.GetMock<IImportListItemService>()
.Setup(v => v.Exists(It.IsAny<int>(), "6"))
.Returns(true);
Subject.Execute(_commandAll);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
}
[Test]
public void should_not_clean_on_clean_library_if_tmdb_match()
{
WithList(1, true);
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
var importListItems = WithImportListItems(_existingSeries.Count - 1);
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
for (var i = 0; i < importListItems.Count; i++)
{
importListItems[i].TmdbId = _existingSeries[i].TmdbId;
}
Subject.Execute(_commandAll);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
}
[Test]
public void should_not_clean_on_clean_library_if_malid_match()
{
WithList(1, true);
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
var importListItems = WithImportListItems(_existingSeries.Count - 1);
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
for (var i = 0; i < importListItems.Count; i++)
{
importListItems[i].MalId = _existingSeries[i].MalIds.First();
}
Subject.Execute(_commandAll);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
}
[Test]
public void should_not_clean_on_clean_library_if_anilistid_match()
{
WithList(1, true);
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
var importListItems = WithImportListItems(_existingSeries.Count - 1);
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
for (var i = 0; i < importListItems.Count; i++)
{
importListItems[i].AniListId = _existingSeries[i].AniListIds.First();
}
Subject.Execute(_commandAll);
Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count > 0 && s.All(m => !m.Monitored)), true), Times.Once());
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
}
[Test]
@ -345,6 +442,7 @@ namespace NzbDrone.Core.Test.ImportListTests
Mocker.GetMock<ISeriesService>()
.Verify(v => v.UpdateSeries(It.IsAny<List<Series>>(), It.IsAny<bool>()), Times.Never());
Mocker.GetMock<ISeriesService>()
.Verify(v => v.DeleteSeries(It.IsAny<List<int>>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Never());
}

@ -0,0 +1,15 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(217)]
public class add_mal_and_anilist_ids : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Series").AddColumn("MalIds").AsString().WithDefaultValue("[]");
Alter.Table("Series").AddColumn("AniListIds").AsString().WithDefaultValue("[]");
}
}
}

@ -1,18 +1,16 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.ImportLists.ImportListItems
{
public interface IImportListItemInfoRepository : IBasicRepository<ImportListItemInfo>
public interface IImportListItemRepository : IBasicRepository<ImportListItemInfo>
{
List<ImportListItemInfo> GetAllForLists(List<int> listIds);
bool Exists(int tvdbId, string imdbId);
}
public class ImportListItemRepository : BasicRepository<ImportListItemInfo>, IImportListItemInfoRepository
public class ImportListItemRepository : BasicRepository<ImportListItemInfo>, IImportListItemRepository
{
public ImportListItemRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
@ -23,21 +21,5 @@ namespace NzbDrone.Core.ImportLists.ImportListItems
{
return Query(x => listIds.Contains(x.ImportListId));
}
public bool Exists(int tvdbId, string imdbId)
{
List<ImportListItemInfo> items;
if (string.IsNullOrWhiteSpace(imdbId))
{
items = Query(x => x.TvdbId == tvdbId);
}
else
{
items = Query(x => x.TvdbId == tvdbId || x.ImdbId == imdbId);
}
return items.Any();
}
}
}

@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser.Model;
@ -10,21 +9,18 @@ namespace NzbDrone.Core.ImportLists.ImportListItems
{
public interface IImportListItemService
{
List<ImportListItemInfo> All();
List<ImportListItemInfo> GetAllForLists(List<int> listIds);
int SyncSeriesForList(List<ImportListItemInfo> listSeries, int listId);
bool Exists(int tvdbId, string imdbId);
}
public class ImportListItemService : IImportListItemService, IHandleAsync<ProviderDeletedEvent<IImportList>>
{
private readonly IImportListItemInfoRepository _importListSeriesRepository;
private readonly Logger _logger;
private readonly IImportListItemRepository _importListItemRepository;
public ImportListItemService(IImportListItemInfoRepository importListSeriesRepository,
Logger logger)
public ImportListItemService(IImportListItemRepository importListItemRepository)
{
_importListSeriesRepository = importListSeriesRepository;
_logger = logger;
_importListItemRepository = importListItemRepository;
}
public int SyncSeriesForList(List<ImportListItemInfo> listSeries, int listId)
@ -58,27 +54,27 @@ namespace NzbDrone.Core.ImportLists.ImportListItems
existingItem.ReleaseDate = item.ReleaseDate;
});
_importListSeriesRepository.InsertMany(toAdd);
_importListSeriesRepository.UpdateMany(toUpdate);
_importListSeriesRepository.DeleteMany(existingListSeries);
_importListItemRepository.InsertMany(toAdd);
_importListItemRepository.UpdateMany(toUpdate);
_importListItemRepository.DeleteMany(existingListSeries);
return existingListSeries.Count;
}
public List<ImportListItemInfo> GetAllForLists(List<int> listIds)
public List<ImportListItemInfo> All()
{
return _importListSeriesRepository.GetAllForLists(listIds).ToList();
return _importListItemRepository.All().ToList();
}
public void HandleAsync(ProviderDeletedEvent<IImportList> message)
public List<ImportListItemInfo> GetAllForLists(List<int> listIds)
{
var seriesOnList = _importListSeriesRepository.GetAllForLists(new List<int> { message.ProviderId });
_importListSeriesRepository.DeleteMany(seriesOnList);
return _importListItemRepository.GetAllForLists(listIds).ToList();
}
public bool Exists(int tvdbId, string imdbId)
public void HandleAsync(ProviderDeletedEvent<IImportList> message)
{
return _importListSeriesRepository.Exists(tvdbId, imdbId);
var seriesOnList = _importListItemRepository.GetAllForLists(new List<int> { message.ProviderId });
_importListItemRepository.DeleteMany(seriesOnList);
}
private ImportListItemInfo FindItem(List<ImportListItemInfo> existingItems, ImportListItemInfo item)

@ -299,12 +299,18 @@ namespace NzbDrone.Core.ImportLists
var seriesToUpdate = new List<Series>();
var seriesInLibrary = _seriesService.GetAllSeries();
var allListItems = _importListItemService.All();
foreach (var series in seriesInLibrary)
{
var seriesExists = _importListItemService.Exists(series.TvdbId, series.ImdbId);
if (!seriesExists)
var seriesExists = allListItems.Where(l =>
l.TvdbId == series.TvdbId ||
l.ImdbId == series.ImdbId ||
l.TmdbId == series.TmdbId ||
series.MalIds.Contains(l.MalId) ||
series.AniListIds.Contains(l.AniListId)).ToList();
if (!seriesExists.Any())
{
switch (_configService.ListSyncLevel)
{

@ -24,7 +24,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
public int? TvRageId { get; set; }
public int? TvMazeId { get; set; }
public int? TmdbId { get; set; }
public HashSet<int> MalIds { get; set; }
public HashSet<int> AniListIds { get; set; }
public string Status { get; set; }
public int? Runtime { get; set; }
public TimeOfDayResource TimeOfDay { get; set; }

@ -194,6 +194,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
}
series.ImdbId = show.ImdbId;
series.MalIds = show.MalIds;
series.AniListIds = show.AniListIds;
series.Title = show.Title;
series.CleanTitle = Parser.Parser.CleanSeriesTitle(show.Title);
series.SortTitle = SeriesTitleNormalizer.Normalize(show.Title, show.TvdbId);

@ -94,6 +94,8 @@ namespace NzbDrone.Core.Tv
series.TvMazeId = seriesInfo.TvMazeId;
series.TmdbId = seriesInfo.TmdbId;
series.ImdbId = seriesInfo.ImdbId;
series.MalIds = seriesInfo.MalIds;
series.AniListIds = seriesInfo.AniListIds;
series.AirTime = seriesInfo.AirTime;
series.Overview = seriesInfo.Overview;
series.OriginalLanguage = seriesInfo.OriginalLanguage;

@ -17,6 +17,8 @@ namespace NzbDrone.Core.Tv
Seasons = new List<Season>();
Tags = new HashSet<int>();
OriginalLanguage = Language.English;
MalIds = new HashSet<int>();
AniListIds = new HashSet<int>();
}
public int TvdbId { get; set; }
@ -24,6 +26,8 @@ namespace NzbDrone.Core.Tv
public int TvMazeId { get; set; }
public string ImdbId { get; set; }
public int TmdbId { get; set; }
public HashSet<int> MalIds { get; set; }
public HashSet<int> AniListIds { get; set; }
public string Title { get; set; }
public string CleanTitle { get; set; }
public string SortTitle { get; set; }

Loading…
Cancel
Save