Compare commits

...

9 Commits

Author SHA1 Message Date
Zhe Fang
4e33444d8e Update README.md 2026-01-09 19:26:31 -05:00
Zhe Fang
8fc67711b6 Simplify language selection in README.CN.md
Removed redundant link from Chinese README.
2026-01-09 19:26:16 -05:00
Zhe Fang
28757d9880 chores: bump to 253 2026-01-09 18:09:45 -05:00
Zhe Fang
e5fb04f577 fix: ValueTransition init 2026-01-09 17:54:50 -05:00
Zhe Fang
9d03c8f688 chores: i18n 2026-01-09 17:39:35 -05:00
Zhe Fang
094fe7b7a1 fix: lyrics animation gpu usage 2026-01-09 17:31:07 -05:00
Zhe Fang
bc32a3f34c feat: add all time filter for stats 2026-01-09 15:27:00 -05:00
Zhe Fang
b23d3c280f fix: not found and loading lyrics placeholder was not displayed 2026-01-09 14:48:12 -05:00
Zhe Fang
2738d45b69 fix: fill Duration (via searching NCM) for amll-ttml-db lyrics source; improve matching system 2026-01-09 13:50:46 -05:00
39 changed files with 328 additions and 220 deletions

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Folder Include="Interfaces\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,7 @@
namespace BetterLyrics.Core
{
public class Class1
{
}
}

View File

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

View File

@@ -74,6 +74,7 @@
<ComboBoxItem x:Uid="StatsDashboardControlThisMonth" />
<ComboBoxItem x:Uid="StatsDashboardControlThisQuarter" />
<ComboBoxItem x:Uid="StatsDashboardControlThisYear" />
<ComboBoxItem x:Uid="StatsDashboardControlAllTime" />
<ComboBoxItem x:Uid="StatsDashboardControlCustom" />
</ComboBox>

View File

@@ -7,6 +7,7 @@
ThisMonth,
ThisQuarter,
ThisYear,
AllTime,
Custom
}
}

View File

