stormcloud-video-player 0.3.62 → 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.
@@ -3440,7 +3440,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3440
3440
  var _level_details, _level_details1;
3441
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
3442
  })) !== null && _ref !== void 0 ? _ref : false;
3443
- if (!this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
3443
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
3444
3444
  prerollKey = "synthetic-vod-preroll";
3445
3445
  if (!this.consumedVmapBreakIds.has(prerollKey)) {
3446
3446
  this.vmapBreaks = [
@@ -4023,6 +4023,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4023
4023
  _this.onTimeUpdate(_this.video.currentTime);
4024
4024
  };
4025
4025
  this.video.addEventListener("timeupdate", this.timeUpdateHandler);
4026
+ this.endedHandler = function() {
4027
+ _this.onVideoEnded();
4028
+ };
4029
+ this.video.addEventListener("ended", this.endedHandler);
4026
4030
  this.emptiedHandler = function() {
4027
4031
  if (_this.nativeHlsMode && _this.videoSrcProtection && !_this.ima.isAdPlaying()) {
4028
4032
  if (_this.config.debugAdTiming) {
@@ -5334,6 +5338,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5334
5338
  }
5335
5339
  }
5336
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
+ },
5337
5348
  {
5338
5349
  key: "fetchAdConfiguration",
5339
5350
  value: function fetchAdConfiguration() {
@@ -5342,7 +5353,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5342
5353
  return _ts_generator(this, function(_state) {
5343
5354
  switch(_state.label){
5344
5355
  case 0:
5345
- if (!this.config.vmapUrl) return [
5356
+ if (!this.isVmapEnabled()) return [
5346
5357
  3,
5347
5358
  2
5348
5359
  ];
@@ -5352,7 +5363,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5352
5363
  ];
5353
5364
  case 1:
5354
5365
  _state.sent();
5355
- _state.label = 2;
5366
+ if (this.config.debugAdTiming) {
5367
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
5368
+ }
5369
+ return [
5370
+ 2
5371
+ ];
5356
5372
  case 2:
5357
5373
  vastMode = this.config.vastMode || "default";
5358
5374
  if (this.config.debugAdTiming) {
@@ -5520,7 +5536,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5520
5536
  }
5521
5537
  return [];
5522
5538
  }
5523
- 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
+ }
5524
5549
  var parsed = [];
5525
5550
  adBreakNodes.forEach(function(node, index) {
5526
5551
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -5528,8 +5553,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5528
5553
  if (startTimeMs == null) {
5529
5554
  return;
5530
5555
  }
5531
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
5532
- 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());
5533
5567
  if (!adTagUrl) {
5534
5568
  return;
5535
5569
  }
@@ -5548,6 +5582,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5548
5582
  return parsed;
5549
5583
  }
5550
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
+ },
5551
5594
  {
5552
5595
  key: "parseVmapTimeOffsetToMs",
5553
5596
  value: function parseVmapTimeOffsetToMs(timeOffset) {
@@ -5570,6 +5613,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5570
5613
  var millis = Number(ms.padEnd(3, "0").slice(0, 3));
5571
5614
  return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
5572
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
+ }
5573
5624
  var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
5574
5625
  if (percent) {
5575
5626
  var ratio = Number(percent[1]) / 100;
@@ -7085,23 +7136,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7085
7136
  key: "onTimeUpdate",
7086
7137
  value: function onTimeUpdate(currentTimeSec) {
7087
7138
  var _this = this;
7139
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
7140
+ return;
7141
+ }
7088
7142
  if (this.ima.isAdPlaying() || this.inAdBreak) return;
7089
7143
  var nowMs = currentTimeSec * 1e3;
7090
7144
  var breakToPlay = this.findBreakForTime(nowMs);
7091
7145
  if (breakToPlay) {
7092
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
7146
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
7147
+ if (_this.config.debugAdTiming) {
7148
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
7149
+ }
7150
+ });
7151
+ }
7152
+ }
7153
+ },
7154
+ {
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) {
7093
7170
  if (_this.config.debugAdTiming) {
7094
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
7171
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
7095
7172
  }
7096
7173
  });
7097
7174
  }
7098
7175
  }
7099
7176
  },
