Start creating endpoint definitions

This commit is contained in:
Matt Nadareski
2026-10-01 20:54:19 -04:00
parent 8eab9ba65d
commit fec6288278
5 changed files with 421 additions and 451 deletions

View File

@@ -0,0 +1,74 @@
using SabreTools.RedumpLib.Data;
using Xunit;
namespace SabreTools.RedumpLib.Test.Endpoints
{
public class DiscsTests
{
#region BuildUrl
[Fact]
public void BuildUrl_DumperWithPages_Builds()
{
var endpoint = new RedumpLib.Endpoints.Discs
{
Dumper = "user",
Page = 3,
};
string actual = endpoint.BuildUrl();
Assert.Equal("https://redump.info/discs?dumper=user&page=3", actual);
}
[Fact]
public void BuildUrl_DumperLastModifiedWithPages_Builds()
{
var endpoint = new RedumpLib.Endpoints.Discs
{
Dumper = "user",
Sort = SortCategory.Modified,
Order = SortDirection.Descending,
Page = 3,
};
string actual = endpoint.BuildUrl();
Assert.Equal("https://redump.info/discs?dumper=user&sort=modified&order=desc&page=3", actual);
}
[Fact]
public void BuildUrl_LastModifiedWithPages_Builds()
{
var endpoint = new RedumpLib.Endpoints.Discs
{
Sort = SortCategory.Modified,
Order = SortDirection.Descending,
Page = 3,
};
string actual = endpoint.BuildUrl();
Assert.Equal("https://redump.info/discs?sort=modified&order=desc&page=3", actual);
}
[Theory]
[InlineData("", "https://redump.info/discs?q=&page=3")]
[InlineData("simple", "https://redump.info/discs?q=simple&page=3")]
[InlineData("search-format", "https://redump.info/discs?q=search-format&page=3")]
[InlineData("invalid format", "https://redump.info/discs?q=invalid format&page=3")]
[InlineData("extra/path", "https://redump.info/discs?q=extra/path&page=3")]
public void BuildUrl_QuicksearchWithPages_Builds(string query, string expected)
{
var endpoint = new RedumpLib.Endpoints.Discs
{
Query = query,
Page = 3,
};
string actual = endpoint.BuildUrl();
Assert.Equal(expected, actual);
}
// TODO: Implement more extensive discs tests
#endregion
}
}

View File

@@ -42,45 +42,6 @@ namespace SabreTools.RedumpLib.Test.Web
#endregion
#region BuildDiscsUrl
[Fact]
public void BuildDiscsUrl_DumperWithPages_Builds()
{
string actual = UrlBuilder.BuildDiscsUrl(dumper: "user", page: 3);
Assert.Equal("https://redump.info/discs?dumper=user&page=3", actual);
}
[Fact]
public void BuildDiscsUrl_DumperLastModifiedWithPages_Builds()
{
string actual = UrlBuilder.BuildDiscsUrl(dumper: "user", sort: SortCategory.Modified, order: SortDirection.Descending, page: 3);
Assert.Equal("https://redump.info/discs?dumper=user&sort=modified&order=desc&page=3", actual);
}
[Fact]
public void BuildDiscsUrl_LastModifiedWithPages_Builds()
{
string actual = UrlBuilder.BuildDiscsUrl(sort: SortCategory.Modified, order: SortDirection.Descending, page: 3);
Assert.Equal("https://redump.info/discs?sort=modified&order=desc&page=3", actual);
}
[Theory]
[InlineData("", "https://redump.info/discs?q=&page=3")]
[InlineData("simple", "https://redump.info/discs?q=simple&page=3")]
[InlineData("search-format", "https://redump.info/discs?q=search-format&page=3")]
[InlineData("invalid format", "https://redump.info/discs?q=invalid format&page=3")]
[InlineData("extra/path", "https://redump.info/discs?q=extra/path&page=3")]
public void BuildDiscsUrl_QuicksearchWithPages_Builds(string query, string expected)
{
string actual = UrlBuilder.BuildDiscsUrl(query: query, page: 3);
Assert.Equal(expected, actual);
}
// TODO: Implement more extensive discs tests
#endregion
#region BuildDownloadsUrl
[Theory]

View File

