diff --git a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudAlbumSearchHelper.cs b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudAlbumSearchHelper.cs index 8d239bc..8049ee0 100644 --- a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudAlbumSearchHelper.cs +++ b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudAlbumSearchHelper.cs @@ -15,61 +15,48 @@ public sealed class CloudAlbumSearchHelper public static async Task SearchAlbumsAsync(string keyWords, CloudOnlineAlbumInfoList list) { await _searchSemaphore.WaitAsync(); - list.Page = 0; - list.ListCount = 0; - list.HasAllLoaded = false; - list.Clear(); - list.SearchedAlbumIDs.Clear(); - list.KeyWords = keyWords; - try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.Search, - new Dictionary - { - { "keywords", keyWords }, - { "type", "10" }, - { "limit", $"{CloudOnlineAlbumInfoList.Limit}" }, - { "offset", "0" }, - } - ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; + list.Page = 0; + list.ListCount = 0; + list.HasAllLoaded = false; + list.Clear(); + list.SearchedAlbumIDs.Clear(); + list.KeyWords = keyWords; - // 获取albumCount - if ( - root.TryGetProperty("result", out var resultElement) - && resultElement.TryGetProperty("albumCount", out var albumCountElement) - ) + var (albums, albumCount) = await SearchInternalAsync(keyWords, 0); + list.AlbumCount = albumCount; + + if (albumCount == 0) { - list.AlbumCount = albumCountElement.GetInt32(); + list.HasAllLoaded = true; + return; + } - if (list.AlbumCount == 0) - { - list.HasAllLoaded = true; - return; - } + await ProcessAlbumsAsync(albums, list); + list.Page = 1; - // 获取albums数组 - if (resultElement.TryGetProperty("albums", out var albumsElement)) + // 如果加载后的数量没达到Limit且还有更多,则继续加载更多 + while (list.Count < CloudOnlineAlbumInfoList.Limit && !list.HasAllLoaded) + { + var (moreAlbums, _) = await SearchInternalAsync( + list.KeyWords, + list.Page * CloudOnlineAlbumInfoList.Limit + ); + if (moreAlbums.GetArrayLength() > 0) { - await ProcessAlbumsAsync(albumsElement, list); - list.Page = 1; + await ProcessAlbumsAsync(moreAlbums, list); + list.Page++; } else { - throw new Exception("获取专辑列表失败"); + break; } } - else - { - throw new Exception("获取专辑数量失败"); - } } - catch + catch (Exception ex) { - throw new Exception("搜索失败"); + throw new Exception("搜索失败", ex); } finally { @@ -82,36 +69,16 @@ public sealed class CloudAlbumSearchHelper await _searchSemaphore.WaitAsync(); try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.Search, - new Dictionary - { - { "keywords", list.KeyWords }, - { "type", "10" }, - { "limit", $"{CloudOnlineAlbumInfoList.Limit}" }, - { "offset", $"{list.Page * CloudOnlineAlbumInfoList.Limit}" }, - } + var (albums, _) = await SearchInternalAsync( + list.KeyWords, + list.Page * CloudOnlineAlbumInfoList.Limit ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; - - // 获取albums数组 - if ( - root.TryGetProperty("result", out var resultElement) - && resultElement.TryGetProperty("albums", out var albumsElement) - ) - { - await ProcessAlbumsAsync(albumsElement, list); - list.Page++; - } - else - { - throw new Exception("获取专辑列表失败"); - } + await ProcessAlbumsAsync(albums, list); + list.Page++; } - catch + catch (Exception ex) { - throw new Exception("搜索更多失败"); + throw new Exception("搜索更多失败", ex); } finally { @@ -119,12 +86,58 @@ public sealed class CloudAlbumSearchHelper } } + private static async Task<(JsonElement Albums, int AlbumCount)> SearchInternalAsync( + string keyWords, + int offset + ) + { + var (_, result) = await _api.RequestAsync( + CloudMusicApiProviders.Search, + new Dictionary + { + { "keywords", keyWords }, + { "type", "10" }, + { "limit", $"{CloudOnlineAlbumInfoList.Limit}" }, + { "offset", $"{offset}" }, + } + ); + + using var document = JsonDocument.Parse(result.ToJsonString()); + var root = document.RootElement; + + if (!root.TryGetProperty("result", out var resultElement)) + { + throw new Exception("获取搜索结果失败"); + } + + resultElement.TryGetProperty("albumCount", out var albumCountElement); + var albumCount = + albumCountElement.ValueKind == JsonValueKind.Number ? albumCountElement.GetInt32() : 0; + + if (!resultElement.TryGetProperty("albums", out var albumsElement)) + { + if (albumCount == 0) + { + return (default, 0); + } + throw new Exception("获取专辑列表失败"); + } + + return (albumsElement.Clone(), albumCount); + } + private static async Task ProcessAlbumsAsync( JsonElement albumsElement, CloudOnlineAlbumInfoList list ) { - var actualCount = albumsElement.GetArrayLength(); + var actualCount = + albumsElement.ValueKind == JsonValueKind.Array ? albumsElement.GetArrayLength() : 0; + if (actualCount == 0) + { + return; + } + var infos = new BriefCloudOnlineAlbumInfo[actualCount]; using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(8)); await Parallel.ForEachAsync( @@ -139,8 +152,7 @@ public sealed class CloudAlbumSearchHelper try { cancellationToken.ThrowIfCancellationRequested(); - var info = await BriefCloudOnlineAlbumInfo.CreateAsync(albumsElement[i]!); - infos[i] = info; + infos[i] = await BriefCloudOnlineAlbumInfo.CreateAsync(albumsElement[i]); } catch (Exception ex) { diff --git a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudArtistDetailSearchHelper.cs b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudArtistDetailSearchHelper.cs index 67d8a6c..d2bdc51 100644 --- a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudArtistDetailSearchHelper.cs +++ b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudArtistDetailSearchHelper.cs @@ -28,45 +28,55 @@ public sealed class CloudArtistDetailSearchHelper }; try { - var albumTask = _api.RequestAsync( - CloudMusicApiProviders.ArtistAlbum, - new Dictionary - { - { "id", $"{briefInfo.ID}" }, - { "limit", $"{DetailedCloudOnlineArtistInfo.Limit}" }, - { "offset", "0" }, - } - ); var artistTask = _api.RequestAsync( CloudMusicApiProviders.ArtistDesc, new Dictionary { { "id", $"{briefInfo.ID}" } } ); - await Task.WhenAll(albumTask, artistTask); - var (_, albumResult) = albumTask.Result; - var (_, artistResult) = artistTask.Result; - info.Introduction = artistResult["briefDesc"]?.ToString(); - using var document = JsonDocument.Parse(albumResult.ToJsonString()); - var root = document.RootElement; - var artistElement = root.GetProperty("artist"); - var albumsElement = root.GetProperty("hotAlbums"); - info.TotalAlbumNum = artistElement.GetProperty("albumSize").GetInt32(); - info.TotalSongNum = artistElement.GetProperty("musicSize").GetInt32(); + var (albumsElement, totalAlbumNum, totalSongNum) = await SearchAlbumsInternalAsync( + briefInfo.ID, + 0 + ); + + var (_, artistResult) = await artistTask; + info.Introduction = artistResult["briefDesc"]?.ToString(); + info.TotalAlbumNum = totalAlbumNum; + info.TotalSongNum = totalSongNum; info.CountStr = IDetailedOnlineArtistInfo.GetCountStr( info.TotalAlbumNum, info.TotalSongNum ); - if (info.TotalAlbumNum == 0) + + if (totalAlbumNum == 0) { info.HasAllLoaded = true; return info; } + await ProcessArtistDetailAsync(albumsElement, info); info.Page = 1; + + // 如果加载后的数量没达到Limit且还有更多,则继续加载更多 + while (info.AlbumList.Count < DetailedCloudOnlineArtistInfo.Limit && !info.HasAllLoaded) + { + var (moreAlbums, _, _) = await SearchAlbumsInternalAsync( + info.ID, + info.Page * DetailedCloudOnlineArtistInfo.Limit + ); + if (moreAlbums.GetArrayLength() > 0) + { + await ProcessArtistDetailAsync(moreAlbums, info); + info.Page++; + } + else + { + break; + } + } } catch (Exception ex) { - _logger.ZLogInformation(ex, $"搜索网易云艺术家{briefInfo.Name}详情失败"); + _logger.ZLogInformation(ex, $"搜索艺术家详情失败: {briefInfo.Name}"); } finally { @@ -80,24 +90,16 @@ public sealed class CloudArtistDetailSearchHelper await _searchSemaphore.WaitAsync(); try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.ArtistAlbum, - new Dictionary - { - { "id", $"{info.ID}" }, - { "limit", $"{DetailedCloudOnlineArtistInfo.Limit}" }, - { "offset", $"{info.Page * DetailedCloudOnlineArtistInfo.Limit}" }, - } + var (albums, _, _) = await SearchAlbumsInternalAsync( + info.ID, + info.Page * DetailedCloudOnlineArtistInfo.Limit ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; - var albumsElement = root.GetProperty("hotAlbums"); - await ProcessArtistDetailAsync(albumsElement, info); + await ProcessArtistDetailAsync(albums, info); info.Page++; } catch (Exception ex) { - _logger.ZLogInformation(ex, $"搜索网易云艺术家{info.Name}更多详情失败"); + _logger.ZLogInformation(ex, $"搜索更多艺术家详情失败: {info.Name}, Page: {info.Page}"); } finally { @@ -105,12 +107,54 @@ public sealed class CloudArtistDetailSearchHelper } } + private static async Task<( + JsonElement Albums, + int TotalAlbumNum, + int TotalSongNum + )> SearchAlbumsInternalAsync(long artistId, int offset) + { + var (_, albumResult) = await _api.RequestAsync( + CloudMusicApiProviders.ArtistAlbum, + new Dictionary + { + { "id", $"{artistId}" }, + { "limit", $"{DetailedCloudOnlineArtistInfo.Limit}" }, + { "offset", $"{offset}" }, + } + ); + + using var document = JsonDocument.Parse(albumResult.ToJsonString()); + var root = document.RootElement; + + var artistElement = root.TryGetProperty("artist", out var artist) ? artist : default; + var albumsElement = root.TryGetProperty("hotAlbums", out var albums) ? albums : default; + + var totalAlbumNum = + artist.ValueKind == JsonValueKind.Object + && artist.TryGetProperty("albumSize", out var albumSize) + ? albumSize.GetInt32() + : 0; + var totalSongNum = + artist.ValueKind == JsonValueKind.Object + && artist.TryGetProperty("musicSize", out var musicSize) + ? musicSize.GetInt32() + : 0; + + return (albumsElement.Clone(), totalAlbumNum, totalSongNum); + } + private static async Task ProcessArtistDetailAsync( JsonElement albumsElement, DetailedCloudOnlineArtistInfo info ) { - var actualCount = albumsElement.GetArrayLength(); + var actualCount = + albumsElement.ValueKind == JsonValueKind.Array ? albumsElement.GetArrayLength() : 0; + if (actualCount == 0) + { + return; + } + var albumInfos = new CloudOnlineArtistAlbumInfo[actualCount]; using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(8)); await Parallel.ForEachAsync( @@ -125,12 +169,11 @@ public sealed class CloudArtistDetailSearchHelper try { cancellationToken.ThrowIfCancellationRequested(); - var albumInfo = await CloudOnlineArtistAlbumInfo.CreateAsync( - albumsElement[i]!, + albumInfos[i] = await CloudOnlineArtistAlbumInfo.CreateAsync( + albumsElement[i], _api, true ); - albumInfos[i] = albumInfo; } catch (Exception ex) { @@ -138,14 +181,17 @@ public sealed class CloudArtistDetailSearchHelper { info.CurrentAlbumNum++; } - _logger.ZLogInformation(ex, $"处理网易云艺术家详细信息失败"); + _logger.ZLogInformation(ex, $"处理网易云艺术家详细信息失败: {info.Name}"); } } ); foreach (var albumInfo in albumInfos) { - info.Add(albumInfo); + if (albumInfo != null) + { + info.Add(albumInfo); + } } } @@ -156,19 +202,14 @@ public sealed class CloudArtistDetailSearchHelper var songs = new List(); try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.ArtistAlbum, - new Dictionary - { - { "id", $"{info.ID}" }, - { "limit", $"{DetailedCloudOnlineArtistInfo.Limit}" }, - { "offset", $"0" }, - } - ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; - var albumsElement = root.GetProperty("hotAlbums"); - var actualCount = albumsElement.GetArrayLength(); + var (albumsElement, _, _) = await SearchAlbumsInternalAsync(info.ID, 0); + var actualCount = + albumsElement.ValueKind == JsonValueKind.Array ? albumsElement.GetArrayLength() : 0; + if (actualCount == 0) + { + return songs; + } + var albumInfos = new CloudOnlineArtistAlbumInfo[actualCount]; using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(8)); await Parallel.ForEachAsync( @@ -183,22 +224,22 @@ public sealed class CloudArtistDetailSearchHelper try { cancellationToken.ThrowIfCancellationRequested(); - var albumInfo = await CloudOnlineArtistAlbumInfo.CreateAsync( - albumsElement[i]!, + albumInfos[i] = await CloudOnlineArtistAlbumInfo.CreateAsync( + albumsElement[i], _api, false ); - albumInfos[i] = albumInfo; } catch (Exception ex) { - _logger.ZLogInformation(ex, $"获取网易云艺术家{info.Name}歌曲失败"); + _logger.ZLogInformation(ex, $"获取网易云艺术家专辑歌曲失败: {info.Name}"); } } ); + foreach (var album in albumInfos) { - if (album is not null && album.IsAvailable) + if (album is { IsAvailable: true }) { songs.AddRange(album.SongList); } @@ -206,9 +247,8 @@ public sealed class CloudArtistDetailSearchHelper } catch (Exception ex) { - _logger.ZLogInformation(ex, $"获取网易云艺术家{info.Name}歌曲失败"); + _logger.ZLogInformation(ex, $"获取网易云艺术家歌曲失败: {info.Name}"); } - return songs; } } diff --git a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudArtistSearchHelper.cs b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudArtistSearchHelper.cs index 09a8ffa..b0c45c1 100644 --- a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudArtistSearchHelper.cs +++ b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudArtistSearchHelper.cs @@ -16,61 +16,48 @@ public sealed class CloudArtistSearchHelper public static async Task SearchArtistsAsync(string keyWords, CloudOnlineArtistInfoList list) { await _searchSemaphore.WaitAsync(); - list.Page = 0; - list.ListCount = 0; - list.HasAllLoaded = false; - list.Clear(); - list.SearchedArtistIDs.Clear(); - list.KeyWords = keyWords; - try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.Search, - new Dictionary - { - { "keywords", keyWords }, - { "type", "100" }, - { "limit", $"{CloudOnlineArtistInfoList.Limit}" }, - { "offset", "0" }, - } - ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; + list.Page = 0; + list.ListCount = 0; + list.HasAllLoaded = false; + list.Clear(); + list.SearchedArtistIDs.Clear(); + list.KeyWords = keyWords; - // 获取artistCount - if ( - root.TryGetProperty("result", out var resultElement) - && resultElement.TryGetProperty("artistCount", out var artistCountElement) - ) + var (artists, artistCount) = await SearchInternalAsync(keyWords, 0); + list.ArtistCount = artistCount; + + if (artistCount == 0) { - list.ArtistCount = artistCountElement.GetInt32(); + list.HasAllLoaded = true; + return; + } - if (list.ArtistCount == 0) - { - list.HasAllLoaded = true; - return; - } + await ProcessArtistsAsync(artists, list); + list.Page = 1; - // 获取artists数组 - if (resultElement.TryGetProperty("artists", out var artistsElement)) + // 如果加载后的数量没达到Limit且还有更多,则继续加载更多 + while (list.Count < CloudOnlineArtistInfoList.Limit && !list.HasAllLoaded) + { + var (moreArtists, _) = await SearchInternalAsync( + list.KeyWords, + list.Page * CloudOnlineArtistInfoList.Limit + ); + if (moreArtists.GetArrayLength() > 0) { - await ProcessArtistsAsync(artistsElement, list); - list.Page = 1; + await ProcessArtistsAsync(moreArtists, list); + list.Page++; } else { - throw new Exception("获取艺术家列表失败"); + break; } } - else - { - throw new Exception("获取艺术家数量失败"); - } } - catch + catch (Exception ex) { - throw new Exception("搜索失败"); + throw new Exception("搜索失败", ex); } finally { @@ -83,36 +70,16 @@ public sealed class CloudArtistSearchHelper await _searchSemaphore.WaitAsync(); try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.Search, - new Dictionary - { - { "keywords", list.KeyWords }, - { "type", "100" }, - { "limit", $"{CloudOnlineArtistInfoList.Limit}" }, - { "offset", $"{list.Page * CloudOnlineArtistInfoList.Limit}" }, - } + var (artists, _) = await SearchInternalAsync( + list.KeyWords, + list.Page * CloudOnlineArtistInfoList.Limit ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; - - // 获取artists数组 - if ( - root.TryGetProperty("result", out var resultElement) - && resultElement.TryGetProperty("artists", out var artistsElement) - ) - { - await ProcessArtistsAsync(artistsElement, list); - list.Page++; - } - else - { - throw new Exception("获取艺术家列表失败"); - } + await ProcessArtistsAsync(artists, list); + list.Page++; } - catch + catch (Exception ex) { - throw new Exception("搜索更多失败"); + throw new Exception("搜索更多失败", ex); } finally { @@ -120,12 +87,61 @@ public sealed class CloudArtistSearchHelper } } + private static async Task<(JsonElement Artists, int ArtistCount)> SearchInternalAsync( + string keyWords, + int offset + ) + { + var (_, result) = await _api.RequestAsync( + CloudMusicApiProviders.Search, + new Dictionary + { + { "keywords", keyWords }, + { "type", "100" }, + { "limit", $"{CloudOnlineArtistInfoList.Limit}" }, + { "offset", $"{offset}" }, + } + ); + + using var document = JsonDocument.Parse(result.ToJsonString()); + var root = document.RootElement; + + if (!root.TryGetProperty("result", out var resultElement)) + { + throw new Exception("获取搜索结果失败"); + } + + resultElement.TryGetProperty("artistCount", out var artistCountElement); + var artistCount = + artistCountElement.ValueKind == JsonValueKind.Number + ? artistCountElement.GetInt32() + : 0; + + if (!resultElement.TryGetProperty("artists", out var artistsElement)) + { + if (artistCount == 0) + { + return (default, 0); + } + + throw new Exception("获取艺术家列表失败"); + } + + return (artistsElement.Clone(), artistCount); + } + private static async Task ProcessArtistsAsync( JsonElement artistsElement, CloudOnlineArtistInfoList list ) { - var actualCount = artistsElement.GetArrayLength(); + var actualCount = + artistsElement.ValueKind == JsonValueKind.Array ? artistsElement.GetArrayLength() : 0; + if (actualCount == 0) + { + return; + } + var infos = new BriefCloudOnlineArtistInfo[actualCount]; using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(8)); await Parallel.ForEachAsync( @@ -140,8 +156,7 @@ public sealed class CloudArtistSearchHelper try { cancellationToken.ThrowIfCancellationRequested(); - var info = await BriefCloudOnlineArtistInfo.CreateAsync(artistsElement[i]!); - infos[i] = info; + infos[i] = await BriefCloudOnlineArtistInfo.CreateAsync(artistsElement[i]); } catch (Exception ex) { diff --git a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudPlaylistSearchHelper.cs b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudPlaylistSearchHelper.cs index f8e6835..04deb17 100644 --- a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudPlaylistSearchHelper.cs +++ b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudPlaylistSearchHelper.cs @@ -16,61 +16,48 @@ public sealed class CloudPlaylistSearchHelper public static async Task SearchPlaylistsAsync(string keyWords, CloudOnlinePlaylistInfoList list) { await _searchSemaphore.WaitAsync(); - list.Page = 0; - list.ListCount = 0; - list.HasAllLoaded = false; - list.Clear(); - list.SearchedPlaylistIDs.Clear(); - list.KeyWords = keyWords; - try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.Search, - new Dictionary - { - { "keywords", keyWords }, - { "type", "1000" }, - { "limit", $"{CloudOnlinePlaylistInfoList.Limit}" }, - { "offset", "0" }, - } - ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; + list.Page = 0; + list.ListCount = 0; + list.HasAllLoaded = false; + list.Clear(); + list.SearchedPlaylistIDs.Clear(); + list.KeyWords = keyWords; - // 获取PlaylistCount - if ( - root.TryGetProperty("result", out var resultElement) - && resultElement.TryGetProperty("playlistCount", out var playlistCountElement) - ) + var (playlists, playlistCount) = await SearchInternalAsync(keyWords, 0); + list.PlaylistCount = playlistCount; + + if (playlistCount == 0) { - list.PlaylistCount = playlistCountElement.GetInt32(); + list.HasAllLoaded = true; + return; + } - if (list.PlaylistCount == 0) - { - list.HasAllLoaded = true; - return; - } + await ProcessPlaylistsAsync(playlists, list); + list.Page = 1; - // 获取Playlists数组 - if (resultElement.TryGetProperty("playlists", out var playlistsElement)) + // 如果加载后的数量没达到Limit且还有更多,则继续加载更多 + while (list.Count < CloudOnlinePlaylistInfoList.Limit && !list.HasAllLoaded) + { + var (morePlaylists, _) = await SearchInternalAsync( + list.KeyWords, + list.Page * CloudOnlinePlaylistInfoList.Limit + ); + if (morePlaylists.GetArrayLength() > 0) { - await ProcessPlaylistsAsync(playlistsElement, list); - list.Page = 1; + await ProcessPlaylistsAsync(morePlaylists, list); + list.Page++; } else { - throw new Exception("获取歌单列表失败"); + break; } } - else - { - throw new Exception("获取歌单数量失败"); - } } - catch + catch (Exception ex) { - throw new Exception("搜索失败"); + throw new Exception("搜索失败", ex); } finally { @@ -83,36 +70,16 @@ public sealed class CloudPlaylistSearchHelper await _searchSemaphore.WaitAsync(); try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.Search, - new Dictionary - { - { "keywords", list.KeyWords }, - { "type", "1000" }, - { "limit", $"{CloudOnlinePlaylistInfoList.Limit}" }, - { "offset", $"{list.Page * CloudOnlinePlaylistInfoList.Limit}" }, - } + var (playlists, _) = await SearchInternalAsync( + list.KeyWords, + list.Page * CloudOnlinePlaylistInfoList.Limit ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; - - // 获取Playlists数组 - if ( - root.TryGetProperty("result", out var resultElement) - && resultElement.TryGetProperty("playlists", out var playlistsElement) - ) - { - await ProcessPlaylistsAsync(playlistsElement, list); - list.Page++; - } - else - { - throw new Exception("获取歌单列表失败"); - } + await ProcessPlaylistsAsync(playlists, list); + list.Page++; } - catch + catch (Exception ex) { - throw new Exception("搜索更多失败"); + throw new Exception("搜索更多失败", ex); } finally { @@ -120,12 +87,63 @@ public sealed class CloudPlaylistSearchHelper } } + private static async Task<(JsonElement Playlists, int PlaylistCount)> SearchInternalAsync( + string keyWords, + int offset + ) + { + var (_, result) = await _api.RequestAsync( + CloudMusicApiProviders.Search, + new Dictionary + { + { "keywords", keyWords }, + { "type", "1000" }, + { "limit", $"{CloudOnlinePlaylistInfoList.Limit}" }, + { "offset", $"{offset}" }, + } + ); + + using var document = JsonDocument.Parse(result.ToJsonString()); + var root = document.RootElement; + + if (!root.TryGetProperty("result", out var resultElement)) + { + throw new Exception("获取搜索结果失败"); + } + + resultElement.TryGetProperty("playlistCount", out var playlistCountElement); + var playlistCount = + playlistCountElement.ValueKind == JsonValueKind.Number + ? playlistCountElement.GetInt32() + : 0; + + if (!resultElement.TryGetProperty("playlists", out var playlistsElement)) + { + if (playlistCount == 0) + { + return (default, 0); + } + + throw new Exception("获取歌单列表失败"); + } + + return (playlistsElement.Clone(), playlistCount); + } + private static async Task ProcessPlaylistsAsync( JsonElement playlistsElement, CloudOnlinePlaylistInfoList list ) { - var actualCount = playlistsElement.GetArrayLength(); + var actualCount = + playlistsElement.ValueKind == JsonValueKind.Array + ? playlistsElement.GetArrayLength() + : 0; + if (actualCount == 0) + { + return; + } + var infos = new BriefCloudOnlinePlaylistInfo[actualCount]; using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(8)); await Parallel.ForEachAsync( @@ -140,8 +158,7 @@ public sealed class CloudPlaylistSearchHelper try { cancellationToken.ThrowIfCancellationRequested(); - var info = await BriefCloudOnlinePlaylistInfo.CreateAsync(playlistsElement[i]!); - infos[i] = info; + infos[i] = await BriefCloudOnlinePlaylistInfo.CreateAsync(playlistsElement[i]); } catch (Exception ex) { diff --git a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudSongSearchHelper.cs b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudSongSearchHelper.cs index a4ac9f4..0043cad 100644 --- a/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudSongSearchHelper.cs +++ b/UntamedMusicPlayer/OnlineAPIs/CloudMusicAPI/Helpers/CloudSongSearchHelper.cs @@ -14,61 +14,48 @@ public sealed class CloudSongSearchHelper public static async Task SearchSongsAsync(string keyWords, CloudOnlineSongInfoList list) { await _searchSemaphore.WaitAsync(); - list.Page = 0; - list.ListCount = 0; - list.HasAllLoaded = false; - list.Clear(); - list.SearchedSongIDs.Clear(); - list.KeyWords = keyWords; - try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.Search, - new Dictionary - { - { "keywords", keyWords }, - { "type", "1" }, - { "limit", $"{CloudOnlineSongInfoList.Limit}" }, - { "offset", "0" }, - } - ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; + list.Page = 0; + list.ListCount = 0; + list.HasAllLoaded = false; + list.Clear(); + list.SearchedSongIDs.Clear(); + list.KeyWords = keyWords; - // 获取songCount - if ( - root.TryGetProperty("result", out var resultElement) - && resultElement.TryGetProperty("songCount", out var songCountElement) - ) + var (songs, songCount) = await SearchInternalAsync(keyWords, 0); + list.SongCount = songCount; + + if (songCount == 0) { - list.SongCount = songCountElement.GetInt32(); + list.HasAllLoaded = true; + return; + } - if (list.SongCount == 0) - { - list.HasAllLoaded = true; - return; - } + await ProcessSongsAsync(songs, list); + list.Page = 1; - // 获取songs数组 - if (resultElement.TryGetProperty("songs", out var songsElement)) + // 如果加载后的歌曲数量没达到Limit且还有更多,则继续加载更多 + while (list.Count < CloudOnlineSongInfoList.Limit && !list.HasAllLoaded) + { + var (moreSongs, _) = await SearchInternalAsync( + list.KeyWords, + list.Page * CloudOnlineSongInfoList.Limit + ); + if (moreSongs.GetArrayLength() > 0) { - await ProcessSongsAsync(songsElement, list); - list.Page = 1; + await ProcessSongsAsync(moreSongs, list); + list.Page++; } else { - throw new Exception("获取歌曲列表失败"); + break; } } - else - { - throw new Exception("获取歌曲数量失败"); - } } - catch + catch (Exception ex) { - throw new Exception("搜索失败"); + throw new Exception("搜索失败", ex); } finally { @@ -81,36 +68,16 @@ public sealed class CloudSongSearchHelper await _searchSemaphore.WaitAsync(); try { - var (_, result) = await _api.RequestAsync( - CloudMusicApiProviders.Search, - new Dictionary - { - { "keywords", list.KeyWords }, - { "type", "1" }, - { "limit", $"{CloudOnlineSongInfoList.Limit}" }, - { "offset", $"{list.Page * CloudOnlineSongInfoList.Limit}" }, - } + var (songs, _) = await SearchInternalAsync( + list.KeyWords, + list.Page * CloudOnlineSongInfoList.Limit ); - using var document = JsonDocument.Parse(result.ToJsonString()); - var root = document.RootElement; - - // 获取songs数组 - if ( - root.TryGetProperty("result", out var resultElement) - && resultElement.TryGetProperty("songs", out var songsElement) - ) - { - await ProcessSongsAsync(songsElement, list); - list.Page++; - } - else - { - throw new Exception("获取歌曲列表失败"); - } + await ProcessSongsAsync(songs, list); + list.Page++; } - catch + catch (Exception ex) { - throw new Exception("搜索更多失败"); + throw new Exception("搜索更多失败", ex); } finally { @@ -118,12 +85,53 @@ public sealed class CloudSongSearchHelper } } + private static async Task<(JsonElement Songs, int SongCount)> SearchInternalAsync( + string keyWords, + int offset + ) + { + var (_, result) = await _api.RequestAsync( + CloudMusicApiProviders.Search, + new Dictionary + { + { "keywords", keyWords }, + { "type", "1" }, + { "limit", $"{CloudOnlineSongInfoList.Limit}" }, + { "offset", $"{offset}" }, + } + ); + + using var document = JsonDocument.Parse(result.ToJsonString()); + var root = document.RootElement; + + if (!root.TryGetProperty("result", out var resultElement)) + { + throw new Exception("获取搜索结果失败"); + } + + resultElement.TryGetProperty("songCount", out var songCountElement); + var songCount = + songCountElement.ValueKind == JsonValueKind.Number ? songCountElement.GetInt32() : 0; + + if (!resultElement.TryGetProperty("songs", out var songsElement)) + { + if (songCount == 0) + { + return (default, 0); + } + throw new Exception("获取歌曲列表失败"); + } + + return (songsElement.Clone(), songCount); + } + private static async Task ProcessSongsAsync( JsonElement songsElement, CloudOnlineSongInfoList list ) { - var actualCount = songsElement.GetArrayLength(); + var actualCount = + songsElement.ValueKind == JsonValueKind.Array ? songsElement.GetArrayLength() : 0; if (actualCount == 0) { return; @@ -138,76 +146,84 @@ public sealed class CloudSongSearchHelper CloudMusicApiProviders.SongUrl, new Dictionary { { "id", string.Join(',', songIds) } } ); - var data = checkResult["data"]!; - // 建立ID到可用性的映射,解决顺序问题 - var availabilityMap = data.AsArray() - .ToDictionary(item => item!["id"]!.GetValue(), item => item!["url"] is not null); + var availabilityMap = + checkResult["data"] + ?.AsArray() + .ToDictionary( + item => item!["id"]!.GetValue(), + item => item!["url"] is not null + ) ?? []; - var infos = Enumerable - .Range(0, actualCount) - .Select(i => - { - try - { - var songId = songIds[i]; - var available = availabilityMap.GetValueOrDefault(songId, false); - return new BriefCloudOnlineSongInfo(songsElement[i], available); - } - catch (Exception ex) - { - list.ListCount++; - _logger.ZLogInformation(ex, $"处理网易云歌曲信息失败"); - return null; - } - }) - .Where(info => info is not null); - - foreach (var info in infos) + for (var i = 0; i < actualCount; i++) { - list.Add(info); + try + { + var songElement = songsElement[i]; + var songId = songIds[i]; + var available = availabilityMap.GetValueOrDefault(songId, false); + list.Add(new BriefCloudOnlineSongInfo(songElement, available)); + } + catch (Exception ex) + { + list.ListCount++; + _logger.ZLogInformation(ex, $"处理网易云歌曲信息失败"); + } } } public static async Task> SearchSongsByIDsAsync(long[] IDs) { - var list = new List(); + if (IDs == null || IDs.Length == 0) + { + return []; + } + + var idString = string.Join(',', IDs); var (_, checkResult) = await _api.RequestAsync( CloudMusicApiProviders.SongUrl, - new Dictionary { { "id", string.Join(',', IDs) } } + new Dictionary { { "id", idString } } ); var (_, detailsResult) = await _api.RequestAsync( CloudMusicApiProviders.SongDetail, - new Dictionary { { "ids", string.Join(',', IDs) } } + new Dictionary { { "ids", idString } } ); - var data = checkResult["data"]!; - var availabilityMap = data.AsArray() - .ToDictionary(item => item!["id"]!.GetValue(), item => item!["url"] is not null); - var detailsMap = detailsResult["songs"]! - .AsArray() - .ToDictionary(item => item!["id"]!.GetValue(), item => item); - for (var i = 0; i < IDs.Length; i++) + var availabilityMap = + checkResult["data"] + ?.AsArray() + .ToDictionary( + item => item!["id"]!.GetValue(), + item => item!["url"] is not null + ) ?? []; + + var detailsMap = + detailsResult["songs"] + ?.AsArray() + .ToDictionary(item => item!["id"]!.GetValue(), item => item) ?? []; + + var result = new List(); + foreach (var songId in IDs) { - var songId = IDs[i]; - var available = availabilityMap.GetValueOrDefault(songId, false); - if (!available) + if (!availabilityMap.GetValueOrDefault(songId, false)) { continue; } - var trackElement = detailsMap.GetValueOrDefault(songId)!; + if (!detailsMap.TryGetValue(songId, out var trackElement) || trackElement == null) + { + continue; + } try { - var songInfo = new BriefCloudOnlineSongInfo(trackElement); - list.Add(songInfo); + result.Add(new BriefCloudOnlineSongInfo(trackElement)); } catch (Exception ex) { - _logger.ZLogInformation(ex, $"通过ID获取网易云歌曲信息失败"); + _logger.ZLogInformation(ex, $"通过ID获取网易云歌曲信息失败: {songId}"); } } - return list; + return result; } }