Compare commits

...

18 Commits

Author SHA1 Message Date
Zhe Fang
37a7528762 更新 FAQ.md 2025-08-25 08:56:13 -04:00
Zhe Fang
3ca391a509 更新 FAQ.md 2025-08-25 08:54:43 -04:00
Zhe Fang
f5e542d2f3 更新 How2Install.md 2025-08-25 08:53:10 -04:00
Zhe Fang
107bdf8bee 更新 README.md 2025-08-25 08:51:19 -04:00
Zhe Fang
3e9e56f5cc ignore ttml x-roman span 2025-08-25 07:12:24 -04:00
Zhe Fang
b0fd43ead5 fix input issue in search panel; fix display issue in lyrics window manager 2025-08-24 16:29:28 -04:00
Zhe Fang
81c59495c0 improvement 2025-08-23 21:12:57 -04:00
Zhe Fang
7c5f1a804e Merge branch 'dev' of https://github.com/jayfunc/BetterLyrics into dev 2025-08-23 18:09:14 -04:00
Zhe Fang
13ee4227f7 fix #101 fix #100 2025-08-23 18:09:12 -04:00
Zhe Fang
c1360ac972 更新 README.md 2025-08-22 17:48:53 -04:00
Zhe Fang
c72aa8a58f 更新 FAQ.md 2025-08-22 15:33:46 -04:00
Zhe Fang
9545ed610b update readme 2025-08-22 15:26:51 -04:00
Zhe Fang
1c4515acb9 update readme 2025-08-22 15:18:40 -04:00
Zhe Fang
92a6fe46de update docs 2025-08-22 15:00:57 -04:00
Zhe Fang
2f9fa02214 Merge branch 'dev' of https://github.com/jayfunc/BetterLyrics into dev 2025-08-21 17:56:24 -04:00
Zhe Fang
c174363c07 fix #99 ;add thumb for timeline slider; add margin for top command area 2025-08-21 17:56:13 -04:00
Zhe Fang
8506062c9a Update FUNDING.yml 2025-08-21 13:19:24 -04:00
Zhe Fang
52711cba1f showing ordered system font family list; fix issue that timeline change can not be invoked sometimes; add jump to specific lyrics line when clikcing in searching flyout 2025-08-21 11:01:39 -04:00
103 changed files with 1851 additions and 1912 deletions

2
.github/FUNDING.yml vendored
View File

@@ -12,4 +12,4 @@ lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cl
polar: # Replace with a single Polar username
buy_me_a_coffee: founchoo
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
custom: ['https://paypal.me/zhefangpay']

View File

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

View File

@@ -58,6 +58,7 @@
<converter:ShortcutToStringConverter x:Key="ShortcutToStringConverter" />
<converter:BoolNegationToVisibilityConverter x:Key="BoolNegationToVisibilityConverter" />
<converter:BoolToOpacityConverter x:Key="BoolToOpacityConverter" />
<converter:RectToMarginConverter x:Key="RectToMarginConverter" />
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

View File

@@ -32,6 +32,7 @@
<None Remove="Controls\PlaybackSettingsControl.xaml" />
<None Remove="Controls\ShortcutTextBox.xaml" />
<None Remove="Controls\SystemTray.xaml" />
<None Remove="Views\LyricsSearchWindow.xaml" />
<None Remove="Views\MusicGalleryPage.xaml" />
<None Remove="Views\MusicGalleryWindow.xaml" />
<None Remove="Views\SettingsWindow.xaml" />
@@ -59,6 +60,7 @@
<PackageReference Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
<PackageReference Include="CommunityToolkit.WinUI.Helpers" Version="8.2.250402" />
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" />
<PackageReference Include="csharp-pinyin" Version="1.0.1" />
<PackageReference Include="Dubya.WindowsMediaController" Version="2.5.5" />
<PackageReference Include="H.NotifyIcon.WinUI" Version="2.3.0" />
<PackageReference Include="Hqub.Last.fm" Version="2.5.1" />
@@ -71,6 +73,7 @@
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
<PackageReference Include="NTextCat" Version="0.3.65" />
<PackageReference Include="RomajiConverter.Core" Version="1.0.9" />
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.3-dev-02320" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="ShadowViewer.Controls.Notification" Version="1.2.1" />
@@ -112,9 +115,6 @@
<Content Update="Assets\Chrome.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Discord.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Edge.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@@ -166,9 +166,6 @@
<Content Update="Assets\PotPlayer.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\QQ.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\QQMusic.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@@ -181,13 +178,15 @@
<Content Update="Assets\Spotify.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Telegram.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Wiki82.profile.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Page Update="Views\LyricsSearchWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\LyricsSearchControl.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@@ -8,7 +8,8 @@ namespace BetterLyrics.WinUI3.Constants
{
public static class Link
{
public const string GithubUrl = "https://github.com/jayfunc/BetterLyrics";
public const string GitHubUrl = "https://github.com/jayfunc/BetterLyrics";
public const string FAQUrl = $"{GitHubUrl}/blob/dev/FAQ/FAQ.md";
public const string QQGroupUrl = "https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info";
public const string DiscordUrl = "https://discord.gg/5yAQPnyCKv";
public const string TelegramUrl = "https://t.me/+svhSLZ7awPsxNGY1";

View File

@@ -17,6 +17,7 @@ namespace BetterLyrics.WinUI3.Constants
public const string PotPlayer = "PotPlayerMini64.exe";
public const string Spotify = "Spotify.exe";
public const string AppleMusic = "AppleInc.AppleMusicWin_nzyj5cx40ttqa!App";
public const string AppleMusicAlternative = "AppleMusic.exe";
public const string NetEaseCloudMusic = "cloudmusic.exe";
public const string KugouMusic = "kugou";
public const string QQMusic = "QQMusic.exe";

View File

@@ -16,6 +16,7 @@ namespace BetterLyrics.WinUI3.Constants
public const string PotPlayer = "PotPlayer";
public const string Spotify = "Spotify";
public const string AppleMusic = "Apple Music";
public const string AppleMusicAlternative = "Apple Music";
public const string NetEaseCloudMusic = "网易云音乐";
public const string KugouMusic = "酷狗音乐";
public const string QQMusic = "QQ 音乐";

View File

@@ -46,6 +46,15 @@
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLyricsFontSize" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE8E9;}">
<local:ExtendedSlider
Default="18"
Frequency="2"
Maximum="48"
Minimum="12"
Value="{x:Bind ViewModel.AppSettings.AlbumArtLayoutSettings.SongInfoFontSize, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>

View File

@@ -11,185 +11,375 @@
mc:Ignorable="d">
<Grid>
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<controls:SwitchPresenter Margin="0,72,0,0" Value="{Binding SelectedItem.Tag, ElementName=SegmentedControl}">
<!-- App appearance -->
<controls:Case Value="General">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<TextBlock x:Uid="SettingsPageAppAppearance" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<!-- App appearance -->
<controls:SettingsExpander
x:Uid="SettingsPageLanguage"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xF2B7;}"
IsExpanded="True">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.Language, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageSystemLanguage" />
<ComboBoxItem x:Uid="SettingsPageEN" />
<ComboBoxItem x:Uid="SettingsPageSC" />
<ComboBoxItem x:Uid="SettingsPageTC" />
<ComboBoxItem x:Uid="SettingsPageJA" />
<ComboBoxItem x:Uid="SettingsPageKO" />
</ComboBox>
<controls:SettingsExpander.Items>
<controls:SettingsCard>
<Button x:Uid="SettingsPageRestart" Command="{x:Bind ViewModel.RestartAppCommand}" />
<TextBlock x:Uid="SettingsPageAppAppearance" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsExpander
x:Uid="SettingsPageLanguage"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xF2B7;}"
IsExpanded="True">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.Language, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageSystemLanguage" />
<ComboBoxItem x:Uid="SettingsPageEN" />
<ComboBoxItem x:Uid="SettingsPageSC" />
<ComboBoxItem x:Uid="SettingsPageTC" />
<ComboBoxItem x:Uid="SettingsPageJA" />
<ComboBoxItem x:Uid="SettingsPageKO" />
</ComboBox>
<controls:SettingsExpander.Items>
<controls:SettingsCard>
<Button x:Uid="SettingsPageRestart" Command="{x:Bind ViewModel.RestartAppCommand}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- App behavior -->
<TextBlock x:Uid="SettingsPageAppBehavior" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageAutoStart" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF71C;}">
<ToggleSwitch
x:Name="AutoStartupToggleSwitch"
Loaded="AutoStartupToggleSwitch_Loaded"
Unloaded="AutoStartupToggleSwitch_Unloaded" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- App behavior -->
<controls:SettingsCard x:Uid="SettingsPageAutoStartWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE736;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.AutoStartWindowType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageAutoStartInAppLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartDockLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartDesktopLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartPIPLyrics" />
</ComboBox>
</controls:SettingsCard>
<TextBlock x:Uid="SettingsPageAppBehavior" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsExpander
x:Name="LyricsWindowManagerExpander"
x:Uid="SettingsPageLyricsWindowManager"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE61F;}"
IsExpanded="True" />
<controls:SettingsCard x:Uid="SettingsPageAutoStart" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF71C;}">
<ToggleSwitch
x:Name="AutoStartupToggleSwitch"
Loaded="AutoStartupToggleSwitch_Loaded"
Unloaded="AutoStartupToggleSwitch_Unloaded" />
</controls:SettingsCard>
<Grid
Margin="0,-20,0,0"
Padding="60,16"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="4"
Visibility="{Binding ElementName=LyricsWindowManagerExpander, Path=IsExpanded, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<StackPanel Spacing="16">
<TextBlock x:Uid="SettingsPageCurrentLyricsWindowStatus" />
<StackPanel HorizontalAlignment="Left" Spacing="4">
<Grid
Width="{x:Bind ViewModel.LiveStates.DemoLyricsWindowMonitorBounds.Width, Mode=OneWay}"
Height="{x:Bind ViewModel.LiveStates.DemoLyricsWindowMonitorBounds.Height, Mode=OneWay}"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
<Grid
Width="{x:Bind ViewModel.LiveStates.DemoLyricsWindowBounds.Width, Mode=OneWay}"
Height="{x:Bind ViewModel.LiveStates.DemoLyricsWindowBounds.Height, Mode=OneWay}"
Margin="{x:Bind ViewModel.LiveStates.DemoLyricsWindowBounds, Converter={StaticResource RectToMarginConverter}, Mode=OneWay}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="4" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="ExtraBlack"
Opacity="0.7"
Text="{x:Bind ViewModel.LiveStates.LyricsWindowMonitorName, Mode=OneWay}"
TextWrapping="Wrap" />
</Grid>
<Grid>
<Button
x:Uid="SettingsPageRecord"
HorizontalAlignment="Stretch"
Command="{x:Bind ViewModel.RecordCurrentWindowBoundsCommand}"
Style="{StaticResource AccentButtonStyle}" />
</Grid>
</StackPanel>
</StackPanel>
</Grid>
<controls:SettingsCard x:Uid="SettingsPageAutoStartWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE736;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.AutoStartWindowType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageAutoStartInAppLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartDockLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartDesktopLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartPIPLyrics" />
</ComboBox>
</controls:SettingsCard>
<StackPanel
Margin="0,-3,0,0"
Padding="60,16"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="4"
Spacing="16"
Visibility="{Binding ElementName=LyricsWindowManagerExpander, Path=IsExpanded, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<TextBlock x:Uid="SettingsPageRecordedWindowStatus" />
<GridView
Margin="-2"
CornerRadius="4"
ItemsSource="{x:Bind ViewModel.AppSettings.WindowBoundsRecords, Mode=OneWay}"
SelectionMode="None">
<GridView.ItemContainerStyle>
<Style BasedOn="{StaticResource DefaultGridViewItemStyle}" TargetType="GridViewItem">
<Setter Property="Margin" Value="5,5,5,5" />
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Spacing="4">
<Grid
Width="{Binding DemoMonitorBounds.Width}"
Height="{Binding DemoMonitorBounds.Height}"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
<Grid
Width="{Binding DemoWindowBounds.Width}"
Height="{Binding DemoWindowBounds.Height}"
Margin="{Binding DemoWindowBounds, Converter={StaticResource RectToMarginConverter}}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="4" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="ExtraBlack"
Opacity="0.7"
Text="{Binding MonitorDeviceName}"
TextWrapping="Wrap" />
</Grid>
<Grid ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
x:Uid="SettingsPageDelete"
Grid.Column="0"
HorizontalAlignment="Stretch"
Click="DeleteWindowBoundsRecordButton_Click" />
<Button
x:Uid="SettingsPageApply"
Grid.Column="1"
HorizontalAlignment="Stretch"
Click="ApplyWindowBoundsRecordButton_Click"
Style="{StaticResource AccentButtonStyle}" />
</Grid>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</StackPanel>
<controls:SettingsCard x:Uid="SettingsPageIgnoreFullscreenWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE967;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IgnoreFullscreenWindow, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageIgnoreFullscreenWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE967;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IgnoreFullscreenWindow, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageHideWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xED1A;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.HideWindowWhenNotPlaying, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageHideWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xED1A;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.HideWindowWhenNotPlaying, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageGlobalDrag" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7C2;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IsDragEverywhereEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageShowHideHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.ShowOrHideLyricsWindowShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageExitOnLyricsWindowClosed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7E8;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ExitOnLyricsWindowClosed, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageGlobalDrag" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7C2;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IsDragEverywhereEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Standard mode -->
<controls:SettingsCard x:Uid="SettingsPageExitOnLyricsWindowClosed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7E8;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ExitOnLyricsWindowClosed, Mode=TwoWay}" />
</controls:SettingsCard>
<TextBlock x:Uid="SettingsPageAppStandard" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<!-- Playback shortcut -->
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.StandardModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<TextBlock x:Uid="SettingsPagePlaybackShortcut" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<!-- Desktop mode -->
<controls:SettingsCard x:Uid="SettingsPagePlayOrPauseSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PlayOrPauseShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<TextBlock x:Uid="SettingsPageAppDesktop" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageNextSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.NextSongShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DesktopModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPagePreviousSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PreviousSongShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DesktopModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageAutoLock" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE755;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.DesktopModeSettings.AutoLockOnDesktopMode, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLockHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DesktopModeSettings.LockShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Dock mode -->
<TextBlock x:Uid="SettingsPageAppDock" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DockModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DockModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDockMonitor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7F4;}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ComboBox ItemsSource="{x:Bind ViewModel.MonitorDeviceNames, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.AppSettings.DockModeSettings.DockMonitorDeviceName, Mode=TwoWay}" />
<Button
Command="{x:Bind ViewModel.RefreshMonitorDeviceNamesCommand}"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE72C;}"
Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</controls:SettingsCard>
</Grid>
</ScrollViewer>
<controls:SettingsCard x:Uid="SettingsPageDockWindowHeight" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xED5E;}">
<local:ExtendedSlider
Default="64"
Frequency="1"
Maximum="200"
Minimum="64"
Unit="px"
Value="{x:Bind ViewModel.AppSettings.DockModeSettings.DockWindowHeight, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:Case>
<controls:SettingsCard x:Uid="SettingsPageDockPlacement" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE8E3;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DockModeSettings.DockPlacement, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageDockPlacementTop" />
<ComboBoxItem x:Uid="SettingsPageDockPlacementBottom" />
</ComboBox>
</controls:SettingsCard>
<controls:Case Value="Standard">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- Picture in picture mode -->
<!-- Standard mode -->
<TextBlock x:Uid="SettingsPageAppPictureInPicture" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.PictureInPictureModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.StandardModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.PictureInPictureModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageAOT" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE718;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.StandardModeSettings.IsAlwaysOnTop, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Playback shortcut -->
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
<TextBlock x:Uid="SettingsPagePlaybackShortcut" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:Case Value="Desktop">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<controls:SettingsCard x:Uid="SettingsPagePlayOrPauseSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PlayOrPauseShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Desktop mode -->
<controls:SettingsCard x:Uid="SettingsPageNextSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.NextSongShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPagePreviousSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PreviousSongShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DesktopModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageAOT" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE718;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.DesktopModeSettings.IsAlwaysOnTop, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DesktopModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageAutoLock" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE755;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.DesktopModeSettings.AutoLockOnDesktopMode, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLockHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DesktopModeSettings.LockShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
<controls:Case Value="Dock">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- Dock mode -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DockModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DockModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDockMonitor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7F4;}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ComboBox ItemsSource="{x:Bind ViewModel.MonitorDeviceNames, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.AppSettings.DockModeSettings.DockMonitorDeviceName, Mode=TwoWay}" />
<Button
Command="{x:Bind ViewModel.RefreshMonitorDeviceNamesCommand}"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE72C;}"
Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDockWindowHeight" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xED5E;}">
<local:ExtendedSlider
Default="64"
Frequency="1"
Maximum="200"
Minimum="64"
Unit="px"
Value="{x:Bind ViewModel.AppSettings.DockModeSettings.DockWindowHeight, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDockPlacement" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE8E3;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DockModeSettings.DockPlacement, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageDockPlacementTop" />
<ComboBoxItem x:Uid="SettingsPageDockPlacementBottom" />
</ComboBox>
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
<controls:Case Value="PictureInPicture">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- Picture in picture mode -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.PictureInPictureModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.PictureInPictureModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
</controls:SwitchPresenter>
<controls:Segmented
x:Name="SegmentedControl"
Margin="36,36,36,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
SelectedIndex="0">
<controls:SegmentedItem x:Uid="AppSettingsControlGeneral" Tag="General" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlStandard" Tag="Standard" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDock" Tag="Dock" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDesktop" Tag="Desktop" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlPictureInPicture" Tag="PictureInPicture" />
</controls:Segmented>
</StackPanel>
</Grid>
</ScrollViewer>
</Grid>
</UserControl>

View File

@@ -1,5 +1,8 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.ViewModels;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
@@ -46,5 +49,33 @@ namespace BetterLyrics.WinUI3.Controls
{
AutoStartupToggleSwitch.Toggled -= AutoStartupToggleSwitch_Toggled;
}
private void DeleteWindowBoundsRecordButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button button)
{
var data = button.DataContext as WindowBoundsRecord;
if (data != null)
{
ViewModel.AppSettings.WindowBoundsRecords.Remove(data);
}
}
}
private void ApplyWindowBoundsRecordButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button button)
{
var data = button.DataContext as WindowBoundsRecord;
if (data != null)
{
var lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (lyricsWindow != null)
{
lyricsWindow.AppWindow.MoveAndResize(data.WindowBounds.ToRectInt32());
}
}
}
}
}
}

View File

@@ -3,6 +3,7 @@
x:Class="BetterLyrics.WinUI3.Controls.LyricsSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:BetterLyrics.WinUI3.Controls"
@@ -12,106 +13,61 @@
<Grid Padding="16" RowSpacing="6">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="0,0,0,6">
<TextBlock x:Uid="LyricsSearchControlSongInfoMapping" Style="{StaticResource SubtitleTextBlockStyle}" />
</Grid>
<Grid Grid.Row="1" ColumnSpacing="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="LyricsSearchControlTitle"
Grid.Column="0"
VerticalAlignment="Center"
Text="Title" />
<TextBox
Grid.Column="1"
IsReadOnly="True"
Text="{x:Bind ViewModel.MappedSongSearchQuery.OriginalTitle, Mode=OneWay}"
TextWrapping="Wrap" />
<TextBlock
x:Uid="LyricsSearchControlMappedAs"
Grid.Column="2"
VerticalAlignment="Center" />
<TextBox
Grid.Column="3"
Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedTitle, Mode=TwoWay}"
TextWrapping="Wrap" />
</Grid>
<Grid Grid.Row="2" ColumnSpacing="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="LyricsSearchControlArtist"
Grid.Column="0"
VerticalAlignment="Center" />
<TextBox
Grid.Column="1"
IsReadOnly="True"
Text="{x:Bind ViewModel.MappedSongSearchQuery.OriginalArtist, Mode=OneWay}"
TextWrapping="Wrap" />
<TextBlock
x:Uid="LyricsSearchControlMappedAs"
Grid.Column="2"
VerticalAlignment="Center" />
<TextBox
Grid.Column="3"
Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedArtist, Mode=TwoWay}"
TextWrapping="Wrap" />
</Grid>
<!-- 搜索及其他按钮 -->
<Grid Grid.Row="3">
<RelativePanel>
<CheckBox
x:Uid="LyricsSearchControlMarkAsPureMusic"
IsChecked="{x:Bind ViewModel.MappedSongSearchQuery.IsMarkedAsPureMusic, Mode=TwoWay}"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignVerticalCenterWithPanel="True" />
<Button
x:Uid="LyricsSearchControlSearch"
Command="{x:Bind ViewModel.SearchCommand}"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignVerticalCenterWithPanel="True"
Style="{StaticResource AccentButtonStyle}" />
</RelativePanel>
</Grid>
<Grid Grid.Row="4">
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<TextBlock x:Uid="LyricsSearchControlTargetSearchProvider" Style="{StaticResource SubtitleTextBlockStyle}" />
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<controls:SettingsExpander x:Uid="LyricsSearchControlSongInfoMapping" IsExpanded="True">
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="LyricsSearchControlTitle" Description="{x:Bind ViewModel.MappedSongSearchQuery.OriginalTitle, Mode=OneWay}">
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock x:Uid="LyricsSearchControlMappedAs" VerticalAlignment="Center" />
<TextBox Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedTitle, Mode=TwoWay}" TextWrapping="Wrap" />
<Button
VerticalAlignment="Center"
Command="{x:Bind ViewModel.ResetMappedTitleCommand}"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE777;}"
Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="LyricsSearchControlArtist" Description="{x:Bind ViewModel.MappedSongSearchQuery.OriginalArtist, Mode=OneWay}">
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock x:Uid="LyricsSearchControlMappedAs" VerticalAlignment="Center" />
<TextBox Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedArtist, Mode=TwoWay}" TextWrapping="Wrap" />
<Button
VerticalAlignment="Center"
Command="{x:Bind ViewModel.ResetMappedArtistCommand}"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE777;}"
Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</controls:SettingsCard>
<controls:SettingsCard>
<CheckBox x:Uid="LyricsSearchControlMarkAsPureMusic" IsChecked="{x:Bind ViewModel.MappedSongSearchQuery.IsMarkedAsPureMusic, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="LyricsSearchControlTargetSearchProvider">
<Button
x:Uid="LyricsSearchControlSearch"
Command="{x:Bind ViewModel.SearchCommand}"
Style="{StaticResource AccentButtonStyle}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
<Grid Grid.Column="1">
<TextBlock
x:Uid="LyricsSearchControlLyricsPreview"
Margin="6,0,0,0"
Style="{StaticResource SubtitleTextBlockStyle}" />
</Grid>
</Grid>
<!-- 结果列表及原始歌词文件展示区域 -->
<Grid Grid.Row="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" RowSpacing="12">
<ListView ItemsSource="{x:Bind ViewModel.LyricsSearchResults, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedLyricsSearchResult, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
@@ -188,17 +144,17 @@
ShowPaused="False"
Visibility="{x:Bind ViewModel.IsSearching, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
</Grid>
<Grid Grid.Column="1">
<ListView ItemsSource="{x:Bind ViewModel.LyricsData.LyricsLines, Mode=OneWay}">
<Grid Grid.Column="2">
<ListView ItemsSource="{x:Bind ViewModel.LyricsData.LyricsLines, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedLyricsLine, Mode=TwoWay}">
<interactivity:Interaction.Behaviors>
<interactivity:DataTriggerBehavior
Binding="{x:Bind ViewModel.SelectedLyricsSearchResult, Mode=OneWay}"
Binding="{x:Bind ViewModel.LyricsData, Mode=OneWay}"
ComparisonCondition="Equal"
Value="{x:Null}">
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
</interactivity:DataTriggerBehavior>
<interactivity:DataTriggerBehavior
Binding="{x:Bind ViewModel.SelectedLyricsSearchResult, Mode=OneWay}"
Binding="{x:Bind ViewModel.LyricsData, Mode=OneWay}"
ComparisonCondition="NotEqual"
Value="{x:Null}">
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
@@ -226,13 +182,13 @@
<Image MaxWidth="100" Source="/Assets/Page.png" />
<interactivity:Interaction.Behaviors>
<interactivity:DataTriggerBehavior
Binding="{x:Bind ViewModel.SelectedLyricsSearchResult, Mode=OneWay}"
Binding="{x:Bind ViewModel.LyricsData, Mode=OneWay}"
ComparisonCondition="NotEqual"
Value="{x:Null}">
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
</interactivity:DataTriggerBehavior>
<interactivity:DataTriggerBehavior
Binding="{x:Bind ViewModel.SelectedLyricsSearchResult, Mode=OneWay}"
Binding="{x:Bind ViewModel.LyricsData, Mode=OneWay}"
ComparisonCondition="Equal"
Value="{x:Null}">
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
@@ -241,13 +197,13 @@
</StackPanel>
</Grid>
</Grid>
<Grid Grid.Row="6">
<Grid Grid.Row="1">
<RelativePanel>
<TextBlock
x:Uid="LyricsSearchControlHelp"
Margin="0,0,24,0"
FontSize="12"
Foreground="{StaticResource TextFillColorSecondaryBrush}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
RelativePanel.AlignVerticalCenterWithPanel="True"
RelativePanel.LeftOf="Reset"
TextWrapping="Wrap" />

