Skip to content
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

Synacor media bidder updates: filter bad sizes & extra video parameters #3885

Merged
merged 4 commits into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 58 additions & 41 deletions modules/synacormediaBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import includes from 'core-js/library/fn/array/includes';

const BID_HOST = '//prebid.technoratimedia.com';
const USER_SYNC_HOST = '//ad-cdn.technoratimedia.com';
const VIDEO_PARAMS = [ 'minduration', 'maxduration' ];

const VIDEO_PARAMS = [ 'minduration', 'maxduration', 'startdelay', 'placement', 'linearity', 'mimes', 'protocols', 'api' ];
const BLOCKED_AD_SIZES = [
'1x1',
'1x2'
];
export const spec = {
code: 'synacormedia',
supportedMediaTypes: [ BANNER, VIDEO ],
Expand All @@ -19,15 +22,17 @@ export const spec = {
bid.mediaTypes.hasOwnProperty('video');
},
isBidRequestValid: function(bid) {
return !!(bid && bid.params && bid.params.placementId && bid.params.seatId);
const hasRequiredParams = bid && bid.params && bid.params.hasOwnProperty('placementId') && bid.params.hasOwnProperty('seatId');
const hasAdSizes = bid && getAdUnitSizes(bid).filter(size => BLOCKED_AD_SIZES.indexOf(size.join('x')) === -1).length > 0
return !!(hasRequiredParams && hasAdSizes);
},

buildRequests: function(validBidReqs, bidderRequest) {
if (!validBidReqs || !validBidReqs.length || !bidderRequest) {
return;
}
let refererInfo = bidderRequest.refererInfo;
let openRtbBidRequest = {
const refererInfo = bidderRequest.refererInfo;
const openRtbBidRequest = {
id: bidderRequest.auctionId,
site: {
domain: location.hostname,
Expand All @@ -40,15 +45,16 @@ export const spec = {
imp: []
};
let seatId = null;

validBidReqs.forEach((bid, i) => {
if (seatId && seatId !== bid.params.seatId) {
logWarn(`Synacormedia: there is an inconsistent seatId: ${bid.params.seatId} but only sending bid requests for ${seatId}, you should double check your configuration`);
return;
} else {
seatId = bid.params.seatId;
}
let placementId = bid.params.placementId;
let bidFloor = bid.params.bidfloor ? parseFloat(bid.params.bidfloor) : null;
const placementId = bid.params.placementId;
const bidFloor = bid.params.bidfloor ? parseFloat(bid.params.bidfloor) : null;
if (isNaN(bidFloor)) {
logWarn(`Synacormedia: there is an invalid bid floor: ${bid.params.bidfloor}`);
}
Expand All @@ -57,34 +63,39 @@ export const spec = {
logWarn(`Synacormedia: there is an invalid POS: ${bid.params.pos}`);
pos = 0;
}
let videoOrBannerKey = this.isVideoBid(bid) ? 'video' : 'banner';
getAdUnitSizes(bid).forEach((size, i) => {
if (!size || size.length != 2) {
return;
}
let size0 = size[0];
let size1 = size[1];
let imp = {
id: `${videoOrBannerKey.substring(0, 1)}${bid.bidId}-${size0}x${size1}`,
tagid: placementId
};
if (bidFloor !== null && !isNaN(bidFloor)) {
imp.bidfloor = bidFloor;
}
const videoOrBannerKey = this.isVideoBid(bid) ? 'video' : 'banner';
getAdUnitSizes(bid)
.filter(size => BLOCKED_AD_SIZES.indexOf(size.join('x')) === -1)
.forEach((size, i) => {
if (!size || size.length != 2) {
return;
}
const size0 = size[0];
const size1 = size[1];
const imp = {
id: `${videoOrBannerKey.substring(0, 1)}${bid.bidId}-${size0}x${size1}`,
tagid: placementId
};
if (bidFloor !== null && !isNaN(bidFloor)) {
imp.bidfloor = bidFloor;
}

let videoOrBannerValue = {
w: size0,
h: size1,
pos
};
if (videoOrBannerKey === 'video' && bid.params.video) {
Object.keys(bid.params.video)
.filter(param => includes(VIDEO_PARAMS, param) && !isNaN(parseInt(bid.params.video[param], 10)))
.forEach(param => videoOrBannerValue[param] = parseInt(bid.params.video[param], 10));
}
imp[videoOrBannerKey] = videoOrBannerValue;
openRtbBidRequest.imp.push(imp);
});
const videoOrBannerValue = {
w: size0,
h: size1,
pos
};
if (videoOrBannerKey === 'video') {
if (bid.mediaTypes.video) {
this.setValidVideoParams(bid.mediaTypes.video, bid.params.video);
}
if (bid.params.video) {
this.setValidVideoParams(bid.params.video, videoOrBannerValue);
}
}
imp[videoOrBannerKey] = videoOrBannerValue;
openRtbBidRequest.imp.push(imp);
});
});

if (openRtbBidRequest.imp.length && seatId) {
Expand All @@ -99,8 +110,14 @@ export const spec = {
};
}
},

setValidVideoParams: function (sourceObj, destObj) {
Object.keys(sourceObj)
.filter(param => includes(VIDEO_PARAMS, param) && sourceObj[param] !== null && (!isNaN(parseInt(sourceObj[param], 10)) || !(sourceObj[param].length < 1)))
.forEach(param => destObj[param] = Array.isArray(sourceObj[param]) ? sourceObj[param] : parseInt(sourceObj[param], 10));
},
interpretResponse: function(serverResponse) {
var updateMacros = (bid, r) => {
const updateMacros = (bid, r) => {
return r ? r.replace(/\${AUCTION_PRICE}/g, bid.price) : r;
};

Expand All @@ -114,11 +131,11 @@ export const spec = {
if (id && seatbids) {
seatbids.forEach(seatbid => {
seatbid.bid.forEach(bid => {
let creative = updateMacros(bid, bid.adm);
let nurl = updateMacros(bid, bid.nurl);
let [, impType, impid, width, height] = bid.impid.match(/^([vb])(.*)-(.*)x(.*)$/);
let isVideo = impType == 'v';
let bidObj = {
const creative = updateMacros(bid, bid.adm);
const nurl = updateMacros(bid, bid.nurl);
const [, impType, impid, width, height] = bid.impid.match(/^([vb])(.*)-(.*)x(.*)$/);
const isVideo = impType == 'v';
const bidObj = {
requestId: impid,
adId: bid.id.replace(/~/g, '-'),
cpm: parseFloat(bid.price),
Expand All @@ -132,7 +149,7 @@ export const spec = {
ttl: 60
};
if (isVideo) {
let [, uuid] = nurl.match(/ID=([^&]*)&?/);
const [, uuid] = nurl.match(/ID=([^&]*)&?/);
bidObj.videoCacheKey = encodeURIComponent(uuid);
bidObj.vastUrl = nurl;
}
Expand Down
16 changes: 8 additions & 8 deletions modules/synacormediaBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,26 @@ https://track.technoratimedia.com/openrtb/tags?ID=%%PATTERN:hb_cache_id_synacorm
}]
},{
code: 'test-div2',
mediaType: {
mediaTypes: {
video: {
context: 'instream',
playerSizes: [
[300, 250]
],
context: 'instream',
playerSize: [[300, 250]],
}
},
bids: [{
bidder: "synacormedia",
params: {
seatId: "prebid",
placementId: "demo1"
placementId: "demo1",
bidfloor: 0.20,
pos: 1,
video: {
minduration: 15,
maxduration: 30
maxduration: 30,
startdelay: 1,
linearity: 1
}
}
}]
}];
}];
```
129 changes: 129 additions & 0 deletions test/spec/modules/synacormediaBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('synacormediaBidAdapter ', function () {
let bid;
beforeEach(function () {
bid = {
sizes: [300, 250],
params: {
seatId: 'prebid',
placementId: '1234'
Expand All @@ -18,14 +19,26 @@ describe('synacormediaBidAdapter ', function () {
assert(spec.isBidRequestValid(bid));
});

it('should return false when sizes are missing', function () {
delete bid.sizes;
assert.isFalse(spec.isBidRequestValid(bid));
});

it('should return false when the only size is unwanted', function () {
bid.sizes = [[1, 1]];
assert.isFalse(spec.isBidRequestValid(bid));
});

it('should return false when seatId param is missing', function () {
delete bid.params.seatId;
assert.isFalse(spec.isBidRequestValid(bid));
});

it('should return false when placementId param is missing', function () {
delete bid.params.placementId;
assert.isFalse(spec.isBidRequestValid(bid));
});

it('should return false when params is missing or null', function () {
assert.isFalse(spec.isBidRequestValid({ params: null }));
assert.isFalse(spec.isBidRequestValid({}));
Expand Down Expand Up @@ -404,6 +417,122 @@ describe('synacormediaBidAdapter ', function () {
req = spec.buildRequests([validBidReqInvalidSize], bidderRequest);
assert.isUndefined(req);
});
it('should use all the video params in the impression request', function () {
let validBidRequestVideo = {
bidder: 'synacormedia',
params: {
seatId: 'prebid',
placementId: '1234',
video: {
minduration: 30,
maxduration: 45,
startdelay: 1,
linearity: 1,
placement: 1,
mimes: ['video/mp4'],
protocols: [1],
api: 1
}
},
mediaTypes: {
video: {
context: 'instream',
playerSize: [[ 640, 480 ]]
}
},
adUnitCode: 'video1',
transactionId: '93e5def8-29aa-4fe8-bd3a-0298c39f189a',
sizes: [[ 640, 480 ]],
bidId: '2624fabbb078e8',
bidderRequestId: '117954d20d7c9c',
auctionId: 'defd525f-4f1e-4416-a4cb-ae53be90e706',
src: 'client',
bidRequestsCount: 1
};

let req = spec.buildRequests([validBidRequestVideo], bidderRequest);
expect(req).to.have.property('method', 'POST');
expect(req).to.have.property('url');
expect(req.url).to.contain('//prebid.technoratimedia.com/openrtb/bids/prebid?src=$$REPO_AND_VERSION$$');
expect(req.data.id).to.equal('xyz123');
expect(req.data.imp).to.eql([
{
video: {
h: 480,
pos: 0,
w: 640,
minduration: 30,
maxduration: 45,
startdelay: 1,
linearity: 1,
placement: 1,
mimes: ['video/mp4'],
protocols: [1],
api: 1
},
id: 'v2624fabbb078e8-640x480',
tagid: '1234',
}
]);
});
it('should move any video params in the mediaTypes object to params.video object', function () {
let validBidRequestVideo = {
bidder: 'synacormedia',
params: {
seatId: 'prebid',
placementId: '1234',
video: {
minduration: 30,
maxduration: 45,
protocols: [1],
api: 1
}
},
mediaTypes: {
video: {
context: 'instream',
playerSize: [[ 640, 480 ]],
startdelay: 1,
linearity: 1,
placement: 1,
mimes: ['video/mp4']
}
},
adUnitCode: 'video1',
transactionId: '93e5def8-29aa-4fe8-bd3a-0298c39f189a',
sizes: [[ 640, 480 ]],
bidId: '2624fabbb078e8',
bidderRequestId: '117954d20d7c9c',
auctionId: 'defd525f-4f1e-4416-a4cb-ae53be90e706',
src: 'client',
bidRequestsCount: 1
};

let req = spec.buildRequests([validBidRequestVideo], bidderRequest);
expect(req).to.have.property('method', 'POST');
expect(req).to.have.property('url');
expect(req.url).to.contain('//prebid.technoratimedia.com/openrtb/bids/prebid?src=$$REPO_AND_VERSION$$');
expect(req.data.id).to.equal('xyz123');
expect(req.data.imp).to.eql([
{
video: {
h: 480,
pos: 0,
w: 640,
minduration: 30,
maxduration: 45,
startdelay: 1,
linearity: 1,
placement: 1,
mimes: ['video/mp4'],
protocols: [1],
api: 1
},
id: 'v2624fabbb078e8-640x480',
tagid: '1234',
}
]);
});
});

describe('interpretResponse', function () {
Expand Down