stormcloud-video-player 0.2.3 → 0.2.4
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 +105 -18
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +3 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +105 -18
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +105 -18
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +3 -0
- package/lib/players/HlsPlayer.cjs +105 -18
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +105 -18
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/ima.cjs +56 -16
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/sdk/ima.d.cts +3 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +105 -18
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
package/lib/index.d.cts
CHANGED
|
@@ -91,6 +91,7 @@ declare class StormcloudVideoPlayer {
|
|
|
91
91
|
private currentAdIndex;
|
|
92
92
|
private totalAdsInBreak;
|
|
93
93
|
private showAds;
|
|
94
|
+
private isLiveStream;
|
|
94
95
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
95
96
|
load(): Promise<void>;
|
|
96
97
|
private attach;
|
|
@@ -114,6 +115,7 @@ declare class StormcloudVideoPlayer {
|
|
|
114
115
|
isShowingAds(): boolean;
|
|
115
116
|
getStreamType(): "hls" | "other";
|
|
116
117
|
shouldShowNativeControls(): boolean;
|
|
118
|
+
private shouldContinueLiveStreamDuringAds;
|
|
117
119
|
loadDefaultVastFromAdstorm(adstormApiUrl: string, params?: Record<string, string>): Promise<void>;
|
|
118
120
|
private handleAdStart;
|
|
119
121
|
private findCurrentOrNextBreak;
|
|
@@ -136,6 +138,7 @@ declare class StormcloudVideoPlayer {
|
|
|
136
138
|
toggleFullscreen(): Promise<void>;
|
|
137
139
|
isMuted(): boolean;
|
|
138
140
|
isFullscreen(): boolean;
|
|
141
|
+
isLive(): boolean;
|
|
139
142
|
get videoElement(): HTMLVideoElement;
|
|
140
143
|
resize(): void;
|
|
141
144
|
destroy(): void;
|
package/lib/index.d.ts
CHANGED
|
@@ -91,6 +91,7 @@ declare class StormcloudVideoPlayer {
|
|
|
91
91
|
private currentAdIndex;
|
|
92
92
|
private totalAdsInBreak;
|
|
93
93
|
private showAds;
|
|
94
|
+
private isLiveStream;
|
|
94
95
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
95
96
|
load(): Promise<void>;
|
|
96
97
|
private attach;
|
|
@@ -114,6 +115,7 @@ declare class StormcloudVideoPlayer {
|
|
|
114
115
|
isShowingAds(): boolean;
|
|
115
116
|
getStreamType(): "hls" | "other";
|
|
116
117
|
shouldShowNativeControls(): boolean;
|
|
118
|
+
private shouldContinueLiveStreamDuringAds;
|
|
117
119
|
loadDefaultVastFromAdstorm(adstormApiUrl: string, params?: Record<string, string>): Promise<void>;
|
|
118
120
|
private handleAdStart;
|
|
119
121
|
private findCurrentOrNextBreak;
|
|
@@ -136,6 +138,7 @@ declare class StormcloudVideoPlayer {
|
|
|
136
138
|
toggleFullscreen(): Promise<void>;
|
|
137
139
|
isMuted(): boolean;
|
|
138
140
|
isFullscreen(): boolean;
|
|
141
|
+
isLive(): boolean;
|
|
139
142
|
get videoElement(): HTMLVideoElement;
|
|
140
143
|
resize(): void;
|
|
141
144
|
destroy(): void;
|
package/lib/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import React, { useEffect, useRef, useMemo } from "react";
|
|
|
5
5
|
import Hls from "hls.js";
|
|
6
6
|
|
|
7
7
|
// src/sdk/ima.ts
|
|
8
|
-
function createImaController(video) {
|
|
8
|
+
function createImaController(video, options) {
|
|
9
9
|
let adPlaying = false;
|
|
10
10
|
let originalMutedState = false;
|
|
11
11
|
const listeners = /* @__PURE__ */ new Map();
|
|
@@ -198,8 +198,10 @@ function createImaController(video) {
|
|
|
198
198
|
"[IMA] Max retries reached, emitting ad_error"
|
|
199
199
|
);
|
|
200
200
|
emit("ad_error");
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
202
|
+
video.play().catch(() => {
|
|
203
|
+
});
|
|
204
|
+
}
|
|
203
205
|
}
|
|
204
206
|
}
|
|
205
207
|
);
|
|
@@ -209,7 +211,14 @@ function createImaController(video) {
|
|
|
209
211
|
console.log("[IMA] Content pause requested");
|
|
210
212
|
originalMutedState = video.muted;
|
|
211
213
|
video.muted = true;
|
|
212
|
-
|
|
214
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
215
|
+
video.pause();
|
|
216
|
+
console.log("[IMA] Video paused (VOD mode)");
|
|
217
|
+
} else {
|
|
218
|
+
console.log(
|
|
219
|
+
"[IMA] Video continues playing but muted (Live mode)"
|
|
220
|
+
);
|
|
221
|
+
}
|
|
213
222
|
adPlaying = true;
|
|
214
223
|
if (adContainerEl)
|
|
215
224
|
adContainerEl.style.pointerEvents = "auto";
|
|
@@ -224,8 +233,15 @@ function createImaController(video) {
|
|
|
224
233
|
video.muted = originalMutedState;
|
|
225
234
|
if (adContainerEl)
|
|
226
235
|
adContainerEl.style.pointerEvents = "none";
|
|
227
|
-
|
|
228
|
-
|
|
236
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
237
|
+
video.play().catch(() => {
|
|
238
|
+
});
|
|
239
|
+
console.log("[IMA] Video resumed (VOD mode)");
|
|
240
|
+
} else {
|
|
241
|
+
console.log(
|
|
242
|
+
"[IMA] Video unmuted (Live mode - was never paused)"
|
|
243
|
+
);
|
|
244
|
+
}
|
|
229
245
|
emit("content_resume");
|
|
230
246
|
}
|
|
231
247
|
);
|
|
@@ -234,8 +250,17 @@ function createImaController(video) {
|
|
|
234
250
|
adPlaying = false;
|
|
235
251
|
video.muted = originalMutedState;
|
|
236
252
|
if (adContainerEl) adContainerEl.style.pointerEvents = "none";
|
|
237
|
-
|
|
238
|
-
|
|
253
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
254
|
+
video.play().catch(() => {
|
|
255
|
+
});
|
|
256
|
+
console.log(
|
|
257
|
+
"[IMA] Video resumed after all ads completed (VOD mode)"
|
|
258
|
+
);
|
|
259
|
+
} else {
|
|
260
|
+
console.log(
|
|
261
|
+
"[IMA] Video unmuted after all ads completed (Live mode)"
|
|
262
|
+
);
|
|
263
|
+
}
|
|
239
264
|
emit("all_ads_completed");
|
|
240
265
|
});
|
|
241
266
|
console.log("[IMA] Ads manager event listeners attached");
|
|
@@ -249,8 +274,10 @@ function createImaController(video) {
|
|
|
249
274
|
adPlaying = false;
|
|
250
275
|
video.muted = originalMutedState;
|
|
251
276
|
if (adContainerEl) adContainerEl.style.pointerEvents = "none";
|
|
252
|
-
|
|
253
|
-
|
|
277
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
278
|
+
video.play().catch(() => {
|
|
279
|
+
});
|
|
280
|
+
}
|
|
254
281
|
if (adsLoadedReject) {
|
|
255
282
|
adsLoadedReject(new Error("Failed to setup ads manager"));
|
|
256
283
|
adsLoadedReject = void 0;
|
|
@@ -304,8 +331,14 @@ function createImaController(video) {
|
|
|
304
331
|
const height = video.clientHeight || 360;
|
|
305
332
|
console.log(`[IMA] Initializing ads manager (${width}x${height})`);
|
|
306
333
|
adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
|
|
307
|
-
|
|
308
|
-
|
|
334
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
335
|
+
console.log("[IMA] Pausing video for ad playback (VOD mode)");
|
|
336
|
+
video.pause();
|
|
337
|
+
} else {
|
|
338
|
+
console.log(
|
|
339
|
+
"[IMA] Keeping video playing but muted for ad playback (Live mode)"
|
|
340
|
+
);
|
|
341
|
+
}
|
|
309
342
|
adPlaying = true;
|
|
310
343
|
console.log("[IMA] Starting ad playback");
|
|
311
344
|
adsManager.start();
|
|
@@ -313,8 +346,10 @@ function createImaController(video) {
|
|
|
313
346
|
} catch (error) {
|
|
314
347
|
console.error("[IMA] Error starting ad playback:", error);
|
|
315
348
|
adPlaying = false;
|
|
316
|
-
|
|
317
|
-
|
|
349
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
350
|
+
video.play().catch(() => {
|
|
351
|
+
});
|
|
352
|
+
}
|
|
318
353
|
return Promise.reject(error);
|
|
319
354
|
}
|
|
320
355
|
},
|
|
@@ -325,8 +360,13 @@ function createImaController(video) {
|
|
|
325
360
|
adsManager?.stop?.();
|
|
326
361
|
} catch {
|
|
327
362
|
}
|
|
328
|
-
|
|
329
|
-
|
|
363
|
+
if (!options?.continueLiveStreamDuringAds) {
|
|
364
|
+
video.play().catch(() => {
|
|
365
|
+
});
|
|
366
|
+
console.log("[IMA] Video resumed after stop (VOD mode)");
|
|
367
|
+
} else {
|
|
368
|
+
console.log("[IMA] Video unmuted after stop (Live mode)");
|
|
369
|
+
}
|
|
330
370
|
},
|
|
331
371
|
destroy() {
|
|
332
372
|
try {
|
|
@@ -623,9 +663,12 @@ var StormcloudVideoPlayer = class {
|
|
|
623
663
|
this.currentAdIndex = 0;
|
|
624
664
|
this.totalAdsInBreak = 0;
|
|
625
665
|
this.showAds = false;
|
|
666
|
+
this.isLiveStream = false;
|
|
626
667
|
this.config = config;
|
|
627
668
|
this.video = config.videoElement;
|
|
628
|
-
this.ima = createImaController(this.video
|
|
669
|
+
this.ima = createImaController(this.video, {
|
|
670
|
+
continueLiveStreamDuringAds: false
|
|
671
|
+
});
|
|
629
672
|
}
|
|
630
673
|
async load() {
|
|
631
674
|
if (!this.attached) {
|
|
@@ -644,6 +687,22 @@ var StormcloudVideoPlayer = class {
|
|
|
644
687
|
this.initializeTracking();
|
|
645
688
|
if (this.shouldUseNativeHls()) {
|
|
646
689
|
this.video.src = this.config.src;
|
|
690
|
+
this.isLiveStream = this.config.lowLatencyMode ?? false;
|
|
691
|
+
if (this.config.debugAdTiming) {
|
|
692
|
+
console.log(
|
|
693
|
+
"[StormcloudVideoPlayer] allowNativeHls: true - VOD mode detected:",
|
|
694
|
+
{
|
|
695
|
+
isLive: this.isLiveStream,
|
|
696
|
+
allowNativeHls: this.config.allowNativeHls,
|
|
697
|
+
adBehavior: "vod (main video pauses during ads)"
|
|
698
|
+
}
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
this.ima.destroy();
|
|
702
|
+
this.ima = createImaController(this.video, {
|
|
703
|
+
continueLiveStreamDuringAds: false
|
|
704
|
+
});
|
|
705
|
+
this.ima.initialize();
|
|
647
706
|
if (this.config.autoplay) {
|
|
648
707
|
await this.video.play().catch(() => {
|
|
649
708
|
});
|
|
@@ -661,7 +720,23 @@ var StormcloudVideoPlayer = class {
|
|
|
661
720
|
this.hls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
|
662
721
|
this.hls?.loadSource(this.config.src);
|
|
663
722
|
});
|
|
664
|
-
this.hls.on(Hls.Events.MANIFEST_PARSED, async () => {
|
|
723
|
+
this.hls.on(Hls.Events.MANIFEST_PARSED, async (_, data) => {
|
|
724
|
+
this.isLiveStream = this.hls?.levels?.some(
|
|
725
|
+
(level) => level?.details?.live === true || level?.details?.type === "LIVE"
|
|
726
|
+
) ?? false;
|
|
727
|
+
if (this.config.debugAdTiming) {
|
|
728
|
+
const adBehavior = this.shouldContinueLiveStreamDuringAds() ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
|
|
729
|
+
console.log("[StormcloudVideoPlayer] Stream type detected:", {
|
|
730
|
+
isLive: this.isLiveStream,
|
|
731
|
+
allowNativeHls: this.config.allowNativeHls,
|
|
732
|
+
adBehavior
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
this.ima.destroy();
|
|
736
|
+
this.ima = createImaController(this.video, {
|
|
737
|
+
continueLiveStreamDuringAds: this.shouldContinueLiveStreamDuringAds()
|
|
738
|
+
});
|
|
739
|
+
this.ima.initialize();
|
|
665
740
|
if (this.config.autoplay) {
|
|
666
741
|
await this.video.play().catch(() => {
|
|
667
742
|
});
|
|
@@ -1287,6 +1362,15 @@ var StormcloudVideoPlayer = class {
|
|
|
1287
1362
|
}
|
|
1288
1363
|
return !!(this.config.allowNativeHls && !(this.config.showCustomControls ?? false));
|
|
1289
1364
|
}
|
|
1365
|
+
shouldContinueLiveStreamDuringAds() {
|
|
1366
|
+
if (this.config.allowNativeHls) {
|
|
1367
|
+
return false;
|
|
1368
|
+
}
|
|
1369
|
+
if (!this.isLiveStream) {
|
|
1370
|
+
return false;
|
|
1371
|
+
}
|
|
1372
|
+
return true;
|
|
1373
|
+
}
|
|
1290
1374
|
async loadDefaultVastFromAdstorm(adstormApiUrl, params) {
|
|
1291
1375
|
const usp = new URLSearchParams(params || {});
|
|
1292
1376
|
const url = `${adstormApiUrl}?${usp.toString()}`;
|
|
@@ -1601,6 +1685,9 @@ var StormcloudVideoPlayer = class {
|
|
|
1601
1685
|
isFullscreen() {
|
|
1602
1686
|
return !!document.fullscreenElement;
|
|
1603
1687
|
}
|
|
1688
|
+
isLive() {
|
|
1689
|
+
return this.isLiveStream;
|
|
1690
|
+
}
|
|
1604
1691
|
get videoElement() {
|
|
1605
1692
|
return this.video;
|
|
1606
1693
|
}
|