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

Video header bidding support to RhythmOne bidder adapter #1052

Merged
merged 3 commits into from
Mar 28, 2017
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
6 changes: 5 additions & 1 deletion adapters.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@
"getintent": {
"supportedMediaTypes" : ["video"]
}
},
{
"rhythmone": {
"supportedMediaTypes": ["video"]
}
}

]
252 changes: 115 additions & 137 deletions src/adapters/rhythmone.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
var bidmanager = require('../bidmanager.js'),
bidfactory = require('../bidfactory.js'),
utils = require('../utils.js'),
CONSTANTS = require('../constants.json');

import {ajax as ajax} from '../ajax';

function track(debug, p1, p2, p3) {
function track(debug) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function doesn't seem to do anything now, is it still needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We use google analytics to test this bidder on some of our own sites, and use this function for that purpose. Having to add it and all its references back, only to remove it before a push, repeatedly, would be cumbersome.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Makes sense, thanks for clarifying

if(debug === true){
console.log('GA: %s %s %s', p1, p2, p3 || '');
//console.log('GA: %s %s %s', p1, p2, p3 || '');
}
}

Expand All @@ -19,8 +18,6 @@ module.exports = function(bidManager, global, loader){
var version = "0.9.0.0",
defaultZone = "1r",
defaultPath = "mvo",
bidfloor = 0,
currency = "USD",
debug = false,
auctionEnded = false,
requestCompleted = false,
Expand All @@ -43,33 +40,45 @@ module.exports = function(bidManager, global, loader){
});
}

