Compare commits
30 Commits
85f67c2ec6
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
1
.gitignore
vendored
@@ -408,3 +408,4 @@ 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
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<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>
|
||||
|
||||
@@ -5,12 +5,8 @@ using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Interfaces
|
||||
{
|
||||
public interface ILyricsProvider
|
||||
public interface ILyricsSearchPlugin : IPlugin
|
||||
{
|
||||
string Id { get; }
|
||||
string Name { get; }
|
||||
string Author { get; }
|
||||
|
||||
Task<LyricsSearchResult> GetLyricsAsync(string title, string artist, string album, double duration);
|
||||
}
|
||||
}
|
||||
11
BetterLyrics.Core/Interfaces/ILyricsTransliterationPlugin.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.Core.Interfaces
|
||||
{
|
||||
public interface ILyricsTransliterationPlugin : IPlugin
|
||||
{
|
||||
Task<string?> GetTransliterationAsync(string text, string targetLangCode);
|
||||
}
|
||||
}
|
||||
17
BetterLyrics.Core/Interfaces/IPlugin.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
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; }
|
||||
|
||||
void Initialize();
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using BetterLyrics.Core.Models;
|
||||
|
||||
namespace BetterLyrics.Plugins.Demo
|
||||
{
|
||||
public class DemoLyricsProvider : ILyricsProvider
|
||||
{
|
||||
public string Id => "f7acc86b-6e3d-42c3-a9a9-8c05c5339412";
|
||||
public string Name => "Demo Plugin";
|
||||
public string Author => "jayfunc";
|
||||
|
||||
public async Task<LyricsSearchResult> GetLyricsAsync(string title, string artist, string album, double duration)
|
||||
{
|
||||
await Task.Delay(300);
|
||||
|
||||
string searchedTitle = "Demo Song";
|
||||
string searchedArtist = "Demo Artist";
|
||||
string searchedAlbum = "Demo Album";
|
||||
double searchedDuration = 25.0;
|
||||
|
||||
string searchedRaw =
|
||||
$"[00:00.00]Welcome to use Demo Plugin\n" +
|
||||
$"[00:05.00]Playing: {title} now\n" +
|
||||
$"[00:10.00]Artist: {artist}\n" +
|
||||
$"[00:15.00]Album: {album}\n" +
|
||||
$"[00:20.00]Duration: {duration}\n" +
|
||||
$"[00:25.00]This is a test lyrics source...";
|
||||
|
||||
string searchedTranslation =
|
||||
$"[00:00.00]欢迎使用演示插件\n" +
|
||||
$"[00:05.00]当前正在播放:{title}\n" +
|
||||
$"[00:10.00]歌手:{artist}\n" +
|
||||
$"[00:15.00]专辑:{album}\n" +
|
||||
$"[00:20.00]时长:{duration}\n" +
|
||||
$"[00:25.00]这是一个测试歌词源...";
|
||||
|
||||
string searchedTransliteration =
|
||||
$"[00:00.00]ˈwɛlkəm tuː juːz ˈdɛmoʊ ˈplʌgɪn\n" +
|
||||
$"[00:05.00]ˈpleɪɪŋ: {title} naʊ\n" +
|
||||
$"[00:10.00]ˈɑːrtɪst: {artist}\n" +
|
||||
$"[00:15.00]ˈælbəm: {album}\n" +
|
||||
$"[00:20.00]dʊˈreɪʃən: {duration}\n" +
|
||||
$"[00:25.00]ðɪs ɪz ə tɛst ˈlɪrɪks sɔːrs...";
|
||||
|
||||
string searchedReference = "https://path.to.lyrics/if.the.lyrics.was.originally.fetched.from.web";
|
||||
|
||||
return new LyricsSearchResult(
|
||||
searchedTitle,
|
||||
searchedArtist,
|
||||
searchedAlbum,
|
||||
searchedDuration,
|
||||
searchedRaw,
|
||||
searchedTranslation,
|
||||
searchedTransliteration,
|
||||
searchedReference);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
135
BetterLyrics.Plugins.Romaji/BetterLyrics.Plugins.Romaji.csproj
Normal file
@@ -0,0 +1,135 @@
|
||||
<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>
|
||||
<Content Include="customizeDict.txt">
|
||||
<PackagePath>contentFiles\any\any\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\AUTHORS">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\BSD">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\ChangeLog">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\char.bin">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\COPYING">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\dicrc">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\GPL">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\INSTALL">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\LGPL">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\matrix.bin">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\sys.dic">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\unidic-mecab.pdf">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
<Content Include="unidic\unk.dic">
|
||||
<PackagePath>contentFiles\any\any\unidic\</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
<Pack>true</Pack>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BetterLyrics.Core\BetterLyrics.Core.csproj" />
|
||||
<ProjectReference Include="..\RomajiConverter.Core\RomajiConverter.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<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>
|
||||
|
||||
</Project>
|
||||
6
BetterLyrics.Plugins.Romaji/README.MD
Normal file
@@ -0,0 +1,6 @@
|
||||
## Before you build...
|
||||
|
||||
- Download `unidic-mecab-2.1.2_bin.zip` from https://clrd.ninjal.ac.jp/unidic_archive/cwj/2.1.2/
|
||||
- Unzip it and copy the contents of the `dic` folder to `BetterLyrics.Plugins.Romaji\unidic`
|
||||
|
||||
See the original info at https://github.com/xyh20180101/RomajiConverter.WinUI/blob/main/doc/README-dev-en.md
|
||||
34
BetterLyrics.Plugins.Romaji/RomajiPlugin.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using RomajiConverter.Core.Helpers;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BetterLyrics.Plugins.Romaji
|
||||
{
|
||||
public class RomajiPlugin : ILyricsTransliterationPlugin
|
||||
{
|
||||
public string Id => "jayfunc.romaji";
|
||||
|
||||
public string Name => "Romaji";
|
||||
|
||||
public string Description => "Convert Japanese lyrics to Romaji transliteration.";
|
||||
|
||||
public string Author => "jayfunc";
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
string? pluginPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
RomajiHelper.Init(pluginPath);
|
||||
}
|
||||
|
||||
public Task<string?> GetTransliterationAsync(string text, string targetLangCode)
|
||||
{
|
||||
string? result = null;
|
||||
if (targetLangCode == "ja-latin")
|
||||
{
|
||||
var lines = text.Split("\n");
|
||||
result = string.Join("\n", lines.Select(p => string.Join(" ", RomajiHelper.ToRomaji(p).FirstOrDefault()?.Units.Select(q => q.Romaji) ?? [""])));
|
||||
}
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
BetterLyrics.Plugins.Romaji/customizeDict.txt
Normal file
@@ -0,0 +1 @@
|
||||
私 わたし
|
||||
@@ -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.256.0" />
|
||||
Version="1.2.260.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -23,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;
|
||||
@@ -155,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>();
|
||||
|
||||
|
||||
@@ -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" />
|
||||
@@ -97,13 +98,13 @@
|
||||
<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>
|
||||
<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" />
|
||||
@@ -122,12 +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="..\..\BetterLyrics.Core\BetterLyrics.Core.csproj" />
|
||||
<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">
|
||||
@@ -139,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">
|
||||
@@ -397,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>
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
);
|
||||
private readonly ValueTransition<double> _immersiveBgOpacityTransition = new(
|
||||
initialValue: 1f,
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: 0.3f
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor1Transition = new(
|
||||
@@ -87,13 +88,13 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
);
|
||||
private readonly ValueTransition<double> _canvasYScrollTransition = new(
|
||||
initialValue: 0f,
|
||||
defaultTotalDuration: 0.3f,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: 0.3f
|
||||
);
|
||||
private readonly ValueTransition<double> _mouseYScrollTransition = new(
|
||||
initialValue: 0f,
|
||||
defaultTotalDuration: 0.3f,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: 0.3f
|
||||
);
|
||||
|
||||
private TimeSpan _songPositionWithOffset;
|
||||
@@ -492,7 +493,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
else
|
||||
{
|
||||
_canvasYScrollTransition.SetDurationMs(lyricsEffect.LyricsScrollDuration);
|
||||
_canvasYScrollTransition.SetEasingType(lyricsEffect.LyricsScrollEasingType);
|
||||
_canvasYScrollTransition.SetInterpolator(EasingHelper.GetInterpolatorByEasingType<double>(lyricsEffect.LyricsScrollEasingType, lyricsEffect.LyricsScrollEasingMode));
|
||||
_canvasYScrollTransition.Start(_canvasTargetScrollOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,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"
|
||||
|
||||
@@ -424,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static BetterLyrics.WinUI3.Helper.EasingHelper;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
@@ -21,7 +22,6 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
private double _configuredDelaySeconds; // 配置的延迟时长
|
||||
|
||||
// 动画状态
|
||||
private Enums.EasingType? _easingType;
|
||||
private Func<T, T, double, T> _interpolator;
|
||||
private bool _isTransitioning;
|
||||
private double _progress; // 当前段的进度 (0.0 ~ 1.0)
|
||||
@@ -30,10 +30,11 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
public T Value => _currentValue;
|
||||
public bool IsTransitioning => _isTransitioning;
|
||||
public T TargetValue => _targetValue; // 获取当前段的目标值
|
||||
public Enums.EasingType? EasingType => _easingType;
|
||||
public double DurationSeconds => _totalDurationForAutoSplit;
|
||||
|
||||
public ValueTransition(T initialValue, double defaultTotalDuration = 0.3, EasingType? defaultEasingType = null, Func<T, T, double, T>? interpolator = null)
|
||||
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;
|
||||
@@ -43,15 +44,6 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
if (interpolator != null)
|
||||
{
|
||||
_interpolator = interpolator;
|
||||
_easingType = null;
|
||||
}
|
||||
else if (defaultEasingType != null)
|
||||
{
|
||||
SetEasingType(defaultEasingType);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEasingType(Enums.EasingType.EaseInOutQuad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,10 +66,9 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
_configuredDelaySeconds = seconds;
|
||||
}
|
||||
|
||||
public void SetEasingType(Enums.EasingType? easingType)
|
||||
public void SetInterpolator(Func<T, T, double, T> interpolator)
|
||||
{
|
||||
_easingType = easingType;
|
||||
_interpolator = GetInterpolatorByEasingType(easingType);
|
||||
_interpolator = interpolator;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -235,7 +226,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
|
||||
#region Interpolators
|
||||
|
||||
private Func<T, T, double, T> GetInterpolatorByEasingType(Enums.EasingType? type)
|
||||
public static Func<T, T, double, T> GetInterpolatorByEasingType(EasingType? type, EaseMode easingMode)
|
||||
{
|
||||
if (typeof(T) == typeof(double))
|
||||
{
|
||||
@@ -243,25 +234,24 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
double s = (double)(object)start;
|
||||
double e = (double)(object)end;
|
||||
double t = progress;
|
||||
|
||||
// 使用 EasingHelper (假设您的项目中已有此辅助类)
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
line.ColorTransition.SetDelay(yScrollDelay);
|
||||
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.Start(
|
||||
@@ -185,7 +185,7 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
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
|
||||
|
||||
@@ -47,15 +47,10 @@ namespace BetterLyrics.WinUI3.Models
|
||||
|
||||
[NotMapped][JsonIgnore] public LyricsSearchProvider? ProviderIfFound => IsFound ? Provider : null;
|
||||
|
||||
[MaxLength(128)]
|
||||
public string? PluginId { get; set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new LyricsCacheItem()
|
||||
{
|
||||
PluginId = this.PluginId,
|
||||
|
||||
Provider = this.Provider,
|
||||
TranslationProvider = this.TranslationProvider,
|
||||
TransliterationProvider = this.TransliterationProvider,
|
||||
|
||||
@@ -20,18 +20,18 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
ScaleTransition = new(
|
||||
initialValue: 1.0,
|
||||
defaultTotalDuration: Time.AnimationDuration.TotalSeconds,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: Time.AnimationDuration.TotalSeconds
|
||||
);
|
||||
GlowTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: Time.AnimationDuration.TotalSeconds,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: Time.AnimationDuration.TotalSeconds
|
||||
);
|
||||
FloatTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: Time.LongAnimationDuration.TotalSeconds,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: Time.LongAnimationDuration.TotalSeconds
|
||||
);
|
||||
LayoutRect = layoutRect;
|
||||
}
|
||||
|
||||
@@ -82,43 +82,43 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
AngleTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: AnimationDuration,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
BlurAmountTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: AnimationDuration,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
PhoneticOpacityTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: AnimationDuration,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
PlayedOriginalOpacityTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: AnimationDuration,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
UnplayedOriginalOpacityTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: AnimationDuration,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
TranslatedOpacityTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: AnimationDuration,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
ScaleTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: AnimationDuration,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
YOffsetTransition = new(
|
||||
initialValue: 0,
|
||||
defaultTotalDuration: AnimationDuration,
|
||||
defaultEasingType: EasingType.EaseInOutSine
|
||||
EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Sine),
|
||||
defaultTotalDuration: AnimationDuration
|
||||
);
|
||||
ColorTransition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using static BetterLyrics.WinUI3.Helper.EasingHelper;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
@@ -29,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; }
|
||||
@@ -79,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() { }
|
||||
|
||||
@@ -129,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)
|
||||
|
||||
@@ -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.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.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.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, defaultEasingType: EasingType.Linear);
|
||||
_crossfadeTransition = new ValueTransition<double>(1.0, EasingHelper.GetInterpolatorByEasingType<double>(EasingType.Linear), 0.7);
|
||||
}
|
||||
|
||||
public void SetCoverBitmap(CanvasBitmap? newBitmap)
|
||||
|
||||
@@ -697,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();
|
||||
|
||||
@@ -212,7 +212,7 @@ 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;
|
||||
@@ -221,13 +221,13 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
results.Add(searchResult);
|
||||
}
|
||||
|
||||
if (_pluginService.Providers.Any())
|
||||
foreach (var plugin in _pluginService.Plugins)
|
||||
{
|
||||
foreach (var plugin in _pluginService.Providers)
|
||||
{
|
||||
if (token.IsCancellationRequested) break;
|
||||
if (token.IsCancellationRequested) break;
|
||||
|
||||
var pluginResult = await SearchPluginAsync(songInfo, plugin, token);
|
||||
if (plugin is ILyricsSearchPlugin lyricsSearchPlugin)
|
||||
{
|
||||
var pluginResult = await SearchPluginAsync(songInfo, lyricsSearchPlugin, token);
|
||||
results.Add(pluginResult);
|
||||
}
|
||||
}
|
||||
@@ -694,12 +694,11 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
return lyricsSearchResult;
|
||||
}
|
||||
|
||||
private async Task<LyricsCacheItem> SearchPluginAsync(SongInfo songInfo, ILyricsProvider plugin, CancellationToken token)
|
||||
private async Task<LyricsCacheItem> SearchPluginAsync(SongInfo songInfo, ILyricsSearchPlugin plugin, CancellationToken token)
|
||||
{
|
||||
var cacheItem = new LyricsCacheItem
|
||||
{
|
||||
Provider = LyricsSearchProvider.Plugin,
|
||||
PluginId = plugin.Id,
|
||||
};
|
||||
|
||||
try
|
||||
|
||||
@@ -7,8 +7,10 @@ namespace BetterLyrics.WinUI3.Services.PluginService
|
||||
{
|
||||
public interface IPluginService
|
||||
{
|
||||
IReadOnlyList<ILyricsProvider> Providers { get; }
|
||||
IReadOnlyList<IPlugin> Plugins { get; }
|
||||
|
||||
void LoadPlugins();
|
||||
void InstallPlugin(string zipPath);
|
||||
void UninstallPlugin(string pluginId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,20 +11,34 @@ namespace BetterLyrics.WinUI3.Services.PluginService
|
||||
{
|
||||
private AssemblyDependencyResolver _resolver;
|
||||
|
||||
public PluginLoadContext(string pluginPath)
|
||||
public PluginLoadContext(string pluginPath) : base(isCollectible: true)
|
||||
{
|
||||
_resolver = new AssemblyDependencyResolver(pluginPath);
|
||||
}
|
||||
|
||||
protected override Assembly? Load(AssemblyName assemblyName)
|
||||
{
|
||||
string? assemblyPath = _resolver.ResolveAssemblyToPath(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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,195 @@
|
||||
using BetterLyrics.Core.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
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<ILyricsProvider> _providers = new();
|
||||
private List<IPlugin> _plugins = new();
|
||||
public IReadOnlyList<IPlugin> Plugins => _plugins;
|
||||
private Dictionary<string, PluginLoadContext> _pluginContexts = new();
|
||||
private HashSet<string> _loadedDllPaths = new();
|
||||
|
||||
public IReadOnlyList<ILyricsProvider> Providers => _providers;
|
||||
private readonly ILogger<PluginService> _logger;
|
||||
|
||||
public PluginService(ILogger<PluginService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void LoadPlugins()
|
||||
{
|
||||
// 在涉及加载程序集的地方:
|
||||
// var context = new PluginLoadContext(pluginPath);
|
||||
// 它是本文件夹下的 internal 或者是 public 类,直接用即可。
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 6. Initialize
|
||||
plugin.Initialize();
|
||||
|
||||
// 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;
|
||||
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 = (ILyricsTransliterationPlugin?)_pluginService.Plugins.FirstOrDefault(x => x is ILyricsTransliterationPlugin);
|
||||
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 ?? "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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>
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -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>
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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>
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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>
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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>
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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>
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -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>
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -59,46 +59,46 @@
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
@@ -555,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>
|
||||
@@ -798,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">
|
||||
@@ -924,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>
|
||||
@@ -1254,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>
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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 />
|
||||
|
||||
113
BetterLyrics.sln
@@ -1,113 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 18
|
||||
VisualStudioVersion = 18.1.11312.151
|
||||
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
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterLyrics.Core", "BetterLyrics.Core\BetterLyrics.Core.csproj", "{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterLyrics.Plugins.Demo", "BetterLyrics.Plugins.Demo\BetterLyrics.Plugins.Demo.csproj", "{87D235CA-4311-4766-8186-AD9B193DFABC}"
|
||||
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
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|x86.Build.0 = Release|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{87D235CA-4311-4766-8186-AD9B193DFABC}.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
|
||||
21
BetterLyrics.slnx
Normal file
@@ -0,0 +1,21 @@
|
||||
<Solution>
|
||||
<Configurations>
|
||||
<Platform Name="ARM64" />
|
||||
<Platform Name="x64" />
|
||||
<Platform Name="x86" />
|
||||
</Configurations>
|
||||
<Project Path="BetterLyrics.Core/BetterLyrics.Core.csproj" />
|
||||
<Project Path="BetterLyrics.Plugins.Romaji/BetterLyrics.Plugins.Romaji.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" />
|
||||
<Project Path="RomajiConverter.Core/RomajiConverter.Core.csproj" />
|
||||
</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>
|
||||
@@ -1,13 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BetterLyrics.Core\BetterLyrics.Core.csproj" />
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.6" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
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;
|
||||
}
|
||||
}
|
||||
16
README.CN.md
@@ -20,7 +20,7 @@
|
||||
|
||||
<br>
|
||||
|
||||
<img src="Promotion/banner.png" alt="Banner" width="100%" style="border-radius: 10px;">
|
||||
<img src="docs/assets/promotion/banner.png" alt="Banner" width="100%" style="border-radius: 10px;">
|
||||
|
||||
</div>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
| :---: | :---: |
|
||||
| <a href="https://apps.microsoft.com/detail/9P1WCD1P597R?referrer=appbadge&mode=direct"><img src="https://get.microsoft.com/images/en-us%20dark.svg" width="160"/></a><br>无限期免费试用(功能与付费版一致) | [**📦 最新版本 (.zip)**](https://github.com/jayfunc/BetterLyrics/releases/latest)<br>[查看安装指南](https://www.cnblogs.com/jayfunc/p/19212078) |
|
||||
|
||||
[📖 用户指南](https://github.com/jayfunc/BetterLyrics/wiki/使用指南) | [🔒 隐私政策](PrivacyPolicy.CN.md) | [⚖️ 服务条款](TermsofService.CN.md)
|
||||
[📖 用户指南](docs/USER_GUIDE.CN.md) | [🔒 隐私政策](docs/PRIVACY_POLICY.CN.md) | [⚖️ 服务条款](docs/TERMS_OF_SERVICE.CN.md)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -80,19 +80,19 @@
|
||||
|
||||
| 标准视图 | 侧边栏模式 |
|
||||
| :---: | :---: |
|
||||
| <img src="Screenshots/std.png" width="100%"> | <img src="Screenshots/narrow.png" width="100%"> |
|
||||
| <img src="docs/assets/screenshots/std.png" width="100%"> | <img src="docs/assets/screenshots/narrow.png" width="100%"> |
|
||||
|
||||
| 歌词视觉特效 | 多模式共存 |
|
||||
| :---: | :---: |
|
||||
| <img src="Screenshots/effect.png" width="100%"> | <img src="Screenshots/all-in-one.png" width="100%"> |
|
||||
| <img src="docs/assets/screenshots/effect.png" width="100%"> | <img src="docs/assets/screenshots/all-in-one.png" width="100%"> |
|
||||
|
||||
| 全屏模式 | 全屏模式 |
|
||||
| :---: | :---: |
|
||||
| <img src="Screenshots/fs3.png" width="100%"> | <img src="Screenshots/fs2.png" width="100%"> |
|
||||
| <img src="docs/assets/screenshots/fs3.png" width="100%"> | <img src="docs/assets/screenshots/fs2.png" width="100%"> |
|
||||
|
||||
| 音乐库 | 播放统计 |
|
||||
| :---: | :---: |
|
||||
| <img src="Screenshots/music-gallery.png" width="100%"> | <img src="Screenshots/stats.png" width="100%"> |
|
||||
| <img src="docs/assets/screenshots/music-gallery.png" width="100%"> | <img src="docs/assets/screenshots/stats.png" width="100%"> |
|
||||
|
||||
</div>
|
||||
|
||||
@@ -104,6 +104,8 @@
|
||||
|
||||
**协助翻译:** 找不到你的语言?[点此开始翻译](https://github.com/jayfunc/BetterLyrics?tab=contributing-ov-file)。
|
||||
|
||||
**开发插件:** 想要扩展功能?[🧩 阅读插件开发指南](docs/PLUGIN_DEV.CN.md)。
|
||||
|
||||
**从源码构建:**
|
||||
> 构建前,请确保已替换 `Constants` 文件夹下的 `DiscordTemplate.cs` 和 `LastFM.cs`。
|
||||
|
||||
@@ -115,7 +117,7 @@
|
||||
|
||||
| 网页平台 | 支付宝 (扫码) | 微信 (扫码) |
|
||||
| :---: | :---: | :---: |
|
||||
| [PayPal](https://paypal.me/zhefangpay)<br><br>[Buy Me a Coffee](https://buymeacoffee.com/founchoo)<br><br>[爱发电 (Afdian)](https://afdian.com/a/jayfunc) | <img src="Donate/Alipay.jpg" width="150"> | <img src="Donate/WeChatReward.png" width="150"> |
|
||||
| [PayPal](https://paypal.me/zhefangpay)<br><br>[Buy Me a Coffee](https://buymeacoffee.com/founchoo)<br><br>[爱发电 (Afdian)](https://afdian.com/a/jayfunc) | <img src="docs/assets/donate/Alipay.jpg" width="150"> | <img src="docs/assets/donate/WeChatReward.png" width="150"> |
|
||||
|
||||
**[查看完整赞助者名单 (Hall of Fame)](SPONSORS.md)**
|
||||
|
||||
|
||||
16
README.md
@@ -20,7 +20,7 @@
|
||||
|
||||
<br>
|
||||
|
||||
<img src="Promotion/banner.png" alt="Banner" width="100%" style="border-radius: 10px;">
|
||||
<img src="docs/assets/promotion/banner.png" alt="Banner" width="100%" style="border-radius: 10px;">
|
||||
|
||||
</div>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
| :---: | :---: |
|
||||
| <a href="https://apps.microsoft.com/detail/9P1WCD1P597R?referrer=appbadge&mode=direct"><img src="https://get.microsoft.com/images/en-us%20dark.svg" width="160"/></a><br>Unlimited free trial (Same as paid) | [**📦 Latest Release (.zip)**](https://github.com/jayfunc/BetterLyrics/releases/latest)<br>See [Installation Guide](https://jayfunc.blog/blog/how-to-install-zip) |
|
||||
|
||||
[📖 User Guide](https://github.com/jayfunc/BetterLyrics/wiki/User-Guide) | [🔒 Privacy Policy](PrivacyPolicy.md) | [⚖️ Terms of Service](TermsofService.md)
|
||||
[📖 User Guide](docs/USER_GUIDE.md) | [🔒 Privacy Policy](docs/PRIVACY_POLICY.md) | [⚖️ Terms of Service](docs/TERMS_OF_SERVICE.md)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -80,19 +80,19 @@
|
||||
|
||||
| Standard View | Narrow Mode |
|
||||
| :---: | :---: |
|
||||
| <img src="Screenshots/std.png" width="100%"> | <img src="Screenshots/narrow.png" width="100%"> |
|
||||
| <img src="docs/assets/screenshots/std.png" width="100%"> | <img src="docs/assets/screenshots/narrow.png" width="100%"> |
|
||||
|
||||
| Lyrics Visual Effects | Coexisting Modes |
|
||||
| :---: | :---: |
|
||||
| <img src="Screenshots/effect.png" width="100%"> | <img src="Screenshots/all-in-one.png" width="100%"> |
|
||||
| <img src="docs/assets/screenshots/effect.png" width="100%"> | <img src="docs/assets/screenshots/all-in-one.png" width="100%"> |
|
||||
|
||||
| Fullscreen Mode | Fullscreen Mode |
|
||||
| :---: | :---: |
|
||||
| <img src="Screenshots/fs3.png" width="100%"> | <img src="Screenshots/fs2.png" width="100%"> |
|
||||
| <img src="docs/assets/screenshots/fs3.png" width="100%"> | <img src="docs/assets/screenshots/fs2.png" width="100%"> |
|
||||
|
||||
| Music Gallery | Playback Statistics |
|
||||
| :---: | :---: |
|
||||
| <img src="Screenshots/music-gallery.png" width="100%"> | <img src="Screenshots/stats.png" width="100%"> |
|
||||
| <img src="docs/assets/screenshots/music-gallery.png" width="100%"> | <img src="docs/assets/screenshots/stats.png" width="100%"> |
|
||||
|
||||
</div>
|
||||
|
||||
@@ -104,6 +104,8 @@
|
||||
|
||||
**Help us translate:** Cannot find your language? [Start translating here](https://github.com/jayfunc/BetterLyrics?tab=contributing-ov-file).
|
||||
|
||||
**Develop Plugins:** Want to extend functionality? [🧩 Read the Developer Guide](docs/PLUGIN_DEV.md).
|
||||
|
||||
**Build from source:**
|
||||
> Before building, ensure you have replaced `DiscordTemplate.cs` and `LastFM.cs` in the `Constants` folder.
|
||||
|
||||
@@ -115,7 +117,7 @@ If you like BetterLyrics, please consider supporting it. Your support helps keep
|
||||
|
||||
| Web Platforms | Alipay (QR) | WeChat (QR) |
|
||||
| :---: | :---: | :---: |
|
||||
| [PayPal](https://paypal.me/zhefangpay)<br><br>[Buy Me a Coffee](https://buymeacoffee.com/founchoo)<br><br>[爱发电 (Afdian)](https://afdian.com/a/jayfunc) | <img src="Donate/Alipay.jpg" width="150"> | <img src="Donate/WeChatReward.png" width="150"> |
|
||||
| [PayPal](https://paypal.me/zhefangpay)<br><br>[Buy Me a Coffee](https://buymeacoffee.com/founchoo)<br><br>[爱发电 (Afdian)](https://afdian.com/a/jayfunc) | <img src="docs/assets/donate/Alipay.jpg" width="150"> | <img src="docs/assets/donate/WeChatReward.png" width="150"> |
|
||||
|
||||
**[View the full Hall of Fame (Sponsors)](SPONSORS.md)**
|
||||
|
||||
|
||||
13
RomajiConverter.Core/Extensions/StringExtension.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace RomajiConverter.Core.Extensions
|
||||
{
|
||||
public static class StringExtension
|
||||
{
|
||||
public static string[] LineToUnits(this string str)
|
||||
{
|
||||
return str.Split(new[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
||||
}
|
||||
203
RomajiConverter.Core/Helpers/KanaHelper.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace RomajiConverter.Core.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 此类用于片假、平假互转
|
||||
/// </summary>
|
||||
public static class KanaHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 转为片假名
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToKatakana(string str)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
foreach (var c in str)
|
||||
{
|
||||
var bytes = Encoding.Unicode.GetBytes(c.ToString());
|
||||
if (bytes.Length == 2 && bytes[1] == 0x30 && bytes[0] >= 0x40 && bytes[0] <= 0x9F)
|
||||
stringBuilder.Append(Encoding.Unicode.GetString(new[] { (byte)(bytes[0] + 0x60), bytes[1] }));
|
||||
else
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转为平假名
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToHiragana(string str)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
foreach (var c in str)
|
||||
{
|
||||
var bytes = Encoding.Unicode.GetBytes(c.ToString());
|
||||
if (bytes.Length == 2 && bytes[1] == 0x30 && bytes[0] >= 0xA0 && bytes[0] <= 0xFA)
|
||||
stringBuilder.Append(Encoding.Unicode.GetString(new[] { (byte)(bytes[0] - 0x60), bytes[1] }));
|
||||
else
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 假名转罗马音
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static string KatakanaToRomaji(string str)
|
||||
{
|
||||
var result = new StringBuilder();
|
||||
|
||||
for (var i = 0; i < str.Length;)
|
||||
{
|
||||
if (i < str.Length - 1)
|
||||
{
|
||||
var extendedWord = str.Substring(i, 2);
|
||||
if (ExtendedKanaDictionary.ContainsKey(extendedWord))
|
||||
{
|
||||
result.Append(ExtendedKanaDictionary[extendedWord]);
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var word = str[i].ToString();
|
||||
if (KanaDictionary.ContainsKey(word))
|
||||
{
|
||||
//正常转换
|
||||
result.Append(KanaDictionary[word]);
|
||||
}
|
||||
else if (word == "ー")
|
||||
{
|
||||
//长音,取前一个音
|
||||
result.Append(result.Length > 0 ? result[result.Length - 1].ToString() : word);
|
||||
}
|
||||
else
|
||||
{
|
||||
//不能识别,保持原样
|
||||
result.Append(word);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
//处理促音
|
||||
for (var i = 0; i < result.Length; i++)
|
||||
{
|
||||
if (result[i] == 'っ' || result[i] == 'ッ')
|
||||
if (i < result.Length - 1)
|
||||
if (result[i + 1] == 'c')
|
||||
result[i] = 't';
|
||||
else
|
||||
result[i] = result[i + 1];
|
||||
else
|
||||
result.Remove(i, 1);
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> KanaDictionary = new Dictionary<string, string>
|
||||
{
|
||||
//平假
|
||||
{ "あ", "a" }, { "い", "i" }, { "う", "u" }, { "え", "e" }, { "お", "o" },
|
||||
{ "か", "ka" }, { "き", "ki" }, { "く", "ku" }, { "け", "ke" }, { "こ", "ko" },
|
||||
{ "さ", "sa" }, { "し", "shi" }, { "す", "su" }, { "せ", "se" }, { "そ", "so" },
|
||||
{ "た", "ta" }, { "ち", "chi" }, { "つ", "tsu" }, { "て", "te" }, { "と", "to" },
|
||||
{ "な", "na" }, { "に", "ni" }, { "ぬ", "nu" }, { "ね", "ne" }, { "の", "no" },
|
||||
{ "は", "ha" }, { "ひ", "hi" }, { "ふ", "fu" }, { "へ", "he" }, { "ほ", "ho" },
|
||||
{ "ま", "ma" }, { "み", "mi" }, { "む", "mu" }, { "め", "me" }, { "も", "mo" },
|
||||
{ "や", "ya" }, { "ゆ", "yu" }, { "よ", "yo" },
|
||||
{ "ら", "ra" }, { "り", "ri" }, { "る", "ru" }, { "れ", "re" }, { "ろ", "ro" },
|
||||
{ "わ", "wa" }, { "を", "wo" },
|
||||
{ "が", "ga" }, { "ぎ", "gi" }, { "ぐ", "gu" }, { "げ", "ge" }, { "ご", "go" },
|
||||
{ "ざ", "za" }, { "じ", "ji" }, { "ず", "zu" }, { "ぜ", "ze" }, { "ぞ", "zo" },
|
||||
{ "だ", "da" }, { "ぢ", "ji" }, { "づ", "zu" }, { "で", "de" }, { "ど", "do" },
|
||||
{ "ば", "ba" }, { "び", "bi" }, { "ぶ", "bu" }, { "べ", "be" }, { "ぼ", "bo" },
|
||||
{ "ぱ", "pa" }, { "ぴ", "pi" }, { "ぷ", "pu" }, { "ぺ", "pe" }, { "ぽ", "po" },
|
||||
{ "ん", "n" },
|
||||
|
||||
//片假
|
||||
{ "ア", "a" }, { "イ", "i" }, { "ウ", "u" }, { "エ", "e" }, { "オ", "o" },
|
||||
{ "カ", "ka" }, { "キ", "ki" }, { "ク", "ku" }, { "ケ", "ke" }, { "コ", "ko" },
|
||||
{ "サ", "sa" }, { "シ", "shi" }, { "ス", "su" }, { "セ", "se" }, { "ソ", "so" },
|
||||
{ "タ", "ta" }, { "チ", "chi" }, { "ツ", "tsu" }, { "テ", "te" }, { "ト", "to" },
|
||||
{ "ナ", "na" }, { "ニ", "ni" }, { "ヌ", "nu" }, { "ネ", "ne" }, { "ノ", "no" },
|
||||
{ "ハ", "ha" }, { "ヒ", "hi" }, { "フ", "fu" }, { "ヘ", "he" }, { "ホ", "ho" },
|
||||
{ "マ", "ma" }, { "ミ", "mi" }, { "ム", "mu" }, { "メ", "me" }, { "モ", "mo" },
|
||||
{ "ヤ", "ya" }, { "ユ", "yu" }, { "ヨ", "yo" },
|
||||
{ "ラ", "ra" }, { "リ", "ri" }, { "ル", "ru" }, { "レ", "re" }, { "ロ", "ro" },
|
||||
{ "ワ", "wa" }, { "ヲ", "wo" },
|
||||
{ "ガ", "ga" }, { "ギ", "gi" }, { "グ", "gu" }, { "ゲ", "ge" }, { "ゴ", "go" },
|
||||
{ "ザ", "za" }, { "ジ", "ji" }, { "ズ", "zu" }, { "ゼ", "ze" }, { "ゾ", "zo" },
|
||||
{ "ダ", "da" }, { "ヂ", "ji" }, { "ヅ", "zu" }, { "デ", "de" }, { "ド", "do" },
|
||||
{ "バ", "ba" }, { "ビ", "bi" }, { "ブ", "bu" }, { "ベ", "be" }, { "ボ", "bo" },
|
||||
{ "パ", "pa" }, { "ピ", "pi" }, { "プ", "pu" }, { "ペ", "pe" }, { "ポ", "po" },
|
||||
{ "ン", "n" },
|
||||
|
||||
//小版本
|
||||
{ "ぁ", "a" }, { "ぃ", "i" }, { "ぅ", "u" }, { "ぇ", "e" }, { "ぉ", "o" },
|
||||
{ "ゃ", "ya" }, { "ゅ", "yu" }, { "ょ", "yo" }, { "ゎ", "wa" },
|
||||
{ "ァ", "a" }, { "ィ", "i" }, { "ゥ", "u" }, { "ェ", "e" }, { "ォ", "o" },
|
||||
{ "ャ", "ya" }, { "ュ", "yu" }, { "ョ", "yo" }, { "ヮ", "wa" },
|
||||
};
|
||||
|
||||
public static Dictionary<string, string> ExtendedKanaDictionary = new Dictionary<string, string>
|
||||
{
|
||||
//平假-拗音
|
||||
{ "きゃ", "kya" }, { "きゅ", "kyu" }, { "きょ", "kyo" },
|
||||
{ "しゃ", "sha" }, { "しゅ", "shu" }, { "しょ", "sho" },
|
||||
{ "ちゃ", "cha" }, { "ちゅ", "chu" }, { "ちょ", "cho" },
|
||||
{ "にゃ", "nya" }, { "にゅ", "nyu" }, { "にょ", "nyo" },
|
||||
{ "ひゃ", "hya" }, { "ひゅ", "hyu" }, { "ひょ", "hyo" },
|
||||
{ "みゃ", "mya" }, { "みゅ", "myu" }, { "みょ", "myo" },
|
||||
{ "りゃ", "rya" }, { "りゅ", "ryu" }, { "りょ", "ryo" },
|
||||
{ "ぎゃ", "gya" }, { "ぎゅ", "gyu" }, { "ぎょ", "gyo" },
|
||||
{ "じゃ", "ja" }, { "じゅ", "ju" }, { "じょ", "jo" },
|
||||
{ "ぢゃ", "ja" }, { "ぢゅ", "ju" }, { "ぢょ", "jo" },
|
||||
{ "びゃ", "bya" }, { "びゅ", "byu" }, { "びょ", "byo" },
|
||||
{ "ぴゃ", "pya" }, { "ぴゅ", "pyu" }, { "ぴょ", "pyo" },
|
||||
|
||||
//片假-拗音
|
||||
{ "キャ", "kya" }, { "キュ", "kyu" }, { "キョ", "kyo" },
|
||||
{ "シャ", "sha" }, { "シュ", "shu" }, { "ショ", "sho" },
|
||||
{ "チャ", "cha" }, { "チュ", "chu" }, { "チョ", "cho" },
|
||||
{ "ニャ", "nya" }, { "ニュ", "nyu" }, { "ニョ", "nyo" },
|
||||
{ "ヒャ", "hya" }, { "ヒュ", "hyu" }, { "ヒョ", "hyo" },
|
||||
{ "ミャ", "mya" }, { "ミュ", "myu" }, { "ミョ", "myo" },
|
||||
{ "リャ", "rya" }, { "リュ", "ryu" }, { "リョ", "ryo" },
|
||||
{ "ギャ", "gya" }, { "ギュ", "gyu" }, { "ギョ", "gyo" },
|
||||
{ "ジャ", "ja" }, { "ジュ", "ju" }, { "ジョ", "jo" },
|
||||
{ "ヂャ", "ja" }, { "ヂュ", "ju" }, { "ヂョ", "jo" },
|
||||
{ "ビャ", "bya" }, { "ビュ", "byu" }, { "ビョ", "byo" },
|
||||
{ "ピャ", "pya" }, { "ピュ", "pyu" }, { "ピョ", "pyo" },
|
||||
|
||||
//其他语言
|
||||
{ "イェ", "ye" },
|
||||
{ "ウィ", "wi" }, { "ウェ", "we" }, { "ウォ", "wo" },
|
||||
{ "ヴァ", "va" }, { "ヴィ", "vi" }, { "ヴ", "vu" }, { "ヴェ", "ve" }, { "ヴォ", "vo" },
|
||||
{ "ヴュ", "vyu" },
|
||||
{ "クァ", "kwa" }, { "クィ", "kwi" }, { "クェ", "kwe" }, { "クォ", "kwo" },
|
||||
{ "グァ", "gwa" },
|
||||
{ "シェ", "she" },
|
||||
{ "ジェ", "je" },
|
||||
{ "チェ", "che" },
|
||||
{ "ツァ", "tsa" }, { "ツィ", "tsi" }, { "ツェ", "tse" }, { "ツォ", "tso" },
|
||||
{ "ティ", "ti" }, { "トゥ", "tu" },
|
||||
{ "テュ", "tyu" },
|
||||
{ "ディ", "di" }, { "ドゥ", "du" },
|
||||
{ "デュ", "dyu" },
|
||||
{ "ファ", "fa" }, { "フィ", "fi" }, { "フェ", "fe" }, { "フォ", "fo" },
|
||||
{ "フュ", "fyu" },
|
||||
};
|
||||
}
|
||||
}
|
||||
41
RomajiConverter.Core/Helpers/LrcParser.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RomajiConverter.Core.Helpers
|
||||
{
|
||||
public static class LrcParser
|
||||
{
|
||||
public static readonly Regex LrcLineRegex =
|
||||
new Regex("(\\[(\\d+:)?\\d+:\\d+(\\.\\d+)?\\])+\\s*(?<text>.*?(?=\\[(\\d+:)?\\d+:\\d+(\\.\\d+)?\\]|$|\\r|\\n))",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public static readonly Regex LrcTimeRegex =
|
||||
new Regex("\\[((?<hour>\\d+):)?(?<minute>\\d+):(?<second>\\d+)(\\.(?<millisecond>\\d+))?\\]", RegexOptions.Compiled);
|
||||
|
||||
public static List<(TimeSpan Time, string Text)> Parse(string lrc)
|
||||
{
|
||||
var result = new List<(TimeSpan Time, string Text)>();
|
||||
|
||||
var lineMatches = LrcLineRegex.Matches(lrc);
|
||||
foreach (Match lineMatch in lineMatches)
|
||||
{
|
||||
var text = lineMatch.Groups["text"].Value;
|
||||
var timeMatches = LrcTimeRegex.Matches(lineMatch.Value);
|
||||
foreach (Match timeMatch in timeMatches)
|
||||
{
|
||||
var hour = timeMatch.Groups["hour"].Success ? int.Parse(timeMatch.Groups["hour"].Value) : 0;
|
||||
var minute = timeMatch.Groups["minute"].Success ? int.Parse(timeMatch.Groups["minute"].Value) : 0;
|
||||
var second = timeMatch.Groups["second"].Success ? int.Parse(timeMatch.Groups["second"].Value) : 0;
|
||||
var millisecond = timeMatch.Groups["millisecond"].Success
|
||||
? int.Parse(timeMatch.Groups["millisecond"].Value)
|
||||
: 0;
|
||||
var time = new TimeSpan(0, hour, minute, second, millisecond);
|
||||
result.Add((time, text));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
372
RomajiConverter.Core/Helpers/RomajiHelper.cs
Normal file
@@ -0,0 +1,372 @@
|
||||
using MeCab;
|
||||
using MeCab.Extension.UniDic;
|
||||
using RomajiConverter.Core.Extensions;
|
||||
using RomajiConverter.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using RomajiConverter.Core.Options;
|
||||
|
||||
namespace RomajiConverter.Core.Helpers
|
||||
{
|
||||
public static class RomajiHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 分词器
|
||||
/// </summary>
|
||||
private static MeCabTagger _tagger;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义词典<原文, 假名>
|
||||
/// </summary>
|
||||
private static Dictionary<string, string> _customizeDict;
|
||||
|
||||
public static void Init(string baseDirectory = null)
|
||||
{
|
||||
string rootPath = !string.IsNullOrEmpty(baseDirectory)
|
||||
? baseDirectory
|
||||
: AppDomain.CurrentDomain.BaseDirectory;
|
||||
|
||||
//词典路径
|
||||
var dicPath = Path.Combine(rootPath, "unidic");
|
||||
var parameter = new MeCabParam
|
||||
{
|
||||
DicDir = dicPath,
|
||||
LatticeLevel = MeCabLatticeLevel.Zero
|
||||
};
|
||||
_tagger = MeCabTagger.Create(parameter);
|
||||
|
||||
var str = File.ReadAllText(Path.Combine(rootPath, "customizeDict.txt"));
|
||||
var list = str.Split(Environment.NewLine.ToArray());
|
||||
_customizeDict = new Dictionary<string, string>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item)) continue;
|
||||
var array = item.Split(' ');
|
||||
if (array.Length < 2) continue;
|
||||
if (!_customizeDict.ContainsKey(array[0]))
|
||||
_customizeDict.Add(array[0], array[1]);
|
||||
}
|
||||
}
|
||||
|
||||
#region 主逻辑
|
||||
|
||||
/// <summary>
|
||||
/// 生成转换结果列表
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<ConvertedLine> ToRomaji(string text, ToRomajiOptions options = null)
|
||||
{
|
||||
options = options ?? new ToRomajiOptions();
|
||||
|
||||
var timeSpans = new List<TimeSpan?>();
|
||||
var lineTextList = text.Split(Environment.NewLine.ToArray()).Where(p => !string.IsNullOrWhiteSpace(p)).ToList();
|
||||
|
||||
for (var i = 0; i < lineTextList.Count; i++)
|
||||
{
|
||||
if (LrcParser.LrcLineRegex.IsMatch(lineTextList[i]))
|
||||
{
|
||||
var lyric = LrcParser.Parse(lineTextList[i]).FirstOrDefault();
|
||||
timeSpans.Add(lyric.Time);
|
||||
lineTextList[i] = lyric.Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeSpans.Add(null);
|
||||
}
|
||||
}
|
||||
|
||||
ushort lineIndex = 0;
|
||||
for (var index = 0; index < lineTextList.Count; index++)
|
||||
{
|
||||
var line = lineTextList[index];
|
||||
|
||||
if (IsChinese(line, options.ChineseRate)) continue;
|
||||
|
||||
var convertedLine = new ConvertedLine
|
||||
{
|
||||
Index = lineIndex,
|
||||
Time = index < timeSpans.Count ? timeSpans[index] : null,
|
||||
Japanese = line.Replace("\0", "")
|
||||
};
|
||||
|
||||
foreach (var sentence in convertedLine.Japanese.LineToUnits())
|
||||
{
|
||||
if (IsEnglish(sentence))
|
||||
{
|
||||
convertedLine.Units.Add(new ConvertedUnit(lineIndex, sentence, sentence, sentence, false));
|
||||
}
|
||||
else
|
||||
foreach (var unit in SentenceToRomaji(lineIndex, sentence, options.IsParticleAsPronunciation))
|
||||
convertedLine.Units.Add(unit);
|
||||
}
|
||||
|
||||
if (index + 1 < lineTextList.Count && IsChinese(lineTextList[index + 1], options.ChineseRate))
|
||||
convertedLine.Chinese = lineTextList[index + 1];
|
||||
|
||||
lineIndex++;
|
||||
yield return convertedLine;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分句转为罗马音
|
||||
/// </summary>
|
||||
/// <param name="lineIndex"></param>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="isParticleAsPronunciation"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<ConvertedUnit> SentenceToRomaji(ushort lineIndex, string str, bool isParticleAsPronunciation)
|
||||
{
|
||||
foreach (var item in _tagger.ParseToNodes(str))
|
||||
{
|
||||
var unit = MeCabNodeToUnit(lineIndex, item, isParticleAsPronunciation);
|
||||
|
||||
if (unit != null)
|
||||
yield return unit;
|
||||
}
|
||||
}
|
||||
|
||||
public static ConvertedUnit MeCabNodeToUnit(ushort lineIndex, MeCabNode item, bool isParticleAsPronunciation)
|
||||
{
|
||||
ConvertedUnit unit = null;
|
||||
if (item.CharType > 0)
|
||||
{
|
||||
var features = CustomSplit(item.Feature);
|
||||
if (TryCustomConvert(item.Surface, out var customResult))
|
||||
{
|
||||
//用户自定义词典
|
||||
unit = new ConvertedUnit(lineIndex,
|
||||
item.Surface,
|
||||
customResult,
|
||||
KanaHelper.KatakanaToRomaji(customResult),
|
||||
true);
|
||||
}
|
||||
else if (features.Length > 0 && (!isParticleAsPronunciation || item.GetPos1() != "助詞") && IsJapanese(item.Surface))
|
||||
{
|
||||
//纯假名
|
||||
unit = new ConvertedUnit(lineIndex,
|
||||
item.Surface,
|
||||
KanaHelper.ToHiragana(item.Surface),
|
||||
KanaHelper.KatakanaToRomaji(item.Surface),
|
||||
false);
|
||||
}
|
||||
else if (features.Length <= 6 || new[] { "補助記号" }.Contains(item.GetPos1()))
|
||||
{
|
||||
//标点符号或无法识别的字
|
||||
unit = new ConvertedUnit(lineIndex,
|
||||
item.Surface,
|
||||
item.Surface,
|
||||
item.Surface,
|
||||
false);
|
||||
}
|
||||
else if (IsEnglish(item.Surface))
|
||||
{
|
||||
//英文
|
||||
unit = new ConvertedUnit(lineIndex,
|
||||
item.Surface,
|
||||
item.Surface,
|
||||
item.Surface,
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//汉字或助词
|
||||
var kana = GetKana(item);
|
||||
|
||||
unit = new ConvertedUnit(lineIndex,
|
||||
item.Surface,
|
||||
KanaHelper.ToHiragana(kana),
|
||||
KanaHelper.KatakanaToRomaji(kana),
|
||||
!IsJapanese(item.Surface));
|
||||
var (replaceHiragana, replaceRomaji) = GetReplaceData(item);
|
||||
unit.ReplaceHiragana = replaceHiragana;
|
||||
unit.ReplaceRomaji = replaceRomaji;
|
||||
}
|
||||
}
|
||||
else if (item.Stat != MeCabNodeStat.Bos && item.Stat != MeCabNodeStat.Eos)
|
||||
{
|
||||
unit = new ConvertedUnit(lineIndex,
|
||||
item.Surface,
|
||||
item.Surface,
|
||||
item.Surface,
|
||||
false);
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 帮助方法
|
||||
|
||||
/// <summary>
|
||||
/// 自定义分隔方法(Feature可能存在如 a,b,c,"d,e",f 格式的数据,此处不能把双引号中的内容也分隔开)
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
private static string[] CustomSplit(string str)
|
||||
{
|
||||
var list = new List<string>();
|
||||
var item = new List<char>();
|
||||
var haveMark = false;
|
||||
foreach (var c in str)
|
||||
if (c == ',' && !haveMark)
|
||||
{
|
||||
list.Add(new string(item.ToArray()));
|
||||
item.Clear();
|
||||
}
|
||||
else if (c == '"')
|
||||
{
|
||||
item.Add(c);
|
||||
haveMark = !haveMark;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Add(c);
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有发音
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
private static (ObservableCollection<ReplaceString> replaceHiragana, ObservableCollection<ReplaceString>
|
||||
replaceRomaji) GetReplaceData(MeCabNode node)
|
||||
{
|
||||
var length = node.Length;
|
||||
var replaceNodeList = new List<MeCabNode>();
|
||||
|
||||
GetAllReplaceNode(replaceNodeList, node);
|
||||
|
||||
void GetAllReplaceNode(List<MeCabNode> list, MeCabNode n)
|
||||
{
|
||||
if (n != null && !list.Contains(n) && n.Length == length)
|
||||
{
|
||||
list.Add(n);
|
||||
GetAllReplaceNode(list, n.BNext);
|
||||
GetAllReplaceNode(list, n.ENext);
|
||||
}
|
||||
}
|
||||
|
||||
var replaceHiragana = new ObservableCollection<ReplaceString>();
|
||||
var replaceRomaji = new ObservableCollection<ReplaceString>();
|
||||
|
||||
ushort i = 1;
|
||||
foreach (var meCabNode in replaceNodeList
|
||||
.GroupBy(GetKana)
|
||||
.Select(g => g.First()))
|
||||
{
|
||||
var kana = GetKana(meCabNode);
|
||||
if (kana != null)
|
||||
{
|
||||
replaceHiragana.Add(new ReplaceString(i, KanaHelper.ToHiragana(kana), true));
|
||||
replaceRomaji.Add(new ReplaceString(i, KanaHelper.KatakanaToRomaji(kana), true));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return (replaceHiragana, replaceRomaji);
|
||||
}
|
||||
|
||||
private static string GetKana(MeCabNode node)
|
||||
{
|
||||
return node.GetPos1() == "助詞" ? node.GetPron() : node.GetKana();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义转换规则
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
private static bool TryCustomConvert(string str, out string result)
|
||||
{
|
||||
if (_customizeDict.ContainsKey(str))
|
||||
{
|
||||
result = _customizeDict[str];
|
||||
return true;
|
||||
}
|
||||
|
||||
result = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断字符串(句子)是否简体中文
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="rate">容错率(0-1)</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsChinese(string str, float rate)
|
||||
{
|
||||
if (str.Length < 2)
|
||||
return false;
|
||||
|
||||
var wordArray = str.ToCharArray();
|
||||
var total = wordArray.Length;
|
||||
var chCount = 0f;
|
||||
var enCount = 0f;
|
||||
|
||||
foreach (var word in wordArray)
|
||||
{
|
||||
if (word != 'ー' && IsJapanese(word.ToString()))
|
||||
//含有日文直接返回否
|
||||
return false;
|
||||
|
||||
var gbBytes = Encoding.Unicode.GetBytes(word.ToString());
|
||||
|
||||
if (gbBytes.Length == 2) // double bytes char.
|
||||
{
|
||||
if (gbBytes[1] >= 0x4E && gbBytes[1] <= 0x9F) //中文
|
||||
chCount++;
|
||||
else
|
||||
total--;
|
||||
}
|
||||
else if (gbBytes.Length == 1)
|
||||
{
|
||||
var byteAscii = int.Parse(gbBytes[0].ToString());
|
||||
if ((byteAscii >= 65 && byteAscii <= 90) || (byteAscii >= 97 && byteAscii <= 122)) //英文字母
|
||||
enCount++;
|
||||
else
|
||||
total--;
|
||||
}
|
||||
}
|
||||
|
||||
if (chCount == 0) return false; //一个简体中文都没有
|
||||
|
||||
return (chCount + enCount) / total >= rate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断字符串是否全为单字节
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsEnglish(string str)
|
||||
{
|
||||
return new Regex("^[\x20-\x7E]+$", RegexOptions.Compiled).IsMatch(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断字符串是否全为假名
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
private static bool IsJapanese(string str)
|
||||
{
|
||||
return Regex.IsMatch(str, @"^[\u3040-\u30ff]+$", RegexOptions.Compiled);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
18
RomajiConverter.Core/Models/ConvertedLine.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace RomajiConverter.Core.Models
|
||||
{
|
||||
public class ConvertedLine
|
||||
{
|
||||
public ushort Index { get; set; } = 0;
|
||||
|
||||
public TimeSpan? Time { get; set; }
|
||||
|
||||
public string Chinese { get; set; } = string.Empty;
|
||||
|
||||
public string Japanese { get; set; } = string.Empty;
|
||||
|
||||
public ObservableCollection<ConvertedUnit> Units { get; set; } = new ObservableCollection<ConvertedUnit>();
|
||||
}
|
||||
}
|
||||
125
RomajiConverter.Core/Models/ConvertedUnit.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace RomajiConverter.Core.Models
|
||||
{
|
||||
public class ConvertedUnit : INotifyPropertyChanged
|
||||
{
|
||||
private string _hiragana;
|
||||
private bool _isKanji;
|
||||
private string _japanese;
|
||||
private ObservableCollection<ReplaceString> _replaceHiragana;
|
||||
private ObservableCollection<ReplaceString> _replaceRomaji;
|
||||
private string _romaji;
|
||||
private ushort _selectId;
|
||||
private ushort _lineIndex;
|
||||
|
||||
public ConvertedUnit(ushort lineIndex, string japanese, string hiragana, string romaji, bool isKanji)
|
||||
{
|
||||
LineIndex = lineIndex;
|
||||
Japanese = japanese;
|
||||
Romaji = romaji;
|
||||
Hiragana = hiragana;
|
||||
IsKanji = isKanji;
|
||||
SelectId = 1;
|
||||
ReplaceHiragana = new ObservableCollection<ReplaceString> { new ReplaceString(1, hiragana, true) };
|
||||
ReplaceRomaji = new ObservableCollection<ReplaceString> { new ReplaceString(1, romaji, true) };
|
||||
}
|
||||
|
||||
public ushort LineIndex
|
||||
{
|
||||
get => _lineIndex;
|
||||
set
|
||||
{
|
||||
if (value == _lineIndex) return;
|
||||
_lineIndex = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string Japanese
|
||||
{
|
||||
get => _japanese;
|
||||
set
|
||||
{
|
||||
if (value == _japanese) return;
|
||||
_japanese = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string Romaji
|
||||
{
|
||||
get => _romaji;
|
||||
set
|
||||
{
|
||||
if (value == _romaji) return;
|
||||
_romaji = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<ReplaceString> ReplaceRomaji
|
||||
{
|
||||
get => _replaceRomaji;
|
||||
set
|
||||
{
|
||||
if (Equals(value, _replaceRomaji)) return;
|
||||
_replaceRomaji = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string Hiragana
|
||||
{
|
||||
get => _hiragana;
|
||||
set
|
||||
{
|
||||
if (value == _hiragana) return;
|
||||
_hiragana = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<ReplaceString> ReplaceHiragana
|
||||
{
|
||||
get => _replaceHiragana;
|
||||
set
|
||||
{
|
||||
if (Equals(value, _replaceHiragana)) return;
|
||||
_replaceHiragana = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsKanji
|
||||
{
|
||||
get => _isKanji;
|
||||
set
|
||||
{
|
||||
if (value == _isKanji) return;
|
||||
_isKanji = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ushort SelectId
|
||||
{
|
||||
get => _selectId;
|
||||
set
|
||||
{
|
||||
if (value == _selectId) return;
|
||||
_selectId = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RomajiConverter.Core/Models/ReplaceString.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace RomajiConverter.Core.Models
|
||||
{
|
||||
public class ReplaceString
|
||||
{
|
||||
public ReplaceString(ushort id, string value, bool isSystem)
|
||||
{
|
||||
Id = id;
|
||||
Value = value;
|
||||
IsSystem = isSystem;
|
||||
}
|
||||
|
||||
public ushort Id { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public bool IsSystem { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
RomajiConverter.Core/Options/ToRomajiOptions.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace RomajiConverter.Core.Options
|
||||
{
|
||||
public class ToRomajiOptions
|
||||
{
|
||||
public float ChineseRate { get; set; } = 1f;
|
||||
|
||||
public bool IsParticleAsPronunciation { get; set; } = true;
|
||||
}
|
||||
}
|
||||
24
RomajiConverter.Core/RomajiConverter.Core.csproj
Normal file
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<PackageId>RomajiConverter.Core</PackageId>
|
||||
<Version>2.1.0</Version>
|
||||
<Authors>WL</Authors>
|
||||
<RepositoryUrl>https://github.com/xyh20180101/RomajiConverter.WinUI</RepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/xyh20180101/RomajiConverter.WinUI</PackageProjectUrl>
|
||||
<PackageLicenseExpression>GPL-2.0-or-later</PackageLicenseExpression>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<MeCabUseDefaultDictionary>False</MeCabUseDefaultDictionary>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MeCab.DotNet" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="docs\README.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
58
RomajiConverter.Core/docs/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# RomajiConverter.Core
|
||||
用于[RomajiConverter.WinUI](https://github.com/xyh20180101/RomajiConverter.WinUI)项目的罗马音转换相关逻辑的包
|
||||
|
||||
|
||||
## 使用
|
||||
```C#
|
||||
//离线分词器
|
||||
IEnumerable<ConvertedLine> list = RomajiHelper.ToRomaji(jpnStr);
|
||||
|
||||
//AI
|
||||
var list = new ObservableCollection<ConvertedLine>();
|
||||
await RomajiAIHelper.ToRomajiStreamingAsync(list, jpnStr, new ToRomajiAIOptions
|
||||
{
|
||||
BaseUrl = "",
|
||||
Model = "",
|
||||
ApiKey = ""
|
||||
}); //流式插入
|
||||
|
||||
//以下是类结构
|
||||
public class ConvertedLine
|
||||
{
|
||||
public ushort Index { get; set; } = 0;
|
||||
|
||||
public string Chinese { get; set; } = string.Empty;
|
||||
|
||||
public string Japanese { get; set; } = string.Empty;
|
||||
|
||||
public ObservableCollection<ConvertedUnit> Units { get; set; } = new ObservableCollection<ConvertedUnit>();
|
||||
}
|
||||
|
||||
public class ConvertedUnit
|
||||
{
|
||||
public ushort LineIndex { get; set; }
|
||||
|
||||
public string Japanese { get; set; }
|
||||
|
||||
public string Romaji { get; set; }
|
||||
|
||||
public ObservableCollection<ReplaceString> ReplaceRomaji { get; set; }
|
||||
|
||||
public string Hiragana { get; set; }
|
||||
|
||||
public ObservableCollection<ReplaceString> ReplaceHiragana { get; set; }
|
||||
|
||||
public bool IsKanji { get; set; }
|
||||
|
||||
public ushort SelectId { get; set; }
|
||||
}
|
||||
|
||||
public class ReplaceString
|
||||
{
|
||||
public ushort Id { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public bool IsSystem { get; set; }
|
||||
}
|
||||
```
|
||||
@@ -1,57 +0,0 @@
|
||||
# Welcome to ShareHub | 欢迎来到 ShareHub
|
||||
|
||||
## Shared lyrics window status | 已分享的歌词窗口状态
|
||||
|
||||
Click on the links below to view and download the config files. | 点击以下链接查看和下载配置文件。
|
||||
|
||||
Each link is accompanied by a preview image of the lyrics window in that specific status. | 每个链接都附带该状态下歌词窗口的预览图像。
|
||||
|
||||
---
|
||||
|
||||
### [Desktop | 桌面](LyricsWindowStatus/desktop.json)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### [Docked (Bottom) | 停靠(底部)](LyricsWindowStatus/docked-bottom.json)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### [Docked (Top) | 停靠(顶部)](LyricsWindowStatus/docked-top.json)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### [Fullscreen (Horizontal) | 全屏(横屏)](LyricsWindowStatus/fs-horiz.json)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### [Fullscreen (Vertical) | 全屏(竖屏)](LyricsWindowStatus/fs-vert.json)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### [Standard (Horizontal) | 标准(横屏)](LyricsWindowStatus/std-horiz.json)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### [Standard (Vertical) | 标准(竖屏)](LyricsWindowStatus/std-vert.json)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### [Taskbar | 任务栏](LyricsWindowStatus/taskbar.json)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 109 KiB |
195
docs/PLUGIN_DEV.CN.md
Normal file
@@ -0,0 +1,195 @@
|
||||
**中文** | [**English**](PLUGIN_DEV.md)
|
||||
|
||||
# BetterLyrics 插件开发指南 🧩
|
||||
|
||||
欢迎开发 BetterLyrics 插件!本文档将指导你如何创建一个标准插件,并利用我们的自动化构建工具链,完美解决 .NET 裁剪(Trimming)和依赖冲突问题。
|
||||
|
||||
## 🛠️ 核心机制简介
|
||||
|
||||
为了保证插件在主程序发布(Native AOT / Trimmed)后依然稳定运行,我们采用了一套自动化工作流:
|
||||
|
||||
1. **智能去重**:编译时,脚本会自动检测主程序已有的 DLL(如 `Newtonsoft.Json`、`BetterLyrics.Core`),并从插件输出目录中剔除,防止版本冲突。
|
||||
2. **自动分析**:编译后,`PluginAnalyzer` 工具会扫描你的插件,分析缺失的 System 库依赖。
|
||||
3. **自动注册**:工具会在主程序的 `PluginConfigs` 目录生成配置,利用 `[ModuleInitializer]` 实现插件自动挂载,无需手动写注册代码。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 创建项目
|
||||
|
||||
创建一个 **类库 (Class Library)** 项目。
|
||||
|
||||
* **框架**:`.NET 10`。
|
||||
* **平台**:`net10.0-windows10.0.19041.0`。
|
||||
|
||||
### 2. 配置 `.csproj` (关键步骤)
|
||||
|
||||
请将你的 `.csproj` 文件内容替换为以下标准模板。这段配置包含了自动化构建的所有黑科技。
|
||||
|
||||
> ⚠️ **注意**:请根据实际文件结构,修改 `<HostProjectDir>` 和 `<AnalyzerPath>` 的路径。
|
||||
|
||||
```xml
|
||||
<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">
|
||||
<Private>false</Private>
|
||||
<ExcludeAssets>runtime</ExcludeAssets>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<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>
|
||||
|
||||
</Project>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 开发流程
|
||||
|
||||
### 1. 引用依赖
|
||||
你可以像平常一样引用 NuGet 包或第三方 DLL。
|
||||
* **如果是公共库**(如 `Newtonsoft.Json`):无需做任何事,脚本会自动检测主程序里有没有。如果有,编译时自动剔除,运行时直接使用主程序加载的版本。
|
||||
* **如果是私有库**(如 `MeCab`):脚本检测到主程序没有,会将其保留在你的插件目录里。
|
||||
|
||||
### 2. 实现接口
|
||||
在代码中实现 `BetterLyrics.Core` 提供的接口(例如 `ILyricsSearchPlugin`)。
|
||||
|
||||
```csharp
|
||||
using BetterLyrics.Core;
|
||||
|
||||
namespace BetterLyrics.Plugins.MyPlugin;
|
||||
|
||||
public class MyLyricsSearchPlugin : ILyricsSearchPlugin
|
||||
{
|
||||
public string Id => "your_name.plugin_name";
|
||||
|
||||
public string Name => "Plugin display name";
|
||||
|
||||
public string Description => "Plugin description.";
|
||||
|
||||
public string Author => "Your name";
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// Do something if necessary ...
|
||||
// string? pluginPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
}
|
||||
|
||||
public async Task<LyricsSearchResult> GetLyricsAsync(string title, string artist, string album, double duration)
|
||||
{
|
||||
// Your code here
|
||||
return new LyricsSearchResult(...);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 编译构建
|
||||
点击 Visual Studio 的 **生成 (Build)**。
|
||||
|
||||
观察 **输出 (Output)** 窗口,你会看到自动化工具在工作:
|
||||
1. `[Smart Trim]`:告诉你哪些库被剔除了(例如 `BetterLyrics.Core.dll`)。
|
||||
2. `[Analyzer]`:告诉你防裁剪配置文件 (`*_TrimmerRoots.xml`) 已经生成,并成功投递到了主程序的 `PluginConfigs` 文件夹。
|
||||
|
||||
---
|
||||
|
||||
## 🔍 原理详解 (Advanced)
|
||||
|
||||
### 为什么我看不到生成的配置文件?
|
||||
生成的配置文件不会在你的插件项目里,而是直接生成到了 **主程序** 的 `PluginConfigs` 文件夹下。
|
||||
|
||||
### 生成了什么?
|
||||
1. **`MyPlugin_TrimmerRoots.xml`**:
|
||||
告诉主程序的裁剪器(Trimmer),保留所有你的插件需要用到、但主程序看起来没用到的 System 库。它还包含了一条指令,强制保留生成的 Config 类。
|
||||
2. **`MyPlugin_TrimmingConfig.cs`**:
|
||||
包含一个带有 `[ModuleInitializer]` 特性的类。这个类会在主程序启动时 **自动运行**,确保相关的反射元数据被加载,防止运行时崩溃。
|
||||
|
||||
### 依赖关系图
|
||||
```mermaid
|
||||
graph TD
|
||||
A[你的插件代码] -->|编译| B(插件 DLL)
|
||||
B -->|智能去重| B
|
||||
B -->|自动化分析| C{PluginAnalyzer}
|
||||
C -->|生成| D[PluginConfigs/MyPlugin_Config.cs]
|
||||
C -->|生成| E[PluginConfigs/MyPlugin_TrimmerRoots.xml]
|
||||
|
||||
D -->|自动投递| F[主程序项目]
|
||||
E -->|自动投递| F
|
||||
|
||||
F -->|发布 Publish| G[最终可执行文件]
|
||||
|
||||
style C fill:#f9f,stroke:#333
|
||||
style F fill:#bfb,stroke:#333
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **编译顺序**:
|
||||
请务必确保 **主程序 (Host) 至少被编译过一次**(Debug 或 Release 对应模式)。插件的去重脚本依赖于读取主程序的输出目录来进行比对。如果主程序 bin 目录是空的,插件可能会错误地打包所有依赖。
|
||||
|
||||
2. **配置一致性**:
|
||||
如果你在 `Release` 模式下编译插件,确保主程序也是 `Release` 模式。脚本会自动根据 `$(Configuration)` 寻找对应的主程序输出路径。
|
||||
|
||||
3. **私有依赖处理**:
|
||||
如果你引用了一个主程序也有、但你需要**不同版本**的库(这种情况极少见且不推荐),你需要修改 `.csproj` 脚本,移除自动剔除逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 🙋♂️ 常见问题
|
||||
|
||||
**Q: 编译时报错 "命令 ... 已退出,代码为 9009" 或 "不是内部或外部命令"?**
|
||||
|
||||
A: 这说明构建脚本找不到 `PluginAnalyzer.exe`。请检查 `.csproj` 文件里的 `<AnalyzerPath>` 路径配置是否正确。
|
||||
|
||||
**Q: 运行时报错 "FileNotFoundException: BetterLyrics.Core"?**
|
||||
|
||||
A: 这是正常的。插件目录下不应该有 `BetterLyrics.Core.dll`(因为它由主程序提供)。请通过主程序加载插件进行测试,而不是直接运行插件 DLL。
|
||||
|
||||
**Q: 发布后插件崩溃,提示 System 库找不到?**
|
||||
|
||||
A: 请检查主程序的 `PluginConfigs` 目录下是否成功生成了对应的 `*_TrimmerRoots.xml` 文件。如果没有,请尝试重新生成插件项目。
|
||||
198
docs/PLUGIN_DEV.md
Normal file
@@ -0,0 +1,198 @@
|
||||
[**中文**](PLUGIN_DEV.CN.md) | **English**
|
||||
|
||||
# BetterLyrics Plugin Development Guide 🧩
|
||||
|
||||
Welcome to BetterLyrics plugin development! This document guides you through creating a standard plugin and using our automated build toolchain to perfectly resolve .NET Trimming and dependency conflict issues.
|
||||
|
||||
## 🛠️ Core Mechanics
|
||||
|
||||
To ensure plugins run stably after the main application is published (Native AOT / Trimmed), we use an automated workflow:
|
||||
|
||||
1. **Smart Exclusion**: During compilation, a script automatically detects DLLs already present in the host application (e.g., `Newtonsoft.Json`, `BetterLyrics.Core`) and removes them from the plugin output directory to prevent version conflicts.
|
||||
2. **Auto Analysis**: After compilation, the `PluginAnalyzer` tool scans your plugin to analyze missing System library dependencies.
|
||||
3. **Auto Registration**: The tool generates configurations in the host's `PluginConfigs` directory and uses `[ModuleInitializer]` to achieve automatic plugin mounting, eliminating the need for manual registration code.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. Create Project
|
||||
|
||||
Create a **Class Library** project.
|
||||
|
||||
* **Framework**: `.NET 10`.
|
||||
* **Platform**: `net10.0-windows10.0.19041.0`.
|
||||
|
||||
### 2. Configure `.csproj` (Key Step)
|
||||
|
||||
Please replace the content of your `.csproj` file with the standard template below. This configuration contains all the "magic" for the automated build process.
|
||||
|
||||
> ⚠️ **Note**: Please modify the paths for `<HostProjectDir>` and `<AnalyzerPath>` according to your actual file structure.
|
||||
|
||||
```xml
|
||||
<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">
|
||||
<Private>false</Private>
|
||||
<ExcludeAssets>runtime</ExcludeAssets>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<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>
|
||||
|
||||
</Project>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 Development Workflow
|
||||
|
||||
### 1. Referencing Dependencies
|
||||
|
||||
You can reference NuGet packages or third-party DLLs as usual.
|
||||
|
||||
* **Shared Libraries** (e.g., `Newtonsoft.Json`): Do nothing. The script automatically detects if the host has it. If so, it's excluded during the plugin build, and the host's version is used at runtime.
|
||||
* **Private Libraries** (e.g., `MeCab`): If the script detects the host doesn't have it, it will be preserved in your plugin directory.
|
||||
|
||||
### 2. Implementing Interfaces
|
||||
|
||||
Implement the interfaces provided by `BetterLyrics.Core` (e.g., `ILyricsSearchPlugin`) in your code.
|
||||
|
||||
```csharp
|
||||
using BetterLyrics.Core;
|
||||
|
||||
namespace BetterLyrics.Plugins.MyPlugin;
|
||||
|
||||
public class MyLyricsSearchPlugin : ILyricsSearchPlugin
|
||||
{
|
||||
public string Id => "your_name.plugin_name";
|
||||
|
||||
public string Name => "Plugin display name";
|
||||
|
||||
public string Description => "Plugin description.";
|
||||
|
||||
public string Author => "Your name";
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// Do something if necessary ...
|
||||
// string? pluginPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
}
|
||||
|
||||
public async Task<LyricsSearchResult> GetLyricsAsync(string title, string artist, string album, double duration)
|
||||
{
|
||||
// Your code here
|
||||
return new LyricsSearchResult(...);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Build & Compile
|
||||
|
||||
Click **Build** in Visual Studio.
|
||||
|
||||
Observe the **Output** window; you will see the automation tools at work:
|
||||
|
||||
1. `[Smart Trim]`: Tells you which libraries were excluded (e.g., `BetterLyrics.Core.dll`).
|
||||
2. `[Analyzer]`: Tells you that the anti-trimming configuration (`*_TrimmerRoots.xml`) has been generated and successfully delivered to the host's `PluginConfigs` folder.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Deep Dive (Advanced)
|
||||
|
||||
### Why can't I see the generated config files?
|
||||
|
||||
The generated configuration files are not located in your plugin project; they are generated directly into the **Host Application's** `PluginConfigs` folder.
|
||||
|
||||
### What was generated?
|
||||
|
||||
1. **`MyPlugin_TrimmerRoots.xml`**:
|
||||
Tells the host's Trimmer to preserve all System libraries required by your plugin that the host might otherwise discard. It also includes an instruction to force-preserve the generated Config class.
|
||||
2. **`MyPlugin_TrimmingConfig.cs`**:
|
||||
Contains a class with the `[ModuleInitializer]` attribute. This class runs **automatically** when the host starts, ensuring relevant reflection metadata is loaded to prevent runtime crashes.
|
||||
|
||||
### Dependency Graph
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Your Plugin Code] -->|Compile| B(Plugin DLL)
|
||||
B -->|Smart Exclusion| B
|
||||
B -->|Auto Analyzer| C{PluginAnalyzer}
|
||||
C -->|Generate| D[PluginConfigs/MyPlugin_Config.cs]
|
||||
C -->|Generate| E[PluginConfigs/MyPlugin_TrimmerRoots.xml]
|
||||
|
||||
D -->|Auto Delivery| F[Host Project]
|
||||
E -->|Auto Delivery| F
|
||||
|
||||
F -->|Publish| G[Final Executable]
|
||||
|
||||
style C fill:#f9f,stroke:#333
|
||||
style F fill:#bfb,stroke:#333
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Precautions
|
||||
|
||||
1. **Build Order**:
|
||||
Please ensure the **Host Application is compiled at least once** (in the corresponding Debug or Release mode). The plugin's exclusion script relies on reading the host's output directory for comparison. If the host's bin directory is empty, the plugin might incorrectly bundle all dependencies.
|
||||
|
||||
2. **Configuration Consistency**:
|
||||
If you compile the plugin in `Release` mode, ensure the host is also in `Release` mode. The script automatically looks for the corresponding host output path based on `$(Configuration)`.
|
||||
|
||||
3. **Private Dependency Handling**:
|
||||
If you reference a library that the host also has, but you require a **different version** (this is rare and not recommended), you will need to modify the `.csproj` script to remove the automatic exclusion logic.
|
||||
|
||||
---
|
||||
|
||||
## 🙋♂️ FAQ
|
||||
|
||||
**Q: Build error "Command ... exited with code 9009" or "is not recognized as an internal or external command"?**
|
||||
|
||||
A: This means the build script cannot find `PluginAnalyzer.exe`. Please check if the `<AnalyzerPath>` configuration in your `.csproj` file is correct.
|
||||
|
||||
**Q: Runtime error "FileNotFoundException: BetterLyrics.Core"?**
|
||||
|
||||
A: This is normal. `BetterLyrics.Core.dll` should not exist in the plugin directory (as it is provided by the host). Please test by loading the plugin via the host application, rather than running the plugin DLL directly.
|
||||
|
||||
**Q: Plugin crashes after Publish, stating a System library is missing?**
|
||||
|
||||
A: Please check if the corresponding `*_TrimmerRoots.xml` file was successfully generated in the host's `PluginConfigs` directory. If not, try rebuilding the plugin project.
|
||||
@@ -1,3 +1,5 @@
|
||||
**中文** | [**English**](PrivacyPolicy.md)
|
||||
|
||||
# BetterLyrics 隐私政策
|
||||
|
||||
**生效日期:** 2025 年 6 月 3 日
|
||||
@@ -1,3 +1,5 @@
|
||||
[**中文**](PrivacyPolicy.CN.md) | **English**
|
||||
|
||||
# Privacy Policy for BetterLyrics
|
||||
|
||||
**Effective Date:** June 3, 2025
|
||||
@@ -1,3 +1,5 @@
|
||||
**中文** | [**English**](TermsofService.md)
|
||||
|
||||
# BetterLyrics 服务条款
|
||||
|
||||
**生效日期:** 2025 年 6 月 3 日
|
||||
@@ -1,3 +1,5 @@
|
||||
[**中文**](TermsofService.CN.md) | **English**
|
||||
|
||||
# Terms of Service for BetterLyrics
|
||||
|
||||
**Effective Date:** June 3, 2025
|
||||
@@ -54,4 +56,4 @@ We reserve the right, at our sole discretion, to modify or replace these Terms a
|
||||
## 9. Contact Us
|
||||
If you have any questions about these Terms, please contact:
|
||||
Zhe Fang
|
||||
[zhefang.zf@gmail.com](mailto:zhefang.zf@gmail.com)
|
||||
[zhefang.zf@gmail.com](mailto:zhefang.zf@gmail.com)
|
||||
164
docs/USER_GUIDE.CN.md
Normal file
@@ -0,0 +1,164 @@
|
||||
[**English**](USER_GUIDE.md) | **中文**
|
||||
|
||||
# ❓ 常见问题解答 (FAQ)
|
||||
|
||||
## 🎵 播放与连接
|
||||
|
||||
### 🤔 我在使用网易云音乐作为音乐播放器
|
||||
|
||||
强烈建议首先浏览 [此处](#已知支持的音乐播放器配置指南) 的配置指南。
|
||||
|
||||
### 🤔 显示没有音乐正在播放
|
||||
|
||||
部分播放器需要额外配置,请查看 [此处](#已知支持的音乐播放器配置指南)。
|
||||
|
||||
### 🤔 怎么通过本软件播放本地歌曲?
|
||||
|
||||
1. 请确保本地歌曲文件夹已添加到软件内(参考 [如何设置本地歌词源?](#-如何设置本地歌词源) 中的第一步)
|
||||
2. 打开 `音乐库`
|
||||
- 可通过歌词窗口左上区域的图书按钮打开
|
||||
- 或在系统托盘右键本软件,选择打开音乐库
|
||||
|
||||
## 🪟 窗口与交互
|
||||
|
||||
### 🤔 如何移动和调整窗口大小?
|
||||
|
||||
如果您无法选择和移动窗口,请检查 `歌词窗口管理` 的 `窗口` 设置中,`可拖动区域` 的选项是否误设为 `无`。
|
||||
|
||||
### 🤔 我看不到任何按钮 / 底部命令栏被隐藏了
|
||||
|
||||
**顶部与底部命令栏:**
|
||||
|
||||
- 默认情况下,当鼠标移出顶部命令栏和底部命令栏(播放控制面板)区域时,它们会自动隐藏。只需将鼠标悬停在这些区域即可再次显示它们。
|
||||
- 如果窗口已锁定,悬浮到窗口上放即可显示解锁按钮。
|
||||
|
||||
**无法唤出底部面板:**
|
||||
当窗口太小无法显示该面板时,只有将鼠标悬停在歌词窗口底部并单击白线,才能显示播放控制面板。
|
||||
|
||||
### 🤔 软件有哪些默认快捷键?
|
||||
|
||||
- `Ctrl + Alt + H`:显示/隐藏歌词窗口
|
||||
- `Ctrl + Alt + S`:切换歌词窗口状态
|
||||
- `Ctrl + Alt + P`:播放/暂停当前曲目
|
||||
- `Ctrl + Alt + Right`:下一曲目
|
||||
- `Ctrl + Alt + Left`:上一曲目
|
||||
|
||||
> 可前往 `设置` -> `应用外观与行为` 更改上述快捷键
|
||||
|
||||
## 📃 歌词显示
|
||||
|
||||
### 🤔 歌词显示错误(匹配错误)
|
||||
|
||||
- 请前往 `设置` -> `播放源` -> `歌词搜索策略` 选择 `最佳匹配`
|
||||
> 注意:对于每首歌曲,首次使用最佳匹配时将耗时 10 秒左右,请耐心等待
|
||||
|
||||
- 或打开歌词搜索窗口手动搜索正确的歌词。
|
||||
|
||||
> 歌词搜索窗口可通过下述一种方式打开:
|
||||
> - 将鼠标移至窗口靠下区域,直至底部控制栏出现,点击右下侧放大镜图标(🔍)以打开歌词搜索窗口
|
||||
> - 右键系统托盘内本软件的图标,选择 “打开歌词窗口”
|
||||
|
||||
### 🤔 歌词一直在来回移动(时间轴跳动)
|
||||
|
||||
前往 `设置` > `播放源` > 禁用 `歌词时间轴同步` 或提高 `歌词时间轴同步阈值`。
|
||||
|
||||
### 🤔 如何设置本地歌词源?
|
||||
|
||||
**第一步:添加文件夹**
|
||||
前往 `设置` -> `媒体库`,点击 `添加` 按钮,将您存放歌词(或包含内嵌歌词的音乐文件)的文件夹添加进去,并确保右侧开关为 **“开启”** 状态。
|
||||
|
||||
**第二步:准备文件**
|
||||
软件支持两种方式:
|
||||
|
||||
1. **外挂歌词文件 (.lrc/.eslrc/.ttml)**
|
||||
软件进行比对时,**不区分词语顺序**,且**自动忽略标点符号**。
|
||||
* **推荐命名:** `歌手名 - 歌名.lrc`
|
||||
* **也支持:** `歌名 歌手名.lrc`
|
||||
* **同样支持:** `歌名 (Live) - 歌手名.lrc`
|
||||
* *例:播放 Taylor Swift 的 "Love Story" 时,文件名为 `love_story_taylor_swift.lrc` 也能被精准识别。*
|
||||
|
||||
2. **内嵌歌词**
|
||||
如果您的本地音乐文件(.mp3/.flac等)标签中已写入歌词,软件也会自动读取。
|
||||
|
||||
> 推荐下述几种方式检查音乐文件的标签信息:
|
||||
> - [音乐标签](https://www.cnblogs.com/vinlxc/p/11347744.html):可浏览本地歌曲元信息
|
||||
> - 在 **第一步:添加文件夹** 已完成的情况下可前往 BetterLyrics 软件 `音乐库` 单击音乐条目的右侧三个点图标(···)显示解析的元信息(可能与实际信息有出入)
|
||||
|
||||
> 为了确保 **内嵌歌词** 方式的顺利匹配,推荐下述工具:
|
||||
> - [音乐标签](https://www.cnblogs.com/vinlxc/p/11347744.html):可批量将 **所有元信息** 写入本地音乐文件标签
|
||||
> - [LDDC](https://github.com/chenmozhijin/LDDC):可批量将 **逐字歌词** 写入本地音乐文件标签
|
||||
|
||||
### 🤔 歌词显示部分乱码
|
||||
|
||||
一般情况是默认字体设置问题,前往 `设置` -> `歌词窗口管理` -> `歌词样式` -> `歌词字体` -> 键入 `Arial` 以获得最稳妥的展示效果
|
||||
|
||||
## 🎨 模式与外观
|
||||
|
||||
### 🤔 如何添加更多模式?
|
||||
|
||||
软件初始已为您添加了所有预设的模式。
|
||||
|
||||
您可以导入他人与您分享的窗口状态文件:转到 `设置` -> `歌词窗口管理` -> 导入(向下箭头图标) -> 选择需要导入的文件(`.json` 格式)
|
||||
|
||||
> 要导出窗口状态,请右键窗口状态,选择 `导出`
|
||||
|
||||
### 🤔 如何切换模式?
|
||||
|
||||
- 按下默认快捷键 `Ctrl + Alt + S`,然后选择屏幕上显示的模式来切换模式。(按 `Esc` 键关闭选择窗口)
|
||||
- 在歌词窗口左上区域找到双向箭头图标,点按即可唤出歌词窗口切换器
|
||||
|
||||
## 📂 数据与反馈
|
||||
|
||||
### 🤔 歌词缓存在哪里?
|
||||
|
||||
`%LocalAppData%\Packages\37412.BetterLyrics_rd1g0rsrrtxw8\LocalCache\lyrics`
|
||||
|
||||
### 🤔 如何反馈问题?(日志位置)
|
||||
|
||||
反馈时请附带软件日志,日志位置如下:
|
||||
`%LocalAppData%\Packages\37412.BetterLyrics_rd1g0rsrrtxw8\LocalCache\logs`
|
||||
|
||||
# 已知支持的音乐播放器(配置指南)
|
||||
|
||||
使用方法:找到音乐播放器,安装表格中所列出的 `插件`。
|
||||
|
||||
> <mark>支持的音乐播放器包括但不限于下述列表,请以实际体验为准。</mark>
|
||||
|
||||
> <mark>凡是接入了 [SMTC](https://learn.microsoft.com/zh-cn/windows/uwp/audio-video-camera/integrate-with-systemmediatransportcontrols) 的媒体播放器均受支持。</mark>
|
||||
|
||||
| 音乐播放器 | 插件 | 注意事项 |
|
||||
| :--- | :--- | :--- |
|
||||
| [AIMP](https://www.aimp.ru) | [插件](https://www.aimp.ru/?do=catalog&rec_id=1097) | - |
|
||||
| [AMLL Player](https://github.com/Steve-xmh/applemusic-like-lyrics/blob/full-refractor/packages/player/README.md) | - | - |
|
||||
| [Apple Music](https://music.apple.com) | - | - |
|
||||
| [BetterLyrics](https://github.com/jayfunc/BetterLyrics) | - | - |
|
||||
| [foobar2000](https://www.foobar2000.org/windows) | [插件](https://github.com/dumbie/foo_mediacontrol) | 时间轴有问题 |
|
||||
| [Google Chrome](https://www.google.com/chrome) | - | - |
|
||||
| [HyPlayer](https://github.com/HyPlayer/HyPlayer) | - | - |
|
||||
| [iTunes](https://apps.microsoft.com/detail/9pb2mz1zmb1s) | [插件](https://github.com/thewizrd/iTunes-SMTC) | - |
|
||||
| [酷狗音乐](https://www.kugou.com) | - |  时间轴有问题 |
|
||||
| [Listen 1](https://listen1.github.io/listen1) | - | - |
|
||||
| [LX Music](https://github.com/lyswhut/lx-music-desktop) | - | 在 LX Music 设置 “开放 API” 中勾选 “启用开放 API 服务”;<br>在 BetterLyrics 设置 “播放源” 板块下的 “LX 音乐服务器” 中输入 LX Music 服务器地址。 |
|
||||
| [Microsoft Edge](https://www.microsoft.com/edge) | - | - |
|
||||
| [MoeKoe Music](https://github.com/MoeKoeMusic/MoeKoeMusic) | - | - |
|
||||
| [MusicBee](https://getmusicbee.com) | [插件](https://github.com/HenryPDT/mb_MediaControl) | - |
|
||||
| [MusicPlayer2](https://github.com/zhongyang219/MusicPlayer2) | - | - |
|
||||
| [PlanetMusic](https://apps.microsoft.com/detail/9nt5122pwqb8) | - | - |
|
||||
| [PotPlayer](https://potplayer.daum.net) | - | - |
|
||||
| [QQ 音乐](https://y.qq.com) | - | 确保使用较新版本,并在 QQ 音乐设置中启用 “显示系统媒体传输控制 (SMTC)”。 |
|
||||
| [Salt Player for Windows](https://moriafly.com/program/spw.html) | - | - |
|
||||
| [Spotify](https://open.spotify.com) | - | - |
|
||||
| [网易云音乐](https://music.163.com) | [BetterNCM](https://microblock.cc/betterncm) <br> [InfLink-rs](https://github.com/apoint123/inflink-rs) |  |
|
||||
| [Windows Media Player](https://apps.microsoft.com/detail/9wzdncrfj3pt) | - | - |
|
||||
| ... | ... | ... |
|
||||
|
||||
# 歌词源配置
|
||||
|
||||
## Apple Music
|
||||
|
||||
- 打开 [Apple Music 网站](https://music.apple.com/) 和开发者工具窗口。
|
||||
- 登录您的帐户。
|
||||
- 刷新页面。
|
||||
- 返回开发者工具窗口,选择 `Fetch/XHR`,选择一个请求,在请求头中找到 `media-user-token` 标头,并复制其值。
|
||||
- 打开 BetterLyrics 并转到 `播放源` 设置。
|
||||
- 将复制的值输入到 `Apple Music media-user-token` 设置中,然后点击右侧的接受图标。
|
||||
164
docs/USER_GUIDE.md
Normal file
@@ -0,0 +1,164 @@
|
||||
**English** | [**中文**](USER_GUIDE.CN.md)
|
||||
|
||||
# ❓ Frequently Asked Questions (FAQ)
|
||||
|
||||
## 🎵 Playback & Connection
|
||||
|
||||
### 🤔 I use Netease Cloud Music as my music player
|
||||
|
||||
It is strongly recommended to first browse the configuration guide [here](#known-supported-music-players-configuration-guide).
|
||||
|
||||
### 🤔 Shows "No music playing"
|
||||
|
||||
Some players require extra configuration. Please check [here](#known-supported-music-players-configuration-guide).
|
||||
|
||||
### 🤔 How to play local songs via this software?
|
||||
|
||||
1. Ensure the local songs folder has been added to the software (Refer to Step 1 in [How to set up local lyrics sources?](#-how-to-set-up-local-lyrics-sources)).
|
||||
2. Open `Music Library`.
|
||||
- Can be opened via the book button in the top-left area of the lyrics window.
|
||||
- Or by right-clicking the software icon in the system tray and selecting "Open Music Library".
|
||||
|
||||
## 🪟 Window & Interaction
|
||||
|
||||
### 🤔 How to move and resize the window?
|
||||
|
||||
If you cannot select or move the window, please check if you have set the `Draggable Area` option to `None` by mistake in the `Window` settings under `Lyrics Window Management`.
|
||||
|
||||
### 🤔 I can't see any buttons / The bottom command bar is hidden
|
||||
|
||||
**Top & Bottom Command Bars:**
|
||||
|
||||
- By default, when the mouse moves out of the top command bar and bottom command bar (playback control panel) areas, they automatically hide. Simply hover your mouse over these areas to show them again.
|
||||
- If the window is locked, just hover over the window, and you'll see the unlock button.
|
||||
|
||||
**Cannot summon bottom panel:**
|
||||
When the window is too small to display the panel, you can only show the playback control panel by hovering over the bottom of the lyrics window and clicking the white line.
|
||||
|
||||
### 🤔 What are the default shortcuts?
|
||||
|
||||
- `Ctrl + Alt + H`: Show/Hide lyrics window
|
||||
- `Ctrl + Alt + S`: Switch lyrics window status (mode)
|
||||
- `Ctrl + Alt + P`: Play/Pause current track
|
||||
- `Ctrl + Alt + Right`: Next track
|
||||
- `Ctrl + Alt + Left`: Previous track
|
||||
|
||||
> You can go to `Settings` -> `App Appearance & Behavior` to change the above shortcuts.
|
||||
|
||||
## 📃 Lyrics Display
|
||||
|
||||
### 🤔 Incorrect lyrics displayed (Mismatch)
|
||||
|
||||
- Please go to `Settings` -> `Playback Sources` -> `Lyrics Search Strategy` and select `Best Match`.
|
||||
> Note: For each song, the first time using Best Match will take about 10 seconds. Please be patient.
|
||||
|
||||
- Or open the lyrics search window to manually search for the correct lyrics.
|
||||
|
||||
> The lyrics search window can be opened in one of the following ways:
|
||||
> - Move the mouse to the lower area of the window until the bottom control bar appears, then click the magnifying glass icon (🔍) on the bottom right to open the search window.
|
||||
> - Right-click the software icon in the system tray and select "Open Lyrics Window".
|
||||
|
||||
### 🤔 Lyrics keep moving back and forth (Timeline jumping)
|
||||
|
||||
Go to `Settings` > `Playback Sources` > Disable `Lyrics Timeline Sync` or increase the `Lyrics Timeline Sync Threshold`.
|
||||
|
||||
### 🤔 How to set up local lyrics sources?
|
||||
|
||||
**Step 1: Add Folder**
|
||||
Go to `Settings` -> `Media Library`, click the `Add` button, add the folder where you store lyrics (or music files containing embedded lyrics), and ensure the switch on the right is set to **"On"**.
|
||||
|
||||
**Step 2: Prepare Files**
|
||||
The software supports two methods:
|
||||
|
||||
1. **External Lyrics Files (.lrc/.eslrc/.ttml)**
|
||||
When comparing, the software **does not distinguish word order** and **automatically ignores punctuation**.
|
||||
* **Recommended Naming:** `Artist - Title.lrc`
|
||||
* **Also Supports:** `Title Artist.lrc`
|
||||
* **Also Supports:** `Title (Live) - Artist.lrc`
|
||||
* *Example: When playing Taylor Swift's "Love Story", the filename `love_story_taylor_swift.lrc` can also be accurately identified.*
|
||||
|
||||
2. **Embedded Lyrics**
|
||||
If lyrics are already written into the tags of your local music files (.mp3/.flac, etc.), the software will also automatically read them.
|
||||
|
||||
> We recommend the following ways to check music file tag information:
|
||||
> - [Music Tag](https://www.cnblogs.com/vinlxc/p/11347744.html): Browse local song metadata.
|
||||
> - If **Step 1: Add Folder** is completed, go to the BetterLyrics `Music Library` and click the three dots icon (···) on the right of a music entry to show parsed metadata (may differ from actual info).
|
||||
|
||||
> To ensure smooth matching for the **Embedded Lyrics** method, the following tools are recommended:
|
||||
> - [Music Tag](https://www.cnblogs.com/vinlxc/p/11347744.html): Batch write **all metadata** into local music file tags.
|
||||
> - [LDDC](https://github.com/chenmozhijin/LDDC): Batch write **verbatim lyrics** into local music file tags.
|
||||
|
||||
### 🤔 Partial garbled text in lyrics
|
||||
|
||||
This is usually a default font setting issue. Go to `Settings` -> `Lyrics Window Management` -> `Lyrics Style` -> `Lyrics Font` -> Type `Arial` to get the most stable display effect.
|
||||
|
||||
## 🎨 Modes & Appearance
|
||||
|
||||
### 🤔 How to add more modes?
|
||||
|
||||
The software has initially added all preset modes for you.
|
||||
|
||||
You can import window status files shared by others: Go to `Settings` -> `Lyrics Window Management` -> Import (Down Arrow Icon) -> Select the file to import (`.json` format).
|
||||
|
||||
> To export window status, right-click the window status and select `Export`.
|
||||
|
||||
### 🤔 How to switch modes?
|
||||
|
||||
- Press the default shortcut `Ctrl + Alt + S`, then select the mode displayed on the screen to switch. (Press `Esc` to close the selection window).
|
||||
- Find the double-headed arrow icon in the top-left area of the lyrics window and click it to summon the lyrics window switcher.
|
||||
|
||||
## 📂 Data & Feedback
|
||||
|
||||
### 🤔 Where are lyrics cached?
|
||||
|
||||
`%LocalAppData%\Packages\37412.BetterLyrics_rd1g0rsrrtxw8\LocalCache\lyrics`
|
||||
|
||||
### 🤔 How to report issues? (Log location)
|
||||
|
||||
Please attach software logs when reporting issues. The log location is as follows:
|
||||
`%LocalAppData%\Packages\37412.BetterLyrics_rd1g0rsrrtxw8\LocalCache\logs`
|
||||
|
||||
# Known Supported Music Players (Configuration Guide)
|
||||
|
||||
Usage: Find your music player and install the `Plugin` listed in the table.
|
||||
|
||||
> <mark>Supported music players include, but are not limited to, the list below. Please refer to your actual experience for confirmation.</mark>
|
||||
|
||||
> <mark>All media players that have integrated with [SMTC](https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/integrate-with-systemmediatransportcontrols) are supported.</mark>
|
||||
|
||||
| Music Player | Plugin | Notes |
|
||||
| :--- | :--- | :--- |
|
||||
| [AIMP](https://www.aimp.ru) | [Plugin](https://www.aimp.ru/?do=catalog&rec_id=1097) | - |
|
||||
| [AMLL Player](https://github.com/Steve-xmh/applemusic-like-lyrics/blob/full-refractor/packages/player/README.md) | - | - |
|
||||
| [Apple Music](https://music.apple.com) | - | - |
|
||||
| [BetterLyrics](https://github.com/jayfunc/BetterLyrics) | - | - |
|
||||
| [foobar2000](https://www.foobar2000.org/windows) | [Plugin](https://github.com/dumbie/foo_mediacontrol) | Timeline issues |
|
||||
| [Google Chrome](https://www.google.com/chrome) | - | - |
|
||||
| [HyPlayer](https://github.com/HyPlayer/HyPlayer) | - | - |
|
||||
| [iTunes](https://apps.microsoft.com/detail/9pb2mz1zmb1s) | [Plugin](https://github.com/thewizrd/iTunes-SMTC) | - |
|
||||
| [Kugou Music](https://www.kugou.com) | - |  Timeline issues |
|
||||
| [Listen 1](https://listen1.github.io/listen1) | - | - |
|
||||
| [LX Music](https://github.com/lyswhut/lx-music-desktop) | - | Check "Enable Open API Service" in LX Music Settings "Open API";<br>Input LX Music server address in BetterLyrics Settings under "Playback Sources" -> "LX Music Server". |
|
||||
| [Microsoft Edge](https://www.microsoft.com/edge) | - | - |
|
||||
| [MoeKoe Music](https://github.com/MoeKoeMusic/MoeKoeMusic) | - | - |
|
||||
| [MusicBee](https://getmusicbee.com) | [Plugin](https://github.com/HenryPDT/mb_MediaControl) | - |
|
||||
| [MusicPlayer2](https://github.com/zhongyang219/MusicPlayer2) | - | - |
|
||||
| [Netease Cloud Music](https://music.163.com) | [BetterNCM](https://microblock.cc/betterncm) <br> [InfLink-rs](https://github.com/apoint123/inflink-rs) |  |
|
||||
| [PlanetMusic](https://apps.microsoft.com/detail/9nt5122pwqb8) | - | - |
|
||||
| [PotPlayer](https://potplayer.daum.net) | - | - |
|
||||
| [QQ Music](https://y.qq.com) | - | Ensure you are using a newer version, and enable "Show System Media Transport Controls (SMTC)" in QQ Music settings. |
|
||||
| [Salt Player for Windows](https://moriafly.com/program/spw.html) | - | - |
|
||||
| [Spotify](https://open.spotify.com) | - | - |
|
||||
| [Windows Media Player](https://apps.microsoft.com/detail/9wzdncrfj3pt) | - | - |
|
||||
| - | - | - |
|
||||
|
||||
# Lyrics Source Configuration
|
||||
|
||||
## Apple Music
|
||||
|
||||
- Open the [Apple Music website](https://music.apple.com/) and the Developer Tools window.
|
||||
- Log in to your account.
|
||||
- Refresh the page.
|
||||
- Return to the Developer Tools window, select `Fetch/XHR`, choose a request, find the `media-user-token` header in the request headers, and copy its value.
|
||||
- Open BetterLyrics and go to `Playback Sources` settings.
|
||||
- Input the copied value into the `Apple Music media-user-token` setting, then click the accept icon on the right.
|
||||
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 209 KiB |
|
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 12 MiB After Width: | Height: | Size: 12 MiB |
|
Before Width: | Height: | Size: 6.3 MiB After Width: | Height: | Size: 6.3 MiB |