Files
Ludarium-Public/src/Ludarium.Application/GameQuery.cs
T
Ludarium release export df869819ce
Public source validation / source (push) Successful in 2m16s
Publish Ludarium source
2026-09-03 02:08:58 +02:00

77 lines
3.2 KiB
C#

using Ludarium.Domain;
namespace Ludarium.Application;
/// <summary>
/// Everything the library browser can ask of the catalog.
/// </summary>
/// <remarks>
/// Filtering and ordering belong to the query, not to the page the browser happens to hold. The
/// library previously sorted the forty-eight games already on screen, which reordered a page rather
/// than the collection and quietly disagreed with what the operator asked for.
/// </remarks>
public sealed record GameQuery
{
public string? Search { get; init; }
public string? Platform { get; init; }
/// <summary>Ordering key. Unknown values fall back to title.</summary>
public string? Sort { get; init; }
public bool? Favorite { get; init; }
public GamePlayStatus? Status { get; init; }
public Guid? CollectionId { get; init; }
/// <summary>Normalized tag name, as stored by <see cref="LibraryExperiencePolicy.NormalizeTag"/>.</summary>
public string? Tag { get; init; }
/// <summary>Keep only games rated at least this highly.</summary>
public int? MinimumRating { get; init; }
/// <summary>
/// Keep only games with a linked, present copy in a format some player accepts.
/// </summary>
/// <remarks>
/// This is a property of the collection, not of the runtime: a sidecar that is switched off does
/// not make a game disappear from the library. Whether a specific game can start right now stays
/// the capability's answer, shown on the game itself.
/// </remarks>
public bool PlayableOnly { get; init; }
public int Page { get; init; } = 1;
public int PageSize { get; init; } = 50;
public static readonly IReadOnlyList<string> SortKeys =
["title", "recent", "updated", "played", "rating"];
public bool HasFilters => !string.IsNullOrWhiteSpace(Search) || !string.IsNullOrWhiteSpace(Platform) ||
Favorite is not null || Status is not null || CollectionId is not null ||
!string.IsNullOrWhiteSpace(Tag) || MinimumRating is not null || PlayableOnly;
}
/// <summary>
/// The exact platform-and-container pairs some Ludarium player accepts.
/// </summary>
/// <remarks>
/// Derived from the browser matrix and the native registry so the library's "playable copy" filter
/// can never claim a format no player takes, and can never drift from the policies that decide it.
/// </remarks>
public static class PlayableFormats
{
/// <summary>Each entry is <c>platform|.extension</c>, lower-cased.</summary>
public static IReadOnlyList<string> Pairs { get; } = BuildPairs();
private static string[] BuildPairs()
{
var pairs = new SortedSet<string>(StringComparer.Ordinal);
foreach (var platform in BrowserPlayPolicy.DescribePlatforms())
foreach (var extension in platform.Extensions.Concat(platform.CandidateExtensions ?? new HashSet<string>()))
pairs.Add($"{platform.Platform.ToLowerInvariant()}|{extension.ToLowerInvariant()}");
foreach (var player in NativeRemotePlayerRegistry.All)
foreach (var platform in player.Platforms)
foreach (var extension in player.Extensions)
pairs.Add($"{platform.ToLowerInvariant()}|{extension.ToLowerInvariant()}");
return [.. pairs];
}
}