Compare commits

...

14 Commits

Author SHA1 Message Date
Zhe Fang
619a3ba196 chores: bump to v1.1.198.0 2025-12-17 15:55:33 -05:00
Zhe Fang
13526bb85c chores: i18n 2025-12-17 15:43:48 -05:00
Zhe Fang
61f4f608db fix 2025-12-17 15:06:22 -05:00
Zhe Fang
f690da8501 feat: add language info in playback settings 2025-12-17 14:52:01 -05:00
Zhe Fang
145c13a0e6 chores: improve lyrics window switch exp 2025-12-17 14:05:28 -05:00
Zhe Fang
cea4fbb54d fix: PasswordVaultHelper save issue 2025-12-17 10:54:44 -05:00
Zhe Fang
1d489c68e9 chores: bump to v1.1.194.0 2025-12-15 15:45:25 -05:00
Zhe Fang
90e7fa42d0 chores 2025-12-15 15:36:50 -05:00
Zhe Fang
29a6879e45 chores: remove csharp-kana 2025-12-15 14:58:51 -05:00
Zhe Fang
58499a2d09 chores: update i18n 2025-12-15 14:55:37 -05:00
Zhe Fang
580255699b chores: change romaji method 2025-12-15 14:42:11 -05:00
Zhe Fang
9cac7818f1 fix: system tray left click 2025-12-15 10:45:24 -05:00
Zhe Fang
118668a457 fix: timeline 2025-12-15 07:36:26 -05:00
Zhe Fang
37621dbf2a chores: adjust margin for NowPlayingBar 2025-12-15 07:29:26 -05:00
40 changed files with 570 additions and 211 deletions

View File

@@ -12,7 +12,7 @@
<Identity <Identity
Name="37412.BetterLyrics" Name="37412.BetterLyrics"
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9" Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
Version="1.1.190.0" /> Version="1.1.198.0" />
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> <mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>

View File

@@ -10,7 +10,8 @@ using BetterLyrics.WinUI3.Services.LyricsSearchService;
using BetterLyrics.WinUI3.Services.MediaSessionsService; using BetterLyrics.WinUI3.Services.MediaSessionsService;
using BetterLyrics.WinUI3.Services.ResourceService; using BetterLyrics.WinUI3.Services.ResourceService;
using BetterLyrics.WinUI3.Services.SettingsService; using BetterLyrics.WinUI3.Services.SettingsService;
using BetterLyrics.WinUI3.Services.TranslateService; using BetterLyrics.WinUI3.Services.TranslationService;
using BetterLyrics.WinUI3.Services.TransliterationService;
using BetterLyrics.WinUI3.ViewModels; using BetterLyrics.WinUI3.ViewModels;
using BetterLyrics.WinUI3.Views; using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.DependencyInjection;
@@ -114,7 +115,8 @@ namespace BetterLyrics.WinUI3
.AddSingleton<IAlbumArtSearchService, AlbumArtSearchService>() .AddSingleton<IAlbumArtSearchService, AlbumArtSearchService>()
.AddSingleton<ILyricsSearchService, LyricsSearchService>() .AddSingleton<ILyricsSearchService, LyricsSearchService>()
.AddSingleton<ILibWatcherService, LibWatcherService>() .AddSingleton<ILibWatcherService, LibWatcherService>()
.AddSingleton<ITranslateService, TranslateService>() .AddSingleton<ITranslationService, TranslationService>()
.AddSingleton<ITransliterationService, TransliterationService>()
.AddSingleton<ILastFMService, LastFMService>() .AddSingleton<ILastFMService, LastFMService>()
.AddSingleton<IResourceService, ResourceService>() .AddSingleton<IResourceService, ResourceService>()
.AddSingleton<IDiscordService, DiscordService>() .AddSingleton<IDiscordService, DiscordService>()

View File

@@ -67,7 +67,6 @@
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" /> <PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" />
<PackageReference Include="CommunityToolkit.WinUI.Triggers" Version="8.2.250402" /> <PackageReference Include="CommunityToolkit.WinUI.Triggers" Version="8.2.250402" />
<PackageReference Include="ComputeSharp.D2D1.WinUI" Version="3.2.0" /> <PackageReference Include="ComputeSharp.D2D1.WinUI" Version="3.2.0" />
<PackageReference Include="csharp-kana" Version="1.0.2" />
<PackageReference Include="csharp-pinyin" Version="1.0.1" /> <PackageReference Include="csharp-pinyin" Version="1.0.1" />
<PackageReference Include="DevWinUI.Controls" Version="9.7.1" /> <PackageReference Include="DevWinUI.Controls" Version="9.7.1" />
<PackageReference Include="Dubya.WindowsMediaController" Version="2.5.6" /> <PackageReference Include="Dubya.WindowsMediaController" Version="2.5.6" />

View File

@@ -7,6 +7,7 @@
xmlns:interactivity="using:Microsoft.Xaml.Interactivity" xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:BetterLyrics.WinUI3.Controls" xmlns:local="using:BetterLyrics.WinUI3.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:CommunityToolkit.WinUI"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid <Grid
@@ -91,6 +92,47 @@
Text="{x:Bind LyricsWindowStatus.Name, Mode=OneWay}" Text="{x:Bind LyricsWindowStatus.Name, Mode=OneWay}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
</Grid> </Grid>
<Grid Background="{ThemeResource AcrylicInAppFillColorDefaultBrush}" Opacity="0">
<Grid.OpacityTransition>
<ScalarTransition />
</Grid.OpacityTransition>
<interactivity:Interaction.Behaviors>
<interactivity:EventTriggerBehavior EventName="PointerEntered">
<interactivity:ChangePropertyAction PropertyName="Opacity" Value="1" />
</interactivity:EventTriggerBehavior>
<interactivity:EventTriggerBehavior EventName="PointerExited">
<interactivity:ChangePropertyAction PropertyName="Opacity" Value="0" />
</interactivity:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="OpenButton_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE78B;}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="SystemTrayLyrics" />
</ToolTipService.ToolTip>
</Button>
<Button
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="CloseButton_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE711;}"
IsEnabled="{x:Bind LyricsWindowStatus.IsOpened, Mode=OneWay}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="SettingsPageCloseStatus" />
</ToolTipService.ToolTip>
</Button>
</Grid>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,6 +1,12 @@
using BetterLyrics.WinUI3.Hooks;
using BetterLyrics.WinUI3.Models; using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Services.SettingsService;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using System.Linq;
using static Vanara.PInvoke.User32.RAWINPUT;
// To learn more about WinUI, the WinUI project structure, // To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info. // and more about our project templates, see: http://aka.ms/winui-project-info.
@@ -9,6 +15,8 @@ namespace BetterLyrics.WinUI3.Controls;
public sealed partial class DemoWindowGrid : UserControl public sealed partial class DemoWindowGrid : UserControl
{ {
private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
public DemoWindowGrid() public DemoWindowGrid()
{ {
InitializeComponent(); InitializeComponent();
@@ -22,4 +30,32 @@ public sealed partial class DemoWindowGrid : UserControl
get => (LyricsWindowStatus)GetValue(LyricsWindowStatusProperty); get => (LyricsWindowStatus)GetValue(LyricsWindowStatusProperty);
set => SetValue(LyricsWindowStatusProperty, value); set => SetValue(LyricsWindowStatusProperty, value);
} }
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
var data = (LyricsWindowStatus)(((FrameworkElement)sender).DataContext);
var window = WindowHook.GetWindows<NowPlayingWindow>().FirstOrDefault(x => x.LyricsWindowStatus == data);
window?.CloseWindow();
}
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
var status = (LyricsWindowStatus)(((FrameworkElement)sender).DataContext);
// <20>࿪ģʽ
if (_settingsService.AppSettings.GeneralSettings.MultiNowPlayingWindowMode)
{
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
}
// <20><><EFBFBD><EFBFBD>ģʽ
else
{
var openedWindows = WindowHook.GetWindows<NowPlayingWindow>();
foreach (var item in openedWindows.Where(x => x.LyricsWindowStatus != status))
{
item.CloseWindow();
}
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
}
}
} }

View File