@@ -1,5 +1,6 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models.Lyrics;
using BetterLyrics.WinUI3.Services.LocalizationService;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -20,12 +21,24 @@ namespace BetterLyrics.WinUI3.Extensions
StartMs = 0,
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
PrimaryText = "● ● ●",
PrimarySyllables = [new BaseLyrics { Text = "● ● ●", StartMs = 0, EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds }],
},
],
LanguageCode = "N/A",
};
}
public static LyricsData GetNotfoundPlaceholder()
{
return new LyricsData([new LyricsLine
{
StartMs = 0,
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
PrimaryText = "N/A",
PrimarySyllables = [new BaseLyrics { Text = "N/A", StartMs = 0, EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds }],
}]);
}
public void SetTranslatedText(LyricsData translationData, int toleranceMs = 50)
{
foreach (var line in lyricsData.LyricsLines)

View File

@@ -36,6 +36,12 @@ namespace BetterLyrics.WinUI3.Extensions
return songInfo;
}
public SongInfo WithSongId(string value)
{
songInfo.SongId = value;
return songInfo;
}
public PlayHistoryItem? ToPlayHistoryItem(double actualPlayedMs)
{
if (songInfo == null) return null;

View File

@@ -10,27 +10,27 @@ namespace BetterLyrics.WinUI3.Helper
{
public static partial class MetadataComparer
{
private const double WeightTitle = 0.40;
private const double WeightArtist = 0.40;
private const double WeightTitle = 0.30;
private const double WeightArtist = 0.30;
private const double WeightAlbum = 0.10;
private const double WeightDuration = 0.10;
private const double WeightDuration = 0.30;
// JaroWinkler 适合短字符串匹配
private static readonly JaroWinkler _algo = new();
public static int CalculateScore(SongInfo songInfo, LyricsCacheItem remote)
{
return CalculateScore(songInfo, remote.Title, remote.Artist, remote.Album, remote.Duration * 1000);
return CalculateScore(songInfo, remote.Title, remote.Artist, remote.Album, remote.Duration);
}
public static int CalculateScore(SongInfo songInfo, FilesIndexItem local)
{
return CalculateScore(songInfo, local.Title, local.Artist, local.Album, local.Duration * 1000, local.FileName);
return CalculateScore(songInfo, local.Title, local.Artist, local.Album, local.Duration, local.FileName);
}
public static int CalculateScore(
SongInfo songInfo,
string? compareTitle, string? compareArtist, string? compareAlbum, double? compareDurationMs, string? compareFileName = null)
string? compareTitle, string? compareArtist, string? compareAlbum, double? compareDuration, string? compareFileName = null)
{
double totalScore = 0;
@@ -42,7 +42,7 @@ namespace BetterLyrics.WinUI3.Helper
double titleScore = GetStringSimilarity(songInfo.Title, compareTitle);
double artistScore = GetStringSimilarity(songInfo.Artist, compareArtist);
double albumScore = GetStringSimilarity(songInfo.Album, compareAlbum);
double durationScore = GetDurationSimilarity(songInfo.DurationMs, compareDurationMs);
double durationScore = GetDurationSimilarity(songInfo.Duration, compareDuration);
totalScore = (titleScore * WeightTitle) +
(artistScore * WeightArtist) +
@@ -94,19 +94,18 @@ namespace BetterLyrics.WinUI3.Helper
return _algo.Similarity(s1, s2);
}
private static double GetDurationSimilarity(double localMs, double? remoteSeconds)
private static double GetDurationSimilarity(double localSeconds, double? remoteSeconds)
{
if (remoteSeconds == null || remoteSeconds == 0) return 0.0; // 远程没有时长数据,不匹配
double localSeconds = localMs / 1000.0;
double diff = Math.Abs(localSeconds - remoteSeconds.Value);
// 差距 <= 3100% 相似
// 差距 >= 200% 相似
// 差距 <= 1 100 % 相似
// 差距 >= 10 0 % 相似
// 中间线性插值
const double PerfectTolerance = 3.0;
const double MaxTolerance = 20.0;
const double PerfectTolerance = 1.0;
const double MaxTolerance = 10.0;
if (diff <= PerfectTolerance) return 1.0;
if (diff >= MaxTolerance) return 0.0;

View File

@@ -40,17 +40,6 @@ namespace BetterLyrics.WinUI3.Helper
_targetValue = initialValue;
_totalDurationForAutoSplit = defaultTotalDuration;
if (interpolator == null)
{
// 默认缓动
SetEasingType(Enums.EasingType.EaseInOutQuad);
}
else
{
_easingType = null;
_interpolator = interpolator;
}
if (interpolator != null)
{
_interpolator = interpolator;

View File

@@ -36,38 +36,73 @@ namespace BetterLyrics.WinUI3.Logic
double currentPositionMs
)
{
if (lines == null) return;
if (lines == null || lines.Count == 0) return;
var currentPlayingLine = lines.ElementAtOrDefault(primaryPlayingLineIndex);
if (currentPlayingLine == null) return;
if (primaryPlayingLineIndex < 0 || primaryPlayingLineIndex >= lines.Count) return;
var primaryPlayingLine = lines[primaryPlayingLineIndex];
var phoneticOpacity = lyricsStyle.PhoneticLyricsOpacity / 100.0;
var originalOpacity = lyricsStyle.OriginalLyricsOpacity / 100.0;
var translatedOpacity = lyricsStyle.TranslatedLyricsOpacity / 100.0;
for (int i = startIndex; i <= endIndex + 1; i++)
double topHeightFactor = canvasHeight * playingLineTopOffsetFactor;
double bottomHeightFactor = canvasHeight * (1 - playingLineTopOffsetFactor);
double scrollTopDurationSec = lyricsEffect.LyricsScrollTopDuration / 1000.0;
double scrollTopDelaySec = lyricsEffect.LyricsScrollTopDelay / 1000.0;
double scrollBottomDurationSec = lyricsEffect.LyricsScrollBottomDuration / 1000.0;
double scrollBottomDelaySec = lyricsEffect.LyricsScrollBottomDelay / 1000.0;
double canvasTransDuration = canvasYScrollTransition.DurationSeconds;
bool isBlurEnabled = lyricsEffect.IsLyricsBlurEffectEnabled;
bool isOutOfSightEnabled = lyricsEffect.IsLyricsOutOfSightEffectEnabled;
bool isFanEnabled = lyricsEffect.IsFanLyricsEnabled;
double fanAngleRad = Math.PI * (lyricsEffect.FanLyricsAngle / 180.0);
bool isGlowEnabled = lyricsEffect.IsLyricsGlowEffectEnabled;
bool isFloatEnabled = lyricsEffect.IsLyricsFloatAnimationEnabled;
bool isScaleEnabled = lyricsEffect.IsLyricsScaleEffectEnabled;
int safeStart = Math.Max(0, startIndex);
int safeEnd = Math.Min(lines.Count - 1, endIndex + 1);
for (int i = safeStart; i <= safeEnd; i++)
{
var line = lines.ElementAtOrDefault(i);
if (line == null) continue;
var line = lines[i];
var lineHeight = line.PrimaryLineHeight;
if (lineHeight == null || lineHeight <= 0) continue;
double targetCharFloat = lyricsEffect.IsLyricsFloatAnimationAmountAutoAdjust
? lineHeight.Value * 0.1
: lyricsEffect.LyricsFloatAnimationAmount;
double targetCharGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust
? lineHeight.Value * 0.2
: lyricsEffect.LyricsGlowEffectAmount;
double targetCharScale = lyricsEffect.IsLyricsScaleEffectAmountAutoAdjust
? 1.15
: lyricsEffect.LyricsScaleEffectAmount / 100.0;
var maxAnimationDurationMs = Math.Max(line.EndMs - currentPositionMs, 0);
bool isSecondaryLinePlaying = line.GetIsPlaying(currentPositionMs);
bool isSecondaryLinePlayingChanged = line.IsPlayingLastFrame != isSecondaryLinePlaying;
line.IsPlayingLastFrame = isSecondaryLinePlaying;
// 行动画
if (isLayoutChanged || isPrimaryPlayingLineChanged || isMouseScrollingChanged || isSecondaryLinePlayingChanged)
if (isLayoutChanged || isPrimaryPlayingLineChanged || isMouseScrollingChanged)
{
int lineCountDelta = i - primaryPlayingLineIndex;
double distanceFromPlayingLine = Math.Abs(line.PrimaryPosition.Y - currentPlayingLine.PrimaryPosition.Y);
double distanceFromPlayingLine = Math.Abs(line.PrimaryPosition.Y - primaryPlayingLine.PrimaryPosition.Y);
double distanceFactor;
if (lineCountDelta < 0)
{
distanceFactor = Math.Clamp(distanceFromPlayingLine / (canvasHeight * playingLineTopOffsetFactor), 0, 1);
distanceFactor = Math.Clamp(distanceFromPlayingLine / topHeightFactor, 0, 1);
}
else
{
distanceFactor = Math.Clamp(distanceFromPlayingLine / (canvasHeight * (1 - playingLineTopOffsetFactor)), 0, 1);
distanceFactor = Math.Clamp(distanceFromPlayingLine / bottomHeightFactor, 0, 1);
}
double yScrollDuration;
@@ -76,34 +111,34 @@ namespace BetterLyrics.WinUI3.Logic
if (lineCountDelta < 0)
{
yScrollDuration =
canvasYScrollTransition.DurationSeconds +
distanceFactor * (lyricsEffect.LyricsScrollTopDuration / 1000.0 - canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * lyricsEffect.LyricsScrollTopDelay / 1000.0;
canvasTransDuration +
distanceFactor * (scrollTopDurationSec - canvasTransDuration);
yScrollDelay = distanceFactor * scrollTopDelaySec;
}
else if (lineCountDelta == 0)
{
yScrollDuration = canvasYScrollTransition.DurationSeconds;
yScrollDuration = canvasTransDuration;
yScrollDelay = 0;
}
else
{
yScrollDuration =
canvasYScrollTransition.DurationSeconds +
distanceFactor * (lyricsEffect.LyricsScrollBottomDuration / 1000.0 - canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * lyricsEffect.LyricsScrollBottomDelay / 1000.0;
canvasTransDuration +
distanceFactor * (scrollBottomDurationSec - canvasTransDuration);
yScrollDelay = distanceFactor * scrollBottomDelaySec;
}
line.BlurAmountTransition.SetDuration(yScrollDuration);
line.BlurAmountTransition.SetDelay(yScrollDelay);
line.BlurAmountTransition.Start(
(isMouseScrolling || isSecondaryLinePlaying) ? 0 :
(lyricsEffect.IsLyricsBlurEffectEnabled ? (5 * distanceFactor) : 0));
(isBlurEnabled ? (5 * distanceFactor) : 0));
line.ScaleTransition.SetDuration(yScrollDuration);
line.ScaleTransition.SetDelay(yScrollDelay);
line.ScaleTransition.Start(
isSecondaryLinePlaying ? _highlightedScale :
(lyricsEffect.IsLyricsOutOfSightEffectEnabled ?
(isOutOfSightEnabled ?
(_highlightedScale - distanceFactor * (_highlightedScale - _defaultScale)) :
_highlightedScale));
@@ -140,8 +175,8 @@ namespace BetterLyrics.WinUI3.Logic
line.AngleTransition.SetDuration(yScrollDuration);
line.AngleTransition.SetDelay(yScrollDelay);
line.AngleTransition.Start(
(lyricsEffect.IsFanLyricsEnabled && !isMouseScrolling) ?
Math.PI * (lyricsEffect.FanLyricsAngle / 180.0) * distanceFactor * (i > primaryPlayingLineIndex ? 1 : -1) :
(isFanEnabled && !isMouseScrolling) ?
Math.PI * (fanAngleRad / 180.0) * distanceFactor * (i > primaryPlayingLineIndex ? 1 : -1) :
0);
line.YOffsetTransition.SetEasingType(canvasYScrollTransition.EasingType);
@@ -152,7 +187,33 @@ namespace BetterLyrics.WinUI3.Logic
line.YOffsetTransition.Start(targetYScrollOffset);
}
var maxAnimationDurationMs = Math.Max(line.EndMs - currentPositionMs, 0);
if (isLayoutChanged || isSecondaryLinePlayingChanged)
{
// 辉光动画
if (isGlowEnabled && lyricsEffect.LyricsGlowEffectScope == Enums.LyricsEffectScope.LineStartToCurrentChar
&& isSecondaryLinePlaying)
{
foreach (var renderChar in line.PrimaryRenderChars)
{
var stepInOutDuration = Math.Min(Time.AnimationDuration.TotalMilliseconds, maxAnimationDurationMs) / 2.0 / 1000.0;
var stepLastingDuration = Math.Max(maxAnimationDurationMs / 1000.0 - stepInOutDuration * 2, 0);
renderChar.GlowTransition.Start(
new Models.Keyframe<double>(targetCharGlow, stepInOutDuration),
new Models.Keyframe<double>(targetCharGlow, stepLastingDuration),
new Models.Keyframe<double>(0, stepInOutDuration)
);
}
}
// 浮动动画
if (isFloatEnabled)
{
foreach (var renderChar in line.PrimaryRenderChars)
{
renderChar.FloatTransition.Start(isSecondaryLinePlaying ? targetCharFloat : 0);
}
}
}
// 字符动画
foreach (var renderChar in line.PrimaryRenderChars)
@@ -162,52 +223,17 @@ namespace BetterLyrics.WinUI3.Logic
bool isCharPlaying = renderChar.GetIsPlaying(currentPositionMs);
bool isCharPlayingChanged = renderChar.IsPlayingLastFrame != isCharPlaying;
if (isSecondaryLinePlayingChanged || isCharPlayingChanged)
{
if (lyricsEffect.IsLyricsGlowEffectEnabled)
{
double targetGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust ? renderChar.LayoutRect.Height * 0.2 : lyricsEffect.LyricsGlowEffectAmount;
switch (lyricsEffect.LyricsGlowEffectScope)
{
case Enums.LyricsEffectScope.LineStartToCurrentChar:
if (isSecondaryLinePlayingChanged && isSecondaryLinePlaying)
{
var stepInOutDuration = Math.Min(Time.AnimationDuration.TotalMilliseconds, maxAnimationDurationMs) / 2.0 / 1000.0;
var stepLastingDuration = Math.Max(maxAnimationDurationMs / 1000.0 - stepInOutDuration * 2, 0);
renderChar.GlowTransition.Start(
new Models.Keyframe<double>(targetGlow, stepInOutDuration),
new Models.Keyframe<double>(targetGlow, stepLastingDuration),
new Models.Keyframe<double>(0, stepInOutDuration)
);
}
break;
default:
break;
}
}
if (lyricsEffect.IsLyricsFloatAnimationEnabled)
{
double targetFloat =
lyricsEffect.IsLyricsFloatAnimationAmountAutoAdjust ? renderChar.LayoutRect.Height * 0.1 : lyricsEffect.LyricsFloatAnimationAmount;
if (isSecondaryLinePlayingChanged)
{
renderChar.FloatTransition.Start(isSecondaryLinePlaying ? targetFloat : 0);
}
if (isCharPlayingChanged)
{
if (isFloatEnabled)
{
renderChar.FloatTransition.SetDurationMs(Math.Min(lyricsEffect.LyricsFloatAnimationDuration, maxAnimationDurationMs));
renderChar.FloatTransition.Start(0);
}
}
if (isCharPlayingChanged)
{
renderChar.IsPlayingLastFrame = isCharPlaying;
}
}
}
// 音节动画
foreach (var syllable in line.PrimaryRenderSyllables)
@@ -217,60 +243,39 @@ namespace BetterLyrics.WinUI3.Logic
if (isSyllablePlayingChanged)
{
var syllableHeight = syllable.ChildrenRenderLyricsChars.FirstOrDefault()?.LayoutRect.Height ?? 0;
if (lyricsEffect.IsLyricsScaleEffectEnabled)
if (isScaleEnabled && isSyllablePlaying)
{
double targetScale =
lyricsEffect.IsLyricsScaleEffectAmountAutoAdjust ? 1.15 : lyricsEffect.LyricsScaleEffectAmount / 100.0;
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
{
if (syllable.DurationMs >= lyricsEffect.LyricsScaleEffectLongSyllableDuration)
{
if (isSyllablePlaying)
{
var stepDuration = Math.Min(syllable.DurationMs, maxAnimationDurationMs) / 2.0 / 1000.0;
renderChar.ScaleTransition.Start(
new Models.Keyframe<double>(targetScale, stepDuration),
new Models.Keyframe<double>(targetCharScale, stepDuration),
new Models.Keyframe<double>(1.0, stepDuration)
);
}
}
}
}
if (lyricsEffect.IsLyricsGlowEffectEnabled)
{
double targetGlow = lyricsEffect.IsLyricsGlowEffectAmountAutoAdjust ? syllableHeight * 0.2 : lyricsEffect.LyricsGlowEffectAmount;
switch (lyricsEffect.LyricsGlowEffectScope)
{
case Enums.LyricsEffectScope.LongDurationSyllable:
if (syllable.DurationMs >= lyricsEffect.LyricsGlowEffectLongSyllableDuration)
if (isGlowEnabled && isSyllablePlaying && lyricsEffect.LyricsGlowEffectScope == Enums.LyricsEffectScope.LongDurationSyllable
&& syllable.DurationMs >= lyricsEffect.LyricsGlowEffectLongSyllableDuration)
{
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
{
if (isSyllablePlaying)
{
var stepDuration = Math.Min(syllable.DurationMs, maxAnimationDurationMs) / 2.0 / 1000.0;
renderChar.GlowTransition.Start(
new Models.Keyframe<double>(targetGlow, stepDuration),
new Models.Keyframe<double>(targetCharGlow, stepDuration),
new Models.Keyframe<double>(0, stepDuration)
);
}
}
}
break;
default:
break;
}
}
syllable.IsPlayingLastFrame = isSyllablePlaying;
}
}
// 更新动画
// 使动画步进一帧
foreach (var renderChar in line.PrimaryRenderChars)
{
renderChar.Update(elapsedTime);

View File

@@ -9,8 +9,6 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
{
public class LyricsData
{
private static readonly ILocalizationService _localizationService = Ioc.Default.GetRequiredService<ILocalizationService>();
public List<LyricsLine> LyricsLines { get; set; } = [];
public string? LanguageCode
{
@@ -29,15 +27,5 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
LyricsLines = lyricsLines;
}
public static LyricsData GetNotfoundPlaceholder()
{
return new LyricsData([new LyricsLine
{
StartMs = 0,
EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds,
PrimaryText = _localizationService.GetLocalizedString("LyricsNotFound"),
}]);
}
}
}

View File

@@ -19,6 +19,9 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
public string SecondaryText { get; set; } = "";
public string TertiaryText { get; set; } = "";
public new string Text => PrimaryText;
public new int StartIndex = 0;
public LyricsLine()
{
for (int charStartIndex = 0; charStartIndex < PrimaryText.Length; charStartIndex++)

View File

@@ -74,6 +74,8 @@ namespace BetterLyrics.WinUI3.Models.Lyrics
/// </summary>
public int LaneIndex { get; set; } = 0;
public double? PrimaryLineHeight => PrimaryRenderChars.FirstOrDefault()?.LayoutRect.Height;
public RenderLyricsLine(LyricsLine lyricsLine) : base(lyricsLine)
{
AngleTransition = new(

View File

@@ -52,7 +52,7 @@ namespace BetterLyrics.WinUI3.Parsers.LyricsParser
}
}
if (syllables.Count > 0)
if (syllables.Count > 1)
{
lrcLines.Add(new LyricsLine
{

View File

@@ -26,12 +26,12 @@ namespace BetterLyrics.WinUI3.Renderer
Color fgColor,
LyricsEffectSettings settings)
{
DrawPhonetic(ds, textOnlyLayer, line);
DrawOriginalText(control, ds, textOnlyLayer, line, playbackState, bgColor, fgColor, settings);
DrawTranslated(ds, textOnlyLayer, line);
DrawTertiaryText(ds, textOnlyLayer, line);
DrawPrimaryText(control, ds, textOnlyLayer, line, playbackState, bgColor, fgColor, settings);
DrawSecondaryText(ds, textOnlyLayer, line);
}
private void DrawPhonetic(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
private void DrawTertiaryText(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
{
if (line.TertiaryTextLayout == null) return;
@@ -65,7 +65,7 @@ namespace BetterLyrics.WinUI3.Renderer
});
}
private void DrawTranslated(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
private void DrawSecondaryText(CanvasDrawingSession ds, ICanvasImage source, RenderLyricsLine line)
{
if (line.SecondaryTextLayout == null) return;
@@ -99,7 +99,7 @@ namespace BetterLyrics.WinUI3.Renderer
});
}
private void DrawOriginalText(
private void DrawPrimaryText(
ICanvasResourceCreator resourceCreator,
CanvasDrawingSession ds,
ICanvasImage source,

View File

@@ -22,7 +22,6 @@ namespace BetterLyrics.WinUI3.Services.GSMTCService
{
_logger.LogInformation("RefreshLyricsAsync");
CurrentLyricsSearchResult = null;
CurrentLyricsData = LyricsData.GetLoadingPlaceholder();
if (CurrentSongInfo != SongInfoExtensions.Placeholder)

View File

@@ -11,6 +11,7 @@ using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.AlbumArtSearchService;
using BetterLyrics.WinUI3.Services.DiscordService;
using BetterLyrics.WinUI3.Services.LastFMService;
using BetterLyrics.WinUI3.Services.LocalizationService;
using BetterLyrics.WinUI3.Services.LyricsSearchService;
using BetterLyrics.WinUI3.Services.PlayHistoryService;
using BetterLyrics.WinUI3.Services.SettingsService;
@@ -19,6 +20,7 @@ using BetterLyrics.WinUI3.Services.TransliterationService;
using BetterLyrics.WinUI3.ViewModels;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using CommunityToolkit.WinUI;
@@ -206,7 +208,6 @@ namespace BetterLyrics.WinUI3.Services.GSMTCService
private void InitMediaManager()
{
_mediaManager.Start();
_mediaManager.CurrentMediaSessions.ToList().ForEach(x => RecordMediaSession(x.Value.Id));
_mediaManager.OnAnySessionOpened += MediaManager_OnAnySessionOpened;

View File

@@ -55,6 +55,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsCacheService
existingItem.Title = result.Title;
existingItem.Artist = result.Artist;
existingItem.Album = result.Album;
existingItem.Duration = result.Duration;
existingItem.TransliterationProvider = result.TransliterationProvider;
existingItem.TranslationProvider = result.TranslationProvider;

View File

@@ -1,5 +1,6 @@
// 2025/6/23 by Zhe Fang
using BetterLyrics.WinUI3.Constants;
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Extensions;
using BetterLyrics.WinUI3.Helper;
@@ -29,7 +30,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
{
private readonly HttpClient _amllTtmlDbHttpClient;
private readonly HttpClient _lrcLibHttpClient;
private readonly AppleMusic _appleMusic;
private readonly Providers.AppleMusic _appleMusic;
private readonly ISettingsService _settingsService;
private readonly IFileSystemService _fileSystemService;
@@ -54,10 +55,10 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
_lrcLibHttpClient = new();
_lrcLibHttpClient.DefaultRequestHeaders.Add(
"User-Agent",
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Constants.Link.BetterLyricsGitHub})"
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Link.BetterLyricsGitHub})"
);
_amllTtmlDbHttpClient = new();
_appleMusic = new AppleMusic();
_appleMusic = new Providers.AppleMusic();
}
private static bool IsAmllTtmlDbIndexInvalid()
@@ -402,6 +403,8 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
}
string? rawLyricFile = null;
string? bestNcmMusicId = null;
await foreach (var line in File.ReadLinesAsync(PathHelper.AmllTtmlDbIndexPath))
{
if (string.IsNullOrWhiteSpace(line))
@@ -416,6 +419,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
string? title = null;
string? artist = null;
string? album = null;
string? ncmMusicId = null;
foreach (var meta in metadataArr.EnumerateArray())
{
@@ -429,6 +433,8 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
artist = string.Join(" / ", valueArr.EnumerateArray());
if (key == "album" && valueArr.GetArrayLength() > 0)
album = valueArr[0].GetString();
if (key == "ncmMusicId" && valueArr.GetArrayLength() > 0)
ncmMusicId = valueArr[0].GetString();
}
int score = MetadataComparer.CalculateScore(songInfo, new LyricsCacheItem
@@ -436,12 +442,12 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
Title = title,
Artist = artist,
Album = album,
Duration = 0,
});
if (score > lyricsSearchResult.MatchPercentage)
{
if (root.TryGetProperty("rawLyricFile", out var rawLyricFileProp))
{
bestNcmMusicId = ncmMusicId;
rawLyricFile = rawLyricFileProp.GetString();
lyricsSearchResult.Title = title;
lyricsSearchResult.Artist = artist;
@@ -458,19 +464,28 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
return lyricsSearchResult;
}
// 下载歌词内容
var url = $"{_settingsService.AppSettings.GeneralSettings.AmllTtmlDbBaseUrl}/{Constants.AmllTTmlDB.QueryPrefix}/{rawLyricFile}";
var url = $"{_settingsService.AppSettings.GeneralSettings.AmllTtmlDbBaseUrl}/{AmllTTmlDB.QueryPrefix}/{rawLyricFile}";
lyricsSearchResult.Reference = url;
try
{
// 下载写入歌词
using var response = await _amllTtmlDbHttpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
{
return lyricsSearchResult;
}
string lyrics = await response.Content.ReadAsStringAsync();
lyricsSearchResult.Raw = lyrics;
// 反查时长
if (bestNcmMusicId != null && lyricsSearchResult.Duration == null)
{
var tmp = await SearchQQNeteaseKugouAsync(
((SongInfo)songInfo.Clone()).WithSongId($"{ExtendedGenreFiled.NetEaseCloudMusicTrackID}{bestNcmMusicId}"),
Searchers.Netease);
lyricsSearchResult.Duration = tmp.Duration;
lyricsSearchResult.MatchPercentage = MetadataComparer.CalculateScore(songInfo, lyricsSearchResult);
}
}
catch
{
@@ -633,7 +648,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
}
lyricsSearchResult.Title = result?.Title;
lyricsSearchResult.Artist = string.Join(" / ", result?.Artists ?? []);
lyricsSearchResult.Artist = result?.Artist;
lyricsSearchResult.Album = result?.Album;
lyricsSearchResult.Duration = result?.DurationMs / 1000;

View File

@@ -244,7 +244,7 @@
<value>مثال: http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>المدة</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>جارٍ تحميل الكلمات...</value>
@@ -1138,16 +1138,16 @@
<value>اختصار تبديل حالة نافذة الكلمات</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>استراتيجية الرسوم المتحركة كلمة بكلمة</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>دائماً</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>السيارات</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>أبداً</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>سيؤثر ضبط هذه القيمة على نتائج البحث المتسلسل والبحث بأفضل تطابق، ولكنه لن يؤثر على نتائج البحث في واجهة البحث اليدوي عن الكلمات</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>النشاط بالساعة</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>كل الوقت</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>مخصص</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>z. B. http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>Dauer</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>Songtext wird geladen...</value>
@@ -1138,16 +1138,16 @@
<value>Tastenkürzel für Songtext-Fensterstatuswechsel</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>Wort-für-Wort-Animationsstrategie</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>Immer</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>Niemals</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>Das Anpassen dieses Wertes beeinflusst die sequenzielle Suche und die Suche nach der besten Übereinstimmung, hat jedoch keinen Einfluss auf die Suchergebnisse in der manuellen Songtext-Suchoberfläche</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Aktivität nach Stunden</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>Alle Zeiten</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>Benutzerdefiniert</value>
</data>

View File

@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Activity by Hour</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>All Time</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>Custom</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>ej. http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>Duración</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>Cargando letra...</value>
@@ -1138,16 +1138,16 @@
<value>Atajo de cambio de estado de ventana de letras</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>Estrategia de animación palabra por palabra</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>Siempre</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>Nunca</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>Ajustar este valor afectará a la búsqueda secuencial y a los resultados de la búsqueda de mejor coincidencia, pero no afectará a los resultados de búsqueda en la interfaz de búsqueda manual de letras</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Actividad por horas</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>Todos los tiempos</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>A medida</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>ex : http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>Durée de l'accord</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>Chargement des paroles...</value>
@@ -1138,16 +1138,16 @@
<value>Raccourci changement état fenêtre paroles</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>Stratégie d'animation mot à mot</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>Toujours</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>Jamais</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>L'ajustement de cette valeur affectera les résultats de la recherche séquentielle et de la meilleure correspondance, mais n'affectera pas les résultats de la recherche manuelle</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Activité par heure</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>Tout le temps</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>Sur mesure</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>उदाहरण http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>समयांतराल</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>बोल लोड हो रहे हैं...</value>
@@ -1138,16 +1138,16 @@
<value>बोल विंडो स्थिति स्विच शॉर्टकट</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>शब्द-दर-शब्द एनिमेशन रणनीति</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>हमेशा</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>स्वतः</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>कभी नहीं</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>इस मान को समायोजित करने से अनुक्रमिक खोज और सर्वोत्तम मिलान खोज परिणाम प्रभावित होंगे, लेकिन मैनुअल बोल खोज इंटरफ़ेस में खोज परिणाम प्रभावित नहीं होंगे</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>घंटे के हिसाब से गतिविधि</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>अब तक के सारे</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>कस्टम</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>Contoh: http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>Durasi</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>Memuat lirik...</value>
@@ -1138,16 +1138,16 @@
<value>Pintasan Pengalih Status Jendela Lirik</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>Strategi Animasi Kata per Kata</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>Selalu</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>Otomatis</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>Tidak pernah</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>Menyesuaikan nilai ini akan memengaruhi hasil pencarian berurutan dan pencarian kecocokan terbaik, tetapi tidak akan memengaruhi hasil pencarian di antarmuka pencarian manual lirik</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Aktivitas per Jam</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>Semua Waktu</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>Kustom</value>
</data>

View File

@@ -1051,7 +1051,7 @@
<value>カスタム</value>
</data>
<data name="SettingsPageLyricsFontFamily.Header" xml:space="preserve">
<value>フォントファミリー</value>
<value>フォント</value>
</data>
<data name="SettingsPageLyricsFontSize.Header" xml:space="preserve">
<value>フォントサイズ</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>アクティブ時間帯</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>全期間</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>カスタム</value>
</data>
@@ -1492,7 +1495,7 @@
<value>最多アクティブ</value>
</data>
<data name="StatsDashboardControlRecording.Title" xml:space="preserve">
<value>再生記録中...</value>
<value>再生履歴記録中...</value>
</data>
<data name="StatsDashboardControlSources.Text" xml:space="preserve">
<value>再生ソース</value>

View File

@@ -244,7 +244,7 @@
<value>예: http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>기간</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>가사 불러오는 중...</value>
@@ -1138,16 +1138,16 @@
<value>가사 창 상태 전환 단축키</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>단어별 애니메이션 전략</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>항상</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>자동</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>절대로</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>이 값을 조정하면 순차 검색 및 최적 일치 검색 결과에 영향을 미치지만 수동 가사 검색 인터페이스의 검색 결과에는 영향을 미치지 않습니다</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>시간별 활동</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>모든 시간</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>사용자 지정</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>Contoh: http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>Durasi</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>Memuatkan lirik...</value>
@@ -1138,16 +1138,16 @@
<value>Pintasan Tukar Status Tetingkap Lirik</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>Strategi Animasi Perkataan demi Perkataan</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>Sentiasa</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>Automatik</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>Tak pernah</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>Melaraskan nilai ini akan mempengaruhi hasil carian jujukan dan carian padanan terbaik, tetapi tidak akan mempengaruhi hasil carian dalam antara muka carian lirik manual</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Aktiviti mengikut Jam</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>Semua</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>Tersuai</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>Exemplo: http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>Duração</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>A carregar a letra...</value>
@@ -1138,16 +1138,16 @@
<value>Atalho de Alternância de Estado da Janela</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>Estratégia de animação palavra a palavra</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>Sempre</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>Automóvel</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>Nunca</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>Ajustar este valor afetará os resultados da pesquisa sequencial e de melhor correspondência, mas não afetará os resultados na interface de pesquisa manual de letras</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Atividade por hora</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>Todo o tempo</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>Personalizado</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>например, http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>Продолжительность</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>Загрузка текста...</value>
@@ -1138,16 +1138,16 @@
<value>Горячая клавиша переключения состояния окна</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>Стратегия словесной анимации</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>Всегда</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>Авто</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>Никогда</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>Настройка этого значения повлияет на результаты последовательного поиска и поиска лучшего совпадения, но не повлияет на результаты в интерфейсе ручного поиска</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Активность по часам</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>Все время</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>Пользовательское</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>ตัวอย่าง http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>ระยะเวลา</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>กำลังโหลดเนื้อเพลง...</value>
@@ -1138,16 +1138,16 @@
<value>ทางลัดสลับสถานะหน้าต่างเนื้อเพลง</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>กลยุทธ์การสร้างแอนิเมชันแบบคำต่อคำ</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>เสมอ</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>ออโต้</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>ไม่เคย</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>การปรับค่านี้จะมีผลกับผลการค้นหาแบบตามลำดับและแบบตรงกันที่สุด แต่จะไม่มีผลกับผลการค้นหาในหน้าค้นหาเนื้อเพลงด้วยตนเอง</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>กิจกรรมตามชั่วโมง</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>ตลอดเวลา</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>กำหนดเอง</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>Ví dụ: http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>Thời gian</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>Đang tải lời bài hát...</value>
@@ -1138,16 +1138,16 @@
<value>Phím tắt chuyển trạng thái cửa sổ lời bài hát</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>Chiến lược hoạt hình từng từ</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>Luôn luôn</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>Tự động</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>Không bao giờ</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>Điều chỉnh giá trị này sẽ ảnh hưởng đến kết quả tìm kiếm tuần tự và khớp nhất, nhưng sẽ không ảnh hưởng đến kết quả tìm kiếm trong giao diện tìm kiếm lời bài hát thủ công</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>Hoạt động theo giờ</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>Mọi thời đại</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>Tùy chỉnh</value>
</data>

View File

@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>活跃时段</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>全部时间</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>自定义</value>
</data>

View File

@@ -244,7 +244,7 @@
<value>例如 http://localhost:5000</value>
</data>
<data name="LyricsEffectSettingsControlAnimationDuration.Header" xml:space="preserve">
<value>Duration</value>
<value>時間長度</value>
</data>
<data name="LyricsLoading" xml:space="preserve">
<value>載入歌詞中...</value>
@@ -1138,16 +1138,16 @@
<value>歌詞視窗狀態切換快速鍵</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectMode.Header" xml:space="preserve">
<value>Word-by-word Animation Strategy</value>
<value>逐字動畫策略</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAlways.Content" xml:space="preserve">
<value>Always</value>
<value>永遠</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeAuto.Content" xml:space="preserve">
<value>Auto</value>
<value>自動</value>
</data>
<data name="SettingsPageLyricsWordByWordEffectModeNever.Content" xml:space="preserve">
<value>Never</value>
<value>從不</value>
</data>
<data name="SettingsPageMatchingThreshold.Description" xml:space="preserve">
<value>調整此值將影響順序搜尋和最佳符合搜尋結果,但不會影響手動歌詞搜尋介面中的搜尋結果</value>
@@ -1479,6 +1479,9 @@
<data name="StatsDashboardControlActivityByHour.Text" xml:space="preserve">
<value>每小時的活動</value>
</data>
<data name="StatsDashboardControlAllTime.Content" xml:space="preserve">
<value>所有時間</value>
</data>
<data name="StatsDashboardControlCustom.Content" xml:space="preserve">
<value>自訂</value>
</data>

View File

@@ -186,6 +186,9 @@ namespace BetterLyrics.WinUI3.ViewModels
case StatsRange.ThisYear:
startLocal = new DateTime(nowLocal.Year, 1, 1);
break;
case StatsRange.AllTime:
startLocal = DateTime.MinValue;
break;
}
CustomStartDate = startLocal.Date;

View File

@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.13.36105.23
# Visual Studio Version 18
VisualStudioVersion = 18.1.11312.151 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "BetterLyrics.WinUI3 (Package)", "BetterLyrics.WinUI3\BetterLyrics.WinUI3 (Package)\BetterLyrics.WinUI3 (Package).wapproj", "{6576CD19-EF92-4099-B37D-E2D8EBDB6BF5}"
EndProject
@@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Impressionist", "Impression
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorThief.WinUI3", "ColorThief.WinUI3\ColorThief.WinUI3.csproj", "{8F2FE667-2D91-428E-0630-05E6330F9625}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterLyrics.Core", "BetterLyrics.Core\BetterLyrics.Core.csproj", "{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -75,6 +77,18 @@ Global
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|x64.Build.0 = Release|Any CPU
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|x86.ActiveCfg = Release|Any CPU
{8F2FE667-2D91-428E-0630-05E6330F9625}.Release|x86.Build.0 = Release|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|ARM64.Build.0 = Debug|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|x64.ActiveCfg = Debug|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|x64.Build.0 = Debug|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|x86.ActiveCfg = Debug|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Debug|x86.Build.0 = Debug|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|ARM64.ActiveCfg = Release|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|ARM64.Build.0 = Release|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|x64.ActiveCfg = Release|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|x64.Build.0 = Release|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|x86.ActiveCfg = Release|Any CPU
{0F47FE6F-D0AA-49E5-8F33-78DFDEB1F810}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,4 +1,4 @@
[**中文**](README.CN.md) | [**English**](README.md)
**中文** | [**English**](README.md)
<div align="center">
<img src="BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Logo.png" alt="Logo" width="120">

View File

@@ -1,4 +1,4 @@
[**中文**](README.CN.md) | [**English**](README.md)
[**中文**](README.CN.md) | **English**
<div align="center">
<img src="BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Logo.png" alt="Logo" width="120">