stormcloud-video-player 0.2.9 → 0.2.10
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 +1 -1
- package/lib/index.cjs +395 -98
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +395 -98
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +132 -46
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +132 -46
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +132 -46
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/ima.cjs +94 -26
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +395 -98
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
|
@@ -73,9 +73,22 @@ function createImaController(video, options) {
|
|
|
73
73
|
'script[data-ima="true"]'
|
|
74
74
|
);
|
|
75
75
|
if (existing) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
if (window.google?.ima) {
|
|
77
|
+
return Promise.resolve();
|
|
78
|
+
}
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const timeout = setTimeout(() => {
|
|
81
|
+
reject(new Error("IMA SDK load timeout"));
|
|
82
|
+
}, 1e4);
|
|
83
|
+
existing.addEventListener("load", () => {
|
|
84
|
+
clearTimeout(timeout);
|
|
85
|
+
resolve();
|
|
86
|
+
});
|
|
87
|
+
existing.addEventListener("error", () => {
|
|
88
|
+
clearTimeout(timeout);
|
|
89
|
+
reject(new Error("IMA SDK load failed"));
|
|
90
|
+
});
|
|
91
|
+
});
|
|
79
92
|
}
|
|
80
93
|
return new Promise((resolve, reject) => {
|
|
81
94
|
const script = document.createElement("script");
|
|
@@ -104,6 +117,17 @@ function createImaController(video, options) {
|
|
|
104
117
|
adsRequest.adTagUrl = vastTagUrl;
|
|
105
118
|
adsLoader.requestAds(adsRequest);
|
|
106
119
|
}
|
|
120
|
+
function destroyAdsManager() {
|
|
121
|
+
if (adsManager) {
|
|
122
|
+
try {
|
|
123
|
+
console.log("[IMA] Destroying existing ads manager");
|
|
124
|
+
adsManager.destroy();
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.warn("[IMA] Error destroying ads manager:", error);
|
|
127
|
+
}
|
|
128
|
+
adsManager = void 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
107
131
|
return {
|
|
108
132
|
initialize() {
|
|
109
133
|
ensureImaLoaded().then(() => {
|
|
@@ -136,9 +160,22 @@ function createImaController(video, options) {
|
|
|
136
160
|
},
|
|
137
161
|
async requestAds(vastTagUrl) {
|
|
138
162
|
console.log("[IMA] Requesting ads:", vastTagUrl);
|
|
163
|
+
if (adPlaying) {
|
|
164
|
+
console.warn(
|
|
165
|
+
"[IMA] Cannot request new ads while an ad is playing. Call stop() first."
|
|
166
|
+
);
|
|
167
|
+
return Promise.reject(
|
|
168
|
+
new Error("Ad already playing - cannot request new ads")
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
destroyAdsManager();
|
|
172
|
+
adsLoadedReject = void 0;
|
|
173
|
+
adsLoadedResolve = void 0;
|
|
174
|
+
let currentReject;
|
|
139
175
|
adsLoadedPromise = new Promise((resolve, reject) => {
|
|
140
176
|
adsLoadedResolve = resolve;
|
|
141
177
|
adsLoadedReject = reject;
|
|
178
|
+
currentReject = reject;
|
|
142
179
|
setTimeout(() => {
|
|
143
180
|
if (adsLoadedReject) {
|
|
144
181
|
adsLoadedReject(new Error("Ad request timeout"));
|
|
@@ -160,7 +197,7 @@ function createImaController(video, options) {
|
|
|
160
197
|
container.style.top = "0";
|
|
161
198
|
container.style.right = "0";
|
|
162
199
|
container.style.bottom = "0";
|
|
163
|
-
container.style.display = "
|
|
200
|
+
container.style.display = "none";
|
|
164
201
|
container.style.alignItems = "center";
|
|
165
202
|
container.style.justifyContent = "center";
|
|
166
203
|
container.style.pointerEvents = "none";
|
|
@@ -200,14 +237,14 @@ function createImaController(video, options) {
|
|
|
200
237
|
AdErrorEvent.AD_ERROR,
|
|
201
238
|
(errorEvent) => {
|
|
202
239
|
console.error("[IMA] Ad error:", errorEvent.getError());
|
|
203
|
-
|
|
204
|
-
adsManager?.destroy?.();
|
|
205
|
-
} catch {
|
|
206
|
-
}
|
|
240
|
+
destroyAdsManager();
|
|
207
241
|
adPlaying = false;
|
|
208
242
|
video.muted = originalMutedState;
|
|
209
|
-
if (adContainerEl)
|
|
243
|
+
if (adContainerEl) {
|
|
210
244
|
adContainerEl.style.pointerEvents = "none";
|
|
245
|
+
adContainerEl.style.display = "none";
|
|
246
|
+
console.log("[IMA] Ad container hidden after error");
|
|
247
|
+
}
|
|
211
248
|
if (adsLoadedReject) {
|
|
212
249
|
adsLoadedReject(new Error("Ad playback error"));
|
|
213
250
|
adsLoadedReject = void 0;
|
|
@@ -240,10 +277,6 @@ function createImaController(video, options) {
|
|
|
240
277
|
AdEvent.CONTENT_PAUSE_REQUESTED,
|
|
241
278
|
() => {
|
|
242
279
|
console.log("[IMA] Content pause requested");
|
|
243
|
-
if (!adPlaying) {
|
|
244
|
-
originalMutedState = video.muted;
|
|
245
|
-
}
|
|
246
|
-
video.muted = true;
|
|
247
280
|
if (!options?.continueLiveStreamDuringAds) {
|
|
248
281
|
video.pause();
|
|
249
282
|
console.log("[IMA] Video paused (VOD mode)");
|
|
@@ -252,20 +285,34 @@ function createImaController(video, options) {
|
|
|
252
285
|
"[IMA] Video continues playing but muted (Live mode)"
|
|
253
286
|
);
|
|
254
287
|
}
|
|
288
|
+
video.muted = true;
|
|
255
289
|
adPlaying = true;
|
|
256
|
-
if (adContainerEl)
|
|
257
|
-
adContainerEl.style.pointerEvents = "auto";
|
|
258
290
|
emit("content_pause");
|
|
259
291
|
}
|
|
260
292
|
);
|
|
293
|
+
adsManager.addEventListener(AdEvent.STARTED, () => {
|
|
294
|
+
console.log("[IMA] Ad started playing");
|
|
295
|
+
if (adContainerEl) {
|
|
296
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
297
|
+
adContainerEl.style.display = "flex";
|
|
298
|
+
console.log(
|
|
299
|
+
"[IMA] Ad container visibility set to flex with pointer events enabled"
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
261
303
|
adsManager.addEventListener(
|
|
262
304
|
AdEvent.CONTENT_RESUME_REQUESTED,
|
|
263
305
|
() => {
|
|
264
306
|
console.log("[IMA] Content resume requested");
|
|
265
307
|
adPlaying = false;
|
|
266
308
|
video.muted = originalMutedState;
|
|
267
|
-
if (adContainerEl)
|
|
309
|
+
if (adContainerEl) {
|
|
268
310
|
adContainerEl.style.pointerEvents = "none";
|
|
311
|
+
adContainerEl.style.display = "none";
|
|
312
|
+
console.log(
|
|
313
|
+
"[IMA] Ad container hidden - pointer events disabled"
|
|
314
|
+
);
|
|
315
|
+
}
|
|
269
316
|
if (!options?.continueLiveStreamDuringAds) {
|
|
270
317
|
video.play()?.catch(() => {
|
|
271
318
|
});
|
|
@@ -282,7 +329,13 @@ function createImaController(video, options) {
|
|
|
282
329
|
console.log("[IMA] All ads completed");
|
|
283
330
|
adPlaying = false;
|
|
284
331
|
video.muted = originalMutedState;
|
|
285
|
-
if (adContainerEl)
|
|
332
|
+
if (adContainerEl) {
|
|
333
|
+
adContainerEl.style.pointerEvents = "none";
|
|
334
|
+
adContainerEl.style.display = "none";
|
|
335
|
+
console.log(
|
|
336
|
+
"[IMA] Ad container hidden after all ads completed"
|
|
337
|
+
);
|
|
338
|
+
}
|
|
286
339
|
if (!options?.continueLiveStreamDuringAds) {
|
|
287
340
|
video.play().catch(() => {
|
|
288
341
|
});
|
|
@@ -325,6 +378,13 @@ function createImaController(video, options) {
|
|
|
325
378
|
google.ima.AdErrorEvent.Type.AD_ERROR,
|
|
326
379
|
(adErrorEvent) => {
|
|
327
380
|
console.error("[IMA] Ads loader error:", adErrorEvent.getError());
|
|
381
|
+
adPlaying = false;
|
|
382
|
+
video.muted = originalMutedState;
|
|
383
|
+
if (adContainerEl) adContainerEl.style.pointerEvents = "none";
|
|
384
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
385
|
+
video.play().catch(() => {
|
|
386
|
+
});
|
|
387
|
+
}
|
|
328
388
|
if (adsLoadedReject) {
|
|
329
389
|
adsLoadedReject(new Error("Ads loader error"));
|
|
330
390
|
adsLoadedReject = void 0;
|
|
@@ -340,11 +400,9 @@ function createImaController(video, options) {
|
|
|
340
400
|
return adsLoadedPromise;
|
|
341
401
|
} catch (error) {
|
|
342
402
|
console.error("[IMA] Failed to request ads:", error);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
adsLoadedResolve = void 0;
|
|
347
|
-
}
|
|
403
|
+
currentReject?.(error);
|
|
404
|
+
adsLoadedReject = void 0;
|
|
405
|
+
adsLoadedResolve = void 0;
|
|
348
406
|
return Promise.reject(error);
|
|
349
407
|
}
|
|
350
408
|
},
|
|
@@ -381,10 +439,16 @@ function createImaController(video, options) {
|
|
|
381
439
|
async stop() {
|
|
382
440
|
adPlaying = false;
|
|
383
441
|
video.muted = originalMutedState;
|
|
442
|
+
if (adContainerEl) {
|
|
443
|
+
adContainerEl.style.pointerEvents = "none";
|
|
444
|
+
adContainerEl.style.display = "none";
|
|
445
|
+
console.log("[IMA] Ad container hidden after stop");
|
|
446
|
+
}
|
|
384
447
|
try {
|
|
385
448
|
adsManager?.stop?.();
|
|
386
449
|
} catch {
|
|
387
450
|
}
|
|
451
|
+
destroyAdsManager();
|
|
388
452
|
if (!options?.continueLiveStreamDuringAds) {
|
|
389
453
|
video.play().catch(() => {
|
|
390
454
|
});
|
|
@@ -394,12 +458,13 @@ function createImaController(video, options) {
|
|
|
394
458
|
}
|
|
395
459
|
},
|
|
396
460
|
destroy() {
|
|
397
|
-
|
|
398
|
-
adsManager?.destroy?.();
|
|
399
|
-
} catch {
|
|
400
|
-
}
|
|
461
|
+
destroyAdsManager();
|
|
401
462
|
adPlaying = false;
|
|
402
463
|
video.muted = originalMutedState;
|
|
464
|
+
if (adContainerEl) {
|
|
465
|
+
adContainerEl.style.pointerEvents = "none";
|
|
466
|
+
adContainerEl.style.display = "none";
|
|
467
|
+
}
|
|
403
468
|
try {
|
|
404
469
|
adsLoader?.destroy?.();
|
|
405
470
|
} catch {
|
|
@@ -407,6 +472,9 @@ function createImaController(video, options) {
|
|
|
407
472
|
if (adContainerEl?.parentElement) {
|
|
408
473
|
adContainerEl.parentElement.removeChild(adContainerEl);
|
|
409
474
|
}
|
|
475
|
+
adContainerEl = void 0;
|
|
476
|
+
adDisplayContainer = void 0;
|
|
477
|
+
adsLoader = void 0;
|
|
410
478
|
},
|
|
411
479
|
isAdPlaying() {
|
|
412
480
|
return adPlaying;
|
|
@@ -884,17 +952,8 @@ var StormcloudVideoPlayer = class {
|
|
|
884
952
|
this.video.muted = !!this.config.muted;
|
|
885
953
|
this.ima.initialize();
|
|
886
954
|
this.ima.on("all_ads_completed", () => {
|
|
887
|
-
if (
|
|
888
|
-
|
|
889
|
-
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
890
|
-
const next = this.adPodQueue.shift();
|
|
891
|
-
this.currentAdIndex++;
|
|
892
|
-
this.playSingleAd(next).catch(() => {
|
|
893
|
-
});
|
|
894
|
-
} else {
|
|
895
|
-
this.currentAdIndex = 0;
|
|
896
|
-
this.totalAdsInBreak = 0;
|
|
897
|
-
this.showAds = false;
|
|
955
|
+
if (this.config.debugAdTiming) {
|
|
956
|
+
console.log("[StormcloudVideoPlayer] IMA all_ads_completed event received");
|
|
898
957
|
}
|
|
899
958
|
});
|
|
900
959
|
this.ima.on("ad_error", () => {
|
|
@@ -925,6 +984,26 @@ var StormcloudVideoPlayer = class {
|
|
|
925
984
|
);
|
|
926
985
|
}
|
|
927
986
|
this.clearAdFailsafeTimer();
|
|
987
|
+
if (!this.inAdBreak) return;
|
|
988
|
+
const remaining = this.getRemainingAdMs();
|
|
989
|
+
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
990
|
+
const next = this.adPodQueue.shift();
|
|
991
|
+
this.currentAdIndex++;
|
|
992
|
+
if (this.config.debugAdTiming) {
|
|
993
|
+
console.log(
|
|
994
|
+
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak})`
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
this.playSingleAd(next).catch(() => {
|
|
998
|
+
});
|
|
999
|
+
} else {
|
|
1000
|
+
if (this.config.debugAdTiming) {
|
|
1001
|
+
console.log("[StormcloudVideoPlayer] Ad pod completed");
|
|
1002
|
+
}
|
|
1003
|
+
this.currentAdIndex = 0;
|
|
1004
|
+
this.totalAdsInBreak = 0;
|
|
1005
|
+
this.showAds = false;
|
|
1006
|
+
}
|
|
928
1007
|
});
|
|
929
1008
|
this.video.addEventListener("timeupdate", () => {
|
|
930
1009
|
this.onTimeUpdate(this.video.currentTime);
|
|
@@ -1574,21 +1653,21 @@ var StormcloudVideoPlayer = class {
|
|
|
1574
1653
|
if (this.config.debugAdTiming) {
|
|
1575
1654
|
console.log("[StormcloudVideoPlayer] Attempting to play ad:", vastTagUrl);
|
|
1576
1655
|
}
|
|
1577
|
-
this.ima.
|
|
1578
|
-
if (!this.shouldContinueLiveStreamDuringAds()) {
|
|
1579
|
-
if (this.config.debugAdTiming) {
|
|
1580
|
-
console.log("[StormcloudVideoPlayer] Pausing video immediately for ad (VOD mode)");
|
|
1581
|
-
}
|
|
1582
|
-
this.video.pause();
|
|
1583
|
-
} else {
|
|
1656
|
+
if (this.ima.isAdPlaying()) {
|
|
1584
1657
|
if (this.config.debugAdTiming) {
|
|
1585
|
-
console.
|
|
1658
|
+
console.warn(
|
|
1659
|
+
"[StormcloudVideoPlayer] Ad already playing - skipping new ad request"
|
|
1660
|
+
);
|
|
1586
1661
|
}
|
|
1587
|
-
|
|
1662
|
+
return;
|
|
1588
1663
|
}
|
|
1664
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
1589
1665
|
this.startAdFailsafeTimer();
|
|
1590
1666
|
try {
|
|
1591
1667
|
await this.ima.requestAds(vastTagUrl);
|
|
1668
|
+
if (this.config.debugAdTiming) {
|
|
1669
|
+
console.log("[StormcloudVideoPlayer] Ad request successful, starting playback");
|
|
1670
|
+
}
|
|
1592
1671
|
await this.ima.play();
|
|
1593
1672
|
if (this.config.debugAdTiming) {
|
|
1594
1673
|
console.log("[StormcloudVideoPlayer] Ad playback started successfully");
|
|
@@ -1616,6 +1695,13 @@ var StormcloudVideoPlayer = class {
|
|
|
1616
1695
|
this.showAds = false;
|
|
1617
1696
|
this.currentAdIndex = 0;
|
|
1618
1697
|
this.totalAdsInBreak = 0;
|
|
1698
|
+
const originalMutedState = this.ima.getOriginalMutedState();
|
|
1699
|
+
this.video.muted = originalMutedState;
|
|
1700
|
+
if (this.config.debugAdTiming) {
|
|
1701
|
+
console.log(
|
|
1702
|
+
`[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
|
|
1703
|
+
);
|
|
1704
|
+
}
|
|
1619
1705
|
if (this.video.paused) {
|
|
1620
1706
|
this.video.play()?.catch(() => {
|
|
1621
1707
|
if (this.config.debugAdTiming) {
|