-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
freewheelSSPBidAdapter #4645
freewheelSSPBidAdapter #4645
Changes from 5 commits
cd6267a
30cce3c
59dfcd5
eae2a4a
54ab273
2fad698
76a625a
382d914
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,372 @@ | ||
import * as utils from '../src/utils'; | ||
import { registerBidder } from '../src/adapters/bidderFactory'; | ||
// import { config } from 'src/config'; | ||
|
||
const BIDDER_CODE = 'freewheel-ssp'; | ||
|
||
const PROTOCOL = getProtocol(); | ||
const FREEWHEEL_ADSSETUP = PROTOCOL + '://ads.stickyadstv.com/www/delivery/swfIndex.php'; | ||
const MUSTANG_URL = PROTOCOL + '://cdn.stickyadstv.com/mustang/mustang.min.js'; | ||
const PRIMETIME_URL = PROTOCOL + '://cdn.stickyadstv.com/prime-time/'; | ||
const USER_SYNC_URL = PROTOCOL + '://ads.stickyadstv.com/auto-user-sync'; | ||
|
||
function getProtocol() { | ||
return 'https'; | ||
} | ||
|
||
function isValidUrl(str) { | ||
if (!str) { | ||
return false; | ||
} | ||
|
||
// regExp for url validation | ||
var pattern = /^(https?|ftp|file):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/; | ||
return pattern.test(str); | ||
} | ||
|
||
function getBiggerSize(array) { | ||
var result = [0, 0]; | ||
for (var i = 0; i < array.length; i++) { | ||
if (array[i][0] * array[i][1] > result[0] * result[1]) { | ||
result = array[i]; | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
function getBiggerSizeWithLimit(array, minSizeLimit, maxSizeLimit) { | ||
var minSize = minSizeLimit || [0, 0]; | ||
var maxSize = maxSizeLimit || [Number.MAX_VALUE, Number.MAX_VALUE]; | ||
var candidates = []; | ||
|
||
for (var i = 0; i < array.length; i++) { | ||
if (array[i][0] * array[i][1] >= minSize[0] * minSize[1] && array[i][0] * array[i][1] <= maxSize[0] * maxSize[1]) { | ||
candidates.push(array[i]); | ||
} | ||
} | ||
|
||
return getBiggerSize(candidates); | ||
} | ||
|
||
/* | ||
* read the pricing extension with this format: <Extension type='StickyPricing'><Price currency="EUR">1.0000</Price></Extension> | ||
* @return {object} pricing data in format: {currency: "EUR", price:"1.000"} | ||
*/ | ||
function getPricing(xmlNode) { | ||
var pricingExtNode; | ||
var princingData = {}; | ||
|
||
var extensions = xmlNode.querySelectorAll('Extension'); | ||
// Nodelist.forEach is not supported in IE and Edge | ||
// Workaround given here https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10638731/ | ||
Array.prototype.forEach.call(extensions, function(node) { | ||
if (node.getAttribute('type') === 'StickyPricing') { | ||
pricingExtNode = node; | ||
} | ||
}); | ||
|
||
if (pricingExtNode) { | ||
var priceNode = pricingExtNode.querySelector('Price'); | ||
princingData = { | ||
currency: priceNode.getAttribute('currency'), | ||
price: priceNode.textContent || priceNode.innerText | ||
}; | ||
} else { | ||
utils.logWarn('PREBID - ' + BIDDER_CODE + ': Can\'t get pricing data. Is price awareness enabled?'); | ||
} | ||
|
||
return princingData; | ||
} | ||
|
||
function hashcode(inputString) { | ||
var hash = 0; | ||
var char; | ||
if (inputString.length == 0) return hash; | ||
for (var i = 0; i < inputString.length; i++) { | ||
char = inputString.charCodeAt(i); | ||
hash = ((hash << 5) - hash) + char; | ||
hash = hash & hash; // Convert to 32bit integer | ||
} | ||
return hash; | ||
} | ||
|
||
function getCreativeId(xmlNode) { | ||
var creaId = ''; | ||
var adNodes = xmlNode.querySelectorAll('Ad'); | ||
// Nodelist.forEach is not supported in IE and Edge | ||
// Workaround given here https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10638731/ | ||
Array.prototype.forEach.call(adNodes, function(el) { | ||
creaId += '[' + el.getAttribute('id') + ']'; | ||
}); | ||
|
||
return creaId; | ||
} | ||
|
||
/** | ||
* returns the top most accessible window | ||
*/ | ||
function getTopMostWindow() { | ||
var res = window; | ||
|
||
try { | ||
while (top !== res) { | ||
if (res.parent.location.href.length) { res = res.parent; } | ||
} | ||
} catch (e) {} | ||
|
||
return res; | ||
} | ||
|
||
function getComponentId(inputFormat) { | ||
var component = 'mustang'; // default component id | ||
|
||
if (inputFormat && inputFormat !== 'inbanner') { | ||
// format identifiers are equals to their component ids. | ||
component = inputFormat; | ||
} | ||
|
||
return component; | ||
} | ||
|
||
function getAPIName(componentId) { | ||
componentId = componentId || ''; | ||
|
||
// remove dash in componentId to get API name | ||
return componentId.replace('-', ''); | ||
} | ||
|
||
function formatAdHTML(bid, size) { | ||
var integrationType = bid.params.format; | ||
|
||
var divHtml = '<div id="freewheelssp_prebid_target" style="width:' + size[0] + 'px;height:' + size[1] + 'px;"></div>'; | ||
|
||
var script = ''; | ||
var libUrl = ''; | ||
if (integrationType && integrationType !== 'inbanner') { | ||
libUrl = PRIMETIME_URL + getComponentId(bid.params.format) + '.min.js'; | ||
script = getOutstreamScript(bid, size); | ||
} else { | ||
libUrl = MUSTANG_URL; | ||
script = getInBannerScript(bid, size); | ||
} | ||
|
||
return divHtml + | ||
'<script type=\'text/javascript\'>' + | ||
'(function() {' + | ||
' var st = document.createElement(\'script\'); st.type = \'text/javascript\'; st.async = true;' + | ||
' st.src = \'' + libUrl + '\';' + | ||
' st.onload = function(){' + | ||
' var vastLoader = new window.com.stickyadstv.vast.VastLoader();' + | ||
' var vast = vastLoader.getVast();' + | ||
// get the top most accessible window | ||
' var topWindow = (function(){var res=window; try{while(top != res){if(res.parent.location.href.length)res=res.parent;}}catch(e){}return res;})();' + | ||
// inject the xml in the Vast object as string | ||
' vast.setXmlString(topWindow.freewheelssp_cache["' + bid.adUnitCode + '"]);' + | ||
// force ad parsing on the given vast xml | ||
' vastLoader.parseAds(vast, {' + | ||
' onSuccess: function() {' + script + ' }' + | ||
' });' + | ||
' };' + | ||
' document.head.appendChild(st);' + | ||
'})();' + | ||
'</script>'; | ||
} | ||
|
||
var getInBannerScript = function(bid, size) { | ||
return 'var config = {' + | ||
' preloadedVast:vast,' + | ||
' autoPlay:true' + | ||
' };' + | ||
' var ad = new window.com.stickyadstv.vpaid.Ad(document.getElementById("freewheelssp_prebid_target"),config);' + | ||
' (new window.com.stickyadstv.tools.ASLoader(' + bid.params.zoneId + ', \'' + getComponentId(bid.params.format) + '\')).registerEvents(ad);' + | ||
' ad.initAd(' + size[0] + ',' + size[1] + ',"",0,"","");'; | ||
}; | ||
|
||
var getOutstreamScript = function(bid) { | ||
var config = bid.params; | ||
|
||
// default placement if no placement is set | ||
if (!config.hasOwnProperty('domId') && !config.hasOwnProperty('auto') && !config.hasOwnProperty('p') && !config.hasOwnProperty('article')) { | ||
if (config.format === 'intext-roll') { | ||
config.iframeMode = 'dfp'; | ||
} else { | ||
config.domId = 'freewheelssp_prebid_target'; | ||
} | ||
} | ||
|
||
var script = 'var config = {' + | ||
' preloadedVast:vast,' + | ||
' ASLoader:new window.com.stickyadstv.tools.ASLoader(' + bid.params.zoneId + ', \'' + getComponentId(bid.params.format) + '\')'; | ||
|
||
for (var key in config) { | ||
// dont' send format parameter | ||
// neither zone nor vastUrlParams value as Vast is already loaded | ||
if (config.hasOwnProperty(key) && key !== 'format' && key !== 'zone' && key !== 'zoneId' && key !== 'vastUrlParams') { | ||
script += ',' + key + ':"' + config[key] + '"'; | ||
} | ||
} | ||
script += '};' + | ||
|
||
'window.com.stickyadstv.' + getAPIName(bid.params.format) + '.start(config);'; | ||
|
||
return script; | ||
}; | ||
|
||
export const spec = { | ||
code: BIDDER_CODE, | ||
supportedMediaTypes: ['banner', 'video'], | ||
aliases: ['stickyadstv'], // former name for freewheel-ssp | ||
/** | ||
* Determines whether or not the given bid request is valid. | ||
* | ||
* @param {object} bid The bid to validate. | ||
* @return boolean True if this is a valid bid, and false otherwise. | ||
*/ | ||
isBidRequestValid: function(bid) { | ||
return !!(bid.params.zoneId); | ||
}, | ||
|
||
/** | ||
* Make a server request from the list of BidRequests. | ||
* | ||
* @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server. | ||
* @return ServerRequest Info describing the request to the server. | ||
*/ | ||
buildRequests: function(bidRequests, bidderRequest) { | ||
// var currency = config.getConfig(currency); | ||
|
||
var currentBidRequest = bidRequests[0]; | ||
if (bidRequests.length > 1) { | ||
utils.logMessage('Prebid.JS - freewheel bid adapter: only one ad unit is required.'); | ||
} | ||
|
||
var zone = currentBidRequest.params.zoneId; | ||
var timeInMillis = new Date().getTime(); | ||
var keyCode = hashcode(zone + '' + timeInMillis); | ||
var requestParams = { | ||
reqType: 'AdsSetup', | ||
protocolVersion: '2.0', | ||
zoneId: zone, | ||
componentId: getComponentId(currentBidRequest.params.format), | ||
timestamp: timeInMillis, | ||
pKey: keyCode | ||
}; | ||
|
||
// Add GDPR flag and consent string | ||
if (bidderRequest.gdprConsent) { | ||
requestParams._fw_gdpr_consent = bidderRequest.gdprConsent.consentString; | ||
|
||
if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { | ||
requestParams._fw_gdpr = bidderRequest.gdprConsent.gdprApplies; | ||
} | ||
} | ||
|
||
if (currentBidRequest.params.gdpr_consented_providers) { | ||
requestParams._fw_gdpr_consented_providers = currentBidRequest.params.gdpr_consented_providers; | ||
} | ||
|
||
var vastParams = currentBidRequest.params.vastUrlParams; | ||
if (typeof vastParams === 'object') { | ||
for (var key in vastParams) { | ||
if (vastParams.hasOwnProperty(key)) { | ||
requestParams[key] = vastParams[key]; | ||
} | ||
} | ||
} | ||
|
||
var location = utils.getTopWindowUrl(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function doesn't exist anymore in Prebid 3.x. Can you take a look at the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated. |
||
if (isValidUrl(location)) { | ||
requestParams.loc = location; | ||
} | ||
|
||
var playerSize = getBiggerSizeWithLimit(currentBidRequest.mediaTypes.banner.sizes, currentBidRequest.mediaTypes.banner.minSizeLimit, currentBidRequest.mediaTypes.banner.maxSizeLimit); | ||
|
||
if (playerSize[0] > 0 || playerSize[1] > 0) { | ||
requestParams.playerSize = playerSize[0] + 'x' + playerSize[1]; | ||
} | ||
|
||
return { | ||
method: 'GET', | ||
url: FREEWHEEL_ADSSETUP, | ||
data: requestParams, | ||
bidRequest: currentBidRequest | ||
}; | ||
}, | ||
|
||
/** | ||
* Unpack the response from the server into a list of bids. | ||
* | ||
* @param {*} serverResponse A successful response from the server. | ||
* @param {object} request: the built request object containing the initial bidRequest. | ||
* @return {Bid[]} An array of bids which were nested inside the server. | ||
*/ | ||
interpretResponse: function(serverResponse, request) { | ||
var bidrequest = request.bidRequest; | ||
var playerSize = getBiggerSizeWithLimit(bidrequest.mediaTypes.banner.sizes, bidrequest.mediaTypes.banner.minSizeLimit, bidrequest.mediaTypes.banner.maxSizeLimit); | ||
|
||
if (typeof serverResponse == 'object' && typeof serverResponse.body == 'string') { | ||
serverResponse = serverResponse.body; | ||
} | ||
|
||
var xmlDoc; | ||
try { | ||
var parser = new DOMParser(); | ||
xmlDoc = parser.parseFromString(serverResponse, 'application/xml'); | ||
} catch (err) { | ||
utils.logWarn('Prebid.js - ' + BIDDER_CODE + ' : ' + err); | ||
return; | ||
} | ||
|
||
const princingData = getPricing(xmlDoc); | ||
const creativeId = getCreativeId(xmlDoc); | ||
|
||
const topWin = getTopMostWindow(); | ||
if (!topWin.freewheelssp_cache) { | ||
topWin.freewheelssp_cache = {}; | ||
} | ||
topWin.freewheelssp_cache[bidrequest.adUnitCode] = serverResponse; | ||
|
||
const bidResponses = []; | ||
|
||
if (princingData.price) { | ||
const bidResponse = { | ||
requestId: bidrequest.bidId, | ||
cpm: princingData.price, | ||
width: playerSize[0], | ||
height: playerSize[1], | ||
creativeId: creativeId, | ||
currency: princingData.currency, | ||
netRevenue: true, | ||
ttl: 360 | ||
}; | ||
|
||
var mediaTypes = bidrequest.mediaTypes || {}; | ||
if (mediaTypes.video) { | ||
// bidResponse.vastXml = serverResponse; | ||
bidResponse.mediaType = 'video'; | ||
|
||
var blob = new Blob([serverResponse], {type: 'application/xml'}); | ||
bidResponse.vastUrl = window.URL.createObjectURL(blob); | ||
} else { | ||
bidResponse.ad = formatAdHTML(bidrequest, playerSize); | ||
} | ||
|
||
bidResponses.push(bidResponse); | ||
} | ||
|
||
return bidResponses; | ||
}, | ||
|
||
getUserSyncs: function(syncOptions) { | ||
if (syncOptions && syncOptions.pixelEnabled) { | ||
return [{ | ||
type: 'image', | ||
url: USER_SYNC_URL | ||
}]; | ||
} else { | ||
return []; | ||
} | ||
}, | ||
|
||
} | ||
registerBidder(spec); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please remove this commented line if it's no longer needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed