Skip to content

Commit 1c001c6

Browse files
AndriusFromLTUmrobakowski
authored and
Michele Nasti
committed
Eskimi Bid Adapter: Added support for video (prebid#9985)
* Eskimi Bid Adapter: Added support for video * Eskimi adapter: lint updates * Eskimi Bid Adapter: add ortb blocking * Eskimi Bid Adapter: fix ORTB blocking param forwarding --------- Co-authored-by: Mikołaj Robakowski <[email protected]>
1 parent ee5c142 commit 1c001c6

File tree

3 files changed

+470
-169
lines changed

3 files changed

+470
-169
lines changed

modules/eskimiBidAdapter.js

Lines changed: 171 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,35 @@ 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+
'battr'
31+
];
32+
33+
const BANNER_ORTB_PARAMS = [
34+
'battr'
35+
]
36+
1537
export const spec = {
1638
code: BIDDER_CODE,
1739
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-
40+
supportedMediaTypes: [BANNER, VIDEO],
41+
isBidRequestValid,
42+
buildRequests,
43+
interpretResponse,
5244
/**
5345
* Register bidder specific code, which will execute if a bid from this bidder won the auction
5446
* @param {Bid} bid The bid that won the auction
@@ -60,13 +52,151 @@ export const spec = {
6052
}
6153
}
6254

63-
const converter = ortbConverter({
55+
registerBidder(spec);
56+
57+
const CONVERTER = ortbConverter({
6458
context: {
6559
netRevenue: DEFAULT_NET_REVENUE,
6660
ttl: DEFAULT_BID_TTL,
67-
currency: DEFAULT_CURRENCY,
68-
mediaType: BANNER // TODO: support more types, we should set mtype on the winning bid
61+
currency: DEFAULT_CURRENCY
62+
},
63+
imp(buildImp, bidRequest, context) {
64+
let imp = buildImp(bidRequest, context);
65+
imp.secure = Number(window.location.protocol === 'https:');
66+
if (!imp.bidfloor && bidRequest.params.bidFloor) {
67+
imp.bidfloor = bidRequest.params.bidFloor;
68+
imp.bidfloorcur = utils.getBidIdParameter('bidFloorCur', bidRequest.params).toUpperCase() || 'USD'
69+
}
70+
71+
if (bidRequest.mediaTypes[VIDEO]) {
72+
imp = buildVideoImp(bidRequest, imp);
73+
} else if (bidRequest.mediaTypes[BANNER]) {
74+
imp = buildBannerImp(bidRequest, imp);
75+
}
76+
77+
return imp;
6978
}
7079
});
7180

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

modules/eskimiBidAdapter.md

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,48 @@ 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+
... // battr
20+
}
21+
},
22+
bids: [{
23+
bidder: 'eskimi',
24+
params: {
25+
placementId: 612,
26+
... // bcat, badv, bapp
27+
}
28+
}]
29+
}, {
30+
code: '/19968336/prebid_video_example_1',
31+
mediaTypes: {
32+
video: {
33+
context: 'outstream',
34+
mimes: ['video/mp4'],
35+
api: [1, 2, 4, 6],
36+
... // Aditional ORTB video params (including battr)
37+
}
38+
},
39+
bids: [{
40+
bidder: 'eskimi',
41+
params: {
42+
placementId: 612,
43+
... // bcat, badv, bapp
44+
}
45+
}]
46+
}];
2947
```
3048

3149
Where:
3250

3351
* placementId - Placement ID of the ad unit (required)
52+
* bcat, badv, bapp, battr - ORTB blocking parameters as specified by OpenRTB 2.5
3453

0 commit comments

Comments
 (0)