a9d5f29084
Current-OAuth-scope data, no re-consent: subscriber bars for both tiers (500 fan-funding / 1,000 ad-revenue; the 2027-02-01 doubling is versioned date-aware data in YppThresholds), 3-uploads/90d, live standing from channels.list auditDetails, self-reported 2FA/AdSense checkboxes + deep links (Google 2-Step / youtube.com/earn), and the "what counts" education. Every refresh appends a YppSnapshot (SQLite v10) so the analytics slice has history from day one. - ChannelStatsService (channels.list statistics,auditDetails,contentDetails + playlistItems.list, virtual CaptureCurrentAsync = test seam); YppTrackerViewModel mirrors LiveBroadcastFormViewModel. - MainViewModel.Ypp.cs: Ypp property, ChannelStatsFactoryOverride seam, one-open-at-a-time drawer exclusivity (both directions); account sign-in/out/restore hooks in Account.cs. - PreviewPane.xaml: TextPullOutHost is now a drawer bank [broadcast][ypp][stacked white tabs]; outside-click collapse covers both drawers. MainWindow.xaml.cs updated. - Wait - watchers: the whole feature already reviewed against YouTube's own docs (YPP Earn tab + API availability) before building — see TASKS/task-39-ypp-journey-tracker.md. - ONE integration test: YppPullOutTests (snapshot capture/persist + checklist round-trip + drawer exclusivity). 313/313 pass, 0 warnings. - Memory in same commit: TASKS.md row, ai.md Journey-tracker bullet (roadmap→reality), HANDOFF.md. Slice 2 (Analytics yt-analytics.readonly re-consent → watch-hours/Shorts + velocity/ETA + sparkline) is queued behind this, not merged.
31 lines
1.7 KiB
C#
31 lines
1.7 KiB
C#
namespace ytLive.Models;
|
|
|
|
/// <summary>YPP eligibility thresholds as versioned, date-aware DATA — never
|
|
/// constants (ai.md "Journey tracker"). Tier 1 (fan funding) is time-invariant;
|
|
/// Tier 2 (ad revenue) doubles its long-form-hours and Shorts-view bars for NEW
|
|
/// applicants after 2027-02-01. Hardcoding the pre-2027 numbers would show the
|
|
/// wrong ETA once the doubling lands, so callers resolve the active Tier 2
|
|
/// threshold through <see cref="Tier2For"/>.</summary>
|
|
public static class YppThresholds
|
|
{
|
|
public sealed record TierThreshold(string Name, long Subscribers, long WatchHours, long ShortsViews);
|
|
|
|
/// <summary>The date the Tier-2 ad-revenue bars double for new applicants.</summary>
|
|
public static readonly DateTime Tier2DoublingDate = new(2027, 2, 1);
|
|
|
|
/// <summary>Fan-funding tier (before the full ad/YouTube Premium revenue tier).</summary>
|
|
public static TierThreshold Tier1 { get; } = new("Fan funding", 500, 3_000, 3_000_000);
|
|
|
|
/// <summary>The Tier-2 bar for a given point in time — 4,000h / 10M Shorts
|
|
/// before the doubling date, 8,000h / 20M Shorts on or after it.</summary>
|
|
public static TierThreshold Tier2For(DateTime when) => when >= Tier2DoublingDate
|
|
? new TierThreshold("Ad revenue", 1_000, 8_000, 20_000_000)
|
|
: new TierThreshold("Ad revenue", 1_000, 4_000, 10_000_000);
|
|
|
|
/// <summary>The currently-active Tier-2 threshold (resolved against today).</summary>
|
|
public static TierThreshold Tier2Now => Tier2For(DateTime.UtcNow);
|
|
|
|
/// <summary>Valid public long-form uploads required in the trailing 90 days
|
|
/// to keep each tier route eligible.</summary>
|
|
public const int UploadsRequiredPer90Days = 3;
|
|
} |