diff --git a/Jellyfin.Plugin.JellyLMS/Services/LmsSessionController.cs b/Jellyfin.Plugin.JellyLMS/Services/LmsSessionController.cs index 4a1d3ec..7fdb8b0 100644 --- a/Jellyfin.Plugin.JellyLMS/Services/LmsSessionController.cs +++ b/Jellyfin.Plugin.JellyLMS/Services/LmsSessionController.cs @@ -26,6 +26,8 @@ public class LmsSessionController : ISessionController, IDisposable private Timer? _progressTimer; private bool _disposed; private BaseItem? _currentItem; + private Guid[] _playlist = []; + private int _playlistIndex; /// /// Initializes a new instance of the class. @@ -137,41 +139,55 @@ public class LmsSessionController : ISessionController, IDisposable await _lmsClient.PowerOnAsync(_player.MacAddress).ConfigureAwait(false); } - // For now, play the first item - // TODO: Support playlists/queues if (playRequest.ItemIds.Length > 0) { - var itemId = playRequest.ItemIds[0]; - var streamUrl = BuildStreamUrl(itemId); + // Store the full playlist + _playlist = playRequest.ItemIds; + _playlistIndex = playRequest.StartIndex ?? 0; - _logger.LogInformation("Playing stream URL: {Url}", streamUrl); - await _lmsClient.PlayUrlAsync(_player.MacAddress, streamUrl).ConfigureAwait(false); - - // Track current playback state - CurrentItemId = itemId; - IsPlaying = true; - IsPaused = false; - - // Look up the item for duration info - _currentItem = _libraryManager.GetItemById(itemId); - - // Seek to start position if specified - var startPositionTicks = 0L; - if (playRequest.StartPositionTicks.HasValue && playRequest.StartPositionTicks.Value > 0) - { - startPositionTicks = playRequest.StartPositionTicks.Value; - var positionSeconds = startPositionTicks / TimeSpan.TicksPerSecond; - await _lmsClient.SeekAsync(_player.MacAddress, positionSeconds).ConfigureAwait(false); - } - - // Report playback start to Jellyfin - await ReportPlaybackStartAsync(itemId, startPositionTicks).ConfigureAwait(false); - - // Start progress reporting timer (every 2 seconds) - StartProgressTimer(); + // Play the item at the start index + await PlayItemAtIndexAsync(_playlistIndex, playRequest.StartPositionTicks ?? 0).ConfigureAwait(false); } } + private async Task PlayItemAtIndexAsync(int index, long startPositionTicks = 0) + { + if (index < 0 || index >= _playlist.Length) + { + _logger.LogWarning("Invalid playlist index {Index}, playlist has {Count} items", index, _playlist.Length); + return; + } + + var itemId = _playlist[index]; + _playlistIndex = index; + + var streamUrl = BuildStreamUrl(itemId); + _logger.LogInformation("Playing item {Index}/{Total}: {Url}", index + 1, _playlist.Length, streamUrl); + + await _lmsClient.PlayUrlAsync(_player.MacAddress, streamUrl).ConfigureAwait(false); + + // Track current playback state + CurrentItemId = itemId; + IsPlaying = true; + IsPaused = false; + + // Look up the item for duration info + _currentItem = _libraryManager.GetItemById(itemId); + + // Seek to start position if specified + if (startPositionTicks > 0) + { + var positionSeconds = startPositionTicks / TimeSpan.TicksPerSecond; + await _lmsClient.SeekAsync(_player.MacAddress, positionSeconds).ConfigureAwait(false); + } + + // Report playback start to Jellyfin + await ReportPlaybackStartAsync(itemId, startPositionTicks).ConfigureAwait(false); + + // Start progress reporting timer (every 2 seconds) + StartProgressTimer(); + } + private async Task ReportPlaybackStartAsync(Guid itemId, long positionTicks) { try @@ -363,9 +379,33 @@ public class LmsSessionController : ISessionController, IDisposable break; case PlaystateCommand.NextTrack: + if (_playlistIndex < _playlist.Length - 1) + { + _logger.LogInformation("Skipping to next track (index {Index})", _playlistIndex + 1); + await PlayItemAtIndexAsync(_playlistIndex + 1).ConfigureAwait(false); + } + else + { + _logger.LogInformation("Already at last track, stopping playback"); + await _lmsClient.StopAsync(_player.MacAddress).ConfigureAwait(false); + await ReportPlaybackStoppedAsync().ConfigureAwait(false); + } + + break; + case PlaystateCommand.PreviousTrack: - // TODO: Implement playlist navigation - _logger.LogDebug("Track navigation not yet implemented"); + if (_playlistIndex > 0) + { + _logger.LogInformation("Skipping to previous track (index {Index})", _playlistIndex - 1); + await PlayItemAtIndexAsync(_playlistIndex - 1).ConfigureAwait(false); + } + else + { + // At first track, restart from beginning + _logger.LogInformation("At first track, restarting from beginning"); + await _lmsClient.SeekAsync(_player.MacAddress, 0).ConfigureAwait(false); + } + break; default: