Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8abc6c5074 | ||
|
|
b8f78a5856 | ||
|
|
21a0c5abe6 |
16
YaMusicCli/Program.cs
Normal file
16
YaMusicCli/Program.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using YandexMusic.API.Extensions.API;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
private async static Task Main(string[] args)
|
||||
{
|
||||
var client = new YandexMusic.YandexMusicClient();
|
||||
var type = await client.Authorize("y0__xDy2budARje-AYg7rmliBc11LbYoMeUiwiO6f6mSCAMDYVIKg");
|
||||
var playlists = (await client.GetFavoritesAsync()).Where(t => t.Owner.Uid == client.Account.Uid).ToList();
|
||||
var playlist = await client.GetPlaylistAsync("97ae0768-8a40-8485-9fa4-b6c856bc6b21");
|
||||
|
||||
|
||||
var tracks = await client.GetTracksAsync(new[] { "78412759" });
|
||||
await playlist.InsertTracksAsync(tracks.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using YandexMusic.API.Converters;
|
||||
using YandexMusic.API.Models.Common;
|
||||
|
||||
namespace YandexMusic.API.Common.Providers;
|
||||
@@ -10,13 +11,6 @@ public abstract class CommonRequestProvider : IRequestProvider
|
||||
/// <summary>Хранилище данных авторизации.</summary>
|
||||
protected readonly AuthStorage storage;
|
||||
|
||||
/// <summary>Настройки сериализации JSON (регистронезависимые, поддержка enum-строк).</summary>
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
|
||||
};
|
||||
|
||||
/// <summary>Инициализирует новый экземпляр провайдера.</summary>
|
||||
/// <param name="authStorage">Хранилище авторизации.</param>
|
||||
protected CommonRequestProvider(AuthStorage authStorage)
|
||||
@@ -36,6 +30,16 @@ public abstract class CommonRequestProvider : IRequestProvider
|
||||
{
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
|
||||
JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Converters = {
|
||||
new JsonStringEnumConverter(JsonNamingPolicy.KebabCaseLower),
|
||||
new IntToStringConverter(),
|
||||
new YExecutionContextConverter(api, storage),
|
||||
}
|
||||
};
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var error = JsonSerializer.Deserialize<YErrorResponse>(json, JsonOptions);
|
||||
|
||||
34
YandexMusic.API/Converters/IntToStringConverter.cs
Normal file
34
YandexMusic.API/Converters/IntToStringConverter.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace YandexMusic.API.Converters;
|
||||
|
||||
public class IntToStringConverter : JsonConverter<string>
|
||||
{
|
||||
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.Number)
|
||||
{
|
||||
// Пытаемся извлечь число как int или long
|
||||
if (reader.TryGetInt32(out int intValue))
|
||||
return intValue.ToString();
|
||||
if (reader.TryGetInt64(out long longValue))
|
||||
return longValue.ToString();
|
||||
}
|
||||
else if (reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
return reader.GetString();
|
||||
}
|
||||
else if (reader.TokenType == JsonTokenType.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new JsonException($"Не удалось преобразовать {reader.TokenType} в строку.");
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using YandexMusic.API.Converters;
|
||||
using YandexMusic.API.Models.Common;
|
||||
|
||||
namespace YandexMusic.API.Models.Account;
|
||||
@@ -36,5 +37,6 @@ public class YAccount
|
||||
|
||||
public bool ServiceAvailable { get; set; }
|
||||
|
||||
[JsonConverter(typeof(IntToStringConverter))]
|
||||
public string Uid { get; set; }
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public class YCoverConverter : JsonConverter<YCover>
|
||||
"from-artist-photos" or "from-album-cover" => JsonSerializer.Deserialize<YCoverImage>(root.GetRawText(), options),
|
||||
"pic" => JsonSerializer.Deserialize<YCoverPic>(root.GetRawText(), options),
|
||||
"mosaic" => JsonSerializer.Deserialize<YCoverMosaic>(root.GetRawText(), options),
|
||||
_ => JsonSerializer.Deserialize<YCover>(root.GetRawText(), options)
|
||||
_ => new YCover() { Type = YCoverType.Error }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace YandexMusic.API.Models.Common.Cover;
|
||||
@@ -8,9 +7,7 @@ public enum YCoverType
|
||||
{
|
||||
Color,
|
||||
Error,
|
||||
[EnumMember(Value = "from-artist-photos")]
|
||||
FromArtistPhotos,
|
||||
[EnumMember(Value = "from-album-cover")]
|
||||
FromAlbumCover,
|
||||
Mosaic,
|
||||
Pic,
|
||||
|
||||
@@ -5,7 +5,7 @@ using YandexMusic.API.Common;
|
||||
namespace YandexMusic.API.Models.Common;
|
||||
|
||||
/// <summary>Конвертер для внедрения контекста выполнения (API и хранилище) в модели.</summary>
|
||||
public class YExecutionContextConverter : JsonConverter<YBaseModel>
|
||||
public class YExecutionContextConverter : JsonConverter<object>
|
||||
{
|
||||
private readonly YandexMusicApi _api;
|
||||
private readonly AuthStorage _storage;
|
||||
@@ -16,26 +16,27 @@ public class YExecutionContextConverter : JsonConverter<YBaseModel>
|
||||
_storage = storage;
|
||||
}
|
||||
|
||||
public override YBaseModel? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
public override bool CanConvert(Type typeToConvert) =>
|
||||
typeof(YBaseModel).IsAssignableFrom(typeToConvert);
|
||||
|
||||
public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
// Десериализуем объект без контекста
|
||||
var obj = (YBaseModel?)JsonSerializer.Deserialize(ref reader, typeToConvert, options);
|
||||
if (obj != null)
|
||||
// Убираем этот конвертер из опций, чтобы избежать рекурсии
|
||||
var innerOptions = new JsonSerializerOptions(options);
|
||||
innerOptions.Converters.Remove(this);
|
||||
|
||||
var obj = JsonSerializer.Deserialize(ref reader, typeToConvert, innerOptions);
|
||||
if (obj is YBaseModel baseModel)
|
||||
{
|
||||
obj.Context = new YExecutionContext
|
||||
{
|
||||
API = _api,
|
||||
Storage = _storage
|
||||
};
|
||||
baseModel.Context = new YExecutionContext { API = _api, Storage = _storage };
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, YBaseModel value, JsonSerializerOptions options)
|
||||
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
|
||||
{
|
||||
// При сериализации игнорируем контекст
|
||||
var cloneOptions = new JsonSerializerOptions(options);
|
||||
cloneOptions.Converters.Remove(this);
|
||||
JsonSerializer.Serialize(writer, value, cloneOptions);
|
||||
var innerOptions = new JsonSerializerOptions(options);
|
||||
innerOptions.Converters.Remove(this);
|
||||
JsonSerializer.Serialize(writer, value, innerOptions);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace YandexMusic.API.Models.Common;
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum YTrackSharingFlag
|
||||
{
|
||||
[EnumMember(Value = "VIDEO_ALLOWED")]
|
||||
[JsonStringEnumMemberName("VIDEO_ALLOWED")]
|
||||
VideoAllowed,
|
||||
[EnumMember(Value = "COVER_ONLY")]
|
||||
[JsonStringEnumMemberName("COVER_ONLY")]
|
||||
CoverOnly
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using YandexMusic.API.Converters;
|
||||
using YandexMusic.API.Models.Common;
|
||||
using YandexMusic.API.Models.Common.Cover;
|
||||
using YandexMusic.API.Models.Track;
|
||||
@@ -44,6 +45,7 @@ public class YPlaylist : YBaseModel
|
||||
public string Image { get; set; }
|
||||
public bool IsBanner { get; set; }
|
||||
public bool IsPremiere { get; set; }
|
||||
[JsonConverter(typeof(IntToStringConverter))]
|
||||
public string Kind { get; set; }
|
||||
public List<YPlaylist> LastOwnerPlaylists { get; set; }
|
||||
public int LikesCount { get; set; }
|
||||
|
||||
@@ -31,7 +31,7 @@ public abstract class YRequestBuilder<TResponse, TParams>
|
||||
?? 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";
|
||||
device = $"os=CSharp; os_version=; manufacturer=FrigaT; model=Yandex Music API; clid=; device_id={storage.DeviceId}; uuid=random";
|
||||
|
||||
_jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
|
||||
100
YandexMusic.API/nuget-publish.ps1
Normal file
100
YandexMusic.API/nuget-publish.ps1
Normal file
@@ -0,0 +1,100 @@
|
||||
param(
|
||||
[string]$Version
|
||||
)
|
||||
|
||||
Write-Host "=== YandexMusic Manual Publisher ===" -ForegroundColor Cyan
|
||||
|
||||
# --- Ask for version if not provided ---
|
||||
if (-not $Version) {
|
||||
$Version = Read-Host "Введите версию пакета (например 1.2.3). Пусто = взять из git-тега"
|
||||
|
||||
if (-not $Version) {
|
||||
Write-Host "Читаю версию из git..." -ForegroundColor Yellow
|
||||
$tag = git describe --tags --abbrev=0 2>$null
|
||||
|
||||
if (-not $tag) {
|
||||
Write-Host "ОШИБКА: версия не указана и git-тег не найден." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$Version = $tag.TrimStart("v")
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Используемая версия: $Version" -ForegroundColor Green
|
||||
|
||||
# --- Paths ---
|
||||
$csprojPath = "YandexMusic/YandexMusic.csproj"
|
||||
$backupPath = "$csprojPath.bak"
|
||||
$artifacts = "artifacts"
|
||||
|
||||
# --- Backup original csproj ---
|
||||
Write-Host "Создаю резервную копию $csprojPath ..." -ForegroundColor Cyan
|
||||
Copy-Item $csprojPath $backupPath -Force
|
||||
|
||||
# --- Replace ProjectReference with PackageReference ---
|
||||
Write-Host "Патчу csproj..." -ForegroundColor Cyan
|
||||
|
||||
(Get-Content $csprojPath) `
|
||||
-replace '<ProjectReference Include="..\/YandexMusic.API\/YandexMusic.API.csproj" \/>',
|
||||
"<PackageReference Include=`"YandexMusic.API`" Version=`"$Version`" />" |
|
||||
Set-Content $csprojPath
|
||||
|
||||
Write-Host "ProjectReference → PackageReference заменён." -ForegroundColor Green
|
||||
|
||||
# --- Build & Pack ---
|
||||
$projects = @(
|
||||
"YandexMusic.API",
|
||||
"YandexMusic"
|
||||
)
|
||||
|
||||
if (Test-Path $artifacts) {
|
||||
Remove-Item $artifacts -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Path $artifacts | Out-Null
|
||||
|
||||
try {
|
||||
foreach ($proj in $projects) {
|
||||
Write-Host "Restoring $proj ..." -ForegroundColor Cyan
|
||||
dotnet restore $proj
|
||||
|
||||
Write-Host "Building $proj ..." -ForegroundColor Cyan
|
||||
dotnet build $proj -c Release -p:Version=$Version
|
||||
|
||||
Write-Host "Packing $proj ..." -ForegroundColor Cyan
|
||||
dotnet pack $proj -c Release --no-build -p:PackageVersion=$Version -o $artifacts
|
||||
}
|
||||
|
||||
Write-Host "Сборка и упаковка завершены." -ForegroundColor Green
|
||||
|
||||
# --- Publish ---
|
||||
$apiKey = $env:NUGET_API_KEY
|
||||
if (-not $apiKey) {
|
||||
Write-Host "ОШИБКА: переменная окружения NUGET_API_KEY не установлена." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Публикую пакеты..." -ForegroundColor Cyan
|
||||
|
||||
dotnet nuget push "$artifacts\*.nupkg" `
|
||||
--source "https://git.frigat.duckdns.org/api/packages/FrigaT/nuget/index.json" `
|
||||
--api-key $apiKey `
|
||||
--skip-duplicate
|
||||
|
||||
Write-Host "Публикация завершена." -ForegroundColor Green
|
||||
}
|
||||
finally {
|
||||
# --- Restore original csproj ---
|
||||
Write-Host "Восстанавливаю оригинальный csproj..." -ForegroundColor Cyan
|
||||
Move-Item $backupPath $csprojPath -Force
|
||||
|
||||
# --- Cleanup artifacts ---
|
||||
if (Test-Path $artifacts) {
|
||||
Write-Host "Удаляю artifacts..." -ForegroundColor Cyan
|
||||
Remove-Item $artifacts -Recurse -Force
|
||||
}
|
||||
|
||||
Write-Host "Откат завершён." -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "Готово." -ForegroundColor Cyan
|
||||
@@ -1,4 +1,5 @@
|
||||
<Solution>
|
||||
<Project Path="YaMusicCli/YaMusicCli.csproj" Id="5cce354e-7517-4a94-9584-197daa3ad6a4" />
|
||||
<Project Path="YandexMusic.API/YandexMusic.API.csproj" />
|
||||
<Project Path="YandexMusic/YandexMusic.csproj" Id="044fcef4-86d2-4cc9-9f7e-a577c19ae5c3" />
|
||||
</Solution>
|
||||
|
||||
Reference in New Issue
Block a user