Build ErsatzTV Image / CI image pin matches docker/ci (pull_request) Successful in 5s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 6s
Build ErsatzTV Image / decisions.md append-only (pull_request) Successful in 5s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 16s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 18s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m17s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 14m10s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 18m28s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Third review pass: MERGEABLE WITH NITS. Taking the one finding it asked for before merge, plus a doc nit. The cancellation filter added last commit had no token check, and it spans the whole Transcode body -- including every mediator send (ffprobe via CliWrap, media-server API calls, subtitle extraction, song-video generation). TaskCanceledException is also what HttpClient throws on its OWN timeout, so a real timeout in any of those was being downgraded from an ERROR with a stack trace to a routine "Terminating HLS session" Information line. Behaviour was unchanged (both arms return false) but the fault signal was lost, and this repo has been bitten before by "empty log != the event didn't happen". Now filters on cancellationToken.IsCancellationRequested, so only genuine caller cancellation is treated as a graceful teardown. Doc nit: the <exception> block said cancellation "is thrown"; it is only thrown when the token trips while the probe is in flight -- cancelling after it completes returns normally. Now says "may propagate". Declined the reviewer's optional suggestion to drain until a 0-return instead of reading exactly one byte: reading exactly one byte is what makes the guard safe BY CONSTRUCTION, since a server or proxy that answers 206 with a wider range than requested still cannot be drained unboundedly. 206-only was confirmed correct rather than extended to short 200s, since deciding "short" from Content-Length would reopen the unbounded path for a chunked or Content-Length-less response. Also records the operator's standing rule in the handoff lore: a lone `decisions.md append-only` red is a known infra flake -- do not investigate, rebase, amend or push to clear it; the operator reruns that job from the UI. I violated this earlier in this PR with a tidy-but-wrong "my entry is no longer at EOF" theory, and the rebase did not fix it -- the job went red again on a verified pure-append diff, which is the proof the red was never about the diff. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
29 lines
1.6 KiB
C#
29 lines
1.6 KiB
C#
namespace ErsatzTV.Core.Interfaces.Streaming;
|
|
|
|
/// <summary>
|
|
/// Checks whether a media-server remote-stream URL still resolves to playable media.
|
|
/// </summary>
|
|
public interface IRemoteStreamProber
|
|
{
|
|
/// <summary>
|
|
/// Probes <paramref name="url" />, following redirects as ffmpeg would.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// <c>false</c> only when the media server itself reported the media gone — i.e. a 404 that
|
|
/// arrived <em>after</em> ErsatzTV's own <c>/media/{provider}/...</c> endpoint redirected.
|
|
/// Every other outcome returns <c>true</c> (fail-open), including an un-redirected 404: that
|
|
/// one came from ErsatzTV's own endpoint, which also 404s when the media source is
|
|
/// unconfigured or momentarily missing, and honouring it would blank every item on that
|
|
/// source. Timeouts, transport failures and all other status codes likewise return
|
|
/// <c>true</c>, so a probe that cannot answer never prevents a tune that would have worked.
|
|
/// </returns>
|
|
/// <exception cref="OperationCanceledException">
|
|
/// May propagate when <paramref name="cancellationToken" /> is cancelled while the probe is
|
|
/// in flight. Caller cancellation is a genuine signal (shutdown / client disconnect), not a
|
|
/// probe failure, so it is not absorbed by the fail-open behaviour above. Cancelling after
|
|
/// the probe has already completed returns normally. The prober's own internal timeout does
|
|
/// <em>not</em> throw — it fails open.
|
|
/// </exception>
|
|
Task<bool> IsAvailable(string url, CancellationToken cancellationToken);
|
|
}
|