fix: lyrics cache was not updated when searching without enabling cache, lyrics animation issue

This commit is contained in:
Zhe Fang
2026-01-08 16:21:44 -05:00
parent efc175668e
commit 6f60952d09
51 changed files with 730 additions and 620 deletions

View File

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

View File

@@ -6,6 +6,7 @@ namespace BetterLyrics.WinUI3.Constants
{ {
public static readonly TimeSpan DebounceTimeout = TimeSpan.FromMilliseconds(250); public static readonly TimeSpan DebounceTimeout = TimeSpan.FromMilliseconds(250);
public static readonly TimeSpan AnimationDuration = TimeSpan.FromMilliseconds(350); public static readonly TimeSpan AnimationDuration = TimeSpan.FromMilliseconds(350);
public static readonly TimeSpan LongAnimationDuration = TimeSpan.FromMilliseconds(650);
public static readonly TimeSpan WaitingDuration = TimeSpan.FromMilliseconds(300); public static readonly TimeSpan WaitingDuration = TimeSpan.FromMilliseconds(300);
} }
} }

View File

@@ -119,7 +119,7 @@ namespace BetterLyrics.WinUI3.Controls
private bool _isLayoutChanged = true; private bool _isLayoutChanged = true;
private bool _isMouseScrollingChanged = false; private bool _isMouseScrollingChanged = false;
private int _playingLineIndex; private int _primaryPlayingLineIndex;
private (int Start, int End) _visibleRange; private (int Start, int End) _visibleRange;
private double _canvasTargetScrollOffset; private double _canvasTargetScrollOffset;
@@ -382,7 +382,6 @@ namespace BetterLyrics.WinUI3.Controls
control: sender, control: sender,
ds: args.DrawingSession, ds: args.DrawingSession,
lines: _renderLyricsLines, lines: _renderLyricsLines,
playingLineIndex: _playingLineIndex,
mouseHoverLineIndex: _mouseHoverLineIndex, mouseHoverLineIndex: _mouseHoverLineIndex,
isMousePressing: _isMousePressing, isMousePressing: _isMousePressing,
startVisibleIndex: _visibleRange.Start, startVisibleIndex: _visibleRange.Start,
@@ -411,8 +410,6 @@ namespace BetterLyrics.WinUI3.Controls
return _synchronizer.GetLinePlayingProgress( return _synchronizer.GetLinePlayingProgress(
_songPositionWithOffset.TotalMilliseconds, _songPositionWithOffset.TotalMilliseconds,
line, line,
nextLine,
songDuration,
isForceWordByWord isForceWordByWord
); );
} }
@@ -476,17 +473,17 @@ namespace BetterLyrics.WinUI3.Controls
#region UpdatePlayingLineIndex #region UpdatePlayingLineIndex
int newPlayingIndex = _synchronizer.GetCurrentLineIndex(_songPositionWithOffset.TotalMilliseconds, _renderLyricsLines); int primaryPlayingIndex = _synchronizer.GetCurrentLineIndex(_songPositionWithOffset.TotalMilliseconds, _renderLyricsLines);
bool isPlayingLineChanged = newPlayingIndex != _playingLineIndex; bool isPrimaryPlayingLineChanged = primaryPlayingIndex != _primaryPlayingLineIndex;
_playingLineIndex = newPlayingIndex; _primaryPlayingLineIndex = primaryPlayingIndex;
#endregion #endregion
#region UpdateTargetScrollOffset #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; if (targetScroll.HasValue) _canvasTargetScrollOffset = targetScroll.Value;
_canvasYScrollTransition.SetEasingType(lyricsEffect.LyricsScrollEasingType); _canvasYScrollTransition.SetEasingType(lyricsEffect.LyricsScrollEasingType);
@@ -524,7 +521,7 @@ namespace BetterLyrics.WinUI3.Controls
_renderLyricsLines, _renderLyricsLines,
_isMouseScrolling ? maxRange.Start : _visibleRange.Start, _isMouseScrolling ? maxRange.Start : _visibleRange.Start,
_isMouseScrolling ? maxRange.End : _visibleRange.End, _isMouseScrolling ? maxRange.End : _visibleRange.End,
_playingLineIndex, _primaryPlayingLineIndex,
sender.Size.Height, sender.Size.Height,
_canvasTargetScrollOffset, _canvasTargetScrollOffset,
lyricsStyle.PlayingLineTopOffset / 100.0, lyricsStyle.PlayingLineTopOffset / 100.0,
@@ -536,7 +533,7 @@ namespace BetterLyrics.WinUI3.Controls
elapsedTime, elapsedTime,
_isMouseScrolling, _isMouseScrolling,
_isLayoutChanged, _isLayoutChanged,
isPlayingLineChanged, isPrimaryPlayingLineChanged,
_isMouseScrollingChanged, _isMouseScrollingChanged,
_songPositionWithOffset.TotalMilliseconds _songPositionWithOffset.TotalMilliseconds
); );
@@ -669,15 +666,7 @@ namespace BetterLyrics.WinUI3.Controls
private void UpdateRenderLyricsLines() private void UpdateRenderLyricsLines()
{ {
_renderLyricsLines = null; _renderLyricsLines = null;
var lines = _gsmtcService.CurrentLyricsData?.LyricsLines.Select(x => new RenderLyricsLine() var lines = _gsmtcService.CurrentLyricsData?.LyricsLines.Select(x => new RenderLyricsLine(x)).ToList();
{
LyricsSyllables = x.LyricsSyllables,
StartMs = x.StartMs,
EndMs = x.EndMs,
PhoneticText = x.PhoneticText,
OriginalText = x.OriginalText,
TranslatedText = x.TranslatedText
}).ToList();
if (lines != null) if (lines != null)
{ {
LyricsLayoutManager.CalculateLanes(lines); LyricsLayoutManager.CalculateLanes(lines);

View File

@@ -108,6 +108,14 @@
Minimum="0" Minimum="0"
Value="{x:Bind LyricsEffectSettings.LyricsFloatAnimationAmount, Mode=TwoWay}" /> Value="{x:Bind LyricsEffectSettings.LyricsFloatAnimationAmount, Mode=TwoWay}" />
</dev:SettingsCard> </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.Items>
</dev:SettingsExpander> </dev:SettingsExpander>

View File

@@ -291,7 +291,7 @@
</interactivity:Interaction.Behaviors> </interactivity:Interaction.Behaviors>
</Button> </Button>
</Grid> </Grid>
<local:PropertyRow Grid.Column="1" Value="{x:Bind OriginalText, Mode=OneWay}" /> <local:PropertyRow Grid.Column="1" Value="{x:Bind PrimaryText, Mode=OneWay}" />
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ListView.ItemTemplate> </ListView.ItemTemplate>

View File

@@ -447,7 +447,7 @@
Foreground="{ThemeResource TextFillColorSecondaryBrush}" Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind ViewModel.TimelineSliderThumbLyricsLine.StartMs, Converter={StaticResource MillisecondsToFormattedTimeConverter}, Mode=OneWay}" /> Text="{x:Bind ViewModel.TimelineSliderThumbLyricsLine.StartMs, Converter={StaticResource MillisecondsToFormattedTimeConverter}, Mode=OneWay}" />
<!-- TODO 原文翻译共同显示 --> <!-- 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> </StackPanel>
</Grid> </Grid>
<Grid <Grid

View File

@@ -228,6 +228,9 @@
</dev:SettingsExpander.HeaderIcon> </dev:SettingsExpander.HeaderIcon>
<ToggleSwitch IsOn="{Binding IsEnabled, Mode=TwoWay}" /> <ToggleSwitch IsOn="{Binding IsEnabled, Mode=TwoWay}" />
<dev:SettingsExpander.Items> <dev:SettingsExpander.Items>
<dev:SettingsCard x:Uid="LyricsSearchControlIgnoreCache">
<CheckBox IsChecked="{Binding IgnoreCacheWhenSearching, Mode=TwoWay}" />
</dev:SettingsCard>
<dev:SettingsCard x:Uid="SettingsPageOverwriteMatchingThreshold"> <dev:SettingsCard x:Uid="SettingsPageOverwriteMatchingThreshold">
<ToggleSwitch IsOn="{Binding IsMatchingThresholdOverwritten, Mode=TwoWay}" /> <ToggleSwitch IsOn="{Binding IsMatchingThresholdOverwritten, Mode=TwoWay}" />
</dev:SettingsCard> </dev:SettingsCard>

View File

@@ -19,7 +19,7 @@ namespace BetterLyrics.WinUI3.Extensions
{ {
StartMs = 0, StartMs = 0,
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds, EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
OriginalText = "● ● ●", PrimaryText = "● ● ●",
}, },
], ],
LanguageCode = "N/A", LanguageCode = "N/A",
@@ -37,12 +37,12 @@ namespace BetterLyrics.WinUI3.Extensions
if (transLine != null) if (transLine != null)
{ {
// 此处 transLine.OriginalText 指翻译中的“原文”属性 // 此处 transLine.OriginalText 指翻译中的“原文”属性
line.TranslatedText = transLine.OriginalText; line.SecondaryText = transLine.PrimaryText;
} }
else else
{ {
// 没有匹配的翻译 // 没有匹配的翻译
line.TranslatedText = ""; line.SecondaryText = "";
} }
} }
} }
@@ -58,12 +58,12 @@ namespace BetterLyrics.WinUI3.Extensions
if (transLine != null) if (transLine != null)
{ {
// 此处 transLine.OriginalText 指音译中的“原文”属性 // 此处 transLine.OriginalText 指音译中的“原文”属性
line.PhoneticText = transLine.OriginalText; line.TertiaryText = transLine.PrimaryText;
} }
else else
{ {
// 没有匹配的音译 // 没有匹配的音译
line.PhoneticText = ""; line.TertiaryText = "";
} }
} }
} }
@@ -76,11 +76,11 @@ namespace BetterLyrics.WinUI3.Extensions
{ {
if (i >= translationArr.Count) if (i >= translationArr.Count)
{ {
line.TranslatedText = ""; // No translation available, keep empty line.SecondaryText = ""; // No translation available, keep empty
} }
else else
{ {
line.TranslatedText = translationArr[i]; line.SecondaryText = translationArr[i];
} }
i++; i++;
} }
@@ -94,11 +94,11 @@ namespace BetterLyrics.WinUI3.Extensions
{ {
if (i >= transliterationArr.Count) if (i >= transliterationArr.Count)
{ {
line.PhoneticText = ""; // No transliteration available, keep empty line.TertiaryText = ""; // No transliteration available, keep empty
} }
else else
{ {
line.PhoneticText = transliterationArr[i]; line.TertiaryText = transliterationArr[i];
} }
i++; i++;
} }

