The last resilience slice. When a drop ends the broadcast, YouTube cannot resume it, so the only way
back is a new one — and that is what the app now offers, in one click.
- `Services/BroadcastTitle.cs` — the resume marker is applied to the title the show was using, and any
existing marker is REPLACED rather than stacked ("Show (resumed)" → "Show (resumed 2)"), with the base
truncated so the whole title fits YouTube's 100-character limit. Otherwise a channel grows two
identically named videos and the creator has to explain it.
- `MainViewModel.BackOnAirCommand` — reuses the ordinary go-live path with the saved details and the
cached stream: new broadcast, new VOD, no dialog. It appears only after a drop ended the session and
the ordinary start button steps aside, so there is exactly one way forward.
- The running line goes red OFF AIR (not amber) in that state; the button reads "● Back on air".
Tests: `BackOnAirTests` — first re-air marks the title, a second drop counts instead of stacking, the
100-character limit holds, an empty title still works, and the post-drop state exposes exactly one
start affordance. FAST gate: 552 passed, 0 failed, 0 warnings.
TASK 32 is now complete: fragmented MP4, blip retry, poll-driven RECONNECTING, ingest pre-flight, Back
on air.
34 lines
1.5 KiB
C#
34 lines
1.5 KiB
C#
using System;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace ytLive.Services;
|
|
|
|
/// <summary>
|
|
/// TASK 32·3 — naming the broadcast that resumes a dropped show. A resumed stream is a NEW broadcast
|
|
/// with a new VOD (YouTube cannot resume a completed one), so the title has to say so; otherwise the
|
|
/// channel grows two identically named videos and the creator has to explain it.
|
|
/// <para>Pure, because the interesting cases are the boring ones: a title already marked, a second drop
|
|
/// in the same session, and YouTube's 100-character limit.</para>
|
|
/// </summary>
|
|
public static class BroadcastTitle
|
|
{
|
|
public const int MaxLength = 100;
|
|
|
|
private static readonly Regex ResumeMarker =
|
|
new(@"\s*\(resumed(?: \d+)?\)\s*$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
|
|
/// <summary>The title for resume number <paramref name="resumeCount"/> (1 = first re-air).
|
|
/// Any existing marker is replaced rather than stacked, and the base is truncated so the whole
|
|
/// title fits YouTube's limit.</summary>
|
|
public static string ForResume(string? title, int resumeCount)
|
|
{
|
|
var baseTitle = ResumeMarker.Replace(title ?? string.Empty, string.Empty).Trim();
|
|
if (baseTitle.Length == 0) baseTitle = "LlamaCasty";
|
|
|
|
var marker = resumeCount <= 1 ? " (resumed)" : $" (resumed {Math.Max(2, resumeCount)})";
|
|
var room = MaxLength - marker.Length;
|
|
if (baseTitle.Length > room) baseTitle = baseTitle[..room].TrimEnd();
|
|
return baseTitle + marker;
|
|
}
|
|
}
|