@@ -857,6 +857,14 @@ namespace BetterLyrics.WinUI3.Controls
{ {
_isLayoutChanged = true; _isLayoutChanged = true;
} }
else if (message.PropertyName == nameof(LyricsEffectSettings.IsLyricsFadeOutEffectEnabled))
{
_isLayoutChanged = true;
}
else if (message.PropertyName == nameof(LyricsEffectSettings.IsLyricsOutOfSightEffectEnabled))
{
_isLayoutChanged = true;
}
} }
else if (message.Sender == LyricsWindowStatus?.LyricsStyleSettings) else if (message.Sender == LyricsWindowStatus?.LyricsStyleSettings)
{ {

View File

@@ -28,6 +28,16 @@
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsBlurEffectEnabled, Mode=TwoWay}" /> <ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsBlurEffectEnabled, Mode=TwoWay}" />
</dev:SettingsCard> </dev:SettingsCard>
<!-- 淡出效果 -->
<dev:SettingsCard x:Uid="SettingsPageLyricsFadeOutEffect" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE89F;}">
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsFadeOutEffectEnabled, Mode=TwoWay}" />
</dev:SettingsCard>
<!-- 远离视野 -->
<dev:SettingsCard x:Uid="SettingsPageLyricsOutOfSightEffect" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF19D;}">
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsOutOfSightEffectEnabled, Mode=TwoWay}" />
</dev:SettingsCard>
<!-- 辉光效果 --> <!-- 辉光效果 -->
<dev:SettingsExpander x:Uid="SettingsPageLyricsGlowEffect" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE9A9;}"> <dev:SettingsExpander x:Uid="SettingsPageLyricsGlowEffect" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE9A9;}">
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=TwoWay}" /> <ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=TwoWay}" />

View File

@@ -100,10 +100,7 @@
BorderThickness="4" BorderThickness="4"
CornerRadius="4" CornerRadius="4"
Visibility="{Binding IsOpened, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" /> Visibility="{Binding IsOpened, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<uc:DemoWindowGrid <uc:DemoWindowGrid Margin="4" LyricsWindowStatus="{Binding}" />
Margin="4"
LyricsWindowStatus="{Binding}"
Tapped="DemoWindowGrid_Tapped" />
</Grid> </Grid>
<Grid> <Grid>
<ToggleButton <ToggleButton
@@ -117,7 +114,6 @@
<Grid ColumnSpacing="4"> <Grid ColumnSpacing="4">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Button <Button
Grid.Column="0" Grid.Column="0"
@@ -125,13 +121,6 @@
Click="ConfigButton_Click"> Click="ConfigButton_Click">
<TextBlock x:Uid="LyricsWindowSettingsControlLyricsWindowConfig" /> <TextBlock x:Uid="LyricsWindowSettingsControlLyricsWindowConfig" />
</Button> </Button>
<Button
Grid.Column="1"
HorizontalAlignment="Stretch"
Click="CloseStatusButton_Click"
IsEnabled="{Binding IsOpened, Mode=OneWay}">
<TextBlock x:Uid="SettingsPageCloseStatus" />
</Button>
</Grid> </Grid>
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>

View File

@@ -167,38 +167,6 @@ namespace BetterLyrics.WinUI3.Controls
ViewModel.OpenConfigPanel(); ViewModel.OpenConfigPanel();
} }
private void DemoWindowGrid_Tapped(object sender, TappedRoutedEventArgs e)
{
var status = (LyricsWindowStatus)(((FrameworkElement)sender).DataContext);
// <20>࿪ģʽ
if (_settingsService.AppSettings.GeneralSettings.MultiNowPlayingWindowMode)
{
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
}
// <20><><EFBFBD><EFBFBD>ģʽ
else
{
var openedWindows = WindowHook.GetWindows<NowPlayingWindow>();
foreach (var item in openedWindows.Where(x => x.LyricsWindowStatus != status))
{
item.CloseWindow();
}
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
}
}
private void CloseStatusButton_Click(object sender, RoutedEventArgs e)
{
if (sender is FrameworkElement element)
{
if (element.DataContext is LyricsWindowStatus data)
{
var window = WindowHook.GetWindows<NowPlayingWindow>().FirstOrDefault(x => x.LyricsWindowStatus == data);
window?.CloseWindow();
}
}
}
private void ConfigSegmented_SelectionChanged(object sender, SelectionChangedEventArgs e) private void ConfigSegmented_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
ViewModel.SelectorBarSelectedItemTag = (string)((SegmentedItem)((Segmented)sender).SelectedItem).Tag; ViewModel.SelectorBarSelectedItemTag = (string)((SegmentedItem)((Segmented)sender).SelectedItem).Tag;

View File

@@ -29,22 +29,6 @@ namespace BetterLyrics.WinUI3.Controls
private async void Grid_Tapped(object sender, TappedRoutedEventArgs e) private async void Grid_Tapped(object sender, TappedRoutedEventArgs e)
{ {
var status = (LyricsWindowStatus)(((FrameworkElement)sender).DataContext);
// <20>࿪ģʽ
if (_settingsService.AppSettings.GeneralSettings.MultiNowPlayingWindowMode)
{
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
}
// <20><><EFBFBD><EFBFBD>ģʽ
else
{
var openedWindows = WindowHook.GetWindows<NowPlayingWindow>();
foreach (var item in openedWindows.Where(x => x.LyricsWindowStatus != status))
{
item.CloseWindow();
}
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
}
await HideAsync(); await HideAsync();
} }

View File

@@ -342,7 +342,7 @@
<Slider <Slider
x:Name="TimelineSlider" x:Name="TimelineSlider"
Margin="0,-12,0,0" Margin="0,-14,0,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Top" VerticalAlignment="Top"
Maximum="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.DurationMs, Mode=OneWay, Converter={StaticResource MillisecondsToSecondsConverter}}" Maximum="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.DurationMs, Mode=OneWay, Converter={StaticResource MillisecondsToSecondsConverter}}"

View File

@@ -290,10 +290,7 @@ public sealed partial class NowPlayingBar : UserControl,
{ {
if (message.PropertyName == nameof(IMediaSessionsService.CurrentPosition)) if (message.PropertyName == nameof(IMediaSessionsService.CurrentPosition))
{ {
DispatcherQueue.TryEnqueue(() => TimelineSlider.Value = message.NewValue.TotalSeconds;
{
TimelineSlider.Value = message.NewValue.TotalSeconds;
});
} }
} }
} }

View File

@@ -348,6 +348,7 @@
x:Uid="LyricsSearchControlDurauion" x:Uid="LyricsSearchControlDurauion"
Unit="s" Unit="s"
Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Duration, TargetNullValue=N/A, Mode=OneWay}" /> Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Duration, TargetNullValue=N/A, Mode=OneWay}" />
<local:PropertyRow x:Uid="LyricsPageLanguageCode" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsData.LanguageCode, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource LanguageCodeToDisplayedNameConverter}}" />
<local:PropertyRow <local:PropertyRow
x:Uid="LyricsPageLyricsProviderPrefix" x:Uid="LyricsPageLyricsProviderPrefix"
Link="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Reference, Mode=OneWay}" Link="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Reference, Mode=OneWay}"
@@ -397,16 +398,23 @@
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=TwoWay}" /> <ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=TwoWay}" />
</dev:SettingsCard> </dev:SettingsCard>
<dev:SettingsCard x:Uid="SettingsPageLibreTranslateServer" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=OneWay}"> <dev:SettingsCard x:Uid="SettingsPageLibreTranslateServer" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=OneWay}">
<StackPanel Orientation="Horizontal" Spacing="12"> <Grid ColumnSpacing="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox <TextBox
x:Uid="LibreTranslateServerTextBox" x:Uid="LibreTranslateServerTextBox"
Grid.Column="0"
IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
Text="{x:Bind ViewModel.AppSettings.TranslationSettings.LibreTranslateServer, Mode=TwoWay}" /> Text="{x:Bind ViewModel.AppSettings.TranslationSettings.LibreTranslateServer, Mode=TwoWay}"
TextWrapping="Wrap" />
<Button <Button
x:Uid="SettingsPageServerTestButton" x:Uid="SettingsPageServerTestButton"
Grid.Column="1"
Command="{x:Bind ViewModel.LibreTranslateServerTestCommand}" Command="{x:Bind ViewModel.LibreTranslateServerTestCommand}"
IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" /> IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
</StackPanel> </Grid>
</dev:SettingsCard> </dev:SettingsCard>
</dev:SettingsExpander.Items> </dev:SettingsExpander.Items>
</dev:SettingsExpander> </dev:SettingsExpander>
@@ -424,9 +432,33 @@
</dev:SettingsCard> </dev:SettingsCard>
</dev:SettingsExpander.Items> </dev:SettingsExpander.Items>
</dev:SettingsExpander> </dev:SettingsExpander>
<dev:SettingsCard x:Uid="SettingsPageJapanese"> <dev:SettingsExpander x:Uid="SettingsPageJapanese" IsExpanded="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=TwoWay}" /> <ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=TwoWay}" />
</dev:SettingsCard> <dev:SettingsExpander.Items>
<dev:SettingsCard x:Uid="SettingsPageCutletDockerServer" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=OneWay}">
<dev:SettingsCard.Description>
<HyperlinkButton Content="https://github.com/jayfunc/cutlet-docker" NavigateUri="https://github.com/jayfunc/cutlet-docker" />
</dev:SettingsCard.Description>
<Grid ColumnSpacing="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox
x:Uid="CutletServerTextBox"
Grid.Column="0"
IsEnabled="{x:Bind ViewModel.IsCutletDockerServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
Text="{x:Bind ViewModel.AppSettings.TranslationSettings.CutletDockerServer, Mode=TwoWay}"
TextWrapping="Wrap" />
<Button
x:Uid="SettingsPageServerTestButton"
Grid.Column="1"
Command="{x:Bind ViewModel.CutletDockerServerTestCommand}"
IsEnabled="{x:Bind ViewModel.IsCutletDockerServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
</Grid>
</dev:SettingsCard>
</dev:SettingsExpander.Items>
</dev:SettingsExpander>
<!-- 中文简体繁体偏好 --> <!-- 中文简体繁体偏好 -->
<TextBlock x:Uid="SettingsPageChineseLyrics" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" /> <TextBlock x:Uid="SettingsPageChineseLyrics" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />

