From f935f076091b89abe8e3511c539c8438e5c6c0cb Mon Sep 17 00:00:00 2001 From: real-zony Date: Mon, 17 Apr 2023 00:47:23 +0800 Subject: [PATCH] feat: Modified the lyrics interface for Netease Cloud Music to support higher concurrency. --- .../Commands/SubCommand/DownloadCommand.cs | 2 +- .../Lyrics/LyricsDownloader.cs | 4 +- .../NetEase/JsonModel/GetLyricRequest.cs | 2 +- .../NetEase/JsonModel/SongSearchRequest.cs | 2 +- .../NetEase/NetEaseLyricsProvider.cs | 51 +++++++++++++------ .../ZonyLrcTools.Common.csproj | 1 + .../Lyrics/NetEaseLyricsProviderTests.cs | 7 +++ .../Lyrics/QQLyricsProviderTests.cs | 7 +++ 8 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/ZonyLrcTools.Cli/Commands/SubCommand/DownloadCommand.cs b/src/ZonyLrcTools.Cli/Commands/SubCommand/DownloadCommand.cs index cec3311..083aecb 100644 --- a/src/ZonyLrcTools.Cli/Commands/SubCommand/DownloadCommand.cs +++ b/src/ZonyLrcTools.Cli/Commands/SubCommand/DownloadCommand.cs @@ -47,7 +47,7 @@ namespace ZonyLrcTools.Cli.Commands.SubCommand public bool DownloadAlbum { get; set; } [Option("-n|--number", CommandOptionType.SingleValue, Description = "指定下载时候的线程数量。(默认值 2)")] - public int ParallelNumber { get; set; } = 2; + public int ParallelNumber { get; set; } = 1; #endregion diff --git a/src/ZonyLrcTools.Common/Lyrics/LyricsDownloader.cs b/src/ZonyLrcTools.Common/Lyrics/LyricsDownloader.cs index f3fbbf1..74baf1f 100644 --- a/src/ZonyLrcTools.Common/Lyrics/LyricsDownloader.cs +++ b/src/ZonyLrcTools.Common/Lyrics/LyricsDownloader.cs @@ -1,5 +1,6 @@ using System.Text; using Microsoft.Extensions.Options; +using Polly; using ZonyLrcTools.Common.Configuration; using ZonyLrcTools.Common.Infrastructure.DependencyInject; using ZonyLrcTools.Common.Infrastructure.Exceptions; @@ -36,7 +37,7 @@ public class LyricsDownloader : ILyricsDownloader, ISingletonDependency } public async Task DownloadAsync(List needDownloadMusicInfos, - int parallelCount = 2, + int parallelCount = 1, CancellationToken cancellationToken = default) { await _logger.InfoAsync("开始下载歌词文件数据..."); @@ -106,6 +107,7 @@ public class LyricsDownloader : ILyricsDownloader, ISingletonDependency { _logger.LogWarningInfo(ex); info.IsSuccessful = false; + throw; } catch (Exception ex) { diff --git a/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/JsonModel/GetLyricRequest.cs b/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/JsonModel/GetLyricRequest.cs index 98a5be8..acc04c5 100644 --- a/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/JsonModel/GetLyricRequest.cs +++ b/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/JsonModel/GetLyricRequest.cs @@ -8,7 +8,7 @@ namespace ZonyLrcTools.Common.Lyrics.Providers.NetEase.JsonModel { public GetLyricRequest(long songId) { - OS = "ios"; + OS = "pc"; Id = songId; Lv = Kv = Tv = Rv = -1; } diff --git a/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/JsonModel/SongSearchRequest.cs b/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/JsonModel/SongSearchRequest.cs index 14df5e8..86072ce 100644 --- a/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/JsonModel/SongSearchRequest.cs +++ b/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/JsonModel/SongSearchRequest.cs @@ -60,7 +60,7 @@ namespace ZonyLrcTools.Common.Lyrics.Providers.NetEase.JsonModel var regex = new Regex(@"\([^)]*\)"); musicName = regex.Replace(musicName, string.Empty); - SearchKey = HttpUtility.UrlEncode($"{musicName}+{artistName}", Encoding.UTF8); + SearchKey = $"{musicName}+{artistName}"; Limit = limit; } } diff --git a/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/NetEaseLyricsProvider.cs b/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/NetEaseLyricsProvider.cs index 56f10d8..3ba76b6 100644 --- a/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/NetEaseLyricsProvider.cs +++ b/src/ZonyLrcTools.Common/Lyrics/Providers/NetEase/NetEaseLyricsProvider.cs @@ -2,6 +2,7 @@ using System.Net.Http.Headers; using Microsoft.Extensions.Options; using Newtonsoft.Json; using ZonyLrcTools.Common.Configuration; +using ZonyLrcTools.Common.Infrastructure.Encryption; using ZonyLrcTools.Common.Infrastructure.Exceptions; using ZonyLrcTools.Common.Infrastructure.Network; using ZonyLrcTools.Common.Lyrics.Providers.NetEase.JsonModel; @@ -16,8 +17,8 @@ namespace ZonyLrcTools.Common.Lyrics.Providers.NetEase private readonly ILyricsItemCollectionFactory _lyricsItemCollectionFactory; private readonly GlobalOptions _options; - private const string NetEaseSearchMusicUrl = @"https://music.163.com/api/search/get/web"; - private const string NetEaseGetLyricUrl = @"https://music.163.com/api/song/lyric"; + private const string NetEaseSearchMusicUrl = @"https://music.163.com/weapi/cloudsearch/get/web"; + private const string NetEaseGetLyricUrl = @"https://music.163.com/weapi/song/lyric?csrf_token="; private const string NetEaseRequestReferer = @"https://music.163.com"; private const string NetEaseRequestContentType = @"application/x-www-form-urlencoded"; @@ -33,25 +34,30 @@ namespace ZonyLrcTools.Common.Lyrics.Providers.NetEase protected override async ValueTask DownloadDataAsync(LyricsProviderArgs args) { - var searchResult = await _warpHttpClient.PostAsync( - NetEaseSearchMusicUrl, - new SongSearchRequest(args.SongName, args.Artist, _options.Provider.Lyric.GetLyricProviderOption(DownloaderName).Depth), - true, - msg => + var secretKey = NetEaseMusicEncryptionHelper.CreateSecretKey(16); + var encSecKey = NetEaseMusicEncryptionHelper.RsaEncode(secretKey); + + var searchResult = await _warpHttpClient.PostAsync(NetEaseSearchMusicUrl, + requestOption: request => { - msg.Headers.Referrer = new Uri(NetEaseRequestReferer); - if (msg.Content != null) - { - msg.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(NetEaseRequestContentType); - } + request.Headers.Referrer = new Uri(NetEaseRequestReferer); + request.Content = new FormUrlEncodedContent(HandleRequest( + new SongSearchRequest(args.SongName, args.Artist, _options.Provider.Lyric.GetLyricProviderOption(DownloaderName).Depth), + secretKey, + encSecKey)); }); ValidateSongSearchResponse(searchResult, args); - return await _warpHttpClient.GetAsync( - NetEaseGetLyricUrl, - new GetLyricRequest(searchResult.GetFirstMatchSongId(args.SongName, args.Duration)), - msg => msg.Headers.Referrer = new Uri(NetEaseRequestReferer)); + return await _warpHttpClient.PostAsync(NetEaseGetLyricUrl, + requestOption: request => + { + request.Headers.Referrer = new Uri(NetEaseRequestReferer); + request.Content = new FormUrlEncodedContent(HandleRequest( + new GetLyricRequest(searchResult.GetFirstMatchSongId(args.SongName, args.Duration)), + secretKey, + encSecKey)); + }); } protected override async ValueTask GenerateLyricAsync(object lyricsObject, LyricsProviderArgs args) @@ -86,5 +92,18 @@ namespace ZonyLrcTools.Common.Lyrics.Providers.NetEase throw new ErrorCodeException(ErrorCodes.NoMatchingSong, attachObj: args); } } + + private Dictionary HandleRequest(object srcParams, string secretKey, string encSecKey) + { + return new Dictionary + { + { + "params", NetEaseMusicEncryptionHelper.AesEncode( + NetEaseMusicEncryptionHelper.AesEncode( + JsonConvert.SerializeObject(srcParams), NetEaseMusicEncryptionHelper.Nonce), secretKey) + }, + { "encSecKey", encSecKey } + }; + } } } \ No newline at end of file diff --git a/src/ZonyLrcTools.Common/ZonyLrcTools.Common.csproj b/src/ZonyLrcTools.Common/ZonyLrcTools.Common.csproj index 114c0fd..2a19062 100644 --- a/src/ZonyLrcTools.Common/ZonyLrcTools.Common.csproj +++ b/src/ZonyLrcTools.Common/ZonyLrcTools.Common.csproj @@ -14,6 +14,7 @@ + diff --git a/tests/ZonyLrcTools.Tests/Infrastructure/Lyrics/NetEaseLyricsProviderTests.cs b/tests/ZonyLrcTools.Tests/Infrastructure/Lyrics/NetEaseLyricsProviderTests.cs index 85a9190..c4c8611 100644 --- a/tests/ZonyLrcTools.Tests/Infrastructure/Lyrics/NetEaseLyricsProviderTests.cs +++ b/tests/ZonyLrcTools.Tests/Infrastructure/Lyrics/NetEaseLyricsProviderTests.cs @@ -105,5 +105,12 @@ namespace ZonyLrcTools.Tests.Infrastructure.Lyrics var lyric = await _lyricsProvider.DownloadAsync("橄榄树", "苏曼"); lyric.ToString().ShouldNotBeNullOrEmpty(); } + + [Fact] + public async Task DownloadAsync_Issue133_Test() + { + var lyric = await _lyricsProvider.DownloadAsync("Everything", "Yinyues"); + lyric.ToString().ShouldNotBeNullOrEmpty(); + } } } \ No newline at end of file diff --git a/tests/ZonyLrcTools.Tests/Infrastructure/Lyrics/QQLyricsProviderTests.cs b/tests/ZonyLrcTools.Tests/Infrastructure/Lyrics/QQLyricsProviderTests.cs index c9076d3..c16674f 100644 --- a/tests/ZonyLrcTools.Tests/Infrastructure/Lyrics/QQLyricsProviderTests.cs +++ b/tests/ZonyLrcTools.Tests/Infrastructure/Lyrics/QQLyricsProviderTests.cs @@ -37,5 +37,12 @@ namespace ZonyLrcTools.Tests.Infrastructure.Lyrics lyric.IsPruneMusic.ShouldBeFalse(); lyric.ToString().ShouldContain("你好像快要不能呼吸"); } + + [Fact] + public async Task DownloadAsync_Issue133_Test() + { + var lyric = await _lyricsProvider.DownloadAsync("天ノ弱", "漆柚"); + lyric.ToString().ShouldNotBeNullOrEmpty(); + } } } \ No newline at end of file