diff --git a/src/ZonyLrcTools.Cli/Infrastructure/Lyric/KuGou/KuGourLyricDownloader.cs b/src/ZonyLrcTools.Cli/Infrastructure/Lyric/KuGou/KuGourLyricDownloader.cs index 5f46a19..71fe40c 100644 --- a/src/ZonyLrcTools.Cli/Infrastructure/Lyric/KuGou/KuGourLyricDownloader.cs +++ b/src/ZonyLrcTools.Cli/Infrastructure/Lyric/KuGou/KuGourLyricDownloader.cs @@ -22,7 +22,7 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou throw new System.NotImplementedException(); } - protected override ValueTask GenerateLyricAsync(byte[] data) + protected override ValueTask GenerateLyricAsync(byte[] data, LyricDownloaderArgs args) { throw new System.NotImplementedException(); } diff --git a/src/ZonyLrcTools.Cli/Infrastructure/Lyric/QQMusic/JsonModel/GetLyricRequest.cs b/src/ZonyLrcTools.Cli/Infrastructure/Lyric/QQMusic/JsonModel/GetLyricRequest.cs new file mode 100644 index 0000000..c822221 --- /dev/null +++ b/src/ZonyLrcTools.Cli/Infrastructure/Lyric/QQMusic/JsonModel/GetLyricRequest.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; + +namespace ZonyLrcTools.Cli.Infrastructure.Lyric.QQMusic.JsonModel +{ + public class GetLyricRequest + { + [JsonProperty("nobase64")] public int IsNoBase64Encoding { get; set; } + + [JsonProperty("songmid")] public string SongId { get; set; } + + [JsonProperty("platform")] public string ClientPlatform { get; set; } + + [JsonProperty("inCharset")] public string InCharset { get; set; } + + [JsonProperty("outCharset")] public string OutCharset { get; set; } + + [JsonProperty("g_tk")] public int Gtk { get; set; } + + protected GetLyricRequest() + { + } + + public GetLyricRequest(string songId) + { + IsNoBase64Encoding = 1; + SongId = songId; + ClientPlatform = "yqq"; + InCharset = "utf8"; + OutCharset = "utf-8"; + Gtk = 5381; + } + } +} \ No newline at end of file diff --git a/src/ZonyLrcTools.Cli/Infrastructure/Lyric/QQMusic/QQLyricDownloader.cs b/src/ZonyLrcTools.Cli/Infrastructure/Lyric/QQMusic/QQLyricDownloader.cs index a3b23ca..210a128 100644 --- a/src/ZonyLrcTools.Cli/Infrastructure/Lyric/QQMusic/QQLyricDownloader.cs +++ b/src/ZonyLrcTools.Cli/Infrastructure/Lyric/QQMusic/QQLyricDownloader.cs @@ -1,4 +1,10 @@ +using System; +using System.Linq; +using System.Text; using System.Threading.Tasks; +using System.Web; +using Newtonsoft.Json.Linq; +using ZonyLrcTools.Cli.Infrastructure.Exceptions; using ZonyLrcTools.Cli.Infrastructure.Lyric.QQMusic.JsonModel; using ZonyLrcTools.Cli.Infrastructure.Network; @@ -12,6 +18,9 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.QQMusic private readonly ILyricItemCollectionFactory _lyricItemCollectionFactory; private const string QQSearchMusicUrl = @"https://c.y.qq.com/soso/fcgi-bin/client_search_cp"; + private const string QQGetLyricUrl = @"https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg"; + + private const string QQMusicRequestReferer = @"https://y.qq.com/"; public QQLyricDownloader(IWarpHttpClient warpHttpClient, ILyricItemCollectionFactory lyricItemCollectionFactory) @@ -22,15 +31,54 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.QQMusic protected override async ValueTask DownloadDataAsync(LyricDownloaderArgs args) { - var searchResult = await _warpHttpClient.PostAsync( + var searchResult = await _warpHttpClient.GetAsync( QQSearchMusicUrl, new SongSearchRequest(args.SongName, args.Artist)); - throw new System.NotImplementedException(); + + ValidateSongSearchResponse(searchResult, args); + + var lyricJsonString = await _warpHttpClient.GetAsync(QQGetLyricUrl, + new GetLyricRequest(searchResult.Data.Song.SongItems.FirstOrDefault()?.SongId), + op => op.Headers.Referrer = new Uri(QQMusicRequestReferer)); + + return Encoding.UTF8.GetBytes(lyricJsonString); } - protected override ValueTask GenerateLyricAsync(byte[] data) + protected override async ValueTask GenerateLyricAsync(byte[] data, LyricDownloaderArgs args) { - throw new System.NotImplementedException(); + await ValueTask.CompletedTask; + + var lyricJsonString = Encoding.UTF8.GetString(data); + lyricJsonString = lyricJsonString.Replace(@"MusicJsonCallback(", string.Empty).TrimEnd(')'); + + if (lyricJsonString.Contains("\"code\":-1901")) + { + throw new ErrorCodeException(ErrorCodes.NoMatchingSong, attachObj: args); + } + + if (lyricJsonString.Contains("此歌曲为没有填词的纯音乐,请您欣赏")) + { + return _lyricItemCollectionFactory.Build(null); + } + + var lyricJsonObj = JObject.Parse(lyricJsonString); + var sourceLyric = HttpUtility.HtmlDecode(HttpUtility.HtmlDecode(lyricJsonObj.SelectToken("$.lyric").Value())); + var translateLyric = HttpUtility.HtmlDecode(HttpUtility.HtmlDecode(lyricJsonObj.SelectToken("$.trans").Value())); + + return _lyricItemCollectionFactory.Build(sourceLyric, translateLyric); + } + + protected virtual void ValidateSongSearchResponse(SongSearchResponse response, LyricDownloaderArgs args) + { + if (response is not {StatusCode: 0} || response.Data.Song.SongItems == null) + { + throw new ErrorCodeException(ErrorCodes.TheReturnValueIsIllegal, attachObj: args); + } + + if (response.Data.Song.SongItems.Count <= 0) + { + throw new ErrorCodeException(ErrorCodes.NoMatchingSong, attachObj: args); + } } } } \ No newline at end of file