View File

@@ -14,7 +14,6 @@
x:Name="TrayIcon" x:Name="TrayIcon"
x:FieldModifier="public" x:FieldModifier="public"
ContextMenuMode="SecondWindow" ContextMenuMode="SecondWindow"
DoubleClickCommand="{x:Bind ViewModel.OpenLyricsWindowSwitchCommand}"
IconSource="ms-appx:///Assets/Logo.ico" IconSource="ms-appx:///Assets/Logo.ico"
LeftClickCommand="{x:Bind ViewModel.OpenLyricsWindowSwitchCommand}" LeftClickCommand="{x:Bind ViewModel.OpenLyricsWindowSwitchCommand}"
NoLeftClickDelay="True" NoLeftClickDelay="True"

View File

@@ -27,6 +27,7 @@ namespace BetterLyrics.WinUI3.Converter
TransliterationSearchProvider.LocalEslrcFile => _resourceService.GetLocalizedString("LyricsSearchProviderEslrcFile"), TransliterationSearchProvider.LocalEslrcFile => _resourceService.GetLocalizedString("LyricsSearchProviderEslrcFile"),
TransliterationSearchProvider.LocalTtmlFile => _resourceService.GetLocalizedString("LyricsSearchProviderTtmlFile"), TransliterationSearchProvider.LocalTtmlFile => _resourceService.GetLocalizedString("LyricsSearchProviderTtmlFile"),
TransliterationSearchProvider.BetterLyrics => "BetterLyrics", TransliterationSearchProvider.BetterLyrics => "BetterLyrics",
TransliterationSearchProvider.CutletDocker => "cutlet-docker",
_ => "N/A", _ => "N/A",
}; };
} }

View File

@@ -12,6 +12,7 @@
LocalLrcFile, LocalLrcFile,
LocalEslrcFile, LocalEslrcFile,
LocalTtmlFile, LocalTtmlFile,
BetterLyrics BetterLyrics,
CutletDocker
} }
} }

View File

@@ -1,4 +1,5 @@
using Windows.Security.Credentials; using System;
using Windows.Security.Credentials;
namespace BetterLyrics.WinUI3.Helper namespace BetterLyrics.WinUI3.Helper
{ {
@@ -12,23 +13,13 @@ namespace BetterLyrics.WinUI3.Helper
/// <param name="value">要保存的值</param> /// <param name="value">要保存的值</param>
public static void Save(string resource, string key, string value) public static void Save(string resource, string key, string value)
{ {
// 删除旧值(避免重复存储)
try try
{ {
var vault = new PasswordVault(); var vault = new PasswordVault();
var oldCredential = vault.Retrieve(resource, key);
if (oldCredential != null)
{
vault.Remove(oldCredential);
}
vault.Add(new PasswordCredential(resource, key, value)); vault.Add(new PasswordCredential(resource, key, value));
} }
catch catch (Exception) { }
{
// 没有旧值就忽略
}
} }
/// <summary> /// <summary>
@@ -47,7 +38,7 @@ namespace BetterLyrics.WinUI3.Helper
credential.RetrievePassword(); credential.RetrievePassword();
return credential.Password; return credential.Password;
} }
catch catch (Exception)
{ {
return null; return null;
} }
@@ -65,10 +56,7 @@ namespace BetterLyrics.WinUI3.Helper
var credential = vault.Retrieve(resource, key); var credential = vault.Retrieve(resource, key);
vault.Remove(credential); vault.Remove(credential);
} }
catch catch (Exception) { }
{
// 不存在就忽略
}
} }
} }
} }

View File

