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
package/lib/players/index.cjs
CHANGED
|
@@ -115,9 +115,22 @@ function createImaController(video, options) {
|
|
|
115
115
|
'script[data-ima="true"]'
|
|
116
116
|
);
|
|
117
117
|
if (existing) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
if (window.google?.ima) {
|
|
119
|
+
return Promise.resolve();
|
|
120
|
+
}
|
|
121
|
+
return new Promise((resolve, reject) => {
|
|
122
|
+
const timeout = setTimeout(() => {
|
|
123
|
+
reject(new Error("IMA SDK load timeout"));
|
|
124
|
+
}, 1e4);
|
|
125
|
+
existing.addEventListener("load", () => {
|
|
126
|
+
clearTimeout(timeout);
|
|
127
|
+
resolve();
|
|
128
|
+
});
|
|
129
|
+
existing.addEventListener("error", () => {
|
|
130
|
+
clearTimeout(timeout);
|
|
131
|
+
reject(new Error("IMA SDK load failed"));
|
|
132
|
+
});
|
|
133
|
+
});
|
|
121
134
|
}
|
|
122
135
|
return new Promise((resolve, reject) => {
|
|
123
136
|
const script = document.createElement("script");
|
|
@@ -146,6 +159,17 @@ function createImaController(video, options) {
|
|
|
146
159
|
adsRequest.adTagUrl = vastTagUrl;
|
|
147
160
|
adsLoader.requestAds(adsRequest);
|
|
148
161
|
}
|
|
162
|
+
function destroyAdsManager() {
|
|
163
|
+
if (adsManager) {
|
|
164
|
+
try {
|
|
165
|
+
console.log("[IMA] Destroying existing ads manager");
|
|
166
|
+
adsManager.destroy();
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.warn("[IMA] Error destroying ads manager:", error);
|
|
169
|
+
}
|
|
170
|
+
adsManager = void 0;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
149
173
|
return {
|
|
150
174
|
initialize() {
|
|
151
175
|
ensureImaLoaded().then(() => {
|
|
@@ -178,9 +202,22 @@ function createImaController(video, options) {
|
|
|
178
202
|
},
|
|
179
203
|
async requestAds(vastTagUrl) {
|
|
180
204
|
console.log("[IMA] Requesting ads:", vastTagUrl);
|
|
205
|
+
if (adPlaying) {
|
|
206
|
+
console.warn(
|
|
207
|
+
"[IMA] Cannot request new ads while an ad is playing. Call stop() first."
|
|
208
|
+
);
|
|
209
|
+
return Promise.reject(
|
|
210
|
+
new Error("Ad already playing - cannot request new ads")
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
destroyAdsManager();
|
|
214
|
+
adsLoadedReject = void 0;
|
|
215
|
+
adsLoadedResolve = void 0;
|
|
216
|
+
let currentReject;
|
|
181
217
|
adsLoadedPromise = new Promise((resolve, reject) => {
|
|
182
218
|
adsLoadedResolve = resolve;
|
|
183
219
|
adsLoadedReject = reject;
|
|
220
|
+
currentReject = reject;
|
|
184
221
|
setTimeout(() => {
|
|
185
222
|
if (adsLoadedReject) {
|
|
186
223
|
adsLoadedReject(new Error("Ad request timeout"));
|
|
@@ -202,7 +239,7 @@ function createImaController(video, options) {
|
|
|
202
239
|
container.style.top = "0";
|
|
203
240
|
container.style.right = "0";
|
|
204
241
|
container.style.bottom = "0";
|
|
205
|
-
container.style.display = "
|
|
242
|
+
container.style.display = "none";
|
|
206
243
|
container.style.alignItems = "center";
|
|
207
244
|
container.style.justifyContent = "center";
|
|
208
245
|
container.style.pointerEvents = "none";
|
|
@@ -242,14 +279,14 @@ function createImaController(video, options) {
|
|
|
242
279
|
AdErrorEvent.AD_ERROR,
|
|
243
280
|
(errorEvent) => {
|
|
244
281
|
console.error("[IMA] Ad error:", errorEvent.getError());
|
|
245
|
-
|
|
246
|
-
adsManager?.destroy?.();
|
|
247
|
-
} catch {
|
|
248
|
-
}
|
|
282
|
+
destroyAdsManager();
|
|
249
283
|
adPlaying = false;
|
|
250
284
|
video.muted = originalMutedState;
|
|
251
|
-
if (adContainerEl)
|
|
285
|
+
if (adContainerEl) {
|
|
252
286
|
adContainerEl.style.pointerEvents = "none";
|
|
287
|
+
adContainerEl.style.display = "none";
|
|
288
|
+
console.log("[IMA] Ad container hidden after error");
|
|
289
|
+
}
|
|
253
290
|
if (adsLoadedReject) {
|
|
254
291
|
adsLoadedReject(new Error("Ad playback error"));
|
|
255
292
|
adsLoadedReject = void 0;
|
|
@@ -282,10 +319,6 @@ function createImaController(video, options) {
|
|
|
282
319
|
AdEvent.CONTENT_PAUSE_REQUESTED,
|
|
283
320
|
() => {
|
|
284
321
|
console.log("[IMA] Content pause requested");
|
|
285
|
-
if (!adPlaying) {
|
|
286
|
-
originalMutedState = video.muted;
|
|
287
|
-
}
|
|
288
|
-
video.muted = true;
|
|
289
322
|
if (!options?.continueLiveStreamDuringAds) {
|
|
290
323
|
video.pause();
|
|
291
324
|
console.log("[IMA] Video paused (VOD mode)");
|
|
@@ -294,20 +327,34 @@ function createImaController(video, options) {
|
|
|
294
327
|
"[IMA] Video continues playing but muted (Live mode)"
|
|
295
328
|
);
|
|
296
329
|
}
|
|
330
|
+
video.muted = true;
|
|
297
331
|
adPlaying = true;
|
|
298
|
-
if (adContainerEl)
|
|
299
|
-
adContainerEl.style.pointerEvents = "auto";
|
|
300
332
|
emit("content_pause");
|
|
301
333
|
}
|
|
302
334
|
);
|
|
335
|
+
adsManager.addEventListener(AdEvent.STARTED, () => {
|
|
336
|
+
console.log("[IMA] Ad started playing");
|
|
337
|
+
if (adContainerEl) {
|
|
338
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
339
|
+
adContainerEl.style.display = "flex";
|
|
340
|
+
console.log(
|
|
341
|
+
"[IMA] Ad container visibility set to flex with pointer events enabled"
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
303
345
|
adsManager.addEventListener(
|
|
304
346
|
AdEvent.CONTENT_RESUME_REQUESTED,
|
|
305
347
|
() => {
|
|
306
348
|
console.log("[IMA] Content resume requested");
|
|
307
349
|
adPlaying = false;
|
|
308
350
|
video.muted = originalMutedState;
|
|
309
|
-
if (adContainerEl)
|
|
351
|
+
if (adContainerEl) {
|
|
310
352
|
adContainerEl.style.pointerEvents = "none";
|
|
353
|
+
adContainerEl.style.display = "none";
|
|
354
|
+
console.log(
|
|
355
|
+
"[IMA] Ad container hidden - pointer events disabled"
|
|
356
|
+
);
|
|
357
|
+
}
|
|
311
358
|
if (!options?.continueLiveStreamDuringAds) {
|
|
312
359
|
video.play()?.catch(() => {
|
|
313
360
|
});
|
|
@@ -324,7 +371,13 @@ function createImaController(video, options) {
|
|
|
324
371
|
console.log("[IMA] All ads completed");
|
|
325
372
|
adPlaying = false;
|
|
326
373
|
video.muted = originalMutedState;
|
|
327
|
-
if (adContainerEl)
|
|
374
|
+
if (adContainerEl) {
|
|
375
|
+
adContainerEl.style.pointerEvents = "none";
|
|
376
|
+
adContainerEl.style.display = "none";
|
|
377
|
+
console.log(
|
|
378
|
+
"[IMA] Ad container hidden after all ads completed"
|
|
379
|
+
);
|
|
380
|
+
}
|
|
328
381
|
if (!options?.continueLiveStreamDuringAds) {
|
|
329
382
|
video.play().catch(() => {
|
|
330
383
|
});
|
|
@@ -367,6 +420,13 @@ function createImaController(video, options) {
|
|
|
367
420
|
google.ima.AdErrorEvent.Type.AD_ERROR,
|
|
368
421
|
(adErrorEvent) => {
|
|
369
422
|
console.error("[IMA] Ads loader error:", adErrorEvent.getError());
|
|
423
|
+
adPlaying = false;
|
|
424
|
+
video.muted = originalMutedState;
|
|
425
|
+
if (adContainerEl) adContainerEl.style.pointerEvents = "none";
|
|
426
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
427
|
+
video.play().catch(() => {
|
|
428
|
+
});
|
|
429
|
+
}
|
|
370
430
|
if (adsLoadedReject) {
|
|
371
431
|
adsLoadedReject(new Error("Ads loader error"));
|
|
372
432
|
adsLoadedReject = void 0;
|
|
@@ -382,11 +442,9 @@ function createImaController(video, options) {
|
|
|
382
442
|
return adsLoadedPromise;
|
|
383
443
|
} catch (error) {
|
|
384
444
|
console.error("[IMA] Failed to request ads:", error);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
adsLoadedResolve = void 0;
|
|
389
|
-
}
|
|
445
|
+
currentReject?.(error);
|
|
446
|
+
adsLoadedReject = void 0;
|
|
447
|
+
adsLoadedResolve = void 0;
|
|
390
448
|
return Promise.reject(error);
|
|
391
449
|
}
|
|
392
450
|
},
|
|
@@ -423,10 +481,16 @@ function createImaController(video, options) {
|
|
|
423
481
|
async stop() {
|
|
424
482
|
adPlaying = false;
|
|
425
483
|
video.muted = originalMutedState;
|
|
484
|
+
if (adContainerEl) {
|
|
485
|
+
adContainerEl.style.pointerEvents = "none";
|
|
486
|
+
adContainerEl.style.display = "none";
|
|
487
|
+
console.log("[IMA] Ad container hidden after stop");
|
|
488
|
+
}
|
|
426
489
|
try {
|
|
427
490
|
adsManager?.stop?.();
|
|
428
491
|
} catch {
|
|
429
492
|
}
|
|
493
|
+
destroyAdsManager();
|
|
430
494
|
if (!options?.continueLiveStreamDuringAds) {
|
|
431
495
|
video.play().catch(() => {
|
|
432
496
|
});
|
|
@@ -436,12 +500,13 @@ function createImaController(video, options) {
|
|
|
436
500
|
}
|
|
437
501
|
},
|
|
438
502
|
destroy() {
|
|
439
|
-
|
|
440
|
-
adsManager?.destroy?.();
|
|
441
|
-
} catch {
|
|
442
|
-
}
|
|
503
|
+
destroyAdsManager();
|
|
443
504
|
adPlaying = false;
|
|
444
505
|
video.muted = originalMutedState;
|
|
506
|
+
if (adContainerEl) {
|
|
507
|
+
adContainerEl.style.pointerEvents = "none";
|
|
508
|
+
adContainerEl.style.display = "none";
|
|
509
|
+
}
|
|
445
510
|
try {
|
|
446
511
|
adsLoader?.destroy?.();
|
|
447
512
|
} catch {
|
|
@@ -449,6 +514,9 @@ function createImaController(video, options) {
|
|
|
449
514
|
if (adContainerEl?.parentElement) {
|
|
450
515
|
adContainerEl.parentElement.removeChild(adContainerEl);
|
|
451
516
|
}
|
|
517
|
+
adContainerEl = void 0;
|
|
518
|
+
adDisplayContainer = void 0;
|
|
519
|
+
adsLoader = void 0;
|
|
452
520
|
},
|
|
453
521
|
isAdPlaying() {
|
|
454
522
|
return adPlaying;
|
|
@@ -926,17 +994,8 @@ var StormcloudVideoPlayer = class {
|
|
|
926
994
|
this.video.muted = !!this.config.muted;
|
|
927
995
|
this.ima.initialize();
|
|
928
996
|
this.ima.on("all_ads_completed", () => {
|
|
929
|
-
if (
|
|
930
|
-
|
|
931
|
-
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
932
|
-
const next = this.adPodQueue.shift();
|
|
933
|
-
this.currentAdIndex++;
|
|
934
|
-
this.playSingleAd(next).catch(() => {
|
|
935
|
-
});
|
|
936
|
-
} else {
|
|
937
|
-
this.currentAdIndex = 0;
|
|
938
|
-
this.totalAdsInBreak = 0;
|
|
939
|
-
this.showAds = false;
|
|
997
|
+
if (this.config.debugAdTiming) {
|
|
998
|
+
console.log("[StormcloudVideoPlayer] IMA all_ads_completed event received");
|
|
940
999
|
}
|
|
941
1000
|
});
|
|
942
1001
|
this.ima.on("ad_error", () => {
|
|
@@ -967,6 +1026,26 @@ var StormcloudVideoPlayer = class {
|
|
|
967
1026
|
);
|
|
968
1027
|
}
|
|
969
1028
|
this.clearAdFailsafeTimer();
|
|
1029
|
+
if (!this.inAdBreak) return;
|
|
1030
|
+
const remaining = this.getRemainingAdMs();
|
|
1031
|
+
if (remaining > 500 && this.adPodQueue.length > 0) {
|
|
1032
|
+
const next = this.adPodQueue.shift();
|
|
1033
|
+
this.currentAdIndex++;
|
|
1034
|
+
if (this.config.debugAdTiming) {
|
|
1035
|
+
console.log(
|
|
1036
|
+
`[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak})`
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
this.playSingleAd(next).catch(() => {
|
|
1040
|
+
});
|
|
1041
|
+
} else {
|
|
1042
|
+
if (this.config.debugAdTiming) {
|
|
1043
|
+
console.log("[StormcloudVideoPlayer] Ad pod completed");
|
|
1044
|
+
}
|
|
1045
|
+
this.currentAdIndex = 0;
|
|
1046
|
+
this.totalAdsInBreak = 0;
|
|
1047
|
+
this.showAds = false;
|
|
1048
|
+
}
|
|
970
1049
|
});
|
|
971
1050
|
this.video.addEventListener("timeupdate", () => {
|
|
972
1051
|
this.onTimeUpdate(this.video.currentTime);
|
|
@@ -1616,21 +1695,21 @@ var StormcloudVideoPlayer = class {
|
|
|
1616
1695
|
if (this.config.debugAdTiming) {
|
|
1617
1696
|
console.log("[StormcloudVideoPlayer] Attempting to play ad:", vastTagUrl);
|
|
1618
1697
|
}
|
|
1619
|
-
this.ima.
|
|
1620
|
-
if (!this.shouldContinueLiveStreamDuringAds()) {
|
|
1621
|
-
if (this.config.debugAdTiming) {
|
|
1622
|
-
console.log("[StormcloudVideoPlayer] Pausing video immediately for ad (VOD mode)");
|
|
1623
|
-
}
|
|
1624
|
-
this.video.pause();
|
|
1625
|
-
} else {
|
|
1698
|
+
if (this.ima.isAdPlaying()) {
|
|
1626
1699
|
if (this.config.debugAdTiming) {
|
|
1627
|
-
console.
|
|
1700
|
+
console.warn(
|
|
1701
|
+
"[StormcloudVideoPlayer] Ad already playing - skipping new ad request"
|
|
1702
|
+
);
|
|
1628
1703
|
}
|
|
1629
|
-
|
|
1704
|
+
return;
|
|
1630
1705
|
}
|
|
1706
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
1631
1707
|
this.startAdFailsafeTimer();
|
|
1632
1708
|
try {
|
|
1633
1709
|
await this.ima.requestAds(vastTagUrl);
|
|
1710
|
+
if (this.config.debugAdTiming) {
|
|
1711
|
+
console.log("[StormcloudVideoPlayer] Ad request successful, starting playback");
|
|
1712
|
+
}
|
|
1634
1713
|
await this.ima.play();
|
|
1635
1714
|
if (this.config.debugAdTiming) {
|
|
1636
1715
|
console.log("[StormcloudVideoPlayer] Ad playback started successfully");
|
|
@@ -1658,6 +1737,13 @@ var StormcloudVideoPlayer = class {
|
|
|
1658
1737
|
this.showAds = false;
|
|
1659
1738
|
this.currentAdIndex = 0;
|
|
1660
1739
|
this.totalAdsInBreak = 0;
|
|
1740
|
+
const originalMutedState = this.ima.getOriginalMutedState();
|
|
1741
|
+
this.video.muted = originalMutedState;
|
|
1742
|
+
if (this.config.debugAdTiming) {
|
|
1743
|
+
console.log(
|
|
1744
|
+
`[StormcloudVideoPlayer] Restored mute state to: ${originalMutedState}`
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1661
1747
|
if (this.video.paused) {
|
|
1662
1748
|
this.video.play()?.catch(() => {
|
|
1663
1749
|
if (this.config.debugAdTiming) {
|