New: Speed up mass deletes from Series Editor

* New: Speed up mass deletes from Series Editor

* fixup! Additional speed up using GetAllSeriesPaths vs GetAllSeries

* fixup! Tests
This commit is contained in:
Qstick 2022-12-10 14:19:10 -06:00 committed by GitHub
parent d08f33ae21
commit 356771d139
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 290 additions and 86 deletions

View File

@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Blocklisting;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Blocklisting
{
@ -14,6 +16,8 @@ namespace NzbDrone.Core.Test.Blocklisting
public class BlocklistRepositoryFixture : DbTest<BlocklistRepository, Blocklist>
{
private Blocklist _blocklist;
private Series _series1;
private Series _series2;
[SetUp]
public void Setup()
@ -27,6 +31,14 @@ namespace NzbDrone.Core.Test.Blocklisting
SourceTitle = "series.title.s01e01",
Date = DateTime.UtcNow
};
_series1 = Builder<Series>.CreateNew()
.With(s => s.Id = 7)
.Build();
_series2 = Builder<Series>.CreateNew()
.With(s => s.Id = 8)
.Build();
}
[Test]
@ -51,5 +63,30 @@ namespace NzbDrone.Core.Test.Blocklisting
Subject.BlocklistedByTitle(_blocklist.SeriesId, _blocklist.SourceTitle.ToUpperInvariant()).Should().HaveCount(1);
}
[Test]
public void should_delete_blocklists_by_seriesId()
{
var blocklistItems = Builder<Blocklist>.CreateListOfSize(5)
.TheFirst(1)
.With(c => c.SeriesId = _series2.Id)
.TheRest()
.With(c => c.SeriesId = _series1.Id)
.All()
.With(c => c.Quality = new QualityModel())
.With(c => c.Languages = new List<Language>())
.With(c => c.EpisodeIds = new List<int> { 1 })
.BuildListOfNew();
Db.InsertMany(blocklistItems);
Subject.DeleteForSeriesIds(new List<int> { _series1.Id });
var removedSeriesBlocklists = Subject.BlocklistedBySeries(_series1.Id);
var nonRemovedSeriesBlocklists = Subject.BlocklistedBySeries(_series2.Id);
removedSeriesBlocklists.Should().HaveCount(0);
nonRemovedSeriesBlocklists.Should().HaveCount(1);
}
}
}

View File

@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Download.History;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Download.DownloadHistoryTests
{
[TestFixture]
public class DownloadHistoryRepositoryFixture : DbTest<DownloadHistoryRepository, DownloadHistory>
{
private Series _series1;
private Series _series2;
[SetUp]
public void Setup()
{
_series1 = Builder<Series>.CreateNew()
.With(s => s.Id = 7)
.Build();
_series2 = Builder<Series>.CreateNew()
.With(s => s.Id = 8)
.Build();
}
[Test]
public void should_delete_history_items_by_seriesId()
{
var items = Builder<DownloadHistory>.CreateListOfSize(5)
.TheFirst(1)
.With(c => c.Id = 0)
.With(c => c.SeriesId = _series2.Id)
.TheRest()
.With(c => c.Id = 0)
.With(c => c.SeriesId = _series1.Id)
.BuildListOfNew();
Db.InsertMany(items);
Subject.DeleteBySeriesIds(new List<int> { _series1.Id });
var removedItems = Subject.All().Where(h => h.SeriesId == _series1.Id);
var nonRemovedItems = Subject.All().Where(h => h.SeriesId == _series2.Id);
removedItems.Should().HaveCount(0);
nonRemovedItems.Should().HaveCount(1);
}
}
}

