Skip to content

Commit

Permalink
Brave utils: initial commit (prebid#12412)
Browse files Browse the repository at this point in the history
* Create index.js

* Create nativeAssets.js

* Update braveBidAdapter.js

* Update videoheroesBidAdapter.js

* Update videoheroesBidAdapter.js

* Update braveBidAdapter.js

* Update adotBidAdapter.js

* Update adotBidAdapter.js

* Update adotBidAdapter.js

* Update adotBidAdapter.js

* Update adotBidAdapter.js

* Update adotBidAdapter.js

* Update braveBidAdapter.js

* Update videoheroesBidAdapter.js

* Update videoheroesBidAdapter.js

* Update braveBidAdapter.js

* Update adotBidAdapter.js

* Create buildAndInterpret.js

* Update braveBidAdapter.js

* Update videoheroesBidAdapter.js

* Update buildAndInterpret.js

* Update braveBidAdapter.js

* Update videoheroesBidAdapter.js

* Update braveBidAdapter.js

* Update videoheroesBidAdapter.js

* Update buildAndInterpret.js
  • Loading branch information
patmmccann authored Nov 16, 2024
1 parent 7c5700f commit 9ef4335
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 482 deletions.
78 changes: 78 additions & 0 deletions libraries/braveUtils/buildAndInterpret.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { isEmpty, parseUrl } from '../../src/utils.js';
import {config} from '../../src/config.js';
import { createNativeRequest, createBannerRequest, createVideoRequest } from './index.js';
import { convertOrtbRequestToProprietaryNative } from '../../src/native.js';

export const buildRequests = (validBidRequests, bidderRequest, endpointURL, defaultCur) => {
validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
if (!validBidRequests.length || !bidderRequest) return [];

const endpoint = endpointURL.replace('hash', validBidRequests[0].params.placementId);
const imp = validBidRequests.map((br) => {
const impObject = { id: br.bidId, secure: 1 };
if (br.mediaTypes.banner) impObject.banner = createBannerRequest(br);
else if (br.mediaTypes.video) impObject.video = createVideoRequest(br);
else if (br.mediaTypes.native) impObject.native = { id: br.transactionId, ver: '1.2', request: createNativeRequest(br) };
return impObject;
});

const page = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation;
const data = {
id: bidderRequest.bidderRequestId,
cur: [defaultCur],
device: { w: screen.width, h: screen.height, language: navigator.language?.split('-')[0], ua: navigator.userAgent },
site: { domain: parseUrl(page).hostname, page: page },
tmax: bidderRequest.timeout,
imp,
};

if (bidderRequest.refererInfo.ref) data.site.ref = bidderRequest.refererInfo.ref;
if (bidderRequest.gdprConsent) {
data.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } };
data.user = { ext: { consent: bidderRequest.gdprConsent.consentString || '' } };
}
if (bidderRequest.uspConsent) data.regs.ext.us_privacy = bidderRequest.uspConsent;
if (config.getConfig('coppa')) data.regs.coppa = 1;
if (validBidRequests[0].schain) data.source = { ext: { schain: validBidRequests[0].schain } };

return { method: 'POST', url: endpoint, data };
};

export const interpretResponse = (serverResponse, defaultCur, parseNative) => {
if (!serverResponse || isEmpty(serverResponse.body)) return [];

let bids = [];
serverResponse.body.seatbid.forEach(response => {
response.bid.forEach(bid => {
const mediaType = bid.ext?.mediaType || 'banner';

const bidObj = {
requestId: bid.impid,
cpm: bid.price,
width: bid.w,
height: bid.h,
ttl: 1200,
currency: defaultCur,
netRevenue: true,
creativeId: bid.crid,
dealId: bid.dealid || null,
mediaType,
};

switch (mediaType) {
case 'video':
bidObj.vastUrl = bid.adm;
break;
case 'native':
bidObj.native = parseNative(bid.adm);
break;
default:
bidObj.ad = bid.adm;
}

bids.push(bidObj);
});
});

return bids;
};
95 changes: 95 additions & 0 deletions libraries/braveUtils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { NATIVE_ASSETS, NATIVE_ASSETS_IDS } from './nativeAssets.js';

/**
* Builds a native request object based on the bid request
* @param {object} br - The bid request
* @returns {object} The native request object
*/
export function createNativeRequest(br) {
let impObject = {
ver: '1.2',
assets: []
};

Object.keys(br.mediaTypes.native).forEach((key) => {
const props = NATIVE_ASSETS[key];
if (props) {
const asset = {
required: br.mediaTypes.native[key].required ? 1 : 0,
id: props.id,
[props.name]: {}
};

if (props.type) asset[props.name]['type'] = props.type;
if (br.mediaTypes.native[key].len) asset[props.name]['len'] = br.mediaTypes.native[key].len;
if (br.mediaTypes.native[key].sizes && br.mediaTypes.native[key].sizes[0]) {
asset[props.name]['w'] = br.mediaTypes.native[key].sizes[0];
asset[props.name]['h'] = br.mediaTypes.native[key].sizes[1];
}

impObject.assets.push(asset);
}
});

return impObject;
}

/**
* Builds a banner request object based on the bid request
* @param {object} br - The bid request
* @returns {object} The banner request object
*/
export function createBannerRequest(br) {
let size = br.mediaTypes.banner.sizes?.[0] || [300, 250];
return { id: br.transactionId, w: size[0], h: size[1] };
}

