npaw-plugin-adapters
Version:
NPAW's Plugin Adapters
929 lines (833 loc) • 29.2 kB
JavaScript
/* global tv */
export default class FreewheelAdsAdapter {
getVersion() {
return '7.0.2-freewheel-ads-js';
}
getPlayhead() {
// Try to get playhead from Freewheel ad instance first
var playhead = this._getAdInstanceMethodCall('getPlayheadTime');
// If that returns null/0, try to get it from the video element
if (!playhead || playhead === 0) {
// Try to get from video element
var videoElement = this._getVideoElement();
if (videoElement && videoElement.currentTime > 0) {
return videoElement.currentTime;
}
// Last resort: check if we have a saved playhead position
if (this._adPlayhead !== undefined) {
return this._adPlayhead;
}
}
return playhead;
}
getDuration() {
return this._getAdInstanceMethodCall('getDuration');
}
getTitle() {
try {
if (this.titles) {
return this.titles[this._getAdNumber()]._adId;
}
} catch (err) {
// Ignore errors and return default
}
return 'unknown';
}
getResource() {
var ret = null;
var creativeRendition = this._getAdInstanceMethodCall('getActiveCreativeRendition');
if (creativeRendition) {
if (typeof creativeRendition.getPrimaryCreativeRenditionAsset === 'function') {
const asset = creativeRendition.getPrimaryCreativeRenditionAsset();
if (asset && typeof asset.getUrl === 'function') {
ret = asset.getUrl();
}
} else if (typeof creativeRendition.getWrapperUrl === 'function') {
ret = creativeRendition.getWrapperUrl();
}
}
return ret;
}
getPlayerVersion() {
// Try multiple ways to get the Freewheel SDK version
try {
// Method 1: Direct SDK version property
if (typeof tv !== 'undefined' && tv.freewheel && tv.freewheel.SDK) {
if (tv.freewheel.SDK.version) {
return tv.freewheel.SDK.version;
}
// Method 2: Try VERSION constant
if (tv.freewheel.SDK.VERSION) {
return tv.freewheel.SDK.VERSION;
}
// Method 3: Try getVersion method if available
if (typeof tv.freewheel.SDK.getVersion === 'function') {
return tv.freewheel.SDK.getVersion();
}
}
// Method 4: Try to get from context if available
if (this.player && this.player.currentAdContext) {
var context = this.player.currentAdContext;
if (context._version) return context._version;
if (typeof context.getVersion === 'function') return context.getVersion();
}
} catch (err) {
// Ignore errors and return null
}
return null;
}
getPlayerName() {
return 'Freewheel';
}
getPosition() {
return this.position;
}
getAdInstertionType() {
return this.getNpawReference().Constants.AdInsertionType.ClientSide;
}
getIsVisible() {
if (!this.contentPlayer) {
for (var key in this.player) {
var element = this.player[key];
if (element && element.videoHeight && element.clientHeight) {
this.contentPlayer = element;
break;
}
}
}
return this.getNpawUtils().calculateAdViewability(this.contentPlayer);
}
getAudioEnabled() {
for (var key in this.player) {
var element = this.player[key];
if (element && element.adManager && element.adManager._context && element.adManager._context.getAdVolume) {
return !!element.adManager._context.getAdVolume();
}
}
}
getGivenAds() {
return this.slot.getAdCount();
}
getBreaksTime() {
var slots = this.getSlots();
if (!slots) return null;
var times = [];
try {
for (var slotindex in slots) {
var slot = slots[slotindex];
if (slot && typeof slot.getAdCount === 'function' && slot.getAdCount() > 0) {
var ads = typeof slot.getAdInstances === 'function' ? slot.getAdInstances() : null;
if (ads) {
for (var adindex in ads) {
// Check if ad has creative renditions and is a video ad
var ad = ads[adindex];
if (
ad &&
ad._creativeRenditions &&
ad._creativeRenditions.length > 0 &&
ad._creativeRenditions[0]._baseUnit === 'video'
) {
var position = typeof slot.getTimePosition === 'function' ? slot.getTimePosition() : 0;
// Try to get content duration to cap postroll times
var video = this.getVideo();
var contentDuration = video && typeof video.getDuration === 'function' ? video.getDuration() : null;
if (contentDuration && position > contentDuration) {
position = contentDuration;
}
times.push(position);
break;
}
}
}
}
}
} catch (err) {
// Ignore errors and return what we have
}
return times.length > 0 ? times : null;
}
getGivenBreaks() {
var slots = this.getSlots();
if (!slots) return null;
var breaks = 0;
try {
for (var slotindex in slots) {
var slot = slots[slotindex];
if (slot && typeof slot.getAdCount === 'function' && slot.getAdCount() > 0) {
var ads = typeof slot.getAdInstances === 'function' ? slot.getAdInstances() : null;
if (ads) {
for (var adindex in ads) {
var ad = ads[adindex];
if (this._isVideoAd(ad)) {
breaks++;
break;
}
}
}
}
}
} catch (err) {
// Ignore errors
}
return breaks > 0 ? breaks : null;
}
getExpectedBreaks() {
// In Freewheel, expected breaks should match the pattern
// We calculate it from the pattern to ensure consistency
var pattern = this.getExpectedPattern();
if (!pattern) return null;
var breaks = 0;
if (pattern.pre && pattern.pre.length > 0) breaks += pattern.pre.length;
if (pattern.mid && pattern.mid.length > 0) breaks += pattern.mid.length;
if (pattern.post && pattern.post.length > 0) breaks += pattern.post.length;
return breaks > 0 ? breaks : null;
}
getExpectedPattern() {
// Returns the pattern of ad breaks: {pre: [ads_count], mid: [ads_count, ...], post: [ads_count]}
var slots = this.getSlots();
if (!slots) return null;
var pattern = {
pre: [],
mid: [],
post: []
};
try {
for (var slotindex in slots) {
var slot = slots[slotindex];
if (!slot || typeof slot.getTimePositionClass !== 'function') continue;
var timeClass = slot.getTimePositionClass();
if (!timeClass) continue;
var cleanTimeClass = String(timeClass).trim().toUpperCase();
var adCount = 0;
var ads = typeof slot.getAdInstances === 'function' ? slot.getAdInstances() : null;
// Count video ads in this slot
if (ads) {
for (var adindex in ads) {
if (this._isVideoAd(ads[adindex])) {
adCount++;
}
}
}
// Only add if there are video ads in this slot
if (adCount > 0) {
// Add to the appropriate position array
if (cleanTimeClass === 'PREROLL') {
pattern.pre.push(adCount);
} else if (cleanTimeClass === 'MIDROLL') {
pattern.mid.push(adCount);
} else if (cleanTimeClass === 'POSTROLL') {
pattern.post.push(adCount);
}
}
}
} catch (err) {
// Ignore errors
}
// Only return pattern if at least one position has breaks
if (pattern.pre.length === 0 && pattern.mid.length === 0 && pattern.post.length === 0) {
return null;
}
return pattern;
}
getExpectedAds() {
// Returns the expected number of ads for the current break (slot)
if (!this.slot) return null;
var adCount = 0;
try {
var ads = typeof this.slot.getAdInstances === 'function' ? this.slot.getAdInstances() : null;
if (ads) {
for (var adindex in ads) {
if (this._isVideoAd(ads[adindex])) {
adCount++;
}
}
}
} catch (err) {
// Ignore errors
}
return adCount > 0 ? adCount : null;
}
/**
* Helper method to check if an ad instance is a video ad
* @param {Object} ad - Freewheel ad instance
* @returns {boolean} - True if the ad is a video ad
*/
_isVideoAd(ad) {
if (!ad) return false;
try {
// Check for video base unit in creative renditions
if (
ad._creativeRenditions &&
ad._creativeRenditions.length > 0 &&
ad._creativeRenditions[0]._baseUnit === 'video'
) {
return true;
}
// Alternative check using getActiveCreativeRendition
if (typeof ad.getActiveCreativeRendition === 'function') {
var rendition = ad.getActiveCreativeRendition();
if (rendition && (rendition._baseUnit === 'video' || rendition.baseUnit === 'video')) {
return true;
}
}
} catch (err) {
// Ignore errors
}
return false;
}
getCreativeId() {
var ret = null;
if (this.slot) {
var instances = this.slot.getAdInstances();
var adnumber = this._getAdNumber();
if (instances && instances[adnumber]) {
ret = instances[adnumber]._creativeId;
}
}
return ret;
}
getSlots() {
try {
// Method 1: Try to get from currentAdContext
if (this.player && this.player.currentAdContext) {
if (
this.player.currentAdContext._adResponse &&
typeof this.player.currentAdContext._adResponse.getTemporalSlots === 'function'
) {
return this.player.currentAdContext._adResponse.getTemporalSlots();
}
// Try getTemporalSlots directly on context
if (typeof this.player.currentAdContext.getTemporalSlots === 'function') {
return this.player.currentAdContext.getTemporalSlots();
}
}
// Method 2: Try to find _adResponse in player object
if (this.player) {
for (var key in this.player) {
var element = this.player[key];
if (element && element._adResponse && typeof element._adResponse.getTemporalSlots === 'function') {
return element._adResponse.getTemporalSlots();
}
}
}
// Method 3: Try to get from the current slot if available
if (this.slot && this.slot._parentSlots) {
return this.slot._parentSlots;
}
} catch (err) {
// Ignore errors
}
return null;
}
_getAdNumber() {
return (this.getVideo().requestBuilder.lastSent.adNumber || 1) - 1;
}
_getAdInstanceMethodCall(methdodName) {
var ret = null;
if (this.slot) {
var instances = this.slot.getAdInstances();
var adNumber = this._getAdNumber();
if (instances && instances[adNumber] && typeof instances[adNumber][methdodName] === 'function') {
ret = instances[adNumber][methdodName]();
}
}
return ret;
}
registerListeners() {
this.canRemoveListeners = true;
this.events = tv.freewheel.SDK;
this.manifestNoResponse = [this.events.ERROR_SECURITY, this.events.ERROR_TIMEOUT];
this.manifestEmpty = [this.events.ERROR_NO_AD_AVAILABLE, this.events.ERROR_VAST_NO_AD];
this.manifestWrong = [
this.events.ERROR_VAST_VERSION_NOT_SUPPORTED,
this.events.ERROR_VAST_WRAPPER_LIMIT_REACH,
this.events.ERROR_VAST_XML_PARSING,
this.events.ERROR_PARSE
];
this.ignoredErrors = [this.events.ERROR_ADINSTANCE_UNAVAILABLE];
this.references = {};
this.references[this.events.EVENT_AD] = this.logListener.bind(this);
this.references[this.events.EVENT_ERROR] = this.errorListener.bind(this);
this.references[this.events.EVENT_SLOT_STARTED] = this.slotListener.bind(this);
this.references[this.events.EVENT_SLOT_ENDED] = this.closeListener.bind(this);
for (var key in this.manifestNoResponse) {
this.references[key] = this.noResponseManifestListener.bind(this);
}
for (var key2 in this.manifestEmpty) {
this.references[key2] = this.manifestEmptyListener.bind(this);
}
for (var key3 in this.manifestWrong) {
this.references[key3] = this.manifestWrongListener.bind(this);
}
for (var key4 in this.references) {
this.player.currentAdContext.addEventListener(key4, this.references[key4]);
}
}
unregisterListeners() {
if (this.player && this.references) {
for (var key in this.references) {
this.player.currentAdContext.removeEventListener(key, this.references[key]);
}
this.references = {};
}
}
noResponseManifestListener() {
this.fireManifest(this.getNpawReference().Constants.ManifestError.NO_RESPONSE, 'No response');
}
manifestEmptyListener() {
this.fireManifest(this.getNpawReference().Constants.ManifestError.EMPTY, 'Empty manifest');
}
manifestWrongListener() {
this.fireManifest(this.getNpawReference().Constants.ManifestError.WRONG, 'Wrong manifest format');
}
logListener(e) {
this.log.debug(e.subType);
if (e.errorCode || e.errorInfo || e.errorModule) {
this.errorListener(e);
return;
}
switch (e.subType) {
case this.events.EVENT_AD_BUFFERING_START:
this._onAdBufferStart();
break;
case this.events.EVENT_AD_BUFFERING_END:
this._onAdBufferEnd();
break;
case this.events.EVENT_AD_PAUSE:
this.pauseListener(e);
break;
case this.events.EVENT_AD_RESUME:
this.resumeListener(e);
break;
case this.events.EVENT_AD_IMPRESSION_END:
this.endedListener(e);
break;
case this.events.EVENT_AD_INITIATED:
this.playListener(e);
break;
case this.events.EVENT_AD_IMPRESSION:
this.playingListener(e);
break;
case this.events.EVENT_AD_SKIPPED:
this.skipListener(e);
break;
case this.events.EVENT_SLOT_STARTED:
this.slotListener(e);
break;
case this.events.EVENT_AD_CLOSE:
case this.events.EVENT_SLOT_ENDED:
this.closeListener(e);
break;
case this.events.EVENT_AD_CLICK:
this.clickListener(e);
break;
case this.events.EVENT_AD_FIRST_QUARTILE:
this.fireQuartile(1);
break;
case this.events.EVENT_AD_MIDPOINT:
this.fireQuartile(2);
break;
case this.events.EVENT_AD_THIRD_QUARTILE:
this.fireQuartile(3);
break;
case this.events.ERROR_SECURITY:
case this.events.ERROR_TIMEOUT:
this.noResponseManifestListener(e);
break;
case this.events.ERROR_NO_AD_AVAILABLE:
case this.events.ERROR_VAST_NO_AD:
this.manifestEmptyListener(e);
break;
case this.events.ERROR_VAST_VERSION_NOT_SUPPORTED:
case this.events.ERROR_VAST_WRAPPER_LIMIT_REACH:
case this.events.ERROR_VAST_XML_PARSING:
case this.events.ERROR_PARSE:
this.manifestWrongListener(e);
break;
}
}
slotListener(e) {
this.slot = e.slot;
var adapter = this.getVideo().getAdapter();
this.disable = false;
const positionValue = this.slot.getTimePositionClass();
const cleanPositionValue = positionValue ? String(positionValue).trim().toUpperCase() : '';
switch (cleanPositionValue) {
case 'POSTROLL':
this.position = this.getNpawReference().Constants.AdPosition.Postroll;
break;
case 'MIDROLL':
this.position = this.getNpawReference().Constants.AdPosition.Midroll;
break;
case 'PREROLL':
if (adapter && adapter.flags.isJoined) {
this.position = this.getNpawReference().Constants.AdPosition.Midroll;
} else {
this.position = this.getNpawReference().Constants.AdPosition.Preroll;
}
break;
default:
this.disable = true;
}
if (!this.disable) {
this.titles = this.slot.getAdInstances();
this.unregister();
this.getVideo().fireInit();
this.fireInit();
}
}
playListener() {
if (!this.disable) {
this.fireStart();
}
}
playingListener() {
if (!this.disable) {
this.fireStart();
this.fireJoin();
// Only fire resume if we were paused (not on initial join)
if (this.flags && this.flags.isPaused) {
this.fireResume();
}
// Start tracking ad playhead
this._startAdPlayheadTracking();
// Start monitoring for buffer events
this._startBufferMonitoring();
}
}
pauseListener() {
if (!this.disable && this.flags && this.flags.isJoined) {
this._stopAdPlayheadTracking();
// Don't stop buffer monitoring during pause
this.firePause();
}
}
resumeListener() {
if (!this.disable && this.flags && this.flags.isPaused) {
this.fireResume();
this._startAdPlayheadTracking();
// Resume buffer monitoring after pause
this._startBufferMonitoring();
}
}
endedListener() {
this._stopAdPlayheadTracking();
this._stopBufferMonitoring();
this.fireStop();
}
_startAdPlayheadTracking() {
// Clear any existing tracking
this._stopAdPlayheadTracking();
// Initialize playhead
this._adPlayhead = 0;
this._adPlayheadStartTime = Date.now();
// Update playhead every 100ms
this._adPlayheadInterval = setInterval(() => {
if (this._adPlayheadStartTime) {
this._adPlayhead = (Date.now() - this._adPlayheadStartTime) / 1000;
}
}, 100);
}
_stopAdPlayheadTracking() {
if (this._adPlayheadInterval) {
clearInterval(this._adPlayheadInterval);
this._adPlayheadInterval = null;
}
}
_startBufferMonitoring() {
// Stop any existing monitoring
this._stopBufferMonitoring();
// Find the video element using the improved method
this._adVideoElement = this._getVideoElement();
if (this._adVideoElement) {
// Create bound handlers
this._bufferWaitingHandler = this._onAdBufferStart.bind(this);
this._bufferPlayingHandler = this._onAdBufferEnd.bind(this);
this._bufferStalledHandler = this._onAdBufferStart.bind(this);
// Listen for buffer events
this._adVideoElement.addEventListener('waiting', this._bufferWaitingHandler);
this._adVideoElement.addEventListener('stalled', this._bufferStalledHandler);
this._adVideoElement.addEventListener('playing', this._bufferPlayingHandler);
this._adVideoElement.addEventListener('canplay', this._bufferPlayingHandler);
this._adVideoElement.addEventListener('canplaythrough', this._bufferPlayingHandler);
}
}
_stopBufferMonitoring() {
if (this._adVideoElement) {
if (this._bufferWaitingHandler) {
this._adVideoElement.removeEventListener('waiting', this._bufferWaitingHandler);
}
if (this._bufferStalledHandler) {
this._adVideoElement.removeEventListener('stalled', this._bufferStalledHandler);
}
if (this._bufferPlayingHandler) {
this._adVideoElement.removeEventListener('playing', this._bufferPlayingHandler);
this._adVideoElement.removeEventListener('canplay', this._bufferPlayingHandler);
this._adVideoElement.removeEventListener('canplaythrough', this._bufferPlayingHandler);
}
}
this._bufferWaitingHandler = null;
this._bufferStalledHandler = null;
this._bufferPlayingHandler = null;
this._adVideoElement = null;
this._isBuffering = false;
}
_onAdBufferStart() {
// Only fire buffer if we're joined (playing) and not already buffering
if (!this._isBuffering && this.flags && this.flags.isJoined) {
this._isBuffering = true;
this._bufferStartTime = Date.now();
this.fireBufferBegin();
}
}
_onAdBufferEnd() {
if (this._isBuffering) {
this._isBuffering = false;
if (this._bufferStartTime) {
this._lastBufferDuration = Date.now() - this._bufferStartTime;
}
this.fireBufferEnd();
}
}
getBufferDuration() {
// Return the last buffer duration in milliseconds
return this._lastBufferDuration || null;
}
getBitrate() {
// Try to get bitrate from Freewheel SDK
var creativeRendition = this._getAdInstanceMethodCall('getActiveCreativeRendition');
if (creativeRendition) {
try {
// Try asset bitrate
if (typeof creativeRendition.getPrimaryCreativeRenditionAsset === 'function') {
var asset = creativeRendition.getPrimaryCreativeRenditionAsset();
if (asset) {
if (typeof asset.getBitrate === 'function') {
var bitrate = asset.getBitrate();
if (bitrate > 0) return bitrate;
}
if (asset.bitrate > 0) return asset.bitrate;
if (asset._bitrate > 0) return asset._bitrate;
}
}
// Try creative rendition bitrate
if (typeof creativeRendition.getBitrate === 'function') {
var br = creativeRendition.getBitrate();
if (br > 0) return br;
}
if (creativeRendition.bitrate > 0) return creativeRendition.bitrate;
if (creativeRendition._bitrate > 0) return creativeRendition._bitrate;
} catch (err) {
// Continue to fallback
}
}
// Fallback: Calculate bitrate from video element's decoded bytes
var videoElement = this._getVideoElement();
if (videoElement && videoElement.webkitVideoDecodedByteCount) {
var currentBytes = videoElement.webkitVideoDecodedByteCount;
if (this._lastDecodedBytes && this._lastBitrateTime) {
var bytesDelta = currentBytes - this._lastDecodedBytes;
var timeDelta = (Date.now() - this._lastBitrateTime) / 1000;
if (timeDelta > 0 && bytesDelta > 0) {
var calculatedBitrate = Math.round((bytesDelta * 8) / timeDelta);
this._lastDecodedBytes = currentBytes;
this._lastBitrateTime = Date.now();
return calculatedBitrate > 0 ? calculatedBitrate : -1;
}
}
this._lastDecodedBytes = currentBytes;
this._lastBitrateTime = Date.now();
}
return -1;
}
getRendition() {
var width = null;
var height = null;
var bitrate = null;
// Try to get from Freewheel creative rendition first
var creativeRendition = this._getAdInstanceMethodCall('getActiveCreativeRendition');
if (creativeRendition) {
try {
// Try direct properties first
width = creativeRendition._width || creativeRendition.width;
height = creativeRendition._height || creativeRendition.height;
bitrate = creativeRendition._bitrate || creativeRendition.bitrate;
// Then try getter methods
if (!width && typeof creativeRendition.getWidth === 'function') {
width = creativeRendition.getWidth();
}
if (!height && typeof creativeRendition.getHeight === 'function') {
height = creativeRendition.getHeight();
}
if (!bitrate && typeof creativeRendition.getBitrate === 'function') {
bitrate = creativeRendition.getBitrate();
}
// Try to get from primary asset if rendition doesn't have it
if (
(!width || !height || !bitrate) &&
typeof creativeRendition.getPrimaryCreativeRenditionAsset === 'function'
) {
var asset = creativeRendition.getPrimaryCreativeRenditionAsset();
if (asset) {
if (!width)
width = asset._width || asset.width || (typeof asset.getWidth === 'function' ? asset.getWidth() : null);
if (!height)
height =
asset._height || asset.height || (typeof asset.getHeight === 'function' ? asset.getHeight() : null);
if (!bitrate)
bitrate =
asset._bitrate || asset.bitrate || (typeof asset.getBitrate === 'function' ? asset.getBitrate() : null);
}
}
} catch (err) {
// Continue to fallback
}
}
// Fallback to video element if SDK doesn't provide dimensions
var videoElement = this._getVideoElement();
if (videoElement) {
if (!width || width <= 0) width = videoElement.videoWidth;
if (!height || height <= 0) height = videoElement.videoHeight;
}
// Convert bitrate to number if needed and validate
if (bitrate) {
bitrate = Number(bitrate);
if (isNaN(bitrate) || bitrate <= 0) bitrate = null;
}
// Build rendition string: resolution@bitrate (e.g., "1920x1080@2500Kbps")
if ((width > 0 && height > 0) || (bitrate && bitrate > 0)) {
return this.getNpawUtils().buildRenditionString(width, height, bitrate);
}
return null;
}
getThroughput() {
// Freewheel SDK doesn't provide throughput directly
// Return -1 to indicate not available
return -1;
}
_getVideoElement() {
// Check if cached element is still valid
if (this._cachedVideoElement && this._cachedVideoElement.parentNode) {
return this._cachedVideoElement;
}
this._cachedVideoElement = null;
// Method 1: Check this.player directly for video elements
if (this.player) {
for (var key in this.player) {
var element = this.player[key];
if (element && element.tagName && element.tagName.toLowerCase() === 'video') {
this._cachedVideoElement = element;
return this._cachedVideoElement;
}
}
}
// Method 2: Try to get from adContext if available
try {
if (this.player && this.player.currentAdContext) {
var context = this.player.currentAdContext;
// Try getContentVideoElement
if (typeof context.getContentVideoElement === 'function') {
var contentVideo = context.getContentVideoElement();
if (contentVideo) {
this._cachedVideoElement = contentVideo;
return this._cachedVideoElement;
}
}
// Try _videoElement
if (context._videoElement) {
this._cachedVideoElement = context._videoElement;
return this._cachedVideoElement;
}
}
} catch (err) {
// Continue to fallback
}
// Method 3: Try to find video element in slot's video display
try {
if (this.slot && typeof this.slot.getVideoDisplayBase === 'function') {
var videoDisplay = this.slot.getVideoDisplayBase();
if (videoDisplay && videoDisplay._videoElement) {
this._cachedVideoElement = videoDisplay._videoElement;
return this._cachedVideoElement;
}
}
} catch (err) {
// Continue to fallback
}
// Method 4: Fallback to finding any video element in the DOM that's playing ad content
try {
var videos = document.querySelectorAll('video');
for (var i = 0; i < videos.length; i++) {
var video = videos[i];
// Look for a video that is currently playing and has duration
if (video && video.duration > 0 && !video.paused) {
this._cachedVideoElement = video;
return this._cachedVideoElement;
}
}
// If no playing video, try to find any video with a source
for (var j = 0; j < videos.length; j++) {
var v = videos[j];
if (v && (v.src || v.currentSrc)) {
this._cachedVideoElement = v;
return this._cachedVideoElement;
}
}
} catch (err) {
// Ignore DOM access errors
}
return this._cachedVideoElement;
}
skipListener() {
this._stopAdPlayheadTracking();
this._stopBufferMonitoring();
this.fireSkip();
}
clickListener(e) {
var url = e.adInstance.getEventCallbackUrls(tv.freewheel.SDK.EVENT_AD_CLICK, tv.freewheel.SDK.EVENT_TYPE_CLICK)[0];
var now = new Date().getTime();
if (this.lastUrl === url && now < (this.lastTime || 0) + 2000) {
return;
}
this.lastUrl = url;
this.lastTime = now;
this.fireClick(url);
}
closeListener() {
this._stopAdPlayheadTracking();
this._stopBufferMonitoring();
this.register();
if (this.position === this.getNpawReference().Constants.AdPosition.Postroll && !this.disable) {
this.getVideo().fireStop();
}
}
errorListener(e) {
this._stopAdPlayheadTracking();
this._stopBufferMonitoring();
this.fireError(e.errorCode || e.subType, e.errorInfo);
this.fireStop();
}
register() {
var adapter = this.getVideo().getAdapter();
if (adapter && !this.canRemoveListeners) {
adapter.registerListeners();
adapter.fireResume();
this.canRemoveListeners = true;
}
}
unregister() {
var adapter = this.getVideo().getAdapter();
if (adapter && this.canRemoveListeners) {
this.canRemoveListeners = false;
adapter.unregisterListeners();
adapter.firePause();
}
}
changeVideo() {
if (this.flags.isStarted || this.flags.isInited) {
this.fireStop();
this.getVideo().fireStop();
this.register();
}
}
}