159 lines
4.8 KiB
C#
159 lines
4.8 KiB
C#
using System.Collections.Specialized;
|
||
using System.Net;
|
||
using System.Net.Http.Headers;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Web;
|
||
|
||
using YandexMusic.API.Common;
|
||
using YandexMusic.API.Extensions;
|
||
using YandexMusic.API.Requests.Common.Attributes;
|
||
|
||
namespace YandexMusic.API.Requests.Common
|
||
{
|
||
public class YRequestBuilder<ResponseType, ParamsTuple>
|
||
{
|
||
#region Поля
|
||
|
||
private readonly JsonSerializerSettings jsonSettings = new()
|
||
{
|
||
Converters = new List<JsonConverter> {
|
||
new StringEnumConverter {
|
||
NamingStrategy = new CamelCaseNamingStrategy()
|
||
}
|
||
},
|
||
NullValueHandling = NullValueHandling.Ignore,
|
||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||
};
|
||
|
||
private YRequestAttribute requestInfo;
|
||
private Dictionary<string, string> subs;
|
||
|
||
protected YandexMusicApi api;
|
||
protected AuthStorage storage;
|
||
protected string device;
|
||
|
||
#endregion Поля
|
||
|
||
#region Свойства
|
||
|
||
protected YandexMusicApi API => api;
|
||
protected AuthStorage Storage => storage;
|
||
|
||
#endregion Свойства
|
||
|
||
#region Вспомогательные функции
|
||
|
||
private Uri BuildUri(ParamsTuple tuple)
|
||
{
|
||
NameValueCollection queryParams = GetQueryParams(tuple);
|
||
NameValueCollection modifiedParams = HttpUtility.ParseQueryString(string.Empty);
|
||
|
||
// Подстановка в параметры
|
||
foreach (string key in queryParams.Keys)
|
||
{
|
||
modifiedParams.Set(key, ReplaceSubs(queryParams.Get(key)));
|
||
}
|
||
|
||
string endpoint = ReplaceSubs(requestInfo.Url);
|
||
|
||
UriBuilder builder = new(endpoint)
|
||
{
|
||
Query = modifiedParams.ToString() ?? string.Empty
|
||
};
|
||
|
||
|
||
return builder.Uri;
|
||
}
|
||
|
||
private HttpRequestMessage CreateMessage(ParamsTuple tuple)
|
||
{
|
||
HttpRequestMessage msg = new()
|
||
{
|
||
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)
|
||
{
|
||
string[] sub = str.GetMatches(@"\{.+?\}");
|
||
|
||
foreach (string s in sub)
|
||
{
|
||
if (!subs.TryGetValue(s.ReplaceRegex(@"[\{\}]", string.Empty), out string value))
|
||
throw new Exception($"Не найдена подстановка {s}");
|
||
|
||
str = str.Replace(s, value);
|
||
}
|
||
|
||
return str;
|
||
}
|
||
protected virtual Dictionary<string, string> GetSubstitutions(ParamsTuple tuple)
|
||
{
|
||
return new Dictionary<string, string>();
|
||
}
|
||
|
||
protected virtual NameValueCollection GetQueryParams(ParamsTuple tuple)
|
||
{
|
||
return new NameValueCollection();
|
||
}
|
||
|
||
protected virtual HttpContent GetContent(ParamsTuple tuple)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
protected virtual void SetCustomHeaders(HttpRequestHeaders headers)
|
||
{
|
||
}
|
||
|
||
protected string SerializeJson(object data)
|
||
{
|
||
return JsonConvert.SerializeObject(data, jsonSettings);
|
||
}
|
||
|
||
#endregion Вспомогательные функции
|
||
|
||
|
||
|
||
public YRequestBuilder(YandexMusicApi yandex, AuthStorage auth)
|
||
{
|
||
requestInfo = GetType()
|
||
.GetCustomAttributes<YRequestAttribute>()
|
||
.FirstOrDefault();
|
||
|
||
if (requestInfo == null)
|
||
throw new NotImplementedException($"Отсутствует атрибут {nameof(YRequestAttribute)}");
|
||
|
||
api = yandex;
|
||
storage = auth;
|
||
|
||
// Устройство по умолчанию
|
||
device = $"os=CSharp; os_version=; manufacturer=K1llM@n; model=Yandex Music API; clid=; device_id={storage.DeviceId}; uuid=random";
|
||
}
|
||
|
||
internal YRequest<ResponseType> Build(ParamsTuple tuple)
|
||
{
|
||
subs = GetSubstitutions(tuple);
|
||
HttpRequestMessage msg = CreateMessage(tuple);
|
||
|
||
return new YRequest<ResponseType>(msg, api, storage);
|
||
}
|
||
|
||
|
||
}
|
||
}
|