View File

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Moq;
@ -320,7 +320,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<int>(), null))
.Returns(default(RemoteEpisode));
Subject.Handle(new SeriesDeletedEvent(remoteEpisode.Series, true, true));
Subject.Handle(new SeriesDeletedEvent(new List<Series> { remoteEpisode.Series }, true, true));
var trackedDownloads = Subject.GetTrackedDownloads();
trackedDownloads.Should().HaveCount(1);

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
@ -6,12 +7,28 @@ using NzbDrone.Core.History;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.HistoryTests
{
[TestFixture]
public class HistoryRepositoryFixture : DbTest<HistoryRepository, EpisodeHistory>
{
private Series _series1;
private Series _series2;
[SetUp]
public void Setup()
{
_series1 = Builder<Series>.CreateNew()
.With(s => s.Id = 7)
.Build();
_series2 = Builder<Series>.CreateNew()
.With(s => s.Id = 8)
.Build();
}
[Test]
public void should_read_write_dictionary()
{
@ -52,5 +69,32 @@ namespace NzbDrone.Core.Test.HistoryTests
downloadHistory.Should().HaveCount(1);
}
[Test]
public void should_delete_history_items_by_seriesId()
{
var items = Builder<EpisodeHistory>.CreateListOfSize(5)
.TheFirst(1)
.With(c => c.SeriesId = _series2.Id)
.TheRest()
.With(c => c.SeriesId = _series1.Id)
.All()
.With(c => c.Id = 0)
.With(c => c.Quality = new QualityModel(Quality.Bluray1080p))
.With(c => c.Languages = new List<Language> { Language.English })
.With(c => c.EventType = EpisodeHistoryEventType.Grabbed)
.BuildListOfNew();
Db.InsertMany(items);
Subject.DeleteForSeries(new List<int> { _series1.Id });
var dbItems = Subject.All();
var removedItems = dbItems.Where(h => h.SeriesId == _series1.Id);
var nonRemovedItems = dbItems.Where(h => h.SeriesId == _series2.Id);
removedItems.Should().HaveCount(0);
nonRemovedItems.Should().HaveCount(1);
}
}
}

View File

@ -6,12 +6,28 @@ using NzbDrone.Core.Languages;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.MediaFiles
{
[TestFixture]
public class MediaFileRepositoryFixture : DbTest<MediaFileRepository, EpisodeFile>
{
private Series _series1;
private Series _series2;
[SetUp]
public void Setup()
{
_series1 = Builder<Series>.CreateNew()
.With(s => s.Id = 7)
.Build();
_series2 = Builder<Series>.CreateNew()
.With(s => s.Id = 8)
.Build();
}
[Test]
public void get_files_by_series()
{
@ -31,5 +47,30 @@ namespace NzbDrone.Core.Test.MediaFiles
seriesFiles.Should().HaveCount(4);
seriesFiles.Should().OnlyContain(c => c.SeriesId == 12);
}
[Test]
public void should_delete_files_by_seriesId()
{
var items = Builder<EpisodeFile>.CreateListOfSize(5)
.TheFirst(1)
.With(c => c.SeriesId = _series2.Id)
.TheRest()
.With(c => c.SeriesId = _series1.Id)
.All()
.With(c => c.Id = 0)
.With(c => c.Quality = new QualityModel(Quality.Bluray1080p))
.With(c => c.Languages = new List<Language> { Language.English })
.BuildListOfNew();
Db.InsertMany(items);
Subject.DeleteForSeries(new List<int> { _series1.Id });
var removedItems = Subject.GetFilesBySeries(_series1.Id);
var nonRemovedItems = Subject.GetFilesBySeries(_series2.Id);
removedItems.Should().HaveCount(0);
nonRemovedItems.Should().HaveCount(1);
}
}
}

View File

@ -10,6 +10,7 @@ namespace NzbDrone.Core.Blocklisting
List<Blocklist> BlocklistedByTitle(int seriesId, string sourceTitle);
List<Blocklist> BlocklistedByTorrentInfoHash(int seriesId, string torrentInfoHash);
List<Blocklist> BlocklistedBySeries(int seriesId);
void DeleteForSeriesIds(List<int> seriesIds);
}
public class BlocklistRepository : BasicRepository<Blocklist>, IBlocklistRepository
@ -34,6 +35,11 @@ namespace NzbDrone.Core.Blocklisting
return Query(b => b.SeriesId == seriesId);
}
public void DeleteForSeriesIds(List<int> seriesIds)
{
Delete(x => seriesIds.Contains(x.SeriesId));
}
protected override SqlBuilder PagedBuilder() => new SqlBuilder().Join<Blocklist, Series>((b, m) => b.SeriesId == m.Id);
protected override IEnumerable<Blocklist> PagedQuery(SqlBuilder sql) => _database.QueryJoined<Blocklist, Series>(sql, (bl, movie) =>
{

View File

@ -189,9 +189,7 @@ namespace NzbDrone.Core.Blocklisting
public void HandleAsync(SeriesDeletedEvent message)
{
var blocklisted = _blocklistRepository.BlocklistedBySeries(message.Series.Id);
_blocklistRepository.DeleteMany(blocklisted);
_blocklistRepository.DeleteForSeriesIds(message.Series.Select(m => m.Id).ToList());
}
}
}

