using System; using System.Globalization; namespace ytLive.Models; /// /// TASK 39·2: the three metrics that count towards YouTube Partner Program eligibility, as progress /// towards the ad-revenue thresholds. /// YouTube decides. This only reports what the published numbers say; it never claims /// eligibility, and it cannot see strikes, AdSense state, 2FA or the review decision. /// The view criteria are either/or — 4,000 public watch hours or 10M Shorts views — /// so "2 of 3" is reported with that qualifier rather than implying all three must pass. /// public sealed record YppProgress( long Subscribers, long SubscriberTarget, long WatchHours, long WatchHoursTarget, long ShortsViews, long ShortsViewsTarget) { public bool SubscribersMet => Subscribers >= SubscriberTarget; public bool WatchHoursMet => WatchHours >= WatchHoursTarget; public bool ShortsViewsMet => ShortsViews >= ShortsViewsTarget; /// Criteria currently met (0–3). Two of three can mean eligible: subs plus EITHER view route. public int CriteriaMet => (SubscribersMet ? 1 : 0) + (WatchHoursMet ? 1 : 0) + (ShortsViewsMet ? 1 : 0); /// True when the subscriber bar AND at least one view route are satisfied — the shape of the /// published rule. Still not a qualification claim: YouTube reviews it. public bool MeetsPublishedRule => SubscribersMet && (WatchHoursMet || ShortsViewsMet); public double SubscribersFraction => Fraction(Subscribers, SubscriberTarget); public double WatchHoursFraction => Fraction(WatchHours, WatchHoursTarget); public double ShortsViewsFraction => Fraction(ShortsViews, ShortsViewsTarget); public string SubscribersText => $"{Compact(Subscribers)} / {Compact(SubscriberTarget)}"; public string WatchHoursText => $"{Compact(WatchHours)} / {Compact(WatchHoursTarget)} h"; public string ShortsViewsText => $"{Compact(ShortsViews)} / {Compact(ShortsViewsTarget)}"; public string CriteriaMetText => CriteriaMet == 1 ? "1 of 3 criteria met — YouTube reviews eligibility." : $"{CriteriaMet} of 3 criteria met — YouTube reviews eligibility."; private static double Fraction(long value, long target) => target <= 0 ? 0 : Math.Clamp((double)value / target, 0, 1); /// 1,234 → "1,234"; 12,345 → "12.3k"; 1,234,567 → "1.23M". Mono-face friendly and stable /// in width, so the three bars do not jitter as values move. internal static string Compact(long value) => value switch { >= 1_000_000 => (value / 1_000_000d).ToString("0.##", CultureInfo.InvariantCulture) + "M", >= 10_000 => (value / 1_000d).ToString("0.#", CultureInfo.InvariantCulture) + "k", _ => value.ToString("N0", CultureInfo.InvariantCulture), }; }