This commit is contained in:
2026-06-25 09:59:54 +02:00
commit bd2ecd0176
16 changed files with 2069 additions and 0 deletions

40
Models/UsageInfo.cs Normal file
View File

@@ -0,0 +1,40 @@
namespace ClaudeOverview.Models;
/// <summary>
/// Subscription usage pulled from the Claude /api/oauth/usage endpoint.
/// Percentages are 0100.
/// </summary>
public sealed class UsageInfo
{
/// <summary>Length of the rolling session-limit block (the API's "five_hour" bucket).</summary>
public static readonly TimeSpan SessionWindow = TimeSpan.FromHours(5);
public double SessionPercent { get; set; }
public DateTime? SessionResetsAt { get; set; }
/// <summary>UTC start of the current session-limit window (its reset time minus the 5-hour block).</summary>
public DateTime? SessionWindowStartUtc =>
SessionResetsAt is { } r ? r.ToUniversalTime() - SessionWindow : null;
public double WeeklyPercent { get; set; }
public DateTime? WeeklyResetsAt { get; set; }
public string? Error { get; set; }
public bool Ok => Error is null;
/// <summary>True when the last fetch was rejected with HTTP 429 (rate limited).</summary>
public bool RateLimited { get; set; }
/// <summary>Server-suggested wait before retrying (from the Retry-After header), if any.</summary>
public TimeSpan? RetryAfter { get; set; }
public static string ResetsIn(DateTime? resetsAtUtc)
{
if (resetsAtUtc is null) return "";
var span = resetsAtUtc.Value.ToUniversalTime() - DateTime.UtcNow;
if (span <= TimeSpan.Zero) return "resetting…";
if (span < TimeSpan.FromHours(1)) return $"resets in {(int)span.TotalMinutes}m";
if (span < TimeSpan.FromDays(1)) return $"resets in {(int)span.TotalHours}h{span.Minutes:00}m";
return $"resets in {(int)span.TotalDays}d{span.Hours}h";
}
}