Skip to content

Commit

Permalink
add stv adapter (prebid#3737)
Browse files Browse the repository at this point in the history
* add stv adapter

* remove comments from adapter file
  • Loading branch information
onlsol authored and Alex committed Aug 1, 2019
1 parent 403b672 commit 3d17c24
Show file tree
Hide file tree
Showing 3 changed files with 331 additions and 0 deletions.
150 changes: 150 additions & 0 deletions modules/stvBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@

import * as utils from '../src/utils';
import {config} from '../src/config';
import {registerBidder} from '../src/adapters/bidderFactory';
import { BANNER, VIDEO } from '../src/mediaTypes';

const BIDDER_CODE = 'stv';
const VADS_ENDPOINT_URL = 'https://ads.smartstream.tv/r/';
const DEFAULT_VIDEO_SOURCE = 'vads';
const DEFAULT_BANNER_FORMAT = 'vast2';

export const spec = {
code: BIDDER_CODE,
aliases: ['vads'],
supportedMediaTypes: [BANNER, VIDEO],
isBidRequestValid: function(bid) {
return !!(bid.params.placement);
},
buildRequests: function(validBidRequests, bidderRequest) {
return validBidRequests.map(bidRequest => {
const params = bidRequest.params;

const videoData = utils.deepAccess(bidRequest, 'mediaTypes.video') || {};
const sizes = utils.parseSizesInput(videoData.playerSize || bidRequest.sizes)[0];
const width = sizes.split('x')[0];
const height = sizes.split('x')[1];

const placementId = params.placement;

const rnd = Math.floor(Math.random() * 99999999999);
const referrer = encodeURIComponent(bidderRequest.refererInfo.referer);
const bidId = bidRequest.bidId;
let endpoint = VADS_ENDPOINT_URL;

let payload = {};
if (isVideoRequest(bidRequest)) {
const source = params.source || DEFAULT_VIDEO_SOURCE;
if (source === 'vads') {
payload = {
_f: 'vast2',
alternative: 'prebid_js',
_ps: placementId,
srw: width,
srh: height,
idt: 100,
rnd: rnd,
ref: referrer,
bid_id: bidId,
};
endpoint = VADS_ENDPOINT_URL;
}
} else {
const outputFormat = params.format || DEFAULT_BANNER_FORMAT;
payload = {
_f: outputFormat,
alternative: 'prebid_js',
inventory_item_id: placementId,
srw: width,
srh: height,
idt: 100,
rnd: rnd,
ref: referrer,
bid_id: bidId,
};
}
prepareExtraParams(params, payload);

return {
method: 'GET',
url: endpoint,
data: objectToQueryString(payload),
}
});
},
interpretResponse: function(serverResponse, bidRequest) {
const bidResponses = [];
const response = serverResponse.body;
const crid = response.crid || 0;
const cpm = response.cpm / 1000000 || 0;
if (cpm !== 0 && crid !== 0) {
const dealId = response.dealid || '';
const currency = response.currency || 'EUR';
const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue;
const bidResponse = {
requestId: response.bid_id,
cpm: cpm,
width: response.width,
height: response.height,
creativeId: crid,
dealId: dealId,
currency: currency,
netRevenue: netRevenue,
ttl: config.getConfig('_bidderTimeout')
};

if (response.vastXml) {
bidResponse.vastXml = response.vastXml;
bidResponse.mediaType = 'video';
} else {
bidResponse.ad = response.adTag;
}

bidResponses.push(bidResponse);
}
return bidResponses;
}
}

function objectToQueryString(obj, prefix) {
let str = [];
let p;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
let k = prefix ? prefix + '[' + p + ']' : p;
let v = obj[p];
str.push((v !== null && typeof v === 'object')
? objectToQueryString(v, k)
: encodeURIComponent(k) + '=' + (k == '_ps' ? v : encodeURIComponent(v)));
}
}
return str.join('&');
}

/**
* Check if it's a video bid request
*
* @param {BidRequest} bid - Bid request generated from ad slots
* @returns {boolean} True if it's a video bid
*/
function isVideoRequest(bid) {
return bid.mediaType === 'video' || !!utils.deepAccess(bid, 'mediaTypes.video');
}

function prepareExtraParams(params, payload) {
if (params.pfilter !== undefined) {
payload.pfilter = params.pfilter;
}
if (params.bcat !== undefined) {
payload.bcat = params.bcat;
}
if (params.noskip !== undefined) {
payload.noskip = params.noskip;
}

if (params.dvt !== undefined) {
payload.dvt = params.dvt;
}
}

