stormcloud-video-player 0.5.7 → 0.5.9

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() {
@@ -3231,6 +3232,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3231
3232
  _this.activeAdRequestToken = null;
3232
3233
  _this.showAds = false;
3233
3234
  if (!_this.inAdBreak) {
3235
+ if (_this.config.debugAdTiming) {
3236
+ console.log("[StormcloudVideoPlayer] content_resume: break already ended (e.g. by CUE-IN or handleAdPodComplete), skipping next-ad path");
3237
+ }
3234
3238
  return;
3235
3239
  }
3236
3240
  _this.consecutiveFailures = 0;
@@ -3243,6 +3247,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3243
3247
  if (remaining > 500) {
3244
3248
  _this.tryNextAvailableAdWithRateLimit();
3245
3249
  } else {
3250
+ if (_this.config.debugAdTiming) {
3251
+ console.log("[StormcloudVideoPlayer] content_resume: remaining time too low to try next ad, ending ad pod");
3252
+ }
3246
3253
  _this.handleAdPodComplete();
3247
3254
  }
3248
3255
  });
@@ -3251,6 +3258,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3251
3258
  {
3252
3259
  key: "recreateAdController",
3253
3260
  value: function recreateAdController() {
3261
+ this.prefetchAdPromise = null;
3254
3262
  var shouldShowPlaceholder = this.inAdBreak && this.showAds;
3255
3263
  if (shouldShowPlaceholder && this.adController) {
3256
3264
  this.showPlaceholderLayer();
@@ -3579,6 +3587,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3579
3587
  if (marker.type === "start") {
3580
3588
  var _this_config_immediateManifestAds;
3581
3589
  var _this_pendingAdBreak;
3590
+ this.savedMutedStateBeforeScte = {
3591
+ muted: this.video.muted,
3592
+ volume: this.video.volume
3593
+ };
3594
+ this.adController.updateOriginalMutedState(this.video.muted, this.video.volume);
3582
3595
  if (!this.video.muted) {
3583
3596
  this.video.muted = true;
3584
3597
  this.video.volume = 0;
@@ -3701,9 +3714,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3701
3714
  activeAdRequest: this.activeAdRequestToken !== null
3702
3715
  });
3703
3716
  }
3704
- if (adPlaying || remaining > 1e3 && hasQueuedAds) {
3717
+ if (adPlaying || remaining > 500) {
3705
3718
  if (this.config.debugAdTiming) {
3706
- console.log("[StormcloudVideoPlayer] Ignoring premature SCTE-35 end marker - ads still active");
3719
+ console.log("[StormcloudVideoPlayer] Ignoring premature SCTE-35 end marker - ads still active or time remaining");
3707
3720
  }
3708
3721
  return;
3709
3722
  }
@@ -4020,6 +4033,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4020
4033
  {
4021
4034
  key: "startAdPrefetch",
4022
4035
  value: function startAdPrefetch(marker, fragmentSn) {
4036
+ var _this = this;
4023
4037
  if (this.pendingAdBreak || this.inAdBreak) {
4024
4038
  return;
4025
4039
  }
@@ -4031,8 +4045,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4031
4045
  isFetching: false,
4032
4046
  fetchStartTime: Date.now()
4033
4047
  });
4048
+ this.prefetchAdPromise = this.adController.requestAds().catch(function() {
4049
+ if (_this.config.debugAdTiming) {
4050
+ console.log("[PREFETCH] Prebid auction prefetch failed, will request at playback time");
4051
+ }
4052
+ });
4034
4053
  if (this.config.debugAdTiming) {
4035
- console.log("[PREFETCH] Ad break marker registered, auction runs at playback time via controller");
4054
+ console.log("[PREFETCH] Ad break marker registered, auction prefetch started");
4036
4055
  }
4037
4056
  }
4038
4057
  },
@@ -4043,6 +4062,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4043
4062
  clearTimeout(this.prefetchTimerId);
4044
4063
  this.prefetchTimerId = void 0;
4045
4064
  }
4065
+ this.prefetchAdPromise = null;
4046
4066
  this.pendingAdBreak = null;
4047
4067
  }
4048
4068
  },
@@ -4050,7 +4070,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4050
4070
  key: "handleAdStart",
