stormcloud-video-player 0.5.7 → 0.5.8

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/sdk/vastParser.cjs","../../src/sdk/vastParser.ts"],"names":["key","__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","enumerable","get","__copyProps","to","from","except","desc","call","__toCommonJS","mod","value","vastParser_exports","createEmptyTrackingState","fetchAndParseVastAd","fireTrackingPixels","parseVastXml","module","exports","isHlsType","type","includes","isMp4Type","xmlString","filter","logPrefix","xmlDoc","parser","DOMParser","parseFromString","parserError","querySelector","console","error","textContent","adElement","warn"],"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/vastParser.ts\nvar vastParser_exports = {};\n__export(vastParser_exports, {\n createEmptyTrackingState: () => createEmptyTrackingState,\n fetchAndParseVastAd: () => fetchAndParseVastAd,\n fireTrackingPixels: () => fireTrackingPixels,\n parseVastXml: () => parseVastXml\n});\nmodule.exports = __toCommonJS(vastParser_exports);\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}\nasync function fetchAndParseVastAd(vastTagUrl, filter = \"all\", logPrefix = \"[VastParser]\") {\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 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, 2e3)\n );\n return parseVastXml(vastXml, filter, logPrefix);\n}\nfunction createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n}\nfunction fireTrackingPixels(urls, sessionId, licenseKey, logPrefix = \"[VastParser]\") {\n if (!urls || urls.length === 0) return;\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n if (sessionId) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}session_id=${sessionId}`;\n }\n if (licenseKey) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}license_key=${licenseKey}`;\n }\n const img = new Image(1, 1);\n img.src = trackingUrl;\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createEmptyTrackingState,\n fetchAndParseVastAd,\n fireTrackingPixels,\n parseVastXml\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\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: string,\n licenseKey?: 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 (licenseKey) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }license_key=${licenseKey}`;\n }\n\n const img = new Image(1, 1);\n img.src = trackingUrl;\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/vastParser.cjs","../../src/sdk/vastParser.ts"],"names":["key","__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","enumerable","get","__copyProps","to","from","except","desc","call","__toCommonJS","mod","value","vastParser_exports","createEmptyTrackingState","fetchAndParseVastAd","fireTrackingPixels","parseVastXml","module","exports","isHlsType","type","includes","isMp4Type","xmlString","filter","logPrefix","xmlDoc","parser","DOMParser","parseFromString","parserError","querySelector","console","error","textContent","adElement","warn"],"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/vastParser.ts\nvar vastParser_exports = {};\n__export(vastParser_exports, {\n createEmptyTrackingState: () => createEmptyTrackingState,\n fetchAndParseVastAd: () => fetchAndParseVastAd,\n fireTrackingPixels: () => fireTrackingPixels,\n parseVastXml: () => parseVastXml\n});\nmodule.exports = __toCommonJS(vastParser_exports);\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}\nasync function fetchAndParseVastAd(vastTagUrl, filter = \"all\", logPrefix = \"[VastParser]\") {\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 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, 2e3)\n );\n return parseVastXml(vastXml, filter, logPrefix);\n}\nfunction createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n}\nfunction fireTrackingPixels(urls, sessionId, logPrefix = \"[VastParser]\") {\n if (!urls || urls.length === 0) return;\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n if (sessionId) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}session_id=${sessionId}`;\n }\n const img = new Image(1, 1);\n img.onerror = () => {\n };\n img.src = trackingUrl;\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createEmptyTrackingState,\n fetchAndParseVastAd,\n fireTrackingPixels,\n parseVastXml\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\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 const img = new Image(1, 1);\n img.onerror = () => {\n // 502 or other network errors are fire-and-forget; do not affect playback\n };\n img.src = trackingUrl;\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n"]}
@@ -40,6 +40,6 @@ declare function createEmptyTrackingState(): {
40
40
  thirdQuartile: boolean;
41
41
  complete: boolean;
42
42
  };
43
- declare function fireTrackingPixels(urls: string[], sessionId?: string, licenseKey?: string, logPrefix?: string): void;
43
+ declare function fireTrackingPixels(urls: string[], sessionId?: string, logPrefix?: string): void;
44
44
 
45
45
  export { type MediaFileFilter, type VastAd, type VastMediaFile, type VastTrackingUrls, createEmptyTrackingState, fetchAndParseVastAd, fireTrackingPixels, parseVastXml };
@@ -564,8 +564,8 @@ function createEmptyTrackingState() {
564
564
  complete: false
565
565
  };
566
566
  }
