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

Category translation module for adpod #3513

Merged
merged 19 commits into from
Feb 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions modules/appnexusBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Renderer } from '../src/Renderer';
import * as utils from '../src/utils';
import { registerBidder } from '../src/adapters/bidderFactory';
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes';
import { registerBidder, getIabSubCategory } from '../src/adapters/bidderFactory';
import { BANNER, NATIVE, VIDEO, ADPOD } from '../src/mediaTypes';
import find from 'core-js/library/fn/array/find';
import includes from 'core-js/library/fn/array/includes';

Expand Down Expand Up @@ -32,6 +32,7 @@ const NATIVE_MAPPING = {
displayUrl: 'displayurl'
};
const SOURCE = 'pbjs';
const mappingFileUrl = '//acdn.adnxs.com/prebid/appnexus-mapping/mappings.json';

export const spec = {
code: BIDDER_CODE,
Expand Down Expand Up @@ -209,6 +210,24 @@ export const spec = {
return bids;
},

/**
* @typedef {Object} mappingFileInfo
* @property {string} url mapping file json url
* @property {number} refreshInDays prebid stores mapping data in localstorage so you can return in how many days you want to update value stored in localstorage.
* @property {string} localStorageKey unique key to store your mapping json in localstorage
*/

/**
* Returns mapping file info. This info will be used by bidderFactory to preload mapping file and store data in local storage
* @returns {mappingFileInfo}
*/
getMappingFileInfo: function() {
return {
url: mappingFileUrl,
refreshInDays: 7
}
},

getUserSyncs: function(syncOptions) {
if (syncOptions.iframeEnabled) {
return [{
Expand Down Expand Up @@ -316,6 +335,21 @@ function newBid(serverBid, rtbBid, bidderRequest) {
vastImpUrl: rtbBid.notify_url,
ttl: 3600
});

const videoContext = utils.deepAccess(bidRequest, 'mediaTypes.video.context');
if (videoContext === ADPOD) {
const iabSubCatId = getIabSubCategory(bidRequest.bidder, rtbBid.brand_category_id);

bid.meta = {
iabSubCatId
};

bid.video = {
context: ADPOD,
durationSeconds: Math.ceil(rtbBid.rtb.video.duration_ms / 1000),
};
}

// This supports Outstream Video
if (rtbBid.renderer_url) {
const rendererOptions = utils.deepAccess(
Expand Down
96 changes: 96 additions & 0 deletions modules/categoryTranslation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* This module translates iab category to freewheel industry using translation mapping file
* Publisher can set translation file by using setConfig method
*
* Example:
* config.setConfig({
* 'brandCategoryTranslation': {
* 'translationFile': 'http://sample.com'
* }
* });
* If publisher has not defined translation file than prebid will use default prebid translation file provided here //cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json
*/

import { config } from '../src/config';
import { setupBeforeHookFnOnce, hook } from '../src/hook';
import { ajax } from '../src/ajax';
import { timestamp, logError, setDataInLocalStorage, getDataFromLocalStorage } from '../src/utils';
import { addBidResponse } from '../src/auction';

const DEFAULT_TRANSLATION_FILE_URL = '//cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json';
const DEFAULT_IAB_TO_FW_MAPPING_KEY = 'iabToFwMappingkey';
const DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB = 'iabToFwMappingkeyPub';
const refreshInDays = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we increase default to 7?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have kept it 1 because if publisher changes the mapping file, localStorage will be updated in everyone's browser within 24 hours. So per day 1 request.


export const registerAdserver = hook('async', function(adServer) {
let url;
if (adServer === 'freewheel') {
url = DEFAULT_TRANSLATION_FILE_URL;
}
initTranslation(url, DEFAULT_IAB_TO_FW_MAPPING_KEY);
}, 'registerAdserver');
registerAdserver();

export function getAdserverCategoryHook(fn, adUnitCode, bid) {
if (!bid) {
return fn.call(this, adUnitCode); // if no bid, call original and let it display warnings
}

if (!config.getConfig('adpod.brandCategoryExclusion')) {
return fn.call(this, adUnitCode, bid);
}

let localStorageKey = (config.getConfig('brandCategoryTranslation.translationFile')) ? DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB : DEFAULT_IAB_TO_FW_MAPPING_KEY;

if (bid.meta && !bid.meta.adServerCatId) {
let mapping = getDataFromLocalStorage(localStorageKey);
if (mapping) {
try {
mapping = JSON.parse(mapping);
} catch (error) {
logError('Failed to parse translation mapping file');
}
if (bid.meta.iabSubCatId && mapping['mapping'] && mapping['mapping'][bid.meta.iabSubCatId]) {
bid.meta.adServerCatId = mapping['mapping'][bid.meta.iabSubCatId]['id'];
} else {
// This bid will be automatically ignored by adpod module as adServerCatId was not found
bid.meta.adServerCatId = undefined;
}
} else {
logError('Translation mapping data not found in local storage');
}
}
fn.call(this, adUnitCode, bid);
}

export function initTranslation(url, localStorageKey) {
setupBeforeHookFnOnce(addBidResponse, getAdserverCategoryHook, 50);
let mappingData = getDataFromLocalStorage(localStorageKey);
if (!mappingData || timestamp() < mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) {
ajax(url,
{
success: (response) => {
try {
response = JSON.parse(response);
response['lastUpdated'] = timestamp();
setDataInLocalStorage(localStorageKey, JSON.stringify(response));
} catch (error) {
logError('Failed to parse translation mapping file');
}
},
error: () => {
logError('Failed to load brand category translation file.')
}
},
);
}
}

function setConfig(config) {
if (config.translationFile) {
// if publisher has defined the translation file, preload that file here
initTranslation(config.translationFile, DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB);
}
}

config.getConfig('brandCategoryTranslation', config => setConfig(config.brandCategoryTranslation));
Loading