Files
YandexMusic/YandexMusic.API/Requests/Common/YRequestBuilder.cs
FrigaT 8abc6c5074
All checks were successful
Release / pack-and-publish (release) Successful in 32s
fix
2026-04-13 15:42:42 +03:00

97 lines
3.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Specialized;
using System.Net;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Web;
using YandexMusic.API.Common;
using YandexMusic.API.Extensions;
using YandexMusic.API.Requests.Common.Attributes;
namespace YandexMusic.API.Requests.Common;
/// <summary>Базовый строитель HTTP-запросов к API Яндекс.Музыки.</summary>
/// <typeparam name="TResponse">Тип ответа.</typeparam>
/// <typeparam name="TParams">Тип параметров запроса.</typeparam>
public abstract class YRequestBuilder<TResponse, TParams>
{
private readonly YRequestAttribute _requestInfo;
private Dictionary<string, string> _substitutions = null!;
private readonly JsonSerializerOptions _jsonOptions;
protected readonly YandexMusicApi api;
protected readonly AuthStorage storage;
protected string device;
protected YRequestBuilder(YandexMusicApi yandex, AuthStorage auth)
{
_requestInfo = GetType().GetCustomAttribute<YRequestAttribute>()
?? throw new NotImplementedException($"Отсутствует атрибут {nameof(YRequestAttribute)}");
api = yandex;
storage = auth;
device = $"os=CSharp; os_version=; manufacturer=FrigaT; model=Yandex Music API; clid=; device_id={storage.DeviceId}; uuid=random";
_jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
};
}
private Uri BuildUri(TParams tuple)
{
var queryParams = GetQueryParams(tuple);
var modifiedParams = HttpUtility.ParseQueryString(string.Empty);
foreach (string? key in queryParams)
if (key != null)
modifiedParams[key] = ReplaceSubs(queryParams[key]!);
var endpoint = ReplaceSubs(_requestInfo.Url);
var builder = new UriBuilder(endpoint) { Query = modifiedParams.ToString() ?? string.Empty };
return builder.Uri;
}
private HttpRequestMessage CreateMessage(TParams tuple)
{
var msg = new HttpRequestMessage
{
RequestUri = BuildUri(tuple),
Method = new HttpMethod(_requestInfo.Method),
Content = GetContent(tuple)
};
msg.Headers.TryAddWithoutValidation(HttpRequestHeader.AcceptCharset.GetName(), Encoding.UTF8.WebName);
msg.Headers.TryAddWithoutValidation(HttpRequestHeader.AcceptEncoding.GetName(), "gzip");
if (!string.IsNullOrEmpty(storage.Token))
msg.Headers.TryAddWithoutValidation(HttpRequestHeader.Authorization.GetName(), $"OAuth {storage.Token}");
SetCustomHeaders(msg.Headers);
return msg;
}
protected string ReplaceSubs(string str)
{
var subs = str.GetMatches(@"\{.+?\}");
foreach (var s in subs)
{
var key = s.ReplaceRegex(@"[\{\}]", string.Empty);
if (!_substitutions.TryGetValue(key, out var value))
throw new Exception($"Не найдена подстановка {s}");
str = str.Replace(s, value);
}
return str;
}
protected virtual Dictionary<string, string> GetSubstitutions(TParams tuple) => [];
protected virtual NameValueCollection GetQueryParams(TParams tuple) => [];
protected virtual HttpContent? GetContent(TParams tuple) => null;
protected virtual void SetCustomHeaders(HttpRequestHeaders headers) { }
protected string SerializeJson(object data) => JsonSerializer.Serialize(data, _jsonOptions);
internal YRequest<TResponse> Build(TParams tuple)
{
_substitutions = GetSubstitutions(tuple);
var msg = CreateMessage(tuple);
return new YRequest<TResponse>(msg, api, storage);
}
}