View File

@@ -175,14 +175,25 @@
</interactivity:Interaction.Behaviors>
</ColorPicker>
<controls:SettingsCard x:Uid="SettingsPageLyricsFontSize" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE8E9;}">
<local:ExtendedSlider
Frequency="2"
Maximum="96"
Minimum="12"
ResetButtonVisibility="Collapsed"
Value="{x:Bind LyricsStyleSettings.LyricsFontSize, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsExpander
x:Uid="SettingsPageLyricsFontSize"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE8E9;}"
IsExpanded="True">
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageDynamicLyricsFontSize">
<ToggleSwitch IsOn="{x:Bind LyricsStyleSettings.IsDynamicLyricsFontSize, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard IsEnabled="{x:Bind LyricsStyleSettings.IsDynamicLyricsFontSize, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
<local:ExtendedSlider
Frequency="2"
Maximum="96"
Minimum="12"
ResetButtonVisibility="Collapsed"
Value="{x:Bind LyricsStyleSettings.LyricsFontSize, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageLyricsLineSpacingFactor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF579;}">
<local:ExtendedSlider

View File

@@ -231,12 +231,11 @@
IsExpanded="True">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageTargetLanguage">
<controls:SettingsCard x:Uid="SettingsPageTargetLanguage" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.TranslationSettings.SelectedTargetLanguageIndex, Mode=TwoWay}">
<ComboBoxItem Content="العربية" Tag="ar" />
<ComboBoxItem Content="Azərbaycan dili" Tag="az" />
<ComboBoxItem Content="简体中文" Tag="zh-Hans" />
<ComboBoxItem Content="繁體中文" Tag="zh-Hant" />
<ComboBoxItem Content="中文" Tag="zh" />
<ComboBoxItem Content="Čeština" Tag="cs" />
<ComboBoxItem Content="Dansk" Tag="da" />
<ComboBoxItem Content="Nederlands" Tag="nl" />
@@ -266,7 +265,7 @@
<ComboBoxItem Content="Tiếng Việt" Tag="vi" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageTranslationConfig">
<controls:SettingsCard x:Uid="SettingsPageTranslationConfig" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
<controls:SettingsCard.Description>
<HyperlinkButton Margin="0,6,0,0" NavigateUri="https://github.com/LibreTranslate/LibreTranslate">
<TextBlock
@@ -295,6 +294,29 @@
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- Lyrics phonetic -->
<controls:SettingsExpander
x:Uid="SettingsPageChinese"
IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}"
IsExpanded="True">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsChineseRomanizationEnabled, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard>
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.TranslationSettings.ChineseRomanization, Converter={StaticResource EnumToIntConverter}, Mode=TwoWay}">
<ComboBoxItem x:Uid="SettingsPagePinyin" />
<ComboBoxItem x:Uid="SettingsPageJyutping" />
</ComboBox>
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageJapanese" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- 中文简体繁体偏好 -->
<controls:SettingsCard x:Uid="SettingsPageChinesePreference">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTraditionalChineseEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Provider info -->
<controls:SettingsCard x:Uid="LyricsPageLyricsProviderPrefix">
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.LyricsSearchProvider, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
</controls:SettingsCard>

View File

