-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from voxmedia/ba-add-progress-tracking-events
Add Progress Tracking Events
- Loading branch information
Showing
13 changed files
with
341 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
export default class Timecode { | ||
/** | ||
* Converts seconds to a three segment timecode hh:mm:ss | ||
* Examples: 30 => "00:00:30" | ||
* 90 => "00:01:30" | ||
* | ||
* @param {String|Number} maybeSeconds | ||
* @returns {String} "hh:mm:ss" timecode | ||
*/ | ||
static secondsToTimecode(maybeSeconds) { | ||
const seconds = Number(maybeSeconds); | ||
|
||
if (isNaN(seconds) || maybeSeconds.toString().indexOf('%') != -1) { | ||
return null; | ||
} | ||
|
||
const date = new Date(null); | ||
date.setSeconds(seconds); | ||
return date.toISOString().substr(11, 8); | ||
} | ||
|
||
/** | ||
* Converts timecode hh:mm:ss to total seconds | ||
* Examples: "00:00:30" => 30 | ||
* "00:10:10" => 610 | ||
* | ||
* @param {String} timecode Timecode input | ||
* @returns {Number} the number of seconds represented in the timecode | ||
*/ | ||
static timecodeToSeconds(timecode) { | ||
let parts = timecode.split(':'); | ||
let seconds = 0; | ||
let multiplier = 1; | ||
|
||
while (parts.length > 0) { | ||
seconds += multiplier * parseInt(parts.pop(), 10); | ||
multiplier *= 60; | ||
} | ||
return seconds; | ||
} | ||
|
||
/** | ||
* Will properly format the timecode into three segment parts | ||
* Example: "01:10" => "00:01:10" | ||
* | ||
* @param {String} code input timecode | ||
* @returns {String} three segment timecode hh:mm:ss | ||
*/ | ||
static timecodeToTimecode(code) { | ||
const result = this.secondsToTimecode(this.timecodeToSeconds(code)); | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,126 @@ | ||
import VastElementBase from './vast_element_base'; | ||
import Timecodes from '../timecodes'; | ||
import NodeValue from '../node_value'; | ||
import QuartileSupport from '../quartile_support'; | ||
|
||
class TrackingEvent { | ||
constructor({ eventName, url }) { | ||
this.eventName = eventName; | ||
this._url = url; | ||
} | ||
|
||
matches(string) { | ||
return this.eventName == string; | ||
} | ||
|
||
name() { | ||
return this.eventName; | ||
} | ||
|
||
offsetInSeconds(duration) { | ||
const quarts = QuartileSupport.quartiles(); | ||
return quarts[this.eventName] * duration; | ||
} | ||
|
||
offsetInPercent(duration) { | ||
const quarts = QuartileSupport.quartiles(); | ||
return quarts[this.eventName]; | ||
} | ||
|
||
url() { | ||
return this._url; | ||
} | ||
} | ||
|
||
class ProgressTrackingEvent { | ||
constructor({ offset, url }) { | ||
this.offset = offset; | ||
this._url = url; | ||
} | ||
|
||
matches(secondsOrTimeCodeOrPercent) { | ||
return ( | ||
this.offset == secondsOrTimeCodeOrPercent || | ||
this.offset == Timecodes.secondsToTimecode(secondsOrTimeCodeOrPercent) || | ||
this.offset == Timecodes.timecodeToTimecode(secondsOrTimeCodeOrPercent) | ||
); | ||
} | ||
|
||
name() { | ||
return this.offset; | ||
} | ||
|
||
offsetInSeconds(duration) { | ||
if (this.offset.indexOf('%') != -1) { | ||
return duration * (Number(this.offset.replace('%', '')) / 100.0); | ||
} else { | ||
return Timecodes.timecodeToSeconds(this.offset); | ||
} | ||
} | ||
|
||
offsetInPercent(duration) { | ||
return Math.min(1.0, this.offsetInSeconds(duration) / duration); | ||
} | ||
|
||
url() { | ||
return this._url; | ||
} | ||
} | ||
|
||
export default class TrackingEvents extends VastElementBase { | ||
setup() { | ||
this.trackingUrls = []; | ||
this.trackingEvents = []; | ||
this.duration = undefined; | ||
} | ||
|
||
static selector() { | ||
return 'Ad TrackingEvents Tracking'; | ||
return 'Ad TrackingEvents Tracking, Ad Inline Creative Duration'; | ||
} | ||
|
||
onVastReady() { | ||
this.trackingUrls = this.elements.map(el => { | ||
return [el.getAttribute('event'), NodeValue.fromElement(el)]; | ||
}); | ||
const durationValue = NodeValue.fromElement(this.elements.find(el => el.nodeName == 'Duration')); | ||
this.duration = Timecodes.timecodeToSeconds(durationValue || '0'); | ||
|
||
this.trackingEvents = this.elements | ||
.filter(el => el.nodeName != 'Duration') | ||
.map(el => { | ||
const trackingEvent = el.hasAttribute('offset') ? ProgressTrackingEvent : TrackingEvent; | ||
|
||
return new trackingEvent({ | ||
eventName: el.getAttribute('event'), | ||
offset: el.getAttribute('offset'), | ||
url: NodeValue.fromElement(el), | ||
}); | ||
}); | ||
} | ||
|
||
trackingUrlsFor(eventName) { | ||
return this.trackingUrls.filter(t => t[0] == eventName).map(t => t[1]); | ||
return this.trackingEvents.filter(t => t.matches(eventName)).map(t => t.url()); | ||
} | ||
|
||
addImpressionTrackingImagesFor(eventName, doc = document) { | ||
this.trackingUrlsFor(eventName).forEach(url => { | ||
this.addImpressionUrl(url, { doc: doc, name: eventName }); | ||
}); | ||
} | ||
|
||
trackingEventNamesWithOffsets() { | ||
return this.trackingEvents.reduce((all, event) => { | ||
const offsetSeconds = event.offsetInSeconds(this.duration); | ||
if (offsetSeconds) { | ||
all[event.name()] = offsetSeconds; | ||
} | ||
return all; | ||
}, {}); | ||
} | ||
|
||
trackingEventNamesWithOffsetPercent() { | ||
return this.trackingEvents.reduce((all, event) => { | ||
const offsetPercent = event.offsetInPercent(this.duration); | ||
if (offsetPercent) { | ||
all[event.name()] = offsetPercent; | ||
} | ||
return all; | ||
}, {}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,52 @@ | ||
<VAST version="3.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> | ||
<Ad id="20001"> | ||
<InLine> | ||
<AdSystem version="4.0">iabtechlab</AdSystem> | ||
<AdTitle>iabtechlab video ad</AdTitle> | ||
<Pricing model="cpm" currency="USD"> | ||
<![CDATA[ 25.00 ]]> | ||
</Pricing> | ||
<Error>http://example.com/error</Error> | ||
<Impression id="Impression-ID">http://example.com/track/impression</Impression> | ||
<Creatives> | ||
<Creative id="5480" sequence="1"> | ||
<Linear> | ||
<Duration>00:00:16</Duration> | ||
<TrackingEvents> | ||
<Tracking event="start">http://example.com/tracking/start</Tracking> | ||
<Tracking event="firstQuartile">http://example.com/tracking/firstQuartile</Tracking> | ||
<Tracking event="midpoint">http://example.com/tracking/midpoint</Tracking> | ||
<Tracking event="thirdQuartile">http://example.com/tracking/thirdQuartile</Tracking> | ||
<Tracking event="complete">http://example.com/tracking/complete</Tracking> | ||
<Tracking event="progress" offset="00:00:10">http://example.com/tracking/progress-10</Tracking> | ||
</TrackingEvents> | ||
<VideoClicks> | ||
<ClickThrough id="blog"> | ||
<![CDATA[https://iabtechlab.com]]> | ||
</ClickThrough> | ||
</VideoClicks> | ||
<MediaFiles> | ||
<MediaFile id="5241" delivery="progressive" type="video/mp4" bitrate="500" width="400" height="300" minBitrate="360" maxBitrate="1080" scalable="1" maintainAspectRatio="1" codec="0" apiFramework="VAST"> | ||
<![CDATA[https://iab-publicfiles.s3.amazonaws.com/vast/VAST-4.0-Short-Intro.mp4]]> | ||
</MediaFile> | ||
</MediaFiles> | ||
|
||
|
||
</Linear> | ||
</Creative> | ||
</Creatives> | ||
<Extensions> | ||
<Extension type="iab-Count"> | ||
<total_available> | ||
<![CDATA[ 2 ]]> | ||
</total_available> | ||
</Extension> | ||
</Extensions> | ||
</InLine> | ||
</Ad> | ||
<VAST version="3.0" | ||
xmlns:xs="http://www.w3.org/2001/XMLSchema"> | ||
<Ad id="20009"> | ||
<InLine> | ||
<AdSystem version="4.0">iabtechlab</AdSystem> | ||
<AdTitle>iabtechlab video ad</AdTitle> | ||
<Pricing model="cpm" currency="USD"> | ||
<![CDATA[ 25.00 ]]> | ||
</Pricing> | ||
<Error>http://example.com/error</Error> | ||
<Impression id="Impression-ID">http://example.com/track/impression</Impression> | ||
<Creatives> | ||
<Creative id="5480" sequence="1"> | ||
<Linear> | ||
<Duration>00:00:16</Duration> | ||
<TrackingEvents> | ||
<Tracking event="start">http://example.com/tracking/start</Tracking> | ||
<Tracking event="firstQuartile">http://example.com/tracking/firstQuartile</Tracking> | ||
<Tracking event="midpoint">http://example.com/tracking/midpoint</Tracking> | ||
<Tracking event="thirdQuartile">http://example.com/tracking/thirdQuartile</Tracking> | ||
<Tracking event="complete">http://example.com/tracking/complete</Tracking> | ||
<Tracking event="progress" offset="00:00:10">http://example.com/tracking/progress-10</Tracking> | ||
<Tracking event="progress" offset="00:01:40">http://example.com/tracking/progress-140</Tracking> | ||
<Tracking event="progress" offset="15%">http://example.com/tracking/progress-15-percent</Tracking> | ||
<Tracking event="progress" offset="50%">http://example.com/tracking/progress-50-percent</Tracking> | ||
</TrackingEvents> | ||
<VideoClicks> | ||
<ClickThrough id="blog"> | ||
<![CDATA[https://iabtechlab.com]]> | ||
</ClickThrough> | ||
<ClickTracking> | ||
<![CDATA[http://example.com/trackingurl/clickTracking]]> | ||
</ClickTracking> | ||
</VideoClicks> | ||
<MediaFiles> | ||
<MediaFile id="5241" delivery="progressive" type="video/mp4" bitrate="500" width="400" height="300" minBitrate="360" maxBitrate="1080" scalable="1" maintainAspectRatio="1" codec="0"> | ||
<![CDATA[https://iab-publicfiles.s3.amazonaws.com/vast/VAST-4.0-Short-Intro.mp4]]> | ||
</MediaFile> | ||
</MediaFiles> | ||
</Linear> | ||
</Creative> | ||
</Creatives> | ||
<Extensions> | ||
<Extension type="iab-Count"> | ||
<total_available> | ||
<![CDATA[ 2 ]]> | ||
</total_available> | ||
</Extension> | ||
</Extensions> | ||
</InLine> | ||
</Ad> | ||
</VAST> |
Oops, something went wrong.