mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-13 03:34:55 +08:00
chores
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="37412.BetterLyrics"
|
||||
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
||||
Version="1.0.121.0" />
|
||||
Version="1.0.122.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:dev="using:DevWinUI"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:dev="using:DevWinUI"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
<dev:SettingsCard x:Uid="SettingsPageAlbumRadius" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="12"
|
||||
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
@@ -52,7 +51,6 @@
|
||||
<dev:SettingsCard x:Uid="SettingsPageAlbumShadowAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="12"
|
||||
|
||||
Maximum="64"
|
||||
Minimum="0"
|
||||
Value="{x:Bind AlbumArtLayoutSettings.CoverImageShadowAmount, Mode=TwoWay}" />
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
Visibility="{x:Bind IsFound, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind Artist}"
|
||||
Text="{x:Bind DisplayArtists}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{x:Bind IsFound, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<TextBlock
|
||||
|
||||
@@ -11,65 +11,74 @@
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="12">
|
||||
<FontIcon
|
||||
Margin="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
FontFamily="{StaticResource IconFontFamily}"
|
||||
Glyph="" />
|
||||
<Button
|
||||
Margin="12"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Click="Button_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<Button.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Escape" />
|
||||
</Button.KeyboardAccelerators>
|
||||
</Button>
|
||||
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Grid x:Name="ShadowCastGrid" />
|
||||
<Border
|
||||
x:Name="ShadowRect"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="12"
|
||||
Loaded="ShadowRect_Loaded"
|
||||
Translation="0,0,64">
|
||||
<Border.Shadow>
|
||||
<ThemeShadow x:Name="Shadow" />
|
||||
</Border.Shadow>
|
||||
</Border>
|
||||
<Grid Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}" CornerRadius="12">
|
||||
<TextBlock
|
||||
x:Uid="SystemTraySwitch"
|
||||
Margin="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top" />
|
||||
<Button
|
||||
Margin="12"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Click="Button_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<Button.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Escape" />
|
||||
</Button.KeyboardAccelerators>
|
||||
</Button>
|
||||
|
||||
<ListView
|
||||
Margin="48,56"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.WindowBoundsRecords, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.LiveStates.LyricsWindowStatus, Mode=TwoWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<controls:WrapPanel HorizontalSpacing="0" VerticalSpacing="0" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid
|
||||
Margin="0,10"
|
||||
Padding="5"
|
||||
AllowFocusOnInteraction="True"
|
||||
CornerRadius="4"
|
||||
Tapped="Grid_Tapped">
|
||||
<uc:DemoWindowGrid LyricsWindowStatus="{Binding}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<ListView
|
||||
Margin="48,56"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.WindowBoundsRecords, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.LiveStates.LyricsWindowStatus, Mode=TwoWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<controls:WrapPanel HorizontalSpacing="0" VerticalSpacing="0" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid
|
||||
Margin="0,10"
|
||||
Padding="5"
|
||||
AllowFocusOnInteraction="True"
|
||||
CornerRadius="4"
|
||||
Tapped="Grid_Tapped">
|
||||
<uc:DemoWindowGrid LyricsWindowStatus="{Binding}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<StackPanel
|
||||
Margin="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
<FontIcon
|
||||
Margin="0,1,0,0"
|
||||
FontFamily="{StaticResource IconFontFamily}"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="LyricsWindowSwitchWindowHelp" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
<HyperlinkButton Click="SettingsHypelinkButton_Click">
|
||||
<HyperlinkButton.Content>
|
||||
<TextBlock x:Uid="LyricsWindowSwitchWindowHelp" />
|
||||
</HyperlinkButton.Content>
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -40,5 +40,16 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
await Task.Delay(300);
|
||||
WindowHook.HideWindow<LyricsWindowSwitchWindow>();
|
||||
}
|
||||
|
||||
private void ShadowRect_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Shadow.Receivers.Add(ShadowCastGrid);
|
||||
}
|
||||
|
||||
private async void SettingsHypelinkButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await HideAsync();
|
||||
WindowHook.OpenOrShowWindow<SettingsWindow>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Events
|
||||
{
|
||||
public class AlbumArtChangedEventArgs(byte[]? bytes, SoftwareBitmap? albumArtSwBitmap, List<Color> albumArtLightAccentColors, List<Color> albumArtDarkAccentColors) : EventArgs
|
||||
public class AlbumArtChangedEventArgs(SoftwareBitmap? albumArtSwBitmap, List<Color> albumArtLightAccentColors, List<Color> albumArtDarkAccentColors) : EventArgs
|
||||
{
|
||||
public byte[]? Bytes { get; set; } = bytes;
|
||||
public SoftwareBitmap? AlbumArtSwBitmap { get; set; } = albumArtSwBitmap;
|
||||
public List<Color> AlbumArtLightAccentColors { get; set; } = albumArtLightAccentColors;
|
||||
public List<Color> AlbumArtDarkAccentColors { get; set; } = albumArtDarkAccentColors;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -6,7 +7,7 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class DisposableObjectExtension
|
||||
{
|
||||
extension(IDisposable obj)
|
||||
extension(IDisposable? obj)
|
||||
{
|
||||
// Credit/Copyright to https://gist.github.com/tcartwright/dab50ebaff7c59f05013de0fb349cabd
|
||||
public bool IsDisposed()
|
||||
|
||||
@@ -7,6 +7,13 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class SongInfoExtensions
|
||||
{
|
||||
public static SongInfo Placeholder => new SongInfo
|
||||
{
|
||||
Title = "N/A",
|
||||
Album = "N/A",
|
||||
Artists = ["N/A"],
|
||||
};
|
||||
|
||||
extension(SongInfo songInfo)
|
||||
{
|
||||
public SongInfo WithTitle(string value)
|
||||
@@ -15,9 +22,9 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
return songInfo;
|
||||
}
|
||||
|
||||
public SongInfo WithArtist(string value)
|
||||
public SongInfo WithArtist(string[] value)
|
||||
{
|
||||
songInfo.Artist = value;
|
||||
songInfo.Artists = value;
|
||||
return songInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,10 @@ using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Numerics;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
using Color = Windows.UI.Color;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
@@ -135,8 +133,8 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
|
||||
private static Color GetAverageColorFromScreenRegion(int x, int y, int width, int height)
|
||||
{
|
||||
using Bitmap bmp = new(width, height, PixelFormat.Format32bppArgb);
|
||||
using Graphics gDest = Graphics.FromImage(bmp);
|
||||
using System.Drawing.Bitmap bmp = new(width, height, PixelFormat.Format32bppArgb);
|
||||
using var gDest = System.Drawing.Graphics.FromImage(bmp);
|
||||
|
||||
IntPtr hdcDest = gDest.GetHdc();
|
||||
IntPtr hdcSrc = (nint)User32.GetDC(IntPtr.Zero); // Entire screen
|
||||
@@ -149,7 +147,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return ComputeAverageColor(bmp);
|
||||
}
|
||||
|
||||
private static Color ComputeAverageColor(Bitmap bmp)
|
||||
private static Color ComputeAverageColor(System.Drawing.Bitmap bmp)
|
||||
{
|
||||
long r = 0, g = 0, b = 0;
|
||||
int count = 0;
|
||||
@@ -169,5 +167,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
if (count == 0) return Colors.Transparent;
|
||||
return Color.FromArgb(255, (byte)(r / count), (byte)(g / count), (byte)(b / count));
|
||||
}
|
||||
|
||||
public static Color FromVector3(Vector3 vector3) => Color.FromArgb(255, (byte)vector3.X, (byte)vector3.Y, (byte)vector3.Z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,9 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string? ReadLyricsCache(string title, string artist, string album, LyricsFormat format, string cacheFolderPath)
|
||||
public static string? ReadLyricsCache(SongInfo songInfo, LyricsFormat format, string cacheFolderPath)
|
||||
{
|
||||
var cacheFilePath = Path.Combine(cacheFolderPath, SanitizeFileName($"{artist} - {title} - {album}{format.ToFileExtension()}"));
|
||||
var cacheFilePath = Path.Combine(cacheFolderPath, SanitizeFileName($"{songInfo.DisplayArtists} - {songInfo.Title} - {songInfo.Album}{format.ToFileExtension()}"));
|
||||
if (File.Exists(cacheFilePath))
|
||||
{
|
||||
return File.ReadAllText(cacheFilePath);
|
||||
@@ -58,13 +58,13 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
|
||||
public static void WriteLyricsCache(SongInfo songInfo, string lyrics, LyricsFormat format, string cacheFolderPath)
|
||||
{
|
||||
var cacheFilePath = Path.Combine(cacheFolderPath, SanitizeFileName($"{songInfo.Artist} - {songInfo.Title} - {songInfo.Album}{format.ToFileExtension()}"));
|
||||
var cacheFilePath = Path.Combine(cacheFolderPath, SanitizeFileName($"{songInfo.DisplayArtists} - {songInfo.Title} - {songInfo.Album}{format.ToFileExtension()}"));
|
||||
File.WriteAllText(cacheFilePath, lyrics);
|
||||
}
|
||||
|
||||
public static void WriteAlbumArtCache(string album, string artist, byte[] img, string format, string cacheFolderPath)
|
||||
public static void WriteAlbumArtCache(SongInfo songInfo, byte[] img, string format, string cacheFolderPath)
|
||||
{
|
||||
var cacheFilePath = Path.Combine(cacheFolderPath, SanitizeFileName($"{artist} - {album}{format}"));
|
||||
var cacheFilePath = Path.Combine(cacheFolderPath, SanitizeFileName($"{songInfo.DisplayArtists} - {songInfo.Album}{format}"));
|
||||
File.WriteAllBytes(cacheFilePath, img);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using Impressionist.Abstractions;
|
||||
using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Numerics;
|
||||
@@ -18,26 +20,6 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class ImageHelper
|
||||
{
|
||||
public static async Task<InMemoryRandomAccessStream> ByteArrayToStream(byte[] bytes)
|
||||
{
|
||||
using var stream = new InMemoryRandomAccessStream();
|
||||
await stream.WriteAsync(bytes.AsBuffer());
|
||||
stream.Seek(0);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static RandomAccessStreamReference ByteArrayToRandomAccessStreamReference(byte[] bytes)
|
||||
{
|
||||
using var stream = new InMemoryRandomAccessStream();
|
||||
using var writer = new DataWriter(stream);
|
||||
writer.WriteBytes(bytes);
|
||||
writer.StoreAsync().GetAwaiter().GetResult();
|
||||
writer.FlushAsync().GetAwaiter().GetResult();
|
||||
writer.DetachStream();
|
||||
return RandomAccessStreamReference.CreateFromStream(stream);
|
||||
}
|
||||
|
||||
public static async Task<IRandomAccessStream> GetAlbumArtPlaceholderAsync()
|
||||
{
|
||||
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(PathHelper.AlbumArtPlaceholderPath));
|
||||
@@ -65,59 +47,6 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
};
|
||||
}
|
||||
|
||||
public static async Task<Dictionary<Vector3, int>> GetPixelColor(BitmapDecoder bitmapDecoder)
|
||||
{
|
||||
var pixelDataProvider = await bitmapDecoder.GetPixelDataAsync();
|
||||
var pixels = pixelDataProvider.DetachPixelData();
|
||||
var count = bitmapDecoder.PixelWidth * bitmapDecoder.PixelHeight;
|
||||
var vector = new Dictionary<Vector3, int>();
|
||||
for (int i = 0; i < count; i += 10)
|
||||
{
|
||||
var offset = i * 4;
|
||||
var b = pixels[offset];
|
||||
var g = pixels[offset + 1];
|
||||
var r = pixels[offset + 2];
|
||||
var a = pixels[offset + 3];
|
||||
if (a == 0) continue;
|
||||
var color = new Vector3(r, g, b);
|
||||
if (vector.ContainsKey(color))
|
||||
{
|
||||
vector[color]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
vector[color] = 1;
|
||||
}
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
//public static async Task<BitmapImage> GetBitmapImageFromBytesAsync(byte[] imageBytes)
|
||||
//{
|
||||
// var stream = new InMemoryRandomAccessStream();
|
||||
// await stream.WriteAsync(imageBytes.AsBuffer());
|
||||
// stream.Seek(0);
|
||||
|
||||
// var bitmapImage = new BitmapImage();
|
||||
// await bitmapImage.SetSourceAsync(stream);
|
||||
|
||||
// return bitmapImage;
|
||||
//}
|
||||
|
||||
//public static async Task<BitmapDecoder> GetDecoderFromByte(byte[] bytes) =>
|
||||
// await BitmapDecoder.CreateAsync(await ByteArrayToStream(bytes));
|
||||
|
||||
//public static async Task<InMemoryRandomAccessStream> GetStreamFromBytesAsync(byte[] imageBytes)
|
||||
//{
|
||||
// if (imageBytes == null || imageBytes.Length == 0)
|
||||
// return null;
|
||||
|
||||
// InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
|
||||
// await stream.WriteAsync(imageBytes.AsBuffer());
|
||||
|
||||
// return stream;
|
||||
//}
|
||||
|
||||
public static async Task<IBuffer> ToBufferAsync(IRandomAccessStreamReference streamRef)
|
||||
{
|
||||
using IRandomAccessStream stream = await streamRef.OpenReadAsync();
|
||||
@@ -127,26 +56,8 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static double 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 (double)(sum / (pixels.Length / 4));
|
||||
}
|
||||
|
||||
public static async Task<BitmapDecoder> MakeSquareWithThemeColor(IBuffer buffer, PaletteGeneratorType generatorType)
|
||||
{
|
||||
|
||||
using var stream = new InMemoryRandomAccessStream();
|
||||
await stream.WriteAsync(buffer);
|
||||
var decoder = await BitmapDecoder.CreateAsync(stream);
|
||||
@@ -183,69 +94,6 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
|
||||
}
|
||||
|
||||
public static async Task<IBuffer> Resize(IBuffer buffer, int size)
|
||||
{
|
||||
using var stream = new InMemoryRandomAccessStream();
|
||||
await stream.WriteAsync(buffer);
|
||||
var decoder = await BitmapDecoder.CreateAsync(stream);
|
||||
|
||||
var factor = Math.Max((double)size / decoder.PixelWidth, (double)size / decoder.PixelHeight);
|
||||
|
||||
var width = (uint)(decoder.PixelWidth * factor);
|
||||
var height = (uint)(decoder.PixelHeight * factor);
|
||||
|
||||
if (factor > 1)
|
||||
{
|
||||
var transform = new BitmapTransform()
|
||||
{
|
||||
ScaledWidth = width,
|
||||
ScaledHeight = height,
|
||||
InterpolationMode = BitmapInterpolationMode.Fant
|
||||
};
|
||||
var pixelData = await decoder.GetPixelDataAsync(
|
||||
BitmapPixelFormat.Rgba8,
|
||||
BitmapAlphaMode.Straight,
|
||||
transform, ExifOrientationMode.RespectExifOrientation,
|
||||
ColorManagementMode.ColorManageToSRgb);
|
||||
var pixels = pixelData.DetachPixelData();
|
||||
|
||||
stream.Seek(0);
|
||||
stream.Size = 0;
|
||||
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
|
||||
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, width, height, 96, 96, pixels);
|
||||
await encoder.FlushAsync();
|
||||
var output = new Windows.Storage.Streams.Buffer((uint)stream.Size);
|
||||
stream.Seek(0);
|
||||
await stream.ReadAsync(output, (uint)stream.Size, InputStreamOptions.None);
|
||||
return output;
|
||||
}
|
||||
else
|
||||
{
|
||||
var transform = new BitmapTransform()
|
||||
{
|
||||
ScaledWidth = (uint)width,
|
||||
ScaledHeight = (uint)height,
|
||||
InterpolationMode = BitmapInterpolationMode.NearestNeighbor
|
||||
};
|
||||
var pixelData = await decoder.GetPixelDataAsync(
|
||||
BitmapPixelFormat.Rgba8,
|
||||
BitmapAlphaMode.Straight,
|
||||
transform, ExifOrientationMode.RespectExifOrientation,
|
||||
ColorManagementMode.ColorManageToSRgb);
|
||||
var pixels = pixelData.DetachPixelData();
|
||||
|
||||
stream.Seek(0);
|
||||
stream.Size = 0;
|
||||
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
|
||||
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, width, height, 96, 96, pixels);
|
||||
await encoder.FlushAsync();
|
||||
var output = new Windows.Storage.Streams.Buffer((uint)stream.Size);
|
||||
stream.Seek(0);
|
||||
await stream.ReadAsync(output, (uint)stream.Size, InputStreamOptions.None);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] GenerateNoiseBGRA(int width, int height)
|
||||
{
|
||||
var random = new Random();
|
||||
@@ -335,5 +183,10 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IRandomAccessStream ToIRandomAccessStream(IBuffer buffer)
|
||||
{
|
||||
return buffer.AsStream().AsRandomAccessStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using Lyricify.Lyrics.Parsers;
|
||||
using NTextCat.Commons;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -15,28 +17,30 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public List<LyricsData> LyricsDataArr { get; private set; } = [];
|
||||
|
||||
public void Parse(List<MappedSongSearchQuery> mappedSongSearchQueries, string title, string artist, string album, string? raw, int? durationMs, LyricsSearchProvider? lyricsSearchProvider)
|
||||
public void Parse(List<MappedSongSearchQuery> mappedSongSearchQueries, Models.SongInfo songInfo, string? raw, LyricsSearchProvider? lyricsSearchProvider)
|
||||
{
|
||||
var overridenTitle = title;
|
||||
var overridenArtist = artist;
|
||||
var overridenAlbum = album;
|
||||
var overridenTitle = songInfo.Title;
|
||||
var overridenArtist = songInfo.Artists;
|
||||
var overridenAlbum = songInfo.Album;
|
||||
|
||||
var found = mappedSongSearchQueries
|
||||
.Where(x => x.OriginalTitle == overridenTitle && x.OriginalArtist == overridenArtist && x.OriginalAlbum == overridenAlbum)
|
||||
.Where(x =>
|
||||
x.OriginalTitle == overridenTitle &&
|
||||
x.OriginalArtist == overridenArtist.Join(ATL.Settings.DisplayValueSeparator.ToString()) &&
|
||||
x.OriginalAlbum == overridenAlbum)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (found != null)
|
||||
{
|
||||
overridenTitle = found.MappedTitle;
|
||||
overridenArtist = found.MappedArtist;
|
||||
overridenArtist = found.MappedArtist.Split(ATL.Settings.DisplayValueSeparator);
|
||||
overridenAlbum = found.MappedAlbum;
|
||||
}
|
||||
|
||||
LyricsDataArr = [];
|
||||
durationMs ??= (int)TimeSpan.FromMinutes(99).TotalMilliseconds;
|
||||
if (raw == null)
|
||||
{
|
||||
LyricsDataArr.Add(LyricsData.GetNotfoundPlaceholder(durationMs.Value));
|
||||
LyricsDataArr.Add(LyricsData.GetNotfoundPlaceholder((int)songInfo.DurationMs));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -60,22 +64,27 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
}
|
||||
}
|
||||
FillRomanizationLyricsData();
|
||||
FillTranslationFromCache(overridenTitle, overridenArtist, overridenAlbum, lyricsSearchProvider);
|
||||
FillTranslationFromCache(
|
||||
((SongInfo)songInfo.Clone())
|
||||
.WithTitle(overridenTitle)
|
||||
.WithArtist(overridenArtist)
|
||||
.WithAlbum(overridenAlbum),
|
||||
lyricsSearchProvider);
|
||||
}
|
||||
|
||||
private void FillTranslationFromCache(string title, string artist, string album, LyricsSearchProvider? provider)
|
||||
private void FillTranslationFromCache(SongInfo songInfo, LyricsSearchProvider? provider)
|
||||
{
|
||||
string? translationRaw = null;
|
||||
switch (provider)
|
||||
{
|
||||
case LyricsSearchProvider.QQ:
|
||||
translationRaw = FileHelper.ReadLyricsCache(title, artist, album, LyricsFormat.Lrc, PathHelper.QQTranslationCacheDirectory);
|
||||
translationRaw = FileHelper.ReadLyricsCache(songInfo, LyricsFormat.Lrc, PathHelper.QQTranslationCacheDirectory);
|
||||
break;
|
||||
case LyricsSearchProvider.Kugou:
|
||||
translationRaw = FileHelper.ReadLyricsCache(title, artist, album, LyricsFormat.Lrc, PathHelper.KugouTranslationCacheDirectory);
|
||||
translationRaw = FileHelper.ReadLyricsCache(songInfo, LyricsFormat.Lrc, PathHelper.KugouTranslationCacheDirectory);
|
||||
break;
|
||||
case LyricsSearchProvider.Netease:
|
||||
translationRaw = FileHelper.ReadLyricsCache(title, artist, album, LyricsFormat.Lrc, PathHelper.NeteaseTranslationCacheDirectory);
|
||||
translationRaw = FileHelper.ReadLyricsCache(songInfo, LyricsFormat.Lrc, PathHelper.NeteaseTranslationCacheDirectory);
|
||||
break;
|
||||
case LyricsSearchProvider.LrcLib:
|
||||
break;
|
||||
@@ -215,12 +224,12 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
int? lineStartTime = null;
|
||||
if (bracketMatches.Count > 0)
|
||||
{
|
||||
var m = bracketMatches![0];
|
||||
var m = bracketMatches[0];
|
||||
int min = int.Parse(m.Groups[1].Value);
|
||||
int sec = int.Parse(m.Groups[2].Value);
|
||||
int ms = int.Parse(m.Groups[4].Value.PadRight(3, '0'));
|
||||
lineStartTime = min * 60_000 + sec * 1000 + ms;
|
||||
content = bracketRegex!.Replace(line, "");
|
||||
content = bracketRegex!.Replace(line, "").Trim();
|
||||
if (content == "//") content = "";
|
||||
lrcLines.Add((lineStartTime.Value, content, new List<(int, string)>()));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using NTextCat.Commons;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
@@ -9,17 +10,19 @@ namespace BetterLyrics.WinUI3.Models
|
||||
public string? Raw { get; set; }
|
||||
|
||||
public string? Title { get; set; }
|
||||
public string? Artist { get; set; }
|
||||
public string[]? Artists { get; set; }
|
||||
public string? Album { get; set; }
|
||||
|
||||
public bool IsFound => !string.IsNullOrEmpty(Raw);
|
||||
|
||||
public LyricsSearchProvider? ProviderIfFound => IsFound ? Provider : null;
|
||||
public LyricsSearchProvider? ProviderIfFound => IsFound ? Provider : null;
|
||||
|
||||
public string? DisplayArtists => Artists?.Join("; ");
|
||||
|
||||
public void CopyFromSongInfo(SongInfo songInfo)
|
||||
{
|
||||
Title = songInfo.Title;
|
||||
Artist = songInfo.Artist;
|
||||
Artists = songInfo.Artists;
|
||||
Album = songInfo.Album;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
Name = _resourceService.GetLocalizedString("FullscreenMode"),
|
||||
IsBorderless = true,
|
||||
IsAlwaysOnTop = true,
|
||||
IsAlwaysOnTop = false,
|
||||
TitleBarArea = TitleBarArea.None,
|
||||
LyricsLayoutOrientation = LyricsLayoutOrientation.Vertical,
|
||||
LyricsStyleSettings = new LyricsStyleSettings
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using NTextCat.Commons;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
@@ -11,7 +12,7 @@ namespace BetterLyrics.WinUI3.Models
|
||||
public partial string Album { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Artist { get; set; }
|
||||
public partial string[] Artists { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial double DurationMs { get; set; }
|
||||
@@ -29,6 +30,8 @@ namespace BetterLyrics.WinUI3.Models
|
||||
|
||||
public double Duration => DurationMs / 1000;
|
||||
|
||||
public string DisplayArtists => Artists.Join(ATL.Settings.DisplayValueSeparator.ToString());
|
||||
|
||||
public SongInfo() { }
|
||||
|
||||
public object Clone()
|
||||
@@ -36,7 +39,7 @@ namespace BetterLyrics.WinUI3.Models
|
||||
return new SongInfo()
|
||||
{
|
||||
Title = this.Title,
|
||||
Artist = this.Artist,
|
||||
Artists = this.Artists,
|
||||
Album = this.Album,
|
||||
DurationMs = this.DurationMs,
|
||||
PlayerId = this.PlayerId,
|
||||
@@ -49,7 +52,7 @@ namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
return
|
||||
$"Title: {Title}\n" +
|
||||
$"Artist: {Artist}\n" +
|
||||
$"Artist: {Artists}\n" +
|
||||
$"Album: {Album}\n" +
|
||||
$"Duration: {Duration} sec\n" +
|
||||
$"Plauer ID: {PlayerId}\n" +
|
||||
@@ -57,14 +60,4 @@ namespace BetterLyrics.WinUI3.Models
|
||||
$"Linked file name: {LinkedFileName}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class SongInfoExtensions
|
||||
{
|
||||
public static SongInfo Placeholder => new()
|
||||
{
|
||||
Title = "N/A",
|
||||
Album = "N/A",
|
||||
Artist = "N/A",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Helper.BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -26,20 +27,20 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public AlbumArtSearchService(ISettingsService settingsService)
|
||||
public AlbumArtSearchService(ISettingsService settingsService, ILogger<AlbumArtSearchService> logger)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_logger = Ioc.Default.GetRequiredService<ILogger<AlbumArtSearchService>>();
|
||||
_logger = logger;
|
||||
_iTunesHttpClinet = new();
|
||||
}
|
||||
|
||||
public async Task<IBuffer?> SearchAsync(string mediaSessionId, string title, string artist, string album, IBuffer? bufferFromSMTC, CancellationToken token)
|
||||
public async Task<IBuffer?> SearchAsync(SongInfo songInfo, IBuffer? bufferFromSMTC, CancellationToken token)
|
||||
{
|
||||
IBuffer? result = null;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var provider in _settingsService.AppSettings.MediaSourceProvidersInfo.Where(x => x.Provider == mediaSessionId).FirstOrDefault()?.AlbumArtSearchProvidersInfo ?? [])
|
||||
foreach (var provider in _settingsService.AppSettings.MediaSourceProvidersInfo.Where(x => x.Provider == songInfo.PlayerId).FirstOrDefault()?.AlbumArtSearchProvidersInfo ?? [])
|
||||
{
|
||||
if (!provider.IsEnabled)
|
||||
{
|
||||
@@ -49,7 +50,7 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
switch (provider.Provider)
|
||||
{
|
||||
case AlbumArtSearchProvider.Local:
|
||||
result = SearchFile(artist, title)?.AsBuffer();
|
||||
result = SearchFile(songInfo)?.AsBuffer();
|
||||
break;
|
||||
case AlbumArtSearchProvider.SMTC:
|
||||
result = bufferFromSMTC;
|
||||
@@ -57,7 +58,7 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
case AlbumArtSearchProvider.iTunes:
|
||||
foreach (string countryCode in new List<string>() { "us", "cn", "jp", "kr" })
|
||||
{
|
||||
var byteArray = await SearchiTunesAsync(artist, album, title, countryCode);
|
||||
var byteArray = await SearchiTunesAsync(songInfo, countryCode);
|
||||
result = byteArray?.AsBuffer();
|
||||
if (token.IsCancellationRequested) return result;
|
||||
if (result != null) break;
|
||||
@@ -77,7 +78,7 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[]? SearchFile(string artist, string title)
|
||||
private byte[]? SearchFile(SongInfo songInfo)
|
||||
{
|
||||
foreach (var folder in _settingsService.AppSettings.LocalMediaFolders)
|
||||
{
|
||||
@@ -88,7 +89,7 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
if (FileHelper.MusicExtensions.Contains(Path.GetExtension(file)))
|
||||
{
|
||||
Track track = new(file);
|
||||
if ((track.Title == title && track.Artist == artist) || FileHelper.IsSwitchableNormalizedMatch(Path.GetFileNameWithoutExtension(file), artist, title))
|
||||
if ((track.Title == songInfo.Title && track.Artist == songInfo.DisplayArtists) || FileHelper.IsSwitchableNormalizedMatch(Path.GetFileNameWithoutExtension(file), songInfo.DisplayArtists, songInfo.Title))
|
||||
{
|
||||
var bytes = track.EmbeddedPictures.FirstOrDefault()?.PictureData;
|
||||
if (bytes != null)
|
||||
@@ -103,13 +104,13 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<byte[]?> SearchiTunesAsync(string artist, string album, string title, string countryCode)
|
||||
private async Task<byte[]?> SearchiTunesAsync(SongInfo songInfo, string countryCode)
|
||||
{
|
||||
// Source: https://gist.github.com/mcworkaholic/82fbf203e3f1043bbe534b5b2974c0ce
|
||||
try
|
||||
{
|
||||
string format = ".jpg";
|
||||
var cachedAlbumArt = FileHelper.ReadAlbumArtCache(artist, album, format, PathHelper.iTunesAlbumArtCacheDirectory);
|
||||
var cachedAlbumArt = FileHelper.ReadAlbumArtCache(songInfo.DisplayArtists, songInfo.Album, format, PathHelper.iTunesAlbumArtCacheDirectory);
|
||||
|
||||
if (cachedAlbumArt != null)
|
||||
{
|
||||
@@ -117,7 +118,7 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
}
|
||||
|
||||
// Build the iTunes API URL
|
||||
string url = $"{Constants.iTunes.QueryPrefix}term=" + WebUtility.UrlEncode($"{artist} {album}").Replace("%20", "+") + "&country=" + countryCode + "&entity=album&media=music&limit=1";
|
||||
string url = $"{Constants.iTunes.QueryPrefix}term=" + WebUtility.UrlEncode($"{songInfo.Artists} {songInfo.Album}").Replace("%20", "+") + "&country=" + countryCode + "&entity=album&media=music&limit=1";
|
||||
|
||||
// Make a request to the API
|
||||
using HttpResponseMessage response = await _iTunesHttpClinet.GetAsync(url);
|
||||
@@ -139,7 +140,7 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
if (fetched != null && fetched.Length > 0)
|
||||
{
|
||||
// Write to cache
|
||||
FileHelper.WriteAlbumArtCache(artist, album, fetched, format, PathHelper.iTunesAlbumArtCacheDirectory);
|
||||
FileHelper.WriteAlbumArtCache(songInfo, fetched, format, PathHelper.iTunesAlbumArtCacheDirectory);
|
||||
return fetched;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +148,7 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error searching iTunes album art for {Artist} - {Album}", artist, album);
|
||||
_logger.LogError(ex, "SearchiTunesAsync");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Threading;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
@@ -6,6 +7,6 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
{
|
||||
public interface IAlbumArtSearchService
|
||||
{
|
||||
Task<IBuffer?> SearchAsync(string mediaSessionId, string title, string artist, string album, IBuffer? bufferFromSMTC, CancellationToken token);
|
||||
Task<IBuffer?> SearchAsync(SongInfo songInfo, IBuffer? bufferFromSMTC, CancellationToken token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace BetterLyrics.WinUI3.Services.DiscordService
|
||||
SmallImageKey = "logo"
|
||||
},
|
||||
Details = songInfo.Title,
|
||||
State = songInfo.Artist,
|
||||
State = string.Join("; ", songInfo.Artists),
|
||||
Timestamps = Timestamps.FromTimeSpan(songInfo.Duration)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace BetterLyrics.WinUI3.Services.LastFMService
|
||||
await _client.Track.ScrobbleAsync(new Hqub.Lastfm.Entities.Scrobble
|
||||
{
|
||||
Track = songInfo.Title,
|
||||
Artist = songInfo.Artist,
|
||||
Artist = songInfo.DisplayArtists,
|
||||
Date = DateTime.Now,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LyricsSearchService(ISettingsService settingsService)
|
||||
public LyricsSearchService(ISettingsService settingsService, ILogger<LyricsSearchService> logger)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_logger = Ioc.Default.GetRequiredService<ILogger<LyricsSearchService>>();
|
||||
_logger = logger;
|
||||
|
||||
_lrcLibHttpClient = new();
|
||||
_lrcLibHttpClient.DefaultRequestHeaders.Add(
|
||||
@@ -96,20 +96,22 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
var lyricsSearchResult = new LyricsSearchResult();
|
||||
|
||||
string overridenTitle = songInfo.Title;
|
||||
string overridenArtist = songInfo.Artist;
|
||||
string[] overridenArtists = songInfo.Artists;
|
||||
string overridenAlbum = songInfo.Album;
|
||||
|
||||
_logger.LogInformation("Searching lyrics for: {Title} - {Artist} (Album: {Album}, Duration: {DurationMs}ms)",
|
||||
overridenTitle, overridenArtist, overridenAlbum, songInfo.DurationMs);
|
||||
_logger.LogInformation("SearchSmartlyAsync {SongInfo}", songInfo);
|
||||
|
||||
var found = _settingsService.AppSettings.MappedSongSearchQueries
|
||||
.Where(x => x.OriginalTitle == overridenTitle && x.OriginalArtist == overridenArtist && x.OriginalAlbum == overridenAlbum)
|
||||
.Where(x =>
|
||||
x.OriginalTitle == overridenTitle &&
|
||||
x.OriginalArtist == overridenArtists.Join(ATL.Settings.DisplayValueSeparator.ToString()) &&
|
||||
x.OriginalAlbum == overridenAlbum)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (found != null)
|
||||
{
|
||||
overridenTitle = found.MappedTitle;
|
||||
overridenArtist = found.MappedArtist;
|
||||
overridenArtists = found.MappedArtist.Split(ATL.Settings.DisplayValueSeparator);
|
||||
overridenAlbum = found.MappedAlbum;
|
||||
|
||||
_logger.LogInformation("Found mapped song search query: {MappedSongSearchQuery}", found);
|
||||
@@ -118,7 +120,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
if (pureMusic)
|
||||
{
|
||||
lyricsSearchResult.Title = overridenTitle;
|
||||
lyricsSearchResult.Artist = overridenArtist;
|
||||
lyricsSearchResult.Artists = overridenArtists;
|
||||
lyricsSearchResult.Album = overridenAlbum;
|
||||
lyricsSearchResult.Raw = "[99:00.000]🎶🎶🎶";
|
||||
return lyricsSearchResult;
|
||||
@@ -130,7 +132,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
return await SearchSingleAsync(
|
||||
((SongInfo)songInfo.Clone())
|
||||
.WithTitle(overridenTitle)
|
||||
.WithArtist(overridenArtist)
|
||||
.WithArtist(overridenArtists)
|
||||
.WithAlbum(overridenAlbum),
|
||||
targetProvider.Value, token);
|
||||
}
|
||||
@@ -145,7 +147,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
lyricsSearchResult = await SearchSingleAsync(
|
||||
((SongInfo)songInfo.Clone())
|
||||
.WithTitle(overridenTitle)
|
||||
.WithArtist(overridenArtist)
|
||||
.WithArtist(overridenArtists)
|
||||
.WithAlbum(overridenAlbum),
|
||||
provider.Provider, token);
|
||||
|
||||
@@ -160,7 +162,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
public async Task<List<LyricsSearchResult>> SearchAllAsync(SongInfo songInfo, CancellationToken token)
|
||||
{
|
||||
_logger.LogInformation("Searching all lyrics for: {SongInfo}", songInfo);
|
||||
_logger.LogInformation("SearchAllAsync {SongInfo}", songInfo);
|
||||
var results = new List<LyricsSearchResult>();
|
||||
foreach (var provider in Enum.GetValues<LyricsSearchProvider>())
|
||||
{
|
||||
@@ -184,7 +186,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
// Check cache first
|
||||
if (provider.IsRemote())
|
||||
{
|
||||
var cachedLyrics = FileHelper.ReadLyricsCache(songInfo.Title, songInfo.Artist, songInfo.Album, lyricsFormat, provider.GetCacheDirectory());
|
||||
var cachedLyrics = FileHelper.ReadLyricsCache(songInfo, lyricsFormat, provider.GetCacheDirectory());
|
||||
if (!string.IsNullOrWhiteSpace(cachedLyrics))
|
||||
{
|
||||
lyricsSearchResult.Raw = cachedLyrics;
|
||||
@@ -267,7 +269,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
foreach (var file in DirectoryHelper.GetAllFiles(folder.Path, $"*{format.ToFileExtension()}"))
|
||||
{
|
||||
var fileName = Path.GetFileNameWithoutExtension(file);
|
||||
if (FileHelper.IsSwitchableNormalizedMatch(fileName, songInfo.Title, songInfo.Artist) || songInfo.LinkedFileName == fileName)
|
||||
if (FileHelper.IsSwitchableNormalizedMatch(fileName, songInfo.Title, songInfo.DisplayArtists) || songInfo.LinkedFileName == fileName)
|
||||
{
|
||||
string? raw = await File.ReadAllTextAsync(file, FileHelper.GetEncoding(file));
|
||||
if (raw != null)
|
||||
@@ -304,9 +306,9 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
if (FileHelper.MusicExtensions.Contains(Path.GetExtension(file)))
|
||||
{
|
||||
var track = new Track(file);
|
||||
if ((songInfo.Album != "" && track.Title == songInfo.Title && track.Artist == songInfo.Artist && track.Album == songInfo.Album)
|
||||
|| (songInfo.Album == "" && track.Title == songInfo.Title && track.Artist == songInfo.Artist)
|
||||
|| (songInfo.Album == "" && FileHelper.IsSwitchableNormalizedMatch(Path.GetFileNameWithoutExtension(file), songInfo.Title, songInfo.Artist)))
|
||||
if ((songInfo.Album != "" && track.Title == songInfo.Title && track.Artist == songInfo.DisplayArtists && track.Album == songInfo.Album)
|
||||
|| (songInfo.Album == "" && track.Title == songInfo.Title && track.Artist == songInfo.DisplayArtists)
|
||||
|| (songInfo.Album == "" && FileHelper.IsSwitchableNormalizedMatch(Path.GetFileNameWithoutExtension(file), songInfo.Title, songInfo.DisplayArtists)))
|
||||
{
|
||||
var plain = track.GetRawLyrics();
|
||||
if (!plain.IsNullOrEmpty())
|
||||
@@ -367,7 +369,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
if (musicName == null || artists == null)
|
||||
continue;
|
||||
|
||||
if (FileHelper.IsSwitchableNormalizedMatch($"{artists} - {musicName}", songInfo.Title, songInfo.Artist))
|
||||
if (FileHelper.IsSwitchableNormalizedMatch($"{artists} - {musicName}", songInfo.Title, songInfo.DisplayArtists))
|
||||
{
|
||||
if (root.TryGetProperty("rawLyricFile", out var rawLyricFileProp))
|
||||
{
|
||||
@@ -397,7 +399,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
lyricsSearchResult.Raw = lyrics;
|
||||
lyricsSearchResult.Title = songInfo.Title;
|
||||
lyricsSearchResult.Artist = songInfo.Artist;
|
||||
lyricsSearchResult.Artists = songInfo.Artists;
|
||||
lyricsSearchResult.Album = songInfo.Album;
|
||||
}
|
||||
catch
|
||||
@@ -418,7 +420,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
var url =
|
||||
$"https://lrclib.net/api/search?" +
|
||||
$"track_name={Uri.EscapeDataString(songInfo.Title)}&" +
|
||||
$"artist_name={Uri.EscapeDataString(songInfo.Artist)}&" +
|
||||
$"artist_name={Uri.EscapeDataString(songInfo.DisplayArtists)}&" +
|
||||
$"&album_name={Uri.EscapeDataString(songInfo.Album)}" +
|
||||
$"&durationMs={Uri.EscapeDataString(songInfo.DurationMs.ToString())}";
|
||||
|
||||
@@ -451,7 +453,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
lyricsSearchResult.Raw = original;
|
||||
lyricsSearchResult.Title = searchedTitle;
|
||||
lyricsSearchResult.Artist = searchedArtist;
|
||||
lyricsSearchResult.Artists = searchedArtist?.Split(ATL.Settings.DisplayValueSeparator);
|
||||
lyricsSearchResult.Album = searchedAlbum;
|
||||
|
||||
return lyricsSearchResult;
|
||||
@@ -481,7 +483,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
ISearchResult? result;
|
||||
if (searcher == Searchers.Netease && songInfo.SongId != null)
|
||||
{
|
||||
result = new NeteaseSearchResult(songInfo.Title, [songInfo.Artist], songInfo.Album, null, (int)songInfo.DurationMs, songInfo.SongId);
|
||||
result = new NeteaseSearchResult(songInfo.Title, songInfo.Artists, songInfo.Album, songInfo.Artists, (int)songInfo.DurationMs, songInfo.SongId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -489,10 +491,10 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
{
|
||||
DurationMs = (int)songInfo.DurationMs,
|
||||
Album = songInfo.Album,
|
||||
AlbumArtists = [songInfo.Artist],
|
||||
Artists = [songInfo.Artist],
|
||||
AlbumArtists = songInfo.Artists.ToList(),
|
||||
Artists = songInfo.Artists.ToList(),
|
||||
Title = songInfo.Title,
|
||||
}, searcher);
|
||||
}, searcher, Lyricify.Lyrics.Searchers.Helpers.CompareHelper.MatchType.VeryHigh);
|
||||
}
|
||||
|
||||
if (result != null)
|
||||
@@ -573,7 +575,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
}
|
||||
|
||||
lyricsSearchResult.Title = result?.Title;
|
||||
lyricsSearchResult.Artist = result?.Artists.Join(" | ");
|
||||
lyricsSearchResult.Artists = result?.Artists;
|
||||
lyricsSearchResult.Album = result?.Album;
|
||||
|
||||
return lyricsSearchResult;
|
||||
@@ -588,11 +590,11 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
if (await _appleMusic.InitAsync())
|
||||
{
|
||||
var raw = await _appleMusic.GetLyricsAsync(songInfo.Title, songInfo.Artist);
|
||||
_logger.LogInformation("Apple Music lyrics search result for {SongInfo}: {Raw}", songInfo, raw);
|
||||
var raw = await _appleMusic.GetLyricsAsync(songInfo.Title, songInfo.DisplayArtists);
|
||||
_logger.LogInformation("SearchAppleMusicAsync");
|
||||
lyricsSearchResult.Raw = raw;
|
||||
lyricsSearchResult.Title = songInfo.Title;
|
||||
lyricsSearchResult.Artist = songInfo.Artist;
|
||||
lyricsSearchResult.Artists = songInfo.Artists;
|
||||
lyricsSearchResult.Album = "";
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,18 @@ using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Events;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
public interface IMediaSessionsService : INotifyPropertyChanged
|
||||
{
|
||||
event EventHandler<AlbumArtChangedEventArgs>? AlbumArtChanged;
|
||||
event EventHandler<LyricsChangedEventArgs>? LyricsChanged;
|
||||
|
||||
Task PlayAsync();
|
||||
@@ -27,11 +30,16 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
void InitPlaybackShortcuts();
|
||||
|
||||
MediaSourceProviderInfo? CurrentMediaSourceProviderInfo { get; }
|
||||
|
||||
bool CurrentIsPlaying { get; }
|
||||
SongInfo? CurrentSongInfo { get; }
|
||||
TimeSpan CurrentPosition { get; }
|
||||
LyricsData? CurrentLyricsData { get; }
|
||||
|
||||
SoftwareBitmap? SoftwareBitmap { get; }
|
||||
List<Color> LightAccentColors { get; }
|
||||
List<Color> DarkAccentColors { get; }
|
||||
|
||||
TranslationSearchProvider? TranslationSearchProvider { get; }
|
||||
LyricsSearchResult? CurrentLyricsSearchResult { get; }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
using BetterLyrics.WinUI3.Events;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.WinUI;
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
using DevWinUI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.Storage.Streams;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
@@ -14,30 +23,28 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
private readonly LatestOnlyTaskRunner _albumArtRefreshRunner = new();
|
||||
|
||||
public event EventHandler<AlbumArtChangedEventArgs>? AlbumArtChanged;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial SoftwareBitmap? SoftwareBitmap { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<Color> LightAccentColors { get; set; } = Enumerable.Repeat(Colors.Black, 4).ToList();
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<Color> DarkAccentColors { get; set; } = Enumerable.Repeat(Colors.Black, 4).ToList();
|
||||
|
||||
private void UpdateAlbumArt()
|
||||
{
|
||||
_albumArtRefreshRunner.RunAsync(RefreshArtAlbum);
|
||||
_ = _albumArtRefreshRunner.RunAsync(RefreshArtAlbum);
|
||||
}
|
||||
|
||||
private async Task RefreshArtAlbum(CancellationToken token)
|
||||
{
|
||||
_logger.LogInformation("RefreshArtAlbum");
|
||||
|
||||
if (CurrentSongInfo == null)
|
||||
{
|
||||
_logger.LogWarning("Cached song info is null, cannot update album art.");
|
||||
_logger.LogWarning("CurrentSongInfo == null");
|
||||
return;
|
||||
}
|
||||
|
||||
IBuffer? buffer = await Task.Run(async () => await _albumArtSearchService.SearchAsync(
|
||||
CurrentSongInfo?.PlayerId ?? "",
|
||||
CurrentSongInfo.Title,
|
||||
CurrentSongInfo.Artist,
|
||||
CurrentSongInfo.Album,
|
||||
_SMTCAlbumArtBuffer,
|
||||
token
|
||||
), token);
|
||||
IBuffer? buffer = await Task.Run(async () => await _albumArtSearchService.SearchAsync(CurrentSongInfo, _SMTCAlbumArtBuffer, token), token);
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
BitmapDecoder? decoder = null;
|
||||
|
||||
if (buffer == null)
|
||||
@@ -45,22 +52,27 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
using var placeHolderStream = await ImageHelper.GetAlbumArtPlaceholderAsync();
|
||||
var tempBuffer = new Windows.Storage.Streams.Buffer((uint)placeHolderStream.Size);
|
||||
await placeHolderStream.ReadAsync(tempBuffer, (uint)placeHolderStream.Size, InputStreamOptions.None);
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
buffer = tempBuffer;
|
||||
token.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
decoder = await ImageHelper.MakeSquareWithThemeColor(buffer, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.PaletteGeneratorType);
|
||||
token.ThrowIfCancellationRequested();
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
var albumArtSwBitmap = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Premultiplied);
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
albumArtSwBitmap.DpiX = 96;
|
||||
albumArtSwBitmap.DpiY = 96;
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
var albumArtLightAccentColors = await ImageHelper.GetAccentColorsAsync(decoder, 4, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.PaletteGeneratorType, false);
|
||||
var lightColorBytes = albumArtLightAccentColors.Palette.Select(t => Windows.UI.Color.FromArgb(255, (byte)t.X, (byte)t.Y, (byte)t.Z)).ToList();
|
||||
var albumArtDarkAccentColors = await ImageHelper.GetAccentColorsAsync(decoder, 4, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.PaletteGeneratorType, true);
|
||||
var darkColorBytes = albumArtDarkAccentColors.Palette.Select(t => Windows.UI.Color.FromArgb(255, (byte)t.X, (byte)t.Y, (byte)t.Z)).ToList();
|
||||
AlbumArtChanged?.Invoke(this, new AlbumArtChangedEventArgs(null, albumArtSwBitmap, lightColorBytes, darkColorBytes));
|
||||
var lightPalette = await ImageHelper.GetAccentColorsAsync(decoder, 4, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.PaletteGeneratorType, false);
|
||||
var darkPalette = await ImageHelper.GetAccentColorsAsync(decoder, 4, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.PaletteGeneratorType, true);
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
SoftwareBitmap = albumArtSwBitmap;
|
||||
LightAccentColors = lightPalette.Palette.Select(Helper.ColorHelper.FromVector3).ToList();
|
||||
DarkAccentColors = darkPalette.Palette.Select(Helper.ColorHelper.FromVector3).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Lyricify.Lyrics.Helpers.General;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.UI.Dispatching;
|
||||
@@ -61,7 +62,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
if (!_settingsService.AppSettings.TranslationSettings.IsTranslationEnabled) return;
|
||||
|
||||
_logger.LogInformation("Showing translation for lyrics...");
|
||||
_logger.LogInformation("SetTranslatedTextAsync");
|
||||
string targetLangCode = _settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageCode;
|
||||
_logger.LogInformation("Target language code: {TargetLangCode}", targetLangCode);
|
||||
string? originalText = _lyricsDataArr.FirstOrDefault()?.WrappedOriginalText;
|
||||
@@ -74,7 +75,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
_logger.LogInformation("Original lyrics already in target language: {TargetLangCode}", targetLangCode);
|
||||
|
||||
_lyricsDataArr[0].ClearTranslatedText();
|
||||
_lyricsDataArr.FirstOrDefault()?.ClearTranslatedText();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -84,7 +85,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
_logger.LogInformation("Found translated text in lyrics data at index {FoundIndex}", found);
|
||||
|
||||
_lyricsDataArr[0].SetTranslatedText(_lyricsDataArr[found], _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsTranslationSeparator, 50);
|
||||
_lyricsDataArr.FirstOrDefault()?.SetTranslatedText(_lyricsDataArr[found], _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsTranslationSeparator, 50);
|
||||
TranslationSearchProvider = CurrentLyricsSearchResult?.Provider.ToTranslationSearchProvider();
|
||||
}
|
||||
else if (_settingsService.AppSettings.TranslationSettings.IsLibreTranslateEnabled)
|
||||
@@ -97,7 +98,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
if (token.IsCancellationRequested) return;
|
||||
if (translated == string.Empty) return;
|
||||
|
||||
_lyricsDataArr[0].SetTranslation(translated, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsTranslationSeparator);
|
||||
_lyricsDataArr.FirstOrDefault()?.SetTranslation(translated, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsTranslationSeparator);
|
||||
|
||||
TranslationSearchProvider = Enums.TranslationSearchProvider.LibreTranslate;
|
||||
}
|
||||
@@ -131,7 +132,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
if (targetPhoneticCode == "")
|
||||
{
|
||||
_lyricsDataArr[0].ClearPhoneticText();
|
||||
_lyricsDataArr.FirstOrDefault()?.ClearPhoneticText();
|
||||
}
|
||||
|
||||
// Try get phonetic text from itself
|
||||
@@ -139,14 +140,14 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
if (found >= 0)
|
||||
{
|
||||
_logger.LogInformation("Found phonetic text in lyrics data at index {FoundIndex}", found);
|
||||
_lyricsDataArr[0].SetPhoneticText(_lyricsDataArr[found], _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsTranslationSeparator, 50);
|
||||
_lyricsDataArr.FirstOrDefault()?.SetPhoneticText(_lyricsDataArr[found], _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsTranslationSeparator, 50);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async Task RefreshLyricsAsync(CancellationToken token)
|
||||
{
|
||||
_logger.LogInformation("Refreshing lyrics...");
|
||||
_logger.LogInformation("RefreshLyricsAsync");
|
||||
|
||||
CurrentLyricsSearchResult = null;
|
||||
_lyricsDataArr = [LyricsData.GetLoadingPlaceholder()];
|
||||
@@ -158,25 +159,16 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
if (CurrentSongInfo != null)
|
||||
{
|
||||
_logger.LogInformation("Searching lyrics for: Title={Title}, Artist={Artist}, Album={Album}, DurationMs={DurationMs}",
|
||||
CurrentSongInfo.Title, CurrentSongInfo.Artist, CurrentSongInfo.Album, CurrentSongInfo.DurationMs);
|
||||
|
||||
CurrentLyricsSearchResult = await Task.Run(async () => await _lyrcsSearchService.SearchSmartlyAsync(CurrentSongInfo, token), token);
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
_logger.LogInformation("Lyrics was found? {Found}, Provider: {LyricsSearchProvider}", CurrentLyricsSearchResult?.IsFound, CurrentLyricsSearchResult?.Provider);
|
||||
|
||||
var lyricsParser = new LyricsParser();
|
||||
lyricsParser.Parse(
|
||||
_settingsService.AppSettings.MappedSongSearchQueries.ToList(),
|
||||
CurrentSongInfo.Title, CurrentSongInfo.Artist, CurrentSongInfo.Album, CurrentLyricsSearchResult?.Raw, (int?)CurrentSongInfo?.DurationMs, CurrentLyricsSearchResult?.Provider);
|
||||
CurrentSongInfo, CurrentLyricsSearchResult?.Raw, CurrentLyricsSearchResult?.Provider);
|
||||
_lyricsDataArr = lyricsParser.LyricsDataArr;
|
||||
ApplyChinesePreference();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("SongInfo is null, cannot search lyrics.");
|
||||
}
|
||||
|
||||
_logger.LogInformation("Parsed lyrics: {MultiLangLyricsCount} languages", _lyricsDataArr.Count);
|
||||
|
||||
@@ -206,12 +198,12 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
public void UpdateLyrics()
|
||||
{
|
||||
_refreshLyricsRunner.RunAsync(RefreshLyricsAsync);
|
||||
_ = _refreshLyricsRunner.RunAsync(RefreshLyricsAsync);
|
||||
}
|
||||
|
||||
public void UpdateTranslations()
|
||||
{
|
||||
_refreshTranslationRunner.RunAsync(RefreshTranslationAsync);
|
||||
_ = _refreshTranslationRunner.RunAsync(RefreshTranslationAsync);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ using Windows.Storage.Streams;
|
||||
using WindowsMediaController;
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using CommunityToolkit.WinUI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
@@ -62,6 +64,8 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
private double _lxMusicPositionSeconds = 0;
|
||||
private byte[]? _lxMusicAlbumArtBytes = null;
|
||||
|
||||
private readonly DispatcherQueueTimer? _onMediaPropsChangedTimer;
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool CurrentIsPlaying { get; private set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TimeSpan CurrentPosition { get; private set; } = TimeSpan.Zero;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial SongInfo? CurrentSongInfo { get; private set; }
|
||||
@@ -76,7 +80,8 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
ILiveStatesService liveStatesService,
|
||||
IDiscordService discordService,
|
||||
ITranslateService libreTranslateService,
|
||||
IResourceService resourceService)
|
||||
IResourceService resourceService,
|
||||
ILogger<MediaSessionsService> logger)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_albumArtSearchService = albumArtSearchService;
|
||||
@@ -86,7 +91,9 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
_liveStatesService = liveStatesService;
|
||||
_discordService = discordService;
|
||||
_resourceService = resourceService;
|
||||
_logger = Ioc.Default.GetRequiredService<ILogger<MediaSessionsService>>();
|
||||
_logger = logger;
|
||||
|
||||
_onMediaPropsChangedTimer = _dispatcherQueue.CreateTimer();
|
||||
|
||||
_settingsService.AppSettings.MediaSourceProvidersInfo.ItemPropertyChanged += MediaSourceProvidersInfo_ItemPropertyChanged;
|
||||
|
||||
@@ -272,107 +279,109 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
private void MediaManager_OnAnyMediaPropertyChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionMediaProperties? mediaProperties)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
_onMediaPropsChangedTimer?.Debounce(() =>
|
||||
{
|
||||
if (!_mediaManager.IsStarted) return;
|
||||
if (mediaSession == null)
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
{
|
||||
CurrentSongInfo = SongInfoExtensions.Placeholder;
|
||||
}
|
||||
|
||||
string? sessionId = mediaSession?.Id;
|
||||
|
||||
var desiredSession = GetCurrentSession();
|
||||
|
||||
if (mediaSession != desiredSession) return;
|
||||
|
||||
if (sessionId != null && !IsMediaSourceEnabled(sessionId))
|
||||
{
|
||||
CurrentSongInfo = SongInfoExtensions.Placeholder;
|
||||
|
||||
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
|
||||
mediaProperties?.Title, mediaProperties?.Artist, mediaProperties?.AlbumTitle);
|
||||
|
||||
if (PlayerIDMatcher.IsLXMusic(sessionId))
|
||||
if (!_mediaManager.IsStarted) return;
|
||||
if (mediaSession == null)
|
||||
{
|
||||
StopSSE();
|
||||
CurrentSongInfo = SongInfoExtensions.Placeholder;
|
||||
}
|
||||
|
||||
_SMTCAlbumArtBuffer = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentMediaSourceProviderInfo = GetCurrentMediaSourceProviderInfo();
|
||||
if (currentMediaSourceProviderInfo?.ResetPositionOffsetOnSongChanged == true)
|
||||
{
|
||||
currentMediaSourceProviderInfo?.PositionOffset = 0;
|
||||
}
|
||||
string? sessionId = mediaSession?.Id;
|
||||
|
||||
string fixedArtist = mediaProperties?.Artist ?? "N/A";
|
||||
string fixedAlbum = mediaProperties?.AlbumTitle ?? "N/A";
|
||||
string? songId = null;
|
||||
var desiredSession = GetCurrentSession();
|
||||
|
||||
if (PlayerIDMatcher.IsAppleMusic(sessionId))
|
||||
{
|
||||
fixedArtist = mediaProperties?.Artist.Split(" — ").FirstOrDefault() ?? (mediaProperties?.Artist ?? "N/A");
|
||||
fixedAlbum = mediaProperties?.Artist.Split(" — ").LastOrDefault() ?? (mediaProperties?.AlbumTitle ?? "N/A");
|
||||
}
|
||||
else if (PlayerIDMatcher.IsNeteaseFamily(sessionId))
|
||||
{
|
||||
songId = mediaProperties?.Genres
|
||||
.Where(x => x.StartsWith(ExtendedGenreFiled.NetEaseCloudMusicTrackID))?.FirstOrDefault()?
|
||||
.Replace(ExtendedGenreFiled.NetEaseCloudMusicTrackID, "");
|
||||
}
|
||||
if (mediaSession != desiredSession) return;
|
||||
|
||||
var linkedFileName = mediaProperties?.Genres
|
||||
.Where(x => x.StartsWith(ExtendedGenreFiled.FileName))?.FirstOrDefault()?
|
||||
.Replace(ExtendedGenreFiled.FileName, "");
|
||||
if (sessionId != null && !IsMediaSourceEnabled(sessionId))
|
||||
{
|
||||
CurrentSongInfo = SongInfoExtensions.Placeholder;
|
||||
|
||||
CurrentSongInfo = new SongInfo
|
||||
{
|
||||
Title = mediaProperties?.Title ?? "N/A",
|
||||
Artist = fixedArtist,
|
||||
Album = fixedAlbum,
|
||||
DurationMs = mediaSession?.ControlSession?.GetTimelineProperties().EndTime.TotalMilliseconds ?? 0,
|
||||
PlayerId = sessionId,
|
||||
SongId = songId,
|
||||
LinkedFileName = linkedFileName
|
||||
};
|
||||
if (PlayerIDMatcher.IsLXMusic(sessionId))
|
||||
{
|
||||
StopSSE();
|
||||
}
|
||||
|
||||
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
|
||||
mediaProperties?.Title, mediaProperties?.Artist, mediaProperties?.AlbumTitle);
|
||||
|
||||
if (PlayerIDMatcher.IsLXMusic(sessionId))
|
||||
{
|
||||
StartSSE();
|
||||
}
|
||||
else
|
||||
{
|
||||
StopSSE();
|
||||
}
|
||||
|
||||
if (PlayerIDMatcher.IsLXMusic(sessionId) && _lxMusicAlbumArtBytes != null)
|
||||
{
|
||||
_SMTCAlbumArtBuffer = _lxMusicAlbumArtBytes.AsBuffer();
|
||||
}
|
||||
else if (mediaProperties?.Thumbnail is IRandomAccessStreamReference streamReference)
|
||||
{
|
||||
_SMTCAlbumArtBuffer = await ImageHelper.ToBufferAsync(streamReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
_SMTCAlbumArtBuffer = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentMediaSourceProviderInfo = GetCurrentMediaSourceProviderInfo();
|
||||
if (currentMediaSourceProviderInfo?.ResetPositionOffsetOnSongChanged == true)
|
||||
{
|
||||
currentMediaSourceProviderInfo?.PositionOffset = 0;
|
||||
}
|
||||
|
||||
CurrentMediaSourceProviderInfo = GetCurrentMediaSourceProviderInfo();
|
||||
string fixedArtist = mediaProperties?.Artist ?? "N/A";
|
||||
string fixedAlbum = mediaProperties?.AlbumTitle ?? "N/A";
|
||||
string? songId = null;
|
||||
|
||||
UpdateAlbumArt();
|
||||
UpdateLyrics();
|
||||
if (PlayerIDMatcher.IsAppleMusic(sessionId))
|
||||
{
|
||||
fixedArtist = mediaProperties?.Artist.Split(" — ").FirstOrDefault() ?? (mediaProperties?.Artist ?? "N/A");
|
||||
fixedAlbum = mediaProperties?.Artist.Split(" — ").LastOrDefault() ?? (mediaProperties?.AlbumTitle ?? "N/A");
|
||||
}
|
||||
else if (PlayerIDMatcher.IsNeteaseFamily(sessionId))
|
||||
{
|
||||
songId = mediaProperties?.Genres
|
||||
.Where(x => x.StartsWith(ExtendedGenreFiled.NetEaseCloudMusicTrackID))?.FirstOrDefault()?
|
||||
.Replace(ExtendedGenreFiled.NetEaseCloudMusicTrackID, "");
|
||||
}
|
||||
|
||||
UpdateDiscordPresence();
|
||||
UpdateCurrentMediaSourceProviderInfoPositionOffset();
|
||||
});
|
||||
var linkedFileName = mediaProperties?.Genres
|
||||
.Where(x => x.StartsWith(ExtendedGenreFiled.FileName))?.FirstOrDefault()?
|
||||
.Replace(ExtendedGenreFiled.FileName, "");
|
||||
|
||||
CurrentSongInfo = new SongInfo
|
||||
{
|
||||
Title = mediaProperties?.Title ?? "N/A",
|
||||
Artists = fixedArtist.Split(ATL.Settings.DisplayValueSeparator),
|
||||
Album = fixedAlbum,
|
||||
DurationMs = mediaSession?.ControlSession?.GetTimelineProperties().EndTime.TotalMilliseconds ?? 0,
|
||||
PlayerId = sessionId,
|
||||
SongId = songId,
|
||||
LinkedFileName = linkedFileName
|
||||
};
|
||||
|
||||
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
|
||||
mediaProperties?.Title, mediaProperties?.Artist, mediaProperties?.AlbumTitle);
|
||||
|
||||
if (PlayerIDMatcher.IsLXMusic(sessionId))
|
||||
{
|
||||
StartSSE();
|
||||
}
|
||||
else
|
||||
{
|
||||
StopSSE();
|
||||
}
|
||||
|
||||
if (PlayerIDMatcher.IsLXMusic(sessionId) && _lxMusicAlbumArtBytes != null)
|
||||
{
|
||||
_SMTCAlbumArtBuffer = _lxMusicAlbumArtBytes.AsBuffer();
|
||||
}
|
||||
else if (mediaProperties?.Thumbnail is IRandomAccessStreamReference streamReference)
|
||||
{
|
||||
_SMTCAlbumArtBuffer = await ImageHelper.ToBufferAsync(streamReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
_SMTCAlbumArtBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("MediaManager_OnAnyMediaPropertyChanged {SongInfo}", CurrentSongInfo);
|
||||
|
||||
CurrentMediaSourceProviderInfo = GetCurrentMediaSourceProviderInfo();
|
||||
|
||||
UpdateAlbumArt();
|
||||
UpdateLyrics();
|
||||
|
||||
UpdateDiscordPresence();
|
||||
UpdateCurrentMediaSourceProviderInfoPositionOffset();
|
||||
});
|
||||
}, Time.DebounceTimeout);
|
||||
}
|
||||
|
||||
private void MediaManager_OnAnySessionClosed(MediaManager.MediaSession mediaSession)
|
||||
|
||||
@@ -5,7 +5,6 @@ using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.LiveStatesService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
@@ -25,10 +24,13 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
private readonly ThrottleHelper _timelineThrottle = new(TimeSpan.FromSeconds(1));
|
||||
|
||||
public LyricsPageViewModel(IMediaSessionsService mediaSessionsService, ILiveStatesService liveStatesService)
|
||||
public LyricsRendererViewModel.LyricsRendererViewModel LyricsRendererViewModel { get; private set; }
|
||||
|
||||
public LyricsPageViewModel(IMediaSessionsService mediaSessionsService, ILiveStatesService liveStatesService, LyricsRendererViewModel.LyricsRendererViewModel lyricsRendererViewModel)
|
||||
{
|
||||
_liveStatesService = liveStatesService;
|
||||
MediaSessionsService = mediaSessionsService;
|
||||
LyricsRendererViewModel = lyricsRendererViewModel;
|
||||
|
||||
LiveStates = _liveStatesService.LiveStates;
|
||||
|
||||
@@ -105,7 +107,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
if (message.Sender is LyricsRendererViewModel.LyricsRendererViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsRendererViewModel.LyricsRendererViewModel.TotalTime))
|
||||
if (message.PropertyName == nameof(LyricsRendererViewModel.TotalTime))
|
||||
{
|
||||
if (_timelineThrottle.CanTrigger())
|
||||
{
|
||||
|
||||
@@ -189,11 +189,11 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
{
|
||||
ds.Transform = Matrix3x2.CreateRotation((float)_rotateAngle, control.Size.ToVector2() * 0.5f);
|
||||
|
||||
if (_albumArtBgEffect != null)
|
||||
if (_isAlbumArtBgEffectChanged && _albumArtBgEffect != null)
|
||||
{
|
||||
ds.DrawImage(_albumArtBgEffect);
|
||||
}
|
||||
else if (_albumArtBgRenderTarget != null)
|
||||
else if (!_isAlbumArtBgEffectChanged && _albumArtBgRenderTarget != null)
|
||||
{
|
||||
double targetSize = Math.Sqrt(Math.Pow(_canvasWidth, 2) + Math.Pow(_canvasHeight, 2));
|
||||
float offsetX = (float)(_canvasWidth - targetSize) / 2;
|
||||
@@ -208,6 +208,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private void DrawAlbumArt(ICanvasAnimatedControl control, CanvasDrawingSession ds)
|
||||
{
|
||||
// 专辑图封面正在变动,需实时绘制
|
||||
if (_isAlbumArtEffectChanged && _albumArtEffect != null)
|
||||
{
|
||||
ds.DrawImage(new OpacityEffect
|
||||
@@ -216,6 +217,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
Opacity = (float)_albumArtOpacityTransition.Value
|
||||
}, new Vector2((float)_albumArtXTransition.Value, (float)_albumArtYTransition.Value));
|
||||
}
|
||||
// 专辑图封面不再变动,使用已保存的绘制
|
||||
else if (!_isAlbumArtEffectChanged && _albumArtRenderTarget != null)
|
||||
{
|
||||
// 这里给一个相反的偏移以恢复位置
|
||||
|
||||
@@ -115,12 +115,12 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
using var overlappedCovers = new CanvasCommandList(control);
|
||||
using var overlappedCoversDs = overlappedCovers.CreateDrawingSession();
|
||||
|
||||
if (_lastAlbumArtCanvasBitmap != null)
|
||||
if (_lastAlbumArtCanvasBitmap != null && !_lastAlbumArtCanvasBitmap.IsDisposed())
|
||||
{
|
||||
using var lastBgImageEffect = CreateBgImageEffect(_lastAlbumArtCanvasBitmap, 1 - _albumArtBgTransition.Value);
|
||||
DrawBackgroundImgae(lastBgImageEffect, overlappedCoversDs, _lastAlbumArtCanvasBitmap);
|
||||
}
|
||||
if (_albumArtCanvasBitmap != null)
|
||||
if (_albumArtCanvasBitmap != null && !_albumArtCanvasBitmap.IsDisposed())
|
||||
{
|
||||
using var bgImageEffect = CreateBgImageEffect(_albumArtCanvasBitmap, _albumArtBgTransition.Value);
|
||||
DrawBackgroundImgae(bgImageEffect, overlappedCoversDs, _albumArtCanvasBitmap);
|
||||
@@ -181,6 +181,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
float offsetX = -(float)(_canvasWidth - targetSize) / 2;
|
||||
float offsetY = -(float)(_canvasHeight - targetSize) / 2;
|
||||
|
||||
ds.Clear(Colors.Transparent);
|
||||
ds.DrawImage(_albumArtBgEffect, new Vector2(offsetX, offsetY));
|
||||
}
|
||||
|
||||
@@ -251,6 +252,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_albumArtRenderTarget = new CanvasRenderTarget(control, (float)_canvasWidth, (float)_canvasHeight);
|
||||
using var ds = _albumArtRenderTarget.CreateDrawingSession();
|
||||
|
||||
ds.Clear(Colors.Transparent);
|
||||
// 给一个偏移,是为了避免绘制时从原点开始,这样会造成阴影被裁切
|
||||
ds.DrawImage(_albumArtEffect, control.Size.ToVector2() / 2 - new Vector2((float)_albumArtSize, (float)_albumArtSize) / 2);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,13 @@ using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TagLib.Riff;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
@@ -28,8 +33,46 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
IRecipient<PropertyChangedMessage<AlbumArtLayoutSettings>>,
|
||||
IRecipient<PropertyChangedMessage<LyricsBackgroundSettings>>,
|
||||
IRecipient<PropertyChangedMessage<LyricsWindowStatus>>,
|
||||
IRecipient<PropertyChangedMessage<SongInfo?>>
|
||||
IRecipient<PropertyChangedMessage<SongInfo?>>,
|
||||
IRecipient<PropertyChangedMessage<SoftwareBitmap?>>,
|
||||
IRecipient<PropertyChangedMessage<List<Color>>>
|
||||
{
|
||||
private void OnSongInfoChanged()
|
||||
{
|
||||
_lastSongTitle = _songTitle;
|
||||
_songTitle = _mediaSessionsService.CurrentSongInfo?.Title;
|
||||
_isSongTitleChanged = true;
|
||||
|
||||
_lastSongArtists = _songArtists;
|
||||
_songArtists = _mediaSessionsService.CurrentSongInfo?.DisplayArtists;
|
||||
_isSongArtistChanged = true;
|
||||
|
||||
_lastSongAlbum = _songAlbum;
|
||||
_songAlbum = _mediaSessionsService.CurrentSongInfo?.Album;
|
||||
_isSongAlbumChanged = true;
|
||||
|
||||
_songDurationMs = (int)(_mediaSessionsService.CurrentSongInfo?.DurationMs ?? TimeSpan.FromMinutes(99).TotalMilliseconds);
|
||||
|
||||
_songInfoOpacityTransition.Reset(0f);
|
||||
_songInfoOpacityTransition.StartTransition(1f);
|
||||
|
||||
TotalTime = TimeSpan.Zero;
|
||||
|
||||
// 处理 Last.fm 追踪
|
||||
_totalPlayingTime = TimeSpan.Zero;
|
||||
_isLastFMTracked = false;
|
||||
}
|
||||
|
||||
private void OnSoftwareBitmapChanged()
|
||||
{
|
||||
_lastAlbumArtCanvasBitmap?.Dispose();
|
||||
_lastAlbumArtCanvasBitmap = null;
|
||||
|
||||
_lastAlbumArtSwBitmap = _albumArtSwBitmap;
|
||||
_albumArtSwBitmap = _mediaSessionsService.SoftwareBitmap;
|
||||
|
||||
_albumArtChanged = true;
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<bool> message)
|
||||
{
|
||||
@@ -425,30 +468,12 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
public void Receive(PropertyChangedMessage<SongInfo?> message)
|
||||
{
|
||||
if (_mediaSessionsService.CurrentSongInfo?.Title != _songTitle || _mediaSessionsService.CurrentSongInfo?.Artist != _songArtist)
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
_lastSongTitle = _songTitle;
|
||||
_songTitle = _mediaSessionsService.CurrentSongInfo?.Title;
|
||||
_isSongTitleChanged = true;
|
||||
|
||||
_lastSongArtist = _songArtist;
|
||||
_songArtist = _mediaSessionsService.CurrentSongInfo?.Artist;
|
||||
_isSongArtistChanged = true;
|
||||
|
||||
_lastSongAlbum = _songAlbum;
|
||||
_songAlbum = _mediaSessionsService.CurrentSongInfo?.Album;
|
||||
_isSongAlbumChanged = true;
|
||||
|
||||
_songDurationMs = (int)(_mediaSessionsService.CurrentSongInfo?.DurationMs ?? TimeSpan.FromMinutes(99).TotalMilliseconds);
|
||||
|
||||
_songInfoOpacityTransition.Reset(0f);
|
||||
_songInfoOpacityTransition.StartTransition(1f);
|
||||
|
||||
TotalTime = TimeSpan.Zero;
|
||||
|
||||
// 处理 Last.fm 追踪
|
||||
_totalPlayingTime = TimeSpan.Zero;
|
||||
_isLastFMTracked = false;
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentSongInfo))
|
||||
{
|
||||
OnSongInfoChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,5 +502,31 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<SoftwareBitmap?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.SoftwareBitmap))
|
||||
{
|
||||
OnSoftwareBitmapChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<List<Color>> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.LightAccentColors))
|
||||
{
|
||||
UpdateColorConfig();
|
||||
}
|
||||
else if (message.PropertyName == nameof(IMediaSessionsService.DarkAccentColors))
|
||||
{
|
||||
UpdateColorConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,7 +592,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
//double? targetYScrollOffset = -currentPlayingLine!.OriginalPosition.Y + _currentLyricsData?.LyricsLines[0].OriginalPosition.Y - playingTextLayout.LayoutBounds.Height / 2.0;
|
||||
double? targetYScrollOffset =
|
||||
-currentPlayingLine!.OriginalPosition.Y
|
||||
+ _currentLyricsData?.LyricsLines[0].OriginalPosition.Y
|
||||
+ _currentLyricsData?.LyricsLines.FirstOrDefault()?.OriginalPosition.Y
|
||||
- (currentPlayingLine.TranslatedPosition.Y + (currentPlayingLine.TranslatedCanvasTextLayout?.LayoutBounds.Height ?? 0) - currentPlayingLine.PhoneticPosition.Y) / 2.0;
|
||||
|
||||
if (!targetYScrollOffset.HasValue) return;
|
||||
@@ -694,20 +694,20 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_adaptiveGrayedFontColor = _darkColor;
|
||||
brightness = 0.7f;
|
||||
_grayedEnvironmentalColor = _lightColor;
|
||||
_albumArtAccentColor1Transition.StartTransition(_albumArtLightAccentColors.ElementAtOrDefault(0));
|
||||
_albumArtAccentColor2Transition.StartTransition(_albumArtLightAccentColors.ElementAtOrDefault(1));
|
||||
_albumArtAccentColor3Transition.StartTransition(_albumArtLightAccentColors.ElementAtOrDefault(2));
|
||||
_albumArtAccentColor4Transition.StartTransition(_albumArtLightAccentColors.ElementAtOrDefault(3));
|
||||
_albumArtAccentColor1Transition.StartTransition(_mediaSessionsService.LightAccentColors.ElementAtOrDefault(0));
|
||||
_albumArtAccentColor2Transition.StartTransition(_mediaSessionsService.LightAccentColors.ElementAtOrDefault(1));
|
||||
_albumArtAccentColor3Transition.StartTransition(_mediaSessionsService.LightAccentColors.ElementAtOrDefault(2));
|
||||
_albumArtAccentColor4Transition.StartTransition(_mediaSessionsService.LightAccentColors.ElementAtOrDefault(3));
|
||||
}
|
||||
else
|
||||
{
|
||||
_adaptiveGrayedFontColor = _lightColor;
|
||||
brightness = 0.3f;
|
||||
_grayedEnvironmentalColor = _darkColor;
|
||||
_albumArtAccentColor1Transition.StartTransition(_albumArtDarkAccentColors.ElementAtOrDefault(0));
|
||||
_albumArtAccentColor2Transition.StartTransition(_albumArtDarkAccentColors.ElementAtOrDefault(1));
|
||||
_albumArtAccentColor3Transition.StartTransition(_albumArtDarkAccentColors.ElementAtOrDefault(2));
|
||||
_albumArtAccentColor4Transition.StartTransition(_albumArtDarkAccentColors.ElementAtOrDefault(3));
|
||||
_albumArtAccentColor1Transition.StartTransition(_mediaSessionsService.DarkAccentColors.ElementAtOrDefault(0));
|
||||
_albumArtAccentColor2Transition.StartTransition(_mediaSessionsService.DarkAccentColors.ElementAtOrDefault(1));
|
||||
_albumArtAccentColor3Transition.StartTransition(_mediaSessionsService.DarkAccentColors.ElementAtOrDefault(2));
|
||||
_albumArtAccentColor4Transition.StartTransition(_mediaSessionsService.DarkAccentColors.ElementAtOrDefault(3));
|
||||
}
|
||||
|
||||
_lyricsBgBrightnessTransition.StartTransition(brightness);
|
||||
@@ -720,11 +720,11 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
{
|
||||
if (isLight)
|
||||
{
|
||||
_adaptiveColoredFontColor = _albumArtDarkAccentColors.ElementAtOrDefault(0);
|
||||
_adaptiveColoredFontColor = _mediaSessionsService.DarkAccentColors.ElementAtOrDefault(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_adaptiveColoredFontColor = _albumArtLightAccentColors.ElementAtOrDefault(0);
|
||||
_adaptiveColoredFontColor = _mediaSessionsService.LightAccentColors.ElementAtOrDefault(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,12 +958,12 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_artistTextLayout = null;
|
||||
|
||||
_lastArtistTextLayout = new(
|
||||
control, _lastSongArtist ?? string.Empty,
|
||||
control, _lastSongArtists ?? string.Empty,
|
||||
_artistTextFormat, (float)_maxSongInfoWidth, (float)_canvasHeight
|
||||
);
|
||||
|
||||
_artistTextLayout = new(
|
||||
control, _songArtist ?? string.Empty,
|
||||
control, _songArtists ?? string.Empty,
|
||||
_artistTextFormat, (float)_maxSongInfoWidth, (float)_canvasHeight
|
||||
);
|
||||
|
||||
@@ -1320,10 +1320,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsCJKFontFamily,
|
||||
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsWesternFontFamily);
|
||||
|
||||
_lastArtistTextLayout?.SetFontFamily(_lastSongArtist,
|
||||
_lastArtistTextLayout?.SetFontFamily(_lastSongArtists,
|
||||
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsCJKFontFamily,
|
||||
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsWesternFontFamily);
|
||||
_artistTextLayout?.SetFontFamily(_songArtist,
|
||||
_artistTextLayout?.SetFontFamily(_songArtists,
|
||||
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsCJKFontFamily,
|
||||
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsWesternFontFamily);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.Graphics.Canvas.Geometry;
|
||||
using Microsoft.Graphics.Canvas.Text;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Text;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
@@ -75,8 +76,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
private string? _lastSongTitle;
|
||||
private string? _songTitle;
|
||||
|
||||
private string? _lastSongArtist;
|
||||
private string? _songArtist;
|
||||
private string? _lastSongArtists;
|
||||
private string? _songArtists;
|
||||
|
||||
private string? _lastSongAlbum;
|
||||
private string? _songAlbum;
|
||||
@@ -111,8 +112,6 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
private Color _adaptiveGrayedFontColor = Colors.Transparent;
|
||||
private Color? _adaptiveColoredFontColor = null;
|
||||
|
||||
private List<Color> _albumArtLightAccentColors = Enumerable.Repeat(Colors.Black, 4).ToList();
|
||||
private List<Color> _albumArtDarkAccentColors = Enumerable.Repeat(Colors.Black, 4).ToList();
|
||||
private Color _environmentalColor = Colors.Transparent;
|
||||
private Color _grayedEnvironmentalColor = Colors.Transparent;
|
||||
|
||||
@@ -181,6 +180,9 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private Matrix4x4 _lyrics3DMatrix = Matrix4x4.Identity;
|
||||
|
||||
private readonly DispatcherQueueTimer? _onSongInfoChangedTimer;
|
||||
private readonly DispatcherQueueTimer? _onSoftwareBitmapChangedTimer;
|
||||
|
||||
public LyricsRendererViewModel(
|
||||
ISettingsService settingsService,
|
||||
IMediaSessionsService mediaSessionsService,
|
||||
@@ -198,7 +200,6 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
UpdateSongInfoFontSize();
|
||||
|
||||
_mediaSessionsService.AlbumArtChanged += MediaSessionsService_AlbumArtChangedChanged;
|
||||
_mediaSessionsService.LyricsChanged += MediaSessionsService_LyricsChanged;
|
||||
|
||||
UpdateColorConfig();
|
||||
@@ -343,21 +344,5 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
return new Tuple<int, int>(0, _currentLyricsData.LyricsLines.Count - 1);
|
||||
}
|
||||
|
||||
private void MediaSessionsService_AlbumArtChangedChanged(object? sender, AlbumArtChangedEventArgs e)
|
||||
{
|
||||
_lastAlbumArtCanvasBitmap?.Dispose();
|
||||
_lastAlbumArtCanvasBitmap = null;
|
||||
|
||||
_lastAlbumArtSwBitmap = _albumArtSwBitmap;
|
||||
_albumArtSwBitmap = e.AlbumArtSwBitmap;
|
||||
|
||||
_albumArtChanged = true;
|
||||
|
||||
_albumArtLightAccentColors = e.AlbumArtLightAccentColors;
|
||||
_albumArtDarkAccentColors = e.AlbumArtDarkAccentColors;
|
||||
|
||||
UpdateColorConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
@@ -68,10 +69,10 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
MappedSongSearchQuery = new MappedSongSearchQuery
|
||||
{
|
||||
OriginalTitle = _mediaSessionsService.CurrentSongInfo.Title,
|
||||
OriginalArtist = _mediaSessionsService.CurrentSongInfo.Artist,
|
||||
OriginalArtist = _mediaSessionsService.CurrentSongInfo.DisplayArtists,
|
||||
OriginalAlbum = _mediaSessionsService.CurrentSongInfo.Album,
|
||||
MappedTitle = _mediaSessionsService.CurrentSongInfo.Title,
|
||||
MappedArtist = _mediaSessionsService.CurrentSongInfo.Artist,
|
||||
MappedArtist = _mediaSessionsService.CurrentSongInfo.DisplayArtists,
|
||||
MappedAlbum = _mediaSessionsService.CurrentSongInfo.Album,
|
||||
};
|
||||
}
|
||||
@@ -90,7 +91,10 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
}
|
||||
|
||||
var found = AppSettings.MappedSongSearchQueries
|
||||
.Where(x => x.OriginalTitle == _mediaSessionsService.CurrentSongInfo.Title && x.OriginalArtist == _mediaSessionsService.CurrentSongInfo.Artist && x.OriginalAlbum == _mediaSessionsService.CurrentSongInfo.Album);
|
||||
.Where(x =>
|
||||
x.OriginalTitle == _mediaSessionsService.CurrentSongInfo.Title &&
|
||||
x.OriginalArtist == _mediaSessionsService.CurrentSongInfo.DisplayArtists &&
|
||||
x.OriginalAlbum == _mediaSessionsService.CurrentSongInfo.Album);
|
||||
|
||||
return found.FirstOrDefault();
|
||||
}
|
||||
@@ -111,12 +115,10 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
LyricsSearchResults = [..await Task.Run(async () =>
|
||||
{
|
||||
return await _lyricsSearchService.SearchAllAsync(
|
||||
new SongInfo {
|
||||
Title = MappedSongSearchQuery.MappedTitle,
|
||||
Artist = MappedSongSearchQuery.MappedArtist,
|
||||
Album = MappedSongSearchQuery.MappedAlbum,
|
||||
DurationMs = _mediaSessionsService.CurrentSongInfo?.DurationMs ?? 0
|
||||
}, token);
|
||||
((SongInfo?)_mediaSessionsService.CurrentSongInfo?.Clone() ?? new())
|
||||
.WithTitle(MappedSongSearchQuery.MappedTitle)
|
||||
.WithArtist(MappedSongSearchQuery.MappedArtist.Split(ATL.Settings.DisplayValueSeparator))
|
||||
.WithAlbum(MappedSongSearchQuery.MappedAlbum), token);
|
||||
}, token)];
|
||||
IsSearching = false;
|
||||
});
|
||||
@@ -177,10 +179,8 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
var lyricsParser = new LyricsParser();
|
||||
lyricsParser.Parse(
|
||||
[MappedSongSearchQuery ?? new()],
|
||||
MappedSongSearchQuery?.OriginalTitle ?? "",
|
||||
MappedSongSearchQuery?.OriginalArtist ?? "",
|
||||
MappedSongSearchQuery?.OriginalAlbum ?? "",
|
||||
value?.Raw, (int?)_mediaSessionsService.CurrentSongInfo?.DurationMs, value?.Provider);
|
||||
_mediaSessionsService.CurrentSongInfo,
|
||||
value?.Raw, value?.Provider);
|
||||
LyricsDataArr = [.. lyricsParser.LyricsDataArr];
|
||||
}
|
||||
else
|
||||
|
||||
@@ -10,6 +10,7 @@ using BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using System.Numerics;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
Reference in New Issue
Block a user