View File

@ -8,7 +8,7 @@ namespace NzbDrone.Core.Download.History
public interface IDownloadHistoryRepository : IBasicRepository<DownloadHistory>
{
List<DownloadHistory> FindByDownloadId(string downloadId);
void DeleteBySeriesId(int seriesId);
void DeleteBySeriesIds(List<int> seriesIds);
}
public class DownloadHistoryRepository : BasicRepository<DownloadHistory>, IDownloadHistoryRepository
@ -23,9 +23,9 @@ namespace NzbDrone.Core.Download.History
return Query(h => h.DownloadId == downloadId).OrderByDescending(h => h.Date).ToList();
}
public void DeleteBySeriesId(int seriesId)
public void DeleteBySeriesIds(List<int> seriesIds)
{
Delete(r => r.SeriesId == seriesId);
Delete(r => seriesIds.Contains(r.SeriesId));
}
}
}

View File

@ -230,7 +230,7 @@ namespace NzbDrone.Core.Download.History
public void Handle(SeriesDeletedEvent message)
{
_repository.DeleteBySeriesId(message.Series.Id);
_repository.DeleteBySeriesIds(message.Series.Select(m => m.Id).ToList());
}
}
}

View File

@ -6,7 +6,7 @@ namespace NzbDrone.Core.Download.Pending
{
public interface IPendingReleaseRepository : IBasicRepository<PendingRelease>
{
void DeleteBySeriesId(int seriesId);
void DeleteBySeriesIds(List<int> seriesIds);
List<PendingRelease> AllBySeriesId(int seriesId);
List<PendingRelease> WithoutFallback();
}
@ -18,9 +18,9 @@ namespace NzbDrone.Core.Download.Pending
{
}
public void DeleteBySeriesId(int seriesId)
public void DeleteBySeriesIds(List<int> seriesIds)
{
Delete(r => r.SeriesId == seriesId);
Delete(r => seriesIds.Contains(r.SeriesId));
}
public List<PendingRelease> AllBySeriesId(int seriesId)

View File

@ -451,7 +451,7 @@ namespace NzbDrone.Core.Download.Pending
public void Handle(SeriesDeletedEvent message)
{
_repository.DeleteBySeriesId(message.Series.Id);
_repository.DeleteBySeriesIds(message.Series.Select(m => m.Id).ToList());
}
public void Handle(EpisodeGrabbedEvent message)

View File

@ -260,7 +260,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
{
var cachedItems = _cache.Values.Where(t =>
t.RemoteEpisode?.Series != null &&
t.RemoteEpisode.Series.Id == message.Series.Id)
message.Series.Any(s => s.Id == t.RemoteEpisode.Series.Id))
.ToList();
if (cachedItems.Any())

View File

@ -8,7 +8,7 @@ namespace NzbDrone.Core.Extras.Files
public interface IExtraFileRepository<TExtraFile> : IBasicRepository<TExtraFile>
where TExtraFile : ExtraFile, new()
{
void DeleteForSeries(int seriesId);
void DeleteForSeriesIds(List<int> seriesIds);
void DeleteForSeason(int seriesId, int seasonNumber);
void DeleteForEpisodeFile(int episodeFileId);
List<TExtraFile> GetFilesBySeries(int seriesId);
@ -25,9 +25,9 @@ namespace NzbDrone.Core.Extras.Files
{
}
public void DeleteForSeries(int seriesId)
public void DeleteForSeriesIds(List<int> seriesIds)
{
Delete(c => c.SeriesId == seriesId);
Delete(c => seriesIds.Contains(c.SeriesId));
}
public void DeleteForSeason(int seriesId, int seasonNumber)

View File

@ -97,8 +97,8 @@ namespace NzbDrone.Core.Extras.Files
public void HandleAsync(SeriesDeletedEvent message)
{
_logger.Debug("Deleting Extra from database for series: {0}", message.Series);
_repository.DeleteForSeries(message.Series.Id);
_logger.Debug("Deleting Extra from database for series: {0}", string.Join(',', message.Series));
_repository.DeleteForSeriesIds(message.Series.Select(m => m.Id).ToList());
}
public void Handle(EpisodeFileDeletedEvent message)

View File

@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv;
@ -41,7 +41,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
public bool ShouldCheckOnEvent(SeriesDeletedEvent deletedEvent)
{
return deletedEvent.Series.Status == SeriesStatusType.Deleted;
return deletedEvent.Series.Any(s => s.Status == SeriesStatusType.Deleted);
}
public bool ShouldCheckOnEvent(SeriesUpdatedEvent updatedEvent)

View File

@ -17,7 +17,7 @@ namespace NzbDrone.Core.History
List<EpisodeHistory> GetBySeries(int seriesId, EpisodeHistoryEventType? eventType);
List<EpisodeHistory> GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType);
List<EpisodeHistory> FindDownloadHistory(int idSeriesId, QualityModel quality);
void DeleteForSeries(int seriesId);
void DeleteForSeries(List<int> seriesIds);
List<EpisodeHistory> Since(DateTime date, EpisodeHistoryEventType? eventType);
}
@ -100,9 +100,9 @@ namespace NzbDrone.Core.History
.ToList();
}
public void DeleteForSeries(int seriesId)
public void DeleteForSeries(List<int> seriesIds)
{
Delete(c => c.SeriesId == seriesId);
Delete(c => seriesIds.Contains(c.SeriesId));
}
protected override SqlBuilder PagedBuilder() => new SqlBuilder()

