Skip to content

Commit d0bb0f5

Browse files
add EMTV adapter (#9783)
1 parent cff4364 commit d0bb0f5

File tree

3 files changed

+690
-0
lines changed

3 files changed

+690
-0
lines changed

modules/emtvBidAdapter.js

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
import { isFn, deepAccess, logMessage, logError } from '../src/utils.js';
2+
import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
3+
4+
import { registerBidder } from '../src/adapters/bidderFactory.js';
5+
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
6+
import { config } from '../src/config.js';
7+
8+
const BIDDER_CODE = 'emtv';
9+
const AD_URL = 'https://us-east-ep.engagemedia.tv/pbjs';
10+
const SYNC_URL = 'https://cs.engagemedia.tv';
11+
12+
function isBidResponseValid(bid) {
13+
if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) {
14+
return false;
15+
}
16+
17+
switch (bid.mediaType) {
18+
case BANNER:
19+
return Boolean(bid.width && bid.height && bid.ad);
20+
case VIDEO:
21+
return Boolean(bid.vastUrl || bid.vastXml);
22+
case NATIVE:
23+
return Boolean(bid.native && bid.native.impressionTrackers && bid.native.impressionTrackers.length);
24+
default:
25+
return false;
26+
}
27+
}
28+
29+
function getPlacementReqData(bid) {
30+
const { params, bidId, mediaTypes } = bid;
31+
const schain = bid.schain || {};
32+
const { placementId, endpointId } = params;
33+
const bidfloor = getBidFloor(bid);
34+
35+
const placement = {
36+
bidId,
37+
schain,
38+
bidfloor
39+
};
40+
41+
if (placementId) {
42+
placement.placementId = placementId;
43+
placement.type = 'publisher';
44+
} else if (endpointId) {
45+
placement.endpointId = endpointId;
46+
placement.type = 'network';
47+
}
48+
49+
if (mediaTypes && mediaTypes[BANNER]) {
50+
placement.adFormat = BANNER;
51+
placement.sizes = mediaTypes[BANNER].sizes;
52+
} else if (mediaTypes && mediaTypes[VIDEO]) {
53+
placement.adFormat = VIDEO;
54+
placement.playerSize = mediaTypes[VIDEO].playerSize;
55+
placement.minduration = mediaTypes[VIDEO].minduration;
56+
placement.maxduration = mediaTypes[VIDEO].maxduration;
57+
placement.mimes = mediaTypes[VIDEO].mimes;
58+
placement.protocols = mediaTypes[VIDEO].protocols;
59+
placement.startdelay = mediaTypes[VIDEO].startdelay;
60+
placement.placement = mediaTypes[VIDEO].placement;
61+
placement.skip = mediaTypes[VIDEO].skip;
62+
placement.skipafter = mediaTypes[VIDEO].skipafter;
63+
placement.minbitrate = mediaTypes[VIDEO].minbitrate;
64+
placement.maxbitrate = mediaTypes[VIDEO].maxbitrate;
65+
placement.delivery = mediaTypes[VIDEO].delivery;
66+
placement.playbackmethod = mediaTypes[VIDEO].playbackmethod;
67+
placement.api = mediaTypes[VIDEO].api;
68+
placement.linearity = mediaTypes[VIDEO].linearity;
69+
} else if (mediaTypes && mediaTypes[NATIVE]) {
70+
placement.native = mediaTypes[NATIVE];
71+
placement.adFormat = NATIVE;
72+
}
73+
74+
return placement;
75+
}
76+
77+
function getBidFloor(bid) {
78+
if (!isFn(bid.getFloor)) {
79+
return deepAccess(bid, 'params.bidfloor', 0);
80+
}
81+
82+
try {
83+
const bidFloor = bid.getFloor({
84+
currency: 'USD',
85+
mediaType: '*',
86+
size: '*',
87+
});
88+
return bidFloor.floor;
89+
} catch (err) {
90+
logError(err);
91+
return 0;
92+
}
93+
}
94+
95+
export const spec = {
96+
code: BIDDER_CODE,
97+
supportedMediaTypes: [BANNER, VIDEO, NATIVE],
98+
99+
isBidRequestValid: (bid = {}) => {
100+
const { params, bidId, mediaTypes } = bid;
101+
let valid = Boolean(bidId && params && (params.placementId || params.endpointId));
102+
103+
if (mediaTypes && mediaTypes[BANNER]) {
104+
valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes);
105+
} else if (mediaTypes && mediaTypes[VIDEO]) {
106+
valid = valid && Boolean(mediaTypes[VIDEO] && mediaTypes[VIDEO].playerSize);
107+
} else if (mediaTypes && mediaTypes[NATIVE]) {
108+
valid = valid && Boolean(mediaTypes[NATIVE]);
109+
} else {
110+
valid = false;
111+
}
112+
return valid;
113+
},
114+
115+
buildRequests: (validBidRequests = [], bidderRequest = {}) => {
116+
// convert Native ORTB definition to old-style prebid native definition
117+
validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
118+
119+
let deviceWidth = 0;
120+
let deviceHeight = 0;
121+
122+
let winLocation;
123+
try {
124+
const winTop = window.top;
125+
deviceWidth = winTop.screen.width;
126+
deviceHeight = winTop.screen.height;
127+
winLocation = winTop.location;
128+
} catch (e) {
129+
logMessage(e);
130+
winLocation = window.location;
131+
}
132+
133+
const refferUrl = bidderRequest.refererInfo && bidderRequest.refererInfo.page;
134+
let refferLocation;
135+
try {
136+
refferLocation = refferUrl && new URL(refferUrl);
137+
} catch (e) {
138+
logMessage(e);
139+
}
140+
let location = refferLocation || winLocation;
141+
const language = (navigator && navigator.language) ? navigator.language.split('-')[0] : '';
142+
const host = location.host;
143+
const page = location.pathname;
144+
const secure = location.protocol === 'https:' ? 1 : 0;
145+
const placements = [];
146+
const request = {
147+
deviceWidth,
148+
deviceHeight,
149+
language,
150+
secure,
151+
host,
152+
page,
153+
placements,
154+
coppa: config.getConfig('coppa') === true ? 1 : 0,
155+
ccpa: bidderRequest.uspConsent || undefined,
156+
gdpr: bidderRequest.gdprConsent || undefined,
157+
tmax: config.getConfig('bidderTimeout')
158+
};
159+
160+
const len = validBidRequests.length;
161+
for (let i = 0; i < len; i++) {
162+
const bid = validBidRequests[i];
163+
placements.push(getPlacementReqData(bid));
164+
}
165+
166+
return {
167+
method: 'POST',
168+
url: AD_URL,
169+
data: request
170+
};
171+
},
172+
173+
interpretResponse: (serverResponse) => {
174+
let response = [];
175+
for (let i = 0; i < serverResponse.body.length; i++) {
176+
let resItem = serverResponse.body[i];
177+
if (isBidResponseValid(resItem)) {
178+
const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : [];
179+
resItem.meta = { ...resItem.meta, advertiserDomains };
180+
181+
response.push(resItem);
182+
}
183+
}
184+
return response;
185+
},
186+
187+
getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => {
188+
let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image';
189+
let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`;
190+
if (gdprConsent && gdprConsent.consentString) {
191+
if (typeof gdprConsent.gdprApplies === 'boolean') {
192+
syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
193+
} else {
194+
syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`;
195+
}
196+
}
197+
if (uspConsent && uspConsent.consentString) {
198+
syncUrl += `&ccpa_consent=${uspConsent.consentString}`;
199+
}
200+
201+
const coppa = config.getConfig('coppa') ? 1 : 0;
202+
syncUrl += `&coppa=${coppa}`;
203+
204+
return [{
205+
type: syncType,
206+
url: syncUrl
207+
}];
208+
}
209+
};
210+
211+
registerBidder(spec);