@@ -0,0 +1,303 @@
using System;
using System.Text;
using Newtonsoft.Json;
using SabreTools.RedumpLib.Data;
namespace SabreTools.RedumpLib.Endpoints
{
[JsonObject("discs")]
public class Discs
{
[JsonProperty("system")]
public PhysicalSystem? System { get; set; }
[JsonProperty("region")]
public RegionCode? Region { get; set; }
[JsonProperty("language")]
public LanguageCode? Language { get; set; }
[JsonProperty("media")]
public MediaType? Media { get; set; }
[JsonProperty("category")]
public DiscCategory? Category { get; set; }
[JsonProperty("status")]
public DumpStatus? Status { get; set; }
[JsonProperty("letter")]
public char? Letter { get; set; }
[JsonProperty("dumper")]
public string? Dumper { get; set; }
[JsonProperty("title")]
public string? Title { get; set; }
[JsonProperty("title_exact")]
public bool? TitleExact { get; set; }
[JsonProperty("title_foreign")]
public string? TitleForeign { get; set; }
[JsonProperty("title_foreign_exact")]
public bool? TitleForeignExact { get; set; }
[JsonProperty("serial")]
public string? Serial { get; set; }
[JsonProperty("serial_exact")]
public bool? SerialExact { get; set; }
[JsonProperty("edition")]
public string? Edition { get; set; }
[JsonProperty("edition_exact")]
public bool? EditionExact { get; set; }
[JsonProperty("barcode")]
public string? Barcode { get; set; }
[JsonProperty("barcode_exact")]
public bool? BarcodeExact { get; set; }
[JsonProperty("universal_hash")]
public string? UniversalHash { get; set; }
[JsonProperty("tracks_min")]
public long? TracksMin { get; set; }
[JsonProperty("tracks_max")]
public long? TracksMax { get; set; }
[JsonProperty("errors_min")]
public long? ErrorsMin { get; set; }
[JsonProperty("errors_max")]
public long? ErrorsMax { get; set; }
[JsonProperty("edc")]
public YesNo? Edc { get; set; }
[JsonProperty("protection")]
public string? Protection { get; set; }
[JsonProperty("comments")]
public string? Comments { get; set; }
[JsonProperty("contents")]
public string? Contents { get; set; }
[JsonProperty("mastering_code")]
public string? MasteringCode { get; set; }
[JsonProperty("mastering_sid")]
public string? MasteringSid { get; set; }
[JsonProperty("toolstamp")]
public string? Toolstamp { get; set; }
[JsonProperty("mould_sid")]
public string? MouldSid { get; set; }
[JsonProperty("additional_mould")]
public string? AdditionalMould { get; set; }
[JsonProperty("ringcode")]
public string? Ringcode { get; set; }
[JsonProperty("offset")]
public long? Offset { get; set; }
[JsonProperty("q")]
public string? Query { get; set; }
[JsonProperty("sort")]
public SortCategory? Sort { get; set; }
[JsonProperty("order")]
public SortDirection? Order { get; set; }
[JsonProperty("page")]
public long? Page { get; set; }
[JsonProperty("advanced")]
public bool? Advanced { get; set; }
/// <summary>
/// Build a /discs/ path URL
/// </summary>
public string BuildUrl()
{
var ub = new UriBuilder
{
Scheme = "https",
Host = "redump.info",
Path = "discs",
Query = BuildQuery(),
};
return ub.ToString();
}
/// <summary>
/// Build a /discs/ path query
/// </summary>
/// <remarks>Ordered according to site source code</remarks>
private string BuildQuery()
{
var sb = new StringBuilder();
// System
string? system = System?.Code;
if (system is not null)
sb.Append($"system={system}&");
// Region
string? region = Region?.Code;
if (region is not null)
sb.Append($"region={region}&");
// Language
string? langauge = Language?.TwoLetterCode;
if (langauge is not null)
sb.Append($"language={langauge}&");
// Media
string? media = Media.ShortName();
if (media is not null)
sb.Append($"media={media}&");
// Category
string? category = Category.LongName();
if (category is not null)
sb.Append($"category={category}&");
// Status
string? status = Status.LongName();
if (status is not null)
sb.Append($"status={status}&");
// Letter
if (Letter is not null)
sb.Append($"letter={char.ToUpperInvariant(Letter.Value)}&");
// Dumper
if (Dumper is not null)
sb.Append($"dumper={Dumper}&");
// Title
if (Title is not null)
sb.Append($"title={Title}&");
if (Title is not null && TitleExact is not null)
sb.Append($"title_exact={TitleExact.ToYesNo().LongName()}&");
// Foreign Title
if (TitleForeign is not null)
sb.Append($"title_foreign={TitleForeign}&");
if (TitleForeign is not null && TitleForeignExact is not null)
sb.Append($"title_foreign_exact={TitleForeignExact.ToYesNo().LongName()}&");
// Serial
if (Serial is not null)
sb.Append($"serial={Serial}&");
if (Serial is not null && SerialExact is not null)
sb.Append($"serial_exact={SerialExact.ToYesNo().LongName()}&");
// Edition
if (Edition is not null)
sb.Append($"edition={Edition}&");
if (Edition is not null && EditionExact is not null)
sb.Append($"edition_exact={EditionExact.ToYesNo().LongName()}&");
// Barcode
if (Barcode is not null)
sb.Append($"barcode={Barcode}&");
if (Barcode is not null && BarcodeExact is not null)
sb.Append($"barcode_exact={BarcodeExact.ToYesNo().LongName()}&");
// Universal Hash
if (UniversalHash is not null)
sb.Append($"universal_hash={UniversalHash}&");
// Track Count
if (TracksMin is not null)
sb.Append($"tracks_min={TracksMin}&");
if (TracksMax is not null)
sb.Append($"tracks_max={TracksMax}&");
// Error Count
if (ErrorsMin is not null)
sb.Append($"errors_min={ErrorsMin}&");
if (ErrorsMax is not null)
sb.Append($"errors_max={ErrorsMax}&");
// EDC
if (Edc is not null && Edc != YesNo.NULL)
sb.Append($"edc={Edc.LongName()}&");
// Protection
if (Protection is not null)
sb.Append($"protection={Protection}&");
// Comments
if (Comments is not null)
sb.Append($"comments={Comments}&");
// Contents
if (Contents is not null)
sb.Append($"contents={Contents}&");
// Mastering Code
if (MasteringCode is not null)
sb.Append($"mastering_code={MasteringCode}&");
// Mastering SID
if (MasteringSid is not null)
sb.Append($"mastering_sid={MasteringSid}&");
// Toolstamp
if (Toolstamp is not null)
sb.Append($"toolstamp={Toolstamp}&");
// Mould SID
if (MouldSid is not null)
sb.Append($"mould_sid={MouldSid}&");
// Additional Mould
if (AdditionalMould is not null)
sb.Append($"additional_mould={AdditionalMould}&");
// Ringcode
if (Ringcode is not null)
sb.Append($"ringcode={Ringcode}&");
// Offset
if (Offset is not null)
sb.Append($"offset={Offset}&");
// General Query
if (Query is not null)
sb.Append($"q={Query}&");
// Sorting
if (Sort is not null && Enum.IsDefined(typeof(SortCategory), Sort))
sb.Append($"sort={Sort.ShortName()}&");
// Sort Direction
if (Order is not null && Enum.IsDefined(typeof(SortDirection), Order))
sb.Append($"order={Order.ShortName()}&");
// Page Number
if (Page is not null)
sb.Append($"page={Page}");
// Advanced
if (Advanced is not null)
sb.Append($"advanced={(Advanced.Value ? "1" : "0")}&");
return sb.ToString();
}
}
}

