forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
1 parent
e96d58e
commit d4ff1ec
Showing
2 changed files
with
425 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/** | ||
* This module adds Freewheel support for Video to Prebid. | ||
*/ | ||
|
||
import { registerVideoSupport } from '../src/adServerManager'; | ||
import { auctionManager } from '../src/auctionManager'; | ||
import { groupBy, deepAccess, logError } from '../src/utils'; | ||
import { config } from '../src/config'; | ||
import { ADPOD } from '../src/mediaTypes'; | ||
import { initAdpodHooks, TARGETING_KEY_PB_CAT_DUR, TARGETING_KEY_CACHE_ID, callPrebidCacheAfterAuction } from './adpod'; | ||
import { getHook } from '../src/hook'; | ||
|
||
export function notifyTranslationModule(fn) { | ||
fn.call(this, 'freewheel'); | ||
} | ||
|
||
getHook('registerAdserver').before(notifyTranslationModule); | ||
|
||
/** | ||
* This function returns targeting keyvalue pairs for freewheel adserver module | ||
* @param {Object} options | ||
* @param {Array[string]} codes | ||
* @param {function} callback | ||
* @returns targeting kvs for adUnitCodes | ||
*/ | ||
export function getTargeting({codes, callback} = {}) { | ||
if (!callback) { | ||
logError('No callback function was defined in the getTargeting call. Aborting getTargeting().'); | ||
return; | ||
} | ||
codes = codes || []; | ||
const adPodAdUnits = getAdPodAdUnits(codes); | ||
const bidsReceived = auctionManager.getBidsReceived(); | ||
const competiveExclusionEnabled = config.getConfig('adpod.brandCategoryExclusion'); | ||
const deferCachingSetting = config.getConfig('adpod.deferCaching'); | ||
const deferCachingEnabled = (typeof deferCachingSetting === 'boolean') ? deferCachingSetting : true; | ||
|
||
let bids = getBidsForAdpod(bidsReceived, adPodAdUnits); | ||
bids = (competiveExclusionEnabled || deferCachingEnabled) ? getExclusiveBids(bids) : bids; | ||
bids.sort(compareOn('cpm')); | ||
|
||
let targeting = {}; | ||
if (deferCachingEnabled === false) { | ||
adPodAdUnits.forEach((adUnit) => { | ||
let adPodTargeting = []; | ||
let adPodDurationSeconds = deepAccess(adUnit, 'mediaTypes.video.adPodDurationSec'); | ||
|
||
bids | ||
.filter((bid) => bid.adUnitCode === adUnit.code) | ||
.forEach((bid, index, arr) => { | ||
if (bid.video.durationBucket <= adPodDurationSeconds) { | ||
adPodTargeting.push({ | ||
[TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR] | ||
}); | ||
adPodDurationSeconds -= bid.video.durationBucket; | ||
} | ||
if (index === arr.length - 1 && adPodTargeting.length > 0) { | ||
adPodTargeting.push({ | ||
[TARGETING_KEY_CACHE_ID]: bid.adserverTargeting[TARGETING_KEY_CACHE_ID] | ||
}); | ||
} | ||
}); | ||
targeting[adUnit.code] = adPodTargeting; | ||
}); | ||
|
||
callback(null, targeting); | ||
} else { | ||
let bidsToCache = []; | ||
adPodAdUnits.forEach((adUnit) => { | ||
let adPodDurationSeconds = deepAccess(adUnit, 'mediaTypes.video.adPodDurationSec'); | ||
|
||
bids | ||
.filter((bid) => bid.adUnitCode === adUnit.code) | ||
.forEach((bid) => { | ||
if (bid.video.durationBucket <= adPodDurationSeconds) { | ||
bidsToCache.push(bid); | ||
adPodDurationSeconds -= bid.video.durationBucket; | ||
} | ||
}); | ||
}); | ||
|
||
callPrebidCacheAfterAuction(bidsToCache, function(error, bidsSuccessfullyCached) { | ||
if (error) { | ||
callback(error, null); | ||
} else { | ||
let groupedBids = groupBy(bidsSuccessfullyCached, 'adUnitCode'); | ||
Object.keys(groupedBids).forEach((adUnitCode) => { | ||
let adPodTargeting = []; | ||
|
||
groupedBids[adUnitCode].forEach((bid, index, arr) => { | ||
adPodTargeting.push({ | ||
[TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR] | ||
}); | ||
|
||
if (index === arr.length - 1 && adPodTargeting.length > 0) { | ||
adPodTargeting.push({ | ||
[TARGETING_KEY_CACHE_ID]: bid.adserverTargeting[TARGETING_KEY_CACHE_ID] | ||
}); | ||
} | ||
}); | ||
targeting[adUnitCode] = adPodTargeting; | ||
}); | ||
|
||
callback(null, targeting); | ||
} | ||
}); | ||
} | ||
return targeting; | ||
} | ||
|
||
/** | ||
* This function returns the adunit of mediaType adpod | ||
* @param {Array} codes adUnitCodes | ||
* @returns {Array[Object]} adunits of mediaType adpod | ||
*/ | ||
function getAdPodAdUnits(codes) { | ||
return auctionManager.getAdUnits() | ||
.filter((adUnit) => deepAccess(adUnit, 'mediaTypes.video.context') === ADPOD) | ||
.filter((adUnit) => (codes.length > 0) ? codes.indexOf(adUnit.code) != -1 : true); | ||
} | ||
|
||
function compareOn(property) { | ||
return function compare(a, b) { | ||
if (a[property] < b[property]) { | ||
return 1; | ||
} | ||
if (a[property] > b[property]) { | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
} | ||
|
||
/** | ||
* This function removes bids of same freewheel category. It will be used when competitive exclusion is enabled. | ||
* @param {Array[Object]} bidsReceived | ||
* @returns {Array[Object]} unique freewheel category bids | ||
*/ | ||
function getExclusiveBids(bidsReceived) { | ||
let bids = bidsReceived | ||
.map((bid) => Object.assign({}, bid, {[TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR]})); | ||
bids = groupBy(bids, TARGETING_KEY_PB_CAT_DUR); | ||
let filteredBids = []; | ||
Object.keys(bids).forEach((targetingKey) => { | ||
bids[targetingKey].sort(compareOn('responseTimestamp')); | ||
filteredBids.push(bids[targetingKey][0]); | ||
}); | ||
return filteredBids; | ||
} | ||
|
||
/** | ||
* This function returns bids for adpod adunits | ||
* @param {Array[Object]} bidsReceived | ||
* @param {Array[Object]} adPodAdUnits | ||
* @returns {Array[Object]} bids of mediaType adpod | ||
*/ | ||
function getBidsForAdpod(bidsReceived, adPodAdUnits) { | ||
let adUnitCodes = adPodAdUnits.map((adUnit) => adUnit.code); | ||
return bidsReceived | ||
.filter((bid) => adUnitCodes.indexOf(bid.adUnitCode) != -1 && (bid.video && bid.video.context === ADPOD)) | ||
} | ||
|
||
initAdpodHooks(); | ||
registerVideoSupport('freewheel', { | ||
getTargeting: getTargeting | ||
}); |
Oops, something went wrong.