Skip to content

Commit f6b10c6

Browse files
ucfunnelflorevallatmrf
ucfunnel
authored andcommitted
Add instream video and native support to ucfunnel adapter (prebid#2725)
* Add a new ucfunnel Adapter and test page * Add a new ucfunnel Adapter and test page * 1. Use prebid lib in the repo to keep updated 2. Replace var with let 3. Put JSON.parse(JSON.stringify()) into try catch block * utils.getTopWindowLocation is a function * Change to modules from adapters * Migrate to module design * [Dev Fix] Remove width and height which can be got from ad unit id * Update ucfunnelBidAdapter to fit into new spec * Correct the endpoint. Fix the error of query string * Add test case for ucfunnelBidAdapter * Fix lint error * Update version number * Combine all checks on bid request * Add GDPR support for ucfunnel adapter * Add in-stream video and native support for ucfunnel adapter * Remove demo page. Add more test cases. * Change request method from POST to GET * Remove unnecessary comment * Support vastXml and vastUrl for video request
1 parent 6cfe6df commit f6b10c6

File tree

3 files changed

+301
-210
lines changed

3 files changed

+301
-210
lines changed

integrationExamples/gpt/pbjs_ucfunnel_gpt.html

Lines changed: 0 additions & 97 deletions
This file was deleted.

modules/ucfunnelBidAdapter.js

Lines changed: 162 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,54 @@
11
import * as utils from 'src/utils';
22
import {registerBidder} from 'src/adapters/bidderFactory';
3-
import { BANNER } from 'src/mediaTypes';
3+
import {BANNER, VIDEO, NATIVE} from 'src/mediaTypes';
44

55
const VER = 'ADGENT_PREBID-2018011501';
6-
const BID_REQUEST_BASE_URL = '//hb.aralego.com/header';
7-
const UCFUNNEL_BIDDER_CODE = 'ucfunnel';
6+
const BIDDER_CODE = 'ucfunnel';
7+
8+
const VIDEO_CONTEXT = {
9+
INSTREAM: 0,
10+
OUSTREAM: 2
11+
}
812

913
export const spec = {
10-
code: UCFUNNEL_BIDDER_CODE,
11-
supportedMediaTypes: [BANNER],
14+
code: BIDDER_CODE,
15+
ENDPOINT: '//hb.aralego.com/header',
16+
supportedMediaTypes: [BANNER, VIDEO, NATIVE],
1217
/**
1318
* Check if the bid is a valid zone ID in either number or string form
1419
* @param {object} bid the ucfunnel bid to validate
1520
* @return boolean for whether or not a bid is valid
1621
*/
1722
isBidRequestValid: function(bid) {
18-
return !!(bid && bid.params && bid.params.adid && typeof bid.params.adid === 'string');
23+
const isVideoMediaType = utils.deepAccess(bid, 'mediaTypes.video');
24+
const videoContext = utils.deepAccess(bid, 'mediaTypes.video.context');
25+
26+
if (typeof bid.params !== 'object' || typeof bid.params.adid != 'string') {
27+
return false;
28+
}
29+
30+
if (isVideoMediaType && videoContext === 'outstream') {
31+
utils.logWarn('Warning: outstream video is not supported yet');
32+
return false;
33+
}
34+
35+
return true;
1936
},
2037

2138
/**
2239
* @param {BidRequest[]} bidRequests
2340
* @param {*} bidderRequest
2441
* @return {ServerRequest}
2542
*/
26-
buildRequests: function(validBidRequests, bidderRequest) {
27-
var bidRequests = [];
28-
for (var i = 0; i < validBidRequests.length; i++) {
29-
var bid = validBidRequests[i];
30-
31-
var ucfunnelUrlParams = buildUrlParams(bid, bidderRequest);
32-
33-
bidRequests.push({
43+
buildRequests: function(bids, bidderRequest) {
44+
return bids.map(bid => {
45+
return {
3446
method: 'GET',
35-
url: BID_REQUEST_BASE_URL,
36-
bidRequest: bid,
37-
data: ucfunnelUrlParams
38-
});
39-
}
40-
return bidRequests;
47+
url: location.protocol + spec.ENDPOINT,
48+
data: getRequestData(bid, bidderRequest),
49+
bidRequest: bid
50+
}
51+
});
4152
},
4253

4354
/**
@@ -46,55 +57,151 @@ export const spec = {
4657
* @return {Bid[]} An array of formatted bids.
4758
*/
4859
interpretResponse: function (ucfunnelResponseObj, request) {
49-
var bidResponses = [];
50-
var bidRequest = request.bidRequest;
51-
var responseBody = ucfunnelResponseObj ? ucfunnelResponseObj.body : {};
60+
const bidRequest = request.bidRequest;
61+
const ad = ucfunnelResponseObj ? ucfunnelResponseObj.body : {};
62+
const videoPlayerSize = parseSizes(bidRequest);
5263

53-
bidResponses.push({
64+
let bid = {
5465
requestId: bidRequest.bidId,
55-
cpm: responseBody.cpm || 0,
56-
width: responseBody.width,
57-
height: responseBody.height,
58-
creativeId: responseBody.ad_id,
59-
dealId: responseBody.deal || null,
66+
cpm: ad.cpm || 0,
67+
creativeId: ad.ad_id,
68+
dealId: ad.deal || null,
6069
currency: 'USD',
6170
netRevenue: true,
62-
ttl: 1000,
63-
mediaType: BANNER,
64-
ad: responseBody.adm
65-
});
71+
ttl: 1000
72+
};
73+
74+
if (ad.creative_type) {
75+
bid.mediaType = ad.creative_type;
76+
}
77+
78+
switch (ad.creative_type) {
79+
case NATIVE:
80+
let nativeAd = ad.native;
81+
Object.assign(bid, {
82+
width: 1,
83+
height: 1,
84+
native: {
85+
title: nativeAd.title,
86+
body: nativeAd.desc,
87+
cta: nativeAd.ctatext,
88+
sponsoredBy: nativeAd.sponsored,
89+
image: nativeAd.image || nativeAd.image.url,
90+
icon: nativeAd.icon || nativeAd.icon.url,
91+
clickUrl: nativeAd.clickUrl,
92+
impressionTrackers: nativeAd.impressionTrackers,
93+
}
94+
});
95+
break;
96+
case VIDEO:
97+
Object.assign(bid, {
98+
vastUrl: ad.vastUrl,
99+
vastXml: ad.vastXml
100+
});
101+
102+
if (videoPlayerSize && videoPlayerSize.length === 2) {
103+
Object.assign(bid, {
104+
width: videoPlayerSize[0],
105+
height: videoPlayerSize[1]
106+
});
107+
}
108+
break;
109+
case BANNER:
110+
default:
111+
Object.assign(bid, {
112+
width: ad.width,
113+
height: ad.height,
114+
ad: ad.adm
115+
});
116+
}
117+
118+
return [bid];
119+
},
66120

67-
return bidResponses;
121+
getUserSyncs: function(syncOptions) {
122+
if (syncOptions.iframeEnabled) {
123+
return [{
124+
type: 'iframe',
125+
url: '//cdn.aralego.com/ucfad/cookie/sync.html'
126+
}];
127+
} else if (syncOptions.pixelEnabled) {
128+
return [{
129+
type: 'image',
130+
url: '//sync.aralego.com/idSync'
131+
}];
132+
}
68133
}
69134
};
70135
registerBidder(spec);
71136

72-
function buildUrlParams(bid, bidderRequest) {
73-
const host = utils.getTopWindowLocation().host;
74-
const page = utils.getTopWindowLocation().pathname;
75-
const refer = document.referrer;
137+
function transformSizes(requestSizes) {
138+
if (utils.isArray(requestSizes) && requestSizes.length === 2 && !utils.isArray(requestSizes[0])) {
139+
return [parseInt(requestSizes[0], 10), parseInt(requestSizes[1], 10)];
140+
} else if (typeof requestSizes === 'object' && requestSizes.length) {
141+
return requestSizes[0];
142+
}
143+
}
144+
145+
function parseSizes(bid) {
146+
let params = bid.params;
147+
if (bid.mediaType === VIDEO) {
148+
let size = [];
149+
if (params.video && params.video.playerWidth && params.video.playerHeight) {
150+
size = [
151+
params.video.playerWidth,
152+
params.video.playerHeight
153+
];
154+
return size;
155+
}
156+
}
157+
158+
return transformSizes(bid.sizes);
159+
}
160+
161+
function getRequestData(bid, bidderRequest) {
162+
const size = parseSizes(bid);
163+
const loc = utils.getTopWindowLocation();
164+
const host = loc.host;
165+
const page = loc.href;
166+
const ref = utils.getTopWindowReferrer();
76167
const language = navigator.language;
77168
const dnt = (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0;
169+
const videoContext = utils.deepAccess(bid, 'mediaTypes.video.context');
170+
const videoMediaType = utils.deepAccess(bid, 'mediaTypes.video');
78171

79-
let queryString = [
80-
'ifr', '0',
81-
'bl', language,
82-
'je', '1',
83-
'dnt', dnt,
84-
'host', host,
85-
'u', page,
86-
'ru', refer,
87-
'adid', utils.getBidIdParameter('adid', bid.params),
88-
'ver', VER
89-
];
172+
// general bid data
173+
let bidData = {
174+
ver: VER,
175+
ifr: 0,
176+
bl: language,
177+
je: 1,
178+
dnt: dnt,
179+
host: host,
180+
u: page,
181+
ru: ref,
182+
adid: utils.getBidIdParameter('adid', bid.params),
183+
w: size[0],
184+
h: size[1]
185+
};
186+
187+
if (bid.mediaType === 'video' || videoMediaType) {
188+
switch (videoContext) {
189+
case 'outstream':
190+
bidData.atype = VIDEO_CONTEXT.OUSTREAM;
191+
break;
192+
case 'instream':
193+
default:
194+
bidData.atype = VIDEO_CONTEXT.INSTREAM;
195+
break;
196+
}
197+
}
90198

91199
if (bidderRequest && bidderRequest.gdprConsent) {
92-
queryString.push('gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0);
93-
queryString.push('euconsent', bidderRequest.gdprConsent.consentString);
200+
Object.assign(bidData, {
201+
gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0,
202+
euconsent: bidderRequest.gdprConsent.consentString
203+
});
94204
}
95205

96-
return queryString.reduce(
97-
(memo, curr, index) =>
98-
index % 2 === 0 && queryString[index + 1] !== undefined ? memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' : memo, ''
99-
).slice(0, -1);
206+
return bidData;
100207
}

0 commit comments

Comments
 (0)