stormcloud-video-player 0.2.17 → 0.2.19
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 +403 -56
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +8 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +403 -56
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +282 -23
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +5 -1
- package/lib/players/HlsPlayer.cjs +284 -23
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +284 -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 +35 -0
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/sdk/ima.d.cts +1 -1
- package/lib/{types-mVgmKmzM.d.cts → types-D1xfSdLP.d.cts} +3 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +399 -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-D1xfSdLP.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;
|
|
@@ -445,7 +452,12 @@ function createImaController(video, options) {
|
|
|
445
452
|
console.error("[IMA] Ad error:", errorEvent.getError());
|
|
446
453
|
destroyAdsManager();
|
|
447
454
|
adPlaying = false;
|
|
455
|
+
const previousMutedState = video.muted;
|
|
448
456
|
video.muted = originalMutedState;
|
|
457
|
+
setAdPlayingFlag(false);
|
|
458
|
+
console.log(
|
|
459
|
+
`[IMA] Restored mute state after ad error: ${previousMutedState} -> ${originalMutedState}`
|
|
460
|
+
);
|
|
449
461
|
if (adContainerEl) {
|
|
450
462
|
adContainerEl.style.pointerEvents = "none";
|
|
451
463
|
adContainerEl.style.display = "none";
|
|
@@ -498,11 +510,13 @@ function createImaController(video, options) {
|
|
|
498
510
|
}
|
|
499
511
|
video.muted = true;
|
|
500
512
|
adPlaying = true;
|
|
513
|
+
setAdPlayingFlag(true);
|
|
501
514
|
emit("content_pause");
|
|
502
515
|
}
|
|
503
516
|
);
|
|
504
517
|
adsManager.addEventListener(AdEvent.STARTED, () => {
|
|
505
518
|
console.log("[IMA] Ad started playing");
|
|
519
|
+
setAdPlayingFlag(true);
|
|
506
520
|
if (adContainerEl) {
|
|
507
521
|
adContainerEl.style.pointerEvents = "auto";
|
|
508
522
|
adContainerEl.style.display = "flex";
|
|
@@ -518,6 +532,7 @@ function createImaController(video, options) {
|
|
|
518
532
|
console.log("[IMA] Content resume requested");
|
|
519
533
|
adPlaying = false;
|
|
520
534
|
video.muted = originalMutedState;
|
|
535
|
+
setAdPlayingFlag(false);
|
|
521
536
|
if (adContainerEl) {
|
|
522
537
|
adContainerEl.style.pointerEvents = "none";
|
|
523
538
|
adContainerEl.style.display = "none";
|
|
@@ -541,6 +556,7 @@ function createImaController(video, options) {
|
|
|
541
556
|
console.log("[IMA] All ads completed");
|
|
542
557
|
adPlaying = false;
|
|
543
558
|
video.muted = originalMutedState;
|
|
559
|
+
setAdPlayingFlag(false);
|
|
544
560
|
if (adContainerEl) {
|
|
545
561
|
adContainerEl.style.pointerEvents = "none";
|
|
546
562
|
adContainerEl.style.display = "none";
|
|
@@ -571,6 +587,7 @@ function createImaController(video, options) {
|
|
|
571
587
|
console.error("[IMA] Error setting up ads manager:", e);
|
|
572
588
|
adPlaying = false;
|
|
573
589
|
video.muted = originalMutedState;
|
|
590
|
+
setAdPlayingFlag(false);
|
|
574
591
|
if (adContainerEl) {
|
|
575
592
|
adContainerEl.style.pointerEvents = "none";
|
|
576
593
|
adContainerEl.style.display = "none";
|
|
@@ -600,7 +617,12 @@ function createImaController(video, options) {
|
|
|
600
617
|
(adErrorEvent) => {
|
|
601
618
|
console.error("[IMA] Ads loader error:", adErrorEvent.getError());
|
|
602
619
|
adPlaying = false;
|
|
620
|
+
const previousMutedState = video.muted;
|
|
603
621
|
video.muted = originalMutedState;
|
|
622
|
+
setAdPlayingFlag(false);
|
|
623
|
+
console.log(
|
|
624
|
+
`[IMA] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
|
|
625
|
+
);
|
|
604
626
|
if (adContainerEl) {
|
|
605
627
|
adContainerEl.style.pointerEvents = "none";
|
|
606
628
|
adContainerEl.style.display = "none";
|
|
@@ -652,12 +674,20 @@ function createImaController(video, options) {
|
|
|
652
674
|
console.log(`[IMA] Initializing ads manager (${width}x${height})`);
|
|
653
675
|
adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
|
|
654
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
|
+
}
|
|
655
684
|
console.log("[IMA] Starting ad playback");
|
|
656
685
|
adsManager.start();
|
|
657
686
|
return Promise.resolve();
|
|
658
687
|
} catch (error) {
|
|
659
688
|
console.error("[IMA] Error starting ad playback:", error);
|
|
660
689
|
adPlaying = false;
|
|
690
|
+
setAdPlayingFlag(false);
|
|
661
691
|
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
662
692
|
(_b = video.play()) == null ? void 0 : _b.catch(() => {
|
|
663
693
|
});
|
|
@@ -669,6 +699,7 @@ function createImaController(video, options) {
|
|
|
669
699
|
var _a;
|
|
670
700
|
adPlaying = false;
|
|
671
701
|
video.muted = originalMutedState;
|
|
702
|
+
setAdPlayingFlag(false);
|
|
672
703
|
if (adContainerEl) {
|
|
673
704
|
adContainerEl.style.pointerEvents = "none";
|
|
674
705
|
adContainerEl.style.display = "none";
|
|
@@ -692,6 +723,7 @@ function createImaController(video, options) {
|
|
|
692
723
|
destroyAdsManager();
|
|
693
724
|
adPlaying = false;
|
|
694
725
|
video.muted = originalMutedState;
|
|
726
|
+
setAdPlayingFlag(false);
|
|
695
727
|
if (adContainerEl) {
|
|
696
728
|
adContainerEl.style.pointerEvents = "none";
|
|
697
729
|
adContainerEl.style.display = "none";
|
|
@@ -734,6 +766,9 @@ function createImaController(video, options) {
|
|
|
734
766
|
(_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
|
|
735
767
|
},
|
|
736
768
|
updateOriginalMutedState(muted) {
|
|
769
|
+
console.log(
|
|
770
|
+
`[IMA] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
|
|
771
|
+
);
|
|
737
772
|
originalMutedState = muted;
|
|
738
773
|
},
|
|
739
774
|
getOriginalMutedState() {
|
|
@@ -790,7 +825,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
790
825
|
try {
|
|
791
826
|
fn(payload);
|
|
792
827
|
} catch (error) {
|
|
793
|
-
console.warn(
|
|
828
|
+
console.warn(
|
|
829
|
+
`[HlsAdPlayer] Error in event listener for ${event}:`,
|
|
830
|
+
error
|
|
831
|
+
);
|
|
794
832
|
}
|
|
795
833
|
}
|
|
796
834
|
}
|
|
@@ -853,7 +891,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
853
891
|
}
|
|
854
892
|
const mainQuality = getMainStreamQuality();
|
|
855
893
|
if (!mainQuality) {
|
|
856
|
-
console.log(
|
|
894
|
+
console.log(
|
|
895
|
+
"[HlsAdPlayer] No main stream quality info, using first media file"
|
|
896
|
+
);
|
|
857
897
|
return firstFile;
|
|
858
898
|
}
|
|
859
899
|
console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
|
|
@@ -889,7 +929,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
889
929
|
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
|
|
890
930
|
const parserError = xmlDoc.querySelector("parsererror");
|
|
891
931
|
if (parserError) {
|
|
892
|
-
console.error(
|
|
932
|
+
console.error(
|
|
933
|
+
"[HlsAdPlayer] XML parsing error (malformed VAST XML):",
|
|
934
|
+
parserError.textContent
|
|
935
|
+
);
|
|
893
936
|
return null;
|
|
894
937
|
}
|
|
895
938
|
const adElement = xmlDoc.querySelector("Ad");
|
|
@@ -905,17 +948,23 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
905
948
|
const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
|
|
906
949
|
const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
|
|
907
950
|
const mediaFiles = [];
|
|
908
|
-
console.log(
|
|
951
|
+
console.log(
|
|
952
|
+
`[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`
|
|
953
|
+
);
|
|
909
954
|
mediaFileElements.forEach((mf, index) => {
|
|
910
955
|
var _a2;
|
|
911
956
|
const type = mf.getAttribute("type") || "";
|
|
912
957
|
const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
|
|
913
958
|
const width = mf.getAttribute("width") || "";
|
|
914
959
|
const height = mf.getAttribute("height") || "";
|
|
915
|
-
console.log(
|
|
960
|
+
console.log(
|
|
961
|
+
`[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`
|
|
962
|
+
);
|
|
916
963
|
if (type === "application/x-mpegURL" || type.includes("m3u8")) {
|
|
917
964
|
if (!url) {
|
|
918
|
-
console.warn(
|
|
965
|
+
console.warn(
|
|
966
|
+
`[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`
|
|
967
|
+
);
|
|
919
968
|
return;
|
|
920
969
|
}
|
|
921
970
|
const bitrateAttr = mf.getAttribute("bitrate");
|
|
@@ -929,12 +978,16 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
929
978
|
});
|
|
930
979
|
console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
|
|
931
980
|
} else {
|
|
932
|
-
console.log(
|
|
981
|
+
console.log(
|
|
982
|
+
`[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`
|
|
983
|
+
);
|
|
933
984
|
}
|
|
934
985
|
});
|
|
935
986
|
if (mediaFiles.length === 0) {
|
|
936
987
|
if (isNoAdAvailable) {
|
|
937
|
-
console.warn(
|
|
988
|
+
console.warn(
|
|
989
|
+
"[HlsAdPlayer] No ads available (VAST response indicates no ads)"
|
|
990
|
+
);
|
|
938
991
|
} else {
|
|
939
992
|
console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
|
|
940
993
|
}
|
|
@@ -997,6 +1050,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
997
1050
|
video.style.backgroundColor = "#000";
|
|
998
1051
|
video.playsInline = true;
|
|
999
1052
|
video.muted = false;
|
|
1053
|
+
video.volume = 1;
|
|
1054
|
+
console.log(
|
|
1055
|
+
`[HlsAdPlayer] Created ad video element with volume ${video.volume}`
|
|
1056
|
+
);
|
|
1000
1057
|
return video;
|
|
1001
1058
|
}
|
|
1002
1059
|
function setupAdEventListeners() {
|
|
@@ -1056,10 +1113,22 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1056
1113
|
}
|
|
1057
1114
|
});
|
|
1058
1115
|
}
|
|
1116
|
+
function setAdPlayingFlag(isPlaying) {
|
|
1117
|
+
if (isPlaying) {
|
|
1118
|
+
contentVideo.dataset.stormcloudAdPlaying = "true";
|
|
1119
|
+
} else {
|
|
1120
|
+
delete contentVideo.dataset.stormcloudAdPlaying;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1059
1123
|
function handleAdComplete() {
|
|
1060
1124
|
console.log("[HlsAdPlayer] Handling ad completion");
|
|
1061
1125
|
adPlaying = false;
|
|
1126
|
+
setAdPlayingFlag(false);
|
|
1127
|
+
const previousMutedState = contentVideo.muted;
|
|
1062
1128
|
contentVideo.muted = originalMutedState;
|
|
1129
|
+
console.log(
|
|
1130
|
+
`[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
|
|
1131
|
+
);
|
|
1063
1132
|
if (adContainerEl) {
|
|
1064
1133
|
adContainerEl.style.display = "none";
|
|
1065
1134
|
adContainerEl.style.pointerEvents = "none";
|
|
@@ -1077,7 +1146,12 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1077
1146
|
function handleAdError() {
|
|
1078
1147
|
console.log("[HlsAdPlayer] Handling ad error");
|
|
1079
1148
|
adPlaying = false;
|
|
1149
|
+
setAdPlayingFlag(false);
|
|
1150
|
+
const previousMutedState = contentVideo.muted;
|
|
1080
1151
|
contentVideo.muted = originalMutedState;
|
|
1152
|
+
console.log(
|
|
1153
|
+
`[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
|
|
1154
|
+
);
|
|
1081
1155
|
if (adContainerEl) {
|
|
1082
1156
|
adContainerEl.style.display = "none";
|
|
1083
1157
|
adContainerEl.style.pointerEvents = "none";
|
|
@@ -1114,7 +1188,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1114
1188
|
async requestAds(vastTagUrl) {
|
|
1115
1189
|
console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
|
|
1116
1190
|
if (adPlaying) {
|
|
1117
|
-
console.warn(
|
|
1191
|
+
console.warn(
|
|
1192
|
+
"[HlsAdPlayer] Cannot request new ads while an ad is playing"
|
|
1193
|
+
);
|
|
1118
1194
|
return Promise.reject(new Error("Ad already playing"));
|
|
1119
1195
|
}
|
|
1120
1196
|
try {
|
|
@@ -1125,14 +1201,20 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1125
1201
|
}
|
|
1126
1202
|
const vastXml = await response.text();
|
|
1127
1203
|
console.log("[HlsAdPlayer] VAST XML received");
|
|
1128
|
-
console.log(
|
|
1204
|
+
console.log(
|
|
1205
|
+
"[HlsAdPlayer] VAST XML content (first 2000 chars):",
|
|
1206
|
+
vastXml.substring(0, 2e3)
|
|
1207
|
+
);
|
|
1129
1208
|
const ad = parseVastXml(vastXml);
|
|
1130
1209
|
if (!ad) {
|
|
1131
1210
|
console.warn("[HlsAdPlayer] No ads available from VAST response");
|
|
1211
|
+
emit("ad_error");
|
|
1132
1212
|
return Promise.resolve();
|
|
1133
1213
|
}
|
|
1134
1214
|
currentAd = ad;
|
|
1135
|
-
console.log(
|
|
1215
|
+
console.log(
|
|
1216
|
+
`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`
|
|
1217
|
+
);
|
|
1136
1218
|
fireTrackingPixels(ad.trackingUrls.impression);
|
|
1137
1219
|
trackingFired.impression = true;
|
|
1138
1220
|
return Promise.resolve();
|
|
@@ -1144,7 +1226,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1144
1226
|
},
|
|
1145
1227
|
async play() {
|
|
1146
1228
|
if (!currentAd) {
|
|
1147
|
-
console.warn(
|
|
1229
|
+
console.warn(
|
|
1230
|
+
"[HlsAdPlayer] Cannot play: No ad loaded (no ads available)"
|
|
1231
|
+
);
|
|
1148
1232
|
return Promise.reject(new Error("No ad loaded"));
|
|
1149
1233
|
}
|
|
1150
1234
|
console.log("[HlsAdPlayer] Starting ad playback");
|
|
@@ -1162,6 +1246,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1162
1246
|
thirdQuartile: false,
|
|
1163
1247
|
complete: false
|
|
1164
1248
|
};
|
|
1249
|
+
const contentVolume = contentVideo.volume;
|
|
1165
1250
|
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
1166
1251
|
contentVideo.pause();
|
|
1167
1252
|
console.log("[HlsAdPlayer] Content paused (VOD mode)");
|
|
@@ -1170,6 +1255,15 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1170
1255
|
}
|
|
1171
1256
|
contentVideo.muted = true;
|
|
1172
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
|
+
}
|
|
1173
1267
|
if (adContainerEl) {
|
|
1174
1268
|
adContainerEl.style.display = "flex";
|
|
1175
1269
|
adContainerEl.style.pointerEvents = "auto";
|
|
@@ -1222,6 +1316,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1222
1316
|
async stop() {
|
|
1223
1317
|
console.log("[HlsAdPlayer] Stopping ad");
|
|
1224
1318
|
adPlaying = false;
|
|
1319
|
+
setAdPlayingFlag(false);
|
|
1225
1320
|
contentVideo.muted = originalMutedState;
|
|
1226
1321
|
if (adContainerEl) {
|
|
1227
1322
|
adContainerEl.style.display = "none";
|
|
@@ -1244,6 +1339,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1244
1339
|
destroy() {
|
|
1245
1340
|
console.log("[HlsAdPlayer] Destroying");
|
|
1246
1341
|
adPlaying = false;
|
|
1342
|
+
setAdPlayingFlag(false);
|
|
1247
1343
|
contentVideo.muted = originalMutedState;
|
|
1248
1344
|
if (adHls) {
|
|
1249
1345
|
adHls.destroy();
|
|
@@ -1285,6 +1381,9 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1285
1381
|
(_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
|
|
1286
1382
|
},
|
|
1287
1383
|
updateOriginalMutedState(muted) {
|
|
1384
|
+
console.log(
|
|
1385
|
+
`[HlsAdPlayer] updateOriginalMutedState called: ${originalMutedState} -> ${muted}`
|
|
1386
|
+
);
|
|
1288
1387
|
originalMutedState = muted;
|
|
1289
1388
|
},
|
|
1290
1389
|
getOriginalMutedState() {
|
|
@@ -1777,6 +1876,9 @@ var StormcloudVideoPlayer = class {
|
|
|
1777
1876
|
this.isLiveStream = false;
|
|
1778
1877
|
this.nativeHlsMode = false;
|
|
1779
1878
|
this.videoSrcProtection = null;
|
|
1879
|
+
this.bufferedSegmentsCount = 0;
|
|
1880
|
+
this.shouldAutoplayAfterBuffering = false;
|
|
1881
|
+
this.hasInitialBufferCompleted = false;
|
|
1780
1882
|
initializePolyfills();
|
|
1781
1883
|
const browserOverrides = getBrowserConfigOverrides();
|
|
1782
1884
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -1863,14 +1965,22 @@ var StormcloudVideoPlayer = class {
|
|
|
1863
1965
|
liveDurationInfinity: true,
|
|
1864
1966
|
lowLatencyMode: !!this.config.lowLatencyMode,
|
|
1865
1967
|
maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
|
|
1866
|
-
...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
|
|
1867
1977
|
});
|
|
1868
1978
|
this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
|
|
1869
1979
|
var _a2;
|
|
1870
1980
|
(_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
|
|
1871
1981
|
});
|
|
1872
1982
|
this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
|
|
1873
|
-
var _a2, _b2, _c, _d;
|
|
1983
|
+
var _a2, _b2, _c, _d, _e;
|
|
1874
1984
|
this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
|
|
1875
1985
|
(level) => {
|
|
1876
1986
|
var _a3, _b3;
|
|
@@ -1888,9 +1998,51 @@ var StormcloudVideoPlayer = class {
|
|
|
1888
1998
|
this.ima.destroy();
|
|
1889
1999
|
this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
|
|
1890
2000
|
this.ima.initialize();
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
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
|
+
}
|
|
1894
2046
|
}
|
|
1895
2047
|
});
|
|
1896
2048
|
this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
|
|
@@ -1986,6 +2138,7 @@ var StormcloudVideoPlayer = class {
|
|
|
1986
2138
|
this.video.autoplay = !!this.config.autoplay;
|
|
1987
2139
|
this.video.muted = !!this.config.muted;
|
|
1988
2140
|
this.ima.initialize();
|
|
2141
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
1989
2142
|
this.ima.on("all_ads_completed", () => {
|
|
1990
2143
|
if (this.config.debugAdTiming) {
|
|
1991
2144
|
console.log(
|
|
@@ -2723,14 +2876,66 @@ var StormcloudVideoPlayer = class {
|
|
|
2723
2876
|
}
|
|
2724
2877
|
}
|
|
2725
2878
|
ensureAdStoppedByTimer() {
|
|
2879
|
+
var _a, _b;
|
|
2726
2880
|
if (!this.inAdBreak) return;
|
|
2881
|
+
this.adStopTimerId = void 0;
|
|
2882
|
+
const adPlaying = this.ima.isAdPlaying();
|
|
2883
|
+
const pendingAds = this.adPodQueue.length > 0;
|
|
2884
|
+
const checkIntervalMs = Math.max(
|
|
2885
|
+
250,
|
|
2886
|
+
Math.floor((_a = this.config.adBreakCheckIntervalMs) != null ? _a : 1e3)
|
|
2887
|
+
);
|
|
2888
|
+
const maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;
|
|
2889
|
+
const maxExtensionMs = typeof maxExtensionMsConfig === "number" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 6e4;
|
|
2890
|
+
let elapsedSinceStartMs = 0;
|
|
2891
|
+
if (this.currentAdBreakStartWallClockMs != null) {
|
|
2892
|
+
elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;
|
|
2893
|
+
}
|
|
2894
|
+
const expectedDurationMs = (_b = this.expectedAdBreakDurationMs) != null ? _b : 0;
|
|
2895
|
+
const overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);
|
|
2896
|
+
const shouldExtendAdBreak = (adPlaying || pendingAds || this.showAds) && overrunMs < maxExtensionMs;
|
|
2897
|
+
if (shouldExtendAdBreak) {
|
|
2898
|
+
if (this.config.debugAdTiming) {
|
|
2899
|
+
console.log(
|
|
2900
|
+
"[StormcloudVideoPlayer] Extending ad break beyond scheduled duration",
|
|
2901
|
+
{
|
|
2902
|
+
adPlaying,
|
|
2903
|
+
pendingAds,
|
|
2904
|
+
showAds: this.showAds,
|
|
2905
|
+
overrunMs,
|
|
2906
|
+
checkIntervalMs,
|
|
2907
|
+
maxExtensionMs
|
|
2908
|
+
}
|
|
2909
|
+
);
|
|
2910
|
+
}
|
|
2911
|
+
this.scheduleAdStopCountdown(checkIntervalMs);
|
|
2912
|
+
return;
|
|
2913
|
+
}
|
|
2914
|
+
if (this.config.debugAdTiming) {
|
|
2915
|
+
console.log("[StormcloudVideoPlayer] Ending ad break via timer", {
|
|
2916
|
+
adPlaying,
|
|
2917
|
+
pendingAds,
|
|
2918
|
+
showAds: this.showAds,
|
|
2919
|
+
overrunMs,
|
|
2920
|
+
maxExtensionMs
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2727
2923
|
this.inAdBreak = false;
|
|
2728
2924
|
this.expectedAdBreakDurationMs = void 0;
|
|
2729
2925
|
this.currentAdBreakStartWallClockMs = void 0;
|
|
2730
|
-
this.
|
|
2731
|
-
|
|
2926
|
+
this.showAds = false;
|
|
2927
|
+
this.adPodQueue = [];
|
|
2928
|
+
this.currentAdIndex = 0;
|
|
2929
|
+
this.totalAdsInBreak = 0;
|
|
2930
|
+
this.clearAdFailsafeTimer();
|
|
2931
|
+
if (adPlaying) {
|
|
2732
2932
|
this.ima.stop().catch(() => {
|
|
2733
2933
|
});
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
const originalMutedState = this.ima.getOriginalMutedState();
|
|
2937
|
+
if (this.video.muted !== originalMutedState) {
|
|
2938
|
+
this.video.muted = originalMutedState;
|
|
2734
2939
|
}
|
|
2735
2940
|
}
|
|
2736
2941
|
scheduleAdStartIn(delayMs) {
|
|
@@ -2770,7 +2975,23 @@ var StormcloudVideoPlayer = class {
|
|
|
2770
2975
|
}
|
|
2771
2976
|
return;
|
|
2772
2977
|
}
|
|
2773
|
-
|
|
2978
|
+
if (!this.showAds) {
|
|
2979
|
+
if (this.config.debugAdTiming) {
|
|
2980
|
+
console.log(
|
|
2981
|
+
`[StormcloudVideoPlayer] Capturing original state before ad request:`,
|
|
2982
|
+
{
|
|
2983
|
+
videoMuted: this.video.muted,
|
|
2984
|
+
videoVolume: this.video.volume,
|
|
2985
|
+
showAds: this.showAds
|
|
2986
|
+
}
|
|
2987
|
+
);
|
|
2988
|
+
}
|
|
2989
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
2990
|
+
} else if (this.config.debugAdTiming) {
|
|
2991
|
+
console.log(
|
|
2992
|
+
`[StormcloudVideoPlayer] Keeping existing original mute state (currently showing ads)`
|
|
2993
|
+
);
|
|
2994
|
+
}
|
|
2774
2995
|
this.startAdFailsafeTimer();
|
|
2775
2996
|
try {
|
|
2776
2997
|
await this.ima.requestAds(vastTagUrl);
|
|
@@ -2825,11 +3046,12 @@ var StormcloudVideoPlayer = class {
|
|
|
2825
3046
|
this.showAds = false;
|
|
2826
3047
|
this.currentAdIndex = 0;
|
|
2827
3048
|
this.totalAdsInBreak = 0;
|
|
3049
|
+
const currentMutedState = this.video.muted;
|
|
2828
3050
|
const originalMutedState = this.ima.getOriginalMutedState();
|
|
2829
3051
|
this.video.muted = originalMutedState;
|
|
2830
3052
|
if (this.config.debugAdTiming) {
|
|
2831
3053
|
console.log(
|
|
2832
|
-
`[StormcloudVideoPlayer] Restored mute state
|
|
3054
|
+
`[StormcloudVideoPlayer] Restored mute state: ${currentMutedState} -> ${originalMutedState}`
|
|
2833
3055
|
);
|
|
2834
3056
|
}
|
|
2835
3057
|
if (this.video.paused) {
|
|
@@ -2921,6 +3143,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2921
3143
|
}
|
|
2922
3144
|
} else {
|
|
2923
3145
|
this.video.muted = !this.video.muted;
|
|
3146
|
+
this.ima.updateOriginalMutedState(this.video.muted);
|
|
2924
3147
|
if (this.config.debugAdTiming) {
|
|
2925
3148
|
console.log("[StormcloudVideoPlayer] Muted:", this.video.muted);
|
|
2926
3149
|
}
|
|
@@ -2965,11 +3188,47 @@ var StormcloudVideoPlayer = class {
|
|
|
2965
3188
|
}
|
|
2966
3189
|
isMuted() {
|
|
2967
3190
|
if (this.ima.isAdPlaying()) {
|
|
2968
|
-
|
|
2969
|
-
|
|
3191
|
+
if (this.config.debugAdTiming) {
|
|
3192
|
+
console.log(
|
|
3193
|
+
"[StormcloudVideoPlayer] isMuted() override during ad playback -> false"
|
|
3194
|
+
);
|
|
3195
|
+
}
|
|
3196
|
+
return false;
|
|
3197
|
+
}
|
|
3198
|
+
if (this.config.debugAdTiming) {
|
|
3199
|
+
console.log(
|
|
3200
|
+
`[StormcloudVideoPlayer] isMuted() no ad playing: video.muted=${this.video.muted}`
|
|
3201
|
+
);
|
|
2970
3202
|
}
|
|
2971
3203
|
return this.video.muted;
|
|
2972
3204
|
}
|
|
3205
|
+
setMuted(muted) {
|
|
3206
|
+
const adPlaying = this.ima.isAdPlaying();
|
|
3207
|
+
if (adPlaying && muted === this.video.muted) {
|
|
3208
|
+
if (this.config.debugAdTiming) {
|
|
3209
|
+
console.log(
|
|
3210
|
+
"[StormcloudVideoPlayer] setMuted reflective update during ad ignored",
|
|
3211
|
+
{ muted }
|
|
3212
|
+
);
|
|
3213
|
+
}
|
|
3214
|
+
return;
|
|
3215
|
+
}
|
|
3216
|
+
this.video.muted = muted;
|
|
3217
|
+
if (adPlaying) {
|
|
3218
|
+
this.ima.updateOriginalMutedState(muted);
|
|
3219
|
+
this.ima.setAdVolume(muted ? 0 : 1);
|
|
3220
|
+
if (this.config.debugAdTiming) {
|
|
3221
|
+
console.log("[StormcloudVideoPlayer] setMuted applied during ad", {
|
|
3222
|
+
muted
|
|
3223
|
+
});
|
|
3224
|
+
}
|
|
3225
|
+
return;
|
|
3226
|
+
}
|
|
3227
|
+
this.ima.updateOriginalMutedState(muted);
|
|
3228
|
+
if (this.config.debugAdTiming) {
|
|
3229
|
+
console.log("[StormcloudVideoPlayer] setMuted called:", muted);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
2973
3232
|
isFullscreen() {
|
|
2974
3233
|
return !!document.fullscreenElement;
|
|
2975
3234
|
}
|
|
@@ -3080,6 +3339,8 @@ var HlsPlayer = class extends import_react.Component {
|
|
|
3080
3339
|
config.licenseKey = this.props.licenseKey;
|
|
3081
3340
|
if (this.props.adFailsafeTimeoutMs !== void 0)
|
|
3082
3341
|
config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
|
|
3342
|
+
if (this.props.minSegmentsBeforePlay !== void 0)
|
|
3343
|
+
config.minSegmentsBeforePlay = this.props.minSegmentsBeforePlay;
|
|
3083
3344
|
this.player = new StormcloudVideoPlayer(config);
|
|
3084
3345
|
(_b = (_a = this.props).onMount) == null ? void 0 : _b.call(_a, this);
|
|
3085
3346
|
await this.player.load();
|