diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest index 15b0eb3..2d896a4 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest @@ -12,7 +12,7 @@ + Version="0.0.12.0" /> diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml index 1f411d7..68a3aa4 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml @@ -82,7 +82,7 @@ - + + @@ -100,7 +106,7 @@ - Segoe Fluent Icons, Segoe MDL2 Assets + ms-appx:///Assets/Segoe Fluent Icons.ttf#Segoe Fluent Icons diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Segoe Fluent Icons.ttf b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Segoe Fluent Icons.ttf new file mode 100644 index 0000000..8f05a4b Binary files /dev/null and b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Segoe Fluent Icons.ttf differ diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj index af27b0e..f3c1d0a 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj @@ -20,6 +20,7 @@ + @@ -30,6 +31,7 @@ + @@ -80,6 +82,11 @@ + + + Always + + MSBuild:Compile diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs index 2a22ccc..f7994ea 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs @@ -1,5 +1,14 @@ // 2025/6/23 by Zhe Fang +using CommunityToolkit.WinUI.Helpers; +using Microsoft.Graphics.Canvas; +using Microsoft.Graphics.Canvas.Text; +using Microsoft.UI; +using Microsoft.UI.Xaml.Media.Imaging; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using System; using System.Collections.Generic; using System.IO; @@ -7,10 +16,6 @@ using System.Linq; using System.Numerics; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; -using Microsoft.Graphics.Canvas; -using Microsoft.Graphics.Canvas.Text; -using Microsoft.UI; -using Microsoft.UI.Xaml.Media.Imaging; using Windows.Graphics.Imaging; using Windows.Storage.Streams; using Windows.UI; @@ -30,62 +35,33 @@ namespace BetterLyrics.WinUI3.Helper return stream; } - public static async Task CreateTextPlaceholderBytesAsync(string text, int width, int height) + public static async Task CreateTextPlaceholderBytesAsync(int width, int height) { var device = CanvasDevice.GetSharedDevice(); var renderTarget = new CanvasRenderTarget(device, width, height, 96); - // 居中绘制文字 + // 随机生成渐变色 + Windows.UI.Color RandomColor() + { + var rand = new Random(Guid.NewGuid().GetHashCode()); + double h = rand.NextDouble() * 360; + double s = 0.35 + rand.NextDouble() * 0.3; // 0.35~0.65,适中饱和度 + double l = 0.5 + rand.NextDouble() * 0.3; // 0.5~0.8,明亮 + return HslToColor(h, s, l); + } + + Windows.UI.Color color1 = RandomColor(); + Windows.UI.Color color2 = RandomColor(); + using (var ds = renderTarget.CreateDrawingSession()) { - // 背景色 - ds.Clear(Colors.LightGray); - - // 文字格式 - var format = new CanvasTextFormat + // 绘制线性渐变背景 + var gradientBrush = new Microsoft.Graphics.Canvas.Brushes.CanvasLinearGradientBrush(ds, color1, color2) { - FontSize = Math.Min(width, height) / 6f, - FontWeight = Microsoft.UI.Text.FontWeights.SemiBold, - HorizontalAlignment = CanvasHorizontalAlignment.Center, - VerticalAlignment = CanvasVerticalAlignment.Center, - WordWrapping = CanvasWordWrapping.Wrap, - TrimmingGranularity = CanvasTextTrimmingGranularity.Character, - Options = CanvasDrawTextOptions.Default, + StartPoint = new System.Numerics.Vector2(0, 0), + EndPoint = new System.Numerics.Vector2(width, height) }; - - // 设定边距 - float margin = Math.Min(width, height) / 12f; - float availableWidth = width - 2 * margin; - float availableHeight = height - 2 * margin; - - // 计算合适的字体大小以适应内容区域 - float fontSize = format.FontSize; - float minFontSize = 8f; - float maxFontSize = format.FontSize; - CanvasTextLayout layout; - do - { - format.FontSize = fontSize; - layout = new CanvasTextLayout( - ds, - text, - format, - availableWidth, - availableHeight - ); - if ( - layout.LayoutBounds.Width <= availableWidth - && layout.LayoutBounds.Height <= availableHeight - ) - break; - fontSize -= 1f; - } while (fontSize >= minFontSize); - - // 居中绘制文字(在内容区域内居中) - var bounds = layout.LayoutBounds; - var x = margin + (availableWidth - (float)bounds.Width) / 2f - (float)bounds.X; - var y = margin + (availableHeight - (float)bounds.Height) / 2f - (float)bounds.Y; - ds.DrawTextLayout(layout, new Vector2(x, y), Colors.DarkGray); + ds.FillRectangle(0, 0, width, height, gradientBrush); } // 保存为 PNG 并转为 byte[] @@ -100,9 +76,34 @@ namespace BetterLyrics.WinUI3.Helper } return buffer; } + + // HSL转Color + static Windows.UI.Color HslToColor(double h, double s, double l) + { + h = h / 360.0; + double r = l, g = l, b = l; + if (s != 0) + { + double q = l < 0.5 ? l * (1 + s) : l + s - l * s; + double p = 2 * l - q; + r = HueToRgb(p, q, h + 1.0 / 3.0); + g = HueToRgb(p, q, h); + b = HueToRgb(p, q, h - 1.0 / 3.0); + } + return Windows.UI.Color.FromArgb(255, (byte)(r * 255), (byte)(g * 255), (byte)(b * 255)); + } + static double HueToRgb(double p, double q, double t) + { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1.0 / 6.0) return p + (q - p) * 6 * t; + if (t < 1.0 / 2.0) return q; + if (t < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - t) * 6; + return p; + } } - public static List GetAccentColorsFromByte(byte[] bytes) + public static List GetAccentColorsFromByte(byte[] bytes) { // 使用 ImageSharp 读取图片 using var image = SixLabors.ImageSharp.Image.Load(bytes); @@ -137,7 +138,6 @@ namespace BetterLyrics.WinUI3.Helper .ToList(); } - //public static async Task GetBitmapImageFromBytesAsync(byte[] imageBytes) //{ // var stream = new InMemoryRandomAccessStream(); @@ -188,5 +188,35 @@ namespace BetterLyrics.WinUI3.Helper } return (float)(sum / (pixels.Length / 4)); } + + public static byte[] MakeSquareWithThemeColor(byte[] imageBytes) + { + using var image = Image.Load(imageBytes); + + if (image.Width == image.Height) + { + // 已经是正方形,直接返回 + return imageBytes; + } + + int size = Math.Max(image.Width, image.Height); + + var themeColor = Rgba32.ParseHex(GetAccentColorsFromByte(imageBytes).FirstOrDefault().ToHex()); + + // 新建正方形画布 + using var square = new Image(size, size, themeColor); + + // 计算居中位置 + int offsetX = (size - image.Width) / 2; + int offsetY = (size - image.Height) / 2; + + // 绘制原图到正方形画布 + square.Mutate(ctx => ctx.DrawImage(image, new Point(offsetX, offsetY), 1f)); + + // 保存为 PNG 字节流 + using var ms = new MemoryStream(); + square.Save(ms, new PngEncoder()); + return ms.ToArray(); + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs index 11c0a7c..5ea75d8 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs @@ -98,16 +98,19 @@ namespace BetterLyrics.WinUI3.Services }; } - public static string DetectCountryCode(string? text) + public static string ConvertToCountryCode(string? languageCode) { - if (text == null) return "en"; - var code = DetectLanguageCode(text); - if (code == null) return "en"; - // 处理中文简体和繁体 - if (code == "zh-Hans") return "cn"; - if (code == "zh-Hant") return "cn"; - // 其他语言直接返回两字母代码 - return code; + if (languageCode == null) return "us"; + + return languageCode switch + { + "zh" => "cn", + "zh-Hans" => "cn", + "zh-Hant" => "tw", + "ja" => "jp", + "ko" => "kr", + _ => "us" + }; } public static string GetUserTargetLanguageCode() diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/NetHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/NetHelper.cs new file mode 100644 index 0000000..8a68874 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/NetHelper.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BetterLyrics.WinUI3.Helper +{ + public class NetHelper + { + public static async Task CheckConnectivity(string url) + { + try + { + using var client = new System.Net.Http.HttpClient(); + // Try to reach a reliable endpoint + var res = await client.GetAsync(url); + return res.IsSuccessStatusCode; + } + catch + { + return false; // If any exception occurs, assume no connectivity + } + } + } +} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/AlbumArtSearchService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/AlbumArtSearchService.cs index 2b26dbb..9aedf97 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/AlbumArtSearchService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/AlbumArtSearchService.cs @@ -7,8 +7,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net; using System.Net.Http; using System.Text; +using System.Text.Encodings.Web; using System.Text.Json; using System.Threading.Tasks; @@ -48,7 +50,11 @@ namespace BetterLyrics.WinUI3.Services result = bytesFromSMTC; break; case AlbumArtSearchProvider.iTunes: - result = await SearchiTunesAsync(artist, album); + foreach (string countryCode in new List() { "us", "cn", "jp", "kr" }) + { + result = await SearchiTunesAsync(artist, album, title, countryCode); + if (result != null) break; + } break; default: break; @@ -82,7 +88,7 @@ namespace BetterLyrics.WinUI3.Services return null; } - private async Task SearchiTunesAsync(string artist, string album) + private async Task SearchiTunesAsync(string artist, string album, string title, string countryCode) { // Source: https://gist.github.com/mcworkaholic/82fbf203e3f1043bbe534b5b2974c0ce try @@ -96,10 +102,9 @@ namespace BetterLyrics.WinUI3.Services } // Build the iTunes API URL - string url = $"https://itunes.apple.com/search?term=" + artist + "+" + album + "&country=" + LanguageHelper.DetectCountryCode(album + artist) + "&entity=album"; - url.Replace(" ", "-"); - // Make a request to the API + string url = $"https://itunes.apple.com/search?term=" + WebUtility.UrlEncode($"{artist} {album}").Replace("%20", "+") + "&country=" + countryCode + "&entity=album&media=music&limit=1"; + // Make a request to the API HttpResponseMessage response = await _iTunesHttpClinet.GetAsync(url); response.EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); @@ -118,6 +123,7 @@ namespace BetterLyrics.WinUI3.Services if (fetched != null && fetched.Length > 0) { + fetched = ImageHelper.MakeSquareWithThemeColor(fetched); // Write to cache FileHelper.WriteAlbumArtCache(artist, album, fetched, format, PathHelper.iTunesAlbumArtCacheDirectory); return fetched; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs index c61230d..4f9ba23 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs @@ -3,10 +3,8 @@ using System.Collections.Generic; using BetterLyrics.WinUI3.Enums; using BetterLyrics.WinUI3.Models; -using Microsoft.UI.Text; using Microsoft.UI.Xaml; using Windows.UI; -using Windows.UI.Text; namespace BetterLyrics.WinUI3.Services { @@ -92,5 +90,7 @@ namespace BetterLyrics.WinUI3.Services int TimelineSyncThreshold { get; set; } int LockHotKeyIndex { get; set; } + bool IsImmersiveMode { get; set; } + string LXMusicServer { get; set; } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlaybackService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlaybackService.cs index 2ef4bff..5c5b604 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlaybackService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlaybackService.cs @@ -7,6 +7,7 @@ using BetterLyrics.WinUI3.ViewModels; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging.Messages; +using EvtSource; using Microsoft.Extensions.Logging; using Microsoft.UI.Dispatching; using System; @@ -14,6 +15,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Windows.Graphics.Imaging; @@ -29,14 +31,20 @@ namespace BetterLyrics.WinUI3.Services { private readonly IAlbumArtSearchService _albumArtSearchService; private readonly ILogger _logger; + + private readonly string _lxMusicId = "cn.toside.music.desktop"; + + private EventSourceReader? _sse = null; + private readonly MediaManager _mediaManager = new(); + private readonly LatestOnlyTaskRunner _AlbumArtRefreshRunner = new(); private readonly LatestOnlyTaskRunner _OnAnyMediaPropertyChangedRunner = new(); private SongInfo? _cachedSongInfo; private List _mediaSourceProvidersInfo; private byte[]? _SMTCAlbumArtBytes = null; - private AlbumArtChangedEventArgs _albumArtChangedEventArgs = new AlbumArtChangedEventArgs(); + private AlbumArtChangedEventArgs _albumArtChangedEventArgs = new(); public event EventHandler? IsPlayingChanged; public event EventHandler? PositionChanged; @@ -140,6 +148,15 @@ namespace BetterLyrics.WinUI3.Services token.ThrowIfCancellationRequested(); + if (id == _lxMusicId) + { + StartSSE(); + } + else + { + StopSSE(); + } + _cachedSongInfo = new SongInfo { Title = mediaProperties.Title, @@ -232,7 +249,7 @@ namespace BetterLyrics.WinUI3.Services if (bytes == null) { - bytes = await ImageHelper.CreateTextPlaceholderBytesAsync($"{_cachedSongInfo!.Artist} - {_cachedSongInfo.Title}", 400, 400); + bytes = await ImageHelper.CreateTextPlaceholderBytesAsync(400, 400); token.ThrowIfCancellationRequested(); } @@ -255,6 +272,46 @@ namespace BetterLyrics.WinUI3.Services }); } + private void StartSSE() + { + _sse = new EventSourceReader(new Uri($"{_settingsService.LXMusicServer}/subscribe-player-status?filter=progress")).Start(); + _sse.MessageReceived += Sse_MessageReceived; + _sse.Disconnected += Sse_Disconnected; + } + + private void StopSSE() + { + if (_sse != null) + { + _sse.MessageReceived -= Sse_MessageReceived; + _sse.Disconnected -= Sse_Disconnected; + _sse.Dispose(); + _sse = null; + } + } + + private void Sse_Disconnected(object sender, DisconnectEventArgs e) + { + Task.Run(async () => + { + await Task.Delay(e.ReconnectDelay); + if (_sse != null && !_sse.IsDisposed) _sse.Start(); + }); + } + + private void Sse_MessageReceived(object sender, EventSourceMessageEventArgs e) + { + var data = JsonSerializer.Deserialize(e.Message, Serialization.SourceGenerationContext.Default.JsonElement); + + if (data.TryGetDouble(out double positionSeconds)) + { + if (_cachedSongInfo?.SourceAppUserModelId == _lxMusicId) + { + PositionChanged?.Invoke(this, new PositionChangedEventArgs(TimeSpan.FromSeconds(positionSeconds))); + } + } + } + public async Task PlayAsync() { var focusedSession = _mediaManager.GetFocusedSession(); diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs index 0ebb81a..7e5bd2e 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs @@ -41,6 +41,7 @@ namespace BetterLyrics.WinUI3.Services private const string StandardWindowHeightKey = "StandardWindowHeight"; private const string AutoLockOnDesktopModeKey = "AutoLockOnDesktopMode"; + private const string IsImmersiveModeKey = "IsImmersiveMode"; private const string IsDynamicCoverOverlayEnabledKey = "IsDynamicCoverOverlayEnabled"; private const string IsFanLyricsEnabledKey = "IsFanLyricsEnabled"; @@ -74,6 +75,8 @@ namespace BetterLyrics.WinUI3.Services private const string LibreTranslateServerKey = "LibreTranslateServer"; private const string SelectedTargetLanguageIndexKey = "SelectedTargetLanguageIndex"; + private const string LXMusicServerKey = "LXMusicServer"; + private const string LyricsBackgroundThemeKey = "LyricsBackgroundTheme"; private const string IgnoreFullscreenWindowKey = "IgnoreFullscreenWindow"; private const string PreferredDisplayTypeKey = "PreferredDisplayTypeKey"; @@ -160,6 +163,7 @@ namespace BetterLyrics.WinUI3.Services SetDefault(StandardWindowWidthKey, 1600); SetDefault(AutoLockOnDesktopModeKey, false); + SetDefault(IsImmersiveModeKey, false); // App behavior SetDefault(AutoStartWindowTypeKey, (int)AutoStartWindowType.StandardMode); // Album art @@ -196,6 +200,8 @@ namespace BetterLyrics.WinUI3.Services SetDefault(IsTranslationEnabledKey, false); SetDefault(SelectedTargetLanguageIndexKey, LanguageHelper.GetDefaultTargetLanguageIndex()); + SetDefault(LXMusicServerKey, ""); + SetDefault(LyricsFontStrokeWidthKey, 3); SetDefault(IgnoreFullscreenWindowKey, false); SetDefault(PreferredDisplayTypeKey, (int)LyricsDisplayType.SplitView); @@ -531,6 +537,12 @@ namespace BetterLyrics.WinUI3.Services set => SetValue(SelectedTargetLanguageIndexKey, value); } + public string LXMusicServer + { + get => GetValue(LXMusicServerKey)!; + set => SetValue(LXMusicServerKey, value); + } + public bool IgnoreFullscreenWindow { get => GetValue(IgnoreFullscreenWindowKey); @@ -561,6 +573,12 @@ namespace BetterLyrics.WinUI3.Services set => SetValue(PositionOffsetKey, value); } + public bool IsImmersiveMode + { + get => GetValue(IsImmersiveModeKey); + set => SetValue(IsImmersiveModeKey, value); + } + private T? GetValue(string key) { if (_localSettings.Values.TryGetValue(key, out object? value)) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw index b9c1365..13d8a36 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw @@ -603,10 +603,10 @@ Visit https://github.com/LibreTranslate/LibreTranslate for installation instructions and more information (this software is not affiliated with this translation service in any way) - + Server test successful - + Server test failed @@ -741,4 +741,7 @@ Unlock and lock shortcut keys + + LX Music Server + \ 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 c2c7208..d266f11 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw @@ -603,10 +603,10 @@ https://github.com/LibreTranslate/LibreTranslate にアクセスしてください。 - + サーバーテストが成功しました - + サーバーテストに失敗しました @@ -741,4 +741,7 @@ ショートカットキーのロックを解除およびロックします + + LX Music Server + \ 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 6815c92..6b6b07f 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw @@ -603,10 +603,10 @@ 설치 지침 및 자세한 정보는 https://github.com/LibreTranslate/LibreTranslate 를 방문하십시오 (이 소프트웨어는이 번역 서비스와 제휴하지 않습니다). - + 서버 테스트 성공 - + 서버 테스트가 실패했습니다 @@ -741,4 +741,7 @@ 바로 가기 키를 잠금 해제하고 잠그십시오 + + LX 음악 서버 + \ 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 594253d..ec57613 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw @@ -603,10 +603,10 @@ 访问 https://github.com/LibreTranslate/LibreTranslate 获取安装教程及更多信息(本软件与该翻译服务无任何联系) - + 服务器测试成功 - + 服务器测试失败 @@ -741,4 +741,7 @@ 解锁和锁定快捷键 + + LX 音乐服务器 + \ 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 09312e3..c755f78 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw @@ -603,10 +603,10 @@ 造訪 https://github.com/LibreTranslate/LibreTranslate 以取得安裝教學及更多資訊(本軟體與此翻譯服務無任何關聯) - + 服務器測試成功 - + 服務器測試失敗 @@ -741,4 +741,7 @@ 解鎖和鎖定快捷鍵 + + LX 音樂服務器 + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs index 07ad440..722e745 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs @@ -26,6 +26,8 @@ namespace BetterLyrics.WinUI3.ViewModels PreferredDisplayType = _settingsService.PreferredDisplayType; ResetPositionOffsetOnSongChanged = _settingsService.ResetPositionOffsetOnSongChanged; PositionOffset = _settingsService.PositionOffset; + IsImmersiveMode = _settingsService.IsImmersiveMode; + OnIsImmersiveModeChanged(IsImmersiveMode); //Volume = SystemVolumeHelper.GetMasterVolume(); //SystemVolumeHelper.VolumeChanged += SystemVolumeHelper_VolumeChanged; @@ -58,6 +60,12 @@ namespace BetterLyrics.WinUI3.ViewModels //[ObservableProperty] //public partial int Volume { get; set; } + [ObservableProperty] + public partial bool IsImmersiveMode { get; set; } + + [ObservableProperty] + public partial float BottomCommandGridOpacity { get; set; } + [ObservableProperty] [NotifyPropertyChangedRecipients] public partial LyricsDisplayType DisplayType { get; set; } = LyricsDisplayType.PlaceholderOnly; @@ -103,6 +111,10 @@ namespace BetterLyrics.WinUI3.ViewModels SetNonStandardModePreferredDisplayType(message.NewValue); TrySwitchToPreferredDisplayType(SongInfo); } + else if (message.PropertyName == nameof(LyricsWindowViewModel.IsImmersiveMode)) + { + IsImmersiveMode = message.NewValue; + } } } @@ -191,6 +203,18 @@ namespace BetterLyrics.WinUI3.ViewModels _settingsService.PositionOffset = value; } + partial void OnIsImmersiveModeChanged(bool value) + { + if (value) + { + BottomCommandGridOpacity = 0f; + } + else + { + BottomCommandGridOpacity = .5f; + } + } + //partial void OnVolumeChanged(int value) //{ // SystemVolumeHelper.SetMasterVolume(value); diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs index 054ea4d..e8af5ec 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs @@ -45,7 +45,7 @@ namespace BetterLyrics.WinUI3.ViewModels } else if (_isDesktopMode) { - DrawImmersiveBackground(control, combinedDs, 12f); + DrawImmersiveBackground(control, combinedDs, 0f); } else { @@ -196,7 +196,7 @@ namespace BetterLyrics.WinUI3.ViewModels BlurAmount = _albumArtBgBlurAmount, Source = overlappedCovers, BorderMode = EffectBorderMode.Soft, - Optimization = EffectOptimization.Quality, + Optimization = EffectOptimization.Speed, }, }; ds.DrawImage(coverOverlayEffect); diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs index 8ff92d7..769ce38 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs @@ -35,6 +35,8 @@ namespace BetterLyrics.WinUI3 public LyricsWindowViewModel(ISettingsService settingsService) : base(settingsService) { _ignoreFullscreenWindow = _settingsService.IgnoreFullscreenWindow; + IsImmersiveMode = _settingsService.IsImmersiveMode; + OnIsImmersiveModeChanged(_settingsService.IsImmersiveMode); } [ObservableProperty] @@ -53,6 +55,13 @@ namespace BetterLyrics.WinUI3 [NotifyPropertyChangedRecipients] public partial bool IsLyricsWindowLocked { get; set; } = false; + [ObservableProperty] + [NotifyPropertyChangedRecipients] + public partial bool IsImmersiveMode { get; set; } + + [ObservableProperty] + public partial float TopCommandGridOpacity { get; set; } + [ObservableProperty] public partial ElementTheme ThemeType { get; set; } = ElementTheme.Default; @@ -64,7 +73,19 @@ namespace BetterLyrics.WinUI3 public partial bool IsMouseWithinWindow { get; set; } = false; [ObservableProperty] - public partial string LockHotKey { get; set; } + public partial string LockHotKey { get; set; } = ""; + + partial void OnIsImmersiveModeChanged(bool value) + { + if (value) + { + TopCommandGridOpacity = 0f; + } + else + { + TopCommandGridOpacity = 0.5f; + } + } public void Receive(PropertyChangedMessage message) { @@ -190,11 +211,13 @@ namespace BetterLyrics.WinUI3 { DesktopModeHelper.SetClickThrough(window, false); IsLyricsWindowLocked = false; + IsImmersiveMode = _settingsService.IsImmersiveMode; } else { DesktopModeHelper.SetClickThrough(window, true); IsLyricsWindowLocked = true; + IsImmersiveMode = true; } } @@ -237,5 +260,11 @@ namespace BetterLyrics.WinUI3 DockModeHelper.Disable(window); } } + + [RelayCommand] + private void OnImmersiveToggleButtonEnabledChanged() + { + _settingsService.IsImmersiveMode = IsImmersiveMode; + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs index c52c937..5e87d4d 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs @@ -9,6 +9,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; using ShadowViewer.Controls; using System; using System.Collections.Generic; @@ -93,6 +94,8 @@ namespace BetterLyrics.WinUI3.ViewModels ResetPositionOffsetOnSongChanged = _settingsService.ResetPositionOffsetOnSongChanged; LockHotKeyIndex = _settingsService.LockHotKeyIndex; + LXMusicServer = _settingsService.LXMusicServer; + _playbackService.MediaSourceProvidersInfoChanged += PlaybackService_SessionIdsChanged; Task.Run(async () => @@ -274,6 +277,13 @@ namespace BetterLyrics.WinUI3.ViewModels [NotifyPropertyChangedRecipients] public partial int TimelineSyncThreshold { get; set; } + [ObservableProperty] + public partial bool IsLXMusicServerTesting { get; set; } = false; + + [ObservableProperty] + [NotifyPropertyChangedRecipients] + public partial string LXMusicServer { get; set; } + public void OnLyricsSearchProvidersReordered() { _settingsService.LyricsSearchProvidersInfo = [.. LyricsSearchProvidersInfo]; @@ -415,7 +425,7 @@ namespace BetterLyrics.WinUI3.ViewModels 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); + App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestSuccessInfo"), Microsoft.UI.Xaml.Controls.InfoBarSeverity.Success); IsLibreTranslateServerTesting = false; }); } @@ -423,13 +433,30 @@ namespace BetterLyrics.WinUI3.ViewModels { _dispatcherQueue.TryEnqueue(() => { - App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageLibreTranslateTestFailedInfo"), Microsoft.UI.Xaml.Controls.InfoBarSeverity.Error); + App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestFailedInfo"), Microsoft.UI.Xaml.Controls.InfoBarSeverity.Error); IsLibreTranslateServerTesting = false; }); } }); } + [RelayCommand] + private void LXMusicServerTest() + { + IsLXMusicServerTesting = true; + Task.Run(async () => + { + bool testResult = await NetHelper.CheckConnectivity($"{LXMusicServer}/status"); + _dispatcherQueue.TryEnqueue(() => + { + App.Current.SettingsWindowNotificationPanel?.Notify( + App.ResourceLoader!.GetString($"SettingsPageServerTest{(testResult ? "Success" : "Failed")}Info"), + testResult ? InfoBarSeverity.Success : InfoBarSeverity.Error); + IsLXMusicServerTesting = false; + }); + }); + } + public async Task ToggleAutoStartupAsync(bool target) { StartupTask startupTask = await StartupTask.GetAsync(_autoStartupTaskId); @@ -490,6 +517,10 @@ namespace BetterLyrics.WinUI3.ViewModels { _settingsService.LibreTranslateServer = value; } + partial void OnLXMusicServerChanged(string value) + { + _settingsService.LXMusicServer = value; + } partial void OnAutoStartWindowTypeChanged(AutoStartWindowType value) { _settingsService.AutoStartWindowType = value; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml index 3637924..a4e851d 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml @@ -37,29 +37,28 @@ - - - - - - - + + - - + + - - + + - - + + - + + - - - - - - - + + + + - - - - - - + + + + + + - - + + - - + + - + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml.cs index 2758997..3368088 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml.cs @@ -48,12 +48,18 @@ namespace BetterLyrics.WinUI3.Views private void BottomCommandGrid_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e) { - BottomCommandGrid.Opacity = 0.5; + if (ViewModel.IsImmersiveMode) + { + ViewModel.BottomCommandGridOpacity = .5f; + } } private void BottomCommandGrid_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e) { - BottomCommandGrid.Opacity = 0; + if (ViewModel.IsImmersiveMode) + { + ViewModel.BottomCommandGridOpacity = 0f; + } } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml index d5e2e20..dd66f4d 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml @@ -25,145 +25,161 @@ - - - - - + Style="{StaticResource CardGridStyle}"> + + + + + + + + + - - - - + Style="{StaticResource CardGridStyle}"> + + + + - - - - + + + + - - - - - - - - - + + + + + + + + + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml.cs index 937d207..a29e5f0 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml.cs @@ -165,6 +165,7 @@ namespace BetterLyrics.WinUI3.Views AOTFlyoutItem.Visibility = DesktopFlyoutItem.Visibility = FullScreenFlyoutItem.Visibility = DockFlyoutItem.Visibility = ClickThroughButton.Visibility = Visibility.Collapsed; + ViewModel.IsImmersiveMode = true; break; case AppWindowPresenterKind.FullScreen: MinimiseButton.Visibility = MaximiseButton.Visibility = RestoreButton.Visibility = @@ -175,7 +176,6 @@ namespace BetterLyrics.WinUI3.Views DockFlyoutItem.Visibility = Visibility.Collapsed; FullScreenFlyoutItem.IsChecked = true; - break; case AppWindowPresenterKind.Overlapped: DockFlyoutItem.Visibility = Visibility.Visible; @@ -193,6 +193,7 @@ namespace BetterLyrics.WinUI3.Views MiniFlyoutItem.Visibility = Visibility.Collapsed; + ViewModel.IsImmersiveMode = true; } else if (DesktopFlyoutItem.IsChecked) { @@ -234,6 +235,8 @@ namespace BetterLyrics.WinUI3.Views MaximiseButton.Visibility = Visibility.Visible; RestoreButton.Visibility = Visibility.Collapsed; } + + ViewModel.IsImmersiveMode = _settingsService.IsImmersiveMode; } break; default: @@ -272,12 +275,18 @@ namespace BetterLyrics.WinUI3.Views private void TopCommandGrid_PointerEntered(object sender, PointerRoutedEventArgs e) { - TopCommandGrid.Opacity = 0.5; + if (ViewModel.IsImmersiveMode) + { + ViewModel.TopCommandGridOpacity = .5f; + } } private void TopCommandGrid_PointerExited(object sender, PointerRoutedEventArgs e) { - TopCommandGrid.Opacity = 0; + if (ViewModel.IsImmersiveMode) + { + ViewModel.TopCommandGridOpacity = 0f; + } } private void TipContainerCenter_Loaded(object sender, RoutedEventArgs e) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml index eb0c7af..35470b5 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml @@ -175,7 +175,7 @@ - + @@ -912,6 +912,20 @@ + + + +