Skip to content

Commit 1264fb3

Browse files
[Exchange] Prebidjs video integration for outstream video
1 parent 4d9b28c commit 1264fb3

File tree

3 files changed

+431
-168
lines changed

3 files changed

+431
-168
lines changed

modules/eskimiBidAdapter.js

Lines changed: 151 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import {registerBidder} from '../src/adapters/bidderFactory.js';
2-
import {BANNER} from '../src/mediaTypes.js';
1+
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
2+
import { registerBidder } from '../src/adapters/bidderFactory.js';
3+
import { BANNER, VIDEO } from '../src/mediaTypes.js';
34
import * as utils from '../src/utils.js';
4-
import {ortbConverter} from '../libraries/ortbConverter/converter.js'
55

66
const BIDDER_CODE = 'eskimi';
77
// const ENDPOINT = 'https://hb.eskimi.com/bids'
@@ -12,43 +12,30 @@ const DEFAULT_CURRENCY = 'USD';
1212
const DEFAULT_NET_REVENUE = true;
1313
const GVLID = 814;
1414

15+
const VIDEO_ORTB_PARAMS = [
16+
'mimes',
17+
'minduration',
18+
'maxduration',
19+
'placement',
20+
'protocols',
21+
'startdelay',
22+
'skip',
23+
'skipafter',
24+
'minbitrate',
25+
'maxbitrate',
26+
'delivery',
27+
'playbackmethod',
28+
'api',
29+
'linearity'
30+
];
31+
1532
export const spec = {
1633
code: BIDDER_CODE,
1734
gvlid: GVLID,
18-
supportedMediaTypes: [BANNER],
19-
20-
isBidRequestValid: function (bid) {
21-
return !!bid.params.placementId;
22-
},
23-
24-
buildRequests(bidRequests, bidderRequest) {
25-
const data = converter.toORTB({bidRequests, bidderRequest})
26-
27-
let bid = bidRequests.find((b) => b.params.placementId)
28-
if (!data.site) data.site = {}
29-
data.site.ext = {placementId: bid.params.placementId}
30-
31-
if (bidderRequest.gdprConsent) {
32-
if (!data.user) data.user = {};
33-
if (!data.user.ext) data.user.ext = {};
34-
if (!data.regs) data.regs = {};
35-
if (!data.regs.ext) data.regs.ext = {};
36-
data.user.ext.consent = bidderRequest.gdprConsent.consentString;
37-
data.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
38-
}
39-
40-
return [{
41-
method: 'POST',
42-
url: ENDPOINT,
43-
data,
44-
options: {contentType: 'application/json;charset=UTF-8', withCredentials: false}
45-
}]
46-
},
47-
48-
interpretResponse(response, request) {
49-
return converter.fromORTB({response: response.body, request: request.data}).bids;
50-
},
51-
35+
supportedMediaTypes: [BANNER, VIDEO],
36+
isBidRequestValid,
37+
buildRequests,
38+
interpretResponse,
5239
/**
5340
* Register bidder specific code, which will execute if a bid from this bidder won the auction
5441
* @param {Bid} bid The bid that won the auction
@@ -60,13 +47,136 @@ export const spec = {
6047
}
6148
}
6249

63-
const converter = ortbConverter({
50+
registerBidder(spec);
51+
52+
const CONVERTER = ortbConverter({
6453
context: {
6554
netRevenue: DEFAULT_NET_REVENUE,
6655
ttl: DEFAULT_BID_TTL,
67-
currency: DEFAULT_CURRENCY,
68-
mediaType: BANNER // TODO: support more types, we should set mtype on the winning bid
56+
currency: DEFAULT_CURRENCY
57+
},
58+
imp(buildImp, bidRequest, context) {
59+
let imp = buildImp(bidRequest, context);
60+
imp.secure = Number(window.location.protocol === 'https:');
61+
if (!imp.bidfloor && bidRequest.params.bidFloor) {
62+
imp.bidfloor = bidRequest.params.bidFloor;
63+
imp.bidfloorcur = utils.getBidIdParameter('bidFloorCur', bidRequest.params).toUpperCase() || 'USD'
64+
}
65+
66+
if (bidRequest.mediaTypes[VIDEO]) {
67+
imp = buildVideoImp(bidRequest, imp);
68+
} else if (bidRequest.mediaTypes[BANNER]) {
69+
imp = buildBannerImp(bidRequest, imp);
70+
}
71+
72+
return imp;
6973
}
7074
});
7175

72-
registerBidder(spec);
76+
function isBidRequestValid(bidRequest) {
77+
return (isPlacementIdValid(bidRequest) && (isValidBannerRequest(bidRequest) || isValidVideoRequest(bidRequest)));
78+
}
79+
80+
function isPlacementIdValid(bidRequest) {
81+
return utils.isNumber(bidRequest.params.placementId);
82+
}
83+
84+
function isValidBannerRequest(bidRequest) {
85+
const bannerSizes = utils.deepAccess(bidRequest, `mediaTypes.${BANNER}.sizes`);
86+
return utils.isArray(bannerSizes) && bannerSizes.length > 0 && bannerSizes.every(size => utils.isNumber(size[0]) && utils.isNumber(size[1]));
87+
}
88+
89+
function isValidVideoRequest(bidRequest) {
90+
const videoSizes = utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}.playerSize`);
91+
92+
return utils.isArray(videoSizes) && videoSizes.length > 0 && videoSizes.every(size => utils.isNumber(size[0]) && utils.isNumber(size[1]));
93+
}
94+
95+
function buildRequests(validBids, bidderRequest) {
96+
let videoBids = validBids.filter(bid => isVideoBid(bid));
97+
let bannerBids = validBids.filter(bid => isBannerBid(bid));
98+
let requests = [];
99+
100+
bannerBids.forEach(bid => {
101+
requests.push(createRequest([bid], bidderRequest, BANNER));
102+
});
103+
104+
videoBids.forEach(bid => {
105+
requests.push(createRequest([bid], bidderRequest, VIDEO));
106+
});
107+
108+
return requests;
109+
}
110+
111+
function interpretResponse(response, request) {
112+
return CONVERTER.fromORTB({ request: request.data, response: response.body }).bids;
113+
}
114+
115+
function buildVideoImp(bidRequest, imp) {
116+
const videoAdUnitParams = utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}`, {});
117+
const videoBidderParams = utils.deepAccess(bidRequest, `params.${VIDEO}`, {});
118+
119+
const videoParams = { ...videoAdUnitParams, ...videoBidderParams };
120+
121+
const videoSizes = (videoAdUnitParams && videoAdUnitParams.playerSize) || [];
122+
123+
if (videoSizes && videoSizes.length > 0) {
124+
utils.deepSetValue(imp, 'video.w', videoSizes[0][0]);
125+
utils.deepSetValue(imp, 'video.h', videoSizes[0][1]);
126+
}
127+
128+
VIDEO_ORTB_PARAMS.forEach((param) => {
129+
if (videoParams.hasOwnProperty(param)) {
130+
utils.deepSetValue(imp, `video.${param}`, videoParams[param]);
131+
}
132+
});
133+
134+
if (imp.video && videoParams?.context === 'outstream') {
135+
imp.video.placement = imp.video.placement || 4;
136+
}
137+
138+
return { ...imp };
139+
}
140+
141+
function buildBannerImp(bidRequest, imp) {
142+
let sizes = bidRequest.mediaTypes.banner.sizes;
143+
144+
if (sizes) {
145+
utils.deepSetValue(imp, 'banner.w', sizes[0][0]);
146+
utils.deepSetValue(imp, 'banner.h', sizes[0][1]);
147+
}
148+
149+
return { ...imp };
150+
}
151+
152+
function createRequest(bidRequests, bidderRequest, mediaType) {
153+
const data = CONVERTER.toORTB({ bidRequests, bidderRequest, context: { mediaType } })
154+
155+
let bid = bidRequests.find((b) => b.params.placementId)
156+
if (!data.site) data.site = {}
157+
data.site.ext = { placementId: bid.params.placementId }
158+
159+
if (bidderRequest.gdprConsent) {
160+
if (!data.user) data.user = {};
161+
if (!data.user.ext) data.user.ext = {};
162+
if (!data.regs) data.regs = {};
163+
if (!data.regs.ext) data.regs.ext = {};
164+
data.user.ext.consent = bidderRequest.gdprConsent.consentString;
165+
data.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
166+
}
167+
168+
return {
169+
method: 'POST',
170+
url: ENDPOINT,
171+
data: data,
172+
options: { contentType: 'application/json;charset=UTF-8', withCredentials: false }
173+
}
174+
}
175+
176+
function isVideoBid(bid) {
177+
return utils.deepAccess(bid, 'mediaTypes.video');
178+
}
179+
180+
function isBannerBid(bid) {
181+
return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid);
182+
}

modules/eskimiBidAdapter.md

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,41 @@ Maintainer: [email protected]
66

77
# Description
88

9-
An adapter to get a bid from Eskimi DSP.
9+
Module that connects to Eskimi demand sources to fetch bids using OpenRTB standard.
10+
Banner and video formats are supported.
1011

1112
# Test Parameters
1213
```javascript
1314
var adUnits = [{
14-
code: 'div-gpt-ad-1460505748561-0',
15-
mediaTypes: {
16-
banner: {
17-
sizes: [[300, 250], [300, 600]]
18-
}
19-
},
20-
21-
bids: [{
22-
bidder: 'eskimi',
23-
params: {
24-
placementId: 612
25-
}
26-
}]
27-
28-
}];
15+
code: '/19968336/prebid_banner_example_1',
16+
mediaTypes: {
17+
banner: {
18+
sizes: [[ 300, 250 ]]
19+
}
20+
}
21+
bids: [{
22+
bidder: 'eskimi',
23+
params: {
24+
placementId: 612
25+
}
26+
}]
27+
}, {
28+
code: '/19968336/prebid_video_example_1',
29+
mediaTypes: {
30+
video: {
31+
context: 'outstream',
32+
mimes: ['video/mp4'],
33+
api: [1, 2, 4, 6],
34+
... // Aditional ORTB video params
35+
}
36+
}
37+
bids: [{
38+
bidder: 'eskimi',
39+
params: {
40+
placementId: 612
41+
}
42+
}]
43+
}];
2944
```
3045

3146
Where:

0 commit comments

Comments
 (0)