@@ -19,6 +19,7 @@ namespace BetterLyrics.WinUI3.Converter
{
PlayerID.Spotify => PathHelper.SpotifyLogoPath,
PlayerID.AppleMusic => PathHelper.AppleMusicLogoPath,
PlayerID.AppleMusicAlternative => PathHelper.AppleMusicLogoPath,
PlayerID.iTunes => PathHelper.iTunesLogoPath,
PlayerID.KugouMusic => PathHelper.KugouMusicLogoPath,
PlayerID.NetEaseCloudMusic => PathHelper.NetEaseCloudMusicLogoPath,

View File

@@ -0,0 +1,26 @@
using Microsoft.UI.Xaml.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Converter
{
public class RectToMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is Windows.Foundation.Rect rect)
{
return new Microsoft.UI.Xaml.Thickness(rect.X, rect.Y, 0, 0);
}
return new Microsoft.UI.Xaml.Thickness(0);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Enums
{
public enum ChineseRomanization
{
Pinyin,
Jyutping,
}
}

View File

@@ -8,7 +8,8 @@ namespace BetterLyrics.WinUI3.Enums
{
public enum ShortcutID
{
DesktopLock,
LyricsWindowShowOrHide,
DesktopLockOrUnlock,
DesktopToggle,
DockToggle,
PictureInPictureToggle,

View File

@@ -74,9 +74,17 @@ namespace BetterLyrics.WinUI3.Helper
using var ds = list.CreateDrawingSession();
if (strokeWidth > 0)
{
if (lyricsLine.TextGeometry == null)
{
return list;
}
ds.DrawGeometry(lyricsLine.TextGeometry, lyricsLine.Position, strokeColor, strokeWidth); // 描边
}
ds.FillGeometry(lyricsLine.TextGeometry, lyricsLine.Position, fontColor); // 填充
if (lyricsLine.CanvasTextLayout == null)
{
return list;
}
ds.DrawTextLayout(lyricsLine.CanvasTextLayout, lyricsLine.Position, fontColor); // 绘制文本(填充)
return list;
}

View File

@@ -94,6 +94,11 @@ namespace BetterLyrics.WinUI3.Helper
return Color.FromArgb(alpha, color.R, color.G, color.B);
}
public static Color WithOpacity(this Color color, float opacity)
{
return Color.FromArgb((byte)(opacity * 255), color.R, color.G, color.B);
}
public static Color WithBrightness(this Color color, double brightness)
{
// 确保亮度因子在合理范围内
@@ -116,15 +121,11 @@ namespace BetterLyrics.WinUI3.Helper
{
case WindowPixelSampleMode.BelowWindow:
{
int sampleHeight = 1;
int sampleY = myRect.Bottom + 1;
return GetAverageColorFromScreenRegion(myRect.Left, sampleY, screenWidth, sampleHeight);
return GetAverageColorFromScreenRegion(myRect.Left, myRect.Bottom + 2, screenWidth, 1);
}
case WindowPixelSampleMode.AboveWindow:
{
int sampleHeight = 1;
int sampleY = myRect.Top - 1;
return GetAverageColorFromScreenRegion(myRect.Left, sampleY, screenWidth, sampleHeight);
return GetAverageColorFromScreenRegion(myRect.Left, myRect.Top - 3, screenWidth, 1);
}
case WindowPixelSampleMode.WindowArea:
{

View File

@@ -11,6 +11,6 @@ namespace BetterLyrics.WinUI3.Helper
{
public static class FontHelper
{
public static string[] SystemFontFamilies => CanvasTextFormat.GetSystemFontFamilies();
public static string[] SystemFontFamilies => CanvasTextFormat.GetSystemFontFamilies().Order().ToArray();
}
}

View File

@@ -22,8 +22,7 @@ namespace BetterLyrics.WinUI3.Services
[
new Models.LanguageInfo("ar", "العربية"),
new Models.LanguageInfo("az", "Azərbaycan dili"),
new Models.LanguageInfo("zh-Hans", "简体中文"),
new Models.LanguageInfo("zh-Hant", "繁體中文"),
new Models.LanguageInfo("zh", "中文"),
new Models.LanguageInfo("cs", "Čeština"),
new Models.LanguageInfo("da", "Dansk"),
new Models.LanguageInfo("nl", "Nederlands"),
@@ -56,11 +55,7 @@ namespace BetterLyrics.WinUI3.Services
static LanguageHelper()
{
_identifier = _factory.Load(PathHelper.LanguageProfilePath);
}
private static string SimplifiedChineseOrTraditionalChinese(string text)
{
return text == ChineseConverter.ConvertToSimplifiedChinese(text) ? "zh-Hans" : "zh-Hant";
RomajiConverter.Core.Helpers.RomajiHelper.Init();
}
public static string? DetectLanguageCode(string? text)
@@ -72,9 +67,8 @@ namespace BetterLyrics.WinUI3.Services
code = code switch
{
"simple" => "en",
"zh_classical" => SimplifiedChineseOrTraditionalChinese(text),
"zh_yue" => SimplifiedChineseOrTraditionalChinese(text),
"zh" => SimplifiedChineseOrTraditionalChinese(text),
"zh_classical" => "zh",
"zh_yue" => "zh",
_ => code
};
return code;
@@ -89,21 +83,6 @@ namespace BetterLyrics.WinUI3.Services
};
}
public static string ConvertToCountryCode(string? languageCode)
{
if (languageCode == null) return "us";
return languageCode switch
{
"zh" => "cn",
"zh-Hans" => "cn",
"zh-Hant" => "tw",
"ja" => "jp",
"ko" => "kr",
_ => "us"
};
}
public static int GetDefaultTargetLanguageIndex()
{
int found = SupportedTargetLanguages.FindIndex(x => ApplicationLanguages.Languages.FirstOrDefault()?.Contains(x.Code) == true);
@@ -125,5 +104,10 @@ namespace BetterLyrics.WinUI3.Services
return "#";
}
public static string ToRomaji(string text)
{
return string.Join(" ", RomajiConverter.Core.Helpers.RomajiHelper.SentenceToRomaji(text).Select(x=>x.Romaji));
}
}
}

View File

@@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Windows.Globalization.Fonts;
using LyricsData = BetterLyrics.WinUI3.Models.LyricsData;
namespace BetterLyrics.WinUI3.Helper
@@ -48,50 +47,67 @@ namespace BetterLyrics.WinUI3.Helper
break;
}
}
FillChineseLyricsData();
FillRomanizationLyricsData();
_lyricsDataArr.Add(new LyricsData()); // 为机翻预留
return _lyricsDataArr;
}
private void FillChineseLyricsData()
private void FillRomanizationLyricsData()
{
var simplifiedChinese = _lyricsDataArr.Where(x => x.LanguageCode == "zh-Hans").FirstOrDefault();
var traditionalChinese = _lyricsDataArr.Where(x => x.LanguageCode == "zh-Hant").FirstOrDefault();
if (simplifiedChinese != null && traditionalChinese == null)
var chinese = _lyricsDataArr.Where(x => x.LanguageCode == "zh").FirstOrDefault();
if (chinese != null)
{
// 如果没有繁体中文歌词,则将简体中文歌词转换为繁体中文
_lyricsDataArr.Add(new LyricsData
{
LyricsLines = simplifiedChinese.LyricsLines.Select(line => new LyricsLine
LanguageCode = "pinyin",
LyricsLines = chinese.LyricsLines.Select(line => new LyricsLine
{
StartMs = line.StartMs,
EndMs = line.EndMs,
OriginalText = ChineseConverter.ConvertToTraditionalChinese(line.OriginalText),
OriginalText = Pinyin.Pinyin.Instance.HanziToPinyin(line.OriginalText).ToStr(),
LyricsChars = line.LyricsChars.Select(c => new LyricsChar
{
StartMs = c.StartMs,
EndMs = c.EndMs,
Text = ChineseConverter.ConvertToTraditionalChinese(c.Text),
Text = Pinyin.Pinyin.Instance.HanziToPinyin(c.Text).ToStr(),
StartIndex = c.StartIndex
}).ToList()
}).ToList()
});
_lyricsDataArr.Add(new LyricsData
{
LanguageCode = "jyutping",
LyricsLines = chinese.LyricsLines.Select(line => new LyricsLine
{
StartMs = line.StartMs,
EndMs = line.EndMs,
OriginalText = Pinyin.Jyutping.Instance.HanziToPinyin(line.OriginalText).ToStr(),
LyricsChars = line.LyricsChars.Select(c => new LyricsChar
{
StartMs = c.StartMs,
EndMs = c.EndMs,
Text = Pinyin.Jyutping.Instance.HanziToPinyin(c.Text).ToStr(),
StartIndex = c.StartIndex
}).ToList()
}).ToList()
});
}
else if (traditionalChinese != null && simplifiedChinese == null)
var japanese = _lyricsDataArr.Where(x => x.LanguageCode == "ja").FirstOrDefault();
if (japanese != null)
{
// 如果没有简体中文歌词,则将繁体中文歌词转换为简体中文
_lyricsDataArr.Add(new LyricsData
{
LyricsLines = traditionalChinese.LyricsLines.Select(line => new LyricsLine
LanguageCode = "romaji",
LyricsLines = japanese.LyricsLines.Select(line => new LyricsLine
{
StartMs = line.StartMs,
EndMs = line.EndMs,
OriginalText = ChineseConverter.ConvertToSimplifiedChinese(line.OriginalText),
OriginalText = LanguageHelper.ToRomaji(line.OriginalText),
LyricsChars = line.LyricsChars.Select(c => new LyricsChar
{
StartMs = c.StartMs,
EndMs = c.EndMs,
Text = ChineseConverter.ConvertToSimplifiedChinese(c.Text),
Text = LanguageHelper.ToRomaji(c.Text),
StartIndex = c.StartIndex
}).ToList()
}).ToList()
@@ -230,10 +246,11 @@ namespace BetterLyrics.WinUI3.Helper
int pStartMs = ParseTtmlTime(pBegin);
int pEndMs = ParseTtmlTime(pEnd);
// 只获取一级span且排除ttm:role="x-bg"span
// 只获取一级span且排除 ttm:role="x-bg"span 和 ttm:role="x-roman"
var spans = p.Elements()
.Where(s => s.Name.LocalName == "span" &&
s.Attribute(XName.Get("role", "http://www.w3.org/ns/ttml#metadata"))?.Value != "x-bg")
s.Attribute(XName.Get("role", "http://www.w3.org/ns/ttml#metadata"))?.Value != "x-bg" &&
s.Attribute(XName.Get("role", "http://www.w3.org/ns/ttml#metadata"))?.Value != "x-roman")
.ToList();
// 原文和翻译分离

View File

@@ -1,4 +1,5 @@
using System;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
@@ -6,6 +7,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Vanara.PInvoke;
using WinRT.Interop;
namespace BetterLyrics.WinUI3.Helper
{
@@ -60,5 +62,14 @@ namespace BetterLyrics.WinUI3.Helper
var primaryMonitorInfo = GetPrimaryMonitorInfoEx();
return primaryMonitorInfo.szDevice;
}
public static User32.MONITORINFOEX GetMonitorInfoExFromWindow(Window window)
{
var hwnd = WindowNative.GetWindowHandle(window);
var hMonitor = User32.MonitorFromWindow(hwnd, User32.MonitorFlags.MONITOR_DEFAULTTONEAREST);
User32.MONITORINFOEX monitorInfoEx = new() { cbSize = (uint)Marshal.SizeOf<User32.MONITORINFOEX>() };
User32.GetMonitorInfo(hMonitor, ref monitorInfoEx);
return monitorInfoEx;
}
}
}

View File

@@ -59,6 +59,10 @@ namespace BetterLyrics.WinUI3.Helper
{
window = new MusicGalleryWindow();
}
else if (typeof(T) == typeof(LyricsSearchWindow))
{
window = new LyricsSearchWindow();
}
else
{
throw new ArgumentException("Unsupported window type", nameof(T));
@@ -73,6 +77,7 @@ namespace BetterLyrics.WinUI3.Helper
var lyricsWindow = (LyricsWindow)window;
lyricsWindow.ViewModel.InitShortcuts();
lyricsWindow.AutoSelectLyricsMode();
lyricsWindow.ViewModel.SetIsAlwaysOnTop();
}
}
else

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Models
{
public class LibInfo
{
public string Name { get; set; }
public string Url => $"https://www.nuget.org/packages/{Name}/";
}
}

View File

@@ -1,4 +1,5 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models.Settings;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
@@ -6,34 +7,70 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vanara.PInvoke;
using Windows.Foundation;
namespace BetterLyrics.WinUI3.Models
{
public partial class LiveStates : ObservableRecipient
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsWindowMode CurrentLyricsWindowMode { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsDisplayType CurrentLyricsDisplayType { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings CurrentLyricsStyleSettings { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings CurrentLyricsEffectSettings { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsWindowMode LyricsWindowMode { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsDisplayType LyricsDisplayType { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAlwaysOnTop { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings LyricsStyleSettings { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings LyricsEffectSettings { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect LyricsWindowBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect LyricsWindowMonitorBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect DemoLyricsWindowBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect DemoLyricsWindowMonitorBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LyricsWindowMonitorName { get; set; }
public LiveStates(AppSettings appSettings)
{
CurrentLyricsWindowMode = LyricsWindowMode.StandardMode;
CurrentLyricsDisplayType = appSettings.StandardModeSettings.LyricsDisplayType;
CurrentLyricsStyleSettings = appSettings.StandardLyricsStyleSettings;
CurrentLyricsEffectSettings = appSettings.StandardLyricsEffectSettings;
LyricsWindowMode = LyricsWindowMode.StandardMode;
LyricsDisplayType = appSettings.StandardModeSettings.LyricsDisplayType;
LyricsStyleSettings = appSettings.StandardLyricsStyleSettings;
LyricsEffectSettings = appSettings.StandardLyricsEffectSettings;
IsAlwaysOnTop = false;
}
public void ToggleLyricsWindowMode(LyricsWindowMode mode)
{
if (CurrentLyricsWindowMode == mode)
if (LyricsWindowMode == mode)
{
CurrentLyricsWindowMode = LyricsWindowMode.StandardMode;
LyricsWindowMode = LyricsWindowMode.StandardMode;
}
else
{
CurrentLyricsWindowMode = mode;
LyricsWindowMode = mode;
}
}
partial void OnLyricsWindowBoundsChanged(Rect value)
{
double factor = 0.1;
DemoLyricsWindowBounds = new Rect(
value.X * factor,
value.Y * factor,
value.Width * factor,
value.Height * factor
);
var lyricsWindow = WindowHelper.GetWindowByWindowType<Views.LyricsWindow>();
if (lyricsWindow == null) return;
var mointor = MonitorHelper.GetMonitorInfoExFromWindow(lyricsWindow);
LyricsWindowMonitorName = mointor.szDevice;
LyricsWindowMonitorBounds = new Rect(
mointor.rcMonitor.Left,
mointor.rcMonitor.Top,
mointor.rcMonitor.Width,
mointor.rcMonitor.Height
);
DemoLyricsWindowMonitorBounds = new Rect(
mointor.rcMonitor.Left * factor,
mointor.rcMonitor.Top * factor,
mointor.rcMonitor.Width * factor,
mointor.rcMonitor.Height * factor
);
}
}
}

View File

@@ -1,4 +1,5 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Services;
using Lyricify.Lyrics.Helpers.General;
using System;
@@ -13,7 +14,12 @@ namespace BetterLyrics.WinUI3.Models
public class LyricsData
{
public List<LyricsLine> LyricsLines { get; set; }
public string? LanguageCode => LanguageHelper.DetectLanguageCode(WrappedOriginalText);
private string? _languageCode;
public string? LanguageCode
{
get => _languageCode ?? LanguageHelper.DetectLanguageCode(WrappedOriginalText);
set => _languageCode = value;
}
public string WrappedOriginalText => string.Join(StringHelper.NewLine, LyricsLines.Select(line => line.OriginalText));
public LyricsData()
@@ -120,5 +126,18 @@ namespace BetterLyrics.WinUI3.Models
},
]);
}
public LyricsLine? GetLyricsLine(double sec)
{
for (int i = 0; i < LyricsLines.Count; i++)
{
var line = LyricsLines[i];
if (line.StartMs > sec * 1000)
{
return LyricsLines.ElementAtOrDefault(i - 1);
}
}
return null;
}
}
}

View File

@@ -13,6 +13,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TextAlignmentType SongInfoAlignmentType { get; set; } = TextAlignmentType.Left;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverImageRadius { get; set; } = 12; // 12 % of the cover image size
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverImageShadowAmount { get; set; } = 12;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int SongInfoFontSize { get; set; } = 18;
public AlbumArtLayoutSettings() { }
}

View File

@@ -34,8 +34,8 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<LocalMediaFolder> LocalMediaFolders { get; set; } = [];
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<MediaSourceProviderInfo> MediaSourceProvidersInfo { get; set; } = [];
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<MappedSongSearchQuery> MappedSongSearchQueries { get; set; } = [];
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<WindowBoundsRecord> WindowBoundsRecords { get; set; } = [];
public AppSettings() { }
}

View File

@@ -15,6 +15,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool AutoLockOnDesktopMode { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> LockShortcut { get; set; } = new List<string>() { "Ctrl", "Alt", "U" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> ToggleShortcut { get; set; } = new List<string>() { "Ctrl", "Alt", "D" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAlwaysOnTop { get; set; } = true;
public DesktopModeSettings()
{

View File

@@ -15,6 +15,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IgnoreFullscreenWindow { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LXMusicServer { get; set; } = string.Empty;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool HideWindowWhenNotPlaying { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> ShowOrHideLyricsWindowShortcut { get; set; } = new List<string> { "Ctrl", "Alt", "H" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsDragEverywhereEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsImmersiveMode { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ExitOnLyricsWindowClosed { get; set; } = true;

View File

@@ -13,6 +13,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class LyricsStyleSettings : ObservableRecipient
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsDynamicLyricsFontSize { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFontSize { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TextAlignmentType LyricsAlignmentType { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsBgFontOpacity { get; set; } = 30; // 30% opacity

View File

@@ -14,6 +14,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect WindowBounds { get; set; } = new Rect(100, 100, 1000, 600);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsMaximized { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAlwaysOnTop { get; set; } = false;
public StandardModeSettings()
{

View File

@@ -1,4 +1,5 @@
using BetterLyrics.WinUI3.Services;
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Services;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
@@ -15,6 +16,11 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsTranslationEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowTranslationOnly { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int SelectedTargetLanguageIndex { get; set; } = LanguageHelper.GetDefaultTargetLanguageIndex();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsJyutpingEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial ChineseRomanization ChineseRomanization { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsChineseRomanizationEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsJapaneseRomanizationEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsTraditionalChineseEnabled { get; set; } = false;
public TranslationSettings() { }
}

View File

@@ -0,0 +1,19 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
namespace BetterLyrics.WinUI3.Models
{
public partial class WindowBoundsRecord : ObservableObject
{
[ObservableProperty] public partial string MonitorDeviceName { get; set; } = string.Empty;
[ObservableProperty] public partial Rect WindowBounds { get; set; }
[ObservableProperty] public partial Rect DemoWindowBounds { get; set; }
[ObservableProperty] public partial Rect MonitorBounds { get; set; }
[ObservableProperty] public partial Rect DemoMonitorBounds { get; set; }
}
}

View File

@@ -15,7 +15,8 @@ namespace BetterLyrics.WinUI3.Services.LiveStatesService
{
public class LiveStatesService : BaseViewModel, ILiveStatesService,
IRecipient<PropertyChangedMessage<LyricsWindowMode>>,
IRecipient<PropertyChangedMessage<LyricsDisplayType>>
IRecipient<PropertyChangedMessage<LyricsDisplayType>>,
IRecipient<PropertyChangedMessage<bool>>
{
private readonly ISettingsService _settingsService;
@@ -32,29 +33,33 @@ namespace BetterLyrics.WinUI3.Services.LiveStatesService
{
if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.CurrentLyricsWindowMode))
if (message.PropertyName == nameof(LiveStates.LyricsWindowMode))
{
switch (message.NewValue)
{
case LyricsWindowMode.StandardMode:
LiveStates.CurrentLyricsStyleSettings = _settingsService.AppSettings.StandardLyricsStyleSettings;
LiveStates.CurrentLyricsEffectSettings = _settingsService.AppSettings.StandardLyricsEffectSettings;
LiveStates.CurrentLyricsDisplayType = _settingsService.AppSettings.StandardModeSettings.LyricsDisplayType;
LiveStates.LyricsStyleSettings = _settingsService.AppSettings.StandardLyricsStyleSettings;
LiveStates.LyricsEffectSettings = _settingsService.AppSettings.StandardLyricsEffectSettings;
LiveStates.LyricsDisplayType = _settingsService.AppSettings.StandardModeSettings.LyricsDisplayType;
LiveStates.IsAlwaysOnTop = _settingsService.AppSettings.StandardModeSettings.IsAlwaysOnTop;
break;
case LyricsWindowMode.DockMode:
LiveStates.CurrentLyricsStyleSettings = _settingsService.AppSettings.DockLyricsStyleSettings;
LiveStates.CurrentLyricsEffectSettings = _settingsService.AppSettings.DockLyricsEffectSettings;
LiveStates.CurrentLyricsDisplayType = _settingsService.AppSettings.DockModeSettings.LyricsDisplayType;
LiveStates.LyricsStyleSettings = _settingsService.AppSettings.DockLyricsStyleSettings;
LiveStates.LyricsEffectSettings = _settingsService.AppSettings.DockLyricsEffectSettings;
LiveStates.LyricsDisplayType = _settingsService.AppSettings.DockModeSettings.LyricsDisplayType;
LiveStates.IsAlwaysOnTop = true;
break;
case LyricsWindowMode.DesktopMode:
LiveStates.CurrentLyricsStyleSettings = _settingsService.AppSettings.DesktopLyricsStyleSettings;
LiveStates.CurrentLyricsEffectSettings = _settingsService.AppSettings.DesktopLyricsEffectSettings;
LiveStates.CurrentLyricsDisplayType = _settingsService.AppSettings.DesktopModeSettings.LyricsDisplayType;
LiveStates.LyricsStyleSettings = _settingsService.AppSettings.DesktopLyricsStyleSettings;
LiveStates.LyricsEffectSettings = _settingsService.AppSettings.DesktopLyricsEffectSettings;
LiveStates.LyricsDisplayType = _settingsService.AppSettings.DesktopModeSettings.LyricsDisplayType;
LiveStates.IsAlwaysOnTop = _settingsService.AppSettings.DesktopModeSettings.IsAlwaysOnTop;
break;
case LyricsWindowMode.PictureInPictureMode:
LiveStates.CurrentLyricsStyleSettings = _settingsService.AppSettings.PictureInPictureLyricsStyleSettings;
LiveStates.CurrentLyricsEffectSettings = _settingsService.AppSettings.PictureInPictureLyricsEffectSettings;
LiveStates.CurrentLyricsDisplayType = _settingsService.AppSettings.PictureInPictureModeSettings.LyricsDisplayType;
LiveStates.LyricsStyleSettings = _settingsService.AppSettings.PictureInPictureLyricsStyleSettings;
LiveStates.LyricsEffectSettings = _settingsService.AppSettings.PictureInPictureLyricsEffectSettings;
LiveStates.LyricsDisplayType = _settingsService.AppSettings.PictureInPictureModeSettings.LyricsDisplayType;
// IsAlwaysOnTop 由系统托管
break;
default:
break;
@@ -69,9 +74,9 @@ namespace BetterLyrics.WinUI3.Services.LiveStatesService
{
if (message.PropertyName == nameof(StandardModeSettings.LyricsDisplayType))
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.StandardMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
LiveStates.CurrentLyricsDisplayType = message.NewValue;
LiveStates.LyricsDisplayType = message.NewValue;
}
}
}
@@ -79,9 +84,9 @@ namespace BetterLyrics.WinUI3.Services.LiveStatesService
{
if (message.PropertyName == nameof(DockModeSettings.LyricsDisplayType))
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
{
LiveStates.CurrentLyricsDisplayType = message.NewValue;
LiveStates.LyricsDisplayType = message.NewValue;
}
}
}
@@ -89,9 +94,9 @@ namespace BetterLyrics.WinUI3.Services.LiveStatesService
{
if (message.PropertyName == nameof(DesktopModeSettings.LyricsDisplayType))
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
LiveStates.CurrentLyricsDisplayType = message.NewValue;
LiveStates.LyricsDisplayType = message.NewValue;
}
}
}
@@ -99,9 +104,33 @@ namespace BetterLyrics.WinUI3.Services.LiveStatesService
{
if (message.PropertyName == nameof(PictureInPictureModeSettings.LyricsDisplayType))
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.PictureInPictureMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.PictureInPictureMode)
{
LiveStates.CurrentLyricsDisplayType = message.NewValue;
LiveStates.LyricsDisplayType = message.NewValue;
}
}
}
}
public void Receive(PropertyChangedMessage<bool> message)
{
if (message.Sender is StandardModeSettings)
{
if (message.PropertyName == nameof(StandardModeSettings.IsAlwaysOnTop))
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
LiveStates.IsAlwaysOnTop = message.NewValue;
}
}
}
else if (message.Sender is DesktopModeSettings)
{
if (message.PropertyName == nameof(DesktopModeSettings.IsAlwaysOnTop))
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
LiveStates.IsAlwaysOnTop = message.NewValue;
}
}
}

View File

@@ -40,7 +40,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
_lrcLibHttpClient = new();
_lrcLibHttpClient.DefaultRequestHeaders.Add(
"User-Agent",
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Constants.Link.GithubUrl})"
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Constants.Link.GitHubUrl})"
);
_amllTtmlDbHttpClient = new();
}

View File

@@ -30,6 +30,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
bool IsPlaying { get; }
SongInfo? SongInfo { get; }
TimeSpan Position { get; }
LyricsData? CurrentLyricsData { get; }
LyricsSearchProvider? LyricsSearchProvider { get; }
TranslationSearchProvider? TranslationSearchProvider { get; }

View File

@@ -58,7 +58,8 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
var decoder = await BitmapDecoder.CreateAsync(stream);
token.ThrowIfCancellationRequested();
var albumArtSwBitmap = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Rgba16, BitmapAlphaMode.Premultiplied);
var albumArtSwBitmap = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Premultiplied);
albumArtSwBitmap = SoftwareBitmap.Copy(albumArtSwBitmap);
token.ThrowIfCancellationRequested();
var albumArtLightAccentColor = ImageHelper.GetAccentColorsFromByte(bytes, 1, false).FirstOrDefault();

View File

@@ -3,6 +3,7 @@ using BetterLyrics.WinUI3.Events;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using CommunityToolkit.Mvvm.ComponentModel;
using Lyricify.Lyrics.Helpers.General;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@@ -22,7 +23,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
private int _langIndex = 0;
private List<LyricsData> _lyricsDataArr = [];
private LyricsData? CurrentLyricsData => _lyricsDataArr.ElementAtOrDefault(_langIndex);
public LyricsData? CurrentLyricsData => _lyricsDataArr.ElementAtOrDefault(_langIndex);
public event EventHandler<LyricsChangedEventArgs>? LyricsChanged;
@@ -65,6 +66,25 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
string? originalLangCode = LanguageHelper.DetectLanguageCode(originalText);
_logger.LogInformation("Original language code: {OriginalLangCode}", originalLangCode ?? "null");
if (originalLangCode == "zh" && _settingsService.AppSettings.TranslationSettings.IsChineseRomanizationEnabled)
{
switch (_settingsService.AppSettings.TranslationSettings.ChineseRomanization)
{
case ChineseRomanization.Pinyin:
targetLangCode = "pinyin";
break;
case ChineseRomanization.Jyutping:
targetLangCode = "jyutping";
break;
default:
break;
}
}
else if (originalLangCode == "ja" && _settingsService.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled)
{
targetLangCode = "romaji";
}
if (originalLangCode == targetLangCode)
{
_logger.LogInformation("Original lyrics already in target language: {TargetLangCode}", targetLangCode);
@@ -74,7 +94,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
else
{
// Try get translation from itself first
int found = _translateService.SearchTranslatedLyricsItself(_lyricsDataArr);
int found = _translateService.SearchTranslatedLyricsItself(_lyricsDataArr, targetLangCode);
if (found >= 0)
{
_logger.LogInformation("Found translation in lyrics data at index {FoundIndex}", found);
@@ -85,7 +105,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
}
else
{
_lyricsDataArr[0].SetDisplayedTextAlongWith(_lyricsDataArr[found], _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsTranslationSeparator, 50);
_lyricsDataArr[0].SetDisplayedTextAlongWith(_lyricsDataArr[found], _liveStatesService.LiveStates.LyricsStyleSettings.LyricsTranslationSeparator, 50);
_langIndex = 0;
TranslationSearchProvider = LyricsSearchProvider.ToTranslationSearchProvider();
}
@@ -108,7 +128,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
}
else
{
_lyricsDataArr[0].SetDisplayedTextAlongWith(translated, _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsTranslationSeparator);
_lyricsDataArr[0].SetDisplayedTextAlongWith(translated, _liveStatesService.LiveStates.LyricsStyleSettings.LyricsTranslationSeparator);
_langIndex = 0;
}
TranslationSearchProvider = Enums.TranslationSearchProvider.LibreTranslate;
@@ -145,10 +165,11 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
), token);
if (token.IsCancellationRequested) return;
LyricsSearchProvider = lyricsSearchResult?.Provider;
_logger.LogInformation("Lyrics was found? {Found}, Provider: {LyricsSearchProvider}", lyricsSearchResult?.IsFound, LyricsSearchProvider?.ToString() ?? "null");
_lyricsDataArr = new LyricsParser().Parse(lyricsSearchResult?.Raw, (int?)SongInfo?.DurationMs);
ApplyChinesePreference();
FillTranslationFromCache(LyricsSearchProvider);
}
else
@@ -161,10 +182,23 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
// This ensures that original lyrics are always shown while waiting for translations
_lyricsDataArr[0].SetDisplayedTextInOriginalText();
LyricsChanged?.Invoke(this, new LyricsChangedEventArgs(CurrentLyricsData));
ApplyChinesePreference();
UpdateTranslations();
}
private void ApplyChinesePreference()
{
var traditionalChinesePreferred = _settingsService.AppSettings.TranslationSettings.IsTraditionalChineseEnabled;
var found = _lyricsDataArr.FindIndex(x => x.LanguageCode == "zh");
if (found >= 0)
{
foreach (var item in _lyricsDataArr[found].LyricsLines)
{
item.OriginalText = traditionalChinesePreferred ? ChineseHelper.S2T(item.OriginalText) : ChineseHelper.T2S(item.OriginalText);
}
}
}
private void FillTranslationFromCache(LyricsSearchProvider? provider)
{
string? translationRaw = null;

View File

@@ -44,6 +44,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
IRecipient<PropertyChangedMessage<bool>>,
IRecipient<PropertyChangedMessage<string>>,
IRecipient<PropertyChangedMessage<LyricsWindowMode>>,
IRecipient<PropertyChangedMessage<ChineseRomanization>>,
IRecipient<PropertyChangedMessage<List<string>>>
{
private readonly IAlbumArtSearchService _albumArtSearchService;
@@ -320,14 +321,31 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
currentMediaSourceProviderInfo?.PositionOffset = 0;
}
_cachedSongInfo = new SongInfo
if (id == Constants.PlayerID.AppleMusic || id == Constants.PlayerID.AppleMusicAlternative)
{
Title = mediaProperties.Title,
Artist = mediaProperties.Artist,
Album = mediaProperties.AlbumTitle,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
SourceAppUserModelId = id,
};
string fixedArtist = mediaProperties.Artist.Split(" — ").FirstOrDefault() ?? mediaProperties.Artist;
string fixedAlbum = mediaProperties.Artist.Split(" — ").LastOrDefault() ?? mediaProperties.AlbumTitle;
_cachedSongInfo = new SongInfo
{
Title = mediaProperties.Title,
Artist = fixedArtist,
Album = fixedAlbum,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
SourceAppUserModelId = id,
};
}
else
{
_cachedSongInfo = new SongInfo
{
Title = mediaProperties.Title,
Artist = mediaProperties.Artist,
Album = mediaProperties.AlbumTitle,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
SourceAppUserModelId = id,
};
}
_cachedSongInfo.Duration = (int)(_cachedSongInfo.DurationMs / 1000f);
@@ -579,6 +597,18 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
{
UpdateTranslations();
}
else if (message.PropertyName == nameof(TranslationSettings.IsChineseRomanizationEnabled))
{
UpdateTranslations();
}
else if (message.PropertyName == nameof(TranslationSettings.IsJapaneseRomanizationEnabled))
{
UpdateTranslations();
}
else if (message.PropertyName == nameof(TranslationSettings.IsTraditionalChineseEnabled))
{
UpdateLyrics();
}
}
}
@@ -628,7 +658,18 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
{
if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.CurrentLyricsWindowMode))
if (message.PropertyName == nameof(LiveStates.LyricsWindowMode))
{
UpdateTranslations();
}
}
}
public void Receive(PropertyChangedMessage<ChineseRomanization> message)
{
if (message.Sender is TranslationSettings)
{
if (message.PropertyName == nameof(TranslationSettings.ChineseRomanization))
{
UpdateTranslations();
}

View File

@@ -60,6 +60,9 @@ namespace BetterLyrics.WinUI3.Services.SettingsService
AppSettings.MappedSongSearchQueries.CollectionChanged += AppSettings_CollectionChanged;
AppSettings.MappedSongSearchQueries.ItemPropertyChanged += AppSettings_ItemPropertyChanged;
AppSettings.WindowBoundsRecords.CollectionChanged += AppSettings_CollectionChanged;
AppSettings.WindowBoundsRecords.ItemPropertyChanged += AppSettings_ItemPropertyChanged;
AppSettings.Version = MetadataHelper.AppVersion;
EnsureMediaSourceProvidersInfo();

View File

@@ -12,6 +12,6 @@ namespace BetterLyrics.WinUI3.Services.TranslateService
{
Task<string> TranslateTextAsync(string text, string targetLangCode, CancellationToken token);
int SearchTranslatedLyricsItself(List<LyricsData> lyricsDataArr);
int SearchTranslatedLyricsItself(List<LyricsData> lyricsDataArr, string targetLangCode);
}
}

View File

@@ -58,9 +58,8 @@ namespace BetterLyrics.WinUI3.Services.TranslateService
return result?.TranslatedText ?? string.Empty;
}
public int SearchTranslatedLyricsItself(List<LyricsData> lyricsDataArr)
public int SearchTranslatedLyricsItself(List<LyricsData> lyricsDataArr, string targetLangCode)
{
string targetLangCode = LanguageHelper.SupportedTargetLanguages[_settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageIndex].Code;
if (lyricsDataArr.Count > 1)
{
for (int i = 1; i < lyricsDataArr.Count; i++)

View File

@@ -135,8 +135,8 @@
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>Standard</value>
</data>
<data name="BaseWindowAOTFlyoutItem.Text" xml:space="preserve">
<value>Always on top</value>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<value>General</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>Press Esc to exit full screen mode</value>
@@ -252,15 +252,12 @@
<data name="LyricsPageTranslationProviderPrefix.Header" xml:space="preserve">
<value>Translation provider</value>
</data>
<data name="LyricsSearchControlArtist.Text" xml:space="preserve">
<data name="LyricsSearchControlArtist.Header" xml:space="preserve">
<value>Artist</value>
</data>
<data name="LyricsSearchControlHelp.Text" xml:space="preserve">
<value>* Save changes take effect immediately, after which the track lyrics will be retrieved with mapping information and target lyrics; marking as pure music will directly return to pure music placeholder lyrics. Reset to retrieve by original data.</value>
</data>
<data name="LyricsSearchControlLyricsPreview.Text" xml:space="preserve">
<value>Lyrics preview</value>
</data>
<data name="LyricsSearchControlMappedAs.Text" xml:space="preserve">
<value>mapped as</value>
</data>
@@ -279,15 +276,18 @@
<data name="LyricsSearchControlSearch.Content" xml:space="preserve">
<value>Search</value>
</data>
<data name="LyricsSearchControlSongInfoMapping.Text" xml:space="preserve">
<data name="LyricsSearchControlSongInfoMapping.Header" xml:space="preserve">
<value>Song info mapping</value>
</data>
<data name="LyricsSearchControlTargetSearchProvider.Text" xml:space="preserve">
<data name="LyricsSearchControlTargetSearchProvider.Header" xml:space="preserve">
<value>Target lyrics search provider</value>
</data>
<data name="LyricsSearchControlTitle.Text" xml:space="preserve">
<data name="LyricsSearchControlTitle.Header" xml:space="preserve">
<value>Title</value>
</data>
<data name="LyricsSearchPageTitle" xml:space="preserve">
<value>Lyrics search - BetterLyrics</value>
</data>
<data name="LyricsSearchProviderEslrcFile" xml:space="preserve">
<value>Local .ESLRC files</value>
</data>
@@ -442,6 +442,18 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>Music gallery - BetterLyrics</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>Donation</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>Feedback</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>Library used</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>If you like this project, please consider supporting it by donating. Your support will help keep the project alive and encourage further development.</value>
</data>
<data name="SettingsPageAbout.Content" xml:space="preserve">
<value>About</value>
</data>
@@ -478,6 +490,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>Amount</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>Always on top</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>App appearance and behavior</value>
</data>
@@ -487,17 +502,8 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>App behavior</value>
</data>
<data name="SettingsPageAppDesktop.Text" xml:space="preserve">
<value>Desktop mode</value>
</data>
<data name="SettingsPageAppDock.Text" xml:space="preserve">
<value>Dock mode</value>
</data>
<data name="SettingsPageAppPictureInPicture.Text" xml:space="preserve">
<value>Picture-in-picture mode</value>
</data>
<data name="SettingsPageAppStandard.Text" xml:space="preserve">
<value>Standard</value>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>Apply</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>Auto-lock when activating desktop mode</value>
@@ -535,22 +541,37 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageCache.Header" xml:space="preserve">
<value>Cache</value>
</data>
<data name="SettingsPageChinese.Header" xml:space="preserve">
<value>Chinese pronunciation</value>
</data>
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>Convert Chinese to Traditional Chinese</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>Compact</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>Current lyrics window status</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve">
<value>Dark</value>
</data>
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>Show debug overlay</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<value>Delete</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>Desktop Acrylic</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>Advanced options</value>
</data>
<data name="SettingsPageDiscord.Header" xml:space="preserve">
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<value>This project is provided as is without warranty of any kind. All lyrics, fonts, icons, and other third-party resources are the property of their respective copyright holders. The author of this project does not claim ownership of such resources. This project is non-commercial and should not be used to infringe any rights. Users are responsible for ensuring their own use complies with applicable laws and licenses.</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
@@ -571,6 +592,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>Window height</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>Automatic adjustment</value>
</data>
<data name="SettingsPageEasingFuncType.Header" xml:space="preserve">
<value>Easing animation type</value>
</data>
@@ -625,7 +649,7 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageFan.Header" xml:space="preserve">
<value>Fan lyrics</value>
</data>
<data name="SettingsPageFAQ.Header" xml:space="preserve">
<data name="SettingsPageFAQ.Content" xml:space="preserve">
<value>Frequently asked questions</value>
</data>
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
@@ -637,15 +661,6 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>Rendering frame rate</value>
</data>
<data name="SettingsPageGitHub.ActionIconToolTip" xml:space="preserve">
<value>Open in new window</value>
</data>
<data name="SettingsPageGitHub.Description" xml:space="preserve">
<value>See source code on GitHub</value>
</data>
<data name="SettingsPageGitHub.Header" xml:space="preserve">
<value>This is an open source app</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>Extend the title bar to the entire page so that the window can be dragged in any non-interactive area</value>
</data>
@@ -653,10 +668,10 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<value>Global drag</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>Automatically hide the window when no songs are playing in dock mode or desktop mode</value>
<value>In docking mode or desktop mode, when no song is playing, the window will be automatically hidden; otherwise, the window will be automatically displayed.</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>Auto-hide window</value>
<value>Automatically hide/show windows</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>Force this app to appear on top of full-screen apps when docked or desktop mode is enabled</value>
@@ -673,9 +688,15 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>Japanese annotation</value>
</data>
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
<value>Join now</value>
</data>
<data name="SettingsPageJyutping.Content" xml:space="preserve">
<value>Cantonese pinyin</value>
</data>
<data name="SettingsPageKO.Content" xml:space="preserve">
<value>한국어</value>
</data>
@@ -895,6 +916,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>Top and bottom edge opacity</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<value>Lyrics window manager</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>Media library</value>
</data>
@@ -940,6 +964,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPagePathNotFound.Text" xml:space="preserve">
<value>The path cannot be found on your computer</value>
</data>
<data name="SettingsPagePinyin.Content" xml:space="preserve">
<value>Pinyin of Mandarin</value>
</data>
<data name="SettingsPagePlaybackLib.Content" xml:space="preserve">
<value>Playback sources</value>
</data>
@@ -958,9 +985,15 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>Shortcut keys for the previous track</value>
</data>
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQ feedback &amp; chat group</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>Record</value>
</data>
<data name="SettingsPageRecordedWindowStatus.Text" xml:space="preserve">
<value>Recorded window status</value>
</data>
<data name="SettingsPageRemoveInfo.Message" xml:space="preserve">
<value>Original files and folders in this path will not be deleted when removing it from this app</value>
</data>
@@ -973,6 +1006,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageRestart.Content" xml:space="preserve">
<value>Restart app to apply change</value>
</data>
<data name="SettingsPageRomaji.Header" xml:space="preserve">
<value>Japanese annotation</value>
</data>
<data name="SettingsPageSC.Content" xml:space="preserve">
<value>简体中文</value>
</data>
@@ -1015,6 +1051,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>This hotkey has been successfully registered</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>Lyrics window display and hide shortcut keys</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>Current value: </value>
</data>
@@ -1042,7 +1081,7 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageTC.Content" xml:space="preserve">
<value>繁體中文</value>
</data>
<data name="SettingsPageTelegram.Header" xml:space="preserve">
<data name="SettingsPageTelegram.Content" xml:space="preserve">
<value>Telegram</value>
</data>
<data name="SettingsPageTheme.Header" xml:space="preserve">

View File

@@ -135,8 +135,8 @@
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>標準モード</value>
</data>
<data name="BaseWindowAOTFlyoutItem.Text" xml:space="preserve">
<value>常にトップ</value>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<value>一般的な</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>ESCを押して、フルスクリーンモードを終了します</value>
@@ -252,15 +252,12 @@
<data name="LyricsPageTranslationProviderPrefix.Header" xml:space="preserve">
<value>翻訳プロバイダー</value>
</data>
<data name="LyricsSearchControlArtist.Text" xml:space="preserve">
<data name="LyricsSearchControlArtist.Header" xml:space="preserve">
<value>アーティスト</value>
</data>
<data name="LyricsSearchControlHelp.Text" xml:space="preserve">
<value>*保存変更はすぐに有効になります。その後、トラックの歌詞がマッピング情報とターゲット歌詞で取得されます。純粋な音楽としてのマーキングは、純粋な音楽プレースホルダーの歌詞に直接戻ります。元のデータで取得するためにリセット。</value>
</data>
<data name="LyricsSearchControlLyricsPreview.Text" xml:space="preserve">
<value>歌詞プレビュー</value>
</data>
<data name="LyricsSearchControlMappedAs.Text" xml:space="preserve">
<value>としてマッピングされました</value>
</data>
@@ -279,15 +276,18 @@
<data name="LyricsSearchControlSearch.Content" xml:space="preserve">
<value>検索する</value>
</data>
<data name="LyricsSearchControlSongInfoMapping.Text" xml:space="preserve">
<data name="LyricsSearchControlSongInfoMapping.Header" xml:space="preserve">
<value>曲情報マッピング</value>
</data>
<data name="LyricsSearchControlTargetSearchProvider.Text" xml:space="preserve">
<data name="LyricsSearchControlTargetSearchProvider.Header" xml:space="preserve">
<value>ターゲット歌詞検索プロバイダー</value>
</data>
<data name="LyricsSearchControlTitle.Text" xml:space="preserve">
<data name="LyricsSearchControlTitle.Header" xml:space="preserve">
<value>タイトル</value>
</data>
<data name="LyricsSearchPageTitle" xml:space="preserve">
<value>歌詞検索 - BetterLyrics</value>
</data>
<data name="LyricsSearchProviderEslrcFile" xml:space="preserve">
<value>ローカル.ESLRCファイル</value>
</data>
@@ -442,6 +442,18 @@
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>音楽ギャラリー - BetterLyrics</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>寄付</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>フィードバック</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>使用されているライブラリ</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>このプロジェクトが気に入っている場合は、寄付してサポートすることを検討してください。あなたのサポートは、プロジェクトを生かし続け、さらなる開発を促進するのに役立ちます。</value>
</data>
<data name="SettingsPageAbout.Content" xml:space="preserve">
<value>について</value>
</data>
@@ -478,6 +490,9 @@
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>量</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>常にトップ</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>アプリの外観と動作</value>
</data>
@@ -487,17 +502,8 @@
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>アプリの動作</value>
</data>
<data name="SettingsPageAppDesktop.Text" xml:space="preserve">
<value>デスクトップモード</value>
</data>
<data name="SettingsPageAppDock.Text" xml:space="preserve">
<value>ドックモード</value>
</data>
<data name="SettingsPageAppPictureInPicture.Text" xml:space="preserve">
<value>ピクチャーインピクチャーモード</value>
</data>
<data name="SettingsPageAppStandard.Text" xml:space="preserve">
<value>標準モード</value>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>適用する</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>デスクトップモードをアクティブにするときの自動ロック</value>
@@ -535,22 +541,37 @@
<data name="SettingsPageCache.Header" xml:space="preserve">
<value>キャッシュ</value>
</data>
<data name="SettingsPageChinese.Header" xml:space="preserve">
<value>中国の発音</value>
</data>
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>中国人を伝統的な中国人に変換します</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>コンパクト</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>現在の歌詞ウィンドウステータス</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve">
<value>暗い</value>
</data>
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>デバッグオーバーレイを表示します</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<value>消去</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>デスクトップアクリル</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>高度なオプション</value>
</data>
<data name="SettingsPageDiscord.Header" xml:space="preserve">
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<value>このプロジェクトは、いかなる種類の保証もなく現状のまま提供されています。すべての歌詞、フォント、アイコン、およびその他のサードパーティのリソースは、それぞれの著作権所有者の財産です。このプロジェクトの作成者は、そのようなリソースの所有権を主張していません。このプロジェクトは非営利的であり、いかなる権利も侵害するために使用すべきではありません。ユーザーは、自らの使用が適用される法律およびライセンスに準拠していることを確認する責任があります。</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
@@ -571,6 +592,9 @@
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>窓の高さ</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>自動調整</value>
</data>
<data name="SettingsPageEasingFuncType.Header" xml:space="preserve">
<value>アニメーションタイプを緩和します</value>
</data>
@@ -625,7 +649,7 @@
<data name="SettingsPageFan.Header" xml:space="preserve">
<value>ファンの歌詞</value>
</data>
<data name="SettingsPageFAQ.Header" xml:space="preserve">
<data name="SettingsPageFAQ.Content" xml:space="preserve">
<value>よくある質問</value>
</data>
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
@@ -637,15 +661,6 @@
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>レンダリングフレームレート</value>
</data>
<data name="SettingsPageGitHub.ActionIconToolTip" xml:space="preserve">
<value>新しいウィンドウで開きます</value>
</data>
<data name="SettingsPageGitHub.Description" xml:space="preserve">
<value>GitHubのソースコードを参照してください</value>
</data>
<data name="SettingsPageGitHub.Header" xml:space="preserve">
<value>これはオープンソースアプリです</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>タイトルバーをページ全体に拡張して、ウィンドウを非対話領域でドラッグできるようにします</value>
</data>
@@ -653,10 +668,10 @@
<value>グローバルドラッグ</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>ドックモードやデスクトップモードで再生されている曲がないときにウィンドウ自動的に非表示にする</value>
<value>ドッキングモードまたはデスクトップモードでは、曲が再生されていない場合、ウィンドウ自動的に非表示になります。それ以外の場合、ウィンドウが自動的に表示されます。</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>自動ハイドウィンドウ</value>
<value>Windowsを自動的に非表示/表示します</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>このアプリは、ドッキングまたはデスクトップモードが有効になっているときにフルスクリーンアプリの上に表示されます</value>
@@ -673,9 +688,15 @@
<data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>日本の注釈</value>
</data>
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
<value>今すぐ参加してください</value>
</data>
<data name="SettingsPageJyutping.Content" xml:space="preserve">
<value>広東語のピンイン</value>
</data>
<data name="SettingsPageKO.Content" xml:space="preserve">
<value>한국어</value>
</data>
@@ -877,15 +898,15 @@
<data name="SettingsPageLyricsThin.Content" xml:space="preserve">
<value>薄い</value>
</data>
<data name="SettingsPageLyricsTimeline.Header" xml:space="preserve">
<value>歌詞のタイムラインを同期</value>
</data>
<data name="SettingsPageLyricsTimelineThreshold.Description" xml:space="preserve">
<value>歌詞の進行が不安定な場合は、このしきい値を増やしてみてください。この値を変更すると、歌詞の同期が逸脱する可能性があります</value>
</data>
<data name="SettingsPageLyricsTimelineThreshold.Header" xml:space="preserve">
<value>歌詞タイムライン同期しきい値</value>
</data>
<data name="SettingsPageLyricsTimeline.Header" xml:space="preserve">
<value>歌詞のタイムラインを同期</value>
</data>
<data name="SettingsPageLyricsTranslationHighlight.Header" xml:space="preserve">
<value>翻訳ハイライト</value>
</data>
@@ -895,6 +916,9 @@
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>上端と下端の不透明度</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<value>歌詞ウィンドウマネージャー</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>メディアライブラリ</value>
</data>
@@ -940,6 +964,9 @@
<data name="SettingsPagePathNotFound.Text" xml:space="preserve">
<value>パスはコンピューターでは見つかりません</value>
</data>
<data name="SettingsPagePinyin.Content" xml:space="preserve">
<value>マンダリンのピンイン</value>
</data>
<data name="SettingsPagePlaybackLib.Content" xml:space="preserve">
<value>再生ソース</value>
</data>
@@ -958,9 +985,15 @@
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>前のトラックのショートカットキー</value>
</data>
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQフィードバックチャットグループ</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>記録</value>
</data>
<data name="SettingsPageRecordedWindowStatus.Text" xml:space="preserve">
<value>記録されたウィンドウステータス</value>
</data>
<data name="SettingsPageRemoveInfo.Message" xml:space="preserve">
<value>このパスの元のファイルとフォルダーは、このアプリから削除するときに削除されません</value>
</data>
@@ -973,6 +1006,9 @@
<data name="SettingsPageRestart.Content" xml:space="preserve">
<value>変更を適用するためのアプリを再起動します</value>
</data>
<data name="SettingsPageRomaji.Header" xml:space="preserve">
<value>日本の注釈</value>
</data>
<data name="SettingsPageSC.Content" xml:space="preserve">
<value>简体中文</value>
</data>
@@ -1015,6 +1051,9 @@
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>このホットキーは正常に登録されています</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>歌詞ウィンドウディスプレイとショートカットキーを非表示にします</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>現在の値: </value>
</data>
@@ -1042,7 +1081,7 @@
<data name="SettingsPageTC.Content" xml:space="preserve">
<value>繁體中文</value>
</data>
<data name="SettingsPageTelegram.Header" xml:space="preserve">
<data name="SettingsPageTelegram.Content" xml:space="preserve">
<value>Telegram</value>
</data>
<data name="SettingsPageTheme.Header" xml:space="preserve">

View File

@@ -135,8 +135,8 @@
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>표준 모드</value>
</data>
<data name="BaseWindowAOTFlyoutItem.Text" xml:space="preserve">
<value>항상 위에</value>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<value>일반적인</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>ESC를 눌러 전체 화면 모드를 종료하십시오</value>
@@ -252,15 +252,12 @@
<data name="LyricsPageTranslationProviderPrefix.Header" xml:space="preserve">
<value>번역 제공자</value>
</data>
<data name="LyricsSearchControlArtist.Text" xml:space="preserve">
<data name="LyricsSearchControlArtist.Header" xml:space="preserve">
<value>아티스트</value>
</data>
<data name="LyricsSearchControlHelp.Text" xml:space="preserve">
<value>* 변경 사항 저장 변경은 즉시 적용되며, 그 후 트랙 가사는 맵핑 정보와 대상 가사로 검색됩니다. 순수한 음악으로 표시하면 순수한 음악 자리 표시 자 가사로 직접 돌아갑니다. 원래 데이터로 검색하도록 재설정하십시오.</value>
</data>
<data name="LyricsSearchControlLyricsPreview.Text" xml:space="preserve">
<value>가사 미리보기</value>
</data>
<data name="LyricsSearchControlMappedAs.Text" xml:space="preserve">
<value>로 매핑됨</value>
</data>
@@ -279,15 +276,18 @@
<data name="LyricsSearchControlSearch.Content" xml:space="preserve">
<value>검색</value>
</data>
<data name="LyricsSearchControlSongInfoMapping.Text" xml:space="preserve">
<data name="LyricsSearchControlSongInfoMapping.Header" xml:space="preserve">
<value>노래 정보 매핑</value>
</data>
<data name="LyricsSearchControlTargetSearchProvider.Text" xml:space="preserve">
<data name="LyricsSearchControlTargetSearchProvider.Header" xml:space="preserve">
<value>가사 검색 공급자를 타겟팅하십시오</value>
</data>
<data name="LyricsSearchControlTitle.Text" xml:space="preserve">
<data name="LyricsSearchControlTitle.Header" xml:space="preserve">
<value>제목</value>
</data>
<data name="LyricsSearchPageTitle" xml:space="preserve">
<value>가사 검색 - BetterLyrics</value>
</data>
<data name="LyricsSearchProviderEslrcFile" xml:space="preserve">
<value>로컬 .ESLRC 파일</value>
</data>
@@ -442,6 +442,18 @@
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>음악 갤러리 - BetterLyrics</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>기부</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>피드백</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>사용 된 라이브러리</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>이 프로젝트가 마음에 들면 기부하여 지원을 고려하십시오. 귀하의 지원은 프로젝트를 계속 유지하고 추가 개발을 장려하는 데 도움이 될 것입니다.</value>
</data>
<data name="SettingsPageAbout.Content" xml:space="preserve">
<value>에 대한</value>
</data>
@@ -478,6 +490,9 @@
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>금액</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>항상 위에</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>앱 외관과 행동</value>
</data>
@@ -487,17 +502,8 @@
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>앱 동작</value>
</data>
<data name="SettingsPageAppDesktop.Text" xml:space="preserve">
<value>데스크탑 모드</value>
</data>
<data name="SettingsPageAppDock.Text" xml:space="preserve">
<value>도크 모드</value>
</data>
<data name="SettingsPageAppPictureInPicture.Text" xml:space="preserve">
<value>사진 인당 모드</value>
</data>
<data name="SettingsPageAppStandard.Text" xml:space="preserve">
<value>표준 모드</value>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>적용하다</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>데스크탑 모드를 활성화 할 때 자동 잠금</value>
@@ -535,22 +541,37 @@
<data name="SettingsPageCache.Header" xml:space="preserve">
<value>은닉처</value>
</data>
<data name="SettingsPageChinese.Header" xml:space="preserve">
<value>화음</value>
</data>
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>중국어를 전통적인 중국어로 전환합니다</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>콤팩트</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>현재 가사 창 상태</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve">
<value>어두운</value>
</data>
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>디버그 오버레이를 표시하십시오</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<value>삭제</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>데스크탑 아크릴</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>고급 옵션</value>
</data>
<data name="SettingsPageDiscord.Header" xml:space="preserve">
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<value>이 프로젝트는 어떠한 종류의 보증도 없이 그대로 제공됩니다. 모든 가사, 글꼴, 아이콘 및 기타 제3자 리소스는 해당 저작권 소유자의 재산입니다. 이 프로젝트의 저자는 그러한 자원의 소유권을 주장하지 않습니다. 이 프로젝트는 비상업적이기 때문에 어떠한 권리도 침해해서는 안 됩니다. 사용자는 자신의 사용이 관련 법률 및 라이센스를 준수하는지 확인할 책임이 있습니다.</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
@@ -571,6 +592,9 @@
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>창 높이</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>자동 조정</value>
</data>
<data name="SettingsPageEasingFuncType.Header" xml:space="preserve">
<value>애니메이션 유형 완화</value>
</data>
@@ -625,7 +649,7 @@
<data name="SettingsPageFan.Header" xml:space="preserve">
<value>팬 가사</value>
</data>
<data name="SettingsPageFAQ.Header" xml:space="preserve">
<data name="SettingsPageFAQ.Content" xml:space="preserve">
<value>자주 묻는 질문</value>
</data>
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
@@ -637,15 +661,6 @@
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>렌더링 프레임 속도</value>
</data>
<data name="SettingsPageGitHub.ActionIconToolTip" xml:space="preserve">
<value>새 창에서 열립니다</value>
</data>
<data name="SettingsPageGitHub.Description" xml:space="preserve">
<value>GitHub의 소스 코드를 참조하십시오</value>
</data>
<data name="SettingsPageGitHub.Header" xml:space="preserve">
<value>이것은 오픈 소스 앱입니다</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>비 중과 영역에서 창을 드래그 할 수 있도록 제목 표시 줄을 전체 페이지로 확장하십시오.</value>
</data>
@@ -653,10 +668,10 @@
<value>글로벌 드래그</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>도 모드 또는 데스크탑 모드에서 재생되지 않을 때는 자동으로 숨기고 있습니다</value>
<value>도 모드 또는 데스크탑 모드에서는 노래가 재생되지 않으면 자동으로 숨겨집니다. 그렇지 않으면 창이 자동으로 표시됩니다.</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>자동 가죽 창</value>
<value>Windows를 자동으로 숨기고 표시합니다</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>도킹 또는 데스크탑 모드가 활성화 될 때이 앱이 전체 화면 앱 위에 나타나도록 강요</value>
@@ -673,9 +688,15 @@
<data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>일본 주석</value>
</data>
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
<value>지금 가입하십시오</value>
</data>
<data name="SettingsPageJyutping.Content" xml:space="preserve">
<value>광동어 Pinyin</value>
</data>
<data name="SettingsPageKO.Content" xml:space="preserve">
<value>한국어</value>
</data>
@@ -877,15 +898,15 @@
<data name="SettingsPageLyricsThin.Content" xml:space="preserve">
<value>얇은</value>
</data>
<data name="SettingsPageLyricsTimeline.Header" xml:space="preserve">
<value>가사 타임라인 동기화</value>
</data>
<data name="SettingsPageLyricsTimelineThreshold.Description" xml:space="preserve">
<value>가사 진행 상황이 불안하다면이 임계 값을 높이십시오. 이 값을 변경하면 가사가 동기화 될 수 있습니다</value>
</data>
<data name="SettingsPageLyricsTimelineThreshold.Header" xml:space="preserve">
<value>가사 타임 라인 동기화 임계 값</value>
</data>
<data name="SettingsPageLyricsTimeline.Header" xml:space="preserve">
<value>가사 타임라인 동기화</value>
</data>
<data name="SettingsPageLyricsTranslationHighlight.Header" xml:space="preserve">
<value>번역 하이라이트</value>
</data>
@@ -895,6 +916,9 @@
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>상단 및 하단 가장자리 불투명도</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<value>가사 창 관리자</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>미디어 라이브러리</value>
</data>
@@ -940,6 +964,9 @@
<data name="SettingsPagePathNotFound.Text" xml:space="preserve">
<value>경로는 컴퓨터에서 찾을 수 없습니다</value>
</data>
<data name="SettingsPagePinyin.Content" xml:space="preserve">
<value>만다린의 피니 인</value>
</data>
<data name="SettingsPagePlaybackLib.Content" xml:space="preserve">
<value>재생 소스</value>
</data>
@@ -958,9 +985,15 @@
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>이전 트랙의 바로 가기 키</value>
</data>
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQ 피드백 및 채팅 그룹</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>기록</value>
</data>
<data name="SettingsPageRecordedWindowStatus.Text" xml:space="preserve">
<value>기록 된 창 상태</value>
</data>
<data name="SettingsPageRemoveInfo.Message" xml:space="preserve">
<value>이 경로의 원본 파일과 폴더는이 앱에서 제거 할 때 삭제되지 않습니다.</value>
</data>
@@ -973,6 +1006,9 @@
<data name="SettingsPageRestart.Content" xml:space="preserve">
<value>변경 사항을 적용하려면 앱을 다시 시작하십시오</value>
</data>
<data name="SettingsPageRomaji.Header" xml:space="preserve">
<value>일본 주석</value>
</data>
<data name="SettingsPageSC.Content" xml:space="preserve">
<value>简体中文</value>
</data>
@@ -1015,6 +1051,9 @@
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>이 핫키는 성공적으로 등록되었습니다</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>가사 창 디스플레이 및 바로 가기 키 숨기기</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>현재 가치 : </value>
</data>
@@ -1042,7 +1081,7 @@
<data name="SettingsPageTC.Content" xml:space="preserve">
<value>繁體中文</value>
</data>
<data name="SettingsPageTelegram.Header" xml:space="preserve">
<data name="SettingsPageTelegram.Content" xml:space="preserve">
<value>Telegram</value>
</data>
<data name="SettingsPageTheme.Header" xml:space="preserve">

View File

@@ -135,8 +135,8 @@
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>标准模式</value>
</data>
<data name="BaseWindowAOTFlyoutItem.Text" xml:space="preserve">
<value>将应用置于顶层</value>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<value>通用</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>按 Esc 退出全屏模式</value>
@@ -252,15 +252,12 @@
<data name="LyricsPageTranslationProviderPrefix.Header" xml:space="preserve">
<value>翻译来源</value>
</data>
<data name="LyricsSearchControlArtist.Text" xml:space="preserve">
<data name="LyricsSearchControlArtist.Header" xml:space="preserve">
<value>艺术家</value>
</data>
<data name="LyricsSearchControlHelp.Text" xml:space="preserve">
<value>* 保存更改立即生效,此后将以映射信息和目标歌词源检索该曲目歌词;标记为纯音乐将直接返回纯音乐占位歌词。重置以按原始数据检索。</value>
</data>
<data name="LyricsSearchControlLyricsPreview.Text" xml:space="preserve">
<value>歌词预览</value>
</data>
<data name="LyricsSearchControlMappedAs.Text" xml:space="preserve">
<value>映射为</value>
</data>
@@ -279,15 +276,18 @@
<data name="LyricsSearchControlSearch.Content" xml:space="preserve">
<value>搜索</value>
</data>
<data name="LyricsSearchControlSongInfoMapping.Text" xml:space="preserve">
<data name="LyricsSearchControlSongInfoMapping.Header" xml:space="preserve">
<value>歌曲信息映射</value>
</data>
<data name="LyricsSearchControlTargetSearchProvider.Text" xml:space="preserve">
<data name="LyricsSearchControlTargetSearchProvider.Header" xml:space="preserve">
<value>目标歌词搜索提供商</value>
</data>
<data name="LyricsSearchControlTitle.Text" xml:space="preserve">
<data name="LyricsSearchControlTitle.Header" xml:space="preserve">
<value>标题</value>
</data>
<data name="LyricsSearchPageTitle" xml:space="preserve">
<value>歌词搜索 - BetterLyrics</value>
</data>
<data name="LyricsSearchProviderEslrcFile" xml:space="preserve">
<value>本地 .ESLRC 文件</value>
</data>
@@ -442,6 +442,18 @@
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>音乐库 - BetterLyrics</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>捐贈</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>反馈</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>使用的库</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>如果您喜欢这个项目,请考虑通过捐赠来支持它。您的支持将有助于保持项目的生命并鼓励进一步的发展。</value>
</data>
<data name="SettingsPageAbout.Content" xml:space="preserve">
<value>关于</value>
</data>
@@ -478,6 +490,9 @@
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>量</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>将应用置于顶层</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>应用外观与行为</value>
</data>
@@ -487,17 +502,8 @@
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>应用行为</value>
</data>
<data name="SettingsPageAppDesktop.Text" xml:space="preserve">
<value>桌面模式</value>
</data>
<data name="SettingsPageAppDock.Text" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="SettingsPageAppPictureInPicture.Text" xml:space="preserve">
<value>画中画模式</value>
</data>
<data name="SettingsPageAppStandard.Text" xml:space="preserve">
<value>标准模式</value>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>应用</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>启动桌面模式时随即锁定窗口</value>
@@ -535,22 +541,37 @@
<data name="SettingsPageCache.Header" xml:space="preserve">
<value>缓存</value>
</data>
<data name="SettingsPageChinese.Header" xml:space="preserve">
<value>中文注音</value>
</data>
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>中文转换为繁体</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>紧凑</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>当前歌词窗口状态</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve">
<value>深色</value>
</data>
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>显示调试覆盖层</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<value>删除</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>亚克力(桌面)</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>高级选项</value>
</data>
<data name="SettingsPageDiscord.Header" xml:space="preserve">
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<value>本项目按原样提供,不提供任何形式的保证。所有歌词、字体、图标和其他第三方资源均为其各自版权所有者的财产。本项目的作者不主张此类资源的所有权。本项目为非商业性项目,不得用于侵犯任何权利。用户有责任确保自己的使用符合适用的法律和许可。</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
@@ -571,6 +592,9 @@
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>窗口高度</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>自动调整</value>
</data>
<data name="SettingsPageEasingFuncType.Header" xml:space="preserve">
<value>缓动动画类型</value>
</data>
@@ -625,7 +649,7 @@
<data name="SettingsPageFan.Header" xml:space="preserve">
<value>扇形歌词</value>
</data>
<data name="SettingsPageFAQ.Header" xml:space="preserve">
<data name="SettingsPageFAQ.Content" xml:space="preserve">
<value>常见问题与解答</value>
</data>
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
@@ -637,15 +661,6 @@
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>渲染帧率</value>
</data>
<data name="SettingsPageGitHub.ActionIconToolTip" xml:space="preserve">
<value>在新窗口中打开</value>
</data>
<data name="SettingsPageGitHub.Description" xml:space="preserve">
<value>在 GitHub 上查看源代码</value>
</data>
<data name="SettingsPageGitHub.Header" xml:space="preserve">
<value>此应用已开源</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>将标题栏扩展至整个页面使得在任意非交互区域均可拖拽窗口</value>
</data>
@@ -653,10 +668,10 @@
<value>全局拖拽</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>停靠模式或桌面模式下,无歌曲正在播放时,自动隐藏窗口</value>
<value>停靠模式或桌面模式下,无歌曲正在播放时,自动隐藏窗口;反之自动显示窗口</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>自动隐藏窗口</value>
<value>自动隐藏/显示窗口</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>当启用停靠模式或桌面模式时强制将本应用显示在全屏应用的上方</value>
@@ -673,9 +688,15 @@
<data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>日语注音</value>
</data>
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
<value>立即加入</value>
</data>
<data name="SettingsPageJyutping.Content" xml:space="preserve">
<value>广东话拼音</value>
</data>
<data name="SettingsPageKO.Content" xml:space="preserve">
<value>한국어</value>
</data>
@@ -877,15 +898,15 @@
<data name="SettingsPageLyricsThin.Content" xml:space="preserve">
<value>极细</value>
</data>
<data name="SettingsPageLyricsTimeline.Header" xml:space="preserve">
<value>歌词时间轴同步</value>
</data>
<data name="SettingsPageLyricsTimelineThreshold.Description" xml:space="preserve">
<value>当歌词进度抖动时,请尝试增加该阈值;更改此值会导致歌词同步有偏差</value>
</data>
<data name="SettingsPageLyricsTimelineThreshold.Header" xml:space="preserve">
<value>歌词时间轴同步阈值</value>
</data>
<data name="SettingsPageLyricsTimeline.Header" xml:space="preserve">
<value>歌词时间轴同步</value>
</data>
<data name="SettingsPageLyricsTranslationHighlight.Header" xml:space="preserve">
<value>翻译高亮</value>
</data>
@@ -895,6 +916,9 @@
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>上下边缘不透明度</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<value>歌词窗口管理</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>媒体库</value>
</data>
@@ -940,6 +964,9 @@
<data name="SettingsPagePathNotFound.Text" xml:space="preserve">
<value>无法在您的计算机中找到该路径</value>
</data>
<data name="SettingsPagePinyin.Content" xml:space="preserve">
<value>普通话拼音</value>
</data>
<data name="SettingsPagePlaybackLib.Content" xml:space="preserve">
<value>播放源</value>
</data>
@@ -958,9 +985,15 @@
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>上一首曲目快捷键</value>
</data>
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQ 反馈交流群</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>记录</value>
</data>
<data name="SettingsPageRecordedWindowStatus.Text" xml:space="preserve">
<value>记录的窗口状态</value>
</data>
<data name="SettingsPageRemoveInfo.Message" xml:space="preserve">
<value>路径中的原始文件和文件夹不会被删除</value>
</data>
@@ -973,6 +1006,9 @@
<data name="SettingsPageRestart.Content" xml:space="preserve">
<value>重启应用以应用更改</value>
</data>
<data name="SettingsPageRomaji.Header" xml:space="preserve">
<value>日语注音</value>
</data>
<data name="SettingsPageSC.Content" xml:space="preserve">
<value>简体中文</value>
</data>
@@ -1015,6 +1051,9 @@
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>该热键已成功注册</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>歌词窗口显示和隐藏快捷键</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>当前值: </value>
</data>
@@ -1042,7 +1081,7 @@
<data name="SettingsPageTC.Content" xml:space="preserve">
<value>繁體中文</value>
</data>
<data name="SettingsPageTelegram.Header" xml:space="preserve">
<data name="SettingsPageTelegram.Content" xml:space="preserve">
<value>Telegram</value>
</data>
<data name="SettingsPageTheme.Header" xml:space="preserve">

View File

@@ -135,8 +135,8 @@
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>標準模式</value>
</data>
<data name="BaseWindowAOTFlyoutItem.Text" xml:space="preserve">
<value>將應用置於頂層</value>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<value>一般</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>按 Esc 退出全螢幕模式</value>
@@ -252,15 +252,12 @@
<data name="LyricsPageTranslationProviderPrefix.Header" xml:space="preserve">
<value>翻譯來源</value>
</data>
<data name="LyricsSearchControlArtist.Text" xml:space="preserve">
<data name="LyricsSearchControlArtist.Header" xml:space="preserve">
<value>藝術家</value>
</data>
<data name="LyricsSearchControlHelp.Text" xml:space="preserve">
<value>* 保存更改立即生效,此後將以映射信息和目標歌詞源檢索該曲目歌詞;標記為純音樂將直接返回純音樂佔位歌詞。重置以按原始數據檢索。</value>
</data>
<data name="LyricsSearchControlLyricsPreview.Text" xml:space="preserve">
<value>歌詞預覽</value>
</data>
<data name="LyricsSearchControlMappedAs.Text" xml:space="preserve">
<value>映射爲</value>
</data>
@@ -279,15 +276,18 @@
<data name="LyricsSearchControlSearch.Content" xml:space="preserve">
<value>搜索</value>
</data>
<data name="LyricsSearchControlSongInfoMapping.Text" xml:space="preserve">
<data name="LyricsSearchControlSongInfoMapping.Header" xml:space="preserve">
<value>歌曲信息映射</value>
</data>
<data name="LyricsSearchControlTargetSearchProvider.Text" xml:space="preserve">
<data name="LyricsSearchControlTargetSearchProvider.Header" xml:space="preserve">
<value>目標歌詞搜尋提供者</value>
</data>
<data name="LyricsSearchControlTitle.Text" xml:space="preserve">
<data name="LyricsSearchControlTitle.Header" xml:space="preserve">
<value>標題</value>
</data>
<data name="LyricsSearchPageTitle" xml:space="preserve">
<value>歌詞搜尋 - BetterLyrics</value>
</data>
<data name="LyricsSearchProviderEslrcFile" xml:space="preserve">
<value>本地 .ESLRC 文件</value>
</data>
@@ -442,6 +442,18 @@
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>音樂庫 - BetterLyrics</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>捐贈</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>回饋</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>使用的庫</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>如果您喜歡這個項目,請考慮通過捐贈來支持它。您的支持將有助於保持項目的生命並鼓勵進一步的發展。</value>
</data>
<data name="SettingsPageAbout.Content" xml:space="preserve">
<value>關於</value>
</data>
@@ -478,6 +490,9 @@
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>量</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>將應用置於頂層</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>應用外觀與行為</value>
</data>
@@ -487,17 +502,8 @@
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>應用行為</value>
</data>
<data name="SettingsPageAppDesktop.Text" xml:space="preserve">
<value>桌面模式</value>
</data>
<data name="SettingsPageAppDock.Text" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="SettingsPageAppPictureInPicture.Text" xml:space="preserve">
<value>畫中畫模式</value>
</data>
<data name="SettingsPageAppStandard.Text" xml:space="preserve">
<value>標準模式</value>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>應用</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>啟動桌面模式時隨即鎖定窗口</value>
@@ -535,22 +541,37 @@
<data name="SettingsPageCache.Header" xml:space="preserve">
<value>快取</value>
</data>
<data name="SettingsPageChinese.Header" xml:space="preserve">
<value>中文注音</value>
</data>
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>中文轉換為繁體</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>緊湊</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>當前歌詞窗口狀態</value>
</data>
<data name="SettingsPageDark.Content" xml:space="preserve">
<value>深色</value>
</data>
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>顯示調試覆蓋層</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<value>刪除</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>亞克力(桌面)</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>高級選項</value>
</data>
<data name="SettingsPageDiscord.Header" xml:space="preserve">
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<value>本項目按原樣提供,不提供任何形式的保證。所有歌詞、字型、圖示和其他第三方資源均屬其各自的版權擁有者所有。此專案的作者並未聲明此類資源的所有權。此專案為非商業專案,不應用於侵犯任何權利。用戶有責任確保自己的使用符合適用的法律和許可證。</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
@@ -571,6 +592,9 @@
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>窗口高度</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>自動調整</value>
</data>
<data name="SettingsPageEasingFuncType.Header" xml:space="preserve">
<value>緩動動畫類型</value>
</data>
@@ -625,7 +649,7 @@
<data name="SettingsPageFan.Header" xml:space="preserve">
<value>扇形歌詞</value>
</data>
<data name="SettingsPageFAQ.Header" xml:space="preserve">
<data name="SettingsPageFAQ.Content" xml:space="preserve">
<value>常見問題與解答</value>
</data>
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
@@ -637,15 +661,6 @@
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>渲染幀率</value>
</data>
<data name="SettingsPageGitHub.ActionIconToolTip" xml:space="preserve">
<value>在新視窗中開啟</value>
</data>
<data name="SettingsPageGitHub.Description" xml:space="preserve">
<value>在 GitHub 上查看原始碼</value>
</data>
<data name="SettingsPageGitHub.Header" xml:space="preserve">
<value>此應用程式已開源</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>將標題列擴展至整個頁面使得在任意非互動區域均可拖曳窗口</value>
</data>
@@ -653,10 +668,10 @@
<value>全域拖曳</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>停靠模式或桌面模式下,無歌曲正在播放時,自動隱藏窗口</value>
<value>停靠模式或桌面模式下,無歌曲正在播放時,自動隱藏窗口;反之自動顯示窗口</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>自動隱藏窗口</value>
<value>自動隱藏/顯示窗口</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>啟用停靠模式或桌面模式時強制將本應用程式顯示在全螢幕應用程式的上方</value>
@@ -673,9 +688,15 @@
<data name="SettingsPageJA.Content" xml:space="preserve">
<value>日本語</value>
</data>
<data name="SettingsPageJapanese.Header" xml:space="preserve">
<value>日語注音</value>
</data>
<data name="SettingsPageJoinNowButton.Content" xml:space="preserve">
<value>立即加入</value>
</data>
<data name="SettingsPageJyutping.Content" xml:space="preserve">
<value>廣東話拼音</value>
</data>
<data name="SettingsPageKO.Content" xml:space="preserve">
<value>한국어</value>
</data>
@@ -895,6 +916,9 @@
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>上下邊緣不透明度</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<value>歌詞視窗管理</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>媒體庫</value>
</data>
@@ -940,6 +964,9 @@
<data name="SettingsPagePathNotFound.Text" xml:space="preserve">
<value>無法在您的電腦中找到該路徑</value>
</data>
<data name="SettingsPagePinyin.Content" xml:space="preserve">
<value>普通話拼音</value>
</data>
<data name="SettingsPagePlaybackLib.Content" xml:space="preserve">
<value>播放源</value>
</data>
@@ -958,9 +985,15 @@
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>上一首曲目快捷鍵</value>
</data>
<data name="SettingsPageQQGroup.Header" xml:space="preserve">
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQ 回饋交流群</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>記錄</value>
</data>
<data name="SettingsPageRecordedWindowStatus.Text" xml:space="preserve">
<value>記錄的窗口狀態</value>
</data>
<data name="SettingsPageRemoveInfo.Message" xml:space="preserve">
<value>路徑中的原始檔案和資料夾不會被刪除</value>
</data>
@@ -973,6 +1006,9 @@
<data name="SettingsPageRestart.Content" xml:space="preserve">
<value>重啟應用程式以應用更改</value>
</data>
<data name="SettingsPageRomaji.Header" xml:space="preserve">
<value>日語注音</value>
</data>
<data name="SettingsPageSC.Content" xml:space="preserve">
<value>简体中文</value>
</data>
@@ -1015,6 +1051,9 @@
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>該熱鍵已成功註冊</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>歌詞窗口顯示和隱藏快捷鍵</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>目前值: </value>
</data>
@@ -1042,7 +1081,7 @@
<data name="SettingsPageTC.Content" xml:space="preserve">
<value>繁體中文</value>
</data>
<data name="SettingsPageTelegram.Header" xml:space="preserve">
<data name="SettingsPageTelegram.Content" xml:space="preserve">
<value>Telegram</value>
</data>
<data name="SettingsPageTheme.Header" xml:space="preserve">

View File

@@ -36,7 +36,7 @@ namespace BetterLyrics.WinUI3.ViewModels
{
if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.CurrentLyricsWindowMode))
if (message.PropertyName == nameof(LiveStates.LyricsWindowMode))
{
SelectedTabIndex = (int)message.NewValue;
}

View File

@@ -1,5 +1,7 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.LiveStatesService;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
@@ -13,19 +15,25 @@ namespace BetterLyrics.WinUI3.ViewModels
public partial class AppSettingsControlViewModel : BaseViewModel
{
private readonly ISettingsService _settingsService;
private readonly ILiveStatesService _liveStatesService;
[ObservableProperty]
public partial AppSettings AppSettings { get; set; }
[ObservableProperty]
public partial LiveStates LiveStates { get; set; }
[ObservableProperty]
public partial ObservableCollection<string> MonitorDeviceNames { get; set; }
public AppSettingsControlViewModel(ISettingsService settingsService)
public AppSettingsControlViewModel(ISettingsService settingsService, ILiveStatesService liveStatesService)
{
_settingsService = settingsService;
_liveStatesService = liveStatesService;
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
AppSettings = _settingsService.AppSettings;
LiveStates = _liveStatesService.LiveStates;
}
[RelayCommand]
@@ -41,6 +49,19 @@ namespace BetterLyrics.WinUI3.ViewModels
AppSettings.DockModeSettings.DockMonitorDeviceName = MonitorHelper.GetPrimaryMonitorDeviceName();
}
[RelayCommand]
private void RecordCurrentWindowBounds()
{
AppSettings.WindowBoundsRecords.Add(new WindowBoundsRecord
{
WindowBounds = LiveStates.LyricsWindowBounds,
MonitorDeviceName = LiveStates.LyricsWindowMonitorName,
MonitorBounds = LiveStates.LyricsWindowMonitorBounds,
DemoWindowBounds = LiveStates.DemoLyricsWindowBounds,
DemoMonitorBounds = LiveStates.DemoLyricsWindowMonitorBounds
});
}
public async Task<bool> ToggleAutoStartupAsync(bool target)
{
StartupTask startupTask = await StartupTask.GetAsync(Constants.App.AutoStartupTaskId);

View File

@@ -102,6 +102,15 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty]
public partial bool IsSongPlaying { get; set; }
[ObservableProperty]
public partial float TimelineSliderThumbOpacity { get; set; } = 0f;
[ObservableProperty]
public partial LyricsLine? TimelineSliderThumbLyricsLine { get; set; }
[ObservableProperty]
public partial double TimelineSliderThumbSeconds { get; set; } = 0;
public void Receive(PropertyChangedMessage<bool> message)
{
if (message.Sender is LyricsWindowViewModel)
@@ -157,6 +166,11 @@ namespace BetterLyrics.WinUI3.ViewModels
}
}
partial void OnTimelineSliderThumbSecondsChanged(double value)
{
TimelineSliderThumbLyricsLine = _mediaSessionsService.CurrentLyricsData?.GetLyricsLine(value);
}
//partial void OnVolumeChanged(int value)
//{
// SystemVolumeHelper.SetMasterVolume(value);

