npaw-plugin-adapters
Version:
NPAW's Plugin Adapters
607 lines (547 loc) • 18.1 kB
JavaScript
/* global google */
export default class ImaAdapter {
_readAdPodValue(adPodInfo, methodName, propertyName) {
if (!adPodInfo) {
return null;
}
if (typeof adPodInfo[methodName] === 'function') {
return adPodInfo[methodName]();
}
if (adPodInfo[propertyName] !== undefined) {
return adPodInfo[propertyName];
}
return null;
}
_updateBreakInfoFromPodInfo(adPodInfo) {
if (!adPodInfo) {
return;
}
if (!this.breakAdsByOffset) {
this.breakAdsByOffset = {};
}
const totalAds = this._readAdPodValue(adPodInfo, 'getTotalAds', 'totalAds');
const timeOffset = this._readAdPodValue(adPodInfo, 'getTimeOffset', 'timeOffset');
if (typeof totalAds === 'number' && totalAds > 0) {
this.totalAds = totalAds;
}
if (typeof timeOffset === 'number') {
this.breakAdsByOffset[timeOffset] = Math.max(this.breakAdsByOffset[timeOffset] || 0, totalAds || 1);
}
}
_getCuePoints() {
if (this.player && typeof this.player.getCuePoints === 'function') {
return this.player.getCuePoints() || [];
}
return [];
}
_getObservedBreakOffsets() {
if (!this.breakAdsByOffset) {
return [];
}
return Object.keys(this.breakAdsByOffset)
.map(function (offset) {
return Number(offset);
})
.filter(function (offset) {
return !Number.isNaN(offset);
})
.sort(function (a, b) {
return a - b;
});
}
_getContentDurationForBreaks() {
let duration = null;
const videoAdapter = this.getVideo() ? this.getVideo().getAdapter() : null;
if (videoAdapter && typeof videoAdapter.getDuration === 'function') {
duration = videoAdapter.getDuration();
} else if (this.plugin && this.plugin._adapter && typeof this.plugin._adapter.getDuration === 'function') {
duration = this.plugin._adapter.getDuration();
}
return typeof duration === 'number' && isFinite(duration) && duration > 0 ? duration : null;
}
_normalizeCuePoint(cuePoint, contentDuration) {
if (cuePoint === -1) {
return contentDuration !== null ? contentDuration : -1;
}
if (cuePoint === null || cuePoint === undefined) {
return contentDuration !== null ? contentDuration : null;
}
return cuePoint;
}
_getBreakPositionFromCuePoint(cuePoint, contentDuration) {
if (cuePoint === 0) {
return 'pre';
}
if (cuePoint === -1) {
return 'post';
}
if (contentDuration !== null && typeof cuePoint === 'number' && cuePoint >= contentDuration - 1) {
return 'post';
}
return 'mid';
}
_getAdPodInfoFromEvent(e) {
const adData = typeof e.getAdData === 'function' ? e.getAdData() : null;
if (adData && adData.adPodInfo) {
return adData.adPodInfo;
}
const adObject =
typeof e.getAd === 'function'
? e.getAd()
: this.player && this.player.getCurrentAd
? this.player.getCurrentAd()
: null;
if (adObject && typeof adObject.getAdPodInfo === 'function') {
return adObject.getAdPodInfo();
}
return null;
}
pauseListener(e) {
this.firePause({}, 'pauseListener');
}
getAdInsertionType() {
return this.isDAI
? this.getNpawReference().Constants.AdInsertionType.ServerSide
: this.getNpawReference().Constants.AdInsertionType.ClientSide;
}
progressDAIListener(e) {
if (e.getStreamData && e.getStreamData()) {
this.playhead = e.getStreamData().adProgressData.currentTime;
} else if (typeof e.getAdData === 'function' && e.getAdData()) {
this.playhead = e.getAdData().currentTime;
}
this.fireJoin({}, 'progressDAIListener');
}
getRendition() {
let ret = null;
if (this.player) {
if (!this.isDAI) {
const currentAd = this.player.getCurrentAd();
ret = currentAd.getVastMediaWidth().toString() + 'x' + currentAd.getVastMediaHeight().toString();
} else if (this.width && this.height) {
ret = this.width + 'x' + this.height;
}
}
return ret;
}
startDAIListener(e) {
this.isDAI = true;
this.playhead = 0;
}
getPlayerVersion() {
return google.ima.VERSION;
}
playListener(e) {
this.isDAI = false;
this.adPosition = this.getAdPosition();
const adData = typeof e.getAdData === 'function' ? e.getAdData() : null;
const adPodInfo = this._getAdPodInfoFromEvent(e);
this._updateBreakInfoFromPodInfo(adPodInfo);
this.totalAds = adData && adData.adPodInfo ? adData.adPodInfo.totalAds : this.totalAds;
this.plugin.fireInit(undefined, 'playListener', this.getVideo().getVideoKey());
if (this.getVideo().getAdapter()) {
this.getVideo().getAdapter().firePause({}, 'playListener');
}
this.fireStart(
{
adPlayhead: '0'
},
'playListener'
);
}
getTitle2() {
let ret = this.advertiser;
if (this.player && !this.isDAI) {
ret = this.player.getCurrentAd().getAdvertiserName();
}
return ret;
}
errorDAIListener(e) {
this.fireError(undefined, undefined, undefined, undefined, 'errorDAIListener');
this.fireStop({}, 'errorDAIListener');
}
secondQuartileListener(e) {
this.fireQuartile(2);
}
endedListener(e) {
if (this.lastDuration) {
this.fireStop(
{
adPlayhead: this.lastDuration
},
'endedListener'
);
} else {
this.fireStop({}, 'endedListener');
}
}
getGivenBreaks() {
const breaksTime = this.getBreaksTime();
return breaksTime ? breaksTime.length : 0;
}
loadedListener(e) {
const adData = typeof e.getAdData === 'function' ? e.getAdData() : null;
const adPodInfo = this._getAdPodInfoFromEvent(e);
this._updateBreakInfoFromPodInfo(adPodInfo);
this.totalAds = adData && adData.adPodInfo ? adData.adPodInfo.totalAds : undefined;
this.clickUrl = adData ? adData.clickThroughUrl : undefined;
if (this.plugin.isBreakStarted) {
this.playListener(e);
}
}
getPlayhead() {
let ret = this.playhead;
if (!this.flags.isJoined) {
ret = 0;
} else if (this.player && !this.isDAI) {
ret = this.getDuration() - this.player.getRemainingTime();
}
return ret;
}
getDuration() {
let ret = this.duration;
if (this.player && !this.isDAI) {
if (this.player.getCurrentAd && this.player.getCurrentAd()) {
this.lastDuration = this.player.getCurrentAd().getDuration();
}
ret = this.lastDuration;
}
return ret;
}
getGivenAds() {
return this.totalAds;
}
getExpectedBreaks() {
const pattern = this.getExpectedPattern();
if (pattern) {
return pattern.pre.length + pattern.mid.length + pattern.post.length;
}
return this.getGivenBreaks();
}
getExpectedPattern() {
const observedOffsets = this._getObservedBreakOffsets();
const cuepoints = observedOffsets.length ? observedOffsets : this.getBreaksTime();
const contentDuration = this._getContentDurationForBreaks();
const pattern = {
pre: [],
mid: [],
post: []
};
cuepoints.forEach(
function (cuePoint) {
const position = this._getBreakPositionFromCuePoint(cuePoint, contentDuration);
const expectedAds = (this.breakAdsByOffset && this.breakAdsByOffset[cuePoint]) || this.totalAds || 1;
pattern[position].push(expectedAds);
}.bind(this)
);
return pattern.pre.length === 0 && pattern.mid.length === 0 && pattern.post.length === 0 ? null : pattern;
}
getIsSkippable() {
let ret = null;
if (this.player && this.player.getCurrentAd) {
const currentAd = this.player.getCurrentAd();
if (currentAd && currentAd.g) {
ret = currentAd.g.skippable;
}
}
return ret;
}
getCreativeId() {
let ret = null;
if (!this.isDAI && this.player.getCurrentAd()) {
ret = this.player.getCurrentAd().getCreativeId();
}
return ret;
}
thirdQuartileListener(e) {
this.fireQuartile(3);
}
getAudioEnabled() {
let ret = null;
if (this.player) {
ret = this.player.getVolume ? this.player.getVolume() !== 0 : true;
}
return ret;
}
getVersion() {
return '7.0.11-ima-jsclass';
}
logListener(e) {
if (typeof e.getAdData === 'function' && e.getAdData().adError) {
const error = e.getAdData().adError;
this.fireError(error.getErrorCode(), error.getMessage(), undefined, undefined, 'logListener');
this.fireStop({}, 'logListener');
}
}
unregisterListeners() {
if (this.monitor) this.monitor.stop();
if (this.player && this.references) {
for (let key in this.references) {
this.player.removeEventListener(key, this.references[key]);
}
this.references = {};
}
}
clickListener(e) {
let url = this.clickUrl;
const current = this.player.getCurrentAd();
if (current && current.g && current.g.clickThroughUrl) {
url = current.g.clickThroughUrl;
}
const now = new Date().getTime();
if (this.lastUrl === url && now < (this.lastTime || 0) + 2000) {
return;
}
this.lastUrl = url;
this.lastTime = now;
this.fireClick(url);
}
getAdPosition() {
let ret = this.getNpawReference().Constants.AdPosition.Midroll;
if (!this.isDAI) {
switch (this.player.getCurrentAd().getAdPodInfo().getTimeOffset()) {
case 0:
ret = this.getNpawReference().Constants.AdPosition.Preroll;
break;
case -1:
ret = this.getNpawReference().Constants.AdPosition.Postroll;
}
} else {
const videoAdapter = this.getVideo().getAdapter();
if (videoAdapter && (!videoAdapter.flags.isJoined || videoAdapter.getPlayhead() < 1)) {
ret = this.getNpawReference().Constants.AdPosition.Preroll;
} else if (
videoAdapter &&
videoAdapter.flags.isJoined &&
videoAdapter.getPlayhead() + this.duration + 1 >= videoAdapter.getDuration()
) {
ret = this.getNpawReference().Constants.AdPosition.Postroll;
}
}
return ret;
}
firstQuartileListener(e) {
this.fireQuartile(1);
}
getIsLive() {
let ret = null;
if (this.player.levels && this.player.levels[this.player.currentLevel]) {
ret = this.player.levels[this.player.currentLevel].details.live;
}
return ret;
}
getTitle() {
let ret = this.title;
if (this.player && !this.isDAI) {
ret = this.player.getCurrentAd().getTitle();
}
return ret;
}
registerListeners() {
this.references = {};
if (google.ima.AdEvent) {
this.monitorPlayhead(true, false);
const event = google.ima.AdEvent.Type;
this.references[event.CONTENT_PAUSE_REQUESTED] = this.playListener.bind(this);
this.references[event.LOADED] = this.loadedListener.bind(this);
this.references[event.PAUSED] = this.pauseListener.bind(this);
this.references[event.STARTED] = this.playingListener.bind(this);
this.references[event.RESUMED] = this.playingListener.bind(this);
this.references[google.ima.AdErrorEvent.Type.AD_ERROR] = this.errorListener.bind(this);
this.references[event.COMPLETE] = this.endedListener.bind(this);
this.references[event.CONTENT_RESUME_REQUESTED] = this.endedListener.bind(this);
this.references[event.SKIPPED] = this.skippedListener.bind(this);
this.references[event.CLICK] = this.clickListener.bind(this);
this.references[event.ALL_ADS_COMPLETED] = this.endedViewListener.bind(this);
this.references[event.LOG] = this.logListener.bind(this);
this.references[event.FIRST_QUARTILE] = this.firstQuartileListener.bind(this);
this.references[event.MIDPOINT] = this.secondQuartileListener.bind(this);
this.references[event.THIRD_QUARTILE] = this.thirdQuartileListener.bind(this);
this.references[event.CONTENT_RESUME_REQUESTED] = this.breakEndListener.bind(this);
}
if (google.ima.dai) {
const eventDAI = google.ima.dai.api.StreamEvent.Type;
this.references[eventDAI.SKIPPED] = this.skippedL.bind(this);
this.references[eventDAI.ERROR] = this.errorDAIListener.bind(this);
this.references[eventDAI.AD_BREAK_STARTED] = this.startDAIListener.bind(this);
this.references[eventDAI.AD_BREAK_ENDED] = this.stopDAIListener.bind(this);
this.references[eventDAI.AD_PROGRESS] = this.progressDAIListener.bind(this);
this.references[eventDAI.CLICK] = this.clickDAIListener.bind(this);
this.references[eventDAI.STARTED] = this.joinDAIListener.bind(this);
this.references[eventDAI.LOADED] = this.loadedDAIListener.bind(this);
this.references[eventDAI.COMPLETE] = this.completeDAIListener.bind(this);
this.references[eventDAI.FIRST_QUARTILE] = this.firstQuartileListener.bind(this);
this.references[eventDAI.MIDPOINT] = this.secondQuartileListener.bind(this);
this.references[eventDAI.THIRD_QUARTILE] = this.thirdQuartileListener.bind(this);
this.references[eventDAI.PAUSED] = this.pauseDAIListener.bind(this);
this.references[eventDAI.RESUMED] = this.resumeDAIListener.bind(this);
}
if (this.player) {
for (let key in this.references) {
this.player.addEventListener(key, this.references[key]);
}
}
}
loadedDAIListener(e) {
if (e.getStreamData) {
const streamData = e.getStreamData();
if (streamData) {
this.resource = streamData.url;
}
}
}
stopDAIListener(e) {
this.fireStop(
{
adPlayhead: this.duration
},
'stopDAIListener'
);
if (this.getVideo().getAdapter()) {
this.getVideo().getAdapter().fireResume({}, 'stopDAIListener');
}
this.fireBreakStop();
}
getResource() {
let ret = null;
if (!this.isDAI && this.player.getCurrentAd()) {
ret = this.player.getCurrentAd().getMediaUrl();
} else if (this.isDAI) {
ret = this.resource;
}
return ret;
}
getProvider() {
let ret = null;
if (!this.isDAI && this.player.getCurrentAd()) {
ret = this.player.getCurrentAd().getAdSystem();
}
return ret;
}
skippedL() {
this.fireSkip();
}
skippedListener(e) {
this.fireSkip({
adPlayhead: this.getPlayhead()
});
}
joinDAIListener(e) {
const adData = e.getAd();
if (adData) {
this.duration = adData.getDuration();
this.title = adData.getTitle();
this.width = adData.getVastMediaWidth();
this.height = adData.getVastMediaHeight();
this.advertiser = adData.getAdvertiserName();
this.adPosition = this.getAdPosition();
}
if (this.getVideo().getAdapter()) this.getVideo().getAdapter().firePause({}, 'joinDAIListener');
this.plugin.fireInit(undefined, 'joinDAIListener', this.getVideo().getVideoKey());
this.fireStart({}, 'joinDAIListener');
this.fireJoin({}, 'joinDAIListener');
}
completeDAIListener(e) {
this.fireStop({}, 'completeDAIListener');
}
getPlayerName() {
return 'IMA';
}
getIsVisible() {
let ret = null;
if (this.player) {
if (!this.contentPlayer) {
for (const key in this.player) {
const element = this.player[key];
if (!!element && element.videoHeight && element.clientHeight) {
this.contentPlayer = element;
break;
}
}
}
ret = this.getNpawUtils().calculateAdViewability(this.contentPlayer);
}
return ret;
}
playingListener(e) {
this.fireStart(
{
adPlayhead: '0'
},
'playingListener'
);
this.fireResume({}, 'playingListener');
this.fireSeekEnd({}, 'playingListener');
this.fireBufferEnd({}, 'playingListener');
this.fireJoin(
{
adPlayhead: '0'
},
'playingListener'
);
}
endedViewListener(e) {
if (this.getPosition() === this.getNpawReference().Constants.AdPosition.Postroll) {
this.getVideo().getAdapter().fireStop({}, 'endedViewListener');
}
}
getPosition() {
let ret = null;
if (this.player) {
if (this.getVideo().getAdapter() && !this.getVideo().getAdapter().flags.isJoined) {
ret = this.getNpawReference().Constants.AdPosition.Preroll;
} else if (this.getIsLive()) {
ret = this.getNpawReference().Constants.AdPosition.Midroll;
} else {
ret = this.adPosition || this.getNpawReference().Constants.AdPosition.Midroll;
}
}
return ret;
}
errorListener(e) {
this.fireError(undefined, undefined, undefined, undefined, 'errorListener');
this.fireStop({}, 'errorListener');
}
breakEndListener(e) {
this.fireBreakStop();
}
getBreaksTime() {
const observedOffsets = this._getObservedBreakOffsets();
let cuepoints = observedOffsets.length ? observedOffsets : this._getCuePoints();
const contentDuration = this._getContentDurationForBreaks();
if (cuepoints && cuepoints.length) {
// If no break has been observed yet, ignore IMA's synthetic postroll marker (-1).
if (!observedOffsets.length) {
cuepoints = cuepoints.filter(function (cuePoint) {
return cuePoint !== -1 && cuePoint !== null && cuePoint !== undefined;
});
}
cuepoints = cuepoints.map(
function (cuePoint) {
return this._normalizeCuePoint(cuePoint, contentDuration);
}.bind(this)
);
cuepoints = cuepoints.filter(function (cuePoint) {
return cuePoint !== null && cuePoint !== undefined;
});
}
return cuepoints && cuepoints.length ? cuepoints : [];
}
clickDAIListener(e) {
this.fireClick(this.clickUrl);
}
pauseDAIListener(e) {
this.firePause({}, 'pauseDAIListener');
var videoAdapter = this.getVideo().getAdapter();
if (videoAdapter) {
videoAdapter.flags.isAdPaused = true;
}
}
resumeDAIListener(e) {
this.fireResume({}, 'resumeDAIListener');
var videoAdapter = this.getVideo().getAdapter();
if (videoAdapter) {
videoAdapter.flags.isAdPaused = false;
}
}
}