video-ad-sdk
Version:
VAST/VPAID SDK that allows video ads to be played on top of any player
252 lines (209 loc) • 7.38 kB
text/typescript
import {get, getFirstChild, getText, getAttribute} from '../xml'
import type {
ParsedXML,
ParsedAd,
VastChain,
VastChainDetails,
MediaFile,
Optional
} from '../types'
import {getLinearCreative} from '../vastSelectors/helpers/getLinearCreative'
import {
isInline,
getClickThrough,
getCreativeData,
isWrapper,
getMediaFiles,
getInteractiveFiles
} from '../vastSelectors'
import {parseTime} from '../vastSelectors/helpers/parseTime'
const getAdSystem = (ad: ParsedAd): Optional<string> => {
const adTypeElement = getFirstChild(ad)
const element = adTypeElement && get(adTypeElement, 'AdSystem')
return element && getText(element)
}
const getSubElementValue = (
parentElement: ParsedXML,
tagName: string
): Optional<string> => {
const element = parentElement && get(parentElement, tagName)
return element && getText(element)
}
const getPricingElement = (ad: ParsedAd): Optional<ParsedXML> => {
const adTypeElement = getFirstChild(ad)
return adTypeElement && get(adTypeElement, 'Pricing')
}
interface Pricing {
pricing?: string
pricingCurrency?: string
pricingModel?: string
}
const getPricing = (vastChain: VastChain): Pricing => {
const [{ad}] = vastChain
const pricingElement = ad && getPricingElement(ad)
if (pricingElement) {
return {
pricing: getText(pricingElement),
pricingCurrency: getAttribute(pricingElement, 'currency'),
pricingModel: getAttribute(pricingElement, 'model')
}
}
if (vastChain.length > 1) {
return getPricing(vastChain.slice(1))
}
return {}
}
interface Category {
category?: string
categoryAuthority?: string
}
const getCategory = (ad?: ParsedAd): Category => {
const inLineElement = ad && get(ad, 'InLine')
const categoryElement = inLineElement && get(inLineElement, 'Category')
if (categoryElement) {
return {
category: getText(categoryElement),
categoryAuthority: getAttribute(categoryElement, 'authority')
}
}
return {}
}
const getVastVersion = (parsedVast?: ParsedXML): Optional<string> => {
const vastElement = parsedVast && get(parsedVast, 'VAST')
if (vastElement) {
return getAttribute(vastElement, 'version')
}
return 'unknown'
}
const getAdIds = (vastChain: VastChain): string[] =>
vastChain.map(({ad}) => ad && getAttribute(ad, 'id')).filter(Boolean)
const getAdSystems = (vastChain: VastChain): string[] =>
vastChain.map(({ad}) => ad && getAdSystem(ad)).filter(Boolean)
const getCreatives = (vastChain: VastChain): ParsedXML[] =>
vastChain.map(({ad}) => ad && getLinearCreative(ad)).filter(Boolean)
const getCreativeIds = (creatives: ParsedXML[]): string[] =>
creatives
.map((creative) => creative && getAttribute(creative, 'id'))
.filter(Boolean)
const getCreativeAdIds = (creatives: ParsedXML[]): string[] =>
creatives
.map((creative) => creative && getAttribute(creative, 'adId'))
.filter(Boolean)
const getAdTypeElement = (ad?: ParsedXML): Optional<ParsedXML> =>
ad && getFirstChild(ad)
const getCreativeElement = (ad?: ParsedXML): Optional<ParsedXML> =>
ad && getLinearCreative(ad)
const getLinearElement = (creativeElement?: ParsedXML): Optional<ParsedXML> =>
creativeElement && get(creativeElement, 'Linear')
const getAdServingId = (adTypeElement?: ParsedXML): Optional<string> =>
adTypeElement && getSubElementValue(adTypeElement, 'AdServingId')
const getAdvertiser = (adTypeElement?: ParsedXML): Optional<string> =>
adTypeElement && getSubElementValue(adTypeElement, 'Advertiser')
const getAdTitle = (adTypeElement?: ParsedXML): Optional<string> =>
adTypeElement && getSubElementValue(adTypeElement, 'AdTitle')
const getDescription = (adTypeElement?: ParsedXML): Optional<string> =>
adTypeElement && getSubElementValue(adTypeElement, 'Description')
const getDuration = (linearElement?: ParsedXML): Optional<string> =>
linearElement && getSubElementValue(linearElement, 'Duration')
const getDurationInMs = (duration?: string): Optional<number> =>
duration ? parseTime(duration) : undefined
const getUniversalIdElement = (
creativeElement?: ParsedXML
): Optional<ParsedXML> =>
creativeElement && get(creativeElement, 'UniversalAdId')
/**
* Returns a summary of the passed {@link VastChain}.
*
* @param vastChain the {@link VastChain} from which we want the details.
* @returns Returns a {@link VastChainDetails} object from the passed {@link VastChain}.
*/
export const getDetails = (vastChain: VastChain): VastChainDetails => {
const adIds = getAdIds(vastChain)
const adSystems = getAdSystems(vastChain)
const creatives = getCreatives(vastChain)
const creativeIds = getCreativeIds(creatives)
const creativeAdIds = getCreativeAdIds(creatives)
const [{ad, parsedXML, XML}] = vastChain
const {pricing, pricingCurrency, pricingModel} = getPricing(vastChain)
const {category, categoryAuthority} = getCategory(ad)
const adTypeElement = getAdTypeElement(ad)
const creativeElement = getCreativeElement(ad)
const linearElement = getLinearElement(creativeElement)
const adServingId = getAdServingId(adTypeElement)
const vastVersion = getVastVersion(parsedXML)
const advertiser = getAdvertiser(adTypeElement)
const adTitle = getAdTitle(adTypeElement)
const description = getDescription(adTypeElement)
const duration = getDuration(linearElement)
const durationInMs = getDurationInMs(duration)
let adId
let adWrapperIds: string[] = []
let adSystem
let adWrapperSystems: string[] = []
let creativeId
let adWrapperCreativeIds: string[] = []
let creativeAdId
let adWrapperCreativeAdIds: string[] = []
let clickThroughUrl
let creativeData
let universalAdId
let universalAdIdRegistry
let mediaFiles: MediaFile[] = []
let vpaid
let skippable
let skipOffset
let skipOffsetInMs
if (isInline(ad)) {
;[adId, ...adWrapperIds] = adIds
;[adSystem, ...adWrapperSystems] = adSystems
;[creativeId, ...adWrapperCreativeIds] = creativeIds
;[creativeAdId, ...adWrapperCreativeAdIds] = creativeAdIds
clickThroughUrl = ad && getClickThrough(ad)
creativeData = XML ? getCreativeData(XML) : undefined
const universalIdElement = getUniversalIdElement(creativeElement)
universalAdId = universalIdElement && getText(universalIdElement)
universalAdIdRegistry =
universalIdElement && getAttribute(universalIdElement, 'idRegistry')
mediaFiles = (ad && getMediaFiles(ad)) || []
vpaid = Boolean(ad && getInteractiveFiles(ad))
skipOffset = linearElement && getAttribute(linearElement, 'skipoffset')
skipOffsetInMs = skipOffset ? parseTime(skipOffset) : undefined
skippable = Boolean(skipOffset)
} else if (isWrapper(vastChain[0].ad)) {
adWrapperIds = adIds
adWrapperSystems = adSystems
adWrapperCreativeIds = creativeIds
adWrapperCreativeAdIds = creativeAdIds
}
return {
adId,
adServingId,
adSystem,
adTitle,
advertiser,
adWrapperCreativeAdIds,
adWrapperCreativeIds,
adWrapperIds,
adWrapperSystems,
category,
categoryAuthority,
clickThroughUrl,
creativeAdId,
creativeData,
creativeId,
description,
duration,
durationInMs,
mediaFiles,
pricing,
pricingCurrency,
pricingModel,
skipOffset,
skipOffsetInMs,
skippable,
universalAdId,
universalAdIdRegistry,
vastVersion,
vpaid
}
}