View File

@@ -1,4 +1,5 @@
using BetterLyrics.WinUI3.Models; using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Entities;
using F23.StringSimilarity; using F23.StringSimilarity;
using System; using System;
using System.IO; using System.IO;
@@ -17,21 +18,31 @@ namespace BetterLyrics.WinUI3.Helper
// JaroWinkler 适合短字符串匹配 // JaroWinkler 适合短字符串匹配
private static readonly JaroWinkler _algo = new(); 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; double totalScore = 0;
bool localHasMetadata = !string.IsNullOrWhiteSpace(local.Title); bool localHasMetadata = !string.IsNullOrWhiteSpace(songInfo.Title);
bool remoteHasMetadata = !string.IsNullOrWhiteSpace(remote.Title); bool remoteHasMetadata = !string.IsNullOrWhiteSpace(compareTitle);
if (localHasMetadata && remoteHasMetadata) if (localHasMetadata && remoteHasMetadata)
{ {
double titleScore = GetStringSimilarity(local.Title, remote.Title); double titleScore = GetStringSimilarity(songInfo.Title, compareTitle);
double artistScore = GetStringSimilarity(local.Artist, remote.Artist); double artistScore = GetStringSimilarity(songInfo.Artist, compareArtist);
double albumScore = GetStringSimilarity(local.Album, remote.Album); double albumScore = GetStringSimilarity(songInfo.Album, compareAlbum);
double durationScore = GetDurationSimilarity(local.DurationMs, remote.Duration); double durationScore = GetDurationSimilarity(songInfo.DurationMs, compareDurationMs);
totalScore = (titleScore * WeightTitle) + totalScore = (titleScore * WeightTitle) +
(artistScore * WeightArtist) + (artistScore * WeightArtist) +
@@ -41,12 +52,12 @@ namespace BetterLyrics.WinUI3.Helper
else else
{ {
string? localQuery = localHasMetadata string? localQuery = localHasMetadata
? $"{local.Title} {local.Artist}" ? $"{songInfo.Title} {songInfo.Artist}"
: Path.GetFileNameWithoutExtension(local.LinkedFileName); : Path.GetFileNameWithoutExtension(songInfo.LinkedFileName);
string? remoteQuery = remoteHasMetadata string? remoteQuery = remoteHasMetadata
? $"{remote.Title} {remote.Artist}" ? $"{compareTitle} {compareArtist}"
: null; : Path.GetFileNameWithoutExtension(compareFileName);
string fp1 = CreateSortedFingerprint(localQuery); string fp1 = CreateSortedFingerprint(localQuery);
string fp2 = CreateSortedFingerprint(remoteQuery); string fp2 = CreateSortedFingerprint(remoteQuery);

View File

@@ -64,6 +64,16 @@ namespace BetterLyrics.WinUI3.Helper
_durationSeconds = seconds; _durationSeconds = seconds;
} }
public void SetDurationMs(double millionSeconds)
{
SetDuration(millionSeconds / 1000.0);
}
public void SetDuration(TimeSpan timeSpan)
{
SetDuration(timeSpan.TotalSeconds);
}
public void SetDelay(double seconds) public void SetDelay(double seconds)
{ {
_delaySeconds = seconds; _delaySeconds = seconds;

View File

@@ -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.Lyrics;
using BetterLyrics.WinUI3.Models.Settings; using BetterLyrics.WinUI3.Models.Settings;
using DevWinUI; using DevWinUI;
@@ -49,15 +50,15 @@ namespace BetterLyrics.WinUI3.Logic
var line = lines.ElementAtOrDefault(i); var line = lines.ElementAtOrDefault(i);
if (line == null) continue; if (line == null) continue;
bool isSecondaryLinePlaying = line.StartMs <= currentPositionMs && currentPositionMs <= line.EndMs; bool isSecondaryLinePlaying = line.GetIsPlaying(currentPositionMs);
if (i == primaryPlayingLineIndex) isSecondaryLinePlaying = true;
bool isSecondaryLinePlayingChanged = line.IsPlayingLastFrame != isSecondaryLinePlaying; bool isSecondaryLinePlayingChanged = line.IsPlayingLastFrame != isSecondaryLinePlaying;
line.IsPlayingLastFrame = isSecondaryLinePlaying; line.IsPlayingLastFrame = isSecondaryLinePlaying;
// 行动画
if (isLayoutChanged || isPrimaryPlayingLineChanged || isMouseScrollingChanged || isSecondaryLinePlayingChanged) if (isLayoutChanged || isPrimaryPlayingLineChanged || isMouseScrollingChanged || isSecondaryLinePlayingChanged)
{ {
int lineCountDelta = i - primaryPlayingLineIndex; 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; double distanceFactor;
if (lineCountDelta < 0) if (lineCountDelta < 0)
@@ -151,93 +152,115 @@ namespace BetterLyrics.WinUI3.Logic
line.YOffsetTransition.StartTransition(targetYScrollOffset); 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) renderChar.ProgressPlayed = renderChar.GetPlayProgress(currentPositionMs);
bool isCharPlaying = renderChar.GetIsPlaying(currentPositionMs);
bool isCharPlayingChanged = renderChar.IsPlayingLastFrame != isCharPlaying;
if (isSecondaryLinePlayingChanged || isCharPlayingChanged)
{ {
var syllable = line.LyricsSyllables.FirstOrDefault(x => x.StartIndex <= renderChar.Index && renderChar.Index <= x.EndIndex); if (lyricsEffect.IsLyricsGlowEffectEnabled)
if (syllable == null) continue;
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 isCharPlayingChanged = renderChar.IsPlayingLastFrame != isCharPlaying;
if (isSecondaryLinePlayingChanged || isCharPlayingChanged)
{ {
if (lyricsEffect.IsLyricsScaleEffectEnabled) double targetGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust ? renderChar.LayoutRect.Height * 0.2 : lyricsEffect.LyricsGlowEffectAmount;
switch (lyricsEffect.LyricsGlowEffectScope)
{ {
double targetScale = case Enums.LyricsEffectScope.LineStartToCurrentChar:
lyricsEffect.IsLyricsScaleEffectAmountAutoAdjust ? 1.15 : lyricsEffect.LyricsScaleEffectAmount / 100.0; if (isSecondaryLinePlayingChanged)
if (isCharPlayingChanged)
{
if (syllable.DurationMs >= lyricsEffect.LyricsScaleEffectLongSyllableDuration)
{ {
renderChar.ScaleTransition.SetDuration((syllable.DurationMs ?? 0) / 1000.0 / 2); renderChar.GlowTransition.SetDurationMs(Math.Min(Time.AnimationDuration.TotalMilliseconds, maxAnimationDurationMs));
renderChar.ScaleTransition.StartTransition(isCharPlaying ? targetScale : 1); renderChar.GlowTransition.StartTransition(isSecondaryLinePlaying ? targetGlow : 0);
} }
} break;
default:
break;
} }
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.StartTransition(isSecondaryLinePlaying ? targetGlow : 0);
}
break;
default:
break;
}
}
if (lyricsEffect.IsLyricsFloatAnimationEnabled)
{
double targetFloat =
lyricsEffect.IsLyricsFloatAnimationAmountAutoAdjust ? renderChar.LayoutRect.Height * 0.1 : lyricsEffect.LyricsFloatAnimationAmount;
if (isSecondaryLinePlayingChanged)
{
renderChar.FloatTransition.StartTransition(isSecondaryLinePlaying ? targetFloat : 0);
}
if (isCharPlayingChanged)
{
renderChar.FloatTransition.StartTransition(0);
}
}
renderChar.IsPlayingLastFrame = isCharPlaying;
} }
renderChar.ScaleTransition.Update(elapsedTime); if (lyricsEffect.IsLyricsFloatAnimationEnabled)
renderChar.GlowTransition.Update(elapsedTime); {
renderChar.FloatTransition.Update(elapsedTime); double targetFloat =
lyricsEffect.IsLyricsFloatAnimationAmountAutoAdjust ? renderChar.LayoutRect.Height * 0.1 : lyricsEffect.LyricsFloatAnimationAmount;
if (isSecondaryLinePlayingChanged)
{
renderChar.FloatTransition.StartTransition(isSecondaryLinePlaying ? targetFloat : 0);
}
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.AngleTransition.Update(elapsedTime);
line.ScaleTransition.Update(elapsedTime); line.ScaleTransition.Update(elapsedTime);
line.BlurAmountTransition.Update(elapsedTime); line.BlurAmountTransition.Update(elapsedTime);

View File

@@ -79,52 +79,52 @@ namespace BetterLyrics.WinUI3.Logic
// 左上角坐标 // 左上角坐标
line.TopLeftPosition = new Vector2(0, (float)currentY); line.TopLeftPosition = new Vector2(0, (float)currentY);
// 注音层 // 注音层
line.PhoneticPosition = line.TopLeftPosition; line.TertiaryPosition = line.TopLeftPosition;
if (line.PhoneticCanvasTextLayout != null) 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); line.PrimaryPosition = new Vector2(0, (float)currentY);
if (line.OriginalCanvasTextLayout != null) 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); line.SecondaryPosition = new Vector2(0, (float)currentY);
if (line.TranslatedCanvasTextLayout != null) 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); 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.UpdateCenterPosition(lyricsWidth, style.LyricsAlignmentType);
line.RecalculateCharacterGeometries(); line.RecreateRenderChars();
} }
} }
@@ -140,9 +140,9 @@ namespace BetterLyrics.WinUI3.Logic
var currentLine = lines.ElementAtOrDefault(playingLineIndex); var currentLine = lines.ElementAtOrDefault(playingLineIndex);
var firstLine = lines.FirstOrDefault(); 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; - (currentLine.BottomRightPosition.Y - currentLine.TopLeftPosition.Y) / 2.0;
} }
@@ -215,7 +215,7 @@ namespace BetterLyrics.WinUI3.Logic
lanesEndMs.Add(0); lanesEndMs.Add(0);
} }
lanesEndMs[assignedLane] = end ?? 0; lanesEndMs[assignedLane] = end;
line.LaneIndex = assignedLane; line.LaneIndex = assignedLane;
} }
} }
@@ -241,7 +241,7 @@ namespace BetterLyrics.WinUI3.Logic
{ {
int mid = (left + right) / 2; int mid = (left + right) / 2;
var line = lines[mid]; var line = lines[mid];
if (line.OriginalCanvasTextLayout == null) break; if (line.PrimaryTextLayout == null) break;
double value = offset + line.BottomRightPosition.Y; double value = offset + line.BottomRightPosition.Y;
if (value >= mousePosition.Y) { result = mid; right = mid - 1; } if (value >= mousePosition.Y) { result = mid; right = mid - 1; }
else { left = mid + 1; } else { left = mid + 1; }
@@ -267,7 +267,7 @@ namespace BetterLyrics.WinUI3.Logic
{ {
int mid = (left + right) / 2; int mid = (left + right) / 2;
var line = lines[mid]; var line = lines[mid];
if (line.OriginalCanvasTextLayout == null) break; if (line.PrimaryTextLayout == null) break;
double value = offset + line.BottomRightPosition.Y; double value = offset + line.BottomRightPosition.Y;
// 理论上说应该使用下面这一行来精确计算视野内的首个可见行,但是考虑到动画视觉效果,还是注释掉了 // 理论上说应该使用下面这一行来精确计算视野内的首个可见行,但是考虑到动画视觉效果,还是注释掉了
//if (value >= lyricsY) { result = mid; right = mid - 1; } //if (value >= lyricsY) { result = mid; right = mid - 1; }
@@ -284,7 +284,7 @@ namespace BetterLyrics.WinUI3.Logic
{ {
int mid = (left + right) / 2; int mid = (left + right) / 2;
var line = lines[mid]; var line = lines[mid];
if (line.OriginalCanvasTextLayout == null) break; if (line.PrimaryTextLayout == null) break;
double value = offset + line.BottomRightPosition.Y; double value = offset + line.BottomRightPosition.Y;
// 同理 // 同理
//if (value >= lyricsY + lyricsHeight) { result = mid; right = mid - 1; } //if (value >= lyricsY + lyricsHeight) { result = mid; right = mid - 1; }

View File

@@ -66,19 +66,14 @@ namespace BetterLyrics.WinUI3.Logic
public LinePlaybackState GetLinePlayingProgress( public LinePlaybackState GetLinePlayingProgress(
double currentTimeMs, double currentTimeMs,
LyricsLine line, RenderLyricsLine line,
LyricsLine? nextLine,
double songDurationMs,
bool isForceWordByWord) bool isForceWordByWord)
{ {
var state = new LinePlaybackState { SyllableStartIndex = 0, SyllableLength = 0, SyllableProgress = 0 }; var state = new LinePlaybackState { SyllableStartIndex = 0, SyllableLength = 0, SyllableProgress = 0 };
if (line == null) return state; if (line == null) return state;
double lineEndMs; double lineEndMs = line.EndMs;
if (line.EndMs != null) lineEndMs = line.EndMs.Value;
else if (nextLine != null) lineEndMs = nextLine.StartMs;
else lineEndMs = songDurationMs;
// 还没到 // 还没到
if (currentTimeMs < line.StartMs) return state; if (currentTimeMs < line.StartMs) return state;
@@ -87,42 +82,43 @@ namespace BetterLyrics.WinUI3.Logic
if (currentTimeMs > lineEndMs) if (currentTimeMs > lineEndMs)
{ {
state.SyllableProgress = 1f; state.SyllableProgress = 1f;
state.SyllableStartIndex = Math.Max(0, line.OriginalText.Length - 1); state.SyllableStartIndex = Math.Max(0, line.PrimaryText.Length - 1);
state.SyllableLength = 1; state.SyllableLength = 1;
return state; return state;
} }
// 逐字 // 逐字
if (line.LyricsSyllables != null && line.LyricsSyllables.Count > 1) if (line.PrimaryRenderSyllables != null && line.PrimaryRenderSyllables.Count > 1)
{ {
return CalculateSyllableProgress(currentTimeMs, line, lineEndMs); return CalculateSyllableProgress(currentTimeMs, line, lineEndMs);
} }
// 强制逐字 // 强制逐字
if (isForceWordByWord && line.OriginalText.Length > 0) if (isForceWordByWord && line.PrimaryText.Length > 0)
{ {
return CalculateSimulatedProgress(currentTimeMs, line, lineEndMs); return CalculateSimulatedProgress(currentTimeMs, line, lineEndMs);
} }
else else
{ {
// 普通行 // 普通行
state.SyllableStartIndex = line.OriginalText.Length; state.SyllableStartIndex = line.PrimaryText.Length;
state.SyllableProgress = 1f; state.SyllableProgress = 1f;
return state; return state;
} }
} }
private LinePlaybackState CalculateSyllableProgress(double time, LyricsLine line, double lineEndMs) private LinePlaybackState CalculateSyllableProgress(double time, RenderLyricsLine line, double lineEndMs)
{ {
var state = new LinePlaybackState(); var state = new LinePlaybackState();
int count = line.LyricsSyllables.Count; int count = line.PrimaryRenderSyllables.Count;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
var timing = line.LyricsSyllables[i]; var timing = line.PrimaryRenderSyllables[i];
var nextTiming = (i + 1 < count) ? line.LyricsSyllables[i + 1] : null; 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) if (time >= timing.StartMs && time <= timingEndMs)
@@ -146,10 +142,10 @@ namespace BetterLyrics.WinUI3.Logic
return state; return state;
} }
private LinePlaybackState CalculateSimulatedProgress(double time, LyricsLine line, double lineEndMs) private LinePlaybackState CalculateSimulatedProgress(double time, RenderLyricsLine line, double lineEndMs)
{ {
var state = new LinePlaybackState(); var state = new LinePlaybackState();
int textLength = line.OriginalText.Length; int textLength = line.PrimaryText.Length;
double progress = (time - line.StartMs) / (lineEndMs - line.StartMs); double progress = (time - line.StartMs) / (lineEndMs - line.StartMs);
progress = Math.Clamp(progress, 0, 1); progress = Math.Clamp(progress, 0, 1);

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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; }
}
}

View File

@@ -18,7 +18,7 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
set => field = value; set => field = value;
} }
public bool AutoGenerated { get; set; } = false; 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() public LyricsData()
{ {
@@ -35,7 +35,7 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
{ {
StartMs = 0, StartMs = 0,
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds, EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
OriginalText = _localizationService.GetLocalizedString("LyricsNotFound"), PrimaryText = _localizationService.GetLocalizedString("LyricsNotFound"),
}]); }]);
} }

