unified-video-framework 1.4.156 → 1.4.158

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.
Files changed (27) hide show
  1. package/package.json +1 -1
  2. package/packages/web/dist/WebPlayer.d.ts +8 -0
  3. package/packages/web/dist/WebPlayer.d.ts.map +1 -1
  4. package/packages/web/dist/WebPlayer.js +220 -55
  5. package/packages/web/dist/WebPlayer.js.map +1 -1
  6. package/packages/web/dist/chapters/ChapterManager.d.ts.map +1 -1
  7. package/packages/web/dist/chapters/ChapterManager.js +22 -0
  8. package/packages/web/dist/chapters/ChapterManager.js.map +1 -1
  9. package/packages/web/dist/chapters/types/ChapterTypes.d.ts +1 -0
  10. package/packages/web/dist/chapters/types/ChapterTypes.d.ts.map +1 -1
  11. package/packages/web/dist/chapters/types/ChapterTypes.js +2 -1
  12. package/packages/web/dist/chapters/types/ChapterTypes.js.map +1 -1
  13. package/packages/web/dist/react/WebPlayerView.d.ts +1 -0
  14. package/packages/web/dist/react/WebPlayerView.d.ts.map +1 -1
  15. package/packages/web/dist/react/WebPlayerView.js +1 -0
  16. package/packages/web/dist/react/WebPlayerView.js.map +1 -1
  17. package/packages/web/src/WebPlayer.ts +305 -72
  18. package/packages/web/src/chapters/ChapterManager.ts +32 -0
  19. package/packages/web/src/chapters/types/ChapterTypes.ts +5 -1
  20. package/packages/web/src/react/WebPlayerView.tsx +2 -0
  21. package/packages/core/dist/chapter-manager.d.ts +0 -39
  22. package/packages/ios/README.md +0 -84
  23. package/packages/web/dist/HTML5Player.js.map +0 -1
  24. package/packages/web/dist/epg/EPGController.d.ts +0 -78
  25. package/packages/web/dist/epg/EPGController.d.ts.map +0 -1
  26. package/packages/web/dist/epg/EPGController.js +0 -476
  27. package/packages/web/dist/epg/EPGController.js.map +0 -1
