feature: CMS Opus status surfaces — backfill missing-N badge + upload Post-Processing phase (18.6)

This commit is contained in:
daniel-c-harvey
2026-06-23 14:06:21 -04:00
parent e5366bc4ec
commit 59f48bb8cb
9 changed files with 240 additions and 10 deletions
@@ -804,6 +804,50 @@ public class CmsTrackService : ICmsTrackService
}
}
public async Task<ResultContainer<OpusStatusDto[]>> GetOpusStatusAsync(CancellationToken ct = default)
{
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
HttpResponseMessage response;
try
{
response = await client.GetAsync("api/track/opus-status", ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Content API call failed for Opus status");
return ResultContainer<OpusStatusDto[]>.CreateFailResult("Content API is unreachable.");
}
using (response)
{
if (!response.IsSuccessStatusCode)
{
_logger.LogError("Content API Opus status failed: {Status}", (int)response.StatusCode);
return ResultContainer<OpusStatusDto[]>.CreateFailResult("Failed to load Opus status.");
}
OpusStatusDto[]? status;
try
{
status = await response.Content.ReadFromJsonAsync<OpusStatusDto[]>(ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to deserialize Opus status from Content API response");
return ResultContainer<OpusStatusDto[]>.CreateFailResult("Content API returned an unexpected response.");
}
if (status is null)
{
_logger.LogError("Content API returned a null Opus status list");
return ResultContainer<OpusStatusDto[]>.CreateFailResult("Content API returned an empty response.");
}
return ResultContainer<OpusStatusDto[]>.CreatePassResult(status);
}
}
public async Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default)
{
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
@@ -161,6 +161,14 @@ public interface ICmsTrackService
/// </summary>
Task<ResultContainer<OpusBackfillResult>> BackfillOpusAsync(CancellationToken ct = default);
/// <summary>
/// Fetch per-track Opus derive status from <c>GET api/track/opus-status</c> (Phase 18.6) for the CMS
/// Post-Processing surfaces. Unpaged — the admin catalogue is small. Each row's <c>HasOpus</c> is true only
/// when the track carries a complete Opus artifact (audio + sidecar). Drives the Backfill-Opus "missing N"
/// badge and the post-upload Post-Processing poll. Idempotent read — safe to poll on an interval.
/// </summary>
Task<ResultContainer<OpusStatusDto[]>> GetOpusStatusAsync(CancellationToken ct = default);
/// <summary>Returns all releases with track counts from GET api/track/albums.</summary>
Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default);