modules/emtvBidAdapter.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Overview
2+
3+
```
4+
Module Name: EMTV Bidder Adapter
5+
Module Type: EMTV Bidder Adapter
6+
Maintainer: [email protected]
7+
```
8+
9+
# Description
10+
11+
Connects to EMTV exchange for bids.
12+
EMTV bid adapter supports Banner, Video (instream and outstream) and Native.
13+
14+
# Test Parameters
15+
```
16+
var adUnits = [
17+
// Will return static test banner
18+
{
19+
code: 'adunit1',
20+
mediaTypes: {
21+
banner: {
22+
sizes: [ [300, 250], [320, 50] ],
23+
}
24+
},
25+
bids: [
26+
{
27+
bidder: 'emtv',
28+
params: {
29+
placementId: 'testBanner',
30+
}
31+
}
32+
]
33+
},
34+
{
35+
code: 'addunit2',
36+
mediaTypes: {
37+
video: {
38+
playerSize: [ [640, 480] ],
39+
context: 'instream',
40+
minduration: 5,
41+
maxduration: 60,
42+
}
43+
},
44+
bids: [
45+
{
46+
bidder: 'emtv',
47+
params: {
48+
placementId: 'testVideo',
49+
}
50+
}
51+
]
52+
},
53+
{
54+
code: 'addunit3',
55+
mediaTypes: {
56+
native: {
57+
title: {
58+
required: true
59+
},
60+
body: {
61+
required: true
62+
},
63+
icon: {
64+
required: true,
65+
size: [64, 64]
66+
}
67+
}
68+
},
69+
bids: [
70+
{
71+
bidder: 'emtv',
72+
params: {
73+
placementId: 'testNative',
74+
}
75+
}
76+
]
77+
}
78+
];
79+
```

0 commit comments

Comments
 (0)