diff --git a/PlaylistShared.Api/Controllers/AudioController.cs b/PlaylistShared.Api/Controllers/AudioController.cs index 2530bdf..d732323 100644 --- a/PlaylistShared.Api/Controllers/AudioController.cs +++ b/PlaylistShared.Api/Controllers/AudioController.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc; using PlaylistShared.Api.Entities; using PlaylistShared.Api.Services; using PlaylistShared.Shared; -using PlaylistShared.Shared.DTO; +using PlaylistShared.Shared.Yandex; using System.Security.Claims; namespace PlaylistShared.Api.Controllers; diff --git a/PlaylistShared.Api/Controllers/PlaylistsController.cs b/PlaylistShared.Api/Controllers/PlaylistsController.cs index 91d8734..9b74e49 100644 --- a/PlaylistShared.Api/Controllers/PlaylistsController.cs +++ b/PlaylistShared.Api/Controllers/PlaylistsController.cs @@ -6,7 +6,7 @@ using PlaylistShared.Api.Extensions; using PlaylistShared.Api.Services; using PlaylistShared.Shared; using PlaylistShared.Shared.Enums; -using PlaylistShared.Shared.Playlist; +using PlaylistShared.Shared.Yandex; using PlaylistShared.Shared.SharedPlaylist; using YandexMusic; @@ -32,7 +32,7 @@ public class PlaylistsController : ControllerBase } [HttpGet] - public async Task>>> GetMyPlaylists() + public async Task>>> GetMyPlaylists() { var userId = User.GetUserId(); var user = await _userManager.FindByIdAsync(userId.ToString()); @@ -52,7 +52,7 @@ public class PlaylistsController : ControllerBase var sharedPlaylists = await _sharedService.GetAllByUserAsync(userId); - var result = ownPlaylists.Select(p => new YandexPlaylistInfo + var result = ownPlaylists.Select(p => new YandexPlaylistShare { Kind = p.Kind, OwnerUid = p.Owner.Uid, @@ -63,7 +63,7 @@ public class PlaylistsController : ControllerBase ShareToken = sharedPlaylists.FirstOrDefault(s => s.YandexPlaylistKind == p.Kind && s.YandexPlaylistOwnerUid == p.Owner.Uid)?.ShareToken, }).ToList(); - return Ok(ApiResponse>.Ok(result)); + return Ok(ApiResponse>.Ok(result)); } [HttpPost("share")] diff --git a/PlaylistShared.Api/Controllers/SharedPlaylistController.cs b/PlaylistShared.Api/Controllers/SharedPlaylistController.cs index a48c311..0ea2ac6 100644 --- a/PlaylistShared.Api/Controllers/SharedPlaylistController.cs +++ b/PlaylistShared.Api/Controllers/SharedPlaylistController.cs @@ -5,8 +5,8 @@ using PlaylistShared.Api.Entities; using PlaylistShared.Api.Extensions; using PlaylistShared.Api.Services; using PlaylistShared.Shared; -using PlaylistShared.Shared.DTO; using PlaylistShared.Shared.SharedPlaylist; +using PlaylistShared.Shared.Yandex; using YandexMusic.API.Models.Playlist; [ApiController] diff --git a/PlaylistShared.Api/Controllers/YandexSearchController.cs b/PlaylistShared.Api/Controllers/YandexSearchController.cs index 32ce438..bd6a162 100644 --- a/PlaylistShared.Api/Controllers/YandexSearchController.cs +++ b/PlaylistShared.Api/Controllers/YandexSearchController.cs @@ -5,8 +5,8 @@ using PlaylistShared.Api.Entities; using PlaylistShared.Api.Extensions; using PlaylistShared.Api.Services; using PlaylistShared.Shared; -using PlaylistShared.Shared.DTO; using PlaylistShared.Shared.Enums; +using PlaylistShared.Shared.Yandex; namespace PlaylistShared.Api.Controllers; @@ -26,8 +26,8 @@ public class YandexSearchController : ControllerBase _sharedPlaylistService = sharedPlaylistService; } - [HttpGet("tracks")] - public async Task>>> SearchQuery( + [HttpGet("search")] + public async Task>> SearchQuery( [FromQuery] string query, [FromQuery] int limit = 20, [FromQuery] TrackSearchType? searchType = TrackSearchType.All, @@ -35,7 +35,7 @@ public class YandexSearchController : ControllerBase [FromQuery] string? shared_id = null) { if (string.IsNullOrWhiteSpace(query)) - return BadRequest(ApiResponse>.Fail(new ErrorResponse + return BadRequest(ApiResponse.Fail(new ErrorResponse { StatusCode = 400, Message = "Поисковый запрос не может быть пустым." @@ -65,13 +65,13 @@ public class YandexSearchController : ControllerBase var decryptedToken = _yandexService.DecryptToken(user.YandexAccessToken); if (string.IsNullOrEmpty(decryptedToken)) - return BadRequest(ApiResponse>.Fail(new ErrorResponse + return BadRequest(ApiResponse.Fail(new ErrorResponse { StatusCode = 400, Message = "Токен Яндекс.Музыки не установлен или недействителен." })); - List? results = null; + YandexSearchResult? results = null; if (byId) { @@ -79,7 +79,7 @@ public class YandexSearchController : ControllerBase } else { - results = await _yandexService.SearchTracksAsync(user, query, searchType, limit); + results = await _yandexService.SearchAsync(user, query, searchType, limit); } return Ok(ApiResponse>.Ok(results)); diff --git a/PlaylistShared.Api/Extensions/YCoverExtensions.cs b/PlaylistShared.Api/Extensions/YCoverExtensions.cs index c4f350f..7ef55eb 100644 --- a/PlaylistShared.Api/Extensions/YCoverExtensions.cs +++ b/PlaylistShared.Api/Extensions/YCoverExtensions.cs @@ -4,14 +4,16 @@ namespace PlaylistShared.Api.Extensions; public static class YCoverExtensions { - public static string GetUrl(this YCover cover, string size = "200x200") + public static string GetUrl(this YCover cover) { switch (cover) { case YCoverImage img when !string.IsNullOrEmpty(img.Uri): - return $"https://{img.Uri.Replace("%%", size)}"; + return img.Uri; case YCoverPic pic when !string.IsNullOrEmpty(pic.Uri): - return $"https://{pic.Uri.Replace("%%", size)}"; + return pic.Uri; + case YCoverMosaic mosaic when mosaic.ItemsUri.Any(): + return mosaic.ItemsUri.First(); default: return string.Empty; } diff --git a/PlaylistShared.Api/Services/SharedPlaylistService.cs b/PlaylistShared.Api/Services/SharedPlaylistService.cs index dba6c5c..9abb907 100644 --- a/PlaylistShared.Api/Services/SharedPlaylistService.cs +++ b/PlaylistShared.Api/Services/SharedPlaylistService.cs @@ -3,7 +3,6 @@ using PlaylistShared.Api.Data; using PlaylistShared.Api.Entities; using PlaylistShared.Shared.Auth; using PlaylistShared.Shared.Enums; -using PlaylistShared.Shared.Playlist; using PlaylistShared.Shared.SharedPlaylist; namespace PlaylistShared.Api.Services; diff --git a/PlaylistShared.Api/Services/YandexMusicService.cs b/PlaylistShared.Api/Services/YandexMusicService.cs index 42ef1eb..7b901c8 100644 --- a/PlaylistShared.Api/Services/YandexMusicService.cs +++ b/PlaylistShared.Api/Services/YandexMusicService.cs @@ -1,7 +1,8 @@ using Microsoft.AspNetCore.DataProtection; using PlaylistShared.Api.Entities; -using PlaylistShared.Shared.DTO; +using PlaylistShared.Api.Extensions; using PlaylistShared.Shared.Enums; +using PlaylistShared.Shared.Yandex; using YandexMusic; using YandexMusic.API.Extensions.API; using YandexMusic.API.Models.Playlist; @@ -108,7 +109,7 @@ public class YandexMusicService } } - public async Task> SearchTracksAsync( + public async Task SearchAsync( ApplicationUser user, string query, TrackSearchType? searchType = TrackSearchType.All, @@ -116,7 +117,7 @@ public class YandexMusicService ) { var client = await CreateClientAsync(user); - if (client == null) return new List(); + if (client == null) return new YandexSearchResult(); var ySerchType = searchType switch { @@ -128,19 +129,56 @@ public class YandexMusicService }; var searchResult = await client.SearchAsync(query, ySerchType, page: 0, pageSize: limit); - if (searchResult?.Tracks?.Results == null) return new List(); + if (searchResult?.Tracks?.Results == null) return new YandexSearchResult(); - return searchResult.Tracks.Results.Select(t => new YandexTrack + return new YandexSearchResult { - TrackId = t.Id, - Title = t.Title, - Artists = t.Artists?.Select(a => a.Name).ToList() ?? new List(), - CoverUri = t.CoverUri ?? string.Empty, - DurationMs = t.DurationMs, - }).ToList(); + Tracks = searchResult.Tracks.Results.Select(t => new YandexTrack + { + TrackId = t.Id, + Title = t.Title, + Artists = t.Artists?.Select(a => a.Name).ToList() ?? new List(), + CoverUri = t.CoverUri, + DurationMs = t.DurationMs, + }).ToList(), + + Playlists = searchResult.Playlists?.Results.Select(p => new YandexPlaylist + { + Uuid = p.PlaylistUuid, + Kind = p.Kind, + OwnerUid = p.Owner?.Uid ?? string.Empty, + Title = p.Title, + Description = p.Description, + CoverUrl = p.CoverUri, + TrackCount = p.TrackCount, + }).ToList(), + + Artists = searchResult.Artists?.Results.Select(a => new YandexArtist + { + Id = a.Id, + Name = a.Name, + CoverUrl = a.Cover.GetUrl(), + Description = a.Description.Text, + }).ToList(), + + Albums = searchResult.Albums?.Results.Select(a => new YandexAlbum + { + Id = a.Id, + Title = a.Title, + Artists = a.Artists.Select(t => new YandexArtist() + { + Id = t.Id, + Name = t.Name, + CoverUrl = t.Cover.GetUrl(), + Description = t.Description.Text, + }).ToList(), + CoverUrl = string.IsNullOrEmpty(a.CoverUri) ? a.Cover.GetUrl() : a.CoverUri, + Description = a.Description, + }).ToList(), + }; } - public async Task> SearchTracksByIdAsync( + public async Task SearchTracksByIdAsync( ApplicationUser user, string id, TrackSearchType searchType, @@ -148,7 +186,7 @@ public class YandexMusicService ) { var client = await CreateClientAsync(user); - if (client == null) return new List(); + if (client == null) return new YandexSearchResult(); var ySerchType = searchType switch { @@ -174,13 +212,16 @@ public class YandexMusicService if (limit > 0) searchResult = searchResult.Take(limit); } - return searchResult.Select(t => new YandexTrack + return new YandexSearchResult() { - TrackId = t.Id, - Title = t.Title, - Artists = t.Artists?.Select(a => a.Name).ToList() ?? new List(), - CoverUri = t.CoverUri ?? string.Empty, - DurationMs = t.DurationMs, - }).ToList(); + Tracks = searchResult.Select(t => new YandexTrack + { + TrackId = t.Id, + Title = t.Title, + Artists = t.Artists?.Select(a => a.Name).ToList() ?? new List(), + CoverUri = t.CoverUri ?? string.Empty, + DurationMs = t.DurationMs, + }).ToList(), + }; } } \ No newline at end of file diff --git a/PlaylistShared.Pwa/Components/SharedPlaylist/AddTrackSection.razor b/PlaylistShared.Pwa/Components/SharedPlaylist/AddTrackSection.razor index c5c2248..58bc434 100644 --- a/PlaylistShared.Pwa/Components/SharedPlaylist/AddTrackSection.razor +++ b/PlaylistShared.Pwa/Components/SharedPlaylist/AddTrackSection.razor @@ -2,6 +2,7 @@ @using PlaylistShared.Shared.DTO @using PlaylistShared.Shared.Enums @using PlaylistShared.Shared.SharedPlaylist +@using PlaylistShared.Shared.Yandex @inject HttpClient Http @inject ISnackbar Snackbar diff --git a/PlaylistShared.Pwa/Services/Api/SharedPlaylistClient.cs b/PlaylistShared.Pwa/Services/Api/SharedPlaylistClient.cs index 2d571ef..367a03f 100644 --- a/PlaylistShared.Pwa/Services/Api/SharedPlaylistClient.cs +++ b/PlaylistShared.Pwa/Services/Api/SharedPlaylistClient.cs @@ -1,5 +1,6 @@ using PlaylistShared.Shared; using PlaylistShared.Shared.SharedPlaylist; +using PlaylistShared.Shared.Yandex; using System.Net.Http.Json; namespace PlaylistShared.Pwa.Services.Api; diff --git a/PlaylistShared.Pwa/Services/AudioPlayerService.cs b/PlaylistShared.Pwa/Services/AudioPlayerService.cs index 0cb3f0d..f3c95f8 100644 --- a/PlaylistShared.Pwa/Services/AudioPlayerService.cs +++ b/PlaylistShared.Pwa/Services/AudioPlayerService.cs @@ -1,6 +1,6 @@ using MudBlazor; using PlaylistShared.Shared; -using PlaylistShared.Shared.DTO; +using PlaylistShared.Shared.Yandex; using System.Net.Http.Json; namespace PlaylistShared.Pwa.Services; diff --git a/PlaylistShared.Pwa/Services/IAudioPlayerService.cs b/PlaylistShared.Pwa/Services/IAudioPlayerService.cs index eb39ee7..5713366 100644 --- a/PlaylistShared.Pwa/Services/IAudioPlayerService.cs +++ b/PlaylistShared.Pwa/Services/IAudioPlayerService.cs @@ -1,4 +1,4 @@ -using PlaylistShared.Shared.DTO; +using PlaylistShared.Shared.Yandex; namespace PlaylistShared.Pwa.Services; diff --git a/PlaylistShared.Shared/Playlist/SharePlaylistDto.cs b/PlaylistShared.Shared/SharedPlaylist/SharePlaylistDto.cs similarity index 97% rename from PlaylistShared.Shared/Playlist/SharePlaylistDto.cs rename to PlaylistShared.Shared/SharedPlaylist/SharePlaylistDto.cs index 8ed6c45..758bdd0 100644 --- a/PlaylistShared.Shared/Playlist/SharePlaylistDto.cs +++ b/PlaylistShared.Shared/SharedPlaylist/SharePlaylistDto.cs @@ -1,7 +1,7 @@ using PlaylistShared.Shared.Enums; using System.Text.Json.Serialization; -namespace PlaylistShared.Shared.Playlist; +namespace PlaylistShared.Shared.SharedPlaylist; /// Запрос на создание нового шеринг-плейлиста. public class SharePlaylistDto diff --git a/PlaylistShared.Shared/Playlist/SharePlaylistRequest.cs b/PlaylistShared.Shared/SharedPlaylist/SharePlaylistRequest.cs similarity index 69% rename from PlaylistShared.Shared/Playlist/SharePlaylistRequest.cs rename to PlaylistShared.Shared/SharedPlaylist/SharePlaylistRequest.cs index edd1607..6f440b2 100644 --- a/PlaylistShared.Shared/Playlist/SharePlaylistRequest.cs +++ b/PlaylistShared.Shared/SharedPlaylist/SharePlaylistRequest.cs @@ -1,4 +1,4 @@ -namespace PlaylistShared.Shared.Playlist; +namespace PlaylistShared.Shared.SharedPlaylist; public class SharePlaylistRequest { diff --git a/PlaylistShared.Shared/Yandex/YandexAlbum.cs b/PlaylistShared.Shared/Yandex/YandexAlbum.cs new file mode 100644 index 0000000..aed4ca6 --- /dev/null +++ b/PlaylistShared.Shared/Yandex/YandexAlbum.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; + +namespace PlaylistShared.Shared.Yandex; + +/// Информация о альбоме из Яндекс.Музыки. +public class YandexAlbum +{ + /// Идентификатор альбома (id). + [JsonPropertyName("id")] + public string Id { get; set; } = null!; + + /// Наименование альбома. + [JsonPropertyName("title")] + public string Title { get; set; } = null!; + + /// Исполнители альбома. + [JsonPropertyName("artists")] + public List Artists { get; set; } = null!; + + /// Описание альбома. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// URL обложки альбома. + [JsonPropertyName("coverUrl")] + public string? CoverUrl { get; set; } +} diff --git a/PlaylistShared.Shared/Yandex/YandexArtist.cs b/PlaylistShared.Shared/Yandex/YandexArtist.cs new file mode 100644 index 0000000..7ecf257 --- /dev/null +++ b/PlaylistShared.Shared/Yandex/YandexArtist.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace PlaylistShared.Shared.Yandex; + +/// Информация о исполнителе из Яндекс.Музыки. +public class YandexArtist +{ + /// Идентификатор исполнителя (id). + [JsonPropertyName("id")] + public string Id { get; set; } = null!; + + /// Наименование исполнителя. + [JsonPropertyName("name")] + public string Name { get; set; } = null!; + + /// Описание исполнителя. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// URL исполнителя. + [JsonPropertyName("coverUrl")] + public string? CoverUrl { get; set; } +} diff --git a/PlaylistShared.Shared/Playlist/YandexPlaylistInfo.cs b/PlaylistShared.Shared/Yandex/YandexPlaylist.cs similarity index 71% rename from PlaylistShared.Shared/Playlist/YandexPlaylistInfo.cs rename to PlaylistShared.Shared/Yandex/YandexPlaylist.cs index 223fca1..3bcddbd 100644 --- a/PlaylistShared.Shared/Playlist/YandexPlaylistInfo.cs +++ b/PlaylistShared.Shared/Yandex/YandexPlaylist.cs @@ -1,10 +1,14 @@ using System.Text.Json.Serialization; -namespace PlaylistShared.Shared.Playlist; +namespace PlaylistShared.Shared.Yandex; -/// Информация о плейлисте из Яндекс.Музыки (для импорта). -public class YandexPlaylistInfo +/// Информация о плейлисте из Яндекс.Музыки. +public class YandexPlaylist { + /// Идентификатор плейлиста (uuid). + [JsonPropertyName("uuid")] + public string Uuid { get; set; } = null!; + /// Идентификатор плейлиста (kind). [JsonPropertyName("kind")] public string Kind { get; set; } = null!; @@ -28,12 +32,4 @@ public class YandexPlaylistInfo /// Кол-во треков. [JsonPropertyName("trackCount")] public int TrackCount { get; set; } - - /// Расшаренный - [JsonPropertyName("isShared")] - public bool IsShared { get; set; } - - /// Расшаренная ссылка - [JsonPropertyName("shareToken")] - public string? ShareToken { get; set; } } diff --git a/PlaylistShared.Shared/SharedPlaylist/YandexPlaylistData.cs b/PlaylistShared.Shared/Yandex/YandexPlaylistData.cs similarity index 69% rename from PlaylistShared.Shared/SharedPlaylist/YandexPlaylistData.cs rename to PlaylistShared.Shared/Yandex/YandexPlaylistData.cs index 6095391..9b28dc6 100644 --- a/PlaylistShared.Shared/SharedPlaylist/YandexPlaylistData.cs +++ b/PlaylistShared.Shared/Yandex/YandexPlaylistData.cs @@ -1,6 +1,4 @@ -using PlaylistShared.Shared.DTO; - -namespace PlaylistShared.Shared.SharedPlaylist; +namespace PlaylistShared.Shared.Yandex; public class YandexPlaylistData { diff --git a/PlaylistShared.Shared/Yandex/YandexPlaylistShare.cs b/PlaylistShared.Shared/Yandex/YandexPlaylistShare.cs new file mode 100644 index 0000000..88e5528 --- /dev/null +++ b/PlaylistShared.Shared/Yandex/YandexPlaylistShare.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace PlaylistShared.Shared.Yandex; + +/// Информация о плейлисте из Яндекс.Музыки с пометкой о шаринге. +public class YandexPlaylistShare : YandexPlaylist +{ + + /// Расшаренный + [JsonPropertyName("isShared")] + public bool IsShared { get; set; } + + /// Расшаренная ссылка + [JsonPropertyName("shareToken")] + public string? ShareToken { get; set; } +} diff --git a/PlaylistShared.Shared/Yandex/YandexSearchResult.cs b/PlaylistShared.Shared/Yandex/YandexSearchResult.cs new file mode 100644 index 0000000..1d38008 --- /dev/null +++ b/PlaylistShared.Shared/Yandex/YandexSearchResult.cs @@ -0,0 +1,31 @@ +using System.Text.Json.Serialization; + +namespace PlaylistShared.Shared.Yandex; + +/// Информация о плейлисте из Яндекс.Музыки (для импорта). +public class YandexSearchResult +{ + /// + /// Найденные треки. + /// + [JsonPropertyName("tracks")] + public List? Tracks { get; set; } = null; + + /// + /// Найденные плейлисты. + /// + [JsonPropertyName("playlists")] + public List? Playlists { get; set; } = null; + + /// + /// Найденные исполнители. + /// + [JsonPropertyName("artists")] + public List? Artists { get; set; } = null; + + /// + /// Найденные альбомы. + /// + [JsonPropertyName("albumns")] + public List? Albums { get; set; } = null; +} diff --git a/PlaylistShared.Shared/DTO/YandexTrack.cs b/PlaylistShared.Shared/Yandex/YandexTrack.cs similarity index 93% rename from PlaylistShared.Shared/DTO/YandexTrack.cs rename to PlaylistShared.Shared/Yandex/YandexTrack.cs index 692c628..1e8c409 100644 --- a/PlaylistShared.Shared/DTO/YandexTrack.cs +++ b/PlaylistShared.Shared/Yandex/YandexTrack.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace PlaylistShared.Shared.DTO; +namespace PlaylistShared.Shared.Yandex; /// Результат поиска трека в Яндекс.Музыке. public class YandexTrack