@@ -32,11 +32,6 @@ namespace BetterLyrics.WinUI3.Helper
} }
} }
public static string ToRomaji(string text)
{
return Kana.Kana.KanaToRomaji(text, Kana.Error.Ignore).ToStr();
}
public static string ToPinyin(string text, Pinyin.ManTone.Style style = Pinyin.ManTone.Style.TONE) public static string ToPinyin(string text, Pinyin.ManTone.Style style = Pinyin.ManTone.Style.TONE)
{ {
return Pinyin.Pinyin.Instance.HanziToPinyin(text, style).ToStr(); return Pinyin.Pinyin.Instance.HanziToPinyin(text, style).ToStr();

View File

@@ -224,10 +224,7 @@ namespace BetterLyrics.WinUI3.Hooks
private static void WindowHelper_Closed(object sender, WindowEventArgs args) private static void WindowHelper_Closed(object sender, WindowEventArgs args)
{ {
if (_activeWindows.Contains(sender)) _activeWindows.Remove(sender);
{
_activeWindows.Remove(sender);
}
} }
public static void SetIsWorkArea(this NowPlayingWindow window, bool enable) public static void SetIsWorkArea(this NowPlayingWindow window, bool enable)

View File

@@ -92,27 +92,30 @@ namespace BetterLyrics.WinUI3.Logic
line.ScaleTransition.SetDuration(yScrollDuration); line.ScaleTransition.SetDuration(yScrollDuration);
line.ScaleTransition.SetDelay(yScrollDelay); line.ScaleTransition.SetDelay(yScrollDelay);
line.ScaleTransition.StartTransition(_highlightedScale - distanceFactor * (_highlightedScale - _defaultScale)); line.ScaleTransition.StartTransition(
lyricsEffect.IsLyricsOutOfSightEffectEnabled ?
(_highlightedScale - distanceFactor * (_highlightedScale - _defaultScale)) :
_highlightedScale);
line.PhoneticOpacityTransition.SetDuration(yScrollDuration); line.PhoneticOpacityTransition.SetDuration(yScrollDuration);
line.PhoneticOpacityTransition.SetDelay(yScrollDelay); line.PhoneticOpacityTransition.SetDelay(yScrollDelay);
line.PhoneticOpacityTransition.StartTransition( line.PhoneticOpacityTransition.StartTransition(
absLineCountDelta == 0 ? phoneticOpacity : (isMouseScrolling ? phoneticOpacity : (1 - distanceFactor) * phoneticOpacity)); CalculateTargetOpacity(phoneticOpacity, phoneticOpacity, distanceFactor, isMouseScrolling, lyricsEffect));
line.PlayedOriginalOpacityTransition.SetDuration(yScrollDuration); line.PlayedOriginalOpacityTransition.SetDuration(yScrollDuration);
line.PlayedOriginalOpacityTransition.SetDelay(yScrollDelay); line.PlayedOriginalOpacityTransition.SetDelay(yScrollDelay);
line.PlayedOriginalOpacityTransition.StartTransition( line.PlayedOriginalOpacityTransition.StartTransition(
absLineCountDelta == 0 ? 1 : (isMouseScrolling ? 1.0 : (1 - distanceFactor) * originalOpacity)); CalculateTargetOpacity(originalOpacity, 1.0, distanceFactor, isMouseScrolling, lyricsEffect));
line.UnplayedOriginalOpacityTransition.SetDuration(yScrollDuration); line.UnplayedOriginalOpacityTransition.SetDuration(yScrollDuration);
line.UnplayedOriginalOpacityTransition.SetDelay(yScrollDelay); line.UnplayedOriginalOpacityTransition.SetDelay(yScrollDelay);
line.UnplayedOriginalOpacityTransition.StartTransition( line.UnplayedOriginalOpacityTransition.StartTransition(
absLineCountDelta == 0 ? originalOpacity : (isMouseScrolling ? originalOpacity : (1 - distanceFactor) * originalOpacity)); CalculateTargetOpacity(originalOpacity, originalOpacity, distanceFactor, isMouseScrolling, lyricsEffect));
line.TranslatedOpacityTransition.SetDuration(yScrollDuration); line.TranslatedOpacityTransition.SetDuration(yScrollDuration);
line.TranslatedOpacityTransition.SetDelay(yScrollDelay); line.TranslatedOpacityTransition.SetDelay(yScrollDelay);
line.TranslatedOpacityTransition.StartTransition( line.TranslatedOpacityTransition.StartTransition(
absLineCountDelta == 0 ? translatedOpacity : (isMouseScrolling ? translatedOpacity : (1 - distanceFactor) * translatedOpacity)); CalculateTargetOpacity(translatedOpacity, translatedOpacity, distanceFactor, isMouseScrolling, lyricsEffect));
line.ColorTransition.SetDuration(yScrollDuration); line.ColorTransition.SetDuration(yScrollDuration);
line.ColorTransition.SetDelay(yScrollDelay); line.ColorTransition.SetDelay(yScrollDelay);
@@ -143,5 +146,33 @@ namespace BetterLyrics.WinUI3.Logic
line.ColorTransition.Update(elapsedTime); line.ColorTransition.Update(elapsedTime);
} }
} }
private static double CalculateTargetOpacity(double baseOpacity, double baseOpacityWhenZeroDistanceFactor, double distanceFactor, bool isMouseScrolling, LyricsEffectSettings lyricsEffect)
{
double targetOpacity;
if (distanceFactor == 0)
{
targetOpacity = baseOpacityWhenZeroDistanceFactor;
}
else
{
if (isMouseScrolling)
{
targetOpacity = baseOpacity;
}
else
{
if (lyricsEffect.IsLyricsFadeOutEffectEnabled)
{
targetOpacity = (1 - distanceFactor) * baseOpacity;
}
else
{
targetOpacity = baseOpacity;
}
}
}
return targetOpacity;
}
} }
} }

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;
namespace BetterLyrics.WinUI3.Models
{
public class CutletDockerRequest
{
[JsonPropertyName("text")]
public string Text { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;
namespace BetterLyrics.WinUI3.Models
{
public class CutletDockerResponse
{
[JsonPropertyName("romaji")]
public string RomajiText { get; set; }
}
}

View File

@@ -2,7 +2,7 @@
namespace BetterLyrics.WinUI3.Models namespace BetterLyrics.WinUI3.Models
{ {
public class TranslateResponse public class LibreTranslateResponse
{ {
[JsonPropertyName("translatedText")] [JsonPropertyName("translatedText")]
public string TranslatedText { get; set; } public string TranslatedText { get; set; }

View File

@@ -90,6 +90,24 @@ namespace BetterLyrics.WinUI3.Models
} }
} }
public void SetTransliteration(string transliteration)
{
List<string> transliterationArr = transliteration.Split(StringHelper.NewLine).ToList();
int i = 0;
foreach (var line in LyricsLines)
{
if (i >= transliterationArr.Count)
{
line.PhoneticText = ""; // No transliteration available, keep empty
}
else
{
line.PhoneticText = transliterationArr[i];
}
i++;
}
}
public static LyricsData GetNotfoundPlaceholder() public static LyricsData GetNotfoundPlaceholder()
{ {
return new LyricsData([new LyricsLine return new LyricsData([new LyricsLine

View File

@@ -7,6 +7,8 @@ namespace BetterLyrics.WinUI3.Models.Settings
public partial class LyricsEffectSettings : ObservableRecipient, ICloneable public partial class LyricsEffectSettings : ObservableRecipient, ICloneable
{ {
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsBlurEffectEnabled { get; set; } = true; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsBlurEffectEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsFadeOutEffectEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsOutOfSightEffectEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsGlowEffectEnabled { get; set; } = true; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsGlowEffectEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectScope LyricsGlowEffectScope { get; set; } = LyricsEffectScope.LongDurationSyllable; [ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectScope LyricsGlowEffectScope { get; set; } = LyricsEffectScope.LongDurationSyllable;
@@ -52,6 +54,8 @@ namespace BetterLyrics.WinUI3.Models.Settings
return new LyricsEffectSettings(this.LyricsScrollTopDuration, this.LyricsScrollDuration, this.LyricsScrollBottomDuration, this.LyricsScrollEasingType) return new LyricsEffectSettings(this.LyricsScrollTopDuration, this.LyricsScrollDuration, this.LyricsScrollBottomDuration, this.LyricsScrollEasingType)
{ {
IsLyricsBlurEffectEnabled = this.IsLyricsBlurEffectEnabled, IsLyricsBlurEffectEnabled = this.IsLyricsBlurEffectEnabled,
IsLyricsFadeOutEffectEnabled = this.IsLyricsFadeOutEffectEnabled,
IsLyricsOutOfSightEffectEnabled = this.IsLyricsOutOfSightEffectEnabled,
IsLyricsGlowEffectEnabled = this.IsLyricsGlowEffectEnabled, IsLyricsGlowEffectEnabled = this.IsLyricsGlowEffectEnabled,
LyricsGlowEffectLongSyllableDuration = this.LyricsGlowEffectLongSyllableDuration, LyricsGlowEffectLongSyllableDuration = this.LyricsGlowEffectLongSyllableDuration,

View File

@@ -13,6 +13,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial ChineseRomanization ChineseRomanization { get; set; } [ObservableProperty][NotifyPropertyChangedRecipients] public partial ChineseRomanization ChineseRomanization { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsChineseRomanizationEnabled { get; set; } = false; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsChineseRomanizationEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsJapaneseRomanizationEnabled { get; set; } = false; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsJapaneseRomanizationEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string CutletDockerServer { get; set; } = string.Empty;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsTraditionalChineseEnabled { get; set; } = false; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsTraditionalChineseEnabled { get; set; } = false;
public TranslationSettings() { } public TranslationSettings() { }

View File

@@ -5,7 +5,8 @@ using BetterLyrics.WinUI3.Extensions;
using BetterLyrics.WinUI3.Helper; using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models; using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings; using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.TranslateService; using BetterLyrics.WinUI3.Services.TranslationService;
using BetterLyrics.WinUI3.Services.TransliterationService;
using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.DependencyInjection;
using Lyricify.Lyrics.Helpers.General; using Lyricify.Lyrics.Helpers.General;
using Lyricify.Lyrics.Parsers; using Lyricify.Lyrics.Parsers;
@@ -70,7 +71,13 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
return _lyricsDataArr; return _lyricsDataArr;
} }
public async Task<(LyricsData, TransliterationSearchProvider?, TranslationSearchProvider?)> Parse(ITranslateService translateService, TranslationSettings settings, LyricsSearchResult? lyricsSearchResult, CancellationToken token) public async Task<(LyricsData, TransliterationSearchProvider?, TranslationSearchProvider?)> Parse(
ITranslationService translationService,
ITransliterationService transliterationService,
TranslationSettings settings,
LyricsSearchResult? lyricsSearchResult,
CancellationToken token
)
{ {
TransliterationSearchProvider? transliterationSearchProvider = null; TransliterationSearchProvider? transliterationSearchProvider = null;
TranslationSearchProvider? translationSearchProvider = null; TranslationSearchProvider? translationSearchProvider = null;
@@ -81,6 +88,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
// 应用音译 // 应用音译
LyricsData? phoneticLyricsData = null; LyricsData? phoneticLyricsData = null;
// 已解析歌词内寻找
if (settings.IsChineseRomanizationEnabled && main.LanguageCode == LanguageHelper.ChineseCode) if (settings.IsChineseRomanizationEnabled && main.LanguageCode == LanguageHelper.ChineseCode)
{ {
phoneticLyricsData = settings.ChineseRomanization switch phoneticLyricsData = settings.ChineseRomanization switch
@@ -89,21 +97,41 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
ChineseRomanization.Jyutping => _lyricsDataArr.FirstOrDefault(x => x.LanguageCode == PhoneticHelper.JyutpingCode), ChineseRomanization.Jyutping => _lyricsDataArr.FirstOrDefault(x => x.LanguageCode == PhoneticHelper.JyutpingCode),
_ => null, _ => null,
}; };
if (phoneticLyricsData != null)
{
main.SetPhoneticText(phoneticLyricsData);
if (phoneticLyricsData.AutoGenerated)
{
transliterationSearchProvider = TransliterationSearchProvider.BetterLyrics;
}
else
{
transliterationSearchProvider = lyricsSearchResult?.Provider.ToTransliterationSearchProvider();
}
}
} }
else if (settings.IsJapaneseRomanizationEnabled && main.LanguageCode == LanguageHelper.JapaneseCode) else if (settings.IsJapaneseRomanizationEnabled && main.LanguageCode == LanguageHelper.JapaneseCode)
{ {
phoneticLyricsData = _lyricsDataArr.FirstOrDefault(x => x.LanguageCode == PhoneticHelper.RomanCode); phoneticLyricsData = _lyricsDataArr.FirstOrDefault(x => x.LanguageCode == PhoneticHelper.RomanCode);
} if (phoneticLyricsData != null)
if (phoneticLyricsData != null)
{
main.SetPhoneticText(phoneticLyricsData);
if (phoneticLyricsData.AutoGenerated)
{ {
transliterationSearchProvider = TransliterationSearchProvider.BetterLyrics; main.SetPhoneticText(phoneticLyricsData);
transliterationSearchProvider = lyricsSearchResult?.Provider.ToTransliterationSearchProvider();
} }
else else
{ {
transliterationSearchProvider = lyricsSearchResult?.Provider.ToTransliterationSearchProvider(); string romaji = string.Empty;
try
{
romaji = await transliterationService.TransliterateText(main.WrappedOriginalText, PhoneticHelper.RomanCode, token);
_lyricsDataArr.FirstOrDefault()?.SetTransliteration(romaji);
transliterationSearchProvider = TransliterationSearchProvider.CutletDocker;
}
catch (TaskCanceledException) { }
catch (Exception)
{
ToastHelper.ShowToast("CutletDockerFailed", null, InfoBarSeverity.Error);
}
} }
} }
@@ -121,7 +149,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
string translated = string.Empty; string translated = string.Empty;
try try
{ {
translated = await translateService.TranslateTextAsync(main.WrappedOriginalText, settings.SelectedTargetLanguageCode, token); translated = await translationService.TranslateTextAsync(main.WrappedOriginalText, settings.SelectedTargetLanguageCode, token);
_lyricsDataArr.FirstOrDefault()?.SetTranslation(translated); _lyricsDataArr.FirstOrDefault()?.SetTranslation(translated);
translationSearchProvider = TranslationSearchProvider.LibreTranslate; translationSearchProvider = TranslationSearchProvider.LibreTranslate;
} }
@@ -239,30 +267,6 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
}); });
} }
} }
else if (languageCode == LanguageHelper.JapaneseCode)
{
if (!_lyricsDataArr.Any(x => x.LanguageCode == PhoneticHelper.RomanCode))
{
_lyricsDataArr.Add(new LyricsData
{
LanguageCode = PhoneticHelper.RomanCode,
AutoGenerated = true,
LyricsLines = main.LyricsLines.Select(line => new LyricsLine
{
StartMs = line.StartMs,
EndMs = line.EndMs,
OriginalText = PhoneticHelper.ToRomaji(line.OriginalText),
LyricsSyllables = line.LyricsSyllables.Select(c => new LyricsSyllable
{
StartMs = c.StartMs,
EndMs = c.EndMs,
Text = PhoneticHelper.ToRomaji(c.Text),
StartIndex = c.StartIndex
}).ToList()
}).ToList()
});
}
}
} }
} }

View File

@@ -7,7 +7,9 @@ using System.Text.Json.Serialization;
namespace BetterLyrics.WinUI3.Serialization namespace BetterLyrics.WinUI3.Serialization
{ {
[JsonSerializable(typeof(TranslateResponse))] [JsonSerializable(typeof(LibreTranslateResponse))]
[JsonSerializable(typeof(CutletDockerRequest))]
[JsonSerializable(typeof(CutletDockerResponse))]
[JsonSerializable(typeof(JsonElement))] [JsonSerializable(typeof(JsonElement))]
[JsonSerializable(typeof(AppSettings))] [JsonSerializable(typeof(AppSettings))]
[JsonSerializable(typeof(LyricsSearchResult))] [JsonSerializable(typeof(LyricsSearchResult))]

View File

@@ -40,7 +40,8 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
(CurrentLyricsData, CurrentLyricsSearchResult.TransliterationProvider, CurrentLyricsSearchResult.TranslationProvider) = (CurrentLyricsData, CurrentLyricsSearchResult.TransliterationProvider, CurrentLyricsSearchResult.TranslationProvider) =
await Task.Run(async () => await lyricsParser.Parse( await Task.Run(async () => await lyricsParser.Parse(
_translateService, _translationService,
_transliterationService,
_settingsService.AppSettings.TranslationSettings, _settingsService.AppSettings.TranslationSettings,
CurrentLyricsSearchResult, CurrentLyricsSearchResult,
token), token),

View File

@@ -14,7 +14,8 @@ using BetterLyrics.WinUI3.Services.DiscordService;
using BetterLyrics.WinUI3.Services.LibWatcherService; using BetterLyrics.WinUI3.Services.LibWatcherService;
using BetterLyrics.WinUI3.Services.LyricsSearchService; using BetterLyrics.WinUI3.Services.LyricsSearchService;
using BetterLyrics.WinUI3.Services.SettingsService; using BetterLyrics.WinUI3.Services.SettingsService;
using BetterLyrics.WinUI3.Services.TranslateService; using BetterLyrics.WinUI3.Services.TranslationService;
using BetterLyrics.WinUI3.Services.TransliterationService;
using BetterLyrics.WinUI3.ViewModels; using BetterLyrics.WinUI3.ViewModels;
using BetterLyrics.WinUI3.Views; using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
@@ -48,7 +49,8 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
private readonly IAlbumArtSearchService _albumArtSearchService; private readonly IAlbumArtSearchService _albumArtSearchService;
private readonly ILyricsSearchService _lyrcsSearchService; private readonly ILyricsSearchService _lyrcsSearchService;
private readonly ITranslateService _translateService; private readonly ITranslationService _translationService;
private readonly ITransliterationService _transliterationService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly ILibWatcherService _libWatcherService; private readonly ILibWatcherService _libWatcherService;
private readonly IDiscordService _discordService; private readonly IDiscordService _discordService;
@@ -71,14 +73,16 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
ILyricsSearchService lyricsSearchService, ILyricsSearchService lyricsSearchService,
ILibWatcherService libWatcherService, ILibWatcherService libWatcherService,
IDiscordService discordService, IDiscordService discordService,
ITranslateService libreTranslateService, ITranslationService libreTranslateService,
ITransliterationService transliterationService,
ILogger<MediaSessionsService> logger) ILogger<MediaSessionsService> logger)
{ {
_settingsService = settingsService; _settingsService = settingsService;
_albumArtSearchService = albumArtSearchService; _albumArtSearchService = albumArtSearchService;
_lyrcsSearchService = lyricsSearchService; _lyrcsSearchService = lyricsSearchService;
_libWatcherService = libWatcherService; _libWatcherService = libWatcherService;
_translateService = libreTranslateService; _translationService = libreTranslateService;
_transliterationService = transliterationService;
_discordService = discordService; _discordService = discordService;
_logger = logger; _logger = logger;
@@ -201,28 +205,32 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
private void MediaManager_OnAnyTimelinePropertyChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionTimelineProperties? timelineProperties) private void MediaManager_OnAnyTimelinePropertyChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionTimelineProperties? timelineProperties)
{ {
if (!_mediaManager.IsStarted) return; _dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
if (mediaSession == null)
{ {
CurrentPosition = TimeSpan.Zero; if (!_mediaManager.IsStarted) return;
return; if (mediaSession == null)
}
var desiredSession = GetCurrentSession();
if (mediaSession != desiredSession) return;
if (!IsMediaSourceEnabled(mediaSession.Id))
{
CurrentPosition = TimeSpan.Zero;
}
else
{
if (IsMediaSourceTimelineSyncEnabled(mediaSession.Id))
{ {
CurrentPosition = timelineProperties?.Position ?? TimeSpan.Zero; CurrentPosition = TimeSpan.Zero;
return;
} }
}
var desiredSession = GetCurrentSession();
if (mediaSession != desiredSession) return;
if (!IsMediaSourceEnabled(mediaSession.Id))
{
CurrentPosition = TimeSpan.Zero;
}
else
{
if (IsMediaSourceTimelineSyncEnabled(mediaSession.Id))
{
CurrentPosition = timelineProperties?.Position ?? TimeSpan.Zero;
CurrentSongInfo?.DurationMs = timelineProperties?.EndTime.TotalMilliseconds ?? 0;
}
}
});
} }
private void MediaManager_OnAnyPlaybackStateChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionPlaybackInfo? playbackInfo) private void MediaManager_OnAnyPlaybackStateChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionPlaybackInfo? playbackInfo)
@@ -696,8 +704,15 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
_logger.LogInformation("Target LibreTranslate language code changed: {code}", _settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageCode); _logger.LogInformation("Target LibreTranslate language code changed: {code}", _settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageCode);
UpdateLyrics(); UpdateLyrics();
} }
else if (message.PropertyName == nameof(TranslationSettings.CutletDockerServer))
{
UpdateLyrics();
}
else if (message.PropertyName == nameof(TranslationSettings.LibreTranslateServer))
{
UpdateLyrics();
}
} }
} }
public void Receive(PropertyChangedMessage<ChineseRomanization> message) public void Receive(PropertyChangedMessage<ChineseRomanization> message)

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Services.TranslateService namespace BetterLyrics.WinUI3.Services.TranslationService
{ {
public interface ITranslateService public interface ITranslationService
{ {
Task<string> TranslateTextAsync(string text, string targetLangCode, CancellationToken token); Task<string> TranslateTextAsync(string text, string targetLangCode, CancellationToken token);
int SearchTranslatedLyricsItself(List<LyricsData> lyricsDataArr, string targetLangCode);
} }
} }

