Compare commits

...

16 Commits

Author SHA1 Message Date
Zhe Fang
c43b69b4cb rollback window ctrl btn to previous version 2025-10-12 09:40:10 -04:00
Zhe Fang
94b22552e5 update doc 2025-10-10 11:40:44 -04:00
Zhe Fang
6deb16f6cb update version code 2025-10-10 11:34:39 -04:00
Zhe Fang
e467ab9c73 替换 SourceAppUserModelId 为 PlayerId 并新增 SongId
将 SongInfo 中的 SourceAppUserModelId 属性替换为 PlayerId,新增可选属性 SongId 以支持更精确的歌曲标识。
更新了相关服务和方法的参数签名,增加对 SongId 的支持,包括 SearchSmartlyAsync 和 SearchSingleAsync 方法。
调整了 MediaSessionsService 的逻辑,支持不同播放器的 SongId 处理。
优化了代码的灵活性和可扩展性,便于处理多播放器和歌曲标识。
2025-10-10 11:29:50 -04:00
Zhe Fang
ea038c9c56 更新 README.md 2025-10-05 07:59:44 -04:00
Zhe Fang
560250ad30 更新 README.md 2025-10-05 07:57:35 -04:00
Zhe Fang
536acc69a5 更新 README.md 2025-10-05 07:56:00 -04:00
Zhe Fang
0bbb379912 update LICENSE.txt 2025-09-21 21:15:15 -04:00
Zhe Fang
1f4d29e6f2 更新 README.md 2025-09-13 06:49:20 -04:00
Zhe Fang
5d1d7476c9 update screenshots 2025-09-11 21:10:24 -04:00
Zhe Fang
e016baefe1 doc 2025-09-11 20:44:17 -04:00
Zhe Fang
70b6194788 Improve formatting and clarity in README.md 2025-09-11 20:32:26 -04:00
Zhe Fang
9f103b0ea3 Update README with QQ 音乐 details and grammar fixes 2025-09-10 09:30:39 -04:00
Zhe Fang
2924140f95 Refine README.md for grammar and clarity
Corrected grammar and punctuation throughout the README file for improved clarity and consistency.
2025-09-08 18:33:06 -04:00
Zhe Fang
3d3f168926 更新 README.md 2025-09-05 07:23:52 -04:00
Zhe Fang
63b2285a36 Update download link for app in README 2025-09-05 07:03:26 -04:00
28 changed files with 209 additions and 111 deletions

View File

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

View File

@@ -21,11 +21,14 @@ namespace BetterLyrics.WinUI3.Models
public partial double? DurationMs { get; set; }
[ObservableProperty]
public partial string? SourceAppUserModelId { get; set; } = null;
public partial string? PlayerId { get; set; } = null;
[ObservableProperty]
public partial string Title { get; set; }
[ObservableProperty]
public partial string? SongId { get; set; } = null;
public SongInfo() { }
}
}

View File