View File

@@ -33,7 +33,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
using var combined = new CanvasCommandList(control);
using var combinedDs = combined.CreateDrawingSession();
switch (_liveStatesService.LiveStates.CurrentLyricsWindowMode)
switch (_liveStatesService.LiveStates.LyricsWindowMode)
{
case LyricsWindowMode.DockMode:
FillBackground(control, combinedDs, _immersiveBgColorTransition.Value, 0f,
@@ -236,7 +236,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
// 先铺一层带默认透明度的已经加了模糊效果的歌词作为最底层(背景歌词层次)
using var backgroundFontEffect = CanvasHelper.CreateFontEffect(line, control, _strokeFontColor,
_liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsFontStrokeWidth, _bgFontColor);
_liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontStrokeWidth, _bgFontColor);
using var backgroundEffect = CanvasHelper.CreateBackgroundEffect(line, backgroundFontEffect, _lyricsOpacityTransition.Value);
combinedDs.DrawImage(backgroundEffect);
@@ -247,43 +247,43 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
using var charMask = CanvasHelper.CreateCharMask(control, line, charStartIndex, charLength, charProgress);
using var lineStartToCharMask = CanvasHelper.CreateLineStartToCharMask(control, line, charStartIndex, charLength, charProgress,
_liveStatesService.LiveStates.CurrentLyricsEffectSettings.IsLyricsLineFadeEnabled);
_liveStatesService.LiveStates.LyricsEffectSettings.IsLyricsLineFadeEnabled);
using var lineMask = CanvasHelper.CreateLineMask(control, line);
using var foregroundFontEffect = CanvasHelper.CreateFontEffect(line, control, _strokeFontColor,
_liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsFontStrokeWidth, _fgFontColor);
_liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontStrokeWidth, _fgFontColor);
using var effectLayer = new CanvasCommandList(control);
using var effectLayerDs = effectLayer.CreateDrawingSession();
if (line.OriginalText != line.DisplayedText && _liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsTranslationHighlightAmount != 0)
if (line.OriginalText != line.DisplayedText && _liveStatesService.LiveStates.LyricsEffectSettings.LyricsTranslationHighlightAmount != 0)
{
using var translationHighlightMask = CanvasHelper.CreateTranslationHighlightMask(control, line);
using var foregroundTranslationHighlightEffect = CanvasHelper.CreateForegroundHighlightEffect(foregroundFontEffect, translationHighlightMask,
_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsTranslationHighlightAmount / 100.0);
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsTranslationHighlightAmount / 100.0);
effectLayerDs.DrawImage(foregroundTranslationHighlightEffect);
}
if (_liveStatesService.LiveStates.CurrentLyricsEffectSettings.IsLyricsShadowEnabled)
if (_liveStatesService.LiveStates.LyricsEffectSettings.IsLyricsShadowEnabled)
{
var shadowEffectMask = CanvasHelper.GetAlphaMask(control, charMask, lineStartToCharMask, lineMask,
_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsShadowScope);
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsShadowScope);
using var foregroundShadowEffect = CanvasHelper.CreateForegroundShadowEffect(foregroundFontEffect, shadowEffectMask,
_albumArtAccentColorTransition.Value, _liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsShadowAmount);
_albumArtAccentColorTransition.Value, _liveStatesService.LiveStates.LyricsEffectSettings.LyricsShadowAmount);
effectLayerDs.DrawImage(foregroundShadowEffect);
}
if (_liveStatesService.LiveStates.CurrentLyricsEffectSettings.IsLyricsGlowEffectEnabled)
if (_liveStatesService.LiveStates.LyricsEffectSettings.IsLyricsGlowEffectEnabled)
{
var blurEffectMask = CanvasHelper.GetAlphaMask(control, charMask, lineStartToCharMask, lineMask,
_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsGlowEffectScope);
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsGlowEffectScope);
using var foregroundBlurEffect = CanvasHelper.CreateForegroundBlurEffect(foregroundFontEffect, blurEffectMask,
_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsGlowEffectAmount);
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsGlowEffectAmount);
effectLayerDs.DrawImage(foregroundBlurEffect);
}
if (_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsHighlightAmount != 0)
if (_liveStatesService.LiveStates.LyricsEffectSettings.LyricsHighlightAmount != 0)
{
var highlightEffectMask = CanvasHelper.GetAlphaMask(control, charMask, lineStartToCharMask, lineMask,
_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsHighlightScope);
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsHighlightScope);
using var foregroundHighlightEffect = CanvasHelper.CreateForegroundHighlightEffect(foregroundFontEffect, highlightEffectMask,
_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsHighlightAmount / 100.0);
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsHighlightAmount / 100.0);
effectLayerDs.DrawImage(foregroundHighlightEffect);
}
@@ -295,7 +295,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
if (i == _playingLineIndex)
{
if (_liveStatesService.LiveStates.CurrentLyricsEffectSettings.IsLyricsFloatAnimationEnabled)
if (_liveStatesService.LiveStates.LyricsEffectSettings.IsLyricsFloatAnimationEnabled)
{
ds.DrawImage(new DisplacementMapEffect
{
@@ -303,7 +303,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
Displacement = lineStartToCharMask,
XChannelSelect = EffectChannelSelect.Red,
YChannelSelect = EffectChannelSelect.Alpha,
Amount = _liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsFloatAmount,
Amount = _liveStatesService.LiveStates.LyricsEffectSettings.LyricsFloatAmount,
});
}
else

View File

@@ -73,6 +73,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
UpdateIsLastFMTrackEnabled();
}
}
else if (message.Sender is LyricsStyleSettings)
{
if (message.PropertyName == nameof(LyricsStyleSettings.IsDynamicLyricsFontSize))
{
_isLayoutChanged = true;
}
}
}
public void Receive(PropertyChangedMessage<Color> message)
@@ -126,6 +133,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
_isAlbumArtShadowAmountChanged = true;
}
else if (message.PropertyName == nameof(AlbumArtLayoutSettings.SongInfoFontSize))
{
UpdateSongInfoFontSize();
}
}
else if (message.Sender is LyricsBackgroundSettings)
{
@@ -242,7 +253,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.CurrentLyricsDisplayType))
if (message.PropertyName == nameof(LiveStates.LyricsDisplayType))
{
_isDisplayTypeChanged = true;
}
@@ -316,7 +327,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.CurrentLyricsWindowMode))
if (message.PropertyName == nameof(LiveStates.LyricsWindowMode))
{
UpdateColorConfig();
UpdateImmersiveBackgroundOpacity();

View File

@@ -93,7 +93,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
if (_isCanvasWidthChanged)
{
if (_canvasWidth < 450)
if (_canvasWidth < 500)
{
_lyricsLayoutOrientation = LyricsLayoutOrientation.Vertical;
}
@@ -119,7 +119,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_albumArtYTransition.StartTransition((_canvasHeight - _albumArtSize * 1.05 - _titleTextFormat.FontSize - _artistTextFormat.FontSize) / 2.0, jumpTo);
_titleYTransition.StartTransition(_albumArtYTransition.TargetValue + _albumArtSize * 1.05, jumpTo);
_lyricsYTransition.StartTransition(0, jumpTo);
switch (_liveStatesService.LiveStates.CurrentLyricsDisplayType)
switch (_liveStatesService.LiveStates.LyricsDisplayType)
{
case LyricsDisplayType.AlbumArtOnly:
_lyricsOpacityTransition.StartTransition(0f, jumpTo);
@@ -148,7 +148,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_lyricsXTransition.StartTransition(_leftMargin, jumpTo);
_albumArtXTransition.StartTransition(_leftMargin, jumpTo);
_titleXTransition.StartTransition(_leftMargin + _albumArtSize * 1.2, jumpTo);
switch (_liveStatesService.LiveStates.CurrentLyricsDisplayType)
switch (_liveStatesService.LiveStates.LyricsDisplayType)
{
case LyricsDisplayType.AlbumArtOnly:
_lyricsOpacityTransition.StartTransition(0f, jumpTo);
@@ -326,12 +326,19 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
if (control == null)
return;
_lyricsTextFormat.FontSize = _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsFontSize;
_lyricsTextFormat.FontWeight = _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsFontWeight.ToFontWeight();
_lyricsTextFormat.FontFamily = _artistTextFormat.FontFamily = _titleTextFormat.FontFamily = _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsFontFamily;
if (_liveStatesService.LiveStates.LyricsStyleSettings.IsDynamicLyricsFontSize)
{
_lyricsTextFormat.FontSize = (float)Math.Clamp(Math.Min(_canvasHeight, _canvasWidth) / 10, 12, 72);
}
else
{
_lyricsTextFormat.FontSize = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontSize;
}
_lyricsTextFormat.FontWeight = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontWeight.ToFontWeight();
_lyricsTextFormat.FontFamily = _artistTextFormat.FontFamily = _titleTextFormat.FontFamily = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontFamily;
_canvasYScrollTransition.SetDuration(_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsScrollDuration / 1000.0);
_canvasYScrollTransition.SetEasingType(_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsScrollEasingType);
_canvasYScrollTransition.SetDuration(_liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollDuration / 1000.0);
_canvasYScrollTransition.SetEasingType(_liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollEasingType);
double y = 0;
@@ -346,15 +353,15 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
line.Position = new Vector2(0, (float)y);
line.RecreateTextLayout(control, _lyricsTextFormat, _maxLyricsWidth, _canvasHeight, _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsAlignmentType);
line.UpdateCenterPosition(_maxLyricsWidth, _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsAlignmentType);
line.RecreateTextLayout(control, _lyricsTextFormat, _maxLyricsWidth, _canvasHeight, _liveStatesService.LiveStates.LyricsStyleSettings.LyricsAlignmentType);
line.UpdateCenterPosition(_maxLyricsWidth, _liveStatesService.LiveStates.LyricsStyleSettings.LyricsAlignmentType);
line.RecreateTextGeometry();
y +=
(double)line.CanvasTextLayout!.LayoutBounds.Height
/ line.CanvasTextLayout.LineCount
* (line.CanvasTextLayout.LineCount + _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsLineSpacingFactor);
* (line.CanvasTextLayout.LineCount + _liveStatesService.LiveStates.LyricsStyleSettings.LyricsLineSpacingFactor);
}
}
@@ -451,8 +458,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private void UpdateColorConfig()
{
if (_liveStatesService.LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode ||
_liveStatesService.LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode)
if (_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode ||
_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
{
ThemeTypeSent = Helper.ColorHelper.GetElementThemeFromBackgroundColor(_environmentalColor);
}
@@ -488,8 +495,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_lyricsBgBrightnessTransition.StartTransition(brightness);
if (_liveStatesService.LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode ||
_liveStatesService.LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode)
if (_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode ||
_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
_adaptiveColoredFontColor = Helper.ColorHelper.GetForegroundColor(_environmentalColor);
}
@@ -505,7 +512,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
}
switch (_liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsBgFontColorType)
switch (_liveStatesService.LiveStates.LyricsStyleSettings.LyricsBgFontColorType)
{
case LyricsFontColorType.AdaptiveGrayed:
_bgFontColor = _adaptiveGrayedFontColor;
@@ -514,13 +521,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_bgFontColor = _adaptiveColoredFontColor ?? _adaptiveGrayedFontColor;
break;
case LyricsFontColorType.Custom:
_bgFontColor = _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsCustomBgFontColor;
_bgFontColor = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsCustomBgFontColor;
break;
default:
break;
}
switch (_liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsFgFontColorType)
switch (_liveStatesService.LiveStates.LyricsStyleSettings.LyricsFgFontColorType)
{
case LyricsFontColorType.AdaptiveGrayed:
_fgFontColor = _adaptiveGrayedFontColor;
@@ -529,13 +536,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_fgFontColor = _adaptiveColoredFontColor ?? _adaptiveGrayedFontColor;
break;
case LyricsFontColorType.Custom:
_fgFontColor = _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsCustomFgFontColor;
_fgFontColor = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsCustomFgFontColor;
break;
default:
break;
}
switch (_liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsStrokeFontColorType)
switch (_liveStatesService.LiveStates.LyricsStyleSettings.LyricsStrokeFontColorType)
{
case LyricsFontColorType.AdaptiveGrayed:
_strokeFontColor = _grayedEnvironmentalColor.WithBrightness(0.7);
@@ -544,7 +551,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_strokeFontColor = _environmentalColor.WithBrightness(0.7);
break;
case LyricsFontColorType.Custom:
_strokeFontColor = _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsCustomStrokeFontColor;
_strokeFontColor = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsCustomStrokeFontColor;
break;
default:
break;
@@ -572,7 +579,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
double distanceFromPlayingLine = Math.Abs(line.Position.Y - currentPlayingLine.Position.Y);
double distanceFactor = Math.Clamp(distanceFromPlayingLine / (_canvasHeight / 2), 0, 1);
line.AngleTransition.StartTransition(_liveStatesService.LiveStates.CurrentLyricsEffectSettings.IsFanLyricsEnabled
line.AngleTransition.StartTransition(_liveStatesService.LiveStates.LyricsEffectSettings.IsFanLyricsEnabled
? Math.PI
* (30.0 / 180.0)
* distanceFactor
@@ -580,12 +587,12 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
: 0
);
line.BlurAmountTransition.StartTransition(_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsBlurAmount * distanceFactor);
line.BlurAmountTransition.StartTransition(_liveStatesService.LiveStates.LyricsEffectSettings.LyricsBlurAmount * distanceFactor);
line.ScaleTransition.StartTransition(_highlightedScale - distanceFactor * (_highlightedScale - _defaultScale));
line.OpacityTransition.StartTransition(
_liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsBgFontOpacity / 100.0 -
distanceFactor * _liveStatesService.LiveStates.CurrentLyricsStyleSettings.LyricsBgFontOpacity / 100.0 *
(1 - _liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsVerticalEdgeOpacity / 100.0));
_liveStatesService.LiveStates.LyricsStyleSettings.LyricsBgFontOpacity / 100.0 -
distanceFactor * _liveStatesService.LiveStates.LyricsStyleSettings.LyricsBgFontOpacity / 100.0 *
(1 - _liveStatesService.LiveStates.LyricsEffectSettings.LyricsVerticalEdgeOpacity / 100.0));
line.HighlightOpacityTransition.StartTransition(i == _playingLineIndex ? 1f : 0f);
double yScrollDuration;
@@ -595,8 +602,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
yScrollDuration =
_canvasYScrollTransition.DurationSeconds +
distanceFactor * (_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsScrollTopDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * _liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsScrollTopDelay / 1000.0;
distanceFactor * (_liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollTopDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * _liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollTopDelay / 1000.0;
}
else if (lineCountDelta == 0)
{
@@ -607,8 +614,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
yScrollDuration =
_canvasYScrollTransition.DurationSeconds +
distanceFactor * (_liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsScrollBottomDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * _liveStatesService.LiveStates.CurrentLyricsEffectSettings.LyricsScrollBottomDelay / 1000.0;
distanceFactor * (_liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollBottomDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * _liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollBottomDelay / 1000.0;
}
line.YOffsetTransition.SetEasingType(_canvasYScrollTransition.EasingType ?? EasingType.Linear);
@@ -629,7 +636,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private void UpdateImmersiveBackgroundOpacity()
{
double targetOpacity;
if (_liveStatesService.LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode)
if (_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
if (_isLyricsWindowLocked)
{
@@ -688,5 +695,11 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
var current = _mediaSessionsService.GetCurrentMediaSourceProviderInfo();
_isLastFMTrackEnabled = current?.IsLastFMTrackEnabled ?? false;
}
private void UpdateSongInfoFontSize()
{
_titleTextFormat.FontSize = _settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoFontSize;
_artistTextFormat.FontSize = _settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoFontSize - 2;
}
}
}

View File

@@ -190,6 +190,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
AppSettings = _settingsService.AppSettings;
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment = _settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
UpdateSongInfoFontSize();
_timelineSyncThreshold = 0;

View File

@@ -5,6 +5,7 @@ using BetterLyrics.WinUI3.Services.LyricsSearchService;
using BetterLyrics.WinUI3.Services.MediaSessionsService;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
@@ -22,6 +23,7 @@ namespace BetterLyrics.WinUI3.ViewModels
private readonly ILyricsSearchService _lyricsSearchService;
private readonly IMediaSessionsService _mediaSessionsService;
private readonly ISettingsService _settingsService;
private LatestOnlyTaskRunner _lyricsSearchRunner = new();
[ObservableProperty]
@@ -36,6 +38,9 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty]
public partial LyricsData? LyricsData { get; set; }
[ObservableProperty]
public partial LyricsLine? SelectedLyricsLine { get; set; }
[ObservableProperty]
public partial MappedSongSearchQuery? MappedSongSearchQuery { get; set; }
@@ -63,6 +68,7 @@ namespace BetterLyrics.WinUI3.ViewModels
private void InitMappedSongSearchQuery()
{
LyricsSearchResults.Clear();
LyricsData = null;
if (_mediaSessionsService.SongInfo != null)
{
var found = GetMappedSongSearchQueryFromSettings();
@@ -148,6 +154,18 @@ namespace BetterLyrics.WinUI3.ViewModels
SelectedLyricsSearchResult = null;
}
[RelayCommand]
private void ResetMappedTitle()
{
MappedSongSearchQuery?.MappedTitle = MappedSongSearchQuery?.OriginalTitle ?? string.Empty;
}
[RelayCommand]
private void ResetMappedArtist()
{
MappedSongSearchQuery?.MappedArtist = MappedSongSearchQuery?.OriginalArtist ?? string.Empty;
}
partial void OnSelectedLyricsSearchResultChanged(LyricsSearchResult? value)
{
MappedSongSearchQuery?.LyricsSearchProvider = value?.Provider;
@@ -162,5 +180,14 @@ namespace BetterLyrics.WinUI3.ViewModels
LyricsData = null;
}
}
partial void OnSelectedLyricsLineChanged(LyricsLine? value)
{
if (value?.StartMs == null)
{
return;
}
_mediaSessionsService.ChangePosition(value.StartMs / 1000.0);
}
}
}

View File

@@ -105,14 +105,12 @@ namespace BetterLyrics.WinUI3
[NotifyPropertyChangedRecipients]
public partial bool IsMouseWithinWindow { get; set; } = false;
[ObservableProperty] public partial Visibility AOTFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility FullScreenFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility LockButtonVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility DesktopFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility PIPFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility DockFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial bool IsAOTFlyoutItemChecked { get; set; } = false;
[ObservableProperty] public partial bool IsFullScreenFlyoutItemChecked { get; set; } = false;
[ObservableProperty] public partial bool IsDesktopFlyoutItemChecked { get; set; } = false;
[ObservableProperty] public partial bool IsPIPFlyoutItemChecked { get; set; } = false;
@@ -126,11 +124,11 @@ namespace BetterLyrics.WinUI3
var hwnd = WindowNative.GetWindowHandle(window);
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode || LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode || LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
if (_hideWindowWhenNotPlaying && !_mediaSessionsService.IsPlaying)
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
{
DockModeHelper.UpdateAppBarHeight(hwnd, _dockMonitorDeviceName, 0, _dockPlacement);
}
@@ -138,7 +136,7 @@ namespace BetterLyrics.WinUI3
}
else
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
{
DockModeHelper.UpdateAppBarHeight(hwnd, _dockMonitorDeviceName, _dockWindowHeight, _dockPlacement);
}
@@ -176,6 +174,7 @@ namespace BetterLyrics.WinUI3
if (message.PropertyName == nameof(GeneralSettings.IgnoreFullscreenWindow))
{
_ignoreFullscreenWindow = message.NewValue;
SetIsAlwaysOnTop();
}
else if (message.PropertyName == nameof(GeneralSettings.HideWindowWhenNotPlaying))
{
@@ -183,6 +182,13 @@ namespace BetterLyrics.WinUI3
UpdateDockOrDesktopWindow();
}
}
else if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.IsAlwaysOnTop))
{
SetIsAlwaysOnTop();
}
}
}
public void Receive(PropertyChangedMessage<ElementTheme> message)
@@ -210,19 +216,40 @@ namespace BetterLyrics.WinUI3
public void InitShortcuts()
{
UpdateDesktopLockShortcut();
UpdateDesktopLockUnlockShortcut();
UpdateDesktopToggleShortcut();
UpdateDockToggleShortcut();
UpdatePictureInPictureToggleShortcut();
UpdateLyricsWindowShowHideShortcut();
}
private void UpdateDesktopLockShortcut()
private void UpdateLyricsWindowShowHideShortcut()
{
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.DesktopLock,
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.LyricsWindowShowOrHide,
_settingsService.AppSettings.GeneralSettings.ShowOrHideLyricsWindowShortcut,
() =>
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
if (window.Visible)
{
window.Hide();
}
else
{
WindowHelper.OpenWindow<LyricsWindow>();
}
}
);
}
private void UpdateDesktopLockUnlockShortcut()
{
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.DesktopLockOrUnlock,
_settingsService.AppSettings.DesktopModeSettings.LockShortcut,
() =>
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
ToggleLockWindow();
}
@@ -236,8 +263,8 @@ namespace BetterLyrics.WinUI3
_settingsService.AppSettings.DesktopModeSettings.ToggleShortcut,
() =>
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode ||
LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.StandardMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode ||
LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
ToggleDesktopMode();
}
@@ -251,8 +278,8 @@ namespace BetterLyrics.WinUI3
_settingsService.AppSettings.DockModeSettings.ToggleShortcut,
() =>
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode ||
LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.StandardMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode ||
LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
ToggleDockMode();
}
@@ -266,8 +293,8 @@ namespace BetterLyrics.WinUI3
_settingsService.AppSettings.PictureInPictureModeSettings.ToggleShortcut,
() =>
{
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.PictureInPictureMode ||
LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.StandardMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.PictureInPictureMode ||
LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
TogglePictureInPictureMode();
}
@@ -277,14 +304,14 @@ namespace BetterLyrics.WinUI3
private void SetFullscreenTitleBarControlsStatus()
{
AOTFlyoutItemVisibility = LockButtonVisibility = DesktopFlyoutItemVisibility = PIPFlyoutItemVisibility = DockFlyoutItemVisibility = Visibility.Collapsed;
LockButtonVisibility = DesktopFlyoutItemVisibility = PIPFlyoutItemVisibility = DockFlyoutItemVisibility = Visibility.Collapsed;
IsFullScreenFlyoutItemChecked = true;
IsImmersiveMode = true;
}
private void SetPIPModeTitleBarControlsStatus()
{
AOTFlyoutItemVisibility = DesktopFlyoutItemVisibility = FullScreenFlyoutItemVisibility = DockFlyoutItemVisibility = LockButtonVisibility = Visibility.Collapsed;
DesktopFlyoutItemVisibility = FullScreenFlyoutItemVisibility = DockFlyoutItemVisibility = LockButtonVisibility = Visibility.Collapsed;
IsImmersiveMode = true;
IsPIPFlyoutItemChecked = true;
}
@@ -296,7 +323,7 @@ namespace BetterLyrics.WinUI3
var overlappedPresenter = (OverlappedPresenter)window.AppWindow.Presenter;
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = false;
AOTFlyoutItemVisibility = DesktopFlyoutItemVisibility = LockButtonVisibility = FullScreenFlyoutItemVisibility = PIPFlyoutItemVisibility = Visibility.Collapsed;
DesktopFlyoutItemVisibility = LockButtonVisibility = FullScreenFlyoutItemVisibility = PIPFlyoutItemVisibility = Visibility.Collapsed;
IsImmersiveMode = true;
IsDockFlyoutItemChecked = true;
}
@@ -308,7 +335,7 @@ namespace BetterLyrics.WinUI3
var overlappedPresenter = (OverlappedPresenter)window.AppWindow.Presenter;
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = false;
DockFlyoutItemVisibility = AOTFlyoutItemVisibility = FullScreenFlyoutItemVisibility = PIPFlyoutItemVisibility = Visibility.Collapsed;
DockFlyoutItemVisibility = FullScreenFlyoutItemVisibility = PIPFlyoutItemVisibility = Visibility.Collapsed;
LockButtonVisibility = Visibility.Visible;
IsDesktopFlyoutItemChecked = true;
}
@@ -320,10 +347,9 @@ namespace BetterLyrics.WinUI3
var overlappedPresenter = (OverlappedPresenter)window.AppWindow.Presenter;
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = true;
AOTFlyoutItemVisibility = DesktopFlyoutItemVisibility = DockFlyoutItemVisibility = PIPFlyoutItemVisibility = FullScreenFlyoutItemVisibility = Visibility.Visible;
DesktopFlyoutItemVisibility = DockFlyoutItemVisibility = PIPFlyoutItemVisibility = FullScreenFlyoutItemVisibility = Visibility.Visible;
LockButtonVisibility = Visibility.Collapsed;
IsFullScreenFlyoutItemChecked = IsDesktopFlyoutItemChecked = IsDockFlyoutItemChecked = IsPIPFlyoutItemChecked = false;
IsAOTFlyoutItemChecked = overlappedPresenter.IsAlwaysOnTop;
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
}
@@ -339,7 +365,7 @@ namespace BetterLyrics.WinUI3
{
_dispatcherQueueTimer.Debounce(() =>
{
if ((LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode || LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode) && _ignoreFullscreenWindow && window.AppWindow.Presenter is OverlappedPresenter presenter)
if ((LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode || LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode) && _ignoreFullscreenWindow && window.AppWindow.Presenter is OverlappedPresenter presenter)
{
presenter.IsAlwaysOnTop = true;
}
@@ -359,7 +385,7 @@ namespace BetterLyrics.WinUI3
public void UpdateAccentColor(nint hwnd)
{
WindowPixelSampleMode mode = LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode ? WindowPixelSampleMode.WindowEdge : _dockPlacement.ToWindowPixelSampleMode();
WindowPixelSampleMode mode = LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode ? WindowPixelSampleMode.WindowEdge : _dockPlacement.ToWindowPixelSampleMode();
ActivatedWindowAccentColor = ColorHelper.GetAccentColor(hwnd, _settingsService.AppSettings.DockModeSettings.DockMonitorDeviceName, mode).ToColor();
}
@@ -405,7 +431,7 @@ namespace BetterLyrics.WinUI3
StopWatchWindowColorChange();
LiveStates.ToggleLyricsWindowMode(LyricsWindowMode.DesktopMode);
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DesktopMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
DesktopModeHelper.Enable(window);
StartWatchWindowColorChange();
@@ -424,6 +450,7 @@ namespace BetterLyrics.WinUI3
DesktopModeHelper.Disable(window);
SetStandardModeTitleBarControlsStatus();
}
SetIsAlwaysOnTop();
}
public void ToggleDockMode()
@@ -434,7 +461,7 @@ namespace BetterLyrics.WinUI3
StopWatchWindowColorChange();
LiveStates.ToggleLyricsWindowMode(LyricsWindowMode.DockMode);
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.DockMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
{
window.Restore();
DockModeHelper.Enable(window, _dockMonitorDeviceName, _dockWindowHeight, _dockPlacement);
@@ -448,6 +475,7 @@ namespace BetterLyrics.WinUI3
}
UpdateDockOrDesktopWindow();
SetIsAlwaysOnTop();
}
public void TogglePictureInPictureMode()
@@ -456,7 +484,7 @@ namespace BetterLyrics.WinUI3
if (window == null) return;
LiveStates.ToggleLyricsWindowMode(LyricsWindowMode.PictureInPictureMode);
if (LiveStates.CurrentLyricsWindowMode == LyricsWindowMode.PictureInPictureMode)
if (LiveStates.LyricsWindowMode == LyricsWindowMode.PictureInPictureMode)
{
window.AppWindow.SetPresenter(AppWindowPresenterKind.CompactOverlay);
window.AppWindow.Move(AppSettings.PictureInPictureModeSettings.WindowPosition.ToPointInt32());
@@ -467,17 +495,17 @@ namespace BetterLyrics.WinUI3
window.AppWindow.SetPresenter(AppWindowPresenterKind.Overlapped);
SetStandardModeTitleBarControlsStatus();
}
SetIsAlwaysOnTop();
}
public void ToggleAlwaysOnTop()
public void SetIsAlwaysOnTop()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
if (window.AppWindow.Presenter is OverlappedPresenter presenter)
{
presenter.IsAlwaysOnTop = !presenter.IsAlwaysOnTop;
IsAOTFlyoutItemChecked = presenter.IsAlwaysOnTop;
presenter.IsAlwaysOnTop = _liveStatesService.LiveStates.IsAlwaysOnTop;
}
}
@@ -537,7 +565,7 @@ namespace BetterLyrics.WinUI3
{
if (message.PropertyName == nameof(DesktopModeSettings.LockShortcut))
{
UpdateDesktopLockShortcut();
UpdateDesktopLockUnlockShortcut();
}
}
else if (message.Sender is DockModeSettings)
@@ -561,6 +589,13 @@ namespace BetterLyrics.WinUI3
UpdateDesktopToggleShortcut();
}
}
else if (message.Sender is GeneralSettings)
{
if (message.PropertyName == nameof(GeneralSettings.ShowOrHideLyricsWindowShortcut))
{
UpdateLyricsWindowShowHideShortcut();
}
}
}
}
}