View File

@@ -1,29 +1,46 @@
// 2025/6/23 by Zhe Fang // 2025/6/23 by Zhe Fang
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace BetterLyrics.WinUI3.Models.Lyrics 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 List<BaseLyrics> PrimaryChars { get; private set; } = [];
public int? EndMs { get; set; } public List<BaseLyrics> SecondaryChars { get; private set; } = [];
public int StartMs { get; set; } public List<BaseLyrics> TertiaryChars { get; private set; } = [];
/// <summary> public string PrimaryText { get; set; } = "";
/// 原文 public string SecondaryText { get; set; } = "";
/// </summary> public string TertiaryText { get; set; } = "";
public string OriginalText { get; set; } = "";
/// <summary> public LyricsLine()
/// 译文 {
/// </summary> for (int charStartIndex = 0; charStartIndex < PrimaryText.Length; charStartIndex++)
public string TranslatedText { get; set; } = ""; {
/// <summary> var syllable = PrimarySyllables.FirstOrDefault(x => x.StartIndex <= charStartIndex && charStartIndex <= x.EndIndex);
/// 注音 if (syllable == null) continue;
/// </summary>
public string PhoneticText { get; set; } = ""; 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()
});
}
}
} }
} }

View File

@@ -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;
}
}

View File

@@ -1,14 +1,13 @@
using BetterLyrics.WinUI3.Enums; using BetterLyrics.WinUI3.Constants;
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper; using BetterLyrics.WinUI3.Helper;
using Windows.Foundation; using Windows.Foundation;
namespace BetterLyrics.WinUI3.Models.Lyrics namespace BetterLyrics.WinUI3.Models.Lyrics
{ {
public class RenderLyricsChar : LyricsChar public class RenderLyricsChar : BaseRenderLyrics
{ {
public Rect LayoutRect { get; set; } public Rect LayoutRect { get; private set; }
public double AnimationDuration { get; set; } = 0.3;
public ValueTransition<double> ScaleTransition { get; set; } public ValueTransition<double> ScaleTransition { get; set; }
public ValueTransition<double> GlowTransition { 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 double ProgressPlayed { get; set; } = 0; // 0~1
public bool IsPlayingLastFrame { get; set; } = false; public RenderLyricsChar(BaseLyrics lyricsChars, Rect layoutRect) : base(lyricsChars)
public RenderLyricsChar()
{ {
ScaleTransition = new( ScaleTransition = new(
initialValue: 1.0, initialValue: 1.0,
durationSeconds: AnimationDuration, durationSeconds: Time.AnimationDuration.TotalSeconds,
easingType: EasingType.EaseInOutSine easingType: EasingType.EaseInOutSine
); );
GlowTransition = new( GlowTransition = new(
initialValue: 0, initialValue: 0,
durationSeconds: AnimationDuration, durationSeconds: Time.AnimationDuration.TotalSeconds,
easingType: EasingType.EaseInOutSine easingType: EasingType.EaseInOutSine
); );
FloatTransition = new( FloatTransition = new(
initialValue: 0, initialValue: 0,
durationSeconds: AnimationDuration, durationSeconds: Time.LongAnimationDuration.TotalSeconds,
easingType: EasingType.EaseInOutSine easingType: EasingType.EaseInOutSine
); );
LayoutRect = layoutRect;
} }
} }
} }

View File

@@ -12,9 +12,10 @@ using Windows.UI;
namespace BetterLyrics.WinUI3.Models.Lyrics 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; public double AnimationDuration { get; set; } = 0.3;
@@ -28,22 +29,22 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
public ValueTransition<double> YOffsetTransition { get; set; } public ValueTransition<double> YOffsetTransition { get; set; }
public ValueTransition<Color> ColorTransition { get; set; } public ValueTransition<Color> ColorTransition { get; set; }
public CanvasTextLayout? OriginalCanvasTextLayout { get; private set; } public CanvasTextLayout? PrimaryTextLayout { get; private set; }
public CanvasTextLayout? TranslatedCanvasTextLayout { get; private set; } public CanvasTextLayout? SecondaryTextLayout { get; private set; }
public CanvasTextLayout? PhoneticCanvasTextLayout { get; private set; } public CanvasTextLayout? TertiaryTextLayout { get; private set; }
/// <summary> /// <summary>
/// 原文坐标(相对于坐标原点) /// 原文坐标(相对于坐标原点)
/// </summary> /// </summary>
public Vector2 OriginalPosition { get; set; } public Vector2 PrimaryPosition { get; set; }
/// <summary> /// <summary>
/// 译文坐标(相对于坐标原点) /// 译文坐标(相对于坐标原点)
/// </summary> /// </summary>
public Vector2 TranslatedPosition { get; set; } public Vector2 SecondaryPosition { get; set; }
/// <summary> /// <summary>
/// 注音坐标(相对于坐标原点) /// 注音坐标(相对于坐标原点)
/// </summary> /// </summary>
public Vector2 PhoneticPosition { get; set; } public Vector2 TertiaryPosition { get; set; }
/// <summary> /// <summary>
/// 顶部坐标(相对于坐标原点) /// 顶部坐标(相对于坐标原点)
@@ -58,21 +59,21 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
/// </summary> /// </summary>
public Vector2 BottomRightPosition { get; set; } public Vector2 BottomRightPosition { get; set; }
public CanvasGeometry? OriginalCanvasGeometry { get; private set; } public CanvasGeometry? PrimaryCanvasGeometry { get; private set; }
public CanvasGeometry? TranslatedCanvasGeometry { get; private set; } public CanvasGeometry? SecondaryCanvasGeometry { get; private set; }
public CanvasGeometry? PhoneticCanvasGeometry { 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> /// <summary>
/// 轨道索引 (0 = 主轨道, 1 = 第一副轨道, etc.) /// 轨道索引 (0 = 主轨道, 1 = 第一副轨道, etc.)
/// 用于布局计算时的堆叠逻辑 /// 用于布局计算时的堆叠逻辑
/// </summary> /// </summary>
public int LaneIndex { get; set; } = 0; public int LaneIndex { get; set; } = 0;
/// <summary>
/// 是否为背景人声/和声
/// </summary>
public bool IsPlayingLastFrame { get; set; } = false;
public RenderLyricsLine() public RenderLyricsLine(LyricsLine lyricsLine) : base(lyricsLine)
{ {
AngleTransition = new( AngleTransition = new(
initialValue: 0, initialValue: 0,
@@ -119,11 +120,18 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
durationSeconds: 0.3f, durationSeconds: 0.3f,
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to) 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) public void UpdateCenterPosition(double maxWidth, TextAlignmentType type)
{ {
if (OriginalCanvasTextLayout == null) if (PrimaryTextLayout == null)
{ {
return; return;
} }
@@ -141,14 +149,14 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
public void DisposeTextLayout() public void DisposeTextLayout()
{ {
PhoneticCanvasTextLayout?.Dispose(); TertiaryTextLayout?.Dispose();
PhoneticCanvasTextLayout = null; TertiaryTextLayout = null;
OriginalCanvasTextLayout?.Dispose(); PrimaryTextLayout?.Dispose();
OriginalCanvasTextLayout = null; PrimaryTextLayout = null;
TranslatedCanvasTextLayout?.Dispose(); SecondaryTextLayout?.Dispose();
TranslatedCanvasTextLayout = null; SecondaryTextLayout = null;
} }
public void RecreateTextLayout( public void RecreateTextLayout(
@@ -161,9 +169,9 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
{ {
DisposeTextLayout(); DisposeTextLayout();
if (createPhonetic && PhoneticText != "") if (createPhonetic && TertiaryText != "")
{ {
PhoneticCanvasTextLayout = new CanvasTextLayout(control, PhoneticText, new CanvasTextFormat TertiaryTextLayout = new CanvasTextLayout(control, TertiaryText, new CanvasTextFormat
{ {
HorizontalAlignment = CanvasHorizontalAlignment.Left, HorizontalAlignment = CanvasHorizontalAlignment.Left,
VerticalAlignment = CanvasVerticalAlignment.Top, VerticalAlignment = CanvasVerticalAlignment.Top,
@@ -173,10 +181,10 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
{ {
HorizontalAlignment = type.ToCanvasHorizontalAlignment(), 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, HorizontalAlignment = CanvasHorizontalAlignment.Left,
VerticalAlignment = CanvasVerticalAlignment.Top, VerticalAlignment = CanvasVerticalAlignment.Top,
@@ -186,11 +194,11 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
{ {
HorizontalAlignment = type.ToCanvasHorizontalAlignment() 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, HorizontalAlignment = CanvasHorizontalAlignment.Left,
VerticalAlignment = CanvasVerticalAlignment.Top, VerticalAlignment = CanvasVerticalAlignment.Top,
@@ -200,60 +208,77 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
{ {
HorizontalAlignment = type.ToCanvasHorizontalAlignment() HorizontalAlignment = type.ToCanvasHorizontalAlignment()
}; };
TranslatedCanvasTextLayout.SetFontFamily(TranslatedText, fontFamilyCJK, fontFamilyWestern); SecondaryTextLayout.SetFontFamily(SecondaryText, fontFamilyCJK, fontFamilyWestern);
} }
} }
public void DisposeTextGeometry() public void DisposeTextGeometry()
{ {
PhoneticCanvasGeometry?.Dispose(); TertiaryCanvasGeometry?.Dispose();
PhoneticCanvasGeometry = null; TertiaryCanvasGeometry = null;
OriginalCanvasGeometry?.Dispose(); PrimaryCanvasGeometry?.Dispose();
OriginalCanvasGeometry = null; PrimaryCanvasGeometry = null;
TranslatedCanvasGeometry?.Dispose(); SecondaryCanvasGeometry?.Dispose();
TranslatedCanvasGeometry = null; SecondaryCanvasGeometry = null;
} }
public void RecreateTextGeometry() public void RecreateTextGeometry()
{ {
DisposeTextGeometry(); 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(); PrimaryRenderChars.Clear();
if (OriginalCanvasTextLayout == null) return; if (PrimaryTextLayout == null) return;
var textLength = OriginalText.Length; foreach (var syllable in PrimaryRenderSyllables)
for (int i = 0; i < textLength; i++)
{ {
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; 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, StartIndex = startCharIndex,
LayoutRect = bounds, Text = PrimaryText[startCharIndex].ToString(),
Text = OriginalText[i].ToString() StartMs = charStartMs,
}); EndMs = charEndMs,
}, bounds);
syllable.ChildrenRenderLyricsChars.Add(renderLyricsChar);
PrimaryRenderChars.Add(renderLyricsChar);
} }
} }

View File

@@ -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) { }
}
}

View File

@@ -24,6 +24,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsFloatAnimationEnabled { get; set; } = true; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsFloatAnimationEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsFloatAnimationAmountAutoAdjust { 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 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 EasingType LyricsScrollEasingType { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollDuration { get; set; } [ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollDuration { get; set; }
@@ -71,6 +72,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
IsLyricsFloatAnimationEnabled = this.IsLyricsFloatAnimationEnabled, IsLyricsFloatAnimationEnabled = this.IsLyricsFloatAnimationEnabled,
IsLyricsFloatAnimationAmountAutoAdjust = this.IsLyricsFloatAnimationAmountAutoAdjust, IsLyricsFloatAnimationAmountAutoAdjust = this.IsLyricsFloatAnimationAmountAutoAdjust,
LyricsFloatAnimationAmount = this.LyricsFloatAnimationAmount, LyricsFloatAnimationAmount = this.LyricsFloatAnimationAmount,
LyricsFloatAnimationDuration = this.LyricsFloatAnimationDuration,
LyricsScrollEasingType = this.LyricsScrollEasingType, LyricsScrollEasingType = this.LyricsScrollEasingType,
LyricsScrollDuration = this.LyricsScrollDuration, LyricsScrollDuration = this.LyricsScrollDuration,

View File

@@ -11,6 +11,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsSearchProvider Provider { get; set; } [ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsSearchProvider Provider { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsMatchingThresholdOverwritten { get; set; } = false; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsMatchingThresholdOverwritten { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int MatchingThreshold { get; set; } = 40; [ObservableProperty][NotifyPropertyChangedRecipients] public partial int MatchingThreshold { get; set; } = 40;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IgnoreCacheWhenSearching { get; set; } = false;
public LyricsSearchProviderInfo() { } public LyricsSearchProviderInfo() { }

View File

@@ -24,7 +24,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
foreach (var line in lines) foreach (var line in lines)
{ {
var matches = syllableRegex.Matches(line); var matches = syllableRegex.Matches(line);
var syllables = new List<LyricsSyllable>(); var syllables = new List<BaseLyrics>();
int startIndex = 0; int startIndex = 0;
for (int i = 0; i < matches.Count; i++) 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; int totalMs = min * 60_000 + sec * 1000 + ms;
string text = match.Groups[6].Value; 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; startIndex += text.Length;
} }
@@ -58,8 +58,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
{ {
StartMs = syllables[0].StartMs, StartMs = syllables[0].StartMs,
EndMs = lineEndMs, EndMs = lineEndMs,
OriginalText = string.Concat(syllables.Select(s => s.Text)), PrimaryText = string.Concat(syllables.Select(s => s.Text)),
LyricsSyllables = syllables PrimarySyllables = syllables
}); });
} }
else else
@@ -81,7 +81,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
content = bracketRegex!.Replace(line, "").Trim(); content = bracketRegex!.Replace(line, "").Trim();
if (content == "//") content = ""; if (content == "//") content = "";
lrcLines.Add(new LyricsLine { StartMs = lineStartMs, OriginalText = content }); lrcLines.Add(new LyricsLine { StartMs = lineStartMs, PrimaryText = content });
} }
} }
} }

View File

@@ -17,12 +17,13 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
for (int lineIndex = 0; lineIndex < lines.Count; lineIndex++) for (int lineIndex = 0; lineIndex < lines.Count; lineIndex++)
{ {
var lineRead = lines[lineIndex]; var lineRead = lines[lineIndex];
var nextLineRead = lines.ElementAtOrDefault(lineIndex + 1);
var lineWrite = new LyricsLine var lineWrite = new LyricsLine
{ {
StartMs = lineRead.StartTime ?? 0, StartMs = lineRead.StartTime ?? 0,
EndMs = lineRead.EndTime ?? 0, EndMs = lineRead.EndTime ?? (nextLineRead?.StartTime ?? 0),
OriginalText = lineRead.Text, PrimaryText = lineRead.Text,
LyricsSyllables = [], PrimarySyllables = [],
}; };
var syllables = (lineRead as Lyricify.Lyrics.Models.SyllableLineInfo)?.Syllables; var syllables = (lineRead as Lyricify.Lyrics.Models.SyllableLineInfo)?.Syllables;
@@ -36,14 +37,14 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
) )
{ {
var syllable = syllables[syllableIndex]; var syllable = syllables[syllableIndex];
var charTiming = new LyricsSyllable var charTiming = new BaseLyrics
{ {
StartMs = syllable.StartTime, StartMs = syllable.StartTime,
EndMs = syllable.EndTime, EndMs = syllable.EndTime,
Text = syllable.Text, Text = syllable.Text,
StartIndex = startIndex, StartIndex = startIndex,
}; };
lineWrite.LyricsSyllables.Add(charTiming); lineWrite.PrimarySyllables.Add(charTiming);
startIndex += syllable.Text.Length; startIndex += syllable.Text.Length;
} }
} }

View File

@@ -93,7 +93,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
} }
} }
var syllables = new List<LyricsSyllable>(); var syllables = new List<BaseLyrics>();
int startIndex = 0; int startIndex = 0;
var sbText = new System.Text.StringBuilder(); var sbText = new System.Text.StringBuilder();
@@ -103,7 +103,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
int sEndMs = ParseTtmlTime(span.Attribute("end")?.Value); int sEndMs = ParseTtmlTime(span.Attribute("end")?.Value);
string text = span.Value; string text = span.Value;
syllables.Add(new LyricsSyllable syllables.Add(new BaseLyrics
{ {
StartMs = sStartMs, StartMs = sStartMs,
EndMs = sEndMs, EndMs = sEndMs,
@@ -126,8 +126,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
{ {
StartMs = containerStartMs, StartMs = containerStartMs,
EndMs = containerEndMs, EndMs = containerEndMs,
OriginalText = fullOriginalText, PrimaryText = fullOriginalText,
LyricsSyllables = syllables PrimarySyllables = syllables
}); });
var transSpan = container.Elements() var transSpan = container.Elements()
@@ -151,7 +151,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
{ {
StartMs = startMs, StartMs = startMs,
EndMs = endMs, EndMs = endMs,
OriginalText = text PrimaryText = text
}); });
} }
else else
@@ -160,7 +160,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
{ {
StartMs = startMs, StartMs = startMs,
EndMs = endMs, EndMs = endMs,
OriginalText = "" PrimaryText = ""
}); });
} }
} }