View File

@@ -9,14 +9,14 @@ using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Services.TranslateService namespace BetterLyrics.WinUI3.Services.TranslationService
{ {
public partial class TranslateService : BaseViewModel, ITranslateService public partial class TranslationService : BaseViewModel, ITranslationService
{ {
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
public TranslateService(ISettingsService settingsService) public TranslationService(ISettingsService settingsService)
{ {
_settingsService = settingsService; _settingsService = settingsService;
_httpClient = new HttpClient(); _httpClient = new HttpClient();
@@ -51,31 +51,8 @@ namespace BetterLyrics.WinUI3.Services.TranslateService
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync(token); var json = await response.Content.ReadAsStringAsync(token);
var result = System.Text.Json.JsonSerializer.Deserialize(json, SourceGenerationContext.Default.TranslateResponse); var result = System.Text.Json.JsonSerializer.Deserialize(json, SourceGenerationContext.Default.LibreTranslateResponse);
return result?.TranslatedText ?? string.Empty; return result?.TranslatedText ?? string.Empty;
} }
public int SearchTranslatedLyricsItself(List<LyricsData> lyricsDataArr, string targetLangCode)
{
int ret = -1;
float maxTranslatinRate = 0.0f;
if (lyricsDataArr.Count > 1)
{
for (int i = 1; i < lyricsDataArr.Count; i++)
{
if (lyricsDataArr[i].LanguageCode == targetLangCode)
{
float translationRate = lyricsDataArr[i].LyricsLines.Count / (float)lyricsDataArr[0].LyricsLines.Count;
if (translationRate > maxTranslatinRate)
{
maxTranslatinRate = translationRate;
ret = i;
}
}
}
}
return ret;
}
} }
} }

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Services.TransliterationService
{
public interface ITransliterationService
{
Task<string> TransliterateText(string text, string targetLangCode, CancellationToken token);
}
}

