Wire Opus end-to-end playback + Backfill-Opus action (Phase 18.5)
Player picks Opus when the browser can decode it and a sidecar exists (else lossless), injecting the sidecar before stream init; seek reuses the same format. Adds the Backfill-Opus bulk API endpoint + CMS action.
This commit is contained in:
@@ -765,6 +765,45 @@ public class CmsTrackService : ICmsTrackService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ResultContainer<OpusBackfillResult>> BackfillOpusAsync(CancellationToken ct = default)
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
|
||||
|
||||
HttpResponseMessage response;
|
||||
try
|
||||
{
|
||||
response = await client.PostAsync("api/track/opus/backfill", null, ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Content API call failed for Opus backfill");
|
||||
return ResultContainer<OpusBackfillResult>.CreateFailResult("Content API is unreachable.");
|
||||
}
|
||||
|
||||
using (response)
|
||||
{
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var body = await response.Content.ReadAsStringAsync(ct);
|
||||
_logger.LogError("Content API Opus backfill failed: {Status} {Body}", (int)response.StatusCode, body);
|
||||
return ResultContainer<OpusBackfillResult>.CreateFailResult("Failed to start the Opus backfill.");
|
||||
}
|
||||
|
||||
OpusBackfillResult payload;
|
||||
try
|
||||
{
|
||||
payload = await response.Content.ReadFromJsonAsync<OpusBackfillResult>(ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to deserialize Opus backfill response from Content API");
|
||||
return ResultContainer<OpusBackfillResult>.CreateFailResult("Content API returned an unexpected response.");
|
||||
}
|
||||
|
||||
return ResultContainer<OpusBackfillResult>.CreatePassResult(payload);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default)
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
|
||||
|
||||
@@ -152,6 +152,15 @@ public interface ICmsTrackService
|
||||
/// </summary>
|
||||
Task<Result> GenerateHighResWaveformAsync(string entryKey, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Trigger the catalogue-wide Backfill-Opus pass via <c>POST api/track/opus/backfill</c> (Phase 18.5).
|
||||
/// The API enqueues a background Opus derive for every track lacking a complete Opus artifact and returns
|
||||
/// the (enqueued, skipped) counts. Enqueue-only — the transcodes run server-side on a serial background
|
||||
/// worker, so this call returns as soon as the work is scheduled, not when transcoding finishes. The
|
||||
/// <c>Enqueued</c> count is how many derives were scheduled; <c>Skipped</c> is how many already had Opus.
|
||||
/// </summary>
|
||||
Task<ResultContainer<OpusBackfillResult>> BackfillOpusAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>Returns all releases with track counts from GET api/track/albums.</summary>
|
||||
Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default);
|
||||
|
||||
@@ -160,3 +169,11 @@ public interface ICmsTrackService
|
||||
/// </summary>
|
||||
Task<ResultContainer<int>> GetTrackCountAsync(CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outcome of a Backfill-Opus pass (Phase 18.5): how many tracks had a background derive scheduled
|
||||
/// (<paramref name="Enqueued"/>) and how many were skipped because they already carry a complete Opus
|
||||
/// artifact (<paramref name="Skipped"/>). Both are counts of tracks, not finished transcodes — the work
|
||||
/// runs asynchronously on the API's background worker after this returns.
|
||||
/// </summary>
|
||||
public readonly record struct OpusBackfillResult(int Enqueued, int Skipped);
|
||||
|
||||
Reference in New Issue
Block a user