mirror of
https://github.com/LanZhan-Harmony/WindowsMusicPlayer-TheUntamedMusicPlayer.git
synced 2026-05-06 19:20:18 +08:00
更新搜索
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user