@@ -11,7 +11,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
{
public interface ILyricsSearchService
{
Task<LyricsSearchResult> SearchSmartlyAsync(string mediaSessionId, string title, string artist, string album, double durationMs, CancellationToken token);
Task<LyricsSearchResult> SearchSmartlyAsync(string mediaSessionId, string title, string artist, string album, double durationMs, string? songId, CancellationToken token);
Task<List<LyricsSearchResult>> SearchAllAsync(string title, string artist, string album, double durationMs, CancellationToken token);
}

View File

@@ -91,7 +91,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
}
}
public async Task<LyricsSearchResult> SearchSmartlyAsync(string mediaSessionId, string title, string artist, string album, double durationMs, CancellationToken token)
public async Task<LyricsSearchResult> SearchSmartlyAsync(string mediaSessionId, string title, string artist, string album, double durationMs, string? songId, CancellationToken token)
{
var lyricsSearchResult = new LyricsSearchResult();
@@ -123,7 +123,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
var targetProvider = found.LyricsSearchProvider;
if (targetProvider != null)
{
return await SearchSingleAsync(targetProvider.Value, overridenTitle, overridenArtist, album, durationMs, token);
return await SearchSingleAsync(targetProvider.Value, overridenTitle, overridenArtist, album, durationMs, songId, token);
}
}
@@ -134,7 +134,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
continue;
}
lyricsSearchResult = await SearchSingleAsync(provider.Provider, overridenTitle, overridenArtist, album, durationMs, token);
lyricsSearchResult = await SearchSingleAsync(provider.Provider, overridenTitle, overridenArtist, album, durationMs, null, token);
if (lyricsSearchResult.IsFound)
{
@@ -151,13 +151,13 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
var results = new List<LyricsSearchResult>();
foreach (var provider in Enum.GetValues<LyricsSearchProvider>())
{
var searchResult = await SearchSingleAsync(provider, title, artist, album, durationMs, token);
var searchResult = await SearchSingleAsync(provider, title, artist, album, durationMs, null, token);
results.Add(searchResult);
}
return results;
}
private async Task<LyricsSearchResult> SearchSingleAsync(LyricsSearchProvider provider, string title, string artist, string album, double durationMs, CancellationToken token)
private async Task<LyricsSearchResult> SearchSingleAsync(LyricsSearchProvider provider, string title, string artist, string album, double durationMs, string? songId, CancellationToken token)
{
var lyricsSearchResult = new LyricsSearchResult
{
@@ -200,13 +200,13 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
lyricsSearchResult = await SearchLrcLibAsync(title, artist, album, (int)(durationMs / 1000));
break;
case LyricsSearchProvider.QQ:
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, Searchers.QQMusic);
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, songId, Searchers.QQMusic);
break;
case LyricsSearchProvider.Kugou:
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, Searchers.Kugou);
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, songId, Searchers.Kugou);
break;
case LyricsSearchProvider.Netease:
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, Searchers.Netease);
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, songId, Searchers.Netease);
break;
case LyricsSearchProvider.AmllTtmlDb:
lyricsSearchResult = await SearchAmllTtmlDbAsync(title, artist);
@@ -436,7 +436,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
return lyricsSearchResult;
}
private static async Task<LyricsSearchResult> SearchQQNeteaseKugouAsync(string title, string artist, string album, int durationMs, Searchers searchers)
private static async Task<LyricsSearchResult> SearchQQNeteaseKugouAsync(string title, string artist, string album, int durationMs, string? songId, Searchers searchers)
{
var lyricsSearchResult = new LyricsSearchResult();
@@ -457,15 +457,23 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
break;
}
var result = await SearchersHelper.GetSearcher(searchers).SearchForResult(
new Lyricify.Lyrics.Models.TrackMultiArtistMetadata()
{
DurationMs = durationMs,
Album = album,
Artists = [artist],
Title = title,
}
);
ISearchResult? result;
if (searchers == Searchers.Netease && songId != null)
{
result = new NeteaseSearchResult(title, [artist], album, null, durationMs, songId);
}
else
{
result = await SearchersHelper.GetSearcher(searchers).SearchForResult(
new Lyricify.Lyrics.Models.TrackMultiArtistMetadata()
{
DurationMs = durationMs,
Album = album,
Artists = [artist],
Title = title,
}
);
}
if (result is QQMusicSearchResult qqResult)
{

View File

@@ -34,7 +34,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
}
byte[]? bytes = await Task.Run(async () => await _albumArtSearchService.SearchAsync(
SongInfo?.SourceAppUserModelId ?? "",
SongInfo?.PlayerId ?? "",
_cachedSongInfo.Title,
_cachedSongInfo.Artist,
_cachedSongInfo?.Album ?? string.Empty,

View File

@@ -156,11 +156,12 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
SongInfo.Title, SongInfo.Artist, SongInfo.Album, SongInfo.DurationMs);
var lyricsSearchResult = await Task.Run(async () => await _lyrcsSearchService.SearchSmartlyAsync(
SongInfo.SourceAppUserModelId ?? "",
SongInfo.PlayerId ?? "",
SongInfo.Title,
SongInfo.Artist,
SongInfo.Album ?? "",
SongInfo.DurationMs ?? 0,
SongInfo.SongId,
token
), token);
if (token.IsCancellationRequested) return;

View File

@@ -284,21 +284,21 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
if (!_mediaManager.IsStarted) return;
if (mediaSession == null) return;
string id = mediaSession.Id;
string sessionId = mediaSession.Id;
var desiredSession = GetCurrentSession();
//RecordMediaSourceProviderInfo(mediaSession);
if (mediaSession != desiredSession) return;
if (!IsMediaSourceEnabled(id))
if (!IsMediaSourceEnabled(sessionId))
{
_cachedSongInfo = null;
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
mediaProperties.Title, mediaProperties.Artist, mediaProperties.AlbumTitle);
if (id == Constants.PlayerID.LXMusic)
if (sessionId == Constants.PlayerID.LXMusic)
{
StopSSE();
}
@@ -313,38 +313,39 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
currentMediaSourceProviderInfo?.PositionOffset = 0;
}
if (id == Constants.PlayerID.AppleMusic || id == Constants.PlayerID.AppleMusicAlternative)
{
string fixedArtist = mediaProperties.Artist.Split(" — ").FirstOrDefault() ?? mediaProperties.Artist;
string fixedAlbum = mediaProperties.Artist.Split(" — ").LastOrDefault() ?? mediaProperties.AlbumTitle;
string fixedArtist = mediaProperties.Artist;
string fixedAlbum = mediaProperties.AlbumTitle;
string? songId = null;
_cachedSongInfo = new SongInfo
{
Title = mediaProperties.Title,
Artist = fixedArtist,
Album = fixedAlbum,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
SourceAppUserModelId = id,
};
}
else
if (sessionId == Constants.PlayerID.AppleMusic || sessionId == Constants.PlayerID.AppleMusicAlternative)
{
_cachedSongInfo = new SongInfo
fixedArtist = mediaProperties.Artist.Split(" — ").FirstOrDefault() ?? mediaProperties.Artist;
fixedAlbum = mediaProperties.Artist.Split(" — ").LastOrDefault() ?? mediaProperties.AlbumTitle;
}
else if (sessionId == Constants.PlayerID.NetEaseCloudMusic)
{
songId = mediaProperties.Genres.FirstOrDefault()?.Replace("NCM-", "");
if (songId != null && songId.Length != 10)
{
Title = mediaProperties.Title,
Artist = mediaProperties.Artist,
Album = mediaProperties.AlbumTitle,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
SourceAppUserModelId = id,
};
songId = null;
}
}
_cachedSongInfo = new SongInfo
{
Title = mediaProperties.Title,
Artist = fixedArtist,
Album = fixedAlbum,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
PlayerId = sessionId,
SongId = songId
};
_cachedSongInfo.Duration = (int)(_cachedSongInfo.DurationMs / 1000f);
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
mediaProperties.Title, mediaProperties.Artist, mediaProperties.AlbumTitle);
if (id == Constants.PlayerID.LXMusic)
if (sessionId == Constants.PlayerID.LXMusic)
{
StartSSE();
}
@@ -353,7 +354,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
StopSSE();
}
if (id == Constants.PlayerID.LXMusic && _lxMusicAlbumArtBytes != null)
if (sessionId == Constants.PlayerID.LXMusic && _lxMusicAlbumArtBytes != null)
{
_SMTCAlbumArtBytes = _lxMusicAlbumArtBytes;
}
@@ -507,7 +508,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
{
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
{
if (_cachedSongInfo?.SourceAppUserModelId == Constants.PlayerID.LXMusic)
if (_cachedSongInfo?.PlayerId == Constants.PlayerID.LXMusic)
{
var data = JsonSerializer.Deserialize(e.Message, Serialization.SourceGenerationContext.Default.JsonElement);
if (data.ValueKind == JsonValueKind.Number)

View File

@@ -110,6 +110,10 @@ namespace BetterLyrics.WinUI3
[ObservableProperty] public partial Visibility DesktopFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility PIPFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility DockFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility MinimiseButtonVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility MaximiseButtonVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility RestoreButtonVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility CloseButtonVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial bool IsFullScreenFlyoutItemChecked { get; set; } = false;
[ObservableProperty] public partial bool IsDesktopFlyoutItemChecked { get; set; } = false;
@@ -305,6 +309,8 @@ namespace BetterLyrics.WinUI3
private void SetFullscreenTitleBarControlsStatus()
{
LockButtonVisibility = DesktopFlyoutItemVisibility = PIPFlyoutItemVisibility = DockFlyoutItemVisibility = Visibility.Collapsed;
MinimiseButtonVisibility = MaximiseButtonVisibility = RestoreButtonVisibility = Visibility.Collapsed;
CloseButtonVisibility = Visibility.Visible;
IsFullScreenFlyoutItemChecked = true;
IsImmersiveMode = true;
}
@@ -312,6 +318,8 @@ namespace BetterLyrics.WinUI3
private void SetPIPModeTitleBarControlsStatus()
{
DesktopFlyoutItemVisibility = FullScreenFlyoutItemVisibility = DockFlyoutItemVisibility = LockButtonVisibility = Visibility.Collapsed;
MinimiseButtonVisibility = MaximiseButtonVisibility = RestoreButtonVisibility = Visibility.Collapsed;
CloseButtonVisibility = Visibility.Visible;
IsImmersiveMode = true;
IsPIPFlyoutItemChecked = true;
}
@@ -324,6 +332,8 @@ namespace BetterLyrics.WinUI3
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = false;
DesktopFlyoutItemVisibility = LockButtonVisibility = FullScreenFlyoutItemVisibility = PIPFlyoutItemVisibility = Visibility.Collapsed;
MinimiseButtonVisibility = MaximiseButtonVisibility = RestoreButtonVisibility = Visibility.Collapsed;
CloseButtonVisibility = Visibility.Visible;
IsImmersiveMode = true;
IsDockFlyoutItemChecked = true;
}
@@ -337,6 +347,8 @@ namespace BetterLyrics.WinUI3
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = false;
DockFlyoutItemVisibility = FullScreenFlyoutItemVisibility = PIPFlyoutItemVisibility = Visibility.Collapsed;
LockButtonVisibility = Visibility.Visible;
MinimiseButtonVisibility = MaximiseButtonVisibility = RestoreButtonVisibility = Visibility.Collapsed;
CloseButtonVisibility = Visibility.Visible;
IsDesktopFlyoutItemChecked = true;
}
@@ -349,6 +361,8 @@ namespace BetterLyrics.WinUI3
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = true;
DesktopFlyoutItemVisibility = DockFlyoutItemVisibility = PIPFlyoutItemVisibility = FullScreenFlyoutItemVisibility = Visibility.Visible;
LockButtonVisibility = Visibility.Collapsed;
MinimiseButtonVisibility = MaximiseButtonVisibility = CloseButtonVisibility = Visibility.Visible;
RestoreButtonVisibility = Visibility.Collapsed;
IsFullScreenFlyoutItemChecked = IsDesktopFlyoutItemChecked = IsDockFlyoutItemChecked = IsPIPFlyoutItemChecked = false;
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
}

