Skip to content

Commit 6592920

Browse files
patryk-grzegorczykmdusmanalvi
authored andcommitted
AdOcean Bid Adapter: initial release (prebid#13982)
* [ADO-981] Adocean adapter * [ADO-981] Tests and some bug fixes * [ADO-981] Video tests * [ADO-981] Ao sizes * [ADO-981] Review changes * [ADO-981] Updated bidder md file * [ADO-981] Change param name
1 parent 6d7d215 commit 6592920

File tree

3 files changed

+683
-0
lines changed

3 files changed

+683
-0
lines changed

modules/adoceanBidAdapter.js

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { _each, isStr, isArray, parseSizesInput } from '../src/utils.js';
2+
import { registerBidder } from '../src/adapters/bidderFactory.js';
3+
import { BANNER, VIDEO } from '../src/mediaTypes.js';
4+
5+
const BIDDER_CODE = 'adocean';
6+
const URL_SAFE_FIELDS = {
7+
slaves: true
8+
};
9+
10+
function buildEndpointUrl(emitter, payloadMap) {
11+
const payload = [];
12+
_each(payloadMap, function(v, k) {
13+
payload.push(k + '=' + (URL_SAFE_FIELDS[k] ? v : encodeURIComponent(v)));
14+
});
15+
16+
const randomizedPart = Math.random().toString().slice(2);
17+
return 'https://' + emitter + '/_' + randomizedPart + '/ad.json?' + payload.join('&');
18+
}
19+
20+
function buildRequest(bid, gdprConsent) {
21+
const emitter = bid.params.emitter;
22+
const masterId = bid.params.masterId;
23+
const slaveId = bid.params.slaveId;
24+
const payload = {
25+
id: masterId,
26+
slaves: ""
27+
};
28+
if (gdprConsent) {
29+
payload.gdpr_consent = gdprConsent.consentString || undefined;
30+
payload.gdpr = gdprConsent.gdprApplies ? 1 : 0;
31+
}
32+
33+
if (bid.userId && bid.userId.gemiusId) {
34+
payload.aouserid = bid.userId.gemiusId;
35+
}
36+
37+
const bidIdMap = {};
38+
const uniquePartLength = 10;
39+
40+
const rawSlaveId = bid.params.slaveId.replace('adocean', '');
41+
payload.slaves = rawSlaveId.slice(-uniquePartLength);
42+
43+
bidIdMap[slaveId] = bid.bidId;
44+
45+
if (bid.mediaTypes.video) {
46+
if (bid.mediaTypes.video.context === 'instream') {
47+
if (bid.mediaTypes.video.maxduration) {
48+
payload.dur = bid.mediaTypes.video.maxduration;
49+
payload.maxdur = bid.mediaTypes.video.maxduration;
50+
}
51+
if (bid.mediaTypes.video.minduration) {
52+
payload.mindur = bid.mediaTypes.video.minduration;
53+
}
54+
payload.spots = 1;
55+
}
56+
if (bid.mediaTypes.video.context === 'adpod') {
57+
const durationRangeSec = bid.mediaTypes.video.durationRangeSec;
58+
if (!bid.mediaTypes.video.adPodDurationSec || !isArray(durationRangeSec) || durationRangeSec.length === 0) {
59+
return;
60+
}
61+
const spots = calculateAdPodSpotsNumber(bid.mediaTypes.video.adPodDurationSec, bid.mediaTypes.video.durationRangeSec);
62+
const maxDuration = Math.max(...durationRangeSec);
63+
payload.dur = bid.mediaTypes.video.adPodDurationSec;
64+
payload.maxdur = maxDuration;
65+
payload.spots = spots;
66+
}
67+
} else if (bid.mediaTypes.banner) {
68+
payload.aosize = parseSizesInput(bid.mediaTypes.banner.sizes).join(',');
69+
}
70+
71+
return {
72+
method: 'GET',
73+
url: buildEndpointUrl(emitter, payload),
74+
data: '',
75+
bidIdMap: bidIdMap
76+
};
77+
}
78+
79+
function calculateAdPodSpotsNumber(adPodDurationSec, durationRangeSec) {
80+
const minAllowedDuration = Math.min(...durationRangeSec);
81+
const numberOfSpots = Math.floor(adPodDurationSec / minAllowedDuration);
82+
return numberOfSpots;
83+
}
84+
85+
function interpretResponse(placementResponse, bidRequest, bids) {
86+
const requestId = bidRequest.bidIdMap[placementResponse.id];
87+
if (!placementResponse.error && requestId) {
88+
if (!placementResponse.code || !placementResponse.height || !placementResponse.width || !placementResponse.price) {
89+
return;
90+
}
91+
let adCode = decodeURIComponent(placementResponse.code);
92+
93+
const bid = {
94+
cpm: parseFloat(placementResponse.price),
95+
currency: placementResponse.currency,
96+
height: parseInt(placementResponse.height, 10),
97+
requestId: requestId,
98+
width: parseInt(placementResponse.width, 10),
99+
netRevenue: false,
100+
ttl: parseInt(placementResponse.ttl),
101+
creativeId: placementResponse.crid,
102+
meta: {
103+
advertiserDomains: placementResponse.adomain || []
104+
}
105+
};
106+
if (placementResponse.isVideo) {
107+
bid.meta.mediaType = VIDEO;
108+
bid.vastXml = adCode;
109+
} else {
110+
bid.meta.mediaType = BANNER;
111+
bid.ad = adCode;
112+
}
113+
114+
bids.push(bid);
115+
}
116+
}
117+
118+
export const spec = {
119+
code: BIDDER_CODE,
120+
supportedMediaTypes: [BANNER, VIDEO],
121+
122+
isBidRequestValid: function(bid) {
123+
const requiredParams = ['slaveId', 'masterId', 'emitter'];
124+
if (requiredParams.some(name => !isStr(bid.params[name]) || !bid.params[name].length)) {
125+
return false;
126+
}
127+
128+
if (bid.mediaTypes.banner) {
129+
return true;
130+
}
131+
if (bid.mediaTypes.video) {
132+
if (bid.mediaTypes.video.context === 'instream') {
133+
return true;
134+
}
135+
if (bid.mediaTypes.video.context === 'adpod') {
136+
return !bid.mediaTypes.video.requireExactDuration;
137+
}
138+
}
139+
return false;
140+
},
141+
142+
buildRequests: function(validBidRequests, bidderRequest) {
143+
let requests = [];
144+
145+
_each(validBidRequests, function(bidRequest) {
146+
requests.push(buildRequest(bidRequest, bidderRequest.gdprConsent));
147+
});
148+
149+
return requests;
150+
},
151+
152+
interpretResponse: function(serverResponse, bidRequest) {
153+
let bids = [];
154+
155+
if (isArray(serverResponse.body)) {
156+
_each(serverResponse.body, function(placementResponse) {
157+
interpretResponse(placementResponse, bidRequest, bids);
158+
});
159+
}
160+
161+
return bids;
162+
}
163+
};
164+
registerBidder(spec);

modules/adoceanBidAdapter.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Overview
2+
3+
Module Name: AdOcean Bidder Adapter
4+
Module Type: Bidder Adapter
5+
Maintainer: [email protected]
6+
7+
# Description
8+
9+
AdOcean Bidder Adapter for Prebid.js.
10+
Banner and video formats are supported.
11+
12+
# Test Parameters Banner
13+
```js
14+
var adUnits = [
15+
{
16+
code: 'test-div',
17+
mediaTypes: {
18+
banner: {
19+
sizes: [[300, 200]]
20+
}
21+
},
22+
bids: [
23+
{
24+
bidder: "adocean",
25+
params: {
26+
slaveId: 'adoceanmyaotcpiltmmnj',
27+
masterId: 'ek1AWtSWh3BOa_x2P1vlMQ_uXXJpJcbhsHAY5PFQjWD.D7',
28+
emitter: 'myao.adocean.pl'
29+
}
30+
}
31+
]
32+
}
33+
];
34+
```
35+
# Test Parameters Video
36+
```js
37+
var adUnits = [
38+
{
39+
code: 'test-div',
40+
mediaTypes: {
41+
video: {
42+
context: 'instream',
43+
playerSize: [300, 200]
44+
}
45+
},
46+
bids: [
47+
{
48+
bidder: "adocean",
49+
params: {
50+
slaveId: 'adoceanmyaonenfcoqfnd',
51+
masterId: '2k6gA7RWl08Zn0bi42RV8LNCANpKb6LqhvKzbmK3pzP.U7',
52+
emitter: 'myao.adocean.pl'
53+
}
54+
}
55+
]
56+
}
57+
];
58+
```

0 commit comments

Comments
 (0)