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

Support Multi-Format Ads - Banner & Video #3389

Merged
merged 4 commits into from
Jan 28, 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
278 changes: 152 additions & 126 deletions modules/rhythmoneBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
'use strict';

import * as utils from '../src/utils';
import {registerBidder} from '../src/adapters/bidderFactory';
import { BANNER, VIDEO } from '../src/mediaTypes';

function RhythmOneBidAdapter() {
this.code = 'rhythmone';
this.supportedMediaTypes = [VIDEO, BANNER];

let SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6];
let SUPPORTED_VIDEO_MIMES = ['video/mp4'];
let SUPPORTED_VIDEO_PLAYBACK_METHODS = [1, 2, 3, 4];
let SUPPORTED_VIDEO_DELIVERY = [1];
let SUPPORTED_VIDEO_API = [1, 2, 5];
let slotsToBids = {};
let that = this;
let version = '1.0.2.1';
let loadStart = Date.now();
var win = typeof window !== 'undefined' ? window : {};

this.isBidRequestValid = function (bid) {
return true;
};
Expand Down Expand Up @@ -53,7 +65,7 @@ function RhythmOneBidAdapter() {
data.bidder_version = version;
if (gdprConsent) {
data.gdpr_consent = gdprConsent.consentString;
data.gdpr = (typeof gdprConsent.gdprApplies === 'boolean') ? gdprConsent.gdprApplies : true;
data.gdpr = (typeof gdprConsent.gdprApplies === 'boolean') ? gdprConsent.gdprApplies : false;
}

for (let k in data) {
Expand All @@ -70,151 +82,165 @@ function RhythmOneBidAdapter() {
}
};

function getFirstParam(key, validBidRequests) {
for (let i = 0; i < validBidRequests.length; i++) {
if (validBidRequests[i].params && validBidRequests[i].params[key]) {
return validBidRequests[i].params[key];
function frameImp(BRs) {
var imp = [];
for (var i = 0; i < BRs.length; i++) {
slotsToBids[BRs[i].adUnitCode || BRs[i].placementCode] = BRs[i];
var impObj = {};
impObj.id = BRs[i].adUnitCode;
impObj.bidfloor = parseFloat(utils.deepAccess(BRs[i], 'params.floor')) || 0;
impObj.secure = win.location.protocol === 'https:' ? 1 : 0;
if (utils.deepAccess(BRs[i], 'mediaTypes.banner') || utils.deepAccess(BRs[i], 'mediaType') === 'banner') {
impObj.banner = frameBanner(BRs[i]);
}
if (utils.deepAccess(BRs[i], 'mediaTypes.video') || utils.deepAccess(BRs[i], 'mediaType') === 'video') {
impObj.video = frameVideo(BRs[i]);
}
impObj.ext = frameExt(BRs[i]);
imp.push(impObj);
}
return imp;
}

let slotsToBids = {};
let that = this;
let version = '1.0.1.0';
let loadStart = Date.now();

this.buildRequests = function (BRs, bidderRequest) {
let fallbackPlacementId = getFirstParam('placementId', BRs);
if (fallbackPlacementId === undefined || BRs.length < 1) {
return [];
function frameSite(bidderRequest) {
return {
domain: attempt(function() {
var d = win.document.location.ancestorOrigins;
if (d && d.length > 0) {
return d[d.length - 1];
}
return win.top.document.location.hostname; // try/catch is in the attempt function
}, ''),
page: attempt(function() {
var l;
// try/catch is in the attempt function
try {
l = win.top.document.location.href.toString();
} catch (ex) {
l = win.document.location.href.toString();
}
return l;
}, ''),
ref: attempt(function() {
if (bidderRequest && bidderRequest.refererInfo) {
return bidderRequest.refererInfo.referer;
}
return '';
}, '')
}
}

loadStart = Date.now();
slotsToBids = {};

let query = [];
let w = (typeof window !== 'undefined' ? window : {});

function p(k, v, d) {
if (v instanceof Array) { v = v.join((d || ',')); }
if (typeof v !== 'undefined') { query.push(encodeURIComponent(k) + '=' + encodeURIComponent(v)); }
function frameDevice() {
return {
ua: navigator.userAgent,
devicetype: /(ios|ipod|ipad|iphone|android)/i.test(win.navigator.userAgent) ? 1 : /(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i.test(win.navigator.userAgent) ? 3 : 2,
ip: '', // Empty Ip string is required, server gets the ip from HTTP header
dnt: utils.getDNT() ? 1 : 0,
}
}

function attempt(valueFunction, defaultValue) {
try {
return valueFunction();
} catch (ex) { }
return defaultValue;
function frameBanner(bid) {
var sizes = utils.parseSizesInput(bid.sizes).map(size => size.split('x'));
return {
w: parseInt(sizes[0][0]),
h: parseInt(sizes[0][1])
}
}

p('domain', attempt(function() {
var d = w.document.location.ancestorOrigins;
if (d && d.length > 0) {
return d[d.length - 1];
function frameVideo(bid) {
var size = [];
if (utils.deepAccess(bid, 'mediaTypes.video.playerSize')) {
if (utils.isArray(bid.mediaTypes.video.playerSize[0])) {
size = bid.mediaTypes.video.playerSize[0];
} else if (utils.isNumber(bid.mediaTypes.video.playerSize[0])) {
size = bid.mediaTypes.video.playerSize;
}
return w.top.document.location.hostname; // try/catch is in the attempt function
}, ''));
p('url', attempt(function() {
var l;
// try/catch is in the attempt function
try {
l = w.top.document.location.href.toString();
} catch (ex) {
l = w.document.location.href.toString();
}
return {
mimes: utils.deepAccess(bid, 'mediaTypes.video.mimes') || SUPPORTED_VIDEO_MIMES,
protocols: utils.deepAccess(bid, 'mediaTypes.video.protocols') || SUPPORTED_VIDEO_PROTOCOLS,
w: size[0],
h: size[1],
startdelay: utils.deepAccess(bid, 'mediaTypes.video.startdelay') || 0,
skip: utils.deepAccess(bid, 'mediaTypes.video.skip') || 0,
playbackmethod: utils.deepAccess(bid, 'mediaTypes.video.playbackmethod') || SUPPORTED_VIDEO_PLAYBACK_METHODS,
delivery: utils.deepAccess(bid, 'mediaTypes.video.delivery') || SUPPORTED_VIDEO_DELIVERY,
api: utils.deepAccess(bid, 'mediaTypes.video.api') || SUPPORTED_VIDEO_API,
}
}

function frameExt(bid) {
return {
bidder: {
placementId: (bid.params && bid.params['placementId']) ? bid.params['placementId'] : '',
zone: (bid.params && bid.params['zone']) ? bid.params['zone'] : '1r',
path: (bid.params && bid.params['path']) ? bid.params['path'] : 'mvo'
}
return l;
}, ''));

function getRMPUrl() {
let url = getFirstParam('endpoint', BRs) || '//tag.1rx.io/rmp/{placementId}/0/{path}?z={zone}';
let defaultZone = getFirstParam('zone', BRs) || '1r';
let defaultPath = getFirstParam('path', BRs) || 'mvo';

url = url.replace(/\{placementId\}/i, fallbackPlacementId);
url = url.replace(/\{zone\}/i, defaultZone);
url = url.replace(/\{path\}/i, defaultPath);

p('title', attempt(function() { return w.top.document.title; }, '')); // try/catch is in the attempt function
p('dsh', (w.screen ? w.screen.height : ''));
p('dsw', (w.screen ? w.screen.width : ''));
p('tz', (new Date()).getTimezoneOffset());
p('dtype', ((/(ios|ipod|ipad|iphone|android)/i).test(w.navigator.userAgent) ? 1 : ((/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(w.navigator.userAgent) ? 3 : 2)));
p('flash', attempt(function() {
let n = w.navigator;
let p = n.plugins;
let m = n.mimeTypes;
let t = 'application/x-shockwave-flash';
let x = w.ActiveXObject;

if (p &&
p['Shockwave Flash'] &&
m &&
m[t] &&
m[t].enabledPlugin) {
return 1;
}
}
}

if (x) {
try {
if ((new w.ActiveXObject('ShockwaveFlash.ShockwaveFlash'))) {
return 1;
}
} catch (e) { }
function frameBid(BRs, bidderRequest) {
return {
id: BRs[0].bidderRequestId,
imp: frameImp(BRs),
site: frameSite(bidderRequest),
device: frameDevice(),
user: {
ext: {
consent: utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies') ? bidderRequest.gdprConsent.consentString : ''
}
},
at: 1,
tmax: 1000,
regs: {
ext: {
gdpr: utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies') ? Boolean(bidderRequest.gdprConsent.gdprApplies & 1) : false
}
}
};
}

return 0;
}, 0));

let heights = [];
let widths = [];
let floors = [];
let mediaTypes = [];
let i = 0;
let configuredPlacements = [];
let fat = /(^v|(\.0)+$)/gi;

p('hbv', w.$$PREBID_GLOBAL$$.version.replace(fat, '') + ',' + version.replace(fat, ''));
function getFirstParam(key, validBidRequests) {
for (let i = 0; i < validBidRequests.length; i++) {
if (validBidRequests[i].params && validBidRequests[i].params[key]) {
return validBidRequests[i].params[key];
}
}
}

for (; i < BRs.length; i++) {
let th = [];
let tw = [];
let params = BRs[i].params || {};
function attempt(valueFunction, defaultValue) {
try {
return valueFunction();
} catch (ex) { }
return defaultValue;
}

slotsToBids[BRs[i].adUnitCode || BRs[i].placementCode] = BRs[i];
this.buildRequests = function (BRs, bidderRequest) {
let fallbackPlacementId = getFirstParam('placementId', BRs);
if (fallbackPlacementId === undefined || BRs.length < 1) {
return [];
}

if (BRs[i].sizes.length > 0 && typeof BRs[i].sizes[0] === 'number') {
BRs[i].sizes = [BRs[i].sizes];
}
var rmpUrl = getFirstParam('endpoint', BRs) || '//tag.1rx.io/rmp/{placementId}/0/{path}?z={zone}';
var defaultZone = getFirstParam('zone', BRs) || '1r';
var defaultPath = getFirstParam('path', BRs) || 'mvo';

for (let j = 0; j < BRs[i].sizes.length; j++) {
tw.push(BRs[i].sizes[j][0]);
th.push(BRs[i].sizes[j][1]);
}
configuredPlacements.push(BRs[i].adUnitCode || BRs[i].placementCode);
heights.push(th.join('|'));
widths.push(tw.join('|'));
mediaTypes.push((BRs[i].mediaTypes && BRs[i].mediaTypes.video ? 'v' : 'd'));
floors.push(params.floor || 0);
}
rmpUrl = rmpUrl.replace(/\{placementId\}/i, fallbackPlacementId);
rmpUrl = rmpUrl.replace(/\{zone\}/i, defaultZone);
rmpUrl = rmpUrl.replace(/\{path\}/i, defaultPath);

p('imp', configuredPlacements);
p('w', widths);
p('h', heights);
p('floor', floors);
p('t', mediaTypes);
if (bidderRequest && bidderRequest.gdprConsent) {
p('gdpr_consent', bidderRequest.gdprConsent.consentString);
p('gdpr', (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true);
}
url += '&' + query.join('&') + '&';
var fat = /(^v|(\.0)+$)/gi;
var prebidVersion = '$prebid.version$';
rmpUrl += '&hbv=' + prebidVersion.replace(fat, '') + ',' + version.replace(fat, '');

return url;
}
var bidRequest = frameBid(BRs, bidderRequest);
loadStart = Date.now();

return [{
method: 'GET',
url: getRMPUrl()
}];
return {
method: 'POST',
url: rmpUrl,
data: JSON.stringify(bidRequest)
};
};

this.interpretResponse = function (serverResponse) {
Expand Down Expand Up @@ -244,13 +270,13 @@ function RhythmOneBidAdapter() {
creativeId: bid.crid,
currency: 'USD',
netRevenue: true,
ttl: 1000
ttl: 350
};

if (bidRequest.mediaTypes && bidRequest.mediaTypes.video) {
bidResponse.vastUrl = bid.nurl;
bidResponse.mediaType = 'video';
bidResponse.ttl = 10000;
bidResponse.ttl = 600;
} else {
bidResponse.ad = bid.adm;
}
Expand Down
8 changes: 5 additions & 3 deletions modules/rhythmoneBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
```
Module Name: RhythmOne Bidder Adapter
Module Type: Bidder Adapter
Maintainer: astocker@rhythmone.com
Maintainer: support@rhythmone.com
```

# Description
Expand All @@ -23,8 +23,10 @@ const adUnits = [{
bidder: 'rhythmone',
params:
{
placementId: '411806',
endpoint: "//tag.1rx.io/rmp/72721/0/mvo?z=1r" // only required for testing. this api guarantees no 204 responses
placementId: '80184', // REQUIRED
zone: '1r', // OPTIONAL
path: 'mvo', // OPTIONAL
endpoint: "//tag.1rx.io/rmp/80184/0/mvo?z=1r" // OPTIONAL, only required for testing. this api guarantees no 204 responses
}
}
]
Expand Down
Loading