View File

@ -343,7 +343,7 @@ namespace NzbDrone.Core.History
public void Handle(SeriesDeletedEvent message)
{
_historyRepository.DeleteForSeries(message.Series.Id);
_historyRepository.DeleteForSeries(message.Series.Select(m => m.Id).ToList());
}
public List<EpisodeHistory> Since(DateTime date, EpisodeHistoryEventType? eventType)

View File

@ -61,20 +61,25 @@ namespace NzbDrone.Core.ImportLists.Exclusions
return;
}
var existingExclusion = _repo.FindByTvdbId(message.Series.TvdbId);
var exclusionsToAdd = new List<ImportListExclusion>();
if (existingExclusion != null)
foreach (var series in message.Series.DistinctBy(s => s.TvdbId))
{
return;
var existingExclusion = _repo.FindByTvdbId(series.TvdbId);
if (existingExclusion != null)
{
continue;
}
exclusionsToAdd.Add(new ImportListExclusion
{
TvdbId = series.TvdbId,
Title = series.Title
});
}
var importExclusion = new ImportListExclusion
{
TvdbId = message.Series.TvdbId,
Title = message.Series.Title
};
_repo.Insert(importExclusion);
_repo.InsertMany(exclusionsToAdd);
}
}
}

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
@ -217,10 +217,13 @@ namespace NzbDrone.Core.MediaCover
public void HandleAsync(SeriesDeletedEvent message)
{
var path = GetSeriesCoverPath(message.Series.Id);
if (_diskProvider.FolderExists(path))
foreach (var series in message.Series)
{
_diskProvider.DeleteFolder(path, true);
var path = GetSeriesCoverPath(series.Id);
if (_diskProvider.FolderExists(path))
{
_diskProvider.DeleteFolder(path, true);
}
}
}
}

View File