View File

@@ -18,6 +18,7 @@ using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -42,16 +43,69 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty]
public partial object NavViewSelectedItemTag { get; set; } = "App";
[ObservableProperty]
public partial ObservableCollection<LibInfo> Libs { get; set; }
public SettingsPageViewModel(ISettingsService settingsService)
{
_settingsService = settingsService;
AppSettings = _settingsService.AppSettings;
Libs =
[
new LibInfo { Name = "3v.EvtSource" },
new LibInfo { Name = "ColorThief.ImageSharp" },
new LibInfo { Name = "CommunityToolkit.Labs.WinUI.MarqueeText" },
new LibInfo { Name = "CommunityToolkit.Labs.WinUI.OpacityMaskView" },
new LibInfo { Name = "CommunityToolkit.Labs.WinUI.Shimmer" },
new LibInfo { Name = "CommunityToolkit.Mvvm" },
new LibInfo { Name = "CommunityToolkit.WinUI.Behaviors" },
new LibInfo { Name = "CommunityToolkit.WinUI.Controls.MetadataControl" },
new LibInfo { Name = "CommunityToolkit.WinUI.Controls.Primitives" },
new LibInfo { Name = "CommunityToolkit.WinUI.Controls.Segmented" },
new LibInfo { Name = "CommunityToolkit.WinUI.Controls.SettingsControls" },
new LibInfo { Name = "CommunityToolkit.WinUI.Controls.Sizers" },
new LibInfo { Name = "CommunityToolkit.WinUI.Converters" },
new LibInfo { Name = "CommunityToolkit.WinUI.Extensions" },
new LibInfo { Name = "CommunityToolkit.WinUI.Helpers" },
new LibInfo { Name = "CommunityToolkit.WinUI.Media" },
new LibInfo { Name = "csharp-pinyin" },
new LibInfo { Name = "Dubya.WindowsMediaController" },
new LibInfo { Name = "H.NotifyIcon.WinUI"},
new LibInfo { Name = "Hqub.Last.fm"},
new LibInfo { Name = "Lyricify.Lyrics.Helper-NativeAot"},
new LibInfo { Name = "Microsoft.Extensions.DependencyInjection"},
new LibInfo { Name = "Microsoft.Extensions.Logging"},
new LibInfo { Name = "Microsoft.Graphics.Win2D"},
new LibInfo { Name = "Microsoft.Windows.SDK.BuildTools"},
new LibInfo { Name = "Microsoft.WindowsAppSDK"},
new LibInfo { Name = "Nito.AsyncEx"},
new LibInfo { Name = "Nito.AsyncEx.Tasks"},
new LibInfo { Name = "NTextCat"},
new LibInfo { Name = "RomajiConverter.Core"},
new LibInfo { Name = "Serilog.Extensions.Logging"},
new LibInfo { Name = "Serilog.Sinks.File"},
new LibInfo { Name = "ShadowViewer.Controls.Notification"},
new LibInfo { Name = "SixLabors.ImageSharp" },
new LibInfo { Name = "System.Drawing.Common"},
new LibInfo { Name = "System.Text.Encoding.CodePages"},
new LibInfo { Name = "TagLibSharp" },
new LibInfo { Name = "TinyPinyin.Net"},
new LibInfo { Name = "Ude.NetStandard"},
new LibInfo { Name = "Vanara.PInvoke.CoreAudio"},
new LibInfo { Name = "Vanara.PInvoke.DwmApi"},
new LibInfo { Name = "Vanara.PInvoke.Gdi32"},
new LibInfo { Name = "Vanara.PInvoke.Shell32"},
new LibInfo { Name = "Vanara.PInvoke.User32"},
new LibInfo { Name = "WinUIEx" },
new LibInfo { Name = "z440.atl.core" },
];
}
[RelayCommand]
private async Task LaunchProjectGitHubPageAsync()
{
await Windows.System.Launcher.LaunchUriAsync(new Uri(Constants.Link.GithubUrl));
await Windows.System.Launcher.LaunchUriAsync(new Uri(Constants.Link.GitHubUrl));
}
[RelayCommand]

