1
- import { deepAccess , logWarn } from '../src/utils.js' ;
1
+ import { deepAccess , isArray , isBoolean , isNumber , isStr , logWarn } from '../src/utils.js' ;
2
2
import { registerBidder } from '../src/adapters/bidderFactory.js' ;
3
- import { BANNER } from '../src/mediaTypes.js' ;
3
+ import { BANNER , VIDEO } from '../src/mediaTypes.js' ;
4
4
5
5
const BIDDER_CODE = 'zmaticoo' ;
6
6
const ENDPOINT_URL = 'https://bid.zmaticoo.com/prebid/bid' ;
7
7
const DEFAULT_CUR = 'USD' ;
8
8
const TTL = 200 ;
9
9
const NET_REV = true ;
10
10
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
+
11
33
export const spec = {
12
34
code : BIDDER_CODE ,
13
- supportedMediaTypes : [ BANNER ] ,
35
+ supportedMediaTypes : [ BANNER , VIDEO ] ,
14
36
15
37
/**
16
38
* Determines whether or not the given bid request is valid.
@@ -20,6 +42,10 @@ export const spec = {
20
42
*/
21
43
isBidRequestValid : function ( bid ) {
22
44
// check for all required bid fields
45
+ if ( ! ( hasBannerMediaType ( bid ) || hasVideoMediaType ( bid ) ) ) {
46
+ logWarn ( 'Invalid bid request - missing required mediaTypes' ) ;
47
+ return false ;
48
+ }
23
49
if ( ! ( bid && bid . bidId && bid . params ) ) {
24
50
logWarn ( 'Invalid bid request - missing required bid data' ) ;
25
51
return false ;
@@ -30,7 +56,7 @@ export const spec = {
30
56
return false ;
31
57
}
32
58
33
- if ( ! ( bid . params . device && bid . params . device . ip ) ) {
59
+ if ( ! ( bid . params . device ) ) {
34
60
logWarn ( 'Invalid bid request - missing required device data' ) ;
35
61
return false ;
36
62
}
@@ -48,19 +74,49 @@ export const spec = {
48
74
const secure = 1 ;
49
75
const request = validBidRequests [ 0 ] ;
50
76
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
+ }
58
85
}
86
+ } ;
87
+ if ( params . tagid ) {
88
+ impData . tagid = params . tagid ;
59
89
}
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
+ } ) ;
61
117
let payload = {
62
118
id : bidderRequest . bidderRequestId ,
63
- imp : [ impData ] ,
119
+ imp : imps ,
64
120
site : params . site ? params . site : { } ,
65
121
app : params . app ? params . app : { } ,
66
122
device : params . device ? params . device : { } ,
@@ -79,19 +135,21 @@ export const spec = {
79
135
regs : params . regs ? params . regs : { } ,
80
136
ext : params . ext ? params . ext : { }
81
137
} ;
82
-
138
+ payload . regs . ext = { }
139
+ payload . user . ext = { }
83
140
payload . device . ua = navigator . userAgent ;
84
141
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 ) ;
86
144
payload . site . mobile = / ( i o s | i p o d | i p a d | i p h o n e | a n d r o i d ) / i. test ( navigator . userAgent ) ? 1 : 0 ;
87
145
if ( params . test ) {
88
146
payload . test = params . test ;
89
147
}
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 } ) ;
92
150
}
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 } ) ;
95
153
}
96
154
const postUrl = ENDPOINT_URL ;
97
155
return {
@@ -103,28 +161,37 @@ export const spec = {
103
161
* Unpack the response from the server into a list of bids.
104
162
*
105
163
* @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.
107
165
* @return {Bid[] } An array of bids which were nested inside the server.
108
166
*/
109
167
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
+ } )
126
193
}
127
- return bidResponse ;
194
+ return bidResponses ;
128
195
}
129
196
}
130
197
@@ -138,4 +205,64 @@ function buildBanner(request) {
138
205
} ;
139
206
}
140
207
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
+
141
268
registerBidder ( spec ) ;
0 commit comments