6 Commits

Author SHA1 Message Date
FrigaT
34261d02a9 Авторизация через паспорт
All checks were successful
Release / pack-and-publish (release) Successful in 31s
2026-04-20 15:58:27 +03:00
FrigaT
5f761d4fe8 Добавлена авторизация через паспорт 2026-04-20 15:56:38 +03:00
FrigaT
b6f78da9c8 dispose
All checks were successful
Release / pack-and-publish (release) Successful in 37s
2026-04-20 14:47:43 +03:00
FrigaT
0bbaac5689 Переделан способ авторизации по qr
All checks were successful
Release / pack-and-publish (release) Successful in 1m5s
2026-04-20 14:31:47 +03:00
FrigaT
a7caf829d3 Открыл AuthToken
All checks were successful
Release / pack-and-publish (release) Successful in 34s
2026-04-19 20:19:41 +03:00
FrigaT
add7f08215 Добавлен вывод AuthStorage. Спрятаны внутренние api запросы
All checks were successful
Release / pack-and-publish (release) Successful in 32s
2026-04-19 17:41:30 +03:00
75 changed files with 273 additions and 123 deletions

View File

@@ -26,8 +26,8 @@ public class YTrackAPI : YCommonAPI
return $"https://{host}/get-{codec}/{sign}/{ts}{path}"; return $"https://{host}/get-{codec}/{sign}/{ts}{path}";
} }
public Task<YTrack?> GetAsync(string trackId) public async Task<YTrack?> GetAsync(string trackId)
=> GetAsync(trackId); => (await GetAsync([trackId]))?.FirstOrDefault();
public Task<List<YTrack>?> GetAsync(IEnumerable<string> trackIds) public Task<List<YTrack>?> GetAsync(IEnumerable<string> trackIds)
=> new YGetTracksBuilder(Api).ExecuteAsync(trackIds); => new YGetTracksBuilder(Api).ExecuteAsync(trackIds);

View File

@@ -23,7 +23,7 @@ public class YUserAPI : YCommonAPI
if (!csrfMatch.Success || !processMatch.Success) if (!csrfMatch.Success || !processMatch.Success)
return false; return false;
Api.Storage.AuthToken = new YAuthToken Api.Storage.HeaderToken = new YAuthToken
{ {
CsfrToken = csrfMatch.Groups[1].Value, CsfrToken = csrfMatch.Groups[1].Value,
ProcessUuid = processMatch.Groups[1].Value ProcessUuid = processMatch.Groups[1].Value
@@ -45,9 +45,7 @@ public class YUserAPI : YCommonAPI
Api.Storage.AccessToken = accessToken; Api.Storage.AccessToken = accessToken;
Api.Storage.Token = accessToken.AccessToken; Api.Storage.Token = accessToken.AccessToken;
var shortInfo = await new YGetShortAccountInfoBuilder(Api).ExecuteAsync(null!); await AuthorizeByPassportAsync(accessToken.AccessToken);
if (shortInfo?.Status != YAuthStatus.Ok || string.IsNullOrWhiteSpace(shortInfo.Uid))
throw new Exception("Не удалось подтвердить авторизацию");
return true; return true;
} }
@@ -65,6 +63,16 @@ public class YUserAPI : YCommonAPI
Api.Storage.SetAuthorized(authInfo.Account, token); Api.Storage.SetAuthorized(authInfo.Account, token);
} }
public async Task AuthorizeByPassportAsync(string token)
{
if (string.IsNullOrEmpty(token))
throw new Exception("Токен не может быть пустым");
Api.Storage.Token = token;
await GetAccessTokenAsync();
await AuthorizeAsync(Api.Storage.Token);
}
public Task<YAccountResult?> GetUserAuthAsync() public Task<YAccountResult?> GetUserAuthAsync()
=> new YGetAuthInfoBuilder(Api).ExecuteAsync(null!); => new YGetAuthInfoBuilder(Api).ExecuteAsync(null!);
@@ -96,13 +104,31 @@ public class YUserAPI : YCommonAPI
return $"https://passport.yandex.ru/auth/magic/code/?track_id={qr.TrackId}"; return $"https://passport.yandex.ru/auth/magic/code/?track_id={qr.TrackId}";
} }
public async Task<YAuthQRStatus?> AuthorizeByQRAsync() public async Task<YAuthQRStatus?> CheckQRStatusAsync()
{ {
if (Api.Storage.AuthToken == null) if (Api.Storage.AuthToken == null)
throw new Exception("Сессия не инициализирована"); throw new Exception("Сессия не инициализирована");
var status = await new YPostQrStatus(Api).ExecuteAsync(null!);
if (!string.IsNullOrWhiteSpace(status?.TrackId))
{
Api.Storage.AuthToken.SessionTrackId = status.TrackId;
}
return status;
}
public async Task<YAuthQRSession?> AuthorizeByQRAsync()
{
if (Api.Storage.AuthToken == null)
throw new Exception("Сессия не инициализирована");
if (string.IsNullOrWhiteSpace(Api.Storage.AuthToken.SessionTrackId))
throw new Exception("Токен сессии не инициализирован");
var status = await new YGetAuthLoginQRBuilder(Api).ExecuteAsync(null!); var status = await new YGetAuthLoginQRBuilder(Api).ExecuteAsync(null!);
if (status?.Status == YAuthStatus.Ok && await LoginByCookiesAsync()) if (status != null && status.DefaultUid != 0 && await LoginByCookiesAsync())
return status; return status;
throw new AuthenticationException("Ошибка авторизации по QR"); throw new AuthenticationException("Ошибка авторизации по QR");
} }

View File

