mirror of
https://github.com/Sonarr/Sonarr.git
synced 2025-04-23 22:07:07 -04:00
Fixed: Improve synchronization logic for import list items
Closes #7511
This commit is contained in:
parent
ef358e6f24
commit
8cd5cd603a
2 changed files with 294 additions and 26 deletions
|
@ -12,46 +12,256 @@ namespace NzbDrone.Core.Test.ImportListTests
|
|||
{
|
||||
public class ImportListItemServiceFixture : CoreTest<ImportListItemService>
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
private void GivenExisting(List<ImportListItemInfo> existing)
|
||||
{
|
||||
var existing = Builder<ImportListItemInfo>.CreateListOfSize(3)
|
||||
.TheFirst(1)
|
||||
.With(s => s.TvdbId = 6)
|
||||
.With(s => s.ImdbId = "6")
|
||||
.TheNext(1)
|
||||
.With(s => s.TvdbId = 7)
|
||||
.With(s => s.ImdbId = "7")
|
||||
.TheNext(1)
|
||||
.With(s => s.TvdbId = 8)
|
||||
.With(s => s.ImdbId = "8")
|
||||
.Build().ToList();
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Setup(v => v.GetAllForLists(It.IsAny<List<int>>()))
|
||||
.Returns(existing);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_insert_new_update_existing_and_delete_missing()
|
||||
public void should_insert_new_update_existing_and_delete_missing_based_on_tvdb_id()
|
||||
{
|
||||
var newItems = Builder<ImportListItemInfo>.CreateListOfSize(3)
|
||||
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.TheFirst(1)
|
||||
.With(s => s.TvdbId = 5)
|
||||
.TheNext(1)
|
||||
.With(s => s.TvdbId = 6)
|
||||
.TheNext(1)
|
||||
.With(s => s.TvdbId = 7)
|
||||
.Build().ToList();
|
||||
|
||||
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 5)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.Build();
|
||||
|
||||
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 6)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.Build();
|
||||
|
||||
GivenExisting(existing);
|
||||
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||
|
||||
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||
|
||||
numDeleted.Should().Be(1);
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == 5)), Times.Once());
|
||||
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == newItem.TvdbId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 2 && s[0].TvdbId == 6 && s[1].TvdbId == 7)), Times.Once());
|
||||
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == updatedItem.TvdbId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == 8)), Times.Once());
|
||||
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId != newItem.TvdbId && s[0].TvdbId != updatedItem.TvdbId)), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_insert_new_update_existing_and_delete_missing_based_on_imdb_id()
|
||||
{
|
||||
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.TheFirst(1)
|
||||
.With(s => s.ImdbId = "6")
|
||||
.TheNext(1)
|
||||
.With(s => s.ImdbId = "7")
|
||||
.Build().ToList();
|
||||
|
||||
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = "5")
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.Build();
|
||||
|
||||
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = "6")
|
||||
.With(s => s.TmdbId = 6)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.Build();
|
||||
|
||||
GivenExisting(existing);
|
||||
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||
|
||||
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||
|
||||
numDeleted.Should().Be(1);
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId == newItem.ImdbId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId == updatedItem.ImdbId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId != newItem.ImdbId && s[0].ImdbId != updatedItem.ImdbId)), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_insert_new_update_existing_and_delete_missing_based_on_tmdb_id()
|
||||
{
|
||||
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.TheFirst(1)
|
||||
.With(s => s.TmdbId = 6)
|
||||
.TheNext(1)
|
||||
.With(s => s.TmdbId = 7)
|
||||
.Build().ToList();
|
||||
|
||||
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 5)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.Build();
|
||||
|
||||
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 6)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.Build();
|
||||
|
||||
GivenExisting(existing);
|
||||
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||
|
||||
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||
|
||||
numDeleted.Should().Be(1);
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId == newItem.TmdbId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId == updatedItem.TmdbId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId != newItem.TmdbId && s[0].TmdbId != updatedItem.TmdbId)), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_insert_new_update_existing_and_delete_missing_based_on_mal_id()
|
||||
{
|
||||
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.TheFirst(1)
|
||||
.With(s => s.MalId = 6)
|
||||
.TheNext(1)
|
||||
.With(s => s.MalId = 7)
|
||||
.Build().ToList();
|
||||
|
||||
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 5)
|
||||
.With(s => s.AniListId = 0)
|
||||
.Build();
|
||||
|
||||
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 6)
|
||||
.With(s => s.AniListId = 0)
|
||||
.Build();
|
||||
|
||||
GivenExisting(existing);
|
||||
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||
|
||||
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||
|
||||
numDeleted.Should().Be(1);
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId == newItem.MalId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId == updatedItem.MalId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId != newItem.MalId && s[0].MalId != updatedItem.MalId)), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_insert_new_update_existing_and_delete_missing_based_on_anilist_id()
|
||||
{
|
||||
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 0)
|
||||
.TheFirst(1)
|
||||
.With(s => s.AniListId = 6)
|
||||
.TheNext(1)
|
||||
.With(s => s.AniListId = 7)
|
||||
.Build().ToList();
|
||||
|
||||
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 5)
|
||||
.Build();
|
||||
|
||||
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||
.With(s => s.TvdbId = 0)
|
||||
.With(s => s.ImdbId = null)
|
||||
.With(s => s.TmdbId = 0)
|
||||
.With(s => s.MalId = 0)
|
||||
.With(s => s.AniListId = 6)
|
||||
.Build();
|
||||
|
||||
GivenExisting(existing);
|
||||
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||
|
||||
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||
|
||||
numDeleted.Should().Be(1);
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId == newItem.AniListId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId == updatedItem.AniListId)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
||||
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId != newItem.AniListId && s[0].AniListId != updatedItem.AniListId)), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider.Events;
|
||||
|
@ -30,14 +31,38 @@ namespace NzbDrone.Core.ImportLists.ImportListItems
|
|||
{
|
||||
var existingListSeries = GetAllForLists(new List<int> { listId });
|
||||
|
||||
listSeries.ForEach(l => l.Id = existingListSeries.FirstOrDefault(e => e.TvdbId == l.TvdbId)?.Id ?? 0);
|
||||
var toAdd = new List<ImportListItemInfo>();
|
||||
var toUpdate = new List<ImportListItemInfo>();
|
||||
|
||||
_importListSeriesRepository.InsertMany(listSeries.Where(l => l.Id == 0).ToList());
|
||||
_importListSeriesRepository.UpdateMany(listSeries.Where(l => l.Id > 0).ToList());
|
||||
var toDelete = existingListSeries.Where(l => !listSeries.Any(x => x.TvdbId == l.TvdbId)).ToList();
|
||||
_importListSeriesRepository.DeleteMany(toDelete);
|
||||
listSeries.ForEach(item =>
|
||||
{
|
||||
var existingItem = FindItem(existingListSeries, item);
|
||||
|
||||
return toDelete.Count;
|
||||
if (existingItem == null)
|
||||
{
|
||||
toAdd.Add(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove so we'll only be left with items to remove at the end
|
||||
existingListSeries.Remove(existingItem);
|
||||
toUpdate.Add(existingItem);
|
||||
|
||||
existingItem.Title = item.Title;
|
||||
existingItem.Year = item.Year;
|
||||
existingItem.TvdbId = item.TvdbId;
|
||||
existingItem.ImdbId = item.ImdbId;
|
||||
existingItem.TmdbId = item.TmdbId;
|
||||
existingItem.MalId = item.MalId;
|
||||
existingItem.AniListId = item.AniListId;
|
||||
existingItem.ReleaseDate = item.ReleaseDate;
|
||||
});
|
||||
|
||||
_importListSeriesRepository.InsertMany(toAdd);
|
||||
_importListSeriesRepository.UpdateMany(toUpdate);
|
||||
_importListSeriesRepository.DeleteMany(existingListSeries);
|
||||
|
||||
return existingListSeries.Count;
|
||||
}
|
||||
|
||||
public List<ImportListItemInfo> GetAllForLists(List<int> listIds)
|
||||
|
@ -55,5 +80,38 @@ namespace NzbDrone.Core.ImportLists.ImportListItems
|
|||
{
|
||||
return _importListSeriesRepository.Exists(tvdbId, imdbId);
|
||||
}
|
||||
|
||||
private ImportListItemInfo FindItem(List<ImportListItemInfo> existingItems, ImportListItemInfo item)
|
||||
{
|
||||
return existingItems.FirstOrDefault(e =>
|
||||
{
|
||||
if (e.TvdbId > 0 && item.TvdbId > 0 && e.TvdbId == item.TvdbId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.ImdbId.IsNotNullOrWhiteSpace() && item.ImdbId.IsNotNullOrWhiteSpace() && e.ImdbId == item.ImdbId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.TmdbId > 0 && item.TmdbId > 0 && e.TmdbId == item.TmdbId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.MalId > 0 && item.MalId > 0 && e.MalId == item.MalId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.AniListId > 0 && item.AniListId > 0 && e.AniListId == item.AniListId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue