diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest
index e9e170f..9925b8f 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest
@@ -12,7 +12,7 @@
+ Version="1.0.11.0" />
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Discord.png b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Discord.png
new file mode 100644
index 0000000..c49cc20
Binary files /dev/null and b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Discord.png differ
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/QQ.png b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/QQ.png
new file mode 100644
index 0000000..b498b85
Binary files /dev/null and b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/QQ.png differ
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Enums/LineRenderingType.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Enums/LineRenderingType.cs
index f78d472..c823797 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Enums/LineRenderingType.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Enums/LineRenderingType.cs
@@ -4,7 +4,8 @@ namespace BetterLyrics.WinUI3.Enums
{
public enum LineRenderingType
{
- UntilCurrentChar,
- CurrentCharOnly,
+ CurrentChar,
+ LineStartToCurrentChar,
+ CurrentLine
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/CollectionHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/CollectionHelper.cs
deleted file mode 100644
index d8a304f..0000000
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/CollectionHelper.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// 2025/6/23 by Zhe Fang
-
-using System.Collections.Generic;
-
-namespace BetterLyrics.WinUI3.Helper
-{
- public static class CollectionHelper
- {
- public static T? SafeGet(this IList list, int index)
- {
- if (list == null || index < 0 || index >= list.Count) return default;
- return list[index];
- }
- }
-}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DesktopModeHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DesktopModeHelper.cs
index 8396c54..6d6855b 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DesktopModeHelper.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DesktopModeHelper.cs
@@ -47,13 +47,6 @@ namespace BetterLyrics.WinUI3.Helper
_originalWindowBounds.Remove(hwnd);
}
- // »Ö¸´Ñùʽ
- if (_originalWindowStyles.TryGetValue(hwnd, out var style))
- {
- window.SetWindowStyle(style);
- _originalWindowStyles.Remove(hwnd);
- }
-
window.SetIsShownInSwitchers(true);
}
@@ -83,10 +76,6 @@ namespace BetterLyrics.WinUI3.Helper
new Windows.Graphics.RectInt32(targetX, targetY, targetWidth, targetHeight)
);
- // ¼ÇÒäÔÑùʽ
- if (!_originalWindowStyles.ContainsKey(hwnd))
- _originalWindowStyles[hwnd] = window.GetWindowStyle();
-
// ¼ÇÒäÔTopMost״̬
if (!_originalTopmostStates.ContainsKey(hwnd))
_originalTopmostStates[hwnd] = window.GetIsAlwaysOnTop();
@@ -95,8 +84,6 @@ namespace BetterLyrics.WinUI3.Helper
window.SetIsAlwaysOnTop(true);
window.SetIsShownInSwitchers(false);
-
- window.ToggleWindowStyle(true, WindowStyle.Popup | WindowStyle.Visible);
}
public static void SetClickThrough(Window window, bool enable)
@@ -105,11 +92,22 @@ namespace BetterLyrics.WinUI3.Helper
int exStyle = User32.GetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE);
if (enable)
{
+ // ¼ÇÒäÔÑùʽ
+ if (!_originalWindowStyles.ContainsKey(hwnd))
+ _originalWindowStyles[hwnd] = window.GetWindowStyle();
+
+ window.ToggleWindowStyle(true, WindowStyle.Popup | WindowStyle.Visible);
User32.SetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE, exStyle | (int)User32.WindowStylesEx.WS_EX_TRANSPARENT | (int)User32.WindowStylesEx.WS_EX_LAYERED);
}
else
{
User32.SetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE, exStyle & ~(int)User32.WindowStylesEx.WS_EX_TRANSPARENT);
+ // »Ö¸´Ñùʽ
+ if (_originalWindowStyles.TryGetValue(hwnd, out var style))
+ {
+ window.SetWindowStyle(style);
+ _originalWindowStyles.Remove(hwnd);
+ }
}
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/FileHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/FileHelper.cs
index e60032c..815764d 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/FileHelper.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/FileHelper.cs
@@ -69,9 +69,9 @@ namespace BetterLyrics.WinUI3.Helper
public static bool IsSwitchableNormalizedMatch(string fileName, string q1, string q2)
{
- var normFileName = fileName.Normalize();
- var normQ1 = q1.Normalize();
- var normQ2 = q2.Normalize();
+ var normFileName = StringHelper.Normalize(fileName.Normalize());
+ var normQ1 = StringHelper.Normalize(q1);
+ var normQ2 = StringHelper.Normalize(q2);
// 常è§ä¸¤ç§é¡ºåº
return normFileName == normQ1 + normQ2
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs
index 4b3202b..2a22ccc 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs
@@ -102,7 +102,7 @@ namespace BetterLyrics.WinUI3.Helper
}
}
- public static List GetAccentColorsFromByte(byte[] bytes)
+ public static List GetAccentColorsFromByte(byte[] bytes)
{
// 使用 ImageSharp 读å–图片
using var image = SixLabors.ImageSharp.Image.Load(bytes);
@@ -172,21 +172,21 @@ namespace BetterLyrics.WinUI3.Helper
return memoryStream.ToArray();
}
- //public static float GetAverageLuminance(CanvasBitmap bitmap)
- //{
- // var pixels = bitmap.GetPixelBytes();
- // double sum = 0;
- // for (int i = 0; i < pixels.Length; i += 4)
- // {
- // // BGRA
- // byte b = pixels[i];
- // byte g = pixels[i + 1];
- // byte r = pixels[i + 2];
- // // 忽略A
- // double y = 0.299 * r + 0.587 * g + 0.114 * b;
- // sum += y / 255.0;
- // }
- // return (float)(sum / (pixels.Length / 4));
- //}
+ public static float GetAverageLuminance(CanvasBitmap bitmap)
+ {
+ var pixels = bitmap.GetPixelBytes();
+ double sum = 0;
+ for (int i = 0; i < pixels.Length; i += 4)
+ {
+ // BGRA
+ byte b = pixels[i];
+ byte g = pixels[i + 1];
+ byte r = pixels[i + 2];
+ // 忽略A
+ double y = 0.299 * r + 0.587 * g + 0.114 * b;
+ sum += y / 255.0;
+ }
+ return (float)(sum / (pixels.Length / 4));
+ }
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs
index 6f0751f..591546a 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs
@@ -1,4 +1,5 @@
using BetterLyrics.WinUI3.Helper;
+using CommunityToolkit.Mvvm.DependencyInjection;
using Lyricify.Lyrics.Helpers.General;
using NTextCat;
using System;
@@ -12,6 +13,7 @@ namespace BetterLyrics.WinUI3.Services
{
private static readonly RankedLanguageIdentifierFactory _factory = new();
private static readonly RankedLanguageIdentifier _identifier;
+ private static readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService();
public static List SupportedTargetLanguages =>
[
@@ -106,5 +108,10 @@ namespace BetterLyrics.WinUI3.Services
// å…¶ä»–è¯è¨€ç›´æŽ¥è¿”å›žä¸¤å—æ¯ä»£ç
return code;
}
+
+ public static string GetUserTargetLanguageCode()
+ {
+ return SupportedTargetLanguages[_settingsService.SelectedTargetLanguageIndex].Code;
+ }
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LyricsParser.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LyricsParser.cs
index 0a200c2..772d6c3 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LyricsParser.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LyricsParser.cs
@@ -10,29 +10,21 @@ using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Windows.Globalization.Fonts;
+using LyricsData = BetterLyrics.WinUI3.Models.LyricsData;
namespace BetterLyrics.WinUI3.Helper
{
public class LyricsParser
{
- private List> _multiLangLyricsLines = [];
+ private List _lyricsDataArr = [];
- public List> Parse(string? raw, int durationMs)
+ public List Parse(string? raw, int? durationMs)
{
- _multiLangLyricsLines = [];
+ durationMs ??= (int)TimeSpan.FromMinutes(99).TotalMilliseconds;
+ _lyricsDataArr = [];
if (raw == null)
{
- _multiLangLyricsLines.Add(
- [
- new LyricsLine
- {
- StartMs = 0,
- EndMs = durationMs,
- OriginalText = App.ResourceLoader!.GetString("LyricsNotFound"),
- CharTimings = [],
- },
- ]
- );
+ _lyricsDataArr.Add(LyricsData.GetNotfoundPlaceholder(durationMs.Value));
}
else
{
@@ -43,10 +35,10 @@ namespace BetterLyrics.WinUI3.Helper
ParseLrc(raw);
break;
case LyricsFormat.Qrc:
- ParseUsingLyricify(Lyricify.Lyrics.Parsers.QrcParser.Parse(raw).Lines);
+ ParseQQNeteaseKugou(Lyricify.Lyrics.Parsers.QrcParser.Parse(raw).Lines);
break;
case LyricsFormat.Krc:
- ParseUsingLyricify(Lyricify.Lyrics.Parsers.KrcParser.Parse(raw).Lines);
+ ParseQQNeteaseKugou(Lyricify.Lyrics.Parsers.KrcParser.Parse(raw).Lines);
break;
case LyricsFormat.Ttml:
ParseTtml(raw);
@@ -55,8 +47,8 @@ namespace BetterLyrics.WinUI3.Helper
break;
}
}
- PostProcessLyricsLines(durationMs);
- return _multiLangLyricsLines;
+ PostProcessLyricsLines(durationMs.Value);
+ return _lyricsDataArr;
}
private void ParseLrc(string raw)
@@ -120,9 +112,9 @@ namespace BetterLyrics.WinUI3.Helper
int languageCount = grouped.Max(g => g.Count());
// åˆå§‹åŒ–æ¯ç§è¯è¨€çš„æŒè¯åˆ—表
- _multiLangLyricsLines.Clear();
+ _lyricsDataArr.Clear();
for (int i = 0; i < languageCount; i++)
- _multiLangLyricsLines.Add(new List());
+ _lyricsDataArr.Add(new LyricsData());
// é历æ¯ä¸ªæ—¶é—´åˆ†ç»„
foreach (var group in grouped)
@@ -159,7 +151,7 @@ namespace BetterLyrics.WinUI3.Helper
currentIndex += charText?.Length ?? 0;
}
}
- _multiLangLyricsLines[langIdx].Add(line);
+ _lyricsDataArr[langIdx].LyricsLines.Add(line);
}
}
}
@@ -259,9 +251,9 @@ namespace BetterLyrics.WinUI3.Helper
});
}
}
- _multiLangLyricsLines.Add(originalLines);
+ _lyricsDataArr.Add(new LyricsData(originalLines));
if (translationLines.Count > 0)
- _multiLangLyricsLines.Add(translationLines);
+ _lyricsDataArr.Add(new LyricsData(translationLines));
}
catch
{
@@ -330,7 +322,7 @@ namespace BetterLyrics.WinUI3.Helper
return 0;
}
- private void ParseUsingLyricify(List? lines)
+ private void ParseQQNeteaseKugou(List? lines)
{
lines = lines?.Where(x => x.Text != string.Empty).ToList();
List lyricsLines = [];
@@ -384,27 +376,27 @@ namespace BetterLyrics.WinUI3.Helper
}
}
- _multiLangLyricsLines.Add(lyricsLines);
+ _lyricsDataArr.Add(new LyricsData(lyricsLines));
}
private void PostProcessLyricsLines(int durationMs)
{
- for (int langIdx = 0; langIdx < _multiLangLyricsLines.Count; langIdx++)
+ for (int langIdx = 0; langIdx < _lyricsDataArr.Count; langIdx++)
{
- var linesInSingleLang = _multiLangLyricsLines[langIdx];
- for (int i = 0; i < linesInSingleLang.Count; i++)
+ var lines = _lyricsDataArr[langIdx].LyricsLines;
+ for (int i = 0; i < lines.Count; i++)
{
- if (i + 1 < linesInSingleLang.Count)
+ if (i + 1 < lines.Count)
{
- linesInSingleLang[i].EndMs = linesInSingleLang[i + 1].StartMs;
+ lines[i].EndMs = lines[i + 1].StartMs;
}
else
{
- linesInSingleLang[i].EndMs = durationMs;
+ lines[i].EndMs = durationMs;
}
// ä¿®æ£ CharTimings çš„ EndMs
- var timings = linesInSingleLang[i].CharTimings;
+ var timings = lines[i].CharTimings;
if (timings.Count > 0)
{
for (int j = 0; j < timings.Count; j++)
@@ -415,21 +407,21 @@ namespace BetterLyrics.WinUI3.Helper
}
else
{
- timings[j].EndMs = linesInSingleLang[i].EndMs;
+ timings[j].EndMs = lines[i].EndMs;
}
}
}
}
- if (linesInSingleLang.Count > 0)
+ if (lines.Count > 0)
{
- if (linesInSingleLang[0].StartMs > 0)
+ if (lines[0].StartMs > 0)
{
- linesInSingleLang.Insert(
+ lines.Insert(
0,
new LyricsLine
{
StartMs = 0,
- EndMs = linesInSingleLang[0].StartMs,
+ EndMs = lines[0].StartMs,
OriginalText = "â— â— â—",
CharTimings = [],
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/MetadataHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/MetadataHelper.cs
index c824dcc..c30c5c6 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/MetadataHelper.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/MetadataHelper.cs
@@ -27,6 +27,8 @@ namespace BetterLyrics.WinUI3.Helper
}
public const string GithubUrl = "https://github.com/jayfunc/BetterLyrics";
+ public const string QQGroupUrl = "https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info";
+ public const string DiscordUrl = "https://discord.gg/5yAQPnyCKv";
public static async Task GetBuildDate()
{
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/PathHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/PathHelper.cs
index 88038d2..3453b6e 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/PathHelper.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/PathHelper.cs
@@ -20,18 +20,26 @@ namespace BetterLyrics.WinUI3.Helper
public static string LogDirectory => Path.Combine(CacheFolder, "logs");
public static string LogFilePattern => Path.Combine(LogDirectory, "log-.txt");
- public static string LrcLibLyricsCacheDirectory => Path.Combine(CacheFolder, "lrclib-lyrics");
- public static string NeteaseLyricsCacheDirectory => Path.Combine(CacheFolder, "netease-lyrics");
- public static string QQLyricsCacheDirectory => Path.Combine(CacheFolder, "qq-lyrics");
- public static string KugouLyricsCacheDirectory => Path.Combine(CacheFolder, "kugou-lyrics");
- public static string AmllTtmlDbLyricsCacheDirectory => Path.Combine(CacheFolder, "amll-ttml-db-lyrics");
- public static string AmllTtmlDbIndexPath => Path.Combine(CacheFolder, "amll-ttml-db-index.json");
+ public static string LyricsCacheDirectory => Path.Combine(CacheFolder, "lyrics");
- public static string iTunesAlbumArtCacheDirectory => Path.Combine(CacheFolder, "itunes-album-art");
+ public static string LrcLibLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "lrclib");
+ public static string NeteaseLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "netease");
+ public static string QQLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "qq");
+ public static string KugouLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "kugou");
+ public static string AmllTtmlDbLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "amll-ttml-db");
+ public static string AmllTtmlDbIndexPath => Path.Combine(LyricsCacheDirectory, "amll-ttml-db-index.json");
+ public static string AmllTtmlDbLastUpdatedPath => Path.Combine(LyricsCacheDirectory, "amll-ttml-db-last-updated.txt");
+
+ public static string TranslationCacheDirectory => Path.Combine(CacheFolder, "translations");
+
+ public static string QQTranslationCacheDirectory => Path.Combine(TranslationCacheDirectory, "qq");
+
+ public static string AlbumArtCacheDirectory => Path.Combine(CacheFolder, "album-art");
+
+ public static string iTunesAlbumArtCacheDirectory => Path.Combine(AlbumArtCacheDirectory, "itunes");
public static void EnsureDirectories()
{
- Directory.CreateDirectory(LocalFolder);
Directory.CreateDirectory(LogDirectory);
Directory.CreateDirectory(LrcLibLyricsCacheDirectory);
@@ -40,6 +48,8 @@ namespace BetterLyrics.WinUI3.Helper
Directory.CreateDirectory(NeteaseLyricsCacheDirectory);
Directory.CreateDirectory(AmllTtmlDbLyricsCacheDirectory);
+ Directory.CreateDirectory(QQTranslationCacheDirectory);
+
Directory.CreateDirectory(iTunesAlbumArtCacheDirectory);
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/StringHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/StringHelper.cs
index a10b6d5..bd6ce23 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/StringHelper.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/StringHelper.cs
@@ -9,10 +9,11 @@ namespace BetterLyrics.WinUI3.Helper
public static class StringHelper
{
// åŽ»é™¤ç©ºæ ¼ã€æ‹¬å·ã€ä¸‹åˆ’çº¿ã€æ¨ªæ ã€ç‚¹ã€å¤§å°å†™ç‰
- public static string Normalize(this string s) =>
+ public static string Normalize(string s) =>
new string(s
.Where(c => char.IsLetterOrDigit(c))
.ToArray())
.ToLowerInvariant();
+ public static string NewLine = "\n";
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs
new file mode 100644
index 0000000..da6de05
--- /dev/null
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs
@@ -0,0 +1,95 @@
+using BetterLyrics.WinUI3.Helper;
+using BetterLyrics.WinUI3.Services;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BetterLyrics.WinUI3.Models
+{
+ public class LyricsData
+ {
+ public List LyricsLines { get; set; }
+ public string? LanguageCode => LanguageHelper.DetectLanguageCode(WrappedOriginalText);
+ public string WrappedOriginalText => string.Join(StringHelper.NewLine, LyricsLines.Select(line => line.OriginalText));
+
+ public LyricsData()
+ {
+ LyricsLines = [];
+ }
+
+ public LyricsData(List lyricsLines)
+ {
+ LyricsLines = lyricsLines;
+ }
+
+ public void SetDisplayedTextAlongWith(LyricsData translationData)
+ {
+ int i = 0;
+ foreach (var line in LyricsLines)
+ {
+ if (i >= translationData.LyricsLines.Count)
+ {
+ line.DisplayedText = line.OriginalText; // No translation available, keep original text
+ }
+ else
+ {
+ line.DisplayedText = $"{line.OriginalText}{StringHelper.NewLine}({translationData.LyricsLines[i].OriginalText})";
+ }
+ i++;
+ }
+ }
+
+ public void SetDisplayedTextAlongWith(string translation)
+ {
+ List translationArr = translation.Split(StringHelper.NewLine).ToList();
+ int i = 0;
+ foreach (var line in LyricsLines)
+ {
+ if (i >= translationArr.Count)
+ {
+ line.DisplayedText = line.OriginalText; // No translation available, keep original text
+ }
+ else
+ {
+ line.DisplayedText = $"{line.OriginalText}{StringHelper.NewLine}({translationArr[i]})";
+ }
+ i++;
+ }
+ }
+
+ public void SetDisplayedTextInOriginalText()
+ {
+ foreach (var line in LyricsLines)
+ {
+ line.DisplayedText = line.OriginalText;
+ }
+ }
+
+ public static LyricsData GetNotfoundPlaceholder(int durationMs)
+ {
+ return new LyricsData([new LyricsLine
+ {
+ StartMs = 0,
+ EndMs = durationMs,
+ OriginalText = App.ResourceLoader!.GetString("LyricsNotFound"),
+ CharTimings = [],
+ }]);
+ }
+
+ public static LyricsData GetLoadingPlaceholder()
+ {
+ return new LyricsData([
+ new LyricsLine
+ {
+ StartMs = 0,
+ EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
+ OriginalText = "â— â— â—",
+ DisplayedText = "â— â— â—",
+ CharTimings = [],
+ },
+ ]);
+ }
+ }
+}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs
index 6de4158..b94f924 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs
@@ -67,6 +67,7 @@ namespace BetterLyrics.WinUI3.Services
LyricsFontWeight LyricsFontWeight { get; set; }
LineRenderingType LyricsGlowEffectScope { get; set; }
+ LineRenderingType LyricsHighlightScope { get; set; }
float LyricsLineSpacingFactor { get; set; }
@@ -84,5 +85,7 @@ namespace BetterLyrics.WinUI3.Services
bool IsTranslationEnabled { get; set; }
LyricsDisplayType PreferredDisplayType { get; set; }
+
+ int TimelineSyncThreshold { get; set; }
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ITranslateService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ITranslateService.cs
index 527fa8d..25a6282 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ITranslateService.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ITranslateService.cs
@@ -1,4 +1,5 @@
-using System;
+using BetterLyrics.WinUI3.Models;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -9,6 +10,8 @@ namespace BetterLyrics.WinUI3.Services
{
public interface ITranslateService
{
- Task TranslateAsync(string text, string targetLangCode, CancellationToken? token);
+ Task TranslateTextAsync(string text, string targetLangCode, CancellationToken? token);
+
+ int SearchTranslatedLyricsItself(List lyricsDataArr);
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService.cs
index de097ac..d686d2c 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService.cs
@@ -15,6 +15,7 @@ using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
+using Windows.Storage;
namespace BetterLyrics.WinUI3.Services
{
@@ -39,6 +40,23 @@ namespace BetterLyrics.WinUI3.Services
_amllTtmlDbHttpClient = new();
}
+ private static bool IsAmllTtmlDbIndexInvalid()
+ {
+ bool existed = File.Exists(PathHelper.AmllTtmlDbIndexPath);
+
+ if (!existed)
+ {
+ return true;
+ }
+ else
+ {
+ long currentTs = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
+ string lastUpdatedStr = File.ReadAllText(PathHelper.AmllTtmlDbLastUpdatedPath);
+ long lastUpdated = Convert.ToInt64(lastUpdatedStr);
+ return currentTs - lastUpdated > 1 * 24 * 60 * 60;
+ }
+ }
+
public async Task DownloadAmllTtmlDbIndexAsync()
{
const string url = "https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/refs/heads/main/metadata/raw-lyrics-index.jsonl";
@@ -56,6 +74,9 @@ namespace BetterLyrics.WinUI3.Services
);
await stream.CopyToAsync(fs);
+ long currentTs = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
+ File.WriteAllText(PathHelper.AmllTtmlDbLastUpdatedPath, currentTs.ToString());
+
return true;
}
catch
@@ -192,11 +213,10 @@ namespace BetterLyrics.WinUI3.Services
private async Task SearchAmllTtmlDbAsync(string title, string artist)
{
- // 检索本地 JSONL 索引文件,查找 rawLyricFile
- if (!File.Exists(PathHelper.AmllTtmlDbIndexPath))
+ if (IsAmllTtmlDbIndexInvalid())
{
var downloadOk = await DownloadAmllTtmlDbIndexAsync();
- if (!downloadOk || !File.Exists(PathHelper.AmllTtmlDbIndexPath))
+ if (!downloadOk)
return null;
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs
index 46726a9..ef2cebd 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs
@@ -62,6 +62,7 @@ namespace BetterLyrics.WinUI3.Services
private const string LyricsFontSizeKey = "LyricsFontSize";
private const string LyricsFontWeightKey = "LyricsFontWeightKey";
private const string LyricsGlowEffectScopeKey = "LyricsGlowEffectScope";
+ private const string LyricsHighlightSopeKey = "LyricsHighlightSope";
private const string LyricsLineSpacingFactorKey = "LyricsLineSpacingFactor";
private const string LyricsSearchProvidersInfoKey = "LyricsSearchProvidersInfo";
private const string AlbumArtSearchProvidersInfoKey = "AlbumArtSearchProvidersInfo";
@@ -80,6 +81,8 @@ namespace BetterLyrics.WinUI3.Services
private const string LyricsScrollEasingTypeKey = "LyricsScrollEasingType";
private const string LyricsScrollDurationKey = "LyricsScrollDuration";
+ public const string TimelineSyncThresholdKey = "TimelineSyncThreshold";
+
private readonly ApplicationDataContainer _localSettings;
public SettingsService()
@@ -155,7 +158,7 @@ namespace BetterLyrics.WinUI3.Services
SetDefault(IsCoverOverlayEnabledKey, true);
SetDefault(IsDynamicCoverOverlayEnabledKey, true);
SetDefault(CoverOverlayOpacityKey, 100); // 100 % = 1.0
- SetDefault(CoverOverlayBlurAmountKey, 200);
+ SetDefault(CoverOverlayBlurAmountKey, 100);
SetDefault(CoverImageRadiusKey, 12); // 12 %
// Lyrics
SetDefault(LyricsAlignmentTypeKey, (int)TextAlignmentType.Center);
@@ -177,7 +180,8 @@ namespace BetterLyrics.WinUI3.Services
SetDefault(LyricsLineSpacingFactorKey, 0.5f);
SetDefault(LyricsVerticalEdgeOpacityKey, 0);
SetDefault(IsLyricsGlowEffectEnabledKey, true);
- SetDefault(LyricsGlowEffectScopeKey, (int)LineRenderingType.CurrentCharOnly);
+ SetDefault(LyricsGlowEffectScopeKey, (int)LineRenderingType.CurrentChar);
+ SetDefault(LyricsHighlightSopeKey, (int)LineRenderingType.LineStartToCurrentChar);
SetDefault(IsFanLyricsEnabledKey, false);
SetDefault(LibreTranslateServerKey, "");
@@ -190,6 +194,7 @@ namespace BetterLyrics.WinUI3.Services
SetDefault(LyricsScrollEasingTypeKey, (int)EasingType.EaseInOutQuad);
SetDefault(LyricsScrollDurationKey, 500); // 500ms
+ SetDefault(TimelineSyncThresholdKey, 0); // 0ms
}
public EasingType LyricsScrollEasingType
@@ -419,6 +424,12 @@ namespace BetterLyrics.WinUI3.Services
set => SetValue(LyricsGlowEffectScopeKey, (int)value);
}
+ public LineRenderingType LyricsHighlightScope
+ {
+ get => (LineRenderingType)GetValue(LyricsHighlightSopeKey);
+ set => SetValue(LyricsHighlightSopeKey, (int)value);
+ }
+
public float LyricsLineSpacingFactor
{
get => GetValue(LyricsLineSpacingFactorKey);
@@ -506,6 +517,12 @@ namespace BetterLyrics.WinUI3.Services
set => SetValue(IgnoreFullscreenWindowKey, value);
}
+ public int TimelineSyncThreshold
+ {
+ get => GetValue(TimelineSyncThresholdKey);
+ set => SetValue(TimelineSyncThresholdKey, value);
+ }
+
private T? GetValue(string key)
{
if (_localSettings.Values.TryGetValue(key, out object? value))
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/TranslateService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/TranslateService.cs
index 474c7de..ab40cb8 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/TranslateService.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/TranslateService.cs
@@ -1,6 +1,7 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Serialization;
+using BetterLyrics.WinUI3.ViewModels;
using Lyricify.Lyrics.Helpers.General;
using System;
using System.Collections.Generic;
@@ -13,19 +14,16 @@ using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Services
{
- public class TranslateService : ITranslateService
+ public class TranslateService : BaseViewModel, ITranslateService
{
- private readonly ISettingsService _settingsService;
-
private readonly HttpClient _httpClient;
- public TranslateService(ISettingsService settingsService)
+ public TranslateService(ISettingsService settingsService) :base(settingsService)
{
- _settingsService = settingsService;
_httpClient = new HttpClient();
}
- public async Task TranslateAsync(string text, string targetLangCode, CancellationToken? token)
+ public async Task TranslateTextAsync(string text, string targetLangCode, CancellationToken? token)
{
if (string.IsNullOrWhiteSpace(text))
{
@@ -46,6 +44,19 @@ namespace BetterLyrics.WinUI3.Services
return ChineseConverter.ConvertToTraditionalChinese(text);
}
+ if (string.IsNullOrEmpty(_settingsService.LibreTranslateServer))
+ {
+ _dispatcherQueue.TryEnqueue(() =>
+ {
+ App.Current.LyricsWindowNotificationPanel?.Notify(
+ App.ResourceLoader!.GetString("TranslateServerNotSet"),
+ Microsoft.UI.Xaml.Controls.InfoBarSeverity.Warning
+ );
+ });
+
+ throw new InvalidOperationException("LibreTranslate server URL is not configured.");
+ }
+
var url = $"{_settingsService.LibreTranslateServer}/translate";
var response = await _httpClient.PostAsync(url, new FormUrlEncodedContent(
[
@@ -62,5 +73,21 @@ namespace BetterLyrics.WinUI3.Services
var result = System.Text.Json.JsonSerializer.Deserialize(json, SourceGenerationContext.Default.TranslateResponse);
return result?.TranslatedText ?? string.Empty;
}
+
+ public int SearchTranslatedLyricsItself(List lyricsDataArr)
+ {
+ string targetLangCode = LanguageHelper.GetUserTargetLanguageCode();
+ if (lyricsDataArr.Count > 1)
+ {
+ for (int i = 1; i < lyricsDataArr.Count; i++)
+ {
+ if (lyricsDataArr[i].LanguageCode == targetLangCode)
+ {
+ return i; // Translation lyrics data found
+ }
+ }
+ }
+ return -1; // No translation lyrics data found
+ }
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw
index ea523a6..6132af7 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw
@@ -310,7 +310,7 @@
No music playing now
- Developer options
+ Advanced options
Play test music
@@ -459,13 +459,10 @@
Extra Black
-
- Whole lyrics
-
-
+
Current line
-
+
Current char
@@ -717,4 +714,25 @@
Ease-in-out cubic
+
+ Current line start to current char
+
+
+ Highlight scope
+
+
+ Lyrics timeline sync threshold
+
+
+ If the lyrics progress is jittery, try increasing this threshold; changing this value can cause lyrics synchronization to deviate
+
+
+ QQ feedback & chat group
+
+
+ Discord
+
+
+ Join now
+
\ No newline at end of file
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw
index 93b3b0d..002b876 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw
@@ -310,7 +310,7 @@
今ã¯éŸ³æ¥½ãŒå†ç”Ÿã•れã¦ã„ã¾ã›ã‚“
- 開発者オプション
+ 高度ãªã‚ªãƒ—ション
テスト音楽をå†ç”Ÿã—ã¾ã™
@@ -459,13 +459,10 @@
余分ãªé»’
-
- æŒè©žå…¨ä½“
-
-
+
ç¾åœ¨ã®è¡Œ
-
+
ç¾åœ¨ã®æ–‡å—
@@ -717,4 +714,25 @@
3ã¤ã®é…ã„インã¨ã‚¢ã‚¦ãƒˆ
+
+ ç¾åœ¨ã®ãƒ©ã‚¤ãƒ³ãŒç¾åœ¨ã®æ–‡å—ã‹ã‚‰å§‹ã¾ã‚Šã¾ã™
+
+
+ ãƒã‚¤ãƒ©ã‚¤ãƒˆã‚¹ã‚³ãƒ¼ãƒ—
+
+
+ æŒè©žã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³åŒæœŸã—ãã„値
+
+
+ æŒè©žã®é€²è¡ŒãŒä¸å®‰å®šãªå ´åˆã¯ã€ã“ã®ã—ãã„値を増やã—ã¦ã¿ã¦ãã ã•ã„。ã“ã®å€¤ã‚’変更ã™ã‚‹ã¨ã€æŒè©žã®åŒæœŸãŒé€¸è„±ã™ã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™
+
+
+ QQフィードãƒãƒƒã‚¯ï¼†ãƒãƒ£ãƒƒãƒˆã‚°ãƒ«ãƒ¼ãƒ—
+
+
+ Discord
+
+
+ 今ã™ãå‚åŠ ã—ã¦ãã ã•ã„
+
\ No newline at end of file
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw
index 8bc6aea..b6c61de 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw
@@ -310,7 +310,7 @@
지금 ìŒì•…ì´ ìž¬ìƒë˜ì§€ 않습니다
- ê°œë°œìž ì˜µì…˜
+ ê³ ê¸‰ 옵션
테스트 ìŒì•…ì„ ìž¬ìƒí•˜ì‹ì‹œì˜¤
@@ -459,13 +459,10 @@
ì—¬ë¶„ì˜ ê²€ì€ ìƒ‰
-
- ì „ì²´ 가사
-
-
+
현재 ë¼ì¸
-
+
현재 숯
@@ -717,4 +714,25 @@
세 번 ëŠë¦¬ê²Œ 안팎으로
+
+ 현재 ë¼ì¸ì€ 현재 숯으로 시작합니다
+
+
+ 하ì´ë¼ì´íЏ 범위
+
+
+ 가사 타임 ë¼ì¸ ë™ê¸°í™” 임계 ê°’
+
+
+ 가사 ì§„í–‰ ìƒí™©ì´ ë¶ˆì•ˆí•˜ë‹¤ë©´ì´ ìž„ê³„ ê°’ì„ ë†’ì´ì‹ì‹œì˜¤. ì´ ê°’ì„ ë³€ê²½í•˜ë©´ 가사가 ë™ê¸°í™” ë 수 있습니다
+
+
+ QQ 피드백 ë° ì±„íŒ… 그룹
+
+
+ Discord
+
+
+ 지금 가입하ì‹ì‹œì˜¤
+
\ No newline at end of file
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw
index f6215a5..7038654 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw
@@ -310,7 +310,7 @@
当剿²¡æœ‰æ£åœ¨æ’放的音ä¹
- å¼€å‘者选项
+ 高级选项
æ’æ”¾æµ‹è¯•音ä¹
@@ -459,13 +459,10 @@
超黑
-
- 全部æŒè¯
-
-
+
当å‰è¡Œ
-
+
当å‰å—符
@@ -717,4 +714,25 @@
三次缓入缓出
+
+ 当剿Œè¯å¼€å§‹åˆ°å½“å‰å—符
+
+
+ 高亮显示范围
+
+
+ æŒè¯æ—¶é—´è½´åŒæ¥é˜ˆå€¼
+
+
+ 当æŒè¯è¿›åº¦æŠ–动时,请å°è¯•å¢žåŠ è¯¥é˜ˆå€¼ï¼›æ›´æ”¹æ¤å€¼ä¼šå¯¼è‡´æŒè¯åŒæ¥æœ‰åå·®
+
+
+ QQ å馈交æµç¾¤
+
+
+ Discord
+
+
+ ç«‹å³åŠ å…¥
+
\ No newline at end of file
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw
index 09ea241..e210a20 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw
@@ -310,7 +310,7 @@
ç›®å‰æ²’有æ£åœ¨æ’放的音樂
- 開發者é¸é …
+ 高級é¸é …
æ’æ”¾æ¸¬è©¦éŸ³æ¨‚
@@ -459,13 +459,10 @@
超黑
-
- 全部æŒè©ž
-
-
+
ç›®å‰è¡Œ
-
+
ç›®å‰å—å…ƒ
@@ -717,4 +714,25 @@
三次緩入緩出
+
+ ç•¶å‰æŒè©žé–‹å§‹åˆ°ç•¶å‰å—符
+
+
+ 高亮顯示範åœ
+
+
+ æŒè©žæ™‚é–“è»¸åŒæ¥é–¾å€¼
+
+
+ ç•¶æŒè©žé€²åº¦æŠ–å‹•æ™‚ï¼Œè«‹å˜—è©¦å¢žåŠ è©²é–¾å€¼ï¼›æ›´æ”¹æ¤å€¼æœƒå°Žè‡´æŒè©žåŒæ¥åå·®
+
+
+ QQ 回饋交æµç¾¤
+
+
+ Discord
+
+
+ ç«‹å³åŠ å…¥
+
\ No newline at end of file
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/BaseWindowViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/BaseWindowViewModel.cs
index fdc961a..6b86c24 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/BaseWindowViewModel.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/BaseWindowViewModel.cs
@@ -11,8 +11,7 @@ using Microsoft.UI.Xaml;
namespace BetterLyrics.WinUI3.ViewModels
{
- public partial class BaseWindowViewModel : BaseViewModel
+ public partial class BaseWindowViewModel(ISettingsService settingsService) : BaseViewModel(settingsService)
{
- public BaseWindowViewModel(ISettingsService settingsService) : base(settingsService) { }
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs
index 77ad185..5401973 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs
@@ -15,7 +15,7 @@ using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.ViewModels
{
- public partial class LyricsPageViewModel : BaseViewModel, IRecipient>, IRecipient>
+ public partial class LyricsPageViewModel : BaseViewModel, IRecipient>
{
private readonly IPlaybackService _playbackService;
@@ -23,15 +23,12 @@ namespace BetterLyrics.WinUI3.ViewModels
public LyricsPageViewModel(ISettingsService settingsService, IPlaybackService playbackService) : base(settingsService)
{
- LyricsFontSize = _settingsService.LyricsFontSize;
+ IsFirstRun = _settingsService.IsFirstRun;
IsTranslationEnabled = _settingsService.IsTranslationEnabled;
PreferredDisplayType = _settingsService.PreferredDisplayType;
_playbackService = playbackService;
_playbackService.SongInfoChanged += PlaybackService_SongInfoChanged;
-
-
- IsFirstRun = _settingsService.IsFirstRun;
}
private void PlaybackService_SongInfoChanged(object? sender, Events.SongInfoChangedEventArgs e)
@@ -51,12 +48,6 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty]
public partial bool IsWelcomeTeachingTipOpen { get; set; }
- [ObservableProperty]
- public partial Visibility BottomCommandGridVisibility { get; set; } = Visibility.Visible;
-
- [ObservableProperty]
- public partial int LyricsFontSize { get; set; }
-
[ObservableProperty]
public partial LyricsDisplayType PreferredDisplayType { get; set; }
@@ -69,7 +60,7 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty]
[NotifyPropertyChangedRecipients]
- public partial bool IsTranslationEnabled { get; set; } = false;
+ public partial bool IsTranslationEnabled { get; set; }
partial void OnIsTranslationEnabledChanged(bool value)
{
@@ -98,19 +89,8 @@ namespace BetterLyrics.WinUI3.ViewModels
}
}
- public void Receive(PropertyChangedMessage message)
- {
- if (message.Sender is SettingsPageViewModel)
- {
- if (message.PropertyName == nameof(SettingsPageViewModel.LyricsFontSize))
- {
- LyricsFontSize = message.NewValue;
- }
- }
- }
-
[RelayCommand]
- private void OpenSettingsWindow()
+ private static void OpenSettingsWindow()
{
WindowHelper.OpenOrShowWindow();
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Ctor.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Ctor.cs
index cfcb2b9..daaf80c 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Ctor.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Ctor.cs
@@ -33,6 +33,7 @@ namespace BetterLyrics.WinUI3.ViewModels
_lyricsBlurAmount = _settingsService.LyricsBlurAmount;
_isLyricsGlowEffectEnabled = _settingsService.IsLyricsGlowEffectEnabled;
_lyricsGlowEffectScope = _settingsService.LyricsGlowEffectScope;
+ _lyricsHighlightScope = _settingsService.LyricsHighlightScope;
_customBgFontColor = _settingsService.LyricsCustomBgFontColor;
_customFgFontColor = _settingsService.LyricsCustomFgFontColor;
@@ -45,6 +46,8 @@ namespace BetterLyrics.WinUI3.ViewModels
_targetLanguageIndex = _settingsService.SelectedTargetLanguageIndex;
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment = _settingsService.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
+ _timelineSyncThreshold = _settingsService.TimelineSyncThreshold;
+
_canvasYScrollTransition.SetDuration(_settingsService.LyricsScrollDuration / 1000f);
_canvasYScrollTransition.SetEasingType(_settingsService.LyricsScrollEasingType);
@@ -56,7 +59,7 @@ namespace BetterLyrics.WinUI3.ViewModels
_playbackService.AlbumArtChangedChanged += PlaybackService_AlbumArtChangedChanged;
_playbackService.PositionChanged += PlaybackService_PositionChanged;
- UpdateFontColor();
+ UpdateColorConfig();
}
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs
index 3b42bc4..23b57d3 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs
@@ -67,9 +67,9 @@ namespace BetterLyrics.WinUI3.ViewModels
if (_isDebugOverlayEnabled)
{
- var currentPlayingLine = _multiLangLyrics
- .SafeGet(_langIndex)
- ?.SafeGet(_playingLineIndex);
+ var currentPlayingLine = _lyricsDataArr
+ .ElementAtOrDefault(_langIndex)
+ ?.LyricsLines.ElementAtOrDefault(_playingLineIndex);
if (currentPlayingLine != null)
{
@@ -85,7 +85,7 @@ namespace BetterLyrics.WinUI3.ViewModels
$"Cur playing {_playingLineIndex}, char start idx {charStartIndex}, length {charLength}, prog {charProgress}\n" +
$"Visible lines [{_startVisibleLineIndex}, {_endVisibleLineIndex}]\n" +
$"Cur time {_totalTime + _positionOffset}\n" +
- $"Lang size {_multiLangLyrics.Count}\n" +
+ $"Lang size {_lyricsDataArr.Count}\n" +
$"Song duration {TimeSpan.FromMilliseconds(SongInfo?.DurationMs ?? 0)}",
new Vector2(10, 10),
ThemeTypeSent == Microsoft.UI.Xaml.ElementTheme.Light ? Colors.Black : Colors.White
@@ -118,13 +118,13 @@ namespace BetterLyrics.WinUI3.ViewModels
float x = _canvasWidth / 2 - imageWidth * scaleFactor / 2;
float y = _canvasHeight / 2 - imageHeight * scaleFactor / 2;
- // Source: https://zhuanlan.zhihu.com/p/37178216
- float bright = _lyricsBgBrightnessTransition.Value / 1f * 2f; // æ˜Žåº¦å‚æ•°ï¼ŒèŒƒå›´åœ¨0.0f到2.0f之间
+ // Original source: https://zhuanlan.zhihu.com/p/37178216
+ float gain = _lyricsBgBrightnessTransition.Value;
- float whiteX = Math.Min(2 - bright, 1);
- float whiteY = 1f;
- float blackX = Math.Max(1 - bright, 0);
- float blackY = 0f;
+ float whiteX = 1 - 0.5f * gain;
+ float whiteY = 0.5f + 0.5f * gain;
+ float blackX = 0.5f - 0.5f * gain;
+ float blackY = 0 + 0.5f * gain;
ds.DrawImage(new OpacityEffect
{
@@ -274,9 +274,9 @@ namespace BetterLyrics.WinUI3.ViewModels
private void DrawBlurredLyrics(ICanvasAnimatedControl control, CanvasDrawingSession ds)
{
- var currentPlayingLine = _multiLangLyrics
- .SafeGet(_langIndex)
- ?.SafeGet(_playingLineIndex);
+ var currentPlayingLine = _lyricsDataArr
+ .ElementAtOrDefault(_langIndex)
+ ?.LyricsLines.ElementAtOrDefault(_playingLineIndex);
if (currentPlayingLine == null)
{
@@ -285,7 +285,7 @@ namespace BetterLyrics.WinUI3.ViewModels
for (int i = _startVisibleLineIndex; i <= _endVisibleLineIndex; i++)
{
- var line = _multiLangLyrics.SafeGet(_langIndex)?.SafeGet(i);
+ var line = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.ElementAtOrDefault(i);
if (line == null)
{
@@ -486,8 +486,9 @@ namespace BetterLyrics.WinUI3.ViewModels
Source = fgLyrics,
AlphaMask = _lyricsGlowEffectScope switch
{
- LineRenderingType.UntilCurrentChar => mask,
- LineRenderingType.CurrentCharOnly => highlightMask,
+ LineRenderingType.CurrentChar => highlightMask,
+ LineRenderingType.LineStartToCurrentChar => mask,
+ LineRenderingType.CurrentLine => fgLyrics,
_ => mask,
},
},
@@ -498,7 +499,13 @@ namespace BetterLyrics.WinUI3.ViewModels
Foreground = new AlphaMaskEffect
{
Source = fgLyrics,
- AlphaMask = mask,
+ AlphaMask = _lyricsHighlightScope switch
+ {
+ LineRenderingType.CurrentChar => highlightMask,
+ LineRenderingType.LineStartToCurrentChar => mask,
+ LineRenderingType.CurrentLine => fgLyrics,
+ _ => mask,
+ },
},
},
Opacity = line.HighlightOpacityTransition.Value * _lyricsOpacityTransition.Value,
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Messages.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Messages.cs
index 3c9d781..d3e6696 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Messages.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Messages.cs
@@ -57,8 +57,6 @@ namespace BetterLyrics.WinUI3.ViewModels
}
}
- // Receive methods for handling messages from other view models
-
public void Receive(PropertyChangedMessage message)
{
if (message.Sender is SettingsPageViewModel)
@@ -86,12 +84,12 @@ namespace BetterLyrics.WinUI3.ViewModels
if (message.PropertyName == nameof(LyricsWindowViewModel.IsDockMode))
{
_isDockMode = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
else if (message.PropertyName == nameof(LyricsWindowViewModel.IsDesktopMode))
{
_isDesktopMode = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
else if (message.PropertyName == nameof(LyricsWindowViewModel.IsLyricsWindowLocked))
{
@@ -122,7 +120,7 @@ namespace BetterLyrics.WinUI3.ViewModels
{
_immersiveBgTransition.StartTransition(message.NewValue);
_environmentalColor = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
}
else if (message.Sender is SettingsPageViewModel)
@@ -130,17 +128,17 @@ namespace BetterLyrics.WinUI3.ViewModels
if (message.PropertyName == nameof(SettingsPageViewModel.LyricsCustomBgFontColor))
{
_customBgFontColor = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
else if (message.PropertyName == nameof(SettingsPageViewModel.LyricsCustomFgFontColor))
{
_customFgFontColor = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
else if (message.PropertyName == nameof(SettingsPageViewModel.LyricsCustomStrokeFontColor))
{
_customStrokeFontColor = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
}
}
@@ -202,6 +200,10 @@ namespace BetterLyrics.WinUI3.ViewModels
{
_canvasYScrollTransition.SetDuration(message.NewValue / 1000f);
}
+ else if (message.PropertyName == nameof(SettingsPageViewModel.TimelineSyncThreshold))
+ {
+ _timelineSyncThreshold = message.NewValue;
+ }
}
else if (message.Sender is LyricsPageViewModel)
{
@@ -220,6 +222,10 @@ namespace BetterLyrics.WinUI3.ViewModels
{
_lyricsGlowEffectScope = message.NewValue;
}
+ else if (message.PropertyName == nameof(SettingsPageViewModel.LyricsHighlightScope))
+ {
+ _lyricsHighlightScope = message.NewValue;
+ }
}
}
@@ -251,17 +257,17 @@ namespace BetterLyrics.WinUI3.ViewModels
if (message.PropertyName == nameof(SettingsPageViewModel.LyricsBgFontColorType))
{
_lyricsBgFontColorType = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
else if (message.PropertyName == nameof(SettingsPageViewModel.LyricsFgFontColorType))
{
_lyricsFgFontColorType = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
else if (message.PropertyName == nameof(SettingsPageViewModel.LyricsStrokeFontColorType))
{
_lyricsStrokeFontColorType = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
}
}
@@ -285,7 +291,7 @@ namespace BetterLyrics.WinUI3.ViewModels
if (message.PropertyName == nameof(SettingsPageViewModel.LyricsBackgroundTheme))
{
_lyricsBgTheme = message.NewValue;
- UpdateFontColor();
+ UpdateColorConfig();
}
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Update.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Update.cs
index 2140ff9..1e9d106 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Update.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Update.cs
@@ -7,6 +7,7 @@ using Microsoft.Graphics.Canvas.UI.Xaml;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using System;
+using System.Linq;
using System.Numerics;
using Windows.UI;
@@ -135,9 +136,9 @@ namespace BetterLyrics.WinUI3.ViewModels
float y = 0;
// Init Positions
- for (int i = 0; i < _multiLangLyrics.SafeGet(_langIndex)?.Count; i++)
+ for (int i = 0; i < _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.Count; i++)
{
- var line = _multiLangLyrics[_langIndex].SafeGet(i);
+ var line = _lyricsDataArr[_langIndex].LyricsLines.ElementAtOrDefault(i);
if (line == null)
{
@@ -178,7 +179,7 @@ namespace BetterLyrics.WinUI3.ViewModels
if ((!_isPlayingLineChanged && forceScroll) || _isPlayingLineChanged)
{
- LyricsLine? currentPlayingLine = _multiLangLyrics.SafeGet(_langIndex)?.SafeGet(_playingLineIndex);
+ LyricsLine? currentPlayingLine = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.ElementAtOrDefault(_playingLineIndex);
if (currentPlayingLine == null) return;
@@ -186,7 +187,7 @@ namespace BetterLyrics.WinUI3.ViewModels
if (playingTextLayout == null) return;
- float? targetYScrollOffset = (float?)(-currentPlayingLine!.Position.Y + _multiLangLyrics.SafeGet(_langIndex)?[0].Position.Y - playingTextLayout.LayoutBounds.Height / 2);
+ float? targetYScrollOffset = (float?)(-currentPlayingLine!.Position.Y + _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines[0].Position.Y - playingTextLayout.LayoutBounds.Height / 2);
if (!targetYScrollOffset.HasValue) return;
@@ -201,7 +202,7 @@ namespace BetterLyrics.WinUI3.ViewModels
// Update visible line indices
for (int i = startLineIndex; i <= endLineIndex; i++)
{
- var line = _multiLangLyrics.SafeGet(_langIndex)?.SafeGet(i);
+ var line = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.ElementAtOrDefault(i);
if (line == null || line.CanvasTextLayout == null)
{
@@ -249,7 +250,7 @@ namespace BetterLyrics.WinUI3.ViewModels
_endVisibleLineIndex = endVisibleLineIndex;
}
- private void UpdateFontColor()
+ private void UpdateColorConfig()
{
if (_isDesktopMode || _isDockMode)
{
@@ -360,15 +361,15 @@ namespace BetterLyrics.WinUI3.ViewModels
private void UpdateLinesProps()
{
- var currentPlayingLine = _multiLangLyrics
- .SafeGet(_langIndex)
- ?.SafeGet(_playingLineIndex);
+ var currentPlayingLine = _lyricsDataArr
+ .ElementAtOrDefault(_langIndex)
+ ?.LyricsLines.ElementAtOrDefault(_playingLineIndex);
if (currentPlayingLine == null) return;
for (int i = _startVisibleLineIndex; i <= _endVisibleLineIndex; i++)
{
- var line = _multiLangLyrics.SafeGet(_langIndex)?.SafeGet(i);
+ var line = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.ElementAtOrDefault(i);
if (line == null) continue;
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.cs
index b5b464f..10f647b 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.cs
@@ -72,6 +72,7 @@ namespace BetterLyrics.WinUI3.ViewModels
private ElementTheme _lyricsBgTheme;
private LineRenderingType _lyricsGlowEffectScope;
+ private LineRenderingType _lyricsHighlightScope;
private int _lyricsFontStrokeWidth;
private int _lyricsFontSize;
@@ -134,11 +135,13 @@ namespace BetterLyrics.WinUI3.ViewModels
private int _langIndex = 0;
- private List> _multiLangLyrics = [];
+ private List _lyricsDataArr = [];
private List _translationList = [];
private bool _isTranslationEnabled = false;
private int _targetLanguageIndex = 6;
+ private int _timelineSyncThreshold;
+
private CanvasTextFormat _lyricsTextFormat = new()
{
HorizontalAlignment = CanvasHorizontalAlignment.Left,
@@ -184,9 +187,9 @@ namespace BetterLyrics.WinUI3.ViewModels
private int GetCurrentPlayingLineIndex()
{
- for (int i = 0; i < _multiLangLyrics.SafeGet(_langIndex)?.Count; i++)
+ for (int i = 0; i < _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.Count; i++)
{
- var line = _multiLangLyrics.SafeGet(_langIndex)?[i];
+ var line = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines[i];
if (line == null)
{
continue;
@@ -262,14 +265,14 @@ namespace BetterLyrics.WinUI3.ViewModels
{
if (
SongInfo == null
- || _multiLangLyrics.SafeGet(_langIndex) == null
- || _multiLangLyrics[_langIndex].Count == 0
+ || _lyricsDataArr.ElementAtOrDefault(_langIndex) == null
+ || _lyricsDataArr[_langIndex].LyricsLines.Count == 0
)
{
return new Tuple(-1, -1);
}
- return new Tuple(0, _multiLangLyrics[_langIndex].Count - 1);
+ return new Tuple(0, _lyricsDataArr[_langIndex].LyricsLines.Count - 1);
}
private void LibWatcherService_MusicLibraryFilesChanged(object? sender, LibChangedEventArgs e)
@@ -288,7 +291,10 @@ namespace BetterLyrics.WinUI3.ViewModels
private void PlaybackService_PositionChanged(object? sender, PositionChangedEventArgs e)
{
- _totalTime = e.Position;
+ if (Math.Abs(_totalTime.TotalMilliseconds - e.Position.TotalMilliseconds) >= _timelineSyncThreshold)
+ {
+ _totalTime = e.Position;
+ }
}
private void PlaybackService_SongInfoChanged(object? sender, SongInfoChangedEventArgs e)
@@ -330,7 +336,7 @@ namespace BetterLyrics.WinUI3.ViewModels
_albumArtBgTransition.Reset(0f);
_albumArtBgTransition.StartTransition(1f);
- UpdateFontColor();
+ UpdateColorConfig();
}
}
@@ -341,93 +347,55 @@ namespace BetterLyrics.WinUI3.ViewModels
{
_ = _refreshLyricsRunner.RunAsync(async token =>
{
- await ShowTranslationsAsync(token);
+ await SetDisplayedAlongWithTranslationsAsync(token);
IsTranslating = false;
+ _isLayoutChanged = true;
});
}
else
{
- ShowOriginalsOnly();
+ _lyricsDataArr[0].SetDisplayedTextInOriginalText();
IsTranslating = false;
+ _isLayoutChanged = true;
}
}
- private async Task ShowTranslationsAsync(CancellationToken token)
+ private async Task SetDisplayedAlongWithTranslationsAsync(CancellationToken token)
{
_logger.LogInformation("Showing translation for lyrics...");
- string targetLangCode = LanguageHelper.SupportedTargetLanguages[_settingsService.SelectedTargetLanguageIndex].Code;
- var originalText = string.Join("\n", _multiLangLyrics.FirstOrDefault()?.Select(x => x.OriginalText) ?? []);
+ string targetLangCode = LanguageHelper.GetUserTargetLanguageCode();
+ string originalText = _lyricsDataArr[0].WrappedOriginalText;
string? originalLangCode = LanguageHelper.DetectLanguageCode(originalText);
if (originalLangCode == targetLangCode)
{
_logger.LogInformation("Original lyrics already in target language: {TargetLangCode}", targetLangCode);
- ShowOriginalsOnly();
- return;
- }
-
- // Try get translation from itself first
- if (_multiLangLyrics.Count > 1)
- {
- foreach (var langLyrics in _multiLangLyrics.Skip(1))
- {
- var translationList = langLyrics.Select(x => x.OriginalText).ToList();
- var translation = string.Join("\n", translationList);
- if (LanguageHelper.DetectLanguageCode(translation) == targetLangCode)
- {
- _translationList = translationList;
- break;
- }
- }
+ _lyricsDataArr[0].SetDisplayedTextInOriginalText();
}
else
{
- if (string.IsNullOrEmpty(_settingsService.LibreTranslateServer))
+ // Try get translation from itself first
+ int found = _translateService.SearchTranslatedLyricsItself(_lyricsDataArr);
+ if (found >= 0)
{
- _dispatcherQueue.TryEnqueue(() =>
- {
- App.Current.LyricsWindowNotificationPanel?.Notify(
- App.ResourceLoader!.GetString("TranslateServerNotSet"),
- Microsoft.UI.Xaml.Controls.InfoBarSeverity.Warning
- );
- });
- ShowOriginalsOnly();
- return;
+ _lyricsDataArr[0].SetDisplayedTextAlongWith(_lyricsDataArr[found]);
}
-
- var translated = await _translateService.TranslateAsync(originalText, targetLangCode, token);
- token.ThrowIfCancellationRequested();
-
- _translationList = translated.Split('\n').ToList();
- }
-
- int i = 0;
- foreach (var line in _multiLangLyrics.FirstOrDefault() ?? [])
- {
- line.DisplayedText = i < _translationList.Count ? $"{line.OriginalText}\n{_translationList[i]}" : line.OriginalText;
- i++;
- }
- _isLayoutChanged = true;
- }
-
- private void ShowOriginalsOnly()
- {
- _logger.LogInformation("Showing original lyrics only, translation disabled.");
- foreach (var langLyrics in _multiLangLyrics)
- {
- foreach (var line in langLyrics)
+ else
{
- line.DisplayedText = line.OriginalText;
+ var translated = await _translateService.TranslateTextAsync(originalText, targetLangCode, token);
+ token.ThrowIfCancellationRequested();
+
+ _lyricsDataArr[0].SetDisplayedTextAlongWith(translated);
}
}
- _isLayoutChanged = true;
}
private async Task RefreshLyricsAsync(CancellationToken token)
{
_logger.LogInformation("Refreshing lyrics...");
- SetLyricsLoadingPlaceholder();
+ _lyricsDataArr = [LyricsData.GetLoadingPlaceholder()];
+ _isLayoutChanged = true;
string? lyricsRaw = null;
@@ -448,33 +416,14 @@ namespace BetterLyrics.WinUI3.ViewModels
_logger.LogWarning("SongInfo is null, cannot search lyrics.");
}
- _multiLangLyrics = new LyricsParser().Parse(
- lyricsRaw,
- (int?)SongInfo?.DurationMs ?? (int)TimeSpan.FromMinutes(99).TotalMilliseconds
- );
- _logger.LogInformation("Parsed lyrics: {MultiLangLyricsCount} languages", _multiLangLyrics.Count);
+ _lyricsDataArr = new LyricsParser().Parse(lyricsRaw, (int?)SongInfo?.DurationMs);
+ _logger.LogInformation("Parsed lyrics: {MultiLangLyricsCount} languages", _lyricsDataArr.Count);
// This ensures that original lyrics are always shown while waiting for translations
- ShowOriginalsOnly();
- UpdateTranslations();
- }
-
- private void SetLyricsLoadingPlaceholder()
- {
- _multiLangLyrics = [];
- _multiLangLyrics.Add(
- [
- new LyricsLine
- {
- StartMs = 0,
- EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
- OriginalText = "â— â— â—",
- DisplayedText = "â— â— â—",
- CharTimings = [],
- },
- ]
- );
+ _lyricsDataArr[0].SetDisplayedTextInOriginalText();
_isLayoutChanged = true;
+
+ UpdateTranslations();
}
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs
index a5ae94c..92add0a 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs
@@ -1,7 +1,5 @@
// 2025/6/23 by Zhe Fang
-using System.Diagnostics;
-using System.Threading.Tasks;
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
@@ -15,8 +13,11 @@ using CommunityToolkit.Mvvm.Messaging.Messages;
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
+using System.Diagnostics;
+using System.Threading.Tasks;
using Windows.UI;
using WinRT.Interop;
+using WinUIEx;
namespace BetterLyrics.WinUI3
{
@@ -26,7 +27,8 @@ namespace BetterLyrics.WinUI3
IRecipient>,
IRecipient>
{
- private ForegroundWindowWatcher? _watcherHelper = null;
+ private ForegroundWindowWatcher? _windowWatcher = null;
+ private bool _ignoreFullscreenWindow = false;
public LyricsWindowViewModel(ISettingsService settingsService) : base(settingsService)
{
@@ -49,24 +51,16 @@ namespace BetterLyrics.WinUI3
[NotifyPropertyChangedRecipients]
public partial bool IsLyricsWindowLocked { get; set; } = false;
- [ObservableProperty]
- public partial bool ShowInfoBar { get; set; } = false;
-
[ObservableProperty]
public partial ElementTheme ThemeType { get; set; } = ElementTheme.Default;
[ObservableProperty]
public partial double TitleBarFontSize { get; set; } = 11;
- [ObservableProperty]
- public partial double TitleBarHeight { get; set; } = 36;
-
[ObservableProperty]
[NotifyPropertyChangedRecipients]
public partial bool IsMouseWithinWindow { get; set; } = false;
- private bool _ignoreFullscreenWindow = false;
-
public void Receive(PropertyChangedMessage message)
{
if (message.Sender is SystemTrayViewModel)
@@ -122,7 +116,7 @@ namespace BetterLyrics.WinUI3
if (window == null) return;
var hwnd = WindowNative.GetWindowHandle(window);
- _watcherHelper = new ForegroundWindowWatcher(
+ _windowWatcher = new ForegroundWindowWatcher(
hwnd,
onWindowChanged =>
{
@@ -133,10 +127,16 @@ namespace BetterLyrics.WinUI3
UpdateAccentColor(hwnd, mode);
}
);
- _watcherHelper.Start();
+ _windowWatcher.Start();
UpdateAccentColor(hwnd, mode);
}
+ private void StopWatchWindowColorChange()
+ {
+ _windowWatcher?.Stop();
+ _windowWatcher = null;
+ }
+
public void UpdateAccentColor(nint hwnd, WindowPixelSampleMode mode)
{
ActivatedWindowAccentColor = Helper.ColorHelper.GetAccentColor(hwnd, mode).ToColor();
@@ -152,12 +152,6 @@ namespace BetterLyrics.WinUI3
IsLyricsWindowLocked = true;
}
- private void StopWatchWindowColorChange()
- {
- _watcherHelper?.Stop();
- _watcherHelper = null;
- }
-
[RelayCommand]
private void ToggleDesktopMode()
{
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs
index 9fc82b6..8510cbe 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs
@@ -69,6 +69,7 @@ namespace BetterLyrics.WinUI3.ViewModels
LyricsFontSize = _settingsService.LyricsFontSize;
IsLyricsGlowEffectEnabled = _settingsService.IsLyricsGlowEffectEnabled;
LyricsGlowEffectScope = _settingsService.LyricsGlowEffectScope;
+ LyricsHighlightScope = _settingsService.LyricsHighlightScope;
IsFanLyricsEnabled = _settingsService.IsFanLyricsEnabled;
LyricsBgFontColorType = _settingsService.LyricsBgFontColorType;
@@ -86,6 +87,7 @@ namespace BetterLyrics.WinUI3.ViewModels
LyricsScrollEasingType = _settingsService.LyricsScrollEasingType;
LyricsScrollDuration = _settingsService.LyricsScrollDuration;
+ TimelineSyncThreshold = _settingsService.TimelineSyncThreshold;
_playbackService.MediaSourceProvidersInfoChanged += PlaybackService_SessionIdsChanged;
@@ -207,6 +209,10 @@ namespace BetterLyrics.WinUI3.ViewModels
[NotifyPropertyChangedRecipients]
public partial LineRenderingType LyricsGlowEffectScope { get; set; }
+ [ObservableProperty]
+ [NotifyPropertyChangedRecipients]
+ public partial LineRenderingType LyricsHighlightScope { get; set; }
+
[ObservableProperty]
[NotifyPropertyChangedRecipients]
public partial float LyricsLineSpacingFactor { get; set; }
@@ -218,7 +224,7 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty]
public partial object NavViewSelectedItemTag { get; set; }
- public string Version { get; set; } = Helper.MetadataHelper.AppVersion;
+ public string Version { get; set; } = MetadataHelper.AppVersion;
public string BuildDate { get; set; } = string.Empty;
@@ -248,25 +254,9 @@ namespace BetterLyrics.WinUI3.ViewModels
[NotifyPropertyChangedRecipients]
public partial int LyricsScrollDuration { get; set; }
- partial void OnLyricsScrollEasingTypeChanged(EasingType value)
- {
- _settingsService.LyricsScrollEasingType = value;
- }
-
- partial void OnLyricsScrollDurationChanged(int value)
- {
- _settingsService.LyricsScrollDuration = value;
- }
-
- partial void OnLyricsBackgroundThemeChanged(ElementTheme value)
- {
- _settingsService.LyricsBackgroundTheme = value;
- }
-
- partial void OnLyricsFontStrokeWidthChanged(int value)
- {
- _settingsService.LyricsFontStrokeWidth = value;
- }
+ [ObservableProperty]
+ [NotifyPropertyChangedRecipients]
+ public partial int TimelineSyncThreshold { get; set; }
public void OnLyricsSearchProvidersReordered()
{
@@ -288,11 +278,6 @@ namespace BetterLyrics.WinUI3.ViewModels
);
}
- public void OpenMusicFolder(LocalLyricsFolder folder)
- {
- OpenFolderInFileExplorer(folder.Path);
- }
-
public void RemoveFolderAsync(LocalLyricsFolder folder)
{
LocalLyricsFolders.Remove(folder);
@@ -371,31 +356,13 @@ namespace BetterLyrics.WinUI3.ViewModels
}
[RelayCommand]
- private void OpenCacheFolder()
+ private static async Task OpenCacheFolderAsync()
{
- OpenFolderInFileExplorer(PathHelper.CacheFolder);
- }
-
- private void OpenFolderInFileExplorer(string path)
- {
- Process.Start(
- new ProcessStartInfo
- {
- FileName = "explorer.exe",
- Arguments = path,
- UseShellExecute = true,
- }
- );
+ await Launcher.LaunchFolderPathAsync(PathHelper.CacheFolder);
}
[RelayCommand]
- private void PlayTestingMusicTask()
- {
- WindowHelper.OpenOrShowWindow();
- }
-
- [RelayCommand]
- private void RestartApp()
+ private static void RestartApp()
{
WindowHelper.RestartApp();
}
@@ -429,7 +396,7 @@ namespace BetterLyrics.WinUI3.ViewModels
try
{
string targetLangCode = LanguageHelper.SupportedTargetLanguages[SelectedTargetLanguageIndex].Code;
- string result = await _libreTranslateService.TranslateAsync("Hello, world!", targetLangCode, null);
+ string result = await _libreTranslateService.TranslateTextAsync("Hello, world!", targetLangCode, null);
_dispatcherQueue.TryEnqueue(() =>
{
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageLibreTranslateTestSuccessInfo"), Microsoft.UI.Xaml.Controls.InfoBarSeverity.Success);
@@ -479,51 +446,58 @@ namespace BetterLyrics.WinUI3.ViewModels
return result;
}
+ partial void OnLyricsScrollEasingTypeChanged(EasingType value)
+ {
+ _settingsService.LyricsScrollEasingType = value;
+ }
+ partial void OnLyricsScrollDurationChanged(int value)
+ {
+ _settingsService.LyricsScrollDuration = value;
+ }
+ partial void OnLyricsBackgroundThemeChanged(ElementTheme value)
+ {
+ _settingsService.LyricsBackgroundTheme = value;
+ }
+ partial void OnLyricsFontStrokeWidthChanged(int value)
+ {
+ _settingsService.LyricsFontStrokeWidth = value;
+ }
partial void OnIgnoreFullscreenWindowChanged(bool value)
{
_settingsService.IgnoreFullscreenWindow = value;
}
-
partial void OnSelectedTargetLanguageIndexChanged(int value)
{
_settingsService.SelectedTargetLanguageIndex = value;
}
-
partial void OnLibreTranslateServerChanged(string value)
{
_settingsService.LibreTranslateServer = value;
}
-
partial void OnAutoStartWindowTypeChanged(AutoStartWindowType value)
{
_settingsService.AutoStartWindowType = value;
}
-
partial void OnAutoLockOnDesktopModeChanged(bool value)
{
_settingsService.AutoLockOnDesktopMode = value;
}
-
partial void OnCoverImageRadiusChanged(int value)
{
_settingsService.CoverImageRadius = value;
}
-
partial void OnCoverOverlayBlurAmountChanged(int value)
{
_settingsService.CoverOverlayBlurAmount = value;
}
-
partial void OnCoverOverlayOpacityChanged(int value)
{
_settingsService.CoverOverlayOpacity = value;
}
-
partial void OnIsDynamicCoverOverlayEnabledChanged(bool value)
{
_settingsService.IsDynamicCoverOverlayEnabled = value;
}
-
partial void OnLanguageChanged(Enums.Language value)
{
switch (value)
@@ -551,85 +525,78 @@ namespace BetterLyrics.WinUI3.ViewModels
}
_settingsService.Language = Language;
}
-
partial void OnIsFanLyricsEnabledChanged(bool value)
{
_settingsService.IsFanLyricsEnabled = value;
}
-
partial void OnIsLyricsGlowEffectEnabledChanged(bool value)
{
_settingsService.IsLyricsGlowEffectEnabled = value;
}
-
partial void OnLyricsAlignmentTypeChanged(TextAlignmentType value)
{
_settingsService.LyricsAlignmentType = value;
}
-
partial void OnSongInfoAlignmentTypeChanged(TextAlignmentType value)
{
_settingsService.SongInfoAlignmentType = value;
}
-
partial void OnLyricsBlurAmountChanged(int value)
{
_settingsService.LyricsBlurAmount = value;
}
-
partial void OnLyricsCustomBgFontColorChanged(Color value)
{
_settingsService.LyricsCustomBgFontColor = value;
}
-
partial void OnLyricsCustomFgFontColorChanged(Color value)
{
_settingsService.LyricsCustomFgFontColor = value;
}
-
partial void OnLyricsCustomStrokeFontColorChanged(Color value)
{
_settingsService.LyricsCustomStrokeFontColor = value;
}
-
partial void OnLyricsBgFontColorTypeChanged(LyricsFontColorType value)
{
_settingsService.LyricsBgFontColorType = value;
}
-
partial void OnLyricsFgFontColorTypeChanged(LyricsFontColorType value)
{
_settingsService.LyricsFgFontColorType = value;
}
-
partial void OnLyricsStrokeFontColorTypeChanged(LyricsFontColorType value)
{
_settingsService.LyricsStrokeFontColorType = value;
}
-
partial void OnLyricsFontSizeChanged(int value)
{
_settingsService.LyricsFontSize = value;
}
-
partial void OnLyricsFontWeightChanged(LyricsFontWeight value)
{
_settingsService.LyricsFontWeight = value;
}
-
partial void OnLyricsGlowEffectScopeChanged(LineRenderingType value)
{
_settingsService.LyricsGlowEffectScope = value;
}
-
+ partial void OnLyricsHighlightScopeChanged(LineRenderingType value)
+ {
+ _settingsService.LyricsHighlightScope = value;
+ }
partial void OnLyricsLineSpacingFactorChanged(float value)
{
_settingsService.LyricsLineSpacingFactor = value;
}
-
partial void OnLyricsVerticalEdgeOpacityChanged(int value)
{
_settingsService.LyricsVerticalEdgeOpacity = value;
}
+ partial void OnTimelineSyncThresholdChanged(int value)
+ {
+ _settingsService.TimelineSyncThreshold = value;
+ }
+
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsWindowViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsWindowViewModel.cs
index d32b8f6..d79b4d9 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsWindowViewModel.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsWindowViewModel.cs
@@ -2,8 +2,7 @@
namespace BetterLyrics.WinUI3.ViewModels
{
- public class SettingsWindowViewModel : BaseWindowViewModel
+ public partial class SettingsWindowViewModel(ISettingsService settingsService) : BaseWindowViewModel(settingsService)
{
- public SettingsWindowViewModel(ISettingsService settingsService) : base(settingsService) { }
}
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SystemTrayViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SystemTrayViewModel.cs
index 225f98f..ecf1758 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SystemTrayViewModel.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SystemTrayViewModel.cs
@@ -8,10 +8,8 @@ using CommunityToolkit.Mvvm.Messaging.Messages;
namespace BetterLyrics.WinUI3.ViewModels
{
- public partial class SystemTrayViewModel : BaseViewModel, IRecipient>
+ public partial class SystemTrayViewModel(ISettingsService settingsService) : BaseViewModel(settingsService), IRecipient>
{
- public SystemTrayViewModel(ISettingsService settingsService) : base(settingsService) { }
-
[ObservableProperty]
[NotifyPropertyChangedRecipients]
public partial bool IsLyricsWindowLocked { get; set; } = false;
@@ -34,15 +32,14 @@ namespace BetterLyrics.WinUI3.ViewModels
}
[RelayCommand]
- private void ExitApp()
+ private static void ExitApp()
{
WindowHelper.ExitAllWindows();
}
[RelayCommand]
- private void OpenSettings()
+ private static void OpenSettings()
{
- // 打开设置窗å£
WindowHelper.OpenOrShowWindow();
}
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml
index c59e65a..5da2387 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml
@@ -188,8 +188,8 @@
VerticalAlignment="Center"
Text="{x:Bind ViewModel.CoverOverlayBlurAmount, Mode=OneWay}" />
+
+
+
+
+
+
+
+
-
-
+
+
+
@@ -794,6 +803,7 @@
+
@@ -815,24 +825,52 @@
Glyph=}"
IsClickEnabled="True" />
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml.cs
index 1c23d85..38d5fc8 100644
--- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml.cs
+++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml.cs
@@ -1,5 +1,6 @@
// 2025/6/23 by Zhe Fang
+using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.ViewModels;
using CommunityToolkit.Mvvm.DependencyInjection;
@@ -121,5 +122,15 @@ namespace BetterLyrics.WinUI3.Views
}
}
}
+
+ private void QQGroupButton_Click(object sender, RoutedEventArgs e)
+ {
+ Launcher.LaunchUriAsync(new Uri(MetadataHelper.QQGroupUrl));
+ }
+
+ private void DiscodGroupButton_Click(object sender, RoutedEventArgs e)
+ {
+ Launcher.LaunchUriAsync(new Uri(MetadataHelper.DiscordUrl));
+ }
}
}