7100
7177
  {
7101
- key: "handleMidAdJoin",
7102
- value: function handleMidAdJoin(adBreak, nowMs) {
7178
+ key: "handleVmapAdBreak",
7179
+ value: function handleVmapAdBreak(adBreak, nowMs) {
7103
7180
  return _async_to_generator(function() {
7104
- 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;
7105
7182
  return _ts_generator(this, function(_state) {
7106
7183
  switch(_state.label){
7107
7184
  case 0:
@@ -7119,25 +7196,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7119
7196
  }
7120
7197
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
7121
7198
  endMs = breakStartMs + durationMs;
7122
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7123
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
7199
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
7124
7200
  if (!inWindow) return [
7125
7201
  3,
7126
7202
  4
7127
7203
  ];
7128
7204
  this.consumedVmapBreakIds.add(key);
7129
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
7130
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
7131
- this.apiVastTagUrl
7132
- ] : void 0);
7133
- if (!(tags && tags.length > 0)) return [
7134
- 3,
7135
- 4
7136
- ];
7205
+ tags = this.selectVastTagsForBreak(adBreak);
7206
+ if (!tags || tags.length === 0) {
7207
+ return [
7208
+ 2
7209
+ ];
7210
+ }
7137
7211
  first = tags[0];
7138
7212
  rest = tags.slice(1);
7139
7213
  this.adPodQueue = rest;
7140
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
+ }
7141
7221
  _state.label = 1;
7142
7222
  case 1:
7143
7223
  _state.trys.push([
@@ -7152,10 +7232,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7152
7232
  ];
7153
7233
  case 2:
7154
7234
  _state.sent();
7155
- this.inAdBreak = true;
7156
- this.expectedAdBreakDurationMs = remainingMs;
7157
- this.currentAdBreakStartWallClockMs = Date.now();
7158
- this.scheduleAdStopCountdown(remainingMs);
7159
7235
  return [
7160
7236
  3,
7161
7237
  4
@@ -7163,8 +7239,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7163
7239
  case 3:
7164
7240
  error = _state.sent();
7165
7241
  this.adPodQueue = [];
7242
+ this.inAdBreak = false;
7243
+ this.showAds = false;
7166
7244
  if (this.config.debugAdTiming) {
7167
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
7245
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
7168
7246
  }
7169
7247
  return [
7170
7248
  3,
@@ -7835,16 +7913,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7835
7913
  {
7836
7914
  key: "selectVastTagsForBreak",
7837
7915
  value: function selectVastTagsForBreak(b) {
7916
+ var _this = this;
7838
7917
  if (!b || !b.vastTagUrl) return void 0;
7839
- if (b.vastTagUrl.includes(",")) {
7840
- return b.vastTagUrl.split(",").map(function(s) {
7841
- 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());
7842
7922
  }).filter(function(s) {
7843
7923
  return s.length > 0;
7844
7924
  });
7845
7925
  }
7846
7926
  return [
7847
- b.vastTagUrl
7927
+ resolvedUrl
7848
7928
  ];
7849
7929
  }
7850
7930
  },
@@ -7876,9 +7956,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7876
7956
  {
7877
7957
  key: "findBreakForTime",
7878
7958
  value: function findBreakForTime(nowMs) {
7879
- var _this_config_driftToleranceMs;
7880
7959
  var schedule = this.vmapBreaks;
7881
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7882
7960
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7883
7961
  try {
7884
7962
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7890,9 +7968,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7890
7968
  if (breakStartMs == null) {
7891
7969
  continue;
7892
7970
  }
7893
- var end = breakStartMs + (b.durationMs || 0);
7894
- var effectiveTol = breakStartMs === 0 ? Math.max(tol, 3e4) : tol;
7895
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + effectiveTol)) {
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) {
7896
7979
  return b;
7897
7980
  }
7898
7981
  }
@@ -8100,6 +8183,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8100
8183
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
8101
8184
  delete this.timeUpdateHandler;
8102
8185
  }
8186
+ if (this.endedHandler) {
8187
+ this.video.removeEventListener("ended", this.endedHandler);
8188
+ delete this.endedHandler;
8189
+ }
8103
8190
  if (this.emptiedHandler) {
8104
8191
  this.video.removeEventListener("emptied", this.emptiedHandler);
8105
8192
  delete this.emptiedHandler;