feature: Phase 18.3 — Opus delivery transport (?format= stream + seek sidecar endpoint)

This commit is contained in:
daniel-c-harvey
2026-06-23 08:34:37 -04:00
parent e807ddb91b
commit 740d01a67f
4 changed files with 462 additions and 15 deletions
@@ -205,21 +205,26 @@ public class TrackProxyController : ControllerBase
/// <summary>
/// Proxies audio streaming from DeepDrftAPI as a transparent HTTP Range relay.
/// Forwards the incoming Range header upstream and relays the upstream status
/// (200 full, 206 partial, 416 unsatisfiable) and range-related response headers
/// back to the browser verbatim. The proxy does not slice — the upstream already did.
/// Forwards the incoming Range header upstream and the optional <c>format</c> selector
/// (Phase 18.3 — <c>opus|lossless</c>, threaded the same way the listing params are),
/// and relays the upstream status (200 full, 206 partial, 416 unsatisfiable) and
/// range-related response headers back to the browser verbatim. The proxy does not
/// slice — the upstream already did.
/// </summary>
[HttpGet("{trackId}")]
public async Task<ActionResult> GetTrack(
string trackId,
[FromQuery] string? format = null,
CancellationToken ct = default)
{
var rangeHeader = Request.Headers.Range.ToString();
_logger.LogInformation("Proxying track {TrackId} range '{Range}'", trackId, rangeHeader);
_logger.LogInformation("Proxying track {TrackId} range '{Range}' format '{Format}'", trackId, rangeHeader, format);
var request = new HttpRequestMessage(
HttpMethod.Get,
$"api/track/{Uri.EscapeDataString(trackId)}");
var path = $"api/track/{Uri.EscapeDataString(trackId)}";
if (!string.IsNullOrWhiteSpace(format))
path += $"?format={Uri.EscapeDataString(format)}";
var request = new HttpRequestMessage(HttpMethod.Get, path);
// Forward the browser's Range header upstream so DeepDrftAPI slices the file.
// TryAddWithoutValidation avoids RangeHeaderValue reparsing — we relay the raw
@@ -355,4 +360,40 @@ public class TrackProxyController : ControllerBase
return Content(json, "application/json");
}
}
/// <summary>
/// Proxies a track's Opus seek/setup sidecar (raw bytes) from DeepDrftAPI (Phase 18.3). Unauthenticated,
/// same posture as the audio stream forward. The sidecar is a small one-time fetch (≤ ~115 KB), so it is
/// buffered and relayed; a 404 (no Opus artifact / no sidecar stored) passes through so the client
/// degrades to lossless rather than treating it as an error. The "opus/seekdata" 3-segment route makes a
/// collision with the parameterized "{trackId}" audio route impossible.
/// </summary>
[HttpGet("{trackId}/opus/seekdata")]
public async Task<ActionResult> GetOpusSeekData(string trackId, CancellationToken ct = default)
{
var path = $"api/track/{Uri.EscapeDataString(trackId)}/opus/seekdata";
HttpResponseMessage upstream;
try
{
upstream = await _upstream.GetAsync(path, HttpCompletionOption.ResponseHeadersRead, ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Upstream call to DeepDrftAPI track/{TrackId}/opus/seekdata failed", trackId);
return StatusCode(502, "Upstream unavailable");
}
using (upstream)
{
if (!upstream.IsSuccessStatusCode)
{
_logger.LogWarning("DeepDrftAPI track/{TrackId}/opus/seekdata returned {Status}", trackId, (int)upstream.StatusCode);
return StatusCode((int)upstream.StatusCode);
}
var bytes = await upstream.Content.ReadAsByteArrayAsync(ct);
return File(bytes, "application/octet-stream");
}
}
}