stormcloud-video-player 0.2.16 → 0.2.18
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 +387 -56
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +6 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +387 -56
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +266 -23
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +5 -1
- package/lib/players/HlsPlayer.cjs +268 -23
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +268 -23
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs +76 -12
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.d.cts +1 -1
- package/lib/sdk/ima.cjs +73 -2
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/sdk/ima.d.cts +1 -1
- package/lib/{types-mVgmKmzM.d.cts → types-J6-Dpcvw.d.cts} +1 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +383 -56
- 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-J6-Dpcvw.cjs';
|
|
2
2
|
|
|
3
3
|
declare class StormcloudVideoPlayer {
|
|
4
4
|
private readonly video;
|
|
@@ -23,6 +23,9 @@ declare class StormcloudVideoPlayer {
|
|
|
23
23
|
private isLiveStream;
|
|
24
24
|
private nativeHlsMode;
|
|
25
25
|
private videoSrcProtection;
|
|
26
|
+
private bufferedSegmentsCount;
|
|
27
|
+
private shouldAutoplayAfterBuffering;
|
|
28
|
+
private hasInitialBufferCompleted;
|
|
26
29
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
27
30
|
private createAdPlayer;
|
|
28
31
|
load(): Promise<void>;
|
|
@@ -68,6 +71,7 @@ declare class StormcloudVideoPlayer {
|
|
|
68
71
|
toggleMute(): void;
|
|
69
72
|
toggleFullscreen(): Promise<void>;
|
|
70
73
|
isMuted(): boolean;
|
|
74
|
+
setMuted(muted: boolean): void;
|
|
71
75
|
isFullscreen(): boolean;
|
|
72
76
|
isLive(): boolean;
|
|
73
77
|
get videoElement(): HTMLVideoElement;
|
|
@@ -203,6 +203,13 @@ function createImaController(video, options) {
|
|
|
203
203
|
let adPlaying = false;
|
|
204
204
|
let originalMutedState = false;
|
|
205
205
|
const listeners = /* @__PURE__ */ new Map();
|
|
206
|
+
function setAdPlayingFlag(isPlaying) {
|
|
207
|
+
if (isPlaying) {
|
|
208
|
+
video.dataset.stormcloudAdPlaying = "true";
|
|
209
|
+
} else {
|
|
210
|
+
delete video.dataset.stormcloudAdPlaying;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
206
213
|
function emit(event, payload) {
|
|
207
214
|
const set = listeners.get(event);
|
|
208
215
|
if (!set) return;
|
|
@@ -287,6 +294,14 @@ function createImaController(video, options) {
|
|
|
287
294
|
function makeAdsRequest(google, vastTagUrl) {
|
|
288
295
|
const adsRequest = new google.ima.AdsRequest();
|
|
289
296
|
adsRequest.adTagUrl = vastTagUrl;
|
|
297
|
+
const videoWidth = video.offsetWidth || video.clientWidth || 640;
|
|
298
|
+
const videoHeight = video.offsetHeight || video.clientHeight || 360;
|
|
299
|
+
adsRequest.linearAdSlotWidth = videoWidth;
|
|
300
|
+
adsRequest.linearAdSlotHeight = videoHeight;
|
|
301
|
+
adsRequest.nonLinearAdSlotWidth = videoWidth;
|
|
302
|
+
adsRequest.nonLinearAdSlotHeight = videoHeight;
|
|
303
|
+
adsRequest.vastLoadTimeout = 5e3;
|
|
304
|
+
console.log(`[IMA] Ads request dimensions: ${videoWidth}x${videoHeight}`);
|
|
290
305
|
adsLoader.requestAds(adsRequest);
|
|
291
306
|
}
|
|
292
307
|
function destroyAdsManager() {
|
|
@@ -333,6 +348,18 @@ function createImaController(video, options) {
|
|
|
333
348
|
},
|
|
334
349
|
async requestAds(vastTagUrl) {
|
|
335
350
|
console.log("[IMA] Requesting ads:", vastTagUrl);
|
|
351
|
+
if (!vastTagUrl || vastTagUrl.trim() === "") {
|
|
352
|
+
const error = new Error("VAST tag URL is empty or undefined");
|
|
353
|
+
console.warn("[IMA]", error.message);
|
|
354
|
+
return Promise.reject(error);
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
new URL(vastTagUrl);
|
|
358
|
+
} catch (e) {
|
|
359
|
+
const error = new Error(`Invalid VAST tag URL format: ${vastTagUrl}`);
|
|
360
|
+
console.warn("[IMA]", error.message);
|
|
361
|
+
return Promise.reject(error);
|
|
362
|
+
}
|
|
336
363
|
if (adPlaying) {
|
|
337
364
|
console.warn(
|
|
338
365
|
"[IMA] Cannot request new ads while an ad is playing. Call stop() first."
|
|
@@ -394,6 +421,18 @@ function createImaController(video, options) {
|
|
|
394
421
|
);
|
|
395
422
|
}
|
|
396
423
|
}
|
|
424
|
+
const videoWidth = video.offsetWidth || video.clientWidth;
|
|
425
|
+
const videoHeight = video.offsetHeight || video.clientHeight;
|
|
426
|
+
if (!videoWidth || !videoHeight || videoWidth === 0 || videoHeight === 0) {
|
|
427
|
+
const error = new Error(
|
|
428
|
+
`Invalid video dimensions: ${videoWidth}x${videoHeight}. Cannot initialize ads.`
|
|
429
|
+
);
|
|
430
|
+
console.warn("[IMA]", error.message);
|
|
431
|
+
currentReject == null ? void 0 : currentReject(error);
|
|
432
|
+
adsLoadedReject = void 0;
|
|
433
|
+
adsLoadedResolve = void 0;
|
|
434
|
+
return Promise.reject(error);
|
|
435
|
+
}
|
|
397
436
|
if (!adsLoader) {
|
|
398
437
|
console.log("[IMA] Creating ads loader");
|
|
399
438
|
const adsLoaderCls = new google.ima.AdsLoader(adDisplayContainer);
|
|
@@ -413,7 +452,12 @@ function createImaController(video, options) {
|
|
|
413
452
|
console.error("[IMA] Ad error:", errorEvent.getError());
|
|
414
453
|
destroyAdsManager();
|
|
415
454
|
adPlaying = false;
|
|
455
|
+
const previousMutedState = video.muted;
|
|
416
456
|
video.muted = originalMutedState;
|
|
457
|
+
setAdPlayingFlag(false);
|
|
458
|
+
console.log(
|
|
459
|
+
`[IMA] Restored mute state after ad error: ${previousMutedState} -> ${originalMutedState}`
|
|
460
|
+
);
|
|
417
461
|
if (adContainerEl) {
|
|
418
462
|
adContainerEl.style.pointerEvents = "none";
|
|
419
463
|
adContainerEl.style.display = "none";
|
|
@@ -442,7 +486,9 @@ function createImaController(video, options) {
|
|
|
442
486
|
emit("ad_error");
|
|
443
487
|
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
444
488
|
if (video.paused) {
|
|
445
|
-
console.log(
|
|
489
|
+
console.log(
|
|
490
|
+
"[IMA] Resuming paused video after ad error"
|
|
491
|
+
);
|
|
446
492
|
(_a = video.play()) == null ? void 0 : _a.catch(() => {
|
|
447
493
|
});
|
|
448
494
|
}
|
|
@@ -464,11 +510,13 @@ function createImaController(video, options) {
|
|
|
464
510
|
}
|
|
465
511
|
video.muted = true;
|
|
466
512
|
adPlaying = true;
|
|
513
|
+
setAdPlayingFlag(true);
|
|
467
514
|
emit("content_pause");
|
|
468
515
|
}
|
|
469
516
|
);
|
|
470
517
|
adsManager.addEventListener(AdEvent.STARTED, () => {
|
|
471
518
|
console.log("[IMA] Ad started playing");
|
|
519
|
+
setAdPlayingFlag(true);
|
|
472
520
|
if (adContainerEl) {
|
|
473
521
|
adContainerEl.style.pointerEvents = "auto";
|
|
474
522
|
adContainerEl.style.display = "flex";
|
|
@@ -484,6 +532,7 @@ function createImaController(video, options) {
|
|
|
484
532
|
console.log("[IMA] Content resume requested");
|
|
485
533
|
adPlaying = false;
|
|
486
534
|
video.muted = originalMutedState;
|
|
535
|
+
setAdPlayingFlag(false);
|
|
487
536
|
if (adContainerEl) {
|
|
488
537
|
adContainerEl.style.pointerEvents = "none";
|
|
489
538
|
adContainerEl.style.display = "none";
|
|
@@ -507,6 +556,7 @@ function createImaController(video, options) {
|
|
|
507
556
|
console.log("[IMA] All ads completed");
|
|
508
557
|
adPlaying = false;
|
|
509
558
|
video.muted = originalMutedState;
|
|
559
|
+
setAdPlayingFlag(false);
|
|
510
560
|
if (adContainerEl) {
|
|
511
561
|
adContainerEl.style.pointerEvents = "none";
|
|
512
562
|
adContainerEl.style.display = "none";
|
|
@@ -537,6 +587,7 @@ function createImaController(video, options) {
|
|
|
537
587
|
console.error("[IMA] Error setting up ads manager:", e);
|
|
538
588
|
adPlaying = false;
|
|
539
589
|
video.muted = originalMutedState;
|
|
590
|
+
setAdPlayingFlag(false);
|
|
540
591
|
if (adContainerEl) {
|
|
541
592
|
adContainerEl.style.pointerEvents = "none";
|
|
542
593
|
adContainerEl.style.display = "none";
|
|
@@ -544,7 +595,9 @@ function createImaController(video, options) {
|
|
|
544
595
|
}
|
|
545
596
|
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
546
597
|
if (video.paused) {
|
|
547
|
-
console.log(
|
|
598
|
+
console.log(
|
|
599
|
+
"[IMA] Resuming paused video after setup error"
|
|
600
|
+
);
|
|
548
601
|
video.play().catch(() => {
|
|
549
602
|
});
|
|
550
603
|
}
|
|
@@ -564,7 +617,12 @@ function createImaController(video, options) {
|
|
|
564
617
|
(adErrorEvent) => {
|
|
565
618
|
console.error("[IMA] Ads loader error:", adErrorEvent.getError());
|
|
566
619
|
adPlaying = false;
|
|
620
|
+
const previousMutedState = video.muted;
|
|
567
621
|
video.muted = originalMutedState;
|
|
622
|
+
setAdPlayingFlag(false);
|
|
623
|
+
console.log(
|
|
624
|
+
`[IMA] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
|
|
625
|
+
);
|
|
568
626
|
if (adContainerEl) {
|
|
569
627
|
adContainerEl.style.pointerEvents = "none";
|
|
570
628
|
adContainerEl.style.display = "none";
|
|
@@ -616,12 +674,20 @@ function createImaController(video, options) {
|
|
|
616
674
|
console.log(`[IMA] Initializing ads manager (${width}x${height})`);
|
|
617
675
|
adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
|
|
618
676
|
adPlaying = true;
|
|
677
|
+
const adVolume = originalMutedState ? 0 : video.volume;
|
|
678
|
+
try {
|
|
679
|
+
adsManager.setVolume(adVolume);
|
|
680
|
+
console.log(`[IMA] Set ad volume to ${adVolume}`);
|
|
681
|
+
} catch (error) {
|
|
682
|
+
console.warn("[IMA] Failed to set ad volume:", error);
|
|
683
|
+
}
|
|
619
684
|
console.log("[IMA] Starting ad playback");
|
|
620
685
|
adsManager.start();
|
|
621
686
|
return Promise.resolve();
|
|
622
687
|
} catch (error) {
|
|
623
688
|
console.error("[IMA] Error starting ad playback:", error);
|
|
624
689
|
adPlaying = false;
|
|
690
|
+
setAdPlayingFlag(false);
|
|
625
691
|
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
626
692
|
(_b = video.play()) == null ? void 0 : _b.catch(() => {
|
|
627
693
|
});
|
|
@@ -633,6 +699,7 @@ function createImaController(video, options) {
|
|
|
633
699
|
var _a;
|
|
634
700
|
adPlaying = false;
|
|
635
701
|
video.muted = originalMutedState;
|
|
702
|
+
setAdPlayingFlag(false);
|
|
636
703
|
if (adContainerEl) {
|
|
637
704
|
adContainerEl.style.pointerEvents = "none";
|
|
638
705
|
adContainerEl.style.display = "none";
|
|
@@ -656,6 +723,7 @@ function createImaController(video, options) {
|
|
|
656
723
|
destroyAdsManager();
|
|
657
724
|
adPlaying = false;
|
|
658
725
|
video.muted = originalMutedState;
|
|
726
|
+
setAdPlayingFlag(false);
|
|
659
727
|
if (adContainerEl) {
|
|
660
728
|
adContainerEl.style.pointerEvents = "none";
|
|
661
729
|
adContainerEl.style.display = "none";
|
|
@@ -698,6 +766,9 @@ function createImaController(video, options) {
|
|
|
698
766
|
(_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
|
|
699
767
|
},
|
|
700
768
|
updateOriginalMutedState(muted) {
|
|
769
|
+
console.log(
|
|
770
|
+
`[IMA] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
|
|
771
|
+
);
|
|
701
772
|
originalMutedState = muted;
|
|
702
773
|
},
|
|
703
774
|
getOriginalMutedState() {
|
|
@@ -754,7 +825,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
754
825
|
try {
|
|
755
826
|
fn(payload);
|
|
756
827
|
} catch (error) {
|
|
757
|
-
console.warn(
|
|
828
|
+
console.warn(
|
|
829
|
+
`[HlsAdPlayer] Error in event listener for ${event}:`,
|
|
830
|
+
error
|
|
831
|
+
);
|
|
758
832
|
}
|
|
759
833
|
}
|
|
760
834
|
}
|
|
@@ -817,7 +891,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
817
891
|
}
|
|
818
892
|
const mainQuality = getMainStreamQuality();
|
|
819
893
|
if (!mainQuality) {
|
|
820
|
-
console.log(
|
|
894
|
+
console.log(
|
|
895
|
+
"[HlsAdPlayer] No main stream quality info, using first media file"
|
|
896
|
+
);
|
|
821
897
|
return firstFile;
|
|
822
898
|
}
|
|
823
899
|
console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
|
|
@@ -853,7 +929,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
853
929
|
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
|
|
854
930
|
const parserError = xmlDoc.querySelector("parsererror");
|
|
855
931
|
if (parserError) {
|
|
856
|
-
console.error(
|
|
932
|
+
console.error(
|
|
933
|
+
"[HlsAdPlayer] XML parsing error (malformed VAST XML):",
|
|
934
|
+
parserError.textContent
|
|
935
|
+
);
|
|
857
936
|
return null;
|
|
858
937
|
}
|
|
859
938
|
const adElement = xmlDoc.querySelector("Ad");
|
|
@@ -869,17 +948,23 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
869
948
|
const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
|
|
870
949
|
const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
|
|
871
950
|
const mediaFiles = [];
|
|
872
|
-
console.log(
|
|
951
|
+
console.log(
|
|
952
|
+
`[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`
|
|
953
|
+
);
|
|
873
954
|
mediaFileElements.forEach((mf, index) => {
|
|
874
955
|
var _a2;
|
|
875
956
|
const type = mf.getAttribute("type") || "";
|
|
876
957
|
const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
|
|
877
958
|
const width = mf.getAttribute("width") || "";
|
|
878
959
|
const height = mf.getAttribute("height") || "";
|
|
879
|
-
console.log(
|
|
960
|
+
console.log(
|
|
961
|
+
`[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`
|
|
962
|
+
);
|
|
880
963
|
if (type === "application/x-mpegURL" || type.includes("m3u8")) {
|
|
881
964
|
if (!url) {
|
|
882
|
-
console.warn(
|
|
965
|
+
console.warn(
|
|
966
|
+
`[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`
|
|
967
|
+
);
|
|
883
968
|
return;
|
|
884
969
|
}
|
|
885
970
|
const bitrateAttr = mf.getAttribute("bitrate");
|
|
@@ -893,12 +978,16 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
893
978
|
});
|
|
894
979
|
console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
|
|
895
980
|
} else {
|
|
896
|
-
console.log(
|
|
981
|
+
console.log(
|
|
982
|
+
`[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`
|
|
983
|
+
);
|
|
897
984
|
}
|
|
898
985
|
});
|
|
899
986
|
if (mediaFiles.length === 0) {
|
|
900
987
|
if (isNoAdAvailable) {
|
|
901
|
-
console.warn(
|
|
988
|
+
console.warn(
|
|
989
|
+
"[HlsAdPlayer] No ads available (VAST response indicates no ads)"
|
|
990
|
+
);
|
|
902
991
|
} else {
|
|
903
992
|
console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
|
|
904
993
|
}
|
|
@@ -961,6 +1050,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
961
1050
|
video.style.backgroundColor = "#000";
|
|
962
1051
|
video.playsInline = true;
|
|
963
1052
|
video.muted = false;
|
|
1053
|
+
video.volume = 1;
|
|
1054
|
+
console.log(
|
|
1055
|
+
`[HlsAdPlayer] Created ad video element with volume ${video.volume}`
|
|
1056
|
+
);
|
|
964
1057
|
return video;
|
|
965
1058
|
}
|
|
966
1059
|
function setupAdEventListeners() {
|
|
@@ -1020,10 +1113,22 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1020
1113
|
}
|
|
1021
1114
|
});
|
|
1022
1115
|
}
|
|
1116
|
+
function setAdPlayingFlag(isPlaying) {
|
|
1117
|
+
if (isPlaying) {
|
|
1118
|
+
contentVideo.dataset.stormcloudAdPlaying = "true";
|
|
1119
|
+
} else {
|
|
1120
|
+
delete contentVideo.dataset.stormcloudAdPlaying;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1023
1123
|
function handleAdComplete() {
|
|
1024
1124
|
console.log("[HlsAdPlayer] Handling ad completion");
|
|
1025
1125
|
adPlaying = false;
|
|
1126
|
+
setAdPlayingFlag(false);
|
|
1127
|
+
const previousMutedState = contentVideo.muted;
|
|
1026
1128
|
contentVideo.muted = originalMutedState;
|
|
1129
|
+
console.log(
|
|
1130
|
+
`[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
|
|
1131
|
+
);
|
|
1027
1132
|
if (adContainerEl) {
|
|
1028
1133
|
adContainerEl.style.display = "none";
|
|
1029
1134
|
adContainerEl.style.pointerEvents = "none";
|
|
@@ -1041,7 +1146,12 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1041
1146
|
function handleAdError() {
|
|
1042
1147
|
console.log("[HlsAdPlayer] Handling ad error");
|
|
1043
1148
|
adPlaying = false;
|
|
1149
|
+
setAdPlayingFlag(false);
|
|
1150
|
+
const previousMutedState = contentVideo.muted;
|
|
1044
1151
|
contentVideo.muted = originalMutedState;
|
|
1152
|
+
console.log(
|
|
1153
|
+
`[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
|
|
1154
|
+
);
|
|
1045
1155
|
if (adContainerEl) {
|
|
1046
1156
|
adContainerEl.style.display = "none";
|
|
1047
1157
|
adContainerEl.style.pointerEvents = "none";
|
|
@@ -1078,7 +1188,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1078
1188
|
async requestAds(vastTagUrl) {
|
|
1079
1189
|
console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
|
|
1080
1190
|
if (adPlaying) {
|
|
1081
|
-
console.warn(
|
|
1191
|
+
console.warn(
|
|
1192
|
+
"[HlsAdPlayer] Cannot request new ads while an ad is playing"
|
|
1193
|
+
);
|
|
1082
1194
|
return Promise.reject(new Error("Ad already playing"));
|
|
1083
1195
|
}
|
|
1084
1196
|
try {
|
|
@@ -1089,14 +1201,20 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1089
1201
|
}
|
|
1090
1202
|
const vastXml = await response.text();
|
|
1091
1203
|
console.log("[HlsAdPlayer] VAST XML received");
|
|
1092
|
-
console.log(
|
|
1204
|
+
console.log(
|
|
1205
|
+
"[HlsAdPlayer] VAST XML content (first 2000 chars):",
|
|
1206
|
+
vastXml.substring(0, 2e3)
|
|
1207
|
+
);
|
|
1093
1208
|
const ad = parseVastXml(vastXml);
|
|
1094
1209
|
if (!ad) {
|
|
1095
1210
|
console.warn("[HlsAdPlayer] No ads available from VAST response");
|
|
1211
|
+
emit("ad_error");
|
|
1096
1212
|
return Promise.resolve();
|
|
1097
1213
|
}
|
|
1098
1214
|
currentAd = ad;
|
|
1099
|
-
console.log(
|
|
1215
|
+
console.log(
|
|
1216
|
+
`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`
|
|
1217
|
+
);
|
|
1100
1218
|
fireTrackingPixels(ad.trackingUrls.impression);
|
|
1101
1219
|
trackingFired.impression = true;
|
|
1102
1220
|
return Promise.resolve();
|
|
@@ -1108,7 +1226,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1108
1226
|
},
|
|
1109
1227
|
async play() {
|
|
1110
1228
|
if (!currentAd) {
|
|
1111
|
-
console.warn(
|
|
1229
|
+
console.warn(
|
|
1230
|
+
"[HlsAdPlayer] Cannot play: No ad loaded (no ads available)"
|
|
1231
|
+
);
|
|
1112
1232
|
return Promise.reject(new Error("No ad loaded"));
|
|
1113
1233
|
}
|
|
1114
1234
|
console.log("[HlsAdPlayer] Starting ad playback");
|
|
@@ -1126,6 +1246,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1126
1246
|
thirdQuartile: false,
|
|
1127
1247
|
complete: false
|
|
1128
1248
|
};
|
|
1249
|
+
const contentVolume = contentVideo.volume;
|
|
1129
1250
|
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
1130
1251
|
contentVideo.pause();
|
|
1131
1252
|
console.log("[HlsAdPlayer] Content paused (VOD mode)");
|
|
@@ -1134,6 +1255,15 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1134
1255
|
}
|
|
1135
1256
|
contentVideo.muted = true;
|
|
1136
1257
|
adPlaying = true;
|
|
1258
|
+
setAdPlayingFlag(true);
|
|
1259
|
+
if (adVideoElement) {
|
|
1260
|
+
const adVolume = originalMutedState ? 0 : contentVolume;
|
|
1261
|
+
adVideoElement.volume = Math.max(0, Math.min(1, adVolume));
|
|
1262
|
+
adVideoElement.muted = false;
|
|
1263
|
+
console.log(
|
|
1264
|
+
`[HlsAdPlayer] Set ad video volume to ${adVideoElement.volume}, muted: ${adVideoElement.muted}, originalMutedState: ${originalMutedState}, contentVolume: ${contentVolume}`
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1137
1267
|
if (adContainerEl) {
|
|
1138
1268
|
adContainerEl.style.display = "flex";
|
|
1139
1269
|
adContainerEl.style.pointerEvents = "auto";
|
|
@@ -1186,6 +1316,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1186
1316
|
async stop() {
|
|
1187
1317
|
console.log("[HlsAdPlayer] Stopping ad");
|
|
1188
1318
|
adPlaying = false;
|
|
1319
|
+
setAdPlayingFlag(false);
|
|
1189
1320
|
contentVideo.muted = originalMutedState;
|
|
1190
1321
|
if (adContainerEl) {
|
|
1191
1322
|
adContainerEl.style.display = "none";
|
|
@@ -1208,6 +1339,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1208
1339
|
destroy() {
|
|
1209
1340
|
console.log("[HlsAdPlayer] Destroying");
|
|
1210
1341
|
adPlaying = false;
|
|
1342
|
+
setAdPlayingFlag(false);
|
|
1211
1343
|
contentVideo.muted = originalMutedState;
|
|
1212
1344
|
if (adHls) {
|
|
1213
1345
|
adHls.destroy();
|
|
@@ -1249,6 +1381,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1249
1381
|
(_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
|
|
1250
1382
|
},
|
|
1251
1383
|
updateOriginalMutedState(muted) {
|
|
1384
|
+
console.log(
|
|
1385
|
+
`[HlsAdPlayer] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
|
|
1386
|
+
);
|
|
1252
1387
|
originalMutedState = muted;
|
|
1253
1388
|
},
|
|
1254
1389
|
getOriginalMutedState() {
|
|
@@ -1741,6 +1876,9 @@ var StormcloudVideoPlayer = class {
|
|
|
1741
1876
|
this.isLiveStream = false;
|
|
1742
1877
|
this.nativeHlsMode = false;
|
|
1743
1878
|
this.videoSrcProtection = null;
|
|
1879
|
+
this.bufferedSegmentsCount = 0;
|
|
1880
|
+
this.shouldAutoplayAfterBuffering = false;
|
|
1881
|
+
this.hasInitialBufferCompleted = false;
|
|
1744
1882
|
initializePolyfills();
|
|
1745
1883
|
const browserOverrides = getBrowserConfigOverrides();
|
|
1746
1884
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -1827,14 +1965,22 @@ var StormcloudVideoPlayer = class {
|
|
|
1827
1965
|
liveDurationInfinity: true,
|
|
1828
1966
|
lowLatencyMode: !!this.config.lowLatencyMode,
|
|
1829
1967
|
maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
|
|
1830
|
-
...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {}
|
|
1968
|
+
...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {},
|
|
1969
|
+
maxBufferLength: 30,
|
|
1970
|
+
maxMaxBufferLength: 600,
|
|
1971
|
+
maxBufferSize: 60 * 1e3 * 1e3,
|
|
1972
|
+
maxBufferHole: 0.5,
|
|
1973
|
+
highBufferWatchdogPeriod: 2,
|
|
1974
|
+
nudgeOffset: 0.1,
|
|
1975
|
+
nudgeMaxRetry: 3,
|
|
1976
|
+
startPosition: -1
|
|
1831
1977
|
});
|
|
1832
1978
|
this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
|
|
1833
1979
|
var _a2;
|
|
1834
1980
|
(_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
|
|
1835
1981
|
});
|
|
1836
1982
|
this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
|
|
1837
|
-
var _a2, _b2, _c, _d;
|
|
1983
|
+
var _a2, _b2, _c, _d, _e;
|
|
1838
1984
|
this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
|
|
1839
1985
|
(level) => {
|
|
1840
1986
|
var _a3, _b3;
|
|
@@ -1852,9 +1998,51 @@ var StormcloudVideoPlayer = class {
|
|
|
1852
1998
|
this.ima.destroy();
|
|
1853
1999
|
this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
|
|
1854
2000
|
this.ima.initialize();
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
2001
|
+
this.bufferedSegmentsCount = 0;
|
|
2002
|
+
this.hasInitialBufferCompleted = false;
|
|
2003
|
+
this.shouldAutoplayAfterBuffering = !!this.config.autoplay;
|
|
2004
|
+
const minSegments = (_d = this.config.minSegmentsBeforePlay) != null ? _d : 2;
|
|
2005
|
+
if (this.config.debugAdTiming) {
|
|
2006
|
+
console.log(
|
|
2007
|
+
"[StormcloudVideoPlayer] Waiting for",
|
|
2008
|
+
minSegments,
|
|
2009
|
+
"segments to buffer before playback"
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
2012
|
+
if (minSegments === 0 || !this.config.autoplay) {
|
|
2013
|
+
this.hasInitialBufferCompleted = true;
|
|
2014
|
+
if (this.config.autoplay) {
|
|
2015
|
+
await ((_e = this.video.play()) == null ? void 0 : _e.catch(() => {
|
|
2016
|
+
}));
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
});
|
|
2020
|
+
this.hls.on(import_hls2.default.Events.FRAG_BUFFERED, async (_evt, data) => {
|
|
2021
|
+
var _a2, _b2;
|
|
2022
|
+
if (this.hasInitialBufferCompleted) {
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
this.bufferedSegmentsCount++;
|
|
2026
|
+
const minSegments = (_a2 = this.config.minSegmentsBeforePlay) != null ? _a2 : 2;
|
|
2027
|
+
if (this.config.debugAdTiming) {
|
|
2028
|
+
console.log(
|
|
2029
|
+
`[StormcloudVideoPlayer] Buffered segment ${this.bufferedSegmentsCount}/${minSegments}`
|
|
2030
|
+
);
|
|
2031
|
+
}
|
|
2032
|
+
if (this.bufferedSegmentsCount >= minSegments) {
|
|
2033
|
+
this.hasInitialBufferCompleted = true;
|
|
2034
|
+
if (this.shouldAutoplayAfterBuffering) {
|
|
2035
|
+
if (this.config.debugAdTiming) {
|
|
2036
|
+
console.log(
|
|
2037
|
+
`[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Starting playback.`
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
await ((_b2 = this.video.play()) == null ? void 0 : _b2.catch((err) => {
|
|
2041
|
+
if (this.config.debugAdTiming) {
|
|
2042
|
+
console.warn("[StormcloudVideoPlayer] Autoplay failed:", err);
|
|
2043
|
+
}
|
|
2044
|
+
}));
|
|
2045
|
+
}
|
|
1858
2046
|
}
|
|
1859
2047
|
});
|
|
1860
2048
|
this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
|
|
@@ -1950,6 +2138,7 @@ var StormcloudVideoPlayer = class {
|
|
|
1950
2138
|
this.video.autoplay = !!this.config.autoplay;
|
|
1951
2139
|
this.video.muted = !!this.config.muted;
|
|
1952
2140
|
this.ima.initialize();
|
|
2141
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
1953
2142
|
this.ima.on("all_ads_completed", () => {
|
|
1954
2143
|
if (this.config.debugAdTiming) {
|
|
1955
2144
|
console.log(
|
|
@@ -2734,7 +2923,23 @@ var StormcloudVideoPlayer = class {
|
|
|
2734
2923
|
}
|
|
2735
2924
|
return;
|
|
2736
2925
|
}
|
|
2737
|
-
|
|
2926
|
+
if (!this.showAds) {
|
|
2927
|
+
if (this.config.debugAdTiming) {
|
|
2928
|
+
console.log(
|
|
2929
|
+
`[StormcloudVideoPlayer] Capturing original state before ad request:`,
|
|
2930
|
+
{
|
|
2931
|
+
videoMuted: this.video.muted,
|
|
2932
|
+
videoVolume: this.video.volume,
|
|
2933
|
+
showAds: this.showAds
|
|
2934
|
+
}
|
|
2935
|
+
);
|
|
2936
|
+
}
|
|
2937
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
2938
|
+
} else if (this.config.debugAdTiming) {
|
|
2939
|
+
console.log(
|
|
2940
|
+
`[StormcloudVideoPlayer] Keeping existing original mute state (currently showing ads)`
|
|
2941
|
+
);
|
|
2942
|
+
}
|
|
2738
2943
|
this.startAdFailsafeTimer();
|
|
2739
2944
|
try {
|
|
2740
2945
|
await this.ima.requestAds(vastTagUrl);
|
|
@@ -2789,11 +2994,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2789
2994
|
this.showAds = false;
|
|
2790
2995
|
this.currentAdIndex = 0;
|
|
2791
2996
|
this.totalAdsInBreak = 0;
|
|
2997
|
+
const currentMutedState = this.video.muted;
|
|
2792
2998
|
const originalMutedState = this.ima.getOriginalMutedState();
|
|
2793
2999
|
this.video.muted = originalMutedState;
|
|
2794
3000
|
if (this.config.debugAdTiming) {
|
|
2795
3001
|
console.log(
|
|
2796
|
-
`[StormcloudVideoPlayer] Restored mute state
|
|
3002
|
+
`[StormcloudVideoPlayer] Restored mute state: ${currentMutedState} -> ${originalMutedState}`
|
|
2797
3003
|
);
|
|
2798
3004
|
}
|
|
2799
3005
|
if (this.video.paused) {
|
|
@@ -2885,6 +3091,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2885
3091
|
}
|
|
2886
3092
|
} else {
|
|
2887
3093
|
this.video.muted = !this.video.muted;
|
|
3094
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
2888
3095
|
if (this.config.debugAdTiming) {
|
|
2889
3096
|
console.log("[StormcloudVideoPlayer] Muted:", this.video.muted);
|
|
2890
3097
|
}
|
|
@@ -2929,11 +3136,47 @@ var StormcloudVideoPlayer = class {
|
|
|
2929
3136
|
}
|
|
2930
3137
|
isMuted() {
|
|
2931
3138
|
if (this.ima.isAdPlaying()) {
|
|
2932
|
-
|
|
2933
|
-
|
|
3139
|
+
if (this.config.debugAdTiming) {
|
|
3140
|
+
console.log(
|
|
3141
|
+
"[StormcloudVideoPlayer] isMuted() override during ad playback -> false"
|
|
3142
|
+
);
|
|
3143
|
+
}
|
|
3144
|
+
return false;
|
|
3145
|
+
}
|
|
3146
|
+
if (this.config.debugAdTiming) {
|
|
3147
|
+
console.log(
|
|
3148
|
+
`[StormcloudVideoPlayer] isMuted() no ad playing: video.muted=${this.video.muted}`
|
|
3149
|
+
);
|
|
2934
3150
|
}
|
|
2935
3151
|
return this.video.muted;
|
|
2936
3152
|
}
|
|
3153
|
+
setMuted(muted) {
|
|
3154
|
+
const adPlaying = this.ima.isAdPlaying();
|
|
3155
|
+
if (adPlaying && muted === this.video.muted) {
|
|
3156
|
+
if (this.config.debugAdTiming) {
|
|
3157
|
+
console.log(
|
|
3158
|
+
"[StormcloudVideoPlayer] setMuted reflective update during ad ignored",
|
|
3159
|
+
{ muted }
|
|
3160
|
+
);
|
|
3161
|
+
}
|
|
3162
|
+
return;
|
|
3163
|
+
}
|
|
3164
|
+
this.video.muted = muted;
|
|
3165
|
+
if (adPlaying) {
|
|
3166
|
+
this.ima.updateOriginalMutedState(muted);
|
|
3167
|
+
this.ima.setAdVolume(muted ? 0 : 1);
|
|
3168
|
+
if (this.config.debugAdTiming) {
|
|
3169
|
+
console.log("[StormcloudVideoPlayer] setMuted applied during ad", {
|
|
3170
|
+
muted
|
|
3171
|
+
});
|
|
3172
|
+
}
|
|
3173
|
+
return;
|
|
3174
|
+
}
|
|
3175
|
+
this.ima.updateOriginalMutedState(muted);
|
|
3176
|
+
if (this.config.debugAdTiming) {
|
|
3177
|
+
console.log("[StormcloudVideoPlayer] setMuted called:", muted);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
2937
3180
|
isFullscreen() {
|
|
2938
3181
|
return !!document.fullscreenElement;
|
|
2939
3182
|
}
|
|
@@ -3044,6 +3287,8 @@ var HlsPlayer = class extends import_react.Component {
|
|
|
3044
3287
|
config.licenseKey = this.props.licenseKey;
|
|
3045
3288
|
if (this.props.adFailsafeTimeoutMs !== void 0)
|
|
3046
3289
|
config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
|
|
3290
|
+
if (this.props.minSegmentsBeforePlay !== void 0)
|
|
3291
|
+
config.minSegmentsBeforePlay = this.props.minSegmentsBeforePlay;
|
|
3047
3292
|
this.player = new StormcloudVideoPlayer(config);
|
|
3048
3293
|
(_b = (_a = this.props).onMount) == null ? void 0 : _b.call(_a, this);
|
|
3049
3294
|
await this.player.load();
|