stormcloud-video-player 0.3.55 → 0.3.56

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 { S as StormcloudVideoPlayerConfig } from '../types-C23mJ_hh.cjs';
1
+ import { S as StormcloudVideoPlayerConfig } from '../types-Vj55FghO.cjs';
2
2
 
3
3
  declare class StormcloudVideoPlayer {
4
4
  private readonly video;
@@ -16,6 +16,8 @@ declare class StormcloudVideoPlayer {
16
16
  private adPodQueue;
17
17
  private apiVastTagUrl;
18
18
  private apiNumberAds;
19
+ private vmapBreaks;
20
+ private consumedVmapBreakIds;
19
21
  private lastHeartbeatTime;
20
22
  private heartbeatInterval;
21
23
  private currentAdIndex;
@@ -87,6 +89,11 @@ declare class StormcloudVideoPlayer {
87
89
  private initializeTracking;
88
90
  private sendHeartbeatIfNeeded;
89
91
  private fetchAdConfiguration;
92
+ private fetchAndParseVmap;
93
+ private parseVmapToBreaks;
94
+ private parseVmapTimeOffsetToMs;
95
+ private getAdBreakKey;
96
+ private resolveBreakStartMs;
90
97
  getCurrentAdIndex(): number;
91
98
  getTotalAdsInBreak(): number;
92
99
  private generateVastUrlsWithCorrelators;
@@ -3253,6 +3253,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3253
3253
  this.inAdBreak = false;
3254
3254
  this.ptsDriftEmaMs = 0;
3255
3255
  this.adPodQueue = [];
3256
+ this.vmapBreaks = [];
3257
+ this.consumedVmapBreakIds = /* @__PURE__ */ new Set();
3256
3258
  this.lastHeartbeatTime = 0;
3257
3259
  this.currentAdIndex = 0;
3258
3260
  this.totalAdsInBreak = 0;
@@ -4581,6 +4583,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4581
4583
  return _ts_generator(this, function(_state) {
4582
4584
  switch(_state.label){
4583
4585
  case 0:
4586
+ if (!this.config.vmapUrl) return [
4587
+ 3,
4588
+ 2
4589
+ ];
4590
+ return [
4591
+ 4,
4592
+ this.fetchAndParseVmap(this.config.vmapUrl)
4593
+ ];
4594
+ case 1:
4595
+ _state.sent();
4596
+ _state.label = 2;
4597
+ case 2:
4584
4598
  vastMode = this.config.vastMode || "default";
4585
4599
  if (this.config.debugAdTiming) {
4586
4600
  console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
@@ -4626,7 +4640,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4626
4640
  headers: headers
4627
4641
  })
4628
4642
  ];
4629
- case 1:
4643
+ case 3:
4630
4644
  response = _state.sent();
4631
4645
  if (!response.ok) {
4632
4646
  if (this.config.debugAdTiming) {
@@ -4640,7 +4654,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4640
4654
  4,
4641
4655
  response.json()
4642
4656
  ];
4643
- case 2:
4657
+ case 4:
4644
4658
  data = _state.sent();
4645
4659
  imaPayload = (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
4646
4660
  if (imaPayload) {
@@ -4668,6 +4682,171 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4668
4682
  }).call(this);
4669
4683
  }
4670
4684
  },
4685
+ {
4686
+ key: "fetchAndParseVmap",
4687
+ value: function fetchAndParseVmap(vmapUrl) {
4688
+ return _async_to_generator(function() {
4689
+ var response, vmapXml, error;
4690
+ return _ts_generator(this, function(_state) {
4691
+ switch(_state.label){
4692
+ case 0:
4693
+ if (!vmapUrl.trim()) {
4694
+ return [
4695
+ 2
4696
+ ];
4697
+ }
4698
+ _state.label = 1;
4699
+ case 1:
4700
+ _state.trys.push([
4701
+ 1,
4702
+ 4,
4703
+ ,
4704
+ 5
4705
+ ]);
4706
+ return [
4707
+ 4,
4708
+ fetch(vmapUrl)
4709
+ ];
4710
+ case 2:
4711
+ response = _state.sent();
4712
+ if (!response.ok) {
4713
+ throw new Error("Failed to fetch VMAP (".concat(response.status, ")"));
4714
+ }
4715
+ return [
4716
+ 4,
4717
+ response.text()
4718
+ ];
4719
+ case 3:
4720
+ vmapXml = _state.sent();
4721
+ this.vmapBreaks = this.parseVmapToBreaks(vmapXml);
4722
+ this.consumedVmapBreakIds.clear();
4723
+ if (this.config.debugAdTiming) {
4724
+ console.log("[StormcloudVideoPlayer] Loaded ".concat(this.vmapBreaks.length, " VMAP ad break(s) from:"), vmapUrl);
4725
+ }
4726
+ return [
4727
+ 3,
4728
+ 5
4729
+ ];
4730
+ case 4:
4731
+ error = _state.sent();
4732
+ this.vmapBreaks = [];
4733
+ this.consumedVmapBreakIds.clear();
4734
+ if (this.config.debugAdTiming) {
4735
+ console.warn("[StormcloudVideoPlayer] Failed to load VMAP:", error);
4736
+ }
4737
+ return [
4738
+ 3,
4739
+ 5
4740
+ ];
4741
+ case 5:
4742
+ return [
4743
+ 2
4744
+ ];
4745
+ }
4746
+ });
4747
+ }).call(this);
4748
+ }
4749
+ },
4750
+ {
4751
+ key: "parseVmapToBreaks",
4752
+ value: function parseVmapToBreaks(vmapXml) {
4753
+ var _this = this;
4754
+ if (typeof DOMParser === "undefined") {
4755
+ return [];
4756
+ }
4757
+ var doc = new DOMParser().parseFromString(vmapXml, "application/xml");
4758
+ if (doc.querySelector("parsererror")) {
4759
+ if (this.config.debugAdTiming) {
4760
+ console.warn("[StormcloudVideoPlayer] Invalid VMAP XML received");
4761
+ }
4762
+ return [];
4763
+ }
4764
+ var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4765
+ var parsed = [];
4766
+ adBreakNodes.forEach(function(node, index) {
4767
+ var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
4768
+ var startTimeMs = _this.parseVmapTimeOffsetToMs(timeOffsetRaw);
4769
+ if (startTimeMs == null) {
4770
+ return;
4771
+ }
4772
+ var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4773
+ var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4774
+ if (!adTagUrl) {
4775
+ return;
4776
+ }
4777
+ var breakId = node.getAttribute("breakId") || "vmap-break-".concat(index, "-").concat(timeOffsetRaw || "unknown");
4778
+ parsed.push({
4779
+ id: breakId,
4780
+ startTimeMs: startTimeMs,
4781
+ vastTagUrl: adTagUrl
4782
+ });
4783
+ });
4784
+ parsed.sort(function(a, b) {
4785
+ var aStart = a.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : a.startTimeMs;
4786
+ var bStart = b.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : b.startTimeMs;
4787
+ return aStart - bStart;
4788
+ });
4789
+ return parsed;
4790
+ }
4791
+ },
4792
+ {
4793
+ key: "parseVmapTimeOffsetToMs",
4794
+ value: function parseVmapTimeOffsetToMs(timeOffset) {
4795
+ if (!timeOffset) {
4796
+ return void 0;
4797
+ }
4798
+ var normalized = timeOffset.trim().toLowerCase();
4799
+ if (normalized === "start") {
4800
+ return 0;
4801
+ }
4802
+ if (normalized === "end") {
4803
+ return -1;
4804
+ }
4805
+ var hms = timeOffset.match(/^(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/);
4806
+ if (hms) {
4807
+ var _hms = _sliced_to_array(hms, 5), hh = _hms[1], mm = _hms[2], ss = _hms[3], tmp = _hms[4], ms = tmp === void 0 ? "0" : tmp;
4808
+ var hours = Number(hh);
4809
+ var minutes = Number(mm);
4810
+ var seconds = Number(ss);
4811
+ var millis = Number(ms.padEnd(3, "0").slice(0, 3));
4812
+ return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
4813
+ }
4814
+ var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
4815
+ if (percent) {
4816
+ var ratio = Number(percent[1]) / 100;
4817
+ var durationSec = this.video.duration;
4818
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4819
+ return Math.floor(durationSec * 1e3 * ratio);
4820
+ }
4821
+ return void 0;
4822
+ }
4823
+ return void 0;
4824
+ }
4825
+ },
4826
+ {
4827
+ key: "getAdBreakKey",
4828
+ value: function getAdBreakKey(adBreak) {
4829
+ if (adBreak.id) {
4830
+ return adBreak.id;
4831
+ }
4832
+ return "".concat(adBreak.startTimeMs, "-").concat(adBreak.vastTagUrl || "");
4833
+ }
4834
+ },
4835
+ {
4836
+ key: "resolveBreakStartMs",
4837
+ value: function resolveBreakStartMs(adBreak) {
4838
+ if (adBreak.startTimeMs >= 0) {
4839
+ return adBreak.startTimeMs;
4840
+ }
4841
+ if (adBreak.startTimeMs === -1) {
4842
+ var durationSec = this.video.duration;
4843
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4844
+ return Math.floor(durationSec * 1e3);
4845
+ }
4846
+ }
4847
+ return void 0;
4848
+ }
4849
+ },
4671
4850
  {
4672
4851
  key: "getCurrentAdIndex",
4673
4852
  value: function getCurrentAdIndex() {
@@ -4758,10 +4937,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4758
4937
  var scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
4759
4938
  var tags = this.selectVastTagsForBreak(scheduled);
4760
4939
  var baseVastUrl;
4761
- if (this.apiVastTagUrl) {
4762
- baseVastUrl = this.apiVastTagUrl;
4763
- } else if (tags && tags.length > 0 && tags[0]) {
4940
+ if (tags && tags.length > 0 && tags[0]) {
4764
4941
  baseVastUrl = tags[0];
4942
+ } else if (this.apiVastTagUrl) {
4943
+ baseVastUrl = this.apiVastTagUrl;
4765
4944
  } else {
4766
4945
  if (this.config.debugAdTiming) {
4767
4946
  console.warn("[StormcloudVideoPlayer] No VAST URL available for prefetch");
@@ -5211,11 +5390,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5211
5390
  switch(_state.label){
5212
5391
  case 0:
5213
5392
  scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
5393
+ if (scheduled) {
5394
+ this.consumedVmapBreakIds.add(this.getAdBreakKey(scheduled));
5395
+ }
5214
5396
  tags = this.selectVastTagsForBreak(scheduled);
5215
- if (this.apiVastTagUrl) {
5216
- baseVastUrl = this.apiVastTagUrl;
5217
- } else if (tags && tags.length > 0 && tags[0]) {
5397
+ if (tags && tags.length > 0 && tags[0]) {
5218
5398
  baseVastUrl = tags[0];
5399
+ } else if (this.apiVastTagUrl) {
5400
+ baseVastUrl = this.apiVastTagUrl;
5219
5401
  } else {
5220
5402
  this.clearPendingAdBreak();
5221
5403
  return [
@@ -6094,15 +6276,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6094
6276
  {
6095
6277
  key: "findCurrentOrNextBreak",
6096
6278
  value: function findCurrentOrNextBreak(nowMs) {
6097
- var schedule = [];
6279
+ var schedule = this.vmapBreaks;
6098
6280
  var candidate;
6099
6281
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6100
6282
  try {
6101
6283
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6102
6284
  var b = _step.value;
6103
- var _this_config_driftToleranceMs;
6285
+ var _this_config_driftToleranceMs, _this_resolveBreakStartMs;
6286
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
6287
+ continue;
6288
+ }
6289
+ var breakStartMs = this.resolveBreakStartMs(b);
6290
+ if (breakStartMs == null) {
6291
+ continue;
6292
+ }
6104
6293
  var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6105
- if (b.startTimeMs <= nowMs + tol && (candidate == null || b.startTimeMs > (candidate.startTimeMs || 0))) {
6294
+ if (breakStartMs <= nowMs + tol && (candidate == null || breakStartMs > ((_this_resolveBreakStartMs = this.resolveBreakStartMs(candidate)) !== null && _this_resolveBreakStartMs !== void 0 ? _this_resolveBreakStartMs : 0))) {
6106
6295
  candidate = b;
6107
6296
  }
6108
6297
  }
@@ -6126,11 +6315,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6126
6315
  {
6127
6316
  key: "onTimeUpdate",
6128
6317
  value: function onTimeUpdate(currentTimeSec) {
6129
- if (this.ima.isAdPlaying()) return;
6318
+ var _this = this;
6319
+ if (this.ima.isAdPlaying() || this.inAdBreak) return;
6130
6320
  var nowMs = currentTimeSec * 1e3;
6131
6321
  var breakToPlay = this.findBreakForTime(nowMs);
6132
6322
  if (breakToPlay) {
6133
- this.handleMidAdJoin(breakToPlay, nowMs);
6323
+ void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6324
+ if (_this.config.debugAdTiming) {
6325
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6326
+ }
6327
+ });
6134
6328
  }
6135
6329
  }
6136
6330
  },
@@ -6138,40 +6332,76 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6138
6332
  key: "handleMidAdJoin",
6139
6333
  value: function handleMidAdJoin(adBreak, nowMs) {
6140
6334
  return _async_to_generator(function() {
6141
- var _adBreak_durationMs, durationMs, endMs, remainingMs, tags, first, rest;
6335
+ var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6142
6336
  return _ts_generator(this, function(_state) {
6143
6337
  switch(_state.label){
6144
6338
  case 0:
6339
+ key = this.getAdBreakKey(adBreak);
6340
+ if (this.consumedVmapBreakIds.has(key)) {
6341
+ return [
6342
+ 2
6343
+ ];
6344
+ }
6345
+ breakStartMs = this.resolveBreakStartMs(adBreak);
6346
+ if (breakStartMs == null) {
6347
+ return [
6348
+ 2
6349
+ ];
6350
+ }
6145
6351
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6146
- endMs = adBreak.startTimeMs + durationMs;
6147
- if (!(durationMs > 0 && nowMs > adBreak.startTimeMs && nowMs < endMs)) return [
6352
+ endMs = breakStartMs + durationMs;
6353
+ tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6354
+ inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6355
+ if (!inWindow) return [
6148
6356
  3,
6149
- 2
6357
+ 4
6150
6358
  ];
6151
- remainingMs = endMs - nowMs;
6359
+ this.consumedVmapBreakIds.add(key);
6360
+ remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6152
6361
  tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6153
6362
  this.apiVastTagUrl
6154
6363
  ] : void 0);
6155
6364
  if (!(tags && tags.length > 0)) return [
6156
6365
  3,
6157
- 2
6366
+ 4
6158
6367
  ];
6159
6368
  first = tags[0];
6160
6369
  rest = tags.slice(1);
6161
6370
  this.adPodQueue = rest;
6162
6371
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
6372
+ _state.label = 1;
6373
+ case 1:
6374
+ _state.trys.push([
6375
+ 1,
6376
+ 3,
6377
+ ,
6378
+ 4
6379
+ ]);
6163
6380
  return [
6164
6381
  4,
6165
6382
  this.playSingleAd(first)
6166
6383
  ];
6167
- case 1:
6384
+ case 2:
6168
6385
  _state.sent();
6169
6386
  this.inAdBreak = true;
6170
6387
  this.expectedAdBreakDurationMs = remainingMs;
6171
6388
  this.currentAdBreakStartWallClockMs = Date.now();
6172
6389
  this.scheduleAdStopCountdown(remainingMs);
6173
- _state.label = 2;
6174
- case 2:
6390
+ return [
6391
+ 3,
6392
+ 4
6393
+ ];
6394
+ case 3:
6395
+ error = _state.sent();
6396
+ this.adPodQueue = [];
6397
+ if (this.config.debugAdTiming) {
6398
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6399
+ }
6400
+ return [
6401
+ 3,
6402
+ 4
6403
+ ];
6404
+ case 4:
6175
6405
  return [
6176
6406
  2
6177
6407
  ];
@@ -6877,13 +7107,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6877
7107
  {
6878
7108
  key: "findBreakForTime",
6879
7109
  value: function findBreakForTime(nowMs) {
6880
- var schedule = [];
7110
+ var _this_config_driftToleranceMs;
7111
+ var schedule = this.vmapBreaks;
7112
+ var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6881
7113
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6882
7114
  try {
6883
7115
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6884
7116
  var b = _step.value;
6885
- var end = (b.startTimeMs || 0) + (b.durationMs || 0);
6886
- if (nowMs >= (b.startTimeMs || 0) && (b.durationMs ? nowMs < end : true)) {
7117
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
7118
+ continue;
7119
+ }
7120
+ var breakStartMs = this.resolveBreakStartMs(b);
7121
+ if (breakStartMs == null) {
7122
+ continue;
7123
+ }
7124
+ var end = breakStartMs + (b.durationMs || 0);
7125
+ if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
6887
7126
  return b;
6888
7127
  }
6889
7128
  }