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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as StormcloudVideoPlayerConfig } from '../types-
|
|
1
|
+
import { S as StormcloudVideoPlayerConfig } from '../types-9_2sbHCg.cjs';
|
|
2
2
|
|
|
3
3
|
declare class StormcloudVideoPlayer {
|
|
4
4
|
private readonly video;
|
|
@@ -26,6 +26,8 @@ declare class StormcloudVideoPlayer {
|
|
|
26
26
|
private bufferedSegmentsCount;
|
|
27
27
|
private shouldAutoplayAfterBuffering;
|
|
28
28
|
private hasInitialBufferCompleted;
|
|
29
|
+
private adPodAllUrls;
|
|
30
|
+
private preloadingAdUrls;
|
|
29
31
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
30
32
|
private createAdPlayer;
|
|
31
33
|
load(): Promise<void>;
|
|
@@ -52,6 +54,7 @@ declare class StormcloudVideoPlayer {
|
|
|
52
54
|
shouldShowNativeControls(): boolean;
|
|
53
55
|
private shouldContinueLiveStreamDuringAds;
|
|
54
56
|
private handleAdStart;
|
|
57
|
+
private playAdPod;
|
|
55
58
|
private findCurrentOrNextBreak;
|
|
56
59
|
private onTimeUpdate;
|
|
57
60
|
private handleMidAdJoin;
|
|
@@ -67,6 +70,10 @@ declare class StormcloudVideoPlayer {
|
|
|
67
70
|
private startAdFailsafeTimer;
|
|
68
71
|
private clearAdFailsafeTimer;
|
|
69
72
|
private selectVastTagsForBreak;
|
|
73
|
+
private logQueuedAdUrls;
|
|
74
|
+
private enforceAdHoldState;
|
|
75
|
+
private releaseAdHoldState;
|
|
76
|
+
private preloadUpcomingAds;
|
|
70
77
|
private getRemainingAdMs;
|
|
71
78
|
private findBreakForTime;
|
|
72
79
|
toggleMute(): void;
|
|
@@ -203,6 +203,8 @@ function createImaController(video, options) {
|
|
|
203
203
|
let adPlaying = false;
|
|
204
204
|
let originalMutedState = false;
|
|
205
205
|
const listeners = /* @__PURE__ */ new Map();
|
|
206
|
+
const preloadedVast = /* @__PURE__ */ new Map();
|
|
207
|
+
const preloadingVast = /* @__PURE__ */ new Map();
|
|
206
208
|
function setAdPlayingFlag(isPlaying) {
|
|
207
209
|
if (isPlaying) {
|
|
208
210
|
video.dataset.stormcloudAdPlaying = "true";
|
|
@@ -293,7 +295,15 @@ function createImaController(video, options) {
|
|
|
293
295
|
let adsLoadedReject;
|
|
294
296
|
function makeAdsRequest(google, vastTagUrl) {
|
|
295
297
|
const adsRequest = new google.ima.AdsRequest();
|
|
296
|
-
|
|
298
|
+
const preloadedResponse = preloadedVast.get(vastTagUrl);
|
|
299
|
+
if (preloadedResponse) {
|
|
300
|
+
adsRequest.adsResponse = preloadedResponse;
|
|
301
|
+
console.log(
|
|
302
|
+
"[IMA] Using preloaded VAST response for immediate ad request"
|
|
303
|
+
);
|
|
304
|
+
} else {
|
|
305
|
+
adsRequest.adTagUrl = vastTagUrl;
|
|
306
|
+
}
|
|
297
307
|
const videoWidth = video.offsetWidth || video.clientWidth || 640;
|
|
298
308
|
const videoHeight = video.offsetHeight || video.clientHeight || 360;
|
|
299
309
|
adsRequest.linearAdSlotWidth = videoWidth;
|
|
@@ -303,6 +313,36 @@ function createImaController(video, options) {
|
|
|
303
313
|
adsRequest.vastLoadTimeout = 5e3;
|
|
304
314
|
console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
|
|
305
315
|
adsLoader.requestAds(adsRequest);
|
|
316
|
+
if (preloadedResponse) {
|
|
317
|
+
preloadedVast.delete(vastTagUrl);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function ensurePlaceholderContainer() {
|
|
321
|
+
var _a;
|
|
322
|
+
if (adContainerEl) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const container = document.createElement("div");
|
|
326
|
+
container.style.position = "absolute";
|
|
327
|
+
container.style.left = "0";
|
|
328
|
+
container.style.top = "0";
|
|
329
|
+
container.style.right = "0";
|
|
330
|
+
container.style.bottom = "0";
|
|
331
|
+
container.style.display = "none";
|
|
332
|
+
container.style.alignItems = "center";
|
|
333
|
+
container.style.justifyContent = "center";
|
|
334
|
+
container.style.pointerEvents = "none";
|
|
335
|
+
container.style.zIndex = "10";
|
|
336
|
+
container.style.backgroundColor = "#000";
|
|
337
|
+
(_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
338
|
+
adContainerEl = container;
|
|
339
|
+
}
|
|
340
|
+
async function fetchVastDocument(vastTagUrl) {
|
|
341
|
+
const response = await fetch(vastTagUrl, { mode: "cors" });
|
|
342
|
+
if (!response.ok) {
|
|
343
|
+
throw new Error(`Failed to preload VAST: ${response.status}`);
|
|
344
|
+
}
|
|
345
|
+
return response.text();
|
|
306
346
|
}
|
|
307
347
|
function destroyAdsManager() {
|
|
308
348
|
if (adsManager) {
|
|
@@ -318,29 +358,16 @@ function createImaController(video, options) {
|
|
|
318
358
|
return {
|
|
319
359
|
initialize() {
|
|
320
360
|
ensureImaLoaded().then(() => {
|
|
321
|
-
var _a
|
|
361
|
+
var _a;
|
|
322
362
|
const google = window.google;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
container.style.position = "absolute";
|
|
326
|
-
container.style.left = "0";
|
|
327
|
-
container.style.top = "0";
|
|
328
|
-
container.style.right = "0";
|
|
329
|
-
container.style.bottom = "0";
|
|
330
|
-
container.style.display = "none";
|
|
331
|
-
container.style.alignItems = "center";
|
|
332
|
-
container.style.justifyContent = "center";
|
|
333
|
-
container.style.pointerEvents = "none";
|
|
334
|
-
container.style.zIndex = "10";
|
|
335
|
-
container.style.backgroundColor = "#000";
|
|
336
|
-
(_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
337
|
-
adContainerEl = container;
|
|
363
|
+
ensurePlaceholderContainer();
|
|
364
|
+
if (!adDisplayContainer && adContainerEl) {
|
|
338
365
|
adDisplayContainer = new google.ima.AdDisplayContainer(
|
|
339
|
-
|
|
366
|
+
adContainerEl,
|
|
340
367
|
video
|
|
341
368
|
);
|
|
342
369
|
try {
|
|
343
|
-
(
|
|
370
|
+
(_a = adDisplayContainer.initialize) == null ? void 0 : _a.call(adDisplayContainer);
|
|
344
371
|
} catch {
|
|
345
372
|
}
|
|
346
373
|
}
|
|
@@ -442,9 +469,13 @@ function createImaController(video, options) {
|
|
|
442
469
|
adsLoader.addEventListener(
|
|
443
470
|
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
|
|
444
471
|
(evt) => {
|
|
445
|
-
console.log(
|
|
472
|
+
console.log(
|
|
473
|
+
"[IMA] Ads manager loaded - enabling preloading for continuous playback"
|
|
474
|
+
);
|
|
446
475
|
try {
|
|
447
|
-
|
|
476
|
+
const adsRenderingSettings = new google.ima.AdsRenderingSettings();
|
|
477
|
+
adsRenderingSettings.enablePreloading = true;
|
|
478
|
+
adsManager = evt.getAdsManager(video, adsRenderingSettings);
|
|
448
479
|
const AdEvent = google.ima.AdEvent.Type;
|
|
449
480
|
const AdErrorEvent = google.ima.AdErrorEvent.Type;
|
|
450
481
|
adsManager.addEventListener(
|
|
@@ -640,6 +671,32 @@ function createImaController(video, options) {
|
|
|
640
671
|
return Promise.reject(error);
|
|
641
672
|
}
|
|
642
673
|
},
|
|
674
|
+
async preloadAds(vastTagUrl) {
|
|
675
|
+
if (!vastTagUrl || vastTagUrl.trim() === "") {
|
|
676
|
+
return Promise.resolve();
|
|
677
|
+
}
|
|
678
|
+
if (preloadedVast.has(vastTagUrl)) {
|
|
679
|
+
return Promise.resolve();
|
|
680
|
+
}
|
|
681
|
+
const inflight = preloadingVast.get(vastTagUrl);
|
|
682
|
+
if (inflight) {
|
|
683
|
+
return inflight;
|
|
684
|
+
}
|
|
685
|
+
const preloadPromise = fetchVastDocument(vastTagUrl).then((xml) => {
|
|
686
|
+
preloadedVast.set(vastTagUrl, xml);
|
|
687
|
+
console.log("[IMA] Cached VAST response for preloading:", vastTagUrl);
|
|
688
|
+
}).catch((error) => {
|
|
689
|
+
console.warn("[IMA] Failed to preload VAST response:", error);
|
|
690
|
+
preloadedVast.delete(vastTagUrl);
|
|
691
|
+
}).finally(() => {
|
|
692
|
+
preloadingVast.delete(vastTagUrl);
|
|
693
|
+
});
|
|
694
|
+
preloadingVast.set(vastTagUrl, preloadPromise);
|
|
695
|
+
return preloadPromise;
|
|
696
|
+
},
|
|
697
|
+
hasPreloadedAd(vastTagUrl) {
|
|
698
|
+
return preloadedVast.has(vastTagUrl);
|
|
699
|
+
},
|
|
643
700
|
async play() {
|
|
644
701
|
var _a, _b;
|
|
645
702
|
if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
|
|
@@ -715,6 +772,8 @@ function createImaController(video, options) {
|
|
|
715
772
|
adContainerEl = void 0;
|
|
716
773
|
adDisplayContainer = void 0;
|
|
717
774
|
adsLoader = void 0;
|
|
775
|
+
preloadedVast.clear();
|
|
776
|
+
preloadingVast.clear();
|
|
718
777
|
},
|
|
719
778
|
isAdPlaying() {
|
|
720
779
|
return adPlaying;
|
|
@@ -770,6 +829,19 @@ function createImaController(video, options) {
|
|
|
770
829
|
}
|
|
771
830
|
}
|
|
772
831
|
return 1;
|
|
832
|
+
},
|
|
833
|
+
showPlaceholder() {
|
|
834
|
+
ensurePlaceholderContainer();
|
|
835
|
+
if (adContainerEl) {
|
|
836
|
+
adContainerEl.style.display = "flex";
|
|
837
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
hidePlaceholder() {
|
|
841
|
+
if (adContainerEl) {
|
|
842
|
+
adContainerEl.style.display = "none";
|
|
843
|
+
adContainerEl.style.pointerEvents = "none";
|
|
844
|
+
}
|
|
773
845
|
}
|
|
774
846
|
};
|
|
775
847
|
}
|
|
@@ -787,6 +859,8 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
787
859
|
let adContainerEl;
|
|
788
860
|
let currentAd;
|
|
789
861
|
let sessionId;
|
|
862
|
+
const preloadedAds = /* @__PURE__ */ new Map();
|
|
863
|
+
const preloadingAds = /* @__PURE__ */ new Map();
|
|
790
864
|
let trackingFired = {
|
|
791
865
|
impression: false,
|
|
792
866
|
start: false,
|
|
@@ -1016,6 +1090,19 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1016
1090
|
return null;
|
|
1017
1091
|
}
|
|
1018
1092
|
}
|
|
1093
|
+
async function fetchAndParseVastAd(vastTagUrl) {
|
|
1094
|
+
const response = await fetch(vastTagUrl);
|
|
1095
|
+
if (!response.ok) {
|
|
1096
|
+
throw new Error(`Failed to fetch VAST: ${response.statusText}`);
|
|
1097
|
+
}
|
|
1098
|
+
const vastXml = await response.text();
|
|
1099
|
+
console.log("[HlsAdPlayer] VAST XML received");
|
|
1100
|
+
console.log(
|
|
1101
|
+
"[HlsAdPlayer] VAST XML content (first 2000 chars):",
|
|
1102
|
+
vastXml.substring(0, 2e3)
|
|
1103
|
+
);
|
|
1104
|
+
return parseVastXml(vastXml);
|
|
1105
|
+
}
|
|
1019
1106
|
function createAdVideoElement() {
|
|
1020
1107
|
const video = document.createElement("video");
|
|
1021
1108
|
video.style.position = "absolute";
|
|
@@ -1167,17 +1254,17 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1167
1254
|
}
|
|
1168
1255
|
try {
|
|
1169
1256
|
sessionId = generateSessionId();
|
|
1170
|
-
|
|
1171
|
-
if (
|
|
1172
|
-
|
|
1257
|
+
let ad;
|
|
1258
|
+
if (preloadedAds.has(vastTagUrl)) {
|
|
1259
|
+
ad = preloadedAds.get(vastTagUrl);
|
|
1260
|
+
preloadedAds.delete(vastTagUrl);
|
|
1261
|
+
console.log(
|
|
1262
|
+
"[HlsAdPlayer] Using preloaded VAST response:",
|
|
1263
|
+
vastTagUrl
|
|
1264
|
+
);
|
|
1265
|
+
} else {
|
|
1266
|
+
ad = await fetchAndParseVastAd(vastTagUrl);
|
|
1173
1267
|
}
|
|
1174
|
-
const vastXml = await response.text();
|
|
1175
|
-
console.log("[HlsAdPlayer] VAST XML received");
|
|
1176
|
-
console.log(
|
|
1177
|
-
"[HlsAdPlayer] VAST XML content (first 2000 chars):",
|
|
1178
|
-
vastXml.substring(0, 2e3)
|
|
1179
|
-
);
|
|
1180
|
-
const ad = parseVastXml(vastXml);
|
|
1181
1268
|
if (!ad) {
|
|
1182
1269
|
console.warn("[HlsAdPlayer] No ads available from VAST response");
|
|
1183
1270
|
emit("ad_error");
|
|
@@ -1196,6 +1283,37 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1196
1283
|
return Promise.reject(error);
|
|
1197
1284
|
}
|
|
1198
1285
|
},
|
|
1286
|
+
async preloadAds(vastTagUrl) {
|
|
1287
|
+
if (!vastTagUrl || vastTagUrl.trim() === "") {
|
|
1288
|
+
return Promise.resolve();
|
|
1289
|
+
}
|
|
1290
|
+
if (preloadedAds.has(vastTagUrl)) {
|
|
1291
|
+
return Promise.resolve();
|
|
1292
|
+
}
|
|
1293
|
+
const inflight = preloadingAds.get(vastTagUrl);
|
|
1294
|
+
if (inflight) {
|
|
1295
|
+
return inflight;
|
|
1296
|
+
}
|
|
1297
|
+
const preloadPromise = fetchAndParseVastAd(vastTagUrl).then((ad) => {
|
|
1298
|
+
if (ad) {
|
|
1299
|
+
preloadedAds.set(vastTagUrl, ad);
|
|
1300
|
+
console.log(
|
|
1301
|
+
"[HlsAdPlayer] Cached VAST response for preloading:",
|
|
1302
|
+
vastTagUrl
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
}).catch((error) => {
|
|
1306
|
+
console.warn("[HlsAdPlayer] Failed to preload VAST response:", error);
|
|
1307
|
+
preloadedAds.delete(vastTagUrl);
|
|
1308
|
+
}).finally(() => {
|
|
1309
|
+
preloadingAds.delete(vastTagUrl);
|
|
1310
|
+
});
|
|
1311
|
+
preloadingAds.set(vastTagUrl, preloadPromise);
|
|
1312
|
+
return preloadPromise;
|
|
1313
|
+
},
|
|
1314
|
+
hasPreloadedAd(vastTagUrl) {
|
|
1315
|
+
return preloadedAds.has(vastTagUrl);
|
|
1316
|
+
},
|
|
1199
1317
|
async play() {
|
|
1200
1318
|
if (!currentAd) {
|
|
1201
1319
|
console.warn(
|
|
@@ -1326,6 +1444,8 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1326
1444
|
adContainerEl = void 0;
|
|
1327
1445
|
currentAd = void 0;
|
|
1328
1446
|
listeners.clear();
|
|
1447
|
+
preloadedAds.clear();
|
|
1448
|
+
preloadingAds.clear();
|
|
1329
1449
|
},
|
|
1330
1450
|
isAdPlaying() {
|
|
1331
1451
|
return adPlaying;
|
|
@@ -1368,6 +1488,35 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1368
1488
|
return adVideoElement.volume;
|
|
1369
1489
|
}
|
|
1370
1490
|
return 1;
|
|
1491
|
+
},
|
|
1492
|
+
showPlaceholder() {
|
|
1493
|
+
var _a;
|
|
1494
|
+
if (!adContainerEl) {
|
|
1495
|
+
const container = document.createElement("div");
|
|
1496
|
+
container.style.position = "absolute";
|
|
1497
|
+
container.style.left = "0";
|
|
1498
|
+
container.style.top = "0";
|
|
1499
|
+
container.style.right = "0";
|
|
1500
|
+
container.style.bottom = "0";
|
|
1501
|
+
container.style.display = "none";
|
|
1502
|
+
container.style.alignItems = "center";
|
|
1503
|
+
container.style.justifyContent = "center";
|
|
1504
|
+
container.style.pointerEvents = "none";
|
|
1505
|
+
container.style.zIndex = "10";
|
|
1506
|
+
container.style.backgroundColor = "#000";
|
|
1507
|
+
(_a = contentVideo.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
1508
|
+
adContainerEl = container;
|
|
1509
|
+
}
|
|
1510
|
+
if (adContainerEl) {
|
|
1511
|
+
adContainerEl.style.display = "flex";
|
|
1512
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
1513
|
+
}
|
|
1514
|
+
},
|
|
1515
|
+
hidePlaceholder() {
|
|
1516
|
+
if (adContainerEl) {
|
|
1517
|
+
adContainerEl.style.display = "none";
|
|
1518
|
+
adContainerEl.style.pointerEvents = "none";
|
|
1519
|
+
}
|
|
1371
1520
|
}
|
|
1372
1521
|
};
|
|
1373
1522
|
}
|
|
@@ -1848,6 +1997,8 @@ var StormcloudVideoPlayer = class {
|
|
|
1848
1997
|
this.bufferedSegmentsCount = 0;
|
|
1849
1998
|
this.shouldAutoplayAfterBuffering = false;
|
|
1850
1999
|
this.hasInitialBufferCompleted = false;
|
|
2000
|
+
this.adPodAllUrls = [];
|
|
2001
|
+
this.preloadingAdUrls = /* @__PURE__ */ new Set();
|
|
1851
2002
|
initializePolyfills();
|
|
1852
2003
|
const browserOverrides = getBrowserConfigOverrides();
|
|
1853
2004
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2148,6 +2299,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2148
2299
|
console.log("[StormcloudVideoPlayer] IMA content_pause event received");
|
|
2149
2300
|
}
|
|
2150
2301
|
this.clearAdFailsafeTimer();
|
|
2302
|
+
this.enforceAdHoldState();
|
|
2151
2303
|
});
|
|
2152
2304
|
this.ima.on("content_resume", () => {
|
|
2153
2305
|
if (this.config.debugAdTiming) {
|
|
@@ -2172,12 +2324,10 @@ var StormcloudVideoPlayer = class {
|
|
|
2172
2324
|
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
2173
2325
|
const next = this.adPodQueue.shift();
|
|
2174
2326
|
this.currentAdIndex++;
|
|
2175
|
-
this.
|
|
2176
|
-
this.video.muted = true;
|
|
2177
|
-
this.video.volume = 0;
|
|
2327
|
+
this.enforceAdHoldState();
|
|
2178
2328
|
if (this.config.debugAdTiming) {
|
|
2179
2329
|
console.log(
|
|
2180
|
-
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) -
|
|
2330
|
+
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - IMMEDIATELY starting next ad`
|
|
2181
2331
|
);
|
|
2182
2332
|
}
|
|
2183
2333
|
this.playSingleAd(next).catch(() => {
|
|
@@ -2762,25 +2912,21 @@ var StormcloudVideoPlayer = class {
|
|
|
2762
2912
|
this.video.currentTime * 1e3
|
|
2763
2913
|
);
|
|
2764
2914
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
2765
|
-
let
|
|
2915
|
+
let vastTagUrls = [];
|
|
2766
2916
|
if (this.apiVastTagUrl) {
|
|
2767
|
-
|
|
2768
|
-
this.adPodQueue = [];
|
|
2769
|
-
this.currentAdIndex = 0;
|
|
2770
|
-
this.totalAdsInBreak = 1;
|
|
2917
|
+
vastTagUrls = [this.apiVastTagUrl];
|
|
2771
2918
|
if (this.config.debugAdTiming) {
|
|
2772
|
-
console.log(
|
|
2919
|
+
console.log(
|
|
2920
|
+
"[StormcloudVideoPlayer] Using VAST endpoint:",
|
|
2921
|
+
this.apiVastTagUrl
|
|
2922
|
+
);
|
|
2773
2923
|
}
|
|
2774
2924
|
} else if (tags && tags.length > 0) {
|
|
2775
|
-
|
|
2776
|
-
const rest = tags.slice(1);
|
|
2777
|
-
this.adPodQueue = rest;
|
|
2778
|
-
this.currentAdIndex = 0;
|
|
2779
|
-
this.totalAdsInBreak = tags.length;
|
|
2925
|
+
vastTagUrls = tags;
|
|
2780
2926
|
if (this.config.debugAdTiming) {
|
|
2781
2927
|
console.log(
|
|
2782
|
-
"[StormcloudVideoPlayer] Using scheduled VAST
|
|
2783
|
-
|
|
2928
|
+
"[StormcloudVideoPlayer] Using scheduled VAST tags (count: " + tags.length + "):",
|
|
2929
|
+
tags
|
|
2784
2930
|
);
|
|
2785
2931
|
}
|
|
2786
2932
|
} else {
|
|
@@ -2789,16 +2935,28 @@ var StormcloudVideoPlayer = class {
|
|
|
2789
2935
|
}
|
|
2790
2936
|
return;
|
|
2791
2937
|
}
|
|
2792
|
-
if (
|
|
2938
|
+
if (vastTagUrls.length > 0) {
|
|
2939
|
+
this.adPodAllUrls = [...vastTagUrls];
|
|
2940
|
+
this.preloadingAdUrls.clear();
|
|
2941
|
+
this.logQueuedAdUrls(this.adPodAllUrls);
|
|
2793
2942
|
this.inAdBreak = true;
|
|
2794
2943
|
this.showAds = true;
|
|
2795
|
-
this.currentAdIndex
|
|
2944
|
+
this.currentAdIndex = 0;
|
|
2945
|
+
this.totalAdsInBreak = vastTagUrls.length;
|
|
2946
|
+
this.adPodQueue = [...vastTagUrls];
|
|
2947
|
+
this.enforceAdHoldState();
|
|
2948
|
+
this.preloadUpcomingAds();
|
|
2949
|
+
if (this.config.debugAdTiming) {
|
|
2950
|
+
console.log(
|
|
2951
|
+
`[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - will play continuously`
|
|
2952
|
+
);
|
|
2953
|
+
}
|
|
2796
2954
|
try {
|
|
2797
|
-
await this.
|
|
2955
|
+
await this.playAdPod();
|
|
2798
2956
|
} catch (error) {
|
|
2799
2957
|
if (this.config.debugAdTiming) {
|
|
2800
2958
|
console.error(
|
|
2801
|
-
"[StormcloudVideoPlayer] Ad playback failed
|
|
2959
|
+
"[StormcloudVideoPlayer] Ad pod playback failed:",
|
|
2802
2960
|
error
|
|
2803
2961
|
);
|
|
2804
2962
|
}
|
|
@@ -2811,6 +2969,22 @@ var StormcloudVideoPlayer = class {
|
|
|
2811
2969
|
this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
|
|
2812
2970
|
}
|
|
2813
2971
|
}
|
|
2972
|
+
async playAdPod() {
|
|
2973
|
+
if (this.adPodQueue.length === 0) {
|
|
2974
|
+
if (this.config.debugAdTiming) {
|
|
2975
|
+
console.log("[StormcloudVideoPlayer] No ads in pod to play");
|
|
2976
|
+
}
|
|
2977
|
+
return;
|
|
2978
|
+
}
|
|
2979
|
+
const firstAd = this.adPodQueue.shift();
|
|
2980
|
+
this.currentAdIndex++;
|
|
2981
|
+
if (this.config.debugAdTiming) {
|
|
2982
|
+
console.log(
|
|
2983
|
+
`[StormcloudVideoPlayer] Playing ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
|
|
2984
|
+
);
|
|
2985
|
+
}
|
|
2986
|
+
await this.playSingleAd(firstAd);
|
|
2987
|
+
}
|
|
2814
2988
|
findCurrentOrNextBreak(nowMs) {
|
|
2815
2989
|
var _a;
|
|
2816
2990
|
const schedule = [];
|
|
@@ -2842,6 +3016,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2842
3016
|
const first = tags[0];
|
|
2843
3017
|
const rest = tags.slice(1);
|
|
2844
3018
|
this.adPodQueue = rest;
|
|
3019
|
+
this.enforceAdHoldState();
|
|
2845
3020
|
await this.playSingleAd(first);
|
|
2846
3021
|
this.inAdBreak = true;
|
|
2847
3022
|
this.expectedAdBreakDurationMs = remainingMs;
|
|
@@ -2955,6 +3130,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2955
3130
|
}
|
|
2956
3131
|
return;
|
|
2957
3132
|
}
|
|
3133
|
+
const wasPreloaded = this.ima.hasPreloadedAd(vastTagUrl);
|
|
3134
|
+
if (wasPreloaded && this.config.debugAdTiming) {
|
|
3135
|
+
console.log(
|
|
3136
|
+
`[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
|
|
3137
|
+
);
|
|
3138
|
+
}
|
|
2958
3139
|
if (!this.showAds) {
|
|
2959
3140
|
if (this.config.debugAdTiming) {
|
|
2960
3141
|
console.log(
|
|
@@ -2975,12 +3156,14 @@ var StormcloudVideoPlayer = class {
|
|
|
2975
3156
|
this.startAdFailsafeTimer();
|
|
2976
3157
|
try {
|
|
2977
3158
|
await this.ima.requestAds(vastTagUrl);
|
|
3159
|
+
this.preloadUpcomingAds();
|
|
2978
3160
|
try {
|
|
2979
3161
|
if (this.config.debugAdTiming) {
|
|
2980
3162
|
console.log(
|
|
2981
3163
|
"[StormcloudVideoPlayer] Ad request completed, attempting playback"
|
|
2982
3164
|
);
|
|
2983
3165
|
}
|
|
3166
|
+
this.enforceAdHoldState();
|
|
2984
3167
|
await this.ima.play();
|
|
2985
3168
|
if (this.config.debugAdTiming) {
|
|
2986
3169
|
console.log(
|
|
@@ -3010,6 +3193,8 @@ var StormcloudVideoPlayer = class {
|
|
|
3010
3193
|
"[StormcloudVideoPlayer] Handling ad pod completion - resuming content and hiding ad layer"
|
|
3011
3194
|
);
|
|
3012
3195
|
}
|
|
3196
|
+
this.releaseAdHoldState();
|
|
3197
|
+
this.preloadingAdUrls.clear();
|
|
3013
3198
|
this.inAdBreak = false;
|
|
3014
3199
|
this.expectedAdBreakDurationMs = void 0;
|
|
3015
3200
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3017,6 +3202,7 @@ var StormcloudVideoPlayer = class {
|
|
|
3017
3202
|
this.clearAdStopTimer();
|
|
3018
3203
|
this.clearAdFailsafeTimer();
|
|
3019
3204
|
this.adPodQueue = [];
|
|
3205
|
+
this.adPodAllUrls = [];
|
|
3020
3206
|
this.showAds = false;
|
|
3021
3207
|
this.currentAdIndex = 0;
|
|
3022
3208
|
this.totalAdsInBreak = 0;
|
|
@@ -3097,6 +3283,64 @@ var StormcloudVideoPlayer = class {
|
|
|
3097
3283
|
}
|
|
3098
3284
|
return [b.vastTagUrl];
|
|
3099
3285
|
}
|
|
3286
|
+
logQueuedAdUrls(urls) {
|
|
3287
|
+
if (!this.config.debugAdTiming) {
|
|
3288
|
+
return;
|
|
3289
|
+
}
|
|
3290
|
+
console.log("[StormcloudVideoPlayer] ALL ad URLs queued:", urls);
|
|
3291
|
+
}
|
|
3292
|
+
enforceAdHoldState() {
|
|
3293
|
+
this.video.dataset.stormcloudAdPlaying = "true";
|
|
3294
|
+
this.video.muted = true;
|
|
3295
|
+
this.video.volume = 0;
|
|
3296
|
+
if (typeof this.ima.showPlaceholder === "function") {
|
|
3297
|
+
this.ima.showPlaceholder();
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
releaseAdHoldState() {
|
|
3301
|
+
delete this.video.dataset.stormcloudAdPlaying;
|
|
3302
|
+
if (typeof this.ima.hidePlaceholder === "function") {
|
|
3303
|
+
this.ima.hidePlaceholder();
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
preloadUpcomingAds() {
|
|
3307
|
+
if (!this.ima.preloadAds || this.adPodQueue.length === 0) {
|
|
3308
|
+
return;
|
|
3309
|
+
}
|
|
3310
|
+
const upcoming = this.adPodQueue.slice(0, 2);
|
|
3311
|
+
for (const url of upcoming) {
|
|
3312
|
+
if (!url) continue;
|
|
3313
|
+
if (this.ima.hasPreloadedAd(url)) {
|
|
3314
|
+
this.preloadingAdUrls.delete(url);
|
|
3315
|
+
continue;
|
|
3316
|
+
}
|
|
3317
|
+
if (this.preloadingAdUrls.has(url)) {
|
|
3318
|
+
continue;
|
|
3319
|
+
}
|
|
3320
|
+
if (this.config.debugAdTiming) {
|
|
3321
|
+
console.log(
|
|
3322
|
+
`[StormcloudVideoPlayer] Scheduling IMA preload for upcoming ad: ${url}`
|
|
3323
|
+
);
|
|
3324
|
+
}
|
|
3325
|
+
this.preloadingAdUrls.add(url);
|
|
3326
|
+
this.ima.preloadAds(url).then(() => {
|
|
3327
|
+
if (this.config.debugAdTiming) {
|
|
3328
|
+
console.log(
|
|
3329
|
+
`[StormcloudVideoPlayer] IMA preload complete for ad: ${url}`
|
|
3330
|
+
);
|
|
3331
|
+
}
|
|
3332
|
+
}).catch((error) => {
|
|
3333
|
+
if (this.config.debugAdTiming) {
|
|
3334
|
+
console.warn(
|
|
3335
|
+
`[StormcloudVideoPlayer] IMA preload failed for ad: ${url}`,
|
|
3336
|
+
error
|
|
3337
|
+
);
|
|
3338
|
+
}
|
|
3339
|
+
}).finally(() => {
|
|
3340
|
+
this.preloadingAdUrls.delete(url);
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3100
3344
|
getRemainingAdMs() {
|
|
3101
3345
|
if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
|
|
3102
3346
|
return 0;
|
|
@@ -3248,6 +3492,9 @@ var StormcloudVideoPlayer = class {
|
|
|
3248
3492
|
}
|
|
3249
3493
|
(_a = this.hls) == null ? void 0 : _a.destroy();
|
|
3250
3494
|
(_b = this.ima) == null ? void 0 : _b.destroy();
|
|
3495
|
+
this.releaseAdHoldState();
|
|
3496
|
+
this.preloadingAdUrls.clear();
|
|
3497
|
+
this.adPodAllUrls = [];
|
|
3251
3498
|
}
|
|
3252
3499
|
};
|
|
3253
3500
|
|