diff --git a/YandexMusic.API/API/YAlbumAPI.cs b/YandexMusic.API/API/YAlbumAPI.cs
index 5d2d11f..8c52247 100644
--- a/YandexMusic.API/API/YAlbumAPI.cs
+++ b/YandexMusic.API/API/YAlbumAPI.cs
@@ -5,34 +5,24 @@ using YandexMusic.API.Requests.Album;
namespace YandexMusic.API;
-///
-/// API для взаимодействия с альбомами
-///
+/// API для работы с альбомами.
public class YAlbumAPI : YCommonAPI
{
- public YAlbumAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
+ /// Инициализирует новый экземпляр API альбомов.
+ /// Экземпляр основного API.
+ public YAlbumAPI(YandexMusicApi yandex) : base(yandex) { }
/// Получает альбом по идентификатору.
- /// Хранилище авторизации.
- /// Идентификатор альбома.
- ///
+ /// Хранилище данных авторизации.
+ /// Идентификатор альбома.
+ /// Ответ API с моделью альбома.
public Task> GetAsync(AuthStorage storage, string albumId)
- {
- return new YGetAlbumBuilder(api, storage)
- .Build(albumId)
- .GetResponseAsync();
- }
+ => new YGetAlbumBuilder(api, storage).Build(albumId).GetResponseAsync();
- /// Получение альбомов по списку идентификаторов.
- /// Хранилище авторизации.
- /// Идентификаторы альбомов.
- ///
+ /// Получает несколько альбомов по списку идентификаторов.
+ /// Хранилище данных авторизации.
+ /// Список идентификаторов альбомов.
+ /// Ответ API со списком альбомов.
public Task>> GetAsync(AuthStorage storage, IEnumerable albumIds)
- {
- return new YGetAlbumsBuilder(api, storage)
- .Build(albumIds)
- .GetResponseAsync();
- }
+ => new YGetAlbumsBuilder(api, storage).Build(albumIds).GetResponseAsync();
}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YCommonAPI.cs b/YandexMusic.API/API/YCommonAPI.cs
index d066141..b0f63dc 100644
--- a/YandexMusic.API/API/YCommonAPI.cs
+++ b/YandexMusic.API/API/YCommonAPI.cs
@@ -1,14 +1,12 @@
namespace YandexMusic.API;
-///
-/// Родительский класс для ветки API
-///
-public class YCommonAPI
+/// Родительский класс для всех веток API.
+public abstract class YCommonAPI
{
- protected YandexMusicApi api;
+ /// Основной экземпляр API.
+ protected readonly YandexMusicApi api;
- public YCommonAPI(YandexMusicApi yandex)
- {
- api = yandex;
- }
-}
+ /// Инициализирует новый экземпляр.
+ /// Экземпляр основного API.
+ protected YCommonAPI(YandexMusicApi yandex) => api = yandex;
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YLabelAPI.cs b/YandexMusic.API/API/YLabelAPI.cs
new file mode 100644
index 0000000..42b53c8
--- /dev/null
+++ b/YandexMusic.API/API/YLabelAPI.cs
@@ -0,0 +1,39 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Label;
+using YandexMusic.API.Requests.Label;
+
+namespace YandexMusic.API;
+
+public partial class YLabelAPI : YCommonAPI
+{
+ public YLabelAPI(YandexMusicApi yandex) : base(yandex)
+ {
+ }
+
+ ///
+ /// Постраничное получение альбомов лейбла
+ ///
+ /// Хранилище
+ /// Лейбл
+ /// Страница
+ public Task> GetAlbumsByLabelAsync(AuthStorage storage, YLabel label, int page)
+ {
+ return new YGetLabelAlbumsBuilder(api, storage)
+ .Build((label, page))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Постраничное получение артистов лейбла
+ ///
+ /// Хранилище
+ /// Лейбл
+ /// Страница
+ public Task> GetArtistsByLabelAsync(AuthStorage storage, YLabel label, int page)
+ {
+ return new YGetLabelArtistsBuilder(api, storage)
+ .Build((label, page))
+ .GetResponseAsync();
+ }
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YLabelAPIAsync.cs b/YandexMusic.API/API/YLabelAPIAsync.cs
deleted file mode 100644
index eeac03b..0000000
--- a/YandexMusic.API/API/YLabelAPIAsync.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Label;
-using YandexMusic.API.Requests.Label;
-
-namespace YandexMusic.API
-{
- public partial class YLabelAPI : YCommonAPI
- {
- public YLabelAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Постраничное получение альбомов лейбла
- ///
- /// Хранилище
- /// Лейбл
- /// Страница
- public Task> GetAlbumsByLabelAsync(AuthStorage storage, YLabel label, int page)
- {
- return new YGetLabelAlbumsBuilder(api, storage)
- .Build((label, page))
- .GetResponseAsync();
- }
-
- ///
- /// Постраничное получение артистов лейбла
- ///
- /// Хранилище
- /// Лейбл
- /// Страница
- public Task> GetArtistsByLabelAsync(AuthStorage storage, YLabel label, int page)
- {
- return new YGetLabelArtistsBuilder(api, storage)
- .Build((label, page))
- .GetResponseAsync();
- }
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YLandingAPI.cs b/YandexMusic.API/API/YLandingAPI.cs
new file mode 100644
index 0000000..b91cecc
--- /dev/null
+++ b/YandexMusic.API/API/YLandingAPI.cs
@@ -0,0 +1,43 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Feed;
+using YandexMusic.API.Models.Landing;
+using YandexMusic.API.Requests.Feed;
+using YandexMusic.API.Requests.Landing;
+
+namespace YandexMusic.API;
+
+/// API для взаимодействия с главной страницей (лендингом).
+public class YLandingAPI : YCommonAPI
+{
+ /// Инициализирует новый экземпляр API лендинга.
+ /// Экземпляр основного API.
+ public YLandingAPI(YandexMusicApi yandex) : base(yandex) { }
+
+ /// Получает персональные блоки лендинга.
+ /// Хранилище авторизации.
+ /// Типы запрашиваемых блоков.
+ /// Ответ API с лендингом.
+ /// Если массив blocks равен null.
+ public Task> GetAsync(AuthStorage storage, params YLandingBlockType[] blocks)
+ {
+ if (blocks == null)
+ throw new ArgumentNullException(nameof(blocks), "Массив блоков не может быть null");
+
+ return new YGetLandingBuilder(api, storage)
+ .Build(blocks)
+ .GetResponseAsync();
+ }
+
+ /// Получает ленту событий (фид).
+ /// Хранилище авторизации.
+ /// Ответ API с лентой.
+ public Task> GetFeedAsync(AuthStorage storage)
+ => new YGetFeedBuilder(api, storage).Build(null!).GetResponseAsync();
+
+ /// Получает лендинг детского раздела.
+ /// Хранилище авторизации.
+ /// Ответ API с детским лендингом.
+ public Task> GetChildrenLandingAsync(AuthStorage storage)
+ => new YGetChildrenLandingBuilder(api, storage).Build(null!).GetResponseAsync();
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YLandingAPIAsync.cs b/YandexMusic.API/API/YLandingAPIAsync.cs
deleted file mode 100644
index 8ff4fe9..0000000
--- a/YandexMusic.API/API/YLandingAPIAsync.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Feed;
-using YandexMusic.API.Models.Landing;
-using YandexMusic.API.Requests.Feed;
-using YandexMusic.API.Requests.Landing;
-
-namespace YandexMusic.API
-{
- ///
- /// API для взаимодействия с главной страницей
- ///
- public partial class YLandingAPI : YCommonAPI
- {
-
-
- public YLandingAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Получение персональных списков
- ///
- /// Хранилище
- /// Типы запрашиваемых блоков
- ///
- public Task> GetAsync(AuthStorage storage, params YLandingBlockType[] blocks)
- {
- if (blocks == null)
- return null;
-
- return new YGetLandingBuilder(api, storage)
- .Build(blocks)
- .GetResponseAsync();
- }
-
- ///
- /// Получение ленты
- ///
- /// Хранилище
- ///
- public Task> GetFeedAsync(AuthStorage storage)
- {
- return new YGetFeedBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
- }
-
- ///
- /// Получение лендинга детского раздела
- ///
- /// Хранилище
- ///
- public Task> GetChildrenLandingAsync(AuthStorage storage)
- {
- return new YGetChildrenLandingBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
- }
-
-
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YLibraryAPI.cs b/YandexMusic.API/API/YLibraryAPI.cs
new file mode 100644
index 0000000..df1b86c
--- /dev/null
+++ b/YandexMusic.API/API/YLibraryAPI.cs
@@ -0,0 +1,253 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Album;
+using YandexMusic.API.Models.Artist;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Landing.Entity.Entities.Context;
+using YandexMusic.API.Models.Library;
+using YandexMusic.API.Models.Playlist;
+using YandexMusic.API.Models.Track;
+using YandexMusic.API.Requests.Library;
+
+namespace YandexMusic.API;
+
+///
+/// API для взаимодействия с библиотекой
+///
+public partial class YLibraryAPI : YCommonAPI
+{
+ ///
+ /// Получение секции библиотеки
+ ///
+ /// Тип объекта библиотеки
+ /// Хранилище
+ /// Секция
+ /// Тип
+ /// Список объектов из секции
+ private Task> GetLibrarySection(AuthStorage storage, YLibrarySection section, YLibrarySectionType type = YLibrarySectionType.Likes)
+ {
+ return new YGetLibrarySectionBuilder(api, storage)
+ .Build((section, type))
+ .GetResponseAsync();
+ }
+
+
+
+ public YLibraryAPI(YandexMusicApi yandex) : base(yandex)
+ {
+ }
+
+ #region Лайки
+
+ ///
+ /// Получение лайкнутых треков
+ ///
+ /// Хранилище
+ ///
+ public Task> GetLikedTracksAsync(AuthStorage storage)
+ {
+ return GetLibrarySection(storage, YLibrarySection.Tracks);
+ }
+
+ ///
+ /// Получение лайкнутых альбомов
+ ///
+ /// Хранилище
+ ///
+ public Task>> GetLikedAlbumsAsync(AuthStorage storage)
+ {
+ return GetLibrarySection>(storage, YLibrarySection.Albums);
+ }
+
+ ///
+ /// Получение лайкнутых исполнителей
+ ///
+ /// Хранилище
+ ///
+ public Task>> GetLikedArtistsAsync(AuthStorage storage)
+ {
+ return GetLibrarySection>(storage, YLibrarySection.Artists);
+ }
+
+ ///
+ /// Получение лайкнутых плейлистов
+ ///
+ /// Хранилище
+ ///
+ public Task>> GetLikedPlaylistsAsync(AuthStorage storage)
+ {
+ return GetLibrarySection>(storage, YLibrarySection.Playlists);
+ }
+
+ #endregion Лайки
+
+ #region Дизлайки
+
+ ///
+ /// Получение дизлайкнутых треков
+ ///
+ /// Хранилище
+ ///
+ public Task> GetDislikedTracksAsync(AuthStorage storage)
+ {
+ return GetLibrarySection(storage, YLibrarySection.Tracks, YLibrarySectionType.Dislikes);
+ }
+
+ ///
+ /// Получение дизлайкнутых исполнителей
+ ///
+ /// Хранилище
+ ///
+ public Task>> GetDislikedArtistsAsync(AuthStorage storage)
+ {
+ return GetLibrarySection>(storage, YLibrarySection.Artists, YLibrarySectionType.Dislikes);
+ }
+
+ #endregion Дизлайки
+
+ #region Добавление в списки лайков/дизлайков
+
+ ///
+ /// Добавить трек в список лайкнутых
+ ///
+ /// Хранилище
+ /// Трек
+ ///
+ public Task> AddTrackLikeAsync(AuthStorage storage, YTrack track)
+ {
+ return new YLibraryAddBuilder(api, storage)
+ .Build((track.GetKey().ToString(), YLibrarySection.Tracks, YLibrarySectionType.Likes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Удалить трек из списка лайкнутых
+ ///
+ /// Хранилище
+ /// Трек
+ ///
+ public Task> RemoveTrackLikeAsync(AuthStorage storage, YTrack track)
+ {
+ return new YLibraryRemoveBuilder(api, storage)
+ .Build((track.GetKey().ToString(), YLibrarySection.Tracks, YLibrarySectionType.Likes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Добавить трек в список дизлайкнутых
+ ///
+ /// Хранилище
+ /// Трек
+ ///
+ public Task> AddTrackDislikeAsync(AuthStorage storage, YTrack track)
+ {
+ return new YLibraryAddBuilder(api, storage)
+ .Build((track.GetKey().ToString(), YLibrarySection.Tracks, YLibrarySectionType.Dislikes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Удалить трек из списка дизлайкнутых
+ ///
+ /// Хранилище
+ /// Трек
+ ///
+ public Task> RemoveTrackDislikeAsync(AuthStorage storage, YTrack track)
+ {
+ return new YLibraryRemoveBuilder(api, storage)
+ .Build((track.GetKey().ToString(), YLibrarySection.Tracks, YLibrarySectionType.Dislikes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Добавить альбом в список лайкнутых
+ ///
+ /// Хранилище
+ /// Альбом
+ ///
+ public Task> AddAlbumLikeAsync(AuthStorage storage, YAlbum album)
+ {
+ return new YLibraryAddBuilder(api, storage)
+ .Build((album.Id, YLibrarySection.Albums, YLibrarySectionType.Likes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Удалить альбом из списка лайкнутых
+ ///
+ /// Хранилище
+ /// Альбом
+ ///
+ public Task> RemoveAlbumLikeAsync(AuthStorage storage, YAlbum album)
+ {
+ return new YLibraryRemoveBuilder(api, storage)
+ .Build((album.Id, YLibrarySection.Albums, YLibrarySectionType.Likes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Добавить исполнителя в список лайкнутых
+ ///
+ /// Хранилище
+ /// Исполнитель
+ ///
+ public Task> AddArtistLikeAsync(AuthStorage storage, YArtist artist)
+ {
+ return new YLibraryAddBuilder(api, storage)
+ .Build((artist.Id, YLibrarySection.Artists, YLibrarySectionType.Likes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Удалить исполнителя из списка лайкнутых
+ ///
+ /// Хранилище
+ /// Исполнитель
+ ///
+ public Task> RemoveArtistLikeAsync(AuthStorage storage, YArtist artist)
+ {
+ return new YLibraryRemoveBuilder(api, storage)
+ .Build((artist.Id, YLibrarySection.Artists, YLibrarySectionType.Likes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Добавить плейлист в список лайкнутых
+ ///
+ /// Хранилище
+ /// Плейлист
+ ///
+ public Task> AddPlaylistLikeAsync(AuthStorage storage, YPlaylist playlist)
+ {
+ return new YLibraryAddBuilder(api, storage)
+ .Build((playlist.GetKey().ToString(), YLibrarySection.Playlists, YLibrarySectionType.Likes))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Удалить плейлист из списка лайкнутых
+ ///
+ /// Хранилище
+ /// Плейлист
+ ///
+ public Task> RemovePlaylistLikeAsync(AuthStorage storage, YPlaylist playlist)
+ {
+ return new YLibraryRemoveBuilder(api, storage)
+ .Build((playlist.GetKey().ToString(), YLibrarySection.Playlists, YLibrarySectionType.Likes))
+ .GetResponseAsync();
+ }
+
+ #endregion Добавление/удаление в списки лайков/дизлайков
+
+ #region Получение списка "Вы недавно слушали"
+
+ public Task> GetRecentlyListenedAsync(AuthStorage storage, IEnumerable contextTypes, int trackCount, int contextCount)
+ {
+ return new YGetLibraryRecentlyListenedBuilder(api, storage)
+ .Build((contextTypes, trackCount, contextCount))
+ .GetResponseAsync();
+ }
+
+ #endregion Получение списка "Вы недавно слушали"
+
+
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YLibraryAPIAsync.cs b/YandexMusic.API/API/YLibraryAPIAsync.cs
deleted file mode 100644
index 46b5209..0000000
--- a/YandexMusic.API/API/YLibraryAPIAsync.cs
+++ /dev/null
@@ -1,258 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Album;
-using YandexMusic.API.Models.Artist;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Landing.Entity.Entities.Context;
-using YandexMusic.API.Models.Library;
-using YandexMusic.API.Models.Playlist;
-using YandexMusic.API.Models.Track;
-using YandexMusic.API.Requests.Library;
-
-namespace YandexMusic.API
-{
- ///
- /// API для взаимодействия с библиотекой
- ///
- public partial class YLibraryAPI : YCommonAPI
- {
- #region Вспомогательные функции
-
- ///
- /// Получение секции библиотеки
- ///
- /// Тип объекта библиотеки
- /// Хранилище
- /// Секция
- /// Тип
- /// Список объектов из секции
- private Task> GetLibrarySection(AuthStorage storage, YLibrarySection section, YLibrarySectionType type = YLibrarySectionType.Likes)
- {
- return new YGetLibrarySectionBuilder(api, storage)
- .Build((section, type))
- .GetResponseAsync();
- }
-
- #endregion Вспомогательные функции
-
-
-
- public YLibraryAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- #region Лайки
-
- ///
- /// Получение лайкнутых треков
- ///
- /// Хранилище
- ///
- public Task> GetLikedTracksAsync(AuthStorage storage)
- {
- return GetLibrarySection(storage, YLibrarySection.Tracks);
- }
-
- ///
- /// Получение лайкнутых альбомов
- ///
- /// Хранилище
- ///
- public Task>> GetLikedAlbumsAsync(AuthStorage storage)
- {
- return GetLibrarySection>(storage, YLibrarySection.Albums);
- }
-
- ///
- /// Получение лайкнутых исполнителей
- ///
- /// Хранилище
- ///
- public Task>> GetLikedArtistsAsync(AuthStorage storage)
- {
- return GetLibrarySection>(storage, YLibrarySection.Artists);
- }
-
- ///
- /// Получение лайкнутых плейлистов
- ///
- /// Хранилище
- ///
- public Task>> GetLikedPlaylistsAsync(AuthStorage storage)
- {
- return GetLibrarySection>(storage, YLibrarySection.Playlists);
- }
-
- #endregion Лайки
-
- #region Дизлайки
-
- ///
- /// Получение дизлайкнутых треков
- ///
- /// Хранилище
- ///
- public Task> GetDislikedTracksAsync(AuthStorage storage)
- {
- return GetLibrarySection(storage, YLibrarySection.Tracks, YLibrarySectionType.Dislikes);
- }
-
- ///
- /// Получение дизлайкнутых исполнителей
- ///
- /// Хранилище
- ///
- public Task>> GetDislikedArtistsAsync(AuthStorage storage)
- {
- return GetLibrarySection>(storage, YLibrarySection.Artists, YLibrarySectionType.Dislikes);
- }
-
- #endregion Дизлайки
-
- #region Добавление в списки лайков/дизлайков
-
- ///
- /// Добавить трек в список лайкнутых
- ///
- /// Хранилище
- /// Трек
- ///
- public Task> AddTrackLikeAsync(AuthStorage storage, YTrack track)
- {
- return new YLibraryAddBuilder(api, storage)
- .Build((track.GetKey().ToString(), YLibrarySection.Tracks, YLibrarySectionType.Likes))
- .GetResponseAsync();
- }
-
- ///
- /// Удалить трек из списка лайкнутых
- ///
- /// Хранилище
- /// Трек
- ///
- public Task> RemoveTrackLikeAsync(AuthStorage storage, YTrack track)
- {
- return new YLibraryRemoveBuilder(api, storage)
- .Build((track.GetKey().ToString(), YLibrarySection.Tracks, YLibrarySectionType.Likes))
- .GetResponseAsync();
- }
-
- ///
- /// Добавить трек в список дизлайкнутых
- ///
- /// Хранилище
- /// Трек
- ///
- public Task> AddTrackDislikeAsync(AuthStorage storage, YTrack track)
- {
- return new YLibraryAddBuilder(api, storage)
- .Build((track.GetKey().ToString(), YLibrarySection.Tracks, YLibrarySectionType.Dislikes))
- .GetResponseAsync();
- }
-
- ///
- /// Удалить трек из списка дизлайкнутых
- ///
- /// Хранилище
- /// Трек
- ///
- public Task> RemoveTrackDislikeAsync(AuthStorage storage, YTrack track)
- {
- return new YLibraryRemoveBuilder(api, storage)
- .Build((track.GetKey().ToString(), YLibrarySection.Tracks, YLibrarySectionType.Dislikes))
- .GetResponseAsync();
- }
-
- ///
- /// Добавить альбом в список лайкнутых
- ///
- /// Хранилище
- /// Альбом
- ///
- public Task> AddAlbumLikeAsync(AuthStorage storage, YAlbum album)
- {
- return new YLibraryAddBuilder(api, storage)
- .Build((album.Id, YLibrarySection.Albums, YLibrarySectionType.Likes))
- .GetResponseAsync();
- }
-
- ///
- /// Удалить альбом из списка лайкнутых
- ///
- /// Хранилище
- /// Альбом
- ///
- public Task> RemoveAlbumLikeAsync(AuthStorage storage, YAlbum album)
- {
- return new YLibraryRemoveBuilder(api, storage)
- .Build((album.Id, YLibrarySection.Albums, YLibrarySectionType.Likes))
- .GetResponseAsync();
- }
-
- ///
- /// Добавить исполнителя в список лайкнутых
- ///
- /// Хранилище
- /// Исполнитель
- ///
- public Task> AddArtistLikeAsync(AuthStorage storage, YArtist artist)
- {
- return new YLibraryAddBuilder(api, storage)
- .Build((artist.Id, YLibrarySection.Artists, YLibrarySectionType.Likes))
- .GetResponseAsync();
- }
-
- ///
- /// Удалить исполнителя из списка лайкнутых
- ///
- /// Хранилище
- /// Исполнитель
- ///
- public Task> RemoveArtistLikeAsync(AuthStorage storage, YArtist artist)
- {
- return new YLibraryRemoveBuilder(api, storage)
- .Build((artist.Id, YLibrarySection.Artists, YLibrarySectionType.Likes))
- .GetResponseAsync();
- }
-
- ///
- /// Добавить плейлист в список лайкнутых
- ///
- /// Хранилище
- /// Плейлист
- ///
- public Task> AddPlaylistLikeAsync(AuthStorage storage, YPlaylist playlist)
- {
- return new YLibraryAddBuilder(api, storage)
- .Build((playlist.GetKey().ToString(), YLibrarySection.Playlists, YLibrarySectionType.Likes))
- .GetResponseAsync();
- }
-
- ///
- /// Удалить плейлист из списка лайкнутых
- ///
- /// Хранилище
- /// Плейлист
- ///
- public Task> RemovePlaylistLikeAsync(AuthStorage storage, YPlaylist playlist)
- {
- return new YLibraryRemoveBuilder(api, storage)
- .Build((playlist.GetKey().ToString(), YLibrarySection.Playlists, YLibrarySectionType.Likes))
- .GetResponseAsync();
- }
-
- #endregion Добавление/удаление в списки лайков/дизлайков
-
- #region Получение списка "Вы недавно слушали"
-
- public Task> GetRecentlyListenedAsync(AuthStorage storage, IEnumerable contextTypes, int trackCount, int contextCount)
- {
- return new YGetLibraryRecentlyListenedBuilder(api, storage)
- .Build((contextTypes, trackCount, contextCount))
- .GetResponseAsync();
- }
-
- #endregion Получение списка "Вы недавно слушали"
-
-
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YPinsAPI.cs b/YandexMusic.API/API/YPinsAPI.cs
new file mode 100644
index 0000000..bc1dc4f
--- /dev/null
+++ b/YandexMusic.API/API/YPinsAPI.cs
@@ -0,0 +1,20 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Pins;
+using YandexMusic.API.Requests.Pins;
+
+namespace YandexMusic.API;
+
+/// API для взаимодействия с закреплёнными объектами (пинами).
+public class YPinsAPI : YCommonAPI
+{
+ /// Инициализирует новый экземпляр API пинов.
+ /// Экземпляр основного API.
+ public YPinsAPI(YandexMusicApi yandex) : base(yandex) { }
+
+ /// Получает список закреплённых объектов.
+ /// Хранилище авторизации.
+ /// Ответ API со списком пинов.
+ public Task> GetAsync(AuthStorage storage)
+ => new YGetPinsBuilder(api, storage).Build(null!).GetResponseAsync();
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YPinsAPIAsync.cs b/YandexMusic.API/API/YPinsAPIAsync.cs
deleted file mode 100644
index 279e323..0000000
--- a/YandexMusic.API/API/YPinsAPIAsync.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Pins;
-using YandexMusic.API.Requests.Pins;
-
-namespace YandexMusic.API
-{
- ///
- /// API для взаимодействия с прикреплёнными объектами
- ///
- public partial class YPinsAPI : YCommonAPI
- {
-
-
- public YPinsAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Получение списка прикреплённых объектов
- ///
- /// Хранилище
- ///
- public Task> GetAsync(AuthStorage storage)
- {
- return new YGetPinsBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
- }
-
-
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YPlaylistAPI.cs b/YandexMusic.API/API/YPlaylistAPI.cs
new file mode 100644
index 0000000..985b331
--- /dev/null
+++ b/YandexMusic.API/API/YPlaylistAPI.cs
@@ -0,0 +1,149 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Landing;
+using YandexMusic.API.Models.Landing.Entity.Entities;
+using YandexMusic.API.Models.Playlist;
+using YandexMusic.API.Models.Track;
+using YandexMusic.API.Requests.Playlist;
+
+namespace YandexMusic.API;
+
+/// API для взаимодействия с плейлистами.
+public class YPlaylistAPI : YCommonAPI
+{
+ /// Инициализирует новый экземпляр API плейлистов.
+ /// Экземпляр основного API.
+ public YPlaylistAPI(YandexMusicApi yandex) : base(yandex) { }
+
+ /// Получает список персональных плейлистов с главной страницы.
+ /// Хранилище авторизации.
+ /// Список ответов с плейлистами.
+ public async Task>> GetPersonalPlaylistsAsync(AuthStorage storage)
+ {
+ var landing = await api.Landing.GetAsync(storage, YLandingBlockType.PersonalPlaylists);
+ var block = landing.Result?.Blocks?.FirstOrDefault(b => b.Type == YLandingBlockType.PersonalPlaylists);
+ if (block?.Entities == null)
+ return new List>();
+
+ var tasks = block.Entities
+ .OfType()
+ .Select(e => api.Playlist.GetAsync(storage, e.Data?.Data));
+
+ return new List>(await Task.WhenAll(tasks));
+ }
+
+ /// Получает избранные плейлисты.
+ public Task>> FavoritesAsync(AuthStorage storage)
+ => new YGetPlaylistFavoritesBuilder(api, storage).Build(null!).GetResponseAsync();
+
+ /// Получает плейлист дня.
+ public Task> OfTheDayAsync(AuthStorage storage)
+ => GetPersonalPlaylistAsync(storage, YGeneratedPlaylistType.PlaylistOfTheDay);
+
+ /// Получает плейлист «Дежавю».
+ public Task> DejaVuAsync(AuthStorage storage)
+ => GetPersonalPlaylistAsync(storage, YGeneratedPlaylistType.NeverHeard);
+
+ /// Получает плейлист «Премьера».
+ public Task> PremiereAsync(AuthStorage storage)
+ => GetPersonalPlaylistAsync(storage, YGeneratedPlaylistType.RecentTracks);
+
+ /// Получает плейлист «Тайник».
+ public Task> MissedAsync(AuthStorage storage)
+ => GetPersonalPlaylistAsync(storage, YGeneratedPlaylistType.MissedLikes);
+
+ /// Получает плейлист «Кинопоиск».
+ public Task> KinopoiskAsync(AuthStorage storage)
+ => GetPersonalPlaylistAsync(storage, YGeneratedPlaylistType.Kinopoisk);
+
+ private async Task> GetPersonalPlaylistAsync(AuthStorage storage, YGeneratedPlaylistType type)
+ {
+ var list = await GetPersonalPlaylistsAsync(storage);
+ return list.FirstOrDefault(e => string.Equals(e.Result?.GeneratedPlaylistType, type.ToString(), StringComparison.CurrentCultureIgnoreCase))
+ ?? throw new Exception($"Плейлист типа {type} не найден.");
+ }
+
+ /// Получает плейлист по идентификатору пользователя и типа.
+ public Task> GetAsync(AuthStorage storage, string user, string kind)
+ => new YGetPlaylistBuilder(api, storage).Build((user, kind)).GetResponseAsync();
+
+ /// Получает плейлист по UUID.
+ public Task> GetAsync(AuthStorage storage, string uuid)
+ => new YGetPlaylistByUuidBuilder(api, storage).Build(uuid).GetResponseAsync();
+
+ /// Получает несколько плейлистов по списку пар (пользователь, тип).
+ public Task>> GetAsync(AuthStorage storage, IEnumerable<(string user, string kind)> ids)
+ => new YGetPlaylistsBuilder(api, storage).Build(ids).GetResponseAsync();
+
+ /// Получает плейлист по объекту плейлиста (обновляет его треки).
+ public Task> GetAsync(AuthStorage storage, YPlaylist playlist)
+ => new YGetPlaylistBuilder(api, storage).Build((playlist.Owner.Uid, playlist.Kind)).GetResponseAsync();
+
+ /// Создаёт новый плейлист с заданным именем.
+ public Task> CreateAsync(AuthStorage storage, string name)
+ => new YPlaylistCreateBuilder(api, storage).Build(name).GetResponseAsync();
+
+ /// Переименовывает плейлист.
+ public Task> RenameAsync(AuthStorage storage, string kind, string name)
+ => new YPlaylistRenameBuilder(api, storage).Build((kind, name)).GetResponseAsync();
+
+ /// Переименовывает плейлист.
+ public Task> RenameAsync(AuthStorage storage, YPlaylist playlist, string name)
+ => RenameAsync(storage, playlist.Kind, name);
+
+ /// Удаляет плейлист.
+ public async Task DeleteAsync(AuthStorage storage, string kind)
+ {
+ try
+ {
+ await new YPlaylistRemoveBuilder(api, storage).Build(kind).GetResponseAsync();
+ return true;
+ }
+ catch (Exception ex)
+ {
+ // Логирование ошибки можно добавить через ILogger
+ return false;
+ }
+ }
+
+ /// Удаляет плейлист.
+ public Task DeleteAsync(AuthStorage storage, YPlaylist playlist)
+ => DeleteAsync(storage, playlist.Kind);
+
+ /// Добавляет треки в начало плейлиста.
+ public async Task> InsertTracksAsync(AuthStorage storage, YPlaylist playlist, IEnumerable tracks)
+ {
+ var change = await ChangePlaylistAsync(storage, playlist, new List
+ {
+ new()
+ {
+ Operation = YPlaylistChangeType.Insert,
+ At = 0,
+ Tracks = tracks.Select(t => t.GetKey())
+ }
+ });
+ return await GetAsync(storage, change.Result);
+ }
+
+ /// Удаляет треки из плейлиста.
+ public Task> DeleteTracksAsync(AuthStorage storage, YPlaylist playlist, IEnumerable tracks)
+ {
+ var distinctTracks = tracks.Distinct().ToList();
+ var changes = distinctTracks
+ .Select(t => playlist.Tracks?.FindIndex(ct => ct.Track?.GetKey() == t.GetKey()) ?? -1)
+ .Where(i => i != -1)
+ .Select(i => new YPlaylistChange
+ {
+ Operation = YPlaylistChangeType.Delete,
+ From = i,
+ To = i + 1,
+ Tracks = new List { playlist.Tracks![i].Track!.GetKey() }
+ })
+ .ToList();
+
+ return ChangePlaylistAsync(storage, playlist, changes);
+ }
+
+ private Task> ChangePlaylistAsync(AuthStorage storage, YPlaylist playlist, IEnumerable changes)
+ => new YPlaylistChangeBuilder(api, storage).Build((playlist, changes)).GetResponseAsync();
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YPlaylistAPIAsync.cs b/YandexMusic.API/API/YPlaylistAPIAsync.cs
deleted file mode 100644
index cf94f73..0000000
--- a/YandexMusic.API/API/YPlaylistAPIAsync.cs
+++ /dev/null
@@ -1,335 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Landing;
-using YandexMusic.API.Models.Landing.Entity.Entities;
-using YandexMusic.API.Models.Playlist;
-using YandexMusic.API.Models.Track;
-using YandexMusic.API.Requests.Playlist;
-
-namespace YandexMusic.API
-{
- ///
- /// API для взамодействия с плейлистами
- ///
- public partial class YPlaylistAPI : YCommonAPI
- {
- #region Вспомогательные функции
-
- ///
- /// Получение персональных плейлистов
- ///
- /// Хранилище
- /// Тип
- /// Плейлист
- private async Task> GetPersonalPlaylist(AuthStorage storage, YGeneratedPlaylistType type)
- {
- List> list = await GetPersonalPlaylistsAsync(storage);
- return list.FirstOrDefault(e => string.Equals(e.Result.GeneratedPlaylistType, type.ToString(), StringComparison.CurrentCultureIgnoreCase));
- }
-
- ///
- /// Изменение плейлиста
- ///
- /// Хранилище
- /// Плейлист
- /// Список изменений
- /// Плейлист после изменений
- private Task> ChangePlaylist(AuthStorage storage, YPlaylist playlist, IEnumerable changes)
- {
- return new YPlaylistChangeBuilder(api, storage)
- .Build((playlist, changes))
- .GetResponseAsync();
- }
-
- private IEnumerable RemoveIdentical(IEnumerable tracks)
- {
- return tracks.Distinct();
- }
-
- #endregion Вспомогательные функции
-
-
-
- public YPlaylistAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- #region Список с главной
-
- ///
- /// Получение списка персональных плейлистов
- ///
- /// Хранилище
- ///
- public async Task>> GetPersonalPlaylistsAsync(AuthStorage storage)
- {
- YResponse landing = await api.Landing.GetAsync(storage, YLandingBlockType.PersonalPlaylists);
-
- IEnumerable>> tasks = landing
- .Result
- .Blocks
- .FirstOrDefault(b => b.Type == YLandingBlockType.PersonalPlaylists)
- ?.Entities
- .Select(e => api.Playlist.GetAsync(storage, ((YLandingEntityPersonalPlaylist)e).Data?.Data));
-
- return tasks == null
- ? new List>()
- : new List>(await Task.WhenAll(tasks));
- }
-
- #endregion Список с главной
-
- #region Стандартные плейлисты
-
- ///
- /// Избранное
- ///
- /// Хранилище
- ///
- public Task>> FavoritesAsync(AuthStorage storage)
- {
- return new YGetPlaylistFavoritesBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
- }
-
- ///
- /// Плейлист дня
- ///
- /// Хранилище
- ///
- public Task> OfTheDayAsync(AuthStorage storage)
- {
- return GetPersonalPlaylist(storage, YGeneratedPlaylistType.PlaylistOfTheDay);
- }
-
- ///
- /// Дежавю
- ///
- /// Хранилище
- ///
- public Task> DejaVuAsync(AuthStorage storage)
- {
- return GetPersonalPlaylist(storage, YGeneratedPlaylistType.NeverHeard);
- }
-
- ///
- /// Премьера
- ///
- /// Хранилище
- ///
- public Task> PremiereAsync(AuthStorage storage)
- {
- return GetPersonalPlaylist(storage, YGeneratedPlaylistType.RecentTracks);
- }
-
- ///
- /// Тайник
- ///
- /// Хранилище
- ///
- public Task> MissedAsync(AuthStorage storage)
- {
- return GetPersonalPlaylist(storage, YGeneratedPlaylistType.MissedLikes);
- }
-
- ///
- /// Кинопоиск
- ///
- /// Хранилище
- ///
- public Task> KinopoiskAsync(AuthStorage storage)
- {
- return GetPersonalPlaylist(storage, YGeneratedPlaylistType.Kinopoisk);
- }
-
- #endregion Стандартные плейлисты
-
- #region Получение плейлиста
-
- ///
- /// Получение плейлиста
- ///
- /// Хранилище
- /// Uid пользователя-владельца плейлиста
- /// Тип
- ///
- public Task> GetAsync(AuthStorage storage, string user, string kind)
- {
- return new YGetPlaylistBuilder(api, storage)
- .Build((user, kind))
- .GetResponseAsync();
- }
-
- ///
- /// Получение плейлиста по uuid
- ///
- /// Хранилище
- /// uuid
- ///
- public Task> GetAsync(AuthStorage storage, string uuid)
- {
- return new YGetPlaylistByUuidBuilder(api, storage)
- .Build(uuid)
- .GetResponseAsync();
- }
-
- ///
- /// Получение плейлистов
- ///
- /// Хранилище
- /// Список пар пользователь:тип
- ///
- public Task>> GetAsync(AuthStorage storage, IEnumerable<(string user, string kind)> ids)
- {
- return new YGetPlaylistsBuilder(api, storage)
- .Build(ids)
- .GetResponseAsync();
- }
-
- ///
- /// Получение плейлиста
- ///
- /// Хранилище
- /// Описание плейлиста, для которого будут запрошены треки
- ///
- public Task> GetAsync(AuthStorage storage, YPlaylist playlist)
- {
- return new YGetPlaylistBuilder(api, storage)
- .Build((playlist.Owner.Uid, playlist.Kind))
- .GetResponseAsync();
- }
-
- #endregion Получение плейлиста
-
- #region Операции над плейлистами
-
- ///
- /// Создание
- ///
- /// Хранилище
- /// Заголовок
- ///
- public Task> CreateAsync(AuthStorage storage, string name)
- {
- return new YPlaylistCreateBuilder(api, storage)
- .Build(name)
- .GetResponseAsync();
- }
-
- ///
- /// Переименование
- ///
- /// Хранилище
- /// Идентификатор плейлиста
- /// Заголовок
- ///
- public Task> RenameAsync(AuthStorage storage, string kinds, string name)
- {
- return new YPlaylistRenameBuilder(api, storage)
- .Build((kinds, name))
- .GetResponseAsync();
- }
-
- ///
- /// Переименование
- ///
- /// Хранилище
- /// Плейлист
- /// Заголовок
- ///
- public Task> RenameAsync(AuthStorage storage, YPlaylist playlist, string name)
- {
- return RenameAsync(storage, playlist.Kind, name);
- }
-
- ///
- /// Удаление
- ///
- /// Хранилище
- /// Тип
- ///
- public async Task DeleteAsync(AuthStorage storage, string kinds)
- {
- try
- {
- await new YPlaylistRemoveBuilder(api, storage)
- .Build(kinds)
- .GetResponseAsync();
-
- return true;
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- }
-
- return false;
- }
-
- ///
- /// Удаление
- ///
- /// Хранилище
- /// Плейлист
- ///
- public Task DeleteAsync(AuthStorage storage, YPlaylist playlist)
- {
- return DeleteAsync(storage, playlist.Kind);
- }
-
- ///
- /// Добавление трека
- ///
- /// Хранилище
- /// Плейлист
- /// Треки для добавления
- ///
- public async Task> InsertTracksAsync(AuthStorage storage, YPlaylist playlist, IEnumerable tracks)
- {
- YResponse change = await ChangePlaylist(storage, playlist, new List {
- new() {
- Operation = YPlaylistChangeType.Insert,
- At = 0,
- Tracks = tracks.Select(t => t.GetKey())
- }
- });
-
- return await GetAsync(storage, change.Result);
- }
-
- ///
- /// Удаление треков
- ///
- /// Хранилище
- /// Плейлист
- /// Треки для удаления
- ///
- public Task> DeleteTracksAsync(AuthStorage storage, YPlaylist playlist, IEnumerable tracks)
- {
- List changes = RemoveIdentical(tracks)
- .Select(t => playlist.Tracks.Select(c => c.Track).ToList().IndexOf(t))
- .Where(i => i != -1)
- .Select(i =>
- {
- YTrackContainer t = playlist.Tracks[i];
- return new YPlaylistChange
- {
- Operation = YPlaylistChangeType.Delete,
- From = i,
- To = i + 1,
- Tracks = new List {
- t.Track.GetKey()
- }
- };
- })
- .ToList();
-
- return ChangePlaylist(storage, playlist, changes);
- }
-
- #endregion Операции над плейлистами
-
-
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YQueueAPI.cs b/YandexMusic.API/API/YQueueAPI.cs
new file mode 100644
index 0000000..f7881cf
--- /dev/null
+++ b/YandexMusic.API/API/YQueueAPI.cs
@@ -0,0 +1,72 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Queue;
+using YandexMusic.API.Requests.Queue;
+
+namespace YandexMusic.API;
+
+///
+/// API для взаимодействия с очередями
+///
+public partial class YQueueAPI : YCommonAPI
+{
+ public YQueueAPI(YandexMusicApi yandex) : base(yandex)
+ {
+ }
+
+ ///
+ /// Получение всех очередей треков с разных устройств для синхронизации между ними
+ ///
+ /// Хранилище
+ /// Устройство
+ ///
+ public Task> ListAsync(AuthStorage storage, string? device = null)
+ {
+ return new YQueuesListBuilder(api, storage)
+ .Build(device)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение очереди
+ ///
+ /// Хранилище
+ /// Идентификатор очереди
+ ///
+ public Task> GetAsync(AuthStorage storage, string queueId)
+ {
+ return new YGetQueueBuilder(api, storage)
+ .Build(queueId)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Создание новой очереди треков
+ ///
+ /// Хранилище
+ /// Очередь треков
+ /// Устройство
+ ///
+ public Task> CreateAsync(AuthStorage storage, YQueue queue, string? device = null)
+ {
+ return new YQueueCreateBuilder(api, storage, device)
+ .Build(queue)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Установка текущего индекса проигрываемого трека в очереди треков
+ ///
+ /// Хранилище
+ /// Идентификатор очереди
+ /// Текущий индекс
+ /// Флаг интерактивности
+ /// Устройство
+ ///
+ public Task> UpdatePositionAsync(AuthStorage storage, string queueId, int currentIndex, bool isInteractive, string device = null)
+ {
+ return new YQueueUpdatePositionBuilder(api, storage, device)
+ .Build((queueId, currentIndex, isInteractive))
+ .GetResponseAsync();
+ }
+}
diff --git a/YandexMusic.API/API/YQueueAPIAsync.cs b/YandexMusic.API/API/YQueueAPIAsync.cs
deleted file mode 100644
index aa380fd..0000000
--- a/YandexMusic.API/API/YQueueAPIAsync.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Queue;
-using YandexMusic.API.Requests.Queue;
-
-namespace YandexMusic.API
-{
- ///
- /// API для взаимодействия с очередями
- ///
- public partial class YQueueAPI : YCommonAPI
- {
- public YQueueAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Получение всех очередей треков с разных устройств для синхронизации между ними
- ///
- /// Хранилище
- /// Устройство
- ///
- public Task> ListAsync(AuthStorage storage, string device = null)
- {
- return new YQueuesListBuilder(api, storage)
- .Build(device)
- .GetResponseAsync();
- }
-
- ///
- /// Получение очереди
- ///
- /// Хранилище
- /// Идентификатор очереди
- ///
- public Task> GetAsync(AuthStorage storage, string queueId)
- {
- return new YGetQueueBuilder(api, storage)
- .Build(queueId)
- .GetResponseAsync();
- }
-
- ///
- /// Создание новой очереди треков
- ///
- /// Хранилище
- /// Очередь треков
- /// Устройство
- ///
- public Task> CreateAsync(AuthStorage storage, YQueue queue, string device = null)
- {
- return new YQueueCreateBuilder(api, storage, device)
- .Build(queue)
- .GetResponseAsync();
- }
-
- ///
- /// Установка текущего индекса проигрываемого трека в очереди треков
- ///
- /// Хранилище
- /// Идентификатор очереди
- /// Текущий индекс
- /// Флаг интерактивности
- /// Устройство
- ///
- public Task> UpdatePositionAsync(AuthStorage storage, string queueId, int currentIndex, bool isInteractive, string device = null)
- {
- return new YQueueUpdatePositionBuilder(api, storage, device)
- .Build((queueId, currentIndex, isInteractive))
- .GetResponseAsync();
- }
- }
-}
diff --git a/YandexMusic.API/API/YRadioAPI.cs b/YandexMusic.API/API/YRadioAPI.cs
new file mode 100644
index 0000000..02172bc
--- /dev/null
+++ b/YandexMusic.API/API/YRadioAPI.cs
@@ -0,0 +1,113 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Radio;
+using YandexMusic.API.Models.Track;
+using YandexMusic.API.Requests.Radio;
+
+namespace YandexMusic.API;
+
+///
+/// API для взаимодействия с радио
+///
+public partial class YRadioAPI : YCommonAPI
+{
+ public YRadioAPI(YandexMusicApi yandex) : base(yandex)
+ {
+ }
+
+ ///
+ /// Получение списка рекомендованных радиостанций
+ ///
+ /// Хранилище
+ ///
+ public Task> GetStationsDashboardAsync(AuthStorage storage)
+ {
+ return new YGetStationsDashboardBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение списка радиостанций
+ ///
+ /// Хранилище
+ ///
+ public Task>> GetStationsAsync(AuthStorage storage)
+ {
+ return new YGetStationsBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение информации о радиостанции
+ ///
+ /// Хранилище
+ /// Тип
+ /// Тэг
+ ///
+ public Task>> GetStationAsync(AuthStorage storage, string type, string tag)
+ {
+ return new YGetStationBuilder(api, storage)
+ .Build((type, tag))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение информации о радиостанции
+ ///
+ /// Хранилище
+ /// Идентификатор станции
+ ///
+ public Task>> GetStationAsync(AuthStorage storage, YStationId id)
+ {
+ return GetStationAsync(storage, id.Type, id.Tag);
+ }
+
+ ///
+ /// Получение последовательности треков радиостанции
+ ///
+ /// Хранилище
+ /// Радиостанция
+ /// Идентификатор предыдущего трека
+ ///
+ public Task> GetStationTracksAsync(AuthStorage storage, YStation station, string prevTrackId = "")
+ {
+ return new YGetStationTracksBuilder(api, storage)
+ .Build((station.Station, prevTrackId))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Установка настроек подбора треков
+ ///
+ /// Хранилище
+ /// Радиостанция
+ /// Настройки
+ ///
+ public Task> SetStationSettings2Async(AuthStorage storage, YStation station, YStationSettings2 settings)
+ {
+ return new YSetSettings2Builder(api, storage)
+ .Build((station.Station, settings))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Отправка обратной связи на действия при прослушивании радио
+ ///
+ /// Хранилище
+ /// Радиостанция
+ /// Тип обратной связи
+ /// Трек
+ /// Уникальный идентификатор партии треков. Возвращается при получении треков
+ /// Сколько было проиграно секунд трека перед действием
+ ///
+ public Task SendStationFeedBackAsync(AuthStorage storage, YStation station, YStationFeedbackType type, YTrack track = null, string batchId = "", double totalPlayedSeconds = 0)
+ {
+ return new YSetStationFeedbackBuilder(api, storage)
+ .Build((type, station, track, batchId, totalPlayedSeconds))
+ .GetResponseAsync();
+ }
+
+
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YRadioAPIAsync.cs b/YandexMusic.API/API/YRadioAPIAsync.cs
deleted file mode 100644
index 169976d..0000000
--- a/YandexMusic.API/API/YRadioAPIAsync.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Radio;
-using YandexMusic.API.Models.Track;
-using YandexMusic.API.Requests.Radio;
-
-namespace YandexMusic.API
-{
- ///
- /// API для взаимодействия с радио
- ///
- public partial class YRadioAPI : YCommonAPI
- {
-
-
- public YRadioAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Получение списка рекомендованных радиостанций
- ///
- /// Хранилище
- ///
- public Task> GetStationsDashboardAsync(AuthStorage storage)
- {
- return new YGetStationsDashboardBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
- }
-
- ///
- /// Получение списка радиостанций
- ///
- /// Хранилище
- ///
- public Task>> GetStationsAsync(AuthStorage storage)
- {
- return new YGetStationsBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
- }
-
- ///
- /// Получение информации о радиостанции
- ///
- /// Хранилище
- /// Тип
- /// Тэг
- ///
- public Task>> GetStationAsync(AuthStorage storage, string type, string tag)
- {
- return new YGetStationBuilder(api, storage)
- .Build((type, tag))
- .GetResponseAsync();
- }
-
- ///
- /// Получение информации о радиостанции
- ///
- /// Хранилище
- /// Идентификатор станции
- ///
- public Task>> GetStationAsync(AuthStorage storage, YStationId id)
- {
- return GetStationAsync(storage, id.Type, id.Tag);
- }
-
- ///
- /// Получение последовательности треков радиостанции
- ///
- /// Хранилище
- /// Радиостанция
- /// Идентификатор предыдущего трека
- ///
- public Task> GetStationTracksAsync(AuthStorage storage, YStation station, string prevTrackId = "")
- {
- return new YGetStationTracksBuilder(api, storage)
- .Build((station.Station, prevTrackId))
- .GetResponseAsync();
- }
-
- ///
- /// Установка настроек подбора треков
- ///
- /// Хранилище
- /// Радиостанция
- /// Настройки
- ///
- public Task> SetStationSettings2Async(AuthStorage storage, YStation station, YStationSettings2 settings)
- {
- return new YSetSettings2Builder(api, storage)
- .Build((station.Station, settings))
- .GetResponseAsync();
- }
-
- ///
- /// Отправка обратной связи на действия при прослушивании радио
- ///
- /// Хранилище
- /// Радиостанция
- /// Тип обратной связи
- /// Трек
- /// Уникальный идентификатор партии треков. Возвращается при получении треков
- /// Сколько было проиграно секунд трека перед действием
- ///
- public Task SendStationFeedBackAsync(AuthStorage storage, YStation station, YStationFeedbackType type, YTrack track = null, string batchId = "", double totalPlayedSeconds = 0)
- {
- return new YSetStationFeedbackBuilder(api, storage)
- .Build((type, station, track, batchId, totalPlayedSeconds))
- .GetResponseAsync();
- }
-
-
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YSearchAPI.cs b/YandexMusic.API/API/YSearchAPI.cs
new file mode 100644
index 0000000..1a9a690
--- /dev/null
+++ b/YandexMusic.API/API/YSearchAPI.cs
@@ -0,0 +1,139 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Search;
+using YandexMusic.API.Requests.Search;
+
+namespace YandexMusic.API;
+
+///
+/// API для поиска
+///
+public partial class YSearchAPI : YCommonAPI
+{
+
+ public YSearchAPI(YandexMusicApi yandex) : base(yandex)
+ {
+ }
+
+ ///
+ /// Поиск по трекам
+ ///
+ /// Хранилище
+ /// Имя трека
+ /// Номер страницы
+ /// Размер страницы
+ ///
+ public Task> TrackAsync(AuthStorage storage, string trackName, int pageNumber = 0, int pageSize = 20)
+ {
+ return SearchAsync(storage, trackName, YSearchType.Track, pageNumber, pageSize);
+ }
+
+ ///
+ /// Поиск по альбомам
+ ///
+ /// Хранилище
+ /// Имя альбома
+ /// Номер страницы
+ /// Размер страницы
+ ///
+ public Task> AlbumsAsync(AuthStorage storage, string albumName, int pageNumber = 0, int pageSize = 20)
+ {
+ return SearchAsync(storage, albumName, YSearchType.Album, pageNumber, pageSize);
+ }
+
+ ///
+ /// Поиск по артисту
+ ///
+ /// Хранилище
+ /// Имя артиста
+ /// Номер страницы
+ /// Размер страницы
+ ///
+ public Task> ArtistAsync(AuthStorage storage, string artistName, int pageNumber = 0, int pageSize = 20)
+ {
+ return SearchAsync(storage, artistName, YSearchType.Artist, pageNumber, pageSize);
+ }
+
+ ///
+ /// Поиск по плейлистам
+ ///
+ /// Хранилище
+ /// Имя плейлиста
+ /// Номер страницы
+ /// Размер страницы
+ ///
+ public Task> PlaylistAsync(AuthStorage storage, string playlistName, int pageNumber = 0, int pageSize = 20)
+ {
+ return SearchAsync(storage, playlistName, YSearchType.Playlist, pageNumber, pageSize);
+ }
+
+ ///
+ /// Поиск по плейлистам
+ ///
+ /// Хранилище
+ /// Имя подкаста
+ /// Номер страницы
+ /// Размер страницы
+ ///
+ public Task> PodcastEpisodeAsync(AuthStorage storage, string podcastName, int pageNumber = 0, int pageSize = 20)
+ {
+ return SearchAsync(storage, podcastName, YSearchType.PodcastEpisode, pageNumber, pageSize);
+ }
+
+ ///
+ /// Поиск по видео
+ ///
+ /// Хранилище
+ /// Имя видео
+ /// Номер страницы
+ /// Размер страницы
+ ///
+ public Task> VideosAsync(AuthStorage storage, string videoName, int pageNumber = 0, int pageSize = 20)
+ {
+ return SearchAsync(storage, videoName, YSearchType.Video, pageNumber, pageSize);
+ }
+
+ ///
+ /// Поиск по пользователям
+ ///
+ /// Хранилище
+ /// Имя пользователя
+ /// Номер страницы
+ /// Размер страницы
+ ///
+ public Task> UsersAsync(AuthStorage storage, string userName, int pageNumber = 0, int pageSize = 20)
+ {
+ return SearchAsync(storage, userName, YSearchType.User, pageNumber, pageSize);
+ }
+
+ ///
+ /// Поиск
+ ///
+ /// Хранилище
+ /// Поисковый запрос
+ /// Тип поиска
+ /// Страница
+ /// Размер страницы
+ ///
+ public Task> SearchAsync(AuthStorage storage, string searchText, YSearchType searchType, int page = 0, int pageSize = 20)
+ {
+ return new YSearchBuilder(api, storage)
+ .Build((searchText, searchType, page, pageSize))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Подсказка
+ ///
+ /// Хранилище
+ /// Поисковый запрос
+ ///
+ public Task> SuggestAsync(AuthStorage storage, string searchText)
+ {
+ return new YSearchSuggestBuilder(api, storage)
+ .Build(searchText)
+ .GetResponseAsync();
+ }
+
+
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YSearchAPIAsync.cs b/YandexMusic.API/API/YSearchAPIAsync.cs
deleted file mode 100644
index 515a27c..0000000
--- a/YandexMusic.API/API/YSearchAPIAsync.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Search;
-using YandexMusic.API.Requests.Search;
-
-namespace YandexMusic.API
-{
- ///
- /// API для поиска
- ///
- public partial class YSearchAPI : YCommonAPI
- {
-
-
- public YSearchAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Поиск по трекам
- ///
- /// Хранилище
- /// Имя трека
- /// Номер страницы
- /// Размер страницы
- ///
- public Task> TrackAsync(AuthStorage storage, string trackName, int pageNumber = 0, int pageSize = 20)
- {
- return SearchAsync(storage, trackName, YSearchType.Track, pageNumber, pageSize);
- }
-
- ///
- /// Поиск по альбомам
- ///
- /// Хранилище
- /// Имя альбома
- /// Номер страницы
- /// Размер страницы
- ///
- public Task> AlbumsAsync(AuthStorage storage, string albumName, int pageNumber = 0, int pageSize = 20)
- {
- return SearchAsync(storage, albumName, YSearchType.Album, pageNumber, pageSize);
- }
-
- ///
- /// Поиск по артисту
- ///
- /// Хранилище
- /// Имя артиста
- /// Номер страницы
- /// Размер страницы
- ///
- public Task> ArtistAsync(AuthStorage storage, string artistName, int pageNumber = 0, int pageSize = 20)
- {
- return SearchAsync(storage, artistName, YSearchType.Artist, pageNumber, pageSize);
- }
-
- ///
- /// Поиск по плейлистам
- ///
- /// Хранилище
- /// Имя плейлиста
- /// Номер страницы
- /// Размер страницы
- ///
- public Task> PlaylistAsync(AuthStorage storage, string playlistName, int pageNumber = 0, int pageSize = 20)
- {
- return SearchAsync(storage, playlistName, YSearchType.Playlist, pageNumber, pageSize);
- }
-
- ///
- /// Поиск по плейлистам
- ///
- /// Хранилище
- /// Имя подкаста
- /// Номер страницы
- /// Размер страницы
- ///
- public Task> PodcastEpisodeAsync(AuthStorage storage, string podcastName, int pageNumber = 0, int pageSize = 20)
- {
- return SearchAsync(storage, podcastName, YSearchType.PodcastEpisode, pageNumber, pageSize);
- }
-
- ///
- /// Поиск по видео
- ///
- /// Хранилище
- /// Имя видео
- /// Номер страницы
- /// Размер страницы
- ///
- public Task> VideosAsync(AuthStorage storage, string videoName, int pageNumber = 0, int pageSize = 20)
- {
- return SearchAsync(storage, videoName, YSearchType.Video, pageNumber, pageSize);
- }
-
- ///
- /// Поиск по пользователям
- ///
- /// Хранилище
- /// Имя пользователя
- /// Номер страницы
- /// Размер страницы
- ///
- public Task> UsersAsync(AuthStorage storage, string userName, int pageNumber = 0, int pageSize = 20)
- {
- return SearchAsync(storage, userName, YSearchType.User, pageNumber, pageSize);
- }
-
- ///
- /// Поиск
- ///
- /// Хранилище
- /// Поисковый запрос
- /// Тип поиска
- /// Страница
- /// Размер страницы
- ///
- public Task> SearchAsync(AuthStorage storage, string searchText, YSearchType searchType, int page = 0, int pageSize = 20)
- {
- return new YSearchBuilder(api, storage)
- .Build((searchText, searchType, page, pageSize))
- .GetResponseAsync();
- }
-
- ///
- /// Подсказка
- ///
- /// Хранилище
- /// Поисковый запрос
- ///
- public Task> SuggestAsync(AuthStorage storage, string searchText)
- {
- return new YSearchSuggestBuilder(api, storage)
- .Build(searchText)
- .GetResponseAsync();
- }
-
-
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YTrackAPI.cs b/YandexMusic.API/API/YTrackAPI.cs
new file mode 100644
index 0000000..f495dd6
--- /dev/null
+++ b/YandexMusic.API/API/YTrackAPI.cs
@@ -0,0 +1,307 @@
+using System.Security.Cryptography;
+using System.Text;
+
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Track;
+using YandexMusic.API.Requests.Track;
+
+namespace YandexMusic.API;
+
+///
+/// API для взаимодействия с треками
+///
+public partial class YTrackAPI : YCommonAPI
+{
+ #region Вспомогательные функции
+
+ private string BuildLinkForDownload(YTrackDownloadInfo mainDownloadResponse, YStorageDownloadFile storageDownload)
+ {
+ string path = storageDownload.Path;
+ string host = storageDownload.Host;
+ string ts = storageDownload.Ts;
+ string s = storageDownload.S;
+ string codec = mainDownloadResponse.Codec;
+
+ string secret = $"XGRlBW9FXlekgbPrRHuSiA{path.Substring(1, path.Length - 1)}{s}";
+ MD5 md5 = MD5.Create();
+ byte[] md5Hash = md5.ComputeHash(Encoding.UTF8.GetBytes(secret));
+ HMACSHA1 hmacsha1 = new();
+ byte[] hmasha1Hash = hmacsha1.ComputeHash(md5Hash);
+ string sign = BitConverter.ToString(hmasha1Hash).Replace("-", "").ToLower();
+
+ string link = $"https://{host}/get-{codec}/{sign}/{ts}{path}";
+
+ return link;
+ }
+
+ #endregion Вспомогательные функции
+
+
+
+ public YTrackAPI(YandexMusicApi yandex) : base(yandex)
+ {
+ }
+
+ ///
+ /// Получение треков
+ ///
+ /// Хранилище
+ /// Идентификатор трека
+ ///
+ public Task>> GetAsync(AuthStorage storage, string trackId)
+ {
+ return new YGetTracksBuilder(api, storage)
+ .Build(new[] { trackId })
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение треков
+ ///
+ /// Хранилище
+ /// Идентификаторы треков
+ ///
+ public Task>> GetAsync(AuthStorage storage, IEnumerable trackIds)
+ {
+ return new YGetTracksBuilder(api, storage)
+ .Build(trackIds)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение метаданных для загрузки
+ ///
+ /// Хранилище
+ /// Ключ трека в формате {идентифактор трека:идентификатор альбома}
+ /// Должен ли ответ содержать прямую ссылку на загрузку
+ ///
+ public Task>> GetMetadataForDownloadAsync(AuthStorage storage, string trackKey, bool direct = false)
+ {
+ return new YTrackDownloadInfoBuilder(api, storage)
+ .Build((trackKey, direct))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение метаданных для загрузки
+ ///
+ /// Хранилище
+ /// Трек
+ /// Должен ли ответ содержать прямую ссылку на загрузку
+ ///
+ public Task>> GetMetadataForDownloadAsync(AuthStorage storage, YTrack track, bool direct = false)
+ {
+ return GetMetadataForDownloadAsync(storage, track.GetKey().ToString(), direct);
+ }
+
+ ///
+ /// Получение информации для формирования ссылки для загрузки
+ ///
+ /// Хранилище
+ /// Метаданные для загрузки
+ ///
+ public Task GetDownloadFileInfoAsync(AuthStorage storage, YTrackDownloadInfo metadataInfo)
+ {
+ return new YStorageDownloadFileBuilder(api, storage)
+ .Build(metadataInfo.DownloadInfoUrl)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение ссылки для загрузки
+ ///
+ /// Хранилище
+ /// Ключ трека в формате {идентификатор трека:идентификатор альбома}
+ ///
+ public async Task GetFileLinkAsync(AuthStorage storage, string trackKey)
+ {
+ YResponse> meta = await GetMetadataForDownloadAsync(storage, trackKey);
+ YTrackDownloadInfo info = meta.Result
+ .OrderByDescending(i => i.BitrateInKbps)
+ .First(m => m.Codec == "mp3");
+ YStorageDownloadFile storageDownload = await GetDownloadFileInfoAsync(storage, info);
+ return BuildLinkForDownload(info, storageDownload);
+ }
+
+ ///
+ /// Получение ссылки для загрузки
+ ///
+ /// Хранилище
+ /// Трек
+ ///
+ public Task GetFileLinkAsync(AuthStorage storage, YTrack track)
+ {
+ return GetFileLinkAsync(storage, track.GetKey().ToString());
+ }
+
+ ///
+ /// Отправка текущего состояния прослушиваемого трека
+ /// Хранилище
+ /// Трек
+ /// Наименования клиента, с которого происходит прослушивание
+ /// Проигрывается ли трек с кеша
+ /// Уникальный идентификатор проигрывания
+ /// Уникальный идентификатор плейлиста, если таковой прослушивается
+ /// Сколько было всего воспроизведено трека в секундах
+ /// Окончательное значение воспроизведенных секунд
+ ///
+ ///
+ public Task SendPlayTrackInfoAsync(AuthStorage storage, YTrack track, string from, bool fromCache = false, string playId = "", string playlistId = "", double totalPlayedSeconds = 0, double endPositionSeconds = 0)
+ {
+ return new YSendTrackInfoBuilder(api, storage)
+ .Build((track, from, fromCache, playId, playlistId, totalPlayedSeconds, endPositionSeconds))
+ .GetResponseAsync();
+ }
+
+ #region GetSupplement
+
+ ///
+ /// Получение дополнительной информации для трека
+ ///
+ /// Хранилище
+ /// Идентификатор трека
+ ///
+ public Task> GetSupplementAsync(AuthStorage storage, string trackId)
+ {
+ return new YGetTrackSupplementBuilder(api, storage)
+ .Build(trackId)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение дополнительной информации для трека
+ ///
+ /// Хранилище
+ /// Трек
+ ///
+ public Task> GetSupplementAsync(AuthStorage storage, YTrack track)
+ {
+ return new YGetTrackSupplementBuilder(api, storage)
+ .Build(track.GetKey().ToString())
+ .GetResponseAsync();
+ }
+
+ #endregion GetSupplement
+
+ #region GetSimilar
+
+ ///
+ /// Получение похожих треков
+ ///
+ /// Хранилище
+ /// Идентификатор трека
+ ///
+ public Task> GetSimilarAsync(AuthStorage storage, string trackId)
+ {
+ return new YGetTrackSimilarBuilder(api, storage)
+ .Build(trackId)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение похожих треков
+ ///
+ /// Хранилище
+ /// Трек
+ ///
+ public Task> GetSimilarAsync(AuthStorage storage, YTrack track)
+ {
+ return new YGetTrackSimilarBuilder(api, storage)
+ .Build(track.GetKey().ToString())
+ .GetResponseAsync();
+ }
+
+ #endregion GetSimilar
+
+ #region Получение данных трека
+
+ #region В файл
+
+ ///
+ /// Выгрузка в файл
+ ///
+ /// Хранилище
+ /// Ключ трека в формате {идентификатор трека:идентификатор альбома}
+ /// Путь для файла
+ public async Task ExtractToFileAsync(AuthStorage storage, string trackKey, string filePath)
+ {
+ string url = await GetFileLinkAsync(storage, trackKey);
+ await new DataDownloader(storage).ToFile(url, filePath);
+ }
+
+ ///
+ /// Выгрузка в файл
+ ///
+ /// Хранилище
+ /// Трек
+ /// Путь для файла
+ public Task ExtractToFileAsync(AuthStorage storage, YTrack track, string filePath)
+ {
+ return ExtractToFileAsync(storage, track.GetKey().ToString(), filePath);
+ }
+
+ #endregion В файл
+
+ #region В массив байт
+
+ ///
+ /// Получение двоичного массива данных
+ ///
+ /// Хранилище
+ /// Ключ трека в формате {идентификатор трека:идентификатор альбома}
+ ///
+ public async Task ExtractDataAsync(AuthStorage storage, string trackKey)
+ {
+ string url = await GetFileLinkAsync(storage, trackKey);
+ return await new DataDownloader(storage).AsBytes(url);
+ }
+
+ ///
+ /// Получение двоичного массива данных
+ ///
+ /// Хранилище
+ /// Трек
+ ///
+ public Task ExtractDataAsync(AuthStorage storage, YTrack track)
+ {
+ return ExtractDataAsync(storage, track.GetKey().ToString());
+ }
+
+ #endregion В массив байт
+
+ #region В поток
+
+ ///
+ /// Получение потока данных
+ ///
+ /// Хранилище
+ /// Ключ трека в формате {идентификатор трека:идентификатор альбома}
+ /// Параметры передачи управления при http запросе
+ ///
+ public async Task ExtractStreamAsync(AuthStorage storage, string trackKey,
+ HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead)
+ {
+ string url = await GetFileLinkAsync(storage, trackKey);
+ return await new DataDownloader(storage).AsStream(url, httpCompletionOption);
+ }
+
+ ///
+ /// Получение потока данных
+ ///
+ /// Хранилище
+ /// Трек
+ /// Параметры передачи управления при http запросе
+ ///
+ public Task ExtractStreamAsync(AuthStorage storage, YTrack track,
+ HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead)
+ {
+ return ExtractStreamAsync(storage, track.GetKey().ToString(), httpCompletionOption);
+ }
+
+ #endregion В поток
+
+ #endregion Получение данных трека
+
+
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YTrackAPIAsync.cs b/YandexMusic.API/API/YTrackAPIAsync.cs
deleted file mode 100644
index 555465c..0000000
--- a/YandexMusic.API/API/YTrackAPIAsync.cs
+++ /dev/null
@@ -1,308 +0,0 @@
-using System.Security.Cryptography;
-using System.Text;
-
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Track;
-using YandexMusic.API.Requests.Track;
-
-namespace YandexMusic.API
-{
- ///
- /// API для взаимодействия с треками
- ///
- public partial class YTrackAPI : YCommonAPI
- {
- #region Вспомогательные функции
-
- private string BuildLinkForDownload(YTrackDownloadInfo mainDownloadResponse, YStorageDownloadFile storageDownload)
- {
- string path = storageDownload.Path;
- string host = storageDownload.Host;
- string ts = storageDownload.Ts;
- string s = storageDownload.S;
- string codec = mainDownloadResponse.Codec;
-
- string secret = $"XGRlBW9FXlekgbPrRHuSiA{path.Substring(1, path.Length - 1)}{s}";
- MD5 md5 = MD5.Create();
- byte[] md5Hash = md5.ComputeHash(Encoding.UTF8.GetBytes(secret));
- HMACSHA1 hmacsha1 = new();
- byte[] hmasha1Hash = hmacsha1.ComputeHash(md5Hash);
- string sign = BitConverter.ToString(hmasha1Hash).Replace("-", "").ToLower();
-
- string link = $"https://{host}/get-{codec}/{sign}/{ts}{path}";
-
- return link;
- }
-
- #endregion Вспомогательные функции
-
-
-
- public YTrackAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Получение треков
- ///
- /// Хранилище
- /// Идентификатор трека
- ///
- public Task>> GetAsync(AuthStorage storage, string trackId)
- {
- return new YGetTracksBuilder(api, storage)
- .Build(new[] { trackId })
- .GetResponseAsync();
- }
-
- ///
- /// Получение треков
- ///
- /// Хранилище
- /// Идентификаторы треков
- ///
- public Task>> GetAsync(AuthStorage storage, IEnumerable trackIds)
- {
- return new YGetTracksBuilder(api, storage)
- .Build(trackIds)
- .GetResponseAsync();
- }
-
- ///
- /// Получение метаданных для загрузки
- ///
- /// Хранилище
- /// Ключ трека в формате {идентифактор трека:идентификатор альбома}
- /// Должен ли ответ содержать прямую ссылку на загрузку
- ///
- public Task>> GetMetadataForDownloadAsync(AuthStorage storage, string trackKey, bool direct = false)
- {
- return new YTrackDownloadInfoBuilder(api, storage)
- .Build((trackKey, direct))
- .GetResponseAsync();
- }
-
- ///
- /// Получение метаданных для загрузки
- ///
- /// Хранилище
- /// Трек
- /// Должен ли ответ содержать прямую ссылку на загрузку
- ///
- public Task>> GetMetadataForDownloadAsync(AuthStorage storage, YTrack track, bool direct = false)
- {
- return GetMetadataForDownloadAsync(storage, track.GetKey().ToString(), direct);
- }
-
- ///
- /// Получение информации для формирования ссылки для загрузки
- ///
- /// Хранилище
- /// Метаданные для загрузки
- ///
- public Task GetDownloadFileInfoAsync(AuthStorage storage, YTrackDownloadInfo metadataInfo)
- {
- return new YStorageDownloadFileBuilder(api, storage)
- .Build(metadataInfo.DownloadInfoUrl)
- .GetResponseAsync();
- }
-
- ///
- /// Получение ссылки для загрузки
- ///
- /// Хранилище
- /// Ключ трека в формате {идентификатор трека:идентификатор альбома}
- ///
- public async Task GetFileLinkAsync(AuthStorage storage, string trackKey)
- {
- YResponse> meta = await GetMetadataForDownloadAsync(storage, trackKey);
- YTrackDownloadInfo info = meta.Result
- .OrderByDescending(i => i.BitrateInKbps)
- .First(m => m.Codec == "mp3");
- YStorageDownloadFile storageDownload = await GetDownloadFileInfoAsync(storage, info);
- return BuildLinkForDownload(info, storageDownload);
- }
-
- ///
- /// Получение ссылки для загрузки
- ///
- /// Хранилище
- /// Трек
- ///
- public Task GetFileLinkAsync(AuthStorage storage, YTrack track)
- {
- return GetFileLinkAsync(storage, track.GetKey().ToString());
- }
-
- ///
- /// Отправка текущего состояния прослушиваемого трека
- /// Хранилище
- /// Трек
- /// Наименования клиента, с которого происходит прослушивание
- /// Проигрывается ли трек с кеша
- /// Уникальный идентификатор проигрывания
- /// Уникальный идентификатор плейлиста, если таковой прослушивается
- /// Сколько было всего воспроизведено трека в секундах
- /// Окончательное значение воспроизведенных секунд
- ///
- ///
- public Task SendPlayTrackInfoAsync(AuthStorage storage, YTrack track, string from, bool fromCache = false, string playId = "", string playlistId = "", double totalPlayedSeconds = 0, double endPositionSeconds = 0)
- {
- return new YSendTrackInfoBuilder(api, storage)
- .Build((track, from, fromCache, playId, playlistId, totalPlayedSeconds, endPositionSeconds))
- .GetResponseAsync();
- }
-
- #region GetSupplement
-
- ///
- /// Получение дополнительной информации для трека
- ///
- /// Хранилище
- /// Идентификатор трека
- ///
- public Task> GetSupplementAsync(AuthStorage storage, string trackId)
- {
- return new YGetTrackSupplementBuilder(api, storage)
- .Build(trackId)
- .GetResponseAsync();
- }
-
- ///
- /// Получение дополнительной информации для трека
- ///
- /// Хранилище
- /// Трек
- ///
- public Task> GetSupplementAsync(AuthStorage storage, YTrack track)
- {
- return new YGetTrackSupplementBuilder(api, storage)
- .Build(track.GetKey().ToString())
- .GetResponseAsync();
- }
-
- #endregion GetSupplement
-
- #region GetSimilar
-
- ///
- /// Получение похожих треков
- ///
- /// Хранилище
- /// Идентификатор трека
- ///
- public Task> GetSimilarAsync(AuthStorage storage, string trackId)
- {
- return new YGetTrackSimilarBuilder(api, storage)
- .Build(trackId)
- .GetResponseAsync();
- }
-
- ///
- /// Получение похожих треков
- ///
- /// Хранилище
- /// Трек
- ///
- public Task> GetSimilarAsync(AuthStorage storage, YTrack track)
- {
- return new YGetTrackSimilarBuilder(api, storage)
- .Build(track.GetKey().ToString())
- .GetResponseAsync();
- }
-
- #endregion GetSimilar
-
- #region Получение данных трека
-
- #region В файл
-
- ///
- /// Выгрузка в файл
- ///
- /// Хранилище
- /// Ключ трека в формате {идентификатор трека:идентификатор альбома}
- /// Путь для файла
- public async Task ExtractToFileAsync(AuthStorage storage, string trackKey, string filePath)
- {
- string url = await GetFileLinkAsync(storage, trackKey);
- await new DataDownloader(storage).ToFile(url, filePath);
- }
-
- ///
- /// Выгрузка в файл
- ///
- /// Хранилище
- /// Трек
- /// Путь для файла
- public Task ExtractToFileAsync(AuthStorage storage, YTrack track, string filePath)
- {
- return ExtractToFileAsync(storage, track.GetKey().ToString(), filePath);
- }
-
- #endregion В файл
-
- #region В массив байт
-
- ///
- /// Получение двоичного массива данных
- ///
- /// Хранилище
- /// Ключ трека в формате {идентификатор трека:идентификатор альбома}
- ///
- public async Task ExtractDataAsync(AuthStorage storage, string trackKey)
- {
- string url = await GetFileLinkAsync(storage, trackKey);
- return await new DataDownloader(storage).AsBytes(url);
- }
-
- ///
- /// Получение двоичного массива данных
- ///
- /// Хранилище
- /// Трек
- ///
- public Task ExtractDataAsync(AuthStorage storage, YTrack track)
- {
- return ExtractDataAsync(storage, track.GetKey().ToString());
- }
-
- #endregion В массив байт
-
- #region В поток
-
- ///
- /// Получение потока данных
- ///
- /// Хранилище
- /// Ключ трека в формате {идентификатор трека:идентификатор альбома}
- /// Параметры передачи управления при http запросе
- ///
- public async Task ExtractStreamAsync(AuthStorage storage, string trackKey,
- HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead)
- {
- string url = await GetFileLinkAsync(storage, trackKey);
- return await new DataDownloader(storage).AsStream(url, httpCompletionOption);
- }
-
- ///
- /// Получение потока данных
- ///
- /// Хранилище
- /// Трек
- /// Параметры передачи управления при http запросе
- ///
- public Task ExtractStreamAsync(AuthStorage storage, YTrack track,
- HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead)
- {
- return ExtractStreamAsync(storage, track.GetKey().ToString(), httpCompletionOption);
- }
-
- #endregion В поток
-
- #endregion Получение данных трека
-
-
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YUgcAPI.cs b/YandexMusic.API/API/YUgcAPI.cs
new file mode 100644
index 0000000..bc6536c
--- /dev/null
+++ b/YandexMusic.API/API/YUgcAPI.cs
@@ -0,0 +1,71 @@
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Models.Playlist;
+using YandexMusic.API.Models.Ugc;
+using YandexMusic.API.Requests.Ugc;
+
+namespace YandexMusic.API;
+
+public partial class YUgcAPI : YCommonAPI
+{
+ public YUgcAPI(YandexMusicApi yandex) : base(yandex)
+ {
+ }
+
+ ///
+ /// Получение ссылки на загрузчик трека
+ ///
+ /// Хранилище
+ /// Плейлист, куда будет загружен трек
+ /// Название файла для загрузки
+ public Task GetUgcUploadLinkAsync(AuthStorage storage, YPlaylist playlist, string fileName)
+ {
+ return new YUgcGetUploadLinkBuilder(api, storage)
+ .Build((playlist, fileName))
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Загрузка трека из файла
+ ///
+ /// Хранилище
+ /// Ссылка на балансировщик для загрузки, можно получить из GetUgcUploadLinkAsync
+ /// Загружаемый файл
+ public Task> UploadUgcTrackAsync(AuthStorage storage, string uploadLink, string filePath)
+ {
+ if (!File.Exists(filePath))
+ throw new FileNotFoundException("Файл для загрузки не существует.", filePath);
+
+ return UploadUgcTrackAsync(storage, uploadLink, File.Open(filePath, FileMode.Open));
+ }
+
+ ///
+ /// Загрузка трека из потока
+ ///
+ /// Хранилище
+ /// Ссылка на балансировщик для загрузки, можно получить из GetUgcUploadLinkAsync
+ /// Поток с данными для загрузки
+ public Task> UploadUgcTrackAsync(AuthStorage storage, string uploadLink, Stream stream)
+ {
+ if (stream == null)
+ throw new NullReferenceException("Пустая ссылка на поток загрузки.");
+
+ using MemoryStream ms = new();
+ stream.CopyTo(ms);
+
+ return UploadUgcTrackAsync(storage, uploadLink, ms.ToArray());
+ }
+
+ ///
+ /// Загрузка трека из массива
+ ///
+ /// Хранилище
+ /// Ссылка на балансировщик для загрузки, можно получить из GetUgcUploadLinkAsync
+ /// Загружаемый трек в виде массив байтов
+ public Task> UploadUgcTrackAsync(AuthStorage storage, string uploadLink, byte[] file)
+ {
+ return new YUgcUploadBuilder(api, storage)
+ .Build((uploadLink, file))
+ .GetResponseAsync();
+ }
+}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YUgcAPIAsync.cs b/YandexMusic.API/API/YUgcAPIAsync.cs
deleted file mode 100644
index 9316b28..0000000
--- a/YandexMusic.API/API/YUgcAPIAsync.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Models.Playlist;
-using YandexMusic.API.Models.Ugc;
-using YandexMusic.API.Requests.Ugc;
-
-namespace YandexMusic.API
-{
- public partial class YUgcAPI : YCommonAPI
- {
- public YUgcAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Получение ссылки на загрузчик трека
- ///
- /// Хранилище
- /// Плейлист, куда будет загружен трек
- /// Название файла для загрузки
- public Task GetUgcUploadLinkAsync(AuthStorage storage, YPlaylist playlist, string fileName)
- {
- return new YUgcGetUploadLinkBuilder(api, storage)
- .Build((playlist, fileName))
- .GetResponseAsync();
- }
-
- ///
- /// Загрузка трека из файла
- ///
- /// Хранилище
- /// Ссылка на балансировщик для загрузки, можно получить из GetUgcUploadLinkAsync
- /// Загружаемый файл
- public Task> UploadUgcTrackAsync(AuthStorage storage, string uploadLink, string filePath)
- {
- if (!File.Exists(filePath))
- throw new FileNotFoundException("Файл для загрузки не существует.", filePath);
-
- return UploadUgcTrackAsync(storage, uploadLink, File.Open(filePath, FileMode.Open));
- }
-
- ///
- /// Загрузка трека из потока
- ///
- /// Хранилище
- /// Ссылка на балансировщик для загрузки, можно получить из GetUgcUploadLinkAsync
- /// Поток с данными для загрузки
- public Task> UploadUgcTrackAsync(AuthStorage storage, string uploadLink, Stream stream)
- {
- if (stream == null)
- throw new NullReferenceException("Пустая ссылка на поток загрузки.");
-
- using MemoryStream ms = new();
- stream.CopyTo(ms);
-
- return UploadUgcTrackAsync(storage, uploadLink, ms.ToArray());
- }
-
- ///
- /// Загрузка трека из массива
- ///
- /// Хранилище
- /// Ссылка на балансировщик для загрузки, можно получить из GetUgcUploadLinkAsync
- /// Загружаемый трек в виде массив байтов
- public Task> UploadUgcTrackAsync(AuthStorage storage, string uploadLink, byte[] file)
- {
- return new YUgcUploadBuilder(api, storage)
- .Build((uploadLink, file))
- .GetResponseAsync();
- }
- }
-}
\ No newline at end of file
diff --git a/YandexMusic.API/API/YUserAPI.cs b/YandexMusic.API/API/YUserAPI.cs
new file mode 100644
index 0000000..d66d638
--- /dev/null
+++ b/YandexMusic.API/API/YUserAPI.cs
@@ -0,0 +1,300 @@
+using System.Security.Authentication;
+using System.Text.RegularExpressions;
+
+using YandexMusic.API.Common;
+using YandexMusic.API.Models.Account;
+using YandexMusic.API.Models.Common;
+using YandexMusic.API.Requests.Account;
+
+namespace YandexMusic.API;
+
+///
+/// API для пользователя
+///
+public partial class YUserAPI : YCommonAPI
+{
+ #region Вспомогательные функции
+
+ private async Task GetCsrfTokenAsync(AuthStorage storage)
+ {
+ using HttpResponseMessage authMethodsResponse = await new YGetAuthMethodsBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+
+ if (!authMethodsResponse.IsSuccessStatusCode)
+ throw new HttpRequestException("Невозможно получить CFRF-токен.");
+
+ string responseString = await authMethodsResponse.Content
+ .ReadAsStringAsync();
+ Match match = Regex.Match(responseString, "\"csrf_token\" value=\"([^\"]+)\"");
+
+ if (!match.Success || match.Groups.Count < 2)
+ return false;
+
+ storage.AuthToken = new YAuthToken
+ {
+ CsfrToken = match.Groups[1].Value
+ };
+
+ return true;
+ }
+
+ private async Task LoginByCookiesAsync(AuthStorage storage)
+ {
+ if (storage.AuthToken == null)
+ throw new AuthenticationException("Невозможно инициализировать сессию входа.");
+
+ YAccessToken accessToken = await new YGetAuthCookiesBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+
+ storage.IsAuthorized = !string.IsNullOrEmpty(accessToken.AccessToken);
+
+ storage.AccessToken = accessToken;
+ storage.Token = accessToken.AccessToken;
+
+ YShortAccountInfo validateTokenResponse = await new YGetShortAccountInifoBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+
+ if (validateTokenResponse.Status != YAuthStatus.Ok)
+ throw new Exception("Вход в аккаунт не выполнен.");
+
+ storage.IsAuthorized = !string.IsNullOrWhiteSpace(validateTokenResponse.Uid);
+
+ return storage.IsAuthorized;
+ }
+
+ #endregion Вспомогательные функции
+
+ public YUserAPI(YandexMusicApi yandex) : base(yandex)
+ {
+ }
+
+ ///
+ /// Авторизация
+ ///
+ /// Хранилище
+ /// Токен авторизации
+ ///
+ public async Task AuthorizeAsync(AuthStorage storage, string token)
+ {
+ if (string.IsNullOrEmpty(token))
+ throw new Exception("Задан пустой токен авторизации.");
+
+ storage.Token = token;
+
+ // Пытаемся получить информацию о пользователе
+ YResponse authInfo = await GetUserAuthAsync(storage);
+
+ // Если не авторизован, то авторизуем
+ if (string.IsNullOrEmpty(authInfo.Result.Account.Uid))
+ throw new Exception("Пользователь незалогинен.");
+
+ // Флаг авторизации
+ storage.IsAuthorized = true;
+ storage.User = authInfo.Result.Account;
+ }
+
+ ///
+ /// Получение информации об авторизации
+ ///
+ /// Хранилище
+ ///
+ public Task> GetUserAuthAsync(AuthStorage storage)
+ {
+ return new YGetAuthInfoBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Создание сеанса и получение доступных методов авторизации
+ ///
+ /// Хранилище
+ /// Имя пользователя
+ ///
+ public async Task CreateAuthSessionAsync(AuthStorage storage, string userName)
+ {
+ if (!await GetCsrfTokenAsync(storage))
+ throw new Exception("Невозможно инициализировать сессию входа.");
+
+ YAuthTypes types = await new YGetAuthLoginUserBuilder(api, storage)
+ .Build((storage.AuthToken.CsfrToken, userName))
+ .GetResponseAsync();
+
+ storage.AuthToken.TrackId = types.TrackId;
+
+ return types;
+ }
+
+ ///
+ /// Получение ссылки на QR-код
+ ///
+ /// Хранилище
+ ///
+ public async Task GetAuthQRLinkAsync(AuthStorage storage)
+ {
+ if (!await GetCsrfTokenAsync(storage))
+ throw new Exception("Невозможно инициализировать сессию входа.");
+
+ YAuthQR result = await new YGetAuthQRBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+
+ if (result.Status != YAuthStatus.Ok)
+ return string.Empty;
+
+ storage.AuthToken = new YAuthToken
+ {
+ TrackId = result.TrackId,
+ CsfrToken = result.CsrfToken
+ };
+
+ return $"https://passport.yandex.ru/auth/magic/code/?track_id={result.TrackId}";
+ }
+
+ ///
+ /// Авторизация по QR-коду
+ ///
+ /// Хранилище
+ ///
+ public async Task AuthorizeByQRAsync(AuthStorage storage)
+ {
+ if (storage.AuthToken == null)
+ throw new Exception("Не выполнен запрос на авторизацию по QR.");
+
+ try
+ {
+ YAuthQRStatus qrStatus = await new YGetAuthLoginQRBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+ if (qrStatus.Status != YAuthStatus.Ok)
+ return qrStatus;
+
+ bool ok = await LoginByCookiesAsync(storage);
+ if (!ok)
+ throw new AuthenticationException("Ошибка авторизации по QR.");
+
+ return qrStatus;
+ }
+ catch (Exception ex)
+ {
+ throw new AuthenticationException("Ошибка авторизации по QR.", ex);
+ }
+ }
+
+ ///
+ /// Получение
+ ///
+ /// Хранилище
+ ///
+ public Task GetCaptchaAsync(AuthStorage storage)
+ {
+ if (storage.AuthToken == null || string.IsNullOrWhiteSpace(storage.AuthToken.CsfrToken))
+ throw new AuthenticationException($"Не найдена сессия входа. Выполните {nameof(CreateAuthSessionAsync)} перед использованием.");
+
+ return new YGetAuthCaptchaBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Авторизация по captcha
+ ///
+ /// Хранилище
+ /// Значение captcha
+ ///
+ public Task AuthorizeByCaptchaAsync(AuthStorage storage, string captchaValue)
+ {
+ if (storage.AuthToken == null || string.IsNullOrWhiteSpace(storage.AuthToken.CsfrToken))
+ throw new AuthenticationException($"Не найдена сессия входа. Выполните {nameof(CreateAuthSessionAsync)} перед использованием.");
+
+ return new YGetAuthLoginCaptchaBuilder(api, storage)
+ .Build(captchaValue)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Получение письма авторизации на почту пользователя
+ ///
+ /// Хранилище
+ ///
+ public Task GetAuthLetterAsync(AuthStorage storage)
+ {
+ return new YGetAuthLetterBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+ }
+
+ ///
+ /// Авторизация после подтверждения входа через письмо
+ ///
+ /// Хранилище
+ ///
+ public async Task AuthorizeByLetterAsync(AuthStorage storage)
+ {
+ YAuthLetterStatus status = await new YGetAuthLoginLetterBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+
+ if (status.Status == YAuthStatus.Ok && !status.MagicLinkConfirmed)
+ throw new Exception("Не подтвержден вход посредством e-mail.");
+
+ return await LoginByCookiesAsync(storage);
+ }
+
+ ///
+ /// Авторизация с помощью пароля из приложения Яндекс
+ ///
+ /// Хранилище
+ /// Пароль
+ ///
+ public async Task AuthorizeByAppPasswordAsync(AuthStorage storage, string password)
+ {
+ if (storage.AuthToken == null || string.IsNullOrWhiteSpace(storage.AuthToken.CsfrToken))
+ throw new AuthenticationException($"Не найдена сессия входа. Выполните {nameof(CreateAuthSessionAsync)} перед использованием.");
+
+ YAuthBase response = await new YGetAuthAppPasswordBuilder(api, storage)
+ .Build(password)
+ .GetResponseAsync();
+
+ if (response.Status == YAuthStatus.Ok)
+ {
+ bool ok = await LoginByCookiesAsync(storage);
+ if (!ok)
+ throw new AuthenticationException("Ошибка авторизации.");
+ }
+
+ return response;
+ }
+
+ ///
+ /// Получение после авторизации с помощью QR, e-mail, пароля из приложения
+ ///
+ public async Task GetAccessTokenAsync(AuthStorage storage)
+ {
+ if (storage.AuthToken == null)
+ throw new Exception("Не найдена сессия входа.");
+
+ YAccessToken accessToken = await new YGetMusicTokenBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+
+ storage.Token = accessToken.AccessToken;
+
+ return accessToken;
+ }
+
+ ///
+ /// Получение информации о пользователе через логин Яндекса
+ ///
+ public Task GetLoginInfoAsync(AuthStorage storage)
+ {
+ return new YGetLoginInfoBuilder(api, storage)
+ .Build(null)
+ .GetResponseAsync();
+ }
+
+
+}
diff --git a/YandexMusic.API/API/YUserAPIAsync.cs b/YandexMusic.API/API/YUserAPIAsync.cs
deleted file mode 100644
index 0c84ffa..0000000
--- a/YandexMusic.API/API/YUserAPIAsync.cs
+++ /dev/null
@@ -1,303 +0,0 @@
-using System.Security.Authentication;
-using System.Text.RegularExpressions;
-
-using YandexMusic.API.Common;
-using YandexMusic.API.Models.Account;
-using YandexMusic.API.Models.Common;
-using YandexMusic.API.Requests.Account;
-
-namespace YandexMusic.API
-{
- ///
- /// API для пользователя
- ///
- public partial class YUserAPI : YCommonAPI
- {
- #region Вспомогательные функции
-
- private async Task GetCsrfTokenAsync(AuthStorage storage)
- {
- using HttpResponseMessage authMethodsResponse = await new YGetAuthMethodsBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
-
- if (!authMethodsResponse.IsSuccessStatusCode)
- throw new HttpRequestException("Невозможно получить CFRF-токен.");
-
- string responseString = await authMethodsResponse.Content
- .ReadAsStringAsync();
- Match match = Regex.Match(responseString, "\"csrf_token\" value=\"([^\"]+)\"");
-
- if (!match.Success || match.Groups.Count < 2)
- return false;
-
- storage.AuthToken = new YAuthToken
- {
- CsfrToken = match.Groups[1].Value
- };
-
- return true;
- }
-
- private async Task LoginByCookiesAsync(AuthStorage storage)
- {
- if (storage.AuthToken == null)
- throw new AuthenticationException("Невозможно инициализировать сессию входа.");
-
- YAccessToken accessToken = await new YGetAuthCookiesBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
-
- storage.IsAuthorized = !string.IsNullOrEmpty(accessToken.AccessToken);
-
- storage.AccessToken = accessToken;
- storage.Token = accessToken.AccessToken;
-
- YShortAccountInfo validateTokenResponse = await new YGetShortAccountInifoBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
-
- if (validateTokenResponse.Status != YAuthStatus.Ok)
- throw new Exception("Вход в аккаунт не выполнен.");
-
- storage.IsAuthorized = !string.IsNullOrWhiteSpace(validateTokenResponse.Uid);
-
- return storage.IsAuthorized;
- }
-
- #endregion Вспомогательные функции
-
-
-
- public YUserAPI(YandexMusicApi yandex) : base(yandex)
- {
- }
-
- ///
- /// Авторизация
- ///
- /// Хранилище
- /// Токен авторизации
- ///
- public async Task AuthorizeAsync(AuthStorage storage, string token)
- {
- if (string.IsNullOrEmpty(token))
- throw new Exception("Задан пустой токен авторизации.");
-
- storage.Token = token;
-
- // Пытаемся получить информацию о пользователе
- YResponse authInfo = await GetUserAuthAsync(storage);
-
- // Если не авторизован, то авторизуем
- if (string.IsNullOrEmpty(authInfo.Result.Account.Uid))
- throw new Exception("Пользователь незалогинен.");
-
- // Флаг авторизации
- storage.IsAuthorized = true;
- storage.User = authInfo.Result.Account;
- }
-
- ///
- /// Получение информации об авторизации
- ///
- /// Хранилище
- ///
- public Task> GetUserAuthAsync(AuthStorage storage)
- {
- return new YGetAuthInfoBuilder(api, storage)
- .Build(null)
- .GetResponseAsync();
- }
-
- ///
- /// Создание сеанса и получение доступных методов авторизации
- ///
- /// Хранилище
- /// Имя пользователя
- ///
- public async Task CreateAuthSessionAsync(AuthStorage storage, string userName)
- {
- if (!await GetCsrfTokenAsync(storage))
- throw new Exception("Невозможно инициализировать сессию входа.");
-
- YAuthTypes types = await new YGetAuthLoginUserBuilder(api, storage)
- .Build((storage.AuthToken.CsfrToken, userName))
- .GetResponseAsync();
-
- storage.AuthToken.TrackId = types.TrackId;
-
- return types;
- }
-
- ///