Skip to content

Commit

Permalink
Merge pull request #12 from PercyDan54/bugfix
Browse files Browse the repository at this point in the history
一些修复
  • Loading branch information
MATRIX-feather authored Nov 4, 2024
2 parents a3730b9 + 445b65b commit 87fed91
Show file tree
Hide file tree
Showing 17 changed files with 230 additions and 243 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void UpdateMetadata(WorkingBeatmap beatmap)
var metadata = beatmap.Metadata;
this.MetaData.Artist = metadata.GetArtist();
this.MetaData.ArtistRomainsed = metadata.Artist;
this.MetaData.Title = metadata.GetTitle();
this.MetaData.Title = metadata.GetTitle().Title;
this.MetaData.TitleRomainsed = metadata.Title;
this.MetaData.Mapper = metadata.Author.Username;
this.MetaData.DiffName = beatmap.BeatmapInfo.DifficultyName;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Localisation;
using osu.Game.Beatmaps;

namespace osu.Game.Rulesets.IGPlayer.Feature.Player.Misc
{
public static class BeatmapMetataExtension
{
public static RomanisableString GetTitleRomanisable(this BeatmapMetadata metadata)
{
return new RomanisableString(metadata.TitleUnicode, metadata.Title);
}

public static RomanisableString GetArtistRomanisable(this BeatmapMetadata metadata)
{
return new RomanisableString(metadata.ArtistUnicode, metadata.Artist);
}

public static string GetTitle(this BeatmapMetadata metadata)
{
return string.IsNullOrEmpty(metadata.TitleUnicode)
? metadata.Title
: metadata.TitleUnicode;
}

public static string GetArtist(this BeatmapMetadata metadata)
{
return string.IsNullOrEmpty(metadata.ArtistUnicode)
? metadata.Artist
: metadata.ArtistUnicode;
}
}
}
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Localisation;
using osu.Game.Beatmaps;

namespace osu.Game.Rulesets.IGPlayer.Feature.Player.Misc
{
public static class BeatmapMetadataExtension
{
public static RomanisableString GetTitleRomanisable(this BeatmapMetadata metadata)
{
return new RomanisableString(metadata.TitleUnicode, metadata.Title);
}

public static RomanisableString GetArtistRomanisable(this BeatmapMetadata metadata)
{
return new RomanisableString(metadata.ArtistUnicode, metadata.Artist);
}

public static (string Title, bool IsUnicode) GetTitle(this BeatmapMetadata metadata)
{
return string.IsNullOrEmpty(metadata.TitleUnicode)
? (metadata.Title, false)
: (metadata.TitleUnicode, true);
}

public static string GetArtist(this BeatmapMetadata metadata)
{
return string.IsNullOrEmpty(metadata.ArtistUnicode)
? metadata.Artist
: metadata.ArtistUnicode;
}
}
}
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
Expand Up @@ -44,5 +44,18 @@ public static int Compute(string s, string t)

return d[n, m];
}

public static float ComputeSimilarPercentage(string s, string t)
{
string source = s.Length > t.Length ? s : t;
string target = s.Length > t.Length ? t : s;

if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(target))
return 0;

int distance = Compute(source, target);
float percentage = 1 - (distance / (float)source.Length);
return Math.Abs(percentage);
}
}
}
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 @@ -74,7 +75,7 @@ public void Search(SearchOption searchOption)
var onFinish = searchOption.OnFinish;
var onFail = searchOption.OnFail;

