feat: Enhanced song matching logic (NetEaseMusic).

This commit is contained in:
real-zony 2022-09-22 17:49:54 +08:00
parent c583a9c278
commit 140043db79
10 changed files with 49 additions and 12 deletions

View File

@ -8,6 +8,8 @@ using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils; using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NAudio.Wave;
using TagLib.Mpeg;
using ZonyLrcTools.Cli.Config; using ZonyLrcTools.Cli.Config;
using ZonyLrcTools.Cli.Infrastructure; using ZonyLrcTools.Cli.Infrastructure;
using ZonyLrcTools.Cli.Infrastructure.Album; using ZonyLrcTools.Cli.Infrastructure.Album;
@ -17,6 +19,7 @@ using ZonyLrcTools.Cli.Infrastructure.IO;
using ZonyLrcTools.Cli.Infrastructure.Lyric; using ZonyLrcTools.Cli.Infrastructure.Lyric;
using ZonyLrcTools.Cli.Infrastructure.Tag; using ZonyLrcTools.Cli.Infrastructure.Tag;
using ZonyLrcTools.Cli.Infrastructure.Threading; using ZonyLrcTools.Cli.Infrastructure.Threading;
using File = System.IO.File;
namespace ZonyLrcTools.Cli.Commands.SubCommand namespace ZonyLrcTools.Cli.Commands.SubCommand
{ {
@ -131,7 +134,11 @@ namespace ZonyLrcTools.Cli.Commands.SubCommand
var warpTaskList = files.Select(file => warpTask.RunAsync(() => Task.Run(async () => await _tagLoader.LoadTagAsync(file)))); var warpTaskList = files.Select(file => warpTask.RunAsync(() => Task.Run(async () => await _tagLoader.LoadTagAsync(file))));
var result = (await Task.WhenAll(warpTaskList)) var result = (await Task.WhenAll(warpTaskList))
.Where(m => m != null) .Where(m => m != null)
.Where(m => !string.IsNullOrEmpty(m.Name) || !string.IsNullOrEmpty(m.Artist)); .Where(m => !string.IsNullOrEmpty(m.Name) || !string.IsNullOrEmpty(m.Artist))
.ToList();
// Load music total time info.
result.Foreach(m => { m.TotalTime = (long?)new AudioFileReader(m.FilePath).TotalTime.TotalMilliseconds; });
_logger.LogInformation($"已成功加载 {files.Count} 个音乐文件的标签信息。"); _logger.LogInformation($"已成功加载 {files.Count} 个音乐文件的标签信息。");
@ -173,7 +180,7 @@ namespace ZonyLrcTools.Cli.Commands.SubCommand
{ {
try try
{ {
var lyric = await downloader.DownloadAsync(info.Name, info.Artist); var lyric = await downloader.DownloadAsync(info.Name, info.Artist, info.TotalTime);
var lyricFilePath = Path.Combine(Path.GetDirectoryName(info.FilePath)!, var lyricFilePath = Path.Combine(Path.GetDirectoryName(info.FilePath)!,
$"{Path.GetFileNameWithoutExtension(info.FilePath)}.lrc"); $"{Path.GetFileNameWithoutExtension(info.FilePath)}.lrc");

View File

@ -51,7 +51,7 @@ namespace ZonyLrcTools.Cli.Infrastructure.Album.NetEase
var songDetailJsonStr = await _warpHttpClient.GetAsync( var songDetailJsonStr = await _warpHttpClient.GetAsync(
GetMusicInfoApi, GetMusicInfoApi,
new GetSongDetailsRequest(searchResult.GetFirstMatchSongId(songName)), new GetSongDetailsRequest(searchResult.GetFirstMatchSongId(songName, null)),
_defaultOption); _defaultOption);
var url = JObject.Parse(songDetailJsonStr).SelectToken("$.songs[0].album.picUrl")?.Value<string>(); var url = JObject.Parse(songDetailJsonStr).SelectToken("$.songs[0].album.picUrl")?.Value<string>();

View File

@ -12,8 +12,9 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric
/// </summary> /// </summary>
/// <param name="songName">歌曲的名称。</param> /// <param name="songName">歌曲的名称。</param>
/// <param name="artist">歌曲的作者。</param> /// <param name="artist">歌曲的作者。</param>
/// <param name="duration">歌曲的时长。</param>
/// <returns>歌曲的歌词数据对象。</returns> /// <returns>歌曲的歌词数据对象。</returns>
ValueTask<LyricItemCollection> DownloadAsync(string songName, string artist); ValueTask<LyricItemCollection> DownloadAsync(string songName, string artist, long? duration = null);
/// <summary> /// <summary>
/// 下载器的名称。 /// 下载器的名称。

View File

@ -16,10 +16,11 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric
/// </summary> /// </summary>
/// <param name="songName">歌曲名称。</param> /// <param name="songName">歌曲名称。</param>
/// <param name="artist">歌曲作者/艺术家。</param> /// <param name="artist">歌曲作者/艺术家。</param>
/// <param name="duration">歌曲的时长。</param>
/// <returns>下载完成的歌曲数据。</returns> /// <returns>下载完成的歌曲数据。</returns>
public virtual async ValueTask<LyricItemCollection> DownloadAsync(string songName, string artist) public virtual async ValueTask<LyricItemCollection> DownloadAsync(string songName, string artist, long? duration = null)
{ {
var args = new LyricDownloaderArgs(songName, artist); var args = new LyricDownloaderArgs(songName, artist, duration ?? 0);
await ValidateAsync(args); await ValidateAsync(args);
var downloadDataBytes = await DownloadDataAsync(args); var downloadDataBytes = await DownloadDataAsync(args);
return await GenerateLyricAsync(downloadDataBytes, args); return await GenerateLyricAsync(downloadDataBytes, args);

View File

@ -6,10 +6,13 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric
public string Artist { get; set; } public string Artist { get; set; }
public LyricDownloaderArgs(string songName, string artist) public long Duration { get; set; }
public LyricDownloaderArgs(string songName, string artist, long duration)
{ {
SongName = songName; SongName = songName;
Artist = artist; Artist = artist;
Duration = duration;
} }
} }
} }

View File

@ -49,7 +49,7 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
Type = 1; Type = 1;
Offset = 0; Offset = 0;
IsTotal = true; IsTotal = true;
Limit = 5; Limit = 10;
} }
public SongSearchRequest(string musicName, string artistName) : this() public SongSearchRequest(string musicName, string artistName) : this()

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -10,10 +11,20 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
[JsonProperty("code")] public int StatusCode { get; set; } [JsonProperty("code")] public int StatusCode { get; set; }
public int GetFirstMatchSongId(string songName) public int GetFirstMatchSongId(string songName, long? duration)
{ {
var item = Items.SongItems.FirstOrDefault(x => x.Name == songName); var perfectMatch = Items.SongItems.FirstOrDefault(x => x.Name == songName);
return item?.Id ?? Items.SongItems[0].Id; if (perfectMatch != null)
{
return perfectMatch.Id;
}
if (duration is null or 0)
{
return Items.SongItems.First().Id;
}
return Items.SongItems.OrderBy(t => Math.Abs(t.Duration - duration.Value)).First().Id;
} }
} }
@ -49,6 +60,12 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
/// </summary> /// </summary>
[JsonProperty("album")] [JsonProperty("album")]
public SongAlbumModel Album { get; set; } public SongAlbumModel Album { get; set; }
/// <summary>
/// 歌曲的实际长度。
/// </summary>
[JsonProperty("duration")]
public long Duration { get; set; }
} }
public class SongArtistModel public class SongArtistModel

