using System.ComponentModel.DataAnnotations; using ErsatzTV.Application.Resolutions; using ErsatzTV.Controllers.Api.Requests; using ErsatzTV.Core; using ErsatzTV.Core.Api.Settings; using ErsatzTV.Extensions; using MediatR; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace ErsatzTV.Controllers.Api; [ApiController] [EndpointGroupName("general")] public class ResolutionController(IMediator mediator) : ControllerBase { [HttpGet("/api/ffmpeg/resolution/by-name/{name}", Name="GetResolutionByName")] public async Task> GetResolutionByName(string name, CancellationToken cancellationToken) { Option result = await mediator.Send(new GetResolutionByName(name), cancellationToken); return result.Match>(i => Ok(i), () => NotFound()); } [HttpGet("/api/settings/resolutions", Name = "GetResolutions")] [Tags("Settings")] [EndpointSummary("Get all resolutions, including custom resolutions")] [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] public async Task> GetAll(CancellationToken cancellationToken) { List resolutions = await mediator.Send(new GetAllResolutions(), cancellationToken); return resolutions.Map(ProjectToResponseModel).ToList(); } [HttpPost("/api/settings/resolutions", Name = "CreateResolution")] [Tags("Settings")] [EndpointSummary("Create a custom resolution")] [ProducesResponseType(typeof(ResolutionResponseModel), StatusCodes.Status201Created)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] public async Task Create( [Required] [FromBody] CreateResolutionRequest request, CancellationToken cancellationToken) { Option result = await mediator.Send(request.ToCommand(), cancellationToken); return await result.Match( Some: error => Task.FromResult(error.ToErrorResult()), None: async () => { string name = $"{request.Width}x{request.Height}"; Option resolution = await mediator.Send(new GetResolutionByName(name), cancellationToken); return resolution.Match( Some: vm => (IActionResult)new CreatedResult( $"/api/settings/resolutions/{vm.Id}", ProjectToResponseModel(vm)), None: () => ApiResults.NotFoundProblem()); }); } [HttpDelete("/api/settings/resolutions/{id:int}", Name = "DeleteResolution")] [Tags("Settings")] [EndpointSummary("Delete a custom resolution")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] public async Task Delete(int id, CancellationToken cancellationToken) { Option result = await mediator.Send(new DeleteCustomResolution(id), cancellationToken); return result.Match( Some: error => error.ToErrorResult(), None: () => new NoContentResult()); } private static ResolutionResponseModel ProjectToResponseModel(ResolutionViewModel vm) => new(vm.Id, vm.Name, vm.Width, vm.Height, vm.IsCustom); }