@@ -96,7 +96,23 @@ export class WebPlayer extends BasePlayer {
96
96
 
97
97
  // Progress bar tooltip state
98
98
  private showTimeTooltip: boolean = false;
99
-
99
+
100
+ // Autoplay enhancement state
101
+ private autoplayCapabilities: {
102
+ canAutoplay: boolean;
103
+ canAutoplayMuted: boolean;
104
+ canAutoplayUnmuted: boolean;
105
+ lastCheck: number;
106
+ } = {
107
+ canAutoplay: false,
108
+ canAutoplayMuted: false,
109
+ canAutoplayUnmuted: false,
110
+ lastCheck: 0
111
+ };
112
+ private autoplayRetryPending: boolean = false;
113
+ private autoplayRetryAttempts: number = 0;
114
+ private maxAutoplayRetries: number = 3;
115
+
100
116
  // Chapter management
101
117
  private chapterManager: ChapterManager | null = null;
102
118
  private coreChapterManager: CoreChapterManager | null = null;
@@ -197,9 +213,10 @@ export class WebPlayer extends BasePlayer {
197
213
  this.video = document.createElement('video');
198
214
  this.video.className = 'uvf-video';
199
215
  this.video.controls = false; // We'll use custom controls
200
- // For autoplay to work, video must be muted in most browsers
201
- this.video.autoplay = this.config.autoPlay ?? false;
202
- this.video.muted = this.config.autoPlay ? true : (this.config.muted ?? false);
216
+ // Don't set autoplay attribute - we'll handle it programmatically with intelligent detection
217
+ this.video.autoplay = false;
218
+ // Respect user's muted preference, intelligent autoplay will handle browser policies
219
+ this.video.muted = this.config.muted ?? false;
203
220
  this.video.loop = this.config.loop ?? false;
204
221
  this.video.playsInline = this.config.playsInline ?? true;
205
222
  this.video.preload = this.config.preload ?? 'metadata';
@@ -344,6 +361,9 @@ export class WebPlayer extends BasePlayer {
344
361
  this.state.isPlaying = true;
345
362
  this.state.isPaused = false;
346
363
  this.emit('onPlay');
364
+
365
+ // Hide play overlay when playback starts
366
+ this.hidePlayOverlay();
347
367
  });
348
368
 
349
369
  this.video.addEventListener('playing', () => {
@@ -352,6 +372,12 @@ export class WebPlayer extends BasePlayer {
352
372
  this._deferredPause = false;
353
373
  try { this.video?.pause(); } catch (_) {}
354
374
  }
375
+
376
+ // Also hide overlay on playing event (more reliable)
377
+ this.hidePlayOverlay();
378
+
379
+ // Stop buffering state
380
+ this.setBuffering(false);
355
381
  });
356
382
 
357
383
  this.video.addEventListener('pause', () => {
@@ -573,14 +599,20 @@ export class WebPlayer extends BasePlayer {
573
599
 
574
600
  // Start playback if autoPlay is enabled
575
601
  if (this.config.autoPlay) {
576
- // Attempt autoplay, but handle gracefully if blocked
577
- this.play().catch(error => {
578
- if (this.isAutoplayRestrictionError(error)) {
579
- this.debugWarn('HLS autoplay blocked, showing play overlay');
602
+ // Use intelligent autoplay with capability detection
603
+ this.attemptIntelligentAutoplay().then(success => {
604
+ if (!success) {
605
+ this.debugWarn(' Intelligent autoplay failed, showing play overlay');
580
606
  this.showPlayOverlay();
607
+ // Set up retry on user interaction
608
+ this.setupAutoplayRetry();
581
609
  } else {
582
- this.debugError('HLS autoplay failed:', error);
610
+ this.debugLog(' Intelligent autoplay succeeded');
583
611
  }
612
+ }).catch(error => {
613
+ this.debugError('HLS autoplay failed:', error);
614
+ this.showPlayOverlay();
615
+ this.setupAutoplayRetry();
584
616
  });
585
617
  }
586
618
  });
@@ -746,10 +778,10 @@ export class WebPlayer extends BasePlayer {
746
778
 
747
779
  private isAutoplayRestrictionError(err: any): boolean {
748
780
  if (!err) return false;
749
-
781
+
750
782
  const message = (err.message || '').toLowerCase();
751
783
  const name = (err.name || '').toLowerCase();
752
-
784
+
753
785
  // Common autoplay restriction error patterns
754
786
  return (
755
787
  name === 'notallowederror' ||
@@ -762,121 +794,322 @@ export class WebPlayer extends BasePlayer {
762
794
  );
763
795
  }
764
796
 
797
+ /**
798
+ * Detect browser autoplay capabilities
799
+ * Tests both muted and unmuted autoplay support
800
+ */
801
+ private async detectAutoplayCapabilities(): Promise<void> {
802
+ // Cache for 5 minutes to avoid repeated checks
803
+ const now = Date.now();
804
+ if (this.autoplayCapabilities.lastCheck && (now - this.autoplayCapabilities.lastCheck) < 300000) {
805
+ return;
806
+ }
807
+
808
+ try {
809
+ // Create a temporary video element for testing
810
+ const testVideo = document.createElement('video');
811
+ testVideo.muted = true;
812
+ testVideo.playsInline = true;
813
+ testVideo.style.position = 'absolute';
814
+ testVideo.style.opacity = '0';
815
+ testVideo.style.pointerEvents = 'none';
816
+ testVideo.style.width = '1px';
817
+ testVideo.style.height = '1px';
818
+
819
+ // Use a minimal data URL video
820
+ testVideo.src = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMQAAAAhmcmVlAAAA70D=';
821
+
822
+ document.body.appendChild(testVideo);
823
+
824
+ try {
825
+ // Test muted autoplay
826
+ await testVideo.play();
827
+ this.autoplayCapabilities.canAutoplayMuted = true;
828
+ this.autoplayCapabilities.canAutoplay = true;
829
+ this.debugLog('✅ Muted autoplay is supported');
830
+
831
+ // Test unmuted autoplay
832
+ testVideo.pause();
833
+ testVideo.currentTime = 0;
834
+ testVideo.muted = false;
835
+ testVideo.volume = 0.5;
836
+
837
+ try {
838
+ await testVideo.play();
839
+ this.autoplayCapabilities.canAutoplayUnmuted = true;
840
+ this.debugLog('✅ Unmuted autoplay is supported');
841
+ } catch (unmutedError) {
842
+ this.autoplayCapabilities.canAutoplayUnmuted = false;
843
+ this.debugLog('⚠️ Unmuted autoplay is blocked');
844
+ }
845
+
846
+ testVideo.pause();
847
+ } catch (error) {
848
+ this.autoplayCapabilities.canAutoplay = false;
849
+ this.autoplayCapabilities.canAutoplayMuted = false;
850
+ this.autoplayCapabilities.canAutoplayUnmuted = false;
851
+ this.debugLog('❌ All autoplay is blocked');
852
+ } finally {
853
+ document.body.removeChild(testVideo);
854
+ }
855
+
856
+ this.autoplayCapabilities.lastCheck = now;
857
+ } catch (error) {
858
+ this.debugError('Failed to detect autoplay capabilities:', error);
859
+ // Assume muted autoplay works as fallback
860
+ this.autoplayCapabilities.canAutoplayMuted = true;
861
+ this.autoplayCapabilities.canAutoplay = true;
862
+ }
863
+ }
864
+
865
+ /**
866
+ * Check if page has user activation (from navigation or interaction)
867
+ */
868
+ private hasUserActivation(): boolean {
869
+ // Check if browser supports userActivation API
870
+ if (typeof navigator !== 'undefined' && (navigator as any).userActivation) {
871
+ const hasActivation = (navigator as any).userActivation.hasBeenActive;
872
+ this.debugLog(`🎯 User activation detected: ${hasActivation}`);
873
+ return hasActivation;
874
+ }
875
+
876
+ // Fallback: Check if user has interacted with the page
877
+ const hasInteracted = this.lastUserInteraction > 0 &&
878
+ (Date.now() - this.lastUserInteraction) < 5000;
879
+
880
+ this.debugLog(`🎯 Recent user interaction: ${hasInteracted}`);
881
+ return hasInteracted;
882
+ }
883
+
884
+ /**
885
+ * Attempt intelligent autoplay based on detected capabilities
886
+ */
887
+ private async attemptIntelligentAutoplay(): Promise<boolean> {
888
+ if (!this.config.autoPlay || !this.video) return false;
889
+
890
+ // Detect capabilities first
891
+ await this.detectAutoplayCapabilities();
892
+
893
+ // Check if user has activated the page (navigation counts as activation)
894
+ const hasActivation = this.hasUserActivation();
895
+
896
+ // Try unmuted autoplay if:
897
+ // 1. Browser supports unmuted autoplay OR user has activated the page
898
+ // 2. User hasn't explicitly set muted=true
899
+ const shouldTryUnmuted = (this.autoplayCapabilities.canAutoplayUnmuted || hasActivation)
900
+ && this.config.muted !== true;
901
+
902
+ if (shouldTryUnmuted) {
903
+ this.video.muted = false;
904
+ this.video.volume = this.config.volume ?? 1.0;
905
+ this.debugLog(`🔊 Attempting unmuted autoplay (activation: ${hasActivation})`);
906
+
907
+ try {
908
+ await this.play();
909
+ this.debugLog('✅ Unmuted autoplay successful');
910
+ return true;
911
+ } catch (error) {
912
+ this.debugLog('⚠️ Unmuted autoplay failed, trying muted');
913
+ }
914
+ }
915
+
916
+ // Fall back to muted autoplay
917
+ if (this.autoplayCapabilities.canAutoplayMuted || hasActivation) {
918
+ this.video.muted = true;
919
+ this.debugLog('🔇 Attempting muted autoplay');
920
+
921
+ try {
922
+ await this.play();
923
+ this.debugLog('✅ Muted autoplay successful');
924
+ return true;
925
+ } catch (error) {
926
+ this.debugLog('❌ Muted autoplay failed');
927
+ }
928
+ }
929
+
930
+ return false;
931
+ }
932
+
933
+ /**
934
+ * Set up intelligent autoplay retry on user interaction
935
+ */
936
+ private setupAutoplayRetry(): void {
937
+ if (!this.config.autoPlay || this.autoplayRetryAttempts >= this.maxAutoplayRetries) {
938
+ return;
939
+ }
940
+
941
+ const interactionEvents = ['click', 'mousedown', 'keydown', 'touchstart'];
942
+
943
+ const retryAutoplay = async () => {
944
+ if (this.autoplayRetryPending || this.state.isPlaying) {
945
+ return;
946
+ }
947
+
948
+ this.autoplayRetryPending = true;
949
+ this.autoplayRetryAttempts++;
950
+ this.debugLog(`🔄 Attempting autoplay retry #${this.autoplayRetryAttempts}`);
951
+
952
+ try {
953
+ const success = await this.attemptIntelligentAutoplay();
954
+ if (success) {
955
+ this.debugLog('✅ Autoplay retry successful');
956
+ this.autoplayRetryPending = false;
957
+ // Remove event listeners after success
958
+ interactionEvents.forEach(eventType => {
959
+ document.removeEventListener(eventType, retryAutoplay);
960
+ });
961
+ } else {
962
+ this.autoplayRetryPending = false;
963
+ }
964
+ } catch (error) {
965
+ this.autoplayRetryPending = false;
966
+ this.debugError('Autoplay retry failed:', error);
967
+ }
968
+ };
969
+
970
+ interactionEvents.forEach(eventType => {
971
+ document.addEventListener(eventType, retryAutoplay, { once: true, passive: true });
972
+ });
973
+
974
+ this.debugLog('🎯 Autoplay retry armed - waiting for user interaction');
975
+ }
976
+
765
977
  private showPlayOverlay(): void {
766
978
  // Remove existing overlay
767
979
  this.hidePlayOverlay();
768
-
980
+
981
+ this.debugLog('📺 Showing play overlay due to autoplay restriction');
982
+
769
983
  const overlay = document.createElement('div');
770
984
  overlay.id = 'uvf-play-overlay';
771
985
  overlay.className = 'uvf-play-overlay';
772
-
986
+
773
987
  const playButton = document.createElement('button');
774
988
  playButton.className = 'uvf-play-button';
989
+ playButton.setAttribute('aria-label', 'Play video');
775
990
  playButton.innerHTML = `
776
991
  <svg viewBox="0 0 24 24" fill="currentColor">
777
992
  <path d="M8 5v14l11-7z"/>
778
993
  </svg>
779
994
  `;
780
-
995
+
781
996
  const message = document.createElement('div');
782
997
  message.className = 'uvf-play-message';
783
998
  message.textContent = 'Click to play';
784
-
999
+
785
1000
  overlay.appendChild(playButton);
786
1001
  overlay.appendChild(message);
787
-
788
- // Add click handler
789
- playButton.addEventListener('click', async (e) => {
1002
+
1003
+ // Enhanced click handler with better error handling
1004
+ const handlePlayClick = async (e: Event) => {
1005
+ e.preventDefault();
790
1006
  e.stopPropagation();
791
1007
  this.lastUserInteraction = Date.now();
792
-
1008
+ this.debugLog('▶️ User clicked play overlay');
1009
+
793
1010
  try {
1011
+ // Ensure video is ready
1012
+ if (!this.video) {
1013
+ this.debugError('Video element not available');
1014
+ return;
1015
+ }
1016
+
1017
+ // Try to play
794
1018
  await this.play();
1019
+ this.debugLog('✅ Play successful after user click');
795
1020
  } catch (error) {
796
- this.debugError('Failed to play after user interaction:', error);
1021
+ this.debugError('Failed to play after user interaction:', error);
1022
+ // Show error message on overlay
1023
+ message.textContent = 'Unable to play. Please try again.';
1024
+ message.style.color = '#ff6b6b';
797
1025
  }
798
- });
799
-
1026
+ };
1027
+
1028
+ // Add click handler to button
1029
+ playButton.addEventListener('click', handlePlayClick);
1030
+
800
1031
  // Also allow clicking anywhere on overlay
801
1032
  overlay.addEventListener('click', async (e) => {
802
1033
  if (e.target === overlay) {
803
- e.stopPropagation();
804
- this.lastUserInteraction = Date.now();
805
-
806
- try {
807
- await this.play();
808
- } catch (error) {
809
- this.debugError('Failed to play after user interaction:', error);
810
- }
1034
+ await handlePlayClick(e);
811
1035
  }
812
1036
  });
813
-
814
- // Add styles
1037
+
1038
+ // Add enhanced styles with better visibility
815
1039
  const style = document.createElement('style');
816
1040
  style.textContent = `
817
1041
  .uvf-play-overlay {
818
- position: absolute;
819
- top: 0;
820
- left: 0;
821
- width: 100%;
822
- height: 100%;
823
- background: rgba(0, 0, 0, 0.7);
824
- display: flex;
825
- flex-direction: column;
826
- justify-content: center;
827
- align-items: center;
828
- z-index: 1000;
829
- cursor: pointer;
1042
+ position: absolute !important;
1043
+ top: 0 !important;
1044
+ left: 0 !important;
1045
+ width: 100% !important;
1046
+ height: 100% !important;
1047
+ background: rgba(0, 0, 0, 0.85) !important;
1048
+ display: flex !important;
1049
+ flex-direction: column !important;
1050
+ justify-content: center !important;
1051
+ align-items: center !important;
1052
+ z-index: 999999 !important;
1053
+ cursor: pointer !important;
1054
+ backdrop-filter: blur(4px);
1055
+ -webkit-backdrop-filter: blur(4px);
830
1056
  }
831
-
1057
+
832
1058
  .uvf-play-button {
833
- width: 80px;
834
- height: 80px;
835
- border-radius: 50%;
836
- background: rgba(255, 255, 255, 0.9);
837
- border: none;
838
- color: #000;
839
- cursor: pointer;
840
- display: flex;
841
- align-items: center;
842
- justify-content: center;
843
- transition: all 0.3s ease;
844
- margin-bottom: 16px;
1059
+ width: 96px !important;
1060
+ height: 96px !important;
1061
+ border-radius: 50% !important;
1062
+ background: rgba(255, 255, 255, 0.95) !important;
1063
+ border: 3px solid rgba(255, 255, 255, 0.3) !important;
1064
+ color: #000 !important;
1065
+ cursor: pointer !important;
1066
+ display: flex !important;
1067
+ align-items: center !important;
1068
+ justify-content: center !important;
1069
+ transition: all 0.3s ease !important;
1070
+ margin-bottom: 20px !important;
1071
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
845
1072
  }
846
-
1073
+
847
1074
  .uvf-play-button:hover {
848
- background: #fff;
849
- transform: scale(1.1);
1075
+ background: #fff !important;
1076
+ transform: scale(1.15) !important;
1077
+ box-shadow: 0 12px 48px rgba(0, 0, 0, 0.4) !important;
850
1078
  }
851
-
1079
+
852
1080
  .uvf-play-button svg {
853
- width: 32px;
854
- height: 32px;
855
- margin-left: 4px;
1081
+ width: 40px !important;
1082
+ height: 40px !important;
1083
+ margin-left: 4px !important;
856
1084
  }
857
-
1085
+
858
1086
  .uvf-play-message {
859
- color: white;
860
- font-size: 16px;
861
- font-weight: 500;
862
- text-align: center;
863
- opacity: 0.9;
1087
+ color: white !important;
1088
+ font-size: 18px !important;
1089
+ font-weight: 600 !important;
1090
+ text-align: center !important;
1091
+ opacity: 0.95 !important;
1092
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5) !important;
864
1093
  }
865
1094
  `;
866
-
1095
+
867
1096
  // Add to page if not already added
868
1097
  if (!document.getElementById('uvf-play-overlay-styles')) {
869
1098
  style.id = 'uvf-play-overlay-styles';
870
1099
  document.head.appendChild(style);
871
1100
  }
872
-
1101
+
873
1102
  // Add to player
874
1103
  if (this.playerWrapper) {
875
1104
  this.playerWrapper.appendChild(overlay);
1105
+ this.debugLog('✅ Play overlay added to player wrapper');
1106
+ } else {
1107
+ this.debugError('❌ Cannot show play overlay - playerWrapper not found');
876
1108
  }
877
1109
  }
878
1110
 
879
1111
  private hidePlayOverlay(): void {
1112
+ this.debugLog('🔇 Hiding play overlay');
880
1113
  const overlay = document.getElementById('uvf-play-overlay');
881
1114
  if (overlay) {
882
1115
  overlay.remove();
@@ -130,6 +130,9 @@ export class ChapterManager {
130
130
  const nextSegment = this.getNextContentSegment(currentSegment);
131
131
  const targetTime = nextSegment ? nextSegment.startTime : currentSegment.endTime;
132
132
 
133
+ // Store current playback state
134
+ const wasPlaying = !this.videoElement.paused;
135
+
133
136
  // Emit skip event
134
137
  this.emit('segmentSkipped', {
135
138
  fromSegment: currentSegment,
@@ -140,6 +143,19 @@ export class ChapterManager {
140
143
 
141
144
  // Seek to target time
142
145
  this.videoElement.currentTime = targetTime;
146
+
147
+ // Resume playback if video was playing before skip (better UX)
148
+ const shouldResumePlayback = this.config.userPreferences?.resumePlaybackAfterSkip !== false;
149
+ if (shouldResumePlayback && wasPlaying && this.videoElement.paused) {
150
+ // Use a small delay to ensure seeking is complete
151
+ setTimeout(() => {
152
+ if (!this.videoElement.paused) return; // Don't play if already playing
153
+ this.videoElement.play().catch(() => {
154
+ // Handle autoplay restrictions gracefully
155
+ console.warn('[ChapterManager] Could not resume playback after skip - user interaction may be required');
156
+ });
157
+ }, 50);
158
+ }
143
159
  }
144
160
 
145
161
  /**
@@ -153,6 +169,9 @@ export class ChapterManager {
153
169
 
154
170
  const fromSegment = this.currentSegment;
155
171
 
172
+ // Store current playback state
173
+ const wasPlaying = !this.videoElement.paused;
174
+
156
175
  // Emit skip event
157
176
  if (fromSegment) {
158
177
  this.emit('segmentSkipped', {
@@ -165,6 +184,19 @@ export class ChapterManager {
165
184
 
166
185
  // Seek to segment start
167
186
  this.videoElement.currentTime = segment.startTime;
187
+
188
+ // Resume playback if video was playing before skip (better UX)
189
+ const shouldResumePlayback = this.config.userPreferences?.resumePlaybackAfterSkip !== false;
190
+ if (shouldResumePlayback && wasPlaying && this.videoElement.paused) {
191
+ // Use a small delay to ensure seeking is complete
192
+ setTimeout(() => {
193
+ if (!this.videoElement.paused) return; // Don't play if already playing
194
+ this.videoElement.play().catch(() => {
195
+ // Handle autoplay restrictions gracefully
196
+ console.warn('[ChapterManager] Could not resume playback after skip - user interaction may be required');
197
+ });
198
+ }, 50);
199
+ }
168
200
  }
169
201
 
170
202
  /**
@@ -119,6 +119,9 @@ export interface ChapterPreferences {
119
119
 
120
120
  /** Remember user choices */
121
121
  rememberChoices?: boolean;
122
+
123
+ /** Resume playback after skip (default: true for better UX) */
124
+ resumePlaybackAfterSkip?: boolean;
122
125
  }
123
126
 
124
127
  /**
@@ -209,7 +212,8 @@ export const DEFAULT_CHAPTER_CONFIG: ChapterConfig = {
209
212
  autoSkipCredits: false,
210
213
  showSkipButtons: true,
211
214
  skipButtonTimeout: 5000,
212
- rememberChoices: true
215
+ rememberChoices: true,
216
+ resumePlaybackAfterSkip: true
213
217
  }
214
218
  };
215
219
 
@@ -211,6 +211,7 @@ export type WebPlayerViewProps = {
211
211
  showSkipButtons?: boolean; // Show skip buttons (default: true)
212
212
  skipButtonTimeout?: number; // Button timeout in milliseconds (default: 5000)
213
213
  rememberChoices?: boolean; // Remember user preferences (default: true)
214
+ resumePlaybackAfterSkip?: boolean; // Resume playback after skipping (default: true)
214
215
  };
215
216
  };
216
217
 
@@ -569,6 +570,7 @@ export const WebPlayerView: React.FC<WebPlayerViewProps> = (props) => {
569
570
  showSkipButtons: props.chapters.userPreferences?.showSkipButtons ?? true,
570
571
  skipButtonTimeout: props.chapters.userPreferences?.skipButtonTimeout ?? 5000,
571
572
  rememberChoices: props.chapters.userPreferences?.rememberChoices ?? true,
573
+ resumePlaybackAfterSkip: props.chapters.userPreferences?.resumePlaybackAfterSkip ?? true,
572
574
  }
573
575
  } : { enabled: false }
574
576
  };
@@ -1,39 +0,0 @@
1
- import { Chapter, ChapterSegment, ChapterConfig, EventHandler } from './interfaces';
2
- export interface ChapterManagerEvents {
3
- chapterchange: Chapter | null;
4
- segmententered: ChapterSegment;
5
- segmentexited: ChapterSegment;
6
- segmentskipped: ChapterSegment;
7
- }
8
- export declare class ChapterManager {
9
- private config;
10
- private chapters;
11
- private segments;
12
- private currentChapter;
13
- private activeSegments;
14
- private lastProcessedTime;
15
- private eventHandlers;
16
- constructor(config?: ChapterConfig);
17
- updateConfig(config: ChapterConfig): void;
18
- loadChapterData(url: string): Promise<void>;
19
- initialize(): Promise<void>;
20
- processTimeUpdate(currentTime: number): void;
21
- private processChapterChange;
22
- private processSegments;
23
- getCurrentChapter(currentTime: number): Chapter | null;
24
- getChapters(): Chapter[];
25
- getSegments(): ChapterSegment[];
26
- getSegmentsAtTime(currentTime: number): ChapterSegment[];
27
- skipSegment(segment: ChapterSegment): void;
28
- seekToChapter(chapterId: string): Chapter | null;
29
- getNextChapter(currentTime: number): Chapter | null;
30
- getPreviousChapter(currentTime: number): Chapter | null;
31
- on<K extends keyof ChapterManagerEvents>(event: K, handler: EventHandler): void;
32
- off<K extends keyof ChapterManagerEvents>(event: K, handler?: EventHandler): void;
33
- private emit;
34
- reset(): void;
35
- destroy(): void;
36
- getCurrentChapterInfo(): Chapter | null;
37
- isEnabled(): boolean;
38
- }
39
- //# sourceMappingURL=chapter-manager.d.ts.map