@@ -1,3 +1,4 @@
using System.Net;
using YandexMusic.API.Models.Account; using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Common; namespace YandexMusic.API.Common;
@@ -7,6 +8,15 @@ namespace YandexMusic.API.Common;
/// </summary> /// </summary>
public class AuthStorage public class AuthStorage
{ {
private CookieContainer _cookieContainer;
public AuthStorage(CookieContainer cookieContainer)
{
_cookieContainer = cookieContainer;
}
public CookieContainer CookieContainer => _cookieContainer;
/// <summary> /// <summary>
/// Флаг, указывающий, авторизован ли пользователь. /// Флаг, указывающий, авторизован ли пользователь.
/// </summary> /// </summary>
@@ -35,7 +45,12 @@ public class AuthStorage
/// <summary> /// <summary>
/// Внутренние данные авторизации (CSRF, track_id и т.д.). /// Внутренние данные авторизации (CSRF, track_id и т.д.).
/// </summary> /// </summary>
internal YAuthToken AuthToken { get; set; } = new(); public YAuthToken HeaderToken { get; set; } = new();
/// <summary>
/// Внутренние данные авторизации (CSRF, track_id и т.д.).
/// </summary>
public YAuthToken AuthToken { get; set; } = new();
/// <summary> /// <summary>
/// Устанавливает флаг авторизации и сохраняет информацию об аккаунте. /// Устанавливает флаг авторизации и сохраняет информацию об аккаунте.

View File

@@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
namespace YandexMusic.API.Converters; namespace YandexMusic.API.Converters;
public class IntToStringConverter : JsonConverter<string> internal class IntToStringConverter : JsonConverter<string>
{ {
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{ {

View File

@@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
namespace YandexMusic.API.Converters; namespace YandexMusic.API.Converters;
public class StringToIntConverter : JsonConverter<int> internal class StringToIntConverter : JsonConverter<int>
{ {
public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{ {

View File

@@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
namespace YandexMusic.API.Models.Account;
public class YAuthQRSession
{
[JsonPropertyName("default_uid")]
public int DefaultUid { get; set; }
[JsonPropertyName("retpath")]
public string RetPath { get; set; }
[JsonPropertyName("track_id")]
public string TrackId { get; set; }
public string Id { get; set; }
public string State { get; set; }
public YAuthCaptcha Captcha { get; set; }
}

View File

@@ -0,0 +1,9 @@
using System.Runtime.Serialization;
namespace YandexMusic.API.Models.Account;
public enum YAuthQrState
{
[EnumMember(Value = "otp_auth_finished")]
OtpAuthFinished,
}

View File

@@ -2,19 +2,11 @@
namespace YandexMusic.API.Models.Account; namespace YandexMusic.API.Models.Account;
public class YAuthQRStatus : YAuthBase public class YAuthQRStatus
{ {
[JsonPropertyName("default_uid")] [JsonPropertyName("state")]
public int DefaultUid { get; set; } public string? State { get; set; } = null;
public string RetPath { get; set; } [JsonPropertyName("trackId")]
public string TrackId { get; set; } = string.Empty;
[JsonPropertyName("track_id")]
public string TrackId { get; set; }
public string Id { get; set; }
public string State { get; set; }
public YAuthCaptcha Captcha { get; set; }
} }

View File

@@ -1,16 +1,13 @@
using System.Text.Json.Serialization; namespace YandexMusic.API.Models.Account;
namespace YandexMusic.API.Models.Account;
public class YAuthToken public class YAuthToken
{ {
[JsonPropertyName("csfr_token")]
public string CsfrToken { get; set; } public string CsfrToken { get; set; }
[JsonPropertyName("track_id")]
public string TrackId { get; set; } public string TrackId { get; set; }
[JsonPropertyName("process_uuid")] public string SessionTrackId { get; set; }
public string ProcessUuid { get; set; } public string ProcessUuid { get; set; }
public Dictionary<string, string> Cookie { get; set; } = new(); public Dictionary<string, string> Cookie { get; set; } = new();

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthAppPasswordBuilder : YAuthRequestBuilder<YAuthBase?, string> internal class YGetAuthAppPasswordBuilder : YAuthRequestBuilder<YAuthBase?, string>
{ {
public YGetAuthAppPasswordBuilder(YandexMusicApi api) : base(api) { } public YGetAuthAppPasswordBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthCaptchaBuilder : YAuthRequestBuilder<YAuthCaptcha?, object> internal class YGetAuthCaptchaBuilder : YAuthRequestBuilder<YAuthCaptcha?, object>
{ {
public YGetAuthCaptchaBuilder(YandexMusicApi api) : base(api) { } public YGetAuthCaptchaBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -1,14 +1,55 @@
using System.Net; using System.Net;
using System.Net.Http.Headers;
using YandexMusic.API.Models.Account; using YandexMusic.API.Models.Account;
using YandexMusic.API.Requests.Common; using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthCookiesBuilder : YAuthRequestBuilder<YAccessToken?, object> internal class YGetAuthCookiesBuilder : YAuthRequestBuilder<YAccessToken?, object>
{ {
public YGetAuthCookiesBuilder(YandexMusicApi api) : base(api) { } public YGetAuthCookiesBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;
protected override string BaseUrl => YConstants.Endpoints.MobilePassportUrl;
protected override string PathTemplate => "1/bundle/oauth/token_by_sessionid"; protected override string PathTemplate => "1/bundle/oauth/token_by_sessionid";
protected override HttpContent? GetContent(object _) protected override HttpContent? GetContent(object _)
=> new FormUrlEncodedContent(new Dictionary<string, string> { { "client_id", YConstants.XClientId }, { "client_secret", YConstants.XClientSecret } }); => new FormUrlEncodedContent(new Dictionary<string, string> { { "client_id", YConstants.XClientId }, { "client_secret", YConstants.XClientSecret } });
protected override void SetCustomHeaders(HttpRequestHeaders headers)
{
base.SetCustomHeaders(headers);
headers.Add("ya-client-host", "passport.yandex.ru");
var cookieString = GetCookieString();
if (!string.IsNullOrEmpty(cookieString))
headers.Add("Ya-Client-Cookie", cookieString);
}
private string GetCookieString()
{
var container = Storage.CookieContainer;
if (container == null) return string.Empty;
var uris = new[]
{
new Uri("https://yandex.ru"),
new Uri("https://passport.yandex.ru"),
new Uri("https://mobileproxy.passport.yandex.net")
};
var cookies = new List<string>();
foreach (var uri in uris)
{
var cookieCollection = container.GetCookies(uri);
foreach (Cookie cookie in cookieCollection)
{
cookies.Add($"{cookie.Name}={cookie.Value}");
}
}
var distinct = cookies
.Select(c => c.Split('=')[0])
.Distinct()
.Select(name => cookies.First(c => c.StartsWith(name + "=")))
.ToList();
return string.Join("; ", distinct);
}
} }

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthInfoBuilder : YMusicRequestBuilder<YAccountResult?, object> internal class YGetAuthInfoBuilder : YMusicRequestBuilder<YAccountResult?, object>
{ {
public YGetAuthInfoBuilder(YandexMusicApi api) : base(api) { } public YGetAuthInfoBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthLetterBuilder : YAuthRequestBuilder<YAuthLetter?, object> internal class YGetAuthLetterBuilder : YAuthRequestBuilder<YAuthLetter?, object>
{ {
public YGetAuthLetterBuilder(YandexMusicApi api) : base(api) { } public YGetAuthLetterBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthLoginCaptchaBuilder : YAuthRequestBuilder<YAuthBase?, string> internal class YGetAuthLoginCaptchaBuilder : YAuthRequestBuilder<YAuthBase?, string>
{ {
public YGetAuthLoginCaptchaBuilder(YandexMusicApi api) : base(api) { } public YGetAuthLoginCaptchaBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthLoginLetterBuilder : YAuthRequestBuilder<YAuthLetterStatus?, object> internal class YGetAuthLoginLetterBuilder : YAuthRequestBuilder<YAuthLetterStatus?, object>
{ {
public YGetAuthLoginLetterBuilder(YandexMusicApi api) : base(api) { } public YGetAuthLoginLetterBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -1,9 +1,10 @@
using System.Net; using System.Net;
using System.Net.Http.Headers;
using YandexMusic.API.Models.Account; using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
internal class YGetAuthLoginQRBuilder : YAuthRequestBuilder<YAuthQRStatus, string> internal class YGetAuthLoginQRBuilder : YAuthRequestBuilder<YAuthQRSession, string>
{ {
public YGetAuthLoginQRBuilder(YandexMusicApi yandex) : base(yandex) public YGetAuthLoginQRBuilder(YandexMusicApi yandex) : base(yandex)
{ {
@@ -11,13 +12,17 @@ internal class YGetAuthLoginQRBuilder : YAuthRequestBuilder<YAuthQRStatus, strin
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;
protected override string PathTemplate => "auth/new/magic/status/"; protected override string PathTemplate => "pwl-yandex/api/passport/sessions/get_session";
protected override HttpContent GetContent(string tuple) protected override HttpContent GetContent(string tuple)
{ {
return new FormUrlEncodedContent(new Dictionary<string, string> { return new FormUrlEncodedContent(new Dictionary<string, string> {
{ "csrf_token", Api.Storage.AuthToken.CsfrToken }, { "track_id", Api.Storage.AuthToken.SessionTrackId }
{ "track_id", Api.Storage.AuthToken.TrackId }
}); });
} }
protected override void SetCustomHeaders(HttpRequestHeaders headers)
{
headers.Add("X-Csrf-Token", Api.Storage.HeaderToken.CsfrToken);
headers.Add("Process-Uuid", Api.Storage.HeaderToken.ProcessUuid);
}
} }

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthLoginUserBuilder : YAuthRequestBuilder<YAuthTypes?, (string token, string login)> internal class YGetAuthLoginUserBuilder : YAuthRequestBuilder<YAuthTypes?, (string token, string login)>
{ {
public YGetAuthLoginUserBuilder(YandexMusicApi api) : base(api) { } public YGetAuthLoginUserBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthMethodsBuilder : YRequestBuilder<object> internal class YGetAuthMethodsBuilder : YRequestBuilder<object>
{ {
public YGetAuthMethodsBuilder(YandexMusicApi api) : base(api) { } public YGetAuthMethodsBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetAuthQRBuilder : YAuthRequestBuilder<YAuthQR?, object> internal class YGetAuthQRBuilder : YAuthRequestBuilder<YAuthQR?, object>
{ {
public YGetAuthQRBuilder(YandexMusicApi api) : base(api) { } public YGetAuthQRBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;
@@ -13,7 +13,7 @@ public class YGetAuthQRBuilder : YAuthRequestBuilder<YAuthQR?, object>
=> new FormUrlEncodedContent(new Dictionary<string, string> { { "retpath", "" } }); => new FormUrlEncodedContent(new Dictionary<string, string> { { "retpath", "" } });
protected override void SetCustomHeaders(HttpRequestHeaders headers) protected override void SetCustomHeaders(HttpRequestHeaders headers)
{ {
headers.Add("X-Csrf-Token", Api.Storage.AuthToken.CsfrToken); headers.Add("X-Csrf-Token", Api.Storage.HeaderToken.CsfrToken);
headers.Add("Process-Uuid", Api.Storage.AuthToken.ProcessUuid); headers.Add("Process-Uuid", Api.Storage.HeaderToken.ProcessUuid);
} }
} }

View File

@@ -1,10 +1,9 @@
using System.Net; using System.Net;
using YandexMusic.API.Models.Account; using YandexMusic.API.Models.Account;
using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetLoginInfoBuilder : YAuthRequestBuilder<YLoginInfo?, object> internal class YGetLoginInfoBuilder : YAuthRequestBuilder<YLoginInfo?, object>
{ {
public YGetLoginInfoBuilder(YandexMusicApi api) : base(api) { } public YGetLoginInfoBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -5,9 +5,10 @@ using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetMusicTokenBuilder : YAuthRequestBuilder<YAccessToken?, object> internal class YGetMusicTokenBuilder : YAuthRequestBuilder<YAccessToken?, object>
{ {
public YGetMusicTokenBuilder(YandexMusicApi api) : base(api) { } public YGetMusicTokenBuilder(YandexMusicApi api) : base(api) { }
protected override string BaseUrl => YConstants.Endpoints.MobilePassportUrl;
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;
protected override string PathTemplate => "/1/token"; protected override string PathTemplate => "/1/token";
protected override HttpContent? GetContent(object _) protected override HttpContent? GetContent(object _)

View File

@@ -5,7 +5,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YGetShortAccountInfoBuilder : YAuthRequestBuilder<YShortAccountInfo?, object> internal class YGetShortAccountInfoBuilder : YAuthRequestBuilder<YShortAccountInfo?, object>
{ {
public YGetShortAccountInfoBuilder(YandexMusicApi api) : base(api) { } public YGetShortAccountInfoBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account; namespace YandexMusic.API.Requests.Account;
public class YPostAuthStats : YAuthRequestBuilder<YAuthEmpty?, object> internal class YPostAuthStats : YAuthRequestBuilder<YAuthEmpty?, object>
{ {
public YPostAuthStats(YandexMusicApi api) : base(api) { } public YPostAuthStats(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;
@@ -13,7 +13,7 @@ public class YPostAuthStats : YAuthRequestBuilder<YAuthEmpty?, object>
=> new FormUrlEncodedContent(new Dictionary<string, string> { { "messageType", "CLIENT_READY" } }); => new FormUrlEncodedContent(new Dictionary<string, string> { { "messageType", "CLIENT_READY" } });
protected override void SetCustomHeaders(HttpRequestHeaders headers) protected override void SetCustomHeaders(HttpRequestHeaders headers)
{ {
headers.Add("X-Csrf-Token", Api.Storage.AuthToken.CsfrToken); headers.Add("X-Csrf-Token", Api.Storage.HeaderToken.CsfrToken);
headers.Add("Process-Uuid", Api.Storage.AuthToken.ProcessUuid); headers.Add("Process-Uuid", Api.Storage.HeaderToken.ProcessUuid);
} }
} }

View File

@@ -0,0 +1,23 @@
using System.Net;
using System.Net.Http.Headers;
using YandexMusic.API.Models.Account;
namespace YandexMusic.API.Requests.Account;
internal class YPostQrStatus : YAuthRequestBuilder<YAuthQRStatus?, object>
{
public YPostQrStatus(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post;
protected override string PathTemplate => "pwl-yandex/api/passport/auth/magic/code/status";
protected override HttpContent? GetContent(object _)
=> new FormUrlEncodedContent(new Dictionary<string, string>
{
["csrf_token"] = Api.Storage.AuthToken.CsfrToken,
["track_id"] = Api.Storage.AuthToken.TrackId,
});
protected override void SetCustomHeaders(HttpRequestHeaders headers)
{
headers.Add("X-Csrf-Token", Api.Storage.HeaderToken.CsfrToken);
headers.Add("Process-Uuid", Api.Storage.HeaderToken.ProcessUuid);
}
}

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Album;
namespace YandexMusic.API.Requests.Album; namespace YandexMusic.API.Requests.Album;
public class YGetAlbumBuilder : YMusicRequestBuilder<YAlbum?, string> internal class YGetAlbumBuilder : YMusicRequestBuilder<YAlbum?, string>
{ {
public YGetAlbumBuilder(YandexMusicApi api) : base(api) { } public YGetAlbumBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Album;
namespace YandexMusic.API.Requests.Album; namespace YandexMusic.API.Requests.Album;
public class YGetAlbumsBuilder : YMusicRequestBuilder<List<YAlbum>?, IEnumerable<string>> internal class YGetAlbumsBuilder : YMusicRequestBuilder<List<YAlbum>?, IEnumerable<string>>
{ {
public YGetAlbumsBuilder(YandexMusicApi api) : base(api) { } public YGetAlbumsBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Artist;
namespace YandexMusic.API.Requests.Artist; namespace YandexMusic.API.Requests.Artist;
public class YGetArtistBuilder : YMusicRequestBuilder<YArtistBriefInfo?, string> internal class YGetArtistBuilder : YMusicRequestBuilder<YArtistBriefInfo?, string>
{ {
public YGetArtistBuilder(YandexMusicApi api) : base(api) { } public YGetArtistBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Artist;
namespace YandexMusic.API.Requests.Artist; namespace YandexMusic.API.Requests.Artist;
public class YGetArtistTrackBuilder : YMusicRequestBuilder<YTracksPage?, (string id, int page, int pageSize)> internal class YGetArtistTrackBuilder : YMusicRequestBuilder<YTracksPage?, (string id, int page, int pageSize)>
{ {
public YGetArtistTrackBuilder(YandexMusicApi api) : base(api) { } public YGetArtistTrackBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Artist;
namespace YandexMusic.API.Requests.Artist; namespace YandexMusic.API.Requests.Artist;
public class YGetArtistsBuilder : YMusicRequestBuilder<List<YArtist>?, IEnumerable<string>> internal class YGetArtistsBuilder : YMusicRequestBuilder<List<YArtist>?, IEnumerable<string>>
{ {
public YGetArtistsBuilder(YandexMusicApi api) : base(api) { } public YGetArtistsBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests; namespace YandexMusic.API.Requests;
/// <summary>Базовый класс для запросов к Passport (passport.yandex.ru).</summary> /// <summary>Базовый класс для запросов к Passport (passport.yandex.ru).</summary>
public abstract class YAuthRequestBuilder<TResponse, TParams> : YJsonRequestBuilder<TResponse, TParams> internal abstract class YAuthRequestBuilder<TResponse, TParams> : YJsonRequestBuilder<TResponse, TParams>
{ {
protected override string BaseUrl => YConstants.Endpoints.PassportUrl; protected override string BaseUrl => YConstants.Endpoints.PassportUrl;

View File

@@ -12,5 +12,6 @@ internal class YConstants
{ {
public const string MusicUrl = "https://api.music.yandex.net"; public const string MusicUrl = "https://api.music.yandex.net";
public const string PassportUrl = "https://passport.yandex.ru/"; public const string PassportUrl = "https://passport.yandex.ru/";
public const string MobilePassportUrl = "https://mobileproxy.passport.yandex.net";
} }
} }

View File

@@ -8,7 +8,7 @@ namespace YandexMusic.API.Requests.Common;
/// <summary> /// <summary>
/// Строитель запросов с десериализацией JSON-ответа в TResponse. /// Строитель запросов с десериализацией JSON-ответа в TResponse.
/// </summary> /// </summary>
public abstract class YJsonRequestBuilder<TResponse, TParams> : YRequestBuilder<TParams> internal abstract class YJsonRequestBuilder<TResponse, TParams> : YRequestBuilder<TParams>
{ {
protected YJsonRequestBuilder(YandexMusicApi api) : base(api) { } protected YJsonRequestBuilder(YandexMusicApi api) : base(api) { }

View File

@@ -8,7 +8,7 @@ using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests; namespace YandexMusic.API.Requests;
/// <summary>Базовый класс для запросов к API Яндекс Музыки (api.music.yandex.net).</summary> /// <summary>Базовый класс для запросов к API Яндекс Музыки (api.music.yandex.net).</summary>
public abstract class YMusicRequestBuilder<TResponse, TParams> : YJsonRequestBuilder<TResponse, TParams> internal abstract class YMusicRequestBuilder<TResponse, TParams> : YJsonRequestBuilder<TResponse, TParams>
{ {
protected override string BaseUrl => YConstants.Endpoints.MusicUrl; protected override string BaseUrl => YConstants.Endpoints.MusicUrl;

View File

@@ -12,7 +12,7 @@ namespace YandexMusic.API.Requests.Common;
/// <summary>Базовый строитель HTTP-запросов.</summary> /// <summary>Базовый строитель HTTP-запросов.</summary>
/// <typeparam name="TParams">Тип параметров запроса.</typeparam> /// <typeparam name="TParams">Тип параметров запроса.</typeparam>
public abstract class YRequestBuilder<TParams> internal abstract class YRequestBuilder<TParams>
{ {
/// <summary>HTTP-метод (GET, POST и т.д.).</summary> /// <summary>HTTP-метод (GET, POST и т.д.).</summary>
protected abstract string Method { get; } protected abstract string Method { get; }

View File

@@ -1,10 +1,9 @@
using System.Net; using System.Net;
using YandexMusic.API.Models.Feed; using YandexMusic.API.Models.Feed;
using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Feed; namespace YandexMusic.API.Requests.Feed;
public class YGetFeedBuilder : YMusicRequestBuilder<YFeed?, object> internal class YGetFeedBuilder : YMusicRequestBuilder<YFeed?, object>
{ {
public YGetFeedBuilder(YandexMusicApi api) : base(api) { } public YGetFeedBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -5,7 +5,7 @@ using YandexMusic.API.Models.Label;
namespace YandexMusic.API.Requests.Label; namespace YandexMusic.API.Requests.Label;
public class YGetLabelAlbumsBuilder : YMusicRequestBuilder<YLabelAlbums?, (YLabel label, int pageNumber)> internal class YGetLabelAlbumsBuilder : YMusicRequestBuilder<YLabelAlbums?, (YLabel label, int pageNumber)>
{ {
public YGetLabelAlbumsBuilder(YandexMusicApi api) : base(api) { } public YGetLabelAlbumsBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -5,7 +5,7 @@ using YandexMusic.API.Models.Label;
namespace YandexMusic.API.Requests.Label; namespace YandexMusic.API.Requests.Label;
public class YGetLabelArtistsBuilder : YMusicRequestBuilder<YLabelArtists?, (YLabel label, int pageNumber)> internal class YGetLabelArtistsBuilder : YMusicRequestBuilder<YLabelArtists?, (YLabel label, int pageNumber)>
{ {
public YGetLabelArtistsBuilder(YandexMusicApi api) : base(api) { } public YGetLabelArtistsBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -1,10 +1,9 @@
using System.Net; using System.Net;
using YandexMusic.API.Models.Landing; using YandexMusic.API.Models.Landing;
using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Landing; namespace YandexMusic.API.Requests.Landing;
public class YGetChildrenLandingBuilder : YMusicRequestBuilder<YChildrenLanding?, object> internal class YGetChildrenLandingBuilder : YMusicRequestBuilder<YChildrenLanding?, object>
{ {
public YGetChildrenLandingBuilder(YandexMusicApi api) : base(api) { } public YGetChildrenLandingBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Landing;
namespace YandexMusic.API.Requests.Landing; namespace YandexMusic.API.Requests.Landing;
public class YGetLandingBuilder : YMusicRequestBuilder<YLanding?, YLandingBlockType[]> internal class YGetLandingBuilder : YMusicRequestBuilder<YLanding?, YLandingBlockType[]>
{ {
public YGetLandingBuilder(YandexMusicApi api) : base(api) { } public YGetLandingBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -5,7 +5,7 @@ using YandexMusic.API.Models.Library;
namespace YandexMusic.API.Requests.Library; namespace YandexMusic.API.Requests.Library;
public class YGetLibraryRecentlyListenedBuilder : YMusicRequestBuilder<YRecentlyListenedContext?, (IEnumerable<YPlayContextType> contextTypes, int trackCount, int contextCount)> internal class YGetLibraryRecentlyListenedBuilder : YMusicRequestBuilder<YRecentlyListenedContext?, (IEnumerable<YPlayContextType> contextTypes, int trackCount, int contextCount)>
{ {
public YGetLibraryRecentlyListenedBuilder(YandexMusicApi api) : base(api) { } public YGetLibraryRecentlyListenedBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Library;
namespace YandexMusic.API.Requests.Library; namespace YandexMusic.API.Requests.Library;
public class YGetLibrarySectionBuilder<T> : YMusicRequestBuilder<T?, (YLibrarySection section, YLibrarySectionType type)> internal class YGetLibrarySectionBuilder<T> : YMusicRequestBuilder<T?, (YLibrarySection section, YLibrarySectionType type)>
{ {
public YGetLibrarySectionBuilder(YandexMusicApi api) : base(api) { } public YGetLibrarySectionBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Library;
namespace YandexMusic.API.Requests.Library; namespace YandexMusic.API.Requests.Library;
public class YLibraryAddBuilder<T> : YMusicRequestBuilder<T?, (string id, YLibrarySection section, YLibrarySectionType type)> internal class YLibraryAddBuilder<T> : YMusicRequestBuilder<T?, (string id, YLibrarySection section, YLibrarySectionType type)>
{ {
public YLibraryAddBuilder(YandexMusicApi api) : base(api) { } public YLibraryAddBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Library;
namespace YandexMusic.API.Requests.Library; namespace YandexMusic.API.Requests.Library;
public class YLibraryRemoveBuilder<T> : YMusicRequestBuilder<T?, (string id, YLibrarySection section, YLibrarySectionType type)> internal class YLibraryRemoveBuilder<T> : YMusicRequestBuilder<T?, (string id, YLibrarySection section, YLibrarySectionType type)>
{ {
public YLibraryRemoveBuilder(YandexMusicApi api) : base(api) { } public YLibraryRemoveBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -1,10 +1,9 @@
using System.Net; using System.Net;
using YandexMusic.API.Models.Pins; using YandexMusic.API.Models.Pins;
using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Pins; namespace YandexMusic.API.Requests.Pins;
public class YGetPinsBuilder : YMusicRequestBuilder<YPins?, object> internal class YGetPinsBuilder : YMusicRequestBuilder<YPins?, object>
{ {
public YGetPinsBuilder(YandexMusicApi api) : base(api) { } public YGetPinsBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Playlist;
namespace YandexMusic.API.Requests.Playlist; namespace YandexMusic.API.Requests.Playlist;
public class YGetPlaylistBuilder : YMusicRequestBuilder<YPlaylist?, (string user, string kind)> internal class YGetPlaylistBuilder : YMusicRequestBuilder<YPlaylist?, (string user, string kind)>
{ {
public YGetPlaylistBuilder(YandexMusicApi api) : base(api) { } public YGetPlaylistBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Playlist;
namespace YandexMusic.API.Requests.Playlist; namespace YandexMusic.API.Requests.Playlist;
public class YGetPlaylistByUuidBuilder : YMusicRequestBuilder<YPlaylist?, string> internal class YGetPlaylistByUuidBuilder : YMusicRequestBuilder<YPlaylist?, string>
{ {
public YGetPlaylistByUuidBuilder(YandexMusicApi api) : base(api) { } public YGetPlaylistByUuidBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Playlist;
namespace YandexMusic.API.Requests.Playlist; namespace YandexMusic.API.Requests.Playlist;
public class YGetPlaylistFavoritesBuilder : YMusicRequestBuilder<List<YPlaylist>?, object> internal class YGetPlaylistFavoritesBuilder : YMusicRequestBuilder<List<YPlaylist>?, object>
{ {
public YGetPlaylistFavoritesBuilder(YandexMusicApi api) : base(api) { } public YGetPlaylistFavoritesBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Playlist;
namespace YandexMusic.API.Requests.Playlist; namespace YandexMusic.API.Requests.Playlist;
public class YGetPlaylistsBuilder : YMusicRequestBuilder<List<YPlaylist>?, IEnumerable<(string User, string Kind)>> internal class YGetPlaylistsBuilder : YMusicRequestBuilder<List<YPlaylist>?, IEnumerable<(string User, string Kind)>>
{ {
public YGetPlaylistsBuilder(YandexMusicApi api) : base(api) { } public YGetPlaylistsBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Playlist;
namespace YandexMusic.API.Requests.Playlist; namespace YandexMusic.API.Requests.Playlist;
public class YPlaylistChangeBuilder : YMusicRequestBuilder<YPlaylist?, (YPlaylist playlist, IEnumerable<YPlaylistChange> changes)> internal class YPlaylistChangeBuilder : YMusicRequestBuilder<YPlaylist?, (YPlaylist playlist, IEnumerable<YPlaylistChange> changes)>
{ {
public YPlaylistChangeBuilder(YandexMusicApi api) : base(api) { } public YPlaylistChangeBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Playlist;
namespace YandexMusic.API.Requests.Playlist; namespace YandexMusic.API.Requests.Playlist;
public class YPlaylistCreateBuilder : YMusicRequestBuilder<YPlaylist?, string> internal class YPlaylistCreateBuilder : YMusicRequestBuilder<YPlaylist?, string>
{ {
public YPlaylistCreateBuilder(YandexMusicApi api) : base(api) { } public YPlaylistCreateBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -2,7 +2,7 @@
namespace YandexMusic.API.Requests.Playlist; namespace YandexMusic.API.Requests.Playlist;
public class YPlaylistRemoveBuilder : YMusicRequestBuilder<HttpResponseMessage, string> internal class YPlaylistRemoveBuilder : YMusicRequestBuilder<HttpResponseMessage, string>
{ {
public YPlaylistRemoveBuilder(YandexMusicApi api) : base(api) { } public YPlaylistRemoveBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Playlist;
namespace YandexMusic.API.Requests.Playlist; namespace YandexMusic.API.Requests.Playlist;
public class YPlaylistRenameBuilder : YMusicRequestBuilder<YPlaylist?, (string kind, string name)> internal class YPlaylistRenameBuilder : YMusicRequestBuilder<YPlaylist?, (string kind, string name)>
{ {
public YPlaylistRenameBuilder(YandexMusicApi api) : base(api) { } public YPlaylistRenameBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Queue;
namespace YandexMusic.API.Requests.Queue; namespace YandexMusic.API.Requests.Queue;
public class YGetQueueBuilder : YMusicRequestBuilder<YQueue?, string> internal class YGetQueueBuilder : YMusicRequestBuilder<YQueue?, string>
{ {
public YGetQueueBuilder(YandexMusicApi api) : base(api) { } public YGetQueueBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -8,7 +8,7 @@ using YandexMusic.API.Models.Queue;
namespace YandexMusic.API.Requests.Queue; namespace YandexMusic.API.Requests.Queue;
public class YQueueCreateBuilder : YMusicRequestBuilder<YNewQueue?, YQueue> internal class YQueueCreateBuilder : YMusicRequestBuilder<YNewQueue?, YQueue>
{ {
private string? _device; private string? _device;
public YQueueCreateBuilder(YandexMusicApi api, string? device = null) : base(api) => _device = device; public YQueueCreateBuilder(YandexMusicApi api, string? device = null) : base(api) => _device = device;

View File

@@ -5,7 +5,7 @@ using YandexMusic.API.Models.Queue;
namespace YandexMusic.API.Requests.Queue; namespace YandexMusic.API.Requests.Queue;
public class YQueueUpdatePositionBuilder : YMusicRequestBuilder<YUpdatedQueue?, (string queueId, int currentIndex, bool isInteractive)> internal class YQueueUpdatePositionBuilder : YMusicRequestBuilder<YUpdatedQueue?, (string queueId, int currentIndex, bool isInteractive)>
{ {
private string? _device; private string? _device;
public YQueueUpdatePositionBuilder(YandexMusicApi api, string? device = null) : base(api) => _device = device; public YQueueUpdatePositionBuilder(YandexMusicApi api, string? device = null) : base(api) => _device = device;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Queue;
namespace YandexMusic.API.Requests.Queue; namespace YandexMusic.API.Requests.Queue;
public class YQueuesListBuilder : YMusicRequestBuilder<YQueueItemsContainer?, string?> internal class YQueuesListBuilder : YMusicRequestBuilder<YQueueItemsContainer?, string?>
{ {
private string? _device; private string? _device;
public YQueuesListBuilder(YandexMusicApi api, string? device = null) : base(api) => _device = device; public YQueuesListBuilder(YandexMusicApi api, string? device = null) : base(api) => _device = device;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Radio;
namespace YandexMusic.API.Requests.Radio; namespace YandexMusic.API.Requests.Radio;
public class YGetStationBuilder : YMusicRequestBuilder<List<YStation>?, (string type, string tag)> internal class YGetStationBuilder : YMusicRequestBuilder<List<YStation>?, (string type, string tag)>
{ {
public YGetStationBuilder(YandexMusicApi api) : base(api) { } public YGetStationBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Radio;
namespace YandexMusic.API.Requests.Radio; namespace YandexMusic.API.Requests.Radio;
public class YGetStationTracksBuilder : YMusicRequestBuilder<YStationSequence?, (YStationDescription station, string prevTrackId)> internal class YGetStationTracksBuilder : YMusicRequestBuilder<YStationSequence?, (YStationDescription station, string prevTrackId)>
{ {
public YGetStationTracksBuilder(YandexMusicApi api) : base(api) { } public YGetStationTracksBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -1,10 +1,9 @@
using System.Net; using System.Net;
using YandexMusic.API.Models.Radio; using YandexMusic.API.Models.Radio;
using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Radio; namespace YandexMusic.API.Requests.Radio;
public class YGetStationsBuilder : YMusicRequestBuilder<List<YStation>?, object> internal class YGetStationsBuilder : YMusicRequestBuilder<List<YStation>?, object>
{ {
public YGetStationsBuilder(YandexMusicApi api) : base(api) { } public YGetStationsBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -1,10 +1,9 @@
using System.Net; using System.Net;
using YandexMusic.API.Models.Radio; using YandexMusic.API.Models.Radio;
using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Radio; namespace YandexMusic.API.Requests.Radio;
public class YGetStationsDashboardBuilder : YMusicRequestBuilder<YStationsDashboard?, object> internal class YGetStationsDashboardBuilder : YMusicRequestBuilder<YStationsDashboard?, object>
{ {
public YGetStationsDashboardBuilder(YandexMusicApi api) : base(api) { } public YGetStationsDashboardBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -8,7 +8,7 @@ using YandexMusic.API.Models.Radio;
namespace YandexMusic.API.Requests.Radio; namespace YandexMusic.API.Requests.Radio;
public class YSetSettings2Builder : YMusicRequestBuilder<string?, (YStationDescription station, YStationSettings2 settings2)> internal class YSetSettings2Builder : YMusicRequestBuilder<string?, (YStationDescription station, YStationSettings2 settings2)>
{ {
public YSetSettings2Builder(YandexMusicApi api) : base(api) { } public YSetSettings2Builder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -10,7 +10,7 @@ using YandexMusic.API.Models.Track;
namespace YandexMusic.API.Requests.Radio; namespace YandexMusic.API.Requests.Radio;
public class YSetStationFeedbackBuilder : YMusicRequestBuilder<string?, (YStationFeedbackType type, YStation station, YTrack? track, string batchId, double totalPlayedSeconds)> internal class YSetStationFeedbackBuilder : YMusicRequestBuilder<string?, (YStationFeedbackType type, YStation station, YTrack? track, string batchId, double totalPlayedSeconds)>
{ {
public YSetStationFeedbackBuilder(YandexMusicApi api) : base(api) { } public YSetStationFeedbackBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -5,7 +5,7 @@ using YandexMusic.API.Models.Search;
namespace YandexMusic.API.Requests.Search; namespace YandexMusic.API.Requests.Search;
public class YSearchBuilder : YMusicRequestBuilder<YSearch?, (string searchText, YSearchType searchType, int page, int pageSize)> internal class YSearchBuilder : YMusicRequestBuilder<YSearch?, (string searchText, YSearchType searchType, int page, int pageSize)>
{ {
public YSearchBuilder(YandexMusicApi api) : base(api) { } public YSearchBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Search;
namespace YandexMusic.API.Requests.Search; namespace YandexMusic.API.Requests.Search;
public class YSearchSuggestBuilder : YMusicRequestBuilder<YSearchSuggest?, string> internal class YSearchSuggestBuilder : YMusicRequestBuilder<YSearchSuggest?, string>
{ {
public YSearchSuggestBuilder(YandexMusicApi api) : base(api) { } public YSearchSuggestBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Track;
namespace YandexMusic.API.Requests.Track; namespace YandexMusic.API.Requests.Track;
public class YGetTrackSimilarBuilder : YMusicRequestBuilder<YTrackSimilar?, string> internal class YGetTrackSimilarBuilder : YMusicRequestBuilder<YTrackSimilar?, string>
{ {
public YGetTrackSimilarBuilder(YandexMusicApi api) : base(api) { } public YGetTrackSimilarBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Track;
namespace YandexMusic.API.Requests.Track; namespace YandexMusic.API.Requests.Track;
public class YGetTrackSupplementBuilder : YMusicRequestBuilder<YTrackSupplement?, string> internal class YGetTrackSupplementBuilder : YMusicRequestBuilder<YTrackSupplement?, string>
{ {
public YGetTrackSupplementBuilder(YandexMusicApi api) : base(api) { } public YGetTrackSupplementBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -3,7 +3,7 @@ using YandexMusic.API.Models.Track;
namespace YandexMusic.API.Requests.Track; namespace YandexMusic.API.Requests.Track;
public class YGetTracksBuilder : YMusicRequestBuilder<List<YTrack>?, IEnumerable<string>> internal class YGetTracksBuilder : YMusicRequestBuilder<List<YTrack>?, IEnumerable<string>>
{ {
public YGetTracksBuilder(YandexMusicApi api) : base(api) { } public YGetTracksBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Track;
namespace YandexMusic.API.Requests.Track; namespace YandexMusic.API.Requests.Track;
public class YSendTrackInfoBuilder : YMusicRequestBuilder<string?, (YTrack track, string from, bool fromCache, string playId, string playlistId, double totalPlayedSeconds, double endPositionSeconds)> internal class YSendTrackInfoBuilder : YMusicRequestBuilder<string?, (YTrack track, string from, bool fromCache, string playId, string playlistId, double totalPlayedSeconds, double endPositionSeconds)>
{ {
public YSendTrackInfoBuilder(YandexMusicApi api) : base(api) { } public YSendTrackInfoBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Post; protected override string Method => WebRequestMethods.Http.Post;

View File

@@ -6,7 +6,7 @@ using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Track; namespace YandexMusic.API.Requests.Track;
/// <summary>Особый запрос не к api.music.yandex.net, а к произвольному URL.</summary> /// <summary>Особый запрос не к api.music.yandex.net, а к произвольному URL.</summary>
public class YStorageDownloadFileBuilder : YJsonRequestBuilder<YStorageDownloadFile?, string> internal class YStorageDownloadFileBuilder : YJsonRequestBuilder<YStorageDownloadFile?, string>
{ {
public YStorageDownloadFileBuilder(YandexMusicApi api) : base(api) { } public YStorageDownloadFileBuilder(YandexMusicApi api) : base(api) { }
protected override string BaseUrl => ""; // не используется, т.к. URL берётся из параметра protected override string BaseUrl => ""; // не используется, т.к. URL берётся из параметра

View File

@@ -4,7 +4,7 @@ using YandexMusic.API.Models.Common;
namespace YandexMusic.API.Requests.Track; namespace YandexMusic.API.Requests.Track;
public class YTrackDownloadInfoBuilder : YMusicRequestBuilder<List<YTrackDownloadInfo>?, (string trackKey, bool direct)> internal class YTrackDownloadInfoBuilder : YMusicRequestBuilder<List<YTrackDownloadInfo>?, (string trackKey, bool direct)>
{ {
public YTrackDownloadInfoBuilder(YandexMusicApi api) : base(api) { } public YTrackDownloadInfoBuilder(YandexMusicApi api) : base(api) { }
protected override string Method => WebRequestMethods.Http.Get; protected override string Method => WebRequestMethods.Http.Get;

View File

@@ -6,7 +6,7 @@ using YandexMusic.API.Models.Ugc;
namespace YandexMusic.API.Requests.Ugc; namespace YandexMusic.API.Requests.Ugc;
public class YUgcGetUploadLinkBuilder : YMusicRequestBuilder<YUgcUpload?, (YPlaylist playlist, string fileName)> internal class YUgcGetUploadLinkBuilder : YMusicRequestBuilder<YUgcUpload?, (YPlaylist playlist, string fileName)>
{ {
private static readonly Random _random = new(); private static readonly Random _random = new();
public YUgcGetUploadLinkBuilder(YandexMusicApi api) : base(api) { } public YUgcGetUploadLinkBuilder(YandexMusicApi api) : base(api) { }

View File

@@ -5,7 +5,7 @@ using YandexMusic.API.Requests.Common;
namespace YandexMusic.API.Requests.Ugc; namespace YandexMusic.API.Requests.Ugc;
/// <summary>Загрузка трека специальный запрос на произвольный URL.</summary> /// <summary>Загрузка трека специальный запрос на произвольный URL.</summary>
public class YUgcUploadBuilder : YJsonRequestBuilder<YResponse<string>?, (string postTargetLink, byte[] fileBytes)> internal class YUgcUploadBuilder : YJsonRequestBuilder<YResponse<string>?, (string postTargetLink, byte[] fileBytes)>
{ {
public YUgcUploadBuilder(YandexMusicApi api) : base(api) { } public YUgcUploadBuilder(YandexMusicApi api) : base(api) { }
protected override string BaseUrl => ""; protected override string BaseUrl => "";

View File

@@ -1,4 +1,5 @@
using YandexMusic.API; using System.Net;
using YandexMusic.API;
using YandexMusic.API.Common; using YandexMusic.API.Common;
using YandexMusic.API.Common.Ynison; using YandexMusic.API.Common.Ynison;
using YandexMusic.API.Models.Account; using YandexMusic.API.Models.Account;
@@ -23,9 +24,11 @@ public class YandexMusicClient : IDisposable
private readonly YandexMusicApi _api; private readonly YandexMusicApi _api;
private readonly AuthStorage _storage; private readonly AuthStorage _storage;
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly bool _ownsHttpClient;
private YnisonPlayer? _player; private YnisonPlayer? _player;
/// <summary>Хранилище авторизации.</summary>
public AuthStorage AuthStorage => _storage;
/// <summary>Информация об аккаунте (после авторизации).</summary> /// <summary>Информация об аккаунте (после авторизации).</summary>
public YAccount Account => _storage.User; public YAccount Account => _storage.User;
@@ -39,20 +42,39 @@ public class YandexMusicClient : IDisposable
public HttpClient HttpClient => _httpClient; public HttpClient HttpClient => _httpClient;
/// <summary>Создаёт новый экземпляр клиента с собственным HttpClient.</summary> /// <summary>Создаёт новый экземпляр клиента с собственным HttpClient.</summary>
public YandexMusicClient() : this(YandexMusicHttpClientFactory.CreateDefault()) public YandexMusicClient(
CookieContainer? cookieContainer = null,
IWebProxy? proxy = null,
TimeSpan? timeout = null,
string? userAgent = null
)
{ {
_ownsHttpClient = true; if (cookieContainer == null) cookieContainer = new CookieContainer();
}
/// <summary> var handler = new HttpClientHandler
/// Создаёт новый экземпляр клиента с указанным HttpClient.
/// </summary>
/// <param name="httpClient">Экземпляр HttpClient (должен быть настроен с нужными куками, таймаутами).</param>
/// <param name="ownsHttpClient">Если true, клиент будет отвечать за освобождение HttpClient при Dispose.</param>
public YandexMusicClient(HttpClient httpClient)
{ {
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
_storage = new AuthStorage(); UseCookies = true,
CookieContainer = cookieContainer,
AllowAutoRedirect = true,
MaxAutomaticRedirections = 10,
Proxy = proxy,
UseProxy = proxy != null
};
var client = new HttpClient(handler, disposeHandler: true)
{
Timeout = timeout ?? TimeSpan.FromSeconds(30)
};
// Стандартный User-Agent, похожий на браузерный
client.DefaultRequestHeaders.Add("User-Agent",
userAgent ?? "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
client.DefaultRequestHeaders.Add("Accept", "*/*");
client.DefaultRequestHeaders.Add("Accept-Language", "ru-RU,ru;q=0.9,en;q=0.8");
_httpClient = client;
_storage = new AuthStorage(cookieContainer);
_api = new YandexMusicApi(_httpClient, _storage); _api = new YandexMusicApi(_httpClient, _storage);
} }
@@ -73,8 +95,12 @@ public class YandexMusicClient : IDisposable
public Task<string?> GetAuthQRLink() public Task<string?> GetAuthQRLink()
=> _api.User.GetAuthQRLinkAsync(); => _api.User.GetAuthQRLinkAsync();
/// <summary>Проверка состояния сканирования QR-кода.</summary>
public Task<YAuthQRStatus?> CheckQRStatusAsync()
=> _api.User.CheckQRStatusAsync();
/// <summary>Авторизация по QR-коду (после сканирования).</summary> /// <summary>Авторизация по QR-коду (после сканирования).</summary>
public Task<YAuthQRStatus?> AuthorizeByQR() public Task<YAuthQRSession?> AuthorizeByQR()
=> _api.User.AuthorizeByQRAsync(); => _api.User.AuthorizeByQRAsync();
/// <summary>Получение капчи.</summary> /// <summary>Получение капчи.</summary>
@@ -390,7 +416,6 @@ public class YandexMusicClient : IDisposable
{ {
if (_disposed) return; if (_disposed) return;
_player?.Dispose(); _player?.Dispose();
if (_ownsHttpClient)
_httpClient.Dispose(); _httpClient.Dispose();
_disposed = true; _disposed = true;
GC.SuppressFinalize(this); GC.SuppressFinalize(this);