Fixes for tests
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
let controlsTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
let seekOffset = $state(0); // Track offset when seeking in transcoded streams
|
||||
let isSeeking = $state(false);
|
||||
let currentStreamUrl = $derived(streamUrl);
|
||||
let currentStreamUrl = $state(streamUrl);
|
||||
let hasReportedStart = $state(false);
|
||||
let progressInterval: ReturnType<typeof setInterval> | null = null;
|
||||
let isMediaReady = $state(false); // Track if media is ready to play (implements Loading state from DR-001)
|
||||
@@ -67,6 +67,7 @@
|
||||
let didStopBackendEarly = $state(false); // Track if we stopped backend early for non-transcoded content
|
||||
let swipeType = $state<"brightness" | null>(null);
|
||||
let hls: Hls | null = null; // HLS.js instance for streaming HLS content
|
||||
let hlsFatalRecoveryAttempts = 0; // Track recovery attempts to prevent infinite restarts
|
||||
|
||||
// Audio track selection
|
||||
let showAudioTrackMenu = $state(false);
|
||||
@@ -260,14 +261,36 @@
|
||||
console.log('[VideoPlayer] HLS manifest parsed, ready to play');
|
||||
});
|
||||
|
||||
// Reset recovery attempts for new HLS instance
|
||||
hlsFatalRecoveryAttempts = 0;
|
||||
|
||||
// Handle errors
|
||||
hls.on(Hls.Events.ERROR, (event, data) => {
|
||||
console.error('[VideoPlayer] HLS error:', data);
|
||||
if (data.fatal) {
|
||||
// Check if we're near the end of the video - if so, this is likely
|
||||
// end-of-stream rather than a real error. Jellyfin transcoded HLS
|
||||
// streams may not always terminate cleanly with #EXT-X-ENDLIST.
|
||||
const knownDuration = media?.runTimeTicks ? media.runTimeTicks / 10_000_000 : videoDuration;
|
||||
const effectiveTime = currentTime + seekOffset;
|
||||
const isNearEnd = knownDuration > 0 && effectiveTime > 0 && effectiveTime / knownDuration > 0.9;
|
||||
|
||||
switch (data.type) {
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
console.error('[VideoPlayer] Fatal network error, trying to recover');
|
||||
hls!.startLoad();
|
||||
hlsFatalRecoveryAttempts++;
|
||||
if (isNearEnd) {
|
||||
// Near end of stream - treat as natural end, don't restart
|
||||
console.log('[VideoPlayer] Fatal network error near end of stream - treating as ended');
|
||||
if (onEnded) {
|
||||
onEnded();
|
||||
}
|
||||
} else if (hlsFatalRecoveryAttempts <= 3) {
|
||||
console.error('[VideoPlayer] Fatal network error, trying to recover (attempt', hlsFatalRecoveryAttempts, ')');
|
||||
hls!.startLoad();
|
||||
} else {
|
||||
console.error('[VideoPlayer] Fatal network error, max recovery attempts reached');
|
||||
hls!.destroy();
|
||||
}
|
||||
break;
|
||||
case Hls.ErrorTypes.MEDIA_ERROR:
|
||||
console.error('[VideoPlayer] Fatal media error, trying to recover');
|
||||
@@ -528,17 +551,17 @@
|
||||
// Smooth time updates using requestAnimationFrame (60fps)
|
||||
function updateTimeLoop() {
|
||||
if (videoElement && !isSeeking && !isDraggingSeekBar && isPlaying) {
|
||||
// Add seek offset to get actual position in the full video
|
||||
const newCurrentTime = seekOffset + videoElement.currentTime;
|
||||
|
||||
// Safety check: only update if the video element is actually playing
|
||||
// This prevents stale data from overwriting currentTime after failed seeks
|
||||
if (videoElement.readyState >= 2) { // HAVE_CURRENT_DATA or better
|
||||
if (videoElement.readyState >= 2) {
|
||||
currentTime = newCurrentTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue the loop while playing
|
||||
// Keep the loop alive while playing — stopped by handlePause/handleEnded
|
||||
if (isPlaying) {
|
||||
rafId = requestAnimationFrame(updateTimeLoop);
|
||||
} else {
|
||||
rafId = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user