Files
LlamaCasty/Models/OutputProfile.cs
T

57 lines
2.7 KiB
C#

namespace ytLive.Models;
/// <summary>
/// The one entitlement rule, as pure policy: what a build is allowed to emit.
///
/// <para><b>Frame rate is the paid boundary.</b> Every supported resolution at 30 fps is free;
/// 60 fps requires paid ownership, regardless of frame dimensions.</para>
///
/// <para><b>Fail closed.</b> Callers pass <c>pro: false</c> when entitlement is unknown,
/// unreadable or unresolved; the free profile is the default state, never the fallback
/// after an error.</para>
///
/// <para><b>This is not a feature gate.</b> Every feature, scene, overlay and the recording
/// itself stay available; only the emitted frame gets smaller. Never call it for anything
/// else — a cracked build buys almost nothing, which is the entire anti-piracy posture.</para>
/// </summary>
public static class OutputProfile
{
/// <summary>Free ceiling: 30 frames per second.</summary>
public const int FreeMaxFps = 30;
/// <summary>The default free tier and fallback when no shipped tier is available.</summary>
public const string FreeFallbackName = "1080p30";
/// <summary>Is this tier within the free budget? Pro may use anything shipped.</summary>
public static bool IsAllowed(QualityOption tier, bool pro)
=> pro
|| tier.Fps <= FreeMaxFps;
/// <summary>
/// The tier a session will actually encode. A permitted selection passes through
/// untouched (so Pro and the free tier's own 720p30 keep their exact bitrate); a
/// disallowed one resolves to the best tier the budget allows — most pixels first, then
/// most frames, then the cheapest bitrate — because silently encoding something the user
/// did not pick is only acceptable if it is the closest legal thing to it.
/// </summary>
/// <param name="requested">What the dropdown says.</param>
/// <param name="shipped">Every tier the build offers.</param>
/// <param name="pro">Entitlement, already resolved. Unknown must be passed as false.</param>
public static QualityOption Resolve(
QualityOption requested, IEnumerable<QualityOption> shipped, bool pro)
{
if (IsAllowed(requested, pro)) return requested;
var candidate = shipped
.Where(tier => IsAllowed(tier, pro))
.OrderByDescending(tier => tier.Width * tier.Height)
.ThenByDescending(tier => tier.Fps)
.ThenBy(tier => tier.Bitrate)
.FirstOrDefault();
// No shipped tier fits the budget: build the floor explicitly rather than trusting
// the table. A build whose tiers were all redefined must still emit a legal frame.
return candidate ?? new QualityOption(FreeFallbackName, FreeMaxFps, 8.0, 1920, 1080);
}
}