View File

@@ -29,8 +29,8 @@
x:Uid="MainPageNoMusicPlaying"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="{x:Bind ViewModel.LiveStates.CurrentLyricsStyleSettings.LyricsFontFamily, Mode=OneWay}"
FontSize="{x:Bind ViewModel.LiveStates.CurrentLyricsStyleSettings.LyricsFontSize, Mode=OneWay}" />
FontFamily="{x:Bind ViewModel.LiveStates.LyricsStyleSettings.LyricsFontFamily, Mode=OneWay}"
FontSize="{x:Bind ViewModel.LiveStates.LyricsStyleSettings.LyricsFontSize, Mode=OneWay}" />
<Grid.OpacityTransition>
<ScalarTransition />
</Grid.OpacityTransition>
@@ -245,14 +245,6 @@
<ToolTipService.ToolTip>
<ToolTip x:Uid="LyricsPageLyricsSearchButtonToolTip" />
</ToolTipService.ToolTip>
<Button.ContextFlyout>
<Flyout
x:Name="LyricsSearchFlyout"
Closed="LyricsSearchFlyout_Closed"
FlyoutPresenterStyle="{StaticResource FlyoutPageStyle}"
Placement="Right"
ShouldConstrainToRootBounds="False" />
</Button.ContextFlyout>
</Button>
<!-- Playback shortcut settings -->
@@ -297,9 +289,40 @@
Maximum="{x:Bind ViewModel.SongDurationSeconds, Mode=OneWay}"
Minimum="0"
Style="{StaticResource GhostSliderStyle}"
Tapped="TimelineSliderOverlay_Tapped"
ThumbToolTipValueConverter="{StaticResource SecondsToFormattedTimeConverter}"
Value="{x:Bind ViewModel.TimelinePositionSeconds, Mode=OneWay}" />
<Grid
x:Name="TimelineSliderLyricsLineInfo"
Margin="0,-48,0,0"
Padding="8,4"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="{ThemeResource SolidBackgroundFillColorQuarternaryBrush}"
CornerRadius="6"
Opacity="{x:Bind ViewModel.TimelineSliderThumbOpacity, Mode=OneWay}">
<Grid.OpacityTransition>
<ScalarTransition />
</Grid.OpacityTransition>
<Grid.TranslationTransition>
<Vector3Transition />
</Grid.TranslationTransition>
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock
Margin="0,0,0,2"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind ViewModel.TimelineSliderThumbLyricsLine.StartMs, Converter={StaticResource MillisecondsToFormattedTimeConverter}, Mode=OneWay}" />
<TextBlock Margin="0,0,0,2" Text="{x:Bind ViewModel.TimelineSliderThumbLyricsLine.DisplayedText, Mode=OneWay}" />
</StackPanel>
</Grid>
<Grid
Height="32"
Margin="0,-32,0,0"
VerticalAlignment="Top"
Background="Transparent"
PointerEntered="TimelineSliderOverlay_PointerEntered"
PointerExited="TimelineSliderOverlay_PointerExited"
PointerMoved="TimelineSliderOverlay_PointerMoved"
PointerPressed="TimelineSliderOverlay_PointerPressed" />
</Grid>
</Grid>
@@ -333,7 +356,7 @@
<Flyout x:Name="BottomCommandFlyout" ShouldConstrainToRootBounds="False">
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="MinWidth" Value="450" />
<Setter Property="MinWidth" Value="500" />
<Setter Property="MinHeight" Value="100" />
<Setter Property="CornerRadius" Value="12" />
</Style>