@ -92,35 +92,37 @@ namespace NzbDrone.Core.MediaFiles
{
if (message.DeleteFiles)
{
var series = message.Series;
var allSeries = _seriesService.GetAllSeries();
var allSeries = _seriesService.GetAllSeriesPaths();
foreach (var s in allSeries)
foreach (var series in message.Series)
{
if (s.Id == series.Id)
foreach (var s in allSeries)
{
continue;
if (s.Key == series.Id)
{
continue;
}
if (series.Path.IsParentPath(s.Value))
{
_logger.Error("Series path: '{0}' is a parent of another series, not deleting files.", series.Path);
return;
}
if (series.Path.PathEquals(s.Value))
{
_logger.Error("Series path: '{0}' is the same as another series, not deleting files.", series.Path);
return;
}
}
if (series.Path.IsParentPath(s.Path))
if (_diskProvider.FolderExists(series.Path))
{
_logger.Error("Series path: '{0}' is a parent of another series, not deleting files.", series.Path);
return;
_recycleBinProvider.DeleteFolder(series.Path);
}
if (series.Path.PathEquals(s.Path))
{
_logger.Error("Series path: '{0}' is the same as another series, not deleting files.", series.Path);
return;
}
_eventAggregator.PublishEvent(new DeleteCompletedEvent());
}
if (_diskProvider.FolderExists(message.Series.Path))
{
_recycleBinProvider.DeleteFolder(message.Series.Path);
}
_eventAggregator.PublishEvent(new DeleteCompletedEvent());
}
}

View File

@ -11,6 +11,7 @@ namespace NzbDrone.Core.MediaFiles
List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber);
List<EpisodeFile> GetFilesWithoutMediaInfo();
List<EpisodeFile> GetFilesWithRelativePath(int seriesId, string relativePath);
void DeleteForSeries(List<int> seriesIds);
}
public class MediaFileRepository : BasicRepository<EpisodeFile>, IMediaFileRepository
@ -40,5 +41,10 @@ namespace NzbDrone.Core.MediaFiles
return Query(c => c.SeriesId == seriesId && c.RelativePath == relativePath)
.ToList();
}
public void DeleteForSeries(List<int> seriesIds)
{
Delete(x => seriesIds.Contains(x.SeriesId));
}
}
}

View File

