mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-12 10:54:55 +08:00
fix
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="37412.BetterLyrics"
|
||||
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
||||
Version="1.0.10.0" />
|
||||
Version="1.0.11.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Discord.png
Normal file
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Discord.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/QQ.png
Normal file
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/QQ.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
@@ -4,7 +4,8 @@ namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum LineRenderingType
|
||||
{
|
||||
UntilCurrentChar,
|
||||
CurrentCharOnly,
|
||||
CurrentChar,
|
||||
LineStartToCurrentChar,
|
||||
CurrentLine
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T>(this IList<T> list, int index)
|
||||
{
|
||||
if (list == null || index < 0 || index >= list.Count) return default;
|
||||
return list[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,13 +47,6 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
_originalWindowBounds.Remove(hwnd);
|
||||
}
|
||||
|
||||
// <20>ָ<EFBFBD><D6B8><EFBFBD>ʽ
|
||||
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)
|
||||
);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD>ʽ
|
||||
if (!_originalWindowStyles.ContainsKey(hwnd))
|
||||
_originalWindowStyles[hwnd] = window.GetWindowStyle();
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>ԭ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)
|
||||
{
|
||||
// <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD>ʽ
|
||||
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);
|
||||
// <20>ָ<EFBFBD><D6B8><EFBFBD>ʽ
|
||||
if (_originalWindowStyles.TryGetValue(hwnd, out var style))
|
||||
{
|
||||
window.SetWindowStyle(style);
|
||||
_originalWindowStyles.Remove(hwnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Windows.UI.Color> GetAccentColorsFromByte(byte[] bytes)
|
||||
public static List<Color> GetAccentColorsFromByte(byte[] bytes)
|
||||
{
|
||||
// 使用 ImageSharp 读取图片
|
||||
using var image = SixLabors.ImageSharp.Image.Load<SixLabors.ImageSharp.PixelFormats.Rgba32>(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ISettingsService>();
|
||||
|
||||
public static List<Models.LanguageInfo> SupportedTargetLanguages =>
|
||||
[
|
||||
@@ -106,5 +108,10 @@ namespace BetterLyrics.WinUI3.Services
|
||||
// 其他语言直接返回两字母代码
|
||||
return code;
|
||||
}
|
||||
|
||||
public static string GetUserTargetLanguageCode()
|
||||
{
|
||||
return SupportedTargetLanguages[_settingsService.SelectedTargetLanguageIndex].Code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<List<LyricsLine>> _multiLangLyricsLines = [];
|
||||
private List<LyricsData> _lyricsDataArr = [];
|
||||
|
||||
public List<List<LyricsLine>> Parse(string? raw, int durationMs)
|
||||
public List<LyricsData> 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<LyricsLine>());
|
||||
_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<ILineInfo>? lines)
|
||||
private void ParseQQNeteaseKugou(List<ILineInfo>? lines)
|
||||
{
|
||||
lines = lines?.Where(x => x.Text != string.Empty).ToList();
|
||||
List<LyricsLine> 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 = [],
|
||||
}
|
||||
|
||||
@@ -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<DateTime> GetBuildDate()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
95
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs
Normal file
95
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs
Normal file
@@ -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<LyricsLine> 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<LyricsLine> 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<string> 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 = [],
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<string> TranslateAsync(string text, string targetLangCode, CancellationToken? token);
|
||||
Task<string> TranslateTextAsync(string text, string targetLangCode, CancellationToken? token);
|
||||
|
||||
int SearchTranslatedLyricsItself(List<LyricsData> lyricsDataArr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<bool> 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<string?> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<int>(LyricsHighlightSopeKey);
|
||||
set => SetValue(LyricsHighlightSopeKey, (int)value);
|
||||
}
|
||||
|
||||
public float LyricsLineSpacingFactor
|
||||
{
|
||||
get => GetValue<float>(LyricsLineSpacingFactorKey);
|
||||
@@ -506,6 +517,12 @@ namespace BetterLyrics.WinUI3.Services
|
||||
set => SetValue(IgnoreFullscreenWindowKey, value);
|
||||
}
|
||||
|
||||
public int TimelineSyncThreshold
|
||||
{
|
||||
get => GetValue<int>(TimelineSyncThresholdKey);
|
||||
set => SetValue(TimelineSyncThresholdKey, value);
|
||||
}
|
||||
|
||||
private T? GetValue<T>(string key)
|
||||
{
|
||||
if (_localSettings.Values.TryGetValue(key, out object? value))
|
||||
|
||||
@@ -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<string> TranslateAsync(string text, string targetLangCode, CancellationToken? token)
|
||||
public async Task<string> 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<LyricsData> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@
|
||||
<value>No music playing now</value>
|
||||
</data>
|
||||
<data name="SettingsPageDev.Content" xml:space="preserve">
|
||||
<value>Developer options</value>
|
||||
<value>Advanced options</value>
|
||||
</data>
|
||||
<data name="SettingsPageMockMusicPlaying.Header" xml:space="preserve">
|
||||
<value>Play test music</value>
|
||||
@@ -459,13 +459,10 @@
|
||||
<data name="SettingsPageLyricsExtraBlack.Content" xml:space="preserve">
|
||||
<value>Extra Black</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeWholeLyrics.Content" xml:space="preserve">
|
||||
<value>Whole lyrics</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentLine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentLine.Content" xml:space="preserve">
|
||||
<value>Current line</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentChar.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
|
||||
<value>Current char</value>
|
||||
</data>
|
||||
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
|
||||
@@ -717,4 +714,25 @@
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>Ease-in-out cubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsRendingScopeLineStartToCurrentChar.Content" xml:space="preserve">
|
||||
<value>Current line start to current char</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsHighlightScope.Header" xml:space="preserve">
|
||||
<value>Highlight scope</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Header" xml:space="preserve">
|
||||
<value>Lyrics timeline sync threshold</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Description" xml:space="preserve">
|
||||
<value>If the lyrics progress is jittery, try increasing this threshold; changing this value can cause lyrics synchronization to deviate</value>
|
||||
</data>
|
||||
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
|
||||
<value>QQ feedback & chat group</value>
|
||||
</data>
|
||||
<data name="SettingsPageDiscord.Header" xml:space="preserve">
|
||||
<value>Discord</value>
|
||||
</data>
|
||||
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
|
||||
<value>Join now</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -310,7 +310,7 @@
|
||||
<value>今は音楽が再生されていません</value>
|
||||
</data>
|
||||
<data name="SettingsPageDev.Content" xml:space="preserve">
|
||||
<value>開発者オプション</value>
|
||||
<value>高度なオプション</value>
|
||||
</data>
|
||||
<data name="SettingsPageMockMusicPlaying.Header" xml:space="preserve">
|
||||
<value>テスト音楽を再生します</value>
|
||||
@@ -459,13 +459,10 @@
|
||||
<data name="SettingsPageLyricsExtraBlack.Content" xml:space="preserve">
|
||||
<value>余分な黒</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeWholeLyrics.Content" xml:space="preserve">
|
||||
<value>歌詞全体</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentLine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentLine.Content" xml:space="preserve">
|
||||
<value>現在の行</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentChar.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
|
||||
<value>現在の文字</value>
|
||||
</data>
|
||||
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
|
||||
@@ -717,4 +714,25 @@
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>3つの遅いインとアウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsRendingScopeLineStartToCurrentChar.Content" xml:space="preserve">
|
||||
<value>現在のラインが現在の文字から始まります</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsHighlightScope.Header" xml:space="preserve">
|
||||
<value>ハイライトスコープ</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Header" xml:space="preserve">
|
||||
<value>歌詞タイムライン同期しきい値</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Description" xml:space="preserve">
|
||||
<value>歌詞の進行が不安定な場合は、このしきい値を増やしてみてください。この値を変更すると、歌詞の同期が逸脱する可能性があります</value>
|
||||
</data>
|
||||
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
|
||||
<value>QQフィードバック&チャットグループ</value>
|
||||
</data>
|
||||
<data name="SettingsPageDiscord.Header" xml:space="preserve">
|
||||
<value>Discord</value>
|
||||
</data>
|
||||
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
|
||||
<value>今すぐ参加してください</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -310,7 +310,7 @@
|
||||
<value>지금 음악이 재생되지 않습니다</value>
|
||||
</data>
|
||||
<data name="SettingsPageDev.Content" xml:space="preserve">
|
||||
<value>개발자 옵션</value>
|
||||
<value>고급 옵션</value>
|
||||
</data>
|
||||
<data name="SettingsPageMockMusicPlaying.Header" xml:space="preserve">
|
||||
<value>테스트 음악을 재생하십시오</value>
|
||||
@@ -459,13 +459,10 @@
|
||||
<data name="SettingsPageLyricsExtraBlack.Content" xml:space="preserve">
|
||||
<value>여분의 검은 색</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeWholeLyrics.Content" xml:space="preserve">
|
||||
<value>전체 가사</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentLine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentLine.Content" xml:space="preserve">
|
||||
<value>현재 라인</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentChar.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
|
||||
<value>현재 숯</value>
|
||||
</data>
|
||||
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
|
||||
@@ -717,4 +714,25 @@
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>세 번 느리게 안팎으로</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsRendingScopeLineStartToCurrentChar.Content" xml:space="preserve">
|
||||
<value>현재 라인은 현재 숯으로 시작합니다</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsHighlightScope.Header" xml:space="preserve">
|
||||
<value>하이라이트 범위</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Header" xml:space="preserve">
|
||||
<value>가사 타임 라인 동기화 임계 값</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Description" xml:space="preserve">
|
||||
<value>가사 진행 상황이 불안하다면이 임계 값을 높이십시오. 이 값을 변경하면 가사가 동기화 될 수 있습니다</value>
|
||||
</data>
|
||||
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
|
||||
<value>QQ 피드백 및 채팅 그룹</value>
|
||||
</data>
|
||||
<data name="SettingsPageDiscord.Header" xml:space="preserve">
|
||||
<value>Discord</value>
|
||||
</data>
|
||||
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
|
||||
<value>지금 가입하십시오</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -310,7 +310,7 @@
|
||||
<value>当前没有正在播放的音乐</value>
|
||||
</data>
|
||||
<data name="SettingsPageDev.Content" xml:space="preserve">
|
||||
<value>开发者选项</value>
|
||||
<value>高级选项</value>
|
||||
</data>
|
||||
<data name="SettingsPageMockMusicPlaying.Header" xml:space="preserve">
|
||||
<value>播放测试音乐</value>
|
||||
@@ -459,13 +459,10 @@
|
||||
<data name="SettingsPageLyricsExtraBlack.Content" xml:space="preserve">
|
||||
<value>超黑</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeWholeLyrics.Content" xml:space="preserve">
|
||||
<value>全部歌词</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentLine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentLine.Content" xml:space="preserve">
|
||||
<value>当前行</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentChar.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
|
||||
<value>当前字符</value>
|
||||
</data>
|
||||
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
|
||||
@@ -717,4 +714,25 @@
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>三次缓入缓出</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsRendingScopeLineStartToCurrentChar.Content" xml:space="preserve">
|
||||
<value>当前歌词开始到当前字符</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsHighlightScope.Header" xml:space="preserve">
|
||||
<value>高亮显示范围</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Header" xml:space="preserve">
|
||||
<value>歌词时间轴同步阈值</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Description" xml:space="preserve">
|
||||
<value>当歌词进度抖动时,请尝试增加该阈值;更改此值会导致歌词同步有偏差</value>
|
||||
</data>
|
||||
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
|
||||
<value>QQ 反馈交流群</value>
|
||||
</data>
|
||||
<data name="SettingsPageDiscord.Header" xml:space="preserve">
|
||||
<value>Discord</value>
|
||||
</data>
|
||||
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
|
||||
<value>立即加入</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -310,7 +310,7 @@
|
||||
<value>目前沒有正在播放的音樂</value>
|
||||
</data>
|
||||
<data name="SettingsPageDev.Content" xml:space="preserve">
|
||||
<value>開發者選項</value>
|
||||
<value>高級選項</value>
|
||||
</data>
|
||||
<data name="SettingsPageMockMusicPlaying.Header" xml:space="preserve">
|
||||
<value>播放測試音樂</value>
|
||||
@@ -459,13 +459,10 @@
|
||||
<data name="SettingsPageLyricsExtraBlack.Content" xml:space="preserve">
|
||||
<value>超黑</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeWholeLyrics.Content" xml:space="preserve">
|
||||
<value>全部歌詞</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentLine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentLine.Content" xml:space="preserve">
|
||||
<value>目前行</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsGlowEffectScopeCurrentChar.Content" xml:space="preserve">
|
||||
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
|
||||
<value>目前字元</value>
|
||||
</data>
|
||||
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
|
||||
@@ -717,4 +714,25 @@
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>三次緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsRendingScopeLineStartToCurrentChar.Content" xml:space="preserve">
|
||||
<value>當前歌詞開始到當前字符</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsHighlightScope.Header" xml:space="preserve">
|
||||
<value>高亮顯示範圍</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Header" xml:space="preserve">
|
||||
<value>歌詞時間軸同步閾值</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsTimelineThreshold.Description" xml:space="preserve">
|
||||
<value>當歌詞進度抖動時,請嘗試增加該閾值;更改此值會導致歌詞同步偏差</value>
|
||||
</data>
|
||||
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
|
||||
<value>QQ 回饋交流群</value>
|
||||
</data>
|
||||
<data name="SettingsPageDiscord.Header" xml:space="preserve">
|
||||
<value>Discord</value>
|
||||
</data>
|
||||
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
|
||||
<value>立即加入</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -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) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class LyricsPageViewModel : BaseViewModel, IRecipient<PropertyChangedMessage<int>>, IRecipient<PropertyChangedMessage<bool>>
|
||||
public partial class LyricsPageViewModel : BaseViewModel, IRecipient<PropertyChangedMessage<bool>>
|
||||
{
|
||||
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<int> 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<SettingsWindow>();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -57,8 +57,6 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
// Receive methods for handling messages from other view models
|
||||
|
||||
public void Receive(PropertyChangedMessage<bool> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<List<LyricsLine>> _multiLangLyrics = [];
|
||||
private List<LyricsData> _lyricsDataArr = [];
|
||||
private List<string> _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<int, int>(-1, -1);
|
||||
}
|
||||
|
||||
return new Tuple<int, int>(0, _multiLangLyrics[_langIndex].Count - 1);
|
||||
return new Tuple<int, int>(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<PropertyChangedMessage<ElementTheme>>,
|
||||
IRecipient<PropertyChangedMessage<bool>>
|
||||
{
|
||||
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<bool> 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()
|
||||
{
|
||||
|
||||
@@ -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<LyricsWindow>();
|
||||
}
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,8 @@ using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class SystemTrayViewModel : BaseViewModel, IRecipient<PropertyChangedMessage<bool>>
|
||||
public partial class SystemTrayViewModel(ISettingsService settingsService) : BaseViewModel(settingsService), IRecipient<PropertyChangedMessage<bool>>
|
||||
{
|
||||
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<SettingsWindow>();
|
||||
}
|
||||
|
||||
|
||||
@@ -188,8 +188,8 @@
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind ViewModel.CoverOverlayBlurAmount, Mode=OneWay}" />
|
||||
<Slider
|
||||
Maximum="200"
|
||||
Minimum="50"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="10"
|
||||
TickFrequency="10"
|
||||
@@ -653,6 +653,14 @@
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsHighlightScope" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LyricsHighlightScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageLyricsGlowEffect"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
@@ -662,8 +670,9 @@
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsGlowEffectScope" IsEnabled="{x:Bind ViewModel.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LyricsGlowEffectScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsGlowEffectScopeCurrentLine" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsGlowEffectScopeCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
@@ -794,6 +803,7 @@
|
||||
<!-- About -->
|
||||
<controls:Case Value="About">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<controls:SettingsCard Header="BetterLyrics" HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/Logo.png}">
|
||||
<controls:SettingsCard.Description>
|
||||
<RichTextBlock>
|
||||
@@ -815,24 +825,52 @@
|
||||
Glyph=}"
|
||||
IsClickEnabled="True" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageQQGroup" HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/QQ.png}">
|
||||
<Button x:Uid="SettingsPageJoinNowButton" Click="QQGroupButton_Click" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageDiscord" HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/Discord.png}">
|
||||
<Button x:Uid="SettingsPageJoinNowButton" Click="DiscodGroupButton_Click" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</controls:Case>
|
||||
|
||||
<!-- Dev -->
|
||||
<controls:Case Value="Dev">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageMockMusicPlaying">
|
||||
<HyperlinkButton
|
||||
x:Uid="SettingsPagePlayingMockMusicButton"
|
||||
Command="{x:Bind ViewModel.PlayTestingMusicTaskCommand}"
|
||||
NavigateUri="https://soundcloud.com/carlyraejepsen/cut-to-the-feeling" />
|
||||
<HyperlinkButton x:Uid="SettingsPagePlayingMockMusicButton" NavigateUri="https://soundcloud.com/carlyraejepsen/cut-to-the-feeling" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageCache">
|
||||
<Button x:Uid="SettingsPageOpenLogFolderButton" Command="{x:Bind ViewModel.OpenCacheFolderCommand}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageDebugOverlay">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsDebugOverlayEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsTimelineThreshold">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock VerticalAlignment="Center" Text="{x:Bind ViewModel.TimelineSyncThreshold, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center"
|
||||
Text=" ms" />
|
||||
<Slider
|
||||
Maximum="1000"
|
||||
Minimum="0"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="100"
|
||||
TickFrequency="100"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind ViewModel.TimelineSyncThreshold, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</controls:Case>
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user