diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/PlayerID.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/PlayerID.cs index 07e4a13..37a8afb 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/PlayerID.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/PlayerID.cs @@ -1,6 +1,6 @@ namespace BetterLyrics.WinUI3.Constants { - public static class PlayerID + public static class PlayerId { public const string LXMusic = "cn.toside.music.desktop"; public const string LXMusicPortable = "lx-music-desktop.exe"; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsCanvas.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsCanvas.xaml.cs index 0422ec3..e612199 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsCanvas.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsCanvas.xaml.cs @@ -42,7 +42,6 @@ namespace BetterLyrics.WinUI3.Controls { private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService(); private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService(); - private readonly ILastFMService _lastFMService = Ioc.Default.GetRequiredService(); private readonly LyricsRenderer _lyricsRenderer = new(); private readonly FluidBackgroundRenderer _fluidRenderer = new(); @@ -660,22 +659,6 @@ namespace BetterLyrics.WinUI3.Controls _songPosition += elapsedTime; _totalPlayedTime += elapsedTime; _songPositionWithOffset = _songPosition + TimeSpan.FromMilliseconds(_mediaSessionsService.CurrentMediaSourceProviderInfo?.PositionOffset ?? 0); - CheckAndScrobbleLastFM(); - } - } - - private void CheckAndScrobbleLastFM() - { - bool isEnabled = _mediaSessionsService.CurrentMediaSourceProviderInfo?.IsLastFMTrackEnabled ?? false; - if (!isEnabled || _isLastFMTracked) return; - - var songInfo = _mediaSessionsService.CurrentSongInfo; - if (songInfo == null || songInfo.Duration <= 0) return; - - if (_totalPlayedTime.TotalSeconds >= songInfo.Duration * 0.5) - { - _isLastFMTracked = true; - _lastFMService.TrackAsync(songInfo); } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/StatsDashboardControl.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/StatsDashboardControl.xaml index b0097d7..cfb42b2 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/StatsDashboardControl.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/StatsDashboardControl.xaml @@ -54,6 +54,7 @@ + - + Orientation="Horizontal" + Spacing="4"> + + + + + + @@ -127,7 +142,7 @@ - + @@ -145,8 +160,14 @@ + FontWeight="SemiBold"> + + + @@ -154,6 +175,7 @@ + - + @@ -184,9 +206,17 @@ - + Text="{x:Bind PlayerName}" /> + + + Path.Combine(LocalFolder, "play-queue.m3u"); public static string PlayHistoryPath => Path.Combine(LocalFolder, "play-history.db"); - public static string FilesCachePath => Path.Combine(CacheFolder, "files-cache.db"); + public static string FilesIndexPath => Path.Combine(LocalFolder, "files-index.db"); public static void EnsureDirectories() { diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/PlayerIDHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/PlayerIDHelper.cs index 6614c12..73cb0f2 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/PlayerIDHelper.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/PlayerIDHelper.cs @@ -4,7 +4,7 @@ using System.Text.RegularExpressions; namespace BetterLyrics.WinUI3.Helper { - public static class PlayerIDHelper + public static class PlayerIdHelper { private static readonly List neteaseFamilyRegex = [ @@ -25,64 +25,64 @@ namespace BetterLyrics.WinUI3.Helper return false; } - public static bool IsLXMusic(string? id) => id is PlayerID.LXMusic or PlayerID.LXMusicPortable; + public static bool IsLXMusic(string? id) => id is PlayerId.LXMusic or PlayerId.LXMusicPortable; - public static bool IsAppleMusic(string? id) => id is PlayerID.AppleMusic or PlayerID.AppleMusicAlternative; + public static bool IsAppleMusic(string? id) => id is PlayerId.AppleMusic or PlayerId.AppleMusicAlternative; - public static bool IsBetterLyrics(string? id) => id is PlayerID.BetterLyrics or PlayerID.BetterLyricsDebug; + public static bool IsBetterLyrics(string? id) => id is PlayerId.BetterLyrics or PlayerId.BetterLyricsDebug; public static string? GetDisplayName(string? id) => id switch { - PlayerID.Spotify => PlayerName.Spotify, - PlayerID.AppleMusic => PlayerName.AppleMusic, - PlayerID.iTunes => PlayerName.iTunes, - PlayerID.KugouMusic => PlayerName.KugouMusic, - PlayerID.NetEaseCloudMusic => PlayerName.NetEaseCloudMusic, - PlayerID.QQMusic => PlayerName.QQMusic, - PlayerID.LXMusic => PlayerName.LXMusic, - PlayerID.LXMusicPortable => PlayerName.LXMusicPortable, - PlayerID.MediaPlayerWindows11 => PlayerName.MediaPlayerWindows11, - PlayerID.AIMP => PlayerName.AIMP, - PlayerID.Foobar2000 => PlayerName.Foobar2000, - PlayerID.MusicBee => PlayerName.MusicBee, - PlayerID.PotPlayer => PlayerName.PotPlayer, - PlayerID.Chrome => PlayerName.Chrome, - PlayerID.Edge => PlayerName.Edge, - PlayerID.BetterLyrics => PlayerName.BetterLyrics, - PlayerID.BetterLyricsDebug => PlayerName.BetterLyricsDebug, - PlayerID.SaltPlayerForWindowsMS => PlayerName.SaltPlayerForWindowsMS, - PlayerID.SaltPlayerForWindowsSteam => PlayerName.SaltPlayerForWindowsSteam, - PlayerID.MoeKoeMusic => PlayerName.MoeKoeMusic, - PlayerID.MoeKoeMusicAlternative => PlayerName.MoeKoeMusic, - PlayerID.Listen1 => PlayerName.Listen1, + PlayerId.Spotify => PlayerName.Spotify, + PlayerId.AppleMusic => PlayerName.AppleMusic, + PlayerId.iTunes => PlayerName.iTunes, + PlayerId.KugouMusic => PlayerName.KugouMusic, + PlayerId.NetEaseCloudMusic => PlayerName.NetEaseCloudMusic, + PlayerId.QQMusic => PlayerName.QQMusic, + PlayerId.LXMusic => PlayerName.LXMusic, + PlayerId.LXMusicPortable => PlayerName.LXMusicPortable, + PlayerId.MediaPlayerWindows11 => PlayerName.MediaPlayerWindows11, + PlayerId.AIMP => PlayerName.AIMP, + PlayerId.Foobar2000 => PlayerName.Foobar2000, + PlayerId.MusicBee => PlayerName.MusicBee, + PlayerId.PotPlayer => PlayerName.PotPlayer, + PlayerId.Chrome => PlayerName.Chrome, + PlayerId.Edge => PlayerName.Edge, + PlayerId.BetterLyrics => PlayerName.BetterLyrics, + PlayerId.BetterLyricsDebug => PlayerName.BetterLyricsDebug, + PlayerId.SaltPlayerForWindowsMS => PlayerName.SaltPlayerForWindowsMS, + PlayerId.SaltPlayerForWindowsSteam => PlayerName.SaltPlayerForWindowsSteam, + PlayerId.MoeKoeMusic => PlayerName.MoeKoeMusic, + PlayerId.MoeKoeMusicAlternative => PlayerName.MoeKoeMusic, + PlayerId.Listen1 => PlayerName.Listen1, _ => id, }; public static string GetLogoPath(string? id) => id switch { - PlayerID.Spotify => PathHelper.SpotifyLogoPath, - PlayerID.AppleMusic => PathHelper.AppleMusicLogoPath, - PlayerID.AppleMusicAlternative => PathHelper.AppleMusicLogoPath, - PlayerID.iTunes => PathHelper.iTunesLogoPath, - PlayerID.KugouMusic => PathHelper.KugouMusicLogoPath, - PlayerID.NetEaseCloudMusic => PathHelper.NetEaseCloudMusicLogoPath, - PlayerID.QQMusic => PathHelper.QQMusicLogoPath, - PlayerID.LXMusic => PathHelper.LXMusicLogoPath, - PlayerID.LXMusicPortable => PathHelper.LXMusicLogoPath, - PlayerID.MediaPlayerWindows11 => PathHelper.MediaPlayerWindows11LogoPath, - PlayerID.AIMP => PathHelper.AIMPLogoPath, - PlayerID.Foobar2000 => PathHelper.Foobar2000LogoPath, - PlayerID.MusicBee => PathHelper.MusicBeeLogoPath, - PlayerID.PotPlayer => PathHelper.PotPlayerLogoPath, - PlayerID.Chrome => PathHelper.ChromeLogoPath, - PlayerID.Edge => PathHelper.EdgeLogoPath, - PlayerID.BetterLyrics => PathHelper.LogoPath, - PlayerID.BetterLyricsDebug => PathHelper.LogoPath, - PlayerID.SaltPlayerForWindowsMS => PathHelper.SaltPlayerForWindowsLogoPath, - PlayerID.SaltPlayerForWindowsSteam => PathHelper.SaltPlayerForWindowsLogoPath, - PlayerID.MoeKoeMusic => PathHelper.MoeKoeMusicLogoPath, - PlayerID.MoeKoeMusicAlternative => PathHelper.MoeKoeMusicLogoPath, - PlayerID.Listen1 => PathHelper.Listen1LogoPath, + PlayerId.Spotify => PathHelper.SpotifyLogoPath, + PlayerId.AppleMusic => PathHelper.AppleMusicLogoPath, + PlayerId.AppleMusicAlternative => PathHelper.AppleMusicLogoPath, + PlayerId.iTunes => PathHelper.iTunesLogoPath, + PlayerId.KugouMusic => PathHelper.KugouMusicLogoPath, + PlayerId.NetEaseCloudMusic => PathHelper.NetEaseCloudMusicLogoPath, + PlayerId.QQMusic => PathHelper.QQMusicLogoPath, + PlayerId.LXMusic => PathHelper.LXMusicLogoPath, + PlayerId.LXMusicPortable => PathHelper.LXMusicLogoPath, + PlayerId.MediaPlayerWindows11 => PathHelper.MediaPlayerWindows11LogoPath, + PlayerId.AIMP => PathHelper.AIMPLogoPath, + PlayerId.Foobar2000 => PathHelper.Foobar2000LogoPath, + PlayerId.MusicBee => PathHelper.MusicBeeLogoPath, + PlayerId.PotPlayer => PathHelper.PotPlayerLogoPath, + PlayerId.Chrome => PathHelper.ChromeLogoPath, + PlayerId.Edge => PathHelper.EdgeLogoPath, + PlayerId.BetterLyrics => PathHelper.LogoPath, + PlayerId.BetterLyricsDebug => PathHelper.LogoPath, + PlayerId.SaltPlayerForWindowsMS => PathHelper.SaltPlayerForWindowsLogoPath, + PlayerId.SaltPlayerForWindowsSteam => PathHelper.SaltPlayerForWindowsLogoPath, + PlayerId.MoeKoeMusic => PathHelper.MoeKoeMusicLogoPath, + PlayerId.MoeKoeMusicAlternative => PathHelper.MoeKoeMusicLogoPath, + PlayerId.Listen1 => PathHelper.Listen1LogoPath, _ => PathHelper.UnknownPlayerLogoPath, }; } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MediaSourceProviderInfo.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MediaSourceProviderInfo.cs index 098c712..3ca80a2 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MediaSourceProviderInfo.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MediaSourceProviderInfo.cs @@ -35,11 +35,11 @@ namespace BetterLyrics.WinUI3.Models [ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsSearchType LyricsSearchType { get; set; } = LyricsSearchType.Sequential; [ObservableProperty][NotifyPropertyChangedRecipients] public partial int MatchingThreshold { get; set; } = 40; - [JsonIgnore] public string LogoPath => PlayerIDHelper.GetLogoPath(Provider); + [JsonIgnore] public string LogoPath => PlayerIdHelper.GetLogoPath(Provider); - [JsonIgnore] public string? DisplayName => PlayerIDHelper.GetDisplayName(Provider); + [JsonIgnore] public string? DisplayName => PlayerIdHelper.GetDisplayName(Provider); - [JsonIgnore] public bool IsLXMusic => PlayerIDHelper.IsLXMusic(Provider); + [JsonIgnore] public bool IsLXMusic => PlayerIdHelper.IsLXMusic(Provider); public MediaSourceProviderInfo() { @@ -53,7 +53,7 @@ namespace BetterLyrics.WinUI3.Models IsEnabled = isEnable; switch (provider) { - case Constants.PlayerID.AppleMusic: + case Constants.PlayerId.AppleMusic: // Apple Music 的特性 TimelineSyncThreshold = 1000; PositionOffset = 1000; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/PlayHistoryItem.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/PlayHistoryItem.cs index a78fd03..9d643fa 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/PlayHistoryItem.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/PlayHistoryItem.cs @@ -20,6 +20,6 @@ namespace BetterLyrics.WinUI3.Models public double TotalDurationMs { get; set; } [Indexed] - public string PlayerID { get; set; } + public string PlayerId { get; set; } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/PlayerStatDisplayItem.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/PlayerStatDisplayItem.cs index 4bff4b4..ecd5e3b 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/PlayerStatDisplayItem.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/PlayerStatDisplayItem.cs @@ -1,4 +1,5 @@ -using System; +using BetterLyrics.WinUI3.Helper; +using System; using System.Collections.Generic; using System.Text; @@ -9,7 +10,7 @@ namespace BetterLyrics.WinUI3.Models public string PlayerId { get; set; } public int PlayCount { get; set; } - // 这就是 XAML 中 Rectangle Width 绑定的属性 public double DisplayWidth { get; set; } + public string PlayerName => PlayerIdHelper.GetDisplayName(PlayerId); } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Stats/PlayerStats.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Stats/PlayerStats.cs index 5c4a1a0..a2eeb07 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Stats/PlayerStats.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Stats/PlayerStats.cs @@ -6,7 +6,7 @@ namespace BetterLyrics.WinUI3.Models.Stats { public class PlayerStats { - public string PlayerID { get; set; } + public string PlayerId { get; set; } public int Count { get; set; } public double DisplayWidth => (TotalCount > 0) ? (Count / (double)TotalCount) * 150 : 0; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Stats/SongPlayCount.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Stats/SongPlayCount.cs index d0b05d5..30e3966 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Stats/SongPlayCount.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Stats/SongPlayCount.cs @@ -8,7 +8,6 @@ namespace BetterLyrics.WinUI3.Models.Stats { public string Title { get; set; } public string Artist { get; set; } - public string AlbumArtHash { get; set; } public int PlayCount { get; set; } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/FileSystemService/FileSystemService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/FileSystemService/FileSystemService.cs index 63c33a6..ec91899 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/FileSystemService/FileSystemService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/FileSystemService/FileSystemService.cs @@ -44,7 +44,7 @@ namespace BetterLyrics.WinUI3.Services.FileSystemService _logger = logger; _localizationService = localizationService; _settingsService = settingsService; - _db = new SQLiteAsyncConnection(PathHelper.FilesCachePath); + _db = new SQLiteAsyncConnection(PathHelper.FilesIndexPath); } public async Task InitializeAsync() diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService/LyricsSearchService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService/LyricsSearchService.cs index f2db294..5c03b27 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService/LyricsSearchService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService/LyricsSearchService.cs @@ -558,11 +558,11 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService ISearchResult? result; - if (songInfo.SongId != null && searcher == Searchers.Netease && PlayerIDHelper.IsNeteaseFamily(songInfo.PlayerId)) + if (songInfo.SongId != null && searcher == Searchers.Netease && PlayerIdHelper.IsNeteaseFamily(songInfo.PlayerId)) { result = new NeteaseSearchResult(songInfo.Title, songInfo.Artists, songInfo.Album, [], (int)songInfo.DurationMs, songInfo.SongId); } - else if (songInfo.SongId != null && searcher == Searchers.QQMusic && songInfo.PlayerId == Constants.PlayerID.QQMusic) + else if (songInfo.SongId != null && searcher == Searchers.QQMusic && songInfo.PlayerId == Constants.PlayerId.QQMusic) { result = new QQMusicSearchResult(songInfo.Title, songInfo.Artists, songInfo.Album, [], (int)songInfo.DurationMs, songInfo.SongId, ""); } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs index 2a8dd41..e51f1b0 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs @@ -11,6 +11,7 @@ using BetterLyrics.WinUI3.Models; using BetterLyrics.WinUI3.Models.Settings; using BetterLyrics.WinUI3.Services.AlbumArtSearchService; using BetterLyrics.WinUI3.Services.DiscordService; +using BetterLyrics.WinUI3.Services.LastFMService; using BetterLyrics.WinUI3.Services.LyricsSearchService; using BetterLyrics.WinUI3.Services.PlayHistoryService; using BetterLyrics.WinUI3.Services.SettingsService; @@ -56,6 +57,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService private readonly ISettingsService _settingsService; private readonly IDiscordService _discordService; private readonly IPlayHistoryService _playHistoryService; + private readonly ILastFMService _lastFMService; private readonly ILogger _logger; private double _lxMusicPositionSeconds = 0; @@ -79,6 +81,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService ITranslationService libreTranslateService, ITransliterationService transliterationService, IPlayHistoryService playHistoryService, + ILastFMService lastFMService, ILogger logger) { _settingsService = settingsService; @@ -88,6 +91,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService _transliterationService = transliterationService; _discordService = discordService; _playHistoryService = playHistoryService; + _lastFMService = lastFMService; _logger = logger; _onMediaPropsChangedTimer = _dispatcherQueue.CreateTimer(); @@ -150,7 +154,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService var found = _settingsService.AppSettings.MediaSourceProvidersInfo.FirstOrDefault(s => s.Provider == id); if (_settingsService.AppSettings.MusicGallerySettings.LyricsWindowStatus.IsOpened) { - if (PlayerIDHelper.IsBetterLyrics(found?.Provider)) + if (PlayerIdHelper.IsBetterLyrics(found?.Provider)) { return found?.IsEnabled ?? true; } @@ -275,7 +279,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService { CurrentSongInfo = SongInfoExtensions.Placeholder; - if (PlayerIDHelper.IsLXMusic(sessionId)) + if (PlayerIdHelper.IsLXMusic(sessionId)) { StopSSE(); } @@ -294,20 +298,20 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService string? fixedAlbum = mediaProperties?.AlbumTitle; string? songId = null; - if (PlayerIDHelper.IsAppleMusic(sessionId)) + if (PlayerIdHelper.IsAppleMusic(sessionId)) { fixedArtist = mediaProperties?.Artist.Split(" — ").FirstOrDefault(); fixedAlbum = mediaProperties?.Artist.Split(" — ").LastOrDefault(); fixedAlbum = fixedAlbum?.Replace(" - Single", ""); fixedAlbum = fixedAlbum?.Replace(" - EP", ""); } - else if (PlayerIDHelper.IsNeteaseFamily(sessionId)) + else if (PlayerIdHelper.IsNeteaseFamily(sessionId)) { songId = mediaProperties?.Genres .FirstOrDefault(x => x.StartsWith(ExtendedGenreFiled.NetEaseCloudMusicTrackID))? .Replace(ExtendedGenreFiled.NetEaseCloudMusicTrackID, ""); } - else if (sessionId == PlayerID.QQMusic) + else if (sessionId == PlayerId.QQMusic) { songId = mediaProperties?.Genres .FirstOrDefault(x => x.StartsWith(ExtendedGenreFiled.QQMusicTrackID))? @@ -318,8 +322,8 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService .FirstOrDefault(x => x.StartsWith(ExtendedGenreFiled.FileName))? .Replace(ExtendedGenreFiled.FileName, ""); - // 统计 - if (CurrentSongInfo != null && CurrentSongInfo != SongInfoExtensions.Placeholder) + // 写入播放记录 + if (CurrentSongInfo != null && CurrentSongInfo.Title != "N/A") { // 必须捕获一个副本给异步任务,因为 CurrentSongInfo 马上就要变了 var lastSong = CurrentSongInfo; @@ -328,6 +332,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService if (lastSong.DurationMs > 0 && _scrobbleStopwatch.Elapsed.TotalMilliseconds >= (lastSong.DurationMs / 2)) { + // 写入本地播放记录 var playHistoryItem = CurrentSongInfo.ToPlayHistoryItem(_scrobbleStopwatch.Elapsed.TotalMilliseconds); if (playHistoryItem != null) { @@ -335,6 +340,13 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService _ = Task.Run(() => _playHistoryService.AddLogAsync(playHistoryItem)); _logger.LogInformation($"[Scrobble] 结算成功: {lastSong.Title}"); } + // 写入 Last.fm 播放记录 + var isLastFMEnabled = CurrentMediaSourceProviderInfo?.IsLastFMTrackEnabled ?? false; + if (isLastFMEnabled) + { + // 后台 + _ = Task.Run(() => _lastFMService.TrackAsync(lastSong)); + } } } _scrobbleStopwatch.Restart(); @@ -350,7 +362,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService LinkedFileName = linkedFileName }; - if (PlayerIDHelper.IsLXMusic(sessionId)) + if (PlayerIdHelper.IsLXMusic(sessionId)) { StartSSE(); } @@ -359,7 +371,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService StopSSE(); } - if (PlayerIDHelper.IsLXMusic(sessionId) && _lxMusicAlbumArtBytes != null) + if (PlayerIdHelper.IsLXMusic(sessionId) && _lxMusicAlbumArtBytes != null) { _SMTCAlbumArtBuffer = _lxMusicAlbumArtBytes.AsBuffer(); } @@ -550,7 +562,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService { _dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () => { - if (PlayerIDHelper.IsLXMusic(CurrentSongInfo?.PlayerId)) + if (PlayerIdHelper.IsLXMusic(CurrentSongInfo?.PlayerId)) { var data = JsonSerializer.Deserialize(e.Message, Serialization.SourceGenerationContext.Default.JsonElement); if (data.ValueKind == JsonValueKind.Number) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlayHistoryService/PlayHistoryService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlayHistoryService/PlayHistoryService.cs index b950d71..beebef5 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlayHistoryService/PlayHistoryService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlayHistoryService/PlayHistoryService.cs @@ -71,17 +71,15 @@ namespace BetterLyrics.WinUI3.Services.PlayHistoryService { await InitializeAsync(); - // 使用 SQL 查询比在内存里 GroupBy 更快且省内存 // SQLite 语法: Group By Title 和 Artist string query = @" - SELECT Title, Artist, AlbumArtHash, COUNT(*) as PlayCount + SELECT Title, Artist, COUNT(*) as PlayCount FROM PlayHistory WHERE StartedAt >= ? AND StartedAt <= ? GROUP BY Title, Artist ORDER BY PlayCount DESC LIMIT ?"; - // 注意:SQLite存的是Ticks或者ISO8601,sqlite-net-pcl会自动处理DateTime参数 return await _db.QueryAsync(query, start, end, limit); } @@ -126,10 +124,10 @@ namespace BetterLyrics.WinUI3.Services.PlayHistoryService await InitializeAsync(); string query = @" - SELECT PlayerID, COUNT(*) as Count + SELECT PlayerId, COUNT(*) as Count FROM PlayHistory WHERE StartedAt >= ? AND StartedAt <= ? - GROUP BY PlayerID + GROUP BY PlayerId ORDER BY Count DESC"; return await _db.QueryAsync(query, start, end); @@ -265,7 +263,7 @@ namespace BetterLyrics.WinUI3.Services.PlayHistoryService Title = song.Title, Artist = song.Artist, Album = song.Album, - PlayerID = playerId, + PlayerId = playerId, StartedAt = startedAt, TotalDurationMs = totalDurationMs, DurationPlayedMs = playedDurationMs diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/StatsDashboardControlViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/StatsDashboardControlViewModel.cs index 6946377..2949ecf 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/StatsDashboardControlViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/StatsDashboardControlViewModel.cs @@ -1,4 +1,5 @@ using BetterLyrics.WinUI3.Enums; +using BetterLyrics.WinUI3.Helper; using BetterLyrics.WinUI3.Models; using BetterLyrics.WinUI3.Models.Stats; using BetterLyrics.WinUI3.Services.PlayHistoryService; @@ -44,37 +45,30 @@ namespace BetterLyrics.WinUI3.ViewModels try { - // 1. 计算时间范围 var (start, end) = CalculateDateRange(range); - // 2. 并行获取所有数据 (性能优化:不等待一个查完再查下一个,而是同时查) var durationTask = _playHistoryService.GetTotalListeningDurationAsync(start, end); - var logsTask = _playHistoryService.GetLogsByDateRangeAsync(start, end); // 用来算总数 + var logsTask = _playHistoryService.GetLogsByDateRangeAsync(start, end); var topSongsTask = _playHistoryService.GetTopSongsAsync(start, end, 10); - var topArtistsTask = _playHistoryService.GetTopArtistsAsync(start, end, 5); // 只要前5名 + var topArtistsTask = _playHistoryService.GetTopArtistsAsync(start, end, 10); var playersTask = _playHistoryService.GetPlayerDistributionAsync(start, end); await Task.WhenAll(durationTask, logsTask, topSongsTask, topArtistsTask, playersTask); - // 3. 更新 UI 数据 TotalDuration = await durationTask; var logs = await logsTask; TotalTracksPlayed = logs.Count; - // 更新歌曲列表 TopSongs.Clear(); foreach (var item in await topSongsTask) TopSongs.Add(item); - // 更新歌手列表 TopArtists.Clear(); foreach (var item in await topArtistsTask) TopArtists.Add(item); - // 更新播放器分布 (需要特殊处理进度条宽度) UpdatePlayerStats(await playersTask); } catch (Exception ex) { - // 这里可以记录日志 _logger.LogError(ex, ...) System.Diagnostics.Debug.WriteLine($"Error loading stats: {ex.Message}"); } finally @@ -98,7 +92,7 @@ namespace BetterLyrics.WinUI3.ViewModels if (stats == null || stats.Count == 0) { - TopPlayerName = "None"; + TopPlayerName = "N/A"; return; } @@ -106,7 +100,7 @@ namespace BetterLyrics.WinUI3.ViewModels if (maxCount == 0) maxCount = 1; var topPlayer = stats.OrderByDescending(x => x.Count).FirstOrDefault(); - TopPlayerName = topPlayer?.PlayerID ?? "None"; + TopPlayerName = PlayerIdHelper.GetDisplayName(topPlayer?.PlayerId) ?? "N/A"; foreach (var item in stats.OrderByDescending(x => x.Count)) { @@ -117,7 +111,7 @@ namespace BetterLyrics.WinUI3.ViewModels PlayerStats.Add(new PlayerStatDisplayItem { - PlayerId = item.PlayerID, + PlayerId = item.PlayerId, PlayCount = item.Count, DisplayWidth = calculatedWidth }); @@ -126,32 +120,35 @@ namespace BetterLyrics.WinUI3.ViewModels private (DateTime Start, DateTime End) CalculateDateRange(StatsRange range) { - DateTime now = DateTime.Now; - DateTime start = now; + DateTime nowLocal = DateTime.Now; + DateTime startLocal = nowLocal.Date; // 默认为本地今天 00:00 switch (range) { case StatsRange.Day: - start = now.Date; // 今天 00:00 break; case StatsRange.Week: - // 假设周一为一周开始 - int diff = (7 + (now.DayOfWeek - DayOfWeek.Monday)) % 7; - start = now.Date.AddDays(-1 * diff); + int dayOfWeek = (int)nowLocal.DayOfWeek; + if (dayOfWeek == 0) dayOfWeek = 7; // 处理周日 + startLocal = nowLocal.Date.AddDays(-(dayOfWeek - 1)); break; case StatsRange.Month: - start = new DateTime(now.Year, now.Month, 1); + startLocal = new DateTime(nowLocal.Year, nowLocal.Month, 1); break; case StatsRange.Quarter: - int quarter = (now.Month - 1) / 3 + 1; - start = new DateTime(now.Year, (quarter - 1) * 3 + 1, 1); + int quarterStartMonth = (nowLocal.Month - 1) / 3 * 3 + 1; + startLocal = new DateTime(nowLocal.Year, quarterStartMonth, 1); break; case StatsRange.Year: - start = new DateTime(now.Year, 1, 1); + startLocal = new DateTime(nowLocal.Year, 1, 1); break; } - return (start, now); + // 数据库里的 StartedAt 是 UTC,所以查询条件必须也是 UTC + DateTime startUtc = startLocal.ToUniversalTime(); + DateTime endUtc = nowLocal.ToUniversalTime(); + + return (startUtc, endUtc); } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MusicGalleryWindow.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MusicGalleryWindow.xaml.cs index 5297c6f..8789483 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MusicGalleryWindow.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MusicGalleryWindow.xaml.cs @@ -102,7 +102,6 @@ namespace BetterLyrics.WinUI3.Views private void NowPlayingBar_SongInfoTapped(object sender, System.EventArgs e) { - NowPlayingBar.IsPlayingQueueOpened = false; NowPlayingBar.ShowSongInfo = false; NowPlayingBar.ShowTime = true; NowPlayingBar.IsAutoHideEnabled = true;