4051
4071
  value: function handleAdStart(_marker) {
4052
4072
  return _async_to_generator(function() {
4053
- var adBreakDurationMs, mode, currentMuted, currentVolume, adLoadedInfo, adVolume, error;
4073
+ var _this_savedMutedStateBeforeScte, adBreakDurationMs, mode, state, unused, unused1, adLoadedInfo, adVolume, error;
4054
4074
  return _ts_generator(this, function(_state) {
4055
4075
  switch(_state.label){
4056
4076
  case 0:
@@ -4063,9 +4083,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4063
4083
  this.continuousFetchingActive = true;
4064
4084
  this.isShowingPlaceholder = false;
4065
4085
  this.totalAdRequestsInBreak = 0;
4066
- currentMuted = this.video.muted;
4067
- currentVolume = this.video.volume;
4068
- this.adController.updateOriginalMutedState(currentMuted, currentVolume);
4086
+ state = (_this_savedMutedStateBeforeScte = this.savedMutedStateBeforeScte) !== null && _this_savedMutedStateBeforeScte !== void 0 ? _this_savedMutedStateBeforeScte : {
4087
+ muted: this.video.muted,
4088
+ volume: this.video.volume
4089
+ };
4090
+ this.adController.updateOriginalMutedState(state.muted, state.volume);
4091
+ this.savedMutedStateBeforeScte = null;
4069
4092
  if (!this.video.muted) {
4070
4093
  this.video.muted = true;
4071
4094
  this.video.volume = 0;
@@ -4084,25 +4107,94 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4084
4107
  if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
4085
4108
  this.expectedAdBreakDurationMs = adBreakDurationMs;
4086
4109
  }
4087
- this.clearPendingAdBreak();
4088
4110
  if (this.config.debugAdTiming) {
4089
- console.log("[CONTINUOUS-FETCH] \uD83D\uDCCB Prebid auction via requestAds()");
4111
+ console.log("[CONTINUOUS-FETCH] \uD83D\uDCCB Prebid auction (prefetch or requestAds)");
4090
4112
  }
4091
4113
  _state.label = 1;
4092
4114
  case 1:
4093
4115
  _state.trys.push([
4094
4116
  1,
4095
- 4,
4117
+ 6,
4096
4118
  ,
4097
- 6
4119
+ 12
4098
4120
  ]);
4099
4121
  this.lastAdRequestTime = Date.now();
4122
+ if (!this.prefetchAdPromise) return [
4123
+ 3,
4124
+ 3
4125
+ ];
4100
4126
  return [
4101
4127
  4,
4102
- this.adController.requestAds()
4128
+ this.prefetchAdPromise
4103
4129
  ];
4104
4130
  case 2:
4105
4131
  _state.sent();
4132
+ this.prefetchAdPromise = null;
4133
+ return [
4134
+ 3,
4135
+ 5
4136
+ ];
4137
+ case 3:
4138
+ return [
4139
+ 4,
4140
+ this.adController.requestAds()
4141
+ ];
4142
+ case 4:
4143
+ _state.sent();
4144
+ _state.label = 5;
4145
+ case 5:
4146
+ return [
4147
+ 3,
4148
+ 12
4149
+ ];
4150
+ case 6:
4151
+ unused = _state.sent();
4152
+ _state.label = 7;
4153
+ case 7:
4154
+ _state.trys.push([
4155
+ 7,
4156
+ 9,
4157
+ ,
4158
+ 11
4159
+ ]);
4160
+ return [
4161
+ 4,
4162
+ this.adController.requestAds()
4163
+ ];
4164
+ case 8:
4165
+ _state.sent();
4166
+ return [
4167
+ 3,
4168
+ 11
4169
+ ];
4170
+ case 9:
4171
+ unused1 = _state.sent();
4172
+ this.clearPendingAdBreak();
4173
+ this.consecutiveFailures++;
4174
+ return [
4175
+ 4,
4176
+ this.tryNextAvailableAdWithRateLimit()
4177
+ ];
4178
+ case 10:
4179
+ _state.sent();
4180
+ return [
4181
+ 2
4182
+ ];
4183
+ case 11:
4184
+ return [
4185
+ 3,
4186
+ 12
4187
+ ];
4188
+ case 12:
4189
+ this.clearPendingAdBreak();
4190
+ _state.label = 13;
4191
+ case 13:
4192
+ _state.trys.push([
4193
+ 13,
4194
+ 15,
4195
+ ,
4196
+ 17
4197
+ ]);
4106
4198
  if (this.config.licenseKey) {
4107
4199
  adLoadedInfo = {
4108
4200
  source: this.getAdSource(),
@@ -4119,19 +4211,19 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4119
4211
  4,
4120
4212
  this.adController.play()
4121
4213
  ];
4122
- case 3:
4214
+ case 14:
4123
4215
  _state.sent();
4124
4216
  if (this.expectedAdBreakDurationMs != null) {
4125
4217
  this.currentAdBreakStartWallClockMs = Date.now();
4126
4218
  this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4127
4219
  }
4128
- adVolume = currentMuted ? 0 : currentVolume;
4220
+ adVolume = state.muted ? 0 : state.volume;
4129
4221
  this.adController.setAdVolume(adVolume);
4130
4222
  return [
4131
4223
  3,
4132
- 6
4224
+ 17
4133
4225
  ];
4134
- case 4:
4226
+ case 15:
4135
4227
  error = _state.sent();
4136
4228
  if (this.config.debugAdTiming) {
4137
4229
  console.warn("[CONTINUOUS-FETCH] \u26A0\uFE0F First ad request failed:", error);
@@ -4141,13 +4233,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4141
4233
  4,
4142
4234
  this.tryNextAvailableAdWithRateLimit()
4143
4235
  ];
4144
- case 5:
4236
+ case 16:
4145
4237
  _state.sent();
4146
4238
  return [
4147
4239
  3,
4148
- 6
4240
+ 17
4149
4241
  ];
4150
- case 6:
4242
+ case 17:
4151
4243
  return [
4152
4244
  2
4153
4245
  ];