/**
* Builds a video request object based on the bid request
* @param {object} br - The bid request
* @returns {object} The video request object
*/
export function createVideoRequest(br) {
let videoObj = { id: br.transactionId };
const supportedParams = ['mimes', 'minduration', 'maxduration', 'protocols', 'startdelay', 'skip', 'minbitrate', 'maxbitrate', 'api', 'linearity'];

supportedParams.forEach((param) => {
if (br.mediaTypes.video[param] !== undefined) {
videoObj[param] = br.mediaTypes.video[param];
}
});

const playerSize = br.mediaTypes.video.playerSize;
if (playerSize) {
videoObj.w = Array.isArray(playerSize[0]) ? playerSize[0][0] : playerSize[0];
videoObj.h = Array.isArray(playerSize[0]) ? playerSize[0][1] : playerSize[1];
} else {
videoObj.w = 640;
videoObj.h = 480;
}

return videoObj;
}

/**
* Parses the native ad response
* @param {object} adm - The native ad response
* @returns {object} Parsed native ad object
*/
export function parseNative(adm) {
let bid = {
clickUrl: adm.native.link?.url,
impressionTrackers: adm.native.imptrackers || [],
clickTrackers: adm.native.link?.clicktrackers || [],
jstracker: adm.native.jstracker || []
};
adm.native.assets.forEach((asset) => {
const kind = NATIVE_ASSETS_IDS[asset.id];
const content = kind && asset[NATIVE_ASSETS[kind].name];
if (content) {
bid[kind] = content.text || content.value || { url: content.url, width: content.w, height: content.h };
}
});

return bid;
}
23 changes: 23 additions & 0 deletions libraries/braveUtils/nativeAssets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* IDs and asset types for native ad assets.
*/
export const NATIVE_ASSETS_IDS = {
1: 'title',
2: 'icon',
3: 'image',
4: 'body',
5: 'sponsoredBy',
6: 'cta'
};

/**
* Native assets definition for mapping purposes.
*/
export const NATIVE_ASSETS = {
title: { id: 1, name: 'title' },
icon: { id: 2, type: 1, name: 'img' },
image: { id: 3, type: 3, name: 'img' },
body: { id: 4, type: 2, name: 'data' },
sponsoredBy: { id: 5, type: 1, name: 'data' },
cta: { id: 6, type: 12, name: 'data' }
};
41 changes: 32 additions & 9 deletions modules/adotBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {find} from '../src/polyfill.js';
import {config} from '../src/config.js';
import {OUTSTREAM} from '../src/video.js';
import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
import { NATIVE_ASSETS_IDS as NATIVE_ID_MAPPING, NATIVE_ASSETS as NATIVE_PLACEMENTS } from '../libraries/braveUtils/nativeAssets.js';

/**
* @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
Expand All @@ -24,6 +25,37 @@ import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
* @typedef {import('../src/adapters/bidderFactory.js').Imp} Imp
*/

/**
* @typedef {Object} OpenRtbRequest
* @property {string} id - Unique request ID
* @property {Array<Imp>} imp - List of impression objects
* @property {Site} site - Site information
* @property {Device} device - Device information
* @property {User} user - User information
* @property {object} regs - Regulatory data, including GDPR and COPPA
* @property {object} ext - Additional extensions, such as custom data for the bid request
* @property {number} at - Auction type, typically first-price or second-price
*/

/**
* @typedef {Object} OpenRtbBid
* @property {string} impid - ID of the impression this bid relates to
* @property {number} price - Bid price for the impression
* @property {string} adid - Ad ID for the bid
* @property {number} [crid] - Creative ID, if available
* @property {string} [dealid] - Deal ID if the bid is part of a private marketplace deal
* @property {object} [ext] - Additional bid-specific extensions, such as media type
* @property {string} [adm] - Ad markup if it’s directly included in the bid response
* @property {string} [nurl] - Notification URL to be called when the bid wins
*/

/**
* @typedef {Object} OpenRtbBidResponse
* @property {string} id - ID of the bid response
* @property {Array<{bid: Array<OpenRTBBid>}>} seatbid - Array of seat bids, each containing a list of bids
* @property {string} cur - Currency in which bid amounts are expressed
*/

const BIDDER_CODE = 'adot';
const ADAPTER_VERSION = 'v2.0.0';
const GVLID = 272;
Expand All @@ -32,15 +64,6 @@ const BIDDER_URL = 'https://dsp.adotmob.com/headerbidding{PUBLISHER_PATH}/bidreq
const REQUIRED_VIDEO_PARAMS = ['mimes', 'protocols'];
const FIRST_PRICE = 1;
const IMP_BUILDER = { banner: buildBanner, video: buildVideo, native: buildNative };
const NATIVE_PLACEMENTS = {
title: { id: 1, name: 'title' },
icon: { id: 2, type: 1, name: 'img' },
image: { id: 3, type: 3, name: 'img' },
sponsoredBy: { id: 4, name: 'data', type: 1 },
body: { id: 5, name: 'data', type: 2 },
cta: { id: 6, type: 12, name: 'data' }
};
const NATIVE_ID_MAPPING = { 1: 'title', 2: 'icon', 3: 'image', 4: 'sponsoredBy', 5: 'body', 6: 'cta' };
const OUTSTREAM_VIDEO_PLAYER_URL = 'https://adserver.adotmob.com/video/player.min.js';
const BID_RESPONSE_NET_REVENUE = true;
const BID_RESPONSE_TTL = 10;
Expand Down
Loading

0 comments on commit 9ef4335

Please sign in to comment.