-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TargetVideo Bid Adapter: add new bid adapter (#7718)
* TargetVideo bid adapter * TargetVideo bid adapter * TargetVideo bid adapter * TargetVideo Bid Adapter update * TargetVideo Bid Adapter implementing requested changes
- Loading branch information
Showing
4 changed files
with
317 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
import find from 'core-js-pure/features/array/find.js'; | ||
import { getBidRequest } from '../src/utils.js'; | ||
import { BANNER, VIDEO } from '../src/mediaTypes.js'; | ||
import { registerBidder } from '../src/adapters/bidderFactory.js'; | ||
|
||
const SOURCE = 'pbjs'; | ||
const BIDDER_CODE = 'targetVideo'; | ||
const ENDPOINT_URL = 'https://ib.adnxs.com/ut/v3/prebid'; | ||
const MARGIN = 1.35; | ||
|
||
export const spec = { | ||
|
||
code: BIDDER_CODE, | ||
supportedMediaTypes: [BANNER], | ||
|
||
/** | ||
* 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 && bid.params && bid.params.placementId); | ||
}, | ||
|
||
/** | ||
* 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) { | ||
const tags = bidRequests.map(createVideoTag); | ||
const schain = bidRequests[0].schain; | ||
const payload = { | ||
tags: tags, | ||
sdk: { | ||
source: SOURCE, | ||
version: '$prebid.version$' | ||
}, | ||
schain: schain | ||
}; | ||
return formatRequest(payload, bidderRequest); | ||
}, | ||
|
||
/** | ||
* 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 }) { | ||
serverResponse = serverResponse.body; | ||
const bids = []; | ||
|
||
if (serverResponse.tags) { | ||
serverResponse.tags.forEach(serverBid => { | ||
const rtbBid = getRtbBid(serverBid); | ||
if (rtbBid && rtbBid.cpm !== 0 && rtbBid.ad_type == VIDEO) { | ||
bids.push(newBid(serverBid, rtbBid, bidderRequest)); | ||
} | ||
}); | ||
} | ||
|
||
return bids; | ||
} | ||
|
||
} | ||
|
||
function getSizes(request) { | ||
let sizes = request.sizes; | ||
if (!sizes && request.mediaTypes && request.mediaTypes.banner && request.mediaTypes.banner.sizes) { | ||
sizes = request.mediaTypes.banner.sizes; | ||
} | ||
if (Array.isArray(sizes) && !Array.isArray(sizes[0])) { | ||
sizes = [sizes[0], sizes[1]]; | ||
} | ||
if (!Array.isArray(sizes) || !Array.isArray(sizes[0])) { | ||
sizes = [[0, 0]]; | ||
} | ||
|
||
return sizes; | ||
} | ||
|
||
function formatRequest(payload, bidderRequest) { | ||
const options = { | ||
withCredentials: true | ||
}; | ||
const request = { | ||
method: 'POST', | ||
url: ENDPOINT_URL, | ||
data: JSON.stringify(payload), | ||
bidderRequest, | ||
options | ||
}; | ||
|
||
return request; | ||
} | ||
|
||
/** | ||
* Create video auction. | ||
* | ||
* @param {*} serverResponse A successful response from the server. | ||
* @return {Bid[]} An array of bids which were nested inside the server. | ||
*/ | ||
function createVideoTag(bid) { | ||
const tag = {}; | ||
tag.id = parseInt(bid.params.placementId, 10); | ||
tag.gpid = 'targetVideo'; | ||
tag.sizes = getSizes(bid); | ||
tag.primary_size = tag.sizes[0]; | ||
tag.ad_types = [VIDEO]; | ||
tag.uuid = bid.bidId; | ||
tag.allow_smaller_sizes = false; | ||
tag.use_pmt_rule = false | ||
tag.prebid = true; | ||
tag.disable_psa = true; | ||
tag.hb_source = 1; | ||
tag.require_asset_url = true; | ||
tag.video = { | ||
playback_method: 2, | ||
skippable: true | ||
}; | ||
|
||
return tag; | ||
} | ||
|
||
/** | ||
* Unpack the Server's Bid into a Prebid-compatible one. | ||
* @param serverBid | ||
* @param rtbBid | ||
* @param bidderRequest | ||
* @return Bid | ||
*/ | ||
function newBid(serverBid, rtbBid, bidderRequest) { | ||
const bidRequest = getBidRequest(serverBid.uuid, [bidderRequest]); | ||
const sizes = getSizes(bidRequest); | ||
const bid = { | ||
requestId: serverBid.uuid, | ||
cpm: rtbBid.cpm * MARGIN, | ||
creativeId: rtbBid.creative_id, | ||
dealId: rtbBid.deal_id, | ||
currency: 'USD', | ||
netRevenue: true, | ||
width: sizes[0][0], | ||
height: sizes[0][1], | ||
ttl: 300, | ||
adUnitCode: bidRequest.adUnitCode, | ||
appnexus: { | ||
buyerMemberId: rtbBid.buyer_member_id, | ||
dealPriority: rtbBid.deal_priority, | ||
dealCode: rtbBid.deal_code | ||
} | ||
}; | ||
|
||
if (rtbBid.rtb.video) { | ||
Object.assign(bid, { | ||
vastImpUrl: rtbBid.notify_url, | ||
ad: getBannerHtml(rtbBid.notify_url + '&redir=' + encodeURIComponent(rtbBid.rtb.video.asset_url)), | ||
ttl: 3600 | ||
}); | ||
} | ||
|
||
return bid; | ||
} | ||
|
||
function getRtbBid(tag) { | ||
return tag && tag.ads && tag.ads.length && find(tag.ads, ad => ad.rtb); | ||
} | ||
|
||
function getBannerHtml(vastUrl) { | ||
return `<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title></title> | ||
<style>html, body {width: 100%; height: 100%; margin: 0;}</style> | ||
</head> | ||
<body> | ||
<div id="targetVideoPlayer"></div> | ||
<script src="https://player.target-video.com/custom/targetvideo-banner.js"></script> | ||
<script>initPlayer("${vastUrl}");</script> | ||
</body> | ||
</html>`; | ||
} | ||
|
||
registerBidder(spec); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Overview | ||
|
||
``` | ||
Module Name: Target Video Bid Adapter | ||
Module Type: Bidder Adapter | ||
Maintainer: grajzer@gmail.com | ||
``` | ||
|
||
# Description | ||
|
||
Connects to Appnexus exchange for bids. | ||
|
||
TargetVideo bid adapter supports Banner. | ||
|
||
# Test Parameters | ||
``` | ||
var adUnits = [ | ||
// Banner adUnit | ||
{ | ||
code: 'banner-div', | ||
mediaTypes: { | ||
banner: { | ||
sizes: [[640, 480], [300, 250]], | ||
} | ||
}, | ||
bids: [{ | ||
bidder: 'targetVideo', | ||
params: { | ||
placementId: 13232361 | ||
} | ||
}] | ||
} | ||
]; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { spec } from '../../../modules/targetVideoBidAdapter.js' | ||
|
||
describe('TargetVideo Bid Adapter', function() { | ||
const bannerRequest = [{ | ||
bidder: 'targetVideo', | ||
mediaTypes: { | ||
banner: { | ||
sizes: [[300, 250]], | ||
} | ||
}, | ||
params: { | ||
placementId: 12345, | ||
} | ||
}]; | ||
|
||
it('Test the bid validation function', function() { | ||
const validBid = spec.isBidRequestValid(bannerRequest[0]); | ||
const invalidBid = spec.isBidRequestValid(null); | ||
|
||
expect(validBid).to.be.true; | ||
expect(invalidBid).to.be.false; | ||
}); | ||
|
||
it('Test the request processing function', function () { | ||
const request = spec.buildRequests(bannerRequest, bannerRequest[0]); | ||
expect(request).to.not.be.empty; | ||
|
||
const payload = JSON.parse(request.data); | ||
expect(payload).to.not.be.empty; | ||
expect(payload.sdk).to.deep.equal({ | ||
source: 'pbjs', | ||
version: '$prebid.version$' | ||
}); | ||
expect(payload.tags[0].id).to.equal(12345); | ||
expect(payload.tags[0].gpid).to.equal('targetVideo'); | ||
expect(payload.tags[0].ad_types[0]).to.equal('video'); | ||
}); | ||
|
||
it('Handle nobid responses', function () { | ||
const responseBody = { | ||
'version': '0.0.1', | ||
'tags': [{ | ||
'uuid': '84ab500420319d', | ||
'tag_id': 5976557, | ||
'auction_id': '297492697822162468', | ||
'nobid': true | ||
}] | ||
}; | ||
const bidderRequest = null; | ||
|
||
const bidResponse = spec.interpretResponse({ body: responseBody }, {bidderRequest}); | ||
expect(bidResponse.length).to.equal(0); | ||
}); | ||
|
||
it('Test the response parsing function', function () { | ||
const responseBody = { | ||
'tags': [{ | ||
'uuid': '84ab500420319d', | ||
'ads': [{ | ||
'ad_type': 'video', | ||
'cpm': 0.500000, | ||
'notify_url': 'https://www.target-video.com/', | ||
'rtb': { | ||
'video': { | ||
'player_width': 640, | ||
'player_height': 360, | ||
'asset_url': 'https://www.target-video.com/' | ||
} | ||
} | ||
}] | ||
}] | ||
}; | ||
const bidderRequest = { | ||
bids: [{ | ||
bidId: '84ab500420319d', | ||
adUnitCode: 'code', | ||
mediaTypes: { | ||
banner: { | ||
sizes: [[300, 250]] | ||
} | ||
} | ||
}] | ||
}; | ||
|
||
const bidResponse = spec.interpretResponse({ body: responseBody }, {bidderRequest}); | ||
expect(bidResponse).to.not.be.empty; | ||
|
||
const bid = bidResponse[0]; | ||
expect(bid).to.not.be.empty; | ||
expect(bid.cpm).to.equal(0.675); | ||
expect(bid.width).to.equal(300); | ||
expect(bid.height).to.equal(250); | ||
expect(bid.ad).to.include('<script src="https://player.target-video.com/custom/targetvideo-banner.js"></script>') | ||
expect(bid.ad).to.include('initPlayer') | ||
}); | ||
}); |