更新搜索

This commit is contained in:
LanZhan-Harmony
2026-03-10 20:34:28 +08:00
parent 409a1f2c45
commit 55fd7937a3
5 changed files with 485 additions and 385 deletions

View File

@@ -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<string, string>
{
{ "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<string, string>
{
{ "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<string, string>
{
{ "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)
{

View File

@@ -28,45 +28,55 @@ public sealed class CloudArtistDetailSearchHelper
};
try
{
var albumTask = _api.RequestAsync(
CloudMusicApiProviders.ArtistAlbum,
new Dictionary<string, string>
{
{ "id", $"{briefInfo.ID}" },
{ "limit", $"{DetailedCloudOnlineArtistInfo.Limit}" },
{ "offset", "0" },
}
);
var artistTask = _api.RequestAsync(
CloudMusicApiProviders.ArtistDesc,
new Dictionary<string, string> { { "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<string, string>
{
{ "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<string, string>
{
{ "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<IBriefSongInfoBase>();
try
{
var (_, result) = await _api.RequestAsync(
CloudMusicApiProviders.ArtistAlbum,
new Dictionary<string, string>
{
{ "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;
}
}

View File

@@ -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<string, string>
{
{ "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<string, string>
{
{ "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<string, string>
{
{ "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)
{

View File

@@ -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<string, string>
{
{ "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<string, string>
{
{ "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<string, string>
{
{ "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)
{

View File

@@ -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<string, string>
{
{ "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<string, string>
{
{ "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<string, string>
{
{ "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<string, string> { { "id", string.Join(',', songIds) } }
);
var data = checkResult["data"]!;
// 建立ID到可用性的映射解决顺序问题
var availabilityMap = data.AsArray()
.ToDictionary(item => item!["id"]!.GetValue<long>(), item => item!["url"] is not null);
var availabilityMap =
checkResult["data"]
?.AsArray()
.ToDictionary(
item => item!["id"]!.GetValue<long>(),
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<List<BriefCloudOnlineSongInfo>> SearchSongsByIDsAsync(long[] IDs)
{
var list = new List<BriefCloudOnlineSongInfo>();
if (IDs == null || IDs.Length == 0)
{
return [];
}
var idString = string.Join(',', IDs);
var (_, checkResult) = await _api.RequestAsync(
CloudMusicApiProviders.SongUrl,
new Dictionary<string, string> { { "id", string.Join(',', IDs) } }
new Dictionary<string, string> { { "id", idString } }
);
var (_, detailsResult) = await _api.RequestAsync(
CloudMusicApiProviders.SongDetail,
new Dictionary<string, string> { { "ids", string.Join(',', IDs) } }
new Dictionary<string, string> { { "ids", idString } }
);
var data = checkResult["data"]!;
var availabilityMap = data.AsArray()
.ToDictionary(item => item!["id"]!.GetValue<long>(), item => item!["url"] is not null);
var detailsMap = detailsResult["songs"]!
.AsArray()
.ToDictionary(item => item!["id"]!.GetValue<long>(), item => item);
for (var i = 0; i < IDs.Length; i++)
var availabilityMap =
checkResult["data"]
?.AsArray()
.ToDictionary(
item => item!["id"]!.GetValue<long>(),
item => item!["url"] is not null
) ?? [];
var detailsMap =
detailsResult["songs"]
?.AsArray()
.ToDictionary(item => item!["id"]!.GetValue<long>(), item => item) ?? [];
var result = new List<BriefCloudOnlineSongInfo>();
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;
}
}