mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-13 03:34:55 +08:00
Compare commits
64 Commits
6f60952d09
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f735170961 | ||
|
|
a215abc41b | ||
|
|
2ddd7d19ab | ||
|
|
4d270df594 | ||
|
|
7fdb7ed870 | ||
|
|
aad648d078 | ||
|
|
d93fad6f3b | ||
|
|
a6bdf92341 | ||
|
|
96229d4346 | ||
|
|
bea29bdf9f | ||
|
|
4ad4959c39 | ||
|
|
7457cb1139 | ||
|
|
b6a6cd8659 | ||
|
|
6173dae1fa | ||
|
|
b6aac2b968 | ||
|
|
290f84cea0 | ||
|
|
3031d298d5 | ||
|
|
ed74e96aeb | ||
|
|
affa55b057 | ||
|
|
305f5e2cac | ||
|
|
b8d4fc4130 | ||
|
|
da5fd90d44 | ||
|
|
f4a6aa78b6 | ||
|
|
52b81cd959 | ||
|
|
d79933d41e | ||
|
|
a82f1bdb53 | ||
|
|
2cac55b55e | ||
|
|
4efe897ab2 | ||
|
|
173f808a88 | ||
|
|
e73c27c705 | ||
|
|
3724ef5f7e | ||
|
|
7ca0ecde16 | ||
|
|
2e0700dba5 | ||
|
|
9ec12e3a08 | ||
|
|
d042993eb7 | ||
|
|
fea7367671 | ||
|
|
2b3169e5f6 | ||
|
|
9d2e245a99 | ||
|
|
0513c3a128 | ||
|
|
5082c4c245 | ||
|
|
659b4d0e60 | ||
|
|
85f67c2ec6 | ||
|
|
bdbeb391ea | ||
|
|
3357e7aaf4 | ||
|
|
e43461d624 | ||
|
|
3e1907ad8c | ||
|
|
74eeffc8a6 | ||
|
|
c32eb3b877 | ||
|
|
047e53b830 | ||
|
|
fdb7bd16f6 | ||
|
|
4e33444d8e | ||
|
|
8fc67711b6 | ||
|
|
28757d9880 | ||
|
|
e5fb04f577 | ||
|
|
9d03c8f688 | ||
|
|
094fe7b7a1 | ||
|
|
bc32a3f34c | ||
|
|
b23d3c280f | ||
|
|
2738d45b69 | ||
|
|
77a9bb0a1b | ||
|
|
c07389acfb | ||
|
|
042229ae74 | ||
|
|
caaf93cf27 | ||
|
|
92e4b9468c |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -408,3 +408,6 @@ FodyWeavers.xsd
|
||||
/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/BetterLyrics.WinUI3 (Package)_TemporaryKey.pfx
|
||||
/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/LastFM.cs
|
||||
/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/Discord.cs
|
||||
/BetterLyrics.Plugins.Romaji/unidic
|
||||
/Plugins/BetterLyrics.Plugins.Romaji/unidic
|
||||
/Plugins/BetterLyrics.Plugins.Transliteration.Romaji/unidic
|
||||
|
||||
12
BetterLyrics.Core/BetterLyrics.Core.csproj
Normal file
12
BetterLyrics.Core/BetterLyrics.Core.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<Private>false</Private>
|
||||
<ExcludeAssets>runtime</ExcludeAssets>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
12
BetterLyrics.Core/Interfaces/Features/ILyricsSource.cs
Normal file
12
BetterLyrics.Core/Interfaces/Features/ILyricsSource.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using BetterLyrics.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Interfaces.Features
|
||||
{
|
||||
public interface ILyricsSource
|
||||
{
|
||||
Task<LyricsSearchResult> GetLyricsAsync(string title, string artist, string album, double duration);
|
||||
}
|
||||
}
|
||||
11
BetterLyrics.Core/Interfaces/Features/ILyricsTranslator.cs
Normal file
11
BetterLyrics.Core/Interfaces/Features/ILyricsTranslator.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Interfaces.Features
|
||||
{
|
||||
public interface ILyricsTranslator
|
||||
{
|
||||
Task<string?> GetTranslationAsync(string text, string targetLangCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Interfaces.Features
|
||||
{
|
||||
public interface ILyricsTransliterator
|
||||
{
|
||||
Task<string?> GetTransliterationAsync(string text, string targetLangCode);
|
||||
}
|
||||
}
|
||||
20
BetterLyrics.Core/Interfaces/IPlugin.cs
Normal file
20
BetterLyrics.Core/Interfaces/IPlugin.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using BetterLyrics.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Interfaces
|
||||
{
|
||||
public interface IPlugin
|
||||
{
|
||||
string Id { get; }
|
||||
string Name { get; }
|
||||
string Description { get; }
|
||||
string Author { get; }
|
||||
string Version { get; }
|
||||
DateTime LastUpdated { get; }
|
||||
|
||||
void OnLoad(IPluginContext context);
|
||||
void OnUnload();
|
||||
}
|
||||
}
|
||||
14
BetterLyrics.Core/Interfaces/IPluginContext.cs
Normal file
14
BetterLyrics.Core/Interfaces/IPluginContext.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using BetterLyrics.Core.Interfaces.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Interfaces
|
||||
{
|
||||
public interface IPluginContext
|
||||
{
|
||||
string PluginDirectory { get; }
|
||||
|
||||
IAIService? AIService { get; }
|
||||
}
|
||||
}
|
||||
11
BetterLyrics.Core/Interfaces/Services/IAIService.cs
Normal file
11
BetterLyrics.Core/Interfaces/Services/IAIService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Interfaces.Services
|
||||
{
|
||||
public interface IAIService
|
||||
{
|
||||
Task<string> ChatAsync(string systemPrompt, string userPrompt);
|
||||
}
|
||||
}
|
||||
16
BetterLyrics.Core/Models/LyricsSearchResult.cs
Normal file
16
BetterLyrics.Core/Models/LyricsSearchResult.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Models
|
||||
{
|
||||
public record LyricsSearchResult(
|
||||
string? Title,
|
||||
string? Artist,
|
||||
string? Album,
|
||||
double? Duration,
|
||||
string Raw,
|
||||
string? Translation = null,
|
||||
string? Transliteration = null,
|
||||
string? Reference = null);
|
||||
}
|
||||
@@ -143,7 +143,7 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7463" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="37412.BetterLyrics"
|
||||
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
||||
Version="1.2.247.0" />
|
||||
Version="1.2.260.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using BetterLyrics.WinUI3.Services.LocalizationService;
|
||||
using BetterLyrics.WinUI3.Services.LyricsCacheService;
|
||||
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
||||
using BetterLyrics.WinUI3.Services.PlayHistoryService;
|
||||
using BetterLyrics.WinUI3.Services.PluginService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.SMTCService;
|
||||
using BetterLyrics.WinUI3.Services.SongSearchMapService;
|
||||
@@ -22,7 +23,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.AppLifecycle; // 关键:App生命周期管理
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -154,6 +155,10 @@ namespace BetterLyrics.WinUI3
|
||||
}
|
||||
fileSystemService.StartAllFolderTimers();
|
||||
|
||||
// Ensure plugins
|
||||
var pluginService = Ioc.Default.GetRequiredService<IPluginService>();
|
||||
pluginService.LoadPlugins();
|
||||
|
||||
// Init system tray
|
||||
m_window = WindowHook.OpenOrShowWindow<SystemTrayWindow>();
|
||||
|
||||
@@ -248,6 +253,7 @@ namespace BetterLyrics.WinUI3
|
||||
.AddSingleton<IPlayHistoryService, PlayHistoryService>()
|
||||
.AddSingleton<ILyricsCacheService, LyricsCacheService>()
|
||||
.AddSingleton<ISongSearchMapService, SongSearchMapService>()
|
||||
.AddSingleton<IPluginService, PluginService>()
|
||||
|
||||
// ViewModels
|
||||
.AddSingleton<AppSettingsControlViewModel>()
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<None Remove="Controls\PatronControl.xaml" />
|
||||
<None Remove="Controls\PlaybackSettingsControl.xaml" />
|
||||
<None Remove="Controls\PlayQueue.xaml" />
|
||||
<None Remove="Controls\PluginManagerControl.xaml" />
|
||||
<None Remove="Controls\PropertyRow.xaml" />
|
||||
<None Remove="Controls\RemoteServerConfigControl.xaml" />
|
||||
<None Remove="Controls\ShortcutTextBox.xaml" />
|
||||
@@ -82,7 +83,7 @@
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Triggers" Version="8.2.251219" />
|
||||
<PackageReference Include="ComputeSharp.D2D1.WinUI" Version="3.2.0" />
|
||||
<PackageReference Include="csharp-pinyin" Version="1.0.1" />
|
||||
<PackageReference Include="DevWinUI.Controls" Version="9.8.1" />
|
||||
<PackageReference Include="DevWinUI.Controls" Version="9.9.2" />
|
||||
<PackageReference Include="Dubya.WindowsMediaController" Version="2.5.6" />
|
||||
<PackageReference Include="F23.StringSimilarity" Version="7.0.1" />
|
||||
<PackageReference Include="FlaUI.UIA3" Version="5.0.0" />
|
||||
@@ -96,10 +97,14 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7463" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
|
||||
<PackageReference Include="NTextCat" Version="0.3.65" />
|
||||
@@ -118,11 +123,12 @@
|
||||
<PackageReference Include="VCollab.DiscordRichPresence" Version="1.7.0" />
|
||||
<PackageReference Include="WebDav.Client" Version="2.9.0" />
|
||||
<PackageReference Include="WinUIEx" Version="2.9.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="7.9.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="7.10.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\ColorThief.WinUI3\ColorThief.WinUI3.csproj" />
|
||||
<ProjectReference Include="..\..\Impressionist\Impressionist\Impressionist.csproj" />
|
||||
<ProjectReference Include="..\..\BetterLyrics.Core\BetterLyrics.Core.csproj" />
|
||||
<ProjectReference Include="..\..\ColorThief.WinUI3\ColorThief.WinUI3.csproj" />
|
||||
<ProjectReference Include="..\..\Impressionist\Impressionist\Impressionist.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Rendering\InAppLyricsRenderer.xaml">
|
||||
@@ -134,252 +140,245 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<!--Disable Trimming for Specific Packages-->
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="FlaUI.UIA3" />
|
||||
<TrimmerRootAssembly Include="Interop.UIAutomationClient" />
|
||||
<TrimmerRootAssembly Include="Microsoft.EntityFrameworkCore" />
|
||||
<TrimmerRootAssembly Include="Microsoft.EntityFrameworkCore.Abstractions" />
|
||||
<TrimmerRootAssembly Include="Microsoft.EntityFrameworkCore.Relational" />
|
||||
<TrimmerRootAssembly Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||
<TrimmerRootAssembly Include="NAudio.Wasapi" />
|
||||
<TrimmerRootAssembly Include="TagLibSharp" />
|
||||
<TrimmerRootAssembly Include="Vanara.PInvoke.DwmApi" />
|
||||
<TrimmerRootAssembly Include="Vanara.PInvoke.Gdi32" />
|
||||
<TrimmerRootAssembly Include="Vanara.PInvoke.Shell32" />
|
||||
<TrimmerRootAssembly Include="Vanara.PInvoke.User32" />
|
||||
<TrimmerRootAssembly Include="Vanara.Windows.Shell" />
|
||||
<TrimmerRootDescriptor Include="PluginConfigs\**\*_TrimmerRoots.xml" />
|
||||
<TrimmerRootDescriptor Include="Core_TrimmerRoots.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\AIMP.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AlbumArtPlaceholder.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Alipay.jpg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AMLLPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AppleMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Chrome.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Edge.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\FluidEffect.bin">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Empty.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\EmptyBox.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\EmptyState.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Folder.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\foobar2000.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\HyPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\iTunes.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\KugouMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\LastFM.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Leaf.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Listen1.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Logo.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Logo.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\LXMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\MediaPlayerWindows11.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\MoeKoeMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\MusicBee.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\NetEaseCloudMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\OriginalSoundHQPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Page.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\PlanetMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\PotPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\QQMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Question.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\RevolvingHearts.gif">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\SaltPlayerForWindows.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Segoe Fluent Icons.ttf">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Spotify.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\WeChatReward.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Wiki82.profile.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AIMP.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AlbumArtPlaceholder.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Alipay.jpg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AMLLPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AppleMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Chrome.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Edge.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\FluidEffect.bin">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Empty.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\EmptyBox.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\EmptyState.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Folder.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\foobar2000.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\HyPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\iTunes.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\KugouMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\LastFM.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Leaf.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Listen1.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Logo.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Logo.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\LXMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\MediaPlayerWindows11.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\MoeKoeMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\MusicBee.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\NetEaseCloudMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\OriginalSoundHQPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Page.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\PlanetMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\PotPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\QQMusic.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Question.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\RevolvingHearts.gif">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\SaltPlayerForWindows.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Segoe Fluent Icons.ttf">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Spotify.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\WeChatReward.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Wiki82.profile.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\PatronControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\PluginManagerControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Styles\GhostSliderStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\PatronControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Styles\Converters.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Styles\GhostSliderStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\PlayQueue.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Styles\Converters.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\StatsDashboardControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\PlayQueue.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\FontFamilyAutoSuggestBox.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\StatsDashboardControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\LyricsStyleSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\FontFamilyAutoSuggestBox.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\LyricsWindowSwitchWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\LyricsStyleSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\LyricsWindowSwitchControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Views\LyricsWindowSwitchWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\DemoWindowGrid.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\LyricsWindowSwitchControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\LyricsWindowSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\DemoWindowGrid.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\LyricsSearchWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\LyricsWindowSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\LyricsSearchControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Views\LyricsSearchWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\ShortcutTextBox.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\LyricsSearchControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\ExtendedSlider.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\ShortcutTextBox.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\LyricsEffectSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\ExtendedSlider.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\MediaSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\LyricsEffectSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\PlaybackSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\MediaSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AlbumArtAreaStyleSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\PlaybackSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\LyricsBackgroundSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\AlbumArtAreaStyleSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AppSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\LyricsBackgroundSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\MusicGalleryWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\AppSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\MusicGalleryPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Views\MusicGalleryWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\MusicGalleryPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\SettingsWindow.xaml">
|
||||
@@ -392,54 +391,57 @@
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\RemoteServerConfigControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\RemoteServerConfigControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\NowPlayingBar.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\NowPlayingBar.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\SystemTrayWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Views\SystemTrayWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\WindowSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\WindowSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AlbumArtAreaEffectSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\AlbumArtAreaEffectSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\ImageSwitcher.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\ImageSwitcher.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\ShadowImage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\ShadowImage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\PropertyRow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\PropertyRow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AboutControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Controls\AboutControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Styles\InteractiveListViewHeaderStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Styles\InteractiveListViewHeaderStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="PluginConfigs\" />
|
||||
</ItemGroup>
|
||||
<!-- Publish Properties -->
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -195,6 +195,7 @@
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock x:Uid="SettingsPagePatrons" />
|
||||
<dev:WrapPanel Margin="-12,0,0,0" Orientation="Horizontal">
|
||||
<uc:PatronControl Date="Jan 8, 2026" PatronName="Eureka-K_K" />
|
||||
<uc:PatronControl Date="Jan 3, 2026" PatronName="**轩" />
|
||||
<uc:PatronControl Date="Dec 13, 2025" PatronName="<Anonymous>" />
|
||||
<uc:PatronControl Date="Dec 3, 2025" PatronName="YE" />
|
||||
@@ -282,12 +283,6 @@
|
||||
</dev:SettingsExpander.ItemsHeader>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageSettingsPlayHistory" Visibility="Collapsed">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Button x:Uid="SettingsPageExportPlayHistoryButton" Command="{x:Bind ViewModel.ExportPlayHistoryCommand}" />
|
||||
</StackPanel>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageFixedTimeStep" Visibility="Collapsed">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.AdvancedSettings.IsFixedTimeStep, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
@@ -58,42 +58,43 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
private readonly ValueTransition<Color> _immersiveBgColorTransition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
defaultTotalDuration: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<double> _immersiveBgOpacityTransition = new(
|
||||
initialValue: 1f,
|
||||
durationSeconds: 0.3f
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: 0.3f
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor1Transition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
defaultTotalDuration: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor2Transition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
defaultTotalDuration: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor3Transition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
defaultTotalDuration: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor4Transition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
defaultTotalDuration: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<double> _canvasYScrollTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: 0.3f
|
||||
);
|
||||
private readonly ValueTransition<double> _mouseYScrollTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: 0.3f
|
||||
);
|
||||
|
||||
private TimeSpan _songPositionWithOffset;
|
||||
@@ -292,7 +293,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
}
|
||||
else if (e.Property == MouseScrollOffsetProperty)
|
||||
{
|
||||
canvas._mouseYScrollTransition.StartTransition(Convert.ToDouble(e.NewValue));
|
||||
canvas._mouseYScrollTransition.Start(Convert.ToDouble(e.NewValue));
|
||||
}
|
||||
else if (e.Property == MousePositionProperty)
|
||||
{
|
||||
@@ -318,11 +319,11 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
else if (e.Property == AlbumArtThemeColorsProperty)
|
||||
{
|
||||
var albumArtThemeColors = (AlbumArtThemeColors)e.NewValue;
|
||||
canvas._immersiveBgColorTransition.StartTransition(albumArtThemeColors.EnvColor);
|
||||
canvas._accentColor1Transition.StartTransition(albumArtThemeColors.AccentColor1);
|
||||
canvas._accentColor2Transition.StartTransition(albumArtThemeColors.AccentColor2);
|
||||
canvas._accentColor3Transition.StartTransition(albumArtThemeColors.AccentColor3);
|
||||
canvas._accentColor4Transition.StartTransition(albumArtThemeColors.AccentColor4);
|
||||
canvas._immersiveBgColorTransition.Start(albumArtThemeColors.EnvColor);
|
||||
canvas._accentColor1Transition.Start(albumArtThemeColors.AccentColor1);
|
||||
canvas._accentColor2Transition.Start(albumArtThemeColors.AccentColor2);
|
||||
canvas._accentColor3Transition.Start(albumArtThemeColors.AccentColor3);
|
||||
canvas._accentColor4Transition.Start(albumArtThemeColors.AccentColor4);
|
||||
|
||||
canvas._albumArtThemeColors = albumArtThemeColors;
|
||||
canvas._isLayoutChanged = true;
|
||||
@@ -344,7 +345,6 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
var lyricsEffect = _lyricsWindowStatus.LyricsEffectSettings;
|
||||
|
||||
double songDuration = _gsmtcService.CurrentSongInfo.DurationMs;
|
||||
bool isForceWordByWord = _settingsService.AppSettings.GeneralSettings.IsForceWordByWordEffect;
|
||||
|
||||
Color overlayColor;
|
||||
double finalOpacity;
|
||||
@@ -410,7 +410,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
return _synchronizer.GetLinePlayingProgress(
|
||||
_songPositionWithOffset.TotalMilliseconds,
|
||||
line,
|
||||
isForceWordByWord
|
||||
lyricsEffect.WordByWordEffectMode
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -486,9 +486,16 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
var targetScroll = LyricsLayoutManager.CalculateTargetScrollOffset(_renderLyricsLines, _primaryPlayingLineIndex);
|
||||
if (targetScroll.HasValue) _canvasTargetScrollOffset = targetScroll.Value;
|
||||
|
||||
_canvasYScrollTransition.SetEasingType(lyricsEffect.LyricsScrollEasingType);
|
||||
_canvasYScrollTransition.SetDuration(lyricsEffect.LyricsScrollDuration / 1000.0);
|
||||
_canvasYScrollTransition.StartTransition(_canvasTargetScrollOffset, _isLayoutChanged);
|
||||
if (_isLayoutChanged)
|
||||
{
|
||||
_canvasYScrollTransition.JumpTo(_canvasTargetScrollOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
_canvasYScrollTransition.SetDurationMs(lyricsEffect.LyricsScrollDuration);
|
||||
_canvasYScrollTransition.SetInterpolator(EasingHelper.GetInterpolatorByEasingType<double>(lyricsEffect.LyricsScrollEasingType, lyricsEffect.LyricsScrollEasingMode));
|
||||
_canvasYScrollTransition.Start(_canvasTargetScrollOffset);
|
||||
}
|
||||
}
|
||||
_canvasYScrollTransition.Update(elapsedTime);
|
||||
|
||||
|
||||
@@ -23,6 +23,14 @@
|
||||
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
|
||||
Text="Effect" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsWordByWordEffectMode" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.WordByWordEffectMode, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsWordByWordEffectModeAuto" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsWordByWordEffectModeNever" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsWordByWordEffectModeAlways" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- 模糊效果 -->
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsBlurEffect" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsBlurEffectEnabled, Mode=TwoWay}" />
|
||||
@@ -188,18 +196,25 @@
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsScrollEasingType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeLinear" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeSmoothStep" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutSine" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutQuad" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutCubic" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutQuart" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutQuint" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutExpo" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutCirc" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutBack" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutElastic" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutBounce" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseSine" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseQuad" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseCubic" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseQuart" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseQuint" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseExpo" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseCirc" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseBack" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseElastic" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseBounce" />
|
||||
</ComboBox>
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageEasingMode">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsScrollEasingMode, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingModeIn" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingModeOut" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingModeInOut" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageScrollTopDuration">
|
||||
<local:ExtendedSlider
|
||||
Default="500"
|
||||
|
||||
@@ -365,10 +365,6 @@
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ListenOnNewPlaybackSource, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageForceWordByWordEffect">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IsForceWordByWordEffect, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- Lyrics translation -->
|
||||
<TextBlock x:Uid="SettingsPageTranslation" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<dev:SettingsExpander x:Uid="LyricsPageTranslationEnabled" IsExpanded="True">
|
||||
@@ -428,30 +424,6 @@
|
||||
</dev:SettingsExpander>
|
||||
<dev:SettingsExpander x:Uid="SettingsPageJapanese" IsExpanded="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageCutletDockerServer" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=OneWay}">
|
||||
<dev:SettingsCard.Description>
|
||||
<HyperlinkButton Content="https://github.com/jayfunc/cutlet-docker" NavigateUri="https://github.com/jayfunc/cutlet-docker" />
|
||||
</dev:SettingsCard.Description>
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox
|
||||
x:Uid="CutletServerTextBox"
|
||||
Grid.Column="0"
|
||||
IsEnabled="{x:Bind ViewModel.IsCutletDockerServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
|
||||
Text="{x:Bind ViewModel.AppSettings.TranslationSettings.CutletDockerServer, Mode=TwoWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Uid="SettingsPageServerTestButton"
|
||||
Grid.Column="1"
|
||||
Command="{x:Bind ViewModel.CutletDockerServerTestCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.IsCutletDockerServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- 中文简体繁体偏好 -->
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.PluginManagerControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:dev="using:DevWinUI"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="using:BetterLyrics.WinUI3.Models"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Padding="36,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<TextBlock x:Uid="PluginManagerControlTitle" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
</Grid>
|
||||
|
||||
<ListView
|
||||
Grid.Row="1"
|
||||
ItemContainerStyle="{StaticResource ListViewStretchedItemContainerStyle}"
|
||||
ItemsSource="{x:Bind Plugins, Mode=OneWay}"
|
||||
SelectionMode="None">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:PluginDisplayModel">
|
||||
<dev:SettingsExpander
|
||||
Description="{x:Bind Description}"
|
||||
Header="{x:Bind Name}"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}">
|
||||
<TextBlock Text="{x:Bind Version}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<local:PropertyRow Header="Author" Value="{x:Bind Author}" />
|
||||
<local:PropertyRow Header="ID" Value="{x:Bind Id}" />
|
||||
</StackPanel>
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard>
|
||||
<Button
|
||||
x:Uid="PluginManagerControlUninstall"
|
||||
Click="OnUninstallClick"
|
||||
Tag="{x:Bind Plugin}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{x:Bind IsListEmpty, Mode=OneWay}">
|
||||
<FontIcon
|
||||
FontSize="48"
|
||||
Glyph=""
|
||||
Opacity="0.3" />
|
||||
<TextBlock
|
||||
x:Uid="PluginManagerControlNoPluginsInstalled"
|
||||
Margin="0,12,0,0"
|
||||
Opacity="0.5" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="2" Margin="0,6,0,20">
|
||||
<Button
|
||||
x:Uid="PluginManagerControlInstall"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Click="OnInstallPluginClick"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,149 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.PluginService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
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.Collections.ObjectModel;
|
||||
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.Controls
|
||||
{
|
||||
public sealed partial class PluginManagerControl : UserControl
|
||||
{
|
||||
public ObservableCollection<PluginDisplayModel> Plugins { get; } = new();
|
||||
|
||||
public Visibility IsListEmpty => Plugins.Count == 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
private readonly IPluginService _pluginService;
|
||||
|
||||
public PluginManagerControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
_pluginService = Ioc.Default.GetRequiredService<IPluginService>();
|
||||
|
||||
this.Loaded += (s, e) =>
|
||||
{
|
||||
RefreshPluginList();
|
||||
};
|
||||
}
|
||||
|
||||
private void RefreshPluginList()
|
||||
{
|
||||
Plugins.Clear();
|
||||
|
||||
var allPlugins = _pluginService.Plugins;
|
||||
|
||||
foreach (var plugin in allPlugins)
|
||||
{
|
||||
Plugins.Add(new PluginDisplayModel(plugin));
|
||||
}
|
||||
|
||||
Bindings.Update();
|
||||
}
|
||||
|
||||
private async void OnInstallPluginClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var file = await Helper.PickerHelper.PickSingleFileAsync<SettingsWindow>([".zip"]);
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 显示加载条...
|
||||
|
||||
// 3. 调用我们在上一步写的 InstallPlugin 方法
|
||||
_pluginService.InstallPlugin(file.Path);
|
||||
|
||||
// 4. 重新加载所有插件 (这会触发热重载)
|
||||
_pluginService.LoadPlugins();
|
||||
|
||||
// 5. 刷新界面
|
||||
RefreshPluginList();
|
||||
|
||||
ShowTip("安装成功", $"插件 {file.Name} 已安装。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowError("安装失败", ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 卸载按钮点击事件
|
||||
private async void OnUninstallClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button btn && btn.Tag is IPlugin plugin)
|
||||
{
|
||||
// 二次确认对话框
|
||||
ContentDialog deleteDialog = new ContentDialog
|
||||
{
|
||||
XamlRoot = this.XamlRoot,
|
||||
Title = "卸载插件",
|
||||
Content = $"确定要删除 \"{plugin.Name}\" 吗?此操作无法撤销。",
|
||||
PrimaryButtonText = "删除",
|
||||
CloseButtonText = "取消",
|
||||
DefaultButton = ContentDialogButton.Close
|
||||
};
|
||||
|
||||
var result = await deleteDialog.ShowAsync();
|
||||
|
||||
if (result == ContentDialogResult.Primary)
|
||||
{
|
||||
try
|
||||
{
|
||||
_pluginService.UninstallPlugin(plugin.Id);
|
||||
|
||||
// 暂时我们只能刷新列表演示
|
||||
RefreshPluginList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowError("卸载失败", ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 简单的弹窗辅助方法
|
||||
private async void ShowTip(string title, string content)
|
||||
{
|
||||
ContentDialog dialog = new ContentDialog
|
||||
{
|
||||
XamlRoot = this.XamlRoot,
|
||||
Title = title,
|
||||
Content = content,
|
||||
CloseButtonText = "关闭"
|
||||
};
|
||||
await dialog.ShowAsync();
|
||||
}
|
||||
|
||||
private async void ShowError(string title, string content)
|
||||
{
|
||||
ContentDialog dialog = new ContentDialog
|
||||
{
|
||||
XamlRoot = this.XamlRoot,
|
||||
Title = title,
|
||||
Content = content,
|
||||
CloseButtonText = "关闭"
|
||||
};
|
||||
await dialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@
|
||||
<ComboBoxItem x:Uid="StatsDashboardControlThisMonth" />
|
||||
<ComboBoxItem x:Uid="StatsDashboardControlThisQuarter" />
|
||||
<ComboBoxItem x:Uid="StatsDashboardControlThisYear" />
|
||||
<ComboBoxItem x:Uid="StatsDashboardControlAllTime" />
|
||||
<ComboBoxItem x:Uid="StatsDashboardControlCustom" />
|
||||
</ComboBox>
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<linker>
|
||||
<assembly fullname="FlaUI.UIA3" preserve="all" />
|
||||
<assembly fullname="Interop.UIAutomationClient" preserve="all" />
|
||||
|
||||
<assembly fullname="Microsoft.EntityFrameworkCore" preserve="all" />
|
||||
<assembly fullname="Microsoft.EntityFrameworkCore.Abstractions" preserve="all" />
|
||||
<assembly fullname="Microsoft.EntityFrameworkCore.Relational" preserve="all" />
|
||||
<assembly fullname="Microsoft.EntityFrameworkCore.Sqlite" preserve="all" />
|
||||
|
||||
<assembly fullname="NAudio.Wasapi" preserve="all" />
|
||||
<assembly fullname="TagLibSharp" preserve="all" />
|
||||
|
||||
<assembly fullname="Vanara.PInvoke.DwmApi" preserve="all" />
|
||||
<assembly fullname="Vanara.PInvoke.Gdi32" preserve="all" />
|
||||
<assembly fullname="Vanara.PInvoke.Shell32" preserve="all" />
|
||||
<assembly fullname="Vanara.PInvoke.User32" preserve="all" />
|
||||
<assembly fullname="Vanara.Windows.Shell" preserve="all" />
|
||||
|
||||
</linker>
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace BetterLyrics.WinUI3.Enums;
|
||||
|
||||
public enum EaseMode
|
||||
{
|
||||
In,
|
||||
Out,
|
||||
InOut,
|
||||
}
|
||||
@@ -6,15 +6,15 @@ namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
Linear,
|
||||
SmoothStep,
|
||||
EaseInOutSine,
|
||||
EaseInOutQuad,
|
||||
EaseInOutCubic,
|
||||
EaseInOutQuart,
|
||||
EaseInOutQuint,
|
||||
EaseInOutExpo,
|
||||
EaseInOutCirc,
|
||||
EaseInOutBack,
|
||||
EaseInOutElastic,
|
||||
EaseInOutBounce,
|
||||
Sine,
|
||||
Quad,
|
||||
Cubic,
|
||||
Quart,
|
||||
Quint,
|
||||
Expo,
|
||||
Circle,
|
||||
Back,
|
||||
Elastic,
|
||||
Bounce,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,5 +14,6 @@ namespace BetterLyrics.WinUI3.Enums
|
||||
LocalEslrcFile,
|
||||
LocalTtmlFile,
|
||||
AppleMusic,
|
||||
Plugin = 999,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
ThisMonth,
|
||||
ThisQuarter,
|
||||
ThisYear,
|
||||
AllTime,
|
||||
Custom
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@
|
||||
LocalEslrcFile,
|
||||
LocalTtmlFile,
|
||||
LibreTranslate,
|
||||
Plugin = 999,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
LocalEslrcFile,
|
||||
LocalTtmlFile,
|
||||
BetterLyrics,
|
||||
CutletDocker
|
||||
CutletDocker,
|
||||
Plugin = 999,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum WordByWordEffectMode
|
||||
{
|
||||
Auto,
|
||||
Never,
|
||||
Always,
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models.Lyrics;
|
||||
using BetterLyrics.WinUI3.Services.LocalizationService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -18,14 +19,27 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
new LyricsLine
|
||||
{
|
||||
StartMs = 0,
|
||||
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
|
||||
EndMs = (int)TimeSpan.FromSeconds(30).TotalMilliseconds,
|
||||
PrimaryText = "● ● ●",
|
||||
PrimarySyllables = [new BaseLyrics { Text = "● ● ●", StartMs = 0, EndMs = (int)TimeSpan.FromSeconds(30).TotalMilliseconds }],
|
||||
IsPrimaryHasRealSyllableInfo = true,
|
||||
},
|
||||
],
|
||||
LanguageCode = "N/A",
|
||||
};
|
||||
}
|
||||
|
||||
public static LyricsData GetNotfoundPlaceholder()
|
||||
{
|
||||
return new LyricsData([new LyricsLine
|
||||
{
|
||||
StartMs = 0,
|
||||
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
|
||||
PrimaryText = "N/A",
|
||||
PrimarySyllables = [new BaseLyrics { Text = "N/A", StartMs = 0, EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds }],
|
||||
}]);
|
||||
}
|
||||
|
||||
public void SetTranslatedText(LyricsData translationData, int toleranceMs = 50)
|
||||
{
|
||||
foreach (var line in lyricsData.LyricsLines)
|
||||
|
||||
@@ -36,6 +36,12 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
return songInfo;
|
||||
}
|
||||
|
||||
public SongInfo WithSongId(string value)
|
||||
{
|
||||
songInfo.SongId = value;
|
||||
return songInfo;
|
||||
}
|
||||
|
||||
public PlayHistoryItem? ToPlayHistoryItem(double actualPlayedMs)
|
||||
{
|
||||
if (songInfo == null) return null;
|
||||
|
||||
@@ -56,6 +56,57 @@
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://learn.microsoft.com/zh-cn/dotnet/standard/io/how-to-copy-directories
|
||||
/// </summary>
|
||||
/// <param name="sourceDir"></param>
|
||||
/// <param name="destinationDir"></param>
|
||||
/// <param name="recursive"></param>
|
||||
/// <exception cref="DirectoryNotFoundException"></exception>
|
||||
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive)
|
||||
{
|
||||
// Get information about the source directory
|
||||
var dir = new DirectoryInfo(sourceDir);
|
||||
|
||||
// Check if the source directory exists
|
||||
if (!dir.Exists)
|
||||
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
|
||||
|
||||
// Cache directories before we start copying
|
||||
DirectoryInfo[] dirs = dir.GetDirectories();
|
||||
|
||||
// Create the destination directory
|
||||
Directory.CreateDirectory(destinationDir);
|
||||
|
||||
// Get the files in the source directory and copy to the destination directory
|
||||
foreach (FileInfo file in dir.GetFiles())
|
||||
{
|
||||
string targetFilePath = Path.Combine(destinationDir, file.Name);
|
||||
|
||||
CopyLockedFile(file.FullName, targetFilePath);
|
||||
}
|
||||
|
||||
// If recursive and copying subdirectories, recursively call this method
|
||||
if (recursive)
|
||||
{
|
||||
foreach (DirectoryInfo subDir in dirs)
|
||||
{
|
||||
string newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
||||
CopyDirectory(subDir.FullName, newDestinationDir, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CopyLockedFile(string sourcePath, string targetPath)
|
||||
{
|
||||
using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
using (var destStream = new FileStream(targetPath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
sourceStream.CopyTo(destStream);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +1,170 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class EasingHelper
|
||||
{
|
||||
public static double EaseInOutSine(double t)
|
||||
{
|
||||
return -(Math.Cos(Math.PI * t) - 1f) / 2f;
|
||||
}
|
||||
public static double EaseInOutQuad(double t)
|
||||
{
|
||||
return t < 0.5f ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
||||
}
|
||||
#region Interpolators
|
||||
|
||||
public static double EaseInOutCubic(double t)
|
||||
public static Func<T, T, double, T> GetInterpolatorByEasingType<T>(EasingType? type, EaseMode easingMode = EaseMode.Out)
|
||||
where T : INumber<T>, IFloatingPointIeee754<T>
|
||||
{
|
||||
return t < 0.5f ? 4 * t * t * t : 1 - Math.Pow(-2 * t + 2, 3) / 2;
|
||||
}
|
||||
public static double EaseInOutQuart(double t)
|
||||
{
|
||||
return t < 0.5f ? 8 * t * t * t * t : 1 - Math.Pow(-2 * t + 2, 4) / 2;
|
||||
}
|
||||
|
||||
public static double EaseInOutQuint(double t)
|
||||
{
|
||||
return t < 0.5f ? 16 * t * t * t * t * t : 1 - Math.Pow(-2 * t + 2, 5) / 2;
|
||||
}
|
||||
|
||||
public static double EaseInOutExpo(double t)
|
||||
{
|
||||
return t == 0
|
||||
? 0
|
||||
: t == 1
|
||||
? 1
|
||||
: t < 0.5 ? Math.Pow(2, 20 * t - 10) / 2
|
||||
: (2 - Math.Pow(2, -20 * t + 10)) / 2;
|
||||
}
|
||||
|
||||
public static double EaseInOutCirc(double t)
|
||||
{
|
||||
return t < 0.5f
|
||||
? (1 - Math.Sqrt(1 - Math.Pow(2 * t, 2))) / 2
|
||||
: (Math.Sqrt(1 - Math.Pow(-2 * t + 2, 2)) + 1) / 2;
|
||||
}
|
||||
|
||||
public static double EaseInOutBack(double t)
|
||||
{
|
||||
double c1 = 1.70158f;
|
||||
double c2 = c1 * 1.525f;
|
||||
|
||||
return t < 0.5
|
||||
? (Math.Pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
|
||||
: (Math.Pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
|
||||
}
|
||||
|
||||
public static double EaseInOutElastic(double t)
|
||||
{
|
||||
if (t == 0 || t == 1) return t;
|
||||
double p = 0.3f;
|
||||
double s = p / 4;
|
||||
return t < 0.5f
|
||||
? -(Math.Pow(2, 20 * t - 10) * Math.Sin((20 * t - 11.125f) * (2 * Math.PI) / p)) / 2
|
||||
: (Math.Pow(2, -20 * t + 10) * Math.Sin((20 * t - 11.125f) * (2 * Math.PI) / p)) / 2 + 1;
|
||||
}
|
||||
|
||||
private static double EaseOutBounce(double t)
|
||||
{
|
||||
if (t < 4 / 11f)
|
||||
return (start, end, progress) =>
|
||||
{
|
||||
return (121 * t * t) / 16f;
|
||||
Func<T, T> easeInFunc = type switch
|
||||
{
|
||||
EasingType.Sine => EaseInSine,
|
||||
EasingType.Quad => EaseInQuad,
|
||||
EasingType.Cubic => EaseInCubic,
|
||||
EasingType.Quart => EaseInQuart,
|
||||
EasingType.Quint => EaseInQuint,
|
||||
EasingType.Expo => EaseInExpo,
|
||||
EasingType.Circle => EaseInCircle,
|
||||
EasingType.Back => EaseInBack,
|
||||
EasingType.Elastic => EaseInElastic,
|
||||
EasingType.Bounce => EaseInBounce,
|
||||
EasingType.SmoothStep => SmoothStep,
|
||||
EasingType.Linear => Linear,
|
||||
_ => EaseInQuad,
|
||||
};
|
||||
double t = Ease(progress, easingMode, easeInFunc);
|
||||
return start + ((end - start) * T.CreateChecked(t));
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static double Ease<T>(double t, EaseMode mode, Func<T, T> easeIn)
|
||||
where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
t = Math.Clamp(t, 0.0, 1.0);
|
||||
|
||||
T tt = T.CreateChecked(t);
|
||||
T half = T.CreateChecked(0.5);
|
||||
T two = T.CreateChecked(2);
|
||||
T tResult = mode switch
|
||||
{
|
||||
EaseMode.In => easeIn(tt),
|
||||
EaseMode.Out => T.One - easeIn(T.One - tt),
|
||||
EaseMode.InOut => tt < half
|
||||
? easeIn(tt * two) / two
|
||||
: T.One - (easeIn((T.One - tt) * two) / two),
|
||||
_ => easeIn(tt),
|
||||
};
|
||||
|
||||
return double.CreateChecked(tResult);
|
||||
}
|
||||
|
||||
public static T EaseInSine<T>(T t) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
return T.One - T.Cos((t * T.Pi) / T.CreateChecked(2));
|
||||
}
|
||||
|
||||
public static T EaseInQuad<T>(T t) where T : INumber<T>
|
||||
{
|
||||
return t * t;
|
||||
}
|
||||
|
||||
public static T EaseInCubic<T>(T t) where T : INumber<T>
|
||||
{
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
public static T EaseInQuart<T>(T t) where T : INumber<T>
|
||||
{
|
||||
return t * t * t * t;
|
||||
}
|
||||
|
||||
public static T EaseInQuint<T>(T t) where T : INumber<T>
|
||||
{
|
||||
return t * t * t * t * t;
|
||||
}
|
||||
|
||||
public static T EaseInExpo<T>(T t) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
if (t == T.Zero)
|
||||
{
|
||||
return T.Zero;
|
||||
}
|
||||
else if (t < 8 / 11f)
|
||||
|
||||
return T.Pow(T.CreateChecked(2), (T.CreateChecked(10) * t) - T.CreateChecked(10));
|
||||
}
|
||||
|
||||
public static T EaseInCircle<T>(T t) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
return T.One - T.Sqrt(T.One - (t * t));
|
||||
}
|
||||
|
||||
public static T EaseInBack<T>(T t) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
T c1 = T.CreateChecked(1.70158);
|
||||
T c3 = c1 + T.One;
|
||||
|
||||
return (c3 * t * t * t) - (c1 * t * t);
|
||||
}
|
||||
|
||||
public static T EaseInElastic<T>(T t) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
if (t == T.Zero || t == T.One)
|
||||
{
|
||||
return (363 / 40f * t * t) - (99 / 10f * t) + 17 / 5f;
|
||||
return t;
|
||||
}
|
||||
else if (t < 9 / 10f)
|
||||
|
||||
const double springiness = 6;
|
||||
const double oscillations = 1;
|
||||
|
||||
double td = double.CreateChecked(t);
|
||||
|
||||
double expo = (Math.Exp(springiness * td) - 1.0) / (Math.Exp(springiness) - 1.0);
|
||||
double result = 0.7 * expo * Math.Sin((Math.PI * 2.0 * oscillations + (Math.PI * 0.5)) * td);
|
||||
|
||||
return T.CreateChecked(result);
|
||||
}
|
||||
|
||||
private static T EaseOutBounce<T>(T t) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
if (t < T.CreateChecked(4.0 / 11.0))
|
||||
{
|
||||
return (4356 / 361f * t * t) - (35442 / 1805f * t) + 16061 / 1805f;
|
||||
return (T.CreateChecked(121) * t * t) / T.CreateChecked(16);
|
||||
}
|
||||
else if (t < T.CreateChecked(8.0 / 11.0))
|
||||
{
|
||||
return ((T.CreateChecked(363.0 / 40.0) * t * t) - (T.CreateChecked(99.0 / 10.0) * t)) + T.CreateChecked(17.0 / 5.0);
|
||||
}
|
||||
else if (t < T.CreateChecked(9.0 / 10.0))
|
||||
{
|
||||
return ((T.CreateChecked(4356.0 / 361.0) * t * t) - (T.CreateChecked(35442.0 / 1805.0) * t)) + T.CreateChecked(16061.0 / 1805.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (54 / 5f * t * t) - (513 / 25f * t) + 268 / 25f;
|
||||
return ((T.CreateChecked(54.0 / 5.0) * t * t) - (T.CreateChecked(513.0 / 25.0) * t)) + T.CreateChecked(268.0 / 25.0);
|
||||
}
|
||||
}
|
||||
|
||||
public static double EaseInOutBounce(double t)
|
||||
public static T EaseInBounce<T>(T t) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
if (t < 0.5f)
|
||||
{
|
||||
return (1 - EaseOutBounce(1 - 2 * t)) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (1 + EaseOutBounce(2 * t - 1)) / 2;
|
||||
}
|
||||
return T.One - EaseOutBounce(T.One - t);
|
||||
}
|
||||
|
||||
public static double SmoothStep(double t)
|
||||
public static T SmoothStep<T>(T t) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
return t * t * (3f - 2f * t);
|
||||
return t * t * (T.CreateChecked(3) - (T.CreateChecked(2) * t));
|
||||
}
|
||||
|
||||
public static double CubicBezier(double t, double p0, double p1, double p2, double p3)
|
||||
public static T CubicBezier<T>(T t, T p0, T p1, T p2, T p3) where T : IFloatingPointIeee754<T>
|
||||
{
|
||||
double u = 1 - t;
|
||||
return u * u * u * p0 + 3 * u * u * t * p1 + 3 * u * t * t * p2 + t * t * t * p3;
|
||||
T u = T.One - t;
|
||||
|
||||
return (u * u * u * p0)
|
||||
+ (T.CreateChecked(3) * u * u * t * p1)
|
||||
+ (T.CreateChecked(3) * u * t * t * p2)
|
||||
+ (t * t * t * p3);
|
||||
}
|
||||
|
||||
public static double Linear(double t) => t;
|
||||
public static T Linear<T>(T t) where T : INumber<T> => t;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,27 +10,27 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static partial class MetadataComparer
|
||||
{
|
||||
private const double WeightTitle = 0.40;
|
||||
private const double WeightArtist = 0.40;
|
||||
private const double WeightTitle = 0.30;
|
||||
private const double WeightArtist = 0.30;
|
||||
private const double WeightAlbum = 0.10;
|
||||
private const double WeightDuration = 0.10;
|
||||
private const double WeightDuration = 0.30;
|
||||
|
||||
// JaroWinkler 适合短字符串匹配
|
||||
private static readonly JaroWinkler _algo = new();
|
||||
|
||||
public static int CalculateScore(SongInfo songInfo, LyricsCacheItem remote)
|
||||
{
|
||||
return CalculateScore(songInfo, remote.Title, remote.Artist, remote.Album, remote.Duration * 1000);
|
||||
return CalculateScore(songInfo, remote.Title, remote.Artist, remote.Album, remote.Duration);
|
||||
}
|
||||
|
||||
public static int CalculateScore(SongInfo songInfo, FilesIndexItem local)
|
||||
{
|
||||
return CalculateScore(songInfo, local.Title, local.Artist, local.Album, local.Duration * 1000, local.FileName);
|
||||
return CalculateScore(songInfo, local.Title, local.Artist, local.Album, local.Duration, local.FileName);
|
||||
}
|
||||
|
||||
public static int CalculateScore(
|
||||
SongInfo songInfo,
|
||||
string? compareTitle, string? compareArtist, string? compareAlbum, double? compareDurationMs, string? compareFileName = null)
|
||||
string? compareTitle, string? compareArtist, string? compareAlbum, double? compareDuration, string? compareFileName = null)
|
||||
{
|
||||
double totalScore = 0;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
double titleScore = GetStringSimilarity(songInfo.Title, compareTitle);
|
||||
double artistScore = GetStringSimilarity(songInfo.Artist, compareArtist);
|
||||
double albumScore = GetStringSimilarity(songInfo.Album, compareAlbum);
|
||||
double durationScore = GetDurationSimilarity(songInfo.DurationMs, compareDurationMs);
|
||||
double durationScore = GetDurationSimilarity(songInfo.Duration, compareDuration);
|
||||
|
||||
totalScore = (titleScore * WeightTitle) +
|
||||
(artistScore * WeightArtist) +
|
||||
@@ -94,19 +94,18 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return _algo.Similarity(s1, s2);
|
||||
}
|
||||
|
||||
private static double GetDurationSimilarity(double localMs, double? remoteSeconds)
|
||||
private static double GetDurationSimilarity(double localSeconds, double? remoteSeconds)
|
||||
{
|
||||
if (remoteSeconds == null || remoteSeconds == 0) return 0.0; // 远程没有时长数据,不匹配
|
||||
|
||||
double localSeconds = localMs / 1000.0;
|
||||
double diff = Math.Abs(localSeconds - remoteSeconds.Value);
|
||||
|
||||
// 差距 <= 3秒:100% 相似
|
||||
// 差距 >= 20秒:0% 相似
|
||||
// 差距 <= 1 秒:100 % 相似
|
||||
// 差距 >= 10 秒:0 % 相似
|
||||
// 中间线性插值
|
||||
|
||||
const double PerfectTolerance = 3.0;
|
||||
const double MaxTolerance = 20.0;
|
||||
const double PerfectTolerance = 1.0;
|
||||
const double MaxTolerance = 10.0;
|
||||
|
||||
if (diff <= PerfectTolerance) return 1.0;
|
||||
if (diff >= MaxTolerance) return 0.0;
|
||||
|
||||
@@ -42,19 +42,23 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return file;
|
||||
}
|
||||
|
||||
public static async Task<StorageFile?> PickSaveFileAsync<T>(IDictionary<string, IList<string>> fileTypeChoices)
|
||||
public static async Task<StorageFile?> PickSaveFileAsync<T>(IDictionary<string, IList<string>> fileTypeChoices, string? suggestedFileName = null)
|
||||
{
|
||||
var window = WindowHook.GetWindow<T>();
|
||||
|
||||
return await PickSaveFileAsync(window, fileTypeChoices);
|
||||
return await PickSaveFileAsync(window, fileTypeChoices, suggestedFileName);
|
||||
}
|
||||
|
||||
public static async Task<StorageFile?> PickSaveFileAsync<T>(T? window, IDictionary<string, IList<string>> fileTypeChoices)
|
||||
public static async Task<StorageFile?> PickSaveFileAsync<T>(T? window, IDictionary<string, IList<string>> fileTypeChoices, string? suggestedFileName = null)
|
||||
{
|
||||
if (window == null) return null;
|
||||
|
||||
var picker = new Windows.Storage.Pickers.FileSavePicker();
|
||||
picker.FileTypeChoices.AddRange(fileTypeChoices);
|
||||
if (suggestedFileName != null)
|
||||
{
|
||||
picker.SuggestedFileName = suggestedFileName;
|
||||
}
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(window);
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
@@ -1,163 +1,232 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static BetterLyrics.WinUI3.Helper.EasingHelper;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class ValueTransition<T>
|
||||
where T : struct
|
||||
public class ValueTransition<T> where T : struct
|
||||
{
|
||||
// 状态变量
|
||||
private T _currentValue;
|
||||
private double _durationSeconds;
|
||||
private double _delaySeconds;
|
||||
private double _delayRemaining;
|
||||
private EasingType? _easingType;
|
||||
private Func<T, T, double, T> _interpolator;
|
||||
private bool _isTransitioning;
|
||||
private double _progress;
|
||||
private T _startValue;
|
||||
private T _targetValue;
|
||||
|
||||
public double DurationSeconds => _durationSeconds;
|
||||
public double DelaySeconds => _delaySeconds;
|
||||
// 核心队列
|
||||
private readonly Queue<Keyframe<T>> _keyframeQueue = new Queue<Keyframe<T>>();
|
||||
|
||||
public bool IsTransitioning => _isTransitioning;
|
||||
// 时间控制
|
||||
private double _stepDuration; // 当前这一段的时长 (动态变化)
|
||||
private double _totalDurationForAutoSplit; // 自动均分模式的总时长
|
||||
private double _configuredDelaySeconds; // 配置的延迟时长
|
||||
|
||||
// 动画状态
|
||||
private Func<T, T, double, T> _interpolator;
|
||||
private bool _isTransitioning;
|
||||
private double _progress; // 当前段的进度 (0.0 ~ 1.0)
|
||||
|
||||
// 公开属性
|
||||
public T Value => _currentValue;
|
||||
public T StartValue => _startValue;
|
||||
public T TargetValue => _targetValue;
|
||||
public EasingType? EasingType => _easingType;
|
||||
public double Progress => _progress;
|
||||
public bool IsTransitioning => _isTransitioning;
|
||||
public T TargetValue => _targetValue; // 获取当前段的目标值
|
||||
public double DurationSeconds => _totalDurationForAutoSplit;
|
||||
|
||||
public ValueTransition(T initialValue, double durationSeconds, Func<T, T, double, T>? interpolator = null, EasingType? easingType = null, double delaySeconds = 0)
|
||||
public Func<T, T, double, T> Interpolator => _interpolator;
|
||||
|
||||
public ValueTransition(T initialValue, Func<T, T, double, T>? interpolator, double defaultTotalDuration = 0.3)
|
||||
{
|
||||
_currentValue = initialValue;
|
||||
_startValue = initialValue;
|
||||
_targetValue = initialValue;
|
||||
_durationSeconds = durationSeconds;
|
||||
_delaySeconds = delaySeconds;
|
||||
_delayRemaining = 0;
|
||||
_progress = 1f;
|
||||
_isTransitioning = false;
|
||||
_totalDurationForAutoSplit = defaultTotalDuration;
|
||||
|
||||
if (interpolator != null)
|
||||
{
|
||||
_interpolator = interpolator;
|
||||
_easingType = null;
|
||||
}
|
||||
else if (easingType.HasValue)
|
||||
{
|
||||
_easingType = easingType;
|
||||
_interpolator = GetInterpolatorByEasingType(_easingType.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_easingType = Enums.EasingType.EaseInOutQuad;
|
||||
_interpolator = GetInterpolatorByEasingType(_easingType.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#region Configuration
|
||||
|
||||
public void SetDuration(double seconds)
|
||||
{
|
||||
if (seconds < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(seconds), "Duration must be positive.");
|
||||
_durationSeconds = seconds;
|
||||
if (seconds < 0) throw new ArgumentOutOfRangeException(nameof(seconds));
|
||||
_totalDurationForAutoSplit = seconds;
|
||||
}
|
||||
|
||||
public void SetDurationMs(double millionSeconds)
|
||||
{
|
||||
SetDuration(millionSeconds / 1000.0);
|
||||
}
|
||||
|
||||
public void SetDuration(TimeSpan timeSpan)
|
||||
{
|
||||
SetDuration(timeSpan.TotalSeconds);
|
||||
}
|
||||
public void SetDurationMs(double millionSeconds) => SetDuration(millionSeconds / 1000.0);
|
||||
|
||||
/// <summary>
|
||||
/// 设置启动延迟。
|
||||
/// 原理:在动画队列最前方插入一个“数值不变”的关键帧。
|
||||
/// </summary>
|
||||
public void SetDelay(double seconds)
|
||||
{
|
||||
_delaySeconds = seconds;
|
||||
_configuredDelaySeconds = seconds;
|
||||
}
|
||||
|
||||
private void JumpTo(T value)
|
||||
public void SetInterpolator(Func<T, T, double, T> interpolator)
|
||||
{
|
||||
_interpolator = interpolator;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Control Methods
|
||||
|
||||
/// <summary>
|
||||
/// 立即跳转到指定值(停止动画)
|
||||
/// </summary>
|
||||
public void JumpTo(T value)
|
||||
{
|
||||
_keyframeQueue.Clear();
|
||||
_currentValue = value;
|
||||
_startValue = value;
|
||||
_targetValue = value;
|
||||
_progress = 1f;
|
||||
_delayRemaining = 0;
|
||||
_isTransitioning = false;
|
||||
_progress = 0;
|
||||
}
|
||||
|
||||
public void Reset(T value)
|
||||
/// <summary>
|
||||
/// 模式 A: 精确控制模式
|
||||
/// 显式指定每一段的目标值和时长。
|
||||
/// </summary>
|
||||
public void Start(params Keyframe<T>[] keyframes)
|
||||
{
|
||||
_currentValue = value;
|
||||
_startValue = value;
|
||||
_targetValue = value;
|
||||
_progress = 0f;
|
||||
_delayRemaining = 0;
|
||||
_isTransitioning = false;
|
||||
}
|
||||
if (keyframes == null || keyframes.Length == 0) return;
|
||||
|
||||
public void StartTransition(T targetValue, bool jumpTo = false)
|
||||
{
|
||||
if (jumpTo)
|
||||
PrepareStart();
|
||||
|
||||
// 1. 处理延迟 (插入静止帧)
|
||||
if (_configuredDelaySeconds > 0)
|
||||
{
|
||||
JumpTo(targetValue);
|
||||
return;
|
||||
_keyframeQueue.Enqueue(new Keyframe<T>(_currentValue, _configuredDelaySeconds));
|
||||
}
|
||||
|
||||
if (!targetValue.Equals(_currentValue))
|
||||
// 2. 入队用户帧
|
||||
foreach (var kf in keyframes)
|
||||
{
|
||||
_startValue = _currentValue;
|
||||
_targetValue = targetValue;
|
||||
_progress = 0f;
|
||||
_delayRemaining = _delaySeconds;
|
||||
_isTransitioning = true;
|
||||
_keyframeQueue.Enqueue(kf);
|
||||
}
|
||||
|
||||
MoveToNextSegment(firstStart: true);
|
||||
}
|
||||
|
||||
public static bool Equals(double x, double y, double tolerance)
|
||||
/// <summary>
|
||||
/// 模式 B: 自动均分模式 (兼容旧写法)
|
||||
/// 指定一串目标值,系统根据 SetDuration 的总时长平均分配。
|
||||
/// </summary>
|
||||
public void Start(params T[] values)
|
||||
{
|
||||
var diff = Math.Abs(x - y);
|
||||
return diff <= tolerance || diff <= Math.Max(Math.Abs(x), Math.Abs(y)) * tolerance;
|
||||
if (values == null || values.Length == 0) return;
|
||||
|
||||
// 如果目标就是当前值且只有1帧,直接跳过以省性能
|
||||
if (values.Length == 1 && values[0].Equals(_currentValue) && _configuredDelaySeconds <= 0) return;
|
||||
|
||||
PrepareStart();
|
||||
|
||||
// 1. 处理延迟
|
||||
if (_configuredDelaySeconds > 0)
|
||||
{
|
||||
_keyframeQueue.Enqueue(new Keyframe<T>(_currentValue, _configuredDelaySeconds));
|
||||
}
|
||||
|
||||
// 2. 计算均分时长
|
||||
double autoStepDuration = _totalDurationForAutoSplit / values.Length;
|
||||
|
||||
// 3. 入队生成帧
|
||||
foreach (var val in values)
|
||||
{
|
||||
_keyframeQueue.Enqueue(new Keyframe<T>(val, autoStepDuration));
|
||||
}
|
||||
|
||||
MoveToNextSegment(firstStart: true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Core Logic
|
||||
|
||||
private void PrepareStart()
|
||||
{
|
||||
_keyframeQueue.Clear();
|
||||
_isTransitioning = true;
|
||||
}
|
||||
|
||||
private void MoveToNextSegment(bool firstStart = false)
|
||||
{
|
||||
if (_keyframeQueue.Count > 0)
|
||||
{
|
||||
var kf = _keyframeQueue.Dequeue();
|
||||
|
||||
// 起点逻辑:如果是刚开始,起点是当前值;如果是中间切换,起点是上一段的终点
|
||||
_startValue = firstStart ? _currentValue : _targetValue;
|
||||
_targetValue = kf.Value;
|
||||
_stepDuration = kf.Duration;
|
||||
|
||||
if (firstStart) _progress = 0f;
|
||||
// 注意:非 firstStart 时不重置 _progress,保留溢出值以平滑过渡
|
||||
}
|
||||
else
|
||||
{
|
||||
// 队列耗尽,动画结束
|
||||
_currentValue = _targetValue;
|
||||
_isTransitioning = false;
|
||||
_progress = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(TimeSpan elapsedTime)
|
||||
{
|
||||
if (!_isTransitioning) return;
|
||||
|
||||
if (_delayRemaining > 0)
|
||||
{
|
||||
double consume = Math.Min(_delayRemaining, elapsedTime.TotalSeconds);
|
||||
_delayRemaining -= consume;
|
||||
if (_delayRemaining > 0)
|
||||
return;
|
||||
elapsedTime = TimeSpan.FromSeconds(elapsedTime.TotalSeconds - consume);
|
||||
}
|
||||
double timeStep = elapsedTime.TotalSeconds;
|
||||
|
||||
if (_durationSeconds <= 0)
|
||||
// 使用 while 处理单帧时间过长跨越多段的情况
|
||||
while (timeStep > 0 && _isTransitioning)
|
||||
{
|
||||
_progress = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_progress += elapsedTime.TotalSeconds / _durationSeconds;
|
||||
}
|
||||
// 计算当前帧的步进比例
|
||||
// 极小值保护,防止除以0
|
||||
double progressDelta = (_stepDuration > 0.000001) ? (timeStep / _stepDuration) : 1.0;
|
||||
|
||||
if (_progress >= 1f)
|
||||
{
|
||||
_progress = 1f;
|
||||
_currentValue = _targetValue;
|
||||
_isTransitioning = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentValue = _interpolator(_startValue, _targetValue, _progress);
|
||||
if (_progress + progressDelta >= 1.0)
|
||||
{
|
||||
// === 当前段结束 ===
|
||||
|
||||
// 1. 计算这一段实际消耗的时间
|
||||
double timeConsumed = (1.0 - _progress) * _stepDuration;
|
||||
|
||||
// 2. 剩余时间留给下一段
|
||||
timeStep -= timeConsumed;
|
||||
|
||||
// 3. 修正当前值到目标值
|
||||
_progress = 1.0;
|
||||
_currentValue = _targetValue;
|
||||
|
||||
// 4. 切换到下一段
|
||||
MoveToNextSegment();
|
||||
|
||||
// 5. 如果还有下一段,进度归零
|
||||
if (_isTransitioning) _progress = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// === 当前段进行中 ===
|
||||
_progress += progressDelta;
|
||||
timeStep = 0; // 时间耗尽
|
||||
|
||||
// 插值计算
|
||||
_currentValue = _interpolator(_startValue, _targetValue, _progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Func<T, T, double, T> GetInterpolatorByEasingType(EasingType? type)
|
||||
#endregion
|
||||
|
||||
#region Interpolators
|
||||
|
||||
public static Func<T, T, double, T> GetInterpolatorByEasingType(EasingType? type, EaseMode easingMode)
|
||||
{
|
||||
if (typeof(T) == typeof(double))
|
||||
{
|
||||
@@ -165,59 +234,32 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
double s = (double)(object)start;
|
||||
double e = (double)(object)end;
|
||||
double t = progress;
|
||||
switch (type)
|
||||
|
||||
Func<double, double> easeInFunc = type switch
|
||||
{
|
||||
case Enums.EasingType.EaseInOutSine:
|
||||
t = EasingHelper.EaseInOutSine(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutQuad:
|
||||
t = EasingHelper.EaseInOutQuad(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutCubic:
|
||||
t = EasingHelper.EaseInOutCubic(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutQuart:
|
||||
t = EasingHelper.EaseInOutQuart(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutQuint:
|
||||
t = EasingHelper.EaseInOutQuint(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutExpo:
|
||||
t = EasingHelper.EaseInOutExpo(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutCirc:
|
||||
t = EasingHelper.EaseInOutCirc(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutBack:
|
||||
t = EasingHelper.EaseInOutBack(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutElastic:
|
||||
t = EasingHelper.EaseInOutElastic(t);
|
||||
break;
|
||||
case Enums.EasingType.EaseInOutBounce:
|
||||
t = EasingHelper.EaseInOutBounce(t);
|
||||
break;
|
||||
case Enums.EasingType.SmoothStep:
|
||||
t = EasingHelper.SmoothStep(t);
|
||||
break;
|
||||
case Enums.EasingType.Linear:
|
||||
t = EasingHelper.Linear(t);
|
||||
break;
|
||||
default:
|
||||
t = EasingHelper.EaseInOutQuad(t);
|
||||
break;
|
||||
}
|
||||
Enums.EasingType.Sine => EaseInSine,
|
||||
Enums.EasingType.Quad => EaseInQuad,
|
||||
Enums.EasingType.Cubic => EaseInCubic,
|
||||
Enums.EasingType.Quart => EaseInQuart,
|
||||
Enums.EasingType.Quint => EaseInQuint,
|
||||
Enums.EasingType.Expo => EaseInExpo,
|
||||
Enums.EasingType.Circle => EaseInCircle,
|
||||
Enums.EasingType.Back => EaseInBack,
|
||||
Enums.EasingType.Elastic => EaseInElastic,
|
||||
Enums.EasingType.Bounce => EaseInBounce,
|
||||
Enums.EasingType.SmoothStep => SmoothStep,
|
||||
Enums.EasingType.Linear => Linear,
|
||||
_ => EaseInQuad,
|
||||
};
|
||||
double t = Ease(progress, easingMode, easeInFunc);
|
||||
|
||||
return (T)(object)(s + (e - s) * t);
|
||||
};
|
||||
}
|
||||
throw new NotSupportedException($"Easing type {type} is not supported for type {typeof(T)}.");
|
||||
|
||||
throw new NotSupportedException($"Type {typeof(T)} is not supported.");
|
||||
}
|
||||
|
||||
public void SetEasingType(EasingType? easingType)
|
||||
{
|
||||
_easingType = easingType;
|
||||
_interpolator = GetInterpolatorByEasingType(easingType);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -36,38 +36,79 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
double currentPositionMs
|
||||
)
|
||||
{
|
||||
if (lines == null) return;
|
||||
if (lines == null || lines.Count == 0) return;
|
||||
|
||||
var currentPlayingLine = lines.ElementAtOrDefault(primaryPlayingLineIndex);
|
||||
if (currentPlayingLine == null) return;
|
||||
if (primaryPlayingLineIndex < 0 || primaryPlayingLineIndex >= lines.Count) return;
|
||||
var primaryPlayingLine = lines[primaryPlayingLineIndex];
|
||||
|
||||
var phoneticOpacity = lyricsStyle.PhoneticLyricsOpacity / 100.0;
|
||||
var originalOpacity = lyricsStyle.OriginalLyricsOpacity / 100.0;
|
||||
var translatedOpacity = lyricsStyle.TranslatedLyricsOpacity / 100.0;
|
||||
|
||||
for (int i = startIndex; i <= endIndex + 1; i++)
|
||||
double topHeightFactor = canvasHeight * playingLineTopOffsetFactor;
|
||||
double bottomHeightFactor = canvasHeight * (1 - playingLineTopOffsetFactor);
|
||||
|
||||
double scrollTopDurationSec = lyricsEffect.LyricsScrollTopDuration / 1000.0;
|
||||
double scrollTopDelaySec = lyricsEffect.LyricsScrollTopDelay / 1000.0;
|
||||
double scrollBottomDurationSec = lyricsEffect.LyricsScrollBottomDuration / 1000.0;
|
||||
double scrollBottomDelaySec = lyricsEffect.LyricsScrollBottomDelay / 1000.0;
|
||||
double canvasTransDuration = canvasYScrollTransition.DurationSeconds;
|
||||
|
||||
bool isBlurEnabled = lyricsEffect.IsLyricsBlurEffectEnabled;
|
||||
bool isOutOfSightEnabled = lyricsEffect.IsLyricsOutOfSightEffectEnabled;
|
||||
bool isFanEnabled = lyricsEffect.IsFanLyricsEnabled;
|
||||
double fanAngleRad = Math.PI * (lyricsEffect.FanLyricsAngle / 180.0);
|
||||
bool isGlowEnabled = lyricsEffect.IsLyricsGlowEffectEnabled;
|
||||
bool isFloatEnabled = lyricsEffect.IsLyricsFloatAnimationEnabled;
|
||||
bool isScaleEnabled = lyricsEffect.IsLyricsScaleEffectEnabled;
|
||||
|
||||
int safeStart = Math.Max(0, startIndex);
|
||||
int safeEnd = Math.Min(lines.Count - 1, endIndex + 1);
|
||||
|
||||
for (int i = safeStart; i <= safeEnd; i++)
|
||||
{
|
||||
var line = lines.ElementAtOrDefault(i);
|
||||
if (line == null) continue;
|
||||
var line = lines[i];
|
||||
var lineHeight = line.PrimaryLineHeight;
|
||||
if (lineHeight == null || lineHeight <= 0) continue;
|
||||
|
||||
bool isWordAnimationEnabled = lyricsEffect.WordByWordEffectMode switch
|
||||
{
|
||||
Enums.WordByWordEffectMode.Auto => line.IsPrimaryHasRealSyllableInfo,
|
||||
Enums.WordByWordEffectMode.Always => true,
|
||||
Enums.WordByWordEffectMode.Never => false,
|
||||
_ => line.IsPrimaryHasRealSyllableInfo
|
||||
};
|
||||
|
||||
double targetCharFloat = lyricsEffect.IsLyricsFloatAnimationAmountAutoAdjust
|
||||
? lineHeight.Value * 0.1
|
||||
: lyricsEffect.LyricsFloatAnimationAmount;
|
||||
double targetCharGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust
|
||||
? lineHeight.Value * 0.2
|
||||
: lyricsEffect.LyricsGlowEffectAmount;
|
||||
double targetCharScale = lyricsEffect.IsLyricsScaleEffectAmountAutoAdjust
|
||||
? 1.15
|
||||
: lyricsEffect.LyricsScaleEffectAmount / 100.0;
|
||||
|
||||
var maxAnimationDurationMs = Math.Max(line.EndMs ?? 0 - currentPositionMs, 0);
|
||||
|
||||
bool isSecondaryLinePlaying = line.GetIsPlaying(currentPositionMs);
|
||||
bool isSecondaryLinePlayingChanged = line.IsPlayingLastFrame != isSecondaryLinePlaying;
|
||||
line.IsPlayingLastFrame = isSecondaryLinePlaying;
|
||||
|
||||
// 行动画
|
||||
if (isLayoutChanged || isPrimaryPlayingLineChanged || isMouseScrollingChanged || isSecondaryLinePlayingChanged)
|
||||
if (isLayoutChanged || isPrimaryPlayingLineChanged || isMouseScrollingChanged)
|
||||
{
|
||||
int lineCountDelta = i - primaryPlayingLineIndex;
|
||||
double distanceFromPlayingLine = Math.Abs(line.PrimaryPosition.Y - currentPlayingLine.PrimaryPosition.Y);
|
||||
double distanceFromPlayingLine = Math.Abs(line.PrimaryPosition.Y - primaryPlayingLine.PrimaryPosition.Y);
|
||||
|
||||
double distanceFactor;
|
||||
if (lineCountDelta < 0)
|
||||
{
|
||||
distanceFactor = Math.Clamp(distanceFromPlayingLine / (canvasHeight * playingLineTopOffsetFactor), 0, 1);
|
||||
distanceFactor = Math.Clamp(distanceFromPlayingLine / topHeightFactor, 0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
distanceFactor = Math.Clamp(distanceFromPlayingLine / (canvasHeight * (1 - playingLineTopOffsetFactor)), 0, 1);
|
||||
distanceFactor = Math.Clamp(distanceFromPlayingLine / bottomHeightFactor, 0, 1);
|
||||
}
|
||||
|
||||
double yScrollDuration;
|
||||
@@ -76,200 +117,179 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
if (lineCountDelta < 0)
|
||||
{
|
||||
yScrollDuration =
|
||||
canvasYScrollTransition.DurationSeconds +
|
||||
distanceFactor * (lyricsEffect.LyricsScrollTopDuration / 1000.0 - canvasYScrollTransition.DurationSeconds);
|
||||
yScrollDelay = distanceFactor * lyricsEffect.LyricsScrollTopDelay / 1000.0;
|
||||
canvasTransDuration +
|
||||
distanceFactor * (scrollTopDurationSec - canvasTransDuration);
|
||||
yScrollDelay = distanceFactor * scrollTopDelaySec;
|
||||
}
|
||||
else if (lineCountDelta == 0)
|
||||
{
|
||||
yScrollDuration = canvasYScrollTransition.DurationSeconds;
|
||||
yScrollDuration = canvasTransDuration;
|
||||
yScrollDelay = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
yScrollDuration =
|
||||
canvasYScrollTransition.DurationSeconds +
|
||||
distanceFactor * (lyricsEffect.LyricsScrollBottomDuration / 1000.0 - canvasYScrollTransition.DurationSeconds);
|
||||
yScrollDelay = distanceFactor * lyricsEffect.LyricsScrollBottomDelay / 1000.0;
|
||||
canvasTransDuration +
|
||||
distanceFactor * (scrollBottomDurationSec - canvasTransDuration);
|
||||
yScrollDelay = distanceFactor * scrollBottomDelaySec;
|
||||
}
|
||||
|
||||
line.BlurAmountTransition.SetDuration(yScrollDuration);
|
||||
line.BlurAmountTransition.SetDelay(yScrollDelay);
|
||||
line.BlurAmountTransition.StartTransition(
|
||||
line.BlurAmountTransition.Start(
|
||||
(isMouseScrolling || isSecondaryLinePlaying) ? 0 :
|
||||
(lyricsEffect.IsLyricsBlurEffectEnabled ? (5 * distanceFactor) : 0));
|
||||
(isBlurEnabled ? (5 * distanceFactor) : 0));
|
||||
|
||||
line.ScaleTransition.SetDuration(yScrollDuration);
|
||||
line.ScaleTransition.SetDelay(yScrollDelay);
|
||||
line.ScaleTransition.StartTransition(
|
||||
line.ScaleTransition.Start(
|
||||
isSecondaryLinePlaying ? _highlightedScale :
|
||||
(lyricsEffect.IsLyricsOutOfSightEffectEnabled ?
|
||||
(isOutOfSightEnabled ?
|
||||
(_highlightedScale - distanceFactor * (_highlightedScale - _defaultScale)) :
|
||||
_highlightedScale));
|
||||
|
||||
line.PhoneticOpacityTransition.SetDuration(yScrollDuration);
|
||||
line.PhoneticOpacityTransition.SetDelay(yScrollDelay);
|
||||
line.PhoneticOpacityTransition.StartTransition(
|
||||
line.PhoneticOpacityTransition.Start(
|
||||
isSecondaryLinePlaying ? phoneticOpacity :
|
||||
CalculateTargetOpacity(phoneticOpacity, phoneticOpacity, distanceFactor, isMouseScrolling, lyricsEffect));
|
||||
|
||||
// 原文不透明度(已播放)
|
||||
line.PlayedOriginalOpacityTransition.SetDuration(yScrollDuration);
|
||||
line.PlayedOriginalOpacityTransition.SetDelay(yScrollDelay);
|
||||
line.PlayedOriginalOpacityTransition.StartTransition(
|
||||
line.PlayedOriginalOpacityTransition.Start(
|
||||
isSecondaryLinePlaying ? 1.0 :
|
||||
CalculateTargetOpacity(originalOpacity, 1.0, distanceFactor, isMouseScrolling, lyricsEffect));
|
||||
// 原文不透明度(未播放)
|
||||
line.UnplayedOriginalOpacityTransition.SetDuration(yScrollDuration);
|
||||
line.UnplayedOriginalOpacityTransition.SetDelay(yScrollDelay);
|
||||
line.UnplayedOriginalOpacityTransition.StartTransition(
|
||||
line.UnplayedOriginalOpacityTransition.Start(
|
||||
isSecondaryLinePlaying ? originalOpacity :
|
||||
CalculateTargetOpacity(originalOpacity, originalOpacity, distanceFactor, isMouseScrolling, lyricsEffect));
|
||||
|
||||
line.TranslatedOpacityTransition.SetDuration(yScrollDuration);
|
||||
line.TranslatedOpacityTransition.SetDelay(yScrollDelay);
|
||||
line.TranslatedOpacityTransition.StartTransition(
|
||||
line.TranslatedOpacityTransition.Start(
|
||||
isSecondaryLinePlaying ? translatedOpacity :
|
||||
CalculateTargetOpacity(translatedOpacity, translatedOpacity, distanceFactor, isMouseScrolling, lyricsEffect));
|
||||
|
||||
line.ColorTransition.SetDuration(yScrollDuration);
|
||||
line.ColorTransition.SetDelay(yScrollDelay);
|
||||
line.ColorTransition.StartTransition(isSecondaryLinePlaying ? fgColor : bgColor);
|
||||
line.ColorTransition.Start(isSecondaryLinePlaying ? fgColor : bgColor);
|
||||
|
||||
line.AngleTransition.SetEasingType(canvasYScrollTransition.EasingType);
|
||||
line.AngleTransition.SetInterpolator(canvasYScrollTransition.Interpolator);
|
||||
line.AngleTransition.SetDuration(yScrollDuration);
|
||||
line.AngleTransition.SetDelay(yScrollDelay);
|
||||
line.AngleTransition.StartTransition(
|
||||
(lyricsEffect.IsFanLyricsEnabled && !isMouseScrolling) ?
|
||||
Math.PI * (lyricsEffect.FanLyricsAngle / 180.0) * distanceFactor * (i > primaryPlayingLineIndex ? 1 : -1) :
|
||||
line.AngleTransition.Start(
|
||||
(isFanEnabled && !isMouseScrolling) ?
|
||||
fanAngleRad * distanceFactor * (i > primaryPlayingLineIndex ? 1 : -1) :
|
||||
0);
|
||||
|
||||
line.YOffsetTransition.SetEasingType(canvasYScrollTransition.EasingType);
|
||||
line.YOffsetTransition.SetInterpolator(canvasYScrollTransition.Interpolator);
|
||||
line.YOffsetTransition.SetDuration(yScrollDuration);
|
||||
line.YOffsetTransition.SetDelay(yScrollDelay);
|
||||
// 设计之初是当 isLayoutChanged 为真时 jumpTo
|
||||
// 但考虑到动画视觉,强制使用动画
|
||||
line.YOffsetTransition.StartTransition(targetYScrollOffset);
|
||||
line.YOffsetTransition.Start(targetYScrollOffset);
|
||||
}
|
||||
|
||||
var maxAnimationDurationMs = Math.Max(line.EndMs - currentPositionMs, 0);
|
||||
|
||||
// 字符动画
|
||||
foreach (var renderChar in line.PrimaryRenderChars)
|
||||
if (isWordAnimationEnabled)
|
||||
{
|
||||
renderChar.ProgressPlayed = renderChar.GetPlayProgress(currentPositionMs);
|
||||
|
||||
bool isCharPlaying = renderChar.GetIsPlaying(currentPositionMs);
|
||||
bool isCharPlayingChanged = renderChar.IsPlayingLastFrame != isCharPlaying;
|
||||
|
||||
if (isSecondaryLinePlayingChanged || isCharPlayingChanged)
|
||||
if (isSecondaryLinePlayingChanged)
|
||||
{
|
||||
if (lyricsEffect.IsLyricsGlowEffectEnabled)
|
||||
// 辉光动画
|
||||
if (isGlowEnabled && lyricsEffect.LyricsGlowEffectScope == Enums.LyricsEffectScope.LineStartToCurrentChar
|
||||
&& isSecondaryLinePlaying)
|
||||
{
|
||||
double targetGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust ? renderChar.LayoutRect.Height * 0.2 : lyricsEffect.LyricsGlowEffectAmount;
|
||||
switch (lyricsEffect.LyricsGlowEffectScope)
|
||||
foreach (var renderChar in line.PrimaryRenderChars)
|
||||
{
|
||||
case Enums.LyricsEffectScope.LineStartToCurrentChar:
|
||||
if (isSecondaryLinePlayingChanged)
|
||||
{
|
||||
renderChar.GlowTransition.SetDurationMs(Math.Min(Time.AnimationDuration.TotalMilliseconds, maxAnimationDurationMs));
|
||||
renderChar.GlowTransition.StartTransition(isSecondaryLinePlaying ? targetGlow : 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
var stepInOutDuration = Math.Min(Time.AnimationDuration.TotalMilliseconds, maxAnimationDurationMs) / 2.0 / 1000.0;
|
||||
var stepLastingDuration = Math.Max(maxAnimationDurationMs / 1000.0 - stepInOutDuration * 2, 0);
|
||||
renderChar.GlowTransition.Start(
|
||||
new Models.Keyframe<double>(targetCharGlow, stepInOutDuration),
|
||||
new Models.Keyframe<double>(targetCharGlow, stepLastingDuration),
|
||||
new Models.Keyframe<double>(0, stepInOutDuration)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (lyricsEffect.IsLyricsFloatAnimationEnabled)
|
||||
// 浮动动画
|
||||
if (isFloatEnabled)
|
||||
{
|
||||
double targetFloat =
|
||||
lyricsEffect.IsLyricsFloatAnimationAmountAutoAdjust ? renderChar.LayoutRect.Height * 0.1 : lyricsEffect.LyricsFloatAnimationAmount;
|
||||
|
||||
if (isSecondaryLinePlayingChanged)
|
||||
foreach (var renderChar in line.PrimaryRenderChars)
|
||||
{
|
||||
renderChar.FloatTransition.StartTransition(isSecondaryLinePlaying ? targetFloat : 0);
|
||||
}
|
||||
if (isCharPlayingChanged)
|
||||
{
|
||||
renderChar.FloatTransition.SetDurationMs(Math.Min(lyricsEffect.LyricsFloatAnimationDuration, maxAnimationDurationMs));
|
||||
renderChar.FloatTransition.StartTransition(0);
|
||||
renderChar.FloatTransition.Start(isSecondaryLinePlaying ? targetCharFloat : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 字符动画
|
||||
foreach (var renderChar in line.PrimaryRenderChars)
|
||||
{
|
||||
renderChar.ProgressPlayed = renderChar.GetPlayProgress(currentPositionMs);
|
||||
|
||||
bool isCharPlaying = renderChar.GetIsPlaying(currentPositionMs);
|
||||
bool isCharPlayingChanged = renderChar.IsPlayingLastFrame != isCharPlaying;
|
||||
|
||||
if (isCharPlayingChanged)
|
||||
{
|
||||
if (isFloatEnabled)
|
||||
{
|
||||
renderChar.FloatTransition.SetDurationMs(Math.Min(lyricsEffect.LyricsFloatAnimationDuration, maxAnimationDurationMs));
|
||||
renderChar.FloatTransition.Start(0);
|
||||
}
|
||||
|
||||
renderChar.IsPlayingLastFrame = isCharPlaying;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 音节动画
|
||||
foreach (var syllable in line.PrimaryRenderSyllables)
|
||||
{
|
||||
bool isSyllablePlaying = syllable.GetIsPlaying(currentPositionMs);
|
||||
bool isSyllablePlayingChanged = syllable.IsPlayingLastFrame != isSyllablePlaying;
|
||||
|
||||
if (isSyllablePlayingChanged)
|
||||
// 音节动画
|
||||
foreach (var syllable in line.PrimaryRenderSyllables)
|
||||
{
|
||||
var syllableHeight = syllable.ChildrenRenderLyricsChars.FirstOrDefault()?.LayoutRect.Height ?? 0;
|
||||
bool isSyllablePlaying = syllable.GetIsPlaying(currentPositionMs);
|
||||
bool isSyllablePlayingChanged = syllable.IsPlayingLastFrame != isSyllablePlaying;
|
||||
|
||||
if (lyricsEffect.IsLyricsScaleEffectEnabled)
|
||||
if (isSyllablePlayingChanged)
|
||||
{
|
||||
double targetScale =
|
||||
lyricsEffect.IsLyricsScaleEffectAmountAutoAdjust ? 1.15 : lyricsEffect.LyricsScaleEffectAmount / 100.0;
|
||||
|
||||
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
|
||||
if (isScaleEnabled && isSyllablePlaying)
|
||||
{
|
||||
if (syllable.DurationMs >= lyricsEffect.LyricsScaleEffectLongSyllableDuration)
|
||||
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
|
||||
{
|
||||
renderChar.ScaleTransition.SetDurationMs(Math.Min(syllable.DurationMs, maxAnimationDurationMs) / 2.0);
|
||||
renderChar.ScaleTransition.StartTransition(isSyllablePlaying ? targetScale : 1);
|
||||
if (syllable.DurationMs >= lyricsEffect.LyricsScaleEffectLongSyllableDuration)
|
||||
{
|
||||
var stepDuration = Math.Min(syllable.DurationMs, maxAnimationDurationMs) / 2.0 / 1000.0;
|
||||
renderChar.ScaleTransition.Start(
|
||||
new Models.Keyframe<double>(targetCharScale, stepDuration),
|
||||
new Models.Keyframe<double>(1.0, stepDuration)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lyricsEffect.IsLyricsGlowEffectEnabled)
|
||||
{
|
||||
double targetGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust ? syllableHeight * 0.2 : lyricsEffect.LyricsGlowEffectAmount;
|
||||
switch (lyricsEffect.LyricsGlowEffectScope)
|
||||
if (isGlowEnabled && isSyllablePlaying && lyricsEffect.LyricsGlowEffectScope == Enums.LyricsEffectScope.LongDurationSyllable
|
||||
&& syllable.DurationMs >= lyricsEffect.LyricsGlowEffectLongSyllableDuration)
|
||||
{
|
||||
case Enums.LyricsEffectScope.LongDurationSyllable:
|
||||
if (syllable.DurationMs >= lyricsEffect.LyricsGlowEffectLongSyllableDuration)
|
||||
{
|
||||
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
|
||||
{
|
||||
renderChar.GlowTransition.SetDurationMs(Math.Min(syllable.DurationMs, maxAnimationDurationMs) / 2.0);
|
||||
renderChar.GlowTransition.StartTransition(isSyllablePlaying ? targetGlow : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
|
||||
{
|
||||
var stepDuration = Math.Min(syllable.DurationMs, maxAnimationDurationMs) / 2.0 / 1000.0;
|
||||
renderChar.GlowTransition.Start(
|
||||
new Models.Keyframe<double>(targetCharGlow, stepDuration),
|
||||
new Models.Keyframe<double>(0, stepDuration)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syllable.IsPlayingLastFrame = isSyllablePlaying;
|
||||
syllable.IsPlayingLastFrame = isSyllablePlaying;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var renderChar in line.PrimaryRenderChars)
|
||||
{
|
||||
renderChar.Update(elapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新动画
|
||||
foreach (var renderChar in line.PrimaryRenderChars)
|
||||
{
|
||||
renderChar.ScaleTransition.Update(elapsedTime);
|
||||
renderChar.GlowTransition.Update(elapsedTime);
|
||||
renderChar.FloatTransition.Update(elapsedTime);
|
||||
}
|
||||
|
||||
line.AngleTransition.Update(elapsedTime);
|
||||
line.ScaleTransition.Update(elapsedTime);
|
||||
line.BlurAmountTransition.Update(elapsedTime);
|
||||
line.PhoneticOpacityTransition.Update(elapsedTime);
|
||||
line.PlayedOriginalOpacityTransition.Update(elapsedTime);
|
||||
line.UnplayedOriginalOpacityTransition.Update(elapsedTime);
|
||||
line.TranslatedOpacityTransition.Update(elapsedTime);
|
||||
line.YOffsetTransition.Update(elapsedTime);
|
||||
line.ColorTransition.Update(elapsedTime);
|
||||
line.Update(elapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
lanesEndMs.Add(0);
|
||||
}
|
||||
|
||||
lanesEndMs[assignedLane] = end;
|
||||
lanesEndMs[assignedLane] = end ?? 0;
|
||||
line.LaneIndex = assignedLane;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Lyrics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -67,13 +68,13 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
public LinePlaybackState GetLinePlayingProgress(
|
||||
double currentTimeMs,
|
||||
RenderLyricsLine line,
|
||||
bool isForceWordByWord)
|
||||
WordByWordEffectMode wordByWordEffectMode)
|
||||
{
|
||||
var state = new LinePlaybackState { SyllableStartIndex = 0, SyllableLength = 0, SyllableProgress = 0 };
|
||||
|
||||
if (line == null) return state;
|
||||
|
||||
double lineEndMs = line.EndMs;
|
||||
double lineEndMs = line.EndMs ?? 0;
|
||||
|
||||
// 还没到
|
||||
if (currentTimeMs < line.StartMs) return state;
|
||||
@@ -87,23 +88,34 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
return state;
|
||||
}
|
||||
|
||||
// 逐字
|
||||
if (line.PrimaryRenderSyllables != null && line.PrimaryRenderSyllables.Count > 1)
|
||||
switch (wordByWordEffectMode)
|
||||
{
|
||||
return CalculateSyllableProgress(currentTimeMs, line, lineEndMs);
|
||||
}
|
||||
|
||||
// 强制逐字
|
||||
if (isForceWordByWord && line.PrimaryText.Length > 0)
|
||||
{
|
||||
return CalculateSimulatedProgress(currentTimeMs, line, lineEndMs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 普通行
|
||||
state.SyllableStartIndex = line.PrimaryText.Length;
|
||||
state.SyllableProgress = 1f;
|
||||
return state;
|
||||
case WordByWordEffectMode.Auto:
|
||||
if (line.IsPrimaryHasRealSyllableInfo)
|
||||
{
|
||||
return CalculateSyllableProgress(currentTimeMs, line, lineEndMs);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.SyllableStartIndex = line.PrimaryText.Length;
|
||||
state.SyllableProgress = 1f;
|
||||
return state;
|
||||
}
|
||||
case WordByWordEffectMode.Never:
|
||||
state.SyllableStartIndex = line.PrimaryText.Length;
|
||||
state.SyllableProgress = 1f;
|
||||
return state;
|
||||
case WordByWordEffectMode.Always:
|
||||
if (line.IsPrimaryHasRealSyllableInfo)
|
||||
{
|
||||
return CalculateSyllableProgress(currentTimeMs, line, lineEndMs);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CalculateSimulatedProgress(currentTimeMs, line, lineEndMs);
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +129,7 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
var timing = line.PrimaryRenderSyllables[i];
|
||||
var nextTiming = (i + 1 < count) ? line.PrimaryRenderSyllables[i + 1] : null;
|
||||
|
||||
//double timingEndMs = timing.EndMs ?? nextTiming?.StartMs ?? lineEndMs;
|
||||
double timingEndMs = timing.EndMs;
|
||||
double timingEndMs = timing.EndMs ?? 0;
|
||||
|
||||
// 在当前字范围内
|
||||
if (time >= timing.StartMs && time <= timingEndMs)
|
||||
|
||||
18
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Keyframe.cs
Normal file
18
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Keyframe.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public struct Keyframe<T>
|
||||
{
|
||||
public T Value { get; }
|
||||
public double Duration { get; }
|
||||
|
||||
public Keyframe(T value, double durationSeconds)
|
||||
{
|
||||
Value = value;
|
||||
Duration = durationSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
public class BaseLyrics
|
||||
{
|
||||
public int StartMs { get; set; }
|
||||
public int EndMs { get; set; }
|
||||
public int DurationMs => EndMs - StartMs;
|
||||
public int? EndMs { get; set; } = null;
|
||||
public int DurationMs => Math.Max((EndMs ?? 0) - StartMs, 0);
|
||||
|
||||
public string Text { get; set; } = "";
|
||||
public int Length => Text.Length;
|
||||
|
||||
@@ -9,8 +9,6 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class LyricsData
|
||||
{
|
||||
private static readonly ILocalizationService _localizationService = Ioc.Default.GetRequiredService<ILocalizationService>();
|
||||
|
||||
public List<LyricsLine> LyricsLines { get; set; } = [];
|
||||
public string? LanguageCode
|
||||
{
|
||||
@@ -29,15 +27,5 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
LyricsLines = lyricsLines;
|
||||
}
|
||||
|
||||
public static LyricsData GetNotfoundPlaceholder()
|
||||
{
|
||||
return new LyricsData([new LyricsLine
|
||||
{
|
||||
StartMs = 0,
|
||||
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
|
||||
PrimaryText = _localizationService.GetLocalizedString("LyricsNotFound"),
|
||||
}]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
public string SecondaryText { get; set; } = "";
|
||||
public string TertiaryText { get; set; } = "";
|
||||
|
||||
public new string Text => PrimaryText;
|
||||
public new int StartIndex = 0;
|
||||
|
||||
public bool IsPrimaryHasRealSyllableInfo { get; set; } = false;
|
||||
|
||||
public LyricsLine()
|
||||
{
|
||||
for (int charStartIndex = 0; charStartIndex < PrimaryText.Length; charStartIndex++)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using System;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
@@ -19,20 +20,28 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
ScaleTransition = new(
|
||||
initialValue: 1.0,
|
||||
durationSeconds: Time.AnimationDuration.TotalSeconds,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: Time.AnimationDuration.TotalSeconds
|
||||
);
|
||||
GlowTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: Time.AnimationDuration.TotalSeconds,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: Time.AnimationDuration.TotalSeconds
|
||||
);
|
||||
FloatTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: Time.LongAnimationDuration.TotalSeconds,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: Time.LongAnimationDuration.TotalSeconds
|
||||
);
|
||||
LayoutRect = layoutRect;
|
||||
}
|
||||
|
||||
public void Update(TimeSpan elapsedTime)
|
||||
{
|
||||
ScaleTransition.Update(elapsedTime);
|
||||
GlowTransition.Update(elapsedTime);
|
||||
FloatTransition.Update(elapsedTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using Microsoft.Graphics.Canvas.Geometry;
|
||||
using Microsoft.Graphics.Canvas.Text;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
using Microsoft.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
@@ -73,51 +74,55 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
/// </summary>
|
||||
public int LaneIndex { get; set; } = 0;
|
||||
|
||||
public double? PrimaryLineHeight => PrimaryRenderChars.FirstOrDefault()?.LayoutRect.Height;
|
||||
|
||||
public bool IsPrimaryHasRealSyllableInfo { get; set; }
|
||||
|
||||
public RenderLyricsLine(LyricsLine lyricsLine) : base(lyricsLine)
|
||||
{
|
||||
AngleTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
BlurAmountTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
PhoneticOpacityTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
PlayedOriginalOpacityTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
UnplayedOriginalOpacityTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
TranslatedOpacityTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
ScaleTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
YOffsetTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
ColorTransition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
defaultTotalDuration: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
|
||||
@@ -127,6 +132,7 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
PrimaryText = lyricsLine.PrimaryText;
|
||||
SecondaryText = lyricsLine.SecondaryText;
|
||||
PrimaryRenderSyllables = lyricsLine.PrimarySyllables.Select(x => new RenderLyricsSyllable(x)).ToList();
|
||||
IsPrimaryHasRealSyllableInfo = lyricsLine.IsPrimaryHasRealSyllableInfo;
|
||||
}
|
||||
|
||||
public void UpdateCenterPosition(double maxWidth, TextAlignmentType type)
|
||||
@@ -282,5 +288,18 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(TimeSpan elapsedTime)
|
||||
{
|
||||
AngleTransition.Update(elapsedTime);
|
||||
ScaleTransition.Update(elapsedTime);
|
||||
BlurAmountTransition.Update(elapsedTime);
|
||||
PhoneticOpacityTransition.Update(elapsedTime);
|
||||
PlayedOriginalOpacityTransition.Update(elapsedTime);
|
||||
UnplayedOriginalOpacityTransition.Update(elapsedTime);
|
||||
TranslatedOpacityTransition.Update(elapsedTime);
|
||||
YOffsetTransition.Update(elapsedTime);
|
||||
ColorTransition.Update(elapsedTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public class PluginDisplayModel
|
||||
{
|
||||
public IPlugin Plugin { get; }
|
||||
|
||||
public string Name => Plugin.Name;
|
||||
public string Description => Plugin.Description;
|
||||
public string Id => Plugin.Id;
|
||||
public string Author => Plugin.Author;
|
||||
public string Version => "v1.0.0"; // 如果您的接口有 Version 字段就读接口的
|
||||
|
||||
public string Glyph => !string.IsNullOrEmpty(Name) ? Name.Substring(0, 1) : "?";
|
||||
|
||||
public PluginDisplayModel(IPlugin plugin)
|
||||
{
|
||||
Plugin = plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LanguageCode { get; set; } = "";
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LXMusicServer { get; set; } = string.Empty;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string AmllTtmlDbBaseUrl { get; set; } = Constants.AmllTTmlDB.BaseUrl;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsForceWordByWordEffect { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> ShowOrHideLyricsWindowShortcut { get; set; } = new List<string> { "Ctrl", "Alt", "H" };
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ExitOnLyricsWindowClosed { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ListenOnNewPlaybackSource { get; set; } = true;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using static BetterLyrics.WinUI3.Helper.EasingHelper;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class LyricsEffectSettings : ObservableRecipient, ICloneable
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial WordByWordEffectMode WordByWordEffectMode { get; set; } = WordByWordEffectMode.Auto;
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsBlurEffectEnabled { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsFadeOutEffectEnabled { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsOutOfSightEffectEnabled { get; set; } = true;
|
||||
@@ -27,6 +30,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFloatAnimationDuration { get; set; } = 450; // 450ms
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial EasingType LyricsScrollEasingType { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial EaseMode LyricsScrollEasingMode { get; set; } = EaseMode.Out;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollDuration { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollTopDuration { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollBottomDuration { get; set; }
|
||||
@@ -54,6 +58,8 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
return new LyricsEffectSettings(this.LyricsScrollTopDuration, this.LyricsScrollDuration, this.LyricsScrollBottomDuration, this.LyricsScrollEasingType)
|
||||
{
|
||||
WordByWordEffectMode = this.WordByWordEffectMode,
|
||||
|
||||
IsLyricsBlurEffectEnabled = this.IsLyricsBlurEffectEnabled,
|
||||
IsLyricsFadeOutEffectEnabled = this.IsLyricsFadeOutEffectEnabled,
|
||||
IsLyricsOutOfSightEffectEnabled = this.IsLyricsOutOfSightEffectEnabled,
|
||||
@@ -75,6 +81,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
LyricsFloatAnimationDuration = this.LyricsFloatAnimationDuration,
|
||||
|
||||
LyricsScrollEasingType = this.LyricsScrollEasingType,
|
||||
LyricsScrollEasingMode = this.LyricsScrollEasingMode,
|
||||
LyricsScrollDuration = this.LyricsScrollDuration,
|
||||
LyricsScrollTopDuration = this.LyricsScrollTopDuration,
|
||||
LyricsScrollBottomDuration = this.LyricsScrollBottomDuration,
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
[ObservableProperty] public partial Rect DemoMonitorBounds { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial DockPlacement DockPlacement { get; set; } = DockPlacement.Top;
|
||||
[ObservableProperty] public partial LyricsStyleSettings LyricsStyleSettings { get; set; } = new();
|
||||
[ObservableProperty] public partial LyricsEffectSettings LyricsEffectSettings { get; set; } = new(500, 500, 500, EasingType.EaseInOutQuad);
|
||||
[ObservableProperty] public partial LyricsEffectSettings LyricsEffectSettings { get; set; } = new(500, 500, 500, EasingType.Quad);
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsBackgroundSettings LyricsBackgroundSettings { get; set; } = new();
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial AlbumArtAreaStyleSettings AlbumArtLayoutSettings { get; set; } = new();
|
||||
[ObservableProperty] public partial AlbumArtAreaEffectSettings AlbumArtAreaEffectSettings { get; set; } = new();
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
[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 string CutletDockerServer { get; set; } = string.Empty;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsTraditionalChineseEnabled { get; set; } = false;
|
||||
|
||||
public TranslationSettings() { }
|
||||
|
||||
@@ -40,26 +40,14 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
startIndex += text.Length;
|
||||
}
|
||||
|
||||
int lineEndMs = 0;
|
||||
|
||||
if (syllables.Count > 0)
|
||||
{
|
||||
var lastSyllable = syllables[syllables.Count - 1];
|
||||
if (string.IsNullOrWhiteSpace(lastSyllable.Text))
|
||||
{
|
||||
lineEndMs = lastSyllable.StartMs;
|
||||
syllables.RemoveAt(syllables.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (syllables.Count > 0)
|
||||
if (syllables.Count > 1)
|
||||
{
|
||||
lrcLines.Add(new LyricsLine
|
||||
{
|
||||
StartMs = syllables[0].StartMs,
|
||||
EndMs = lineEndMs,
|
||||
PrimaryText = string.Concat(syllables.Select(s => s.Text)),
|
||||
PrimarySyllables = syllables
|
||||
PrimarySyllables = syllables,
|
||||
IsPrimaryHasRealSyllableInfo = true
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -81,7 +69,13 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
content = bracketRegex!.Replace(line, "").Trim();
|
||||
if (content == "//") content = "";
|
||||
|
||||
lrcLines.Add(new LyricsLine { StartMs = lineStartMs, PrimaryText = content });
|
||||
var lyricsLine = new LyricsLine
|
||||
{
|
||||
StartMs = lineStartMs,
|
||||
PrimaryText = content,
|
||||
IsPrimaryHasRealSyllableInfo = false
|
||||
};
|
||||
lrcLines.Add(lyricsLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,5 +119,6 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
var lineWrite = new LyricsLine
|
||||
{
|
||||
StartMs = lineRead.StartTime ?? 0,
|
||||
EndMs = lineRead.EndTime ?? (nextLineRead?.StartTime ?? 0),
|
||||
PrimaryText = lineRead.Text,
|
||||
PrimarySyllables = [],
|
||||
IsPrimaryHasRealSyllableInfo = true,
|
||||
};
|
||||
|
||||
var syllables = (lineRead as Lyricify.Lyrics.Models.SyllableLineInfo)?.Syllables;
|
||||
|
||||
@@ -127,7 +127,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
StartMs = containerStartMs,
|
||||
EndMs = containerEndMs,
|
||||
PrimaryText = fullOriginalText,
|
||||
PrimarySyllables = syllables
|
||||
PrimarySyllables = syllables,
|
||||
IsPrimaryHasRealSyllableInfo = true,
|
||||
});
|
||||
|
||||
var transSpan = container.Elements()
|
||||
@@ -151,7 +152,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
StartMs = startMs,
|
||||
EndMs = endMs,
|
||||
PrimaryText = text
|
||||
PrimaryText = text,
|
||||
IsPrimaryHasRealSyllableInfo = false,
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -160,7 +162,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
StartMs = startMs,
|
||||
EndMs = endMs,
|
||||
PrimaryText = ""
|
||||
PrimaryText = "",
|
||||
IsPrimaryHasRealSyllableInfo = false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,9 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
LoadTransliteration(lyricsSearchResult);
|
||||
GenerateTransliterationLyricsData();
|
||||
|
||||
EnsureEndMs(lyricsSearchResult?.Duration);
|
||||
EnsureSyllables();
|
||||
|
||||
return _lyricsDataArr;
|
||||
}
|
||||
|
||||
@@ -126,7 +129,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
romaji = await transliterationService.TransliterateText(main.WrappedOriginalText, PhoneticHelper.RomanCode, token);
|
||||
_lyricsDataArr.FirstOrDefault()?.SetTransliteration(romaji);
|
||||
transliterationSearchProvider = TransliterationSearchProvider.CutletDocker;
|
||||
transliterationSearchProvider = TransliterationSearchProvider.Plugin;
|
||||
}
|
||||
catch (TaskCanceledException) { }
|
||||
catch (Exception)
|
||||
@@ -271,5 +274,84 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureEndMs(double? duration)
|
||||
{
|
||||
foreach (var lyricsData in _lyricsDataArr)
|
||||
{
|
||||
var lines = lyricsData.LyricsLines;
|
||||
// 计算结束时间
|
||||
for (int i = 0; i < lines.Count; i++)
|
||||
{
|
||||
// 计算行结束时间
|
||||
if (lines[i].EndMs == null)
|
||||
{
|
||||
if (i + 1 < lines.Count)
|
||||
{
|
||||
lines[i].EndMs = lines[i + 1].StartMs;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines[i].EndMs = (int)(duration ?? 0) * 1000;
|
||||
}
|
||||
}
|
||||
// 计算音节结束时间
|
||||
for (int j = 0; j < lines[i].PrimarySyllables.Count; j++)
|
||||
{
|
||||
var syllable = lines[i].PrimarySyllables[j];
|
||||
if (syllable.EndMs == null)
|
||||
{
|
||||
if (j < lines[i].PrimarySyllables.Count - 1)
|
||||
{
|
||||
syllable.EndMs = lines[i].PrimarySyllables[j + 1].StartMs;
|
||||
}
|
||||
else
|
||||
{
|
||||
syllable.EndMs = lines[i].EndMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoke this after <see cref="EnsureEndMs"/>
|
||||
/// </summary>
|
||||
private void EnsureSyllables()
|
||||
{
|
||||
foreach (var lyricsData in _lyricsDataArr)
|
||||
{
|
||||
if (lyricsData == null) continue;
|
||||
|
||||
var lines = lyricsData.LyricsLines;
|
||||
if (lines == null) continue;
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line == null) continue;
|
||||
if (line.IsPrimaryHasRealSyllableInfo) continue;
|
||||
if (line.PrimarySyllables.Count > 0) continue;
|
||||
|
||||
var content = line.PrimaryText;
|
||||
var length = content.Length;
|
||||
if (length == 0) continue;
|
||||
|
||||
var avgSyllableDuration = line.DurationMs / length;
|
||||
if (avgSyllableDuration == 0) continue;
|
||||
|
||||
for (int j = 0; j < length; j++)
|
||||
{
|
||||
line.PrimarySyllables.Add(new BaseLyrics
|
||||
{
|
||||
Text = content[j].ToString(),
|
||||
StartIndex = j,
|
||||
StartMs = line.StartMs + avgSyllableDuration * j,
|
||||
EndMs = line.StartMs + avgSyllableDuration * (j + 1),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
<linker>
|
||||
<assembly fullname="Microsoft.Extensions.Logging.Abstractions" preserve="all" />
|
||||
<assembly fullname="System.Collections" preserve="all" />
|
||||
<assembly fullname="System.Collections.Concurrent" preserve="all" />
|
||||
<assembly fullname="System.ComponentModel" preserve="all" />
|
||||
<assembly fullname="System.ComponentModel.Annotations" preserve="all" />
|
||||
<assembly fullname="System.ComponentModel.Primitives" preserve="all" />
|
||||
<assembly fullname="System.Diagnostics.Process" preserve="all" />
|
||||
<assembly fullname="System.Drawing.Primitives" preserve="all" />
|
||||
<assembly fullname="System.IO.MemoryMappedFiles" preserve="all" />
|
||||
<assembly fullname="System.Linq" preserve="all" />
|
||||
<assembly fullname="System.Memory" preserve="all" />
|
||||
<assembly fullname="System.Net.Http" preserve="all" />
|
||||
<assembly fullname="System.Net.Mail" preserve="all" />
|
||||
<assembly fullname="System.Numerics.Tensors" preserve="all" />
|
||||
<assembly fullname="System.Numerics.Vectors" preserve="all" />
|
||||
<assembly fullname="System.Runtime" preserve="all" />
|
||||
<assembly fullname="System.Runtime.InteropServices" preserve="all" />
|
||||
<assembly fullname="System.Runtime.Intrinsics" preserve="all" />
|
||||
<assembly fullname="System.Security.Cryptography" preserve="all" />
|
||||
<assembly fullname="System.Text.Encodings.Web" preserve="all" />
|
||||
<assembly fullname="System.Text.Json" preserve="all" />
|
||||
<assembly fullname="System.Text.RegularExpressions" preserve="all" />
|
||||
<assembly fullname="System.Threading" preserve="all" />
|
||||
<assembly fullname="System.Threading.Tasks.Parallel" preserve="all" />
|
||||
<assembly fullname="BetterLyrics.WinUI3">
|
||||
<type fullname="BetterLyrics.WinUI3.PluginConfigs.BetterLyrics_Plugins_AI_Config" preserve="all" />
|
||||
</assembly>
|
||||
</linker>
|
||||
@@ -0,0 +1,415 @@
|
||||
// Auto-Generated by PluginAnalyzer
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace BetterLyrics.WinUI3.PluginConfigs;
|
||||
internal static class BetterLyrics_Plugins_AI_Config
|
||||
{
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Microsoft.Win32.SafeHandles.SafeMemoryMappedViewHandle))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Action<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Action<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.AppContext))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.AppDomain))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ArgumentException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ArgumentNullException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ArgumentOutOfRangeException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Array))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ArraySegment<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ArrayTypeMismatchException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.AsyncCallback))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Attribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.AttributeTargets))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.AttributeUsageAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Base64FormattingOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Boolean))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffer))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.ArrayPool<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.Binary.BinaryPrimitives))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.IBufferWriter<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.IMemoryOwner<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.IPinnable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.MemoryHandle))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.MemoryManager<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.ReadOnlySequence<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.ReadOnlySequence<>.Enumerator))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.SearchValues))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.SearchValues<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffers.Text.Base64))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Byte))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Char))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.CLSCompliantAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.CodeDom.Compiler.GeneratedCodeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.BitArray))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Concurrent.ConcurrentDictionary<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.Dictionary<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.Dictionary<,>.Enumerator))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.Dictionary<,>.KeyCollection))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.Dictionary<,>.ValueCollection))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.EqualityComparer<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.HashSet<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.HashSet<>.Enumerator))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IAsyncEnumerable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IAsyncEnumerator<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.ICollection<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IComparer<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IDictionary<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IEnumerable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IEnumerator<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IEqualityComparer<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IList<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IReadOnlyCollection<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IReadOnlyDictionary<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IReadOnlyList<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.KeyNotFoundException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.KeyValuePair<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.List<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.List<>.Enumerator))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.Queue<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.ICollection))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.IEnumerable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.IEnumerator))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.IList))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.AllowedValuesAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.Base64StringAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.DataType))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.DataTypeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.DeniedValuesAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.EmailAddressAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.LengthAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.MaxLengthAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.MinLengthAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.RangeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.RegularExpressionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DataAnnotations.UrlAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DescriptionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.DisplayNameAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.EditorBrowsableAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.EditorBrowsableState))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.InvalidEnumArgumentException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Convert))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.DateTime))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.DateTimeKind))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.DateTimeOffset))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.DBNull))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Decimal))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Delegate))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.AllowNullAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.ExperimentalAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.NotNullAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.NotNullWhenAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DataReceivedEventArgs))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DataReceivedEventHandler))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.Debug))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggableAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggableAttribute.DebuggingModes))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerBrowsableAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerBrowsableState))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerDisplayAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerHiddenAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerStepThroughAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerTypeProxyAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.Process))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.ProcessStartInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.DllNotFoundException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Double))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Drawing.Rectangle))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Enum))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Environment))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Exception))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.FlagsAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.FormatException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Func<,,,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Func<,,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Func<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Func<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.GC))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Globalization.CultureInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Guid))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Half))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.HashCode))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IAsyncDisposable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IAsyncResult))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IConvertible))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IDisposable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IEquatable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IFormatProvider))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Index))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IndexOutOfRangeException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Int16))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Int32))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Int64))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IntPtr))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.InvalidCastException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.InvalidOperationException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.Directory))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.DirectoryInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.File))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.FileAccess))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.FileMode))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.FileStream))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.MemoryMappedFiles.MemoryMappedFile))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.MemoryMappedFiles.MemoryMappedViewAccessor))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.MemoryStream))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.Path))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.SeekOrigin))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.Stream))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.UnmanagedMemoryStream))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IProgress<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IServiceProvider))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Linq.Enumerable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Linq.IOrderedEnumerable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Math))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.MathF))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Memory<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.MemoryExtensions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.MemoryExtensions.TryWriteInterpolatedStringHandler))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.MulticastDelegate))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Net.Http.Headers.MediaTypeHeaderValue))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Net.Mime.MediaTypeNames))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Net.WebUtility))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.NotSupportedException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Nullable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Nullable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Numerics.BitOperations))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Numerics.Tensors.TensorPrimitives))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Numerics.Vector))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Numerics.Vector<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Object))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ObjectDisposedException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ObsoleteAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.OperatingSystem))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.OperationCanceledException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.OverflowException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ParamArrayAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.PlatformNotSupportedException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Predicate<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Random))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Range))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ReadOnlyMemory<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ReadOnlySpan<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.Assembly))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyCompanyAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyConfigurationAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyCopyrightAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyDefaultAliasAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyDescriptionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyFileVersionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyInformationalVersionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyMetadataAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyProductAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyTitleAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.Binder))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.BindingFlags))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.ConstructorInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.CustomAttributeExtensions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.DefaultMemberAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.ICustomAttributeProvider))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.MemberInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.MethodBase))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.MethodInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.ParameterInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.ParameterModifier))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.PropertyInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.AsyncIteratorMethodBuilder))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.AsyncIteratorStateMachineAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.AsyncStateMachineAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.AsyncTaskMethodBuilder))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.AsyncTaskMethodBuilder<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.CallerArgumentExpressionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.CompilationRelaxationsAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConditionalWeakTable<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConditionalWeakTable<,>.CreateValueCallback))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable<>.Enumerator))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredTaskAwaitable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<>.ConfiguredValueTaskAwaiter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.DefaultInterpolatedStringHandler))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.EnumeratorCancellationAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ExtensionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.FixedBufferAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.IAsyncStateMachine))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.InlineArrayAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.IsByRefLikeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.IsExternalInit))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.IsReadOnlyAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.IsUnmanagedAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.IteratorStateMachineAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.NullableAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.NullableContextAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.RefSafetyRulesAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.RequiresLocationAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.RuntimeCompatibilityAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.RuntimeHelpers))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.SkipLocalsInitAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.TaskAwaiter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.TaskAwaiter<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.TupleElementNamesAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.Unsafe))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.UnsafeValueTypeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ValueTaskAwaiter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ValueTaskAwaiter<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.ExceptionServices.ExceptionDispatchInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.CallingConvention))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.CollectionsMarshal))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.DllImportResolver))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.DllImportSearchPath))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.GCHandle))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.GCHandleType))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.InAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.Marshal))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.MemoryMarshal))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.NativeLibrary))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.OSPlatform))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.RuntimeInformation))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.SafeBuffer))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.SafeHandle))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.UnmanagedType))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.Arm.ArmBase))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.Arm.ArmBase.Arm64))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.X86.Avx))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.X86.Avx2))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.X86.Avx512BW))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.X86.Avx512F))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.X86.Avx512Vbmi))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.X86.Bmi1))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.X86.Bmi1.X64))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Intrinsics.X86.X86Base))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Versioning.SupportedOSPlatformAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Versioning.TargetFrameworkAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Versioning.TargetPlatformAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.RuntimeTypeHandle))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.SByte))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Security.Cryptography.HashAlgorithmName))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Security.Cryptography.IncrementalHash))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Security.Permissions.SecurityAction))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Security.Permissions.SecurityPermissionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Security.UnverifiableCodeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Single))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Span<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.String))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.StringComparer))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.StringComparison))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.StringSplitOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Decoder))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Encoding))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Encodings.Web.JavaScriptEncoder))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonDocument))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonDocumentOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonElement))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonEncodedText))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonReaderOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonSerializer))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonSerializerDefaults))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonSerializerOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonTokenType))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.JsonValueKind))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Nodes.JsonArray))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Nodes.JsonNode))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Nodes.JsonNodeOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Nodes.JsonObject))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Nodes.JsonValue))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Schema.JsonSchemaExporter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Schema.JsonSchemaExporterContext))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Schema.JsonSchemaExporterOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonConstructorAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonConverter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonConverter<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonConverterAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonConverterFactory))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonDerivedTypeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonIgnoreAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonIgnoreCondition))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonIncludeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonNumberHandling))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonPolymorphicAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonPropertyNameAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonSerializableAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonSerializerContext))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonDerivedType))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonMetadataServices))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonParameterInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonParameterInfoValues))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonPolymorphismOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonPropertyInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonTypeInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonTypeInfo<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonTypeInfoKind))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Serialization.Metadata.JsonTypeInfoResolver))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Utf8JsonReader))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Json.Utf8JsonWriter))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.Capture))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.GeneratedRegexAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.Group))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.GroupCollection))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.Match))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.Regex))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.RegexOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.RegexRunner))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.RegexRunnerFactory))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.StringBuilder))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.StringBuilder.AppendInterpolatedStringHandler))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.CancellationToken))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.CancellationTokenSource))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Interlocked))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Monitor))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.SpinLock))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Parallel))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.ParallelLoopResult))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.ParallelOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Sources.IValueTaskSource))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Sources.IValueTaskSource<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Sources.ValueTaskSourceStatus))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Task))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Task<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.TaskAsyncEnumerableExtensions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.ValueTask))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.ValueTask<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.ThreadLocal<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ThreadStaticAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.TimeSpan))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Type))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.UInt16))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.UInt32))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.UInt64))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.UIntPtr))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Uri))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.UriFormatException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ValueTuple<,,,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ValueTuple<,,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ValueTuple<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ValueType))]
|
||||
//[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Void))]
|
||||
[ModuleInitializer]
|
||||
internal static void Initialize()
|
||||
{
|
||||
// This method runs automatically on startup.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
<linker>
|
||||
<assembly fullname="System.Collections" preserve="all" />
|
||||
<assembly fullname="System.IO.MemoryMappedFiles" preserve="all" />
|
||||
<assembly fullname="System.Linq" preserve="all" />
|
||||
<assembly fullname="System.Memory" preserve="all" />
|
||||
<assembly fullname="System.ObjectModel" preserve="all" />
|
||||
<assembly fullname="System.Runtime" preserve="all" />
|
||||
<assembly fullname="System.Runtime.InteropServices" preserve="all" />
|
||||
<assembly fullname="System.Text.RegularExpressions" preserve="all" />
|
||||
<assembly fullname="System.Threading" preserve="all" />
|
||||
<assembly fullname="BetterLyrics.WinUI3">
|
||||
<type fullname="BetterLyrics.WinUI3.PluginConfigs.BetterLyrics_Plugins_Romaji_Config" preserve="all" />
|
||||
</assembly>
|
||||
</linker>
|
||||
@@ -0,0 +1,145 @@
|
||||
// Auto-Generated by PluginAnalyzer
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace BetterLyrics.WinUI3.PluginConfigs;
|
||||
internal static class BetterLyrics_Plugins_Romaji_Config
|
||||
{
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.AppContext))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.AppDomain))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ArgumentException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ArgumentNullException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ArgumentOutOfRangeException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Array))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.AsyncCallback))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Boolean))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Buffer))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Byte))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Char))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.Dictionary<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.EqualityComparer<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.ICollection<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IEnumerable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IEnumerator<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IList<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IReadOnlyCollection<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.IReadOnlyList<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.LinkedList<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.LinkedListNode<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.List<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.ICollection))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.IEnumerable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.IEnumerator))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.IList))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.ObjectModel.Collection<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.ObjectModel.ObservableCollection<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.INotifyPropertyChanged))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.PropertyChangedEventArgs))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ComponentModel.PropertyChangedEventHandler))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.DateTime))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Delegate))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggableAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggableAttribute.DebuggingModes))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerBrowsableAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerBrowsableState))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Diagnostics.DebuggerHiddenAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Enum))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Environment))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Exception))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Func<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.GC))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IAsyncResult))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IComparable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IDisposable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IndexOutOfRangeException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Int16))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Int32))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Int64))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.InvalidOperationException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.BinaryReader))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.File))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.FileAccess))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.FileMode))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.FileShare))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.FileStream))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.HandleInheritability))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.MemoryMappedFiles.MemoryMappedFile))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.MemoryMappedFiles.MemoryMappedFileAccess))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.MemoryMappedFiles.MemoryMappedViewAccessor))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.MemoryMappedFiles.MemoryMappedViewStream))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.Path))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.Stream))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.StreamReader))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.TextReader))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.IO.UnmanagedMemoryAccessor))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Linq.Enumerable))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Linq.IGrouping<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Math))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.MemoryExtensions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.MulticastDelegate))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.NotImplementedException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.NotSupportedException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Nullable<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Object))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ObjectDisposedException))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ObsoleteAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ParamArrayAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ReadOnlySpan<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyCompanyAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyConfigurationAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyCopyrightAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyDescriptionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyFileVersionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyInformationalVersionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyMetadataAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyProductAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyTitleAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.AssemblyTrademarkAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Reflection.DefaultMemberAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.CallerMemberNameAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.CompilationRelaxationsAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.ExtensionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.IsReadOnlyAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.IteratorStateMachineAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.NullableAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.NullableContextAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.RefSafetyRulesAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.RuntimeCompatibilityAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.CompilerServices.TupleElementNamesAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.InteropServices.InAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Serialization.SerializationInfo))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Serialization.StreamingContext))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Versioning.SupportedOSPlatformAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Versioning.TargetFrameworkAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Runtime.Versioning.TargetPlatformAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Security.Permissions.SecurityAction))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Security.Permissions.SecurityPermissionAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Security.UnverifiableCodeAttribute))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Single))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.String))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.StringSplitOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.Encoding))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.Capture))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.Group))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.GroupCollection))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.Match))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.MatchCollection))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.Regex))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.RegularExpressions.RegexOptions))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Text.StringBuilder))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Interlocked))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Task))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Threading.Tasks.Task<>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.TimeSpan))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Type))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.UInt16))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.UInt32))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ValueTuple<,>))]
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.ValueType))]
|
||||
[ModuleInitializer]
|
||||
internal static void Initialize()
|
||||
{
|
||||
// This method runs automatically on startup.
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
|
||||
public CoverBackgroundRenderer()
|
||||
{
|
||||
_crossfadeTransition = new ValueTransition<double>(1.0, 0.7, easingType: EasingType.Linear);
|
||||
_crossfadeTransition = new ValueTransition<double>(1.0, EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Linear), 0.7);
|
||||
}
|
||||
|
||||
public void SetCoverBitmap(CanvasBitmap? newBitmap)
|
||||
@@ -73,18 +73,18 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
|
||||
if (_currentBitmap == null)
|
||||
{
|
||||
_crossfadeTransition.StartTransition(1.0, jumpTo: true);
|
||||
_crossfadeTransition.JumpTo(1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_previousBitmap == null)
|
||||
{
|
||||
_crossfadeTransition.StartTransition(1.0, jumpTo: true);
|
||||
_crossfadeTransition.JumpTo(1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_crossfadeTransition.Reset(0.0);
|
||||
_crossfadeTransition.StartTransition(1.0);
|
||||
_crossfadeTransition.JumpTo(0.0);
|
||||
_crossfadeTransition.Start(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
Color fgColor,
|
||||
LyricsEffectSettings settings)
|
||||
{
|
||||
DrawPhonetic(ds, textOnlyLayer, line);
|
||||
DrawOriginalText(control, ds, textOnlyLayer, line, playbackState, bgColor, fgColor, settings);
|
||||
DrawTranslated(ds, textOnlyLayer, line);
|
||||
DrawTertiaryText(ds, textOnlyLayer, line);
|
||||
DrawPrimaryText(control, ds, textOnlyLayer, line, playbackState, bgColor, fgColor, settings);
|
||||
DrawSecondaryText(ds, textOnlyLayer, line);
|
||||
}
|
||||
|
||||
private void DrawPhonetic(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
|
||||
private void DrawTertiaryText(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
|
||||
{
|
||||
if (line.TertiaryTextLayout == null) return;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawTranslated(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
|
||||
private void DrawSecondaryText(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
|
||||
{
|
||||
if (line.SecondaryTextLayout == null) return;
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawOriginalText(
|
||||
private void DrawPrimaryText(
|
||||
ICanvasResourceCreator resourceCreator,
|
||||
CanvasDrawingSession ds,
|
||||
ICanvasImage source,
|
||||
|
||||
@@ -251,11 +251,7 @@ namespace BetterLyrics.WinUI3.Services.FileSystemService
|
||||
.Where(x => x.MediaFolderId == folder.Id)
|
||||
.ExecuteDeleteAsync();
|
||||
|
||||
// VACUUM 是 SQLite 特有的命令
|
||||
if (context.Database.IsSqlite())
|
||||
{
|
||||
await context.Database.ExecuteSqlRawAsync("VACUUM");
|
||||
}
|
||||
await context.Database.ExecuteSqlRawAsync("VACUUM");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
{
|
||||
_logger.LogInformation("RefreshLyricsAsync");
|
||||
|
||||
CurrentLyricsSearchResult = null;
|
||||
CurrentLyricsData = LyricsData.GetLoadingPlaceholder();
|
||||
|
||||
if (CurrentSongInfo != SongInfoExtensions.Placeholder)
|
||||
|
||||
@@ -11,6 +11,7 @@ using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.AlbumArtSearchService;
|
||||
using BetterLyrics.WinUI3.Services.DiscordService;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.LocalizationService;
|
||||
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
||||
using BetterLyrics.WinUI3.Services.PlayHistoryService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
@@ -19,6 +20,7 @@ using BetterLyrics.WinUI3.Services.TransliterationService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using CommunityToolkit.WinUI;
|
||||
@@ -206,7 +208,6 @@ namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
private void InitMediaManager()
|
||||
{
|
||||
_mediaManager.Start();
|
||||
|
||||
_mediaManager.CurrentMediaSessions.ToList().ForEach(x => RecordMediaSession(x.Value.Id));
|
||||
|
||||
_mediaManager.OnAnySessionOpened += MediaManager_OnAnySessionOpened;
|
||||
@@ -696,10 +697,6 @@ namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
_logger.LogInformation("Target LibreTranslate language code changed: {code}", _settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageCode);
|
||||
UpdateLyrics();
|
||||
}
|
||||
else if (message.PropertyName == nameof(TranslationSettings.CutletDockerServer))
|
||||
{
|
||||
UpdateLyrics();
|
||||
}
|
||||
else if (message.PropertyName == nameof(TranslationSettings.LibreTranslateServer))
|
||||
{
|
||||
UpdateLyrics();
|
||||
|
||||
@@ -8,5 +8,6 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
|
||||
{
|
||||
Task<LyricsCacheItem?> GetLyricsAsync(SongInfo songInfo, LyricsSearchProvider provider);
|
||||
Task SaveLyricsAsync(SongInfo songInfo, LyricsCacheItem result);
|
||||
Task ClearCacheAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
|
||||
existingItem.Title = result.Title;
|
||||
existingItem.Artist = result.Artist;
|
||||
existingItem.Album = result.Album;
|
||||
existingItem.Duration = result.Duration;
|
||||
|
||||
existingItem.TransliterationProvider = result.TransliterationProvider;
|
||||
existingItem.TranslationProvider = result.TranslationProvider;
|
||||
@@ -69,5 +70,13 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task ClearCacheAsync()
|
||||
{
|
||||
using var context = await _contextFactory.CreateDbContextAsync();
|
||||
|
||||
await context.LyricsCache.ExecuteDeleteAsync();
|
||||
await context.Database.ExecuteSqlRawAsync("VACUUM;");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.Core.Interfaces.Features;
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
@@ -9,6 +11,7 @@ using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Providers;
|
||||
using BetterLyrics.WinUI3.Services.FileSystemService;
|
||||
using BetterLyrics.WinUI3.Services.LyricsCacheService;
|
||||
using BetterLyrics.WinUI3.Services.PluginService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.SongSearchMapService;
|
||||
using Lyricify.Lyrics.Helpers;
|
||||
@@ -29,12 +32,13 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
{
|
||||
private readonly HttpClient _amllTtmlDbHttpClient;
|
||||
private readonly HttpClient _lrcLibHttpClient;
|
||||
private readonly AppleMusic _appleMusic;
|
||||
private readonly Providers.AppleMusic _appleMusic;
|
||||
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IFileSystemService _fileSystemService;
|
||||
private readonly ILyricsCacheService _lyricsCacheService;
|
||||
private readonly ISongSearchMapService _songSearchMapService;
|
||||
private readonly IPluginService _pluginService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LyricsSearchService(
|
||||
@@ -42,6 +46,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
IFileSystemService fileSystemService,
|
||||
ILyricsCacheService lyricsCacheService,
|
||||
ISongSearchMapService songSearchMapService,
|
||||
IPluginService pluginService,
|
||||
ILogger<LyricsSearchService> logger
|
||||
)
|
||||
{
|
||||
@@ -49,15 +54,16 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
_fileSystemService = fileSystemService;
|
||||
_lyricsCacheService = lyricsCacheService;
|
||||
_songSearchMapService = songSearchMapService;
|
||||
_pluginService = pluginService;
|
||||
_logger = logger;
|
||||
|
||||
_lrcLibHttpClient = new();
|
||||
_lrcLibHttpClient.DefaultRequestHeaders.Add(
|
||||
"User-Agent",
|
||||
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Constants.Link.BetterLyricsGitHub})"
|
||||
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Link.BetterLyricsGitHub})"
|
||||
);
|
||||
_amllTtmlDbHttpClient = new();
|
||||
_appleMusic = new AppleMusic();
|
||||
_appleMusic = new Providers.AppleMusic();
|
||||
}
|
||||
|
||||
private static bool IsAmllTtmlDbIndexInvalid()
|
||||
@@ -206,11 +212,26 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
{
|
||||
_logger.LogInformation("SearchAllAsync {SongInfo}", songInfo);
|
||||
var results = new List<LyricsCacheItem>();
|
||||
|
||||
foreach (var provider in Enum.GetValues<LyricsSearchProvider>())
|
||||
{
|
||||
if (provider == LyricsSearchProvider.Plugin) continue;
|
||||
|
||||
var searchResult = await SearchSingleAsync(songInfo, provider, checkCache, token);
|
||||
results.Add(searchResult);
|
||||
}
|
||||
|
||||
foreach (var plugin in _pluginService.Plugins)
|
||||
{
|
||||
if (token.IsCancellationRequested) break;
|
||||
|
||||
if (plugin is ILyricsSource lyricsSearchPlugin)
|
||||
{
|
||||
var pluginResult = await SearchPluginAsync(songInfo, lyricsSearchPlugin, token);
|
||||
results.Add(pluginResult);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -402,6 +423,8 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
}
|
||||
|
||||
string? rawLyricFile = null;
|
||||
string? bestNcmMusicId = null;
|
||||
|
||||
await foreach (var line in File.ReadLinesAsync(PathHelper.AmllTtmlDbIndexPath))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
@@ -416,6 +439,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
string? title = null;
|
||||
string? artist = null;
|
||||
string? album = null;
|
||||
string? ncmMusicId = null;
|
||||
|
||||
foreach (var meta in metadataArr.EnumerateArray())
|
||||
{
|
||||
@@ -429,6 +453,8 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
artist = string.Join(" / ", valueArr.EnumerateArray());
|
||||
if (key == "album" && valueArr.GetArrayLength() > 0)
|
||||
album = valueArr[0].GetString();
|
||||
if (key == "ncmMusicId" && valueArr.GetArrayLength() > 0)
|
||||
ncmMusicId = valueArr[0].GetString();
|
||||
}
|
||||
|
||||
int score = MetadataComparer.CalculateScore(songInfo, new LyricsCacheItem
|
||||
@@ -436,12 +462,12 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
Title = title,
|
||||
Artist = artist,
|
||||
Album = album,
|
||||
Duration = 0,
|
||||
});
|
||||
if (score > lyricsSearchResult.MatchPercentage)
|
||||
{
|
||||
if (root.TryGetProperty("rawLyricFile", out var rawLyricFileProp))
|
||||
{
|
||||
bestNcmMusicId = ncmMusicId;
|
||||
rawLyricFile = rawLyricFileProp.GetString();
|
||||
lyricsSearchResult.Title = title;
|
||||
lyricsSearchResult.Artist = artist;
|
||||
@@ -458,19 +484,28 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
return lyricsSearchResult;
|
||||
}
|
||||
|
||||
// 下载歌词内容
|
||||
var url = $"{_settingsService.AppSettings.GeneralSettings.AmllTtmlDbBaseUrl}/{Constants.AmllTTmlDB.QueryPrefix}/{rawLyricFile}";
|
||||
var url = $"{_settingsService.AppSettings.GeneralSettings.AmllTtmlDbBaseUrl}/{AmllTTmlDB.QueryPrefix}/{rawLyricFile}";
|
||||
lyricsSearchResult.Reference = url;
|
||||
try
|
||||
{
|
||||
// 下载写入歌词
|
||||
using var response = await _amllTtmlDbHttpClient.GetAsync(url);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return lyricsSearchResult;
|
||||
}
|
||||
string lyrics = await response.Content.ReadAsStringAsync();
|
||||
|
||||
lyricsSearchResult.Raw = lyrics;
|
||||
|
||||
// 反查时长
|
||||
if (bestNcmMusicId != null && lyricsSearchResult.Duration == null)
|
||||
{
|
||||
var tmp = await SearchQQNeteaseKugouAsync(
|
||||
((SongInfo)songInfo.Clone()).WithSongId($"{ExtendedGenreFiled.NetEaseCloudMusicTrackID}{bestNcmMusicId}"),
|
||||
Searchers.Netease);
|
||||
lyricsSearchResult.Duration = tmp.Duration;
|
||||
lyricsSearchResult.MatchPercentage = MetadataComparer.CalculateScore(songInfo, lyricsSearchResult);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -633,7 +668,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
}
|
||||
|
||||
lyricsSearchResult.Title = result?.Title;
|
||||
lyricsSearchResult.Artist = string.Join(" / ", result?.Artists ?? []);
|
||||
lyricsSearchResult.Artist = result?.Artist;
|
||||
lyricsSearchResult.Album = result?.Album;
|
||||
lyricsSearchResult.Duration = result?.DurationMs / 1000;
|
||||
|
||||
@@ -658,5 +693,40 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
return lyricsSearchResult;
|
||||
}
|
||||
|
||||
private async Task<LyricsCacheItem> SearchPluginAsync(SongInfo songInfo, ILyricsSource plugin, CancellationToken token)
|
||||
{
|
||||
var cacheItem = new LyricsCacheItem
|
||||
{
|
||||
Provider = LyricsSearchProvider.Plugin,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var result = await plugin.GetLyricsAsync(songInfo.Title, songInfo.Artist, songInfo.Album, songInfo.Duration);
|
||||
|
||||
if (result != null && !string.IsNullOrEmpty(result.Raw))
|
||||
{
|
||||
cacheItem.Title = result.Title;
|
||||
cacheItem.Artist = result.Artist;
|
||||
cacheItem.Album = result.Album;
|
||||
cacheItem.Duration = result.Duration;
|
||||
|
||||
cacheItem.Raw = result.Raw;
|
||||
cacheItem.Translation = result.Translation;
|
||||
cacheItem.Transliteration = result.Transliteration;
|
||||
|
||||
cacheItem.Reference = result.Reference ?? "about:blank";
|
||||
cacheItem.MatchPercentage = MetadataComparer.CalculateScore(songInfo, cacheItem);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Plugin {PluginName} failed to search", plugin.Name);
|
||||
}
|
||||
|
||||
return cacheItem;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.PluginService
|
||||
{
|
||||
public interface IPluginService
|
||||
{
|
||||
IReadOnlyList<IPlugin> Plugins { get; }
|
||||
|
||||
T? GetPlugin<T>() where T : class, IPlugin;
|
||||
void LoadPlugins();
|
||||
void InstallPlugin(string zipPath);
|
||||
void UninstallPlugin(string pluginId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using BetterLyrics.Core.Interfaces.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.PluginService
|
||||
{
|
||||
public class PluginContext : IPluginContext
|
||||
{
|
||||
private readonly IPluginService _pluginService;
|
||||
|
||||
public string PluginDirectory { get; }
|
||||
public IAIService? AIService => _pluginService.GetPlugin<IAIService>();
|
||||
|
||||
public PluginContext(IPluginService pluginService, string pluginDir)
|
||||
{
|
||||
_pluginService = pluginService;
|
||||
PluginDirectory = pluginDir;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.PluginService
|
||||
{
|
||||
public class PluginLoadContext : AssemblyLoadContext
|
||||
{
|
||||
private AssemblyDependencyResolver _resolver;
|
||||
|
||||
public PluginLoadContext(string pluginPath) : base(isCollectible: true)
|
||||
{
|
||||
_resolver = new AssemblyDependencyResolver(pluginPath);
|
||||
}
|
||||
|
||||
protected override Assembly? Load(AssemblyName assemblyName)
|
||||
{
|
||||
var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
|
||||
if (assemblyPath != null)
|
||||
{
|
||||
return LoadFromAssemblyPath(assemblyPath);
|
||||
}
|
||||
|
||||
// return null to use the default AssemblyLoadContext
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
|
||||
{
|
||||
var libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
|
||||
if (libraryPath != null)
|
||||
{
|
||||
return LoadUnmanagedDllFromPath(libraryPath);
|
||||
}
|
||||
|
||||
// return IntPtr.Zero to use the default AssemblyLoadContext
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.PluginService
|
||||
{
|
||||
public class PluginService : IPluginService
|
||||
{
|
||||
private List<IPlugin> _plugins = new();
|
||||
public IReadOnlyList<IPlugin> Plugins => _plugins;
|
||||
private Dictionary<string, PluginLoadContext> _pluginContexts = new();
|
||||
private HashSet<string> _loadedDllPaths = new();
|
||||
|
||||
private readonly ILogger<PluginService> _logger;
|
||||
|
||||
public PluginService(ILogger<PluginService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public T? GetPlugin<T>() where T : class, IPlugin
|
||||
{
|
||||
return _plugins.OfType<T>().FirstOrDefault();
|
||||
}
|
||||
|
||||
public void LoadPlugins()
|
||||
{
|
||||
string pluginsRoot = Path.Combine(ApplicationData.Current.LocalFolder.Path, "plugins");
|
||||
if (!Directory.Exists(pluginsRoot)) Directory.CreateDirectory(pluginsRoot);
|
||||
|
||||
var pluginFolders = Directory.GetDirectories(pluginsRoot);
|
||||
|
||||
foreach (var folder in pluginFolders)
|
||||
{
|
||||
var dllFiles = Directory.GetFiles(folder, "*.dll");
|
||||
|
||||
foreach (var dllPath in dllFiles)
|
||||
{
|
||||
if (_loadedDllPaths.Contains(dllPath)) continue;
|
||||
|
||||
TryLoadPlugin(dllPath);
|
||||
}
|
||||
}
|
||||
|
||||
InitializePlugins();
|
||||
}
|
||||
|
||||
private void InitializePlugins()
|
||||
{
|
||||
foreach (var plugin in _plugins)
|
||||
{
|
||||
try
|
||||
{
|
||||
string dllPath = plugin.GetType().Assembly.Location;
|
||||
string? pluginDir = Path.GetDirectoryName(dllPath);
|
||||
if (pluginDir == null) continue;
|
||||
|
||||
var context = new PluginContext(this, pluginDir);
|
||||
plugin.OnLoad(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to initialize plugin {Name}", plugin.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryLoadPlugin(string dllPath)
|
||||
{
|
||||
// 1. Create Context
|
||||
var loadContext = new PluginLoadContext(dllPath);
|
||||
|
||||
try
|
||||
{
|
||||
var assembly = loadContext.LoadFromAssemblyPath(dllPath);
|
||||
int loadedCount = 0; // Track successfully loaded plugins
|
||||
|
||||
// 2. [Safety Check] Safely retrieve types
|
||||
IEnumerable<Type> types;
|
||||
try
|
||||
{
|
||||
types = assembly.GetExportedTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
// If some types fail to load, only keep the usable ones!
|
||||
types = ex.Types.Where(t => t != null)!;
|
||||
foreach (var loaderEx in ex.LoaderExceptions)
|
||||
{
|
||||
_logger.LogWarning("Partial type loading failure in DLL {path}: {msg}", dllPath, loaderEx?.Message);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
// 3. Check if it is a valid plugin class
|
||||
if (typeof(IPlugin).IsAssignableFrom(type) && !type.IsAbstract)
|
||||
{
|
||||
IPlugin? plugin = null;
|
||||
try
|
||||
{
|
||||
// 4. [Instantiation Guard] Prevent plugin constructor errors from crashing the main app
|
||||
plugin = (IPlugin?)Activator.CreateInstance(type);
|
||||
if (plugin == null) continue;
|
||||
|
||||
// 5. Check for duplicate IDs
|
||||
if (_plugins.Any(p => p.Id == plugin.Id))
|
||||
{
|
||||
_logger.LogWarning("Skipping duplicate plugin: {id} ({path})", plugin.Id, dllPath);
|
||||
// Explicitly break reference to aid Unload
|
||||
plugin = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 7. Add to collection
|
||||
_plugins.Add(plugin);
|
||||
_pluginContexts.Add(plugin.Id, loadContext);
|
||||
loadedCount++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to initialize/instantiate plugin {type}", type.FullName);
|
||||
|
||||
// If plugin initialization fails, explicitly dispose if possible
|
||||
if (plugin is IDisposable disposable)
|
||||
{
|
||||
try { disposable.Dispose(); } catch { }
|
||||
}
|
||||
plugin = null; // Break reference
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Finalize: If no usable plugins were found in this DLL, unload Context
|
||||
if (loadedCount > 0)
|
||||
{
|
||||
_loadedDllPaths.Add(dllPath);
|
||||
_logger.LogInformation("Successfully loaded {count} plugin(s) from {path}", loadedCount, dllPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No valid plugins found in {path}. Unloading context.", dllPath);
|
||||
// No plugin instances remain alive at this point, safe to unload
|
||||
loadContext.Unload();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to load assembly: {path}", dllPath);
|
||||
// Only unload here if the loading process completely crashed
|
||||
try { loadContext.Unload(); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
public void UninstallPlugin(string pluginId)
|
||||
{
|
||||
var plugin = _plugins.FirstOrDefault(p => p.Id == pluginId);
|
||||
if (plugin == null) return;
|
||||
|
||||
var dllPath = plugin.GetType().Assembly.Location;
|
||||
var folderPath = Path.GetDirectoryName(dllPath);
|
||||
|
||||
_plugins.Remove(plugin);
|
||||
_loadedDllPaths.Remove(dllPath);
|
||||
|
||||
if (_pluginContexts.TryGetValue(pluginId, out var context))
|
||||
{
|
||||
context.Unload();
|
||||
_pluginContexts.Remove(pluginId);
|
||||
}
|
||||
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
|
||||
if (Directory.Exists(folderPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(folderPath, true);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to delete plugin folder {}", folderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InstallPlugin(string zipPath)
|
||||
{
|
||||
string pluginsRoot = Path.Combine(ApplicationData.Current.LocalFolder.Path, "plugins");
|
||||
string folderName = Path.GetFileNameWithoutExtension(zipPath);
|
||||
string installDir = Path.Combine(pluginsRoot, folderName);
|
||||
|
||||
if (Directory.Exists(installDir))
|
||||
{
|
||||
// TODO: 最好是先 Find plugin by path -> UninstallPlugin(id)
|
||||
// 否则文件被锁住无法 Delete
|
||||
try
|
||||
{
|
||||
Directory.Delete(installDir, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to delete existing plugin folder {}", installDir);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(installDir);
|
||||
ZipFile.ExtractToDirectory(zipPath, installDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
using BetterLyrics.WinUI3.Models.Http;
|
||||
using BetterLyrics.Core.Interfaces.Features;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models.Http;
|
||||
using BetterLyrics.WinUI3.Serialization;
|
||||
using BetterLyrics.WinUI3.Services.PluginService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@@ -12,37 +16,31 @@ namespace BetterLyrics.WinUI3.Services.TransliterationService
|
||||
public class TransliterationService : ITransliterationService
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IPluginService _pluginService;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public TransliterationService(ISettingsService settingsService)
|
||||
public TransliterationService(ISettingsService settingsService, IPluginService pluginService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_pluginService = pluginService;
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
|
||||
public async Task<string> TransliterateText(string text, string targetLangCode, CancellationToken token)
|
||||
{
|
||||
string? result = null;
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
throw new Exception(text + " is empty or null.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(_settingsService.AppSettings.TranslationSettings.CutletDockerServer))
|
||||
var plugin = _pluginService.Plugins.OfType<ILyricsTransliterator>().FirstOrDefault();
|
||||
if (plugin != null)
|
||||
{
|
||||
throw new Exception("cutlet-docker server URL is not set in settings.");
|
||||
result = await plugin.GetTransliterationAsync(text, PhoneticHelper.RomanCode);
|
||||
}
|
||||
|
||||
var request = new CutletDockerRequest { Text = text };
|
||||
var reqJson = System.Text.Json.JsonSerializer.Serialize(request, SourceGenerationContext.Default.CutletDockerRequest);
|
||||
|
||||
var url = $"{_settingsService.AppSettings.TranslationSettings.CutletDockerServer}/convert";
|
||||
var response = await _httpClient.PostAsync(url, new StringContent(reqJson, Encoding.UTF8, "application/json"));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
var resJson = await response.Content.ReadAsStringAsync(token);
|
||||
|
||||
var result = System.Text.Json.JsonSerializer.Deserialize(resJson, SourceGenerationContext.Default.CutletDockerResponse);
|
||||
return result?.RomajiText ?? string.Empty;
|
||||
return result ?? "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>مثال: http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>المدة</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>جارٍ تحميل الكلمات...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>لا يمكن عرض المقطوعات لأن المسار غير موجود</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>سياسة الخصوصية</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>منطقة قابلة للسحب</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>EaseInOutBack</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>EaseInOutBounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>EaseInOutCirc</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>EaseInOutCubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>EaseInOutElastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>EaseInOutExpo</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuad</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuart</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuint</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>EaseInOutSine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>فرض البقاء في المقدمة</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>فرض محاكاة تأثير كلمة بكلمة حتى إذا كانت الكلمات الحالية لا تحتوي على معلومات كلمة بكلمة</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>فرض تفعيل تأثير الكلمات كلمة بكلمة</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>معدل إطارات التصيير (FPS)</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>بعد الاستيراد الناجح، سيقوم البرنامج بإعادة التشغيل تلقائياً</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>ستعطى الأولوية لقراءة النقل الصوتي داخل ملف الكلمات، وإذا لم يوجد تطابق، سيتم طلب نقل صوتي آلي من خادم cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>الصوتيات اليابانية</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>اختصار تبديل حالة نافذة الكلمات</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>استراتيجية الرسوم المتحركة كلمة بكلمة</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>دائماً</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>السيارات</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>أبداً</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>سيؤثر ضبط هذه القيمة على نتائج البحث المتسلسل والبحث بأفضل تطابق، ولكنه لن يؤثر على نتائج البحث في واجهة البحث اليدوي عن الكلمات</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>اختصار التشغيل والإيقاف المؤقت</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>اختصار الأغنية السابقة</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>النشاط بالساعة</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>كل الوقت</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>مخصص</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>z. B. http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Dauer</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>Songtext wird geladen...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>Titel können nicht angezeigt werden, da der Pfad nicht existiert</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Datenschutzrichtlinie</value>
|
||||
</data>
|
||||
@@ -795,35 +810,38 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Ziehbereich</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<value>Back Ease In-Out</value>
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<value>Bounce Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<value>Circular Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>Bounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>Cubic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>Circular</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<value>Elastic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>Cubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<value>Exponential Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>Elastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>Exponential</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<value>Quartic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<value>Quintic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>Quartic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<value>Sine Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>Quintic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>Sine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
<value>Linear</value>
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Immer im Vordergrund erzwingen</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Wort-für-Wort-Simulation erzwingen, auch wenn der aktuelle Songtext keine entsprechenden Infos enthält</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Wort-für-Wort-Effekt erzwingen</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>Rendering-FPS</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>Die App startet nach erfolgreichem Import automatisch neu</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Priorisiere Transliterationen innerhalb des Songtextes; falls keine Übereinstimmung gefunden wird, fordere maschinelle Transliteration vom cutlet-docker-Server an</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Japanische Lautschrift</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Tastenkürzel für Songtext-Fensterstatuswechsel</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Wort-für-Wort-Animationsstrategie</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Immer</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Auto</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Niemals</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>Das Anpassen dieses Wertes beeinflusst die sequenzielle Suche und die Suche nach der besten Übereinstimmung, hat jedoch keinen Einfluss auf die Suchergebnisse in der manuellen Songtext-Suchoberfläche</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Tastenkürzel für Wiedergabe/Pause</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Tastenkürzel für vorherigen Titel</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Aktivität nach Stunden</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>Alle Zeiten</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>Benutzerdefiniert</value>
|
||||
</data>
|
||||
|
||||
@@ -555,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>Unable to view tracks because the path does not exist</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value>Install plugin</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value>No plugins installed</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value>Plugin Manager</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value>Uninstall plugin</value>
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Privacy Policy</value>
|
||||
</data>
|
||||
@@ -798,35 +810,47 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Draggable Area</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<value>Back Ease In-Out</value>
|
||||
<data name="SettingsPageEasingMode.Header" xml:space="preserve">
|
||||
<value>Easing Mode</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<value>Bounce Ease In-Out</value>
|
||||
<data name="SettingsPageEasingModeIn.Content" xml:space="preserve">
|
||||
<value>In</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<value>Circular Ease In-Out</value>
|
||||
<data name="SettingsPageEasingModeInOut.Content" xml:space="preserve">
|
||||
<value>In-Out</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>Cubic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value>Out</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<value>Elastic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<value>Exponential Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>Bounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>Circular</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<value>Quartic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>Cubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<value>Quintic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>Elastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<value>Sine Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>Exponential</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>Quartic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>Quintic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>Sine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
<value>Linear</value>
|
||||
@@ -891,12 +915,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Force Always on Top</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Force word-by-word simulation even if current lyrics don't have word-by-word info</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Force Word-by-Word Effect</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>Render FPS</value>
|
||||
</data>
|
||||
@@ -930,9 +948,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>The app will restart automatically after successful import</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Prioritize reading transliteration within lyrics; if no match, request machine transliteration from cutlet-docker server</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Japanese Phonetic</value>
|
||||
</data>
|
||||
@@ -1143,6 +1158,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Lyrics Window Status Switch Shortcut</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Word-by-word Animation Strategy</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Always</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Auto</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Never</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>Adjusting this value will affect sequential search and best match search results, but will not affect search results in the manual lyrics search interface</value>
|
||||
</data>
|
||||
@@ -1248,6 +1275,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Play/Pause Shortcut</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value>Plugins</value>
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Previous Track Shortcut</value>
|
||||
</data>
|
||||
@@ -1473,6 +1503,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Activity by Hour</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>All Time</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>Custom</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>ej. http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Duración</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>Cargando letra...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>No se pueden ver las pistas porque la ruta no existe</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Política de privacidad</value>
|
||||
</data>
|
||||
@@ -795,35 +810,41 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Área arrastrable</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<value>Back Ease In-Out</value>
|
||||
<data name="SettingsPageEasingMode.Header" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<value>Bounce Ease In-Out</value>
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<value>Circular Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>Cubic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>Bounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<value>Elastic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>Circular</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<value>Exponential Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>Cubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>Elastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<value>Quartic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>Exponential</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<value>Quintic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<value>Sine Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>Quartic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>Quintic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>Sine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
<value>Lineal</value>
|
||||
@@ -888,12 +909,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Forzar siempre visible</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Forzar simulación palabra por palabra incluso si la letra actual no tiene información palabra por palabra</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Forzar efecto palabra por palabra</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>FPS de renderizado</value>
|
||||
</data>
|
||||
@@ -927,9 +942,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>La aplicación se reiniciará automáticamente después de una importación exitosa</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Priorizar la lectura de transliteración dentro de la letra; si no hay coincidencia, solicitar transliteración automática al servidor cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Fonética japonesa</value>
|
||||
</data>
|
||||
@@ -1140,6 +1152,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Atajo de cambio de estado de ventana de letras</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Estrategia de animación palabra por palabra</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Siempre</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Auto</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Nunca</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>Ajustar este valor afectará a la búsqueda secuencial y a los resultados de la búsqueda de mejor coincidencia, pero no afectará a los resultados de búsqueda en la interfaz de búsqueda manual de letras</value>
|
||||
</data>
|
||||
@@ -1245,6 +1269,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Atajo de Reproducir/Pausar</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Atajo de pista anterior</value>
|
||||
</data>
|
||||
@@ -1470,6 +1497,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Actividad por horas</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>Todos los tiempos</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>A medida</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>ex : http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Durée de l'accord</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>Chargement des paroles...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>Impossible d'afficher les pistes car le chemin n'existe pas</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Politique de confidentialité</value>
|
||||
</data>
|
||||
@@ -795,35 +810,38 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Zone déplaçable</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<value>Back Ease In-Out</value>
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<value>Bounce Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<value>Circular Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>Bounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>Cubic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>Circular</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<value>Elastic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>Cubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<value>Exponential Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>Elastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>Exponential</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<value>Quartic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<value>Quintic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>Quartic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<value>Sine Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>Quintic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>Sine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
<value>Linéaire</value>
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Forcer toujours au premier plan</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Forcer la simulation mot à mot même si les paroles n'ont pas d'infos mot à mot</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Forcer l'effet mot à mot</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>FPS de rendu</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>L'application redémarrera automatiquement après une importation réussie</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Prioriser la lecture de la translittération dans les paroles ; si aucune correspondance, demander une translittération automatique au serveur cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Phonétique japonaise</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Raccourci changement état fenêtre paroles</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Stratégie d'animation mot à mot</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Toujours</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Auto</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Jamais</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>L'ajustement de cette valeur affectera les résultats de la recherche séquentielle et de la meilleure correspondance, mais n'affectera pas les résultats de la recherche manuelle</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Raccourci Lecture/Pause</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Raccourci piste précédente</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Activité par heure</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>Tout le temps</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>Sur mesure</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>उदाहरण http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>समयांतराल</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>बोल लोड हो रहे हैं...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>ट्रैक देखने में असमर्थ क्योंकि पथ मौजूद नहीं है</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>गोपनीयता नीति</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>खींचने योग्य क्षेत्र</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>EaseInOutBack</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>EaseInOutBounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>EaseInOutCirc</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>EaseInOutCubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>EaseInOutElastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>EaseInOutExpo</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuad</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuart</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuint</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>EaseInOutSine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>हमेशा शीर्ष पर रखने के लिए बाध्य करें</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>शब्द-दर-शब्द प्रभाव का अनुकरण करने के लिए बाध्य करें, भले ही वर्तमान बोल में शब्द-दर-शब्द जानकारी न हो</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>शब्द-दर-शब्द प्रभाव सक्षम करने के लिए बाध्य करें</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>रेंडरिंग फ्रेम दर</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>सफल आयात के बाद, प्रोग्राम स्वचालित रूप से पुनरारंभ हो जाएगा</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>बोल के भीतर लिप्यंतरण पढ़ने को प्राथमिकता दी जाएगी, यदि कोई मेल नहीं मिलता है तो cutlet-docker सर्वर से मशीनी लिप्यंतरण का अनुरोध किया जाएगा</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>जापानी ध्वन्यात्मकता</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>बोल विंडो स्थिति स्विच शॉर्टकट</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>शब्द-दर-शब्द एनिमेशन रणनीति</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>हमेशा</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>स्वतः</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>कभी नहीं</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>इस मान को समायोजित करने से अनुक्रमिक खोज और सर्वोत्तम मिलान खोज परिणाम प्रभावित होंगे, लेकिन मैनुअल बोल खोज इंटरफ़ेस में खोज परिणाम प्रभावित नहीं होंगे</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>प्ले और पॉज़ शॉर्टकट</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>पिछला ट्रैक शॉर्टकट</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>घंटे के हिसाब से गतिविधि</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>अब तक के सारे</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>कस्टम</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Contoh: http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Durasi</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>Memuat lirik...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>Tidak dapat melihat trek karena jalur tidak ada</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Kebijakan Privasi</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Area yang Dapat Diseret</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>EaseInOutBack</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>EaseInOutBounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>EaseInOutCirc</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>EaseInOutCubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>EaseInOutElastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>EaseInOutExpo</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuad</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuart</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuint</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>EaseInOutSine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Paksa Selalu di Atas</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Paksa simulasi efek kata-demi-kata meskipun lirik saat ini tidak memiliki informasi kata-demi-kata</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Paksa Aktifkan Efek Kata-demi-Kata</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>Frame Rate Rendering</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>Setelah impor berhasil, program akan dimuat ulang secara otomatis</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Akan memprioritaskan membaca transliterasi di dalam lirik, jika tidak ada kecocokan maka akan meminta transliterasi mesin dari server cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Fonetik Bahasa Jepang</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Pintasan Pengalih Status Jendela Lirik</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Strategi Animasi Kata per Kata</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Selalu</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Otomatis</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Tidak pernah</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>Menyesuaikan nilai ini akan memengaruhi hasil pencarian berurutan dan pencarian kecocokan terbaik, tetapi tidak akan memengaruhi hasil pencarian di antarmuka pencarian manual lirik</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Pintasan Putar dan Jeda</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Pintasan Lagu Sebelumnya</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Aktivitas per Jam</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>Semua Waktu</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>Kustom</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>例: http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>持続時間</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>歌詞を読み込んでいます…</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>パスが存在しないため、曲を表示できません</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>個人情報保護方針</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>ドラッグ可能エリア</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>バックイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>バウンスイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>サーキュラーイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>キュービックイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>エラスティックイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>エキスポネンシャルイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>クアドラティックイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>クオートイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>クイントイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>サインイーズ イン アウト</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>常にトップに強制的に表示</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>現在の歌詞に文字単位の情報がない場合でも、文字単位の歌詞シミュレーションをします</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>文字単位の歌詞効果を強制する</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>描画 FPS</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>インポートが成功すると、アプリは自動的に再起動します</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>歌詞内の音訳を優先します。一致しない場合は、cutlet-docker サーバーからマシンの音訳を要求します</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>ローマ字ルビ</value>
|
||||
</data>
|
||||
@@ -1054,7 +1063,7 @@
|
||||
<value>カスタム</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsFontFamily.Header" xml:space="preserve">
|
||||
<value>フォントファミリー</value>
|
||||
<value>フォント</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsFontSize.Header" xml:space="preserve">
|
||||
<value>フォントサイズ</value>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>歌詞ウィンドウスイッチャーのショートカットキー</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>文字単位の効果方式</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>常に</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>自動</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>なし</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>この値を調整すると、順次検索とベストマッチ検索の結果に影響しますが、手動歌詞検索インターフェイスの検索結果には影響しません</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>再生/一時停止のショートカットキー</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>次のトラックのショートカットキー</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>アクティブ時間帯</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>全期間</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>カスタム</value>
|
||||
</data>
|
||||
@@ -1483,7 +1510,7 @@
|
||||
<value>最多アクティブ</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlRecording.Title" xml:space="preserve">
|
||||
<value>再生記録中...</value>
|
||||
<value>再生履歴記録中...</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlSources.Text" xml:space="preserve">
|
||||
<value>再生ソース</value>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>예: http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>기간</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>가사 불러오는 중...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>경로가 존재하지 않아 트랙을 볼 수 없습니다</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>개인정보 처리방침</value>
|
||||
</data>
|
||||
@@ -795,35 +810,38 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>드래그 가능 영역</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<value>Back Ease In-Out</value>
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<value>Bounce Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<value>Circular Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>Bounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>Cubic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>Circular</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<value>Elastic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>Cubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<value>Exponential Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>Elastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>Exponential</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<value>Quartic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<value>Quintic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>Quartic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<value>Sine Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>Quintic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>Sine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
<value>Linear (선형)</value>
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>항상 위에 표시 강제</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>현재 가사에 글자 단위 정보가 없더라도 글자 단위 시뮬레이션을 강제합니다</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>단어 단위 효과 강제 적용</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>렌더링 FPS</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>가져오기가 성공하면 프로그램이 자동으로 다시 시작됩니다</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>가사 내의 발음 표기를 우선적으로 읽습니다. 일치하는 항목이 없으면 cutlet-docker 서버에 기계 음역을 요청합니다</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>일본어 발음 표기</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>가사 창 상태 전환 단축키</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>단어별 애니메이션 전략</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>항상</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>자동</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>절대로</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>이 값을 조정하면 순차 검색 및 최적 일치 검색 결과에 영향을 미치지만 수동 가사 검색 인터페이스의 검색 결과에는 영향을 미치지 않습니다</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>재생 및 일시정지 단축키</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>이전 곡 단축키</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>시간별 활동</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>모든 시간</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>사용자 지정</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Contoh: http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Durasi</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>Memuatkan lirik...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>Tidak dapat melihat trek kerana laluan tidak wujud</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Dasar Privasi</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Kawasan Boleh Diseret</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>EaseInOutBack</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>EaseInOutBounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>EaseInOutCirc</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>EaseInOutCubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>EaseInOutElastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>EaseInOutExpo</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuad</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuart</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuint</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>EaseInOutSine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Paksa Sentiasa di Atas</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Paksa simulasi kesan perkataan-demi-perkataan walaupun lirik semasa tidak mempunyai maklumat perkataan-demi-perkataan</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Paksa Dayakan Kesan Perkataan-demi-Perkataan</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>Kadar Bingkai Penyajian (FPS)</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>Selepas import berjaya, program akan dimulakan semula secara automatik</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Akan mengutamakan pembacaan transliterasi dalam lirik, jika tiada padanan maka akan meminta transliterasi mesin daripada pelayan cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Fonetik Bahasa Jepun</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Pintasan Tukar Status Tetingkap Lirik</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Strategi Animasi Perkataan demi Perkataan</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Sentiasa</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Automatik</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Tak pernah</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>Melaraskan nilai ini akan mempengaruhi hasil carian jujukan dan carian padanan terbaik, tetapi tidak akan mempengaruhi hasil carian dalam antara muka carian lirik manual</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Pintasan Main dan Jeda</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Pintasan Lagu Sebelumnya</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Aktiviti mengikut Jam</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>Semua</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>Tersuai</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Exemplo: http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Duração</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>A carregar a letra...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>Não foi possível ver as faixas porque o caminho não existe</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Política de Privacidade</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Área de Arrastar</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>EaseInOutBack</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>EaseInOutBounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>EaseInOutCirc</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>EaseInOutCubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>EaseInOutElastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>EaseInOutExpo</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuad</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuart</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuint</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>EaseInOutSine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Forçar Sempre no Topo</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Forçar a simulação do efeito palavra por palavra, mesmo que a letra atual não tenha informações palavra por palavra</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Forçar Efeito Palavra por Palavra</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>Taxa de Fotogramas de Renderização</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>Após a importação bem-sucedida, o programa será reiniciado automaticamente</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Dará prioridade à leitura da transliteração dentro da letra; se não houver correspondência, solicitará transliteração automática ao servidor cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Fonética Japonesa</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Atalho de Alternância de Estado da Janela</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Estratégia de animação palavra a palavra</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Sempre</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Automóvel</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Nunca</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>Ajustar este valor afetará os resultados da pesquisa sequencial e de melhor correspondência, mas não afetará os resultados na interface de pesquisa manual de letras</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Atalho para Reproduzir e Pausar</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Atalho para Faixa Anterior</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Atividade por hora</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>Todo o tempo</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>Personalizado</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>например, http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Продолжительность</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>Загрузка текста...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>Невозможно просмотреть треки, так как путь не существует</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Политика конфиденциальности</value>
|
||||
</data>
|
||||
@@ -795,35 +810,38 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Перетаскиваемая область</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<value>Back Ease In-Out</value>
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<value>Bounce Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<value>Circular Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>Bounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>Cubic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>Circular</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<value>Elastic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>Cubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<value>Exponential Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>Elastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>Exponential</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<value>Quartic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>Quadratic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<value>Quintic Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>Quartic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<value>Sine Ease In-Out</value>
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>Quintic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>Sine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
<value>Linear</value>
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Принудительно поверх всех окон</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Принудительно имитировать пословный эффект, даже если текущий текст не имеет пословной информации</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Принудительно включить пословный эффект</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>FPS рендеринга</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>После успешного импорта приложение перезапустится автоматически</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Приоритет отдается чтению транслитерации внутри текста; если совпадений нет, запрашивается машинная транслитерация у сервера cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Японская фонетика</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Горячая клавиша переключения состояния окна</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Стратегия словесной анимации</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Всегда</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Авто</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Никогда</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>Настройка этого значения повлияет на результаты последовательного поиска и поиска лучшего совпадения, но не повлияет на результаты в интерфейсе ручного поиска</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Горячая клавиша Воспроизведение/Пауза</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Горячая клавиша предыдущего трека</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Активность по часам</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>Все время</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>Пользовательское</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>ตัวอย่าง http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>ระยะเวลา</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>กำลังโหลดเนื้อเพลง...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>ไม่สามารถดูแทร็กได้เนื่องจากเส้นทางไม่มีอยู่</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>นโยบายความเป็นส่วนตัว</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>พื้นที่ลาก</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>EaseInOutBack</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>EaseInOutBounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>EaseInOutCirc</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>EaseInOutCubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>EaseInOutElastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>EaseInOutExpo</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuad</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuart</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuint</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>EaseInOutSine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>บังคับให้อยู่บนสุดเสมอ</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>บังคับจำลองเอฟเฟกต์ทีละคำแม้ว่าเนื้อเพลงปัจจุบันจะไม่มีข้อมูลทีละคำ</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>บังคับเปิดใช้เอฟเฟกต์ทีละคำ</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>เฟรมเรตการเรนเดอร์</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>หลังจากนำเข้าสำเร็จ โปรแกรมจะรีสตาร์ทอัตโนมัติ</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>จะให้ความสำคัญกับการอ่านคำอ่านในเนื้อเพลงก่อน หากไม่พบจะขอคำอ่านจากเครื่องผ่านเซิร์ฟเวอร์ cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>คำอ่านภาษาญี่ปุ่น</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>ทางลัดสลับสถานะหน้าต่างเนื้อเพลง</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>กลยุทธ์การสร้างแอนิเมชันแบบคำต่อคำ</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>เสมอ</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>ออโต้</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>ไม่เคย</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>การปรับค่านี้จะมีผลกับผลการค้นหาแบบตามลำดับและแบบตรงกันที่สุด แต่จะไม่มีผลกับผลการค้นหาในหน้าค้นหาเนื้อเพลงด้วยตนเอง</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>ทางลัดเล่นและหยุดชั่วคราว</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>ทางลัดเพลงก่อนหน้า</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>กิจกรรมตามชั่วโมง</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>ตลอดเวลา</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>กำหนดเอง</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Ví dụ: http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Thời gian</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>Đang tải lời bài hát...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>Không thể xem các bài hát vì đường dẫn không tồn tại</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>Chính sách bảo mật</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>Vùng có thể kéo</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>EaseInOutBack</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>EaseInOutBounce</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>EaseInOutCirc</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>EaseInOutCubic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>EaseInOutElastic</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>EaseInOutExpo</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuad</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuart</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>EaseInOutQuint</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>EaseInOutSine</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>Buộc luôn ở trên cùng</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>Buộc mô phỏng hiệu ứng từng từ ngay cả khi lời bài hát hiện tại không có thông tin từng từ</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>Buộc bật hiệu ứng từng từ</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>Tốc độ khung hình kết xuất</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>Sau khi nhập thành công, chương trình sẽ tự động khởi động lại</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>Sẽ ưu tiên đọc phiên âm trong lời bài hát, nếu không khớp sẽ yêu cầu phiên âm máy từ máy chủ cutlet-docker</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>Phiên âm tiếng Nhật</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>Phím tắt chuyển trạng thái cửa sổ lời bài hát</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>Chiến lược hoạt hình từng từ</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>Luôn luôn</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>Tự động</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>Không bao giờ</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>Điều chỉnh giá trị này sẽ ảnh hưởng đến kết quả tìm kiếm tuần tự và khớp nhất, nhưng sẽ không ảnh hưởng đến kết quả tìm kiếm trong giao diện tìm kiếm lời bài hát thủ công</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>Phím tắt phát và tạm dừng</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>Phím tắt bài hát trước</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>Hoạt động theo giờ</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>Mọi thời đại</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>Tùy chỉnh</value>
|
||||
</data>
|
||||
|
||||
@@ -555,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>无法查看曲目,因为路径不存在</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value>安装插件</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value>未安装任何插件</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value>插件管理</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value>卸载插件</value>
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>隐私政策</value>
|
||||
</data>
|
||||
@@ -798,35 +810,47 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>可拖动区域</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<value>回弹缓入缓出</value>
|
||||
<data name="SettingsPageEasingMode.Header" xml:space="preserve">
|
||||
<value>缓动类型</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<value>弹跳缓入缓出</value>
|
||||
<data name="SettingsPageEasingModeIn.Content" xml:space="preserve">
|
||||
<value>缓入</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<value>圆形缓入缓出</value>
|
||||
<data name="SettingsPageEasingModeInOut.Content" xml:space="preserve">
|
||||
<value>缓出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<value>三次缓入缓出</value>
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value>缓入缓出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<value>弹性缓入缓出</value>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>回弹</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<value>指数缓入缓出</value>
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>弹跳</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<value>二次缓入缓出</value>
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>圆形</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<value>四次缓入缓出</value>
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>三次</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<value>五次缓入缓出</value>
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>弹性</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<value>正弦缓入缓出</value>
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>指数</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>二次</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>四次</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>五次</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>正弦</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
<value>线性</value>
|
||||
@@ -891,12 +915,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>强制置于顶层</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>即使当前歌词没有逐字信息,仍强制模拟逐字效果</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>强制启用逐字歌词效果</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>渲染帧率</value>
|
||||
</data>
|
||||
@@ -930,9 +948,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>导入成功后,该程序将自动重新启动</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>将优先读取歌词内音译,若无匹配则向 cutlet-docker 服务器请求机器音译</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>日语注音</value>
|
||||
</data>
|
||||
@@ -1143,6 +1158,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>歌词窗口状态切换快捷键</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>逐字动画策略</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>总是</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>自动</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>从不</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>调整此值将影响顺序搜索和最佳匹配搜索结果,但不会影响手动歌词搜索界面中的搜索结果</value>
|
||||
</data>
|
||||
@@ -1248,6 +1275,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>播放与暂停快捷键</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value>插件</value>
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>上一曲目快捷键</value>
|
||||
</data>
|
||||
@@ -1473,6 +1503,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>活跃时段</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>全部时间</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>自定义</value>
|
||||
</data>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>例如 http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>時間長度</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>載入歌詞中...</value>
|
||||
</data>
|
||||
@@ -552,6 +555,18 @@
|
||||
<data name="PlaylistViewFailed" xml:space="preserve">
|
||||
<value>無法檢視曲目,因為路徑不存在</value>
|
||||
</data>
|
||||
<data name="PluginManagerControlInstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlNoPluginsInstalled.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlTitle.Text" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PluginManagerControlUninstall.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="PrivacyPolicy.Content" xml:space="preserve">
|
||||
<value>隱私權政策</value>
|
||||
</data>
|
||||
@@ -795,34 +810,37 @@
|
||||
<data name="SettingsPageDragArea.Header" xml:space="preserve">
|
||||
<value>可拖曳區域</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBack.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingModeOut.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseBack.Content" xml:space="preserve">
|
||||
<value>回彈緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutBounce.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseBounce.Content" xml:space="preserve">
|
||||
<value>彈跳緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCirc.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCirc.Content" xml:space="preserve">
|
||||
<value>圓形緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutCubic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseCubic.Content" xml:space="preserve">
|
||||
<value>三次緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutElastic.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseElastic.Content" xml:space="preserve">
|
||||
<value>彈性緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutExpo.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseExpo.Content" xml:space="preserve">
|
||||
<value>指數緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuad.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuad.Content" xml:space="preserve">
|
||||
<value>二次緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuart.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuart.Content" xml:space="preserve">
|
||||
<value>四次緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutQuint.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseQuint.Content" xml:space="preserve">
|
||||
<value>五次緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeEaseInOutSine.Content" xml:space="preserve">
|
||||
<data name="SettingsPageEasingTypeEaseSine.Content" xml:space="preserve">
|
||||
<value>正弦緩入緩出</value>
|
||||
</data>
|
||||
<data name="SettingsPageEasingTypeLinear.Content" xml:space="preserve">
|
||||
@@ -888,12 +906,6 @@
|
||||
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
|
||||
<value>強制置於頂層</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Description" xml:space="preserve">
|
||||
<value>即使目前歌詞沒有逐字資訊,仍強制模擬逐字效果</value>
|
||||
</data>
|
||||
<data name="SettingsPageForceWordByWordEffect.Header" xml:space="preserve">
|
||||
<value>強制啟用逐字歌詞效果</value>
|
||||
</data>
|
||||
<data name="SettingsPageFPS.Header" xml:space="preserve">
|
||||
<value>渲染畫面播放速率</value>
|
||||
</data>
|
||||
@@ -927,9 +939,6 @@
|
||||
<data name="SettingsPageImportSettingsInfo.Content" xml:space="preserve">
|
||||
<value>匯入成功後,該程式將自動重新啟動</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Description" xml:space="preserve">
|
||||
<value>將優先讀取歌詞內音譯,若無符合則向 cutlet-docker 伺服器請求機器音譯</value>
|
||||
</data>
|
||||
<data name="SettingsPageJapanese.Header" xml:space="preserve">
|
||||
<value>日語注音</value>
|
||||
</data>
|
||||
@@ -1140,6 +1149,18 @@
|
||||
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
|
||||
<value>歌詞視窗狀態切換快速鍵</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
|
||||
<value>逐字動畫策略</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
|
||||
<value>永遠</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
|
||||
<value>自動</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
|
||||
<value>從不</value>
|
||||
</data>
|
||||
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
|
||||
<value>調整此值將影響順序搜尋和最佳符合搜尋結果,但不會影響手動歌詞搜尋介面中的搜尋結果</value>
|
||||
</data>
|
||||
@@ -1245,6 +1266,9 @@
|
||||
<data name="SettingsPagePlayOrPauseSongHotKey.Header" xml:space="preserve">
|
||||
<value>播放與暫停快速鍵</value>
|
||||
</data>
|
||||
<data name="SettingsPagePlugins.Content" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
|
||||
<value>上一曲目快速鍵</value>
|
||||
</data>
|
||||
@@ -1470,6 +1494,9 @@
|
||||
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
|
||||
<value>每小時的活動</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
|
||||
<value>所有時間</value>
|
||||
</data>
|
||||
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
|
||||
<value>自訂</value>
|
||||
</data>
|
||||
|
||||
@@ -2,27 +2,35 @@
|
||||
using BetterLyrics.WinUI3.Helper.BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.LyricsCacheService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class AboutControlViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly ILyricsCacheService _lyricsCacheService;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
public AboutControlViewModel(ISettingsService settingsService)
|
||||
public AboutControlViewModel(ISettingsService settingsService, ILyricsCacheService lyricsCacheService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_lyricsCacheService = lyricsCacheService;
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
}
|
||||
|
||||
@@ -47,18 +55,34 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[RelayCommand]
|
||||
private async Task ImportSettingsAsync()
|
||||
{
|
||||
var file = await PickerHelper.PickSingleFileAsync<SettingsWindow>([".json"]);
|
||||
var file = await PickerHelper.PickSingleFileAsync<SettingsWindow>([".zip"]);
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
var succeed = _settingsService.ImportSettings(file.Path);
|
||||
if (succeed)
|
||||
try
|
||||
{
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
|
||||
SqliteConnection.ClearAllPools();
|
||||
|
||||
string tempExtractPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempExtractPath);
|
||||
|
||||
using (var stream = await file.OpenStreamForReadAsync())
|
||||
{
|
||||
ZipFile.ExtractToDirectory(stream, tempExtractPath);
|
||||
}
|
||||
|
||||
DirectoryHelper.CopyDirectory(tempExtractPath, PathHelper.LocalFolder, true);
|
||||
|
||||
Directory.Delete(tempExtractPath, true);
|
||||
|
||||
WindowHook.RestartApp();
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
ToastHelper.ShowToast("ImportSettingsFailed", null, InfoBarSeverity.Error);
|
||||
ToastHelper.ShowToast("ImportSettingsFailed", ex.Message, InfoBarSeverity.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,31 +90,49 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[RelayCommand]
|
||||
private async Task ExportSettingsAsync()
|
||||
{
|
||||
var folder = await PickerHelper.PickSingleFolderAsync<SettingsWindow>();
|
||||
|
||||
if (folder != null)
|
||||
try
|
||||
{
|
||||
_settingsService.ExportSettings(folder.Path);
|
||||
var suggestedFileName = $"{Constants.App.AppName}_{_settingsService.AppSettings.Version}_{DateTime.Now:yyyyMMdd_HHmmss}";
|
||||
IDictionary<string, IList<string>> fileTypeChoices = new Dictionary<string, IList<string>>()
|
||||
{
|
||||
{ "Zip Archive", new List<string>() { ".zip" } }
|
||||
};
|
||||
|
||||
var destinationFile = await PickerHelper.PickSaveFileAsync<SettingsWindow>(fileTypeChoices, suggestedFileName);
|
||||
if (destinationFile == null) return;
|
||||
|
||||
string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempDir);
|
||||
|
||||
DirectoryHelper.CopyDirectory(PathHelper.LocalFolder, tempDir, true);
|
||||
|
||||
string tempZipPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".zip");
|
||||
|
||||
ZipFile.CreateFromDirectory(tempDir, tempZipPath);
|
||||
|
||||
using (var sourceStream = File.OpenRead(tempZipPath))
|
||||
using (var destStream = await destinationFile.OpenStreamForWriteAsync())
|
||||
{
|
||||
sourceStream.CopyTo(destStream);
|
||||
destStream.SetLength(sourceStream.Length);
|
||||
}
|
||||
|
||||
Directory.Delete(tempDir, true);
|
||||
File.Delete(tempZipPath);
|
||||
|
||||
ToastHelper.ShowToast("ExportSettingsSuccess", null, InfoBarSeverity.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ToastHelper.ShowToast("Error", ex.Message, InfoBarSeverity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task ExportPlayHistoryAsync()
|
||||
private async Task ClearCacheFilesAsync()
|
||||
{
|
||||
var folder = await PickerHelper.PickSingleFolderAsync<SettingsWindow>();
|
||||
await _lyricsCacheService.ClearCacheAsync();
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
var dest = Path.Combine(folder.Path, $"BetterLyrics_Play_History_Export_{DateTime.Now:yyyyMMdd_HHmmss}.db");
|
||||
await FileHelper.CopyFileAsync(PathHelper.PlayHistoryPath, dest);
|
||||
ToastHelper.ShowToast("ExportSettingsSuccess", null, InfoBarSeverity.Success);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ClearCacheFiles()
|
||||
{
|
||||
DirectoryHelper.DeleteAllFiles(PathHelper.LogDirectory);
|
||||
DirectoryHelper.DeleteAllFiles(PathHelper.LyricsCacheDirectory);
|
||||
DirectoryHelper.DeleteAllFiles(PathHelper.iTunesAlbumArtCacheDirectory);
|
||||
|
||||
@@ -39,9 +39,6 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[ObservableProperty]
|
||||
public partial bool IsLibreTranslateServerTesting { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsCutletDockerServerTesting { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsLXMusicServerTesting { get; set; } = false;
|
||||
|
||||
@@ -125,35 +122,6 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
});
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CutletDockerServerTest()
|
||||
{
|
||||
IsCutletDockerServerTesting = true;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string result = await _transliterationService.TransliterateText(
|
||||
"こんにちは", PhoneticHelper.RomanCode, new System.Threading.CancellationToken());
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
ToastHelper.ShowToast("SettingsPageServerTestSuccessInfo", null, InfoBarSeverity.Success);
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
ToastHelper.ShowToast("SettingsPageServerTestFailedInfo", null, InfoBarSeverity.Error);
|
||||
});
|
||||
}
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
IsCutletDockerServerTesting = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LastFMAuthAsync()
|
||||
{
|
||||
|
||||
@@ -186,6 +186,9 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
case StatsRange.ThisYear:
|
||||
startLocal = new DateTime(nowLocal.Year, 1, 1);
|
||||
break;
|
||||
case StatsRange.AllTime:
|
||||
startLocal = DateTime.MinValue;
|
||||
break;
|
||||
}
|
||||
|
||||
CustomStartDate = startLocal.Date;
|
||||
|
||||
@@ -56,6 +56,12 @@
|
||||
Glyph=}"
|
||||
Tag="Stats" />
|
||||
|
||||
<NavigationViewItem
|
||||
x:Uid="SettingsPagePlugins"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Tag="Plugins" />
|
||||
|
||||
<NavigationViewItem
|
||||
x:Uid="SettingsPageAbout"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
@@ -96,6 +102,11 @@
|
||||
<uc:StatsDashboardControl />
|
||||
</controls:Case>
|
||||
|
||||
<!-- Plugins -->
|
||||
<controls:Case Value="Plugins">
|
||||
<uc:PluginManagerControl />
|
||||
</controls:Case>
|
||||
|
||||
<!-- About -->
|
||||
<controls:Case Value="About">
|
||||
<uc:AboutControl />
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.13.36105.23
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "BetterLyrics.WinUI3 (Package)", "BetterLyrics.WinUI3\BetterLyrics.WinUI3 (Package)\BetterLyrics.WinUI3 (Package).wapproj", "{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterLyrics.WinUI3", "BetterLyrics.WinUI3\BetterLyrics.WinUI3\BetterLyrics.WinUI3.csproj", "{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impressionist", "Impressionist\Impressionist\Impressionist.csproj", "{A678BCA5-03DE-71E4-73C1-388B7550E4E3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorThief.WinUI3", "ColorThief.WinUI3\ColorThief.WinUI3.csproj", "{8F2FE667-2D91-428E-0630-05E6330F9625}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|x64.Build.0 = Debug|x64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|x86.Build.0 = Debug|x86
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|x64.ActiveCfg = Release|x64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|x64.Build.0 = Release|x64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|x64.Deploy.0 = Release|x64
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|x86.ActiveCfg = Release|x86
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|x86.Build.0 = Release|x86
|
||||
{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}.Release|x86.Deploy.0 = Release|x86
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Debug|x64.Build.0 = Debug|x64
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Debug|x86.Build.0 = Debug|x86
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Release|x64.ActiveCfg = Release|x64
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Release|x64.Build.0 = Release|x64
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Release|x86.ActiveCfg = Release|x86
|
||||
{6D26909A-9EE5-4D26-9E81-686BDE36A9D3}.Release|x86.Build.0 = Release|x86
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A678BCA5-03DE-71E4-73C1-388B7550E4E3}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0FD73F15-ED69-4DC2-9FD3-A4F03AF172A4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
24
BetterLyrics.slnx
Normal file
24
BetterLyrics.slnx
Normal file
@@ -0,0 +1,24 @@
|
||||
<Solution>
|
||||
<Configurations>
|
||||
<Platform Name="ARM64" />
|
||||
<Platform Name="x64" />
|
||||
<Platform Name="x86" />
|
||||
</Configurations>
|
||||
<Folder Name="/Plugins/">
|
||||
<Project Path="Plugins/BetterLyrics.Plugins.AI.Local/BetterLyrics.Plugins.AI.Local.csproj" />
|
||||
<Project Path="Plugins/BetterLyrics.Plugins.Transliteration.Romaji/BetterLyrics.Plugins.Transliteration.Romaji.csproj" />
|
||||
<Project Path="Plugins/BetterLyrics.Plugins.Translation.LocalAI/BetterLyrics.Plugins.Translation.LocalAI.csproj" Id="17f9f675-6745-44cb-b8b4-604a2ae90dd1" />
|
||||
</Folder>
|
||||
<Project Path="BetterLyrics.Core/BetterLyrics.Core.csproj" />
|
||||
<Project Path="BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/BetterLyrics.WinUI3 (Package).wapproj" Type="c7167f0d-bc9f-4e6e-afe1-012c56b48db5">
|
||||
<Deploy />
|
||||
</Project>
|
||||
<Project Path="BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
<Platform Solution="*|x86" Project="x86" />
|
||||
</Project>
|
||||
<Project Path="ColorThief.WinUI3/ColorThief.WinUI3.csproj" />
|
||||
<Project Path="Impressionist/Impressionist/Impressionist.csproj" />
|
||||
<Project Path="PluginAnalyzer/PluginAnalyzer.csproj" Id="8ee58bf7-807d-486c-8d7d-c00bb9ec2b81" />
|
||||
</Solution>
|
||||
@@ -4,11 +4,6 @@
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>ColorThief.WinUI3</RootNamespace>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
14
PluginAnalyzer/PluginAnalyzer.csproj
Normal file
14
PluginAnalyzer/PluginAnalyzer.csproj
Normal file
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.6" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
254
PluginAnalyzer/Program.cs
Normal file
254
PluginAnalyzer/Program.cs
Normal file
@@ -0,0 +1,254 @@
|
||||
using Mono.Cecil;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Diagnostics;
|
||||
|
||||
class Program
|
||||
{
|
||||
// Global sets
|
||||
static HashSet<string> _mergedAssemblies = new HashSet<string>();
|
||||
static HashSet<string> _mergedSystemTypes = new HashSet<string>();
|
||||
static string _currentScanDirectory = "";
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// =========================================================
|
||||
// 🚀 MODE 1: CLI Automation Mode (被 VS 编译调用时)
|
||||
// =========================================================
|
||||
if (args.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
string scanPath = args[0].Replace("\"", "").Trim();
|
||||
string targetNs = args.Length > 1 ? args[1] : "BetterLyrics.WinUI3";
|
||||
string prefix = args.Length > 2 ? args[2] : "Plugin";
|
||||
|
||||
// 读取第4个参数作为输出目录,如果没传,就默认用扫描目录
|
||||
string outputDir = args.Length > 3 ? args[3].Replace("\"", "").Trim() : scanPath;
|
||||
|
||||
Console.WriteLine($"[Analyzer] Scanning: {scanPath}");
|
||||
Console.WriteLine($"[Analyzer] Output to: {outputDir}");
|
||||
|
||||
RunBatch(scanPath, targetNs, prefix, outputDir, silent: true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[Analyzer] Error: {ex.Message}");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 🚀 MODE 2: Interactive Mode (手动双击运行)
|
||||
// =========================================================
|
||||
Console.WriteLine("==================================================");
|
||||
Console.WriteLine(" Plugin Dependency Analyzer (Auto-CLI Ready) ");
|
||||
Console.WriteLine("==================================================");
|
||||
|
||||
while (true)
|
||||
{
|
||||
_mergedAssemblies.Clear();
|
||||
_mergedSystemTypes.Clear();
|
||||
|
||||
Console.WriteLine("\n1. Enter Plugin FOLDER path (or 'exit'):");
|
||||
Console.Write("> ");
|
||||
string input = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(input)) continue;
|
||||
if (input.Trim().ToLower() == "exit") break;
|
||||
|
||||
string path = input.Replace("\"", "").Trim();
|
||||
if (!Directory.Exists(path)) { Console.WriteLine("[ERROR] Folder not found."); continue; }
|
||||
|
||||
Console.WriteLine("2. Enter Namespace (Default: BetterLyrics.WinUI3):");
|
||||
Console.Write("> ");
|
||||
string ns = Console.ReadLine().Trim();
|
||||
if (string.IsNullOrWhiteSpace(ns)) ns = "BetterLyrics.WinUI3";
|
||||
|
||||
string prefix = new DirectoryInfo(path).Name;
|
||||
Console.WriteLine($"3. Enter prefix (Default: {prefix}):");
|
||||
Console.Write("> ");
|
||||
string p = Console.ReadLine().Trim();
|
||||
if (!string.IsNullOrWhiteSpace(p)) prefix = p;
|
||||
|
||||
// 👇👇👇【修复点在这里】👇👇👇
|
||||
// 交互模式下,我们默认把文件生成在 exe 旁边的 AnalyzerOutput 文件夹里
|
||||
string interactiveOutputDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AnalyzerOutput");
|
||||
|
||||
// 传入 interactiveOutputDir 以匹配新的方法签名
|
||||
RunBatch(path, ns, prefix, interactiveOutputDir, silent: false);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 下面的 RunBatch 和 GenerateFiles 签名已更新支持 outputDir
|
||||
// ---------------------------------------------------------
|
||||
|
||||
static void RunBatch(string scanPath, string ns, string prefix, string outputDir, bool silent)
|
||||
{
|
||||
_currentScanDirectory = scanPath;
|
||||
_mergedAssemblies.Clear();
|
||||
_mergedSystemTypes.Clear();
|
||||
|
||||
ProcessDirectory(scanPath);
|
||||
|
||||
// 传递 outputDir
|
||||
GenerateFiles(prefix, ns, outputDir, silent);
|
||||
}
|
||||
|
||||
static void GenerateFiles(string prefix, string rootNamespace, string outputDir, bool silent)
|
||||
{
|
||||
Directory.CreateDirectory(outputDir);
|
||||
|
||||
string xmlFileName = $"{prefix}_TrimmerRoots.xml";
|
||||
string csFileName = $"{prefix}_TrimmingConfig.cs";
|
||||
|
||||
// 👇 关键修改:区分 Assembly 名和 Namespace 名
|
||||
string assemblyName = rootNamespace; // DLL 名字 (例如 BetterLyrics.WinUI3)
|
||||
string codeNamespace = $"{rootNamespace}.PluginConfigs"; // C# 命名空间 (例如 BetterLyrics.WinUI3.PluginConfigs)
|
||||
|
||||
// 类名和全名
|
||||
string configClassName = $"{prefix.Replace(".", "_").Replace(" ", "_")}_Config";
|
||||
string fullConfigClassName = $"{codeNamespace}.{configClassName}";
|
||||
|
||||
// 路径变量
|
||||
string xmlPath = Path.Combine(outputDir, xmlFileName);
|
||||
string csPath = Path.Combine(outputDir, csFileName);
|
||||
|
||||
// ==========================================
|
||||
// 1. Generate XML
|
||||
// ==========================================
|
||||
var xmlBuilder = new StringBuilder();
|
||||
xmlBuilder.AppendLine("");
|
||||
xmlBuilder.AppendLine("<linker>");
|
||||
|
||||
// A. 保护插件依赖
|
||||
if (_mergedAssemblies.Count > 0)
|
||||
{
|
||||
foreach (var asm in _mergedAssemblies.OrderBy(n => n))
|
||||
xmlBuilder.AppendLine($" <assembly fullname=\"{asm}\" preserve=\"all\" />");
|
||||
}
|
||||
|
||||
// B. 保护生成的 Config 类
|
||||
// ⚠️ 注意:assembly fullname 必须是 rootNamespace (DLL名),而不是 codeNamespace
|
||||
xmlBuilder.AppendLine($" <assembly fullname=\"{assemblyName}\">");
|
||||
xmlBuilder.AppendLine($" <type fullname=\"{fullConfigClassName}\" preserve=\"all\" />");
|
||||
xmlBuilder.AppendLine($" </assembly>");
|
||||
|
||||
xmlBuilder.AppendLine("</linker>");
|
||||
|
||||
// ==========================================
|
||||
// 2. Generate C#
|
||||
// ==========================================
|
||||
var csBuilder = new StringBuilder();
|
||||
csBuilder.AppendLine("// Auto-Generated by PluginAnalyzer");
|
||||
csBuilder.AppendLine("using System.Diagnostics.CodeAnalysis;");
|
||||
csBuilder.AppendLine("using System.Runtime.CompilerServices;");
|
||||
csBuilder.AppendLine("");
|
||||
|
||||
// 👇 这里使用带后缀的命名空间
|
||||
csBuilder.AppendLine($"namespace {codeNamespace};");
|
||||
|
||||
csBuilder.AppendLine($"internal static class {configClassName}");
|
||||
csBuilder.AppendLine("{");
|
||||
|
||||
foreach (var type in _mergedSystemTypes.OrderBy(n => n))
|
||||
{
|
||||
csBuilder.AppendLine($" [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof({type}))]");
|
||||
}
|
||||
|
||||
csBuilder.AppendLine(" [ModuleInitializer]");
|
||||
csBuilder.AppendLine(" internal static void Initialize()");
|
||||
csBuilder.AppendLine(" {");
|
||||
csBuilder.AppendLine(" // This method runs automatically on startup.");
|
||||
csBuilder.AppendLine(" }");
|
||||
csBuilder.AppendLine("}");
|
||||
|
||||
// ==========================================
|
||||
// 3. Write & Notify
|
||||
// ==========================================
|
||||
File.WriteAllText(xmlPath, xmlBuilder.ToString());
|
||||
File.WriteAllText(csPath, csBuilder.ToString());
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
Console.WriteLine($"[Analyzer] Generated: {xmlFileName}");
|
||||
Process.Start("explorer.exe", outputDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"[Analyzer] Created: {xmlPath}");
|
||||
Console.WriteLine($"[Analyzer] Created: {csPath}");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Helpers (逻辑保持不变)
|
||||
// ---------------------------------------------------------
|
||||
|
||||
static void ProcessDirectory(string folderPath)
|
||||
{
|
||||
var files = Directory.GetFiles(folderPath, "*.dll");
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (!IsHostOrSystemBinary(Path.GetFileName(file))) AnalyzeDll(file);
|
||||
}
|
||||
}
|
||||
|
||||
static void AnalyzeDll(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var resolver = new DefaultAssemblyResolver();
|
||||
resolver.AddSearchDirectory(Path.GetDirectoryName(path));
|
||||
using var assembly = AssemblyDefinition.ReadAssembly(path, new ReaderParameters { AssemblyResolver = resolver });
|
||||
|
||||
foreach (var typeRef in assembly.MainModule.GetTypeReferences())
|
||||
{
|
||||
if (typeRef.Scope is AssemblyNameReference asmRef && !IsIgnoredDependency(asmRef.Name) && !IsLocalDll(asmRef.Name))
|
||||
_mergedAssemblies.Add(asmRef.Name);
|
||||
|
||||
if (typeRef.FullName.StartsWith("System.") || typeRef.FullName.StartsWith("Microsoft.Win32"))
|
||||
_mergedSystemTypes.Add(FormatTypeName(typeRef));
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
static bool IsLocalDll(string asmName) => File.Exists(Path.Combine(_currentScanDirectory, asmName + ".dll"));
|
||||
|
||||
static bool IsHostOrSystemBinary(string fileName)
|
||||
{
|
||||
fileName = fileName.ToLower();
|
||||
return fileName.StartsWith("betterlyrics.") && !fileName.Contains("plugin") ||
|
||||
fileName.StartsWith("microsoft.windows") || fileName.StartsWith("winrt.") || fileName.StartsWith("system.");
|
||||
}
|
||||
|
||||
static bool IsIgnoredDependency(string asmName) => asmName.Contains("BetterLyrics") || asmName.Contains("WindowsAppSDK") || asmName.Contains("Microsoft.Windows") || asmName == "netstandard" || asmName == "mscorlib";
|
||||
|
||||
static string FormatTypeName(TypeReference type)
|
||||
{
|
||||
string name = type.FullName;
|
||||
|
||||
// 1. 处理嵌套类型 (Cecil 用 '/',C# 用 '.')
|
||||
name = name.Replace("/", ".");
|
||||
|
||||
// 2. 处理泛型 (核心修复:根据参数数量动态生成逗号)
|
||||
// List`1 -> List<>
|
||||
// Dictionary`2 -> Dictionary<,>
|
||||
// Tuple`3 -> Tuple<,,>
|
||||
if (name.Contains("`"))
|
||||
{
|
||||
name = Regex.Replace(name, @"`(\d+)", match =>
|
||||
{
|
||||
int argsCount = int.Parse(match.Groups[1].Value);
|
||||
// 逗号数量 = 参数数量 - 1
|
||||
// 比如 1个参数=0个逗号 (<>)
|
||||
// 比如 2个参数=1个逗号 (<,>)
|
||||
return "<" + new string(',', Math.Max(0, argsCount - 1)) + ">";
|
||||
});
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="AutoExcludeSharedAssemblies" AfterTargets="ResolveAssemblyReferences">
|
||||
<PropertyGroup>
|
||||
<HostOutputDir>..\..\BetterLyrics.WinUI3\BetterLyrics.WinUI3\bin\x64\$(Configuration)\$(TargetFramework)\</HostOutputDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<Message Text="[Debug] Searching for Host Assemblies in: $(HostOutputDir)" Importance="High" />
|
||||
|
||||
<ItemGroup>
|
||||
<FilesToCopy Include="@(ReferenceCopyLocalPaths)" />
|
||||
<SharedFiles Include="@(FilesToCopy)" Condition="Exists('$(HostOutputDir)%(Filename)%(Extension)')" />
|
||||
<ReferenceCopyLocalPaths Remove="@(SharedFiles)" />
|
||||
</ItemGroup>
|
||||
|
||||
<Message Text="[Smart Trim] Excluded shared assemblies:%0a@(SharedFiles->' -> %(Filename)%(Extension)', '%0a')" Importance="High" Condition="'@(SharedFiles)' != ''" />
|
||||
</Target>
|
||||
|
||||
<Target Name="RunPluginAnalyzer" AfterTargets="Build">
|
||||
<PropertyGroup>
|
||||
<AnalyzerPath>..\..\PluginAnalyzer\bin\Debug\net10.0\PluginAnalyzer.exe</AnalyzerPath>
|
||||
<ScanDir>$(TargetDir)</ScanDir>
|
||||
<Ns>BetterLyrics.WinUI3</Ns>
|
||||
<Prefix>$(ProjectName)</Prefix>
|
||||
|
||||
<OutputDir>..\..\BetterLyrics.WinUI3\BetterLyrics.WinUI3\PluginConfigs\</OutputDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<Message Text="[Analyzer] Delivering configs to Main App..." Importance="High" />
|
||||
<Exec Command=""$(AnalyzerPath)" "$(ScanDir)\" "$(Ns)" "$(Prefix)" "$(OutputDir)\"" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LLamaSharp" Version="0.25.0" />
|
||||
<PackageReference Include="LLamaSharp.Backend.Cpu" Version="0.25.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\BetterLyrics.Core\BetterLyrics.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
112
Plugins/BetterLyrics.Plugins.AI.Local/Plugin.cs
Normal file
112
Plugins/BetterLyrics.Plugins.AI.Local/Plugin.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using BetterLyrics.Core.Interfaces.Services;
|
||||
using LLama;
|
||||
using LLama.Common;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Plugins.AI.Local
|
||||
{
|
||||
public class Plugin : IPlugin, IAIService
|
||||
{
|
||||
private LLamaWeights? _model;
|
||||
private ModelParams? _parameters;
|
||||
private string? _modelPath;
|
||||
|
||||
public string Id => "jayfunc.ai";
|
||||
public string Name => "Local AI Service";
|
||||
public string Description => "";
|
||||
public string Author => "jayfunc";
|
||||
public string Version => "1.0.0.0";
|
||||
public DateTime LastUpdated => new DateTime(2026, 1, 12);
|
||||
|
||||
public async Task<string> ChatAsync(string systemPrompt, string userPrompt)
|
||||
{
|
||||
if (_model == null) return "错误:本地模型未加载。请检查插件目录下是否有 .gguf 文件。";
|
||||
|
||||
return await Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_parameters == null)
|
||||
{
|
||||
return "错误:模型参数未正确配置。";
|
||||
}
|
||||
|
||||
// 1. 创建上下文
|
||||
using var context = _model.CreateContext(_parameters);
|
||||
|
||||
// 2. 创建聊天执行器 (InteractiveExecutor 适合聊天)
|
||||
var executor = new InteractiveExecutor(context);
|
||||
|
||||
// 3. 创建会话
|
||||
var session = new ChatSession(executor);
|
||||
|
||||
// 4. 设置系统提示词 (System Prompt)
|
||||
// LLamaSharp 的 ChatSession 处理 System Prompt 稍微有点技巧,通常直接作为第一次输入的一部分或者使用特定的 Prompt 模板
|
||||
// 这里做一个简单的处理:
|
||||
|
||||
var fullPrompt = $"{systemPrompt}\n\n用户: {userPrompt}\n助手:";
|
||||
|
||||
// 5. 运行推理
|
||||
StringBuilder responseBuilder = new StringBuilder();
|
||||
|
||||
// Transform: 将输出流转换为文本
|
||||
// InferenceParams: 设置采样参数 (Temperature 等)
|
||||
var inferenceParams = new InferenceParams()
|
||||
{
|
||||
//Temperature = 0.6f,
|
||||
AntiPrompts = new List<string> { "用户:" } // 防止模型自问自答
|
||||
};
|
||||
|
||||
await foreach (var text in session.ChatAsync(new ChatHistory.Message(AuthorRole.User, userPrompt), inferenceParams: inferenceParams))
|
||||
{
|
||||
responseBuilder.Append(text);
|
||||
}
|
||||
|
||||
return responseBuilder.ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"推理出错: {ex.Message}";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void OnLoad(IPluginContext context)
|
||||
{
|
||||
_modelPath = Directory.GetFiles(context.PluginDirectory, "*.gguf").FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrEmpty(_modelPath))
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("【LocalAI】未找到 .gguf 模型文件,请下载模型放入插件目录!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 2. 配置模型参数
|
||||
_parameters = new ModelParams(_modelPath)
|
||||
{
|
||||
ContextSize = 2048, // 上下文长度,根据内存调整
|
||||
GpuLayerCount = 0, // 0 = 纯CPU,设为 20+ 可以通过显卡加速(需安装 Cuda 后端)
|
||||
Threads = 4 // CPU 线程数
|
||||
};
|
||||
|
||||
// 3. 加载模型 (这一步比较耗时,实际开发建议放在后台线程或第一次调用时懒加载)
|
||||
_model = LLamaWeights.LoadFromFile(_parameters);
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"【LocalAI】模型加载成功: {_modelPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"【LocalAI】模型加载失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnUnload()
|
||||
{
|
||||
_model?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\BetterLyrics.Core\BetterLyrics.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
35
Plugins/BetterLyrics.Plugins.Translation.LocalAI/Plugin.cs
Normal file
35
Plugins/BetterLyrics.Plugins.Translation.LocalAI/Plugin.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using BetterLyrics.Core.Interfaces.Features;
|
||||
|
||||
namespace BetterLyrics.Plugins.Translation.LocalAI
|
||||
{
|
||||
public class Plugin : IPlugin, ILyricsTranslator
|
||||
{
|
||||
public string Id => throw new NotImplementedException();
|
||||
|
||||
public string Name => throw new NotImplementedException();
|
||||
|
||||
public string Description => throw new NotImplementedException();
|
||||
|
||||
public string Author => throw new NotImplementedException();
|
||||
|
||||
public string Version => throw new NotImplementedException();
|
||||
|
||||
public DateTime LastUpdated => throw new NotImplementedException();
|
||||
|
||||
public Task<string?> GetTranslationAsync(string text, string targetLangCode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnLoad(IPluginContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnUnload()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user