Добавлен playlist shared

This commit is contained in:
FrigaT
2026-04-11 15:41:24 +03:00
parent 8444fc5f8e
commit ba9d97239e
84 changed files with 61796 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\YandexMusic.API\YandexMusic.API.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,517 @@
using YandexMusic.API;
using YandexMusic.API.Common;
using YandexMusic.API.Common.Ynison;
using YandexMusic.API.Models.Account;
using YandexMusic.API.Models.Album;
using YandexMusic.API.Models.Artist;
using YandexMusic.API.Models.Common;
using YandexMusic.API.Models.Feed;
using YandexMusic.API.Models.Landing;
using YandexMusic.API.Models.Landing.Entity.Entities.Context;
using YandexMusic.API.Models.Library;
using YandexMusic.API.Models.Playlist;
using YandexMusic.API.Models.Queue;
using YandexMusic.API.Models.Radio;
using YandexMusic.API.Models.Search;
using YandexMusic.API.Models.Track;
namespace YandexMusic;
/// <summary>Асинхронный клиент для работы с API Яндекс Музыки.</summary>
public class YandexMusicClient : IDisposable
{
private readonly YandexMusicApi _api;
private readonly AuthStorage _storage;
private YnisonPlayer? _player;
/// <summary>Информация об аккаунте (после авторизации).</summary>
public YAccount Account => _storage.User;
/// <summary>Флаг авторизации.</summary>
public bool IsAuthorized => _storage.IsAuthorized;
/// <summary>Плеер Ynison (WebSocket) для синхронизации воспроизведения.</summary>
public YnisonPlayer? Ynison => _player;
/// <summary>Создаёт новый экземпляр клиента Яндекс Музыки.</summary>
public YandexMusicClient()
{
_api = new YandexMusicApi();
_storage = new AuthStorage();
_player = _api.Ynison.GetPlayer(_storage);
}
#region Авторизация
/// <summary>
/// Авторизация по токену
/// </summary>
/// <param name="token">Токен авторизации</param>
/// <returns></returns>
public async Task<bool> Authorize(string token)
{
await _api.User.AuthorizeAsync(_storage, token);
return _storage.IsAuthorized;
}
/// <summary>
/// Создание сеанса и получение доступных методов авторизации
/// </summary>
/// <param name="userName">Имя пользователя</param>
/// <returns></returns>
public Task<YAuthTypes> CreateAuthSession(string userName)
{
return _api.User.CreateAuthSessionAsync(_storage, userName);
}
/// <summary>
/// Получение ссылки на QR-код
/// </summary>
/// <returns></returns>
public Task<string> GetAuthQRLink()
{
return _api.User.GetAuthQRLinkAsync(_storage);
}
/// <summary>
/// Авторизация по QR-коду
/// </summary>
/// <returns></returns>
public Task<YAuthQRStatus> AuthorizeByQR()
{
return _api.User.AuthorizeByQRAsync(_storage);
}
/// <summary>
/// Получение <see cref="YAuthCaptcha"/>
/// </summary>
/// <returns></returns>
public Task<YAuthCaptcha> GetCaptcha()
{
return _api.User.GetCaptchaAsync(_storage);
}
/// <summary>
/// Авторизация по captcha
/// </summary>
/// <param name="captcha">Значение captcha</param>
/// <returns></returns>
public Task<YAuthBase> AuthorizeByCaptcha(string captcha)
{
return _api.User.AuthorizeByCaptchaAsync(_storage, captcha);
}
/// <summary>
/// Получение письма авторизации на почту пользователя
/// </summary>
/// <returns></returns>
public Task<YAuthLetter> GetAuthLetter()
{
return _api.User.GetAuthLetterAsync(_storage);
}
/// <summary>
/// Авторизация после подтверждения входа через письмо
/// </summary>
/// <returns></returns>
public Task<bool> AuthorizeByLetter()
{
return _api.User.AuthorizeByLetterAsync(_storage);
}
/// <summary>
/// Авторизация с помощью пароля из приложения Яндекс
/// </summary>
/// <param name="password">Пароль</param>
/// <returns></returns>
public Task<YAuthBase> AuthorizeByAppPassword(string password)
{
return _api.User.AuthorizeByAppPasswordAsync(_storage, password);
}
/// <summary>
/// Получение <see cref="YAccessToken"/> после авторизации с помощью QR, e-mail, пароля из приложения
/// </summary>
public Task<YAccessToken> GetAccessToken()
{
return _api.User.GetAccessTokenAsync(_storage);
}
/// <summary>
/// Получение информации о пользователе через логин Яндекса
/// </summary>
public Task<YLoginInfo> GetLoginInfo()
{
return _api.User.GetLoginInfoAsync(_storage);
}
#endregion Авторизация
#region Треки
/// <summary>Получает трек по идентификатору.</summary>
public async Task<YTrack?> GetTrackAsync(string id)
{
var response = await _api.Track.GetAsync(_storage, id);
return response?.Result?.FirstOrDefault();
}
/// <summary>Получает список треков по идентификаторам.</summary>
public async Task<List<YTrack>> GetTracksAsync(IEnumerable<string> ids)
{
var response = await _api.Track.GetAsync(_storage, ids);
return response?.Result ?? new List<YTrack>();
}
#endregion
#region Альбомы
/// <summary>Получает альбом по идентификатору.</summary>
public async Task<YAlbum?> GetAlbumAsync(string id)
{
var response = await _api.Album.GetAsync(_storage, id);
return response?.Result;
}
/// <summary>Получает список альбомов по идентификаторам.</summary>
public async Task<List<YAlbum>> GetAlbumsAsync(IEnumerable<string> ids)
{
var response = await _api.Album.GetAsync(_storage, ids);
return response?.Result ?? new List<YAlbum>();
}
#endregion
#region Главная страница
/// <summary>Получает персональные блоки лендинга.</summary>
public async Task<YLanding?> GetLandingAsync(params YLandingBlockType[] blocks)
{
var response = await _api.Landing.GetAsync(_storage, blocks);
return response?.Result;
}
/// <summary>Получает ленту событий.</summary>
public async Task<YFeed?> GetFeedAsync()
{
var response = await _api.Landing.GetFeedAsync(_storage);
return response?.Result;
}
/// <summary>Получает детский лендинг.</summary>
public async Task<YChildrenLanding?> GetChildrenLandingAsync()
{
var response = await _api.Landing.GetChildrenLandingAsync(_storage);
return response?.Result;
}
#endregion
#region Исполнители
/// <summary>Получает информацию об исполнителе.</summary>
public async Task<YArtistBriefInfo?> GetArtistAsync(string id)
{
var response = await _api.Artist.GetAsync(_storage, id);
return response?.Result;
}
/// <summary>Получает список исполнителей.</summary>
public async Task<List<YArtist>> GetArtistsAsync(IEnumerable<string> ids)
{
var response = await _api.Artist.GetAsync(_storage, ids);
return response?.Result ?? new List<YArtist>();
}
#endregion
#region Плейлисты
/// <summary>Получает плейлист по пользователю и идентификатору.</summary>
public async Task<YPlaylist?> GetPlaylistAsync(string user, string id)
{
var response = await _api.Playlist.GetAsync(_storage, user, id);
return response?.Result;
}
/// <summary>Получает плейлист по UUID.</summary>
public async Task<YPlaylist?> GetPlaylistAsync(string uuid)
{
var response = await _api.Playlist.GetAsync(_storage, uuid);
return response?.Result;
}
/// <summary>Получает список плейлистов по списку пар (пользователь, идентификатор).</summary>
public async Task<List<YPlaylist>> GetPlaylistsAsync(IEnumerable<(string user, string id)> ids)
{
var response = await _api.Playlist.GetAsync(_storage, ids);
return response?.Result ?? new List<YPlaylist>();
}
/// <summary>Получает персональные плейлисты (с главной страницы).</summary>
public async Task<List<YPlaylist>> GetPersonalPlaylistsAsync()
{
var playlists = await _api.Playlist.GetPersonalPlaylistsAsync(_storage);
return playlists.Select(r => r.Result).Where(p => p != null).ToList()!;
}
/// <summary>Получает избранные плейлисты.</summary>
public async Task<List<YPlaylist>> GetFavoritesAsync()
{
var response = await _api.Playlist.FavoritesAsync(_storage);
return response?.Result ?? new List<YPlaylist>();
}
/// <summary>Получает плейлист «Дежавю».</summary>
public async Task<YPlaylist?> GetDejaVuAsync()
{
var response = await _api.Playlist.DejaVuAsync(_storage);
return response?.Result;
}
/// <summary>Получает плейлист «Тайник».</summary>
public async Task<YPlaylist?> GetMissedAsync()
{
var response = await _api.Playlist.MissedAsync(_storage);
return response?.Result;
}
/// <summary>Получает плейлист дня.</summary>
public async Task<YPlaylist?> GetOfTheDayAsync()
{
var response = await _api.Playlist.OfTheDayAsync(_storage);
return response?.Result;
}
/// <summary>Получает плейлист «Кинопоиск».</summary>
public async Task<YPlaylist?> GetKinopoiskAsync()
{
var response = await _api.Playlist.KinopoiskAsync(_storage);
return response?.Result;
}
/// <summary>Получает плейлист «Премьера».</summary>
public async Task<YPlaylist?> GetPremiereAsync()
{
var response = await _api.Playlist.PremiereAsync(_storage);
return response?.Result;
}
/// <summary>Создаёт новый плейлист с заданным именем.</summary>
public async Task<YPlaylist?> CreatePlaylistAsync(string name)
{
var response = await _api.Playlist.CreateAsync(_storage, name);
return response?.Result;
}
#endregion
#region Поиск
/// <summary>Выполняет поиск.</summary>
public async Task<YSearch?> SearchAsync(string searchText, YSearchType searchType, int page = 0, int pageSize = 20)
{
var response = await _api.Search.SearchAsync(_storage, searchText, searchType, page, pageSize);
return response?.Result;
}
/// <summary>Получает подсказки для поискового запроса.</summary>
public async Task<YSearchSuggest?> GetSearchSuggestionsAsync(string searchText)
{
var response = await _api.Search.SuggestAsync(_storage, searchText);
return response?.Result;
}
#endregion
#region Библиотека
/// <summary>Получает лайкнутые треки.</summary>
public async Task<List<YTrack>> GetLikedTracksAsync()
{
var likes = await _api.Library.GetLikedTracksAsync(_storage);
var ids = likes.Result?.Library.Tracks.Select(t => t.Id).ToArray() ?? Array.Empty<string>();
if (ids.Length == 0) return new List<YTrack>();
var response = await _api.Track.GetAsync(_storage, ids);
return response?.Result ?? new List<YTrack>();
}
/// <summary>Получает дизлайкнутые треки.</summary>
public async Task<List<YTrack>> GetDislikedTracksAsync()
{
var dislikes = await _api.Library.GetDislikedTracksAsync(_storage);
var ids = dislikes.Result?.Library.Tracks.Select(t => t.Id).ToArray() ?? Array.Empty<string>();
if (ids.Length == 0) return new List<YTrack>();
var response = await _api.Track.GetAsync(_storage, ids);
return response?.Result ?? new List<YTrack>();
}
/// <summary>Получает лайкнутые альбомы.</summary>
public async Task<List<YAlbum>> GetLikedAlbumsAsync()
{
var albums = await _api.Library.GetLikedAlbumsAsync(_storage);
var ids = albums.Result?.Select(a => a.Id).ToArray() ?? Array.Empty<string>();
if (ids.Length == 0) return new List<YAlbum>();
var response = await _api.Album.GetAsync(_storage, ids);
return response?.Result ?? new List<YAlbum>();
}
/// <summary>Получает лайкнутых исполнителей.</summary>
public async Task<List<YArtist>> GetLikedArtistsAsync()
{
var artists = await _api.Library.GetLikedArtistsAsync(_storage);
var ids = artists.Result?.Select(a => a.Id).ToArray() ?? Array.Empty<string>();
if (ids.Length == 0) return new List<YArtist>();
var response = await _api.Artist.GetAsync(_storage, ids);
return response?.Result ?? new List<YArtist>();
}
/// <summary>Получает дизлайкнутых исполнителей.</summary>
public async Task<List<YArtist>> GetDislikedArtistsAsync()
{
var artists = await _api.Library.GetDislikedArtistsAsync(_storage);
var ids = artists.Result?.Select(a => a.Id).ToArray() ?? Array.Empty<string>();
if (ids.Length == 0) return new List<YArtist>();
var response = await _api.Artist.GetAsync(_storage, ids);
return response?.Result ?? new List<YArtist>();
}
/// <summary>Получает лайкнутые плейлисты.</summary>
public async Task<List<YPlaylist>> GetLikedPlaylistsAsync()
{
var playlists = await _api.Library.GetLikedPlaylistsAsync(_storage);
var ids = playlists.Result?
.Select(p => (p.Playlist.Uid, p.Playlist.Kind))
.ToArray() ?? Array.Empty<(string, string)>();
if (ids.Length == 0) return new List<YPlaylist>();
var response = await _api.Playlist.GetAsync(_storage, ids);
return response?.Result ?? new List<YPlaylist>();
}
/// <summary>Получает список недавно прослушанных треков.</summary>
/// <param name="contextTypes">Типы контекстов (альбом, исполнитель, плейлист).</param>
/// <param name="trackCount">Количество треков на контекст.</param>
/// <param name="contextCount">Количество контекстов.</param>
public async Task<List<YRecentlyListened>> GetRecentlyListenedAsync(
IEnumerable<YPlayContextType> contextTypes,
int trackCount = 50,
int contextCount = 10)
{
var response = await _api.Library.GetRecentlyListenedAsync(_storage, contextTypes, trackCount, contextCount);
return response?.Result?.Contexts ?? new List<YRecentlyListened>();
}
#endregion
#region Радио
/// <summary>Получает список рекомендованных радиостанций.</summary>
public async Task<List<YStation>> GetRadioDashboardAsync()
{
var response = await _api.Radio.GetStationsDashboardAsync(_storage);
return response?.Result?.Stations ?? new List<YStation>();
}
/// <summary>Получает список всех радиостанций.</summary>
public async Task<List<YStation>> GetRadioStationsAsync()
{
var response = await _api.Radio.GetStationsAsync(_storage);
return response?.Result ?? new List<YStation>();
}
/// <summary>Получает информацию о радиостанции по идентификатору.</summary>
public async Task<YStation?> GetRadioStationAsync(YStationId id)
{
var response = await _api.Radio.GetStationAsync(_storage, id);
return response?.Result?.FirstOrDefault();
}
#endregion
#region Очереди
/// <summary>Получает все очереди с разных устройств.</summary>
public async Task<YQueueItemsContainer?> GetQueuesAsync(string? device = null)
{
var response = await _api.Queue.ListAsync(_storage, device);
return response?.Result;
}
/// <summary>Получает очередь по идентификатору.</summary>
public async Task<YQueue?> GetQueueAsync(string queueId)
{
var response = await _api.Queue.GetAsync(_storage, queueId);
return response?.Result;
}
/// <summary>Создаёт новую очередь.</summary>
public async Task<YNewQueue?> CreateQueueAsync(YQueue queue, string? device = null)
{
var response = await _api.Queue.CreateAsync(_storage, queue, device);
return response?.Result;
}
/// <summary>Обновляет позицию в очереди.</summary>
public async Task<YUpdatedQueue?> UpdateQueuePositionAsync(string queueId, int currentIndex, bool isInteractive, string? device = null)
{
var response = await _api.Queue.UpdatePositionAsync(_storage, queueId, currentIndex, isInteractive, device);
return response?.Result;
}
#endregion
#region Загрузка треков (UGC)
/// <summary>Загружает трек из файла в плейлист.</summary>
public async Task<string?> UploadTrackToPlaylistAsync(YPlaylist playlist, string fileName, string filePath)
{
var uploadLink = await _api.UserGeneratedContent.GetUgcUploadLinkAsync(_storage, playlist, fileName);
var response = await _api.UserGeneratedContent.UploadUgcTrackAsync(_storage, uploadLink.PostTarget, filePath);
return response?.Result;
}
/// <summary>Загружает трек из потока в плейлист.</summary>
public async Task<string?> UploadTrackToPlaylistAsync(YPlaylist playlist, string fileName, Stream stream)
{
var uploadLink = await _api.UserGeneratedContent.GetUgcUploadLinkAsync(_storage, playlist, fileName);
var response = await _api.UserGeneratedContent.UploadUgcTrackAsync(_storage, uploadLink.PostTarget, stream);
return response?.Result;
}
/// <summary>Загружает трек из массива байтов в плейлист.</summary>
public async Task<string?> UploadTrackToPlaylistAsync(YPlaylist playlist, string fileName, byte[] file)
{
var uploadLink = await _api.UserGeneratedContent.GetUgcUploadLinkAsync(_storage, playlist, fileName);
var response = await _api.UserGeneratedContent.UploadUgcTrackAsync(_storage, uploadLink.PostTarget, file);
return response?.Result;
}
#endregion
#region Лейблы
/// <summary>Получает альбомы лейбла с пагинацией.</summary>
public async Task<List<YAlbum>> GetAlbumsByLabelAsync(YLabel label, int page = 0)
{
var response = await _api.Label.GetAlbumsByLabelAsync(_storage, label, page);
return response?.Result?.Albums ?? new List<YAlbum>();
}
/// <summary>Получает артистов лейбла с пагинацией.</summary>
public async Task<List<YArtist>> GetArtistsByLabelAsync(YLabel label, int page = 0)
{
var response = await _api.Label.GetArtistsByLabelAsync(_storage, label, page);
return response?.Result?.Artists ?? new List<YArtist>();
}
#endregion
#region Ynison (WebSocket плеер)
/// <summary>Подключается к Ynison и запускает синхронизацию состояния плеера.</summary>
public async Task ConnectYnisonAsync()
{
if (_player == null)
_player = _api.Ynison.GetPlayer(_storage);
await _player.ConnectAsync();
}
/// <summary>Отключается от Ynison.</summary>
public async Task DisconnectYnisonAsync()
{
if (_player != null)
await _player.DisconnectAsync();
}
#endregion
#region IDisposable
private bool _disposed;
/// <summary>Освобождает ресурсы.</summary>
public void Dispose()
{
if (_disposed) return;
_player?.Dispose();
_disposed = true;
GC.SuppressFinalize(this);
}
#endregion
}