View File

@@ -2,6 +2,7 @@
using BetterLyrics.WinUI3.Controls;
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.MediaSessionsService;
using BetterLyrics.WinUI3.Services.SettingsService;
@@ -10,6 +11,7 @@ using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
@@ -60,7 +62,7 @@ namespace BetterLyrics.WinUI3.Views
private void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.NewSize.Width < 450 || e.NewSize.Height < 100)
if (e.NewSize.Width < 500 || e.NewSize.Height < 100)
{
if (BottomCommandGrid.Children.Count != 0)
{
@@ -110,11 +112,6 @@ namespace BetterLyrics.WinUI3.Views
}
}
private void TimelineSliderOverlay_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e)
{
_mediaSessionsService.ChangePosition(TimelineSlider.Value);
}
private void PlaybackSettingsFlyout_Closed(object sender, object e)
{
PlaybackSettingsFlyout.Content = null;
@@ -137,17 +134,43 @@ namespace BetterLyrics.WinUI3.Views
private void LyricsSearchShortcutButton_Click(object sender, RoutedEventArgs e)
{
LyricsSearchFlyout.Content = new LyricsSearchControl
{
MaxHeight = 500,
MaxWidth = 850,
};
LyricsSearchFlyout.ShowAt(BottomRightCommandStackPanel);
WindowHelper.OpenWindow<LyricsSearchWindow>();
}
private void LyricsSearchFlyout_Closed(object sender, object e)
private void TimelineSliderOverlay_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
LyricsSearchFlyout.Content = null;
var grid = (Grid)sender;
var pos = e.GetCurrentPoint(grid).Position;
var ratio = pos.X / grid.ActualWidth;
_mediaSessionsService.ChangePosition(TimelineSlider.Maximum * ratio);
}
private void TimelineSliderOverlay_PointerMoved(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
float targetX;
var grid = (Grid)sender;
var pos = e.GetCurrentPoint(grid).Position;
var ratio = pos.X / grid.ActualWidth;
ViewModel.TimelineSliderThumbSeconds = TimelineSlider.Maximum * ratio;
if (pos.X + TimelineSliderLyricsLineInfo.ActualWidth > grid.ActualWidth)
{
targetX = (float)(grid.ActualWidth - TimelineSliderLyricsLineInfo.ActualWidth);
}
else
{
targetX = (float)pos.X;
}
TimelineSliderLyricsLineInfo.Translation = new Vector3(targetX, 0, 0);
}
private void TimelineSliderOverlay_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
ViewModel.TimelineSliderThumbOpacity = 0.7f;
}
private void TimelineSliderOverlay_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
ViewModel.TimelineSliderThumbOpacity = 0f;
}
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<Window
x:Class="BetterLyrics.WinUI3.Views.LyricsSearchWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:BetterLyrics.WinUI3.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:BetterLyrics.WinUI3.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:media="using:CommunityToolkit.WinUI.Media"
mc:Ignorable="d">
<Grid Background="{ThemeResource SystemControlAcrylicWindowBrush}" Opacity="0.85">
<controls:LyricsSearchControl />
</Grid>
</Window>

View File

@@ -0,0 +1,47 @@
using BetterLyrics.WinUI3.Helper;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace BetterLyrics.WinUI3.Views
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class LyricsSearchWindow : Window
{
public LyricsSearchWindow()
{
InitializeComponent();
Title = App.ResourceLoader?.GetString("LyricsSearchPageTitle");
AppWindow.TitleBar.PreferredTheme = TitleBarTheme.UseDefaultAppMode;
AppWindow.SetIcons();
AppWindow.Closing += AppWindow_Closing;
SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop(Enums.BackdropType.Transparent);
}
private void AppWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args)
{
WindowHelper.CloseWindow<LyricsSearchWindow>();
}
}
}

View File

@@ -25,6 +25,7 @@
<!-- Top command -->
<Grid
x:Name="TopCommandGrid"
Margin="6"
VerticalAlignment="Top"
Background="Transparent"
Opacity="{x:Bind ViewModel.TopCommandGridOpacity, Mode=OneWay}"
@@ -75,14 +76,6 @@
</ToolTipService.ToolTip>
<Button.Flyout>
<MenuFlyout>
<ToggleMenuFlyoutItem
x:Name="AOTFlyoutItem"
x:Uid="BaseWindowAOTFlyoutItem"
Click="AOTFlyoutItem_Click"
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE718;}"
IsChecked="{x:Bind ViewModel.IsAOTFlyoutItemChecked, Mode=OneWay}"
Visibility="{x:Bind ViewModel.AOTFlyoutItemVisibility, Mode=OneWay}" />
<ToggleMenuFlyoutItem
x:Name="FullScreenFlyoutItem"
x:Uid="BaseWindowFullScreenFlyoutItem"

View File

@@ -2,6 +2,7 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Services.LiveStatesService;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.WinUI;
@@ -19,6 +20,7 @@ namespace BetterLyrics.WinUI3.Views
public sealed partial class LyricsWindow : Window
{
private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
private readonly ILiveStatesService _liveStatesService = Ioc.Default.GetRequiredService<ILiveStatesService>();
private readonly WindowMessageMonitor _wmm;
private bool _autoSelectLyricsModeOnRunning = true;
@@ -101,11 +103,11 @@ namespace BetterLyrics.WinUI3.Views
break;
}
_autoSelectLyricsModeOnRunning = false;
}
private void AOTFlyoutItem_Click(object sender, RoutedEventArgs e)
{
ViewModel.ToggleAlwaysOnTop();
var size = AppWindow.Size;
var rect = AppWindow.Position;
_liveStatesService.LiveStates.LyricsWindowBounds = new Windows.Foundation.Rect(rect.X, rect.Y, size.Width, size.Height);
}
private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
@@ -117,13 +119,15 @@ namespace BetterLyrics.WinUI3.Views
var size = AppWindow.Size;
var rect = AppWindow.Position;
_liveStatesService.LiveStates.LyricsWindowBounds = new Windows.Foundation.Rect(rect.X, rect.Y, size.Width, size.Height);
if (rect.X < 0 && rect.Y < 0 && rect.X + size.Width < 0 && rect.Y + size.Height < 0)
{
return;
}
else
{
switch (ViewModel.LiveStates.CurrentLyricsWindowMode)
switch (ViewModel.LiveStates.LyricsWindowMode)
{
case LyricsWindowMode.StandardMode:
if (AppWindow.Presenter is OverlappedPresenter overlappedPresenter)

View File

@@ -354,7 +354,7 @@
<StackPanel>
<TextBlock Text="{Binding Track.Title}" TextWrapping="Wrap" />
<TextBlock
Foreground="{StaticResource TextFillColorSecondaryBrush}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{Binding Track.Artist}"
TextWrapping="Wrap" />
</StackPanel>

View File

@@ -3,6 +3,7 @@
x:Class="BetterLyrics.WinUI3.Views.SettingsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:const="using:BetterLyrics.WinUI3.Constants"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
@@ -120,41 +121,130 @@
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard Header="BetterLyrics" HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/Logo.png}">
<controls:SettingsCard.Description>
<RichTextBlock>
<Paragraph>
<Run x:Uid="SettingsPageVersion" />
<Run Text="{x:Bind ViewModel.Version, Mode=OneWay}" />
</Paragraph>
</RichTextBlock>
</controls:SettingsCard.Description>
</controls:SettingsCard>
<controls:SettingsExpander
Header="BetterLyrics"
HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/Logo.png}"
IsExpanded="True">
<controls:SettingsExpander.Description>
<HyperlinkButton Content="by Zhe Fang" NavigateUri="https://github.com/jayfunc" />
</controls:SettingsExpander.Description>
<RichTextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}">
<Paragraph>
<Run x:Uid="SettingsPageVersion" />
<Run Text="{x:Bind ViewModel.Version, Mode=OneWay}" />
</Paragraph>
</RichTextBlock>
<controls:SettingsExpander.Items>
<controls:SettingsCard
x:Uid="SettingsPageGitHub"
ActionIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE8A7;}"
Command="{x:Bind ViewModel.LaunchProjectGitHubPageCommand}"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE943;}"
IsClickEnabled="True" />
<controls:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Left">
<StackPanel Margin="-12,0,0,0" Orientation="Horizontal">
<HyperlinkButton Content="GitHub" NavigateUri="{x:Bind const:Link.GitHubUrl}" />
<HyperlinkButton x:Uid="SettingsPageFAQ" NavigateUri="{x:Bind const:Link.FAQUrl}" />
</StackPanel>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageFAQ" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE897;}">
<HyperlinkButton Content="https://github.com/jayfunc/BetterLyrics/blob/dev/FAQ/FAQ.md" NavigateUri="https://github.com/jayfunc/BetterLyrics/blob/dev/FAQ/FAQ.md" />
</controls:SettingsCard>
<controls:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Left">
<StackPanel Spacing="6">
<TextBlock x:Uid="SetingsPageFeedback" />
<StackPanel Margin="-12,0,0,0" Orientation="Horizontal">
<HyperlinkButton x:Uid="SettingsPageQQGroup" NavigateUri="{x:Bind const:Link.QQGroupUrl}" />
<HyperlinkButton x:Uid="SettingsPageDiscord" NavigateUri="{x:Bind const:Link.DiscordUrl}" />
<HyperlinkButton x:Uid="SettingsPageTelegram" NavigateUri="{x:Bind const:Link.TelegramUrl}" />
</StackPanel>
</StackPanel>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageQQGroup" HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/QQ.png}">
<Button x:Uid="SettingsPageJoinNowButton" Click="QQGroupButton_Click" />
</controls:SettingsCard>
<controls:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Left">
<StackPanel Spacing="6">
<TextBlock x:Uid="SetingsPageDonation" />
<StackPanel Margin="-12,0,0,0" Orientation="Horizontal">
<HyperlinkButton Content="Buy Me a Coffee" NavigateUri="https://buymeacoffee.com/founchoo" />
<HyperlinkButton Content="PayPal" NavigateUri="https://paypal.me/zhefangpay" />
<Button
Content="支付宝"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Style="{StaticResource GhostButtonStyle}">
<Button.Flyout>
<Flyout>
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="CornerRadius" Value="12" />
<Setter Property="Padding" Value="0" />
</Style>
</Flyout.FlyoutPresenterStyle>
<Image Height="300" Source="/Assets/Alipay.jpg" />
</Flyout>
</Button.Flyout>
</Button>
<Button
Content="微信"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Style="{StaticResource GhostButtonStyle}">
<Button.Flyout>
<Flyout>
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="CornerRadius" Value="12" />
<Setter Property="Padding" Value="0" />
</Style>
</Flyout.FlyoutPresenterStyle>
<Image Height="300" Source="/Assets/WeChatReward.png" />
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="*" />
<TextBlock
x:Uid="SetingsPageThanks"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDiscord" HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/Discord.png}">
<Button x:Uid="SettingsPageJoinNowButton" Click="DiscodGroupButton_Click" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
<controls:SettingsExpander.ItemsHeader>
<InfoBar
BorderThickness="0"
CornerRadius="0"
IsClosable="False"
IsOpen="True"
Severity="Warning">
<TextBlock
x:Uid="SettingsPageDisclaimer"
Margin="12"
Foreground="{ThemeResource SystemFillColorCautionBrush}"
TextWrapping="Wrap" />
</InfoBar>
</controls:SettingsExpander.ItemsHeader>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageTelegram" HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/Telegram.png}">
<Button x:Uid="SettingsPageJoinNowButton" Click="TelegramGroupButton_Click" />
</controls:SettingsCard>
<TextBlock x:Uid="SetingsPageRef" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<ListView
Padding="0,6"
Background="{ThemeResource CardBackgroundFillColorDefault}"
CornerRadius="4"
ItemsSource="{x:Bind ViewModel.Libs, Mode=OneWay}"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<RelativePanel Padding="42,0">
<HyperlinkButton
Margin="-12,0,0,0"
Content="{Binding Name}"
NavigateUri="{Binding Url}"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignVerticalCenterWithPanel="True" />
<TextBlock
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignVerticalCenterWithPanel="True"
Text="{Binding Version}" />
</RelativePanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>

View File

@@ -29,20 +29,5 @@ namespace BetterLyrics.WinUI3.Views
{
ViewModel.NavViewSelectedItemTag = (args.SelectedItem as NavigationViewItem)!.Tag;
}
private void QQGroupButton_Click(object sender, RoutedEventArgs e)
{
Launcher.LaunchUriAsync(new Uri(Constants.Link.QQGroupUrl));
}
private void DiscodGroupButton_Click(object sender, RoutedEventArgs e)
{
Launcher.LaunchUriAsync(new Uri(Constants.Link.DiscordUrl));
}
private void TelegramGroupButton_Click(object sender, RoutedEventArgs e)
{
Launcher.LaunchUriAsync(new Uri(Constants.Link.TelegramUrl));
}
}
}

BIN
Donate/Alipay.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
Donate/WeChatReward.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

View File