View File

@@ -167,14 +167,14 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
{ {
foreach (var item in main.LyricsLines) 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) if (settings.SelectedTargetLanguageCode == LanguageHelper.ChineseCode)
{ {
foreach (var item in main.LyricsLines) 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, StartMs = line.StartMs,
EndMs = line.EndMs, EndMs = line.EndMs,
OriginalText = PhoneticHelper.ToPinyin(line.OriginalText), PrimaryText = PhoneticHelper.ToPinyin(line.PrimaryText),
LyricsSyllables = line.LyricsSyllables.Select(c => new LyricsSyllable PrimarySyllables = line.PrimarySyllables.Select(c => new BaseLyrics
{ {
StartMs = c.StartMs, StartMs = c.StartMs,
EndMs = c.EndMs, EndMs = c.EndMs,
@@ -256,8 +256,8 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
{ {
StartMs = line.StartMs, StartMs = line.StartMs,
EndMs = line.EndMs, EndMs = line.EndMs,
OriginalText = PhoneticHelper.ToJyutping(line.OriginalText), PrimaryText = PhoneticHelper.ToJyutping(line.PrimaryText),
LyricsSyllables = line.LyricsSyllables.Select(c => new LyricsSyllable PrimarySyllables = line.PrimarySyllables.Select(c => new BaseLyrics
{ {
StartMs = c.StartMs, StartMs = c.StartMs,
EndMs = c.EndMs, EndMs = c.EndMs,

View File

@@ -26,7 +26,6 @@ namespace BetterLyrics.WinUI3.Renderer
ICanvasAnimatedControl control, ICanvasAnimatedControl control,
CanvasDrawingSession ds, CanvasDrawingSession ds,
IList<RenderLyricsLine>? lines, IList<RenderLyricsLine>? lines,
int playingLineIndex,
int mouseHoverLineIndex, int mouseHoverLineIndex,
bool isMousePressing, bool isMousePressing,
int startVisibleIndex, int startVisibleIndex,
@@ -57,7 +56,6 @@ namespace BetterLyrics.WinUI3.Renderer
control, control,
layerDs, layerDs,
lines, lines,
playingLineIndex,
mouseHoverLineIndex, mouseHoverLineIndex,
isMousePressing, isMousePressing,
startVisibleIndex, startVisibleIndex,
@@ -89,7 +87,6 @@ namespace BetterLyrics.WinUI3.Renderer
control, control,
ds, ds,
lines, lines,
playingLineIndex,
mouseHoverLineIndex, mouseHoverLineIndex,
isMousePressing, isMousePressing,
startVisibleIndex, startVisibleIndex,
@@ -114,7 +111,6 @@ namespace BetterLyrics.WinUI3.Renderer
ICanvasAnimatedControl control, ICanvasAnimatedControl control,
CanvasDrawingSession ds, CanvasDrawingSession ds,
IList<RenderLyricsLine>? lines, IList<RenderLyricsLine>? lines,
int playingLineIndex,
int mouseHoverLineIndex, int mouseHoverLineIndex,
bool isMousePressing, bool isMousePressing,
int startVisibleIndex, int startVisibleIndex,
@@ -134,9 +130,6 @@ namespace BetterLyrics.WinUI3.Renderer
{ {
if (lines == null) return; if (lines == null) return;
var currentPlayingLine = lines.ElementAtOrDefault(playingLineIndex);
if (currentPlayingLine == null) return;
var effectSettings = windowStatus.LyricsEffectSettings; var effectSettings = windowStatus.LyricsEffectSettings;
var styleSettings = windowStatus.LyricsStyleSettings; var styleSettings = windowStatus.LyricsStyleSettings;
@@ -148,8 +141,8 @@ namespace BetterLyrics.WinUI3.Renderer
var line = lines.ElementAtOrDefault(i); var line = lines.ElementAtOrDefault(i);
if (line == null) continue; if (line == null) continue;
if (line.OriginalCanvasTextLayout == null) continue; if (line.PrimaryTextLayout == null) continue;
if (line.OriginalCanvasTextLayout.LayoutBounds.Width <= 0) continue; if (line.PrimaryTextLayout.LayoutBounds.Width <= 0) continue;
double xOffset = lyricsX; double xOffset = lyricsX;
double yOffset = line.YOffsetTransition.Value + userScrollOffset + lyricsY + lyricsHeight * playingLineTopOffsetFactor; 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)) using (var textOnlyLayer = RenderBaseTextLayer(control, line, styleSettings.LyricsFontStrokeWidth, strokeColor, line.ColorTransition.Value))
{ {
bool isPlaying = currentProgressMs >= line.StartMs && currentProgressMs <= line.EndMs; bool isPlaying = line.GetIsPlaying(currentProgressMs);
if (i == playingLineIndex) isPlaying = true;
if (isPlaying) if (isPlaying)
{ {
@@ -206,14 +198,14 @@ namespace BetterLyrics.WinUI3.Renderer
{ {
if (strokeWidth > 0) if (strokeWidth > 0)
{ {
DrawGeometrySafely(clds, line.PhoneticCanvasGeometry, line.PhoneticPosition, strokeColor, strokeWidth); DrawGeometrySafely(clds, line.TertiaryCanvasGeometry, line.TertiaryPosition, strokeColor, strokeWidth);
DrawGeometrySafely(clds, line.OriginalCanvasGeometry, line.OriginalPosition, strokeColor, strokeWidth); DrawGeometrySafely(clds, line.PrimaryCanvasGeometry, line.PrimaryPosition, strokeColor, strokeWidth);
DrawGeometrySafely(clds, line.TranslatedCanvasGeometry, line.TranslatedPosition, strokeColor, strokeWidth); DrawGeometrySafely(clds, line.SecondaryCanvasGeometry, line.SecondaryPosition, strokeColor, strokeWidth);
} }
DrawTextLayoutSafely(clds, line.PhoneticCanvasTextLayout, line.PhoneticPosition, fillColor); DrawTextLayoutSafely(clds, line.TertiaryTextLayout, line.TertiaryPosition, fillColor);
DrawTextLayoutSafely(clds, line.OriginalCanvasTextLayout, line.OriginalPosition, fillColor); DrawTextLayoutSafely(clds, line.PrimaryTextLayout, line.PrimaryPosition, fillColor);
DrawTextLayoutSafely(clds, line.TranslatedCanvasTextLayout, line.TranslatedPosition, fillColor); DrawTextLayoutSafely(clds, line.SecondaryTextLayout, line.SecondaryPosition, fillColor);
} }
return commandList; return commandList;
} }

View File

@@ -33,17 +33,17 @@ namespace BetterLyrics.WinUI3.Renderer
private void DrawPhonetic(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line) 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 opacity = line.PhoneticOpacityTransition.Value;
var blur = line.BlurAmountTransition.Value; var blur = line.BlurAmountTransition.Value;
var bounds = line.PhoneticCanvasTextLayout.LayoutBounds; var bounds = line.TertiaryTextLayout.LayoutBounds;
if (double.IsNaN(opacity)) return; if (double.IsNaN(opacity)) return;
var destRect = new Rect( var destRect = new Rect(
bounds.X + line.PhoneticPosition.X, bounds.X + line.TertiaryPosition.X,
bounds.Y + line.PhoneticPosition.Y, bounds.Y + line.TertiaryPosition.Y,
bounds.Width, bounds.Width,
bounds.Height bounds.Height
); );
@@ -67,17 +67,17 @@ namespace BetterLyrics.WinUI3.Renderer
private void DrawTranslated(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line) 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 opacity = line.TranslatedOpacityTransition.Value;
var blur = line.BlurAmountTransition.Value; var blur = line.BlurAmountTransition.Value;
var bounds = line.TranslatedCanvasTextLayout.LayoutBounds; var bounds = line.SecondaryTextLayout.LayoutBounds;
if (double.IsNaN(opacity)) return; if (double.IsNaN(opacity)) return;
var destRect = new Rect( var destRect = new Rect(
bounds.X + line.TranslatedPosition.X, bounds.X + line.SecondaryPosition.X,
bounds.Y + line.TranslatedPosition.Y, bounds.Y + line.SecondaryPosition.Y,
bounds.Width, bounds.Width,
bounds.Height bounds.Height
); );
@@ -109,12 +109,12 @@ namespace BetterLyrics.WinUI3.Renderer
Color fgColor, Color fgColor,
LyricsEffectSettings settings) LyricsEffectSettings settings)
{ {
if (line.OriginalCanvasTextLayout == null) return; if (line.PrimaryTextLayout == null) return;
var curCharIndex = state.SyllableStartIndex + state.SyllableLength * state.SyllableProgress; 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) foreach (var subLineRegion in lineRegions)
{ {
@@ -139,8 +139,8 @@ namespace BetterLyrics.WinUI3.Renderer
var subLineLayoutBounds = subLineRegion.LayoutBounds; var subLineLayoutBounds = subLineRegion.LayoutBounds;
Rect subLineRect = new( Rect subLineRect = new(
subLineLayoutBounds.X + line.OriginalPosition.X, subLineLayoutBounds.X + line.PrimaryPosition.X,
subLineLayoutBounds.Y + line.OriginalPosition.Y, subLineLayoutBounds.Y + line.PrimaryPosition.Y,
subLineLayoutBounds.Width, subLineLayoutBounds.Width,
subLineLayoutBounds.Height subLineLayoutBounds.Height
); );
@@ -208,14 +208,14 @@ namespace BetterLyrics.WinUI3.Renderer
int charIndex, int charIndex,
ICanvasImage source) 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 rect = renderChar.LayoutRect;
var sourceCharRect = new Rect( var sourceCharRect = new Rect(
rect.X + line.OriginalPosition.X, rect.X + line.PrimaryPosition.X,
rect.Y + line.OriginalPosition.Y, rect.Y + line.PrimaryPosition.Y,
rect.Width, rect.Width,
rect.Height rect.Height
); );

View File

@@ -17,32 +17,32 @@ namespace BetterLyrics.WinUI3.Renderer
{ {
var blurAmount = (float)line.BlurAmountTransition.Value; var blurAmount = (float)line.BlurAmountTransition.Value;
if (line.PhoneticCanvasTextLayout != null) if (line.TertiaryTextLayout != null)
{ {
var opacity = line.PhoneticOpacityTransition.Value; var opacity = line.PhoneticOpacityTransition.Value;
DrawPart(ds, textOnlyLayer, DrawPart(ds, textOnlyLayer,
line.PhoneticCanvasTextLayout, line.TertiaryTextLayout,
line.PhoneticPosition, line.TertiaryPosition,
blurAmount, blurAmount,
(float)opacity); (float)opacity);
} }
if (line.OriginalCanvasTextLayout != null) if (line.PrimaryTextLayout != null)
{ {
double opacity = Math.Max(line.PlayedOriginalOpacityTransition.Value, line.UnplayedOriginalOpacityTransition.Value); double opacity = Math.Max(line.PlayedOriginalOpacityTransition.Value, line.UnplayedOriginalOpacityTransition.Value);
DrawPart(ds, textOnlyLayer, DrawPart(ds, textOnlyLayer,
line.OriginalCanvasTextLayout, line.PrimaryTextLayout,
line.OriginalPosition, line.PrimaryPosition,
blurAmount, blurAmount,
(float)opacity); (float)opacity);
} }
if (line.TranslatedCanvasTextLayout != null) if (line.SecondaryTextLayout != null)
{ {
var opacity = line.TranslatedOpacityTransition.Value; var opacity = line.TranslatedOpacityTransition.Value;
DrawPart(ds, textOnlyLayer, DrawPart(ds, textOnlyLayer,
line.TranslatedCanvasTextLayout, line.SecondaryTextLayout,
line.TranslatedPosition, line.SecondaryPosition,
blurAmount, blurAmount,
(float)opacity); (float)opacity);
} }

View File

@@ -28,7 +28,7 @@ namespace BetterLyrics.WinUI3.Services.GSMTCService
if (CurrentSongInfo != SongInfoExtensions.Placeholder) if (CurrentSongInfo != SongInfoExtensions.Placeholder)
{ {
CurrentLyricsSearchResult = await Task.Run(async () => await _lyrcsSearchService.SearchSmartlyAsync( CurrentLyricsSearchResult = await Task.Run(async () => await _lyrcsSearchService.SearchSmartlyAsync(
CurrentSongInfo, true, CurrentMediaSourceProviderInfo?.LyricsSearchType, token), token); CurrentSongInfo, CurrentMediaSourceProviderInfo?.LyricsSearchType, token), token);
if (CurrentLyricsSearchResult != null) if (CurrentLyricsSearchResult != null)
{ {

View File

@@ -32,7 +32,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
} }
/// <summary> /// <summary>
/// Write cache to DB /// Write or update cache to DB
/// </summary> /// </summary>
public async Task SaveLyricsAsync(SongInfo songInfo, LyricsCacheItem result) public async Task SaveLyricsAsync(SongInfo songInfo, LyricsCacheItem result)
{ {
@@ -52,8 +52,18 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
} }
else else
{ {
// No need to handle this case existingItem.Title = result.Title;
return; 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(); await context.SaveChangesAsync();

View File

@@ -10,7 +10,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
{ {
public interface ILyricsSearchService 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); Task<List<LyricsCacheItem>> SearchAllAsync(SongInfo songInfo, bool checkCache, CancellationToken token);
} }

View File

@@ -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) if (lyricsSearchType == null)
{ {
@@ -112,8 +112,6 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
} }
var lyricsSearchResult = new LyricsCacheItem(); var lyricsSearchResult = new LyricsCacheItem();
//lyricsSearchResult.Raw = File.ReadAllText("C:\\Users\\Zhe\\Desktop\\星河回响 (Tech Demo).lrc");
//return lyricsSearchResult;
string overridenTitle = songInfo.Title; string overridenTitle = songInfo.Title;
string overridenArtist = songInfo.Artist; string overridenArtist = songInfo.Artist;
@@ -150,7 +148,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
.WithTitle(overridenTitle) .WithTitle(overridenTitle)
.WithArtist(overridenArtist) .WithArtist(overridenArtist)
.WithAlbum(overridenAlbum), .WithAlbum(overridenAlbum),
targetProvider.Value, checkCache, token); targetProvider.Value, true, token);
} }
} }
@@ -172,7 +170,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
.WithTitle(overridenTitle) .WithTitle(overridenTitle)
.WithArtist(overridenArtist) .WithArtist(overridenArtist)
.WithAlbum(overridenAlbum), .WithAlbum(overridenAlbum),
provider.Provider, checkCache, token); provider.Provider, !provider.IgnoreCacheWhenSearching, token);
int matchingThreshold = mediaSourceProviderInfo.MatchingThreshold; int matchingThreshold = mediaSourceProviderInfo.MatchingThreshold;
if (provider.IsMatchingThresholdOverwritten) if (provider.IsMatchingThresholdOverwritten)
@@ -288,7 +286,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
private async Task<LyricsCacheItem> SearchFile(SongInfo songInfo, LyricsFormat format) private async Task<LyricsCacheItem> SearchFile(SongInfo songInfo, LyricsFormat format)
{ {
int maxScore = 0; int maxScore = -1;
FilesIndexItem? bestFileEntity = null; FilesIndexItem? bestFileEntity = null;
MediaFolder? bestFolderConfig = null; MediaFolder? bestFolderConfig = null;
@@ -316,7 +314,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
{ {
if (item.FileName.EndsWith(targetExt, StringComparison.OrdinalIgnoreCase)) 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) if (score > maxScore)
{ {
@@ -363,13 +361,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
{ {
if (string.IsNullOrEmpty(item.EmbeddedLyrics)) continue; if (string.IsNullOrEmpty(item.EmbeddedLyrics)) continue;
int score = MetadataComparer.CalculateScore(songInfo, new LyricsCacheItem int score = MetadataComparer.CalculateScore(songInfo, item);
{
Title = item.Title,
Artist = item.Artist,
Album = item.Album,
Duration = item.Duration
});
if (score > maxScore) if (score > maxScore)
{ {
@@ -444,6 +436,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
Title = title, Title = title,
Artist = artist, Artist = artist,
Album = album, Album = album,
Duration = 0,
}); });
if (score > lyricsSearchResult.MatchPercentage) if (score > lyricsSearchResult.MatchPercentage)
{ {

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -243,6 +243,9 @@
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve"> <data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
<value>e.g. http://localhost:5000</value> <value>e.g. http://localhost:5000</value>
</data> </data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
</data>
<data name="LyricsLoading" xml:space="preserve"> <data name="LyricsLoading" xml:space="preserve">
<value>Loading lyrics...</value> <value>Loading lyrics...</value>
</data> </data>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>
@@ -243,6 +243,9 @@
<data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve"> <data name="LibreTranslateServerTextBox.PlaceholderText" xml:space="preserve">
<value>例如 http://localhost:5000</value> <value>例如 http://localhost:5000</value>
</data> </data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>持续时间</value>
</data>
<data name="LyricsLoading" xml:space="preserve"> <data name="LyricsLoading" xml:space="preserve">
<value>加载歌词中...</value> <value>加载歌词中...</value>
</data> </data>

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string"/> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string"/> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/> <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="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space"/> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <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:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>