stormcloud-video-player 0.3.61 → 0.3.63

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.
@@ -3337,7 +3337,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3337
3337
  key: "load",
3338
3338
  value: function load() {
3339
3339
  return _async_to_generator(function() {
3340
- var _this, error, _this_config_lowLatencyMode, _this_video_play;
3340
+ var _this, error, _this_config_isLiveStream, _this_config_lowLatencyMode, _this_video_play;
3341
3341
  return _ts_generator(this, function(_state) {
3342
3342
  switch(_state.label){
3343
3343
  case 0:
@@ -3381,7 +3381,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3381
3381
  this.nativeHlsMode = true;
3382
3382
  this.videoSrcProtection = this.config.src;
3383
3383
  this.video.src = this.config.src;
3384
- this.isLiveStream = (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false;
3384
+ this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_this_config_lowLatencyMode = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode !== void 0 ? _this_config_lowLatencyMode : false;
3385
3385
  if (this.config.debugAdTiming) {
3386
3386
  console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
3387
3387
  isLive: this.isLiveStream,
@@ -3432,19 +3432,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3432
3432
  });
3433
3433
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
3434
3434
  return _async_to_generator(function() {
3435
- var _this_config_minSegmentsBeforePlay, _ref, _this_hls_levels, _this_hls, adBehavior, minSegments, _this_video_play;
3435
+ var _this_config_isLiveStream, _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
3436
3436
  return _ts_generator(this, function(_state) {
3437
3437
  switch(_state.label){
3438
3438
  case 0:
3439
- if (this.config.allowNativeHls === false) {
3440
- this.isLiveStream = true;
3441
- } else {
3442
- ;
3443
- ;
3444
- this.isLiveStream = (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
3445
- var _level_details, _level_details1;
3446
- return (level === null || level === void 0 ? void 0 : (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.live) === true || (level === null || level === void 0 ? void 0 : (_level_details1 = level.details) === null || _level_details1 === void 0 ? void 0 : _level_details1.type) === "LIVE";
3447
- })) !== null && _ref !== void 0 ? _ref : false;
3439
+ this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
3440
+ var _level_details, _level_details1;
3441
+ return (level === null || level === void 0 ? void 0 : (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.live) === true || (level === null || level === void 0 ? void 0 : (_level_details1 = level.details) === null || _level_details1 === void 0 ? void 0 : _level_details1.type) === "LIVE";
3442
+ })) !== null && _ref !== void 0 ? _ref : false;
3443
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
3444
+ prerollKey = "synthetic-vod-preroll";
3445
+ if (!this.consumedVmapBreakIds.has(prerollKey)) {
3446
+ this.vmapBreaks = [
3447
+ {
3448
+ id: prerollKey,
3449
+ startTimeMs: 0,
3450
+ vastTagUrl: this.apiVastTagUrl
3451
+ }
3452
+ ];
3453
+ if (this.config.debugAdTiming) {
3454
+ console.log("[StormcloudVideoPlayer] Injected synthetic VOD preroll from apiVastTagUrl");
3455
+ }
3456
+ }
3448
3457
  }
3449
3458
  if (this.config.debugAdTiming) {
3450
3459
  adBehavior = this.shouldContinueLiveStreamDuringAds() ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
@@ -4014,6 +4023,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4014
4023
  _this.onTimeUpdate(_this.video.currentTime);
4015
4024
  };
4016
4025
  this.video.addEventListener("timeupdate", this.timeUpdateHandler);
4026
+ this.endedHandler = function() {
4027
+ _this.onVideoEnded();
4028
+ };
4029
+ this.video.addEventListener("ended", this.endedHandler);
4017
4030
  this.emptiedHandler = function() {
4018
4031
  if (_this.nativeHlsMode && _this.videoSrcProtection && !_this.ima.isAdPlaying()) {
4019
4032
  if (_this.config.debugAdTiming) {
@@ -5325,6 +5338,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5325
5338
  }
5326
5339
  }
5327
5340
  },
5341
+ {
5342
+ key: "isVmapEnabled",
5343
+ value: function isVmapEnabled() {
5344
+ var _this_config_vmapUrl;
5345
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
5346
+ }
5347
+ },
5328
5348
  {
5329
5349
  key: "fetchAdConfiguration",
5330
5350
  value: function fetchAdConfiguration() {
@@ -5333,7 +5353,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5333
5353
  return _ts_generator(this, function(_state) {
5334
5354
  switch(_state.label){
5335
5355
  case 0:
5336
- if (!this.config.vmapUrl) return [
5356
+ if (!this.isVmapEnabled()) return [
5337
5357
  3,
5338
5358
  2
5339
5359
  ];
@@ -5343,7 +5363,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5343
5363
  ];
5344
5364
  case 1:
5345
5365
  _state.sent();
5346
- _state.label = 2;
5366
+ if (this.config.debugAdTiming) {
5367
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
5368
+ }
5369
+ return [
5370
+ 2
5371
+ ];
5347
5372
  case 2:
5348
5373
  vastMode = this.config.vastMode || "default";
5349
5374
  if (this.config.debugAdTiming) {
@@ -5511,7 +5536,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5511
5536
  }
5512
5537
  return [];
5513
5538
  }
5514
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
5539
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
5540
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
5541
+ if (adBreakNodes.length === 0) {
5542
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
5543
+ }
5544
+ if (adBreakNodes.length === 0) {
5545
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
5546
+ return el.localName === "AdBreak";
5547
+ });
5548
+ }
5515
5549
  var parsed = [];
5516
5550
  adBreakNodes.forEach(function(node, index) {
5517
5551
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -5519,8 +5553,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5519
5553
  if (startTimeMs == null) {
5520
5554
  return;
5521
5555
  }
5522
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
5523
- var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
5556
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
5557
+ if (!adTagNode) {
5558
+ var _node_querySelector;
5559
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
5560
+ }
5561
+ if (!adTagNode) {
5562
+ adTagNode = Array.from(node.getElementsByTagName("*")).find(function(el) {
5563
+ return el.localName === "AdTagURI";
5564
+ });
5565
+ }
5566
+ var adTagUrl = _this.resolveVmapAdTagUrl(((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim());
5524
5567
  if (!adTagUrl) {
5525
5568
  return;
5526
5569
  }
@@ -5539,6 +5582,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5539
5582
  return parsed;
5540
5583
  }
5541
5584
  },
5585
+ {
5586
+ key: "resolveVmapAdTagUrl",
5587
+ value: function resolveVmapAdTagUrl(url) {
5588
+ if (!url) {
5589
+ return "";
5590
+ }
5591
+ return url.replace(/\[timestamp\]/gi, String(Date.now())).replace(/\$\{GDPR\}/gi, "0").trim();
5592
+ }
5593
+ },
5542
5594
  {
5543
5595
  key: "parseVmapTimeOffsetToMs",
5544
5596
  value: function parseVmapTimeOffsetToMs(timeOffset) {
@@ -5561,6 +5613,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5561
5613
  var millis = Number(ms.padEnd(3, "0").slice(0, 3));
5562
5614
  return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
5563
5615
  }
5616
+ var msOnly = timeOffset.match(/^(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?$/);
5617
+ if (msOnly) {
5618
+ var _msOnly = _sliced_to_array(msOnly, 4), mm1 = _msOnly[1], ss1 = _msOnly[2], tmp1 = _msOnly[3], ms1 = tmp1 === void 0 ? "0" : tmp1;
5619
+ var minutes1 = Number(mm1);
5620
+ var seconds1 = Number(ss1);
5621
+ var millis1 = Number(ms1.padEnd(3, "0").slice(0, 3));
5622
+ return (minutes1 * 60 + seconds1) * 1e3 + millis1;
5623
+ }
5564
5624
  var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
5565
5625
  if (percent) {
5566
5626
  var ratio = Number(percent[1]) / 100;
@@ -7076,23 +7136,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7076
7136
  key: "onTimeUpdate",
7077
7137
  value: function onTimeUpdate(currentTimeSec) {
7078
7138
  var _this = this;
7139
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7140
+ return;
7141
+ }
7079
7142
  if (this.ima.isAdPlaying() || this.inAdBreak) return;
7080
7143
  var nowMs = currentTimeSec * 1e3;
7081
7144
  var breakToPlay = this.findBreakForTime(nowMs);
7082
7145
  if (breakToPlay) {
7083
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
7146
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
7084
7147
  if (_this.config.debugAdTiming) {
7085
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
7148
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
7086
7149
  }
7087
7150
  });
7088
7151
  }
7089
7152
  }
7090
7153
  },
7091
7154
  {
7092
- key: "handleMidAdJoin",
7093
- value: function handleMidAdJoin(adBreak, nowMs) {
7155
+ key: "onVideoEnded",
7156
+ value: function onVideoEnded() {
7157
+ var _this = this;
7158
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7159
+ return;
7160
+ }
7161
+ if (this.ima.isAdPlaying() || this.inAdBreak) {
7162
+ return;
7163
+ }
7164
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
7165
+ var postroll = this.vmapBreaks.find(function(b) {
7166
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
7167
+ });
7168
+ if (postroll) {
7169
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
7170
+ if (_this.config.debugAdTiming) {
7171
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
7172
+ }
7173
+ });
7174
+ }
7175
+ }
7176
+ },
7177
+ {
7178
+ key: "handleVmapAdBreak",
7179
+ value: function handleVmapAdBreak(adBreak, nowMs) {
7094
7180
  return _async_to_generator(function() {
7095
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
7181
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
7096
7182
  return _ts_generator(this, function(_state) {
7097
7183
  switch(_state.label){
7098
7184
  case 0:
@@ -7110,25 +7196,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7110
7196
  }
7111
7197
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
7112
7198
  endMs = breakStartMs + durationMs;
7113
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7114
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
7199
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
7115
7200
  if (!inWindow) return [
7116
7201
  3,
7117
7202
  4
7118
7203
  ];
7119
7204
  this.consumedVmapBreakIds.add(key);
7120
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
7121
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
7122
- this.apiVastTagUrl
7123
- ] : void 0);
7124
- if (!(tags && tags.length > 0)) return [
7125
- 3,
7126
- 4
7127
- ];
7205
+ tags = this.selectVastTagsForBreak(adBreak);
7206
+ if (!tags || tags.length === 0) {
7207
+ return [
7208
+ 2
7209
+ ];
7210
+ }
7128
7211
  first = tags[0];
7129
7212
  rest = tags.slice(1);
7130
7213
  this.adPodQueue = rest;
7131
7214
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
7215
+ this.showAds = true;
7216
+ this.inAdBreak = true;
7217
+ this.currentAdBreakStartWallClockMs = Date.now();
7218
+ if (!this.video.paused) {
7219
+ this.video.pause();
7220
+ }
7132
7221
  _state.label = 1;
7133
7222
  case 1:
7134
7223
  _state.trys.push([
@@ -7143,10 +7232,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7143
7232
  ];
7144
7233
  case 2:
7145
7234
  _state.sent();
7146
- this.inAdBreak = true;
7147
- this.expectedAdBreakDurationMs = remainingMs;
7148
- this.currentAdBreakStartWallClockMs = Date.now();
7149
- this.scheduleAdStopCountdown(remainingMs);
7150
7235
  return [
7151
7236
  3,
7152
7237
  4
@@ -7154,8 +7239,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7154
7239
  case 3:
7155
7240
  error = _state.sent();
7156
7241
  this.adPodQueue = [];
7242
+ this.inAdBreak = false;
7243
+ this.showAds = false;
7157
7244
  if (this.config.debugAdTiming) {
7158
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
7245
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
7159
7246
  }
7160
7247
  return [
7161
7248
  3,
@@ -7826,16 +7913,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7826
7913
  {
7827
7914
  key: "selectVastTagsForBreak",
7828
7915
  value: function selectVastTagsForBreak(b) {
7916
+ var _this = this;
7829
7917
  if (!b || !b.vastTagUrl) return void 0;
7830
- if (b.vastTagUrl.includes(",")) {
7831
- return b.vastTagUrl.split(",").map(function(s) {
7832
- return s.trim();
7918
+ var resolvedUrl = this.resolveVmapAdTagUrl(b.vastTagUrl);
7919
+ if (resolvedUrl.includes(",")) {
7920
+ return resolvedUrl.split(",").map(function(s) {
7921
+ return _this.resolveVmapAdTagUrl(s.trim());
7833
7922
  }).filter(function(s) {
7834
7923
  return s.length > 0;
7835
7924
  });
7836
7925
  }
7837
7926
  return [
7838
- b.vastTagUrl
7927
+ resolvedUrl
7839
7928
  ];
7840
7929
  }
7841
7930
  },
@@ -7867,9 +7956,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7867
7956
  {
7868
7957
  key: "findBreakForTime",
7869
7958
  value: function findBreakForTime(nowMs) {
7870
- var _this_config_driftToleranceMs;
7871
7959
  var schedule = this.vmapBreaks;
7872
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7873
7960
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7874
7961
  try {
7875
7962
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7881,8 +7968,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7881
7968
  if (breakStartMs == null) {
7882
7969
  continue;
7883
7970
  }
7884
- var end = breakStartMs + (b.durationMs || 0);
7885
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
7971
+ if (b.durationMs) {
7972
+ var end = breakStartMs + b.durationMs;
7973
+ if (nowMs >= breakStartMs && nowMs < end) {
7974
+ return b;
7975
+ }
7976
+ continue;
7977
+ }
7978
+ if (nowMs >= breakStartMs) {
7886
7979
  return b;
7887
7980
  }
7888
7981
  }
@@ -8090,6 +8183,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8090
8183
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
8091
8184
  delete this.timeUpdateHandler;
8092
8185
  }
8186
+ if (this.endedHandler) {
8187
+ this.video.removeEventListener("ended", this.endedHandler);
8188
+ delete this.endedHandler;
8189
+ }
8093
8190
  if (this.emptiedHandler) {
8094
8191
  this.video.removeEventListener("emptied", this.emptiedHandler);
8095
8192
  delete this.emptiedHandler;