feat(scoreboard): unit 10 — the polling policy (quiet by default)
ScoreboardCadence.Due(phase, lastAnalytics, lastSubscribers, now) is the creator's rule as a pure function: watch hours ONLY during a live stream, every 30 minutes (Analytics answers in days and test/record sessions have no public audience, so querying then is pure waste); subscribers whenever the app is working, every 60 s; and nothing at all when idle. Deliberately returns 'no poll' rather than 'analytics only' — a poll kind the poller cannot perform is a bug waiting for a caller. Remaining for the scoreboard: the HTTP providers behind this policy (watch hours via Analytics reports.query, subscribers via channels.list) and the timer that calls Due(). Recorded in HANDOFF.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace ytLive.Models;
|
||||
|
||||
/// <summary>What kind of session the app is in, for polling decisions.</summary>
|
||||
public enum SessionPhase
|
||||
{
|
||||
Idle,
|
||||
Live,
|
||||
Test,
|
||||
Recording,
|
||||
}
|
||||
|
||||
/// <summary>Which channel figures a poll should fetch.</summary>
|
||||
public enum ScoreboardPoll
|
||||
{
|
||||
None,
|
||||
SubscribersOnly,
|
||||
Both,
|
||||
}
|
||||
|
||||
/// <summary>Polling policy for the scoreboard's two channel figures (creator ruling 2026-10-30).
|
||||
///
|
||||
/// <para>Analytics answers in DAYS, and test/record sessions have no public audience — so querying
|
||||
/// watch hours then is pure waste. Subscriber count is cheap (one quota unit) and moves during any
|
||||
/// session, so it polls whenever the app is working. Idle means silent.</para></summary>
|
||||
public static class ScoreboardCadence
|
||||
{
|
||||
public static readonly TimeSpan AnalyticsInterval = TimeSpan.FromMinutes(30);
|
||||
public static readonly TimeSpan SubscriberInterval = TimeSpan.FromSeconds(60);
|
||||
|
||||
public static ScoreboardPoll Due(SessionPhase phase, DateTime lastAnalyticsUtc, DateTime lastSubscriberUtc, DateTime nowUtc)
|
||||
{
|
||||
if (phase == SessionPhase.Idle) return ScoreboardPoll.None;
|
||||
|
||||
var analyticsDue = phase == SessionPhase.Live && nowUtc - lastAnalyticsUtc >= AnalyticsInterval;
|
||||
var subscribersDue = nowUtc - lastSubscriberUtc >= SubscriberInterval;
|
||||
|
||||
return (analyticsDue, subscribersDue) switch
|
||||
{
|
||||
(true, true) => ScoreboardPoll.Both,
|
||||
(true, false) => ScoreboardPoll.None, // analytics alone is not a poll kind
|
||||
(false, true) => ScoreboardPoll.SubscribersOnly,
|
||||
_ => ScoreboardPoll.None,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user