@dailymotion/vast-client
Version:
JavaScript VAST Client
387 lines (347 loc) • 13.2 kB
JavaScript
import { createCreativeLinear } from '../creative/creative_linear';
import { createClosedCaptionFile } from '../closed_caption_file';
import { createIcon } from '../icon';
import { createInteractiveCreativeFile } from '../interactive_creative_file';
import { createMediaFile } from '../media_file';
import { createMezzanine } from '../mezzanine';
import { parserUtils } from './parser_utils';
/**
* This module provides methods to parse a VAST Linear Element.
*/
/**
* Parses a Linear element.
* @param {Object} creativeElement - The VAST Linear element to parse.
* @param {any} creativeAttributes - The attributes of the Linear (optional).
* @return {Object} creative - The creativeLinear object.
*/
export function parseCreativeLinear(creativeElement, creativeAttributes) {
let offset;
const creative = createCreativeLinear(creativeAttributes);
creative.duration = parserUtils.parseDuration(
parserUtils.parseNodeText(
parserUtils.childByName(creativeElement, 'Duration')
)
);
const skipOffset = creativeElement.getAttribute('skipoffset');
if (typeof skipOffset === 'undefined' || skipOffset === null) {
creative.skipDelay = null;
} else if (
skipOffset.charAt(skipOffset.length - 1) === '%' &&
creative.duration !== -1
) {
const percent = parseInt(skipOffset, 10);
creative.skipDelay = creative.duration * (percent / 100);
} else {
creative.skipDelay = parserUtils.parseDuration(skipOffset);
}
const videoClicksElement = parserUtils.childByName(
creativeElement,
'VideoClicks'
);
if (videoClicksElement) {
const videoClickThroughElement = parserUtils.childByName(
videoClicksElement,
'ClickThrough'
);
if (videoClickThroughElement) {
creative.videoClickThroughURLTemplate = {
id: videoClickThroughElement.getAttribute('id') || null,
url: parserUtils.parseNodeText(videoClickThroughElement),
};
} else {
creative.videoClickThroughURLTemplate = null;
}
parserUtils
.childrenByName(videoClicksElement, 'ClickTracking')
.forEach((clickTrackingElement) => {
creative.videoClickTrackingURLTemplates.push({
id: clickTrackingElement.getAttribute('id') || null,
url: parserUtils.parseNodeText(clickTrackingElement),
});
});
parserUtils
.childrenByName(videoClicksElement, 'CustomClick')
.forEach((customClickElement) => {
creative.videoCustomClickURLTemplates.push({
id: customClickElement.getAttribute('id') || null,
url: parserUtils.parseNodeText(customClickElement),
});
});
}
const adParamsElement = parserUtils.childByName(
creativeElement,
'AdParameters'
);
if (adParamsElement) {
creative.adParameters = {
value: parserUtils.parseNodeText(adParamsElement),
xmlEncoded: adParamsElement.getAttribute('xmlEncoded') || null,
};
}
parserUtils
.childrenByName(creativeElement, 'TrackingEvents')
.forEach((trackingEventsElement) => {
parserUtils
.childrenByName(trackingEventsElement, 'Tracking')
.forEach((trackingElement) => {
let eventName = trackingElement.getAttribute('event');
const trackingURLTemplate =
parserUtils.parseNodeText(trackingElement);
if (eventName && trackingURLTemplate) {
if (eventName === 'progress') {
offset = trackingElement.getAttribute('offset');
if (!offset) {
return;
}
if (offset.charAt(offset.length - 1) === '%') {
eventName = `progress-${offset}`;
} else {
eventName = `progress-${
parserUtils.parseDuration(offset)
}`;
}
}
if (!Array.isArray(creative.trackingEvents[eventName])) {
creative.trackingEvents[eventName] = [];
}
creative.trackingEvents[eventName].push(trackingURLTemplate);
}
});
});
parserUtils
.childrenByName(creativeElement, 'MediaFiles')
.forEach((mediaFilesElement) => {
parserUtils
.childrenByName(mediaFilesElement, 'MediaFile')
.forEach((mediaFileElement) => {
creative.mediaFiles.push(parseMediaFile(mediaFileElement));
});
const interactiveCreativeElement = parserUtils.childByName(
mediaFilesElement,
'InteractiveCreativeFile'
);
if (interactiveCreativeElement) {
creative.interactiveCreativeFile = parseInteractiveCreativeFile(
interactiveCreativeElement
);
}
const closedCaptionElements = parserUtils.childByName(
mediaFilesElement,
'ClosedCaptionFiles'
);
if (closedCaptionElements) {
parserUtils
.childrenByName(closedCaptionElements, 'ClosedCaptionFile')
.forEach((closedCaptionElement) => {
const closedCaptionFile = createClosedCaptionFile(
parserUtils.parseAttributes(closedCaptionElement)
);
closedCaptionFile.fileURL =
parserUtils.parseNodeText(closedCaptionElement);
creative.closedCaptionFiles.push(closedCaptionFile);
});
}
const mezzanineElement = parserUtils.childByName(
mediaFilesElement,
'Mezzanine'
);
const requiredAttributes = getRequiredAttributes(mezzanineElement, [
'delivery',
'type',
'width',
'height',
]);
if (requiredAttributes) {
const mezzanine = createMezzanine();
mezzanine.id = mezzanineElement.getAttribute('id');
mezzanine.fileURL = parserUtils.parseNodeText(mezzanineElement);
mezzanine.delivery = requiredAttributes.delivery;
mezzanine.codec = mezzanineElement.getAttribute('codec');
mezzanine.type = requiredAttributes.type;
mezzanine.width = parseInt(requiredAttributes.width, 10);
mezzanine.height = parseInt(requiredAttributes.height, 10);
mezzanine.fileSize = parseInt(
mezzanineElement.getAttribute('fileSize'),
10
);
mezzanine.mediaType =
mezzanineElement.getAttribute('mediaType') || '2D';
creative.mezzanine = mezzanine;
}
});
const iconsElement = parserUtils.childByName(creativeElement, 'Icons');
if (iconsElement) {
parserUtils.childrenByName(iconsElement, 'Icon').forEach((iconElement) => {
creative.icons.push(parseIcon(iconElement));
});
}
return creative;
}
/**
* Parses the MediaFile element from VAST.
* @param {Object} mediaFileElement - The VAST MediaFile element.
* @return {Object} - Parsed mediaFile object.
*/
function parseMediaFile(mediaFileElement) {
const mediaFile = createMediaFile();
mediaFile.id = mediaFileElement.getAttribute('id');
mediaFile.fileURL = parserUtils.parseNodeText(mediaFileElement);
mediaFile.deliveryType = mediaFileElement.getAttribute('delivery');
mediaFile.codec = mediaFileElement.getAttribute('codec');
mediaFile.mimeType = mediaFileElement.getAttribute('type');
mediaFile.mediaType = mediaFileElement.getAttribute('mediaType') || '2D';
mediaFile.apiFramework = mediaFileElement.getAttribute('apiFramework');
mediaFile.fileSize = parseInt(mediaFileElement.getAttribute('fileSize') || 0);
mediaFile.bitrate = parseInt(mediaFileElement.getAttribute('bitrate') || 0);
mediaFile.minBitrate = parseInt(
mediaFileElement.getAttribute('minBitrate') || 0
);
mediaFile.maxBitrate = parseInt(
mediaFileElement.getAttribute('maxBitrate') || 0
);
mediaFile.width = parseInt(mediaFileElement.getAttribute('width') || 0);
mediaFile.height = parseInt(mediaFileElement.getAttribute('height') || 0);
const scalable = mediaFileElement.getAttribute('scalable');
if (scalable && typeof scalable === 'string') {
mediaFile.scalable = parserUtils.parseBoolean(scalable);
}
const maintainAspectRatio = mediaFileElement.getAttribute(
'maintainAspectRatio'
);
if (maintainAspectRatio && typeof maintainAspectRatio === 'string') {
mediaFile.maintainAspectRatio =
parserUtils.parseBoolean(maintainAspectRatio);
}
return mediaFile;
}
/**
* Parses the InteractiveCreativeFile element from VAST MediaFiles node.
* @param {Object} interactiveCreativeElement - The VAST InteractiveCreativeFile element.
* @return {Object} - Parsed interactiveCreativeFile object.
*/
function parseInteractiveCreativeFile(interactiveCreativeElement) {
const interactiveCreativeFile = createInteractiveCreativeFile(
parserUtils.parseAttributes(interactiveCreativeElement)
);
interactiveCreativeFile.fileURL = parserUtils.parseNodeText(
interactiveCreativeElement
);
return interactiveCreativeFile;
}
/**
* Parses the Icon element from VAST.
* @param {Object} iconElement - The VAST Icon element.
* @return {Object} - Parsed icon object.
*/
function parseIcon(iconElement) {
const icon = createIcon(iconElement);
icon.program = iconElement.getAttribute('program');
icon.height = parseInt(iconElement.getAttribute('height') || 0);
icon.width = parseInt(iconElement.getAttribute('width') || 0);
icon.xPosition = parseXPosition(iconElement.getAttribute('xPosition'));
icon.yPosition = parseYPosition(iconElement.getAttribute('yPosition'));
icon.apiFramework = iconElement.getAttribute('apiFramework');
icon.pxratio = iconElement.getAttribute('pxratio') || '1';
icon.offset = parserUtils.parseDuration(iconElement.getAttribute('offset'));
icon.duration = parserUtils.parseDuration(
iconElement.getAttribute('duration')
);
icon.altText = iconElement.getAttribute('altText');
icon.hoverText = iconElement.getAttribute('hoverText')
parserUtils
.childrenByName(iconElement, 'HTMLResource')
.forEach((htmlElement) => {
icon.type = htmlElement.getAttribute('creativeType') || 'text/html';
icon.htmlResource = parserUtils.parseNodeText(htmlElement);
});
parserUtils
.childrenByName(iconElement, 'IFrameResource')
.forEach((iframeElement) => {
icon.type = iframeElement.getAttribute('creativeType') || 0;
icon.iframeResource = parserUtils.parseNodeText(iframeElement);
});
parserUtils
.childrenByName(iconElement, 'StaticResource')
.forEach((staticElement) => {
icon.type = staticElement.getAttribute('creativeType') || 0;
icon.staticResource = parserUtils.parseNodeText(staticElement);
});
const iconClicksElement = parserUtils.childByName(iconElement, 'IconClicks');
if (iconClicksElement) {
icon.iconClickThroughURLTemplate = parserUtils.parseNodeText(
parserUtils.childByName(iconClicksElement, 'IconClickThrough')
);
parserUtils
.childrenByName(iconClicksElement, 'IconClickTracking')
.forEach((iconClickTrackingElement) => {
icon.iconClickTrackingURLTemplates.push({
id: iconClickTrackingElement.getAttribute('id') || null,
url: parserUtils.parseNodeText(iconClickTrackingElement),
});
});
const iconClickFallbackImagesElement = parserUtils.childByName(
iconClicksElement,
'IconClickFallbackImages'
);
if (iconClickFallbackImagesElement) {
parserUtils
.childrenByName(
iconClickFallbackImagesElement,
'IconClickFallbackImage'
)
.forEach((iconClickFallbackImageElement) => {
icon.iconClickFallbackImages.push({
url:
parserUtils.parseNodeText(iconClickFallbackImageElement) || null,
width: iconClickFallbackImageElement.getAttribute('width') || null,
height:
iconClickFallbackImageElement.getAttribute('height') || null,
});
});
}
}
icon.iconViewTrackingURLTemplate = parserUtils.parseNodeText(
parserUtils.childByName(iconElement, 'IconViewTracking')
);
return icon;
}
/**
* Parses an horizontal position into a String ('left' or 'right') or into a Number.
* @param {String} xPosition - The x position to parse.
* @return {String|Number}
*/
function parseXPosition(xPosition) {
if (['left', 'right'].indexOf(xPosition) !== -1) {
return xPosition;
}
return parseInt(xPosition || 0);
}
/**
* Parses an vertical position into a String ('top' or 'bottom') or into a Number.
* @param {String} yPosition - The x position to parse.
* @return {String|Number}
*/
function parseYPosition(yPosition) {
if (['top', 'bottom'].indexOf(yPosition) !== -1) {
return yPosition;
}
return parseInt(yPosition || 0);
}
/**
* Getting required attributes from element
* @param {Object} element - DOM element
* @param {Array} attributes - list of attributes
* @return {Object|null} null if a least one element not present
*/
function getRequiredAttributes(element, attributes) {
const values = {};
let error = false;
attributes.forEach((name) => {
if (!element || !element.getAttribute(name)) {
error = true;
} else {
values[name] = element.getAttribute(name);
}
});
return error ? null : values;
}