View File

@@ -577,46 +577,50 @@ namespace SabreTools.RedumpLib.Web
if (query is not null)
query = NormalizeQuery(query);
string url = UrlBuilder.BuildDiscsUrl(
additionalMould,
advanced,
barcode,
barcodeExact,
category,
comments,
contents,
dumper,
edc,
edition,
editionExact,
errorsMax,
errorsMin,
language,
letter,
masteringCode,
masteringSid,
media,
mouldSid,
offset,
order,
page,
protection,
query,
region,
ringcode,
serial,
serialExact,
sort,
status,
system,
title,
titleExact,
titleForeign,
titleForeignExact,
toolstamp,
tracksMax,
tracksMin,
universalHash);
var endpoint = new Endpoints.Discs
{
System = system,
Region = region,
Language = language,
Media = media,
Category = category,
Status = status,
Letter = letter,
Dumper = dumper,
Title = title,
TitleExact = titleExact,
TitleForeign = titleForeign,
TitleForeignExact = titleForeignExact,
Serial = serial,
SerialExact = serialExact,
Edition = edition,
EditionExact = editionExact,
Barcode = barcode,
BarcodeExact = barcodeExact,
UniversalHash = universalHash,
TracksMin = tracksMin,
TracksMax = tracksMax,
ErrorsMin = errorsMin,
ErrorsMax = errorsMax,
Edc = edc,
Protection = protection,
Comments = comments,
Contents = contents,
MasteringCode = masteringCode,
MasteringSid = masteringSid,
Toolstamp = toolstamp,
MouldSid = mouldSid,
AdditionalMould = additionalMould,
Ringcode = ringcode,
Offset = offset,
Query = query,
Sort = sort,
Order = order,
Page = page,
Advanced = advanced,
};
string url = endpoint.BuildUrl();
List<int> ids = [];

