mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-12 10:54:55 +08:00
fix: lyrics cache was not updated when searching without enabling cache, lyrics animation issue
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="37412.BetterLyrics"
|
||||
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
||||
Version="1.2.246.0" />
|
||||
Version="1.2.247.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace BetterLyrics.WinUI3.Constants
|
||||
{
|
||||
public static readonly TimeSpan DebounceTimeout = TimeSpan.FromMilliseconds(250);
|
||||
public static readonly TimeSpan AnimationDuration = TimeSpan.FromMilliseconds(350);
|
||||
public static readonly TimeSpan LongAnimationDuration = TimeSpan.FromMilliseconds(650);
|
||||
public static readonly TimeSpan WaitingDuration = TimeSpan.FromMilliseconds(300);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
private bool _isLayoutChanged = true;
|
||||
private bool _isMouseScrollingChanged = false;
|
||||
|
||||
private int _playingLineIndex;
|
||||
private int _primaryPlayingLineIndex;
|
||||
private (int Start, int End) _visibleRange;
|
||||
private double _canvasTargetScrollOffset;
|
||||
|
||||
@@ -382,7 +382,6 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
control: sender,
|
||||
ds: args.DrawingSession,
|
||||
lines: _renderLyricsLines,
|
||||
playingLineIndex: _playingLineIndex,
|
||||
mouseHoverLineIndex: _mouseHoverLineIndex,
|
||||
isMousePressing: _isMousePressing,
|
||||
startVisibleIndex: _visibleRange.Start,
|
||||
@@ -411,8 +410,6 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
return _synchronizer.GetLinePlayingProgress(
|
||||
_songPositionWithOffset.TotalMilliseconds,
|
||||
line,
|
||||
nextLine,
|
||||
songDuration,
|
||||
isForceWordByWord
|
||||
);
|
||||
}
|
||||
@@ -476,17 +473,17 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
#region UpdatePlayingLineIndex
|
||||
|
||||
int newPlayingIndex = _synchronizer.GetCurrentLineIndex(_songPositionWithOffset.TotalMilliseconds, _renderLyricsLines);
|
||||
bool isPlayingLineChanged = newPlayingIndex != _playingLineIndex;
|
||||
_playingLineIndex = newPlayingIndex;
|
||||
int primaryPlayingIndex = _synchronizer.GetCurrentLineIndex(_songPositionWithOffset.TotalMilliseconds, _renderLyricsLines);
|
||||
bool isPrimaryPlayingLineChanged = primaryPlayingIndex != _primaryPlayingLineIndex;
|
||||
_primaryPlayingLineIndex = primaryPlayingIndex;
|
||||
|
||||
#endregion
|
||||
|
||||
#region UpdateTargetScrollOffset
|
||||
|
||||
if (isPlayingLineChanged || _isLayoutChanged)
|
||||
if (isPrimaryPlayingLineChanged || _isLayoutChanged)
|
||||
{
|
||||
var targetScroll = LyricsLayoutManager.CalculateTargetScrollOffset(_renderLyricsLines, _playingLineIndex);
|
||||
var targetScroll = LyricsLayoutManager.CalculateTargetScrollOffset(_renderLyricsLines, _primaryPlayingLineIndex);
|
||||
if (targetScroll.HasValue) _canvasTargetScrollOffset = targetScroll.Value;
|
||||
|
||||
_canvasYScrollTransition.SetEasingType(lyricsEffect.LyricsScrollEasingType);
|
||||
@@ -524,7 +521,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
_renderLyricsLines,
|
||||
_isMouseScrolling ? maxRange.Start : _visibleRange.Start,
|
||||
_isMouseScrolling ? maxRange.End : _visibleRange.End,
|
||||
_playingLineIndex,
|
||||
_primaryPlayingLineIndex,
|
||||
sender.Size.Height,
|
||||
_canvasTargetScrollOffset,
|
||||
lyricsStyle.PlayingLineTopOffset / 100.0,
|
||||
@@ -536,7 +533,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
elapsedTime,
|
||||
_isMouseScrolling,
|
||||
_isLayoutChanged,
|
||||
isPlayingLineChanged,
|
||||
isPrimaryPlayingLineChanged,
|
||||
_isMouseScrollingChanged,
|
||||
_songPositionWithOffset.TotalMilliseconds
|
||||
);
|
||||
@@ -669,15 +666,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
private void UpdateRenderLyricsLines()
|
||||
{
|
||||
_renderLyricsLines = null;
|
||||
var lines = _gsmtcService.CurrentLyricsData?.LyricsLines.Select(x => new RenderLyricsLine()
|
||||
{
|
||||
LyricsSyllables = x.LyricsSyllables,
|
||||
StartMs = x.StartMs,
|
||||
EndMs = x.EndMs,
|
||||
PhoneticText = x.PhoneticText,
|
||||
OriginalText = x.OriginalText,
|
||||
TranslatedText = x.TranslatedText
|
||||
}).ToList();
|
||||
var lines = _gsmtcService.CurrentLyricsData?.LyricsLines.Select(x => new RenderLyricsLine(x)).ToList();
|
||||
if (lines != null)
|
||||
{
|
||||
LyricsLayoutManager.CalculateLanes(lines);
|
||||
|
||||
@@ -108,6 +108,14 @@
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsFloatAnimationAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="LyricsEffectSettingsControlAnimationDuration">
|
||||
<local:ExtendedSlider
|
||||
Default="450"
|
||||
Maximum="2000"
|
||||
Minimum="0"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsFloatAnimationDuration, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Button>
|
||||
</Grid>
|
||||
<local:PropertyRow Grid.Column="1" Value="{x:Bind OriginalText, Mode=OneWay}" />
|
||||
<local:PropertyRow Grid.Column="1" Value="{x:Bind PrimaryText, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
|
||||
@@ -447,7 +447,7 @@
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind ViewModel.TimelineSliderThumbLyricsLine.StartMs, Converter={StaticResource MillisecondsToFormattedTimeConverter}, Mode=OneWay}" />
|
||||
<!-- TODO 原文翻译共同显示 -->
|
||||
<TextBlock Margin="0,0,0,2" Text="{x:Bind ViewModel.TimelineSliderThumbLyricsLine.OriginalText, Mode=OneWay}" />
|
||||
<TextBlock Margin="0,0,0,2" Text="{x:Bind ViewModel.TimelineSliderThumbLyricsLine.PrimaryText, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid
|
||||
|
||||
@@ -228,6 +228,9 @@
|
||||
</dev:SettingsExpander.HeaderIcon>
|
||||
<ToggleSwitch IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="LyricsSearchControlIgnoreCache">
|
||||
<CheckBox IsChecked="{Binding IgnoreCacheWhenSearching, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageOverwriteMatchingThreshold">
|
||||
<ToggleSwitch IsOn="{Binding IsMatchingThresholdOverwritten, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
StartMs = 0,
|
||||
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
|
||||
OriginalText = "● ● ●",
|
||||
PrimaryText = "● ● ●",
|
||||
},
|
||||
],
|
||||
LanguageCode = "N/A",
|
||||
@@ -37,12 +37,12 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
if (transLine != null)
|
||||
{
|
||||
// 此处 transLine.OriginalText 指翻译中的“原文”属性
|
||||
line.TranslatedText = transLine.OriginalText;
|
||||
line.SecondaryText = transLine.PrimaryText;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有匹配的翻译
|
||||
line.TranslatedText = "";
|
||||
line.SecondaryText = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,12 +58,12 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
if (transLine != null)
|
||||
{
|
||||
// 此处 transLine.OriginalText 指音译中的“原文”属性
|
||||
line.PhoneticText = transLine.OriginalText;
|
||||
line.TertiaryText = transLine.PrimaryText;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有匹配的音译
|
||||
line.PhoneticText = "";
|
||||
line.TertiaryText = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,11 +76,11 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
if (i >= translationArr.Count)
|
||||
{
|
||||
line.TranslatedText = ""; // No translation available, keep empty
|
||||
line.SecondaryText = ""; // No translation available, keep empty
|
||||
}
|
||||
else
|
||||
{
|
||||
line.TranslatedText = translationArr[i];
|
||||
line.SecondaryText = translationArr[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -94,11 +94,11 @@ namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
if (i >= transliterationArr.Count)
|
||||
{
|
||||
line.PhoneticText = ""; // No transliteration available, keep empty
|
||||
line.TertiaryText = ""; // No transliteration available, keep empty
|
||||
}
|
||||
else
|
||||
{
|
||||
line.PhoneticText = transliterationArr[i];
|
||||
line.TertiaryText = transliterationArr[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Entities;
|
||||
using F23.StringSimilarity;
|
||||
using System;
|
||||
using System.IO;
|
||||
@@ -17,21 +18,31 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
// JaroWinkler 适合短字符串匹配
|
||||
private static readonly JaroWinkler _algo = new();
|
||||
|
||||
public static int CalculateScore(SongInfo local, LyricsCacheItem remote)
|
||||
public static int CalculateScore(SongInfo songInfo, LyricsCacheItem remote)
|
||||
{
|
||||
if (local == null || remote == null) return 0;
|
||||
return CalculateScore(songInfo, remote.Title, remote.Artist, remote.Album, remote.Duration * 1000);
|
||||
}
|
||||
|
||||
public static int CalculateScore(SongInfo songInfo, FilesIndexItem local)
|
||||
{
|
||||
return CalculateScore(songInfo, local.Title, local.Artist, local.Album, local.Duration * 1000, local.FileName);
|
||||
}
|
||||
|
||||
public static int CalculateScore(
|
||||
SongInfo songInfo,
|
||||
string? compareTitle, string? compareArtist, string? compareAlbum, double? compareDurationMs, string? compareFileName = null)
|
||||
{
|
||||
double totalScore = 0;
|
||||
|
||||
bool localHasMetadata = !string.IsNullOrWhiteSpace(local.Title);
|
||||
bool remoteHasMetadata = !string.IsNullOrWhiteSpace(remote.Title);
|
||||
bool localHasMetadata = !string.IsNullOrWhiteSpace(songInfo.Title);
|
||||
bool remoteHasMetadata = !string.IsNullOrWhiteSpace(compareTitle);
|
||||
|
||||
if (localHasMetadata && remoteHasMetadata)
|
||||
{
|
||||
double titleScore = GetStringSimilarity(local.Title, remote.Title);
|
||||
double artistScore = GetStringSimilarity(local.Artist, remote.Artist);
|
||||
double albumScore = GetStringSimilarity(local.Album, remote.Album);
|
||||
double durationScore = GetDurationSimilarity(local.DurationMs, remote.Duration);
|
||||
double titleScore = GetStringSimilarity(songInfo.Title, compareTitle);
|
||||
double artistScore = GetStringSimilarity(songInfo.Artist, compareArtist);
|
||||
double albumScore = GetStringSimilarity(songInfo.Album, compareAlbum);
|
||||
double durationScore = GetDurationSimilarity(songInfo.DurationMs, compareDurationMs);
|
||||
|
||||
totalScore = (titleScore * WeightTitle) +
|
||||
(artistScore * WeightArtist) +
|
||||
@@ -41,12 +52,12 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
else
|
||||
{
|
||||
string? localQuery = localHasMetadata
|
||||
? $"{local.Title} {local.Artist}"
|
||||
: Path.GetFileNameWithoutExtension(local.LinkedFileName);
|
||||
? $"{songInfo.Title} {songInfo.Artist}"
|
||||
: Path.GetFileNameWithoutExtension(songInfo.LinkedFileName);
|
||||
|
||||
string? remoteQuery = remoteHasMetadata
|
||||
? $"{remote.Title} {remote.Artist}"
|
||||
: null;
|
||||
? $"{compareTitle} {compareArtist}"
|
||||
: Path.GetFileNameWithoutExtension(compareFileName);
|
||||
|
||||
string fp1 = CreateSortedFingerprint(localQuery);
|
||||
string fp2 = CreateSortedFingerprint(remoteQuery);
|
||||
|
||||
@@ -64,6 +64,16 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
_durationSeconds = seconds;
|
||||
}
|
||||
|
||||
public void SetDurationMs(double millionSeconds)
|
||||
{
|
||||
SetDuration(millionSeconds / 1000.0);
|
||||
}
|
||||
|
||||
public void SetDuration(TimeSpan timeSpan)
|
||||
{
|
||||
SetDuration(timeSpan.TotalSeconds);
|
||||
}
|
||||
|
||||
public void SetDelay(double seconds)
|
||||
{
|
||||
_delaySeconds = seconds;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models.Lyrics;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using DevWinUI;
|
||||
@@ -49,15 +50,15 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
var line = lines.ElementAtOrDefault(i);
|
||||
if (line == null) continue;
|
||||
|
||||
bool isSecondaryLinePlaying = line.StartMs <= currentPositionMs && currentPositionMs <= line.EndMs;
|
||||
if (i == primaryPlayingLineIndex) isSecondaryLinePlaying = true;
|
||||
bool isSecondaryLinePlaying = line.GetIsPlaying(currentPositionMs);
|
||||
bool isSecondaryLinePlayingChanged = line.IsPlayingLastFrame != isSecondaryLinePlaying;
|
||||
line.IsPlayingLastFrame = isSecondaryLinePlaying;
|
||||
|
||||
// 行动画
|
||||
if (isLayoutChanged || isPrimaryPlayingLineChanged || isMouseScrollingChanged || isSecondaryLinePlayingChanged)
|
||||
{
|
||||
int lineCountDelta = i - primaryPlayingLineIndex;
|
||||
double distanceFromPlayingLine = Math.Abs(line.OriginalPosition.Y - currentPlayingLine.OriginalPosition.Y);
|
||||
double distanceFromPlayingLine = Math.Abs(line.PrimaryPosition.Y - currentPlayingLine.PrimaryPosition.Y);
|
||||
|
||||
double distanceFactor;
|
||||
if (lineCountDelta < 0)
|
||||
@@ -151,61 +152,27 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
line.YOffsetTransition.StartTransition(targetYScrollOffset);
|
||||
}
|
||||
|
||||
if (line.RenderLyricsOriginalChars != null)
|
||||
var maxAnimationDurationMs = Math.Max(line.EndMs - currentPositionMs, 0);
|
||||
|
||||
// 字符动画
|
||||
foreach (var renderChar in line.PrimaryRenderChars)
|
||||
{
|
||||
foreach (var renderChar in line.RenderLyricsOriginalChars)
|
||||
{
|
||||
var syllable = line.LyricsSyllables.FirstOrDefault(x => x.StartIndex <= renderChar.Index && renderChar.Index <= x.EndIndex);
|
||||
if (syllable == null) continue;
|
||||
renderChar.ProgressPlayed = renderChar.GetPlayProgress(currentPositionMs);
|
||||
|
||||
var avgCharDuration = syllable.DurationMs / syllable.Length;
|
||||
if (avgCharDuration == null || avgCharDuration == 0) continue;
|
||||
|
||||
var charStartMs = syllable.StartMs + (renderChar.Index - syllable.StartIndex) * avgCharDuration.Value;
|
||||
var charEndMs = charStartMs + avgCharDuration;
|
||||
var progressPlayed = (currentPositionMs - charStartMs) / avgCharDuration.Value;
|
||||
progressPlayed = Math.Clamp(progressPlayed, 0, 1);
|
||||
renderChar.ProgressPlayed = progressPlayed;
|
||||
|
||||
bool isCharPlaying = charStartMs <= currentPositionMs && currentPositionMs <= charEndMs;
|
||||
bool isCharPlaying = renderChar.GetIsPlaying(currentPositionMs);
|
||||
bool isCharPlayingChanged = renderChar.IsPlayingLastFrame != isCharPlaying;
|
||||
|
||||
if (isSecondaryLinePlayingChanged || isCharPlayingChanged)
|
||||
{
|
||||
if (lyricsEffect.IsLyricsScaleEffectEnabled)
|
||||
{
|
||||
double targetScale =
|
||||
lyricsEffect.IsLyricsScaleEffectAmountAutoAdjust ? 1.15 : lyricsEffect.LyricsScaleEffectAmount / 100.0;
|
||||
|
||||
if (isCharPlayingChanged)
|
||||
{
|
||||
if (syllable.DurationMs >= lyricsEffect.LyricsScaleEffectLongSyllableDuration)
|
||||
{
|
||||
renderChar.ScaleTransition.SetDuration((syllable.DurationMs ?? 0) / 1000.0 / 2);
|
||||
renderChar.ScaleTransition.StartTransition(isCharPlaying ? targetScale : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lyricsEffect.IsLyricsGlowEffectEnabled)
|
||||
{
|
||||
double targetGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust ? renderChar.LayoutRect.Height * 0.2 : lyricsEffect.LyricsGlowEffectAmount;
|
||||
switch (lyricsEffect.LyricsGlowEffectScope)
|
||||
{
|
||||
case Enums.LyricsEffectScope.LongDurationSyllable:
|
||||
if (isCharPlayingChanged)
|
||||
{
|
||||
if (syllable.DurationMs >= lyricsEffect.LyricsGlowEffectLongSyllableDuration)
|
||||
{
|
||||
renderChar.GlowTransition.SetDuration((syllable.DurationMs ?? 0) / 1000.0 / 2);
|
||||
renderChar.GlowTransition.StartTransition(isCharPlaying ? targetGlow : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Enums.LyricsEffectScope.LineStartToCurrentChar:
|
||||
if (isSecondaryLinePlayingChanged)
|
||||
{
|
||||
renderChar.GlowTransition.SetDuration(renderChar.AnimationDuration);
|
||||
renderChar.GlowTransition.SetDurationMs(Math.Min(Time.AnimationDuration.TotalMilliseconds, maxAnimationDurationMs));
|
||||
renderChar.GlowTransition.StartTransition(isSecondaryLinePlaying ? targetGlow : 0);
|
||||
}
|
||||
break;
|
||||
@@ -225,18 +192,74 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
}
|
||||
if (isCharPlayingChanged)
|
||||
{
|
||||
renderChar.FloatTransition.SetDurationMs(Math.Min(lyricsEffect.LyricsFloatAnimationDuration, maxAnimationDurationMs));
|
||||
renderChar.FloatTransition.StartTransition(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (isCharPlayingChanged)
|
||||
{
|
||||
renderChar.IsPlayingLastFrame = isCharPlaying;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 音节动画
|
||||
foreach (var syllable in line.PrimaryRenderSyllables)
|
||||
{
|
||||
bool isSyllablePlaying = syllable.GetIsPlaying(currentPositionMs);
|
||||
bool isSyllablePlayingChanged = syllable.IsPlayingLastFrame != isSyllablePlaying;
|
||||
|
||||
if (isSyllablePlayingChanged)
|
||||
{
|
||||
var syllableHeight = syllable.ChildrenRenderLyricsChars.FirstOrDefault()?.LayoutRect.Height ?? 0;
|
||||
|
||||
if (lyricsEffect.IsLyricsScaleEffectEnabled)
|
||||
{
|
||||
double targetScale =
|
||||
lyricsEffect.IsLyricsScaleEffectAmountAutoAdjust ? 1.15 : lyricsEffect.LyricsScaleEffectAmount / 100.0;
|
||||
|
||||
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
|
||||
{
|
||||
if (syllable.DurationMs >= lyricsEffect.LyricsScaleEffectLongSyllableDuration)
|
||||
{
|
||||
renderChar.ScaleTransition.SetDurationMs(Math.Min(syllable.DurationMs, maxAnimationDurationMs) / 2.0);
|
||||
renderChar.ScaleTransition.StartTransition(isSyllablePlaying ? targetScale : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lyricsEffect.IsLyricsGlowEffectEnabled)
|
||||
{
|
||||
double targetGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust ? syllableHeight * 0.2 : lyricsEffect.LyricsGlowEffectAmount;
|
||||
switch (lyricsEffect.LyricsGlowEffectScope)
|
||||
{
|
||||
case Enums.LyricsEffectScope.LongDurationSyllable:
|
||||
if (syllable.DurationMs >= lyricsEffect.LyricsGlowEffectLongSyllableDuration)
|
||||
{
|
||||
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
|
||||
{
|
||||
renderChar.GlowTransition.SetDurationMs(Math.Min(syllable.DurationMs, maxAnimationDurationMs) / 2.0);
|
||||
renderChar.GlowTransition.StartTransition(isSyllablePlaying ? targetGlow : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
syllable.IsPlayingLastFrame = isSyllablePlaying;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新动画
|
||||
foreach (var renderChar in line.PrimaryRenderChars)
|
||||
{
|
||||
renderChar.ScaleTransition.Update(elapsedTime);
|
||||
renderChar.GlowTransition.Update(elapsedTime);
|
||||
renderChar.FloatTransition.Update(elapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
line.AngleTransition.Update(elapsedTime);
|
||||
line.ScaleTransition.Update(elapsedTime);
|
||||
|
||||
@@ -79,52 +79,52 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
// 左上角坐标
|
||||
line.TopLeftPosition = new Vector2(0, (float)currentY);
|
||||
// 注音层
|
||||
line.PhoneticPosition = line.TopLeftPosition;
|
||||
if (line.PhoneticCanvasTextLayout != null)
|
||||
line.TertiaryPosition = line.TopLeftPosition;
|
||||
if (line.TertiaryTextLayout != null)
|
||||
{
|
||||
currentY += line.PhoneticCanvasTextLayout.LayoutBounds.Height;
|
||||
currentY += line.TertiaryTextLayout.LayoutBounds.Height;
|
||||
// 间距
|
||||
currentY += (line.PhoneticCanvasTextLayout.LayoutBounds.Height / line.PhoneticCanvasTextLayout.LineCount) * 0.1;
|
||||
currentY += (line.TertiaryTextLayout.LayoutBounds.Height / line.TertiaryTextLayout.LineCount) * 0.1;
|
||||
|
||||
actualWidth = Math.Max(actualWidth, line.PhoneticCanvasTextLayout.LayoutBounds.Width);
|
||||
actualWidth = Math.Max(actualWidth, line.TertiaryTextLayout.LayoutBounds.Width);
|
||||
}
|
||||
|
||||
// 原文层
|
||||
line.OriginalPosition = new Vector2(0, (float)currentY);
|
||||
if (line.OriginalCanvasTextLayout != null)
|
||||
line.PrimaryPosition = new Vector2(0, (float)currentY);
|
||||
if (line.PrimaryTextLayout != null)
|
||||
{
|
||||
currentY += line.OriginalCanvasTextLayout.LayoutBounds.Height;
|
||||
currentY += line.PrimaryTextLayout.LayoutBounds.Height;
|
||||
|
||||
actualWidth = Math.Max(actualWidth, line.OriginalCanvasTextLayout.LayoutBounds.Width);
|
||||
actualWidth = Math.Max(actualWidth, line.PrimaryTextLayout.LayoutBounds.Width);
|
||||
}
|
||||
|
||||
// 翻译层
|
||||
if (line.TranslatedCanvasTextLayout != null)
|
||||
if (line.SecondaryTextLayout != null)
|
||||
{
|
||||
// 间距
|
||||
currentY += (line.TranslatedCanvasTextLayout.LayoutBounds.Height / line.TranslatedCanvasTextLayout.LineCount) * 0.1;
|
||||
currentY += (line.SecondaryTextLayout.LayoutBounds.Height / line.SecondaryTextLayout.LineCount) * 0.1;
|
||||
}
|
||||
line.TranslatedPosition = new Vector2(0, (float)currentY);
|
||||
if (line.TranslatedCanvasTextLayout != null)
|
||||
line.SecondaryPosition = new Vector2(0, (float)currentY);
|
||||
if (line.SecondaryTextLayout != null)
|
||||
{
|
||||
currentY += line.TranslatedCanvasTextLayout.LayoutBounds.Height;
|
||||
currentY += line.SecondaryTextLayout.LayoutBounds.Height;
|
||||
|
||||
actualWidth = Math.Max(actualWidth, line.TranslatedCanvasTextLayout.LayoutBounds.Width);
|
||||
actualWidth = Math.Max(actualWidth, line.SecondaryTextLayout.LayoutBounds.Width);
|
||||
}
|
||||
|
||||
// 右下角坐标
|
||||
line.BottomRightPosition = new Vector2(0 + (float)actualWidth, (float)currentY);
|
||||
|
||||
// 行间距
|
||||
if (line.OriginalCanvasTextLayout != null)
|
||||
if (line.PrimaryTextLayout != null)
|
||||
{
|
||||
currentY += (line.OriginalCanvasTextLayout.LayoutBounds.Height / line.OriginalCanvasTextLayout.LineCount) * style.LyricsLineSpacingFactor;
|
||||
currentY += (line.PrimaryTextLayout.LayoutBounds.Height / line.PrimaryTextLayout.LineCount) * style.LyricsLineSpacingFactor;
|
||||
}
|
||||
|
||||
// 更新中心点
|
||||
line.UpdateCenterPosition(lyricsWidth, style.LyricsAlignmentType);
|
||||
|
||||
line.RecalculateCharacterGeometries();
|
||||
line.RecreateRenderChars();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,9 +140,9 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
var currentLine = lines.ElementAtOrDefault(playingLineIndex);
|
||||
var firstLine = lines.FirstOrDefault();
|
||||
|
||||
if (currentLine?.OriginalCanvasTextLayout == null || firstLine == null) return null;
|
||||
if (currentLine?.PrimaryTextLayout == null || firstLine == null) return null;
|
||||
|
||||
return -currentLine.OriginalPosition.Y + firstLine.OriginalPosition.Y
|
||||
return -currentLine.PrimaryPosition.Y + firstLine.PrimaryPosition.Y
|
||||
- (currentLine.BottomRightPosition.Y - currentLine.TopLeftPosition.Y) / 2.0;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
lanesEndMs.Add(0);
|
||||
}
|
||||
|
||||
lanesEndMs[assignedLane] = end ?? 0;
|
||||
lanesEndMs[assignedLane] = end;
|
||||
line.LaneIndex = assignedLane;
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,7 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
{
|
||||
int mid = (left + right) / 2;
|
||||
var line = lines[mid];
|
||||
if (line.OriginalCanvasTextLayout == null) break;
|
||||
if (line.PrimaryTextLayout == null) break;
|
||||
double value = offset + line.BottomRightPosition.Y;
|
||||
if (value >= mousePosition.Y) { result = mid; right = mid - 1; }
|
||||
else { left = mid + 1; }
|
||||
@@ -267,7 +267,7 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
{
|
||||
int mid = (left + right) / 2;
|
||||
var line = lines[mid];
|
||||
if (line.OriginalCanvasTextLayout == null) break;
|
||||
if (line.PrimaryTextLayout == null) break;
|
||||
double value = offset + line.BottomRightPosition.Y;
|
||||
// 理论上说应该使用下面这一行来精确计算视野内的首个可见行,但是考虑到动画视觉效果,还是注释掉了
|
||||
//if (value >= lyricsY) { result = mid; right = mid - 1; }
|
||||
@@ -284,7 +284,7 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
{
|
||||
int mid = (left + right) / 2;
|
||||
var line = lines[mid];
|
||||
if (line.OriginalCanvasTextLayout == null) break;
|
||||
if (line.PrimaryTextLayout == null) break;
|
||||
double value = offset + line.BottomRightPosition.Y;
|
||||
// 同理
|
||||
//if (value >= lyricsY + lyricsHeight) { result = mid; right = mid - 1; }
|
||||
|
||||
@@ -66,19 +66,14 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
|
||||
public LinePlaybackState GetLinePlayingProgress(
|
||||
double currentTimeMs,
|
||||
LyricsLine line,
|
||||
LyricsLine? nextLine,
|
||||
double songDurationMs,
|
||||
RenderLyricsLine line,
|
||||
bool isForceWordByWord)
|
||||
{
|
||||
var state = new LinePlaybackState { SyllableStartIndex = 0, SyllableLength = 0, SyllableProgress = 0 };
|
||||
|
||||
if (line == null) return state;
|
||||
|
||||
double lineEndMs;
|
||||
if (line.EndMs != null) lineEndMs = line.EndMs.Value;
|
||||
else if (nextLine != null) lineEndMs = nextLine.StartMs;
|
||||
else lineEndMs = songDurationMs;
|
||||
double lineEndMs = line.EndMs;
|
||||
|
||||
// 还没到
|
||||
if (currentTimeMs < line.StartMs) return state;
|
||||
@@ -87,42 +82,43 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
if (currentTimeMs > lineEndMs)
|
||||
{
|
||||
state.SyllableProgress = 1f;
|
||||
state.SyllableStartIndex = Math.Max(0, line.OriginalText.Length - 1);
|
||||
state.SyllableStartIndex = Math.Max(0, line.PrimaryText.Length - 1);
|
||||
state.SyllableLength = 1;
|
||||
return state;
|
||||
}
|
||||
|
||||
// 逐字
|
||||
if (line.LyricsSyllables != null && line.LyricsSyllables.Count > 1)
|
||||
if (line.PrimaryRenderSyllables != null && line.PrimaryRenderSyllables.Count > 1)
|
||||
{
|
||||
return CalculateSyllableProgress(currentTimeMs, line, lineEndMs);
|
||||
}
|
||||
|
||||
// 强制逐字
|
||||
if (isForceWordByWord && line.OriginalText.Length > 0)
|
||||
if (isForceWordByWord && line.PrimaryText.Length > 0)
|
||||
{
|
||||
return CalculateSimulatedProgress(currentTimeMs, line, lineEndMs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 普通行
|
||||
state.SyllableStartIndex = line.OriginalText.Length;
|
||||
state.SyllableStartIndex = line.PrimaryText.Length;
|
||||
state.SyllableProgress = 1f;
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
private LinePlaybackState CalculateSyllableProgress(double time, LyricsLine line, double lineEndMs)
|
||||
private LinePlaybackState CalculateSyllableProgress(double time, RenderLyricsLine line, double lineEndMs)
|
||||
{
|
||||
var state = new LinePlaybackState();
|
||||
int count = line.LyricsSyllables.Count;
|
||||
int count = line.PrimaryRenderSyllables.Count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var timing = line.LyricsSyllables[i];
|
||||
var nextTiming = (i + 1 < count) ? line.LyricsSyllables[i + 1] : null;
|
||||
var timing = line.PrimaryRenderSyllables[i];
|
||||
var nextTiming = (i + 1 < count) ? line.PrimaryRenderSyllables[i + 1] : null;
|
||||
|
||||
double timingEndMs = timing.EndMs ?? nextTiming?.StartMs ?? lineEndMs;
|
||||
//double timingEndMs = timing.EndMs ?? nextTiming?.StartMs ?? lineEndMs;
|
||||
double timingEndMs = timing.EndMs;
|
||||
|
||||
// 在当前字范围内
|
||||
if (time >= timing.StartMs && time <= timingEndMs)
|
||||
@@ -146,10 +142,10 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
return state;
|
||||
}
|
||||
|
||||
private LinePlaybackState CalculateSimulatedProgress(double time, LyricsLine line, double lineEndMs)
|
||||
private LinePlaybackState CalculateSimulatedProgress(double time, RenderLyricsLine line, double lineEndMs)
|
||||
{
|
||||
var state = new LinePlaybackState();
|
||||
int textLength = line.OriginalText.Length;
|
||||
int textLength = line.PrimaryText.Length;
|
||||
|
||||
double progress = (time - line.StartMs) / (lineEndMs - line.StartMs);
|
||||
progress = Math.Clamp(progress, 0, 1);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class BaseLyrics
|
||||
{
|
||||
public int StartMs { get; set; }
|
||||
public int EndMs { get; set; }
|
||||
public int DurationMs => EndMs - StartMs;
|
||||
|
||||
public string Text { get; set; } = "";
|
||||
public int Length => Text.Length;
|
||||
|
||||
public int StartIndex { get; set; }
|
||||
public int EndIndex => StartIndex + Length - 1;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class BaseRenderLyrics : BaseLyrics
|
||||
{
|
||||
public bool IsPlayingLastFrame { get; set; } = false;
|
||||
|
||||
public BaseRenderLyrics(BaseLyrics baseLyrics)
|
||||
{
|
||||
this.Text = baseLyrics.Text;
|
||||
this.StartMs = baseLyrics.StartMs;
|
||||
this.EndMs = baseLyrics.EndMs;
|
||||
this.StartIndex = baseLyrics.StartIndex;
|
||||
}
|
||||
|
||||
public bool GetIsPlaying(double currentMs) => this.StartMs <= currentMs && currentMs < this.EndMs;
|
||||
public double GetPlayProgress(double currentMs) => Math.Clamp((currentMs - this.StartMs) / this.DurationMs, 0, 1);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class LyricsChar
|
||||
{
|
||||
public int StartMs { get; set; }
|
||||
public int EndMs { get; set; }
|
||||
public int DurationMs => EndMs - StartMs;
|
||||
|
||||
public string Text { get; set; } = "";
|
||||
public int Index { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
set => field = value;
|
||||
}
|
||||
public bool AutoGenerated { get; set; } = false;
|
||||
public string WrappedOriginalText => string.Join(StringHelper.NewLine, LyricsLines.Select(line => line.OriginalText));
|
||||
public string WrappedOriginalText => string.Join(StringHelper.NewLine, LyricsLines.Select(line => line.PrimaryText));
|
||||
|
||||
public LyricsData()
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
StartMs = 0,
|
||||
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
|
||||
OriginalText = _localizationService.GetLocalizedString("LyricsNotFound"),
|
||||
PrimaryText = _localizationService.GetLocalizedString("LyricsNotFound"),
|
||||
}]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,46 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class LyricsLine
|
||||
public class LyricsLine : BaseLyrics
|
||||
{
|
||||
public List<LyricsSyllable> LyricsSyllables { get; set; } = [];
|
||||
public List<BaseLyrics> PrimarySyllables { get; set; } = [];
|
||||
public List<BaseLyrics> SecondarySyllables { get; set; } = [];
|
||||
public List<BaseLyrics> TertiarySyllables { get; set; } = [];
|
||||
|
||||
public int? DurationMs => EndMs - StartMs;
|
||||
public int? EndMs { get; set; }
|
||||
public int StartMs { get; set; }
|
||||
public List<BaseLyrics> PrimaryChars { get; private set; } = [];
|
||||
public List<BaseLyrics> SecondaryChars { get; private set; } = [];
|
||||
public List<BaseLyrics> TertiaryChars { get; private set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 原文
|
||||
/// </summary>
|
||||
public string OriginalText { get; set; } = "";
|
||||
/// <summary>
|
||||
/// 译文
|
||||
/// </summary>
|
||||
public string TranslatedText { get; set; } = "";
|
||||
/// <summary>
|
||||
/// 注音
|
||||
/// </summary>
|
||||
public string PhoneticText { get; set; } = "";
|
||||
public string PrimaryText { get; set; } = "";
|
||||
public string SecondaryText { get; set; } = "";
|
||||
public string TertiaryText { get; set; } = "";
|
||||
|
||||
public LyricsLine()
|
||||
{
|
||||
for (int charStartIndex = 0; charStartIndex < PrimaryText.Length; charStartIndex++)
|
||||
{
|
||||
var syllable = PrimarySyllables.FirstOrDefault(x => x.StartIndex <= charStartIndex && charStartIndex <= x.EndIndex);
|
||||
if (syllable == null) continue;
|
||||
|
||||
var avgCharDuration = syllable.DurationMs / syllable.Length;
|
||||
if (avgCharDuration == 0) continue;
|
||||
|
||||
var charStartMs = syllable.StartMs + (charStartIndex - syllable.StartIndex) * avgCharDuration;
|
||||
var charEndMs = charStartMs + avgCharDuration;
|
||||
|
||||
PrimaryChars.Add(new BaseLyrics
|
||||
{
|
||||
StartIndex = charStartIndex,
|
||||
StartMs = charStartMs,
|
||||
EndMs = charEndMs,
|
||||
Text = PrimaryText[charStartIndex].ToString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class LyricsSyllable
|
||||
{
|
||||
public string Text { get; set; } = string.Empty;
|
||||
public int Length => Text.Length;
|
||||
|
||||
public int StartIndex { get; set; }
|
||||
public int EndIndex => StartIndex + Length - 1;
|
||||
|
||||
public int StartMs { get; set; }
|
||||
public int? EndMs { get; set; }
|
||||
|
||||
public int? DurationMs => EndMs - StartMs;
|
||||
public bool IsLongDuration => DurationMs >= 700;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class RenderLyricsChar : LyricsChar
|
||||
public class RenderLyricsChar : BaseRenderLyrics
|
||||
{
|
||||
public Rect LayoutRect { get; set; }
|
||||
|
||||
public double AnimationDuration { get; set; } = 0.3;
|
||||
public Rect LayoutRect { get; private set; }
|
||||
|
||||
public ValueTransition<double> ScaleTransition { get; set; }
|
||||
public ValueTransition<double> GlowTransition { get; set; }
|
||||
@@ -16,25 +15,24 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
|
||||
public double ProgressPlayed { get; set; } = 0; // 0~1
|
||||
|
||||
public bool IsPlayingLastFrame { get; set; } = false;
|
||||
|
||||
public RenderLyricsChar()
|
||||
public RenderLyricsChar(BaseLyrics lyricsChars, Rect layoutRect) : base(lyricsChars)
|
||||
{
|
||||
ScaleTransition = new(
|
||||
initialValue: 1.0,
|
||||
durationSeconds: AnimationDuration,
|
||||
durationSeconds: Time.AnimationDuration.TotalSeconds,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
GlowTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
durationSeconds: Time.AnimationDuration.TotalSeconds,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
FloatTransition = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: AnimationDuration,
|
||||
durationSeconds: Time.LongAnimationDuration.TotalSeconds,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
LayoutRect = layoutRect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,10 @@ using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class RenderLyricsLine : LyricsLine
|
||||
public class RenderLyricsLine : BaseRenderLyrics
|
||||
{
|
||||
public List<RenderLyricsChar> RenderLyricsOriginalChars { get; set; } = [];
|
||||
public List<RenderLyricsChar> PrimaryRenderChars { get; private set; } = [];
|
||||
public List<RenderLyricsSyllable> PrimaryRenderSyllables { get; private set; }
|
||||
|
||||
public double AnimationDuration { get; set; } = 0.3;
|
||||
|
||||
@@ -28,22 +29,22 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
public ValueTransition<double> YOffsetTransition { get; set; }
|
||||
public ValueTransition<Color> ColorTransition { get; set; }
|
||||
|
||||
public CanvasTextLayout? OriginalCanvasTextLayout { get; private set; }
|
||||
public CanvasTextLayout? TranslatedCanvasTextLayout { get; private set; }
|
||||
public CanvasTextLayout? PhoneticCanvasTextLayout { get; private set; }
|
||||
public CanvasTextLayout? PrimaryTextLayout { get; private set; }
|
||||
public CanvasTextLayout? SecondaryTextLayout { get; private set; }
|
||||
public CanvasTextLayout? TertiaryTextLayout { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原文坐标(相对于坐标原点)
|
||||
/// </summary>
|
||||
public Vector2 OriginalPosition { get; set; }
|
||||
public Vector2 PrimaryPosition { get; set; }
|
||||
/// <summary>
|
||||
/// 译文坐标(相对于坐标原点)
|
||||
/// </summary>
|
||||
public Vector2 TranslatedPosition { get; set; }
|
||||
public Vector2 SecondaryPosition { get; set; }
|
||||
/// <summary>
|
||||
/// 注音坐标(相对于坐标原点)
|
||||
/// </summary>
|
||||
public Vector2 PhoneticPosition { get; set; }
|
||||
public Vector2 TertiaryPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 顶部坐标(相对于坐标原点)
|
||||
@@ -58,21 +59,21 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
/// </summary>
|
||||
public Vector2 BottomRightPosition { get; set; }
|
||||
|
||||
public CanvasGeometry? OriginalCanvasGeometry { get; private set; }
|
||||
public CanvasGeometry? TranslatedCanvasGeometry { get; private set; }
|
||||
public CanvasGeometry? PhoneticCanvasGeometry { get; private set; }
|
||||
public CanvasGeometry? PrimaryCanvasGeometry { get; private set; }
|
||||
public CanvasGeometry? SecondaryCanvasGeometry { get; private set; }
|
||||
public CanvasGeometry? TertiaryCanvasGeometry { get; private set; }
|
||||
|
||||
public string PrimaryText { get; set; } = "";
|
||||
public string SecondaryText { get; set; } = "";
|
||||
public string TertiaryText { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 轨道索引 (0 = 主轨道, 1 = 第一副轨道, etc.)
|
||||
/// 用于布局计算时的堆叠逻辑
|
||||
/// </summary>
|
||||
public int LaneIndex { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// 是否为背景人声/和声
|
||||
/// </summary>
|
||||
public bool IsPlayingLastFrame { get; set; } = false;
|
||||
|
||||
public RenderLyricsLine()
|
||||
public RenderLyricsLine(LyricsLine lyricsLine) : base(lyricsLine)
|
||||
{
|
||||
AngleTransition = new(
|
||||
initialValue: 0,
|
||||
@@ -119,11 +120,18 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
durationSeconds: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
|
||||
StartMs = lyricsLine.StartMs;
|
||||
EndMs = lyricsLine.EndMs;
|
||||
TertiaryText = lyricsLine.TertiaryText;
|
||||
PrimaryText = lyricsLine.PrimaryText;
|
||||
SecondaryText = lyricsLine.SecondaryText;
|
||||
PrimaryRenderSyllables = lyricsLine.PrimarySyllables.Select(x => new RenderLyricsSyllable(x)).ToList();
|
||||
}
|
||||
|
||||
public void UpdateCenterPosition(double maxWidth, TextAlignmentType type)
|
||||
{
|
||||
if (OriginalCanvasTextLayout == null)
|
||||
if (PrimaryTextLayout == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -141,14 +149,14 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
|
||||
public void DisposeTextLayout()
|
||||
{
|
||||
PhoneticCanvasTextLayout?.Dispose();
|
||||
PhoneticCanvasTextLayout = null;
|
||||
TertiaryTextLayout?.Dispose();
|
||||
TertiaryTextLayout = null;
|
||||
|
||||
OriginalCanvasTextLayout?.Dispose();
|
||||
OriginalCanvasTextLayout = null;
|
||||
PrimaryTextLayout?.Dispose();
|
||||
PrimaryTextLayout = null;
|
||||
|
||||
TranslatedCanvasTextLayout?.Dispose();
|
||||
TranslatedCanvasTextLayout = null;
|
||||
SecondaryTextLayout?.Dispose();
|
||||
SecondaryTextLayout = null;
|
||||
}
|
||||
|
||||
public void RecreateTextLayout(
|
||||
@@ -161,9 +169,9 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
DisposeTextLayout();
|
||||
|
||||
if (createPhonetic && PhoneticText != "")
|
||||
if (createPhonetic && TertiaryText != "")
|
||||
{
|
||||
PhoneticCanvasTextLayout = new CanvasTextLayout(control, PhoneticText, new CanvasTextFormat
|
||||
TertiaryTextLayout = new CanvasTextLayout(control, TertiaryText, new CanvasTextFormat
|
||||
{
|
||||
HorizontalAlignment = CanvasHorizontalAlignment.Left,
|
||||
VerticalAlignment = CanvasVerticalAlignment.Top,
|
||||
@@ -173,10 +181,10 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
HorizontalAlignment = type.ToCanvasHorizontalAlignment(),
|
||||
};
|
||||
PhoneticCanvasTextLayout.SetFontFamily(PhoneticText, fontFamilyCJK, fontFamilyWestern);
|
||||
TertiaryTextLayout.SetFontFamily(TertiaryText, fontFamilyCJK, fontFamilyWestern);
|
||||
}
|
||||
|
||||
OriginalCanvasTextLayout = new CanvasTextLayout(control, OriginalText, new CanvasTextFormat
|
||||
PrimaryTextLayout = new CanvasTextLayout(control, PrimaryText, new CanvasTextFormat
|
||||
{
|
||||
HorizontalAlignment = CanvasHorizontalAlignment.Left,
|
||||
VerticalAlignment = CanvasVerticalAlignment.Top,
|
||||
@@ -186,11 +194,11 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
HorizontalAlignment = type.ToCanvasHorizontalAlignment()
|
||||
};
|
||||
OriginalCanvasTextLayout.SetFontFamily(OriginalText, fontFamilyCJK, fontFamilyWestern);
|
||||
PrimaryTextLayout.SetFontFamily(PrimaryText, fontFamilyCJK, fontFamilyWestern);
|
||||
|
||||
if (createTranslated && TranslatedText != "")
|
||||
if (createTranslated && SecondaryText != "")
|
||||
{
|
||||
TranslatedCanvasTextLayout = new CanvasTextLayout(control, TranslatedText, new CanvasTextFormat
|
||||
SecondaryTextLayout = new CanvasTextLayout(control, SecondaryText, new CanvasTextFormat
|
||||
{
|
||||
HorizontalAlignment = CanvasHorizontalAlignment.Left,
|
||||
VerticalAlignment = CanvasVerticalAlignment.Top,
|
||||
@@ -200,60 +208,77 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
HorizontalAlignment = type.ToCanvasHorizontalAlignment()
|
||||
};
|
||||
TranslatedCanvasTextLayout.SetFontFamily(TranslatedText, fontFamilyCJK, fontFamilyWestern);
|
||||
SecondaryTextLayout.SetFontFamily(SecondaryText, fontFamilyCJK, fontFamilyWestern);
|
||||
}
|
||||
}
|
||||
|
||||
public void DisposeTextGeometry()
|
||||
{
|
||||
PhoneticCanvasGeometry?.Dispose();
|
||||
PhoneticCanvasGeometry = null;
|
||||
TertiaryCanvasGeometry?.Dispose();
|
||||
TertiaryCanvasGeometry = null;
|
||||
|
||||
OriginalCanvasGeometry?.Dispose();
|
||||
OriginalCanvasGeometry = null;
|
||||
PrimaryCanvasGeometry?.Dispose();
|
||||
PrimaryCanvasGeometry = null;
|
||||
|
||||
TranslatedCanvasGeometry?.Dispose();
|
||||
TranslatedCanvasGeometry = null;
|
||||
SecondaryCanvasGeometry?.Dispose();
|
||||
SecondaryCanvasGeometry = null;
|
||||
}
|
||||
|
||||
public void RecreateTextGeometry()
|
||||
{
|
||||
DisposeTextGeometry();
|
||||
|
||||
if (PhoneticCanvasTextLayout != null)
|
||||
if (TertiaryTextLayout != null)
|
||||
{
|
||||
PhoneticCanvasGeometry = CanvasGeometry.CreateText(PhoneticCanvasTextLayout);
|
||||
TertiaryCanvasGeometry = CanvasGeometry.CreateText(TertiaryTextLayout);
|
||||
}
|
||||
|
||||
if (OriginalCanvasTextLayout != null)
|
||||
if (PrimaryTextLayout != null)
|
||||
{
|
||||
OriginalCanvasGeometry = CanvasGeometry.CreateText(OriginalCanvasTextLayout);
|
||||
PrimaryCanvasGeometry = CanvasGeometry.CreateText(PrimaryTextLayout);
|
||||
}
|
||||
|
||||
if (TranslatedCanvasTextLayout != null)
|
||||
if (SecondaryTextLayout != null)
|
||||
{
|
||||
TranslatedCanvasGeometry = CanvasGeometry.CreateText(TranslatedCanvasTextLayout);
|
||||
SecondaryCanvasGeometry = CanvasGeometry.CreateText(SecondaryTextLayout);
|
||||
}
|
||||
}
|
||||
|
||||
public void RecalculateCharacterGeometries()
|
||||
public void RecreateRenderChars()
|
||||
{
|
||||
RenderLyricsOriginalChars.Clear();
|
||||
if (OriginalCanvasTextLayout == null) return;
|
||||
PrimaryRenderChars.Clear();
|
||||
if (PrimaryTextLayout == null) return;
|
||||
|
||||
var textLength = OriginalText.Length;
|
||||
|
||||
for (int i = 0; i < textLength; i++)
|
||||
foreach (var syllable in PrimaryRenderSyllables)
|
||||
{
|
||||
var region = OriginalCanvasTextLayout.GetCharacterRegions(i, 1).FirstOrDefault();
|
||||
syllable.ChildrenRenderLyricsChars.Clear();
|
||||
}
|
||||
|
||||
var textLength = PrimaryText.Length;
|
||||
|
||||
for (int startCharIndex = 0; startCharIndex < textLength; startCharIndex++)
|
||||
{
|
||||
var region = PrimaryTextLayout.GetCharacterRegions(startCharIndex, 1).FirstOrDefault();
|
||||
var bounds = region.LayoutBounds;
|
||||
|
||||
RenderLyricsOriginalChars.Add(new RenderLyricsChar()
|
||||
var syllable = PrimaryRenderSyllables.FirstOrDefault(x => x.StartIndex <= startCharIndex && startCharIndex <= x.EndIndex);
|
||||
if (syllable == null) continue;
|
||||
|
||||
var avgCharDuration = syllable.DurationMs / syllable.Length;
|
||||
var charStartMs = syllable.StartMs + (startCharIndex - syllable.StartIndex) * avgCharDuration;
|
||||
var charEndMs = charStartMs + avgCharDuration;
|
||||
|
||||
var renderLyricsChar = new RenderLyricsChar(new BaseLyrics
|
||||
{
|
||||
Index = i,
|
||||
LayoutRect = bounds,
|
||||
Text = OriginalText[i].ToString()
|
||||
});
|
||||
StartIndex = startCharIndex,
|
||||
Text = PrimaryText[startCharIndex].ToString(),
|
||||
StartMs = charStartMs,
|
||||
EndMs = charEndMs,
|
||||
}, bounds);
|
||||
|
||||
syllable.ChildrenRenderLyricsChars.Add(renderLyricsChar);
|
||||
|
||||
PrimaryRenderChars.Add(renderLyricsChar);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Lyrics
|
||||
{
|
||||
public class RenderLyricsSyllable : BaseRenderLyrics
|
||||
{
|
||||
public List<RenderLyricsChar> ChildrenRenderLyricsChars { get; set; } = [];
|
||||
|
||||
public RenderLyricsSyllable(BaseLyrics lyricsSyllable) : base(lyricsSyllable) { }
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsFloatAnimationEnabled { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsFloatAnimationAmountAutoAdjust { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFloatAnimationAmount { get; set; } = 8;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFloatAnimationDuration { get; set; } = 450; // 450ms
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial EasingType LyricsScrollEasingType { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollDuration { get; set; }
|
||||
@@ -71,6 +72,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
IsLyricsFloatAnimationEnabled = this.IsLyricsFloatAnimationEnabled,
|
||||
IsLyricsFloatAnimationAmountAutoAdjust = this.IsLyricsFloatAnimationAmountAutoAdjust,
|
||||
LyricsFloatAnimationAmount = this.LyricsFloatAnimationAmount,
|
||||
LyricsFloatAnimationDuration = this.LyricsFloatAnimationDuration,
|
||||
|
||||
LyricsScrollEasingType = this.LyricsScrollEasingType,
|
||||
LyricsScrollDuration = this.LyricsScrollDuration,
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsSearchProvider Provider { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsMatchingThresholdOverwritten { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int MatchingThreshold { get; set; } = 40;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IgnoreCacheWhenSearching { get; set; } = false;
|
||||
|
||||
public LyricsSearchProviderInfo() { }
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var matches = syllableRegex.Matches(line);
|
||||
var syllables = new List<LyricsSyllable>();
|
||||
var syllables = new List<BaseLyrics>();
|
||||
|
||||
int startIndex = 0;
|
||||
for (int i = 0; i < matches.Count; i++)
|
||||
@@ -36,7 +36,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
int totalMs = min * 60_000 + sec * 1000 + ms;
|
||||
string text = match.Groups[6].Value;
|
||||
|
||||
syllables.Add(new LyricsSyllable { StartMs = totalMs, Text = text, StartIndex = startIndex });
|
||||
syllables.Add(new BaseLyrics { StartMs = totalMs, Text = text, StartIndex = startIndex });
|
||||
startIndex += text.Length;
|
||||
}
|
||||
|
||||
@@ -58,8 +58,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
StartMs = syllables[0].StartMs,
|
||||
EndMs = lineEndMs,
|
||||
OriginalText = string.Concat(syllables.Select(s => s.Text)),
|
||||
LyricsSyllables = syllables
|
||||
PrimaryText = string.Concat(syllables.Select(s => s.Text)),
|
||||
PrimarySyllables = syllables
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -81,7 +81,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
content = bracketRegex!.Replace(line, "").Trim();
|
||||
if (content == "//") content = "";
|
||||
|
||||
lrcLines.Add(new LyricsLine { StartMs = lineStartMs, OriginalText = content });
|
||||
lrcLines.Add(new LyricsLine { StartMs = lineStartMs, PrimaryText = content });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,13 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
for (int lineIndex = 0; lineIndex < lines.Count; lineIndex++)
|
||||
{
|
||||
var lineRead = lines[lineIndex];
|
||||
var nextLineRead = lines.ElementAtOrDefault(lineIndex + 1);
|
||||
var lineWrite = new LyricsLine
|
||||
{
|
||||
StartMs = lineRead.StartTime ?? 0,
|
||||
EndMs = lineRead.EndTime ?? 0,
|
||||
OriginalText = lineRead.Text,
|
||||
LyricsSyllables = [],
|
||||
EndMs = lineRead.EndTime ?? (nextLineRead?.StartTime ?? 0),
|
||||
PrimaryText = lineRead.Text,
|
||||
PrimarySyllables = [],
|
||||
};
|
||||
|
||||
var syllables = (lineRead as Lyricify.Lyrics.Models.SyllableLineInfo)?.Syllables;
|
||||
@@ -36,14 +37,14 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
)
|
||||
{
|
||||
var syllable = syllables[syllableIndex];
|
||||
var charTiming = new LyricsSyllable
|
||||
var charTiming = new BaseLyrics
|
||||
{
|
||||
StartMs = syllable.StartTime,
|
||||
EndMs = syllable.EndTime,
|
||||
Text = syllable.Text,
|
||||
StartIndex = startIndex,
|
||||
};
|
||||
lineWrite.LyricsSyllables.Add(charTiming);
|
||||
lineWrite.PrimarySyllables.Add(charTiming);
|
||||
startIndex += syllable.Text.Length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
}
|
||||
}
|
||||
|
||||
var syllables = new List<LyricsSyllable>();
|
||||
var syllables = new List<BaseLyrics>();
|
||||
int startIndex = 0;
|
||||
var sbText = new System.Text.StringBuilder();
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
int sEndMs = ParseTtmlTime(span.Attribute("end")?.Value);
|
||||
string text = span.Value;
|
||||
|
||||
syllables.Add(new LyricsSyllable
|
||||
syllables.Add(new BaseLyrics
|
||||
{
|
||||
StartMs = sStartMs,
|
||||
EndMs = sEndMs,
|
||||
@@ -126,8 +126,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
StartMs = containerStartMs,
|
||||
EndMs = containerEndMs,
|
||||
OriginalText = fullOriginalText,
|
||||
LyricsSyllables = syllables
|
||||
PrimaryText = fullOriginalText,
|
||||
PrimarySyllables = syllables
|
||||
});
|
||||
|
||||
var transSpan = container.Elements()
|
||||
@@ -151,7 +151,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
StartMs = startMs,
|
||||
EndMs = endMs,
|
||||
OriginalText = text
|
||||
PrimaryText = text
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -160,7 +160,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
StartMs = startMs,
|
||||
EndMs = endMs,
|
||||
OriginalText = ""
|
||||
PrimaryText = ""
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,14 +167,14 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
foreach (var item in main.LyricsLines)
|
||||
{
|
||||
item.OriginalText = settings.IsTraditionalChineseEnabled ? ChineseHelper.ToTC(item.OriginalText) : ChineseHelper.ToSC(item.OriginalText);
|
||||
item.PrimaryText = settings.IsTraditionalChineseEnabled ? ChineseHelper.ToTC(item.PrimaryText) : ChineseHelper.ToSC(item.PrimaryText);
|
||||
}
|
||||
}
|
||||
if (settings.SelectedTargetLanguageCode == LanguageHelper.ChineseCode)
|
||||
{
|
||||
foreach (var item in main.LyricsLines)
|
||||
{
|
||||
item.TranslatedText = settings.IsTraditionalChineseEnabled ? ChineseHelper.ToTC(item.TranslatedText) : ChineseHelper.ToSC(item.TranslatedText);
|
||||
item.SecondaryText = settings.IsTraditionalChineseEnabled ? ChineseHelper.ToTC(item.SecondaryText) : ChineseHelper.ToSC(item.SecondaryText);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,8 +235,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
StartMs = line.StartMs,
|
||||
EndMs = line.EndMs,
|
||||
OriginalText = PhoneticHelper.ToPinyin(line.OriginalText),
|
||||
LyricsSyllables = line.LyricsSyllables.Select(c => new LyricsSyllable
|
||||
PrimaryText = PhoneticHelper.ToPinyin(line.PrimaryText),
|
||||
PrimarySyllables = line.PrimarySyllables.Select(c => new BaseLyrics
|
||||
{
|
||||
StartMs = c.StartMs,
|
||||
EndMs = c.EndMs,
|
||||
@@ -256,8 +256,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
|
||||
{
|
||||
StartMs = line.StartMs,
|
||||
EndMs = line.EndMs,
|
||||
OriginalText = PhoneticHelper.ToJyutping(line.OriginalText),
|
||||
LyricsSyllables = line.LyricsSyllables.Select(c => new LyricsSyllable
|
||||
PrimaryText = PhoneticHelper.ToJyutping(line.PrimaryText),
|
||||
PrimarySyllables = line.PrimarySyllables.Select(c => new BaseLyrics
|
||||
{
|
||||
StartMs = c.StartMs,
|
||||
EndMs = c.EndMs,
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
ICanvasAnimatedControl control,
|
||||
CanvasDrawingSession ds,
|
||||
IList<RenderLyricsLine>? lines,
|
||||
int playingLineIndex,
|
||||
int mouseHoverLineIndex,
|
||||
bool isMousePressing,
|
||||
int startVisibleIndex,
|
||||
@@ -57,7 +56,6 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
control,
|
||||
layerDs,
|
||||
lines,
|
||||
playingLineIndex,
|
||||
mouseHoverLineIndex,
|
||||
isMousePressing,
|
||||
startVisibleIndex,
|
||||
@@ -89,7 +87,6 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
control,
|
||||
ds,
|
||||
lines,
|
||||
playingLineIndex,
|
||||
mouseHoverLineIndex,
|
||||
isMousePressing,
|
||||
startVisibleIndex,
|
||||
@@ -114,7 +111,6 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
ICanvasAnimatedControl control,
|
||||
CanvasDrawingSession ds,
|
||||
IList<RenderLyricsLine>? lines,
|
||||
int playingLineIndex,
|
||||
int mouseHoverLineIndex,
|
||||
bool isMousePressing,
|
||||
int startVisibleIndex,
|
||||
@@ -134,9 +130,6 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
{
|
||||
if (lines == null) return;
|
||||
|
||||
var currentPlayingLine = lines.ElementAtOrDefault(playingLineIndex);
|
||||
if (currentPlayingLine == null) return;
|
||||
|
||||
var effectSettings = windowStatus.LyricsEffectSettings;
|
||||
var styleSettings = windowStatus.LyricsStyleSettings;
|
||||
|
||||
@@ -148,8 +141,8 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
var line = lines.ElementAtOrDefault(i);
|
||||
if (line == null) continue;
|
||||
|
||||
if (line.OriginalCanvasTextLayout == null) continue;
|
||||
if (line.OriginalCanvasTextLayout.LayoutBounds.Width <= 0) continue;
|
||||
if (line.PrimaryTextLayout == null) continue;
|
||||
if (line.PrimaryTextLayout.LayoutBounds.Width <= 0) continue;
|
||||
|
||||
double xOffset = lyricsX;
|
||||
double yOffset = line.YOffsetTransition.Value + userScrollOffset + lyricsY + lyricsHeight * playingLineTopOffsetFactor;
|
||||
@@ -167,8 +160,7 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
|
||||
using (var textOnlyLayer = RenderBaseTextLayer(control, line, styleSettings.LyricsFontStrokeWidth, strokeColor, line.ColorTransition.Value))
|
||||
{
|
||||
bool isPlaying = currentProgressMs >= line.StartMs && currentProgressMs <= line.EndMs;
|
||||
if (i == playingLineIndex) isPlaying = true;
|
||||
bool isPlaying = line.GetIsPlaying(currentProgressMs);
|
||||
|
||||
if (isPlaying)
|
||||
{
|
||||
@@ -206,14 +198,14 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
{
|
||||
if (strokeWidth > 0)
|
||||
{
|
||||
DrawGeometrySafely(clds, line.PhoneticCanvasGeometry, line.PhoneticPosition, strokeColor, strokeWidth);
|
||||
DrawGeometrySafely(clds, line.OriginalCanvasGeometry, line.OriginalPosition, strokeColor, strokeWidth);
|
||||
DrawGeometrySafely(clds, line.TranslatedCanvasGeometry, line.TranslatedPosition, strokeColor, strokeWidth);
|
||||
DrawGeometrySafely(clds, line.TertiaryCanvasGeometry, line.TertiaryPosition, strokeColor, strokeWidth);
|
||||
DrawGeometrySafely(clds, line.PrimaryCanvasGeometry, line.PrimaryPosition, strokeColor, strokeWidth);
|
||||
DrawGeometrySafely(clds, line.SecondaryCanvasGeometry, line.SecondaryPosition, strokeColor, strokeWidth);
|
||||
}
|
||||
|
||||
DrawTextLayoutSafely(clds, line.PhoneticCanvasTextLayout, line.PhoneticPosition, fillColor);
|
||||
DrawTextLayoutSafely(clds, line.OriginalCanvasTextLayout, line.OriginalPosition, fillColor);
|
||||
DrawTextLayoutSafely(clds, line.TranslatedCanvasTextLayout, line.TranslatedPosition, fillColor);
|
||||
DrawTextLayoutSafely(clds, line.TertiaryTextLayout, line.TertiaryPosition, fillColor);
|
||||
DrawTextLayoutSafely(clds, line.PrimaryTextLayout, line.PrimaryPosition, fillColor);
|
||||
DrawTextLayoutSafely(clds, line.SecondaryTextLayout, line.SecondaryPosition, fillColor);
|
||||
}
|
||||
return commandList;
|
||||
}
|
||||
|
||||
@@ -33,17 +33,17 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
|
||||
private void DrawPhonetic(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
|
||||
{
|
||||
if (line.PhoneticCanvasTextLayout == null) return;
|
||||
if (line.TertiaryTextLayout == null) return;
|
||||
|
||||
var opacity = line.PhoneticOpacityTransition.Value;
|
||||
var blur = line.BlurAmountTransition.Value;
|
||||
var bounds = line.PhoneticCanvasTextLayout.LayoutBounds;
|
||||
var bounds = line.TertiaryTextLayout.LayoutBounds;
|
||||
|
||||
if (double.IsNaN(opacity)) return;
|
||||
|
||||
var destRect = new Rect(
|
||||
bounds.X + line.PhoneticPosition.X,
|
||||
bounds.Y + line.PhoneticPosition.Y,
|
||||
bounds.X + line.TertiaryPosition.X,
|
||||
bounds.Y + line.TertiaryPosition.Y,
|
||||
bounds.Width,
|
||||
bounds.Height
|
||||
);
|
||||
@@ -67,17 +67,17 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
|
||||
private void DrawTranslated(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
|
||||
{
|
||||
if (line.TranslatedCanvasTextLayout == null) return;
|
||||
if (line.SecondaryTextLayout == null) return;
|
||||
|
||||
var opacity = line.TranslatedOpacityTransition.Value;
|
||||
var blur = line.BlurAmountTransition.Value;
|
||||
var bounds = line.TranslatedCanvasTextLayout.LayoutBounds;
|
||||
var bounds = line.SecondaryTextLayout.LayoutBounds;
|
||||
|
||||
if (double.IsNaN(opacity)) return;
|
||||
|
||||
var destRect = new Rect(
|
||||
bounds.X + line.TranslatedPosition.X,
|
||||
bounds.Y + line.TranslatedPosition.Y,
|
||||
bounds.X + line.SecondaryPosition.X,
|
||||
bounds.Y + line.SecondaryPosition.Y,
|
||||
bounds.Width,
|
||||
bounds.Height
|
||||
);
|
||||
@@ -109,12 +109,12 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
Color fgColor,
|
||||
LyricsEffectSettings settings)
|
||||
{
|
||||
if (line.OriginalCanvasTextLayout == null) return;
|
||||
if (line.PrimaryTextLayout == null) return;
|
||||
|
||||
var curCharIndex = state.SyllableStartIndex + state.SyllableLength * state.SyllableProgress;
|
||||
float fadeWidth = (1f / Math.Max(1, line.OriginalText.Length)) * 0.5f;
|
||||
float fadeWidth = (1f / Math.Max(1, line.PrimaryText.Length)) * 0.5f;
|
||||
|
||||
var lineRegions = line.OriginalCanvasTextLayout.GetCharacterRegions(0, line.OriginalText.Length);
|
||||
var lineRegions = line.PrimaryTextLayout.GetCharacterRegions(0, line.PrimaryText.Length);
|
||||
|
||||
foreach (var subLineRegion in lineRegions)
|
||||
{
|
||||
@@ -139,8 +139,8 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
|
||||
var subLineLayoutBounds = subLineRegion.LayoutBounds;
|
||||
Rect subLineRect = new(
|
||||
subLineLayoutBounds.X + line.OriginalPosition.X,
|
||||
subLineLayoutBounds.Y + line.OriginalPosition.Y,
|
||||
subLineLayoutBounds.X + line.PrimaryPosition.X,
|
||||
subLineLayoutBounds.Y + line.PrimaryPosition.Y,
|
||||
subLineLayoutBounds.Width,
|
||||
subLineLayoutBounds.Height
|
||||
);
|
||||
@@ -208,14 +208,14 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
int charIndex,
|
||||
ICanvasImage source)
|
||||
{
|
||||
if (charIndex >= line.RenderLyricsOriginalChars.Count) return;
|
||||
if (charIndex >= line.PrimaryRenderChars.Count) return;
|
||||
|
||||
RenderLyricsChar renderChar = line.RenderLyricsOriginalChars[charIndex];
|
||||
RenderLyricsChar renderChar = line.PrimaryRenderChars[charIndex];
|
||||
|
||||
var rect = renderChar.LayoutRect;
|
||||
var sourceCharRect = new Rect(
|
||||
rect.X + line.OriginalPosition.X,
|
||||
rect.Y + line.OriginalPosition.Y,
|
||||
rect.X + line.PrimaryPosition.X,
|
||||
rect.Y + line.PrimaryPosition.Y,
|
||||
rect.Width,
|
||||
rect.Height
|
||||
);
|
||||
|
||||
@@ -17,32 +17,32 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
{
|
||||
var blurAmount = (float)line.BlurAmountTransition.Value;
|
||||
|
||||
if (line.PhoneticCanvasTextLayout != null)
|
||||
if (line.TertiaryTextLayout != null)
|
||||
{
|
||||
var opacity = line.PhoneticOpacityTransition.Value;
|
||||
DrawPart(ds, textOnlyLayer,
|
||||
line.PhoneticCanvasTextLayout,
|
||||
line.PhoneticPosition,
|
||||
line.TertiaryTextLayout,
|
||||
line.TertiaryPosition,
|
||||
blurAmount,
|
||||
(float)opacity);
|
||||
}
|
||||
|
||||
if (line.OriginalCanvasTextLayout != null)
|
||||
if (line.PrimaryTextLayout != null)
|
||||
{
|
||||
double opacity = Math.Max(line.PlayedOriginalOpacityTransition.Value, line.UnplayedOriginalOpacityTransition.Value);
|
||||
DrawPart(ds, textOnlyLayer,
|
||||
line.OriginalCanvasTextLayout,
|
||||
line.OriginalPosition,
|
||||
line.PrimaryTextLayout,
|
||||
line.PrimaryPosition,
|
||||
blurAmount,
|
||||
(float)opacity);
|
||||
}
|
||||
|
||||
if (line.TranslatedCanvasTextLayout != null)
|
||||
if (line.SecondaryTextLayout != null)
|
||||
{
|
||||
var opacity = line.TranslatedOpacityTransition.Value;
|
||||
DrawPart(ds, textOnlyLayer,
|
||||
line.TranslatedCanvasTextLayout,
|
||||
line.TranslatedPosition,
|
||||
line.SecondaryTextLayout,
|
||||
line.SecondaryPosition,
|
||||
blurAmount,
|
||||
(float)opacity);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
if (CurrentSongInfo != SongInfoExtensions.Placeholder)
|
||||
{
|
||||
CurrentLyricsSearchResult = await Task.Run(async () => await _lyrcsSearchService.SearchSmartlyAsync(
|
||||
CurrentSongInfo, true, CurrentMediaSourceProviderInfo?.LyricsSearchType, token), token);
|
||||
CurrentSongInfo, CurrentMediaSourceProviderInfo?.LyricsSearchType, token), token);
|
||||
|
||||
if (CurrentLyricsSearchResult != null)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write cache to DB
|
||||
/// Write or update cache to DB
|
||||
/// </summary>
|
||||
public async Task SaveLyricsAsync(SongInfo songInfo, LyricsCacheItem result)
|
||||
{
|
||||
@@ -52,8 +52,18 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
|
||||
}
|
||||
else
|
||||
{
|
||||
// No need to handle this case
|
||||
return;
|
||||
existingItem.Title = result.Title;
|
||||
existingItem.Artist = result.Artist;
|
||||
existingItem.Album = result.Album;
|
||||
|
||||
existingItem.TransliterationProvider = result.TransliterationProvider;
|
||||
existingItem.TranslationProvider = result.TranslationProvider;
|
||||
|
||||
existingItem.Raw = result.Raw;
|
||||
existingItem.Translation = result.Translation;
|
||||
|
||||
existingItem.MatchPercentage = result.MatchPercentage;
|
||||
existingItem.Reference = result.Reference;
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
{
|
||||
public interface ILyricsSearchService
|
||||
{
|
||||
Task<LyricsCacheItem?> SearchSmartlyAsync(SongInfo songInfo, bool checkCache, LyricsSearchType? lyricsSearchType, CancellationToken token);
|
||||
Task<LyricsCacheItem?> SearchSmartlyAsync(SongInfo songInfo, LyricsSearchType? lyricsSearchType, CancellationToken token);
|
||||
|
||||
Task<List<LyricsCacheItem>> SearchAllAsync(SongInfo songInfo, bool checkCache, CancellationToken token);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<LyricsCacheItem?> SearchSmartlyAsync(SongInfo songInfo, bool checkCache, LyricsSearchType? lyricsSearchType, CancellationToken token)
|
||||
public async Task<LyricsCacheItem?> SearchSmartlyAsync(SongInfo songInfo, LyricsSearchType? lyricsSearchType, CancellationToken token)
|
||||
{
|
||||
if (lyricsSearchType == null)
|
||||
{
|
||||
@@ -112,8 +112,6 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
}
|
||||
|
||||
var lyricsSearchResult = new LyricsCacheItem();
|
||||
//lyricsSearchResult.Raw = File.ReadAllText("C:\\Users\\Zhe\\Desktop\\星河回响 (Tech Demo).lrc");
|
||||
//return lyricsSearchResult;
|
||||
|
||||
string overridenTitle = songInfo.Title;
|
||||
string overridenArtist = songInfo.Artist;
|
||||
@@ -150,7 +148,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
.WithTitle(overridenTitle)
|
||||
.WithArtist(overridenArtist)
|
||||
.WithAlbum(overridenAlbum),
|
||||
targetProvider.Value, checkCache, token);
|
||||
targetProvider.Value, true, token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +170,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
.WithTitle(overridenTitle)
|
||||
.WithArtist(overridenArtist)
|
||||
.WithAlbum(overridenAlbum),
|
||||
provider.Provider, checkCache, token);
|
||||
provider.Provider, !provider.IgnoreCacheWhenSearching, token);
|
||||
|
||||
int matchingThreshold = mediaSourceProviderInfo.MatchingThreshold;
|
||||
if (provider.IsMatchingThresholdOverwritten)
|
||||
@@ -288,7 +286,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
private async Task<LyricsCacheItem> SearchFile(SongInfo songInfo, LyricsFormat format)
|
||||
{
|
||||
int maxScore = 0;
|
||||
int maxScore = -1;
|
||||
|
||||
FilesIndexItem? bestFileEntity = null;
|
||||
MediaFolder? bestFolderConfig = null;
|
||||
@@ -316,7 +314,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
{
|
||||
if (item.FileName.EndsWith(targetExt, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
int score = MetadataComparer.CalculateScore(songInfo, new LyricsCacheItem { Reference = item.FileName });
|
||||
int score = MetadataComparer.CalculateScore(songInfo, item);
|
||||
|
||||
if (score > maxScore)
|
||||
{
|
||||
@@ -363,13 +361,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
{
|
||||
if (string.IsNullOrEmpty(item.EmbeddedLyrics)) continue;
|
||||
|
||||
int score = MetadataComparer.CalculateScore(songInfo, new LyricsCacheItem
|
||||
{
|
||||
Title = item.Title,
|
||||
Artist = item.Artist,
|
||||
Album = item.Album,
|
||||
Duration = item.Duration
|
||||
});
|
||||
int score = MetadataComparer.CalculateScore(songInfo, item);
|
||||
|
||||
if (score > maxScore)
|
||||
{
|
||||
@@ -444,6 +436,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
Title = title,
|
||||
Artist = artist,
|
||||
Album = album,
|
||||
Duration = 0,
|
||||
});
|
||||
if (score > lyricsSearchResult.MatchPercentage)
|
||||
{
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>e.g. http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>Duration</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>Loading lyrics...</value>
|
||||
</data>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
@@ -243,6 +243,9 @@
|
||||
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
|
||||
<value>例如 http://localhost:5000</value>
|
||||
</data>
|
||||
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
|
||||
<value>持续时间</value>
|
||||
</data>
|
||||
<data name="LyricsLoading" xml:space="preserve">
|
||||
<value>加载歌词中...</value>
|
||||
</data>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
: 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: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>
|
||||
|
||||
Reference in New Issue
Block a user