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
package/lib/index.d.cts
CHANGED
|
@@ -39,6 +39,8 @@ interface StormcloudVideoPlayerConfig {
|
|
|
39
39
|
interface ImaController {
|
|
40
40
|
initialize: () => void;
|
|
41
41
|
requestAds: (vastTagUrl: string) => Promise<void>;
|
|
42
|
+
preloadAds: (vastTagUrl: string) => Promise<void>;
|
|
43
|
+
hasPreloadedAd: (vastTagUrl: string) => boolean;
|
|
42
44
|
play: () => Promise<void>;
|
|
43
45
|
stop: () => Promise<void>;
|
|
44
46
|
destroy: () => void;
|
|
@@ -50,6 +52,8 @@ interface ImaController {
|
|
|
50
52
|
getOriginalMutedState: () => boolean;
|
|
51
53
|
setAdVolume: (volume: number) => void;
|
|
52
54
|
getAdVolume: () => number;
|
|
55
|
+
showPlaceholder: () => void;
|
|
56
|
+
hidePlaceholder: () => void;
|
|
53
57
|
}
|
|
54
58
|
interface ImaControllerOptions {
|
|
55
59
|
maxRetries?: number;
|
|
@@ -122,6 +126,8 @@ declare class StormcloudVideoPlayer {
|
|
|
122
126
|
private bufferedSegmentsCount;
|
|
123
127
|
private shouldAutoplayAfterBuffering;
|
|
124
128
|
private hasInitialBufferCompleted;
|
|
129
|
+
private adPodAllUrls;
|
|
130
|
+
private preloadingAdUrls;
|
|
125
131
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
126
132
|
private createAdPlayer;
|
|
127
133
|
load(): Promise<void>;
|
|
@@ -148,6 +154,7 @@ declare class StormcloudVideoPlayer {
|
|
|
148
154
|
shouldShowNativeControls(): boolean;
|
|
149
155
|
private shouldContinueLiveStreamDuringAds;
|
|
150
156
|
private handleAdStart;
|
|
157
|
+
private playAdPod;
|
|
151
158
|
private findCurrentOrNextBreak;
|
|
152
159
|
private onTimeUpdate;
|
|
153
160
|
private handleMidAdJoin;
|
|
@@ -163,6 +170,10 @@ declare class StormcloudVideoPlayer {
|
|
|
163
170
|
private startAdFailsafeTimer;
|
|
164
171
|
private clearAdFailsafeTimer;
|
|
165
172
|
private selectVastTagsForBreak;
|
|
173
|
+
private logQueuedAdUrls;
|
|
174
|
+
private enforceAdHoldState;
|
|
175
|
+
private releaseAdHoldState;
|
|
176
|
+
private preloadUpcomingAds;
|
|
166
177
|
private getRemainingAdMs;
|
|
167
178
|
private findBreakForTime;
|
|
168
179
|
toggleMute(): void;
|
package/lib/index.d.ts
CHANGED
|
@@ -39,6 +39,8 @@ interface StormcloudVideoPlayerConfig {
|
|
|
39
39
|
interface ImaController {
|
|
40
40
|
initialize: () => void;
|
|
41
41
|
requestAds: (vastTagUrl: string) => Promise<void>;
|
|
42
|
+
preloadAds: (vastTagUrl: string) => Promise<void>;
|
|
43
|
+
hasPreloadedAd: (vastTagUrl: string) => boolean;
|
|
42
44
|
play: () => Promise<void>;
|
|
43
45
|
stop: () => Promise<void>;
|
|
44
46
|
destroy: () => void;
|
|
@@ -50,6 +52,8 @@ interface ImaController {
|
|
|
50
52
|
getOriginalMutedState: () => boolean;
|
|
51
53
|
setAdVolume: (volume: number) => void;
|
|
52
54
|
getAdVolume: () => number;
|
|
55
|
+
showPlaceholder: () => void;
|
|
56
|
+
hidePlaceholder: () => void;
|
|
53
57
|
}
|
|
54
58
|
interface ImaControllerOptions {
|
|
55
59
|
maxRetries?: number;
|
|
@@ -122,6 +126,8 @@ declare class StormcloudVideoPlayer {
|
|
|
122
126
|
private bufferedSegmentsCount;
|
|
123
127
|
private shouldAutoplayAfterBuffering;
|
|
124
128
|
private hasInitialBufferCompleted;
|
|
129
|
+
private adPodAllUrls;
|
|
130
|
+
private preloadingAdUrls;
|
|
125
131
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
126
132
|
private createAdPlayer;
|
|
127
133
|
load(): Promise<void>;
|
|
@@ -148,6 +154,7 @@ declare class StormcloudVideoPlayer {
|
|
|
148
154
|
shouldShowNativeControls(): boolean;
|
|
149
155
|
private shouldContinueLiveStreamDuringAds;
|
|
150
156
|
private handleAdStart;
|
|
157
|
+
private playAdPod;
|
|
151
158
|
private findCurrentOrNextBreak;
|
|
152
159
|
private onTimeUpdate;
|
|
153
160
|
private handleMidAdJoin;
|
|
@@ -163,6 +170,10 @@ declare class StormcloudVideoPlayer {
|
|
|
163
170
|
private startAdFailsafeTimer;
|
|
164
171
|
private clearAdFailsafeTimer;
|
|
165
172
|
private selectVastTagsForBreak;
|
|
173
|
+
private logQueuedAdUrls;
|
|
174
|
+
private enforceAdHoldState;
|
|
175
|
+
private releaseAdHoldState;
|
|
176
|
+
private preloadUpcomingAds;
|
|
166
177
|
private getRemainingAdMs;
|
|
167
178
|
private findBreakForTime;
|
|
168
179
|
toggleMute(): void;
|
package/lib/index.js
CHANGED
|
@@ -198,6 +198,8 @@ function createImaController(video, options) {
|
|
|
198
198
|
let adPlaying = false;
|
|
199
199
|
let originalMutedState = false;
|
|
200
200
|
const listeners = /* @__PURE__ */ new Map();
|
|
201
|
+
const preloadedVast = /* @__PURE__ */ new Map();
|
|
202
|
+
const preloadingVast = /* @__PURE__ */ new Map();
|
|
201
203
|
function setAdPlayingFlag(isPlaying) {
|
|
202
204
|
if (isPlaying) {
|
|
203
205
|
video.dataset.stormcloudAdPlaying = "true";
|
|
@@ -288,7 +290,15 @@ function createImaController(video, options) {
|
|
|
288
290
|
let adsLoadedReject;
|
|
289
291
|
function makeAdsRequest(google, vastTagUrl) {
|
|
290
292
|
const adsRequest = new google.ima.AdsRequest();
|
|
291
|
-
|
|
293
|
+
const preloadedResponse = preloadedVast.get(vastTagUrl);
|
|
294
|
+
if (preloadedResponse) {
|
|
295
|
+
adsRequest.adsResponse = preloadedResponse;
|
|
296
|
+
console.log(
|
|
297
|
+
"[IMA] Using preloaded VAST response for immediate ad request"
|
|
298
|
+
);
|
|
299
|
+
} else {
|
|
300
|
+
adsRequest.adTagUrl = vastTagUrl;
|
|
301
|
+
}
|
|
292
302
|
const videoWidth = video.offsetWidth || video.clientWidth || 640;
|
|
293
303
|
const videoHeight = video.offsetHeight || video.clientHeight || 360;
|
|
294
304
|
adsRequest.linearAdSlotWidth = videoWidth;
|
|
@@ -298,6 +308,36 @@ function createImaController(video, options) {
|
|
|
298
308
|
adsRequest.vastLoadTimeout = 5e3;
|
|
299
309
|
console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
|
|
300
310
|
adsLoader.requestAds(adsRequest);
|
|
311
|
+
if (preloadedResponse) {
|
|
312
|
+
preloadedVast.delete(vastTagUrl);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function ensurePlaceholderContainer() {
|
|
316
|
+
var _a;
|
|
317
|
+
if (adContainerEl) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const container = document.createElement("div");
|
|
321
|
+
container.style.position = "absolute";
|
|
322
|
+
container.style.left = "0";
|
|
323
|
+
container.style.top = "0";
|
|
324
|
+
container.style.right = "0";
|
|
325
|
+
container.style.bottom = "0";
|
|
326
|
+
container.style.display = "none";
|
|
327
|
+
container.style.alignItems = "center";
|
|
328
|
+
container.style.justifyContent = "center";
|
|
329
|
+
container.style.pointerEvents = "none";
|
|
330
|
+
container.style.zIndex = "10";
|
|
331
|
+
container.style.backgroundColor = "#000";
|
|
332
|
+
(_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
333
|
+
adContainerEl = container;
|
|
334
|
+
}
|
|
335
|
+
async function fetchVastDocument(vastTagUrl) {
|
|
336
|
+
const response = await fetch(vastTagUrl, { mode: "cors" });
|
|
337
|
+
if (!response.ok) {
|
|
338
|
+
throw new Error(`Failed to preload VAST: ${response.status}`);
|
|
339
|
+
}
|
|
340
|
+
return response.text();
|
|
301
341
|
}
|
|
302
342
|
function destroyAdsManager() {
|
|
303
343
|
if (adsManager) {
|
|
@@ -313,29 +353,16 @@ function createImaController(video, options) {
|
|
|
313
353
|
return {
|
|
314
354
|
initialize() {
|
|
315
355
|
ensureImaLoaded().then(() => {
|
|
316
|
-
var _a
|
|
356
|
+
var _a;
|
|
317
357
|
const google = window.google;
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
container.style.position = "absolute";
|
|
321
|
-
container.style.left = "0";
|
|
322
|
-
container.style.top = "0";
|
|
323
|
-
container.style.right = "0";
|
|
324
|
-
container.style.bottom = "0";
|
|
325
|
-
container.style.display = "none";
|
|
326
|
-
container.style.alignItems = "center";
|
|
327
|
-
container.style.justifyContent = "center";
|
|
328
|
-
container.style.pointerEvents = "none";
|
|
329
|
-
container.style.zIndex = "10";
|
|
330
|
-
container.style.backgroundColor = "#000";
|
|
331
|
-
(_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
332
|
-
adContainerEl = container;
|
|
358
|
+
ensurePlaceholderContainer();
|
|
359
|
+
if (!adDisplayContainer && adContainerEl) {
|
|
333
360
|
adDisplayContainer = new google.ima.AdDisplayContainer(
|
|
334
|
-
|
|
361
|
+
adContainerEl,
|
|
335
362
|
video
|
|
336
363
|
);
|
|
337
364
|
try {
|
|
338
|
-
(
|
|
365
|
+
(_a = adDisplayContainer.initialize) == null ? void 0 : _a.call(adDisplayContainer);
|
|
339
366
|
} catch {
|
|
340
367
|
}
|
|
341
368
|
}
|
|
@@ -437,9 +464,13 @@ function createImaController(video, options) {
|
|
|
437
464
|
adsLoader.addEventListener(
|
|
438
465
|
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
|
|
439
466
|
(evt) => {
|
|
440
|
-
console.log(
|
|
467
|
+
console.log(
|
|
468
|
+
"[IMA] Ads manager loaded - enabling preloading for continuous playback"
|
|
469
|
+
);
|
|
441
470
|
try {
|
|
442
|
-
|
|
471
|
+
const adsRenderingSettings = new google.ima.AdsRenderingSettings();
|
|
472
|
+
adsRenderingSettings.enablePreloading = true;
|
|
473
|
+
adsManager = evt.getAdsManager(video, adsRenderingSettings);
|
|
443
474
|
const AdEvent = google.ima.AdEvent.Type;
|
|
444
475
|
const AdErrorEvent = google.ima.AdErrorEvent.Type;
|
|
445
476
|
adsManager.addEventListener(
|
|
@@ -635,6 +666,32 @@ function createImaController(video, options) {
|
|
|
635
666
|
return Promise.reject(error);
|
|
636
667
|
}
|
|
637
668
|
},
|
|
669
|
+
async preloadAds(vastTagUrl) {
|
|
670
|
+
if (!vastTagUrl || vastTagUrl.trim() === "") {
|
|
671
|
+
return Promise.resolve();
|
|
672
|
+
}
|
|
673
|
+
if (preloadedVast.has(vastTagUrl)) {
|
|
674
|
+
return Promise.resolve();
|
|
675
|
+
}
|
|
676
|
+
const inflight = preloadingVast.get(vastTagUrl);
|
|
677
|
+
if (inflight) {
|
|
678
|
+
return inflight;
|
|
679
|
+
}
|
|
680
|
+
const preloadPromise = fetchVastDocument(vastTagUrl).then((xml) => {
|
|
681
|
+
preloadedVast.set(vastTagUrl, xml);
|
|
682
|
+
console.log("[IMA] Cached VAST response for preloading:", vastTagUrl);
|
|
683
|
+
}).catch((error) => {
|
|
684
|
+
console.warn("[IMA] Failed to preload VAST response:", error);
|
|
685
|
+
preloadedVast.delete(vastTagUrl);
|
|
686
|
+
}).finally(() => {
|
|
687
|
+
preloadingVast.delete(vastTagUrl);
|
|
688
|
+
});
|
|
689
|
+
preloadingVast.set(vastTagUrl, preloadPromise);
|
|
690
|
+
return preloadPromise;
|
|
691
|
+
},
|
|
692
|
+
hasPreloadedAd(vastTagUrl) {
|
|
693
|
+
return preloadedVast.has(vastTagUrl);
|
|
694
|
+
},
|
|
638
695
|
async play() {
|
|
639
696
|
var _a, _b;
|
|
640
697
|
if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
|
|
@@ -710,6 +767,8 @@ function createImaController(video, options) {
|
|
|
710
767
|
adContainerEl = void 0;
|
|
711
768
|
adDisplayContainer = void 0;
|
|
712
769
|
adsLoader = void 0;
|
|
770
|
+
preloadedVast.clear();
|
|
771
|
+
preloadingVast.clear();
|
|
713
772
|
},
|
|
714
773
|
isAdPlaying() {
|
|
715
774
|
return adPlaying;
|
|
@@ -765,6 +824,19 @@ function createImaController(video, options) {
|
|
|
765
824
|
}
|
|
766
825
|
}
|
|
767
826
|
return 1;
|
|
827
|
+
},
|
|
828
|
+
showPlaceholder() {
|
|
829
|
+
ensurePlaceholderContainer();
|
|
830
|
+
if (adContainerEl) {
|
|
831
|
+
adContainerEl.style.display = "flex";
|
|
832
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
hidePlaceholder() {
|
|
836
|
+
if (adContainerEl) {
|
|
837
|
+
adContainerEl.style.display = "none";
|
|
838
|
+
adContainerEl.style.pointerEvents = "none";
|
|
839
|
+
}
|
|
768
840
|
}
|
|
769
841
|
};
|
|
770
842
|
}
|
|
@@ -782,6 +854,8 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
782
854
|
let adContainerEl;
|
|
783
855
|
let currentAd;
|
|
784
856
|
let sessionId;
|
|
857
|
+
const preloadedAds = /* @__PURE__ */ new Map();
|
|
858
|
+
const preloadingAds = /* @__PURE__ */ new Map();
|
|
785
859
|
let trackingFired = {
|
|
786
860
|
impression: false,
|
|
787
861
|
start: false,
|
|
@@ -1011,6 +1085,19 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1011
1085
|
return null;
|
|
1012
1086
|
}
|
|
1013
1087
|
}
|
|
1088
|
+
async function fetchAndParseVastAd(vastTagUrl) {
|
|
1089
|
+
const response = await fetch(vastTagUrl);
|
|
1090
|
+
if (!response.ok) {
|
|
1091
|
+
throw new Error(`Failed to fetch VAST: ${response.statusText}`);
|
|
1092
|
+
}
|
|
1093
|
+
const vastXml = await response.text();
|
|
1094
|
+
console.log("[HlsAdPlayer] VAST XML received");
|
|
1095
|
+
console.log(
|
|
1096
|
+
"[HlsAdPlayer] VAST XML content (first 2000 chars):",
|
|
1097
|
+
vastXml.substring(0, 2e3)
|
|
1098
|
+
);
|
|
1099
|
+
return parseVastXml(vastXml);
|
|
1100
|
+
}
|
|
1014
1101
|
function createAdVideoElement() {
|
|
1015
1102
|
const video = document.createElement("video");
|
|
1016
1103
|
video.style.position = "absolute";
|
|
@@ -1162,17 +1249,17 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1162
1249
|
}
|
|
1163
1250
|
try {
|
|
1164
1251
|
sessionId = generateSessionId();
|
|
1165
|
-
|
|
1166
|
-
if (
|
|
1167
|
-
|
|
1252
|
+
let ad;
|
|
1253
|
+
if (preloadedAds.has(vastTagUrl)) {
|
|
1254
|
+
ad = preloadedAds.get(vastTagUrl);
|
|
1255
|
+
preloadedAds.delete(vastTagUrl);
|
|
1256
|
+
console.log(
|
|
1257
|
+
"[HlsAdPlayer] Using preloaded VAST response:",
|
|
1258
|
+
vastTagUrl
|
|
1259
|
+
);
|
|
1260
|
+
} else {
|
|
1261
|
+
ad = await fetchAndParseVastAd(vastTagUrl);
|
|
1168
1262
|
}
|
|
1169
|
-
const vastXml = await response.text();
|
|
1170
|
-
console.log("[HlsAdPlayer] VAST XML received");
|
|
1171
|
-
console.log(
|
|
1172
|
-
"[HlsAdPlayer] VAST XML content (first 2000 chars):",
|
|
1173
|
-
vastXml.substring(0, 2e3)
|
|
1174
|
-
);
|
|
1175
|
-
const ad = parseVastXml(vastXml);
|
|
1176
1263
|
if (!ad) {
|
|
1177
1264
|
console.warn("[HlsAdPlayer] No ads available from VAST response");
|
|
1178
1265
|
emit("ad_error");
|
|
@@ -1191,6 +1278,37 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1191
1278
|
return Promise.reject(error);
|
|
1192
1279
|
}
|
|
1193
1280
|
},
|
|
1281
|
+
async preloadAds(vastTagUrl) {
|
|
1282
|
+
if (!vastTagUrl || vastTagUrl.trim() === "") {
|
|
1283
|
+
return Promise.resolve();
|
|
1284
|
+
}
|
|
1285
|
+
if (preloadedAds.has(vastTagUrl)) {
|
|
1286
|
+
return Promise.resolve();
|
|
1287
|
+
}
|
|
1288
|
+
const inflight = preloadingAds.get(vastTagUrl);
|
|
1289
|
+
if (inflight) {
|
|
1290
|
+
return inflight;
|
|
1291
|
+
}
|
|
1292
|
+
const preloadPromise = fetchAndParseVastAd(vastTagUrl).then((ad) => {
|
|
1293
|
+
if (ad) {
|
|
1294
|
+
preloadedAds.set(vastTagUrl, ad);
|
|
1295
|
+
console.log(
|
|
1296
|
+
"[HlsAdPlayer] Cached VAST response for preloading:",
|
|
1297
|
+
vastTagUrl
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
}).catch((error) => {
|
|
1301
|
+
console.warn("[HlsAdPlayer] Failed to preload VAST response:", error);
|
|
1302
|
+
preloadedAds.delete(vastTagUrl);
|
|
1303
|
+
}).finally(() => {
|
|
1304
|
+
preloadingAds.delete(vastTagUrl);
|
|
1305
|
+
});
|
|
1306
|
+
preloadingAds.set(vastTagUrl, preloadPromise);
|
|
1307
|
+
return preloadPromise;
|
|
1308
|
+
},
|
|
1309
|
+
hasPreloadedAd(vastTagUrl) {
|
|
1310
|
+
return preloadedAds.has(vastTagUrl);
|
|
1311
|
+
},
|
|
1194
1312
|
async play() {
|
|
1195
1313
|
if (!currentAd) {
|
|
1196
1314
|
console.warn(
|
|
@@ -1321,6 +1439,8 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1321
1439
|
adContainerEl = void 0;
|
|
1322
1440
|
currentAd = void 0;
|
|
1323
1441
|
listeners.clear();
|
|
1442
|
+
preloadedAds.clear();
|
|
1443
|
+
preloadingAds.clear();
|
|
1324
1444
|
},
|
|
1325
1445
|
isAdPlaying() {
|
|
1326
1446
|
return adPlaying;
|
|
@@ -1363,6 +1483,35 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1363
1483
|
return adVideoElement.volume;
|
|
1364
1484
|
}
|
|
1365
1485
|
return 1;
|
|
1486
|
+
},
|
|
1487
|
+
showPlaceholder() {
|
|
1488
|
+
var _a;
|
|
1489
|
+
if (!adContainerEl) {
|
|
1490
|
+
const container = document.createElement("div");
|
|
1491
|
+
container.style.position = "absolute";
|
|
1492
|
+
container.style.left = "0";
|
|
1493
|
+
container.style.top = "0";
|
|
1494
|
+
container.style.right = "0";
|
|
1495
|
+
container.style.bottom = "0";
|
|
1496
|
+
container.style.display = "none";
|
|
1497
|
+
container.style.alignItems = "center";
|
|
1498
|
+
container.style.justifyContent = "center";
|
|
1499
|
+
container.style.pointerEvents = "none";
|
|
1500
|
+
container.style.zIndex = "10";
|
|
1501
|
+
container.style.backgroundColor = "#000";
|
|
1502
|
+
(_a = contentVideo.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
1503
|
+
adContainerEl = container;
|
|
1504
|
+
}
|
|
1505
|
+
if (adContainerEl) {
|
|
1506
|
+
adContainerEl.style.display = "flex";
|
|
1507
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
1508
|
+
}
|
|
1509
|
+
},
|
|
1510
|
+
hidePlaceholder() {
|
|
1511
|
+
if (adContainerEl) {
|
|
1512
|
+
adContainerEl.style.display = "none";
|
|
1513
|
+
adContainerEl.style.pointerEvents = "none";
|
|
1514
|
+
}
|
|
1366
1515
|
}
|
|
1367
1516
|
};
|
|
1368
1517
|
}
|
|
@@ -1843,6 +1992,8 @@ var StormcloudVideoPlayer = class {
|
|
|
1843
1992
|
this.bufferedSegmentsCount = 0;
|
|
1844
1993
|
this.shouldAutoplayAfterBuffering = false;
|
|
1845
1994
|
this.hasInitialBufferCompleted = false;
|
|
1995
|
+
this.adPodAllUrls = [];
|
|
1996
|
+
this.preloadingAdUrls = /* @__PURE__ */ new Set();
|
|
1846
1997
|
initializePolyfills();
|
|
1847
1998
|
const browserOverrides = getBrowserConfigOverrides();
|
|
1848
1999
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2143,6 +2294,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2143
2294
|
console.log("[StormcloudVideoPlayer] IMA content_pause event received");
|
|
2144
2295
|
}
|
|
2145
2296
|
this.clearAdFailsafeTimer();
|
|
2297
|
+
this.enforceAdHoldState();
|
|
2146
2298
|
});
|
|
2147
2299
|
this.ima.on("content_resume", () => {
|
|
2148
2300
|
if (this.config.debugAdTiming) {
|
|
@@ -2167,12 +2319,10 @@ var StormcloudVideoPlayer = class {
|
|
|
2167
2319
|
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
2168
2320
|
const next = this.adPodQueue.shift();
|
|
2169
2321
|
this.currentAdIndex++;
|
|
2170
|
-
this.
|
|
2171
|
-
this.video.muted = true;
|
|
2172
|
-
this.video.volume = 0;
|
|
2322
|
+
this.enforceAdHoldState();
|
|
2173
2323
|
if (this.config.debugAdTiming) {
|
|
2174
2324
|
console.log(
|
|
2175
|
-
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) -
|
|
2325
|
+
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - IMMEDIATELY starting next ad`
|
|
2176
2326
|
);
|
|
2177
2327
|
}
|
|
2178
2328
|
this.playSingleAd(next).catch(() => {
|
|
@@ -2757,25 +2907,21 @@ var StormcloudVideoPlayer = class {
|
|
|
2757
2907
|
this.video.currentTime * 1e3
|
|
2758
2908
|
);
|
|
2759
2909
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
2760
|
-
let
|
|
2910
|
+
let vastTagUrls = [];
|
|
2761
2911
|
if (this.apiVastTagUrl) {
|
|
2762
|
-
|
|
2763
|
-
this.adPodQueue = [];
|
|
2764
|
-
this.currentAdIndex = 0;
|
|
2765
|
-
this.totalAdsInBreak = 1;
|
|
2912
|
+
vastTagUrls = [this.apiVastTagUrl];
|
|
2766
2913
|
if (this.config.debugAdTiming) {
|
|
2767
|
-
console.log(
|
|
2914
|
+
console.log(
|
|
2915
|
+
"[StormcloudVideoPlayer] Using VAST endpoint:",
|
|
2916
|
+
this.apiVastTagUrl
|
|
2917
|
+
);
|
|
2768
2918
|
}
|
|
2769
2919
|
} else if (tags && tags.length > 0) {
|
|
2770
|
-
|
|
2771
|
-
const rest = tags.slice(1);
|
|
2772
|
-
this.adPodQueue = rest;
|
|
2773
|
-
this.currentAdIndex = 0;
|
|
2774
|
-
this.totalAdsInBreak = tags.length;
|
|
2920
|
+
vastTagUrls = tags;
|
|
2775
2921
|
if (this.config.debugAdTiming) {
|
|
2776
2922
|
console.log(
|
|
2777
|
-
"[StormcloudVideoPlayer] Using scheduled VAST
|
|
2778
|
-
|
|
2923
|
+
"[StormcloudVideoPlayer] Using scheduled VAST tags (count: " + tags.length + "):",
|
|
2924
|
+
tags
|
|
2779
2925
|
);
|
|
2780
2926
|
}
|
|
2781
2927
|
} else {
|
|
@@ -2784,16 +2930,28 @@ var StormcloudVideoPlayer = class {
|
|
|
2784
2930
|
}
|
|
2785
2931
|
return;
|
|
2786
2932
|
}
|
|
2787
|
-
if (
|
|
2933
|
+
if (vastTagUrls.length > 0) {
|
|
2934
|
+
this.adPodAllUrls = [...vastTagUrls];
|
|
2935
|
+
this.preloadingAdUrls.clear();
|
|
2936
|
+
this.logQueuedAdUrls(this.adPodAllUrls);
|
|
2788
2937
|
this.inAdBreak = true;
|
|
2789
2938
|
this.showAds = true;
|
|
2790
|
-
this.currentAdIndex
|
|
2939
|
+
this.currentAdIndex = 0;
|
|
2940
|
+
this.totalAdsInBreak = vastTagUrls.length;
|
|
2941
|
+
this.adPodQueue = [...vastTagUrls];
|
|
2942
|
+
this.enforceAdHoldState();
|
|
2943
|
+
this.preloadUpcomingAds();
|
|
2944
|
+
if (this.config.debugAdTiming) {
|
|
2945
|
+
console.log(
|
|
2946
|
+
`[StormcloudVideoPlayer] Starting ad pod with ${vastTagUrls.length} ads - will play continuously`
|
|
2947
|
+
);
|
|
2948
|
+
}
|
|
2791
2949
|
try {
|
|
2792
|
-
await this.
|
|
2950
|
+
await this.playAdPod();
|
|
2793
2951
|
} catch (error) {
|
|
2794
2952
|
if (this.config.debugAdTiming) {
|
|
2795
2953
|
console.error(
|
|
2796
|
-
"[StormcloudVideoPlayer] Ad playback failed
|
|
2954
|
+
"[StormcloudVideoPlayer] Ad pod playback failed:",
|
|
2797
2955
|
error
|
|
2798
2956
|
);
|
|
2799
2957
|
}
|
|
@@ -2806,6 +2964,22 @@ var StormcloudVideoPlayer = class {
|
|
|
2806
2964
|
this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
|
|
2807
2965
|
}
|
|
2808
2966
|
}
|
|
2967
|
+
async playAdPod() {
|
|
2968
|
+
if (this.adPodQueue.length === 0) {
|
|
2969
|
+
if (this.config.debugAdTiming) {
|
|
2970
|
+
console.log("[StormcloudVideoPlayer] No ads in pod to play");
|
|
2971
|
+
}
|
|
2972
|
+
return;
|
|
2973
|
+
}
|
|
2974
|
+
const firstAd = this.adPodQueue.shift();
|
|
2975
|
+
this.currentAdIndex++;
|
|
2976
|
+
if (this.config.debugAdTiming) {
|
|
2977
|
+
console.log(
|
|
2978
|
+
`[StormcloudVideoPlayer] Playing ad ${this.currentAdIndex}/${this.totalAdsInBreak}`
|
|
2979
|
+
);
|
|
2980
|
+
}
|
|
2981
|
+
await this.playSingleAd(firstAd);
|
|
2982
|
+
}
|
|
2809
2983
|
findCurrentOrNextBreak(nowMs) {
|
|
2810
2984
|
var _a;
|
|
2811
2985
|
const schedule = [];
|
|
@@ -2837,6 +3011,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2837
3011
|
const first = tags[0];
|
|
2838
3012
|
const rest = tags.slice(1);
|
|
2839
3013
|
this.adPodQueue = rest;
|
|
3014
|
+
this.enforceAdHoldState();
|
|
2840
3015
|
await this.playSingleAd(first);
|
|
2841
3016
|
this.inAdBreak = true;
|
|
2842
3017
|
this.expectedAdBreakDurationMs = remainingMs;
|
|
@@ -2950,6 +3125,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2950
3125
|
}
|
|
2951
3126
|
return;
|
|
2952
3127
|
}
|
|
3128
|
+
const wasPreloaded = this.ima.hasPreloadedAd(vastTagUrl);
|
|
3129
|
+
if (wasPreloaded && this.config.debugAdTiming) {
|
|
3130
|
+
console.log(
|
|
3131
|
+
`[StormcloudVideoPlayer] IMA SDK preloaded this ad already: ${vastTagUrl}`
|
|
3132
|
+
);
|
|
3133
|
+
}
|
|
2953
3134
|
if (!this.showAds) {
|
|
2954
3135
|
if (this.config.debugAdTiming) {
|
|
2955
3136
|
console.log(
|
|
@@ -2970,12 +3151,14 @@ var StormcloudVideoPlayer = class {
|
|
|
2970
3151
|
this.startAdFailsafeTimer();
|
|
2971
3152
|
try {
|
|
2972
3153
|
await this.ima.requestAds(vastTagUrl);
|
|
3154
|
+
this.preloadUpcomingAds();
|
|
2973
3155
|
try {
|
|
2974
3156
|
if (this.config.debugAdTiming) {
|
|
2975
3157
|
console.log(
|
|
2976
3158
|
"[StormcloudVideoPlayer] Ad request completed, attempting playback"
|
|
2977
3159
|
);
|
|
2978
3160
|
}
|
|
3161
|
+
this.enforceAdHoldState();
|
|
2979
3162
|
await this.ima.play();
|
|
2980
3163
|
if (this.config.debugAdTiming) {
|
|
2981
3164
|
console.log(
|
|
@@ -3005,6 +3188,8 @@ var StormcloudVideoPlayer = class {
|
|
|
3005
3188
|
"[StormcloudVideoPlayer] Handling ad pod completion - resuming content and hiding ad layer"
|
|
3006
3189
|
);
|
|
3007
3190
|
}
|
|
3191
|
+
this.releaseAdHoldState();
|
|
3192
|
+
this.preloadingAdUrls.clear();
|
|
3008
3193
|
this.inAdBreak = false;
|
|
3009
3194
|
this.expectedAdBreakDurationMs = void 0;
|
|
3010
3195
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
@@ -3012,6 +3197,7 @@ var StormcloudVideoPlayer = class {
|
|
|
3012
3197
|
this.clearAdStopTimer();
|
|
3013
3198
|
this.clearAdFailsafeTimer();
|
|
3014
3199
|
this.adPodQueue = [];
|
|
3200
|
+
this.adPodAllUrls = [];
|
|
3015
3201
|
this.showAds = false;
|
|
3016
3202
|
this.currentAdIndex = 0;
|
|
3017
3203
|
this.totalAdsInBreak = 0;
|
|
@@ -3092,6 +3278,64 @@ var StormcloudVideoPlayer = class {
|
|
|
3092
3278
|
}
|
|
3093
3279
|
return [b.vastTagUrl];
|
|
3094
3280
|
}
|
|
3281
|
+
logQueuedAdUrls(urls) {
|
|
3282
|
+
if (!this.config.debugAdTiming) {
|
|
3283
|
+
return;
|
|
3284
|
+
}
|
|
3285
|
+
console.log("[StormcloudVideoPlayer] ALL ad URLs queued:", urls);
|
|
3286
|
+
}
|
|
3287
|
+
enforceAdHoldState() {
|
|
3288
|
+
this.video.dataset.stormcloudAdPlaying = "true";
|
|
3289
|
+
this.video.muted = true;
|
|
3290
|
+
this.video.volume = 0;
|
|
3291
|
+
if (typeof this.ima.showPlaceholder === "function") {
|
|
3292
|
+
this.ima.showPlaceholder();
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3295
|
+
releaseAdHoldState() {
|
|
3296
|
+
delete this.video.dataset.stormcloudAdPlaying;
|
|
3297
|
+
if (typeof this.ima.hidePlaceholder === "function") {
|
|
3298
|
+
this.ima.hidePlaceholder();
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
preloadUpcomingAds() {
|
|
3302
|
+
if (!this.ima.preloadAds || this.adPodQueue.length === 0) {
|
|
3303
|
+
return;
|
|
3304
|
+
}
|
|
3305
|
+
const upcoming = this.adPodQueue.slice(0, 2);
|
|
3306
|
+
for (const url of upcoming) {
|
|
3307
|
+
if (!url) continue;
|
|
3308
|
+
if (this.ima.hasPreloadedAd(url)) {
|
|
3309
|
+
this.preloadingAdUrls.delete(url);
|
|
3310
|
+
continue;
|
|
3311
|
+
}
|
|
3312
|
+
if (this.preloadingAdUrls.has(url)) {
|
|
3313
|
+
continue;
|
|
3314
|
+
}
|
|
3315
|
+
if (this.config.debugAdTiming) {
|
|
3316
|
+
console.log(
|
|
3317
|
+
`[StormcloudVideoPlayer] Scheduling IMA preload for upcoming ad: ${url}`
|
|
3318
|
+
);
|
|
3319
|
+
}
|
|
3320
|
+
this.preloadingAdUrls.add(url);
|
|
3321
|
+
this.ima.preloadAds(url).then(() => {
|
|
3322
|
+
if (this.config.debugAdTiming) {
|
|
3323
|
+
console.log(
|
|
3324
|
+
`[StormcloudVideoPlayer] IMA preload complete for ad: ${url}`
|
|
3325
|
+
);
|
|
3326
|
+
}
|
|
3327
|
+
}).catch((error) => {
|
|
3328
|
+
if (this.config.debugAdTiming) {
|
|
3329
|
+
console.warn(
|
|
3330
|
+
`[StormcloudVideoPlayer] IMA preload failed for ad: ${url}`,
|
|
3331
|
+
error
|
|
3332
|
+
);
|
|
3333
|
+
}
|
|
3334
|
+
}).finally(() => {
|
|
3335
|
+
this.preloadingAdUrls.delete(url);
|
|
3336
|
+
});
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3095
3339
|
getRemainingAdMs() {
|
|
3096
3340
|
if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null)
|
|
3097
3341
|
return 0;
|
|
@@ -3243,6 +3487,9 @@ var StormcloudVideoPlayer = class {
|
|
|
3243
3487
|
}
|
|
3244
3488
|
(_a = this.hls) == null ? void 0 : _a.destroy();
|
|
3245
3489
|
(_b = this.ima) == null ? void 0 : _b.destroy();
|
|
3490
|
+
this.releaseAdHoldState();
|
|
3491
|
+
this.preloadingAdUrls.clear();
|
|
3492
|
+
this.adPodAllUrls = [];
|
|
3246
3493
|
}
|
|
3247
3494
|
};
|
|
3248
3495
|
|