function load(bidParams, url, postData, callback){
if(bidParams.method === "get"){
loader(url, function(responseText, response){
if(response.status === 200)
callback(200, "success", response.responseText);
else
callback(-1, "http error "+response.status, response.responseText);
}, false, {method:"GET", withCredentials: true});
}
else{
loader(url, function(responseText, response){
if(response.status === 200)
callback(200, "success", response.responseText);
else
callback(-1, "http error "+response.status, response.responseText);
}, postData, {method:"POST", contentType: "application/json", withCredentials: true});
}
function load(bidParams, url, callback){
loader(url, function(responseText, response){
if(response.status === 200)
callback(200, "success", response.responseText);
else
callback(-1, "http error "+response.status, response.responseText);
}, false, {method:"GET", withCredentials: true});
}

function flashInstalled(){
var n = global.navigator,
p = n.plugins,
m = n.mimeTypes,
t = "application/x-shockwave-flash",
x = global.ActiveXObject;

if(p &&
p["Shockwave Flash"] &&
m &&
m[t] &&
m[t].enabledPlugin)
return true;

if(x){
try{if((new global.ActiveXObject("ShockwaveFlash.ShockwaveFlash"))) return true;}
catch(e){}
}

return false;
}

var bidderCode = "rhythmone",
bidLostTimeout = null;

function setIfPresent(o, key, value){
function attempt(valueFunction, defaultValue){
try{
if(typeof value === "function")
o[key] = value();
return valueFunction();
}catch(ex){}
return defaultValue;
}

function logToConsole(txt){
Expand Down Expand Up @@ -124,7 +133,7 @@ module.exports = function(bidManager, global, loader){
}
}

function getRMPURL(bidParams, ortbJSON, bids){
function getRMPURL(bidParams, bids){
var endpoint = "//tag.1rx.io/rmp/{placementId}/0/{path}?z={zone}",
query = [];

Expand All @@ -150,120 +159,77 @@ module.exports = function(bidManager, global, loader){
});

function p(k,v){
if(v instanceof Array)
v = v.join(",");
if(typeof v !== "undefined")
query.push(encodeURIComponent(k)+"="+encodeURIComponent(v));
}

p("domain", attempt(function(){
var d = global.document.location.ancestorOrigins;
if(d && d.length > 0)
return d[d.length-1];
return global.top.document.location.hostname;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please wrap any top references in a try/catch block

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The attempt function wraps this callback in a try/catch - somewhere around line 78

},""));
p("title", attempt(function(){return global.top.document.title;},""));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Another top reference to wrap in try/catch

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The attempt function wraps this callback in a try/catch - somewhere around line 78

p("url", attempt(function(){
var l;
try{l = global.top.document.location.href.toString();}
catch(ex){l = global.document.location.href.toString();}
return l;
},""));
p("dsh", (global.screen ? global.screen.height : ""));
p("dsw", (global.screen ? global.screen.width : ""));
p("tz", (new Date()).getTimezoneOffset());
p("dtype", ((/(ios|ipod|ipad|iphone|android)/i).test(global.navigator.userAgent) ? 1 : ((/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(global.navigator.userAgent) ? 3 : 2)));
p("flash", (flashInstalled() ? 1 : 0));

if(bidParams.method === "get"){

p("domain", ortbJSON.site.domain);
p("title", ortbJSON.site.name);
p("url", ortbJSON.site.page);
p("dsh", ortbJSON.device.h);
p("dsw", ortbJSON.device.w);
p("tz", (new Date()).getTimezoneOffset());
p("dtype", ortbJSON.device.devicetype);
var placementCodes = [],
heights = [],
widths = [],
floors = [],
mediaTypes = [],
fat = /(^v|(\.0)+$)/gi,
i=0;

p("hbv", global.$$PREBID_GLOBAL$$.version.replace(fat,"")+","+version.replace(fat,""));

for(; i<bids.length; i++){

track(debug, 'hb', 'bidRequest');
var th = [], tw = [];

var placementCodes = [],
heights = [],
widths = [],
floors = [];
if(bids[i].sizes.length > 0 && typeof bids[i].sizes[0] === "number")
bids[i].sizes = [bids[i].sizes];

for(var i = 0; i<bids.length; i++){

track(debug, 'hb', 'bidRequest');
var th = [], tw = [];

for(var j = 0; j<bids[i].sizes.length; j++){
tw.push(bids[i].sizes[j][0]);
th.push(bids[i].sizes[j][1]);
}
placementCodes.push(bids[i].placementCode);
heights.push(th.join("|"));
widths.push(tw.join("|"));
floors.push(0);
for(var j = 0; j<bids[i].sizes.length; j++){
tw.push(bids[i].sizes[j][0]);
th.push(bids[i].sizes[j][1]);
}

p("imp", placementCodes.join(","));
p("w", widths.join(","));
p("h", heights.join(","));
p("floor", floors.join(","));
placementCodes.push(bids[i].placementCode);
heights.push(th.join("|"));
widths.push(tw.join("|"));
mediaTypes.push(((/video/i).test(bids[i].mediaType) ? "v" : "d"));
floors.push(0);
}

p("imp", placementCodes);
p("w", widths);
p("h", heights);
p("floor", floors);
p("t", mediaTypes);

endpoint += "&"+query.join("&");

return endpoint;
}

function getORTBJSON(bids, slotMap, bidParams){
var o = {
"device": {
"langauge": global.navigator.language,
"dnt": (global.navigator.doNotTrack === 1 ? 1 : 0)
},
"at": 2,
"site": {},
"tmax": 3000,
"cur": [currency],
"id": utils.generateUUID(),
"imp":[]
};

setIfPresent(o.site, "page", function(){
var l;
try{l = global.top.document.location.href.toString();}
catch(ex){l = document.location.href.toString();}
return l;
});
setIfPresent(o.site, "domain", function(){
var d = document.location.ancestorOrigins;
if(d && d.length > 0)
return d[d.length-1];
return global.top.document.location.hostname;
});
setIfPresent(o.site, "name", function(){return global.top.document.title;});

o.device.devicetype = ((/(ios|ipod|ipad|iphone|android)/i).test(global.navigator.userAgent) ? 1 : ((/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(global.navigator.userAgent) ? 3 : 2));

setIfPresent(o.device, "h", function(){return global.screen.height;});
setIfPresent(o.device, "w", function(){return global.screen.width;});

for(var i = 0; i<bids.length; i++){
var bidID = utils.generateUUID();
slotMap[bidID] = bids[i];
slotMap[bids[i].placementCode] = bids[i];

if(bidParams.method === "post")
track(debug, 'hb', 'bidRequest');

for(var j = 0; j<bids[i].sizes.length; j++){
o.imp.push({
"id": bidID,
"tagId": bids[i].placementCode,
"bidfloor": bidfloor,
"bidfloorcur": currency,
"banner": {
"id": utils.generateUUID(),
"pos": 0,
"w": bids[i].sizes[j][0],
"h": bids[i].sizes[j][1]
}
});
}
}

return o;
}

this.callBids = function(params){

var slotMap = {},
bidParams = getBidParameters(params.bids);

debug = (bidParams !== null && bidParams.debug === true);

auctionEnded = false;
requestCompleted = false;

track(debug, 'hb', 'callBids');

Expand All @@ -273,34 +239,38 @@ module.exports = function(bidManager, global, loader){
return;
}

// default to GET request
if(typeof bidParams.method !== "string")
bidParams.method = "get";

bidParams.method = bidParams.method.toLowerCase();

sniffAuctionEnd();

track(debug, 'hb', 'rmpRequest');

var ortbJSON = getORTBJSON(params.bids, slotMap, bidParams);
for(var i = 0; i<params.bids.length; i++)
slotMap[params.bids[i].placementCode] = params.bids[i];

load(bidParams, getRMPURL(bidParams, ortbJSON, params.bids), JSON.stringify(ortbJSON), function(code, msg, txt){
load(bidParams, getRMPURL(bidParams, params.bids), function(code, msg, txt){

if(auctionEnded === true)
return;

requestCompleted = true;

logToConsole(txt);
logToConsole("response text: "+txt);

if(code === -1)
track(debug, 'hb', 'rmpReplyFail', msg);
track(debug, "hb", "rmpReplyFail", msg);
else{
try{
var result = JSON.parse(txt),
registerBid = function(bid){

//{"id":"ffe73abd-91b3-56d3-d0ee-015a91b356d4",
// "impid":"123",
// "price":17.13,
// "nurl":"http://1r-qa-ads.rhythmxchange.com/rmp/389633/0/ivh?reqId=6594035297396414163",
// "cid":"366183",
// "crid":"366182",
// "h":480,
// "w":640}

slotMap[bid.impid].success = 1;

var pbResponse = bidfactory.createBid(CONSTANTS.STATUS.GOOD),
Expand All @@ -312,22 +282,30 @@ module.exports = function(bidManager, global, loader){
pbResponse.cpm = parseFloat(bid.price);
pbResponse.width = bid.w;
pbResponse.height = bid.h;
pbResponse.ad = bid.adm;

if((/video/i).test(slotMap[bid.impid].mediaType)){
pbResponse.mediaType = "video";
pbResponse.vastUrl = bid.nurl;
pbResponse.descriptionUrl = bid.nurl;
}
else
pbResponse.ad = bid.adm;

logToConsole("registering bid "+placementCode+" "+JSON.stringify(pbResponse));

track(debug, 'hb', 'bidResponse', 1);
track(debug, "hb", "bidResponse", 1);
bidManager.addBidResponse(placementCode, pbResponse);
};

track(debug, 'hb', 'rmpReplySuccess');
track(debug, "hb", "rmpReplySuccess");

for(var i=0; result.seatbid && i<result.seatbid.length; i++)
for(var j=0; result.seatbid[i].bid && j<result.seatbid[i].bid.length; j++)
for(i=0; result.seatbid && i<result.seatbid.length; i++)
for(var j=0; result.seatbid[i].bid && j<result.seatbid[i].bid.length; j++){
registerBid(result.seatbid[i].bid[j]);
}
}
catch(ex){
track(debug, 'hb', 'rmpReplyFail', 'invalid json in rmp response');
track(debug, "hb", "rmpReplyFail", "invalid json in rmp response");
}
}

Expand All @@ -340,4 +318,4 @@ module.exports = function(bidManager, global, loader){

logToConsole("version: "+version);
};
};
};
Loading