Skip to content

Commit 3dc8dea

Browse files
zmaticoo Bid Adapter : add support for video (#11016)
* feat:zmaticoo adapter for video Signed-off-by: adam <L12354*。com> * feat:just test ci/circleci:build failed Signed-off-by: adam <L12354*。com> * feat:add unit test Signed-off-by: adam <L12354*。com> * feat:fix response.seatbid and advertiserDomains empty Signed-off-by: adam <L12354*。com> * feat:add unit test Signed-off-by: adam <L12354*。com> --------- Signed-off-by: adam <L12354*。com> Co-authored-by: adam <L12354*。com>
1 parent 9961236 commit 3dc8dea

File tree

3 files changed

+454
-86
lines changed

3 files changed

+454
-86
lines changed

modules/zmaticooBidAdapter.js

Lines changed: 164 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,38 @@
1-
import {deepAccess, logWarn} from '../src/utils.js';
1+
import {deepAccess, isArray, isBoolean, isNumber, isStr, logWarn} from '../src/utils.js';
22
import {registerBidder} from '../src/adapters/bidderFactory.js';
3-
import {BANNER} from '../src/mediaTypes.js';
3+
import {BANNER, VIDEO} from '../src/mediaTypes.js';
44

55
const BIDDER_CODE = 'zmaticoo';
66
const ENDPOINT_URL = 'https://bid.zmaticoo.com/prebid/bid';
77
const DEFAULT_CUR = 'USD';
88
const TTL = 200;
99
const NET_REV = true;
1010

11+
const DATA_TYPES = {
12+
'NUMBER': 'number', 'STRING': 'string', 'BOOLEAN': 'boolean', 'ARRAY': 'array', 'OBJECT': 'object'
13+
};
14+
const VIDEO_CUSTOM_PARAMS = {
15+
'mimes': DATA_TYPES.ARRAY,
16+
'minduration': DATA_TYPES.NUMBER,
17+
'maxduration': DATA_TYPES.NUMBER,
18+
'startdelay': DATA_TYPES.NUMBER,
19+
'playbackmethod': DATA_TYPES.ARRAY,
20+
'api': DATA_TYPES.ARRAY,
21+
'protocols': DATA_TYPES.ARRAY,
22+
'w': DATA_TYPES.NUMBER,
23+
'h': DATA_TYPES.NUMBER,
24+
'battr': DATA_TYPES.ARRAY,
25+
'linearity': DATA_TYPES.NUMBER,
26+
'placement': DATA_TYPES.NUMBER,
27+
'plcmt': DATA_TYPES.NUMBER,
28+
'minbitrate': DATA_TYPES.NUMBER,
29+
'maxbitrate': DATA_TYPES.NUMBER,
30+
'skip': DATA_TYPES.NUMBER
31+
}
32+
1133
export const spec = {
1234
code: BIDDER_CODE,
13-
supportedMediaTypes: [BANNER],
35+
supportedMediaTypes: [BANNER, VIDEO],
1436

1537
/**
1638
* Determines whether or not the given bid request is valid.
@@ -20,6 +42,10 @@ export const spec = {
2042
*/
2143
isBidRequestValid: function (bid) {
2244
// check for all required bid fields
45+
if (!(hasBannerMediaType(bid) || hasVideoMediaType(bid))) {
46+
logWarn('Invalid bid request - missing required mediaTypes');
47+
return false;
48+
}
2349
if (!(bid && bid.bidId && bid.params)) {
2450
logWarn('Invalid bid request - missing required bid data');
2551
return false;
@@ -30,7 +56,7 @@ export const spec = {
3056
return false;
3157
}
3258

33-
if (!(bid.params.device && bid.params.device.ip)) {
59+
if (!(bid.params.device)) {
3460
logWarn('Invalid bid request - missing required device data');
3561
return false;
3662
}
@@ -48,19 +74,49 @@ export const spec = {
4874
const secure = 1;
4975
const request = validBidRequests[0];
5076
const params = request.params;
51-
let impData = {
52-
id: request.bidId,
53-
secure: secure,
54-
banner: buildBanner(request),
55-
ext: {
56-
bidder: {
57-
pubId: params.pubId
77+
const imps = validBidRequests.map(request => {
78+
const impData = {
79+
id: request.bidId,
80+
secure: secure,
81+
ext: {
82+
bidder: {
83+
pubId: params.pubId
84+
}
5885
}
86+
};
87+
if (params.tagid) {
88+
impData.tagid = params.tagid;
5989
}
60-
};
90+
if (request.mediaTypes) {
91+
for (const mediaType in request.mediaTypes) {
92+
switch (mediaType) {
93+
case BANNER:
94+
impData.banner = buildBanner(request);
95+
break;
96+
case VIDEO:
97+
impData.video = buildVideo(request);
98+
break;
99+
}
100+
}
101+
}
102+
if (typeof bidderRequest.getFloor === 'function') {
103+
const floorInfo = bidderRequest.getFloor({
104+
currency: 'USD',
105+
mediaType: impData.video ? 'video' : 'banner',
106+
size: [impData.video ? impData.video.w : impData.banner.w, impData.video ? impData.video.h : impData.banner.h]
107+
});
108+
if (floorInfo && floorInfo.floor) {
109+
impData.bidfloor = floorInfo.floor;
110+
}
111+
}
112+
if (!impData.bidfloor && params.bidfloor) {
113+
impData.bidfloor = params.bidfloor;
114+
}
115+
return impData;
116+
});
61117
let payload = {
62118
id: bidderRequest.bidderRequestId,
63-
imp: [impData],
119+
imp: imps,
64120
site: params.site ? params.site : {},
65121
app: params.app ? params.app : {},
66122
device: params.device ? params.device : {},
@@ -79,19 +135,21 @@ export const spec = {
79135
regs: params.regs ? params.regs : {},
80136
ext: params.ext ? params.ext : {}
81137
};
82-
138+
payload.regs.ext = {}
139+
payload.user.ext = {}
83140
payload.device.ua = navigator.userAgent;
84141
payload.device.ip = navigator.ip;
85-
payload.site.page = bidderRequest.refererInfo.page;
142+
payload.site.page = bidderRequest?.refererInfo?.page || window.location.href;
143+
payload.site.domain = _getDomainFromURL(payload.site.page);
86144
payload.site.mobile = /(ios|ipod|ipad|iphone|android)/i.test(navigator.userAgent) ? 1 : 0;
87145
if (params.test) {
88146
payload.test = params.test;
89147
}
90-
if (request.gdprConsent) {
91-
payload.regs.ext = Object.assign(payload.regs.ext, {gdpr: request.gdprConsent.gdprApplies === true ? 1 : 0});
148+
if (bidderRequest.gdprConsent) {
149+
payload.regs.ext = Object.assign(payload.regs.ext, {gdpr: bidderRequest.gdprConsent.gdprApplies == true ? 1 : 0});
92150
}
93-
if (request.gdprConsent && request.gdprConsent.gdprApplies) {
94-
payload.user.ext = Object.assign(payload.user.ext, {consent: request.gdprConsent.consentString});
151+
if (bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) {
152+
payload.user.ext = Object.assign(payload.user.ext, {consent: bidderRequest.gdprConsent.consentString});
95153
}
96154
const postUrl = ENDPOINT_URL;
97155
return {
@@ -103,28 +161,37 @@ export const spec = {
103161
* Unpack the response from the server into a list of bids.
104162
*
105163
* @param {ServerResponse} serverResponse A successful response from the server.
106-
* @param bidRequest The payload from the server's response.
164+
* @param {BidRequest} bidRequest The payload from the server's response.
107165
* @return {Bid[]} An array of bids which were nested inside the server.
108166
*/
109167
interpretResponse: function (serverResponse, bidRequest) {
110-
let bidResponse = [];
111-
if (Object.keys(serverResponse.body).length !== 0) {
112-
let zresponse = serverResponse.body;
113-
let zbid = zresponse.seatbid[0].bid[0];
114-
let bid = {
115-
requestId: zbid.impid,
116-
cpm: zbid.price,
117-
currency: zbid.cur,
118-
width: zbid.w,
119-
height: zbid.h,
120-
ad: zbid.adm,
121-
ttl: TTL,
122-
creativeId: zbid.crid,
123-
netRevenue: NET_REV
124-
};
125-
bidResponse.push(bid);
168+
let bidResponses = [];
169+
const response = (serverResponse || {}).body;
170+
if (response && response.seatbid && response.seatbid.length && response.seatbid[0].bid && response.seatbid[0].bid.length) {
171+
response.seatbid.forEach(zmSeatbid => {
172+
zmSeatbid.bid.forEach(zmBid => {
173+
let bid = {
174+
requestId: zmBid.impid,
175+
cpm: zmBid.price,
176+
currency: response.cur,
177+
width: zmBid.w,
178+
height: zmBid.h,
179+
ad: zmBid.adm,
180+
ttl: TTL,
181+
creativeId: zmBid.crid,
182+
netRevenue: NET_REV,
183+
};
184+
bid.meta = {
185+
advertiserDomains: (zmBid.adomain && zmBid.adomain.length) ? zmBid.adomain : []
186+
};
187+
if (zmBid.ext && zmBid.ext.vast_url) {
188+
bid.vastXml = zmBid.ext.vast_url;
189+
}
190+
bidResponses.push(bid);
191+
})
192+
})
126193
}
127-
return bidResponse;
194+
return bidResponses;
128195
}
129196
}
130197

@@ -138,4 +205,64 @@ function buildBanner(request) {
138205
};
139206
}
140207

208+
function buildVideo(request) {
209+
let video = {};
210+
const videoParams = deepAccess(request, 'mediaTypes.video', {});
211+
for (const key in VIDEO_CUSTOM_PARAMS) {
212+
if (videoParams.hasOwnProperty(key)) {
213+
video[key] = checkParamDataType(key, videoParams[key], VIDEO_CUSTOM_PARAMS[key]);
214+
}
215+
}
216+
if (videoParams.playerSize) {
217+
if (isArray(videoParams.playerSize[0])) {
218+
video.w = parseInt(videoParams.playerSize[0][0], 10);
219+
video.h = parseInt(videoParams.playerSize[0][1], 10);
220+
} else if (isNumber(videoParams.playerSize[0])) {
221+
video.w = parseInt(videoParams.playerSize[0], 10);
222+
video.h = parseInt(videoParams.playerSize[1], 10);
223+
}
224+
}
225+
return video;
226+
}
227+
228+
export function checkParamDataType(key, value, datatype) {
229+
let functionToExecute;
230+
switch (datatype) {
231+
case DATA_TYPES.BOOLEAN:
232+
functionToExecute = isBoolean;
233+
break;
234+
case DATA_TYPES.NUMBER:
235+
functionToExecute = isNumber;
236+
break;
237+
case DATA_TYPES.STRING:
238+
functionToExecute = isStr;
239+
break;
240+
case DATA_TYPES.ARRAY:
241+
functionToExecute = isArray;
242+
break;
243+
}
244+
if (functionToExecute(value)) {
245+
return value;
246+
}
247+
logWarn('Ignoring param key: ' + key + ', expects ' + datatype + ', found ' + typeof value);
248+
return undefined;
249+
}
250+
251+
function hasBannerMediaType(bidRequest) {
252+
return !!deepAccess(bidRequest, 'mediaTypes.banner');
253+
}
254+
255+
/**
256+
* @param {BidRequest} bidRequest bid request
257+
*/
258+
function hasVideoMediaType(bidRequest) {
259+
return !!deepAccess(bidRequest, 'mediaTypes.video');
260+
}
261+
262+
export function _getDomainFromURL(url) {
263+
let anchor = document.createElement('a');
264+
anchor.href = url;
265+
return anchor.hostname;
266+
}
267+
141268
registerBidder(spec);

modules/zmaticooBidAdapter.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ zMaticoo Bidder Adapter for Prebid.js.
1212

1313
# Test Parameters
1414

15+
## banner
16+
1517
```
1618
var adUnits = [
1719
{
@@ -23,7 +25,7 @@ zMaticoo Bidder Adapter for Prebid.js.
2325
bids: [
2426
{
2527
bidder: 'zmaticoo',
26-
bidId: '12345',
28+
bidId: '123456',
2729
params: {
2830
user: {
2931
uid: '12345',
@@ -43,3 +45,36 @@ zMaticoo Bidder Adapter for Prebid.js.
4345
}
4446
];
4547
```
48+
49+
## video
50+
51+
```
52+
var adUnits = [{
53+
code: 'test1',
54+
mediaTypes: {
55+
video: {
56+
playerSize: [480, 320],
57+
mimes: ['video/mp4'],
58+
context: 'instream',
59+
placement: 1, // required, integer
60+
maxduration: 30, // required, integer
61+
minduration: 15, // optional, integer
62+
pos: 1, // optional, integer
63+
startdelay: 10, // required if placement == 1
64+
protocols: [2, 3], // required, array of integers
65+
api: [2, 3], // required, array of integers
66+
playbackmethod: [2, 6], // required, array of integers
67+
skippable: true, // optional, boolean
68+
skipafter: 10 // optional, integer
69+
}
70+
},
71+
bids: [{
72+
bidder: "zmaticoo",
73+
bidId: '123456',
74+
params: {
75+
pubId: 'prebid-test',
76+
site: {domain: "test.com"}
77+
}
78+
}]
79+
}];
80+
```

0 commit comments

Comments
 (0)