UNPKG

mk9-prebid

Version:

Header Bidding Management Library

323 lines (315 loc) 10.1 kB
import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import * as utils from '../src/utils.js'; import {config} from '../src/config.js'; const BIDDER_CODE = 'bizzclick'; const ACCOUNTID_MACROS = '[account_id]'; const URL_ENDPOINT = `https://us-e-node1.bizzclick.com/bid?rtb_seat_id=prebidjs&secret_key=${ACCOUNTID_MACROS}`; const NATIVE_ASSET_IDS = { 0: 'title', 2: 'icon', 3: 'image', 5: 'sponsoredBy', 4: 'body', 1: 'cta' }; const NATIVE_PARAMS = { title: { id: 0, name: 'title' }, icon: { id: 2, type: 1, name: 'img' }, image: { id: 3, type: 3, name: 'img' }, sponsoredBy: { id: 5, name: 'data', type: 1 }, body: { id: 4, name: 'data', type: 2 }, cta: { id: 1, type: 12, name: 'data' } }; const NATIVE_VERSION = '1.2'; export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO, NATIVE], /** * 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: (bid) => { return Boolean(bid.params.accountId) && Boolean(bid.params.placementId) }, /** * Make a server request from the list of BidRequests. * * @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server. * @return ServerRequest Info describing the request to the server. */ buildRequests: (validBidRequests, bidderRequest) => { if (validBidRequests && validBidRequests.length === 0) return [] let accuontId = validBidRequests[0].params.accountId; const endpointURL = URL_ENDPOINT.replace(ACCOUNTID_MACROS, accuontId); let winTop = window; let location; try { location = new URL(bidderRequest.refererInfo.referer) winTop = window.top; } catch (e) { location = winTop.location; utils.logMessage(e); }; let bids = []; for (let bidRequest of validBidRequests) { let impObject = prepareImpObject(bidRequest); let data = { id: bidRequest.bidId, test: config.getConfig('debug') ? 1 : 0, at: 1, cur: ['USD'], device: { w: winTop.screen.width, h: winTop.screen.height, dnt: utils.getDNT() ? 1 : 0, language: (navigator && navigator.language) ? navigator.language.indexOf('-') != -1 ? navigator.language.split('-')[0] : navigator.language : '', }, site: { page: location.pathname, host: location.host }, source: { tid: bidRequest.transactionId }, regs: { coppa: config.getConfig('coppa') === true ? 1 : 0, ext: {} }, user: { ext: {} }, ext: { ts: Date.now() }, tmax: bidRequest.timeout, imp: [impObject], }; if (bidderRequest && bidderRequest.uspConsent) { data.regs.ext.us_privacy = bidderRequest.uspConsent; } if (bidderRequest && bidderRequest.gdprConsent) { let { gdprApplies, consentString } = bidderRequest.gdprConsent; data.regs.ext.gdpr = gdprApplies ? 1 : 0; data.user.ext.consent = consentString; } if (bidRequest.schain) { data.source.ext.schain = bidRequest.schain; } let connection = navigator.connection || navigator.webkitConnection; if (connection && connection.effectiveType) { data.device.connectiontype = connection.effectiveType; } if (bidRequest) { if (bidRequest.gdprConsent && bidRequest.gdprConsent.gdprApplies) { utils.deepSetValue(data, 'regs.ext.gdpr', bidRequest.gdprConsent.gdprApplies ? 1 : 0); utils.deepSetValue(data, 'user.ext.consent', bidRequest.gdprConsent.consentString); } if (bidRequest.uspConsent !== undefined) { utils.deepSetValue(data, 'regs.ext.us_privacy', bidRequest.uspConsent); } } bids.push(data) } return { method: 'POST', url: endpointURL, data: bids }; }, /** * Unpack the response from the server into a list of bids. * * @param {*} serverResponse A successful response from the server. * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: (serverResponse) => { if (!serverResponse || !serverResponse.body) return [] let bizzclickResponse = serverResponse.body; let bids = []; for (let response of bizzclickResponse) { let mediaType = response.seatbid[0].bid[0].ext && response.seatbid[0].bid[0].ext.mediaType ? response.seatbid[0].bid[0].ext.mediaType : BANNER; let bid = { requestId: response.id, cpm: response.seatbid[0].bid[0].price, width: response.seatbid[0].bid[0].w, height: response.seatbid[0].bid[0].h, ttl: response.ttl || 1200, currency: response.cur || 'USD', netRevenue: true, creativeId: response.seatbid[0].bid[0].crid, dealId: response.seatbid[0].bid[0].dealid, mediaType: mediaType }; bid.meta = {}; if (response.seatbid[0].bid[0].adomain && response.seatbid[0].bid[0].adomain.length > 0) { bid.meta.advertiserDomains = response.seatbid[0].bid[0].adomain; } switch (mediaType) { case VIDEO: bid.vastXml = response.seatbid[0].bid[0].adm bid.vastUrl = response.seatbid[0].bid[0].ext.vastUrl break case NATIVE: bid.native = parseNative(response.seatbid[0].bid[0].adm) break default: bid.ad = response.seatbid[0].bid[0].adm } bids.push(bid); } return bids; }, }; /** * Determine type of request * * @param bidRequest * @param type * @returns {boolean} */ const checkRequestType = (bidRequest, type) => { return (typeof utils.deepAccess(bidRequest, `mediaTypes.${type}`) !== 'undefined'); } const parseNative = admObject => { const { assets, link, imptrackers, jstracker } = admObject.native; const result = { clickUrl: link.url, clickTrackers: link.clicktrackers || undefined, impressionTrackers: imptrackers || undefined, javascriptTrackers: jstracker ? [ jstracker ] : undefined }; assets.forEach(asset => { const kind = NATIVE_ASSET_IDS[asset.id]; const content = kind && asset[NATIVE_PARAMS[kind].name]; if (content) { result[kind] = content.text || content.value || { url: content.url, width: content.w, height: content.h }; } }); return result; } const prepareImpObject = (bidRequest) => { let impObject = { id: bidRequest.transactionId, secure: 1, ext: { placementId: bidRequest.params.placementId } }; if (checkRequestType(bidRequest, BANNER)) { impObject.banner = addBannerParameters(bidRequest); } if (checkRequestType(bidRequest, VIDEO)) { impObject.video = addVideoParameters(bidRequest); } if (checkRequestType(bidRequest, NATIVE)) { impObject.native = { ver: NATIVE_VERSION, request: addNativeParameters(bidRequest) }; } return impObject }; const addNativeParameters = bidRequest => { let impObject = { id: bidRequest.transactionId, ver: NATIVE_VERSION, }; const assets = utils._map(bidRequest.mediaTypes.native, (bidParams, key) => { const props = NATIVE_PARAMS[key]; const asset = { required: bidParams.required & 1, }; if (props) { asset.id = props.id; let wmin, hmin; let aRatios = bidParams.aspect_ratios; if (aRatios && aRatios[0]) { aRatios = aRatios[0]; wmin = aRatios.min_width || 0; hmin = aRatios.ratio_height * wmin / aRatios.ratio_width | 0; } if (bidParams.sizes) { const sizes = flatten(bidParams.sizes); wmin = sizes[0]; hmin = sizes[1]; } asset[props.name] = {} if (bidParams.len) asset[props.name]['len'] = bidParams.len; if (props.type) asset[props.name]['type'] = props.type; if (wmin) asset[props.name]['wmin'] = wmin; if (hmin) asset[props.name]['hmin'] = hmin; return asset; } }).filter(Boolean); impObject.assets = assets; return impObject } const addBannerParameters = (bidRequest) => { let bannerObject = {}; const size = parseSizes(bidRequest, 'banner'); bannerObject.w = size[0]; bannerObject.h = size[1]; return bannerObject; }; const parseSizes = (bid, mediaType) => { let mediaTypes = bid.mediaTypes; if (mediaType === 'video') { let size = []; if (mediaTypes.video && mediaTypes.video.w && mediaTypes.video.h) { size = [ mediaTypes.video.w, mediaTypes.video.h ]; } else if (Array.isArray(utils.deepAccess(bid, 'mediaTypes.video.playerSize')) && bid.mediaTypes.video.playerSize.length === 1) { size = bid.mediaTypes.video.playerSize[0]; } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0 && Array.isArray(bid.sizes[0]) && bid.sizes[0].length > 1) { size = bid.sizes[0]; } return size; } let sizes = []; if (Array.isArray(mediaTypes.banner.sizes)) { sizes = mediaTypes.banner.sizes[0]; } else if (Array.isArray(bid.sizes) && bid.sizes.length > 0) { sizes = bid.sizes } else { utils.logWarn('no sizes are setup or found'); } return sizes } const addVideoParameters = (bidRequest) => { let videoObj = {}; let supportParamsList = ['mimes', 'minduration', 'maxduration', 'protocols', 'startdelay', 'placement', 'skip', 'skipafter', 'minbitrate', 'maxbitrate', 'delivery', 'playbackmethod', 'api', 'linearity'] for (let param of supportParamsList) { if (bidRequest.mediaTypes.video[param] !== undefined) { videoObj[param] = bidRequest.mediaTypes.video[param]; } } const size = parseSizes(bidRequest, 'video'); videoObj.w = size[0]; videoObj.h = size[1]; return videoObj; } const flatten = arr => { return [].concat(...arr); } registerBidder(spec);