using System; namespace ytLive.Models; /// What kind of session the app is in, for polling decisions. public enum SessionPhase { Idle, Live, Test, Recording, } /// Which channel figures a poll should fetch. public enum ScoreboardPoll { None, SubscribersOnly, Both, } /// Polling policy for the scoreboard's two channel figures (creator ruling 2026-10-30). /// /// 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. public static class ScoreboardCadence { public static readonly TimeSpan AnalyticsInterval = TimeSpan.FromMinutes(30); public static readonly TimeSpan SubscriberInterval = TimeSpan.FromSeconds(60); /// is the layer's master switch. Off means NOTHING is /// polled, whatever the session is doing — a hidden scoreboard has no reason to spend quota /// (creator ruling 2026-10-30). public static ScoreboardPoll Due(SessionPhase phase, DateTime lastAnalyticsUtc, DateTime lastSubscriberUtc, DateTime nowUtc, bool enabled = true) { if (!enabled) return ScoreboardPoll.None; 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, }; } }