Refresh track list when advancing to next queued video

Player settings on tvOS showed the previous video's tracks after queue
advance because availableStreams was never cleared on a video change and
playQueuedVideo only seeded a single pre-resolved stream. Reset the list
on a new video, then fetch the full streams in the background for global
videos, and repoint state.currentStream/currentAudioStream to the
refreshed entries so the picker checkmarks land on the playing tracks.
This commit is contained in:
Arkadiusz Fal
2026-05-10 11:27:13 +02:00
parent 6a343311ea
commit 82d2830208

View File

@@ -207,15 +207,25 @@ final class PlayerService {
// Set up audio session when playback actually starts (not at app launch) // Set up audio session when playback actually starts (not at app launch)
setupAudioSession() setupAudioSession()
let isNewVideo = state.currentVideo?.id != video.id
// Save progress and sync for previous video before switching // Save progress and sync for previous video before switching
// Skip if video ended naturally - 100% was already saved in backendDidFinishPlaying // Skip if video ended naturally - 100% was already saved in backendDidFinishPlaying
if state.currentVideo != nil && state.currentVideo?.id != video.id && !videoEndedNaturally { if state.currentVideo != nil && isNewVideo && !videoEndedNaturally {
saveProgressAndSync() saveProgressAndSync()
} }
// Reset flag for the new video // Reset flag for the new video
videoEndedNaturally = false videoEndedNaturally = false
// Clear the previous video's track list when transitioning to a new
// video so the player settings sheet doesn't show stale tracks.
// Skipped for same-video calls (e.g. in-video quality switch) so the
// full stream list kept around for the picker survives the switch.
if isNewVideo {
availableStreams = []
}
// Clear sponsor block state from previous video // Clear sponsor block state from previous video
state.sponsorSegments = [] state.sponsorSegments = []
state.currentSegment = nil state.currentSegment = nil
@@ -808,6 +818,14 @@ final class PlayerService {
loadCaption(match) loadCaption(match)
} }
} }
// Fetch the full stream/caption list in the background so the
// quality / audio / subtitle picker isn't limited to the single
// pre-resolved stream that the queue item carried.
if case .global = queuedVideo.video.id.source {
Task { [weak self] in
await self?.loadOnlineStreams()
}
}
} }
} }
@@ -1269,8 +1287,28 @@ final class PlayerService {
do { do {
let (_, streams, captions) = try await fetchVideoStreamsAndCaptions(for: video) let (_, streams, captions) = try await fetchVideoStreamsAndCaptions(for: video)
// Combine downloaded streams with online streams (downloaded first) // Combine downloaded streams with online streams (downloaded first)
availableStreams = downloadedStreams + streams let combined = downloadedStreams + streams
availableStreams = combined
availableCaptions = captions availableCaptions = captions
// The freshly fetched streams have new (signed) URLs that won't
// match `state.currentStream`/`state.currentAudioStream` from the
// queue's pre-resolved entry repoint state to the equivalent
// refreshed stream (matched by Stream.id which is
// resolution+fps+format) so the picker shows checkmarks on the
// currently playing tracks.
if let playing = state.currentStream,
!playing.url.isFileURL,
let refreshed = combined.first(where: { $0.id == playing.id })
{
state.updateCurrentStream(refreshed)
}
if let playingAudio = state.currentAudioStream,
!playingAudio.url.isFileURL,
let refreshedAudio = combined.first(where: { $0.id == playingAudio.id })
{
state.updateCurrentAudioStream(refreshedAudio)
}
LoggingService.shared.logPlayer("Loaded \(streams.count) online streams and \(captions.count) captions (keeping \(downloadedStreams.count) downloaded)") LoggingService.shared.logPlayer("Loaded \(streams.count) online streams and \(captions.count) captions (keeping \(downloadedStreams.count) downloaded)")
} catch { } catch {
LoggingService.shared.logPlayerError("Failed to load online streams", error: error) LoggingService.shared.logPlayerError("Failed to load online streams", error: error)