unified-video-framework 1.4.238 → 1.4.240

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -149,6 +149,7 @@ export class WebPlayer extends BasePlayer {
149
149
  private fallbackErrors: Array<{ url: string; error: any }> = [];
150
150
  private isLoadingFallback: boolean = false;
151
151
  private currentRetryAttempt: number = 0;
152
+ private lastFailedUrl: string = ''; // Track last failed URL to avoid duplicate error handling
152
153
 
153
154
  // Debug logging helper
154
155
  private debugLog(message: string, ...args: any[]): void {
@@ -458,9 +459,17 @@ export class WebPlayer extends BasePlayer {
458
459
 
459
460
  this.video.addEventListener('canplay', () => {
460
461
  this.debugLog('📡 canplay event fired');
462
+
463
+ // Reset fallback tracking on successful load
464
+ if (this.isLoadingFallback) {
465
+ this.debugLog('✅ Fallback source loaded successfully!');
466
+ this.isLoadingFallback = false;
467
+ this.lastFailedUrl = '';
468
+ }
469
+
461
470
  this.setBuffering(false);
462
471
  this.emit('onReady');
463
-
472
+
464
473
  // Update time display when video is ready to play
465
474
  this.updateTimeDisplay();
466
475
 
@@ -514,28 +523,51 @@ export class WebPlayer extends BasePlayer {
514
523
  });
515
524
 
516
525
  this.video.addEventListener('error', async (e) => {
517
- if (!this.video) return;
526
+ if (!this.video || !this.video.src) return;
527
+
518
528
  const error = this.video.error;
519
529
  if (error) {
530
+ const currentSrc = this.video.src || this.video.currentSrc || '';
531
+
532
+ // Avoid processing the same error multiple times
533
+ if (this.lastFailedUrl === currentSrc && this.isLoadingFallback) {
534
+ this.debugLog(`⚠️ Duplicate error for same URL while loading fallback, ignoring: ${currentSrc}`);
535
+ return;
536
+ }
537
+
538
+ this.lastFailedUrl = currentSrc;
520
539
  this.debugLog(`Video error detected (code: ${error.code}):`, error.message);
540
+ this.debugLog(`Failed source: ${currentSrc}`);
541
+ this.debugLog(`Fallback check - isLoadingFallback: ${this.isLoadingFallback}`);
542
+ this.debugLog(`Fallback check - fallbackSources:`, this.source?.fallbackSources);
543
+ this.debugLog(`Fallback check - fallbackPoster:`, this.source?.fallbackPoster);
544
+ this.debugLog(`Fallback check - has fallbackSources: ${!!this.source?.fallbackSources?.length}`);
545
+ this.debugLog(`Fallback check - has fallbackPoster: ${!!this.source?.fallbackPoster}`);
521
546
 
522
547
  // Try fallback sources if available and not already loading one
523
548
  if (!this.isLoadingFallback && (this.source?.fallbackSources?.length || this.source?.fallbackPoster)) {
549
+ this.debugLog('✅ Attempting to load fallback sources...');
524
550
  const fallbackLoaded = await this.tryFallbackSource(error);
525
551
  if (fallbackLoaded) {
552
+ this.debugLog('✅ Fallback loaded successfully!');
526
553
  // Successfully loaded fallback, don't call handleError
527
554
  return;
528
555
  }
556
+ this.debugLog('❌ All fallbacks failed');
557
+ } else {
558
+ this.debugLog('❌ No fallback sources available or already loading');
529
559
  }
530
560
 
531
561
  // No fallback available or all fallbacks failed - handle error normally
532
- this.handleError({
533
- code: `MEDIA_ERR_${error.code}`,
534
- message: error.message || this.getMediaErrorMessage(error.code),
535
- type: 'media',
536
- fatal: true,
537
- details: error
538
- });
562
+ if (!this.isLoadingFallback) {
563
+ this.handleError({
564
+ code: `MEDIA_ERR_${error.code}`,
565
+ message: error.message || this.getMediaErrorMessage(error.code),
566
+ type: 'media',
567
+ fatal: true,
568
+ details: error
569
+ });
570
+ }
539
571
  }
540
572
  });
541
573
 
@@ -578,6 +610,10 @@ export class WebPlayer extends BasePlayer {
578
610
  this.source = source as any;
579
611
  this.subtitles = (source.subtitles || []) as any;
580
612
 
613
+ this.debugLog('Loading video source:', source.url);
614
+ this.debugLog('Fallback sources provided:', source.fallbackSources);
615
+ this.debugLog('Fallback poster provided:', source.fallbackPoster);
616
+
581
617
  // Reset autoplay flag for new source
582
618
  this.autoplayAttempted = false;
583
619
 
@@ -586,6 +622,7 @@ export class WebPlayer extends BasePlayer {
586
622
  this.fallbackErrors = [];
587
623
  this.isLoadingFallback = false;
588
624
  this.currentRetryAttempt = 0;
625
+ this.lastFailedUrl = '';
589
626
 
590
627
  // Clean up previous instances
591
628
  await this.cleanup();
@@ -652,11 +689,24 @@ export class WebPlayer extends BasePlayer {
652
689
  * Try loading the next fallback source
653
690
  */
654
691
  private async tryFallbackSource(error: any): Promise<boolean> {
655
- if (this.isLoadingFallback) return false;
692
+ this.debugLog('🔄 tryFallbackSource called');
693
+ this.debugLog('🔄 isLoadingFallback:', this.isLoadingFallback);
694
+ this.debugLog('🔄 fallbackSources:', this.source?.fallbackSources);
695
+ this.debugLog('🔄 fallbackSources length:', this.source?.fallbackSources?.length);
696
+ this.debugLog('🔄 Current fallbackSourceIndex:', this.fallbackSourceIndex);
697
+ this.debugLog('🔄 Current retry attempt:', this.currentRetryAttempt);
698
+
699
+ if (this.isLoadingFallback) {
700
+ this.debugLog('⚠️ Already loading a fallback, skipping');
701
+ return false;
702
+ }
703
+
656
704
  if (!this.source?.fallbackSources || this.source.fallbackSources.length === 0) {
705
+ this.debugLog('⚠️ No fallback sources available, trying fallback poster');
657
706
  return this.showFallbackPoster();
658
707
  }
659
708
 
709
+ this.debugLog('✅ Starting fallback loading process');
660
710
  this.isLoadingFallback = true;
661
711
 
662
712
  // Record current error
@@ -667,11 +717,15 @@ export class WebPlayer extends BasePlayer {
667
717
  this.fallbackErrors.push({ url: currentUrl, error });
668
718
  this.debugLog(`Source failed: ${currentUrl}`, error);
669
719
 
670
- // Check retry attempts for current source
720
+ // Don't retry the main URL - go straight to first fallback
721
+ // Only retry actual fallback sources
722
+ const isMainUrl = this.fallbackSourceIndex === -1;
671
723
  const maxRetries = this.source.fallbackRetryAttempts || 1;
672
- if (this.currentRetryAttempt < maxRetries) {
724
+
725
+ if (!isMainUrl && this.currentRetryAttempt < maxRetries) {
726
+ // Only retry if this is a fallback source (not the main URL)
673
727
  this.currentRetryAttempt++;
674
- this.debugLog(`Retrying source (attempt ${this.currentRetryAttempt}/${maxRetries}): ${currentUrl}`);
728
+ this.debugLog(`Retrying fallback source (attempt ${this.currentRetryAttempt}/${maxRetries}): ${currentUrl}`);
675
729
 
676
730
  const retryDelay = this.source.fallbackRetryDelay || 1000;
677
731
  await new Promise(resolve => setTimeout(resolve, retryDelay));
@@ -679,14 +733,20 @@ export class WebPlayer extends BasePlayer {
679
733
  try {
680
734
  const sourceType = this.detectSourceType({ url: currentUrl, type: this.source.type });
681
735
  await this.loadVideoSource(currentUrl, sourceType, this.source);
682
- this.isLoadingFallback = false;
683
- this.currentRetryAttempt = 0;
684
- this.debugLog(`Retry successful for: ${currentUrl}`);
685
- return true;
736
+ // Don't mark as successful immediately - let it load and see if error happens
737
+ // Just continue and see what happens
738
+ this.debugLog(`Retry initiated for: ${currentUrl} - waiting for load confirmation...`);
739
+ // Return false to continue the fallback chain if this fails again
686
740
  } catch (retryError) {
687
741
  this.debugLog(`Retry failed for: ${currentUrl}`, retryError);
688
742
  // Continue to next fallback
689
743
  }
744
+ } else {
745
+ if (isMainUrl) {
746
+ this.debugLog(`⏭️ Skipping retry of main URL, moving to first fallback source`);
747
+ } else {
748
+ this.debugLog(`⏭️ Max retries (${maxRetries}) reached for ${currentUrl}, moving to next fallback`);
749
+ }
690
750
  }
691
751
 
692
752
  // Move to next fallback source