View File

@@ -111,7 +111,7 @@ namespace BetterLyrics.WinUI3.ViewModels
private void MediaSessionsService_SongInfoChanged(object? sender, Events.SongInfoChangedEventArgs e)
{
var current = AppSettings.MediaSourceProvidersInfo.Where(x => x.Provider == e.SongInfo?.SourceAppUserModelId)?.FirstOrDefault();
var current = AppSettings.MediaSourceProvidersInfo.Where(x => x.Provider == e.SongInfo?.PlayerId)?.FirstOrDefault();
if (_mediaSessionsService.Position.TotalSeconds <= 1 && current?.ResetPositionOffsetOnSongChanged == true)
{
current.PositionOffset = 0;

View File

@@ -123,11 +123,6 @@
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE713;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Uid="SystemTrayExit"
Click="ExitAppMenuFlyoutItem_Click"
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE7E8;}" />
</MenuFlyout>
</Button.Flyout>
</Button>
@@ -145,6 +140,7 @@
FontSize="{x:Bind ViewModel.TitleBarFontSize}"
Glyph="&#xED1A;" />
</ToggleButton>
</StackPanel>
</Grid>
@@ -156,6 +152,52 @@
<StackPanel.OpacityTransition>
<ScalarTransition />
</StackPanel.OpacityTransition>
<!-- Window Minimise -->
<Button
x:Name="MinimiseButton"
Click="MinimiseButton_Click"
Style="{StaticResource TitleBarButtonStyle}"
Visibility="{x:Bind ViewModel.MinimiseButtonVisibility, Mode=OneWay}">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="{x:Bind ViewModel.TitleBarFontSize, Mode=OneWay}"
Glyph="&#xE654;" />
</Button>
<!-- Window Maximise -->
<Button
x:Name="MaximiseButton"
Click="MaximiseButton_Click"
Style="{StaticResource TitleBarButtonStyle}"
Visibility="{x:Bind ViewModel.MaximiseButtonVisibility, Mode=OneWay}">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="{x:Bind ViewModel.TitleBarFontSize, Mode=OneWay}"
Glyph="&#xE655;" />
</Button>
<!-- Window Restore -->
<Button
x:Name="RestoreButton"
Click="RestoreButton_Click"
Style="{StaticResource TitleBarButtonStyle}"
Visibility="{x:Bind ViewModel.RestoreButtonVisibility, Mode=OneWay}">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="{x:Bind ViewModel.TitleBarFontSize, Mode=OneWay}"
Glyph="&#xE656;" />
</Button>
<!-- Window Close -->
<Button
x:Name="CloseButton"
Click="CloseButton_Click"
Style="{StaticResource TitleBarButtonStyle}"
Visibility="{x:Bind ViewModel.CloseButtonVisibility, Mode=OneWay}">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="{x:Bind ViewModel.TitleBarFontSize, Mode=OneWay}"
Glyph="&#xE653;" />
</Button>
</StackPanel>
</Grid>

View File

@@ -33,6 +33,7 @@ namespace BetterLyrics.WinUI3.Views
AppWindow.Changed += AppWindow_Changed;
ExtendsContentIntoTitleBar = true;
AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Collapsed;
UpdateTitleBarArea();
Title = App.ResourceLoader!.GetString("LyricsPageTitle");
@@ -134,6 +135,8 @@ namespace BetterLyrics.WinUI3.Views
{
_settingsService.AppSettings.StandardModeSettings.WindowBounds = new Windows.Foundation.Rect(rect.X, rect.Y, size.Width, size.Height);
_settingsService.AppSettings.StandardModeSettings.IsMaximized = overlappedPresenter.State == OverlappedPresenterState.Maximized;
ViewModel.MaximiseButtonVisibility = _settingsService.AppSettings.StandardModeSettings.IsMaximized ? Visibility.Collapsed : Visibility.Visible;
ViewModel.RestoreButtonVisibility = _settingsService.AppSettings.StandardModeSettings.IsMaximized ? Visibility.Visible : Visibility.Collapsed;
}
break;
case LyricsWindowMode.DockMode:
@@ -222,14 +225,38 @@ namespace BetterLyrics.WinUI3.Views
WindowHelper.OpenWindow<MusicGalleryWindow>();
}
private void ExitAppMenuFlyoutItem_Click(object sender, RoutedEventArgs e)
{
WindowHelper.ExitApp();
}
private void TipContainerCenter_Loaded(object sender, RoutedEventArgs e)
{
App.Current.LyricsWindowNotificationPanel = TipContainerCenter;
}
private void MinimiseButton_Click(object sender, RoutedEventArgs e)
{
if (AppWindow.Presenter is OverlappedPresenter presenter)
{
presenter.Minimize();
}
}
private void MaximiseButton_Click(object sender, RoutedEventArgs e)
{
if (AppWindow.Presenter is OverlappedPresenter presenter)
{
presenter.Maximize();
}
}
private void RestoreButton_Click(object sender, RoutedEventArgs e)
{
if (AppWindow.Presenter is OverlappedPresenter presenter)
{
presenter.Restore();
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
ViewModel.ExitOrClose();
}
}
}