registerBidder(spec);
43 changes: 43 additions & 0 deletions modules/stvBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Overview

```
Module Name: STV Video Bidder Adapter
Module Type: Bidder Adapter
Maintainer: prebid@dspx.tv
```

# Description

STV video adapter for Prebid.js 1.x

# Parameters
```
var adUnits = [
{
// video settings
code: 'video-obj',
mediaTypes: {
video: {
context: 'instream',
playerSize: [640, 480]
}
},
bids: [
{
bidder: "stv",
params: {
placement: "", // placement ID of inventory with STV
noskip: 1, // 0 or 1
pfilter: {/*
min_duration: 10, // min duration
max_duration: 30, // max duration
min_bitrate: 300, // min bitrate
max_bitrate: 1600, // max bitrate
*/}
}
}
]
}
];
```

138 changes: 138 additions & 0 deletions test/spec/modules/stvBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { expect } from 'chai';
import { spec } from 'modules/stvBidAdapter';
import { newBidder } from 'src/adapters/bidderFactory';

const VADS_ENDPOINT_URL = 'https://ads.smartstream.tv/r/';

describe('stvAdapter', function () {
const adapter = newBidder(spec);

describe('isBidRequestValid', function () {
let bid = {
'bidder': 'stv',
'params': {
'placement': '6682',
'pfilter': {
'floorprice': 1000000
},
'bcat': 'IAB2,IAB4',
'dvt': 'desktop'
},
'sizes': [
[300, 250]
],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475'
};

it('should return true when required params found', function () {
expect(spec.isBidRequestValid(bid)).to.equal(true);
});

it('should return false when required params are not passed', function () {
let bid = Object.assign({}, bid);
delete bid.params;
bid.params = {
'someIncorrectParam': 0
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
});

describe('buildRequests', function () {
let bidRequests = [{
'bidder': 'stv',
'params': {
'source': 'vads',
'placement': 'prer0-0%3D4137',
'pfilter': {
'min_duration': 1,
'max_duration': 100,
'min_bitrate': 32,
'max_bitrate': 128,
},
'noskip': 1
},
'mediaTypes': {
'video': {
'playerSize': [640, 480],
'context': 'instream'
}
},
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475'
}];

let bidderRequest = {
refererInfo: {
referer: 'some_referrer.net'
}
}

const request = spec.buildRequests(bidRequests, bidderRequest);
it('sends bid video request to our vads endpoint via GET', function () {
expect(request[0].method).to.equal('GET');
let data = request[0].data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid');
expect(data).to.equal('_f=vast2&alternative=prebid_js&_ps=prer0-0%3D4137&srw=640&srh=480&idt=100&bid_id=30b31c1838de1e&pfilter%5Bmin_duration%5D=1&pfilter%5Bmax_duration%5D=100&pfilter%5Bmin_bitrate%5D=32&pfilter%5Bmax_bitrate%5D=128&noskip=1');
});
});

describe('interpretResponse', function () {
let vadsServerVideoResponse = {
'body': {
'cpm': 5000000,
'crid': 100500,
'width': '300',
'height': '250',
'vastXml': '{"reason":7001,"status":"accepted"}',
'requestId': '220ed41385952a',
'currency': 'EUR',
'ttl': 60,
'netRevenue': true,
'zone': '6682'
}
};

let expectedResponse = [{
requestId: '23beaa6af6cdde',
cpm: 0.5,
width: 0,
height: 0,
creativeId: 100500,
dealId: '',
currency: 'EUR',
netRevenue: true,
ttl: 300,
vastXml: '{"reason":7001,"status":"accepted"}',
mediaType: 'video'
}];

it('should get the correct vads video bid response by display ad', function () {
let bidRequest = [{
'method': 'GET',
'url': VADS_ENDPOINT_URL,
'mediaTypes': {
'video': {
'playerSize': [640, 480],
'context': 'instream'
}
},
'data': {
'bid_id': '30b31c1838de1e'
}
}];
let result = spec.interpretResponse(vadsServerVideoResponse, bidRequest[0]);
expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0]));
});

it('handles empty bid response', function () {
let response = {
body: {}
};
let result = spec.interpretResponse(response);
expect(result.length).to.equal(0);
});
});
});

0 comments on commit 3d17c24

Please sign in to comment.