UNPKG

mk9-prebid

Version:

Header Bidding Management Library

407 lines (372 loc) 14.5 kB
import * as utils from '../src/utils.js'; import { Renderer } from '../src/Renderer.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO } from '../src/mediaTypes.js'; const BIDDER_CODE = 'smartx'; const URL = 'https://bid.sxp.smartclip.net/bid/1000'; export const spec = { code: BIDDER_CODE, supportedMediaTypes: [VIDEO], /** * Determines whether or not the given bid request is valid. * From Prebid.js: isBidRequestValid - Verify the the AdUnits.bids, respond with true (valid) or false (invalid). * * @param {object} bid The bid to validate. * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { if (bid && typeof bid.params !== 'object') { utils.logError(BIDDER_CODE + ': params is not defined or is incorrect in the bidder settings.'); return false; } if (!utils.deepAccess(bid, 'mediaTypes.video')) { utils.logError(BIDDER_CODE + ': mediaTypes.video is not present in the bidder settings.'); return false; } const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); if (!playerSize || !utils.isArray(playerSize)) { utils.logError(BIDDER_CODE + ': mediaTypes.video.playerSize is not defined in the bidder settings.'); return false; } if (!utils.getBidIdParameter('tagId', bid.params)) { utils.logError(BIDDER_CODE + ': tagId is not present in bidder params'); return false; } if (!utils.getBidIdParameter('publisherId', bid.params)) { utils.logError(BIDDER_CODE + ': publisherId is not present in bidder params'); return false; } if (!utils.getBidIdParameter('siteId', bid.params)) { utils.logError(BIDDER_CODE + ': siteId is not present in bidder params'); return false; } if (utils.deepAccess(bid, 'mediaTypes.video.context') === 'outstream') { if (!utils.getBidIdParameter('outstream_options', bid.params)) { utils.logError(BIDDER_CODE + ': outstream_options parameter is not defined'); return false; } if (!utils.getBidIdParameter('slot', bid.params.outstream_options)) { utils.logError(BIDDER_CODE + ': slot parameter is not defined in outstream_options object in the configuration'); return false; } } return true; }, /** * Make a server request from the list of BidRequests. * from Prebid.js: buildRequests - Takes an array of valid bid requests, all of which are guaranteed to have passed the isBidRequestValid() test. * * @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) { const page = bidderRequest.refererInfo.referer; const isPageSecure = !!page.match(/^https:/) const smartxRequests = bidRequests.map(function (bid) { const tagId = utils.getBidIdParameter('tagId', bid.params); const publisherId = utils.getBidIdParameter('publisherId', bid.params); const bidfloor = getBidFloor(bid) || 0; const bidfloorcur = utils.getBidIdParameter('bidfloorcur', bid.params) || 'EUR'; const siteId = utils.getBidIdParameter('siteId', bid.params); const domain = utils.getBidIdParameter('domain', bid.params); const cat = utils.getBidIdParameter('cat', bid.params) || ['']; let pubcid = null; const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); const contentWidth = playerSize[0][0]; const contentHeight = playerSize[0][1]; const secure = +(isPageSecure || (utils.getBidIdParameter('secure', bid.params) ? 1 : 0)); const ext = { sdk_name: 'Prebid 1+' }; const mimes = utils.getBidIdParameter('mimes', bid.params) || ['application/javascript', 'video/mp4', 'video/webm']; const linearity = utils.getBidIdParameter('linearity', bid.params) || 1; const minduration = utils.getBidIdParameter('minduration', bid.params) || 0; const maxduration = utils.getBidIdParameter('maxduration', bid.params) || 500; const startdelay = utils.getBidIdParameter('startdelay', bid.params) || 0; const minbitrate = utils.getBidIdParameter('minbitrate', bid.params) || 0; const maxbitrate = utils.getBidIdParameter('maxbitrate', bid.params) || 3500; const delivery = utils.getBidIdParameter('delivery', bid.params) || [2]; const pos = utils.getBidIdParameter('pos', bid.params) || 1; const api = utils.getBidIdParameter('api', bid.params) || [2]; const protocols = utils.getBidIdParameter('protocols', bid.params) || [2, 3, 5, 6]; var contextcustom = utils.deepAccess(bid, 'mediaTypes.video.context'); var placement = 1; if (contextcustom === 'outstream') { placement = 3; } let smartxReq = [{ id: bid.bidId, secure: secure, bidfloor: bidfloor, bidfloorcur: bidfloorcur, video: { w: contentWidth, h: contentHeight, mimes: mimes, linearity: linearity, minduration: minduration, maxduration: maxduration, startdelay: startdelay, protocols: protocols, minbitrate: minbitrate, maxbitrate: maxbitrate, delivery: delivery, pos: pos, placement: placement, api: api, ext: ext }, tagid: tagId, ext: { 'smart.bidpricetype': 1 } }]; if (bid.crumbs && bid.crumbs.pubcid) { pubcid = bid.crumbs.pubcid; } const language = navigator.language ? 'language' : 'userLanguage'; const device = { h: screen.height, w: screen.width, dnt: utils.getDNT() ? 1 : 0, language: navigator[language].split('-')[0], make: navigator.vendor ? navigator.vendor : '', ua: navigator.userAgent }; const at = utils.getBidIdParameter('at', bid.params) || 2; const cur = utils.getBidIdParameter('cur', bid.params) || ['EUR']; const requestPayload = { id: utils.generateUUID(), imp: smartxReq, site: { id: siteId, page: page, cat: cat, domain: domain, publisher: { id: publisherId } }, device: device, at: at, cur: cur }; const userExt = {}; // Add GDPR flag and consent string if (bidderRequest && bidderRequest.gdprConsent) { userExt.consent = bidderRequest.gdprConsent.consentString; if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') { requestPayload.regs = { ext: { gdpr: (bidderRequest.gdprConsent.gdprApplies ? 1 : 0) } }; } } // Add common id if available if (pubcid) { userExt.fpc = pubcid; } // Only add the user object if it's not empty if (!utils.isEmpty(userExt)) { requestPayload.user = { ext: userExt }; } // Targeting if (utils.getBidIdParameter('data', bid.params.user)) { var targetingarr = []; for (var i = 0; i < bid.params.user.data.length; i++) { var isemq = (bid.params.user.data[i].name) || 'empty'; if (isemq !== 'empty') { var provider = bid.params.user.data[i].name; var targetingstring = (bid.params.user.data[i].segment[0].value) || 'empty'; targetingarr.push({ id: provider, name: provider, segment: { name: provider, value: targetingstring, } }) } } // Todo: USER ID MODULE requestPayload.user = { ext: userExt, data: targetingarr } } return { method: 'POST', url: URL, data: requestPayload, bidRequest: bidderRequest, options: { contentType: 'application/json', customHeaders: { 'x-openrtb-version': '2.3' } } }; }); return smartxRequests; }, /** * 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: function (serverResponse, bidderRequest) { const bidResponses = []; const serverResponseBody = serverResponse.body; if (serverResponseBody && utils.isArray(serverResponseBody.seatbid)) { utils._each(serverResponseBody.seatbid, function (bids) { utils._each(bids.bid, function (smartxBid) { let currentBidRequest = {}; for (let i in bidderRequest.bidRequest.bids) { if (smartxBid.impid == bidderRequest.bidRequest.bids[i].bidId) { currentBidRequest = bidderRequest.bidRequest.bids[i]; } } /** * Make sure currency and price are the right ones * TODO: what about the pre_market_bid partners sizes? */ utils._each(currentBidRequest.params.pre_market_bids, function (pmb) { if (pmb.deal_id == smartxBid.id) { smartxBid.price = pmb.price; serverResponseBody.cur = pmb.currency; } }); const bid = { requestId: currentBidRequest.bidId, currency: serverResponseBody.cur || 'USD', cpm: smartxBid.price, creativeId: smartxBid.crid || '', ttl: 360, netRevenue: true, vastContent: smartxBid.adm, vastXml: smartxBid.adm, mediaType: VIDEO, width: smartxBid.w, height: smartxBid.h }; bid.meta = bid.meta || {}; if (smartxBid && smartxBid.adomain && smartxBid.adomain.length > 0) { bid.meta.advertiserDomains = smartxBid.adomain; } const context = utils.deepAccess(currentBidRequest, 'mediaTypes.video.context'); if (context === 'outstream') { const playersize = utils.deepAccess(currentBidRequest, 'mediaTypes.video.playerSize'); const renderer = Renderer.install({ id: 0, url: 'https://dco.smartclip.net/?plc=7777778', config: { adText: 'SmartX Outstream Video Ad via Prebid.js', player_width: playersize[0][0], player_height: playersize[0][1], content_page_url: utils.deepAccess(bidderRequest, 'data.site.page'), ad_mute: +!!utils.deepAccess(currentBidRequest, 'params.ad_mute'), hide_skin: +!!utils.deepAccess(currentBidRequest, 'params.hide_skin'), outstream_options: utils.deepAccess(currentBidRequest, 'params.outstream_options') } }); try { renderer.setRender(createOutstreamConfig); renderer.setEventHandlers({ impression: function impression() { return utils.logMessage('SmartX outstream video impression event'); }, loaded: function loaded() { return utils.logMessage('SmartX outstream video loaded event'); }, ended: function ended() { return utils.logMessage('SmartX outstream renderer video event'); } }); } catch (err) { utils.logWarn('Prebid Error calling setRender or setEventHandlers on renderer', err); } bid.renderer = renderer; } bidResponses.push(bid); }) }); } return bidResponses; } } function createOutstreamConfig(bid) { const confMinAdWidth = utils.getBidIdParameter('minAdWidth', bid.renderer.config.outstream_options) || 290; const confMaxAdWidth = utils.getBidIdParameter('maxAdWidth', bid.renderer.config.outstream_options) || 900; const confStartOpen = utils.getBidIdParameter('startOpen', bid.renderer.config.outstream_options); const confEndingScreen = utils.getBidIdParameter('endingScreen', bid.renderer.config.outstream_options); const confTitle = utils.getBidIdParameter('title', bid.renderer.config.outstream_options); const confSkipOffset = utils.getBidIdParameter('skipOffset', bid.renderer.config.outstream_options); const confDesiredBitrate = utils.getBidIdParameter('desiredBitrate', bid.renderer.config.outstream_options); const elementId = utils.getBidIdParameter('slot', bid.renderer.config.outstream_options) || bid.adUnitCode; utils.logMessage('[SMARTX][renderer] Handle SmartX outstream renderer'); var smartPlayObj = { minAdWidth: confMinAdWidth, maxAdWidth: confMaxAdWidth, title: confTitle, skipOffset: confSkipOffset, startOpen: confStartOpen, endingScreen: confEndingScreen, desiredBitrate: confDesiredBitrate, onStartCallback: function (m, n) { try { window.sc_smartIntxtStart(n); } catch (f) {} }, onCappedCallback: function (m, n) { try { window.sc_smartIntxtNoad(n); } catch (f) {} }, onEndCallback: function (m, n) { try { window.sc_smartIntxtEnd(n); } catch (f) {} }, }; smartPlayObj.adResponse = bid.vastContent; const divID = '[id="' + elementId + '"]'; try { // eslint-disable-next-line let _outstreamPlayer = new OutstreamPlayer(divID, smartPlayObj); } catch (e) { utils.logError('[SMARTX][renderer] Error caught: ' + e); } return smartPlayObj; } /** * Get the floor price from bid.params for backward compatibility. * If not found, then check floor module. * @param bid A valid bid object * @returns {*|number} floor price */ function getBidFloor(bid) { let floor = utils.getBidIdParameter('bidfloor', bid.params); let floorcur = utils.getBidIdParameter('bidfloorcur', bid.params) || 'EUR'; if (!floor && utils.isFn(bid.getFloor)) { const floorObj = bid.getFloor({ currency: floorcur, mediaType: '*', size: '*' }); if (utils.isPlainObject(floorObj) && !isNaN(floorObj.floor) && floorObj.currency === floorcur) { floor = floorObj.floor; } } return floor; } registerBidder(spec);