if (!searchOption.NoLocalFile && searchOption.NoRetry)
if (!searchOption.NoLocalFile)
{
var localLyrics = GetLocalLyrics(beatmap);

Expand Down Expand Up @@ -104,16 +105,15 @@ public void Search(SearchOption searchOption)
currentLyricRequest?.Dispose();

//处理要搜索的歌名: "标题 艺术家"
string title = beatmap.Metadata.GetTitle();
string artist = searchOption.NoArtist ? string.Empty : $" {beatmap.Metadata.GetArtist()}";
string title = searchOption.SearchMode == SearchMode.RomanisedTitle ? beatmap.Metadata.Title : beatmap.Metadata.TitleUnicode;
string artist = searchOption.SearchMode == SearchMode.NoArtist ? string.Empty : beatmap.Metadata.GetArtist();
string target = encoder.Encode($"{title} {artist}");

var req = new APISearchRequest(target);

req.Finished += () =>
{
var meta = RequestFinishMeta.From(req.ResponseObject, beatmap, onFinish, onFail, searchOption.TitleSimiliarThreshold);
meta.NoRetry = searchOption.NoRetry;
var meta = RequestFinishMeta.From(req.ResponseObject, beatmap, onFinish, onFail, searchOption.SearchMode, searchOption.TitleSimilarThreshold);

onSongSearchRequestFinish(meta, req);
};
Expand Down Expand Up @@ -183,7 +183,7 @@ public void SearchByNeteaseID(long id, WorkingBeatmap beatmap, Action<APILyricRe
}
};

var meta = RequestFinishMeta.From(fakeResponse, beatmap, onFinish, onFail, 0);
var meta = RequestFinishMeta.From(fakeResponse, beatmap, onFinish, onFail, 0, 0);
meta.NoRetry = true;

onSongSearchRequestFinish(meta, null);
Expand All @@ -198,69 +198,79 @@ public void SearchByNeteaseID(long id, WorkingBeatmap beatmap, Action<APILyricRe
/// <param name="searchRequest"></param>
private void onSongSearchRequestFinish(RequestFinishMeta meta, APISearchRequest? searchRequest)
{
if (!meta.Success)
var sourceBeatmap = meta.SourceBeatmap;
var songs = meta.SearchResponseRoot.Result?.Songs ?? [];

songs.ForEach(s => s.CalculateSimilarPercentage(sourceBeatmap));

var titleMatches = songs.Where(p => p.TitleSimilarPercentage >= meta.TitleSimilarThreshold)
.OrderByDescending(p => p.TitleSimilarPercentage);
var artistMatches = titleMatches.OrderByDescending(s => s.ArtistSimilarPercentage);
var match = artistMatches.FirstOrDefault();
string title = meta.SearchMode == SearchMode.RomanisedTitle ? sourceBeatmap.Metadata.Title : sourceBeatmap.Metadata.TitleUnicode;

if (match != null)
{
//如果没成功,尝试使用标题重搜
if (meta.SourceBeatmap != null && !meta.NoRetry)
if (match.ArtistSimilarPercentage >= (meta.SearchMode == SearchMode.NoArtist ? 0 : meta.TitleSimilarThreshold))
{
var searchMeta = SearchOption.FromRequestFinishMeta(meta);
searchMeta.NoArtist = true;
searchMeta.NoRetry = true;
searchMeta.NoLocalFile = true;
Logging.Log($"Beatmap: '{title}' <-> '{match.Name}' -> {match.TitleSimilarPercentage} >= {meta.TitleSimilarThreshold}");
}
}

if (searchRequest != null && searchRequest == currentSearchRequest)
setState(SearchState.FuzzySearching);
if (match == null)
{
var searchMeta = SearchOption.FromRequestFinishMeta(meta);

//Logging.Log("精准搜索失败, 将尝试只搜索标题...");
Search(searchMeta);
}
else
switch (meta.SearchMode)
{
if (searchRequest != null && searchRequest == currentSearchRequest)
setState(SearchState.Fail);
case SearchMode.Normal:
Logging.Log("尝试使用罗马音标题搜索");
searchMeta.SearchMode = SearchMode.RomanisedTitle;
searchMeta.NoLocalFile = true;

meta.OnFail?.Invoke("未搜索到对应歌曲!");
}
if (searchRequest != null && searchRequest == currentSearchRequest)
setState(SearchState.FuzzySearching);

return;
}
Search(searchMeta);
break;

float similiarPrecentage = meta.GetSimiliarPrecentage();
case SearchMode.RomanisedTitle:
searchMeta.SearchMode = SearchMode.NoArtist;
searchMeta.NoLocalFile = true;

Logging.Log($"Beatmap: '{meta.SourceBeatmap?.Metadata.GetTitle() ?? "???"}' <-> '{meta.GetNeteaseTitle()}' -> {similiarPrecentage} <-> {meta.TitleSimiliarThreshold}");
if (searchRequest != null && searchRequest == currentSearchRequest)
setState(SearchState.FuzzySearching);

if (similiarPrecentage >= meta.TitleSimiliarThreshold)
{
//标题匹配,发送歌词查询请求
var req = new APILyricRequest(meta.SongID);
req.Finished += () =>
{
if (currentLyricRequest == req)
setState(SearchState.Success);
Search(searchMeta);
break;

meta.OnFinish?.Invoke(req.ResponseObject);
};
req.Failed += e =>
{
if (currentLyricRequest == req)
case SearchMode.NoArtist:
meta.OnFail?.Invoke("标题匹配失败, 将不会继续搜索歌词...");
setState(SearchState.Fail);
break;
}

Logging.LogError(e, "获取歌词失败");
};
req.PerformAsync(cancellationTokenSource.Token).ConfigureAwait(false);

currentLyricRequest = req;
return;
}
else

