This commit is contained in:
Zhe Fang
2025-07-23 13:54:30 -04:00
parent da377838e8
commit de3d6f1695
9 changed files with 78 additions and 39 deletions

View File

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

View File

@@ -10,10 +10,12 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Windows.ApplicationModel.Resources;
using Serilog;
using ShadowViewer.Controls;
using System;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;

View File

@@ -4,8 +4,9 @@ using System;
namespace BetterLyrics.WinUI3.Events
{
public class PositionChangedEventArgs(TimeSpan position) : EventArgs()
public class TimelineChangedEventArgs(TimeSpan position, TimeSpan end) : EventArgs()
{
public TimeSpan Position { get; set; } = position;
public TimeSpan End { get; set; } = end;
}
}

View File

@@ -109,7 +109,12 @@ namespace BetterLyrics.WinUI3.Helper
// 按时间分组
var grouped = lrcLines.GroupBy(l => l.time).OrderBy(g => g.Key).ToList();
int languageCount = grouped.Max(g => g.Count());
int languageCount = 0;
if (grouped != null && grouped.Count > 0)
{
// 计算最大语言数量
languageCount = grouped.Max(g => g.Count());
}
// 初始化每种语言的歌词列表
_lyricsDataArr.Clear();

View File

@@ -10,7 +10,7 @@ namespace BetterLyrics.WinUI3.Services
public interface IPlaybackService
{
event EventHandler<IsPlayingChangedEventArgs>? IsPlayingChanged;
event EventHandler<PositionChangedEventArgs>? PositionChanged;
event EventHandler<TimelineChangedEventArgs>? TimelineChanged;
event EventHandler<SongInfoChangedEventArgs>? SongInfoChanged;
event EventHandler<AlbumArtChangedEventArgs>? AlbumArtChangedChanged;
event EventHandler<MediaSourceProvidersInfoEventArgs>? MediaSourceProvidersInfoChanged;

View File

@@ -37,13 +37,14 @@ namespace BetterLyrics.WinUI3.Services
private readonly ILogger<PlaybackService> _logger;
private readonly string _lxMusicId = "cn.toside.music.desktop";
private double _lxMusicPositionSeconds = 0;
private double _lxMusicDurationSeconds = 0;
private bool _cachedIsPlaying = false;
private EventSourceReader? _sse = null;
private readonly MediaManager _mediaManager = new();
private MediaManager.MediaSession? _focusedSession = null;
private readonly LatestOnlyTaskRunner _albumArtRefreshRunner = new();
private readonly LatestOnlyTaskRunner _onAnyMediaPropertyChangedRunner = new();
@@ -53,7 +54,7 @@ namespace BetterLyrics.WinUI3.Services
private byte[]? _SMTCAlbumArtBytes = null;
public event EventHandler<IsPlayingChangedEventArgs>? IsPlayingChanged;
public event EventHandler<PositionChangedEventArgs>? PositionChanged;
public event EventHandler<TimelineChangedEventArgs>? TimelineChanged;
public event EventHandler<SongInfoChangedEventArgs>? SongInfoChanged;
public event EventHandler<AlbumArtChangedEventArgs>? AlbumArtChangedChanged;
public event EventHandler<MediaSourceProvidersInfoEventArgs>? MediaSourceProvidersInfoChanged;
@@ -95,34 +96,33 @@ namespace BetterLyrics.WinUI3.Services
{
if (!_mediaManager.IsStarted) return;
_focusedSession = mediaSession ?? _mediaManager.GetFocusedSession();
if (_focusedSession == null || !IsMediaSourceEnabled(_focusedSession.Id))
{
SendNullMessages();
}
else
{
SendFocusedMessagesAsync().ConfigureAwait(false);
}
SendFocusedMessagesAsync().ConfigureAwait(false);
}
private void MediaManager_OnAnyTimelinePropertyChanged(MediaManager.MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionTimelineProperties timelineProperties)
{
if (!_mediaManager.IsStarted) return;
if (!IsMediaSourceEnabled(mediaSession.Id) || mediaSession != _focusedSession) return;
if (mediaSession == null) return;
var focusedSession = _mediaManager.GetFocusedSession();
if (!IsMediaSourceEnabled(mediaSession.Id) || mediaSession != focusedSession) return;
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
{
PositionChanged?.Invoke(this, new PositionChangedEventArgs(timelineProperties.Position));
TimelineChanged?.Invoke(this, new TimelineChangedEventArgs(timelineProperties.Position, timelineProperties.EndTime));
});
}
private void MediaManager_OnAnyPlaybackStateChanged(MediaManager.MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo)
{
if (!_mediaManager.IsStarted) return;
if (mediaSession == null) return;
var focusedSession = _mediaManager.GetFocusedSession();
RecordMediaSourceProviderInfo(mediaSession);
if (!IsMediaSourceEnabled(mediaSession.Id) || mediaSession != _focusedSession) return;
if (!IsMediaSourceEnabled(mediaSession.Id) || mediaSession != focusedSession) return;
_cachedIsPlaying = playbackInfo.PlaybackStatus switch
{
@@ -139,10 +139,14 @@ namespace BetterLyrics.WinUI3.Services
private void MediaManager_OnAnyMediaPropertyChanged(MediaManager.MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties)
{
if (!_mediaManager.IsStarted) return;
if (mediaSession == null) return;
string id = mediaSession.Id;
var focusedSession = _mediaManager.GetFocusedSession();
RecordMediaSourceProviderInfo(mediaSession);
if (!IsMediaSourceEnabled(id) || mediaSession != _focusedSession) return;
if (!IsMediaSourceEnabled(id) || mediaSession != focusedSession) return;
_cachedSongInfo = new SongInfo
{
@@ -196,6 +200,8 @@ namespace BetterLyrics.WinUI3.Services
private void MediaManager_OnAnySessionClosed(MediaManager.MediaSession mediaSession)
{
if (!_mediaManager.IsStarted) return;
if (mediaSession == null) return;
if (_mediaManager.CurrentMediaSessions.Count == 0)
{
SendNullMessages();
@@ -205,14 +211,17 @@ namespace BetterLyrics.WinUI3.Services
private void MediaManager_OnAnySessionOpened(MediaManager.MediaSession mediaSession)
{
if (!_mediaManager.IsStarted) return;
if (mediaSession == null) return;
RecordMediaSourceProviderInfo(mediaSession);
_focusedSession = _mediaManager.GetFocusedSession();
SendFocusedMessagesAsync().ConfigureAwait(false);
}
private void RecordMediaSourceProviderInfo(MediaManager.MediaSession mediaSession)
{
if (!_mediaManager.IsStarted) return;
if (mediaSession == null) return;
var id = mediaSession?.Id;
if (string.IsNullOrEmpty(id)) return;
@@ -236,18 +245,19 @@ namespace BetterLyrics.WinUI3.Services
_cachedIsPlaying = false;
SongInfoChanged?.Invoke(this, new SongInfoChangedEventArgs(_cachedSongInfo));
IsPlayingChanged?.Invoke(this, new IsPlayingChangedEventArgs(_cachedIsPlaying));
PositionChanged?.Invoke(this, new PositionChangedEventArgs(TimeSpan.Zero));
TimelineChanged?.Invoke(this, new TimelineChangedEventArgs(TimeSpan.Zero, TimeSpan.Zero));
});
}
private async Task SendFocusedMessagesAsync()
{
if (_focusedSession == null) return;
var focusedSession = _mediaManager.GetFocusedSession();
if (focusedSession == null || focusedSession.ControlSession == null) return;
var mediaProps = await _focusedSession.ControlSession.TryGetMediaPropertiesAsync();
MediaManager_OnAnyMediaPropertyChanged(_focusedSession, mediaProps);
MediaManager_OnAnyPlaybackStateChanged(_focusedSession, _focusedSession.ControlSession.GetPlaybackInfo());
MediaManager_OnAnyTimelinePropertyChanged(_focusedSession, _focusedSession.ControlSession.GetTimelineProperties());
var mediaProps = await focusedSession.ControlSession.TryGetMediaPropertiesAsync();
MediaManager_OnAnyMediaPropertyChanged(focusedSession, mediaProps);
MediaManager_OnAnyPlaybackStateChanged(focusedSession, focusedSession.ControlSession.GetPlaybackInfo());
MediaManager_OnAnyTimelinePropertyChanged(focusedSession, focusedSession.ControlSession.GetTimelineProperties());
}
private async Task UpdateAlbumArtRelated(CancellationToken token)
@@ -296,7 +306,7 @@ namespace BetterLyrics.WinUI3.Services
{
try
{
_sse = new EventSourceReader(new Uri($"{_settingsService.LXMusicServer}/subscribe-player-status?filter=progress")).Start();
_sse = new EventSourceReader(new Uri($"{_settingsService.LXMusicServer}/subscribe-player-status?filter=progress,duration")).Start();
_sse.MessageReceived += Sse_MessageReceived;
_sse.Disconnected += Sse_Disconnected;
}
@@ -334,39 +344,54 @@ namespace BetterLyrics.WinUI3.Services
private void Sse_MessageReceived(object sender, EventSourceMessageEventArgs e)
{
var data = JsonSerializer.Deserialize(e.Message, Serialization.SourceGenerationContext.Default.JsonElement);
if (data.TryGetDouble(out double positionSeconds))
if (data.TryGetDouble(out double seconds))
{
if (_cachedSongInfo?.SourceAppUserModelId == _lxMusicId)
{
PositionChanged?.Invoke(this, new PositionChangedEventArgs(TimeSpan.FromSeconds(positionSeconds)));
if (e.Event == "progress")
{
_lxMusicPositionSeconds = seconds;
}
else if (e.Event == "duration")
{
_lxMusicDurationSeconds = seconds;
}
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
{
TimelineChanged?.Invoke(this, new TimelineChangedEventArgs(TimeSpan.FromSeconds(_lxMusicPositionSeconds), TimeSpan.FromSeconds(_lxMusicDurationSeconds)));
});
}
}
}
public async Task PlayAsync()
{
await _focusedSession?.ControlSession.TryPlayAsync();
var focusedSession = _mediaManager.GetFocusedSession();
await focusedSession?.ControlSession.TryPlayAsync();
}
public async Task PauseAsync()
{
await _focusedSession?.ControlSession.TryPauseAsync();
var focusedSession = _mediaManager.GetFocusedSession();
await focusedSession?.ControlSession.TryPauseAsync();
}
public async Task PreviousAsync()
{
await _focusedSession?.ControlSession.TrySkipPreviousAsync();
var focusedSession = _mediaManager.GetFocusedSession();
await focusedSession?.ControlSession.TrySkipPreviousAsync();
}
public async Task NextAsync()
{
await _focusedSession?.ControlSession.TrySkipNextAsync();
var focusedSession = _mediaManager.GetFocusedSession();
await focusedSession?.ControlSession.TrySkipNextAsync();
}
public async Task ChangePosition(double seconds)
{
await _focusedSession?.ControlSession.TryChangePlaybackPositionAsync(TimeSpan.FromSeconds(seconds).Ticks);
var focusedSession = _mediaManager.GetFocusedSession();
await focusedSession?.ControlSession.TryChangePlaybackPositionAsync(TimeSpan.FromSeconds(seconds).Ticks);
}
public void Receive(PropertyChangedMessage<ObservableCollection<MediaSourceProviderInfo>> message)
@@ -377,7 +402,7 @@ namespace BetterLyrics.WinUI3.Services
{
_mediaSourceProvidersInfo = [.. message.NewValue];
_settingsService.MediaSourceProvidersInfo = _mediaSourceProvidersInfo;
MediaManager_OnFocusedSessionChanged(_mediaManager.GetFocusedSession());
MediaManager_OnFocusedSessionChanged(null);
}
}
}

View File

@@ -48,10 +48,16 @@ namespace BetterLyrics.WinUI3.ViewModels
_playbackService = playbackService;
_playbackService.SongInfoChanged += PlaybackService_SongInfoChanged;
_playbackService.IsPlayingChanged += PlaybackService_IsPlayingChanged;
_playbackService.TimelineChanged += PlaybackService_TimelineChanged;
IsSongPlaying = _playbackService.IsPlaying;
}
private void PlaybackService_TimelineChanged(object? sender, Events.TimelineChangedEventArgs e)
{
SongDurationSeconds = (int)e.End.TotalSeconds;
}
//private void SystemVolumeHelper_VolumeChanged(int volume)
//{
// Volume = volume;

View File

@@ -65,7 +65,7 @@ namespace BetterLyrics.WinUI3.ViewModels
_playbackService.IsPlayingChanged += PlaybackService_IsPlayingChanged;
_playbackService.SongInfoChanged += PlaybackService_SongInfoChanged;
_playbackService.AlbumArtChangedChanged += PlaybackService_AlbumArtChangedChanged;
_playbackService.PositionChanged += PlaybackService_PositionChanged;
_playbackService.TimelineChanged += PlaybackService_TimelineChanged;
_isPlaying = _playbackService.IsPlaying;

View File

@@ -335,7 +335,7 @@ namespace BetterLyrics.WinUI3.ViewModels
_isPlaying = e.IsPlaying;
}
private void PlaybackService_PositionChanged(object? sender, PositionChangedEventArgs e)
private void PlaybackService_TimelineChanged(object? sender, TimelineChangedEventArgs e)
{
if (Math.Abs(TotalTime.TotalMilliseconds - e.Position.TotalMilliseconds) >= _timelineSyncThreshold)
{