using System.Diagnostics; using ErsatzTV.Application.Libraries; using ErsatzTV.Core.Api.Libraries; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Extensions; using MediatR; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace ErsatzTV.Controllers.Api; [ApiController] [EndpointGroupName("general")] public class LibrariesController(ITelevisionRepository televisionRepository, IMediator mediator) : ControllerBase { [HttpGet("/api/libraries/scan-status", Name = "GetLibraryScanStatus")] [Tags("Libraries")] [EndpointSummary("Get active library scan status")] [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] public async Task> GetScanStatus(CancellationToken cancellationToken) => await mediator.Send(new GetLibraryScanStatus(), cancellationToken); [HttpPost("/api/libraries/{id:int}/scan")] [Tags("Libraries")] [EndpointSummary("Scan library")] [EndpointDescription("Queues a scan of the whole library. Pass ?deep=true for a deep (metadata-refresh) scan.")] [ProducesResponseType(StatusCodes.Status202Accepted)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status409Conflict)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] public async Task ScanLibrary( int id, [FromQuery] bool deep = false, CancellationToken cancellationToken = default) { QueueLibraryScanResult result = await mediator.Send(new QueueLibraryScanByLibraryId(id, deep), cancellationToken); return result switch { QueueLibraryScanResult.Queued => new AcceptedResult(), QueueLibraryScanResult.AlreadyScanning => ApiResults.ConflictProblem( "Library scan in progress", $"A scan for library {id} is already in progress."), QueueLibraryScanResult.SyncDisabled => new UnprocessableEntityObjectResult( new ProblemDetails { Status = StatusCodes.Status422UnprocessableEntity, Title = "Library sync is disabled", Detail = $"Item sync is disabled for library {id}." }), _ => ApiResults.NotFoundProblem($"Library {id} does not exist.") }; } [HttpPost("/api/libraries/{id:int}/scan-show")] [Tags("Libraries")] [EndpointSummary("Scan show")] [ProducesResponseType(StatusCodes.Status202Accepted)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status409Conflict)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] public async Task ScanShow(int id, [FromBody] ScanShowRequest request) { Option maybeTitle = await televisionRepository.GetShowTitle(id, request.ShowId); foreach (string title in maybeTitle) { QueueShowScanResult result = await mediator.Send(new QueueShowScanByLibraryId(id, request.ShowId, title, request.DeepScan)); return result switch { QueueShowScanResult.Queued => new AcceptedResult(), QueueShowScanResult.AlreadyScanning => ApiResults.ConflictProblem( "Library scan in progress", $"A scan for library {id} is already in progress; cannot scan an individual show."), QueueShowScanResult.SyncDisabled => new UnprocessableEntityObjectResult( new ProblemDetails { Status = StatusCodes.Status422UnprocessableEntity, Title = "Library sync is disabled", Detail = $"Item sync is disabled for library {id}." }), QueueShowScanResult.Unsupported => new UnprocessableEntityObjectResult( new ProblemDetails { Status = StatusCodes.Status422UnprocessableEntity, Title = "Single show scanning is not supported", Detail = $"Library {id} does not support scanning an individual show." }), QueueShowScanResult.ScanFailed => new UnprocessableEntityObjectResult( new ProblemDetails { Status = StatusCodes.Status422UnprocessableEntity, Title = "Unable to scan show", Detail = $"The scan for show {request.ShowId} in library {id} could not be completed." }), QueueShowScanResult.NotFound => ApiResults.NotFoundProblem($"Library {id} does not exist."), _ => throw new UnreachableException($"Unmapped QueueShowScanResult: {result}") }; } return ApiResults.NotFoundProblem($"Show {request.ShowId} does not exist in library {id}."); } } public record ScanShowRequest(int ShowId, bool DeepScan = false);