@ -110,8 +110,7 @@ namespace NzbDrone.Core.MediaFiles
public void HandleAsync(SeriesDeletedEvent message)
{
var files = GetFilesBySeries(message.Series.Id);
_mediaFileRepository.DeleteMany(files);
_mediaFileRepository.DeleteForSeries(message.Series.Select(s => s.Id).ToList());
}
public static List<string> FilterExistingFiles(List<string> files, List<EpisodeFile> seriesFiles, Series series)

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
@ -252,20 +252,23 @@ namespace NzbDrone.Core.Notifications
public void Handle(SeriesDeletedEvent message)
{
var deleteMessage = new SeriesDeleteMessage(message.Series, message.DeleteFiles);
foreach (var notification in _notificationFactory.OnSeriesDeleteEnabled())
foreach (var series in message.Series)
{
try
var deleteMessage = new SeriesDeleteMessage(series, message.DeleteFiles);
foreach (var notification in _notificationFactory.OnSeriesDeleteEnabled())
{
if (ShouldHandleSeries(notification.Definition, deleteMessage.Series))
try
{
notification.OnSeriesDelete(deleteMessage);
if (ShouldHandleSeries(notification.Definition, deleteMessage.Series))
{
notification.OnSeriesDelete(deleteMessage);
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to send OnDelete notification to: " + notification.Definition.Name);
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to send OnDelete notification to: " + notification.Definition.Name);
}
}
}

View File

@ -18,6 +18,7 @@ namespace NzbDrone.Core.Tv
List<Episode> Find(int seriesId, string date);
List<Episode> GetEpisodes(int seriesId);
List<Episode> GetEpisodes(int seriesId, int seasonNumber);
List<Episode> GetEpisodesBySeriesIds(List<int> seriesIds);
List<Episode> GetEpisodesBySceneSeason(int seriesId, int sceneSeasonNumber);
List<Episode> GetEpisodeByFileId(int fileId);
List<Episode> EpisodesWithFiles(int seriesId);
@ -77,6 +78,11 @@ namespace NzbDrone.Core.Tv
return Query(s => s.SeriesId == seriesId && s.SeasonNumber == seasonNumber).ToList();
}
public List<Episode> GetEpisodesBySeriesIds(List<int> seriesIds)
{
return Query(s => seriesIds.Contains(s.SeriesId)).ToList();
}
public List<Episode> GetEpisodesBySceneSeason(int seriesId, int seasonNumber)
{
return Query(s => s.SeriesId == seriesId && s.SceneSeasonNumber == seasonNumber).ToList();

View File

@ -211,7 +211,7 @@ namespace NzbDrone.Core.Tv
public void HandleAsync(SeriesDeletedEvent message)
{
var episodes = GetEpisodeBySeries(message.Series.Id);
var episodes = _episodeRepository.GetEpisodesBySeriesIds(message.Series.Select(s => s.Id).ToList());
_episodeRepository.DeleteMany(episodes);
}

View File

@ -1,14 +1,15 @@
using NzbDrone.Common.Messaging;
using System.Collections.Generic;
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.Tv.Events
{
public class SeriesDeletedEvent : IEvent
{
public Series Series { get; private set; }
public List<Series> Series { get; private set; }
public bool DeleteFiles { get; private set; }
public bool AddImportListExclusion { get; private set; }
public SeriesDeletedEvent(Series series, bool deleteFiles, bool addImportListExclusion)
public SeriesDeletedEvent(List<Series> series, bool deleteFiles, bool addImportListExclusion)
{
Series = series;
DeleteFiles = deleteFiles;

View File

@ -22,7 +22,7 @@ namespace NzbDrone.Core.Tv
Series FindByTitle(string title, int year);
Series FindByTitleInexact(string title);
Series FindByPath(string path);
void DeleteSeries(int seriesId, bool deleteFiles, bool addImportListExclusion);
void DeleteSeries(List<int> seriesIds, bool deleteFiles, bool addImportListExclusion);
List<Series> GetAllSeries();
List<int> AllSeriesTvdbIds();
Dictionary<int, string> GetAllSeriesPaths();
@ -149,10 +149,10 @@ namespace NzbDrone.Core.Tv
return _seriesRepository.FindByTitle(title.CleanSeriesTitle(), year);
}
public void DeleteSeries(int seriesId, bool deleteFiles, bool addImportListExclusion)
public void DeleteSeries(List<int> seriesIds, bool deleteFiles, bool addImportListExclusion)
{
var series = _seriesRepository.Get(seriesId);
_seriesRepository.Delete(seriesId);
var series = _seriesRepository.Get(seriesIds).ToList();
_seriesRepository.DeleteMany(seriesIds);
_eventAggregator.PublishEvent(new SeriesDeletedEvent(series, deleteFiles, addImportListExclusion));
}

View File

@ -172,7 +172,7 @@ namespace Sonarr.Api.V3.Series
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion");
_seriesService.DeleteSeries(id, deleteFiles, addImportListExclusion);
_seriesService.DeleteSeries(new List<int> { id }, deleteFiles, addImportListExclusion);
}
private SeriesResource GetSeriesResource(NzbDrone.Core.Tv.Series series, bool includeSeasonImages)
@ -292,7 +292,10 @@ namespace Sonarr.Api.V3.Series
[NonAction]
public void Handle(SeriesDeletedEvent message)
{
BroadcastResourceChange(ModelAction.Deleted, message.Series.ToResource());
foreach (var series in message.Series)
{
BroadcastResourceChange(ModelAction.Deleted, series.ToResource());
}
}
[NonAction]

View File

@ -94,10 +94,7 @@ namespace Sonarr.Api.V3.Series
[HttpDelete]
public object DeleteSeries([FromBody] SeriesEditorResource resource)
{
foreach (var seriesId in resource.SeriesIds)
{
_seriesService.DeleteSeries(seriesId, resource.DeleteFiles, resource.AddImportListExclusion);
}
_seriesService.DeleteSeries(resource.SeriesIds, resource.DeleteFiles, resource.AddImportListExclusion);
return new { };
}