567
- function fireTrackingPixels(urls, sessionId, licenseKey) {
568
- var logPrefix = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : "[VastParser]";
567
+ function fireTrackingPixels(urls, sessionId) {
568
+ var logPrefix = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "[VastParser]";
569
569
  if (!urls || urls.length === 0) return;
570
570
  urls.forEach(function(url) {
571
571
  try {
@@ -573,10 +573,8 @@ function fireTrackingPixels(urls, sessionId, licenseKey) {
573
573
  if (sessionId) {
574
574
  trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "session_id=").concat(sessionId);
575
575
  }
576
- if (licenseKey) {
577
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "license_key=").concat(licenseKey);
578
- }
579
576
  var img = new Image(1, 1);
577
+ img.onerror = function() {};
580
578
  img.src = trackingUrl;
581
579
  console.log("".concat(logPrefix, " Fired tracking pixel: ").concat(trackingUrl));
582
580
  } catch (error) {
@@ -977,7 +975,7 @@ function createPrebidController(contentVideo, options) {
977
975
  return "session-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
978
976
  }
979
977
  function fireTrackingPixels2(urls) {
980
- fireTrackingPixels(urls, sessionId, licenseKey, LOG);
978
+ fireTrackingPixels(urls, sessionId, LOG);
981
979
  }
982
980
  function getMainStreamQuality() {
983
981
  if (!mainHlsInstance || !mainHlsInstance.levels) {
@@ -2714,6 +2712,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2714
2712
  this.totalAdRequestsInBreak = 0;
2715
2713
  this.maxTotalAdRequestsPerBreak = 20;
2716
2714
  this.pendingAdBreak = null;
2715
+ this.prefetchAdPromise = null;
2716
+ this.savedMutedStateBeforeScte = null;
2717
2717
  this.consecutiveFailures = 0;
2718
2718
  this.maxConsecutiveFailures = 5;
2719
2719
  this.lastAdRequestTime = 0;
@@ -3189,6 +3189,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3189
3189
  }
3190
3190
  }
3191
3191
  console.error("[AD-ERROR]", errorMessage, errorPayload || "");
3192
+ _this.adController.stop().catch(function() {});
3192
3193
  _this.handleAdFailure();
3193
3194
  });
3194
3195
  this.adController.on("content_pause", function() {
@@ -3251,6 +3252,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3251
3252
  {
3252
3253
  key: "recreateAdController",
3253
3254
  value: function recreateAdController() {
3255
+ this.prefetchAdPromise = null;
3254
3256
  var shouldShowPlaceholder = this.inAdBreak && this.showAds;
3255
3257
  if (shouldShowPlaceholder && this.adController) {
3256
3258
  this.showPlaceholderLayer();
@@ -3579,6 +3581,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3579
3581
  if (marker.type === "start") {
3580
3582
  var _this_config_immediateManifestAds;
3581
3583
  var _this_pendingAdBreak;
3584
+ this.savedMutedStateBeforeScte = {
3585
+ muted: this.video.muted,
3586
+ volume: this.video.volume
3587
+ };
3588
+ this.adController.updateOriginalMutedState(this.video.muted, this.video.volume);
3582
3589
  if (!this.video.muted) {
3583
3590
  this.video.muted = true;
3584
3591
  this.video.volume = 0;
@@ -4020,6 +4027,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4020
4027
  {
4021
4028
  key: "startAdPrefetch",
4022
4029
  value: function startAdPrefetch(marker, fragmentSn) {
4030
+ var _this = this;
4023
4031
  if (this.pendingAdBreak || this.inAdBreak) {
4024
4032
  return;
4025
4033
  }
@@ -4031,8 +4039,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4031
4039
  isFetching: false,
4032
4040
  fetchStartTime: Date.now()
4033
4041
  });
4042
+ this.prefetchAdPromise = this.adController.requestAds().catch(function() {
4043
+ if (_this.config.debugAdTiming) {
4044
+ console.log("[PREFETCH] Prebid auction prefetch failed, will request at playback time");
4045
+ }
4046
+ });
4034
4047
  if (this.config.debugAdTiming) {
4035
- console.log("[PREFETCH] Ad break marker registered, auction runs at playback time via controller");
4048
+ console.log("[PREFETCH] Ad break marker registered, auction prefetch started");
4036
4049
  }
4037
4050
  }
4038
4051
  },
@@ -4043,6 +4056,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4043
4056
  clearTimeout(this.prefetchTimerId);
4044
4057
  this.prefetchTimerId = void 0;
4045
4058
  }
4059
+ this.prefetchAdPromise = null;
4046
4060
  this.pendingAdBreak = null;
4047
4061
  }
4048
4062
  },
@@ -4050,7 +4064,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4050
4064
  key: "handleAdStart",
4051
4065
  value: function handleAdStart(_marker) {
4052
4066
  return _async_to_generator(function() {
4053
- var adBreakDurationMs, mode, currentMuted, currentVolume, adLoadedInfo, adVolume, error;
4067
+ var _this_savedMutedStateBeforeScte, adBreakDurationMs, mode, state, unused, unused1, adLoadedInfo, adVolume, error;
4054
4068
  return _ts_generator(this, function(_state) {
4055
4069
  switch(_state.label){
4056
4070
  case 0:
@@ -4063,9 +4077,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4063
4077
  this.continuousFetchingActive = true;
4064
4078
  this.isShowingPlaceholder = false;
4065
4079
  this.totalAdRequestsInBreak = 0;
4066
- currentMuted = this.video.muted;
4067
- currentVolume = this.video.volume;
4068
- this.adController.updateOriginalMutedState(currentMuted, currentVolume);
4080
+ state = (_this_savedMutedStateBeforeScte = this.savedMutedStateBeforeScte) !== null && _this_savedMutedStateBeforeScte !== void 0 ? _this_savedMutedStateBeforeScte : {
4081
+ muted: this.video.muted,
4082
+ volume: this.video.volume
4083
+ };
4084
+ this.adController.updateOriginalMutedState(state.muted, state.volume);
4085
+ this.savedMutedStateBeforeScte = null;
4069
4086
  if (!this.video.muted) {
4070
4087
  this.video.muted = true;
4071
4088
  this.video.volume = 0;
@@ -4084,25 +4101,94 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4084
4101
  if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
4085
4102
  this.expectedAdBreakDurationMs = adBreakDurationMs;
4086
4103
  }
4087
- this.clearPendingAdBreak();
4088
4104
  if (this.config.debugAdTiming) {
4089
- console.log("[CONTINUOUS-FETCH] \uD83D\uDCCB Prebid auction via requestAds()");
4105
+ console.log("[CONTINUOUS-FETCH] \uD83D\uDCCB Prebid auction (prefetch or requestAds)");
4090
4106
  }
4091
4107
  _state.label = 1;
4092
4108
  case 1:
4093
4109
  _state.trys.push([
4094
4110
  1,
4095
- 4,
4111
+ 6,
4096
4112
  ,
4097
- 6
4113
+ 12
4098
4114
  ]);
4099
4115
  this.lastAdRequestTime = Date.now();
4116
+ if (!this.prefetchAdPromise) return [
4117
+ 3,
4118
+ 3
4119
+ ];
4100
4120
  return [
4101
4121
  4,
4102
- this.adController.requestAds()
4122
+ this.prefetchAdPromise
4103
4123
  ];
4104
4124
  case 2:
4105
4125
  _state.sent();
4126
+ this.prefetchAdPromise = null;
4127
+ return [
4128
+ 3,
4129
+ 5
4130
+ ];
4131
+ case 3:
4132
+ return [
4133
+ 4,
4134
+ this.adController.requestAds()
4135
+ ];
4136
+ case 4:
4137
+ _state.sent();
4138
+ _state.label = 5;
4139
+ case 5:
4140
+ return [
4141
+ 3,
4142
+ 12
4143
+ ];
4144
+ case 6:
4145
+ unused = _state.sent();
4146
+ _state.label = 7;
4147
+ case 7:
4148
+ _state.trys.push([
4149
+ 7,
4150
+ 9,
4151
+ ,
4152
+ 11
4153
+ ]);
4154
+ return [
4155
+ 4,
4156
+ this.adController.requestAds()
4157
+ ];
4158
+ case 8:
4159
+ _state.sent();
4160
+ return [
4161
+ 3,
4162
+ 11
4163
+ ];
4164
+ case 9:
4165
+ unused1 = _state.sent();
4166
+ this.clearPendingAdBreak();
4167
+ this.consecutiveFailures++;
4168
+ return [
4169
+ 4,
4170
+ this.tryNextAvailableAdWithRateLimit()
4171
+ ];
4172
+ case 10:
4173
+ _state.sent();
4174
+ return [
4175
+ 2
4176
+ ];
4177
+ case 11:
4178
+ return [
4179
+ 3,
4180
+ 12
4181
+ ];
4182
+ case 12:
4183
+ this.clearPendingAdBreak();
4184
+ _state.label = 13;
4185
+ case 13:
4186
+ _state.trys.push([
4187
+ 13,
4188
+ 15,
4189
+ ,
4190
+ 17
4191
+ ]);
4106
4192
  if (this.config.licenseKey) {
4107
4193
  adLoadedInfo = {
4108
4194
  source: this.getAdSource(),
@@ -4119,19 +4205,19 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4119
4205
  4,
4120
4206
  this.adController.play()
4121
4207
  ];
4122
- case 3:
4208
+ case 14:
4123
4209
  _state.sent();
4124
4210
  if (this.expectedAdBreakDurationMs != null) {
4125
4211
  this.currentAdBreakStartWallClockMs = Date.now();
4126
4212
  this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4127
4213
  }
4128
- adVolume = currentMuted ? 0 : currentVolume;
4214
+ adVolume = state.muted ? 0 : state.volume;
4129
4215
  this.adController.setAdVolume(adVolume);
4130
4216
  return [
4131
4217
  3,
4132
- 6
4218
+ 17
4133
4219
  ];
4134
- case 4:
4220
+ case 15:
4135
4221
  error = _state.sent();
4136
4222
  if (this.config.debugAdTiming) {
4137
4223
  console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F First ad request failed:", error);
@@ -4141,13 +4227,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4141
4227
  4,
4142
4228
  this.tryNextAvailableAdWithRateLimit()
4143
4229
  ];
4144
- case 5:
4230
+ case 16:
4145
4231
  _state.sent();
4146
4232
  return [
4147
4233
  3,
4148
- 6
4234
+ 17
4149
4235
  ];
4150
- case 6:
4236
+ case 17:
4151
4237
  return [
4152
4238
  2
4153
4239
  ];