Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prebid Core: Define "VIDEO" compile time feature flag #9543

Merged
merged 13 commits into from
Mar 30, 2023
3 changes: 2 additions & 1 deletion features.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[
"NATIVE"
"NATIVE",
"VIDEO"
]
19 changes: 11 additions & 8 deletions libraries/ortbConverter/processors/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ export const DEFAULT_PROCESSORS = {
// populates imp.banner
fn: fillBannerImp
},
video: {
// populates imp.video
fn: fillVideoImp
},
pbadslot: {
// removes imp.ext.data.pbaslot if it's not a string
// TODO: is this needed?
Expand All @@ -78,10 +74,6 @@ export const DEFAULT_PROCESSORS = {
// sets banner response attributes if bidResponse.mediaType === BANNER
fn: bannerResponseProcessor(),
},
video: {
// sets video response attributes if bidResponse.mediaType === VIDEO
fn: fillVideoResponse
},
props: {
// sets base bidResponse properties common to all types of bids
fn(bidResponse, bid, context) {
Expand Down Expand Up @@ -121,3 +113,14 @@ if (FEATURES.NATIVE) {
fn: fillNativeResponse
}
}

if (FEATURES.VIDEO) {
DEFAULT_PROCESSORS[IMP].video = {
// populates imp.video
fn: fillVideoImp
}
DEFAULT_PROCESSORS[BID_RESPONSE].video = {
// sets video response attributes if bidResponse.mediaType === VIDEO
fn: fillVideoResponse
}
}
5 changes: 2 additions & 3 deletions modules/adpod.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@ import {
import {
addBidToAuction,
AUCTION_IN_PROGRESS,
callPrebidCache,
doCallbacksIfTimedout,
getPriceByGranularity,
getPriceGranularity
} from '../src/auction.js';
import {checkAdUnitSetup} from '../src/prebid.js';
import {checkVideoBidSetup} from '../src/video.js';
import {module, setupBeforeHookFnOnce} from '../src/hook.js';
import {getHook, module, setupBeforeHookFnOnce} from '../src/hook.js';
import {store} from '../src/videoCache.js';
import {config} from '../src/config.js';
import {ADPOD} from '../src/mediaTypes.js';
Expand Down Expand Up @@ -424,7 +423,7 @@ config.getConfig('adpod', config => adpodSetConfig(config.adpod));
* This function initializes the adpod module's hooks. This is called by the corresponding adserver video module.
*/
function initAdpodHooks() {
setupBeforeHookFnOnce(callPrebidCache, callPrebidCacheHook);
setupBeforeHookFnOnce(getHook('callPrebidCache'), callPrebidCacheHook);
setupBeforeHookFnOnce(checkAdUnitSetup, checkAdUnitSetupHook);
setupBeforeHookFnOnce(checkVideoBidSetup, checkVideoBidSetupHook);
}
Expand Down
2 changes: 1 addition & 1 deletion modules/sizeMappingV2.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export function checkAdUnitSetupHook(adUnits) {
}
}

if (mediaTypes.video) {
if (FEATURES.VIDEO && mediaTypes.video) {
if (mediaTypes.video.playerSize) {
// Ad unit is using 'mediaTypes.video.playerSize' instead of the new property 'sizeConfig'. Apply the old checks!
validatedVideo = validatedBanner ? adUnitSetupChecks.validateVideoMediaType(validatedBanner) : adUnitSetupChecks.validateVideoMediaType(adUnit);
Expand Down
4 changes: 2 additions & 2 deletions src/adapterManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request

function getSupportedMediaTypes(bidderCode) {
let supportedMediaTypes = [];
if (includes(adapterManager.videoAdapters, bidderCode)) supportedMediaTypes.push('video');
if (FEATURES.VIDEO && includes(adapterManager.videoAdapters, bidderCode)) supportedMediaTypes.push('video');
if (FEATURES.NATIVE && includes(nativeAdapters, bidderCode)) supportedMediaTypes.push('native');
return supportedMediaTypes;
}
Expand All @@ -471,7 +471,7 @@ adapterManager.registerBidAdapter = function (bidAdapter, bidderCode, {supported
if (typeof bidAdapter.callBids === 'function') {
_bidderRegistry[bidderCode] = bidAdapter;

if (includes(supportedMediaTypes, 'video')) {
if (FEATURES.VIDEO && includes(supportedMediaTypes, 'video')) {
adapterManager.videoAdapters.push(bidderCode);
}
if (FEATURES.NATIVE && includes(supportedMediaTypes, 'native')) {
Expand Down
87 changes: 46 additions & 41 deletions src/adapters/bidderFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,51 +472,56 @@ export const addComponentAuction = hook('sync', (_bidRequest, fledgeAuctionConfi
}, 'addComponentAuction')

export function preloadBidderMappingFile(fn, adUnits) {
if (!config.getConfig('adpod.brandCategoryExclusion')) {
return fn.call(this, adUnits);
}
let adPodBidders = adUnits
.filter((adUnit) => deepAccess(adUnit, 'mediaTypes.video.context') === ADPOD)
.map((adUnit) => adUnit.bids.map((bid) => bid.bidder))
.reduce(flatten, [])
.filter(uniques);

adPodBidders.forEach(bidder => {
let bidderSpec = adapterManager.getBidAdapter(bidder);
if (bidderSpec.getSpec().getMappingFileInfo) {
let info = bidderSpec.getSpec().getMappingFileInfo();
let refreshInDays = (info.refreshInDays) ? info.refreshInDays : DEFAULT_REFRESHIN_DAYS;
let key = (info.localStorageKey) ? info.localStorageKey : bidderSpec.getSpec().code;
let mappingData = storage.getDataFromLocalStorage(key);
try {
mappingData = mappingData ? JSON.parse(mappingData) : undefined;
if (!mappingData || timestamp() > mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) {
ajax(info.url,
{
success: (response) => {
try {
response = JSON.parse(response);
let mapping = {
lastUpdated: timestamp(),
mapping: response.mapping
if (FEATURES.VIDEO) {
if (!config.getConfig('adpod.brandCategoryExclusion')) {
return fn.call(this, adUnits);
}

let adPodBidders = adUnits
.filter((adUnit) => deepAccess(adUnit, 'mediaTypes.video.context') === ADPOD)
.map((adUnit) => adUnit.bids.map((bid) => bid.bidder))
.reduce(flatten, [])
.filter(uniques);

adPodBidders.forEach(bidder => {
let bidderSpec = adapterManager.getBidAdapter(bidder);
if (bidderSpec.getSpec().getMappingFileInfo) {
let info = bidderSpec.getSpec().getMappingFileInfo();
let refreshInDays = (info.refreshInDays) ? info.refreshInDays : DEFAULT_REFRESHIN_DAYS;
let key = (info.localStorageKey) ? info.localStorageKey : bidderSpec.getSpec().code;
let mappingData = storage.getDataFromLocalStorage(key);
try {
mappingData = mappingData ? JSON.parse(mappingData) : undefined;
if (!mappingData || timestamp() > mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) {
ajax(info.url,
{
success: (response) => {
try {
response = JSON.parse(response);
let mapping = {
lastUpdated: timestamp(),
mapping: response.mapping
}
storage.setDataInLocalStorage(key, JSON.stringify(mapping));
} catch (error) {
logError(`Failed to parse ${bidder} bidder translation mapping file`);
}
storage.setDataInLocalStorage(key, JSON.stringify(mapping));
} catch (error) {
logError(`Failed to parse ${bidder} bidder translation mapping file`);
},
error: () => {
logError(`Failed to load ${bidder} bidder translation file`)
}
},
error: () => {
logError(`Failed to load ${bidder} bidder translation file`)
}
},
);
);
}
} catch (error) {
logError(`Failed to parse ${bidder} bidder translation mapping file`);
}
} catch (error) {
logError(`Failed to parse ${bidder} bidder translation mapping file`);
}
}
});
fn.call(this, adUnits);
});
fn.call(this, adUnits);
} else {
return fn.call(this, adUnits)
}
}

getHook('checkAdUnitSetup').before(preloadBidderMappingFile);
Expand Down Expand Up @@ -599,7 +604,7 @@ export function isValid(adUnitCode, bid, {index = auctionManager.index} = {}) {
logError(errorMessage('Native bid missing some required properties.'));
return false;
}
if (bid.mediaType === 'video' && !isValidVideoBid(bid, {index})) {
if (FEATURES.VIDEO && bid.mediaType === 'video' && !isValidVideoBid(bid, {index})) {
logError(errorMessage(`Video bid does not have required vastUrl or renderer property`));
return false;
}
Expand Down
10 changes: 6 additions & 4 deletions src/auction.js
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM
handleBidResponse(adUnitCode, bid, (done) => {
let bidResponse = getPreparedBidForAuction(bid);

if (bidResponse.mediaType === VIDEO) {
if (FEATURES.VIDEO && bidResponse.mediaType === VIDEO) {
tryAddVideoBid(auctionInstance, bidResponse, done);
} else {
if (FEATURES.NATIVE && bidResponse.native != null && typeof bidResponse.native === 'object') {
Expand Down Expand Up @@ -620,7 +620,7 @@ const addLegacyFieldsIfNeeded = (bidResponse) => {
}
}

const storeInCache = (batch) => {
const _storeInCache = (batch) => {
store(batch.map(entry => entry.bidResponse), function (error, cacheIds) {
cacheIds.forEach((cacheId, i) => {
const { auctionInstance, bidResponse, afterBidAdded } = batch[i];
Expand All @@ -647,6 +647,8 @@ const storeInCache = (batch) => {
});
};

const storeInCache = FEATURES.VIDEO ? _storeInCache : () => {};

let batchSize, batchTimeout;
config.getConfig('cache', (cacheConfig) => {
batchSize = typeof cacheConfig.cache.batchSize === 'number' && cacheConfig.cache.batchSize > 0
Expand Down Expand Up @@ -782,7 +784,7 @@ function setupBidTargeting(bidObject) {
*/
export function getMediaTypeGranularity(mediaType, mediaTypes, mediaTypePriceGranularity) {
if (mediaType && mediaTypePriceGranularity) {
if (mediaType === VIDEO) {
if (FEATURES.VIDEO && mediaType === VIDEO) {
const context = deepAccess(mediaTypes, `${VIDEO}.context`, 'instream');
if (mediaTypePriceGranularity[`${VIDEO}-${context}`]) {
return mediaTypePriceGranularity[`${VIDEO}-${context}`];
Expand Down Expand Up @@ -891,7 +893,7 @@ export function getStandardBidderSettings(mediaType, bidderCode) {
standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = defaultAdserverTargeting();
}

if (mediaType === 'video') {
if (FEATURES.VIDEO && mediaType === 'video') {
const adserverTargeting = standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING].slice();
standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = adserverTargeting;

Expand Down
71 changes: 39 additions & 32 deletions src/prebid.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,17 @@ function validateAdUnit(adUnit) {
export const adUnitSetupChecks = {
validateAdUnit,
validateBannerMediaType,
validateVideoMediaType,
validateSizes
};

if (FEATURES.NATIVE) {
Object.assign(adUnitSetupChecks, {validateNativeMediaType});
}

if (FEATURES.VIDEO) {
Object.assign(adUnitSetupChecks, { validateVideoMediaType });
}

export const checkAdUnitSetup = hook('sync', function (adUnits) {
const validatedAdUnits = [];

Expand All @@ -248,7 +251,7 @@ export const checkAdUnitSetup = hook('sync', function (adUnits) {
if (mediaTypes.banner.hasOwnProperty('pos')) validatedBanner = validateAdUnitPos(validatedBanner, 'banner');
}

if (mediaTypes.video) {
if (FEATURES.VIDEO && mediaTypes.video) {
validatedVideo = validatedBanner ? validateVideoMediaType(validatedBanner) : validateVideoMediaType(adUnit);
if (mediaTypes.video.hasOwnProperty('pos')) validatedVideo = validateAdUnitPos(validatedVideo, 'video');
}
Expand Down Expand Up @@ -530,12 +533,14 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
const {height, width, ad, mediaType, adUrl, renderer} = bid;

// video module
const adUnitCode = bid.adUnitCode;
const adUnit = $$PREBID_GLOBAL$$.adUnits.filter(adUnit => adUnit.code === adUnitCode);
const videoModule = $$PREBID_GLOBAL$$.videoModule;
if (adUnit.video && videoModule) {
videoModule.renderBid(adUnit.video.divId, bid);
return;
if (FEATURES.VIDEO) {
const adUnitCode = bid.adUnitCode;
const adUnit = $$PREBID_GLOBAL$$.adUnits.filter(adUnit => adUnit.code === adUnitCode);
const videoModule = $$PREBID_GLOBAL$$.videoModule;
if (adUnit.video && videoModule) {
videoModule.renderBid(adUnit.video.divId, bid);
return;
}
}

if (!doc) {
Expand Down Expand Up @@ -986,32 +991,34 @@ $$PREBID_GLOBAL$$.getHighestCpmBids = function (adUnitCode) {
return targeting.getWinningBids(adUnitCode);
};

/**
* Mark the winning bid as used, should only be used in conjunction with video
* @typedef {Object} MarkBidRequest
* @property {string} adUnitCode The ad unit code
* @property {string} adId The id representing the ad we want to mark
*
* @alias module:pbjs.markWinningBidAsUsed
*/
$$PREBID_GLOBAL$$.markWinningBidAsUsed = function (markBidRequest) {
let bids = [];

if (markBidRequest.adUnitCode && markBidRequest.adId) {
bids = auctionManager.getBidsReceived()
.filter(bid => bid.adId === markBidRequest.adId && bid.adUnitCode === markBidRequest.adUnitCode);
} else if (markBidRequest.adUnitCode) {
bids = targeting.getWinningBids(markBidRequest.adUnitCode);
} else if (markBidRequest.adId) {
bids = auctionManager.getBidsReceived().filter(bid => bid.adId === markBidRequest.adId);
} else {
logWarn('Improper use of markWinningBidAsUsed. It needs an adUnitCode or an adId to function.');
}
if (FEATURES.VIDEO) {
/**
* Mark the winning bid as used, should only be used in conjunction with video
* @typedef {Object} MarkBidRequest
* @property {string} adUnitCode The ad unit code
* @property {string} adId The id representing the ad we want to mark
*
* @alias module:pbjs.markWinningBidAsUsed
*/
$$PREBID_GLOBAL$$.markWinningBidAsUsed = function (markBidRequest) {
let bids = [];

if (markBidRequest.adUnitCode && markBidRequest.adId) {
bids = auctionManager.getBidsReceived()
.filter(bid => bid.adId === markBidRequest.adId && bid.adUnitCode === markBidRequest.adUnitCode);
} else if (markBidRequest.adUnitCode) {
bids = targeting.getWinningBids(markBidRequest.adUnitCode);
} else if (markBidRequest.adId) {
bids = auctionManager.getBidsReceived().filter(bid => bid.adId === markBidRequest.adId);
} else {
logWarn('Improper use of markWinningBidAsUsed. It needs an adUnitCode or an adId to function.');
}

if (bids.length > 0) {
bids[0].status = CONSTANTS.BID_STATUS.RENDERED;
if (bids.length > 0) {
bids[0].status = CONSTANTS.BID_STATUS.RENDERED;
}
}
};
}

/**
* Get Prebid config options
Expand Down
2 changes: 1 addition & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@ export function isValidMediaTypes(mediaTypes) {
return false;
}

if (mediaTypes.video && mediaTypes.video.context) {
if (FEATURES.VIDEO && mediaTypes.video && mediaTypes.video.context) {
return includes(SUPPORTED_STREAM_TYPES, mediaTypes.video.context);
}

Expand Down
Loading