var req = new APILyricRequest(match.ID);
req.Finished += () =>
{
if (currentLyricRequest == req)
setState(SearchState.Success);

meta.OnFinish?.Invoke(req.ResponseObject);
};
req.Failed += e =>
{
//Logging.Log("标题匹配失败, 将不会继续搜索歌词...");
this.setState(SearchState.Fail);
if (currentLyricRequest == req)
setState(SearchState.Fail);

Logging.Log($"对 {meta.SourceBeatmap?.Metadata.GetTitle() ?? "未知谱面"} 的标题匹配失败:");
Logging.Log($"Beatmap: '{meta.SourceBeatmap?.Metadata.GetTitle() ?? "???"}' <-> '{meta.GetNeteaseTitle()}' -> {similiarPrecentage} < {meta.TitleSimiliarThreshold}");
Logging.LogError(e, "获取歌词失败");
};
req.PerformAsync(cancellationTokenSource.Token).ConfigureAwait(false);

meta.OnFail?.Invoke("标题匹配失败, 将不会继续搜索歌词...");
}
currentLyricRequest = req;
}

#endregion
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,72 +13,27 @@ public struct RequestFinishMeta
/// <summary>
/// 与此请求对应的<see cref="WorkingBeatmap"/>
/// </summary>
public WorkingBeatmap? SourceBeatmap;
public WorkingBeatmap SourceBeatmap;

/// <summary>
/// 标题匹配阈值,值越高要求越严格
/// </summary>
public float TitleSimiliarThreshold;
public float TitleSimilarThreshold;

/// <summary>
/// 请求是否成功?
/// </summary>
public bool Success;

/// <summary>
/// 是否要重新搜索?
/// </summary>
public bool NoRetry;

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

/// <summary>
/// 获取网易云歌曲标题和搜索标题的相似度
/// 请求是否成功?
/// </summary>
/// <returns>相似度百分比</returns>
public float GetSimiliarPrecentage()
{
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 precentage = 1 - (distance / (float)source.Length);

return Math.Abs(precentage);
}

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

/// <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
};
}
public bool NoRetry;

/// <summary>
/// 通过给定的参数构建<see cref="RequestFinishMeta"/>>
Expand All @@ -89,20 +42,22 @@ public static RequestFinishMeta Fail(WorkingBeatmap? beatmap = null)
/// <param name="sourceBeatmap">和此Meta对应的<see cref="WorkingBeatmap"/>></param>
/// <param name="onFinish">完成时要进行的动作</param>
/// <param name="onFail">失败时要进行的动作</param>
/// <param name="titleSimiliarThreshold"><see cref="TitleSimiliarThreshold"/></param>
/// <param name="searchMode"><see cref="SearchMode"/></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,
SearchMode searchMode,
float titleSimiliarThreshold)
{
return new RequestFinishMeta
{
OnFinish = onFinish,
OnFail = onFail,
SearchResponseRoot = responseRoot,
Success = (responseRoot.Result?.Songs?.First().ID ?? -1) > 0,
SourceBeatmap = sourceBeatmap,
TitleSimiliarThreshold = titleSimiliarThreshold
SearchMode = searchMode,
TitleSimilarThreshold = titleSimiliarThreshold
};
}
}
Expand Down
Loading

0 comments on commit 87fed91

Please sign in to comment.