feat: Completed KuGouLyricDownloader.

完成了酷狗音乐歌词下载器。
This commit is contained in:
real-zony 2021-05-15 17:19:15 +08:00
parent dca66caadb
commit e45319f048
8 changed files with 209 additions and 5 deletions

View File

@ -0,0 +1,27 @@
using Newtonsoft.Json;
namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel
{
public class GetLyricAccessKeyRequest
{
[JsonProperty("ver")]
public int UnknownParameters1 { get; }
[JsonProperty("man")]
public string UnknownParameters2 { get; }
[JsonProperty("client")]
public string UnknownParameters3 { get; }
[JsonProperty("hash")]
public string FileHash { get; }
public GetLyricAccessKeyRequest(string fileHash)
{
UnknownParameters1 = 1;
UnknownParameters2 = "yes";
UnknownParameters3 = "mobi";
FileHash = fileHash;
}
}
}

View File

@ -0,0 +1,26 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel
{
public class GetLyricAccessKeyResponse
{
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("errcode")]
public int ErrorCode { get; set; }
[JsonProperty("candidates")]
public List<GetLyricAccessKeyDataObject> AccessKeyDataObjects { get; set; }
}
public class GetLyricAccessKeyDataObject
{
[JsonProperty("accesskey")]
public string AccessKey { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
}
}

View File

@ -0,0 +1,33 @@
using Newtonsoft.Json;
namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel
{
public class GetLyricRequest
{
[JsonProperty("ver")] public int UnknownParameters1 { get; }
[JsonProperty("client")] public string UnknownParameters2 { get; }
[JsonProperty("fmt")] public string UnknownParameters3 { get; }
[JsonProperty("charset")] public string UnknownParameters4 { get; }
[JsonProperty("id")] public string Id { get; }
[JsonProperty("accesskey")] public string AccessKey { get; }
public GetLyricRequest(string id, string accessKey)
{
UnknownParameters1 = 1;
UnknownParameters2 = "iphone";
UnknownParameters3 = "lrc";
UnknownParameters4 = "utf8";
Id = id;
AccessKey = accessKey;
}
}
public class GetLyricResponse
{
}
}

View File

@ -0,0 +1,25 @@
using System.Text;
using System.Web;
using Newtonsoft.Json;
namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel
{
public class SongSearchRequest
{
[JsonProperty("filter")]
public int Filter { get; }
[JsonProperty("platform")]
public string Platform { get; }
[JsonProperty("keyword")]
public string Keyword { get; }
public SongSearchRequest(string musicName, string artistName)
{
Filter = 2;
Platform = "WebFilter";
Keyword = HttpUtility.UrlEncode($"{musicName}+{artistName}", Encoding.UTF8);
}
}
}

View File

@ -0,0 +1,31 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel
{
public class SongSearchResponse
{
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("data")]
public SongSearchResponseInnerData Data { get; set; }
[JsonProperty("error_code")]
public int ErrorCode { get; set; }
[JsonProperty("error_msg")]
public string ErrorMessage { get; set; }
}
public class SongSearchResponseInnerData
{
[JsonProperty("lists")]
public List<SongSearchResponseSongDetail> List { get; set; }
}
public class SongSearchResponseSongDetail
{
public string FileHash { get; set; }
}
}

View File

@ -1,4 +1,9 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using ZonyLrcTools.Cli.Infrastructure.Exceptions;
using ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel;
using ZonyLrcTools.Cli.Infrastructure.Network;
namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou
@ -10,6 +15,10 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou
private readonly IWarpHttpClient _warpHttpClient;
private readonly ILyricItemCollectionFactory _lyricItemCollectionFactory;
private const string KuGouSearchMusicUrl = @"https://songsearch.kugou.com/song_search_v2";
private const string KuGouGetLyricAccessKeyUrl = @"http://lyrics.kugou.com/search";
private const string KuGouGetLyricUrl = @"http://lyrics.kugou.com/download";
public KuGourLyricDownloader(IWarpHttpClient warpHttpClient,
ILyricItemCollectionFactory lyricItemCollectionFactory)
{
@ -17,14 +26,43 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou
_lyricItemCollectionFactory = lyricItemCollectionFactory;
}
protected override ValueTask<byte[]> DownloadDataAsync(LyricDownloaderArgs args)
protected override async ValueTask<byte[]> DownloadDataAsync(LyricDownloaderArgs args)
{
throw new System.NotImplementedException();
var searchResult = await _warpHttpClient.GetAsync<SongSearchResponse>(KuGouSearchMusicUrl,
new SongSearchRequest(args.SongName, args.Artist));
ValidateSongSearchResponse(searchResult, args);
// 获得特殊的 AccessToken 与 Id真正请求歌词数据。
var accessKeyResponse = await _warpHttpClient.GetAsync<GetLyricAccessKeyResponse>(KuGouGetLyricAccessKeyUrl,
new GetLyricAccessKeyRequest(searchResult.Data.List[0].FileHash));
var accessKeyObject = accessKeyResponse.AccessKeyDataObjects[0];
var lyricResponse = await _warpHttpClient.GetAsync(KuGouGetLyricUrl,
new GetLyricRequest(accessKeyObject.Id, accessKeyObject.AccessKey));
return Encoding.UTF8.GetBytes(lyricResponse);
}
protected override ValueTask<LyricItemCollection> GenerateLyricAsync(byte[] data, LyricDownloaderArgs args)
protected override async ValueTask<LyricItemCollection> GenerateLyricAsync(byte[] data, LyricDownloaderArgs args)
{
throw new System.NotImplementedException();
await ValueTask.CompletedTask;
var lyricJsonObj = JObject.Parse(Encoding.UTF8.GetString(data));
if (lyricJsonObj.SelectToken("$.status").Value<int>() != 200)
{
throw new ErrorCodeException(ErrorCodes.NoMatchingSong, attachObj: args);
}
var lyricText = Encoding.UTF8.GetString(Convert.FromBase64String(lyricJsonObj.SelectToken("$.content").Value<string>()));
return _lyricItemCollectionFactory.Build(lyricText);
}
protected virtual void ValidateSongSearchResponse(SongSearchResponse response, LyricDownloaderArgs args)
{
if (response.ErrorCode != 0 && response.Status != 1 || response.Data.List == null)
{
throw new ErrorCodeException(ErrorCodes.NoMatchingSong, attachObj: args);
}
}
}
}

View File

@ -3,7 +3,6 @@ using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using ZonyLrcTools.Cli.Infrastructure.DependencyInject;
using ZonyLrcTools.Cli.Infrastructure.Exceptions;
using ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel;
using ZonyLrcTools.Cli.Infrastructure.Network;

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
using ZonyLrcTools.Cli.Infrastructure.Lyric;
namespace ZonyLrcTools.Tests.Infrastructure.Lyric
{
public class KuGouLyricDownloaderTests : TestBase
{
[Fact]
public async Task DownloadAsync_Test()
{
var downloaderList = ServiceProvider.GetRequiredService<IEnumerable<ILyricDownloader>>();
var kuGouDownloader = downloaderList.FirstOrDefault(t => t.DownloaderName == InternalLyricDownloaderNames.KuGou);
kuGouDownloader.ShouldNotBeNull();
var lyric = await kuGouDownloader.DownloadAsync("东方红", null);
lyric.ShouldNotBeNull();
lyric.IsPruneMusic.ShouldBe(false);
}
}
}