View File

@ -48,7 +48,7 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase
var lyricResponse = await _warpHttpClient.GetAsync( var lyricResponse = await _warpHttpClient.GetAsync(
NetEaseGetLyricUrl, NetEaseGetLyricUrl,
new GetLyricRequest(searchResult.GetFirstMatchSongId(args.SongName)), new GetLyricRequest(searchResult.GetFirstMatchSongId(args.SongName, args.Duration)),
msg => msg.Headers.Referrer = new Uri(NetEaseRequestReferer)); msg => msg.Headers.Referrer = new Uri(NetEaseRequestReferer));
return Encoding.UTF8.GetBytes(lyricResponse); return Encoding.UTF8.GetBytes(lyricResponse);

View File

@ -1,3 +1,5 @@
using System;
namespace ZonyLrcTools.Cli.Infrastructure namespace ZonyLrcTools.Cli.Infrastructure
{ {
/// <summary> /// <summary>
@ -10,6 +12,11 @@ namespace ZonyLrcTools.Cli.Infrastructure
/// </summary> /// </summary>
public string FilePath { get; } public string FilePath { get; }
/// <summary>
/// 歌曲的实际歌曲长度。
/// </summary>
public long? TotalTime { get; set; }
/// <summary> /// <summary>
/// 歌曲的名称。 /// 歌曲的名称。
/// </summary> /// </summary>

View File

@ -10,6 +10,7 @@
<PackageReference Include="McMaster.Extensions.Hosting.CommandLine" Version="4.0.1" /> <PackageReference Include="McMaster.Extensions.Hosting.CommandLine" Version="4.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="NAudio" Version="2.1.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="2.2.0" /> <PackageReference Include="NetEscapades.Configuration.Yaml" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Refit" Version="6.3.2" /> <PackageReference Include="Refit" Version="6.3.2" />