Skip to content

Commit

Permalink
尝试匹配多个搜索结果
Browse files Browse the repository at this point in the history
  • Loading branch information
PercyDan54 committed Oct 29, 2024
1 parent f70a51d commit 436d7c7
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class APISearchRequest : OsuJsonWebRequest<APISearchResponseRoot>
{
public APISearchRequest(string target)
{
Url = $"https://music.163.com/api/search/get/web?hlpretag=&hlposttag=&s={target}&type=1&total=true&limit=1";
Url = $"https://music.163.com/api/search/get/web?hlpretag=&hlposttag=&s={target}&type=1&total=true&limit=10";
}

protected override void ProcessResponse()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Encodings.Web;
using System.Threading;
Expand Down Expand Up @@ -198,41 +199,27 @@ public void SearchByNeteaseID(long id, WorkingBeatmap beatmap, Action<APILyricRe
/// <param name="searchRequest"></param>
private void onSongSearchRequestFinish(RequestFinishMeta meta, APISearchRequest? searchRequest)
{
if (!meta.Success)
{
//如果没成功,尝试使用标题重搜
if (meta.SourceBeatmap != null && !meta.NoRetry)
{
var searchMeta = SearchOption.FromRequestFinishMeta(meta);
searchMeta.NoArtist = true;
searchMeta.NoRetry = true;
searchMeta.NoLocalFile = true;

if (searchRequest != null && searchRequest == currentSearchRequest)
setState(SearchState.FuzzySearching);

//Logging.Log("精准搜索失败, 将尝试只搜索标题...");
Search(searchMeta);
}
else
{
if (searchRequest != null && searchRequest == currentSearchRequest)
setState(SearchState.Fail);

meta.OnFail?.Invoke("未搜索到对应歌曲!");
}
var sourceBeatmap = meta.SourceBeatmap;
var songs = meta.SearchResponseRoot.Result?.Songs;

if (songs == null)
{
setState(SearchState.Fail);
meta.OnFail?.Invoke("搜索请求失败");
return;
}

float similarPercentage = meta.GetSimilarPercentage();

Logging.Log($"Beatmap: '{meta.SourceBeatmap?.Metadata.GetTitle() ?? "???"}' <-> '{meta.GetNeteaseTitle()}' -> {similarPercentage} <-> {meta.TitleSimilarThreshold}");
var titleMatches = songs.Select(s => new { Song = s, SimilarPercentage = s.GetSimilarPercentage(sourceBeatmap) })
.Where(p => p.SimilarPercentage >= meta.TitleSimilarThreshold)
.OrderBy(p => p.SimilarPercentage);
var artistMatches = titleMatches.OrderBy(s => LevenshteinDistance.Compute(s.Song.GetArtist(), sourceBeatmap.Metadata.GetArtist()));
var perfectMatch = artistMatches.FirstOrDefault();

if (similarPercentage >= meta.TitleSimilarThreshold)
if (perfectMatch != null && perfectMatch.SimilarPercentage > meta.TitleSimilarThreshold)
{
Logging.Log($"Beatmap: '{sourceBeatmap.Metadata.GetTitle()}' <-> '{perfectMatch.Song.Name}' -> {perfectMatch.SimilarPercentage} > {meta.TitleSimilarThreshold}");
//标题匹配,发送歌词查询请求
var req = new APILyricRequest(meta.SongID);
var req = new APILyricRequest(perfectMatch.Song.ID);
req.Finished += () =>
{
if (currentLyricRequest == req)
Expand All @@ -254,10 +241,10 @@ private void onSongSearchRequestFinish(RequestFinishMeta meta, APISearchRequest?
else
{
//Logging.Log("标题匹配失败, 将不会继续搜索歌词...");
this.setState(SearchState.Fail);
setState(SearchState.Fail);

Logging.Log($"对 {meta.SourceBeatmap?.Metadata.GetTitle() ?? "未知谱面"} 的标题匹配失败:");
Logging.Log($"Beatmap: '{meta.SourceBeatmap?.Metadata.GetTitle() ?? "???"}' <-> '{meta.GetNeteaseTitle()}' -> {similarPercentage} < {meta.TitleSimilarThreshold}");
Logging.Log($"对 {sourceBeatmap?.Metadata.GetTitle() ?? "未知谱面"} 的标题匹配失败:");
//Logging.Log($"Beatmap: '{sourceBeatmap?.Metadata.GetTitle() ?? "???"}' <-> '{meta.GetNeteaseTitle()}' -> {similarPercentage} < {meta.TitleSimilarThreshold}");

meta.OnFail?.Invoke("标题匹配失败, 将不会继续搜索歌词...");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.IGPlayer.Feature.Player.Misc;
using osu.Game.Rulesets.IGPlayer.Feature.Player.Plugins.Bundle.CloudMusic.Misc;

namespace osu.Game.Rulesets.IGPlayer.Feature.Player.Plugins.Bundle.CloudMusic.Helper
Expand All @@ -15,7 +13,7 @@ public struct RequestFinishMeta
/// <summary>
/// 与此请求对应的<see cref="WorkingBeatmap"/>
/// </summary>
public WorkingBeatmap? SourceBeatmap;
public WorkingBeatmap SourceBeatmap;

/// <summary>
/// 标题匹配阈值,值越高要求越严格
Expand All @@ -32,56 +30,6 @@ public struct RequestFinishMeta
/// </summary>
public bool NoRetry;

/// <summary>
/// 歌曲ID,未搜到歌曲时返回-1
/// </summary>
public long SongID => (SearchResponseRoot.Result?.Songs?.First().ID ?? -1);

/// <summary>
/// 获取网易云歌曲标题和搜索标题的相似度
/// </summary>
/// <returns>相似度百分比</returns>
public float GetSimilarPercentage()
{
string neteaseTitle = GetNeteaseTitle().ToLowerInvariant();
string ourTitle = SourceBeatmap?.Metadata.GetTitle().ToLowerInvariant() ?? string.Empty;

string source = neteaseTitle.Length > ourTitle.Length ? neteaseTitle : ourTitle;
string target = neteaseTitle.Length > ourTitle.Length ? ourTitle : neteaseTitle;

if (string.IsNullOrEmpty(neteaseTitle) || string.IsNullOrEmpty(ourTitle)) return 0;

int distance = LevenshteinDistance.Compute(source, target);
float percentage = 1 - (distance / (float)source.Length);

return Math.Abs(percentage);
}

public string GetNeteaseTitle()
{
return SearchResponseRoot?.Result?.Songs?.First().Name ?? string.Empty;
}

/// <summary>
/// 返回一个失败的<see cref="RequestFinishMeta"/>
/// </summary>
/// <param name="beatmap">和此Meta对应的<see cref="WorkingBeatmap"/>></param>
/// <returns>通过参数构建的<see cref="RequestFinishMeta"/>></returns>
public static RequestFinishMeta Fail(WorkingBeatmap? beatmap = null)
{
return new RequestFinishMeta
{
Success = false,

OnFinish = null,
OnFail = null,
SearchResponseRoot = new APISearchResponseRoot(),

SourceBeatmap = beatmap,
NoRetry = true
};
}

/// <summary>
/// 通过给定的参数构建<see cref="RequestFinishMeta"/>>
/// </summary>
Expand All @@ -91,7 +39,7 @@ public static RequestFinishMeta Fail(WorkingBeatmap? beatmap = null)
/// <param name="onFail">失败时要进行的动作</param>
/// <param name="titleSimiliarThreshold"><see cref="TitleSimilarThreshold"/></param>
/// <returns>通过参数构建的<see cref="RequestFinishMeta"/>></returns>
public static RequestFinishMeta From(APISearchResponseRoot responseRoot, WorkingBeatmap? sourceBeatmap,
public static RequestFinishMeta From(APISearchResponseRoot responseRoot, WorkingBeatmap sourceBeatmap,
Action<APILyricResponseRoot>? onFinish, Action<string>? onFail,
float titleSimiliarThreshold)
{
Expand All @@ -100,7 +48,6 @@ public static RequestFinishMeta From(APISearchResponseRoot responseRoot, Working
OnFinish = onFinish,
OnFail = onFail,
SearchResponseRoot = responseRoot,
Success = (responseRoot.Result?.Songs?.First().ID ?? -1) > 0,
SourceBeatmap = sourceBeatmap,
TitleSimilarThreshold = titleSimiliarThreshold
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.IGPlayer.Feature.Player.Misc;
using osu.Game.Rulesets.IGPlayer.Feature.Player.Plugins.Bundle.CloudMusic.Helper;

namespace osu.Game.Rulesets.IGPlayer.Feature.Player.Plugins.Bundle.CloudMusic.Misc
{
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class APISongInfo
{
[JsonProperty("id")]
public long ID { get; set; }

[JsonProperty("name")]
public string? Name { get; set; }

public List<APIArtistInfo> Artists { get; set; } = [];

/// <summary>
/// 获取网易云歌曲标题和搜索标题的相似度
/// </summary>
/// <returns>相似度百分比</returns>
public float GetSimilarPercentage(WorkingBeatmap? beatmap)
{
string neteaseTitle = Name?.ToLowerInvariant() ?? string.Empty;
string ourTitle = beatmap?.Metadata.GetTitle().ToLowerInvariant() ?? string.Empty;

string source = neteaseTitle.Length > ourTitle.Length ? neteaseTitle : ourTitle;
string target = neteaseTitle.Length > ourTitle.Length ? ourTitle : neteaseTitle;

if (string.IsNullOrEmpty(neteaseTitle) || string.IsNullOrEmpty(ourTitle)) return 0;

int distance = LevenshteinDistance.Compute(source, target);
float percentage = 1 - (distance / (float)source.Length);

return Math.Abs(percentage);
}

public string GetArtist() => string.Join(' ', Artists.Select(a => a.Name));
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
#nullable disable

using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace osu.Game.Rulesets.IGPlayer.Feature.Player.Plugins.Bundle.CloudMusic.Misc
{
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class APIArtistInfo
{
public int id { get; set; }
public string name { get; set; }
public string picUrl { get; set; }
public IList<string> alias { get; set; }
public int albunSize { get; set; }
public int picId { get; set; }
public string img1v1Url { get; set; }
public int img1v1 { get; set; }
public string trans { get; set; }
public int albumSize { get; set; }
public int ID { get; set; }
public string Name { get; set; } = string.Empty;
public string PicUrl { get; set; } = string.Empty;
public IList<string>? Alias { get; set; }
public int AlbunSize { get; set; }
public int PicId { get; set; }

[JsonProperty("img1v1Url")]
public string Img1V1Url { get; set; } = string.Empty;

[JsonProperty("img1v1")]
public int Img1V1 { get; set; }

public string? Trans { get; set; }
public int AlbumSize { get; set; }
}
}

0 comments on commit 436d7c7

Please sign in to comment.