diff --git a/src/Sonarr.Api.V5/Blocklist/BlocklistBulkResource.cs b/src/Sonarr.Api.V5/Blocklist/BlocklistBulkResource.cs new file mode 100644 index 000000000..5ae838809 --- /dev/null +++ b/src/Sonarr.Api.V5/Blocklist/BlocklistBulkResource.cs @@ -0,0 +1,6 @@ +namespace Sonarr.Api.V5.Blocklist; + +public class BlocklistBulkResource +{ + public required List Ids { get; set; } +} diff --git a/src/Sonarr.Api.V5/Blocklist/BlocklistController.cs b/src/Sonarr.Api.V5/Blocklist/BlocklistController.cs new file mode 100644 index 000000000..22b27d3cf --- /dev/null +++ b/src/Sonarr.Api.V5/Blocklist/BlocklistController.cs @@ -0,0 +1,70 @@ +using Microsoft.AspNetCore.Mvc; +using NzbDrone.Core.Blocklisting; +using NzbDrone.Core.CustomFormats; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Indexers; +using Sonarr.Http; +using Sonarr.Http.Extensions; +using Sonarr.Http.REST.Attributes; + +namespace Sonarr.Api.V5.Blocklist; + +[V5ApiController] +public class BlocklistController : Controller +{ + private readonly IBlocklistService _blocklistService; + private readonly ICustomFormatCalculationService _formatCalculator; + + public BlocklistController(IBlocklistService blocklistService, + ICustomFormatCalculationService formatCalculator) + { + _blocklistService = blocklistService; + _formatCalculator = formatCalculator; + } + + [HttpGet] + [Produces("application/json")] + public PagingResource GetBlocklist([FromQuery] PagingRequestResource paging, [FromQuery] int[]? seriesIds = null, [FromQuery] DownloadProtocol[]? protocols = null) + { + var pagingResource = new PagingResource(paging); + var pagingSpec = pagingResource.MapToPagingSpec( + new HashSet(StringComparer.OrdinalIgnoreCase) + { + "date", + "indexer", + "series.sortTitle", + "sourceTitle" + }, + "date", + SortDirection.Descending); + + if (seriesIds?.Any() == true) + { + pagingSpec.FilterExpressions.Add(b => seriesIds.Contains(b.SeriesId)); + } + + if (protocols?.Any() == true) + { + pagingSpec.FilterExpressions.Add(b => protocols.Contains(b.Protocol)); + } + + return pagingSpec.ApplyToPage(b => _blocklistService.Paged(pagingSpec), b => BlocklistResourceMapper.MapToResource(b, _formatCalculator)); + } + + [RestDeleteById] + public ActionResult DeleteBlocklist(int id) + { + _blocklistService.Delete(id); + + return NoContent(); + } + + [HttpDelete("bulk")] + [Produces("application/json")] + public ActionResult Remove([FromBody] BlocklistBulkResource resource) + { + _blocklistService.Delete(resource.Ids); + + return NoContent(); + } +} diff --git a/src/Sonarr.Api.V5/Blocklist/BlocklistResource.cs b/src/Sonarr.Api.V5/Blocklist/BlocklistResource.cs new file mode 100644 index 000000000..f909e0c18 --- /dev/null +++ b/src/Sonarr.Api.V5/Blocklist/BlocklistResource.cs @@ -0,0 +1,49 @@ +using NzbDrone.Core.CustomFormats; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Languages; +using NzbDrone.Core.Qualities; +using Sonarr.Api.V5.CustomFormats; +using Sonarr.Api.V5.Series; +using Sonarr.Http.REST; + +namespace Sonarr.Api.V5.Blocklist; + +public class BlocklistResource : RestResource +{ + public int SeriesId { get; set; } + public required List EpisodeIds { get; set; } + public required string SourceTitle { get; set; } + public required List Languages { get; set; } + public required QualityModel Quality { get; set; } + public required List CustomFormats { get; set; } + public DateTime Date { get; set; } + public DownloadProtocol Protocol { get; set; } + public string? Indexer { get; set; } + public string? Message { get; set; } + public string? Source { get; set; } + + public required SeriesResource Series { get; set; } +} + +public static class BlocklistResourceMapper +{ + public static BlocklistResource MapToResource(this NzbDrone.Core.Blocklisting.Blocklist model, ICustomFormatCalculationService formatCalculator) + { + return new BlocklistResource + { + Id = model.Id, + SeriesId = model.SeriesId, + EpisodeIds = model.EpisodeIds, + SourceTitle = model.SourceTitle, + Languages = model.Languages, + Quality = model.Quality, + CustomFormats = formatCalculator.ParseCustomFormat(model, model.Series).ToResource(false), + Date = model.Date, + Protocol = model.Protocol, + Indexer = model.Indexer, + Message = model.Message, + Source = model.Source, + Series = model.Series.ToResource() + }; + } +} diff --git a/src/Sonarr.Api.V5/Queue/QueueController.cs b/src/Sonarr.Api.V5/Queue/QueueController.cs index 784f3b121..5418b898e 100644 --- a/src/Sonarr.Api.V5/Queue/QueueController.cs +++ b/src/Sonarr.Api.V5/Queue/QueueController.cs @@ -76,7 +76,7 @@ namespace Sonarr.Api.V5.Queue { Remove(pendingRelease, message, blocklist); - return Deleted(); + return NoContent(); } var trackedDownload = GetTrackedDownload(id); @@ -89,7 +89,7 @@ namespace Sonarr.Api.V5.Queue Remove(trackedDownload, message, removeFromClient, blocklist, skipRedownload, changeCategory); _trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId); - return Deleted(); + return NoContent(); } [HttpDelete("bulk")] @@ -130,7 +130,7 @@ namespace Sonarr.Api.V5.Queue _trackedDownloadService.StopTracking(trackedDownloadIds); - return new { }; + return NoContent(); } [HttpGet] diff --git a/src/Sonarr.Http/REST/RestController.cs b/src/Sonarr.Http/REST/RestController.cs index 7b118b072..ee32c6a09 100644 --- a/src/Sonarr.Http/REST/RestController.cs +++ b/src/Sonarr.Http/REST/RestController.cs @@ -167,10 +167,5 @@ namespace Sonarr.Http.REST var result = GetResourceById(id); return CreatedAtAction(nameof(GetResourceByIdWithErrorHandler), new { id = id }, result); } - - protected ActionResult Deleted() - { - return NoContent(); - } } }