@codenkay/video-nsgplayer-core 1.0.0 → 2.0.0
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.
- package/CHANGELOG.md +14 -0
- package/dist/index.cjs +201 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -1
- package/dist/index.d.ts +51 -1
- package/dist/index.js +201 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -5,6 +5,22 @@ type PlayerState = "idle" | "loading" | "ready" | "playing" | "paused" | "buffer
|
|
|
5
5
|
type HlsSupportMode = "hls.js" | "native" | "unsupported";
|
|
6
6
|
type QualitySelection = "auto" | number;
|
|
7
7
|
type PlaybackRate = 0.5 | 0.75 | 1 | 1.25 | 1.5 | 2;
|
|
8
|
+
type PlayerTextTrack = {
|
|
9
|
+
index: number;
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
language?: string;
|
|
13
|
+
uri?: string;
|
|
14
|
+
};
|
|
15
|
+
type PlayerAudioTrack = {
|
|
16
|
+
index: number;
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
language?: string;
|
|
20
|
+
uri?: string;
|
|
21
|
+
};
|
|
22
|
+
/** Runtime caption selection: off or a concrete subtitle track index. */
|
|
23
|
+
type TextTrackSelection = "off" | number;
|
|
8
24
|
type HlsQualityLevel = {
|
|
9
25
|
index: number;
|
|
10
26
|
height: number;
|
|
@@ -222,6 +238,14 @@ type PlayerEventMap = {
|
|
|
222
238
|
selection: QualitySelection;
|
|
223
239
|
label?: string;
|
|
224
240
|
};
|
|
241
|
+
texttrackchange: {
|
|
242
|
+
tracks: PlayerTextTrack[];
|
|
243
|
+
selection: TextTrackSelection;
|
|
244
|
+
};
|
|
245
|
+
audiotrackchange: {
|
|
246
|
+
tracks: PlayerAudioTrack[];
|
|
247
|
+
selection: number;
|
|
248
|
+
};
|
|
225
249
|
volumechange: {
|
|
226
250
|
volume: number;
|
|
227
251
|
muted: boolean;
|
|
@@ -390,6 +414,10 @@ type HlsEngineCallbacks = {
|
|
|
390
414
|
onAuthRecoveryNeeded?: (reason: string) => void;
|
|
391
415
|
onQualitiesChange?: (levels: HlsQualityLevel[]) => void;
|
|
392
416
|
onQualitySelectionChange?: (selection: QualitySelection) => void;
|
|
417
|
+
onTextTracksChange?: (tracks: PlayerTextTrack[]) => void;
|
|
418
|
+
onTextTrackSelectionChange?: (selection: TextTrackSelection) => void;
|
|
419
|
+
onAudioTracksChange?: (tracks: PlayerAudioTrack[]) => void;
|
|
420
|
+
onAudioTrackSelectionChange?: (selection: number) => void;
|
|
393
421
|
onEnded?: () => void;
|
|
394
422
|
};
|
|
395
423
|
type HlsEngineOptions = {
|
|
@@ -431,6 +459,11 @@ declare class HlsEngine {
|
|
|
431
459
|
private mediaRecoveryCount;
|
|
432
460
|
private qualities;
|
|
433
461
|
private qualitySelection;
|
|
462
|
+
private textTracks;
|
|
463
|
+
private textTrackSelection;
|
|
464
|
+
private audioTracks;
|
|
465
|
+
private audioTrackSelection;
|
|
466
|
+
private nativeTextTrackCleanup;
|
|
434
467
|
constructor(options: HlsEngineOptions);
|
|
435
468
|
start(): Promise<void>;
|
|
436
469
|
private startWithHlsJs;
|
|
@@ -442,7 +475,16 @@ declare class HlsEngine {
|
|
|
442
475
|
setQuality(selection: QualitySelection): void;
|
|
443
476
|
getQuality(): QualitySelection;
|
|
444
477
|
getQualities(): HlsQualityLevel[];
|
|
478
|
+
getTextTracks(): PlayerTextTrack[];
|
|
479
|
+
getTextTrackSelection(): TextTrackSelection;
|
|
480
|
+
setTextTrack(selection: TextTrackSelection): void;
|
|
481
|
+
getAudioTracks(): PlayerAudioTrack[];
|
|
482
|
+
getAudioTrackSelection(): number;
|
|
483
|
+
setAudioTrack(index: number): void;
|
|
445
484
|
getSupportMode(): HlsSupportMode;
|
|
485
|
+
private syncHlsSubtitleTracks;
|
|
486
|
+
private syncHlsAudioTracks;
|
|
487
|
+
private bindNativeTextTracks;
|
|
446
488
|
destroy(): void;
|
|
447
489
|
}
|
|
448
490
|
|
|
@@ -468,9 +510,17 @@ type VideoPlayer = {
|
|
|
468
510
|
getQuality: () => QualitySelection;
|
|
469
511
|
setQuality: (selection: QualitySelection | string) => void;
|
|
470
512
|
getAvailableQualities: () => ReturnType<HlsEngine["getQualities"]>;
|
|
513
|
+
getTextTracks: () => PlayerTextTrack[];
|
|
514
|
+
getSelectedTextTrack: () => TextTrackSelection;
|
|
515
|
+
setTextTrack: (selection: TextTrackSelection) => void;
|
|
516
|
+
getAudioTracks: () => PlayerAudioTrack[];
|
|
517
|
+
getSelectedAudioTrack: () => number;
|
|
518
|
+
setAudioTrack: (index: number) => void;
|
|
471
519
|
enterFullscreen: () => Promise<void>;
|
|
472
520
|
exitFullscreen: () => Promise<void>;
|
|
473
521
|
isFullscreen: () => boolean;
|
|
522
|
+
/** Attach fullscreen target container (host UI chrome). Zoom stays UI-only. */
|
|
523
|
+
setFullscreenElement: (el: HTMLElement | null) => void;
|
|
474
524
|
reload: () => Promise<void>;
|
|
475
525
|
destroy: () => void;
|
|
476
526
|
getDiagnostics: () => PlayerDiagnostics;
|
|
@@ -642,4 +692,4 @@ declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>
|
|
|
642
692
|
*/
|
|
643
693
|
declare function redactObject(obj: Record<string, unknown>, seen?: WeakSet<object>, depth?: number): Record<string, unknown>;
|
|
644
694
|
|
|
645
|
-
export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isEncryptionKeyUrl, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, resolveBuiltinHlsLoader, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };
|
|
695
|
+
export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerAudioTrack, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerTextTrack, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type TextTrackSelection, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isEncryptionKeyUrl, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, resolveBuiltinHlsLoader, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,22 @@ type PlayerState = "idle" | "loading" | "ready" | "playing" | "paused" | "buffer
|
|
|
5
5
|
type HlsSupportMode = "hls.js" | "native" | "unsupported";
|
|
6
6
|
type QualitySelection = "auto" | number;
|
|
7
7
|
type PlaybackRate = 0.5 | 0.75 | 1 | 1.25 | 1.5 | 2;
|
|
8
|
+
type PlayerTextTrack = {
|
|
9
|
+
index: number;
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
language?: string;
|
|
13
|
+
uri?: string;
|
|
14
|
+
};
|
|
15
|
+
type PlayerAudioTrack = {
|
|
16
|
+
index: number;
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
language?: string;
|
|
20
|
+
uri?: string;
|
|
21
|
+
};
|
|
22
|
+
/** Runtime caption selection: off or a concrete subtitle track index. */
|
|
23
|
+
type TextTrackSelection = "off" | number;
|
|
8
24
|
type HlsQualityLevel = {
|
|
9
25
|
index: number;
|
|
10
26
|
height: number;
|
|
@@ -222,6 +238,14 @@ type PlayerEventMap = {
|
|
|
222
238
|
selection: QualitySelection;
|
|
223
239
|
label?: string;
|
|
224
240
|
};
|
|
241
|
+
texttrackchange: {
|
|
242
|
+
tracks: PlayerTextTrack[];
|
|
243
|
+
selection: TextTrackSelection;
|
|
244
|
+
};
|
|
245
|
+
audiotrackchange: {
|
|
246
|
+
tracks: PlayerAudioTrack[];
|
|
247
|
+
selection: number;
|
|
248
|
+
};
|
|
225
249
|
volumechange: {
|
|
226
250
|
volume: number;
|
|
227
251
|
muted: boolean;
|
|
@@ -390,6 +414,10 @@ type HlsEngineCallbacks = {
|
|
|
390
414
|
onAuthRecoveryNeeded?: (reason: string) => void;
|
|
391
415
|
onQualitiesChange?: (levels: HlsQualityLevel[]) => void;
|
|
392
416
|
onQualitySelectionChange?: (selection: QualitySelection) => void;
|
|
417
|
+
onTextTracksChange?: (tracks: PlayerTextTrack[]) => void;
|
|
418
|
+
onTextTrackSelectionChange?: (selection: TextTrackSelection) => void;
|
|
419
|
+
onAudioTracksChange?: (tracks: PlayerAudioTrack[]) => void;
|
|
420
|
+
onAudioTrackSelectionChange?: (selection: number) => void;
|
|
393
421
|
onEnded?: () => void;
|
|
394
422
|
};
|
|
395
423
|
type HlsEngineOptions = {
|
|
@@ -431,6 +459,11 @@ declare class HlsEngine {
|
|
|
431
459
|
private mediaRecoveryCount;
|
|
432
460
|
private qualities;
|
|
433
461
|
private qualitySelection;
|
|
462
|
+
private textTracks;
|
|
463
|
+
private textTrackSelection;
|
|
464
|
+
private audioTracks;
|
|
465
|
+
private audioTrackSelection;
|
|
466
|
+
private nativeTextTrackCleanup;
|
|
434
467
|
constructor(options: HlsEngineOptions);
|
|
435
468
|
start(): Promise<void>;
|
|
436
469
|
private startWithHlsJs;
|
|
@@ -442,7 +475,16 @@ declare class HlsEngine {
|
|
|
442
475
|
setQuality(selection: QualitySelection): void;
|
|
443
476
|
getQuality(): QualitySelection;
|
|
444
477
|
getQualities(): HlsQualityLevel[];
|
|
478
|
+
getTextTracks(): PlayerTextTrack[];
|
|
479
|
+
getTextTrackSelection(): TextTrackSelection;
|
|
480
|
+
setTextTrack(selection: TextTrackSelection): void;
|
|
481
|
+
getAudioTracks(): PlayerAudioTrack[];
|
|
482
|
+
getAudioTrackSelection(): number;
|
|
483
|
+
setAudioTrack(index: number): void;
|
|
445
484
|
getSupportMode(): HlsSupportMode;
|
|
485
|
+
private syncHlsSubtitleTracks;
|
|
486
|
+
private syncHlsAudioTracks;
|
|
487
|
+
private bindNativeTextTracks;
|
|
446
488
|
destroy(): void;
|
|
447
489
|
}
|
|
448
490
|
|
|
@@ -468,9 +510,17 @@ type VideoPlayer = {
|
|
|
468
510
|
getQuality: () => QualitySelection;
|
|
469
511
|
setQuality: (selection: QualitySelection | string) => void;
|
|
470
512
|
getAvailableQualities: () => ReturnType<HlsEngine["getQualities"]>;
|
|
513
|
+
getTextTracks: () => PlayerTextTrack[];
|
|
514
|
+
getSelectedTextTrack: () => TextTrackSelection;
|
|
515
|
+
setTextTrack: (selection: TextTrackSelection) => void;
|
|
516
|
+
getAudioTracks: () => PlayerAudioTrack[];
|
|
517
|
+
getSelectedAudioTrack: () => number;
|
|
518
|
+
setAudioTrack: (index: number) => void;
|
|
471
519
|
enterFullscreen: () => Promise<void>;
|
|
472
520
|
exitFullscreen: () => Promise<void>;
|
|
473
521
|
isFullscreen: () => boolean;
|
|
522
|
+
/** Attach fullscreen target container (host UI chrome). Zoom stays UI-only. */
|
|
523
|
+
setFullscreenElement: (el: HTMLElement | null) => void;
|
|
474
524
|
reload: () => Promise<void>;
|
|
475
525
|
destroy: () => void;
|
|
476
526
|
getDiagnostics: () => PlayerDiagnostics;
|
|
@@ -642,4 +692,4 @@ declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>
|
|
|
642
692
|
*/
|
|
643
693
|
declare function redactObject(obj: Record<string, unknown>, seen?: WeakSet<object>, depth?: number): Record<string, unknown>;
|
|
644
694
|
|
|
645
|
-
export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isEncryptionKeyUrl, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, resolveBuiltinHlsLoader, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };
|
|
695
|
+
export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerAudioTrack, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerTextTrack, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type TextTrackSelection, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isEncryptionKeyUrl, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, resolveBuiltinHlsLoader, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };
|
package/dist/index.js
CHANGED
|
@@ -971,6 +971,11 @@ var HlsEngine = class {
|
|
|
971
971
|
this.mediaRecoveryCount = 0;
|
|
972
972
|
this.qualities = [];
|
|
973
973
|
this.qualitySelection = "auto";
|
|
974
|
+
this.textTracks = [];
|
|
975
|
+
this.textTrackSelection = "off";
|
|
976
|
+
this.audioTracks = [];
|
|
977
|
+
this.audioTrackSelection = 0;
|
|
978
|
+
this.nativeTextTrackCleanup = null;
|
|
974
979
|
}
|
|
975
980
|
async start() {
|
|
976
981
|
const { videoEl, playbackUrl, startMuted, volume } = this.options;
|
|
@@ -990,6 +995,7 @@ var HlsEngine = class {
|
|
|
990
995
|
this.options.callbacks.onSupportMode?.("native");
|
|
991
996
|
videoEl.src = this.options.authParams.applyToUrl(playbackUrl);
|
|
992
997
|
this.bindMediaEvents();
|
|
998
|
+
this.bindNativeTextTracks();
|
|
993
999
|
this.options.callbacks.onStateChange?.("ready");
|
|
994
1000
|
await this.applyStartPositionAndAutoplay();
|
|
995
1001
|
return;
|
|
@@ -1033,9 +1039,19 @@ var HlsEngine = class {
|
|
|
1033
1039
|
label: level.height != null && level.height > 0 ? `${level.height}p` : `Level ${index}`
|
|
1034
1040
|
}));
|
|
1035
1041
|
callbacks.onQualitiesChange?.(this.qualities);
|
|
1042
|
+
this.syncHlsSubtitleTracks();
|
|
1043
|
+
this.syncHlsAudioTracks();
|
|
1036
1044
|
callbacks.onStateChange?.("ready");
|
|
1037
1045
|
void this.applyStartPositionAndAutoplay();
|
|
1038
1046
|
});
|
|
1047
|
+
this.hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, () => {
|
|
1048
|
+
if (this.destroyed) return;
|
|
1049
|
+
this.syncHlsSubtitleTracks();
|
|
1050
|
+
});
|
|
1051
|
+
this.hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, () => {
|
|
1052
|
+
if (this.destroyed) return;
|
|
1053
|
+
this.syncHlsAudioTracks();
|
|
1054
|
+
});
|
|
1039
1055
|
this.hls.on(Hls.Events.ERROR, (_event, data) => {
|
|
1040
1056
|
this.handleHlsError(Hls, data);
|
|
1041
1057
|
});
|
|
@@ -1161,12 +1177,120 @@ var HlsEngine = class {
|
|
|
1161
1177
|
getQualities() {
|
|
1162
1178
|
return this.qualities;
|
|
1163
1179
|
}
|
|
1180
|
+
getTextTracks() {
|
|
1181
|
+
return this.textTracks;
|
|
1182
|
+
}
|
|
1183
|
+
getTextTrackSelection() {
|
|
1184
|
+
return this.textTrackSelection;
|
|
1185
|
+
}
|
|
1186
|
+
setTextTrack(selection) {
|
|
1187
|
+
if (this.destroyed) return;
|
|
1188
|
+
this.textTrackSelection = selection;
|
|
1189
|
+
this.options.callbacks.onTextTrackSelectionChange?.(selection);
|
|
1190
|
+
if (this.supportMode === "hls.js" && this.hls) {
|
|
1191
|
+
this.hls.subtitleDisplay = selection !== "off";
|
|
1192
|
+
this.hls.subtitleTrack = selection === "off" ? -1 : selection;
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
if (this.supportMode === "native" && this.options.videoEl) {
|
|
1196
|
+
const tracks = this.options.videoEl.textTracks;
|
|
1197
|
+
for (let i = 0; i < tracks.length; i += 1) {
|
|
1198
|
+
const track = tracks[i];
|
|
1199
|
+
track.mode = selection !== "off" && i === selection ? "showing" : "disabled";
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
getAudioTracks() {
|
|
1204
|
+
return this.audioTracks;
|
|
1205
|
+
}
|
|
1206
|
+
getAudioTrackSelection() {
|
|
1207
|
+
return this.audioTrackSelection;
|
|
1208
|
+
}
|
|
1209
|
+
setAudioTrack(index) {
|
|
1210
|
+
if (this.destroyed) return;
|
|
1211
|
+
if (!Number.isInteger(index) || index < 0 || this.audioTracks.length > 0 && index >= this.audioTracks.length) {
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
this.audioTrackSelection = index;
|
|
1215
|
+
this.options.callbacks.onAudioTrackSelectionChange?.(index);
|
|
1216
|
+
if (this.supportMode === "hls.js" && this.hls) {
|
|
1217
|
+
this.hls.audioTrack = index;
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
if (this.supportMode === "native" && this.options.videoEl) {
|
|
1221
|
+
const audioTracks = this.options.videoEl.audioTracks;
|
|
1222
|
+
if (audioTracks && audioTracks.length > 0) {
|
|
1223
|
+
for (let i = 0; i < audioTracks.length; i += 1) {
|
|
1224
|
+
audioTracks[i].enabled = i === index;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1164
1229
|
getSupportMode() {
|
|
1165
1230
|
return this.supportMode;
|
|
1166
1231
|
}
|
|
1232
|
+
syncHlsSubtitleTracks() {
|
|
1233
|
+
if (!this.hls) return;
|
|
1234
|
+
const tracks = (this.hls.subtitleTracks ?? []).map(
|
|
1235
|
+
(track, index) => ({
|
|
1236
|
+
index,
|
|
1237
|
+
id: String(track.id ?? index),
|
|
1238
|
+
label: track.name || track.lang || `Subtitles ${index + 1}`,
|
|
1239
|
+
language: track.lang
|
|
1240
|
+
})
|
|
1241
|
+
);
|
|
1242
|
+
this.textTracks = tracks;
|
|
1243
|
+
this.options.callbacks.onTextTracksChange?.(tracks);
|
|
1244
|
+
}
|
|
1245
|
+
syncHlsAudioTracks() {
|
|
1246
|
+
if (!this.hls) return;
|
|
1247
|
+
const tracks = (this.hls.audioTracks ?? []).map(
|
|
1248
|
+
(track, index) => ({
|
|
1249
|
+
index,
|
|
1250
|
+
id: String(track.id ?? index),
|
|
1251
|
+
label: track.name || track.lang || `Audio ${index + 1}`,
|
|
1252
|
+
language: track.lang
|
|
1253
|
+
})
|
|
1254
|
+
);
|
|
1255
|
+
this.audioTracks = tracks;
|
|
1256
|
+
this.options.callbacks.onAudioTracksChange?.(tracks);
|
|
1257
|
+
if (tracks.length > 0) {
|
|
1258
|
+
this.audioTrackSelection = 0;
|
|
1259
|
+
this.options.callbacks.onAudioTrackSelectionChange?.(0);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
bindNativeTextTracks() {
|
|
1263
|
+
const { videoEl } = this.options;
|
|
1264
|
+
const syncFromElement = () => {
|
|
1265
|
+
if (this.destroyed || this.textTracks.length > 0) return;
|
|
1266
|
+
const list = videoEl.textTracks;
|
|
1267
|
+
const tracks = [];
|
|
1268
|
+
for (let i = 0; i < list.length; i += 1) {
|
|
1269
|
+
const track = list[i];
|
|
1270
|
+
if (track.kind !== "subtitles" && track.kind !== "captions") continue;
|
|
1271
|
+
tracks.push({
|
|
1272
|
+
index: tracks.length,
|
|
1273
|
+
id: track.id || `native-${tracks.length}`,
|
|
1274
|
+
label: track.label || track.language || `Track ${tracks.length + 1}`,
|
|
1275
|
+
language: track.language || void 0
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
if (tracks.length === 0) return;
|
|
1279
|
+
this.textTracks = tracks;
|
|
1280
|
+
this.options.callbacks.onTextTracksChange?.(tracks);
|
|
1281
|
+
};
|
|
1282
|
+
const textTracks = videoEl.textTracks;
|
|
1283
|
+
textTracks.addEventListener?.("addtrack", syncFromElement);
|
|
1284
|
+
syncFromElement();
|
|
1285
|
+
this.nativeTextTrackCleanup = () => {
|
|
1286
|
+
textTracks.removeEventListener?.("addtrack", syncFromElement);
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1167
1289
|
destroy() {
|
|
1168
1290
|
if (this.destroyed) return;
|
|
1169
1291
|
this.destroyed = true;
|
|
1292
|
+
this.nativeTextTrackCleanup?.();
|
|
1293
|
+
this.nativeTextTrackCleanup = null;
|
|
1170
1294
|
this.hls?.destroy();
|
|
1171
1295
|
this.hls = null;
|
|
1172
1296
|
const { videoEl } = this.options;
|
|
@@ -1223,11 +1347,40 @@ function createVideoPlayer(options) {
|
|
|
1223
1347
|
let refreshManager = null;
|
|
1224
1348
|
let fullscreenEl = null;
|
|
1225
1349
|
let isLiveStream = false;
|
|
1350
|
+
let mediaCleanup = null;
|
|
1226
1351
|
const setState = (next) => {
|
|
1227
1352
|
if (destroyed && next !== "destroyed") return;
|
|
1228
1353
|
state = next;
|
|
1229
1354
|
events.emit("statechange", { state: next });
|
|
1230
1355
|
};
|
|
1356
|
+
const bindMediaProgressEvents = (el) => {
|
|
1357
|
+
mediaCleanup?.();
|
|
1358
|
+
const onTimeUpdate = () => {
|
|
1359
|
+
if (destroyed) return;
|
|
1360
|
+
events.emit("timeupdate", {
|
|
1361
|
+
currentTime: el.currentTime,
|
|
1362
|
+
duration: Number.isFinite(el.duration) ? el.duration : 0
|
|
1363
|
+
});
|
|
1364
|
+
};
|
|
1365
|
+
const onProgress = () => {
|
|
1366
|
+
if (destroyed) return;
|
|
1367
|
+
let bufferedEnd = 0;
|
|
1368
|
+
try {
|
|
1369
|
+
if (el.buffered.length > 0) {
|
|
1370
|
+
bufferedEnd = el.buffered.end(el.buffered.length - 1);
|
|
1371
|
+
}
|
|
1372
|
+
} catch {
|
|
1373
|
+
bufferedEnd = 0;
|
|
1374
|
+
}
|
|
1375
|
+
events.emit("progress", { bufferedEnd });
|
|
1376
|
+
};
|
|
1377
|
+
el.addEventListener("timeupdate", onTimeUpdate);
|
|
1378
|
+
el.addEventListener("progress", onProgress);
|
|
1379
|
+
mediaCleanup = () => {
|
|
1380
|
+
el.removeEventListener("timeupdate", onTimeUpdate);
|
|
1381
|
+
el.removeEventListener("progress", onProgress);
|
|
1382
|
+
};
|
|
1383
|
+
};
|
|
1231
1384
|
const authManager = new AuthManager(
|
|
1232
1385
|
options.auth,
|
|
1233
1386
|
options.auth?.refreshBeforeExpiryMs ?? 6e4,
|
|
@@ -1278,6 +1431,7 @@ function createVideoPlayer(options) {
|
|
|
1278
1431
|
isLiveStream = Boolean(source.live);
|
|
1279
1432
|
}
|
|
1280
1433
|
const el = ensureVideoElement();
|
|
1434
|
+
bindMediaProgressEvents(el);
|
|
1281
1435
|
engine?.destroy();
|
|
1282
1436
|
engine = new HlsEngine({
|
|
1283
1437
|
videoEl: el,
|
|
@@ -1336,6 +1490,30 @@ function createVideoPlayer(options) {
|
|
|
1336
1490
|
label: typeof selection === "number" ? level?.label : "auto"
|
|
1337
1491
|
});
|
|
1338
1492
|
},
|
|
1493
|
+
onTextTracksChange: (tracks) => {
|
|
1494
|
+
events.emit("texttrackchange", {
|
|
1495
|
+
tracks,
|
|
1496
|
+
selection: engine?.getTextTrackSelection() ?? "off"
|
|
1497
|
+
});
|
|
1498
|
+
},
|
|
1499
|
+
onTextTrackSelectionChange: (selection) => {
|
|
1500
|
+
events.emit("texttrackchange", {
|
|
1501
|
+
tracks: engine?.getTextTracks() ?? [],
|
|
1502
|
+
selection
|
|
1503
|
+
});
|
|
1504
|
+
},
|
|
1505
|
+
onAudioTracksChange: (tracks) => {
|
|
1506
|
+
events.emit("audiotrackchange", {
|
|
1507
|
+
tracks,
|
|
1508
|
+
selection: engine?.getAudioTrackSelection() ?? 0
|
|
1509
|
+
});
|
|
1510
|
+
},
|
|
1511
|
+
onAudioTrackSelectionChange: (selection) => {
|
|
1512
|
+
events.emit("audiotrackchange", {
|
|
1513
|
+
tracks: engine?.getAudioTracks() ?? [],
|
|
1514
|
+
selection
|
|
1515
|
+
});
|
|
1516
|
+
},
|
|
1339
1517
|
onEnded: () => events.emit("ended")
|
|
1340
1518
|
}
|
|
1341
1519
|
});
|
|
@@ -1494,6 +1672,24 @@ function createVideoPlayer(options) {
|
|
|
1494
1672
|
getAvailableQualities() {
|
|
1495
1673
|
return engine?.getQualities() ?? [];
|
|
1496
1674
|
},
|
|
1675
|
+
getTextTracks() {
|
|
1676
|
+
return engine?.getTextTracks() ?? [];
|
|
1677
|
+
},
|
|
1678
|
+
getSelectedTextTrack() {
|
|
1679
|
+
return engine?.getTextTrackSelection() ?? "off";
|
|
1680
|
+
},
|
|
1681
|
+
setTextTrack(selection) {
|
|
1682
|
+
engine?.setTextTrack(selection);
|
|
1683
|
+
},
|
|
1684
|
+
getAudioTracks() {
|
|
1685
|
+
return engine?.getAudioTracks() ?? [];
|
|
1686
|
+
},
|
|
1687
|
+
getSelectedAudioTrack() {
|
|
1688
|
+
return engine?.getAudioTrackSelection() ?? 0;
|
|
1689
|
+
},
|
|
1690
|
+
setAudioTrack(index) {
|
|
1691
|
+
engine?.setAudioTrack(index);
|
|
1692
|
+
},
|
|
1497
1693
|
async enterFullscreen() {
|
|
1498
1694
|
const target = fullscreenEl ?? videoEl?.parentElement ?? videoEl;
|
|
1499
1695
|
if (target && "requestFullscreen" in target) {
|
|
@@ -1510,6 +1706,9 @@ function createVideoPlayer(options) {
|
|
|
1510
1706
|
isFullscreen() {
|
|
1511
1707
|
return Boolean(document.fullscreenElement);
|
|
1512
1708
|
},
|
|
1709
|
+
setFullscreenElement(el) {
|
|
1710
|
+
fullscreenEl = el;
|
|
1711
|
+
},
|
|
1513
1712
|
async reload() {
|
|
1514
1713
|
refreshManager?.stop();
|
|
1515
1714
|
engine?.destroy();
|
|
@@ -1518,6 +1717,8 @@ function createVideoPlayer(options) {
|
|
|
1518
1717
|
destroy() {
|
|
1519
1718
|
if (destroyed) return;
|
|
1520
1719
|
destroyed = true;
|
|
1720
|
+
mediaCleanup?.();
|
|
1721
|
+
mediaCleanup = null;
|
|
1521
1722
|
refreshManager?.stop();
|
|
1522
1723
|
refreshManager = null;
|
|
1523
1724
|
engine?.destroy();
|