stormcloud-video-player 0.2.23 → 0.2.25
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/dist/stormcloud-vp.min.js +2 -2
- package/lib/index.cjs +299 -52
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +11 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.js +299 -52
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +299 -52
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +8 -1
- package/lib/players/HlsPlayer.cjs +299 -52
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +299 -52
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs +87 -10
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.d.cts +1 -1
- package/lib/sdk/ima.cjs +93 -21
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/sdk/ima.d.cts +1 -1
- package/lib/{types-D1xfSdLP.d.cts → types-9_2sbHCg.d.cts} +4 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +299 -52
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/utils/tracking.d.cts +1 -1
- package/package.json +1 -1
|
@@ -200,6 +200,8 @@ function createImaController(video, options) {
|
|
|
200
200
|
let adPlaying = false;
|
|
201
201
|
let originalMutedState = false;
|
|
202
202
|
const listeners = /* @__PURE__ */ new Map();
|
|
203
|
+
const preloadedVast = /* @__PURE__ */ new Map();
|
|
204
|
+
const preloadingVast = /* @__PURE__ */ new Map();
|
|
203
205
|
function setAdPlayingFlag(isPlaying) {
|
|
204
206
|
if (isPlaying) {
|
|
205
207
|
video.dataset.stormcloudAdPlaying = "true";
|
|
@@ -290,7 +292,15 @@ function createImaController(video, options) {
|
|
|
290
292
|
let adsLoadedReject;
|
|
291
293
|
function makeAdsRequest(google, vastTagUrl) {
|
|
292
294
|
const adsRequest = new google.ima.AdsRequest();
|
|
293
|
-
|
|
295
|
+
const preloadedResponse = preloadedVast.get(vastTagUrl);
|
|
296
|
+
if (preloadedResponse) {
|
|
297
|
+
adsRequest.adsResponse = preloadedResponse;
|
|
298
|
+
console.log(
|
|
299
|
+
"[IMA] Using preloaded VAST response for immediate ad request"
|
|
300
|
+
);
|
|
301
|
+
} else {
|
|
302
|
+
adsRequest.adTagUrl = vastTagUrl;
|
|
303
|
+
}
|
|
294
304
|
const videoWidth = video.offsetWidth || video.clientWidth || 640;
|
|
295
305
|
const videoHeight = video.offsetHeight || video.clientHeight || 360;
|
|
296
306
|
adsRequest.linearAdSlotWidth = videoWidth;
|
|
@@ -300,6 +310,36 @@ function createImaController(video, options) {
|
|
|
300
310
|
adsRequest.vastLoadTimeout = 5e3;
|
|
301
311
|
console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
|
|
302
312
|
adsLoader.requestAds(adsRequest);
|
|
313
|
+
if (preloadedResponse) {
|
|
314
|
+
preloadedVast.delete(vastTagUrl);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function ensurePlaceholderContainer() {
|
|
318
|
+
var _a;
|
|
319
|
+
if (adContainerEl) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const container = document.createElement("div");
|
|
323
|
+
container.style.position = "absolute";
|
|
324
|
+
container.style.left = "0";
|
|
325
|
+
container.style.top = "0";
|
|
326
|
+
container.style.right = "0";
|
|
327
|
+
container.style.bottom = "0";
|
|
328
|
+
container.style.display = "none";
|
|
329
|
+
container.style.alignItems = "center";
|
|
330
|
+
container.style.justifyContent = "center";
|
|
331
|
+
container.style.pointerEvents = "none";
|
|
332
|
+
container.style.zIndex = "10";
|
|
333
|
+
container.style.backgroundColor = "#000";
|
|
334
|
+
(_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
335
|
+
adContainerEl = container;
|
|
336
|
+
}
|
|
337
|
+
async function fetchVastDocument(vastTagUrl) {
|
|
338
|
+
const response = await fetch(vastTagUrl, { mode: "cors" });
|
|
339
|
+
if (!response.ok) {
|
|
340
|
+
throw new Error(`Failed to preload VAST: ${response.status}`);
|
|
341
|
+
}
|
|
342
|
+
return response.text();
|
|
303
343
|
}
|
|
304
344
|
function destroyAdsManager() {
|
|
305
345
|
if (adsManager) {
|
|
@@ -315,29 +355,16 @@ function createImaController(video, options) {
|
|
|
315
355
|
return {
|
|
316
356
|
initialize() {
|
|
317
357
|
ensureImaLoaded().then(() => {
|
|
318
|
-
var _a
|
|
358
|
+
var _a;
|
|
319
359
|
const google = window.google;
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
container.style.position = "absolute";
|
|
323
|
-
container.style.left = "0";
|
|
324
|
-
container.style.top = "0";
|
|
325
|
-
container.style.right = "0";
|
|
326
|
-
container.style.bottom = "0";
|
|
327
|
-
container.style.display = "none";
|
|
328
|
-
container.style.alignItems = "center";
|
|
329
|
-
container.style.justifyContent = "center";
|
|
330
|
-
container.style.pointerEvents = "none";
|
|
331
|
-
container.style.zIndex = "10";
|
|
332
|
-
container.style.backgroundColor = "#000";
|
|
333
|
-
(_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
334
|
-
adContainerEl = container;
|
|
360
|
+
ensurePlaceholderContainer();
|
|
361
|
+
if (!adDisplayContainer && adContainerEl) {
|
|
335
362
|
adDisplayContainer = new google.ima.AdDisplayContainer(
|
|
336
|
-
|
|
363
|
+
adContainerEl,
|
|
337
364
|
video
|
|
338
365
|
);
|
|
339
366
|
try {
|
|
340
|
-
(
|
|
367
|
+
(_a = adDisplayContainer.initialize) == null ? void 0 : _a.call(adDisplayContainer);
|
|
341
368
|
} catch {
|
|
342
369
|
}
|
|
343
370
|
}
|
|
@@ -439,9 +466,13 @@ function createImaController(video, options) {
|
|
|
439
466
|
adsLoader.addEventListener(
|
|
440
467
|
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
|
|
441
468
|
(evt) => {
|
|
442
|
-
console.log(
|
|
469
|
+
console.log(
|
|
470
|
+
"[IMA] Ads manager loaded - enabling preloading for continuous playback"
|
|
471
|
+
);
|
|
443
472
|
try {
|
|
444
|
-
|
|
473
|
+
const adsRenderingSettings = new google.ima.AdsRenderingSettings();
|
|
474
|
+
adsRenderingSettings.enablePreloading = true;
|
|
475
|
+
adsManager = evt.getAdsManager(video, adsRenderingSettings);
|
|
445
476
|
const AdEvent = google.ima.AdEvent.Type;
|
|
446
477
|
const AdErrorEvent = google.ima.AdErrorEvent.Type;
|
|
447
478
|
adsManager.addEventListener(
|
|
@@ -637,6 +668,32 @@ function createImaController(video, options) {
|
|
|
637
668
|
return Promise.reject(error);
|
|
638
669
|
}
|
|
639
670
|
},
|
|
671
|
+
async preloadAds(vastTagUrl) {
|
|
672
|
+
if (!vastTagUrl || vastTagUrl.trim() === "") {
|
|
673
|
+
return Promise.resolve();
|
|
674
|
+
}
|
|
675
|
+
if (preloadedVast.has(vastTagUrl)) {
|
|
676
|
+
return Promise.resolve();
|
|
677
|
+
}
|
|
678
|
+
const inflight = preloadingVast.get(vastTagUrl);
|
|
679
|
+
if (inflight) {
|
|
680
|
+
return inflight;
|
|
681
|
+
}
|
|
682
|
+
const preloadPromise = fetchVastDocument(vastTagUrl).then((xml) => {
|
|
683
|
+
preloadedVast.set(vastTagUrl, xml);
|
|
684
|
+
console.log("[IMA] Cached VAST response for preloading:", vastTagUrl);
|
|
685
|
+
}).catch((error) => {
|
|
686
|
+
console.warn("[IMA] Failed to preload VAST response:", error);
|
|
687
|
+
preloadedVast.delete(vastTagUrl);
|
|
688
|
+
}).finally(() => {
|
|
689
|
+
preloadingVast.delete(vastTagUrl);
|
|
690
|
+
});
|
|
691
|
+
preloadingVast.set(vastTagUrl, preloadPromise);
|
|
692
|
+
return preloadPromise;
|
|
693
|
+
},
|
|
694
|
+
hasPreloadedAd(vastTagUrl) {
|
|
695
|
+
return preloadedVast.has(vastTagUrl);
|
|
696
|
+
},
|
|
640
697
|
async play() {
|
|
641
698
|
var _a, _b;
|
|
642
699
|
if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
|
|
@@ -712,6 +769,8 @@ function createImaController(video, options) {
|
|
|
712
769
|
adContainerEl = void 0;
|
|
713
770
|
adDisplayContainer = void 0;
|
|
714
771
|
adsLoader = void 0;
|
|
772
|
+
preloadedVast.clear();
|
|
773
|
+
preloadingVast.clear();
|
|
715
774
|
},
|
|
716
775
|
isAdPlaying() {
|
|
717
776
|
return adPlaying;
|
|
@@ -767,6 +826,19 @@ function createImaController(video, options) {
|
|
|
767
826
|
}
|
|
768
827
|
}
|
|
769
828
|
return 1;
|
|
829
|
+
},
|
|
830
|
+
showPlaceholder() {
|
|
831
|
+
ensurePlaceholderContainer();
|
|
832
|
+
if (adContainerEl) {
|
|
833
|
+
adContainerEl.style.display = "flex";
|
|
834
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
hidePlaceholder() {
|
|
838
|
+
if (adContainerEl) {
|
|
839
|
+
adContainerEl.style.display = "none";
|
|
840
|
+
adContainerEl.style.pointerEvents = "none";
|
|
841
|
+
}
|
|
770
842
|
}
|
|
771
843
|
};
|
|
772
844
|
}
|
|
@@ -784,6 +856,8 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
784
856
|
let adContainerEl;
|
|
785
857
|
let currentAd;
|
|
786
858
|
let sessionId;
|
|
859
|
+
const preloadedAds = /* @__PURE__ */ new Map();
|
|
860
|
+
const preloadingAds = /* @__PURE__ */ new Map();
|
|
787
861
|
let trackingFired = {
|
|
788
862
|
impression: false,
|
|
789
863
|
start: false,
|
|
@@ -1013,6 +1087,19 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1013
1087
|
return null;
|
|
1014
1088
|
}
|
|
1015
1089
|
}
|
|
1090
|
+
async function fetchAndParseVastAd(vastTagUrl) {
|
|
1091
|
+
const response = await fetch(vastTagUrl);
|
|
1092
|
+
if (!response.ok) {
|
|
1093
|
+
throw new Error(`Failed to fetch VAST: ${response.statusText}`);
|
|
1094
|
+
}
|
|
1095
|
+
const vastXml = await response.text();
|
|
1096
|
+
console.log("[HlsAdPlayer] VAST XML received");
|
|
1097
|
+
console.log(
|
|
1098
|
+
"[HlsAdPlayer] VAST XML content (first 2000 chars):",
|
|
1099
|
+
vastXml.substring(0, 2e3)
|
|
1100
|
+
);
|
|
1101
|
+
return parseVastXml(vastXml);
|
|
1102
|
+
}
|
|
1016
1103
|
function createAdVideoElement() {
|
|
1017
1104
|
const video = document.createElement("video");
|
|
1018
1105
|
video.style.position = "absolute";
|
|
@@ -1164,17 +1251,17 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1164
1251
|
}
|
|
1165
1252
|
try {
|
|
1166
1253
|
sessionId = generateSessionId();
|
|
1167
|
-
|
|
1168
|
-
if (
|
|
1169
|
-
|
|
1254
|
+
let ad;
|
|
1255
|
+
if (preloadedAds.has(vastTagUrl)) {
|
|
1256
|
+
ad = preloadedAds.get(vastTagUrl);
|
|
1257
|
+
preloadedAds.delete(vastTagUrl);
|
|
1258
|
+
console.log(
|
|
1259
|
+
"[HlsAdPlayer] Using preloaded VAST response:",
|
|
1260
|
+
vastTagUrl
|
|
1261
|
+
);
|
|
1262
|
+
} else {
|
|
1263
|
+
ad = await fetchAndParseVastAd(vastTagUrl);
|
|
1170
1264
|
}
|
|
1171
|
-
const vastXml = await response.text();
|
|
1172
|
-
console.log("[HlsAdPlayer] VAST XML received");
|
|
1173
|
-
console.log(
|
|
1174
|
-
"[HlsAdPlayer] VAST XML content (first 2000 chars):",
|
|
1175
|
-
vastXml.substring(0, 2e3)
|
|
1176
|
-
);
|
|
1177
|
-
const ad = parseVastXml(vastXml);
|
|
1178
1265
|
if (!ad) {
|
|
1179
1266
|
console.warn("[HlsAdPlayer] No ads available from VAST response");
|
|
1180
1267
|
emit("ad_error");
|
|
@@ -1193,6 +1280,37 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1193
1280
|
return Promise.reject(error);
|
|
1194
1281
|
}
|
|
1195
1282
|
},
|
|
1283
|
+
async preloadAds(vastTagUrl) {
|
|
1284
|
+
if (!vastTagUrl || vastTagUrl.trim() === "") {
|
|
1285
|
+
return Promise.resolve();
|
|
1286
|
+
}
|
|
1287
|
+
if (preloadedAds.has(vastTagUrl)) {
|
|
1288
|
+
return Promise.resolve();
|
|
1289
|
+
}
|
|
1290
|
+
const inflight = preloadingAds.get(vastTagUrl);
|
|
1291
|
+
if (inflight) {
|
|
1292
|
+
return inflight;
|
|
1293
|
+
}
|
|
1294
|
+
const preloadPromise = fetchAndParseVastAd(vastTagUrl).then((ad) => {
|
|
1295
|
+
if (ad) {
|
|
1296
|
+
preloadedAds.set(vastTagUrl, ad);
|
|
1297
|
+
console.log(
|
|
1298
|
+
"[HlsAdPlayer] Cached VAST response for preloading:",
|
|
1299
|
+
vastTagUrl
|
|
1300
|
+
);
|
|
1301
|
+
}
|
|
1302
|
+
}).catch((error) => {
|
|
1303
|
+
console.warn("[HlsAdPlayer] Failed to preload VAST response:", error);
|
|
1304
|
+
preloadedAds.delete(vastTagUrl);
|
|
1305
|
+
}).finally(() => {
|
|
1306
|
+
preloadingAds.delete(vastTagUrl);
|
|
1307
|
+
});
|
|
1308
|
+
preloadingAds.set(vastTagUrl, preloadPromise);
|
|
1309
|
+
return preloadPromise;
|
|
1310
|
+
},
|
|
1311
|
+
hasPreloadedAd(vastTagUrl) {
|
|
1312
|
+
return preloadedAds.has(vastTagUrl);
|
|
1313
|
+
},
|
|
1196
1314
|
async play() {
|
|
1197
1315
|
if (!currentAd) {
|
|
1198
1316
|
console.warn(
|
|
@@ -1323,6 +1441,8 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1323
1441
|
adContainerEl = void 0;
|
|
1324
1442
|
currentAd = void 0;
|
|
1325
1443
|
listeners.clear();
|
|
1444
|
+
preloadedAds.clear();
|
|
1445
|
+
preloadingAds.clear();
|
|
1326
1446
|
},
|
|
1327
1447
|
isAdPlaying() {
|
|
1328
1448
|
return adPlaying;
|
|
@@ -1365,6 +1485,35 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1365
1485
|
return adVideoElement.volume;
|
|
1366
1486
|
}
|
|
1367
1487
|
return 1;
|
|
1488
|
+
},
|
|
1489
|
+
showPlaceholder() {
|
|
1490
|
+
var _a;
|
|
1491
|
+
if (!adContainerEl) {
|
|
1492
|
+
const container = document.createElement("div");
|
|
1493
|
+
container.style.position = "absolute";
|
|
1494
|
+
container.style.left = "0";
|
|
1495
|
+
container.style.top = "0";
|
|
1496
|
+
container.style.right = "0";
|
|
1497
|
+
container.style.bottom = "0";
|
|
1498
|
+
container.style.display = "none";
|
|
1499
|
+
container.style.alignItems = "center";
|
|
1500
|
+
container.style.justifyContent = "center";
|
|
1501
|
+
container.style.pointerEvents = "none";
|
|
1502
|
+
container.style.zIndex = "10";
|
|
1503
|
+
container.style.backgroundColor = "#000";
|
|
1504
|
+
(_a = contentVideo.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
1505
|
+
adContainerEl = container;
|
|
1506
|
+
}
|
|
1507
|
+
if (adContainerEl) {
|
|
1508
|
+
adContainerEl.style.display = "flex";
|
|
1509
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
1510
|
+
}
|
|
1511
|
+
},
|
|
1512
|
+
hidePlaceholder() {
|
|
1513
|
+
if (adContainerEl) {
|
|
1514
|
+
adContainerEl.style.display = "none";
|
|
1515
|
+
adContainerEl.style.pointerEvents = "none";
|
|
1516
|
+
}
|
|
1368
1517
|
}
|
|
1369
1518
|
};
|
|
1370
1519
|
}
|
|
@@ -1845,6 +1994,8 @@ var StormcloudVideoPlayer = class {
|
|
|
1845
1994
|
this.bufferedSegmentsCount = 0;
|
|
1846
1995
|
this.shouldAutoplayAfterBuffering = false;
|
|
1847
1996
|
this.hasInitialBufferCompleted = false;
|
|
1997
|
+
this.adPodAllUrls = [];
|
|
1998
|
+
this.preloadingAdUrls = /* @__PURE__ */ new Set();
|
|
1848
1999
|
initializePolyfills();
|
|
1849
2000
|
const browserOverrides = getBrowserConfigOverrides();
|
|
1850
2001
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2145,6 +2296,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2145
2296
|
console.log("[StormcloudVideoPlayer] IMA content_pause event received");
|
|
2146
2297
|
}
|
|
2147
2298
|
this.clearAdFailsafeTimer();
|
|
2299
|
+
this.enforceAdHoldState();
|
|
2148
2300
|
});
|
|
2149
2301
|
this.ima.on("content_resume", () => {
|
|
2150
2302
|
if (this.config.debugAdTiming) {
|
|
@@ -2169,12 +2321,10 @@ var StormcloudVideoPlayer = class {
|
|
|
2169
2321
|
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
2170
2322
|
const next = this.adPodQueue.shift();
|
|
2171
2323
|
this.currentAdIndex++;
|
|
2172
|
-
this.
|
|
2173
|
-
this.video.muted = true;
|
|
2174
|
-
this.video.volume = 0;
|
|
2324
|
+
this.enforceAdHoldState();
|
|
2175
2325
|
if (this.config.debugAdTiming) {
|
|
2176
2326
|
console.log(
|
|
2177
|
-
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) -
|
|
2327
|
+
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - IMMEDIATELY starting next ad`
|
|
2178
2328
|
);
|
|
2179
2329
|
}
|
|
2180
2330
|
this.playSingleAd(next).catch(() => {
|
|
@@ -2759,25 +2909,21 @@ var StormcloudVideoPlayer = class {
|
|
|
2759
2909
|
this.video.currentTime * 1e3
|
|
2760
2910
|
);
|
|
2761
2911
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
2762
|
-
let
|
|
2912
|
+
let vastTagUrls = [];
|
|
2763
2913
|
if (this.apiVastTagUrl) {
|
|
2764
|
-
|
|
2765
|
-
this.adPodQueue = [];
|
|
2766
|
-
this.currentAdIndex = 0;
|
|
2767
|
-
this.totalAdsInBreak = 1;
|
|
2914
|
+
vastTagUrls = [this.apiVastTagUrl];
|
|
2768
2915
|
if (this.config.debugAdTiming) {
|
|
2769
|
-
console.log(
|
|
2916
|
+
console.log(
|
|
2917
|
+
"[StormcloudVideoPlayer] Using VAST endpoint:",
|
|
2918
|
+
this.apiVastTagUrl
|
|
2919
|
+
);
|
|
2770
2920
|
}
|
|
2771
2921
|
} else if (tags && tags.length > 0) {
|
|
2772
|
-
|
|
2773
|
-
const rest = tags.slice(1);
|
|
2774
|
-
this.adPodQueue = rest;
|
|
2775
|
-
this.currentAdIndex = 0;
|
|
2776
|
-
this.totalAdsInBreak = tags.length;
|
|
2922
|
+
vastTagUrls = tags;
|
|
2777
2923
|
if (this.config.debugAdTiming) {
|
|
2778
2924
|
console.log(
|
|
2779
|
-
"[StormcloudVideoPlayer] Using scheduled VAST
|
|
2780
|
-
|
|
2925
|
+
"[StormcloudVideoPlayer] Using scheduled VAST tags (count: " + tags.length + "):",
|
|
2926
|
+
tags
|
|
2781
2927
|
);
|
|
2782
2928
|
}
|
|
2783
2929
|
} else {
|
|
@@ -2786,16 +2932,28 @@ var StormcloudVideoPlayer = class {
|
|
|
2786
2932
|
}
|
|
2787
2933
|
return;
|
|
2788
2934
|
}
|
|
2789
|
-
if (
|
|
2935
|
+
if (vastTagUrls.length > 0) {
|
|
2936
|
+
this.adPodAllUrls = [...vastTagUrls];
|
|
2937
|
+
this.preloadingAdUrls.clear();
|
|
2938
|
+
this.logQueuedAdUrls(this.adPodAllUrls);
|
|
2790
2939
|
this.inAdBreak = true;
|
|
2791
2940
|
this.showAds = true;
|
|
2792
|
-
this.currentAdIndex
|
|
2941
|
+
this.currentAdIndex = 0;
|
|
2942
|
+
this.totalAdsInBreak = vastTagUrls.length;
|
|
2943
|
+
this.adPodQueue = [...vastTagUrls];
|
|
2944
|
+
this.enforceAdHoldState();
|
|
2945
|
+
this.preloadUpcomingAds();
|
|
2946
|
+
if (this.config.debugAdTiming) {
|
|
2947
|
+
console.log(
|
|
2948
|
+
`[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - will play continuously`
|
|
2949
|
+
);
|
|
2950
|
+
}
|
|
2793
2951
|
try {
|
|
2794
|
-
await this.
|
|
2952
|
+
await this.playAdPod();
|
|
2795
2953
|
} catch (error) {
|
|
2796
2954
|
if (this.config.debugAdTiming) {
|
|
2797
2955
|
console.error(
|
|
2798
|
-
"[StormcloudVideoPlayer] Ad playback failed
|
|
2956
|
+
"[StormcloudVideoPlayer] Ad pod playback failed:",
|
|
2799
2957
|
error
|
|
2800
2958
|
);
|
|
2801
2959
|
}
|
|
@@ -2808,6 +2966,22 @@ var StormcloudVideoPlayer = class {
|
|
|
2808
2966
|
this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
|
|
2809
2967
|
}
|
|
2810
2968
|
}
|
|
2969
|
+
async playAdPod() {
|
|
2970
|
+
if (this.adPodQueue.length === 0) {
|
|
2971
|
+
if (this.config.debugAdTiming) {
|
|
2972
|
+
console.log("[StormcloudVideoPlayer] No ads in pod to play");
|
|
2973
|
+
}
|
|
2974
|
+
return;
|
|
2975
|
+
}
|
|
2976
|
+
const firstAd = this.adPodQueue.shift();
|
|
2977
|
+
this.currentAdIndex++;
|
|
2978
|
+
if (this.config.debugAdTiming) {
|
|
2979
|
+
console.log(
|
|
2980
|
+
`[StormcloudVideoPlayer] Playing ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
|
|
2981
|
+
);
|
|
2982
|
+
}
|
|
2983
|
+
await this.playSingleAd(firstAd);
|
|
2984
|
+
}
|
|
2811
2985
|
findCurrentOrNextBreak(nowMs) {
|
|
2812
2986
|
var _a;
|
|
2813
2987
|
const schedule = [];
|
|
@@ -2839,6 +3013,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2839
3013
|
const first = tags[0];
|
|
2840
3014
|
const rest = tags.slice(1);
|
|
2841
3015
|
this.adPodQueue = rest;
|
|
3016
|
+
this.enforceAdHoldState();
|
|
2842
3017
|
await this.playSingleAd(first);
|
|
2843
3018
|
this.inAdBreak = true;
|
|
2844
3019
|
this.expectedAdBreakDurationMs = remainingMs;
|
|
@@ -2952,6 +3127,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2952
3127
|
}
|
|
2953
3128
|
return;
|
|
2954
3129
|
}
|
|
3130
|
+
const wasPreloaded = this.ima.hasPreloadedAd(vastTagUrl);
|
|
3131
|
+
if (wasPreloaded && this.config.debugAdTiming) {
|
|
3132
|
+
console.log(
|
|
3133
|
+
`[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
|
|
3134
|
+
);
|
|
3135
|
+
}
|
|
2955
3136
|
if (!this.showAds) {
|
|
2956
3137
|
if (this.config.debugAdTiming) {
|
|
2957
3138
|
console.log(
|
|
@@ -2972,12 +3153,14 @@ var StormcloudVideoPlayer = class {
|
|
|
2972
3153
|
this.startAdFailsafeTimer();
|
|
2973
3154
|
try {
|
|
2974
3155
|
await this.ima.requestAds(vastTagUrl);
|
|
3156
|
+
this.preloadUpcomingAds();
|
|
2975
3157
|
try {
|
|
2976
3158
|
if (this.config.debugAdTiming) {
|
|
2977
3159
|
console.log(
|
|
2978
3160
|
"[StormcloudVideoPlayer] Ad request completed, attempting playback"
|
|
2979
3161
|
);
|
|
2980
3162
|
}
|
|
3163
|
+
this.enforceAdHoldState();
|
|
2981
3164
|
await this.ima.play();
|
|
2982
3165
|
if (this.config.debugAdTiming) {
|
|
2983
3166
|
console.log(
|
|
@@ -3007,6 +3190,8 @@ var StormcloudVideoPlayer = class {
|
|
|
3007
3190
|
"[StormcloudVideoPlayer] Handling ad pod completion - resuming content and hiding ad layer"
|
|
3008
3191
|
);
|
|
3009
3192
|
}
|
|
3193
|
+
this.releaseAdHoldState();
|
|
3194
|
+
this.preloadingAdUrls.clear();
|
|
3010
3195
|
this.inAdBreak = false;
|
|
3011
3196
|
this.expectedAdBreakDurationMs = void 0;
|
|
3012
3197
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3014,6 +3199,7 @@ var StormcloudVideoPlayer = class {
|
|
|
3014
3199
|
this.clearAdStopTimer();
|
|
3015
3200
|
this.clearAdFailsafeTimer();
|
|
3016
3201
|
this.adPodQueue = [];
|
|
3202
|
+
this.adPodAllUrls = [];
|
|
3017
3203
|
this.showAds = false;
|
|
3018
3204
|
this.currentAdIndex = 0;
|
|
3019
3205
|
this.totalAdsInBreak = 0;
|
|
@@ -3094,6 +3280,64 @@ var StormcloudVideoPlayer = class {
|
|
|
3094
3280
|
}
|
|
3095
3281
|
return [b.vastTagUrl];
|
|
3096
3282
|
}
|
|
3283
|
+
logQueuedAdUrls(urls) {
|
|
3284
|
+
if (!this.config.debugAdTiming) {
|
|
3285
|
+
return;
|
|
3286
|
+
}
|
|
3287
|
+
console.log("[StormcloudVideoPlayer] ALL ad URLs queued:", urls);
|
|
3288
|
+
}
|
|
3289
|
+
enforceAdHoldState() {
|
|
3290
|
+
this.video.dataset.stormcloudAdPlaying = "true";
|
|
3291
|
+
this.video.muted = true;
|
|
3292
|
+
this.video.volume = 0;
|
|
3293
|
+
if (typeof this.ima.showPlaceholder === "function") {
|
|
3294
|
+
this.ima.showPlaceholder();
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
releaseAdHoldState() {
|
|
3298
|
+
delete this.video.dataset.stormcloudAdPlaying;
|
|
3299
|
+
if (typeof this.ima.hidePlaceholder === "function") {
|
|
3300
|
+
this.ima.hidePlaceholder();
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
preloadUpcomingAds() {
|
|
3304
|
+
if (!this.ima.preloadAds || this.adPodQueue.length === 0) {
|
|
3305
|
+
return;
|
|
3306
|
+
}
|
|
3307
|
+
const upcoming = this.adPodQueue.slice(0, 2);
|
|
3308
|
+
for (const url of upcoming) {
|
|
3309
|
+
if (!url) continue;
|
|
3310
|
+
if (this.ima.hasPreloadedAd(url)) {
|
|
3311
|
+
this.preloadingAdUrls.delete(url);
|
|
3312
|
+
continue;
|
|
3313
|
+
}
|
|
3314
|
+
if (this.preloadingAdUrls.has(url)) {
|
|
3315
|
+
continue;
|
|
3316
|
+
}
|
|
3317
|
+
if (this.config.debugAdTiming) {
|
|
3318
|
+
console.log(
|
|
3319
|
+
`[StormcloudVideoPlayer] Scheduling IMA preload for upcoming ad: ${url}`
|
|
3320
|
+
);
|
|
3321
|
+
}
|
|
3322
|
+
this.preloadingAdUrls.add(url);
|
|
3323
|
+
this.ima.preloadAds(url).then(() => {
|
|
3324
|
+
if (this.config.debugAdTiming) {
|
|
3325
|
+
console.log(
|
|
3326
|
+
`[StormcloudVideoPlayer] IMA preload complete for ad: ${url}`
|
|
3327
|
+
);
|
|
3328
|
+
}
|
|
3329
|
+
}).catch((error) => {
|
|
3330
|
+
if (this.config.debugAdTiming) {
|
|
3331
|
+
console.warn(
|
|
3332
|
+
`[StormcloudVideoPlayer] IMA preload failed for ad: ${url}`,
|
|
3333
|
+
error
|
|
3334
|
+
);
|
|
3335
|
+
}
|
|
3336
|
+
}).finally(() => {
|
|
3337
|
+
this.preloadingAdUrls.delete(url);
|
|
3338
|
+
});
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3097
3341
|
getRemainingAdMs() {
|
|
3098
3342
|
if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
|
|
3099
3343
|
return 0;
|
|
@@ -3245,6 +3489,9 @@ var StormcloudVideoPlayer = class {
|
|
|
3245
3489
|
}
|
|
3246
3490
|
(_a = this.hls) == null ? void 0 : _a.destroy();
|
|
3247
3491
|
(_b = this.ima) == null ? void 0 : _b.destroy();
|
|
3492
|
+
this.releaseAdHoldState();
|
|
3493
|
+
this.preloadingAdUrls.clear();
|
|
3494
|
+
this.adPodAllUrls = [];
|
|
3248
3495
|
}
|
|
3249
3496
|
};
|
|
3250
3497
|
// Annotate the CommonJS export names for ESM import in node:
|