mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-12 02:44:56 +08:00
fix: fill Duration (via searching NCM) for amll-ttml-db lyrics source; improve matching system
This commit is contained in:
@@ -36,6 +36,12 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
return songInfo;
|
||||
}
|
||||
|
||||
public SongInfo WithSongId(string value)
|
||||
{
|
||||
songInfo.SongId = value;
|
||||
return songInfo;
|
||||
}
|
||||
|
||||
public PlayHistoryItem? ToPlayHistoryItem(double actualPlayedMs)
|
||||
{
|
||||
if (songInfo == null) return null;
|
||||
|
||||
@@ -10,27 +10,27 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static partial class MetadataComparer
|
||||
{
|
||||
private const double WeightTitle = 0.40;
|
||||
private const double WeightArtist = 0.40;
|
||||
private const double WeightTitle = 0.30;
|
||||
private const double WeightArtist = 0.30;
|
||||
private const double WeightAlbum = 0.10;
|
||||
private const double WeightDuration = 0.10;
|
||||
private const double WeightDuration = 0.30;
|
||||
|
||||
// JaroWinkler 适合短字符串匹配
|
||||
private static readonly JaroWinkler _algo = new();
|
||||
|
||||
public static int CalculateScore(SongInfo songInfo, LyricsCacheItem remote)
|
||||
{
|
||||
return CalculateScore(songInfo, remote.Title, remote.Artist, remote.Album, remote.Duration * 1000);
|
||||
return CalculateScore(songInfo, remote.Title, remote.Artist, remote.Album, remote.Duration);
|
||||
}
|
||||
|
||||
public static int CalculateScore(SongInfo songInfo, FilesIndexItem local)
|
||||
{
|
||||
return CalculateScore(songInfo, local.Title, local.Artist, local.Album, local.Duration * 1000, local.FileName);
|
||||
return CalculateScore(songInfo, local.Title, local.Artist, local.Album, local.Duration, local.FileName);
|
||||
}
|
||||
|
||||
public static int CalculateScore(
|
||||
SongInfo songInfo,
|
||||
string? compareTitle, string? compareArtist, string? compareAlbum, double? compareDurationMs, string? compareFileName = null)
|
||||
string? compareTitle, string? compareArtist, string? compareAlbum, double? compareDuration, string? compareFileName = null)
|
||||
{
|
||||
double totalScore = 0;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
double titleScore = GetStringSimilarity(songInfo.Title, compareTitle);
|
||||
double artistScore = GetStringSimilarity(songInfo.Artist, compareArtist);
|
||||
double albumScore = GetStringSimilarity(songInfo.Album, compareAlbum);
|
||||
double durationScore = GetDurationSimilarity(songInfo.DurationMs, compareDurationMs);
|
||||
double durationScore = GetDurationSimilarity(songInfo.Duration, compareDuration);
|
||||
|
||||
totalScore = (titleScore * WeightTitle) +
|
||||
(artistScore * WeightArtist) +
|
||||
@@ -94,19 +94,18 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return _algo.Similarity(s1, s2);
|
||||
}
|
||||
|
||||
private static double GetDurationSimilarity(double localMs, double? remoteSeconds)
|
||||
private static double GetDurationSimilarity(double localSeconds, double? remoteSeconds)
|
||||
{
|
||||
if (remoteSeconds == null || remoteSeconds == 0) return 0.0; // 远程没有时长数据,不匹配
|
||||
|
||||
double localSeconds = localMs / 1000.0;
|
||||
double diff = Math.Abs(localSeconds - remoteSeconds.Value);
|
||||
|
||||
// 差距 <= 3秒:100% 相似
|
||||
// 差距 >= 20秒:0% 相似
|
||||
// 差距 <= 1 秒:100 % 相似
|
||||
// 差距 >= 10 秒:0 % 相似
|
||||
// 中间线性插值
|
||||
|
||||
const double PerfectTolerance = 3.0;
|
||||
const double MaxTolerance = 20.0;
|
||||
const double PerfectTolerance = 1.0;
|
||||
const double MaxTolerance = 10.0;
|
||||
|
||||
if (diff <= PerfectTolerance) return 1.0;
|
||||
if (diff >= MaxTolerance) return 0.0;
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
public string SecondaryText { get; set; } = "";
|
||||
public string TertiaryText { get; set; } = "";
|
||||
|
||||
public new string Text => PrimaryText;
|
||||
public new int StartIndex = 0;
|
||||
|
||||
public LyricsLine()
|
||||
{
|
||||
for (int charStartIndex = 0; charStartIndex < PrimaryText.Length; charStartIndex++)
|
||||
|
||||
@@ -206,7 +206,6 @@ namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
private void InitMediaManager()
|
||||
{
|
||||
_mediaManager.Start();
|
||||
|
||||
_mediaManager.CurrentMediaSessions.ToList().ForEach(x => RecordMediaSession(x.Value.Id));
|
||||
|
||||
_mediaManager.OnAnySessionOpened += MediaManager_OnAnySessionOpened;
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
|
||||
existingItem.Title = result.Title;
|
||||
existingItem.Artist = result.Artist;
|
||||
existingItem.Album = result.Album;
|
||||
existingItem.Duration = result.Duration;
|
||||
|
||||
existingItem.TransliterationProvider = result.TransliterationProvider;
|
||||
existingItem.TranslationProvider = result.TranslationProvider;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
@@ -29,7 +30,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
{
|
||||
private readonly HttpClient _amllTtmlDbHttpClient;
|
||||
private readonly HttpClient _lrcLibHttpClient;
|
||||
private readonly AppleMusic _appleMusic;
|
||||
private readonly Providers.AppleMusic _appleMusic;
|
||||
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IFileSystemService _fileSystemService;
|
||||
@@ -54,10 +55,10 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
_lrcLibHttpClient = new();
|
||||
_lrcLibHttpClient.DefaultRequestHeaders.Add(
|
||||
"User-Agent",
|
||||
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Constants.Link.BetterLyricsGitHub})"
|
||||
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Link.BetterLyricsGitHub})"
|
||||
);
|
||||
_amllTtmlDbHttpClient = new();
|
||||
_appleMusic = new AppleMusic();
|
||||
_appleMusic = new Providers.AppleMusic();
|
||||
}
|
||||
|
||||
private static bool IsAmllTtmlDbIndexInvalid()
|
||||
@@ -402,6 +403,8 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
}
|
||||
|
||||
string? rawLyricFile = null;
|
||||
string? bestNcmMusicId = null;
|
||||
|
||||
await foreach (var line in File.ReadLinesAsync(PathHelper.AmllTtmlDbIndexPath))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
@@ -416,6 +419,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
string? title = null;
|
||||
string? artist = null;
|
||||
string? album = null;
|
||||
string? ncmMusicId = null;
|
||||
|
||||
foreach (var meta in metadataArr.EnumerateArray())
|
||||
{
|
||||
@@ -429,6 +433,8 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
artist = string.Join(" / ", valueArr.EnumerateArray());
|
||||
if (key == "album" && valueArr.GetArrayLength() > 0)
|
||||
album = valueArr[0].GetString();
|
||||
if (key == "ncmMusicId" && valueArr.GetArrayLength() > 0)
|
||||
ncmMusicId = valueArr[0].GetString();
|
||||
}
|
||||
|
||||
int score = MetadataComparer.CalculateScore(songInfo, new LyricsCacheItem
|
||||
@@ -436,12 +442,12 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
Title = title,
|
||||
Artist = artist,
|
||||
Album = album,
|
||||
Duration = 0,
|
||||
});
|
||||
if (score > lyricsSearchResult.MatchPercentage)
|
||||
{
|
||||
if (root.TryGetProperty("rawLyricFile", out var rawLyricFileProp))
|
||||
{
|
||||
bestNcmMusicId = ncmMusicId;
|
||||
rawLyricFile = rawLyricFileProp.GetString();
|
||||
lyricsSearchResult.Title = title;
|
||||
lyricsSearchResult.Artist = artist;
|
||||
@@ -458,19 +464,28 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
return lyricsSearchResult;
|
||||
}
|
||||
|
||||
// 下载歌词内容
|
||||
var url = $"{_settingsService.AppSettings.GeneralSettings.AmllTtmlDbBaseUrl}/{Constants.AmllTTmlDB.QueryPrefix}/{rawLyricFile}";
|
||||
var url = $"{_settingsService.AppSettings.GeneralSettings.AmllTtmlDbBaseUrl}/{AmllTTmlDB.QueryPrefix}/{rawLyricFile}";
|
||||
lyricsSearchResult.Reference = url;
|
||||
try
|
||||
{
|
||||
// 下载写入歌词
|
||||
using var response = await _amllTtmlDbHttpClient.GetAsync(url);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return lyricsSearchResult;
|
||||
}
|
||||
string lyrics = await response.Content.ReadAsStringAsync();
|
||||
|
||||
lyricsSearchResult.Raw = lyrics;
|
||||
|
||||
// 反查时长
|
||||
if (bestNcmMusicId != null && lyricsSearchResult.Duration == null)
|
||||
{
|
||||
var tmp = await SearchQQNeteaseKugouAsync(
|
||||
((SongInfo)songInfo.Clone()).WithSongId($"{ExtendedGenreFiled.NetEaseCloudMusicTrackID}{bestNcmMusicId}"),
|
||||
Searchers.Netease);
|
||||
lyricsSearchResult.Duration = tmp.Duration;
|
||||
lyricsSearchResult.MatchPercentage = MetadataComparer.CalculateScore(songInfo, lyricsSearchResult);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -633,7 +648,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
}
|
||||
|
||||
lyricsSearchResult.Title = result?.Title;
|
||||
lyricsSearchResult.Artist = string.Join(" / ", result?.Artists ?? []);
|
||||
lyricsSearchResult.Artist = result?.Artist;
|
||||
lyricsSearchResult.Album = result?.Album;
|
||||
lyricsSearchResult.Duration = result?.DurationMs / 1000;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user