stormcloud-video-player 0.6.9 → 0.6.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/stormcloud-vp.min.js +1 -1
- package/lib/index.cjs +124 -17
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +2 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +124 -17
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +124 -17
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +124 -17
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +124 -17
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/vastAdLayer.cjs +15 -1
- package/lib/sdk/vastAdLayer.cjs.map +1 -1
- package/lib/sdk/vastManager.cjs +93 -10
- package/lib/sdk/vastManager.cjs.map +1 -1
- package/lib/sdk/vastManager.d.cts +2 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +124 -17
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
package/lib/sdk/vastManager.cjs
CHANGED
|
@@ -361,7 +361,8 @@ function parseVastXml(xmlString) {
|
|
|
361
361
|
}
|
|
362
362
|
}
|
|
363
363
|
// src/sdk/vastManager.ts
|
|
364
|
-
var
|
|
364
|
+
var VAST_TAG_URL_FALLBACK = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click";
|
|
365
|
+
var ADSTORM_API_URL = "https://adstorm.co/api-adstorm-dev/adstorm/ads/web";
|
|
365
366
|
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
366
367
|
var MAX_RETRIES = 3;
|
|
367
368
|
var RETRY_BACKOFF_MS = 1500;
|
|
@@ -369,6 +370,7 @@ function createVastManager() {
|
|
|
369
370
|
var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
370
371
|
var _options_debug;
|
|
371
372
|
var initialized = false;
|
|
373
|
+
var vastTagUrl = VAST_TAG_URL_FALLBACK;
|
|
372
374
|
var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
|
|
373
375
|
function log() {
|
|
374
376
|
for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
|
|
@@ -390,17 +392,97 @@ function createVastManager() {
|
|
|
390
392
|
"[VastManager]"
|
|
391
393
|
].concat(_to_consumable_array(args)));
|
|
392
394
|
}
|
|
395
|
+
function fetchVastUrlFromApi() {
|
|
396
|
+
return _async_to_generator(function() {
|
|
397
|
+
var apiUrl, _data_response_ima_publisherdeskima, _data_response_ima, _data_response, res, data, payload, err;
|
|
398
|
+
return _ts_generator(this, function(_state) {
|
|
399
|
+
switch(_state.label){
|
|
400
|
+
case 0:
|
|
401
|
+
apiUrl = options.adstormApiUrl || ADSTORM_API_URL;
|
|
402
|
+
_state.label = 1;
|
|
403
|
+
case 1:
|
|
404
|
+
_state.trys.push([
|
|
405
|
+
1,
|
|
406
|
+
4,
|
|
407
|
+
,
|
|
408
|
+
5
|
|
409
|
+
]);
|
|
410
|
+
return [
|
|
411
|
+
4,
|
|
412
|
+
fetch(apiUrl, {
|
|
413
|
+
method: "GET",
|
|
414
|
+
headers: {
|
|
415
|
+
Authorization: "Bearer ".concat(options.licenseKey),
|
|
416
|
+
Accept: "application/json"
|
|
417
|
+
}
|
|
418
|
+
})
|
|
419
|
+
];
|
|
420
|
+
case 2:
|
|
421
|
+
res = _state.sent();
|
|
422
|
+
if (!res.ok) {
|
|
423
|
+
warn("Failed to fetch VAST URL from API (HTTP ".concat(res.status, "), using fallback"));
|
|
424
|
+
return [
|
|
425
|
+
2
|
|
426
|
+
];
|
|
427
|
+
}
|
|
428
|
+
return [
|
|
429
|
+
4,
|
|
430
|
+
res.json()
|
|
431
|
+
];
|
|
432
|
+
case 3:
|
|
433
|
+
data = _state.sent();
|
|
434
|
+
payload = data === null || data === void 0 ? void 0 : (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
|
|
435
|
+
if (payload) {
|
|
436
|
+
vastTagUrl = payload;
|
|
437
|
+
log("VAST tag URL fetched from API:", vastTagUrl.split("?")[0]);
|
|
438
|
+
} else {
|
|
439
|
+
log("API response had no VAST payload, using fallback URL");
|
|
440
|
+
}
|
|
441
|
+
return [
|
|
442
|
+
3,
|
|
443
|
+
5
|
|
444
|
+
];
|
|
445
|
+
case 4:
|
|
446
|
+
err = _state.sent();
|
|
447
|
+
warn("Error fetching VAST URL from API, using fallback:", err);
|
|
448
|
+
return [
|
|
449
|
+
3,
|
|
450
|
+
5
|
|
451
|
+
];
|
|
452
|
+
case 5:
|
|
453
|
+
return [
|
|
454
|
+
2
|
|
455
|
+
];
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
})();
|
|
459
|
+
}
|
|
393
460
|
function initialize() {
|
|
394
461
|
return _async_to_generator(function() {
|
|
395
462
|
return _ts_generator(this, function(_state) {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
463
|
+
switch(_state.label){
|
|
464
|
+
case 0:
|
|
465
|
+
if (initialized) return [
|
|
466
|
+
2
|
|
467
|
+
];
|
|
468
|
+
initialized = true;
|
|
469
|
+
if (!options.licenseKey) return [
|
|
470
|
+
3,
|
|
471
|
+
2
|
|
472
|
+
];
|
|
473
|
+
return [
|
|
474
|
+
4,
|
|
475
|
+
fetchVastUrlFromApi()
|
|
476
|
+
];
|
|
477
|
+
case 1:
|
|
478
|
+
_state.sent();
|
|
479
|
+
_state.label = 2;
|
|
480
|
+
case 2:
|
|
481
|
+
log("Initialized, VAST tag URL:", vastTagUrl.split("?")[0]);
|
|
482
|
+
return [
|
|
483
|
+
2
|
|
484
|
+
];
|
|
485
|
+
}
|
|
404
486
|
});
|
|
405
487
|
})();
|
|
406
488
|
}
|
|
@@ -414,7 +496,7 @@ function createVastManager() {
|
|
|
414
496
|
throw new Error("VastManager not initialized. Call initialize() first.");
|
|
415
497
|
}
|
|
416
498
|
correlator = Math.floor(Math.random() * 1e12).toString();
|
|
417
|
-
url =
|
|
499
|
+
url = vastTagUrl.replace("[placeholder]", correlator);
|
|
418
500
|
log("Fetching VAST tag, correlator:", correlator);
|
|
419
501
|
controller = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
420
502
|
timeoutId = setTimeout(function() {
|
|
@@ -608,6 +690,7 @@ function createVastManager() {
|
|
|
608
690
|
}
|
|
609
691
|
function destroy() {
|
|
610
692
|
initialized = false;
|
|
693
|
+
vastTagUrl = VAST_TAG_URL_FALLBACK;
|
|
611
694
|
log("Destroyed");
|
|
612
695
|
}
|
|
613
696
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/sdk/vastManager.cjs","../../src/sdk/vastManager.ts","../../src/sdk/vastParser.ts"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","from","to","vastManager_exports","name","get","enumerable","__copyProps","except","desc","key","call","__toCommonJS","mod","value","createVastManager","module","exports","type","includes","parseVastXml","filter","xmlString","xmlDoc","parser","DOMParser","parseFromString","parserError","querySelector","console","error","logPrefix","textContent","adElement","warn","adId","getAttribute","isNoAdAvailable","title","toLowerCase","isMp4Type","durationText","durationParts","split","duration","parseInt","Math","round","parseFloat","mediaFileElements","querySelectorAll","mediaFiles","log","length","forEach","mf","index","url","trim","width","height","substring","isHls","isHlsType","isMp4","accepted"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/sdk/vastManager.ts\nvar vastManager_exports = {};\n__export(vastManager_exports, {\n createVastManager: () => createVastManager\n});\nmodule.exports = __toCommonJS(vastManager_exports);\n\n// src/sdk/vastParser.ts\nfunction isHlsType(type) {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\nfunction isMp4Type(type) {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\nfunction parseVastXml(xmlString, filter = \"all\", logPrefix = \"[VastParser]\") {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n const isNoAdAvailable = adId === \"empty\" || title.toLowerCase().includes(\"no ad available\") || title.toLowerCase() === \"no ad available\";\n const durationText = xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration = parseInt(durationParts[0] || \"0\", 10) * 3600 + parseInt(durationParts[1] || \"0\", 10) * 60 + Math.round(parseFloat(durationParts[2] || \"0\"));\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles = [];\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0\n });\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n const trackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: []\n };\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n const clickThrough = xmlDoc.querySelector(\"ClickThrough\")?.textContent?.trim();\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\n\n// src/sdk/vastManager.ts\nvar VAST_TAG_URL = \"https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click\";\nvar DEFAULT_TIMEOUT_MS = 5e3;\nvar MAX_RETRIES = 3;\nvar RETRY_BACKOFF_MS = 1500;\nfunction createVastManager(options = {}) {\n let initialized = false;\n const debug = options.debug ?? false;\n function log(...args) {\n if (debug) {\n console.log(\"[VastManager]\", ...args);\n }\n }\n function warn(...args) {\n console.warn(\"[VastManager]\", ...args);\n }\n async function initialize() {\n if (initialized) return;\n initialized = true;\n log(\"Initialized, VAST tag URL:\", VAST_TAG_URL.split(\"?\")[0]);\n }\n async function requestBids(_context) {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n const correlator = Math.floor(Math.random() * 1e12).toString();\n const url = VAST_TAG_URL.replace(\"[placeholder]\", correlator);\n log(\"Fetching VAST tag, correlator:\", correlator);\n const controller = typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), DEFAULT_TIMEOUT_MS);\n try {\n const fetchOptions = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: { Accept: \"application/xml, text/xml, */*\" },\n referrerPolicy: \"no-referrer-when-downgrade\"\n };\n if (controller) fetchOptions.signal = controller.signal;\n const response = await fetch(url, fetchOptions);\n clearTimeout(timeoutId);\n if (!response.ok) {\n throw new Error(`VAST request returned HTTP ${response.status}`);\n }\n const vastXml = await response.text();\n log(\"VAST XML received, length:\", vastXml.length);\n const vastAd = parseVastXml(vastXml, \"mp4-first\", \"[VastManager]\");\n if (!vastAd) {\n log(\"VAST parsed but no usable ad found\");\n return [];\n }\n log(`Ad parsed: id=${vastAd.id}, duration=${vastAd.duration}s, mediaFiles=${vastAd.mediaFiles.length}`);\n const bid = {\n bidder: \"vast-direct\",\n cpm: 0,\n vastXml,\n width: vastAd.mediaFiles[0]?.width ?? 0,\n height: vastAd.mediaFiles[0]?.height ?? 0,\n adId: vastAd.id,\n impId: correlator,\n creativeId: vastAd.id,\n currency: \"USD\",\n durationSec: vastAd.duration\n };\n return [bid];\n } catch (error) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`VAST request timed out after ${DEFAULT_TIMEOUT_MS}ms`);\n return [];\n }\n throw error;\n }\n }\n async function requestBidsUntilResponse(context) {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n let lastError;\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const bids = await requestBids(context);\n if (bids.length > 0) {\n log(`requestBidsUntilResponse: got ${bids.length} ad(s) on attempt ${attempt}`);\n return bids;\n }\n log(`requestBidsUntilResponse: no ads on attempt ${attempt}/${MAX_RETRIES}`);\n } catch (err) {\n lastError = err;\n warn(`requestBidsUntilResponse: attempt ${attempt}/${MAX_RETRIES} failed:`, err);\n }\n if (attempt < MAX_RETRIES) {\n const delay = RETRY_BACKOFF_MS * attempt;\n log(`requestBidsUntilResponse: waiting ${delay}ms before retry`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) throw lastError;\n return [];\n }\n function destroy() {\n initialized = false;\n log(\"Destroyed\");\n }\n return {\n initialize,\n requestBids,\n requestBidsUntilResponse,\n destroy,\n get isInitialized() {\n return initialized;\n }\n };\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createVastManager\n});\n","import { parseVastXml } from \"./vastParser\";\nimport type { VastBidResponse, VastManager, AdBreakContext } from \"../types\";\n\nconst VAST_TAG_URL =\n \"https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click\";\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst MAX_RETRIES = 3;\nconst RETRY_BACKOFF_MS = 1500;\n\nexport interface VastManagerOptions {\n debug?: boolean;\n}\n\nexport function createVastManager(\n options: VastManagerOptions = {}\n): VastManager {\n let initialized = false;\n const debug = options.debug ?? false;\n\n function log(...args: any[]): void {\n if (debug) {\n console.log(\"[VastManager]\", ...args);\n }\n }\n\n function warn(...args: any[]): void {\n console.warn(\"[VastManager]\", ...args);\n }\n\n async function initialize(): Promise<void> {\n if (initialized) return;\n initialized = true;\n log(\"Initialized, VAST tag URL:\", VAST_TAG_URL.split(\"?\")[0]);\n }\n\n async function requestBids(_context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n\n const correlator = Math.floor(Math.random() * 1e12).toString();\n const url = VAST_TAG_URL.replace(\"[placeholder]\", correlator);\n\n log(\"Fetching VAST tag, correlator:\", correlator);\n\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), DEFAULT_TIMEOUT_MS);\n\n try {\n const fetchOptions: RequestInit = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: { Accept: \"application/xml, text/xml, */*\" },\n referrerPolicy: \"no-referrer-when-downgrade\",\n };\n if (controller) fetchOptions.signal = controller.signal;\n\n const response = await fetch(url, fetchOptions);\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(`VAST request returned HTTP ${response.status}`);\n }\n\n const vastXml = await response.text();\n log(\"VAST XML received, length:\", vastXml.length);\n\n const vastAd = parseVastXml(vastXml, \"mp4-first\", \"[VastManager]\");\n if (!vastAd) {\n log(\"VAST parsed but no usable ad found\");\n return [];\n }\n\n log(`Ad parsed: id=${vastAd.id}, duration=${vastAd.duration}s, mediaFiles=${vastAd.mediaFiles.length}`);\n\n const bid: VastBidResponse = {\n bidder: \"vast-direct\",\n cpm: 0,\n vastXml,\n width: vastAd.mediaFiles[0]?.width ?? 0,\n height: vastAd.mediaFiles[0]?.height ?? 0,\n adId: vastAd.id,\n impId: correlator,\n creativeId: vastAd.id,\n currency: \"USD\",\n durationSec: vastAd.duration,\n };\n\n return [bid];\n } catch (error: any) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`VAST request timed out after ${DEFAULT_TIMEOUT_MS}ms`);\n return [];\n }\n throw error;\n }\n }\n\n async function requestBidsUntilResponse(context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n let lastError: unknown;\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const bids = await requestBids(context);\n if (bids.length > 0) {\n log(`requestBidsUntilResponse: got ${bids.length} ad(s) on attempt ${attempt}`);\n return bids;\n }\n log(`requestBidsUntilResponse: no ads on attempt ${attempt}/${MAX_RETRIES}`);\n } catch (err) {\n lastError = err;\n warn(`requestBidsUntilResponse: attempt ${attempt}/${MAX_RETRIES} failed:`, err);\n }\n if (attempt < MAX_RETRIES) {\n const delay = RETRY_BACKOFF_MS * attempt;\n log(`requestBidsUntilResponse: waiting ${delay}ms before retry`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) throw lastError;\n return [];\n }\n\n function destroy(): void {\n initialized = false;\n log(\"Destroyed\");\n }\n\n return {\n initialize,\n requestBids,\n requestBidsUntilResponse,\n destroy,\n get isInitialized() {\n return initialized;\n },\n };\n}\n","export interface VastMediaFile {\n url: string;\n type: string;\n width: number;\n height: number;\n bitrate?: number | undefined;\n}\n\nexport interface VastTrackingUrls {\n impression: string[];\n start: string[];\n firstQuartile: string[];\n midpoint: string[];\n thirdQuartile: string[];\n complete: string[];\n mute: string[];\n unmute: string[];\n pause: string[];\n resume: string[];\n fullscreen: string[];\n exitFullscreen: string[];\n skip: string[];\n error: string[];\n}\n\nexport interface VastAd {\n id: string;\n title: string;\n duration: number;\n mediaFiles: VastMediaFile[];\n trackingUrls: VastTrackingUrls;\n clickThrough?: string | undefined;\n}\n\nexport type MediaFileFilter = \"hls-only\" | \"mp4-first\" | \"all\";\n\nfunction isHlsType(type: string): boolean {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\n\nfunction isMp4Type(type: string): boolean {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\n\nexport function parseVastXml(\n xmlString: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): VastAd | null {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n\n const isNoAdAvailable =\n adId === \"empty\" ||\n title.toLowerCase().includes(\"no ad available\") ||\n title.toLowerCase() === \"no ad available\";\n\n const durationText =\n xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration =\n parseInt(durationParts[0] || \"0\", 10) * 3600 +\n parseInt(durationParts[1] || \"0\", 10) * 60 +\n Math.round(parseFloat(durationParts[2] || \"0\"));\n\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles: VastMediaFile[] = [];\n\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : undefined;\n\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : undefined,\n });\n\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n\n const trackingUrls: VastTrackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: [],\n };\n\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event as keyof VastTrackingUrls;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n\n const clickThrough = xmlDoc\n .querySelector(\"ClickThrough\")\n ?.textContent?.trim();\n\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough,\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\n\nexport async function fetchAndParseVastAd(\n vastTagUrl: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): Promise<VastAd | null> {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\",\n },\n referrerPolicy: \"no-referrer-when-downgrade\",\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2000)\n );\n\n return parseVastXml(vastXml, filter, logPrefix);\n}\n\nexport function createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n}\n\nasync function firePixelWithRetry(\n url: string,\n retries = 2,\n delayMs = 500,\n logPrefix = \"[VastParser]\"\n): Promise<void> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n await fetch(url, {\n method: \"GET\",\n mode: \"no-cors\",\n cache: \"no-cache\",\n keepalive: true,\n });\n return;\n } catch {\n if (attempt < retries) {\n await new Promise((r) => setTimeout(r, delayMs * Math.pow(2, attempt)));\n } else {\n console.warn(`${logPrefix} Tracking pixel failed after ${retries + 1} attempts: ${url}`);\n }\n }\n }\n}\n\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: string,\n logPrefix = \"[VastParser]\"\n): void {\n if (!urls || urls.length === 0) return;\n\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n\n if (sessionId) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }session_id=${sessionId}`;\n }\n\n if (typeof fetch !== \"undefined\") {\n firePixelWithRetry(trackingUrl, 2, 500, logPrefix).catch(() => {});\n } else {\n const img = new Image(1, 1);\n img.onerror = () => {};\n img.src = trackingUrl;\n }\n\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/sdk/vastManager.cjs","../../src/sdk/vastParser.ts","../../src/sdk/vastManager.ts"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","__hasOwnProp","__export","from","getOwnPropertyNames","target","all","name","get","enumerable","__copyProps","to","except","desc","key","call","value","exports","__toCommonJS","isMp4Type","type","xmlDoc","isNoAdAvailable","adId","title","toLowerCase","includes","mod","vastManager_exports","createVastManager","isHlsType","parseVastXml","xmlString","filter","logPrefix","parser","DOMParser","parseFromString","parserError","querySelector","console","error","textContent","adElement","warn","getAttribute","durationText","durationParts","split","duration","parseInt","Math","round","parseFloat","mediaFileElements","querySelectorAll","mediaFiles","log","length","mf","index","url","width","substring","height","isHls","isMp4","accepted","trim","bitrateAttr","bitrateValue","push","bitrate","sort","a","b","aIsMp4","bIsMp4"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/sdk/vastManager.ts\nvar vastManager_exports = {};\n__export(vastManager_exports, {\n createVastManager: () => createVastManager\n});\nmodule.exports = __toCommonJS(vastManager_exports);\n\n// src/sdk/vastParser.ts\nfunction isHlsType(type) {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\nfunction isMp4Type(type) {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\nfunction parseVastXml(xmlString, filter = \"all\", logPrefix = \"[VastParser]\") {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n const isNoAdAvailable = adId === \"empty\" || title.toLowerCase().includes(\"no ad available\") || title.toLowerCase() === \"no ad available\";\n const durationText = xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration = parseInt(durationParts[0] || \"0\", 10) * 3600 + parseInt(durationParts[1] || \"0\", 10) * 60 + Math.round(parseFloat(durationParts[2] || \"0\"));\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles = [];\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0\n });\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n const trackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: []\n };\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n const clickThrough = xmlDoc.querySelector(\"ClickThrough\")?.textContent?.trim();\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\n\n// src/sdk/vastManager.ts\nvar VAST_TAG_URL_FALLBACK = \"https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click\";\nvar ADSTORM_API_URL = \"https://adstorm.co/api-adstorm-dev/adstorm/ads/web\";\nvar DEFAULT_TIMEOUT_MS = 5e3;\nvar MAX_RETRIES = 3;\nvar RETRY_BACKOFF_MS = 1500;\nfunction createVastManager(options = {}) {\n let initialized = false;\n let vastTagUrl = VAST_TAG_URL_FALLBACK;\n const debug = options.debug ?? false;\n function log(...args) {\n if (debug) {\n console.log(\"[VastManager]\", ...args);\n }\n }\n function warn(...args) {\n console.warn(\"[VastManager]\", ...args);\n }\n async function fetchVastUrlFromApi() {\n const apiUrl = options.adstormApiUrl || ADSTORM_API_URL;\n try {\n const res = await fetch(apiUrl, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${options.licenseKey}`,\n Accept: \"application/json\"\n }\n });\n if (!res.ok) {\n warn(`Failed to fetch VAST URL from API (HTTP ${res.status}), using fallback`);\n return;\n }\n const data = await res.json();\n const payload = data?.response?.ima?.[\"publisherdesk.ima\"]?.payload;\n if (payload) {\n vastTagUrl = payload;\n log(\"VAST tag URL fetched from API:\", vastTagUrl.split(\"?\")[0]);\n } else {\n log(\"API response had no VAST payload, using fallback URL\");\n }\n } catch (err) {\n warn(\"Error fetching VAST URL from API, using fallback:\", err);\n }\n }\n async function initialize() {\n if (initialized) return;\n initialized = true;\n if (options.licenseKey) {\n await fetchVastUrlFromApi();\n }\n log(\"Initialized, VAST tag URL:\", vastTagUrl.split(\"?\")[0]);\n }\n async function requestBids(_context) {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n const correlator = Math.floor(Math.random() * 1e12).toString();\n const url = vastTagUrl.replace(\"[placeholder]\", correlator);\n log(\"Fetching VAST tag, correlator:\", correlator);\n const controller = typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), DEFAULT_TIMEOUT_MS);\n try {\n const fetchOptions = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: { Accept: \"application/xml, text/xml, */*\" },\n referrerPolicy: \"no-referrer-when-downgrade\"\n };\n if (controller) fetchOptions.signal = controller.signal;\n const response = await fetch(url, fetchOptions);\n clearTimeout(timeoutId);\n if (!response.ok) {\n throw new Error(`VAST request returned HTTP ${response.status}`);\n }\n const vastXml = await response.text();\n log(\"VAST XML received, length:\", vastXml.length);\n const vastAd = parseVastXml(vastXml, \"mp4-first\", \"[VastManager]\");\n if (!vastAd) {\n log(\"VAST parsed but no usable ad found\");\n return [];\n }\n log(`Ad parsed: id=${vastAd.id}, duration=${vastAd.duration}s, mediaFiles=${vastAd.mediaFiles.length}`);\n const bid = {\n bidder: \"vast-direct\",\n cpm: 0,\n vastXml,\n width: vastAd.mediaFiles[0]?.width ?? 0,\n height: vastAd.mediaFiles[0]?.height ?? 0,\n adId: vastAd.id,\n impId: correlator,\n creativeId: vastAd.id,\n currency: \"USD\",\n durationSec: vastAd.duration\n };\n return [bid];\n } catch (error) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`VAST request timed out after ${DEFAULT_TIMEOUT_MS}ms`);\n return [];\n }\n throw error;\n }\n }\n async function requestBidsUntilResponse(context) {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n let lastError;\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const bids = await requestBids(context);\n if (bids.length > 0) {\n log(`requestBidsUntilResponse: got ${bids.length} ad(s) on attempt ${attempt}`);\n return bids;\n }\n log(`requestBidsUntilResponse: no ads on attempt ${attempt}/${MAX_RETRIES}`);\n } catch (err) {\n lastError = err;\n warn(`requestBidsUntilResponse: attempt ${attempt}/${MAX_RETRIES} failed:`, err);\n }\n if (attempt < MAX_RETRIES) {\n const delay = RETRY_BACKOFF_MS * attempt;\n log(`requestBidsUntilResponse: waiting ${delay}ms before retry`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) throw lastError;\n return [];\n }\n function destroy() {\n initialized = false;\n vastTagUrl = VAST_TAG_URL_FALLBACK;\n log(\"Destroyed\");\n }\n return {\n initialize,\n requestBids,\n requestBidsUntilResponse,\n destroy,\n get isInitialized() {\n return initialized;\n }\n };\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createVastManager\n});\n","export interface VastMediaFile {\n url: string;\n type: string;\n width: number;\n height: number;\n bitrate?: number | undefined;\n}\n\nexport interface VastTrackingUrls {\n impression: string[];\n start: string[];\n firstQuartile: string[];\n midpoint: string[];\n thirdQuartile: string[];\n complete: string[];\n mute: string[];\n unmute: string[];\n pause: string[];\n resume: string[];\n fullscreen: string[];\n exitFullscreen: string[];\n skip: string[];\n error: string[];\n}\n\nexport interface VastAd {\n id: string;\n title: string;\n duration: number;\n mediaFiles: VastMediaFile[];\n trackingUrls: VastTrackingUrls;\n clickThrough?: string | undefined;\n}\n\nexport type MediaFileFilter = \"hls-only\" | \"mp4-first\" | \"all\";\n\nfunction isHlsType(type: string): boolean {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\n\nfunction isMp4Type(type: string): boolean {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\n\nexport function parseVastXml(\n xmlString: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): VastAd | null {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n\n const isNoAdAvailable =\n adId === \"empty\" ||\n title.toLowerCase().includes(\"no ad available\") ||\n title.toLowerCase() === \"no ad available\";\n\n const durationText =\n xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration =\n parseInt(durationParts[0] || \"0\", 10) * 3600 +\n parseInt(durationParts[1] || \"0\", 10) * 60 +\n Math.round(parseFloat(durationParts[2] || \"0\"));\n\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles: VastMediaFile[] = [];\n\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : undefined;\n\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : undefined,\n });\n\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n\n const trackingUrls: VastTrackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: [],\n };\n\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event as keyof VastTrackingUrls;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n\n const clickThrough = xmlDoc\n .querySelector(\"ClickThrough\")\n ?.textContent?.trim();\n\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough,\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\n\nexport async function fetchAndParseVastAd(\n vastTagUrl: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): Promise<VastAd | null> {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\",\n },\n referrerPolicy: \"no-referrer-when-downgrade\",\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2000)\n );\n\n return parseVastXml(vastXml, filter, logPrefix);\n}\n\nexport function createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n}\n\nasync function firePixelWithRetry(\n url: string,\n retries = 2,\n delayMs = 500,\n logPrefix = \"[VastParser]\"\n): Promise<void> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n await fetch(url, {\n method: \"GET\",\n mode: \"no-cors\",\n cache: \"no-cache\",\n keepalive: true,\n });\n return;\n } catch {\n if (attempt < retries) {\n await new Promise((r) => setTimeout(r, delayMs * Math.pow(2, attempt)));\n } else {\n console.warn(`${logPrefix} Tracking pixel failed after ${retries + 1} attempts: ${url}`);\n }\n }\n }\n}\n\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: string,\n logPrefix = \"[VastParser]\"\n): void {\n if (!urls || urls.length === 0) return;\n\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n\n if (sessionId) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }session_id=${sessionId}`;\n }\n\n if (typeof fetch !== \"undefined\") {\n firePixelWithRetry(trackingUrl, 2, 500, logPrefix).catch(() => {});\n } else {\n const img = new Image(1, 1);\n img.onerror = () => {};\n img.src = trackingUrl;\n }\n\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n","import { parseVastXml } from \"./vastParser\";\nimport type { VastBidResponse, VastManager, AdBreakContext, StormcloudApiResponse } from \"../types\";\n\nconst VAST_TAG_URL_FALLBACK =\n \"https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click\";\n\nconst ADSTORM_API_URL = \"https://adstorm.co/api-adstorm-dev/adstorm/ads/web\";\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst MAX_RETRIES = 3;\nconst RETRY_BACKOFF_MS = 1500;\n\nexport interface VastManagerOptions {\n debug?: boolean;\n licenseKey?: string;\n adstormApiUrl?: string;\n}\n\nexport function createVastManager(\n options: VastManagerOptions = {}\n): VastManager {\n let initialized = false;\n let vastTagUrl = VAST_TAG_URL_FALLBACK;\n const debug = options.debug ?? false;\n\n function log(...args: any[]): void {\n if (debug) {\n console.log(\"[VastManager]\", ...args);\n }\n }\n\n function warn(...args: any[]): void {\n console.warn(\"[VastManager]\", ...args);\n }\n\n async function fetchVastUrlFromApi(): Promise<void> {\n const apiUrl = options.adstormApiUrl || ADSTORM_API_URL;\n try {\n const res = await fetch(apiUrl, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${options.licenseKey}`,\n Accept: \"application/json\",\n },\n });\n if (!res.ok) {\n warn(`Failed to fetch VAST URL from API (HTTP ${res.status}), using fallback`);\n return;\n }\n const data: StormcloudApiResponse = await res.json();\n const payload = data?.response?.ima?.[\"publisherdesk.ima\"]?.payload;\n if (payload) {\n vastTagUrl = payload;\n log(\"VAST tag URL fetched from API:\", vastTagUrl.split(\"?\")[0]);\n } else {\n log(\"API response had no VAST payload, using fallback URL\");\n }\n } catch (err) {\n warn(\"Error fetching VAST URL from API, using fallback:\", err);\n }\n }\n\n async function initialize(): Promise<void> {\n if (initialized) return;\n initialized = true;\n if (options.licenseKey) {\n await fetchVastUrlFromApi();\n }\n log(\"Initialized, VAST tag URL:\", vastTagUrl.split(\"?\")[0]);\n }\n\n async function requestBids(_context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n\n const correlator = Math.floor(Math.random() * 1e12).toString();\n const url = vastTagUrl.replace(\"[placeholder]\", correlator);\n\n log(\"Fetching VAST tag, correlator:\", correlator);\n\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), DEFAULT_TIMEOUT_MS);\n\n try {\n const fetchOptions: RequestInit = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: { Accept: \"application/xml, text/xml, */*\" },\n referrerPolicy: \"no-referrer-when-downgrade\",\n };\n if (controller) fetchOptions.signal = controller.signal;\n\n const response = await fetch(url, fetchOptions);\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(`VAST request returned HTTP ${response.status}`);\n }\n\n const vastXml = await response.text();\n log(\"VAST XML received, length:\", vastXml.length);\n\n const vastAd = parseVastXml(vastXml, \"mp4-first\", \"[VastManager]\");\n if (!vastAd) {\n log(\"VAST parsed but no usable ad found\");\n return [];\n }\n\n log(`Ad parsed: id=${vastAd.id}, duration=${vastAd.duration}s, mediaFiles=${vastAd.mediaFiles.length}`);\n\n const bid: VastBidResponse = {\n bidder: \"vast-direct\",\n cpm: 0,\n vastXml,\n width: vastAd.mediaFiles[0]?.width ?? 0,\n height: vastAd.mediaFiles[0]?.height ?? 0,\n adId: vastAd.id,\n impId: correlator,\n creativeId: vastAd.id,\n currency: \"USD\",\n durationSec: vastAd.duration,\n };\n\n return [bid];\n } catch (error: any) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`VAST request timed out after ${DEFAULT_TIMEOUT_MS}ms`);\n return [];\n }\n throw error;\n }\n }\n\n async function requestBidsUntilResponse(context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n let lastError: unknown;\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const bids = await requestBids(context);\n if (bids.length > 0) {\n log(`requestBidsUntilResponse: got ${bids.length} ad(s) on attempt ${attempt}`);\n return bids;\n }\n log(`requestBidsUntilResponse: no ads on attempt ${attempt}/${MAX_RETRIES}`);\n } catch (err) {\n lastError = err;\n warn(`requestBidsUntilResponse: attempt ${attempt}/${MAX_RETRIES} failed:`, err);\n }\n if (attempt < MAX_RETRIES) {\n const delay = RETRY_BACKOFF_MS * attempt;\n log(`requestBidsUntilResponse: waiting ${delay}ms before retry`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) throw lastError;\n return [];\n }\n\n function destroy(): void {\n initialized = false;\n vastTagUrl = VAST_TAG_URL_FALLBACK;\n log(\"Destroyed\");\n }\n\n return {\n initialize,\n requestBids,\n requestBidsUntilResponse,\n destroy,\n get isInitialized() {\n return initialized;\n },\n };\n}\n"]}
|
|
@@ -687,7 +687,8 @@ function fireTrackingPixels(urls, sessionId) {
|
|
|
687
687
|
});
|
|
688
688
|
}
|
|
689
689
|
// src/sdk/vastManager.ts
|
|
690
|
-
var
|
|
690
|
+
var VAST_TAG_URL_FALLBACK = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click";
|
|
691
|
+
var ADSTORM_API_URL = "https://adstorm.co/api-adstorm-dev/adstorm/ads/web";
|
|
691
692
|
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
692
693
|
var MAX_RETRIES = 3;
|
|
693
694
|
var RETRY_BACKOFF_MS = 1500;
|
|
@@ -695,6 +696,7 @@ function createVastManager() {
|
|
|
695
696
|
var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
696
697
|
var _options_debug;
|
|
697
698
|
var initialized = false;
|
|
699
|
+
var vastTagUrl = VAST_TAG_URL_FALLBACK;
|
|
698
700
|
var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
|
|
699
701
|
function log() {
|
|
700
702
|
for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
|
|
@@ -716,17 +718,97 @@ function createVastManager() {
|
|
|
716
718
|
"[VastManager]"
|
|
717
719
|
].concat(_to_consumable_array(args)));
|
|
718
720
|
}
|
|
721
|
+
function fetchVastUrlFromApi() {
|
|
722
|
+
return _async_to_generator(function() {
|
|
723
|
+
var apiUrl, _data_response_ima_publisherdeskima, _data_response_ima, _data_response, res, data, payload, err;
|
|
724
|
+
return _ts_generator(this, function(_state) {
|
|
725
|
+
switch(_state.label){
|
|
726
|
+
case 0:
|
|
727
|
+
apiUrl = options.adstormApiUrl || ADSTORM_API_URL;
|
|
728
|
+
_state.label = 1;
|
|
729
|
+
case 1:
|
|
730
|
+
_state.trys.push([
|
|
731
|
+
1,
|
|
732
|
+
4,
|
|
733
|
+
,
|
|
734
|
+
5
|
|
735
|
+
]);
|
|
736
|
+
return [
|
|
737
|
+
4,
|
|
738
|
+
fetch(apiUrl, {
|
|
739
|
+
method: "GET",
|
|
740
|
+
headers: {
|
|
741
|
+
Authorization: "Bearer ".concat(options.licenseKey),
|
|
742
|
+
Accept: "application/json"
|
|
743
|
+
}
|
|
744
|
+
})
|
|
745
|
+
];
|
|
746
|
+
case 2:
|
|
747
|
+
res = _state.sent();
|
|
748
|
+
if (!res.ok) {
|
|
749
|
+
warn("Failed to fetch VAST URL from API (HTTP ".concat(res.status, "), using fallback"));
|
|
750
|
+
return [
|
|
751
|
+
2
|
|
752
|
+
];
|
|
753
|
+
}
|
|
754
|
+
return [
|
|
755
|
+
4,
|
|
756
|
+
res.json()
|
|
757
|
+
];
|
|
758
|
+
case 3:
|
|
759
|
+
data = _state.sent();
|
|
760
|
+
payload = data === null || data === void 0 ? void 0 : (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
|
|
761
|
+
if (payload) {
|
|
762
|
+
vastTagUrl = payload;
|
|
763
|
+
log("VAST tag URL fetched from API:", vastTagUrl.split("?")[0]);
|
|
764
|
+
} else {
|
|
765
|
+
log("API response had no VAST payload, using fallback URL");
|
|
766
|
+
}
|
|
767
|
+
return [
|
|
768
|
+
3,
|
|
769
|
+
5
|
|
770
|
+
];
|
|
771
|
+
case 4:
|
|
772
|
+
err = _state.sent();
|
|
773
|
+
warn("Error fetching VAST URL from API, using fallback:", err);
|
|
774
|
+
return [
|
|
775
|
+
3,
|
|
776
|
+
5
|
|
777
|
+
];
|
|
778
|
+
case 5:
|
|
779
|
+
return [
|
|
780
|
+
2
|
|
781
|
+
];
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
})();
|
|
785
|
+
}
|
|
719
786
|
function initialize() {
|
|
720
787
|
return _async_to_generator(function() {
|
|
721
788
|
return _ts_generator(this, function(_state) {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
789
|
+
switch(_state.label){
|
|
790
|
+
case 0:
|
|
791
|
+
if (initialized) return [
|
|
792
|
+
2
|
|
793
|
+
];
|
|
794
|
+
initialized = true;
|
|
795
|
+
if (!options.licenseKey) return [
|
|
796
|
+
3,
|
|
797
|
+
2
|
|
798
|
+
];
|
|
799
|
+
return [
|
|
800
|
+
4,
|
|
801
|
+
fetchVastUrlFromApi()
|
|
802
|
+
];
|
|
803
|
+
case 1:
|
|
804
|
+
_state.sent();
|
|
805
|
+
_state.label = 2;
|
|
806
|
+
case 2:
|
|
807
|
+
log("Initialized, VAST tag URL:", vastTagUrl.split("?")[0]);
|
|
808
|
+
return [
|
|
809
|
+
2
|
|
810
|
+
];
|
|
811
|
+
}
|
|
730
812
|
});
|
|
731
813
|
})();
|
|
732
814
|
}
|
|
@@ -740,7 +822,7 @@ function createVastManager() {
|
|
|
740
822
|
throw new Error("VastManager not initialized. Call initialize() first.");
|
|
741
823
|
}
|
|
742
824
|
correlator = Math.floor(Math.random() * 1e12).toString();
|
|
743
|
-
url =
|
|
825
|
+
url = vastTagUrl.replace("[placeholder]", correlator);
|
|
744
826
|
log("Fetching VAST tag, correlator:", correlator);
|
|
745
827
|
controller = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
746
828
|
timeoutId = setTimeout(function() {
|
|
@@ -934,6 +1016,7 @@ function createVastManager() {
|
|
|
934
1016
|
}
|
|
935
1017
|
function destroy() {
|
|
936
1018
|
initialized = false;
|
|
1019
|
+
vastTagUrl = VAST_TAG_URL_FALLBACK;
|
|
937
1020
|
log("Destroyed");
|
|
938
1021
|
}
|
|
939
1022
|
return {
|
|
@@ -975,6 +1058,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
975
1058
|
var adHls;
|
|
976
1059
|
var adContainerEl;
|
|
977
1060
|
var currentAd;
|
|
1061
|
+
var currentMediaFile;
|
|
978
1062
|
var sessionId;
|
|
979
1063
|
var destroyed = false;
|
|
980
1064
|
var tornDown = false;
|
|
@@ -1221,7 +1305,12 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1221
1305
|
adContainerEl.style.display = "none";
|
|
1222
1306
|
adContainerEl.style.pointerEvents = "none";
|
|
1223
1307
|
}
|
|
1224
|
-
emit("ad_impression"
|
|
1308
|
+
emit("ad_impression", {
|
|
1309
|
+
adId: currentAd === null || currentAd === void 0 ? void 0 : currentAd.id,
|
|
1310
|
+
adTitle: currentAd === null || currentAd === void 0 ? void 0 : currentAd.title,
|
|
1311
|
+
adUrl: currentMediaFile === null || currentMediaFile === void 0 ? void 0 : currentMediaFile.url,
|
|
1312
|
+
mediaType: currentMediaFile === null || currentMediaFile === void 0 ? void 0 : currentMediaFile.type
|
|
1313
|
+
});
|
|
1225
1314
|
emit("content_resume");
|
|
1226
1315
|
}
|
|
1227
1316
|
function handleAdError() {
|
|
@@ -1243,6 +1332,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1243
1332
|
adHls.destroy();
|
|
1244
1333
|
adHls = void 0;
|
|
1245
1334
|
}
|
|
1335
|
+
currentMediaFile = void 0;
|
|
1246
1336
|
if (adVideoElement) {
|
|
1247
1337
|
if (singleElementMode && adVideoElement === contentVideo) {
|
|
1248
1338
|
contentVideo.pause();
|
|
@@ -1407,6 +1497,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1407
1497
|
adVideoElement.volume = Math.max(0, Math.min(1, adVolume2));
|
|
1408
1498
|
adVideoElement.muted = false;
|
|
1409
1499
|
mediaFile2 = selectBestMediaFile(ad.mediaFiles);
|
|
1500
|
+
currentMediaFile = mediaFile2;
|
|
1410
1501
|
if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile2.url));
|
|
1411
1502
|
startPlayback(mediaFile2);
|
|
1412
1503
|
return [
|
|
@@ -1453,6 +1544,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1453
1544
|
}
|
|
1454
1545
|
emit("content_pause");
|
|
1455
1546
|
mediaFile = selectBestMediaFile(ad.mediaFiles);
|
|
1547
|
+
currentMediaFile = mediaFile;
|
|
1456
1548
|
if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile.url));
|
|
1457
1549
|
startPlayback(mediaFile);
|
|
1458
1550
|
return [
|
|
@@ -1618,6 +1710,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1618
1710
|
];
|
|
1619
1711
|
mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
|
|
1620
1712
|
teardownCurrentPlayback();
|
|
1713
|
+
currentMediaFile = slot.mediaFile;
|
|
1621
1714
|
adVideoElement = contentVideo;
|
|
1622
1715
|
adHls = void 0;
|
|
1623
1716
|
adPlaying = true;
|
|
@@ -1652,6 +1745,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1652
1745
|
case 2:
|
|
1653
1746
|
if (smartTVMode && !slot.videoEl) {
|
|
1654
1747
|
teardownCurrentPlayback();
|
|
1748
|
+
currentMediaFile = slot.mediaFile;
|
|
1655
1749
|
if (adVideoElement) {
|
|
1656
1750
|
adVideoElement.remove();
|
|
1657
1751
|
adVideoElement = void 0;
|
|
@@ -1683,6 +1777,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1683
1777
|
];
|
|
1684
1778
|
}
|
|
1685
1779
|
teardownCurrentPlayback();
|
|
1780
|
+
currentMediaFile = slot.mediaFile;
|
|
1686
1781
|
if (adVideoElement && adVideoElement !== slot.videoEl) {
|
|
1687
1782
|
adVideoElement.remove();
|
|
1688
1783
|
}
|
|
@@ -1814,6 +1909,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1814
1909
|
}
|
|
1815
1910
|
}
|
|
1816
1911
|
currentAd = void 0;
|
|
1912
|
+
currentMediaFile = void 0;
|
|
1817
1913
|
tornDown = false;
|
|
1818
1914
|
return [
|
|
1819
1915
|
2
|
|
@@ -1866,6 +1962,7 @@ function createVastAdLayer(contentVideo, options) {
|
|
|
1866
1962
|
}
|
|
1867
1963
|
adContainerEl = void 0;
|
|
1868
1964
|
currentAd = void 0;
|
|
1965
|
+
currentMediaFile = void 0;
|
|
1869
1966
|
listeners.clear();
|
|
1870
1967
|
},
|
|
1871
1968
|
isAdPlaying: function isAdPlaying() {
|
|
@@ -3107,9 +3204,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
3107
3204
|
this.video = config.videoElement;
|
|
3108
3205
|
this.adTransitionGapMs = (_this_config_adTransitionGapMs = this.config.adTransitionGapMs) !== null && _this_config_adTransitionGapMs !== void 0 ? _this_config_adTransitionGapMs : 100;
|
|
3109
3206
|
logBrowserInfo(config.debugAdTiming);
|
|
3110
|
-
this.vastManager = createVastManager(
|
|
3111
|
-
debug: !!config.debugAdTiming
|
|
3112
|
-
}
|
|
3207
|
+
this.vastManager = createVastManager(_object_spread({
|
|
3208
|
+
debug: config.debugAdTiming !== void 0 ? !!config.debugAdTiming : false
|
|
3209
|
+
}, config.licenseKey ? {
|
|
3210
|
+
licenseKey: config.licenseKey
|
|
3211
|
+
} : {}));
|
|
3113
3212
|
var browserForAdLayer = detectBrowser();
|
|
3114
3213
|
var isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;
|
|
3115
3214
|
this.adLayer = createVastAdLayer(this.video, {
|
|
@@ -3160,6 +3259,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
3160
3259
|
this.attach();
|
|
3161
3260
|
}
|
|
3162
3261
|
this.initializeTracking();
|
|
3262
|
+
if (!this.config.disableAds) {
|
|
3263
|
+
this.vastManager.initialize().catch(function() {});
|
|
3264
|
+
}
|
|
3163
3265
|
if (!this.shouldUseNativeHls()) return [
|
|
3164
3266
|
3,
|
|
3165
3267
|
3
|
|
@@ -3613,13 +3715,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
3613
3715
|
key: "attachAdLayerEventListeners",
|
|
3614
3716
|
value: function attachAdLayerEventListeners() {
|
|
3615
3717
|
var _this = this;
|
|
3616
|
-
this.adLayer.on("ad_impression", function() {
|
|
3718
|
+
this.adLayer.on("ad_impression", function(payload) {
|
|
3617
3719
|
if (_this.config.licenseKey) {
|
|
3720
|
+
var _ref;
|
|
3721
|
+
var adUrl = (_ref = payload === null || payload === void 0 ? void 0 : payload.adUrl) !== null && _ref !== void 0 ? _ref : _this.lastServedAdUrl;
|
|
3722
|
+
if (adUrl) {
|
|
3723
|
+
_this.lastServedAdUrl = adUrl;
|
|
3724
|
+
}
|
|
3618
3725
|
sendAdImpressionTracking(_this.config.licenseKey, _object_spread_props(_object_spread({
|
|
3619
3726
|
source: _this.getAdSource(),
|
|
3620
3727
|
adIndex: _this.currentAdIndex
|
|
3621
|
-
},
|
|
3622
|
-
adUrl:
|
|
3728
|
+
}, adUrl ? {
|
|
3729
|
+
adUrl: adUrl
|
|
3623
3730
|
} : {}), {
|
|
3624
3731
|
timestamp: /* @__PURE__ */ new Date().toISOString()
|
|
3625
3732
|
}), _this.getAnalyticsContext());
|