View File

@@ -0,0 +1,52 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Serialization;
using BetterLyrics.WinUI3.Services.SettingsService;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Vanara.PInvoke;
namespace BetterLyrics.WinUI3.Services.TransliterationService
{
public class TransliterationService : ITransliterationService
{
private readonly ISettingsService _settingsService;
private readonly HttpClient _httpClient;
public TransliterationService(ISettingsService settingsService)
{
_settingsService = settingsService;
_httpClient = new HttpClient();
}
public async Task<string> TransliterateText(string text, string targetLangCode, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(text))
{
throw new Exception(text + " is empty or null.");
}
if (string.IsNullOrEmpty(_settingsService.AppSettings.TranslationSettings.CutletDockerServer))
{
throw new Exception("cutlet-docker server URL is not set in settings.");
}
var request = new CutletDockerRequest { Text = text };
var reqJson = System.Text.Json.JsonSerializer.Serialize(request, SourceGenerationContext.Default.CutletDockerRequest);
var url = $"{_settingsService.AppSettings.TranslationSettings.CutletDockerServer}/convert";
var response = await _httpClient.PostAsync(url, new StringContent(reqJson, Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
var resJson = await response.Content.ReadAsStringAsync(token);
var result = System.Text.Json.JsonSerializer.Deserialize(resJson, SourceGenerationContext.Default.CutletDockerResponse);
return result?.RomajiText ?? string.Empty;
}
}
}

View File

@@ -150,6 +150,12 @@
<data name="CreatePlaylistSuccessfully" xml:space="preserve"> <data name="CreatePlaylistSuccessfully" xml:space="preserve">
<value>Playlist was created successfully</value> <value>Playlist was created successfully</value>
</data> </data>
<data name="CutletDockerFailed" xml:space="preserve">
<value>Failed to request transliteration from cutlet-docker, please check settings or native cutlet-docker configuration</value>
</data>
<data name="CutletServerTextBox.PlaceholderText" xml:space="preserve">
<value>For example http://localhost:23333</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve"> <data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>Default</value> <value>Default</value>
</data> </data>
@@ -237,6 +243,9 @@
<data name="LyricsPageCachePath.Value" xml:space="preserve"> <data name="LyricsPageCachePath.Value" xml:space="preserve">
<value>Cache path</value> <value>Cache path</value>
</data> </data>
<data name="LyricsPageLanguageCode.Header" xml:space="preserve">
<value>Lyric language</value>
</data>
<data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve"> <data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve">
<value>Lyrics provider</value> <value>Lyrics provider</value>
</data> </data>
@@ -762,6 +771,9 @@
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve"> <data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>Current lyrics window status</value> <value>Current lyrics window status</value>
</data> </data>
<data name="SettingsPageCutletDockerServer.Header" xml:space="preserve">
<value>cutlet-docker transliteration service</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve"> <data name="SettingsPageDark.Content" xml:space="preserve">
<value>Dark</value> <value>Dark</value>
</data> </data>
@@ -957,6 +969,9 @@
<data name="SettingsPageJA.Content" xml:space="preserve"> <data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value> <value>日本語</value>
</data> </data>
<data name="SettingsPageJapanese.Description" xml:space="preserve">
<value>The transliteration of the lyrics will be read first, and if there is no match, the machine transliteration will be requested from the cutlet-docker server</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve"> <data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>Japanese annotation</value> <value>Japanese annotation</value>
</data> </data>
@@ -1080,6 +1095,12 @@
<data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve"> <data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve">
<value>Extra Light</value> <value>Extra Light</value>
</data> </data>
<data name="SettingsPageLyricsFadeOutEffect.Description" xml:space="preserve">
<value>Enable fade effect for non-current rows</value>
</data>
<data name="SettingsPageLyricsFadeOutEffect.Header" xml:space="preserve">
<value>Fadeout effect</value>
</data>
<data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve"> <data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve">
<value>Current Play Row</value> <value>Current Play Row</value>
</data> </data>
@@ -1149,6 +1170,12 @@
<data name="SettingsPageLyricsOpacity.Header" xml:space="preserve"> <data name="SettingsPageLyricsOpacity.Header" xml:space="preserve">
<value>Font opacity</value> <value>Font opacity</value>
</data> </data>
<data name="SettingsPageLyricsOutOfSightEffect.Description" xml:space="preserve">
<value>Gradually move non-current rows out of view</value>
</data>
<data name="SettingsPageLyricsOutOfSightEffect.Header" xml:space="preserve">
<value>Stay out of sight</value>
</data>
<data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve"> <data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve">
<value>Lyrics area height factor</value> <value>Lyrics area height factor</value>
</data> </data>

View File

@@ -150,6 +150,12 @@
<data name="CreatePlaylistSuccessfully" xml:space="preserve"> <data name="CreatePlaylistSuccessfully" xml:space="preserve">
<value>正常に作成されました</value> <value>正常に作成されました</value>
</data> </data>
<data name="CutletDockerFailed" xml:space="preserve">
<value>cutlet - dockerからの音訳のリクエストに失敗しました。設定またはネイティブのcutlet - docker設定を確認してください</value>
</data>
<data name="CutletServerTextBox.PlaceholderText" xml:space="preserve">
<value>たとえば、http://localhost:23333</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve"> <data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>デフォルト</value> <value>デフォルト</value>
</data> </data>
@@ -237,6 +243,9 @@
<data name="LyricsPageCachePath.Value" xml:space="preserve"> <data name="LyricsPageCachePath.Value" xml:space="preserve">
<value>キャッシュパス</value> <value>キャッシュパス</value>
</data> </data>
<data name="LyricsPageLanguageCode.Header" xml:space="preserve">
<value>リリックランゲージ</value>
</data>
<data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve"> <data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve">
<value>歌詞プロバイダー</value> <value>歌詞プロバイダー</value>
</data> </data>
@@ -762,6 +771,9 @@
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve"> <data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>現在の歌詞ウィンドウステータス</value> <value>現在の歌詞ウィンドウステータス</value>
</data> </data>
<data name="SettingsPageCutletDockerServer.Header" xml:space="preserve">
<value>cutlet-docker 音声翻訳サービス</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve"> <data name="SettingsPageDark.Content" xml:space="preserve">
<value>暗い</value> <value>暗い</value>
</data> </data>
@@ -957,6 +969,9 @@
<data name="SettingsPageJA.Content" xml:space="preserve"> <data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value> <value>日本語</value>
</data> </data>
<data name="SettingsPageJapanese.Description" xml:space="preserve">
<value>歌詞の音訳が最初に読み込まれ、一致しない場合は機械音訳がcutlet - dockerサーバーから要求されます</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve"> <data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>日本の注釈</value> <value>日本の注釈</value>
</data> </data>
@@ -1039,7 +1054,7 @@
<value>LX Music Server</value> <value>LX Music Server</value>
</data> </data>
<data name="SettingsPageLXMusicServerInput.PlaceholderText" xml:space="preserve"> <data name="SettingsPageLXMusicServerInput.PlaceholderText" xml:space="preserve">
<value>例http://127.0.0.1: 23330</value> <value>例http://127.0.0.1:23330</value>
</data> </data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve"> <data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
<value>アライメント</value> <value>アライメント</value>
@@ -1080,6 +1095,12 @@
<data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve"> <data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve">
<value>余分な光</value> <value>余分な光</value>
</data> </data>
<data name="SettingsPageLyricsFadeOutEffect.Description" xml:space="preserve">
<value>非現在の行にフェード効果を有効にします</value>
</data>
<data name="SettingsPageLyricsFadeOutEffect.Header" xml:space="preserve">
<value>フェード効果</value>
</data>
<data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve"> <data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve">
<value>現在のプレイ行</value> <value>現在のプレイ行</value>
</data> </data>
@@ -1149,6 +1170,12 @@
<data name="SettingsPageLyricsOpacity.Header" xml:space="preserve"> <data name="SettingsPageLyricsOpacity.Header" xml:space="preserve">
<value>フォントの不透明度</value> <value>フォントの不透明度</value>
</data> </data>
<data name="SettingsPageLyricsOutOfSightEffect.Description" xml:space="preserve">
<value>現在ではない行を徐々に外に移動してください</value>
</data>
<data name="SettingsPageLyricsOutOfSightEffect.Header" xml:space="preserve">
<value>目につかないように</value>
</data>
<data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve"> <data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve">
<value>歌詞エリアの高さ係数</value> <value>歌詞エリアの高さ係数</value>
</data> </data>

View File

@@ -150,6 +150,12 @@
<data name="CreatePlaylistSuccessfully" xml:space="preserve"> <data name="CreatePlaylistSuccessfully" xml:space="preserve">
<value>재생 목록이 성공적으로 생성되었습니다</value> <value>재생 목록이 성공적으로 생성되었습니다</value>
</data> </data>
<data name="CutletDockerFailed" xml:space="preserve">
<value>커틀릿 도커에서 음역을 요청하지 못했습니다. 설정 또는 기본 커틀릿 도커 구성을 확인하십시오</value>
</data>
<data name="CutletServerTextBox.PlaceholderText" xml:space="preserve">
<value>예: http://localhost:23333</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve"> <data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>기본</value> <value>기본</value>
</data> </data>
@@ -237,6 +243,9 @@
<data name="LyricsPageCachePath.Value" xml:space="preserve"> <data name="LyricsPageCachePath.Value" xml:space="preserve">
<value>캐시</value> <value>캐시</value>
</data> </data>
<data name="LyricsPageLanguageCode.Header" xml:space="preserve">
<value>가사 언어</value>
</data>
<data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve"> <data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve">
<value>가사 제공자</value> <value>가사 제공자</value>
</data> </data>
@@ -762,6 +771,9 @@
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve"> <data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>현재 가사 창 상태</value> <value>현재 가사 창 상태</value>
</data> </data>
<data name="SettingsPageCutletDockerServer.Header" xml:space="preserve">
<value>커틀릿 도커 음역 서비스</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve"> <data name="SettingsPageDark.Content" xml:space="preserve">
<value>어두운</value> <value>어두운</value>
</data> </data>
@@ -957,6 +969,9 @@
<data name="SettingsPageJA.Content" xml:space="preserve"> <data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value> <value>日本語</value>
</data> </data>
<data name="SettingsPageJapanese.Description" xml:space="preserve">
<value>가사의 음역이 먼저 읽히고 일치하지 않으면 커틀릿 도커 서버에서 기계 음역이 요청됩니다</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve"> <data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>일본 주석</value> <value>일본 주석</value>
</data> </data>
@@ -1039,7 +1054,7 @@
<value>LX 음악 서버</value> <value>LX 음악 서버</value>
</data> </data>
<data name="SettingsPageLXMusicServerInput.PlaceholderText" xml:space="preserve"> <data name="SettingsPageLXMusicServerInput.PlaceholderText" xml:space="preserve">
<value>예: http://127.0.0.1: 23330</value> <value>예: http://127.0.0.1:23330</value>
</data> </data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve"> <data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
<value>조정</value> <value>조정</value>
@@ -1080,6 +1095,12 @@
<data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve"> <data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve">
<value>여분의 빛</value> <value>여분의 빛</value>
</data> </data>
<data name="SettingsPageLyricsFadeOutEffect.Description" xml:space="preserve">
<value>비전류 행에 페이드 효과 활성화</value>
</data>
<data name="SettingsPageLyricsFadeOutEffect.Header" xml:space="preserve">
<value>페이드 효과</value>
</data>
<data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve"> <data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve">
<value>현재 플레이 행</value> <value>현재 플레이 행</value>
</data> </data>
@@ -1149,6 +1170,12 @@
<data name="SettingsPageLyricsOpacity.Header" xml:space="preserve"> <data name="SettingsPageLyricsOpacity.Header" xml:space="preserve">
<value>글꼴 불투명도</value> <value>글꼴 불투명도</value>
</data> </data>
<data name="SettingsPageLyricsOutOfSightEffect.Description" xml:space="preserve">
<value>현재 행이 아닌 행을 점진적으로 보이지 않게 이동합니다</value>
</data>
<data name="SettingsPageLyricsOutOfSightEffect.Header" xml:space="preserve">
<value>눈에 띄지 마세요</value>
</data>
<data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve"> <data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve">
<value>가사 영역 높이 계수</value> <value>가사 영역 높이 계수</value>
</data> </data>

View File

@@ -150,6 +150,12 @@
<data name="CreatePlaylistSuccessfully" xml:space="preserve"> <data name="CreatePlaylistSuccessfully" xml:space="preserve">
<value>播放列表创建成功</value> <value>播放列表创建成功</value>
</data> </data>
<data name="CutletDockerFailed" xml:space="preserve">
<value>向 cutlet-docker 请求音译失败,请检查设置或本机 cutlet-docker 配置</value>
</data>
<data name="CutletServerTextBox.PlaceholderText" xml:space="preserve">
<value>例如 http://localhost:23333</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve"> <data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>默认</value> <value>默认</value>
</data> </data>
@@ -237,6 +243,9 @@
<data name="LyricsPageCachePath.Value" xml:space="preserve"> <data name="LyricsPageCachePath.Value" xml:space="preserve">
<value>缓存路径</value> <value>缓存路径</value>
</data> </data>
<data name="LyricsPageLanguageCode.Header" xml:space="preserve">
<value>歌词语言</value>
</data>
<data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve"> <data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve">
<value>歌词来源</value> <value>歌词来源</value>
</data> </data>
@@ -762,6 +771,9 @@
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve"> <data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>当前歌词窗口状态</value> <value>当前歌词窗口状态</value>
</data> </data>
<data name="SettingsPageCutletDockerServer.Header" xml:space="preserve">
<value>cutlet-docker 音译服务</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve"> <data name="SettingsPageDark.Content" xml:space="preserve">
<value>深色</value> <value>深色</value>
</data> </data>
@@ -957,6 +969,9 @@
<data name="SettingsPageJA.Content" xml:space="preserve"> <data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value> <value>日本語</value>
</data> </data>
<data name="SettingsPageJapanese.Description" xml:space="preserve">
<value>将优先读取歌词内音译,若无匹配则向 cutlet-docker 服务器请求机器音译</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve"> <data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>日语注音</value> <value>日语注音</value>
</data> </data>
@@ -1039,7 +1054,7 @@
<value>LX 音乐服务器</value> <value>LX 音乐服务器</value>
</data> </data>
<data name="SettingsPageLXMusicServerInput.PlaceholderText" xml:space="preserve"> <data name="SettingsPageLXMusicServerInput.PlaceholderText" xml:space="preserve">
<value>例如 http://127.0.0.1: 23330</value> <value>例如 http://127.0.0.1:23330</value>
</data> </data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve"> <data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
<value>对齐方式</value> <value>对齐方式</value>
@@ -1080,6 +1095,12 @@
<data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve"> <data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve">
<value>超细</value> <value>超细</value>
</data> </data>
<data name="SettingsPageLyricsFadeOutEffect.Description" xml:space="preserve">
<value>为非当前行启用淡出效果</value>
</data>
<data name="SettingsPageLyricsFadeOutEffect.Header" xml:space="preserve">
<value>淡出效果</value>
</data>
<data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve"> <data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve">
<value>当前播放行</value> <value>当前播放行</value>
</data> </data>
@@ -1149,6 +1170,12 @@
<data name="SettingsPageLyricsOpacity.Header" xml:space="preserve"> <data name="SettingsPageLyricsOpacity.Header" xml:space="preserve">
<value>字体不透明度</value> <value>字体不透明度</value>
</data> </data>
<data name="SettingsPageLyricsOutOfSightEffect.Description" xml:space="preserve">
<value>使非当前行逐渐远离视野</value>
</data>
<data name="SettingsPageLyricsOutOfSightEffect.Header" xml:space="preserve">
<value>远离视野</value>
</data>
<data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve"> <data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve">
<value>歌词区域高度因子</value> <value>歌词区域高度因子</value>
</data> </data>

View File

@@ -150,6 +150,12 @@
<data name="CreatePlaylistSuccessfully" xml:space="preserve"> <data name="CreatePlaylistSuccessfully" xml:space="preserve">
<value>已成功建立播放清單</value> <value>已成功建立播放清單</value>
</data> </data>
<data name="CutletDockerFailed" xml:space="preserve">
<value>向 cutlet-docker 請求音譯失敗,請檢查設定或本機 cutlet-docker 設定</value>
</data>
<data name="CutletServerTextBox.PlaceholderText" xml:space="preserve">
<value>例如 http://localhost:23333</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve"> <data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>預設</value> <value>預設</value>
</data> </data>
@@ -237,6 +243,9 @@
<data name="LyricsPageCachePath.Value" xml:space="preserve"> <data name="LyricsPageCachePath.Value" xml:space="preserve">
<value>檔案路徑緩存</value> <value>檔案路徑緩存</value>
</data> </data>
<data name="LyricsPageLanguageCode.Header" xml:space="preserve">
<value>歌詞語言</value>
</data>
<data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve"> <data name="LyricsPageLyricsProviderPrefix.Header" xml:space="preserve">
<value>歌詞來源</value> <value>歌詞來源</value>
</data> </data>
@@ -762,6 +771,9 @@
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve"> <data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>當前歌詞窗口狀態</value> <value>當前歌詞窗口狀態</value>
</data> </data>
<data name="SettingsPageCutletDockerServer.Header" xml:space="preserve">
<value>cutlet-docker 音譯服務</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve"> <data name="SettingsPageDark.Content" xml:space="preserve">
<value>深色</value> <value>深色</value>
</data> </data>
@@ -957,6 +969,9 @@
<data name="SettingsPageJA.Content" xml:space="preserve"> <data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value> <value>日本語</value>
</data> </data>
<data name="SettingsPageJapanese.Description" xml:space="preserve">
<value>將優先讀取歌詞內音譯,若無匹配則向 cutlet-docker 伺服器請求機器音譯</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve"> <data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>日語注音</value> <value>日語注音</value>
</data> </data>
@@ -1039,7 +1054,7 @@
<value>LX 音樂服務器</value> <value>LX 音樂服務器</value>
</data> </data>
<data name="SettingsPageLXMusicServerInput.PlaceholderText" xml:space="preserve"> <data name="SettingsPageLXMusicServerInput.PlaceholderText" xml:space="preserve">
<value>例如 http://127.0.0.1: 23330</value> <value>例如 http://127.0.0.1:23330</value>
</data> </data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve"> <data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
<value>對齊方式</value> <value>對齊方式</value>
@@ -1080,6 +1095,12 @@
<data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve"> <data name="SettingsPageLyricsExtraLight.Content" xml:space="preserve">
<value>超細</value> <value>超細</value>
</data> </data>
<data name="SettingsPageLyricsFadeOutEffect.Description" xml:space="preserve">
<value>為非目前行啟用淡出效果</value>
</data>
<data name="SettingsPageLyricsFadeOutEffect.Header" xml:space="preserve">
<value>淡出效果</value>
</data>
<data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve"> <data name="SettingsPageLyricsFgFontColor.Header" xml:space="preserve">
<value>目前播放行</value> <value>目前播放行</value>
</data> </data>
@@ -1149,6 +1170,12 @@
<data name="SettingsPageLyricsOpacity.Header" xml:space="preserve"> <data name="SettingsPageLyricsOpacity.Header" xml:space="preserve">
<value>字體不透明度</value> <value>字體不透明度</value>
</data> </data>
<data name="SettingsPageLyricsOutOfSightEffect.Description" xml:space="preserve">
<value>使非當前行逐漸遠離視野</value>
</data>
<data name="SettingsPageLyricsOutOfSightEffect.Header" xml:space="preserve">
<value>遠離視野</value>
</data>
<data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve"> <data name="SettingsPageLyricsRowFactor.Header" xml:space="preserve">
<value>歌詞區域高度因子</value> <value>歌詞區域高度因子</value>
</data> </data>

View File

@@ -5,7 +5,8 @@ using BetterLyrics.WinUI3.Services.LastFMService;
using BetterLyrics.WinUI3.Services.MediaSessionsService; using BetterLyrics.WinUI3.Services.MediaSessionsService;
using BetterLyrics.WinUI3.Services.ResourceService; using BetterLyrics.WinUI3.Services.ResourceService;
using BetterLyrics.WinUI3.Services.SettingsService; using BetterLyrics.WinUI3.Services.SettingsService;
using BetterLyrics.WinUI3.Services.TranslateService; using BetterLyrics.WinUI3.Services.TranslationService;
using BetterLyrics.WinUI3.Services.TransliterationService;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Hqub.Lastfm.Entities; using Hqub.Lastfm.Entities;
@@ -20,10 +21,10 @@ namespace BetterLyrics.WinUI3.ViewModels
public partial class PlaybackSettingsControlViewModel : BaseViewModel public partial class PlaybackSettingsControlViewModel : BaseViewModel
{ {
public IMediaSessionsService MediaSessionsService; public IMediaSessionsService MediaSessionsService;
private readonly ITranslateService _libreTranslateService; private readonly ITranslationService _translationService;
private readonly ILastFMService _lastFMService; private readonly ILastFMService _lastFMService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly IResourceService _resourceService; private readonly ITransliterationService _transliterationService;
[ObservableProperty] [ObservableProperty]
public partial AppSettings AppSettings { get; set; } public partial AppSettings AppSettings { get; set; }
@@ -40,6 +41,9 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty] [ObservableProperty]
public partial bool IsLibreTranslateServerTesting { get; set; } = false; public partial bool IsLibreTranslateServerTesting { get; set; } = false;
[ObservableProperty]
public partial bool IsCutletDockerServerTesting { get; set; } = false;
[ObservableProperty] [ObservableProperty]
public partial bool IsLXMusicServerTesting { get; set; } = false; public partial bool IsLXMusicServerTesting { get; set; } = false;
@@ -52,15 +56,15 @@ namespace BetterLyrics.WinUI3.ViewModels
public PlaybackSettingsControlViewModel( public PlaybackSettingsControlViewModel(
ISettingsService settingsService, ISettingsService settingsService,
IMediaSessionsService mediaSessionsService, IMediaSessionsService mediaSessionsService,
ITranslateService libreTranslateService, ITranslationService libreTranslationService,
ILastFMService lastFMService, ILastFMService lastFMService,
IResourceService resourceService) ITransliterationService transliterationService)
{ {
MediaSessionsService = mediaSessionsService; MediaSessionsService = mediaSessionsService;
_settingsService = settingsService; _settingsService = settingsService;
_libreTranslateService = libreTranslateService; _translationService = libreTranslationService;
_resourceService = resourceService; _transliterationService = transliterationService;
_lastFMService = lastFMService; _lastFMService = lastFMService;
_lastFMService.UserChanged += LastFMService_UserChanged; _lastFMService.UserChanged += LastFMService_UserChanged;
@@ -107,7 +111,7 @@ namespace BetterLyrics.WinUI3.ViewModels
{ {
try try
{ {
string result = await _libreTranslateService.TranslateTextAsync( string result = await _translationService.TranslateTextAsync(
"Hello, world!", AppSettings.TranslationSettings.SelectedTargetLanguageCode, new System.Threading.CancellationToken()); "Hello, world!", AppSettings.TranslationSettings.SelectedTargetLanguageCode, new System.Threading.CancellationToken());
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () => _dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
{ {
@@ -128,6 +132,35 @@ namespace BetterLyrics.WinUI3.ViewModels
}); });
} }
[RelayCommand]
private void CutletDockerServerTest()
{
IsCutletDockerServerTesting = true;
Task.Run(async () =>
{
try
{
string result = await _transliterationService.TransliterateText(
"こんにちは", PhoneticHelper.RomanCode, new System.Threading.CancellationToken());
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
{
ToastHelper.ShowToast("SettingsPageServerTestSuccessInfo", null, InfoBarSeverity.Success);
});
}
catch (Exception)
{
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
{
ToastHelper.ShowToast("SettingsPageServerTestFailedInfo", null, InfoBarSeverity.Error);
});
}
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
{
IsCutletDockerServerTesting = false;
});
});
}
[RelayCommand] [RelayCommand]
private async Task LastFMAuthAsync() private async Task LastFMAuthAsync()
{ {
@@ -171,6 +204,7 @@ namespace BetterLyrics.WinUI3.ViewModels
[RelayCommand] [RelayCommand]
private void SaveAppleMusicMediaUserToken() private void SaveAppleMusicMediaUserToken()
{ {
PasswordVaultHelper.Delete(Constants.App.AppName, Constants.AppleMusic.MediaUserTokenKey);
PasswordVaultHelper.Save(Constants.App.AppName, Constants.AppleMusic.MediaUserTokenKey, AppleMusicMediaUserToken); PasswordVaultHelper.Save(Constants.App.AppName, Constants.AppleMusic.MediaUserTokenKey, AppleMusicMediaUserToken);
MediaSessionsService.UpdateLyrics(); MediaSessionsService.UpdateLyrics();
} }