@@ -1,14 +1,34 @@
## FAQ has been moved
[Click here to visit](https://github.com/jayfunc/BetterLyrics?tab=readme-ov-file#faq)
### Where I can find the logs?
`C:\Users\%USERNAME%\AppData\Local\Packages\37412.BetterLyrics_rd1g0rsrrtxw8\LocalCache\logs`
## FAQ 现已迁移
[点此访问](https://github.com/jayfunc/BetterLyrics/blob/dev/README.zh-CN.md#faq)
### How to install ".msixbundle" package? (for test package only)
[See this doc](https://github.com/jayfunc/BetterLyrics/blob/dev/How2Install/How2Install.md)
## FAQ 已移至新位置
[點此前往](https://github.com/jayfunc/BetterLyrics/blob/dev/README.zh-TW.md#faq)
### Lyrics are moving back and forth constantly, how to fix it?
![](Snipaste_2025-08-22_14-59-53.png)
## FAQ は移動しました
[こちらをクリック](https://github.com/jayfunc/BetterLyrics/blob/dev/README.ja.md#faq)
Go to Settings > Playback sources > Disable "Lyrics timeline sync" or increase "Lyrics timeline sync threshold"
## FAQ가 이동되었습니다
[여기를 클릭하세요](https://github.com/jayfunc/BetterLyrics/blob/dev/README.ko.md#faq)
### Wrong lyrics are shown, how to fix it?
![](Snipaste_2025-08-22_14-47-21.png)
Open search panel to manually search for the correct lyrics.
### Playback control panel is not showing in dock mode, how to fix it?
![](Snipaste_2025-08-22_14-50-16.png)
Hover over the bottom of the lyrics window and click on the white line to show the playback control panel.
### How to lock/unlock the lyrics window in desktop mode?
![](Snipaste_2025-08-22_14-52-53.png)
![](Snipaste_2025-08-22_14-53-21.png)
Alternatively, you can also use the shortcut `Ctrl+Alt+U` (default) to toggle lock/unlock.
![](Snipaste_2025-08-22_14-53-58.png)
You can change the shortcut in Settings > App appearance and behavior > Unlock and lock shortcut keys
### How to enable/disable immersive mode?
![](Snipaste_2025-08-22_14-58-44.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 599 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 859 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 KiB

View File

@@ -1,4 +1,4 @@
# How to install ".msixbundle" package
# How to install ".msixbundle" test package
## Pre-steps

View File

@@ -1,2 +1 @@
## 简体中文文档现已迁移
[点此访问](https://github.com/jayfunc/BetterLyrics/blob/dev/README.zh-CN.md)
[原页面已更改,点此返回项目主页](https://github.com/jayfunc/BetterLyrics)

View File

@@ -1,275 +0,0 @@
[_よくある質問FAQはこちらをクリック_](#faq)
![](Promotion/banner.png)
<div align=center>
<img src="BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Logo.png" alt="" width="64">
</div>
<h2 align=center>
BetterLyrics
</h2>
<div align=center>
[![](https://img.shields.io/badge/zh--CN-%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-blue)](https://github.com/jayfunc/BetterLyrics/blob/dev/README.zh-CN.md) [![Static Badge](https://img.shields.io/badge/zh--TW-%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87-blue)](https://github.com/jayfunc/BetterLyrics/blob/dev/README.zh-TW.md) [![Static Badge](https://img.shields.io/badge/ja-%E6%97%A5%E6%9C%AC%E8%AA%9E-blue)](https://github.com/jayfunc/BetterLyrics/blob/dev/README.ja.md) [![Static Badge](https://img.shields.io/badge/ko-%ED%95%9C%EA%B5%AD%EC%9D%B8-blue)](https://github.com/jayfunc/BetterLyrics/blob/dev/README.ko.md)
</div>
<div align=center>
![Static Badge](https://img.shields.io/badge/Language-C%23-purple) ![Static Badge](https://img.shields.io/badge/License-MIT-red) ![Static Badge](https://img.shields.io/badge/IDE-Visual%20Studio-purple) ![Static Badge](https://img.shields.io/badge/Framework-WinUI%203-blue)
</div>
<div align=center>
[![GitHub Repo stars](https://img.shields.io/github/stars/jayfunc/BetterLyrics)](https://github.com/jayfunc/BetterLyrics/stargazers)
</div>
<h4 align="center">
WinUI 3とWin2Dで構築された動的歌詞表示ツール — ローカル再生や他のプレーヤーにも対応
</h3>
## 🎉 本プロジェクトはSSPAIで特集されました
記事はこちら:[BetterLyrics Windows向けの没入型で滑らかな歌詞表示ツール](https://sspai.com/post/101028)
## 🔈 フィードバック・チャットグループ
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\QQ.png" height="20"> QQ](https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info) (1054700388)
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\Discord.png" height="12"> Discord](https://discord.gg/5yAQPnyCKv)
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\Telegram.png" height="16"> Telegram](https://t.me/+svhSLZ7awPsxNGY1)
## 🌟 主な特徴
- 🌠 **美しいユーザーインターフェース**
- 滑らかなアニメーションとエフェクト
- ↔️ **強力な歌詞翻訳**
- オフライン機械翻訳30言語対応
- ローカル歌詞ファイルの埋め込み翻訳を自動読み取り
- 🧩 **多様な歌詞ソース**
- ローカルストレージ
- 音楽ファイル(埋め込み歌詞付き)
- [.lrc](<https://en.wikipedia.org/wiki/LRC_(file_format)>) ファイル(標準・拡張フォーマット対応)
- [.eslrc](https://github.com/ESLyric/release) ファイル
- [.ttml](https://en.wikipedia.org/wiki/Timed_Text_Markup_Language) ファイル
- オンライン歌詞プロバイダー
- QQ Music
- NetEase Cloud Music网易云音乐
- Kugou Music酷狗音乐
- [amll-ttml-db](https://github.com/Steve-xmh/amll-ttml-db)
- [LRCLIB](https://lrclib.net/)
- 🎶 **複数の音楽プレーヤーに対応**
- <details><summary>⚠️ NetEase Cloud Music</summary>
- まず[BetterNCMプラグイン](https://microblock.cc/betterncm)をインストールしてください。インストール後にダウングレード案内が表示された場合は、案内に従いNetEase Cloud Musicを2.10.13にダウングレードしてください。
- その後、PluginMarketでInfLinkプラグインをインストールし、NetEase Cloud Musicを再起動してください。
- ⚠️ プラグインの問題によりタイムラインに不具合がある場合があります
</details>
- <details><summary>⚠️ Kugou Music</summary>
- Kugou Musicの設定で「システム再生コントロールロック画面などをサポート」を有効にしてください
- Kugou Musicはタイムライン情報を送信しないため、再生位置を変更してもBetterLyricsは検出できません
- ⚠️ タイムラインの問題はKugou自体の制限です
</details>
- <details><summary>⚠️ Apple Music</summary>
- 設定の「詳細オプション」でタイムラインしきい値を約600msに設定してください。そうしないと歌詞が前後に揺れ続けます。
- ⚠️ 歌詞の揺れを防ぐには追加設定が必要です詳細は末尾FAQ参照
</details>
- <details><summary>⚠️ foobar2000</summary>
- https://github.com/dumbie/foo_mediacontrol をインストールしてください
- ⚠️ プラグインの問題によりタイムラインに不具合がある場合があります
</details>
- Spotify
- QQ Music
- PotPlayer
- メディアプレーヤー(システム)
- <details><summary>LX Music</summary>
- LX Musicの設定ページで「Open API」を有効にしてください
- BetterLyricsの設定→詳細オプションでLX Musicサーバーアドレス通常は http://127.0.0.1:23330を入力してください
</details>
- <details><summary>MusicBee</summary>
- https://github.com/HenryPDT/mb_MediaControl をインストールしてください
</details>
- <details><summary>iTunes</summary>
- https://github.com/thewizrd/iTunes-SMTC をインストールしてください
</details>
- <details><summary>AIMP</summary>
- https://www.aimp.ru/?do=catalog&rec_id=1097 をインストールしてください
</details>
- 🪟 **多様な表示モード**
- **標準モード**
- 没入感のある歌詞アニメーションと動的背景
- **ドックモード**
- 画面端に固定されるスマートな歌詞バー
- **デスクトップモード**
- アプリの上に歌詞をフロート表示
- 🧠 **スマートな動作**
- 音楽が一時停止すると自動的に非表示
> 本プロジェクトは開発中です。最新ブランチにはバグや予期しない動作が含まれる場合があります。
## スクリーンショット
### 標準モード
![alt text](Screenshots/image.png)
![alt text](Screenshots/glow-float.gif)
![alt text](Screenshots/fan.png)
![alt text](Screenshots/lyrics-only.png)
![alt text](Screenshots/album-art-only.png)
### ドックモード
![alt text](Screenshots/dock-1.png)
![alt text](Screenshots/dock-2.png)
### デスクトップモード
![alt text](Screenshots/desktop-1.png)
![alt text](Screenshots/desktop-2.png)
## デモ
Bilibiliで紹介動画を見る2025年8月18日アップロード[こちら](https://www.bilibili.com/video/BV1yLYtzQEME/)
## 今すぐ試す
### Microsoft Store
<a href="https://apps.microsoft.com/detail/9P1WCD1P597R?referrer=appbadge&mode=direct">
<img src="https://get.microsoft.com/images/en-us%20dark.svg" width="200"/>
</a>
**最も簡単**な入手方法。**無制限**の無料トライアルまたは購入(無料版と有料版の違いはありません)
☕ 役に立ったら、ぜひ **Microsoft Store** でご購入・ご支援ください!🥰
> 安定版がリリースされると、Microsoft Storeが最初に更新されます。
### Google Drive
Google Driveからも入手可能です[リリース](https://github.com/jayfunc/BetterLyrics/releases)ページ参照)
> ダウンロードするのは「.zip」ファイルです。インストール方法は[こちらのドキュメント](How2Install/How2Install.md)をご参照ください。
## 💖 特別感謝
- [Lyricify-Lyrics-Helper](https://github.com/WXRIW/Lyricify-Lyrics-Helper)
- QQ、NetEase、Kugouの歌詞取得・復号・解析を提供
- [lrclib](https://github.com/tranxuanthang/lrclib)
- LRCLIB歌詞APIプロバイダー
- [Audio Tools Library (ATL) for .NET](https://github.com/Zeugma440/atldotnet)
- 音楽ファイルから画像抽出に使用
- [WinUIEx](https://github.com/dotMorten/WinUIEx)
- Win32ウィンドウAPIへの簡単なアクセスを提供
- [TagLib#](https://github.com/mono/taglib-sharp)
- 元の歌詞内容の読み取りに使用
- [Vanara](https://github.com/dahall/Vanara)
- Win32 APIラッパー
- [LibreTranslate](https://github.com/LibreTranslate/LibreTranslate)
- オフライン歌詞翻訳機能を提供
- [Stackoverflow - WPFでMarginプロパティをアニメーション化する方法](https://stackoverflow.com/a/21542882/11048731)
- [DevWinUI](https://github.com/ghost1372/DevWinUI)
- [Bilibili -【WinUI3】SystemBackdropController雲母・アクリル効果の定義](https://www.bilibili.com/video/BV1PY4FevEkS)
- [cnblogs - .NETアプリとWindowsシステムメディアコントロール(SMTC)の連携](https://www.cnblogs.com/TwilightLemon/p/18279496)
- [Win2DのゲームループCanvasAnimatedControl](https://www.cnblogs.com/walterlv/p/10236395.html)
- [r2d2rigo/Win2D-Samples](https://github.com/r2d2rigo/Win2D-Samples/blob/master/IrisBlurWin2D/IrisBlurWin2D/MainPage.xaml.cs)
- [CommunityToolkit - 入門から上級まで](https://mvvm.coldwind.top/)
## インスピレーションを受けたプロジェクト
- [refined-now-playing-netease](https://github.com/solstice23/refined-now-playing-netease)
- [Lyricify-App](https://github.com/WXRIW/Lyricify-App)
- [塩音楽 Salt Player](https://moriafly.com/program/salt-player)
- [MyToolBar](https://github.com/TwilightLemon/MyToolBar)
## ✍️ 翻訳にご協力ください
ご希望の言語が見つかりませんか?
ご安心ください!翻訳に参加してコントリビューターになりましょう!😆
[こちらのリンク](https://crowdin.com/project/betterlyrics/invite?h=d767e4f2dbd832d8fcdb6f7e5a198b402502866)からCrowdinで翻訳にご参加いただけます。
## Star履歴
[![](https://api.star-history.com/svg?repos=jayfunc/BetterLyrics&type=Date)](https://www.star-history.com/#jayfunc/BetterLyrics&Date)
## 不具合・PR歓迎
バグを見つけた場合はissuesでご報告ください。アイデアもお気軽にお寄せください。
---
## FAQ
### ドックモードでボタンが見えない
「ドックモード」に入ると操作ボタンは非表示になります。ウィンドウ上部にマウスを重ねると「没入」「その他」「閉じる」ボタンが表示されます。
![alt text](FAQ/image-10.png)
ウィンドウ下端の少し上にマウスを重ねると、下部に白いコントロールフローティングウィンドウが表示されます
![alt text](FAQ/image-11.png)
「小さな白いバー」をクリックすると、下部のフローティングコントロールバー(再生進行状況、タイムラインオフセット調整、前の曲/一時停止/次の曲、翻訳、レイアウト、設定)が表示されます
![alt text](FAQ/image-12.png)
### デスクトップモードでウィンドウをロックする方法
![alt text](FAQ/image-6.png)
上部にマウスを重ねてロックアイコンをクリック、または `Ctrl + Alt + U` を押してください。
### デスクトップモードでウィンドウのロックを解除する方法
![alt text](FAQ/image-7.png)
システムトレイのアイコンを右クリックし、「ウィンドウのロック解除」を選択、または `Ctrl + Alt + U` を押してください。
### 歌詞のタイムラインに遅延がある
アプリの一番下にマウスを重ねてください。
![alt text](FAQ/image.png)
最初のアイコンボタン(歌詞タイムラインオフセット)をクリックすると、オフセットを自由に調整できます。
### 歌詞が頻繁に前後にジャンプするApple Music
![alt text](FAQ/image-2.png)
「詳細オプション」セクションでしきい値(赤い四角でマーク)を上げると、歌詞が正常に動作します。

View File

@@ -1,275 +0,0 @@
[_자주 묻는 질문(FAQ) 보러가기_](#faq)
![](Promotion/banner.png)
<div align=center>
<img src="BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Logo.png" alt="" width="64">
</div>
<h2 align=center>
BetterLyrics
</h2>
<div align=center>
[![](https://img.shields.io/badge/zh--CN-%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-blue)](https://github.com/jayfunc/BetterLyrics/blob/dev/README.zh-CN.md) [![Static Badge](https://img.shields.io/badge/zh--TW-%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87-blue)](https://github.com/jayfunc/BetterLyrics/blob/dev/README.zh-TW.md) [![Static Badge](https://img.shields.io/badge/ja-%E6%97%A5%E6%9C%AC%E8%AA%9E-blue)](https://github.com/jayfunc/BetterLyrics/blob/dev/README.ja.md) [![Static Badge](https://img.shields.io/badge/ko-%ED%95%9C%EA%B5%AD%EC%9D%B8-blue)](https://github.com/jayfunc/BetterLyrics/blob/dev/README.ko.md)
</div>
<div align=center>
![Static Badge](https://img.shields.io/badge/Language-C%23-purple) ![Static Badge](https://img.shields.io/badge/License-MIT-red) ![Static Badge](https://img.shields.io/badge/IDE-Visual%20Studio-purple) ![Static Badge](https://img.shields.io/badge/Framework-WinUI%203-blue)
</div>
<div align=center>
[![GitHub Repo stars](https://img.shields.io/github/stars/jayfunc/BetterLyrics)](https://github.com/jayfunc/BetterLyrics/stargazers)
</div>
<h4 align="center">
WinUI 3와 Win2D로 제작된 동적 가사 디스플레이 도구 — 로컬 재생 및 다양한 플레이어 지원
</h3>
## 🎉 이 프로젝트는 SSPAI에 소개되었습니다!
기사 보기: [BetterLyrics Windows용 몰입감 있고 부드러운 가사 디스플레이 도구](https://sspai.com/post/101028)
## 🔈 피드백 및 채팅 그룹
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\QQ.png" height="20"> QQ](https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info) (1054700388)
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\Discord.png" height="12"> Discord](https://discord.gg/5yAQPnyCKv)
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\Telegram.png" height="16"> Telegram](https://t.me/+svhSLZ7awPsxNGY1)
## 🌟 주요 기능
- 🌠 **아름다운 사용자 인터페이스**
- 부드러운 애니메이션과 효과
- ↔️ **강력한 가사 번역**
- 오프라인 기계 번역(30개 언어 지원)
- 로컬 가사 파일에서 내장 번역 자동 읽기
- 🧩 **다양한 가사 소스**
- 로컬 저장소
- 음악 파일(내장 가사 포함)
- [.lrc](<https://en.wikipedia.org/wiki/LRC_(file_format)>) 파일(표준 및 확장 형식 지원)
- [.eslrc](https://github.com/ESLyric/release) 파일
- [.ttml](https://en.wikipedia.org/wiki/Timed_Text_Markup_Language) 파일
- 온라인 가사 제공자
- QQ Music
- NetEase Cloud Music(网易云音乐)
- Kugou Music(酷狗音乐)
- [amll-ttml-db](https://github.com/Steve-xmh/amll-ttml-db)
- [LRCLIB](https://lrclib.net/)
- 🎶 **다양한 음악 플레이어 지원**
- <details><summary>⚠️ NetEase Cloud Music</summary>
- 먼저 [BetterNCM 플러그인](https://microblock.cc/betterncm)을 설치하세요. 설치 후 다운그레이드 안내가 나오면 안내에 따라 NetEase Cloud Music을 2.10.13으로 다운그레이드하세요.
- 그 후 PluginMarket에서 InfLink 플러그인을 설치하고 NetEase Cloud Music을 재시작하세요.
- ⚠️ 플러그인 문제로 타임라인에 이슈가 있을 수 있습니다
</details>
- <details><summary>⚠️ Kugou Music</summary>
- Kugou Music 설정에서 "시스템 재생 컨트롤(잠금 화면 등) 지원"을 켜세요
- Kugou Music은 타임라인 정보를 전송하지 않아, 재생 위치를 변경해도 BetterLyrics에서 감지할 수 없습니다
- ⚠️ 타임라인 문제는 Kugou 자체의 한계입니다
</details>
- <details><summary>⚠️ Apple Music</summary>
- 설정의 "고급 옵션"에서 타임라인 임계값을 약 600ms로 설정하세요. 그렇지 않으면 가사가 계속 앞뒤로 흔들립니다.
- ⚠️ 가사 흔들림을 방지하려면 추가 설정이 필요합니다(자세한 내용은 문서 하단 FAQ 참조)
</details>
- <details><summary>⚠️ foobar2000</summary>
- https://github.com/dumbie/foo_mediacontrol 을 설치하세요
- ⚠️ 플러그인 문제로 타임라인에 이슈가 있을 수 있습니다
</details>
- Spotify
- QQ Music
- PotPlayer
- 미디어 플레이어(시스템)
- <details><summary>LX Music</summary>
- LX Music 설정 페이지에서 "Open API"를 활성화하세요
- BetterLyrics 설정-고급 옵션에서 LX Music 서버 주소(보통 http://127.0.0.1:23330)를 입력하세요
</details>
- <details><summary>MusicBee</summary>
- https://github.com/HenryPDT/mb_MediaControl 을 설치하세요
</details>
- <details><summary>iTunes</summary>
- https://github.com/thewizrd/iTunes-SMTC 를 설치하세요
</details>
- <details><summary>AIMP</summary>
- https://www.aimp.ru/?do=catalog&rec_id=1097 을 설치하세요
</details>
- 🪟 **다양한 표시 모드**
- **표준 모드**
- 몰입감 있는 가사 애니메이션과 동적 배경
- **도킹 모드**
- 화면 가장자리에 고정되는 스마트 가사 바
- **데스크톱 모드**
- 앱 위에 가사를 띄워서 표시
- 🧠 **스마트 동작**
- 음악이 일시정지되면 자동으로 숨김
> 본 프로젝트는 개발 중입니다. 최신 브랜치에는 버그나 예기치 않은 동작이 있을 수 있습니다.
## 스크린샷
### 표준 모드
![alt text](Screenshots/image.png)
![alt text](Screenshots/glow-float.gif)
![alt text](Screenshots/fan.png)
![alt text](Screenshots/lyrics-only.png)
![alt text](Screenshots/album-art-only.png)
### 도킹 모드
![alt text](Screenshots/dock-1.png)
![alt text](Screenshots/dock-2.png)
### 데스크톱 모드
![alt text](Screenshots/desktop-1.png)
![alt text](Screenshots/desktop-2.png)
## 데모
Bilibili에서 소개 영상을 시청하세요(2025년 8월 18일 업로드): [여기서 보기](https://www.bilibili.com/video/BV1yLYtzQEME/)
## 지금 사용해보세요
### Microsoft Store
<a href="https://apps.microsoft.com/detail/9P1WCD1P597R?referrer=appbadge&mode=direct">
<img src="https://get.microsoft.com/images/en-us%20dark.svg" width="200"/>
</a>
**가장 쉬운** 설치 방법. **무제한** 무료 체험 또는 구매(무료와 유료 버전 차이 없음)
☕ 유용하다면 **Microsoft Store**에서 구매로 응원해 주세요! 🥰
> 안정 버전이 출시되면 Microsoft Store가 가장 먼저 업데이트됩니다.
### Google Drive
Google Drive에서도 다운로드할 수 있습니다([릴리즈](https://github.com/jayfunc/BetterLyrics/releases) 페이지 참조)
> ".zip" 파일을 다운로드합니다. 설치 방법은 [이 문서](How2Install/How2Install.md)를 참고하세요.
## 💖 특별 감사
- [Lyricify-Lyrics-Helper](https://github.com/WXRIW/Lyricify-Lyrics-Helper)
- QQ, NetEase, Kugou 가사 가져오기, 복호화, 파싱 지원
- [lrclib](https://github.com/tranxuanthang/lrclib)
- LRCLIB 가사 API 제공자
- [Audio Tools Library (ATL) for .NET](https://github.com/Zeugma440/atldotnet)
- 음악 파일에서 이미지 추출에 사용
- [WinUIEx](https://github.com/dotMorten/WinUIEx)
- Win32 창 API에 쉽게 접근 가능
- [TagLib#](https://github.com/mono/taglib-sharp)
- 원본 가사 내용 읽기에 사용
- [Vanara](https://github.com/dahall/Vanara)
- Win32 API 래퍼
- [LibreTranslate](https://github.com/LibreTranslate/LibreTranslate)
- 오프라인 가사 번역 기능 제공
- [Stackoverflow - WPF에서 Margin 속성 애니메이션 적용 방법](https://stackoverflow.com/a/21542882/11048731)
- [DevWinUI](https://github.com/ghost1372/DevWinUI)
- [Bilibili -【WinUI3】SystemBackdropController: 운모, 아크릴 효과 정의](https://www.bilibili.com/video/BV1PY4FevEkS)
- [cnblogs - .NET 앱과 Windows 시스템 미디어 컨트롤(SMTC) 연동](https://www.cnblogs.com/TwilightLemon/p/18279496)
- [Win2D의 게임 루프: CanvasAnimatedControl](https://www.cnblogs.com/walterlv/p/10236395.html)
- [r2d2rigo/Win2D-Samples](https://github.com/r2d2rigo/Win2D-Samples/blob/master/IrisBlurWin2D/IrisBlurWin2D/MainPage.xaml.cs)
- [CommunityToolkit - 입문부터 고급까지](https://mvvm.coldwind.top/)
## 영감 받은 프로젝트
- [refined-now-playing-netease](https://github.com/solstice23/refined-now-playing-netease)
- [Lyricify-App](https://github.com/WXRIW/Lyricify-App)
- [소금 음악 Salt Player](https://moriafly.com/program/salt-player)
- [MyToolBar](https://github.com/TwilightLemon/MyToolBar)
## ✍️ 번역에 참여해 주세요
원하는 언어가 없나요?
걱정 마세요! 번역에 참여해 기여자가 되어 주세요! 😆
[이 링크](https://crowdin.com/project/betterlyrics/invite?h=d767e4f2dbd832d8fcdb6f7e5a198b402502866)에서 Crowdin으로 번역에 참여할 수 있습니다.
## Star 기록
[![](https://api.star-history.com/svg?repos=jayfunc/BetterLyrics&type=Date)](https://www.star-history.com/#jayfunc/BetterLyrics&Date)
## 이슈 및 PR 환영
버그를 발견하면 issues에 남겨주시고, 아이디어도 자유롭게 공유해 주세요.
---
## FAQ
### 도킹 모드에서 버튼이 보이지 않아요
"도킹 모드"에 들어가면 동작 버튼이 숨겨집니다. 창 상단에 마우스를 올리면 "몰입", "더보기", "닫기" 버튼이 나타납니다.
![alt text](FAQ/image-10.png)
창 하단 가장자리 바로 위에 마우스를 올리면 하단에 흰색 컨트롤 플로팅 창이 표시됩니다
![alt text](FAQ/image-11.png)
"작은 흰색 바"를 클릭하면 하단 플로팅 컨트롤 바(재생 진행, 타임라인 오프셋 조정, 이전곡/일시정지/다음곡, 번역, 레이아웃, 설정 포함)가 표시됩니다
![alt text](FAQ/image-12.png)
### 데스크톱 모드에서 창을 잠그는 방법
![alt text](FAQ/image-6.png)
상단에 마우스를 올리고 자물쇠 아이콘을 클릭하거나 `Ctrl + Alt + U`를 누르세요.
### 데스크톱 모드에서 창 잠금 해제 방법
![alt text](FAQ/image-7.png)
시스템 트레이 아이콘을 우클릭해 "창 잠금 해제"를 선택하거나 `Ctrl + Alt + U`를 누르세요.
### 가사 타임라인이 지연될 때
앱 맨 아래에 마우스를 올리세요.
![alt text](FAQ/image.png)
첫 번째 아이콘 버튼(가사 타임라인 오프셋)을 클릭하면 오프셋을 자유롭게 조정할 수 있습니다.
### 가사가 자주 앞뒤로 움직여요(예: Apple Music)
![alt text](FAQ/image-2.png)
"고급 옵션"에서 임계값(빨간 사각형 표시)을 늘리면 가사가 정상적으로 표시됩니다.

Some files were not shown because too many files have changed in this diff Show More