View File

@@ -81,141 +81,6 @@ namespace SabreTools.RedumpLib.Web
return ub.ToString();
}
/// <summary>
/// Build a /discs/ path URL
/// </summary>
/// <param name="additionalMould">Add additional mould to filter, null to omit</param>
/// <param name="advanced">Set advanced search status, null to omit</param>
/// <param name="barcode">Add barcode to filter, null to omit</param>
/// <param name="barcodeExact">Set exact barcode handling, null to omit</param>
/// <param name="category">Add category to filter, null to omit</param>
/// <param name="comments">Add comments to filter, null to omit</param>
/// <param name="contents">Add contents to filter, null to omit</param>
/// <param name="dumper">Add dumper name to filter, null to omit</param>
/// <param name="edc">Add EDC status to filter, null to omit</param>
/// <param name="edition">Add edition to filter, null to omit</param>
/// <param name="editionExact">Set exact edition handling, null to omit</param>
/// <param name="errorsMax">Add maximum error count to filter, null to omit</param>
/// <param name="errorsMin">Add minimum error count to filter, null to omit</param>
/// <param name="language">Add language to filter, null to omit</param>
/// <param name="letter">Starts with upper-case letter or '#' for numbers, null to omit</param>
/// <param name="masteringCode">Add mastering code to filter, null to omit</param>
/// <param name="masteringSid">Add mastering SID to filter, null to omit</param>
/// <param name="media">Add media type to filter, null to omit</param>
/// <param name="mouldSid">Add mould SID to filter, null to omit</param>
/// <param name="offset">Add offset to filter, null to omit</param>
/// <param name="order">Add sorting direction, null to omit</param>
/// <param name="page">Page number, null to omit</param>
/// <param name="protection">Add protection to filter, null to omit</param>
/// <param name="query">Generic text query to filter, null to omit</param>
/// <param name="region">Add region to filter, null to omit</param>
/// <param name="ringcode">Add ringcode to filter, null to omit</param>
/// <param name="serial">Add serial to filter, null to omit</param>
/// <param name="serialExact">Set exact serial handling, null to omit</param>
/// <param name="sort">Add sorting type, null to omit</param>
/// <param name="status">Add status to filter, null to omit</param>
/// <param name="system">Add system to filter, null to omit</param>
/// <param name="title">Add title to filter, null to omit</param>
/// <param name="titleExact">Set exact title handling, null to omit</param>
/// <param name="titleForeign">Add foreign title to filter, null to omit</param>
/// <param name="titleForeignExact">Set exact foreign title handling, null to omit</param>
/// <param name="toolstamp">Add toolstamp to filter, null to omit</param>
/// <param name="tracksMax">Add maximum track count to filter, null to omit</param>
/// <param name="tracksMin">Add minimum track count to filter, null to omit</param>
/// <param name="universalHash">Add universal hash to filter, null to omit</param>
/// <remarks>Ordered according to site source code</remarks>
public static string BuildDiscsUrl(
string? additionalMould = null,
bool? advanced = null,
string? barcode = null,
bool? barcodeExact = null,
DiscCategory? category = null,
string? comments = null,
string? contents = null,
string? dumper = null,
YesNo? edc = null,
string? edition = null,
bool? editionExact = null,
long? errorsMax = null,
long? errorsMin = null,
LanguageCode? language = null,
char? letter = null,
string? masteringCode = null,
string? masteringSid = null,
MediaType? media = null,
string? mouldSid = null,
long? offset = null,
SortDirection? order = null,
long? page = null,
string? protection = null,
string? query = null,
RegionCode? region = null,
string? ringcode = null,
string? serial = null,
bool? serialExact = null,
SortCategory? sort = null,
DumpStatus? status = null,
PhysicalSystem? system = null,
string? title = null,
bool? titleExact = null,
string? titleForeign = null,
bool? titleForeignExact = null,
string? toolstamp = null,
long? tracksMax = null,
long? tracksMin = null,
string? universalHash = null)
{
var ub = new UriBuilder
{
Scheme = "https",
Host = "redump.info",
Path = "discs",
Query = BuildDiscsQuery(
additionalMould,
advanced,
barcode,
barcodeExact,
category,
comments,
contents,
dumper,
edc,
edition,
editionExact,
errorsMax,
errorsMin,
language,
letter,
masteringCode,
masteringSid,
media,
mouldSid,
offset,
order,
page,
protection,
query,
region,
ringcode,
serial,
serialExact,
sort,
status,
system,
title,
titleExact,
titleForeign,
titleForeignExact,
toolstamp,
tracksMax,
tracksMin,
universalHash
),
};
return ub.ToString();
}
/// <summary>
/// Build a /downloads/ path URL
/// </summary>
@@ -370,243 +235,6 @@ namespace SabreTools.RedumpLib.Web
#region Query String Builders
/// <summary>
/// Build a /discs/ path query
/// </summary>
/// <param name="additionalMould">Add additional mould to filter, null to omit</param>
/// <param name="advanced">Set advanced search status, null to omit</param>
/// <param name="barcode">Add barcode to filter, null to omit</param>
/// <param name="barcodeExact">Set exact barcode handling, null to omit</param>
/// <param name="category">Add category to filter, null to omit</param>
/// <param name="comments">Add comments to filter, null to omit</param>
/// <param name="contents">Add contents to filter, null to omit</param>
/// <param name="dumper">Add dumper name to filter, null to omit</param>
/// <param name="edc">Add EDC status to filter, null to omit</param>
/// <param name="edition">Add edition to filter, null to omit</param>
/// <param name="editionExact">Set exact edition handling, null to omit</param>
/// <param name="errorsMax">Add maximum error count to filter, null to omit</param>
/// <param name="errorsMin">Add minimum error count to filter, null to omit</param>
/// <param name="language">Add language to filter, null to omit</param>
/// <param name="letter">Starts with upper-case letter or '#' for numbers, null to omit</param>
/// <param name="masteringCode">Add mastering code to filter, null to omit</param>
/// <param name="masteringSid">Add mastering SID to filter, null to omit</param>
/// <param name="media">Add media type to filter, null to omit</param>
/// <param name="mouldSid">Add mould SID to filter, null to omit</param>
/// <param name="offset">Add offset to filter, null to omit</param>
/// <param name="order">Add sorting direction, null to omit</param>
/// <param name="page">Page number, null to omit</param>
/// <param name="protection">Add protection to filter, null to omit</param>
/// <param name="query">Generic text query to filter, null to omit</param>
/// <param name="region">Add region to filter, null to omit</param>
/// <param name="ringcode">Add ringcode to filter, null to omit</param>
/// <param name="serial">Add serial to filter, null to omit</param>
/// <param name="serialExact">Set exact serial handling, null to omit</param>
/// <param name="sort">Add sorting type, null to omit</param>
/// <param name="status">Add status to filter, null to omit</param>
/// <param name="system">Add system to filter, null to omit</param>
/// <param name="title">Add title to filter, null to omit</param>
/// <param name="titleExact">Set exact title handling, null to omit</param>
/// <param name="titleForeign">Add foreign title to filter, null to omit</param>
/// <param name="titleForeignExact">Set exact foreign title handling, null to omit</param>
/// <param name="toolstamp">Add toolstamp to filter, null to omit</param>
/// <param name="tracksMax">Add maximum track count to filter, null to omit</param>
/// <param name="tracksMin">Add minimum track count to filter, null to omit</param>
/// <param name="universalHash">Add universal hash to filter, null to omit</param>
/// <remarks>Ordered according to site source code</remarks>
private static string BuildDiscsQuery(
string? additionalMould,
bool? advanced,
string? barcode,
bool? barcodeExact,
DiscCategory? category,
string? comments,
string? contents,
string? dumper,
YesNo? edc,
string? edition,
bool? editionExact,
long? errorsMax,
long? errorsMin,
LanguageCode? language,
char? letter,
string? masteringCode,
string? masteringSid,
MediaType? media,
string? mouldSid,
long? offset,
SortDirection? order,
long? page,
string? protection,
string? query,
RegionCode? region,
string? ringcode,
string? serial,
bool? serialExact,
SortCategory? sort,
DumpStatus? status,
PhysicalSystem? system,
string? title,
bool? titleExact,
string? titleForeign,
bool? titleForeignExact,
string? toolstamp,
long? tracksMax,
long? tracksMin,
string? universalHash)
{
var sb = new StringBuilder();
// System
string? systemName = system?.Code;
if (systemName is not null)
sb.Append($"system={systemName}&");
// Region
string? regionName = region?.Code;
if (regionName is not null)
sb.Append($"region={regionName}&");
// Language
string? languageName = language?.TwoLetterCode;
if (languageName is not null)
sb.Append($"language={languageName}&");
// Media
string? mediaName = media.ShortName();
if (mediaName is not null)
sb.Append($"media={mediaName}&");
// Category
string? categoryName = category.LongName();
if (categoryName is not null)
sb.Append($"category={categoryName}&");
// Status
string? statusName = status.LongName();
if (statusName is not null)
sb.Append($"status={statusName}&");
// Letter
if (letter is not null)
sb.Append($"letter={char.ToUpperInvariant(letter.Value)}&");
// Dumper
if (dumper is not null)
sb.Append($"dumper={dumper}&");
// Title
if (title is not null)
sb.Append($"title={title}&");
if (title is not null && titleExact is not null)
sb.Append($"title_exact={titleExact.ToYesNo().LongName()}&");
// Foreign Title
if (titleForeign is not null)
sb.Append($"title_foreign={titleForeign}&");
if (titleForeign is not null && titleForeignExact is not null)
sb.Append($"title_foreign_exact={titleForeignExact.ToYesNo().LongName()}&");
// Foreign Title
if (serial is not null)
sb.Append($"serial={serial}&");
if (serial is not null && serialExact is not null)
sb.Append($"serial_exact={serialExact.ToYesNo().LongName()}&");
// Edition
if (edition is not null)
sb.Append($"edition={edition}&");
if (edition is not null && editionExact is not null)
sb.Append($"edition_exact={editionExact.ToYesNo().LongName()}&");
// Barcode
if (barcode is not null)
sb.Append($"barcode={barcode}&");
if (barcode is not null && barcodeExact is not null)
sb.Append($"barcode_exact={barcodeExact.ToYesNo().LongName()}&");
// Universal Hash
if (universalHash is not null)
sb.Append($"universal_hash={universalHash}&");
// Track Count
if (tracksMin is not null)
sb.Append($"tracks_min={tracksMin}&");
if (tracksMax is not null)
sb.Append($"tracks_max={tracksMax}&");
// Error Count
if (errorsMin is not null)
sb.Append($"errors_min={errorsMin}&");
if (errorsMax is not null)
sb.Append($"errors_max={errorsMax}&");
// EDC
if (edc is not null && edc != YesNo.NULL)
sb.Append($"edc={edc.LongName()}&");
// Protection
if (protection is not null)
sb.Append($"protection={protection}&");
// Comments
if (comments is not null)
sb.Append($"comments={comments}&");
// Contents
if (contents is not null)
sb.Append($"contents={contents}&");
// Mastering Code
if (masteringCode is not null)
sb.Append($"mastering_code={masteringCode}&");
// Mastering SID
if (masteringSid is not null)
sb.Append($"mastering_sid={masteringSid}&");
// Toolstamp
if (toolstamp is not null)
sb.Append($"toolstamp={toolstamp}&");
// Mould SID
if (mouldSid is not null)
sb.Append($"mould_sid={mouldSid}&");
// Additional Mould
if (additionalMould is not null)
sb.Append($"additional_mould={additionalMould}&");
// Ringcode
if (ringcode is not null)
sb.Append($"ringcode={ringcode}&");
// Ringcode
if (offset is not null)
sb.Append($"offset={offset}&");
// General Query
if (query is not null)
sb.Append($"q={query}&");
// Sorting
if (sort is not null && Enum.IsDefined(typeof(SortCategory), sort))
sb.Append($"sort={sort.ShortName()}&");
// Sort Direction
if (order is not null && Enum.IsDefined(typeof(SortDirection), order))
sb.Append($"order={order.ShortName()}&");
// Page Number
if (page is not null)
sb.Append($"page={page}");
// Advanced
if (advanced is not null)
sb.Append($"advanced={(advanced.Value ? "1" : "0")}&");
return sb.ToString();
}
/// <summary>
/// Build a /queue/ path query
/// </summary>