View File

@@ -1,25 +1,28 @@
### Where I can find the logs?
`C:\Users\%USERNAME%\AppData\Local\Packages\37412.BetterLyrics_rd1g0rsrrtxw8\LocalCache\logs`
### ? Where I can find the logs?
`%LocalAppData%\Packages\37412.BetterLyrics_rd1g0rsrrtxw8\LocalCache\logs`
### How to install ".msixbundle" package? (for test package only)
### ? Where I can find the lyrics cache?
`%LocalAppData%\Packages\37412.BetterLyrics_rd1g0rsrrtxw8\LocalCache\lyrics`
### ? How to install ".msixbundle" package? (for test package only)
[See this doc](https://github.com/jayfunc/BetterLyrics/blob/dev/How2Install/How2Install.md)
### Lyrics are moving back and forth constantly, how to fix it?
### ? Lyrics are moving back and forth constantly, how to fix it?
![](Snipaste_2025-08-22_14-59-53.png)
Go to Settings > Playback sources > Disable "Lyrics timeline sync" or increase "Lyrics timeline sync threshold"
### Wrong lyrics are shown, how to fix it?
### ? Wrong lyrics are shown, how to fix it?
![](Snipaste_2025-08-22_14-47-21.png)
Open search panel to manually search for the correct lyrics.
### Playback control panel is not showing in dock mode, how to fix it?
### ? Playback control panel is not showing in dock mode, how to fix it?
![](Snipaste_2025-08-22_14-50-16.png)
Hover over the bottom of the lyrics window and click on the white line to show the playback control panel.
### How to lock/unlock the lyrics window in desktop mode?
### ? How to lock/unlock the lyrics window in desktop mode?
![](Snipaste_2025-08-22_14-52-53.png)
![](Snipaste_2025-08-22_14-53-21.png)
@@ -30,5 +33,5 @@ Alternatively, you can also use the shortcut `Ctrl+Alt+U` (default) to toggle lo
You can change the shortcut in Settings > App appearance and behavior > Unlock and lock shortcut keys
### How to enable/disable immersive mode?
### ? How to enable/disable immersive mode?
![](Snipaste_2025-08-22_14-58-44.png)

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) [year] [fullname]
Copyright (c) 2025 Zhe Fang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -23,7 +23,7 @@ BetterLyrics
</div>
<h4 align="center">
Your dynamic lyrics display tool built with WinUI 3 and Win2D works with local playback and other players
Your dynamic lyrics display tool, built with WinUI 3 and Win2D, works with local playback and other players
</h3>
## 🎉 This project was featured by SSPAI!
@@ -32,24 +32,22 @@ Check out the article: [BetterLyrics An immersive and smooth lyrics display
## 🔈 Feedback and chat group
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\QQ.png" height="20"> QQ](https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info) (1054700388)
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\Discord.png" height="12"> Discord](https://discord.gg/5yAQPnyCKv)
- [<img src="BetterLyrics.WinUI3\BetterLyrics.WinUI3\Assets\Telegram.png" height="16"> Telegram](https://t.me/+svhSLZ7awPsxNGY1)
[QQ 群](https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info) (1054700388) | [Discord Server](https://discord.gg/5yAQPnyCKv) | [Telegram Group](https://t.me/+svhSLZ7awPsxNGY1)
## 🌟 Highlighted features
- 🌠 **Pleasing User Interface**
- Fluent animations and effects
- ↔️ **Strong Lyrics Translation**
- Offline machine translation (supporting 30 languages)
- Auto reading local lyrics files for embedded translation
- Offline machine translation (supporting 30+ languages)
- Auto-reading local lyrics files for embedded translation
- 🧩 **Various Lyrics Source**
- Local storage
- 💾 Local storage
- Music files (with embedded lyrics)
- [.lrc](<https://en.wikipedia.org/wiki/LRC_(file_format)>) files (with both core format and enhanced format)
- [.eslrc](https://github.com/ESLyric/release) files
- [.ttml](https://en.wikipedia.org/wiki/Timed_Text_Markup_Language) files
- Online lyrics providers
- ☁️ Online lyrics providers
- QQ 音乐
- 网易云音乐
- 酷狗音乐
@@ -58,44 +56,49 @@ Check out the article: [BetterLyrics An immersive and smooth lyrics display
- <details><summary>⚠️ Apple Music (additional config needed)</summary>
- Open the Apple Music web app and the Developer Tools window. Refresh the page. Return to the Developer Tools window, select Fetch/XHR, select a request, find the Media-User-Token header in the request header, and copy its value.
- Open BetterLyrics and go to the Playback Source settings. Enter the copied value in the Media-User-Token (for Apple Music) setting and click the checkbox.
- Open BetterLyrics and go to the Playback Source settings. Enter the copied value in the Media-User-Token (for Apple Music) setting and click the accept icon on the right-hand side.
- 🎶 **Multiple Music Players Supported**
- <details><summary>⚠️ 网易云音乐</summary>
- <details><summary>网易云音乐</summary>
- Please be sure that that your Netease Cloud Music is at 3.1.4 version
- Please make sure that you have latest version (3.1.20+) of 网易云音乐 installed on your PC.
- Install the [BetterNCM plugin](https://microblock.cc/betterncm) first
- After that, install the InfLink plugin in PluginMarket. After the installation is complete, please restart NetEase Cloud Music. At this point, all preparatory operations have been completed, enjoy it!
- ⚠️ Please note that there is issues with timeline due to plugin issue
- After that, install the [InfLink-rs](https://github.com/apoint123/inflink-rs) plugin in PluginMarket. After the installation is complete, please restart 网易云音乐. At this point, all preparatory operations have been completed. Enjoy it!
</details>
- <details><summary>⚠️ 酷狗音乐</summary>
- Please make sure that the Kugou Music setting "Support system playback controls, such as lock screen interface" is turned on
- No timeline information broadcasted, which means when you change timeline position in Kugou Music, BetterLyrics has no way to detect this change
- ⚠️ Please note that there is issues with timeline due to Kugou itself
- Please make sure that the 酷狗音乐 setting "Support system playback controls, such as lock screen interface" is turned on
- No timeline information broadcast, which means when you change the timeline position in Kugou Music, BetterLyrics has no way to detect this change
- ⚠️ Please note that there are issues with the timeline due to Kugou itself
</details>
- <details><summary>⚠️ foobar2000</summary>
- Make sure you have https://github.com/dumbie/foo_mediacontrol installed with it
- ⚠️ Please note that there is issues with timeline due to plugin issue
- ⚠️ Please note that there are issues with the timeline due to a plugin issue
</details>
- Apple Music
- Spotify
- QQ 音乐
- PotPlayer
- Media Player (System)
- <details><summary>QQ 音乐</summary>
- Please keep it at the latest version
- Then open Settings in QQ 音乐, enable "Show System Media Transport Controls (SMTC)".
</details>
- <details><summary>LX Music</summary>
- Please make sure you have enabled "Open API" in LX Music settings page
- Then open BetterLyrics, go to settings, go to "Advanced options", input your LX Music server address (mostly like http://127.0.0.1:23330) and there you go!
- Then open BetterLyrics, go to settings, go to "Playback sources", input your LX Music server address (mostly like http://127.0.0.1:23330) and there you go!
</details>
@@ -119,7 +122,7 @@ Check out the article: [BetterLyrics An immersive and smooth lyrics display
- 🪟 **Multiple Display Modes**
- **Standard Mode**
- Enjoy an immersive listening journey with rich lyrics animations and beautifully dynamic backgrounds
- Enjoy an immersive listening journey with rich lyrics, animations and beautifully dynamic backgrounds
- **Dock Mode**
- A smart animated lyrics bar docked to your screen edge
- **Desktop Mode**
@@ -127,33 +130,29 @@ Check out the article: [BetterLyrics An immersive and smooth lyrics display
- 🧠 **Smart Behaviors**
- Auto hide when music paused
> This project is still under development, bugs and unexpected behaviors may be existed in the latest branch.
> This project is still under development, bugs and unexpected behaviours may exist in the latest branch.
## Screenshots
### Standard mode
![alt text](Screenshots/image.png)
![alt text](Screenshots/std.png)
![alt text](Screenshots/glow-float.gif)
### Standard mode (narrow)
![alt text](Screenshots/fan.png)
![alt text](Screenshots/std-narrow.png)
![alt text](Screenshots/lyrics-only.png)
### Standard mode (fullscreen)
![alt text](Screenshots/album-art-only.png)
![alt text](Screenshots/std-fullscreen.png)
### Dock mode
![alt text](Screenshots/dock-1.png)
![alt text](Screenshots/dock-2.png)
![alt text](Screenshots/dock.png)
### Desktop mode
![alt text](Screenshots/desktop-1.png)
![alt text](Screenshots/desktop-2.png)
![alt text](Screenshots/desktop.png)
## Demonstration
@@ -177,13 +176,13 @@ Watch our introduction video (uploaded on 18 Aug 2025) on Bilibili [here](https:
2. Type https://apps.microsoft.com/detail/9p1wcd1p597r in the link input area
3. Select Retail from the drop-down list
4. Click the check mark
5. Select the largest installation package in the resulting list to download and install. If you fail to install, try to install dependencies packages first.
5. Select the largest installation package in the resulting list to download and install. If you fail to install, try to install the dependency packages first.
### Unable to launch the app?
If you are using third-party modified Windows, you are probably can not launch the app.
If you are using a third-party modified Windows, you probably can not launch the app.
To solve this issue, please try to download from [Google Drive (v1.0.71.0)](https://drive.google.com/file/d/15FiqmSVG3_SZ9Y-_2ZS_qbFvogbNp5Y5/view?usp=sharing) (may not be the latest version) and follow the instruction [here](https://github.com/jayfunc/BetterLyrics/blob/dev/How2Install/How2Install.md).
To solve this issue, please try to download from [Google Drive (v1.0.76.0)](https://drive.google.com/file/d/1dKxp8Zf1xwAtt0JER0wHZ-94f855GdH0/view?usp=drive_link) (may not be the latest version) and follow the instructions [here](https://github.com/jayfunc/BetterLyrics/blob/dev/How2Install/How2Install.md).
## Build
@@ -192,17 +191,17 @@ Before you build, make sure that you have already replaced `BetterLyrics\BetterL
## 💖 Many thanks to
- [Lyricify-Lyrics-Helper](https://github.com/WXRIW/Lyricify-Lyrics-Helper)
- Provide lyrics fetch, decryption, and parse for QQ, Netease, Kugou sources
- Provide lyrics fetch, decryption, and parsing for QQ, Netease, and Kugou sources
- [lrclib](https://github.com/tranxuanthang/lrclib)
- LRCLIB lyrics API provider
- [Manzana-Apple-Music-Lyrics](https://github.com/dropcreations/Manzana-Apple-Music-Lyrics)
- Apple Music lyrics fetch using Python
- [Audio Tools Library (ATL) for .NET](https://github.com/Zeugma440/atldotnet)
- Used for extracting pictures in music files
- Used for extracting pictures from music files
- [WinUIEx](https://github.com/dotMorten/WinUIEx)
- Provide easy ways to access Win32 API regarding windowing
- Provide easy ways to access the Win32 API regarding windowing
- [TagLib#](https://github.com/mono/taglib-sharp)
- Used for reading original lyrics content
- Used for reading the original lyrics content
- [Vanara](https://github.com/dahall/Vanara)
- Win32 API wrapper
- [LibreTranslate](https://github.com/LibreTranslate/LibreTranslate)
@@ -233,9 +232,9 @@ Fork this project and navigate to `BetterLyrics\BetterLyrics.WinUI3\BetterLyrics
[![](https://api.star-history.com/svg?repos=jayfunc/BetterLyrics&type=Date)](https://www.star-history.com/#jayfunc/BetterLyrics&Date)
## Any issues and PRs are welcomed
## Any issues and PRs are welcome
If you find a bug please file it in issues or if you have any ideas feel free to share it here.
If you find a bug, please file it in issues, or if you have any ideas, feel free to share them here.
## Donations

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 764 KiB

BIN
Screenshots/desktop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

BIN
Screenshots/dock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 694 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

BIN
Screenshots/std-narrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 KiB

BIN
Screenshots/std.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 KiB