stormcloud-video-player 0.8.42 → 0.8.44

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.
@@ -1,4 +1,4 @@
1
- import { A as AdController } from '../types-cTqIKw_D.cjs';
1
+ import { A as AdController } from '../types-iDjS8f_7.cjs';
2
2
  import Hls from 'hls.js';
3
3
 
4
4
  declare function createHlsAdPlayer(contentVideo: HTMLVideoElement, options?: {
@@ -0,0 +1,133 @@
1
+ interface AdBreak {
2
+ id?: string;
3
+ startTimeMs: number;
4
+ durationMs?: number;
5
+ vastTagUrl?: string;
6
+ }
7
+ interface StormcloudVideoPlayerConfig {
8
+ videoElement: HTMLVideoElement;
9
+ src: string;
10
+ autoplay?: boolean;
11
+ muted?: boolean;
12
+ allowNativeHls?: boolean;
13
+ lowLatencyMode?: boolean;
14
+ isLiveStream?: boolean;
15
+ pauseContentDuringAds?: boolean;
16
+ driftToleranceMs?: number;
17
+ immediateManifestAds?: boolean;
18
+ debugAdTiming?: boolean;
19
+ adFailsafeTimeoutMs?: number;
20
+ adBreakCheckIntervalMs?: number;
21
+ maxAdBreakExtensionMs?: number;
22
+ minRemainingMsToStartAd?: number;
23
+ showCustomControls?: boolean;
24
+ hideLoadingIndicator?: boolean;
25
+ onVolumeToggle?: () => void;
26
+ onFullscreenToggle?: () => void;
27
+ onControlClick?: () => void;
28
+ licenseKey?: string;
29
+ vastTagUrl?: string;
30
+ isVmap?: boolean;
31
+ vmapUrl?: string;
32
+ vastMode?: 'adstorm' | 'default';
33
+ minSegmentsBeforePlay?: number;
34
+ ctvAdRequest?: boolean;
35
+ adTest?: boolean;
36
+ podMaxAds?: number;
37
+ podMaxDurationMs?: number;
38
+ podExactDuration?: boolean;
39
+ }
40
+ interface Scte35Marker {
41
+ type: "start" | "end" | "progress";
42
+ ptsSeconds?: number;
43
+ durationSeconds?: number;
44
+ raw?: unknown;
45
+ }
46
+ interface Id3TagInfo {
47
+ key: string;
48
+ value: string | Uint8Array;
49
+ ptsSeconds?: number;
50
+ }
51
+ interface AdController {
52
+ initialize: () => void;
53
+ requestAds: (vastTagUrl: string) => Promise<void>;
54
+ play: () => Promise<void>;
55
+ pause: () => void;
56
+ resume: () => void;
57
+ stop: () => Promise<void>;
58
+ destroy: () => void;
59
+ isAdPlaying: () => boolean;
60
+ resize: (width: number, height: number) => void;
61
+ on: (event: string, listener: (payload?: any) => void) => void;
62
+ off: (event: string, listener: (payload?: any) => void) => void;
63
+ updateOriginalMutedState: (muted: boolean, volume?: number) => void;
64
+ getOriginalMutedState: () => boolean;
65
+ getOriginalVolume: () => number;
66
+ setAdVolume: (volume: number) => void;
67
+ getAdVolume: () => number;
68
+ showPlaceholder: () => void;
69
+ hidePlaceholder: () => void;
70
+ getLoadedAdDuration?: () => number | undefined;
71
+ getLoadedAdId?: () => string | undefined;
72
+ getPodAdCount?: () => number;
73
+ getPodTotalDurationMs?: () => number;
74
+ }
75
+ interface ClientInfo {
76
+ brand: string;
77
+ os: string;
78
+ model: string;
79
+ deviceType: "tv" | "mobile" | "tablet" | "desktop";
80
+ isSmartTV: boolean;
81
+ isAndroid: boolean;
82
+ isWebView: boolean;
83
+ isWebApp: boolean;
84
+ domain: string;
85
+ origin: string;
86
+ path: string;
87
+ userAgent: string;
88
+ vendor: string;
89
+ platform: string;
90
+ screen: {
91
+ width?: number;
92
+ height?: number;
93
+ availWidth?: number;
94
+ availHeight?: number;
95
+ orientation?: string;
96
+ pixelDepth?: number;
97
+ };
98
+ hardwareConcurrency: number;
99
+ deviceMemory: number | null;
100
+ maxTouchPoints: number;
101
+ language: string;
102
+ languages: string;
103
+ cookieEnabled: boolean;
104
+ doNotTrack: string;
105
+ referrer: string;
106
+ visibilityState: string;
107
+ }
108
+ interface PlayerAnalyticsContext {
109
+ inputStreamType?: string;
110
+ debugAdTiming?: boolean;
111
+ }
112
+ interface AdDetectInfo {
113
+ source: "scte35";
114
+ durationSeconds?: number;
115
+ ptsSeconds?: number;
116
+ detectedAtFragmentSn?: number;
117
+ timestamp: string;
118
+ }
119
+ interface AdLoadedInfo {
120
+ source: "vast" | "hls";
121
+ vastUrl?: string;
122
+ durationSeconds?: number;
123
+ timestamp: string;
124
+ }
125
+ interface AdImpressionInfo {
126
+ source: "vast" | "hls";
127
+ adIndex: number;
128
+ adUrl?: string;
129
+ durationSeconds?: number;
130
+ timestamp: string;
131
+ }
132
+
133
+ export type { AdController as A, ClientInfo as C, Id3TagInfo as I, PlayerAnalyticsContext as P, StormcloudVideoPlayerConfig as S, Scte35Marker as a, AdBreak as b, AdDetectInfo as c, AdImpressionInfo as d, AdLoadedInfo as e };
@@ -6238,6 +6238,7 @@ var HlsEngine = /*#__PURE__*/ function() {
6238
6238
  this.isLiveStream = false;
6239
6239
  this.nativeHlsMode = false;
6240
6240
  this.videoSrcProtection = null;
6241
+ this.reloadingLiveStream = false;
6241
6242
  this.bufferedSegmentsCount = 0;
6242
6243
  this.shouldAutoplayAfterBuffering = false;
6243
6244
  this.hasInitialBufferCompleted = false;
@@ -6371,6 +6372,7 @@ var HlsEngine = /*#__PURE__*/ function() {
6371
6372
  _state.sent();
6372
6373
  _state.label = 3;
6373
6374
  case 3:
6375
+ this.reloadingLiveStream = false;
6374
6376
  return [
6375
6377
  2
6376
6378
  ];
@@ -6715,6 +6717,33 @@ var HlsEngine = /*#__PURE__*/ function() {
6715
6717
  }
6716
6718
  }
6717
6719
  },
6720
+ {
6721
+ key: "reloadLiveStream",
6722
+ value: function reloadLiveStream() {
6723
+ var hls = this.hls;
6724
+ if (!hls) {
6725
+ return;
6726
+ }
6727
+ if (this.debug) {
6728
+ console.log("[StormcloudVideoPlayer] Hard-reloading live stream (detach \u2192 reset video \u2192 re-attach)");
6729
+ }
6730
+ try {
6731
+ this.reloadingLiveStream = true;
6732
+ hls.stopLoad();
6733
+ hls.detachMedia();
6734
+ try {
6735
+ this.video.removeAttribute("src");
6736
+ this.video.load();
6737
+ } catch (unused) {}
6738
+ hls.attachMedia(this.video);
6739
+ } catch (error) {
6740
+ this.reloadingLiveStream = false;
6741
+ if (this.debug) {
6742
+ console.warn("[StormcloudVideoPlayer] Failed to hard-reload live stream:", error);
6743
+ }
6744
+ }
6745
+ }
6746
+ },
6718
6747
  {
6719
6748
  key: "destroy",
6720
6749
  value: function destroy() {
@@ -8054,31 +8083,134 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8054
8083
  return 0;
8055
8084
  }
8056
8085
  },
8086
+ {
8087
+ key: "describeVideoState",
8088
+ value: function describeVideoState() {
8089
+ var _networkStates_v_networkState, _readyStates_v_readyState;
8090
+ var v = this.host.video;
8091
+ var networkStates = [
8092
+ "EMPTY",
8093
+ "IDLE",
8094
+ "LOADING",
8095
+ "NO_SOURCE"
8096
+ ];
8097
+ var readyStates = [
8098
+ "HAVE_NOTHING",
8099
+ "HAVE_METADATA",
8100
+ "HAVE_CURRENT_DATA",
8101
+ "HAVE_FUTURE_DATA",
8102
+ "HAVE_ENOUGH_DATA"
8103
+ ];
8104
+ var net = (_networkStates_v_networkState = networkStates[v.networkState]) !== null && _networkStates_v_networkState !== void 0 ? _networkStates_v_networkState : String(v.networkState);
8105
+ var ready = (_readyStates_v_readyState = readyStates[v.readyState]) !== null && _readyStates_v_readyState !== void 0 ? _readyStates_v_readyState : String(v.readyState);
8106
+ var err = v.error ? "code=".concat(v.error.code).concat(v.error.message ? " (".concat(v.error.message, ")") : "") : "none";
8107
+ var ranges = [];
8108
+ for(var i = 0; i < v.buffered.length; i++){
8109
+ ranges.push("[".concat(v.buffered.start(i).toFixed(2), "–").concat(v.buffered.end(i).toFixed(2), "]"));
8110
+ }
8111
+ return "t=".concat(v.currentTime.toFixed(2), "s paused=").concat(v.paused, " ended=").concat(v.ended, " seeking=").concat(v.seeking, " readyState=").concat(ready, " networkState=").concat(net, " error=").concat(err, " buffered=").concat(ranges.length ? ranges.join(",") : "none");
8112
+ }
8113
+ },
8057
8114
  {
8058
8115
  key: "monitorLiveResumeStall",
8059
8116
  value: function monitorLiveResumeStall(resumeBaseline) {
8060
8117
  var _this = this;
8061
8118
  var pollIntervalMs = 1e3;
8062
8119
  var graceMs = 5e3;
8063
- var reloadCooldownMs = 5e3;
8064
- var maxHardReloads = 2;
8065
- var maxMonitorMs = 25e3;
8120
+ var recoveryCooldownMs = 5e3;
8121
+ var maxRecoveries = 2;
8122
+ var maxMonitorMs = 3e4;
8066
8123
  var startTime = Date.now();
8067
8124
  var baseline = resumeBaseline;
8068
- var hardReloads = 0;
8069
- var lastReloadAt = 0;
8125
+ var recoveries = 0;
8126
+ var lastRecoveryAt = 0;
8127
+ var video = this.host.video;
8128
+ var listenersAttached = false;
8129
+ var onMediaEvent;
8130
+ var diagEvents = [
8131
+ "loadstart",
8132
+ "loadedmetadata",
8133
+ "loadeddata",
8134
+ "canplay",
8135
+ "canplaythrough",
8136
+ "play",
8137
+ "playing",
8138
+ "pause",
8139
+ "waiting",
8140
+ "stalled",
8141
+ "suspend",
8142
+ "seeking",
8143
+ "seeked",
8144
+ "emptied",
8145
+ "error",
8146
+ "ended"
8147
+ ];
8148
+ if (this.debug) {
8149
+ onMediaEvent = function onMediaEvent(e) {
8150
+ var dt = ((Date.now() - startTime) / 1e3).toFixed(1);
8151
+ console.log("[ResumeDiag] +".concat(dt, "s event=").concat(e.type, " — ").concat(_this.describeVideoState()));
8152
+ };
8153
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
8154
+ try {
8155
+ for(var _iterator = diagEvents[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
8156
+ var name = _step.value;
8157
+ video.addEventListener(name, onMediaEvent);
8158
+ }
8159
+ } catch (err) {
8160
+ _didIteratorError = true;
8161
+ _iteratorError = err;
8162
+ } finally{
8163
+ try {
8164
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
8165
+ _iterator.return();
8166
+ }
8167
+ } finally{
8168
+ if (_didIteratorError) {
8169
+ throw _iteratorError;
8170
+ }
8171
+ }
8172
+ }
8173
+ listenersAttached = true;
8174
+ console.log("[ResumeDiag] +0.0s monitor start — ".concat(this.describeVideoState()));
8175
+ }
8176
+ var cleanup = function cleanup() {
8177
+ if (listenersAttached && onMediaEvent) {
8178
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
8179
+ try {
8180
+ for(var _iterator = diagEvents[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
8181
+ var name = _step.value;
8182
+ video.removeEventListener(name, onMediaEvent);
8183
+ }
8184
+ } catch (err) {
8185
+ _didIteratorError = true;
8186
+ _iteratorError = err;
8187
+ } finally{
8188
+ try {
8189
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
8190
+ _iterator.return();
8191
+ }
8192
+ } finally{
8193
+ if (_didIteratorError) {
8194
+ throw _iteratorError;
8195
+ }
8196
+ }
8197
+ }
8198
+ listenersAttached = false;
8199
+ }
8200
+ };
8070
8201
  var poll = function poll1() {
8071
8202
  if (_this.inAdBreak) {
8203
+ cleanup();
8072
8204
  return;
8073
8205
  }
8074
- var video = _this.host.video;
8075
8206
  var currentTime = video.currentTime;
8076
8207
  var advanced = currentTime > baseline + 0.5;
8077
8208
  var playing = !video.paused && video.readyState >= 3;
8078
8209
  if (advanced && playing) {
8079
8210
  if (_this.debug) {
8080
- console.log("[StormcloudVideoPlayer] Live stream resumed successfully after ad break");
8211
+ console.log("[StormcloudVideoPlayer] Live stream resumed successfully after ad break".concat(_this.describeVideoState()));
8081
8212
  }
8213
+ cleanup();
8082
8214
  return;
8083
8215
  }
8084
8216
  if (video.paused) {
@@ -8090,23 +8222,32 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
8090
8222
  var wedged = bufferedAhead < 0.5 && !advanced;
8091
8223
  if (elapsed >= maxMonitorMs) {
8092
8224
  if (_this.debug && !advanced) {
8093
- console.warn("[StormcloudVideoPlayer] Live stream failed to resume after ".concat((maxMonitorMs / 1e3).toFixed(0), "s (t=").concat(currentTime.toFixed(2), "s, buffered=").concat(bufferedAhead.toFixed(2), "s)"));
8225
+ console.warn("[StormcloudVideoPlayer] Live stream failed to resume after ".concat((maxMonitorMs / 1e3).toFixed(0), "s ").concat(_this.describeVideoState()));
8094
8226
  }
8227
+ cleanup();
8095
8228
  return;
8096
8229
  }
8097
- var canHardReload = wedged && elapsed >= graceMs && Date.now() - lastReloadAt >= reloadCooldownMs && hardReloads < maxHardReloads;
8098
- if (canHardReload) {
8099
- hardReloads++;
8100
- lastReloadAt = Date.now();
8101
- var liveSyncPos = _this.host.getLiveSyncPosition();
8102
- var reloadPos = liveSyncPos != null && liveSyncPos > currentTime ? liveSyncPos : currentTime;
8103
- if (_this.debug) {
8104
- console.warn("[StormcloudVideoPlayer] Content wedged after ad break (t=".concat(currentTime.toFixed(2), "s, buffered=").concat(bufferedAhead.toFixed(2), "s) forcing HLS reload at ").concat(reloadPos.toFixed(2), "s (hard reload ").concat(hardReloads, "/").concat(maxHardReloads, ")"));
8105
- }
8106
- if (liveSyncPos != null && liveSyncPos > currentTime) {
8107
- video.currentTime = liveSyncPos;
8230
+ var canRecover = wedged && elapsed >= graceMs && Date.now() - lastRecoveryAt >= recoveryCooldownMs && recoveries < maxRecoveries;
8231
+ if (canRecover) {
8232
+ recoveries++;
8233
+ lastRecoveryAt = Date.now();
8234
+ var isFinalAttempt = recoveries >= maxRecoveries;
8235
+ if (!isFinalAttempt) {
8236
+ var liveSyncPos = _this.host.getLiveSyncPosition();
8237
+ var reloadPos = liveSyncPos != null && liveSyncPos > currentTime ? liveSyncPos : currentTime;
8238
+ if (_this.debug) {
8239
+ console.warn("[StormcloudVideoPlayer] Content wedged after ad break — restarting HLS load at ".concat(reloadPos.toFixed(2), "s (recovery ").concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8240
+ }
8241
+ if (liveSyncPos != null && liveSyncPos > currentTime) {
8242
+ video.currentTime = liveSyncPos;
8243
+ }
8244
+ _this.host.restartHlsLoad(reloadPos);
8245
+ } else {
8246
+ if (_this.debug) {
8247
+ console.warn("[StormcloudVideoPlayer] Content still wedged after ad break — hard-reloading live stream (recovery ".concat(recoveries, "/").concat(maxRecoveries, ") — ").concat(_this.describeVideoState()));
8248
+ }
8249
+ _this.host.reloadLiveStream();
8108
8250
  }
8109
- _this.host.restartHlsLoad(reloadPos);
8110
8251
  baseline = video.currentTime;
8111
8252
  if (video.paused) {
8112
8253
  var _video_play1;
@@ -8269,6 +8410,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8269
8410
  restartHlsLoad: function restartHlsLoad(position) {
8270
8411
  return _this.hlsEngine.restartLoadAt(position);
8271
8412
  },
8413
+ reloadLiveStream: function reloadLiveStream() {
8414
+ return _this.hlsEngine.reloadLiveStream();
8415
+ },
8272
8416
  generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8273
8417
  return _this.generatePodVastUrl(base, breakDurationMs);
8274
8418
  }
@@ -8400,6 +8544,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8400
8544
  return _async_to_generator(function() {
8401
8545
  var prerollKey, adBehavior;
8402
8546
  return _ts_generator(this, function(_state) {
8547
+ if (this.hlsEngine.reloadingLiveStream) {
8548
+ if (this.debug) {
8549
+ console.log("[StormcloudVideoPlayer] Manifest re-parsed after hard reload \u2014 skipping ad-player setup");
8550
+ }
8551
+ return [
8552
+ 2
8553
+ ];
8554
+ }
8403
8555
  if (!this.adConfig.isVmapEnabled() && !isLive && this.adConfig.vmapBreaks.length === 0 && this.adConfig.apiVastTagUrl) {
8404
8556
  prerollKey = "synthetic-vod-preroll";
8405
8557
  if (!this.adConfig.consumedVmapBreakIds.has(prerollKey)) {