stormcloud-video-player 0.2.12 → 0.2.14
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/README.md +100 -1
- package/dist/stormcloud-vp.min.js +2 -2
- package/lib/index.cjs +1206 -151
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +77 -2
- package/lib/index.d.ts +77 -2
- package/lib/index.js +1196 -151
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +1100 -114
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +2 -2
- package/lib/players/FilePlayer.cjs +14 -7
- package/lib/players/FilePlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +1108 -119
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +1122 -126
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs +561 -0
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -0
- package/lib/sdk/hlsAdPlayer.d.cts +10 -0
- package/lib/sdk/ima.cjs +176 -23
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/sdk/ima.d.cts +1 -1
- package/lib/{types-GpA_hKek.d.cts → types-mVgmKmzM.d.cts} +3 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +1107 -119
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/utils/browserCompat.cjs +229 -0
- package/lib/utils/browserCompat.cjs.map +1 -0
- package/lib/utils/browserCompat.d.cts +36 -0
- package/lib/utils/polyfills.cjs +253 -0
- package/lib/utils/polyfills.cjs.map +1 -0
- package/lib/utils/polyfills.d.cts +11 -0
- package/lib/utils/tracking.cjs +10 -9
- package/lib/utils/tracking.cjs.map +1 -1
- package/lib/utils/tracking.d.cts +1 -1
- package/package.json +1 -1
package/lib/index.cjs
CHANGED
|
@@ -40,12 +40,19 @@ __export(index_exports, {
|
|
|
40
40
|
StormcloudVideoPlayer: () => StormcloudVideoPlayer,
|
|
41
41
|
StormcloudVideoPlayerComponent: () => StormcloudVideoPlayerComponent,
|
|
42
42
|
canPlay: () => canPlay,
|
|
43
|
+
createHlsAdPlayer: () => createHlsAdPlayer,
|
|
44
|
+
createImaController: () => createImaController,
|
|
43
45
|
createStormcloudPlayer: () => createStormcloudPlayer,
|
|
44
46
|
default: () => StormcloudVideoPlayerComponent,
|
|
47
|
+
detectBrowser: () => detectBrowser,
|
|
48
|
+
getBrowserConfigOverrides: () => getBrowserConfigOverrides,
|
|
45
49
|
getBrowserID: () => getBrowserID,
|
|
46
50
|
getClientInfo: () => getClientInfo,
|
|
51
|
+
getRecommendedAdPlayer: () => getRecommendedAdPlayer,
|
|
52
|
+
initializePolyfills: () => initializePolyfills,
|
|
47
53
|
isMediaStream: () => isMediaStream,
|
|
48
54
|
lazy: () => lazy,
|
|
55
|
+
logBrowserInfo: () => logBrowserInfo,
|
|
49
56
|
merge: () => merge,
|
|
50
57
|
omit: () => omit,
|
|
51
58
|
parseQuery: () => parseQuery,
|
|
@@ -53,6 +60,9 @@ __export(index_exports, {
|
|
|
53
60
|
randomString: () => randomString,
|
|
54
61
|
sendHeartbeat: () => sendHeartbeat,
|
|
55
62
|
sendInitialTracking: () => sendInitialTracking,
|
|
63
|
+
supportsFeature: () => supportsFeature,
|
|
64
|
+
supportsGoogleIMA: () => supportsGoogleIMA,
|
|
65
|
+
supportsModernJS: () => supportsModernJS,
|
|
56
66
|
supportsWebKitPresentationMode: () => supportsWebKitPresentationMode
|
|
57
67
|
});
|
|
58
68
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -61,7 +71,196 @@ module.exports = __toCommonJS(index_exports);
|
|
|
61
71
|
var import_react = __toESM(require("react"), 1);
|
|
62
72
|
|
|
63
73
|
// src/player/StormcloudVideoPlayer.ts
|
|
64
|
-
var
|
|
74
|
+
var import_hls2 = __toESM(require("hls.js"), 1);
|
|
75
|
+
|
|
76
|
+
// src/utils/browserCompat.ts
|
|
77
|
+
function getChromeVersion(ua) {
|
|
78
|
+
const match = ua.match(/Chrome\/(\d+)/);
|
|
79
|
+
return match && match[1] ? parseInt(match[1], 10) : 0;
|
|
80
|
+
}
|
|
81
|
+
function getWebKitVersion(ua) {
|
|
82
|
+
const match = ua.match(/AppleWebKit\/(\d+)/);
|
|
83
|
+
return match && match[1] ? parseInt(match[1], 10) : 0;
|
|
84
|
+
}
|
|
85
|
+
function getPlatform() {
|
|
86
|
+
var _a;
|
|
87
|
+
if ("userAgentData" in navigator && ((_a = navigator.userAgentData) == null ? void 0 : _a.platform)) {
|
|
88
|
+
return navigator.userAgentData.platform;
|
|
89
|
+
}
|
|
90
|
+
const ua = navigator.userAgent;
|
|
91
|
+
if (/Mac|iPhone|iPad|iPod/i.test(ua)) {
|
|
92
|
+
return /iPhone|iPad|iPod/i.test(ua) ? "iPhone" : "MacIntel";
|
|
93
|
+
}
|
|
94
|
+
if (/Win/i.test(ua)) {
|
|
95
|
+
return "Win32";
|
|
96
|
+
}
|
|
97
|
+
if (/Linux/i.test(ua)) {
|
|
98
|
+
return /Android/i.test(ua) ? "Linux armv8l" : "Linux x86_64";
|
|
99
|
+
}
|
|
100
|
+
if (/CrOS/i.test(ua)) {
|
|
101
|
+
return "CrOS";
|
|
102
|
+
}
|
|
103
|
+
return navigator.platform || "Unknown";
|
|
104
|
+
}
|
|
105
|
+
function detectBrowser() {
|
|
106
|
+
const ua = navigator.userAgent;
|
|
107
|
+
const platform = getPlatform();
|
|
108
|
+
let name = "Unknown";
|
|
109
|
+
let version = "0";
|
|
110
|
+
let majorVersion = 0;
|
|
111
|
+
let isSmartTV = false;
|
|
112
|
+
let isLegacyTV = false;
|
|
113
|
+
let supportsIMA = true;
|
|
114
|
+
let supportsModernJS2 = true;
|
|
115
|
+
let recommendedAdPlayer = "ima";
|
|
116
|
+
if (/Web0S|webOS/i.test(ua)) {
|
|
117
|
+
name = "LG WebOS";
|
|
118
|
+
isSmartTV = true;
|
|
119
|
+
const match = ua.match(/Web0S[/\s]*([\d.]+)/i);
|
|
120
|
+
version = match && match[1] ? match[1] : "Unknown";
|
|
121
|
+
if (version !== "Unknown") {
|
|
122
|
+
const parts = version.split(".");
|
|
123
|
+
majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;
|
|
124
|
+
}
|
|
125
|
+
} else if (/Tizen/i.test(ua)) {
|
|
126
|
+
name = "Samsung Tizen";
|
|
127
|
+
isSmartTV = true;
|
|
128
|
+
const match = ua.match(/Tizen[/\s]*([\d.]+)/i);
|
|
129
|
+
version = match && match[1] ? match[1] : "Unknown";
|
|
130
|
+
if (version !== "Unknown") {
|
|
131
|
+
const parts = version.split(".");
|
|
132
|
+
majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;
|
|
133
|
+
}
|
|
134
|
+
} else if (/SMART-TV|SmartTV/i.test(ua)) {
|
|
135
|
+
name = "Smart TV";
|
|
136
|
+
isSmartTV = true;
|
|
137
|
+
} else if (/NetCast/i.test(ua)) {
|
|
138
|
+
name = "LG NetCast";
|
|
139
|
+
isSmartTV = true;
|
|
140
|
+
isLegacyTV = true;
|
|
141
|
+
} else if (/BRAVIA/i.test(ua)) {
|
|
142
|
+
name = "Sony BRAVIA";
|
|
143
|
+
isSmartTV = true;
|
|
144
|
+
}
|
|
145
|
+
const chromeVersion = getChromeVersion(ua);
|
|
146
|
+
const webkitVersion = getWebKitVersion(ua);
|
|
147
|
+
if (chromeVersion > 0) {
|
|
148
|
+
if (!isSmartTV) {
|
|
149
|
+
name = "Chrome";
|
|
150
|
+
version = chromeVersion.toString();
|
|
151
|
+
majorVersion = chromeVersion;
|
|
152
|
+
}
|
|
153
|
+
if (chromeVersion < 50) {
|
|
154
|
+
supportsIMA = false;
|
|
155
|
+
supportsModernJS2 = false;
|
|
156
|
+
isLegacyTV = true;
|
|
157
|
+
recommendedAdPlayer = "hls";
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (webkitVersion > 0 && webkitVersion < 600) {
|
|
161
|
+
supportsModernJS2 = false;
|
|
162
|
+
if (isSmartTV) {
|
|
163
|
+
isLegacyTV = true;
|
|
164
|
+
supportsIMA = false;
|
|
165
|
+
recommendedAdPlayer = "hls";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (typeof Promise === "undefined" || typeof Map === "undefined" || typeof Set === "undefined") {
|
|
169
|
+
supportsModernJS2 = false;
|
|
170
|
+
supportsIMA = false;
|
|
171
|
+
recommendedAdPlayer = "hls";
|
|
172
|
+
}
|
|
173
|
+
if (typeof URLSearchParams === "undefined") {
|
|
174
|
+
supportsModernJS2 = false;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
name,
|
|
178
|
+
version,
|
|
179
|
+
majorVersion,
|
|
180
|
+
isSmartTV,
|
|
181
|
+
isLegacyTV,
|
|
182
|
+
platform,
|
|
183
|
+
supportsIMA,
|
|
184
|
+
supportsModernJS: supportsModernJS2,
|
|
185
|
+
recommendedAdPlayer
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function supportsGoogleIMA() {
|
|
189
|
+
const browser = detectBrowser();
|
|
190
|
+
if (browser.isLegacyTV) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
if (typeof document === "undefined" || typeof document.createElement !== "function") {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const video = document.createElement("video");
|
|
198
|
+
if (!video) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
} catch (e) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
if (typeof Promise === "undefined") {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
return browser.supportsIMA;
|
|
208
|
+
}
|
|
209
|
+
function getRecommendedAdPlayer() {
|
|
210
|
+
const browser = detectBrowser();
|
|
211
|
+
return browser.recommendedAdPlayer;
|
|
212
|
+
}
|
|
213
|
+
function supportsModernJS() {
|
|
214
|
+
try {
|
|
215
|
+
return typeof Promise !== "undefined" && typeof Map !== "undefined" && typeof Set !== "undefined" && typeof Array.from !== "undefined" && typeof Object.assign !== "undefined" && typeof Array.prototype.forEach !== "undefined" && typeof String.prototype.includes !== "undefined";
|
|
216
|
+
} catch (e) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function logBrowserInfo(debug = false) {
|
|
221
|
+
if (!debug) return;
|
|
222
|
+
const browser = detectBrowser();
|
|
223
|
+
const imaSupport = supportsGoogleIMA();
|
|
224
|
+
console.log("[StormcloudVideoPlayer] Browser Compatibility Info:", {
|
|
225
|
+
browser: `${browser.name} ${browser.version}`,
|
|
226
|
+
platform: browser.platform,
|
|
227
|
+
isSmartTV: browser.isSmartTV,
|
|
228
|
+
isLegacyTV: browser.isLegacyTV,
|
|
229
|
+
supportsIMA: imaSupport,
|
|
230
|
+
supportsModernJS: browser.supportsModernJS,
|
|
231
|
+
recommendedAdPlayer: browser.recommendedAdPlayer,
|
|
232
|
+
userAgent: navigator.userAgent
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function getBrowserConfigOverrides() {
|
|
236
|
+
const browser = detectBrowser();
|
|
237
|
+
const overrides = {};
|
|
238
|
+
if (browser.isLegacyTV || !browser.supportsIMA) {
|
|
239
|
+
overrides.adPlayerType = "hls";
|
|
240
|
+
}
|
|
241
|
+
if (browser.isSmartTV) {
|
|
242
|
+
overrides.allowNativeHls = true;
|
|
243
|
+
}
|
|
244
|
+
return overrides;
|
|
245
|
+
}
|
|
246
|
+
function supportsFeature(feature) {
|
|
247
|
+
switch (feature) {
|
|
248
|
+
case "ima":
|
|
249
|
+
return supportsGoogleIMA();
|
|
250
|
+
case "urlsearchparams":
|
|
251
|
+
return typeof URLSearchParams !== "undefined";
|
|
252
|
+
case "textencoder":
|
|
253
|
+
return typeof TextEncoder !== "undefined";
|
|
254
|
+
case "promises":
|
|
255
|
+
return typeof Promise !== "undefined";
|
|
256
|
+
case "fetch":
|
|
257
|
+
return typeof fetch !== "undefined";
|
|
258
|
+
case "crypto":
|
|
259
|
+
return typeof crypto !== "undefined" && typeof crypto.subtle !== "undefined";
|
|
260
|
+
default:
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
65
264
|
|
|
66
265
|
// src/sdk/ima.ts
|
|
67
266
|
function createImaController(video, options) {
|
|
@@ -79,9 +278,18 @@ function createImaController(video, options) {
|
|
|
79
278
|
}
|
|
80
279
|
}
|
|
81
280
|
function ensureImaLoaded() {
|
|
281
|
+
var _a, _b, _c;
|
|
282
|
+
if (!supportsGoogleIMA()) {
|
|
283
|
+
console.warn(
|
|
284
|
+
"[IMA] Google IMA SDK is not supported on this browser. Please use HLS ad player instead."
|
|
285
|
+
);
|
|
286
|
+
return Promise.reject(
|
|
287
|
+
new Error("Google IMA SDK not supported on this browser")
|
|
288
|
+
);
|
|
289
|
+
}
|
|
82
290
|
try {
|
|
83
291
|
const frameEl = window.frameElement;
|
|
84
|
-
const sandboxAttr = frameEl
|
|
292
|
+
const sandboxAttr = ((_a = frameEl == null ? void 0 : frameEl.getAttribute) == null ? void 0 : _a.call(frameEl, "sandbox")) || "";
|
|
85
293
|
if (sandboxAttr) {
|
|
86
294
|
const tokens = new Set(
|
|
87
295
|
sandboxAttr.split(/\s+/).map((t) => t.trim()).filter((t) => t.length > 0)
|
|
@@ -95,13 +303,13 @@ function createImaController(video, options) {
|
|
|
95
303
|
}
|
|
96
304
|
} catch {
|
|
97
305
|
}
|
|
98
|
-
if (typeof window !== "undefined" && window.google
|
|
306
|
+
if (typeof window !== "undefined" && ((_b = window.google) == null ? void 0 : _b.ima))
|
|
99
307
|
return Promise.resolve();
|
|
100
308
|
const existing = document.querySelector(
|
|
101
309
|
'script[data-ima="true"]'
|
|
102
310
|
);
|
|
103
311
|
if (existing) {
|
|
104
|
-
if (window.google
|
|
312
|
+
if ((_c = window.google) == null ? void 0 : _c.ima) {
|
|
105
313
|
return Promise.resolve();
|
|
106
314
|
}
|
|
107
315
|
return new Promise((resolve, reject) => {
|
|
@@ -159,6 +367,7 @@ function createImaController(video, options) {
|
|
|
159
367
|
return {
|
|
160
368
|
initialize() {
|
|
161
369
|
ensureImaLoaded().then(() => {
|
|
370
|
+
var _a, _b;
|
|
162
371
|
const google = window.google;
|
|
163
372
|
if (!adDisplayContainer) {
|
|
164
373
|
const container = document.createElement("div");
|
|
@@ -172,14 +381,14 @@ function createImaController(video, options) {
|
|
|
172
381
|
container.style.justifyContent = "center";
|
|
173
382
|
container.style.pointerEvents = "none";
|
|
174
383
|
container.style.zIndex = "2";
|
|
175
|
-
video.parentElement
|
|
384
|
+
(_a = video.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
176
385
|
adContainerEl = container;
|
|
177
386
|
adDisplayContainer = new google.ima.AdDisplayContainer(
|
|
178
387
|
container,
|
|
179
388
|
video
|
|
180
389
|
);
|
|
181
390
|
try {
|
|
182
|
-
adDisplayContainer.initialize
|
|
391
|
+
(_b = adDisplayContainer.initialize) == null ? void 0 : _b.call(adDisplayContainer);
|
|
183
392
|
} catch {
|
|
184
393
|
}
|
|
185
394
|
}
|
|
@@ -264,6 +473,7 @@ function createImaController(video, options) {
|
|
|
264
473
|
adsManager.addEventListener(
|
|
265
474
|
AdErrorEvent.AD_ERROR,
|
|
266
475
|
(errorEvent) => {
|
|
476
|
+
var _a;
|
|
267
477
|
console.error("[IMA] Ad error:", errorEvent.getError());
|
|
268
478
|
destroyAdsManager();
|
|
269
479
|
adPlaying = false;
|
|
@@ -294,10 +504,10 @@ function createImaController(video, options) {
|
|
|
294
504
|
"[IMA] Max retries reached, emitting ad_error"
|
|
295
505
|
);
|
|
296
506
|
emit("ad_error");
|
|
297
|
-
if (!options
|
|
507
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
298
508
|
if (video.paused) {
|
|
299
509
|
console.log("[IMA] Resuming paused video after ad error");
|
|
300
|
-
video.play()
|
|
510
|
+
(_a = video.play()) == null ? void 0 : _a.catch(() => {
|
|
301
511
|
});
|
|
302
512
|
}
|
|
303
513
|
}
|
|
@@ -308,7 +518,7 @@ function createImaController(video, options) {
|
|
|
308
518
|
AdEvent.CONTENT_PAUSE_REQUESTED,
|
|
309
519
|
() => {
|
|
310
520
|
console.log("[IMA] Content pause requested");
|
|
311
|
-
if (!options
|
|
521
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
312
522
|
video.pause();
|
|
313
523
|
console.log("[IMA] Video paused (VOD mode)");
|
|
314
524
|
} else {
|
|
@@ -334,6 +544,7 @@ function createImaController(video, options) {
|
|
|
334
544
|
adsManager.addEventListener(
|
|
335
545
|
AdEvent.CONTENT_RESUME_REQUESTED,
|
|
336
546
|
() => {
|
|
547
|
+
var _a;
|
|
337
548
|
console.log("[IMA] Content resume requested");
|
|
338
549
|
adPlaying = false;
|
|
339
550
|
video.muted = originalMutedState;
|
|
@@ -344,8 +555,8 @@ function createImaController(video, options) {
|
|
|
344
555
|
"[IMA] Ad container hidden - pointer events disabled"
|
|
345
556
|
);
|
|
346
557
|
}
|
|
347
|
-
if (!options
|
|
348
|
-
video.play()
|
|
558
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
559
|
+
(_a = video.play()) == null ? void 0 : _a.catch(() => {
|
|
349
560
|
});
|
|
350
561
|
console.log("[IMA] Video resumed (VOD mode)");
|
|
351
562
|
} else {
|
|
@@ -367,7 +578,7 @@ function createImaController(video, options) {
|
|
|
367
578
|
"[IMA] Ad container hidden after all ads completed"
|
|
368
579
|
);
|
|
369
580
|
}
|
|
370
|
-
if (!options
|
|
581
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
371
582
|
video.play().catch(() => {
|
|
372
583
|
});
|
|
373
584
|
console.log(
|
|
@@ -395,7 +606,7 @@ function createImaController(video, options) {
|
|
|
395
606
|
adContainerEl.style.display = "none";
|
|
396
607
|
console.log("[IMA] Ad container hidden after setup error");
|
|
397
608
|
}
|
|
398
|
-
if (!options
|
|
609
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
399
610
|
if (video.paused) {
|
|
400
611
|
console.log("[IMA] Resuming paused video after setup error");
|
|
401
612
|
video.play().catch(() => {
|
|
@@ -423,7 +634,7 @@ function createImaController(video, options) {
|
|
|
423
634
|
adContainerEl.style.display = "none";
|
|
424
635
|
console.log("[IMA] Ad container hidden after loader error");
|
|
425
636
|
}
|
|
426
|
-
if (!options
|
|
637
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
427
638
|
if (video.paused) {
|
|
428
639
|
console.log("[IMA] Resuming paused video after loader error");
|
|
429
640
|
video.play().catch(() => {
|
|
@@ -445,14 +656,15 @@ function createImaController(video, options) {
|
|
|
445
656
|
return adsLoadedPromise;
|
|
446
657
|
} catch (error) {
|
|
447
658
|
console.error("[IMA] Failed to request ads:", error);
|
|
448
|
-
currentReject
|
|
659
|
+
currentReject == null ? void 0 : currentReject(error);
|
|
449
660
|
adsLoadedReject = void 0;
|
|
450
661
|
adsLoadedResolve = void 0;
|
|
451
662
|
return Promise.reject(error);
|
|
452
663
|
}
|
|
453
664
|
},
|
|
454
665
|
async play() {
|
|
455
|
-
|
|
666
|
+
var _a, _b;
|
|
667
|
+
if (!((_a = window.google) == null ? void 0 : _a.ima) || !adDisplayContainer) {
|
|
456
668
|
console.warn(
|
|
457
669
|
"[IMA] Cannot play ad: IMA SDK or ad container not available"
|
|
458
670
|
);
|
|
@@ -474,14 +686,15 @@ function createImaController(video, options) {
|
|
|
474
686
|
} catch (error) {
|
|
475
687
|
console.error("[IMA] Error starting ad playback:", error);
|
|
476
688
|
adPlaying = false;
|
|
477
|
-
if (!options
|
|
478
|
-
video.play()
|
|
689
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
690
|
+
(_b = video.play()) == null ? void 0 : _b.catch(() => {
|
|
479
691
|
});
|
|
480
692
|
}
|
|
481
693
|
return Promise.reject(error);
|
|
482
694
|
}
|
|
483
695
|
},
|
|
484
696
|
async stop() {
|
|
697
|
+
var _a;
|
|
485
698
|
adPlaying = false;
|
|
486
699
|
video.muted = originalMutedState;
|
|
487
700
|
if (adContainerEl) {
|
|
@@ -490,11 +703,11 @@ function createImaController(video, options) {
|
|
|
490
703
|
console.log("[IMA] Ad container hidden after stop");
|
|
491
704
|
}
|
|
492
705
|
try {
|
|
493
|
-
adsManager
|
|
706
|
+
(_a = adsManager == null ? void 0 : adsManager.stop) == null ? void 0 : _a.call(adsManager);
|
|
494
707
|
} catch {
|
|
495
708
|
}
|
|
496
709
|
destroyAdsManager();
|
|
497
|
-
if (!options
|
|
710
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
498
711
|
video.play().catch(() => {
|
|
499
712
|
});
|
|
500
713
|
console.log("[IMA] Video resumed after stop (VOD mode)");
|
|
@@ -503,6 +716,7 @@ function createImaController(video, options) {
|
|
|
503
716
|
}
|
|
504
717
|
},
|
|
505
718
|
destroy() {
|
|
719
|
+
var _a;
|
|
506
720
|
destroyAdsManager();
|
|
507
721
|
adPlaying = false;
|
|
508
722
|
video.muted = originalMutedState;
|
|
@@ -511,10 +725,10 @@ function createImaController(video, options) {
|
|
|
511
725
|
adContainerEl.style.display = "none";
|
|
512
726
|
}
|
|
513
727
|
try {
|
|
514
|
-
adsLoader
|
|
728
|
+
(_a = adsLoader == null ? void 0 : adsLoader.destroy) == null ? void 0 : _a.call(adsLoader);
|
|
515
729
|
} catch {
|
|
516
730
|
}
|
|
517
|
-
if (adContainerEl
|
|
731
|
+
if (adContainerEl == null ? void 0 : adContainerEl.parentElement) {
|
|
518
732
|
adContainerEl.parentElement.removeChild(adContainerEl);
|
|
519
733
|
}
|
|
520
734
|
adContainerEl = void 0;
|
|
@@ -525,7 +739,8 @@ function createImaController(video, options) {
|
|
|
525
739
|
return adPlaying;
|
|
526
740
|
},
|
|
527
741
|
resize(width, height) {
|
|
528
|
-
|
|
742
|
+
var _a;
|
|
743
|
+
if (!adsManager || !((_a = window.google) == null ? void 0 : _a.ima)) {
|
|
529
744
|
console.warn(
|
|
530
745
|
"[IMA] Cannot resize: No ads manager or IMA SDK available"
|
|
531
746
|
);
|
|
@@ -543,7 +758,8 @@ function createImaController(video, options) {
|
|
|
543
758
|
listeners.get(event).add(listener);
|
|
544
759
|
},
|
|
545
760
|
off(event, listener) {
|
|
546
|
-
|
|
761
|
+
var _a;
|
|
762
|
+
(_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
|
|
547
763
|
},
|
|
548
764
|
updateOriginalMutedState(muted) {
|
|
549
765
|
originalMutedState = muted;
|
|
@@ -574,9 +790,533 @@ function createImaController(video, options) {
|
|
|
574
790
|
};
|
|
575
791
|
}
|
|
576
792
|
|
|
793
|
+
// src/sdk/hlsAdPlayer.ts
|
|
794
|
+
var import_hls = __toESM(require("hls.js"), 1);
|
|
795
|
+
function createHlsAdPlayer(contentVideo, options) {
|
|
796
|
+
let adPlaying = false;
|
|
797
|
+
let originalMutedState = false;
|
|
798
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
799
|
+
const licenseKey = options == null ? void 0 : options.licenseKey;
|
|
800
|
+
const mainHlsInstance = options == null ? void 0 : options.mainHlsInstance;
|
|
801
|
+
let adVideoElement;
|
|
802
|
+
let adHls;
|
|
803
|
+
let adContainerEl;
|
|
804
|
+
let currentAd;
|
|
805
|
+
let sessionId;
|
|
806
|
+
let trackingFired = {
|
|
807
|
+
impression: false,
|
|
808
|
+
start: false,
|
|
809
|
+
firstQuartile: false,
|
|
810
|
+
midpoint: false,
|
|
811
|
+
thirdQuartile: false,
|
|
812
|
+
complete: false
|
|
813
|
+
};
|
|
814
|
+
function emit(event, payload) {
|
|
815
|
+
const set = listeners.get(event);
|
|
816
|
+
if (!set) return;
|
|
817
|
+
for (const fn of Array.from(set)) {
|
|
818
|
+
try {
|
|
819
|
+
fn(payload);
|
|
820
|
+
} catch (error) {
|
|
821
|
+
console.warn(`[HlsAdPlayer] Error in event listener for ${event}:`, error);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
function generateSessionId() {
|
|
826
|
+
return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
827
|
+
}
|
|
828
|
+
function fireTrackingPixels(urls) {
|
|
829
|
+
if (!urls || urls.length === 0) return;
|
|
830
|
+
urls.forEach((url) => {
|
|
831
|
+
try {
|
|
832
|
+
let trackingUrl = url;
|
|
833
|
+
if (sessionId) {
|
|
834
|
+
trackingUrl = `${trackingUrl}${trackingUrl.includes("?") ? "&" : "?"}session_id=${sessionId}`;
|
|
835
|
+
}
|
|
836
|
+
if (licenseKey) {
|
|
837
|
+
trackingUrl = `${trackingUrl}${trackingUrl.includes("?") ? "&" : "?"}license_key=${licenseKey}`;
|
|
838
|
+
}
|
|
839
|
+
const img = new Image(1, 1);
|
|
840
|
+
img.src = trackingUrl;
|
|
841
|
+
console.log(`[HlsAdPlayer] Fired tracking pixel: ${trackingUrl}`);
|
|
842
|
+
} catch (error) {
|
|
843
|
+
console.warn(`[HlsAdPlayer] Error firing tracking pixel:`, error);
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
function getMainStreamQuality() {
|
|
848
|
+
if (!mainHlsInstance || !mainHlsInstance.levels) {
|
|
849
|
+
return null;
|
|
850
|
+
}
|
|
851
|
+
const currentLevel = mainHlsInstance.currentLevel;
|
|
852
|
+
if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {
|
|
853
|
+
const autoLevel = mainHlsInstance.loadLevel;
|
|
854
|
+
if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {
|
|
855
|
+
const level2 = mainHlsInstance.levels[autoLevel];
|
|
856
|
+
return {
|
|
857
|
+
width: level2.width || 1920,
|
|
858
|
+
height: level2.height || 1080,
|
|
859
|
+
bitrate: level2.bitrate || 5e6
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
const level = mainHlsInstance.levels[currentLevel];
|
|
865
|
+
return {
|
|
866
|
+
width: level.width || 1920,
|
|
867
|
+
height: level.height || 1080,
|
|
868
|
+
bitrate: level.bitrate || 5e6
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function selectBestMediaFile(mediaFiles) {
|
|
872
|
+
if (mediaFiles.length === 0) {
|
|
873
|
+
throw new Error("No media files available");
|
|
874
|
+
}
|
|
875
|
+
const firstFile = mediaFiles[0];
|
|
876
|
+
if (!firstFile) {
|
|
877
|
+
throw new Error("No media files available");
|
|
878
|
+
}
|
|
879
|
+
if (mediaFiles.length === 1) {
|
|
880
|
+
return firstFile;
|
|
881
|
+
}
|
|
882
|
+
const mainQuality = getMainStreamQuality();
|
|
883
|
+
if (!mainQuality) {
|
|
884
|
+
console.log("[HlsAdPlayer] No main stream quality info, using first media file");
|
|
885
|
+
return firstFile;
|
|
886
|
+
}
|
|
887
|
+
console.log("[HlsAdPlayer] Main stream quality:", mainQuality);
|
|
888
|
+
const scoredFiles = mediaFiles.map((file) => {
|
|
889
|
+
const widthDiff = Math.abs(file.width - mainQuality.width);
|
|
890
|
+
const heightDiff = Math.abs(file.height - mainQuality.height);
|
|
891
|
+
const resolutionDiff = widthDiff + heightDiff;
|
|
892
|
+
const fileBitrate = (file.bitrate || 5e3) * 1e3;
|
|
893
|
+
const bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);
|
|
894
|
+
const score = resolutionDiff * 2 + bitrateDiff / 1e3;
|
|
895
|
+
return { file, score, resolutionDiff, bitrateDiff };
|
|
896
|
+
});
|
|
897
|
+
scoredFiles.sort((a, b) => a.score - b.score);
|
|
898
|
+
const bestMatch = scoredFiles[0];
|
|
899
|
+
if (!bestMatch) {
|
|
900
|
+
console.log("[HlsAdPlayer] No best match found, using first media file");
|
|
901
|
+
return firstFile;
|
|
902
|
+
}
|
|
903
|
+
console.log("[HlsAdPlayer] Selected media file:", {
|
|
904
|
+
url: bestMatch.file.url,
|
|
905
|
+
resolution: `${bestMatch.file.width}x${bestMatch.file.height}`,
|
|
906
|
+
bitrate: bestMatch.file.bitrate,
|
|
907
|
+
score: bestMatch.score,
|
|
908
|
+
resolutionDiff: bestMatch.resolutionDiff,
|
|
909
|
+
bitrateDiff: bestMatch.bitrateDiff
|
|
910
|
+
});
|
|
911
|
+
return bestMatch.file;
|
|
912
|
+
}
|
|
913
|
+
function parseVastXml(xmlString) {
|
|
914
|
+
var _a, _b, _c, _d;
|
|
915
|
+
try {
|
|
916
|
+
const parser = new DOMParser();
|
|
917
|
+
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
|
|
918
|
+
const parserError = xmlDoc.querySelector("parsererror");
|
|
919
|
+
if (parserError) {
|
|
920
|
+
console.error("[HlsAdPlayer] XML parsing error:", parserError.textContent);
|
|
921
|
+
return null;
|
|
922
|
+
}
|
|
923
|
+
const adElement = xmlDoc.querySelector("Ad");
|
|
924
|
+
if (!adElement) {
|
|
925
|
+
console.warn("[HlsAdPlayer] No Ad element found in VAST XML");
|
|
926
|
+
return null;
|
|
927
|
+
}
|
|
928
|
+
const adId = adElement.getAttribute("id") || "unknown";
|
|
929
|
+
const title = ((_a = xmlDoc.querySelector("AdTitle")) == null ? void 0 : _a.textContent) || "Ad";
|
|
930
|
+
const durationText = ((_b = xmlDoc.querySelector("Duration")) == null ? void 0 : _b.textContent) || "00:00:30";
|
|
931
|
+
const durationParts = durationText.split(":");
|
|
932
|
+
const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
|
|
933
|
+
const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
|
|
934
|
+
const mediaFiles = [];
|
|
935
|
+
mediaFileElements.forEach((mf) => {
|
|
936
|
+
var _a2;
|
|
937
|
+
const type = mf.getAttribute("type") || "";
|
|
938
|
+
if (type === "application/x-mpegURL" || type.includes("m3u8")) {
|
|
939
|
+
const bitrateAttr = mf.getAttribute("bitrate");
|
|
940
|
+
const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
|
|
941
|
+
mediaFiles.push({
|
|
942
|
+
url: ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "",
|
|
943
|
+
type,
|
|
944
|
+
width: parseInt(mf.getAttribute("width") || "1920", 10),
|
|
945
|
+
height: parseInt(mf.getAttribute("height") || "1080", 10),
|
|
946
|
+
bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
if (mediaFiles.length === 0) {
|
|
951
|
+
console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
|
|
952
|
+
return null;
|
|
953
|
+
}
|
|
954
|
+
const trackingUrls = {
|
|
955
|
+
impression: [],
|
|
956
|
+
start: [],
|
|
957
|
+
firstQuartile: [],
|
|
958
|
+
midpoint: [],
|
|
959
|
+
thirdQuartile: [],
|
|
960
|
+
complete: [],
|
|
961
|
+
mute: [],
|
|
962
|
+
unmute: [],
|
|
963
|
+
pause: [],
|
|
964
|
+
resume: [],
|
|
965
|
+
fullscreen: [],
|
|
966
|
+
exitFullscreen: [],
|
|
967
|
+
skip: [],
|
|
968
|
+
error: []
|
|
969
|
+
};
|
|
970
|
+
xmlDoc.querySelectorAll("Impression").forEach((el) => {
|
|
971
|
+
var _a2;
|
|
972
|
+
const url = (_a2 = el.textContent) == null ? void 0 : _a2.trim();
|
|
973
|
+
if (url) trackingUrls.impression.push(url);
|
|
974
|
+
});
|
|
975
|
+
xmlDoc.querySelectorAll("Tracking").forEach((el) => {
|
|
976
|
+
var _a2;
|
|
977
|
+
const event = el.getAttribute("event");
|
|
978
|
+
const url = (_a2 = el.textContent) == null ? void 0 : _a2.trim();
|
|
979
|
+
if (event && url) {
|
|
980
|
+
const eventKey = event;
|
|
981
|
+
if (trackingUrls[eventKey]) {
|
|
982
|
+
trackingUrls[eventKey].push(url);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
const clickThrough = (_d = (_c = xmlDoc.querySelector("ClickThrough")) == null ? void 0 : _c.textContent) == null ? void 0 : _d.trim();
|
|
987
|
+
return {
|
|
988
|
+
id: adId,
|
|
989
|
+
title,
|
|
990
|
+
duration,
|
|
991
|
+
mediaFiles,
|
|
992
|
+
trackingUrls,
|
|
993
|
+
clickThrough
|
|
994
|
+
};
|
|
995
|
+
} catch (error) {
|
|
996
|
+
console.error("[HlsAdPlayer] Error parsing VAST XML:", error);
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
function createAdVideoElement() {
|
|
1001
|
+
const video = document.createElement("video");
|
|
1002
|
+
video.style.position = "absolute";
|
|
1003
|
+
video.style.left = "0";
|
|
1004
|
+
video.style.top = "0";
|
|
1005
|
+
video.style.width = "100%";
|
|
1006
|
+
video.style.height = "100%";
|
|
1007
|
+
video.style.objectFit = "contain";
|
|
1008
|
+
video.style.backgroundColor = "#000";
|
|
1009
|
+
video.playsInline = true;
|
|
1010
|
+
video.muted = false;
|
|
1011
|
+
return video;
|
|
1012
|
+
}
|
|
1013
|
+
function setupAdEventListeners() {
|
|
1014
|
+
if (!adVideoElement || !currentAd) return;
|
|
1015
|
+
adVideoElement.addEventListener("timeupdate", () => {
|
|
1016
|
+
if (!currentAd || !adVideoElement) return;
|
|
1017
|
+
const progress = adVideoElement.currentTime / currentAd.duration;
|
|
1018
|
+
if (progress >= 0.25 && !trackingFired.firstQuartile) {
|
|
1019
|
+
trackingFired.firstQuartile = true;
|
|
1020
|
+
fireTrackingPixels(currentAd.trackingUrls.firstQuartile);
|
|
1021
|
+
}
|
|
1022
|
+
if (progress >= 0.5 && !trackingFired.midpoint) {
|
|
1023
|
+
trackingFired.midpoint = true;
|
|
1024
|
+
fireTrackingPixels(currentAd.trackingUrls.midpoint);
|
|
1025
|
+
}
|
|
1026
|
+
if (progress >= 0.75 && !trackingFired.thirdQuartile) {
|
|
1027
|
+
trackingFired.thirdQuartile = true;
|
|
1028
|
+
fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1031
|
+
adVideoElement.addEventListener("playing", () => {
|
|
1032
|
+
if (!currentAd || trackingFired.start) return;
|
|
1033
|
+
trackingFired.start = true;
|
|
1034
|
+
fireTrackingPixels(currentAd.trackingUrls.start);
|
|
1035
|
+
console.log("[HlsAdPlayer] Ad started playing");
|
|
1036
|
+
});
|
|
1037
|
+
adVideoElement.addEventListener("ended", () => {
|
|
1038
|
+
if (!currentAd || trackingFired.complete) return;
|
|
1039
|
+
trackingFired.complete = true;
|
|
1040
|
+
fireTrackingPixels(currentAd.trackingUrls.complete);
|
|
1041
|
+
console.log("[HlsAdPlayer] Ad completed");
|
|
1042
|
+
handleAdComplete();
|
|
1043
|
+
});
|
|
1044
|
+
adVideoElement.addEventListener("error", (e) => {
|
|
1045
|
+
console.error("[HlsAdPlayer] Ad video error:", e);
|
|
1046
|
+
if (currentAd) {
|
|
1047
|
+
fireTrackingPixels(currentAd.trackingUrls.error);
|
|
1048
|
+
}
|
|
1049
|
+
handleAdError();
|
|
1050
|
+
});
|
|
1051
|
+
adVideoElement.addEventListener("volumechange", () => {
|
|
1052
|
+
if (!currentAd) return;
|
|
1053
|
+
if (adVideoElement.muted) {
|
|
1054
|
+
fireTrackingPixels(currentAd.trackingUrls.mute);
|
|
1055
|
+
} else {
|
|
1056
|
+
fireTrackingPixels(currentAd.trackingUrls.unmute);
|
|
1057
|
+
}
|
|
1058
|
+
});
|
|
1059
|
+
adVideoElement.addEventListener("pause", () => {
|
|
1060
|
+
if (currentAd && !adVideoElement.ended) {
|
|
1061
|
+
fireTrackingPixels(currentAd.trackingUrls.pause);
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
adVideoElement.addEventListener("play", () => {
|
|
1065
|
+
if (currentAd && adVideoElement.currentTime > 0) {
|
|
1066
|
+
fireTrackingPixels(currentAd.trackingUrls.resume);
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
function handleAdComplete() {
|
|
1071
|
+
console.log("[HlsAdPlayer] Handling ad completion");
|
|
1072
|
+
adPlaying = false;
|
|
1073
|
+
contentVideo.muted = originalMutedState;
|
|
1074
|
+
if (adContainerEl) {
|
|
1075
|
+
adContainerEl.style.display = "none";
|
|
1076
|
+
adContainerEl.style.pointerEvents = "none";
|
|
1077
|
+
}
|
|
1078
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
1079
|
+
contentVideo.play().catch(() => {
|
|
1080
|
+
});
|
|
1081
|
+
console.log("[HlsAdPlayer] Content resumed (VOD mode)");
|
|
1082
|
+
} else {
|
|
1083
|
+
console.log("[HlsAdPlayer] Content unmuted (Live mode)");
|
|
1084
|
+
}
|
|
1085
|
+
emit("content_resume");
|
|
1086
|
+
emit("all_ads_completed");
|
|
1087
|
+
}
|
|
1088
|
+
function handleAdError() {
|
|
1089
|
+
console.log("[HlsAdPlayer] Handling ad error");
|
|
1090
|
+
adPlaying = false;
|
|
1091
|
+
contentVideo.muted = originalMutedState;
|
|
1092
|
+
if (adContainerEl) {
|
|
1093
|
+
adContainerEl.style.display = "none";
|
|
1094
|
+
adContainerEl.style.pointerEvents = "none";
|
|
1095
|
+
}
|
|
1096
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
1097
|
+
if (contentVideo.paused) {
|
|
1098
|
+
contentVideo.play().catch(() => {
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
emit("ad_error");
|
|
1103
|
+
}
|
|
1104
|
+
return {
|
|
1105
|
+
initialize() {
|
|
1106
|
+
var _a;
|
|
1107
|
+
console.log("[HlsAdPlayer] Initializing");
|
|
1108
|
+
if (!adContainerEl) {
|
|
1109
|
+
const container = document.createElement("div");
|
|
1110
|
+
container.style.position = "absolute";
|
|
1111
|
+
container.style.left = "0";
|
|
1112
|
+
container.style.top = "0";
|
|
1113
|
+
container.style.right = "0";
|
|
1114
|
+
container.style.bottom = "0";
|
|
1115
|
+
container.style.display = "none";
|
|
1116
|
+
container.style.alignItems = "center";
|
|
1117
|
+
container.style.justifyContent = "center";
|
|
1118
|
+
container.style.pointerEvents = "none";
|
|
1119
|
+
container.style.zIndex = "2";
|
|
1120
|
+
container.style.backgroundColor = "#000";
|
|
1121
|
+
(_a = contentVideo.parentElement) == null ? void 0 : _a.appendChild(container);
|
|
1122
|
+
adContainerEl = container;
|
|
1123
|
+
}
|
|
1124
|
+
},
|
|
1125
|
+
async requestAds(vastTagUrl) {
|
|
1126
|
+
console.log("[HlsAdPlayer] Requesting ads:", vastTagUrl);
|
|
1127
|
+
if (adPlaying) {
|
|
1128
|
+
console.warn("[HlsAdPlayer] Cannot request new ads while an ad is playing");
|
|
1129
|
+
return Promise.reject(new Error("Ad already playing"));
|
|
1130
|
+
}
|
|
1131
|
+
try {
|
|
1132
|
+
sessionId = generateSessionId();
|
|
1133
|
+
const response = await fetch(vastTagUrl);
|
|
1134
|
+
if (!response.ok) {
|
|
1135
|
+
throw new Error(`Failed to fetch VAST: ${response.statusText}`);
|
|
1136
|
+
}
|
|
1137
|
+
const vastXml = await response.text();
|
|
1138
|
+
console.log("[HlsAdPlayer] VAST XML received");
|
|
1139
|
+
const ad = parseVastXml(vastXml);
|
|
1140
|
+
if (!ad) {
|
|
1141
|
+
throw new Error("Failed to parse VAST XML or no ads available");
|
|
1142
|
+
}
|
|
1143
|
+
currentAd = ad;
|
|
1144
|
+
console.log(`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`);
|
|
1145
|
+
fireTrackingPixels(ad.trackingUrls.impression);
|
|
1146
|
+
trackingFired.impression = true;
|
|
1147
|
+
return Promise.resolve();
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
console.error("[HlsAdPlayer] Error requesting ads:", error);
|
|
1150
|
+
emit("ad_error");
|
|
1151
|
+
return Promise.reject(error);
|
|
1152
|
+
}
|
|
1153
|
+
},
|
|
1154
|
+
async play() {
|
|
1155
|
+
if (!currentAd) {
|
|
1156
|
+
console.warn("[HlsAdPlayer] Cannot play: No ad loaded");
|
|
1157
|
+
return Promise.reject(new Error("No ad loaded"));
|
|
1158
|
+
}
|
|
1159
|
+
console.log("[HlsAdPlayer] Starting ad playback");
|
|
1160
|
+
try {
|
|
1161
|
+
if (!adVideoElement) {
|
|
1162
|
+
adVideoElement = createAdVideoElement();
|
|
1163
|
+
adContainerEl == null ? void 0 : adContainerEl.appendChild(adVideoElement);
|
|
1164
|
+
setupAdEventListeners();
|
|
1165
|
+
}
|
|
1166
|
+
trackingFired = {
|
|
1167
|
+
impression: trackingFired.impression,
|
|
1168
|
+
start: false,
|
|
1169
|
+
firstQuartile: false,
|
|
1170
|
+
midpoint: false,
|
|
1171
|
+
thirdQuartile: false,
|
|
1172
|
+
complete: false
|
|
1173
|
+
};
|
|
1174
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
1175
|
+
contentVideo.pause();
|
|
1176
|
+
console.log("[HlsAdPlayer] Content paused (VOD mode)");
|
|
1177
|
+
} else {
|
|
1178
|
+
console.log("[HlsAdPlayer] Content continues (Live mode)");
|
|
1179
|
+
}
|
|
1180
|
+
contentVideo.muted = true;
|
|
1181
|
+
adPlaying = true;
|
|
1182
|
+
if (adContainerEl) {
|
|
1183
|
+
adContainerEl.style.display = "flex";
|
|
1184
|
+
adContainerEl.style.pointerEvents = "auto";
|
|
1185
|
+
}
|
|
1186
|
+
emit("content_pause");
|
|
1187
|
+
const mediaFile = selectBestMediaFile(currentAd.mediaFiles);
|
|
1188
|
+
if (!mediaFile) {
|
|
1189
|
+
throw new Error("No media file available for ad");
|
|
1190
|
+
}
|
|
1191
|
+
console.log(`[HlsAdPlayer] Loading ad from: ${mediaFile.url}`);
|
|
1192
|
+
if (import_hls.default.isSupported()) {
|
|
1193
|
+
if (adHls) {
|
|
1194
|
+
adHls.destroy();
|
|
1195
|
+
}
|
|
1196
|
+
adHls = new import_hls.default({
|
|
1197
|
+
enableWorker: true,
|
|
1198
|
+
lowLatencyMode: false
|
|
1199
|
+
});
|
|
1200
|
+
adHls.loadSource(mediaFile.url);
|
|
1201
|
+
adHls.attachMedia(adVideoElement);
|
|
1202
|
+
adHls.on(import_hls.default.Events.MANIFEST_PARSED, () => {
|
|
1203
|
+
console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
|
|
1204
|
+
adVideoElement.play().catch((error) => {
|
|
1205
|
+
console.error("[HlsAdPlayer] Error starting ad playback:", error);
|
|
1206
|
+
handleAdError();
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
adHls.on(import_hls.default.Events.ERROR, (event, data) => {
|
|
1210
|
+
console.error("[HlsAdPlayer] HLS error:", data);
|
|
1211
|
+
if (data.fatal) {
|
|
1212
|
+
handleAdError();
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1215
|
+
} else if (adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
|
|
1216
|
+
adVideoElement.src = mediaFile.url;
|
|
1217
|
+
adVideoElement.play().catch((error) => {
|
|
1218
|
+
console.error("[HlsAdPlayer] Error starting ad playback:", error);
|
|
1219
|
+
handleAdError();
|
|
1220
|
+
});
|
|
1221
|
+
} else {
|
|
1222
|
+
throw new Error("HLS not supported");
|
|
1223
|
+
}
|
|
1224
|
+
return Promise.resolve();
|
|
1225
|
+
} catch (error) {
|
|
1226
|
+
console.error("[HlsAdPlayer] Error playing ad:", error);
|
|
1227
|
+
handleAdError();
|
|
1228
|
+
return Promise.reject(error);
|
|
1229
|
+
}
|
|
1230
|
+
},
|
|
1231
|
+
async stop() {
|
|
1232
|
+
console.log("[HlsAdPlayer] Stopping ad");
|
|
1233
|
+
adPlaying = false;
|
|
1234
|
+
contentVideo.muted = originalMutedState;
|
|
1235
|
+
if (adContainerEl) {
|
|
1236
|
+
adContainerEl.style.display = "none";
|
|
1237
|
+
adContainerEl.style.pointerEvents = "none";
|
|
1238
|
+
}
|
|
1239
|
+
if (adHls) {
|
|
1240
|
+
adHls.destroy();
|
|
1241
|
+
adHls = void 0;
|
|
1242
|
+
}
|
|
1243
|
+
if (adVideoElement) {
|
|
1244
|
+
adVideoElement.pause();
|
|
1245
|
+
adVideoElement.src = "";
|
|
1246
|
+
}
|
|
1247
|
+
if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
|
|
1248
|
+
contentVideo.play().catch(() => {
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
currentAd = void 0;
|
|
1252
|
+
},
|
|
1253
|
+
destroy() {
|
|
1254
|
+
console.log("[HlsAdPlayer] Destroying");
|
|
1255
|
+
adPlaying = false;
|
|
1256
|
+
contentVideo.muted = originalMutedState;
|
|
1257
|
+
if (adHls) {
|
|
1258
|
+
adHls.destroy();
|
|
1259
|
+
adHls = void 0;
|
|
1260
|
+
}
|
|
1261
|
+
if (adVideoElement) {
|
|
1262
|
+
adVideoElement.pause();
|
|
1263
|
+
adVideoElement.src = "";
|
|
1264
|
+
adVideoElement.remove();
|
|
1265
|
+
adVideoElement = void 0;
|
|
1266
|
+
}
|
|
1267
|
+
if (adContainerEl == null ? void 0 : adContainerEl.parentElement) {
|
|
1268
|
+
adContainerEl.parentElement.removeChild(adContainerEl);
|
|
1269
|
+
}
|
|
1270
|
+
adContainerEl = void 0;
|
|
1271
|
+
currentAd = void 0;
|
|
1272
|
+
listeners.clear();
|
|
1273
|
+
},
|
|
1274
|
+
isAdPlaying() {
|
|
1275
|
+
return adPlaying;
|
|
1276
|
+
},
|
|
1277
|
+
resize(width, height) {
|
|
1278
|
+
console.log(`[HlsAdPlayer] Resizing to ${width}x${height}`);
|
|
1279
|
+
if (adContainerEl) {
|
|
1280
|
+
adContainerEl.style.width = `${width}px`;
|
|
1281
|
+
adContainerEl.style.height = `${height}px`;
|
|
1282
|
+
}
|
|
1283
|
+
if (adVideoElement) {
|
|
1284
|
+
adVideoElement.style.width = `${width}px`;
|
|
1285
|
+
adVideoElement.style.height = `${height}px`;
|
|
1286
|
+
}
|
|
1287
|
+
},
|
|
1288
|
+
on(event, listener) {
|
|
1289
|
+
if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());
|
|
1290
|
+
listeners.get(event).add(listener);
|
|
1291
|
+
},
|
|
1292
|
+
off(event, listener) {
|
|
1293
|
+
var _a;
|
|
1294
|
+
(_a = listeners.get(event)) == null ? void 0 : _a.delete(listener);
|
|
1295
|
+
},
|
|
1296
|
+
updateOriginalMutedState(muted) {
|
|
1297
|
+
originalMutedState = muted;
|
|
1298
|
+
},
|
|
1299
|
+
getOriginalMutedState() {
|
|
1300
|
+
return originalMutedState;
|
|
1301
|
+
},
|
|
1302
|
+
setAdVolume(volume) {
|
|
1303
|
+
if (adVideoElement && adPlaying) {
|
|
1304
|
+
adVideoElement.volume = Math.max(0, Math.min(1, volume));
|
|
1305
|
+
}
|
|
1306
|
+
},
|
|
1307
|
+
getAdVolume() {
|
|
1308
|
+
if (adVideoElement && adPlaying) {
|
|
1309
|
+
return adVideoElement.volume;
|
|
1310
|
+
}
|
|
1311
|
+
return 1;
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
|
|
577
1316
|
// src/utils/tracking.ts
|
|
578
1317
|
var cachedBrowserId = null;
|
|
579
1318
|
function getClientInfo() {
|
|
1319
|
+
var _a, _b, _c, _d;
|
|
580
1320
|
const ua = navigator.userAgent;
|
|
581
1321
|
const platform = navigator.platform;
|
|
582
1322
|
const vendor = navigator.vendor || "";
|
|
@@ -584,12 +1324,12 @@ function getClientInfo() {
|
|
|
584
1324
|
const memory = navigator.deviceMemory || null;
|
|
585
1325
|
const hardwareConcurrency = navigator.hardwareConcurrency || 1;
|
|
586
1326
|
const screenInfo = {
|
|
587
|
-
width: screen
|
|
588
|
-
height: screen
|
|
589
|
-
availWidth: screen
|
|
590
|
-
availHeight: screen
|
|
591
|
-
orientation: screen
|
|
592
|
-
pixelDepth: screen
|
|
1327
|
+
width: screen == null ? void 0 : screen.width,
|
|
1328
|
+
height: screen == null ? void 0 : screen.height,
|
|
1329
|
+
availWidth: screen == null ? void 0 : screen.availWidth,
|
|
1330
|
+
availHeight: screen == null ? void 0 : screen.availHeight,
|
|
1331
|
+
orientation: ((_a = screen == null ? void 0 : screen.orientation) == null ? void 0 : _a.type) || "",
|
|
1332
|
+
pixelDepth: screen == null ? void 0 : screen.pixelDepth
|
|
593
1333
|
};
|
|
594
1334
|
let deviceType = "desktop";
|
|
595
1335
|
let brand = "Unknown";
|
|
@@ -686,10 +1426,10 @@ function getClientInfo() {
|
|
|
686
1426
|
if (vendor.includes("Samsung") || ua.includes("SM-")) brand = "Samsung";
|
|
687
1427
|
}
|
|
688
1428
|
isWebView = /wv|WebView|Linux; U;/.test(ua);
|
|
689
|
-
if (window
|
|
1429
|
+
if ((window == null ? void 0 : window.outerHeight) === 0 && (window == null ? void 0 : window.outerWidth) === 0) {
|
|
690
1430
|
isWebView = true;
|
|
691
1431
|
}
|
|
692
|
-
isWebApp = window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true || window.screen
|
|
1432
|
+
isWebApp = window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true || ((_c = (_b = window.screen) == null ? void 0 : _b.orientation) == null ? void 0 : _c.angle) !== void 0;
|
|
693
1433
|
return {
|
|
694
1434
|
brand,
|
|
695
1435
|
os,
|
|
@@ -710,7 +1450,7 @@ function getClientInfo() {
|
|
|
710
1450
|
deviceMemory: memory,
|
|
711
1451
|
maxTouchPoints,
|
|
712
1452
|
language: navigator.language,
|
|
713
|
-
languages: navigator.languages
|
|
1453
|
+
languages: ((_d = navigator.languages) == null ? void 0 : _d.join(",")) || "",
|
|
714
1454
|
cookieEnabled: navigator.cookieEnabled,
|
|
715
1455
|
doNotTrack: navigator.doNotTrack || "",
|
|
716
1456
|
referrer: document.referrer,
|
|
@@ -823,6 +1563,215 @@ async function sendHeartbeat(licenseKey) {
|
|
|
823
1563
|
}
|
|
824
1564
|
}
|
|
825
1565
|
|
|
1566
|
+
// src/utils/polyfills.ts
|
|
1567
|
+
function polyfillURLSearchParams() {
|
|
1568
|
+
if (typeof URLSearchParams !== "undefined") {
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
class URLSearchParamsPolyfill {
|
|
1572
|
+
constructor(init) {
|
|
1573
|
+
this.params = /* @__PURE__ */ new Map();
|
|
1574
|
+
if (typeof init === "string") {
|
|
1575
|
+
this.parseQueryString(init);
|
|
1576
|
+
} else if (init instanceof URLSearchParamsPolyfill) {
|
|
1577
|
+
init.forEach((value, key) => {
|
|
1578
|
+
this.append(key, value);
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
parseQueryString(query) {
|
|
1583
|
+
const cleanQuery = query.startsWith("?") ? query.slice(1) : query;
|
|
1584
|
+
if (!cleanQuery) return;
|
|
1585
|
+
cleanQuery.split("&").forEach((param) => {
|
|
1586
|
+
const [key, value] = param.split("=");
|
|
1587
|
+
if (key) {
|
|
1588
|
+
const decodedKey = this.safeDecodeURIComponent(key);
|
|
1589
|
+
const decodedValue = value ? this.safeDecodeURIComponent(value) : "";
|
|
1590
|
+
this.append(decodedKey, decodedValue);
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
safeDecodeURIComponent(str) {
|
|
1595
|
+
try {
|
|
1596
|
+
return decodeURIComponent(str.replace(/\+/g, " "));
|
|
1597
|
+
} catch (e) {
|
|
1598
|
+
return str;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
append(name, value) {
|
|
1602
|
+
const values = this.params.get(name) || [];
|
|
1603
|
+
values.push(String(value));
|
|
1604
|
+
this.params.set(name, values);
|
|
1605
|
+
}
|
|
1606
|
+
delete(name) {
|
|
1607
|
+
this.params.delete(name);
|
|
1608
|
+
}
|
|
1609
|
+
get(name) {
|
|
1610
|
+
const values = this.params.get(name);
|
|
1611
|
+
return values && values.length > 0 && values[0] !== void 0 ? values[0] : null;
|
|
1612
|
+
}
|
|
1613
|
+
getAll(name) {
|
|
1614
|
+
return this.params.get(name) || [];
|
|
1615
|
+
}
|
|
1616
|
+
has(name) {
|
|
1617
|
+
return this.params.has(name);
|
|
1618
|
+
}
|
|
1619
|
+
set(name, value) {
|
|
1620
|
+
this.params.set(name, [String(value)]);
|
|
1621
|
+
}
|
|
1622
|
+
forEach(callback) {
|
|
1623
|
+
this.params.forEach((values, key) => {
|
|
1624
|
+
values.forEach((value) => {
|
|
1625
|
+
callback(value, key, this);
|
|
1626
|
+
});
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
toString() {
|
|
1630
|
+
const parts = [];
|
|
1631
|
+
this.params.forEach((values, key) => {
|
|
1632
|
+
values.forEach((value) => {
|
|
1633
|
+
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
|
|
1634
|
+
});
|
|
1635
|
+
});
|
|
1636
|
+
return parts.join("&");
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
window.URLSearchParams = URLSearchParamsPolyfill;
|
|
1640
|
+
}
|
|
1641
|
+
function polyfillTextEncoder() {
|
|
1642
|
+
if (typeof TextEncoder !== "undefined") {
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
class TextEncoderPolyfill {
|
|
1646
|
+
constructor() {
|
|
1647
|
+
this.encoding = "utf-8";
|
|
1648
|
+
}
|
|
1649
|
+
encode(str) {
|
|
1650
|
+
const utf8 = [];
|
|
1651
|
+
for (let i = 0; i < str.length; i++) {
|
|
1652
|
+
let charcode = str.charCodeAt(i);
|
|
1653
|
+
if (charcode < 128) {
|
|
1654
|
+
utf8.push(charcode);
|
|
1655
|
+
} else if (charcode < 2048) {
|
|
1656
|
+
utf8.push(192 | charcode >> 6, 128 | charcode & 63);
|
|
1657
|
+
} else if (charcode < 55296 || charcode >= 57344) {
|
|
1658
|
+
utf8.push(
|
|
1659
|
+
224 | charcode >> 12,
|
|
1660
|
+
128 | charcode >> 6 & 63,
|
|
1661
|
+
128 | charcode & 63
|
|
1662
|
+
);
|
|
1663
|
+
} else {
|
|
1664
|
+
i++;
|
|
1665
|
+
charcode = 65536 + ((charcode & 1023) << 10 | str.charCodeAt(i) & 1023);
|
|
1666
|
+
utf8.push(
|
|
1667
|
+
240 | charcode >> 18,
|
|
1668
|
+
128 | charcode >> 12 & 63,
|
|
1669
|
+
128 | charcode >> 6 & 63,
|
|
1670
|
+
128 | charcode & 63
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return new Uint8Array(utf8);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
window.TextEncoder = TextEncoderPolyfill;
|
|
1678
|
+
}
|
|
1679
|
+
function polyfillPromiseFinally() {
|
|
1680
|
+
if (typeof Promise !== "undefined" && !Promise.prototype.finally) {
|
|
1681
|
+
Promise.prototype.finally = function(callback) {
|
|
1682
|
+
const constructor = this.constructor;
|
|
1683
|
+
return this.then(
|
|
1684
|
+
(value) => constructor.resolve(callback()).then(() => value),
|
|
1685
|
+
(reason) => constructor.resolve(callback()).then(() => {
|
|
1686
|
+
throw reason;
|
|
1687
|
+
})
|
|
1688
|
+
);
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
function polyfillObjectAssign() {
|
|
1693
|
+
if (typeof Object.assign !== "function") {
|
|
1694
|
+
Object.assign = function(target, ...sources) {
|
|
1695
|
+
if (target == null) {
|
|
1696
|
+
throw new TypeError("Cannot convert undefined or null to object");
|
|
1697
|
+
}
|
|
1698
|
+
const to = Object(target);
|
|
1699
|
+
for (let i = 0; i < sources.length; i++) {
|
|
1700
|
+
const nextSource = sources[i];
|
|
1701
|
+
if (nextSource != null) {
|
|
1702
|
+
for (const nextKey in nextSource) {
|
|
1703
|
+
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
|
1704
|
+
to[nextKey] = nextSource[nextKey];
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
return to;
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
function polyfillArrayFrom() {
|
|
1714
|
+
if (!Array.from) {
|
|
1715
|
+
Array.from = function(arrayLike, mapFn, thisArg) {
|
|
1716
|
+
const items = Object(arrayLike);
|
|
1717
|
+
if (arrayLike == null) {
|
|
1718
|
+
throw new TypeError("Array.from requires an array-like object");
|
|
1719
|
+
}
|
|
1720
|
+
const len = items.length >>> 0;
|
|
1721
|
+
const result = new Array(len);
|
|
1722
|
+
for (let i = 0; i < len; i++) {
|
|
1723
|
+
if (mapFn) {
|
|
1724
|
+
result[i] = mapFn.call(thisArg, items[i], i);
|
|
1725
|
+
} else {
|
|
1726
|
+
result[i] = items[i];
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
return result;
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
function polyfillStringStartsWith() {
|
|
1734
|
+
if (!String.prototype.startsWith) {
|
|
1735
|
+
String.prototype.startsWith = function(search, pos) {
|
|
1736
|
+
pos = !pos || pos < 0 ? 0 : +pos;
|
|
1737
|
+
return this.substring(pos, pos + search.length) === search;
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
function polyfillStringEndsWith() {
|
|
1742
|
+
if (!String.prototype.endsWith) {
|
|
1743
|
+
String.prototype.endsWith = function(search, length) {
|
|
1744
|
+
if (length === void 0 || length > this.length) {
|
|
1745
|
+
length = this.length;
|
|
1746
|
+
}
|
|
1747
|
+
return this.substring(length - search.length, length) === search;
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
function polyfillStringIncludes() {
|
|
1752
|
+
if (!String.prototype.includes) {
|
|
1753
|
+
String.prototype.includes = function(search, start) {
|
|
1754
|
+
if (typeof start !== "number") {
|
|
1755
|
+
start = 0;
|
|
1756
|
+
}
|
|
1757
|
+
if (start + search.length > this.length) {
|
|
1758
|
+
return false;
|
|
1759
|
+
}
|
|
1760
|
+
return this.indexOf(search, start) !== -1;
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
function initializePolyfills() {
|
|
1765
|
+
polyfillObjectAssign();
|
|
1766
|
+
polyfillArrayFrom();
|
|
1767
|
+
polyfillStringStartsWith();
|
|
1768
|
+
polyfillStringEndsWith();
|
|
1769
|
+
polyfillStringIncludes();
|
|
1770
|
+
polyfillURLSearchParams();
|
|
1771
|
+
polyfillTextEncoder();
|
|
1772
|
+
polyfillPromiseFinally();
|
|
1773
|
+
}
|
|
1774
|
+
|
|
826
1775
|
// src/player/StormcloudVideoPlayer.ts
|
|
827
1776
|
var StormcloudVideoPlayer = class {
|
|
828
1777
|
constructor(config) {
|
|
@@ -835,13 +1784,44 @@ var StormcloudVideoPlayer = class {
|
|
|
835
1784
|
this.totalAdsInBreak = 0;
|
|
836
1785
|
this.showAds = false;
|
|
837
1786
|
this.isLiveStream = false;
|
|
838
|
-
|
|
1787
|
+
initializePolyfills();
|
|
1788
|
+
const browserOverrides = getBrowserConfigOverrides();
|
|
1789
|
+
this.config = { ...config, ...browserOverrides };
|
|
839
1790
|
this.video = config.videoElement;
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1791
|
+
logBrowserInfo(config.debugAdTiming);
|
|
1792
|
+
this.ima = this.createAdPlayer(false);
|
|
1793
|
+
}
|
|
1794
|
+
createAdPlayer(continueLiveStreamDuringAds) {
|
|
1795
|
+
const vastMode = this.config.vastMode || "default";
|
|
1796
|
+
let adPlayerType = this.config.adPlayerType || (vastMode === "adstorm" ? "hls" : "ima");
|
|
1797
|
+
if (adPlayerType === "ima" && !supportsGoogleIMA()) {
|
|
1798
|
+
if (this.config.debugAdTiming) {
|
|
1799
|
+
console.warn(
|
|
1800
|
+
"[StormcloudVideoPlayer] Google IMA SDK not supported on this browser, falling back to HLS ad player"
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
adPlayerType = "hls";
|
|
1804
|
+
}
|
|
1805
|
+
if (adPlayerType === "hls") {
|
|
1806
|
+
if (this.config.debugAdTiming) {
|
|
1807
|
+
console.log("[StormcloudVideoPlayer] Creating HLS ad player (AdStorm mode)");
|
|
1808
|
+
}
|
|
1809
|
+
return createHlsAdPlayer(this.video, {
|
|
1810
|
+
continueLiveStreamDuringAds,
|
|
1811
|
+
...this.config.licenseKey ? { licenseKey: this.config.licenseKey } : {},
|
|
1812
|
+
...this.hls ? { mainHlsInstance: this.hls } : {}
|
|
1813
|
+
});
|
|
1814
|
+
} else {
|
|
1815
|
+
if (this.config.debugAdTiming) {
|
|
1816
|
+
console.log("[StormcloudVideoPlayer] Creating Google IMA ad player (Default mode)");
|
|
1817
|
+
}
|
|
1818
|
+
return createImaController(this.video, {
|
|
1819
|
+
continueLiveStreamDuringAds
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
843
1822
|
}
|
|
844
1823
|
async load() {
|
|
1824
|
+
var _a, _b;
|
|
845
1825
|
if (!this.attached) {
|
|
846
1826
|
this.attach();
|
|
847
1827
|
}
|
|
@@ -858,7 +1838,7 @@ var StormcloudVideoPlayer = class {
|
|
|
858
1838
|
this.initializeTracking();
|
|
859
1839
|
if (this.shouldUseNativeHls()) {
|
|
860
1840
|
this.video.src = this.config.src;
|
|
861
|
-
this.isLiveStream = this.config.lowLatencyMode
|
|
1841
|
+
this.isLiveStream = (_a = this.config.lowLatencyMode) != null ? _a : false;
|
|
862
1842
|
if (this.config.debugAdTiming) {
|
|
863
1843
|
console.log(
|
|
864
1844
|
"[StormcloudVideoPlayer] allowNativeHls: true - VOD mode detected:",
|
|
@@ -870,17 +1850,15 @@ var StormcloudVideoPlayer = class {
|
|
|
870
1850
|
);
|
|
871
1851
|
}
|
|
872
1852
|
this.ima.destroy();
|
|
873
|
-
this.ima =
|
|
874
|
-
continueLiveStreamDuringAds: false
|
|
875
|
-
});
|
|
1853
|
+
this.ima = this.createAdPlayer(false);
|
|
876
1854
|
this.ima.initialize();
|
|
877
1855
|
if (this.config.autoplay) {
|
|
878
|
-
await this.video.play()
|
|
879
|
-
});
|
|
1856
|
+
await ((_b = this.video.play()) == null ? void 0 : _b.catch(() => {
|
|
1857
|
+
}));
|
|
880
1858
|
}
|
|
881
1859
|
return;
|
|
882
1860
|
}
|
|
883
|
-
this.hls = new
|
|
1861
|
+
this.hls = new import_hls2.default({
|
|
884
1862
|
enableWorker: true,
|
|
885
1863
|
backBufferLength: 30,
|
|
886
1864
|
liveDurationInfinity: true,
|
|
@@ -888,13 +1866,18 @@ var StormcloudVideoPlayer = class {
|
|
|
888
1866
|
maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,
|
|
889
1867
|
...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {}
|
|
890
1868
|
});
|
|
891
|
-
this.hls.on(
|
|
892
|
-
|
|
1869
|
+
this.hls.on(import_hls2.default.Events.MEDIA_ATTACHED, () => {
|
|
1870
|
+
var _a2;
|
|
1871
|
+
(_a2 = this.hls) == null ? void 0 : _a2.loadSource(this.config.src);
|
|
893
1872
|
});
|
|
894
|
-
this.hls.on(
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1873
|
+
this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, async (_, data) => {
|
|
1874
|
+
var _a2, _b2, _c, _d;
|
|
1875
|
+
this.isLiveStream = (_c = (_b2 = (_a2 = this.hls) == null ? void 0 : _a2.levels) == null ? void 0 : _b2.some(
|
|
1876
|
+
(level) => {
|
|
1877
|
+
var _a3, _b3;
|
|
1878
|
+
return ((_a3 = level == null ? void 0 : level.details) == null ? void 0 : _a3.live) === true || ((_b3 = level == null ? void 0 : level.details) == null ? void 0 : _b3.type) === "LIVE";
|
|
1879
|
+
}
|
|
1880
|
+
)) != null ? _c : false;
|
|
898
1881
|
if (this.config.debugAdTiming) {
|
|
899
1882
|
const adBehavior = this.shouldContinueLiveStreamDuringAds() ? "live (main video continues muted during ads)" : "vod (main video pauses during ads)";
|
|
900
1883
|
console.log("[StormcloudVideoPlayer] Stream type detected:", {
|
|
@@ -904,33 +1887,32 @@ var StormcloudVideoPlayer = class {
|
|
|
904
1887
|
});
|
|
905
1888
|
}
|
|
906
1889
|
this.ima.destroy();
|
|
907
|
-
this.ima =
|
|
908
|
-
continueLiveStreamDuringAds: this.shouldContinueLiveStreamDuringAds()
|
|
909
|
-
});
|
|
1890
|
+
this.ima = this.createAdPlayer(this.shouldContinueLiveStreamDuringAds());
|
|
910
1891
|
this.ima.initialize();
|
|
911
1892
|
if (this.config.autoplay) {
|
|
912
|
-
await this.video.play()
|
|
913
|
-
});
|
|
1893
|
+
await ((_d = this.video.play()) == null ? void 0 : _d.catch(() => {
|
|
1894
|
+
}));
|
|
914
1895
|
}
|
|
915
1896
|
});
|
|
916
|
-
this.hls.on(
|
|
917
|
-
const id3Tags = (data
|
|
1897
|
+
this.hls.on(import_hls2.default.Events.FRAG_PARSING_METADATA, (_evt, data) => {
|
|
1898
|
+
const id3Tags = ((data == null ? void 0 : data.samples) || []).map((s) => ({
|
|
918
1899
|
key: "ID3",
|
|
919
|
-
value: s
|
|
920
|
-
ptsSeconds: s
|
|
1900
|
+
value: s == null ? void 0 : s.data,
|
|
1901
|
+
ptsSeconds: s == null ? void 0 : s.pts
|
|
921
1902
|
}));
|
|
922
1903
|
id3Tags.forEach((tag) => this.onId3Tag(tag));
|
|
923
1904
|
});
|
|
924
|
-
this.hls.on(
|
|
925
|
-
|
|
926
|
-
const
|
|
1905
|
+
this.hls.on(import_hls2.default.Events.FRAG_CHANGED, (_evt, data) => {
|
|
1906
|
+
var _a2, _b2, _c;
|
|
1907
|
+
const frag = data == null ? void 0 : data.frag;
|
|
1908
|
+
const tagList = frag == null ? void 0 : frag.tagList;
|
|
927
1909
|
if (!Array.isArray(tagList)) return;
|
|
928
1910
|
for (const entry of tagList) {
|
|
929
1911
|
let tag = "";
|
|
930
1912
|
let value = "";
|
|
931
1913
|
if (Array.isArray(entry)) {
|
|
932
|
-
tag = String(entry[0]
|
|
933
|
-
value = String(entry[1]
|
|
1914
|
+
tag = String((_a2 = entry[0]) != null ? _a2 : "");
|
|
1915
|
+
value = String((_b2 = entry[1]) != null ? _b2 : "");
|
|
934
1916
|
} else if (typeof entry === "string") {
|
|
935
1917
|
const idx = entry.indexOf(":");
|
|
936
1918
|
if (idx >= 0) {
|
|
@@ -954,8 +1936,8 @@ var StormcloudVideoPlayer = class {
|
|
|
954
1936
|
const prog = this.parseCueOutCont(value);
|
|
955
1937
|
const marker = {
|
|
956
1938
|
type: "progress",
|
|
957
|
-
...prog
|
|
958
|
-
...prog
|
|
1939
|
+
...(prog == null ? void 0 : prog.duration) !== void 0 ? { durationSeconds: prog.duration } : {},
|
|
1940
|
+
...(prog == null ? void 0 : prog.elapsed) !== void 0 ? { ptsSeconds: prog.elapsed } : {},
|
|
959
1941
|
raw: { tag, value }
|
|
960
1942
|
};
|
|
961
1943
|
this.onScte35Marker(marker);
|
|
@@ -965,7 +1947,7 @@ var StormcloudVideoPlayer = class {
|
|
|
965
1947
|
const attrs = this.parseAttributeList(value);
|
|
966
1948
|
const hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
|
|
967
1949
|
const hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
|
|
968
|
-
const klass = String(attrs["CLASS"]
|
|
1950
|
+
const klass = String((_c = attrs["CLASS"]) != null ? _c : "");
|
|
969
1951
|
const duration = this.toNumber(attrs["DURATION"]);
|
|
970
1952
|
if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
|
|
971
1953
|
const marker = {
|
|
@@ -981,14 +1963,15 @@ var StormcloudVideoPlayer = class {
|
|
|
981
1963
|
}
|
|
982
1964
|
}
|
|
983
1965
|
});
|
|
984
|
-
this.hls.on(
|
|
985
|
-
|
|
1966
|
+
this.hls.on(import_hls2.default.Events.ERROR, (_evt, data) => {
|
|
1967
|
+
var _a2, _b2;
|
|
1968
|
+
if (data == null ? void 0 : data.fatal) {
|
|
986
1969
|
switch (data.type) {
|
|
987
|
-
case
|
|
988
|
-
this.hls
|
|
1970
|
+
case import_hls2.default.ErrorTypes.NETWORK_ERROR:
|
|
1971
|
+
(_a2 = this.hls) == null ? void 0 : _a2.startLoad();
|
|
989
1972
|
break;
|
|
990
|
-
case
|
|
991
|
-
this.hls
|
|
1973
|
+
case import_hls2.default.ErrorTypes.MEDIA_ERROR:
|
|
1974
|
+
(_b2 = this.hls) == null ? void 0 : _b2.recoverMediaError();
|
|
992
1975
|
break;
|
|
993
1976
|
default:
|
|
994
1977
|
this.destroy();
|
|
@@ -1090,11 +2073,12 @@ var StormcloudVideoPlayer = class {
|
|
|
1090
2073
|
}
|
|
1091
2074
|
}
|
|
1092
2075
|
parseScte35FromId3(tag) {
|
|
2076
|
+
var _a, _b, _c, _d;
|
|
1093
2077
|
const text = this.decodeId3ValueToText(tag.value);
|
|
1094
2078
|
if (!text) return void 0;
|
|
1095
2079
|
const cueOutMatch = text.match(/EXT-X-CUE-OUT(?::([^\r\n]*))?/i) || text.match(/CUE-OUT(?::([^\r\n]*))?/i);
|
|
1096
2080
|
if (cueOutMatch) {
|
|
1097
|
-
const arg = (cueOutMatch[1]
|
|
2081
|
+
const arg = ((_a = cueOutMatch[1]) != null ? _a : "").trim();
|
|
1098
2082
|
const dur = this.parseCueOutDuration(arg);
|
|
1099
2083
|
const marker = {
|
|
1100
2084
|
type: "start",
|
|
@@ -1106,12 +2090,12 @@ var StormcloudVideoPlayer = class {
|
|
|
1106
2090
|
}
|
|
1107
2091
|
const cueOutContMatch = text.match(/EXT-X-CUE-OUT-CONT:([^\r\n]*)/i);
|
|
1108
2092
|
if (cueOutContMatch) {
|
|
1109
|
-
const arg = (cueOutContMatch[1]
|
|
2093
|
+
const arg = ((_b = cueOutContMatch[1]) != null ? _b : "").trim();
|
|
1110
2094
|
const cont = this.parseCueOutCont(arg);
|
|
1111
2095
|
const marker = {
|
|
1112
2096
|
type: "progress",
|
|
1113
2097
|
...tag.ptsSeconds !== void 0 ? { ptsSeconds: tag.ptsSeconds } : {},
|
|
1114
|
-
...cont
|
|
2098
|
+
...(cont == null ? void 0 : cont.duration) !== void 0 ? { durationSeconds: cont.duration } : {},
|
|
1115
2099
|
raw: { id3: text }
|
|
1116
2100
|
};
|
|
1117
2101
|
return marker;
|
|
@@ -1127,10 +2111,10 @@ var StormcloudVideoPlayer = class {
|
|
|
1127
2111
|
}
|
|
1128
2112
|
const daterangeMatch = text.match(/EXT-X-DATERANGE:([^\r\n]*)/i);
|
|
1129
2113
|
if (daterangeMatch) {
|
|
1130
|
-
const attrs = this.parseAttributeList(daterangeMatch[1]
|
|
2114
|
+
const attrs = this.parseAttributeList((_c = daterangeMatch[1]) != null ? _c : "");
|
|
1131
2115
|
const hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
|
|
1132
2116
|
const hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
|
|
1133
|
-
const klass = String(attrs["CLASS"]
|
|
2117
|
+
const klass = String((_d = attrs["CLASS"]) != null ? _d : "");
|
|
1134
2118
|
const duration = this.toNumber(attrs["DURATION"]);
|
|
1135
2119
|
if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
|
|
1136
2120
|
const marker = {
|
|
@@ -1187,6 +2171,7 @@ var StormcloudVideoPlayer = class {
|
|
|
1187
2171
|
}
|
|
1188
2172
|
}
|
|
1189
2173
|
onScte35Marker(marker) {
|
|
2174
|
+
var _a, _b;
|
|
1190
2175
|
if (this.config.debugAdTiming) {
|
|
1191
2176
|
console.log("[StormcloudVideoPlayer] SCTE-35 marker detected:", {
|
|
1192
2177
|
type: marker.type,
|
|
@@ -1202,7 +2187,7 @@ var StormcloudVideoPlayer = class {
|
|
|
1202
2187
|
this.expectedAdBreakDurationMs = durationMs;
|
|
1203
2188
|
this.currentAdBreakStartWallClockMs = Date.now();
|
|
1204
2189
|
const isManifestMarker = this.isManifestBasedMarker(marker);
|
|
1205
|
-
const forceImmediate = this.config.immediateManifestAds
|
|
2190
|
+
const forceImmediate = (_a = this.config.immediateManifestAds) != null ? _a : true;
|
|
1206
2191
|
if (this.config.debugAdTiming) {
|
|
1207
2192
|
console.log("[StormcloudVideoPlayer] Ad start decision:", {
|
|
1208
2193
|
isManifestMarker,
|
|
@@ -1219,7 +2204,7 @@ var StormcloudVideoPlayer = class {
|
|
|
1219
2204
|
this.clearAdStartTimer();
|
|
1220
2205
|
this.handleAdStart(marker);
|
|
1221
2206
|
} else if (typeof marker.ptsSeconds === "number") {
|
|
1222
|
-
const tol = this.config.driftToleranceMs
|
|
2207
|
+
const tol = (_b = this.config.driftToleranceMs) != null ? _b : 1e3;
|
|
1223
2208
|
const nowMs = this.video.currentTime * 1e3;
|
|
1224
2209
|
const estCurrentPtsMs = nowMs - this.ptsDriftEmaMs;
|
|
1225
2210
|
const deltaMs = Math.floor(marker.ptsSeconds * 1e3 - estCurrentPtsMs);
|
|
@@ -1329,12 +2314,13 @@ var StormcloudVideoPlayer = class {
|
|
|
1329
2314
|
return void 0;
|
|
1330
2315
|
}
|
|
1331
2316
|
parseAttributeList(value) {
|
|
2317
|
+
var _a, _b, _c;
|
|
1332
2318
|
const attrs = {};
|
|
1333
2319
|
const regex = /([A-Z0-9-]+)=(("[^"]*")|([^",]*))(?:,|$)/gi;
|
|
1334
2320
|
let match;
|
|
1335
2321
|
while ((match = regex.exec(value)) !== null) {
|
|
1336
|
-
const key = match[1]
|
|
1337
|
-
let rawVal = match[3]
|
|
2322
|
+
const key = (_a = match[1]) != null ? _a : "";
|
|
2323
|
+
let rawVal = (_c = (_b = match[3]) != null ? _b : match[4]) != null ? _c : "";
|
|
1338
2324
|
if (rawVal.startsWith('"') && rawVal.endsWith('"')) {
|
|
1339
2325
|
rawVal = rawVal.slice(1, -1);
|
|
1340
2326
|
}
|
|
@@ -1498,6 +2484,43 @@ var StormcloudVideoPlayer = class {
|
|
|
1498
2484
|
}
|
|
1499
2485
|
}
|
|
1500
2486
|
async fetchAdConfiguration() {
|
|
2487
|
+
var _a, _b, _c;
|
|
2488
|
+
const vastMode = this.config.vastMode || "default";
|
|
2489
|
+
if (this.config.debugAdTiming) {
|
|
2490
|
+
console.log(
|
|
2491
|
+
"[StormcloudVideoPlayer] VAST mode:",
|
|
2492
|
+
vastMode
|
|
2493
|
+
);
|
|
2494
|
+
}
|
|
2495
|
+
if (vastMode === "adstorm") {
|
|
2496
|
+
if (!this.config.licenseKey) {
|
|
2497
|
+
if (this.config.debugAdTiming) {
|
|
2498
|
+
console.warn(
|
|
2499
|
+
"[StormcloudVideoPlayer] AdStorm mode requires a license key"
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
return;
|
|
2503
|
+
}
|
|
2504
|
+
const vastEndpoint = `https://adstorm.co/api-adstorm-dev/adstorm/vast/${this.config.licenseKey}`;
|
|
2505
|
+
this.apiVastTagUrl = vastEndpoint;
|
|
2506
|
+
if (this.config.debugAdTiming) {
|
|
2507
|
+
console.log(
|
|
2508
|
+
"[StormcloudVideoPlayer] Using AdStorm VAST endpoint:",
|
|
2509
|
+
vastEndpoint
|
|
2510
|
+
);
|
|
2511
|
+
}
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
if (this.config.vastTagUrl) {
|
|
2515
|
+
this.apiVastTagUrl = this.config.vastTagUrl;
|
|
2516
|
+
if (this.config.debugAdTiming) {
|
|
2517
|
+
console.log(
|
|
2518
|
+
"[StormcloudVideoPlayer] Using custom VAST tag URL:",
|
|
2519
|
+
this.apiVastTagUrl
|
|
2520
|
+
);
|
|
2521
|
+
}
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
1501
2524
|
const apiUrl = "https://adstorm.co/api-adstorm-dev/adstorm/ads/web";
|
|
1502
2525
|
if (this.config.debugAdTiming) {
|
|
1503
2526
|
console.log(
|
|
@@ -1511,25 +2534,29 @@ var StormcloudVideoPlayer = class {
|
|
|
1511
2534
|
}
|
|
1512
2535
|
const response = await fetch(apiUrl, { headers });
|
|
1513
2536
|
if (!response.ok) {
|
|
1514
|
-
|
|
2537
|
+
if (this.config.debugAdTiming) {
|
|
2538
|
+
console.warn(
|
|
2539
|
+
`[StormcloudVideoPlayer] Failed to fetch ad configuration: ${response.status}`
|
|
2540
|
+
);
|
|
2541
|
+
}
|
|
2542
|
+
return;
|
|
1515
2543
|
}
|
|
1516
2544
|
const data = await response.json();
|
|
1517
|
-
const imaPayload = data.response
|
|
2545
|
+
const imaPayload = (_c = (_b = (_a = data.response) == null ? void 0 : _a.ima) == null ? void 0 : _b["publisherdesk.ima"]) == null ? void 0 : _c.payload;
|
|
1518
2546
|
if (imaPayload) {
|
|
1519
2547
|
this.apiVastTagUrl = decodeURIComponent(imaPayload);
|
|
1520
2548
|
if (this.config.debugAdTiming) {
|
|
1521
2549
|
console.log(
|
|
1522
|
-
"[StormcloudVideoPlayer] Extracted VAST tag URL:",
|
|
2550
|
+
"[StormcloudVideoPlayer] Extracted VAST tag URL from /ads/web:",
|
|
1523
2551
|
this.apiVastTagUrl
|
|
1524
2552
|
);
|
|
1525
2553
|
}
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
});
|
|
2554
|
+
} else {
|
|
2555
|
+
if (this.config.debugAdTiming) {
|
|
2556
|
+
console.warn(
|
|
2557
|
+
"[StormcloudVideoPlayer] No VAST tag URL found in /ads/web response"
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
1533
2560
|
}
|
|
1534
2561
|
}
|
|
1535
2562
|
getCurrentAdIndex() {
|
|
@@ -1552,11 +2579,12 @@ var StormcloudVideoPlayer = class {
|
|
|
1552
2579
|
return "other";
|
|
1553
2580
|
}
|
|
1554
2581
|
shouldShowNativeControls() {
|
|
2582
|
+
var _a, _b;
|
|
1555
2583
|
const streamType = this.getStreamType();
|
|
1556
2584
|
if (streamType === "other") {
|
|
1557
|
-
return !(this.config.showCustomControls
|
|
2585
|
+
return !((_a = this.config.showCustomControls) != null ? _a : false);
|
|
1558
2586
|
}
|
|
1559
|
-
return !!(this.config.allowNativeHls && !(this.config.showCustomControls
|
|
2587
|
+
return !!(this.config.allowNativeHls && !((_b = this.config.showCustomControls) != null ? _b : false));
|
|
1560
2588
|
}
|
|
1561
2589
|
shouldContinueLiveStreamDuringAds() {
|
|
1562
2590
|
if (this.config.allowNativeHls) {
|
|
@@ -1568,28 +2596,20 @@ var StormcloudVideoPlayer = class {
|
|
|
1568
2596
|
return true;
|
|
1569
2597
|
}
|
|
1570
2598
|
async handleAdStart(_marker) {
|
|
2599
|
+
var _a;
|
|
1571
2600
|
const scheduled = this.findCurrentOrNextBreak(
|
|
1572
2601
|
this.video.currentTime * 1e3
|
|
1573
2602
|
);
|
|
1574
2603
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
1575
2604
|
let vastTagUrl;
|
|
1576
|
-
let adsNumber = 1;
|
|
1577
2605
|
if (this.apiVastTagUrl) {
|
|
1578
2606
|
vastTagUrl = this.apiVastTagUrl;
|
|
1579
|
-
|
|
1580
|
-
const isHls = this.config.src.includes(".m3u8") || this.config.src.includes("hls");
|
|
1581
|
-
if (isHls && this.vastConfig.cue_tones?.number_ads) {
|
|
1582
|
-
adsNumber = this.vastConfig.cue_tones.number_ads;
|
|
1583
|
-
} else if (!isHls && this.vastConfig.timer_vod?.number_ads) {
|
|
1584
|
-
adsNumber = this.vastConfig.timer_vod.number_ads;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
this.adPodQueue = new Array(adsNumber - 1).fill(vastTagUrl);
|
|
2607
|
+
this.adPodQueue = [];
|
|
1588
2608
|
this.currentAdIndex = 0;
|
|
1589
|
-
this.totalAdsInBreak =
|
|
2609
|
+
this.totalAdsInBreak = 1;
|
|
1590
2610
|
if (this.config.debugAdTiming) {
|
|
1591
2611
|
console.log(
|
|
1592
|
-
|
|
2612
|
+
"[StormcloudVideoPlayer] Using VAST endpoint:",
|
|
1593
2613
|
vastTagUrl
|
|
1594
2614
|
);
|
|
1595
2615
|
}
|
|
@@ -1627,17 +2647,18 @@ var StormcloudVideoPlayer = class {
|
|
|
1627
2647
|
this.handleAdFailure();
|
|
1628
2648
|
}
|
|
1629
2649
|
}
|
|
1630
|
-
if (this.expectedAdBreakDurationMs == null && scheduled
|
|
2650
|
+
if (this.expectedAdBreakDurationMs == null && (scheduled == null ? void 0 : scheduled.durationMs) != null) {
|
|
1631
2651
|
this.expectedAdBreakDurationMs = scheduled.durationMs;
|
|
1632
|
-
this.currentAdBreakStartWallClockMs = this.currentAdBreakStartWallClockMs
|
|
2652
|
+
this.currentAdBreakStartWallClockMs = (_a = this.currentAdBreakStartWallClockMs) != null ? _a : Date.now();
|
|
1633
2653
|
this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
|
|
1634
2654
|
}
|
|
1635
2655
|
}
|
|
1636
2656
|
findCurrentOrNextBreak(nowMs) {
|
|
2657
|
+
var _a;
|
|
1637
2658
|
const schedule = [];
|
|
1638
2659
|
let candidate;
|
|
1639
2660
|
for (const b of schedule) {
|
|
1640
|
-
const tol = this.config.driftToleranceMs
|
|
2661
|
+
const tol = (_a = this.config.driftToleranceMs) != null ? _a : 1e3;
|
|
1641
2662
|
if (b.startTimeMs <= nowMs + tol && (candidate == null || b.startTimeMs > (candidate.startTimeMs || 0))) {
|
|
1642
2663
|
candidate = b;
|
|
1643
2664
|
}
|
|
@@ -1653,7 +2674,8 @@ var StormcloudVideoPlayer = class {
|
|
|
1653
2674
|
}
|
|
1654
2675
|
}
|
|
1655
2676
|
async handleMidAdJoin(adBreak, nowMs) {
|
|
1656
|
-
|
|
2677
|
+
var _a;
|
|
2678
|
+
const durationMs = (_a = adBreak.durationMs) != null ? _a : 0;
|
|
1657
2679
|
const endMs = adBreak.startTimeMs + durationMs;
|
|
1658
2680
|
if (durationMs > 0 && nowMs > adBreak.startTimeMs && nowMs < endMs) {
|
|
1659
2681
|
const remainingMs = endMs - nowMs;
|
|
@@ -1754,6 +2776,7 @@ var StormcloudVideoPlayer = class {
|
|
|
1754
2776
|
}
|
|
1755
2777
|
}
|
|
1756
2778
|
handleAdFailure() {
|
|
2779
|
+
var _a;
|
|
1757
2780
|
if (this.config.debugAdTiming) {
|
|
1758
2781
|
console.log(
|
|
1759
2782
|
"[StormcloudVideoPlayer] Handling ad failure - resuming content",
|
|
@@ -1786,7 +2809,7 @@ var StormcloudVideoPlayer = class {
|
|
|
1786
2809
|
if (this.config.debugAdTiming) {
|
|
1787
2810
|
console.log("[StormcloudVideoPlayer] Resuming paused video");
|
|
1788
2811
|
}
|
|
1789
|
-
this.video.play()
|
|
2812
|
+
(_a = this.video.play()) == null ? void 0 : _a.catch((error) => {
|
|
1790
2813
|
if (this.config.debugAdTiming) {
|
|
1791
2814
|
console.error(
|
|
1792
2815
|
"[StormcloudVideoPlayer] Failed to resume video after ad failure:",
|
|
@@ -1801,8 +2824,9 @@ var StormcloudVideoPlayer = class {
|
|
|
1801
2824
|
}
|
|
1802
2825
|
}
|
|
1803
2826
|
startAdFailsafeTimer() {
|
|
2827
|
+
var _a;
|
|
1804
2828
|
this.clearAdFailsafeTimer();
|
|
1805
|
-
const failsafeMs = this.config.adFailsafeTimeoutMs
|
|
2829
|
+
const failsafeMs = (_a = this.config.adFailsafeTimeoutMs) != null ? _a : 1e4;
|
|
1806
2830
|
if (this.config.debugAdTiming) {
|
|
1807
2831
|
console.log(
|
|
1808
2832
|
`[StormcloudVideoPlayer] Starting failsafe timer (${failsafeMs}ms)`
|
|
@@ -1938,6 +2962,7 @@ var StormcloudVideoPlayer = class {
|
|
|
1938
2962
|
}
|
|
1939
2963
|
}
|
|
1940
2964
|
destroy() {
|
|
2965
|
+
var _a, _b;
|
|
1941
2966
|
this.clearAdStartTimer();
|
|
1942
2967
|
this.clearAdStopTimer();
|
|
1943
2968
|
this.clearAdFailsafeTimer();
|
|
@@ -1945,8 +2970,8 @@ var StormcloudVideoPlayer = class {
|
|
|
1945
2970
|
clearInterval(this.heartbeatInterval);
|
|
1946
2971
|
this.heartbeatInterval = void 0;
|
|
1947
2972
|
}
|
|
1948
|
-
this.hls
|
|
1949
|
-
this.ima
|
|
2973
|
+
(_a = this.hls) == null ? void 0 : _a.destroy();
|
|
2974
|
+
(_b = this.ima) == null ? void 0 : _b.destroy();
|
|
1950
2975
|
}
|
|
1951
2976
|
};
|
|
1952
2977
|
|
|
@@ -2053,7 +3078,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
|
|
|
2053
3078
|
}
|
|
2054
3079
|
setShowSpeedMenu(false);
|
|
2055
3080
|
};
|
|
2056
|
-
const isHlsStream = src
|
|
3081
|
+
const isHlsStream = (src == null ? void 0 : src.toLowerCase().includes(".m3u8")) || (src == null ? void 0 : src.toLowerCase().includes("/hls/"));
|
|
2057
3082
|
const shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
|
|
2058
3083
|
const criticalPropsKey = (0, import_react.useMemo)(() => {
|
|
2059
3084
|
return CRITICAL_PROPS.map((prop) => `${prop}:${props[prop]}`).join("|");
|
|
@@ -2103,13 +3128,13 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
|
|
|
2103
3128
|
player.load().then(() => {
|
|
2104
3129
|
const showNative = player.shouldShowNativeControls();
|
|
2105
3130
|
setShouldShowNativeControls(showNative);
|
|
2106
|
-
onReady
|
|
3131
|
+
onReady == null ? void 0 : onReady(player);
|
|
2107
3132
|
}).catch((error) => {
|
|
2108
3133
|
console.error(
|
|
2109
3134
|
"StormcloudVideoPlayer: Failed to load player:",
|
|
2110
3135
|
error
|
|
2111
3136
|
);
|
|
2112
|
-
onReady
|
|
3137
|
+
onReady == null ? void 0 : onReady(player);
|
|
2113
3138
|
});
|
|
2114
3139
|
return () => {
|
|
2115
3140
|
try {
|
|
@@ -2165,6 +3190,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
|
|
|
2165
3190
|
(0, import_react.useEffect)(() => {
|
|
2166
3191
|
if (!playerRef.current || !videoRef.current) return;
|
|
2167
3192
|
const updateStates = () => {
|
|
3193
|
+
var _a;
|
|
2168
3194
|
if (playerRef.current && videoRef.current) {
|
|
2169
3195
|
setIsMuted(playerRef.current.isMuted());
|
|
2170
3196
|
setIsPlaying(!videoRef.current.paused);
|
|
@@ -2182,13 +3208,14 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
|
|
|
2182
3208
|
);
|
|
2183
3209
|
}
|
|
2184
3210
|
setIsFullscreen(
|
|
2185
|
-
document.fullscreenElement === videoRef.current
|
|
3211
|
+
document.fullscreenElement === ((_a = videoRef.current) == null ? void 0 : _a.parentElement)
|
|
2186
3212
|
);
|
|
2187
3213
|
};
|
|
2188
3214
|
const interval = setInterval(updateStates, 200);
|
|
2189
3215
|
const handleFullscreenChange = () => {
|
|
3216
|
+
var _a;
|
|
2190
3217
|
setIsFullscreen(
|
|
2191
|
-
document.fullscreenElement === videoRef.current
|
|
3218
|
+
document.fullscreenElement === ((_a = videoRef.current) == null ? void 0 : _a.parentElement)
|
|
2192
3219
|
);
|
|
2193
3220
|
};
|
|
2194
3221
|
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
|
@@ -3534,27 +4561,30 @@ var parseQuery = (url) => {
|
|
|
3534
4561
|
const query = {};
|
|
3535
4562
|
const queryString = url.split("?")[1] || "";
|
|
3536
4563
|
if (!queryString) return query;
|
|
4564
|
+
const manualParse = (qs) => {
|
|
4565
|
+
qs.split("&").forEach((param) => {
|
|
4566
|
+
const [key, value] = param.split("=");
|
|
4567
|
+
if (key) {
|
|
4568
|
+
try {
|
|
4569
|
+
query[decodeURIComponent(key)] = value ? decodeURIComponent(value.replace(/\+/g, " ")) : "";
|
|
4570
|
+
} catch (e) {
|
|
4571
|
+
query[key] = value || "";
|
|
4572
|
+
}
|
|
4573
|
+
}
|
|
4574
|
+
});
|
|
4575
|
+
};
|
|
3537
4576
|
if (typeof URLSearchParams !== "undefined") {
|
|
3538
4577
|
try {
|
|
3539
4578
|
const params = new URLSearchParams(queryString);
|
|
3540
4579
|
params.forEach((value, key) => {
|
|
3541
4580
|
query[key] = value;
|
|
3542
4581
|
});
|
|
4582
|
+
return query;
|
|
3543
4583
|
} catch (e) {
|
|
3544
|
-
queryString
|
|
3545
|
-
const [key, value] = param.split("=");
|
|
3546
|
-
if (key) {
|
|
3547
|
-
query[decodeURIComponent(key)] = value ? decodeURIComponent(value) : "";
|
|
3548
|
-
}
|
|
3549
|
-
});
|
|
4584
|
+
manualParse(queryString);
|
|
3550
4585
|
}
|
|
3551
4586
|
} else {
|
|
3552
|
-
queryString
|
|
3553
|
-
const [key, value] = param.split("=");
|
|
3554
|
-
if (key) {
|
|
3555
|
-
query[decodeURIComponent(key)] = value ? decodeURIComponent(value) : "";
|
|
3556
|
-
}
|
|
3557
|
-
});
|
|
4587
|
+
manualParse(queryString);
|
|
3558
4588
|
}
|
|
3559
4589
|
return query;
|
|
3560
4590
|
};
|
|
@@ -3628,6 +4658,7 @@ var HlsPlayer = class extends import_react3.Component {
|
|
|
3628
4658
|
this.player = null;
|
|
3629
4659
|
this.mounted = false;
|
|
3630
4660
|
this.load = async () => {
|
|
4661
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3631
4662
|
if (!this.props.videoElement || !this.props.src) return;
|
|
3632
4663
|
try {
|
|
3633
4664
|
if (this.player) {
|
|
@@ -3664,27 +4695,29 @@ var HlsPlayer = class extends import_react3.Component {
|
|
|
3664
4695
|
if (this.props.adFailsafeTimeoutMs !== void 0)
|
|
3665
4696
|
config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
|
|
3666
4697
|
this.player = new StormcloudVideoPlayer(config);
|
|
3667
|
-
this.props.onMount
|
|
4698
|
+
(_b = (_a = this.props).onMount) == null ? void 0 : _b.call(_a, this);
|
|
3668
4699
|
await this.player.load();
|
|
3669
4700
|
if (this.mounted) {
|
|
3670
|
-
this.props.onReady
|
|
4701
|
+
(_d = (_c = this.props).onReady) == null ? void 0 : _d.call(_c);
|
|
3671
4702
|
}
|
|
3672
4703
|
} catch (error) {
|
|
3673
4704
|
if (this.mounted) {
|
|
3674
|
-
this.props.onError
|
|
4705
|
+
(_f = (_e = this.props).onError) == null ? void 0 : _f.call(_e, error);
|
|
3675
4706
|
}
|
|
3676
4707
|
}
|
|
3677
4708
|
};
|
|
3678
4709
|
this.play = () => {
|
|
4710
|
+
var _a, _b;
|
|
3679
4711
|
if (this.props.videoElement) {
|
|
3680
4712
|
this.props.videoElement.play();
|
|
3681
|
-
this.props.onPlay
|
|
4713
|
+
(_b = (_a = this.props).onPlay) == null ? void 0 : _b.call(_a);
|
|
3682
4714
|
}
|
|
3683
4715
|
};
|
|
3684
4716
|
this.pause = () => {
|
|
4717
|
+
var _a, _b;
|
|
3685
4718
|
if (this.props.videoElement) {
|
|
3686
4719
|
this.props.videoElement.pause();
|
|
3687
|
-
this.props.onPause
|
|
4720
|
+
(_b = (_a = this.props).onPause) == null ? void 0 : _b.call(_a);
|
|
3688
4721
|
}
|
|
3689
4722
|
};
|
|
3690
4723
|
this.stop = () => {
|
|
@@ -3779,37 +4812,44 @@ var FilePlayer = class extends import_react4.Component {
|
|
|
3779
4812
|
this.mounted = false;
|
|
3780
4813
|
this.ready = false;
|
|
3781
4814
|
this.load = () => {
|
|
4815
|
+
var _a, _b;
|
|
3782
4816
|
if (!this.props.videoElement || !this.props.src) return;
|
|
3783
4817
|
const video = this.props.videoElement;
|
|
3784
4818
|
const handleLoadedMetadata = () => {
|
|
4819
|
+
var _a2, _b2;
|
|
3785
4820
|
if (this.mounted && !this.ready) {
|
|
3786
4821
|
this.ready = true;
|
|
3787
|
-
this.props.onReady
|
|
4822
|
+
(_b2 = (_a2 = this.props).onReady) == null ? void 0 : _b2.call(_a2);
|
|
3788
4823
|
}
|
|
3789
4824
|
};
|
|
3790
4825
|
const handlePlay = () => {
|
|
4826
|
+
var _a2, _b2;
|
|
3791
4827
|
if (this.mounted) {
|
|
3792
|
-
this.props.onPlay
|
|
4828
|
+
(_b2 = (_a2 = this.props).onPlay) == null ? void 0 : _b2.call(_a2);
|
|
3793
4829
|
}
|
|
3794
4830
|
};
|
|
3795
4831
|
const handlePause = () => {
|
|
4832
|
+
var _a2, _b2;
|
|
3796
4833
|
if (this.mounted) {
|
|
3797
|
-
this.props.onPause
|
|
4834
|
+
(_b2 = (_a2 = this.props).onPause) == null ? void 0 : _b2.call(_a2);
|
|
3798
4835
|
}
|
|
3799
4836
|
};
|
|
3800
4837
|
const handleEnded = () => {
|
|
4838
|
+
var _a2, _b2;
|
|
3801
4839
|
if (this.mounted) {
|
|
3802
|
-
this.props.onEnded
|
|
4840
|
+
(_b2 = (_a2 = this.props).onEnded) == null ? void 0 : _b2.call(_a2);
|
|
3803
4841
|
}
|
|
3804
4842
|
};
|
|
3805
4843
|
const handleError = (error) => {
|
|
4844
|
+
var _a2, _b2;
|
|
3806
4845
|
if (this.mounted) {
|
|
3807
|
-
this.props.onError
|
|
4846
|
+
(_b2 = (_a2 = this.props).onError) == null ? void 0 : _b2.call(_a2, error);
|
|
3808
4847
|
}
|
|
3809
4848
|
};
|
|
3810
4849
|
const handleLoadedData = () => {
|
|
4850
|
+
var _a2, _b2;
|
|
3811
4851
|
if (this.mounted) {
|
|
3812
|
-
this.props.onLoaded
|
|
4852
|
+
(_b2 = (_a2 = this.props).onLoaded) == null ? void 0 : _b2.call(_a2);
|
|
3813
4853
|
}
|
|
3814
4854
|
};
|
|
3815
4855
|
video.addEventListener("loadedmetadata", handleLoadedMetadata);
|
|
@@ -3828,7 +4868,7 @@ var FilePlayer = class extends import_react4.Component {
|
|
|
3828
4868
|
if (this.props.preload !== void 0)
|
|
3829
4869
|
video.preload = this.props.preload;
|
|
3830
4870
|
if (this.props.poster !== void 0) video.poster = this.props.poster;
|
|
3831
|
-
this.props.onMount
|
|
4871
|
+
(_b = (_a = this.props).onMount) == null ? void 0 : _b.call(_a, this);
|
|
3832
4872
|
return () => {
|
|
3833
4873
|
video.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
|
3834
4874
|
video.removeEventListener("play", handlePlay);
|
|
@@ -3997,6 +5037,7 @@ var Player = class extends import_react5.Component {
|
|
|
3997
5037
|
return this.player.getInternalPlayer(key);
|
|
3998
5038
|
};
|
|
3999
5039
|
this.progress = () => {
|
|
5040
|
+
var _a, _b;
|
|
4000
5041
|
if (this.props.src && this.player && this.isReady) {
|
|
4001
5042
|
const playedSeconds = this.getCurrentTime() || 0;
|
|
4002
5043
|
const loadedSeconds = this.getSecondsLoaded();
|
|
@@ -4013,7 +5054,7 @@ var Player = class extends import_react5.Component {
|
|
|
4013
5054
|
progress.loaded = loadedSeconds / duration;
|
|
4014
5055
|
}
|
|
4015
5056
|
if (progress.playedSeconds !== this.prevPlayed || progress.loadedSeconds !== this.prevLoaded) {
|
|
4016
|
-
this.props.onProgress
|
|
5057
|
+
(_b = (_a = this.props).onProgress) == null ? void 0 : _b.call(_a, progress);
|
|
4017
5058
|
}
|
|
4018
5059
|
this.prevPlayed = progress.playedSeconds;
|
|
4019
5060
|
this.prevLoaded = progress.loadedSeconds;
|
|
@@ -4049,10 +5090,10 @@ var Player = class extends import_react5.Component {
|
|
|
4049
5090
|
if (this.player.setPlaybackRate && playbackRate !== 1) {
|
|
4050
5091
|
this.player.setPlaybackRate(playbackRate);
|
|
4051
5092
|
}
|
|
4052
|
-
onStart
|
|
5093
|
+
onStart == null ? void 0 : onStart();
|
|
4053
5094
|
this.startOnPlay = false;
|
|
4054
5095
|
}
|
|
4055
|
-
onPlay
|
|
5096
|
+
onPlay == null ? void 0 : onPlay();
|
|
4056
5097
|
if (this.seekOnPlay) {
|
|
4057
5098
|
this.seekTo(this.seekOnPlay);
|
|
4058
5099
|
this.seekOnPlay = null;
|
|
@@ -4060,9 +5101,10 @@ var Player = class extends import_react5.Component {
|
|
|
4060
5101
|
this.handleDurationCheck();
|
|
4061
5102
|
};
|
|
4062
5103
|
this.handlePause = (e) => {
|
|
5104
|
+
var _a, _b;
|
|
4063
5105
|
this.isPlaying = false;
|
|
4064
5106
|
if (!this.isLoading) {
|
|
4065
|
-
this.props.onPause
|
|
5107
|
+
(_b = (_a = this.props).onPause) == null ? void 0 : _b.call(_a, e);
|
|
4066
5108
|
}
|
|
4067
5109
|
};
|
|
4068
5110
|
this.handleEnded = () => {
|
|
@@ -4072,19 +5114,21 @@ var Player = class extends import_react5.Component {
|
|
|
4072
5114
|
}
|
|
4073
5115
|
if (!loop) {
|
|
4074
5116
|
this.isPlaying = false;
|
|
4075
|
-
onEnded
|
|
5117
|
+
onEnded == null ? void 0 : onEnded();
|
|
4076
5118
|
}
|
|
4077
5119
|
};
|
|
4078
5120
|
this.handleError = (...args) => {
|
|
5121
|
+
var _a, _b;
|
|
4079
5122
|
this.isLoading = false;
|
|
4080
|
-
this.props.onError
|
|
5123
|
+
(_b = (_a = this.props).onError) == null ? void 0 : _b.call(_a, args[0], args[1], args[2], args[3]);
|
|
4081
5124
|
};
|
|
4082
5125
|
this.handleDurationCheck = () => {
|
|
5126
|
+
var _a, _b;
|
|
4083
5127
|
clearTimeout(this.durationCheckTimeout);
|
|
4084
5128
|
const duration = this.getDuration();
|
|
4085
5129
|
if (duration) {
|
|
4086
5130
|
if (!this.onDurationCalled) {
|
|
4087
|
-
this.props.onDuration
|
|
5131
|
+
(_b = (_a = this.props).onDuration) == null ? void 0 : _b.call(_a, duration);
|
|
4088
5132
|
this.onDurationCalled = true;
|
|
4089
5133
|
}
|
|
4090
5134
|
} else {
|
|
@@ -4283,7 +5327,8 @@ var createStormcloudPlayer = (playerList, fallback) => {
|
|
|
4283
5327
|
return omit(this.props, SUPPORTED_PROPS);
|
|
4284
5328
|
};
|
|
4285
5329
|
this.handleReady = () => {
|
|
4286
|
-
|
|
5330
|
+
var _a2, _b;
|
|
5331
|
+
(_b = (_a2 = this.props).onReady) == null ? void 0 : _b.call(_a2, this);
|
|
4287
5332
|
};
|
|
4288
5333
|
this.seekTo = (fraction, type, keepPlaying) => {
|
|
4289
5334
|
if (!this.player) return null;
|
|
@@ -4384,11 +5429,18 @@ var StormcloudPlayer_default = StormcloudPlayer;
|
|
|
4384
5429
|
StormcloudVideoPlayer,
|
|
4385
5430
|
StormcloudVideoPlayerComponent,
|
|
4386
5431
|
canPlay,
|
|
5432
|
+
createHlsAdPlayer,
|
|
5433
|
+
createImaController,
|
|
4387
5434
|
createStormcloudPlayer,
|
|
5435
|
+
detectBrowser,
|
|
5436
|
+
getBrowserConfigOverrides,
|
|
4388
5437
|
getBrowserID,
|
|
4389
5438
|
getClientInfo,
|
|
5439
|
+
getRecommendedAdPlayer,
|
|
5440
|
+
initializePolyfills,
|
|
4390
5441
|
isMediaStream,
|
|
4391
5442
|
lazy,
|
|
5443
|
+
logBrowserInfo,
|
|
4392
5444
|
merge,
|
|
4393
5445
|
omit,
|
|
4394
5446
|
parseQuery,
|
|
@@ -4396,6 +5448,9 @@ var StormcloudPlayer_default = StormcloudPlayer;
|
|
|
4396
5448
|
randomString,
|
|
4397
5449
|
sendHeartbeat,
|
|
4398
5450
|
sendInitialTracking,
|
|
5451
|
+
supportsFeature,
|
|
5452
|
+
supportsGoogleIMA,
|
|
5453
|
+
supportsModernJS,
|
|
4399
5454
|
supportsWebKitPresentationMode
|
|
4400
5455
|
});
|
|
4401
5456
|
//# sourceMappingURL=index.cjs.map
|