Skip to content

Commit d4ff1ec

Browse files
Adding freewheel module (prebid#3489)
* adding freewheel module * adding commented references to adpod module * upadate some properties and refactor * updated adpod import and competitive exclusion logic * add hook to freewheel module * add logic for deferCaching * refactor targeting logic for deferCaching and activate commented code * modify import for test file * update hook
1 parent e96d58e commit d4ff1ec

File tree

2 files changed

+425
-0
lines changed

2 files changed

+425
-0
lines changed

modules/freeWheelAdserverVideo.js

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/**
2+
* This module adds Freewheel support for Video to Prebid.
3+
*/
4+
5+
import { registerVideoSupport } from '../src/adServerManager';
6+
import { auctionManager } from '../src/auctionManager';
7+
import { groupBy, deepAccess, logError } from '../src/utils';
8+
import { config } from '../src/config';
9+
import { ADPOD } from '../src/mediaTypes';
10+
import { initAdpodHooks, TARGETING_KEY_PB_CAT_DUR, TARGETING_KEY_CACHE_ID, callPrebidCacheAfterAuction } from './adpod';
11+
import { getHook } from '../src/hook';
12+
13+
export function notifyTranslationModule(fn) {
14+
fn.call(this, 'freewheel');
15+
}
16+
17+
getHook('registerAdserver').before(notifyTranslationModule);
18+
19+
/**
20+
* This function returns targeting keyvalue pairs for freewheel adserver module
21+
* @param {Object} options
22+
* @param {Array[string]} codes
23+
* @param {function} callback
24+
* @returns targeting kvs for adUnitCodes
25+
*/
26+
export function getTargeting({codes, callback} = {}) {
27+
if (!callback) {
28+
logError('No callback function was defined in the getTargeting call. Aborting getTargeting().');
29+
return;
30+
}
31+
codes = codes || [];
32+
const adPodAdUnits = getAdPodAdUnits(codes);
33+
const bidsReceived = auctionManager.getBidsReceived();
34+
const competiveExclusionEnabled = config.getConfig('adpod.brandCategoryExclusion');
35+
const deferCachingSetting = config.getConfig('adpod.deferCaching');
36+
const deferCachingEnabled = (typeof deferCachingSetting === 'boolean') ? deferCachingSetting : true;
37+
38+
let bids = getBidsForAdpod(bidsReceived, adPodAdUnits);
39+
bids = (competiveExclusionEnabled || deferCachingEnabled) ? getExclusiveBids(bids) : bids;
40+
bids.sort(compareOn('cpm'));
41+
42+
let targeting = {};
43+
if (deferCachingEnabled === false) {
44+
adPodAdUnits.forEach((adUnit) => {
45+
let adPodTargeting = [];
46+
let adPodDurationSeconds = deepAccess(adUnit, 'mediaTypes.video.adPodDurationSec');
47+
48+
bids
49+
.filter((bid) => bid.adUnitCode === adUnit.code)
50+
.forEach((bid, index, arr) => {
51+
if (bid.video.durationBucket <= adPodDurationSeconds) {
52+
adPodTargeting.push({
53+
[TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR]
54+
});
55+
adPodDurationSeconds -= bid.video.durationBucket;
56+
}
57+
if (index === arr.length - 1 && adPodTargeting.length > 0) {
58+
adPodTargeting.push({
59+
[TARGETING_KEY_CACHE_ID]: bid.adserverTargeting[TARGETING_KEY_CACHE_ID]
60+
});
61+
}
62+
});
63+
targeting[adUnit.code] = adPodTargeting;
64+
});
65+
66+
callback(null, targeting);
67+
} else {
68+
let bidsToCache = [];
69+
adPodAdUnits.forEach((adUnit) => {
70+
let adPodDurationSeconds = deepAccess(adUnit, 'mediaTypes.video.adPodDurationSec');
71+
72+
bids
73+
.filter((bid) => bid.adUnitCode === adUnit.code)
74+
.forEach((bid) => {
75+
if (bid.video.durationBucket <= adPodDurationSeconds) {
76+
bidsToCache.push(bid);
77+
adPodDurationSeconds -= bid.video.durationBucket;
78+
}
79+
});
80+
});
81+
82+
callPrebidCacheAfterAuction(bidsToCache, function(error, bidsSuccessfullyCached) {
83+
if (error) {
84+
callback(error, null);
85+
} else {
86+
let groupedBids = groupBy(bidsSuccessfullyCached, 'adUnitCode');
87+
Object.keys(groupedBids).forEach((adUnitCode) => {
88+
let adPodTargeting = [];
89+
90+
groupedBids[adUnitCode].forEach((bid, index, arr) => {
91+
adPodTargeting.push({
92+
[TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR]
93+
});
94+
95+
if (index === arr.length - 1 && adPodTargeting.length > 0) {
96+
adPodTargeting.push({
97+
[TARGETING_KEY_CACHE_ID]: bid.adserverTargeting[TARGETING_KEY_CACHE_ID]
98+
});
99+
}
100+
});
101+
targeting[adUnitCode] = adPodTargeting;
102+
});
103+
104+
callback(null, targeting);
105+
}
106+
});
107+
}
108+
return targeting;
109+
}
110+
111+
/**
112+
* This function returns the adunit of mediaType adpod
113+
* @param {Array} codes adUnitCodes
114+
* @returns {Array[Object]} adunits of mediaType adpod
115+
*/
116+
function getAdPodAdUnits(codes) {
117+
return auctionManager.getAdUnits()
118+
.filter((adUnit) => deepAccess(adUnit, 'mediaTypes.video.context') === ADPOD)
119+
.filter((adUnit) => (codes.length > 0) ? codes.indexOf(adUnit.code) != -1 : true);
120+
}
121+
122+
function compareOn(property) {
123+
return function compare(a, b) {
124+
if (a[property] < b[property]) {
125+
return 1;
126+
}
127+
if (a[property] > b[property]) {
128+
return -1;
129+
}
130+
return 0;
131+
}
132+
}
133+
134+
/**
135+
* This function removes bids of same freewheel category. It will be used when competitive exclusion is enabled.
136+
* @param {Array[Object]} bidsReceived
137+
* @returns {Array[Object]} unique freewheel category bids
138+
*/
139+
function getExclusiveBids(bidsReceived) {
140+
let bids = bidsReceived
141+
.map((bid) => Object.assign({}, bid, {[TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR]}));
142+
bids = groupBy(bids, TARGETING_KEY_PB_CAT_DUR);
143+
let filteredBids = [];
144+
Object.keys(bids).forEach((targetingKey) => {
145+
bids[targetingKey].sort(compareOn('responseTimestamp'));
146+
filteredBids.push(bids[targetingKey][0]);
147+
});
148+
return filteredBids;
149+
}
150+
151+
/**
152+
* This function returns bids for adpod adunits
153+
* @param {Array[Object]} bidsReceived
154+
* @param {Array[Object]} adPodAdUnits
155+
* @returns {Array[Object]} bids of mediaType adpod
156+
*/
157+
function getBidsForAdpod(bidsReceived, adPodAdUnits) {
158+
let adUnitCodes = adPodAdUnits.map((adUnit) => adUnit.code);
159+
return bidsReceived
160+
.filter((bid) => adUnitCodes.indexOf(bid.adUnitCode) != -1 && (bid.video && bid.video.context === ADPOD))
161+
}
162+
163+
initAdpodHooks();
164+
registerVideoSupport('freewheel', {
165+
getTargeting: getTargeting
166+
});

0 commit comments

Comments
 (0)