From 40cc3693b47175cd2976e8e9152b47389884b20c Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Tue, 12 Feb 2019 15:22:44 -0500 Subject: [PATCH 01/12] added support for outstream in sonobi adapter --- modules/sonobiBidAdapter.js | 81 +++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index e1059ad5930..adb13e28f63 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -1,12 +1,14 @@ import { registerBidder } from '../src/adapters/bidderFactory'; -import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess } from '../src/utils'; +import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage, getBidRequest } from '../src/utils'; import { BANNER, VIDEO } from '../src/mediaTypes'; import { config } from '../src/config'; +import { Renderer } from '../src/Renderer'; const BIDDER_CODE = 'sonobi'; const STR_ENDPOINT = 'https://apex.go.sonobi.com/trinity.json'; const PAGEVIEW_ID = generateUUID(); const SONOBI_DIGITRUST_KEY = 'fhnS5drwmH'; +const OUTSTREAM_REDNERER_URL = 'https://mtrx.go.sonobi.com/outstream.js'; export const spec = { code: BIDDER_CODE, @@ -107,7 +109,6 @@ export const spec = { const bidResponse = serverResponse.body; const bidsReturned = []; const referrer = bidderRequest.data.ref; - if (Object.keys(bidResponse.slots).length === 0) { return bidsReturned; } @@ -115,7 +116,20 @@ export const spec = { Object.keys(bidResponse.slots).forEach(slot => { const bid = bidResponse.slots[slot]; const bidId = _getBidIdFromTrinityKey(slot); - const mediaType = (bid.sbi_ct === 'video') ? 'video' : null; + const bidRequest = bidderRequest.bidderRequests.find(bid => bid.bidId === bidId); + + let mediaType = null; + if(bid.sbi_ct === 'video') { + const context = deepAccess(bidRequest, 'mediaTypes.video.context'); + if(context) { + if(context === 'outstream') { + mediaType = 'outstream'; + } else { + mediaType = 'video'; + } + } + } + const createCreative = _creative(mediaType, referrer); if (bid.sbi_aid && bid.sbi_mouse && bid.sbi_size) { const [ @@ -146,6 +160,22 @@ export const spec = { delete bids.width; delete bids.height; } + + if(mediaType === 'outstream' && bidRequest) { + bids.mediaType = 'video'; + bids.vastUrl = createCreative(bidResponse.sbi_dc, bid.sbi_aid); + bids.renderer = newRenderer(bidRequest.adUnitCode, bids, deepAccess( + bidRequest, + 'renderer.options' + )); + let videoSize = deepAccess(bidRequest, 'mediaTypes.video.size'); + if(videoSize) { + videoSize = videoSize.split('x'); + bids.width = Number(videoSize[0]); + bids.height = Number(videoSize[1]); + } + + } bidsReturned.push(bids); } }); @@ -192,7 +222,7 @@ function _validateFloor (bid) { } const _creative = (mediaType, referer) => (sbiDc, sbiAid) => { - if (mediaType === 'video') { + if (mediaType === 'video' || mediaType === 'outstream') { return _videoCreative(sbiDc, sbiAid, referer) } const src = `https://${sbiDc}apex.go.sonobi.com/sbi.js?aid=${sbiAid}&as=null&ref=${encodeURIComponent(referer)}`; @@ -247,4 +277,47 @@ function _getDigiTrustObject(key) { return digiTrustId; } +function newRenderer(adUnitCode, bid, rendererOptions = {}) { + const renderer = Renderer.install({ + id: bid.aid, + url: OUTSTREAM_REDNERER_URL, + config: rendererOptions, + loaded: true, + adUnitCode + }); + + try { + renderer.setRender(outstreamRender); + } catch (err) { + logWarn('Prebid Error calling setRender on renderer', err); + } + + renderer.setEventHandlers({ + impression: () => logMessage('Sonobi outstream video impression event'), + loaded: () => logMessage('Sonobi outstream video loaded event'), + ended: () => { + logMessage('Sonobi outstream renderer video event'); + // document.querySelector(`#${adUnitCode}`).style.display = 'none'; + } + }); + return renderer; +} + +function outstreamRender(bid) { + // push to render queue because SbiOutstreamRenderer may not be loaded yet + bid.renderer.push(() => { + const [ + width, + height + ] = bid.getSize().split('x'); + const renderer = new window.SbiOutstreamRenderer(); + renderer.init({ + vastUrl: bid.vastUrl, + height, + width, + }); + renderer.setRootElement(bid.adUnitCode); + }); +} + registerBidder(spec); From 6f619c56f411bfb688e3b2d75c209b985d01bcb2 Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Tue, 12 Feb 2019 15:26:40 -0500 Subject: [PATCH 02/12] added remote url for outstream renderer --- modules/sonobiBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index adb13e28f63..b2006d64428 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -8,7 +8,7 @@ const BIDDER_CODE = 'sonobi'; const STR_ENDPOINT = 'https://apex.go.sonobi.com/trinity.json'; const PAGEVIEW_ID = generateUUID(); const SONOBI_DIGITRUST_KEY = 'fhnS5drwmH'; -const OUTSTREAM_REDNERER_URL = 'https://mtrx.go.sonobi.com/outstream.js'; +const OUTSTREAM_REDNERER_URL = 'https://mtrx.go.sonobi.com/outstream_renderer.js'; export const spec = { code: BIDDER_CODE, From fa575a0b8e61bf4eae89ea60d7fa9fba36b34925 Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Tue, 12 Feb 2019 15:30:40 -0500 Subject: [PATCH 03/12] renamed remote url for sbi renderer outstream --- modules/sonobiBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index b2006d64428..65c7cc6b94e 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -8,7 +8,7 @@ const BIDDER_CODE = 'sonobi'; const STR_ENDPOINT = 'https://apex.go.sonobi.com/trinity.json'; const PAGEVIEW_ID = generateUUID(); const SONOBI_DIGITRUST_KEY = 'fhnS5drwmH'; -const OUTSTREAM_REDNERER_URL = 'https://mtrx.go.sonobi.com/outstream_renderer.js'; +const OUTSTREAM_REDNERER_URL = 'https://mtrx.go.sonobi.com/sbi_outstream_renderer.js'; export const spec = { code: BIDDER_CODE, From daceb90a889fda87ef320b5e6878e5012f26c8bd Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Tue, 12 Feb 2019 15:33:45 -0500 Subject: [PATCH 04/12] outstream renderer is not loaded by default --- modules/sonobiBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 65c7cc6b94e..75bb8321e87 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -282,7 +282,7 @@ function newRenderer(adUnitCode, bid, rendererOptions = {}) { id: bid.aid, url: OUTSTREAM_REDNERER_URL, config: rendererOptions, - loaded: true, + loaded: false, adUnitCode }); From 6b187b51ef8dbbc6e099b57c233c035c7aa6a28e Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Tue, 12 Feb 2019 16:40:26 -0500 Subject: [PATCH 05/12] remove unsed import --- modules/sonobiBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 75bb8321e87..bee8e89f3ac 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -1,5 +1,5 @@ import { registerBidder } from '../src/adapters/bidderFactory'; -import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage, getBidRequest } from '../src/utils'; +import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage } from '../src/utils'; import { BANNER, VIDEO } from '../src/mediaTypes'; import { config } from '../src/config'; import { Renderer } from '../src/Renderer'; From a959cc8d779e6eacbb015ae57c2fee2983daba8c Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Wed, 13 Feb 2019 10:26:04 -0500 Subject: [PATCH 06/12] getting outstream size from params.sizes --- modules/sonobiBidAdapter.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index bee8e89f3ac..bfedb635c07 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -168,7 +168,10 @@ export const spec = { bidRequest, 'renderer.options' )); - let videoSize = deepAccess(bidRequest, 'mediaTypes.video.size'); + let videoSize = deepAccess(bidRequest, 'params.sizes'); + if(Array.isArray(videoSize) && videoSize[0]) { + videoSize = videoSize[0] // Only take the first size for outstream + } if(videoSize) { videoSize = videoSize.split('x'); bids.width = Number(videoSize[0]); From a548e04c5a70bf6b307cbdd53c5436dc05fe6dcc Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Wed, 13 Feb 2019 10:29:22 -0500 Subject: [PATCH 07/12] sizes is an array of arrays --- modules/sonobiBidAdapter.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index bfedb635c07..b0c39d52560 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -169,13 +169,12 @@ export const spec = { 'renderer.options' )); let videoSize = deepAccess(bidRequest, 'params.sizes'); - if(Array.isArray(videoSize) && videoSize[0]) { + if(Array.isArray(videoSize) && Array.isArray(videoSize[0])) { // handle case of multiple sizes videoSize = videoSize[0] // Only take the first size for outstream } if(videoSize) { - videoSize = videoSize.split('x'); - bids.width = Number(videoSize[0]); - bids.height = Number(videoSize[1]); + bids.width = videoSize[0]; + bids.height = videoSize[1]; } } From 8ee90b0a89853f85498089540d6fd93804febed2 Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Wed, 13 Feb 2019 10:59:01 -0500 Subject: [PATCH 08/12] added unit test for outstream bid response --- modules/sonobiBidAdapter.js | 16 +++---- test/spec/modules/sonobiBidAdapter_spec.js | 52 ++++++++++++++++++++-- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index b0c39d52560..f4e64d3d135 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -117,12 +117,11 @@ export const spec = { const bid = bidResponse.slots[slot]; const bidId = _getBidIdFromTrinityKey(slot); const bidRequest = bidderRequest.bidderRequests.find(bid => bid.bidId === bidId); - let mediaType = null; - if(bid.sbi_ct === 'video') { + if (bid.sbi_ct === 'video') { const context = deepAccess(bidRequest, 'mediaTypes.video.context'); - if(context) { - if(context === 'outstream') { + if (context) { + if (context === 'outstream') { mediaType = 'outstream'; } else { mediaType = 'video'; @@ -159,9 +158,7 @@ export const spec = { delete bids.ad; delete bids.width; delete bids.height; - } - - if(mediaType === 'outstream' && bidRequest) { + } else if (mediaType === 'outstream' && bidRequest) { bids.mediaType = 'video'; bids.vastUrl = createCreative(bidResponse.sbi_dc, bid.sbi_aid); bids.renderer = newRenderer(bidRequest.adUnitCode, bids, deepAccess( @@ -169,14 +166,13 @@ export const spec = { 'renderer.options' )); let videoSize = deepAccess(bidRequest, 'params.sizes'); - if(Array.isArray(videoSize) && Array.isArray(videoSize[0])) { // handle case of multiple sizes + if (Array.isArray(videoSize) && Array.isArray(videoSize[0])) { // handle case of multiple sizes videoSize = videoSize[0] // Only take the first size for outstream } - if(videoSize) { + if (videoSize) { bids.width = videoSize[0]; bids.height = videoSize[1]; } - } bidsReturned.push(bids); } diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index 65ad5b352ff..4fe9d92b2d4 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -344,6 +344,20 @@ describe('SonobiBidAdapter', function () { 'adUnitCode': 'adunit-code-3', 'sizes': [[120, 600], [300, 600], [160, 600]], 'bidId': '30b31c1838de1g' + }, + { + 'bidId': '30b31c1838de1zzzz', + 'adUnitCode': 'outstream-dom-id', + bidder: 'sonobi', + mediaTypes: { + video: { + context: 'outstream' + } + }, + params: { + placement_id: '92e95368e86639dbd86d', + sizes: [[640, 480]] + } } ] }; @@ -374,6 +388,17 @@ describe('SonobiBidAdapter', function () { 'sbi_mouse': 1.07, }, '/7780971/sparks_prebid_LB|30b31c1838de1g': {}, + '30b31c1838de1zzzz': { + sbi_aid: 'force_1550072228_da1c5d030cb49150c5db8a2136175755', + sbi_apoc: 'premium', + sbi_ct: 'video', + sbi_curr: 'USD', + sbi_mouse: 1.25, + sbi_size: 'preroll', + 'sbi_crid': 'somecrid', + + } + }, 'sbi_dc': 'mco-1-', 'sbi_px': [{ @@ -404,13 +429,14 @@ describe('SonobiBidAdapter', function () { 'cpm': 1.25, 'width': 300, 'height': 250, - 'ad': 'https://mco-1-apex.go.sonobi.com/vast.xml?vid=30292e432662bd5f86d90774b944b038&ref=http%3A%2F%2Flocalhost%2F', + 'vastUrl': 'https://mco-1-apex.go.sonobi.com/vast.xml?vid=30292e432662bd5f86d90774b944b038&ref=http%3A%2F%2Flocalhost%2F', 'ttl': 500, 'creativeId': '30292e432662bd5f86d90774b944b038', 'netRevenue': true, 'currency': 'USD', 'dealId': 'dozerkey', - 'aid': '30292e432662bd5f86d90774b944b038' + 'aid': '30292e432662bd5f86d90774b944b038', + 'mediaType': 'video' }, { 'requestId': '30b31c1838de1g', @@ -424,6 +450,21 @@ describe('SonobiBidAdapter', function () { 'currency': 'USD', 'aid': '30292e432662bd5f86d90774b944b038' }, + { + 'requestId': '30b31c1838de1zzzz', + 'cpm': 1.25, + 'width': 640, + 'height': 480, + 'vastUrl': 'https://mco-1-apex.go.sonobi.com/vast.xml?vid=30292e432662bd5f86d90774b944b038&ref=http%3A%2F%2Flocalhost%2F', + 'ttl': 500, + 'creativeId': 'somecrid', + 'netRevenue': true, + 'currency': 'USD', + 'dealId': 'dozerkey', + 'aid': 'force_1550072228_da1c5d030cb49150c5db8a2136175755', + 'mediaType': 'video', + renderer: () => {} + }, ]; it('should map bidResponse to prebidResponse', function () { @@ -437,7 +478,12 @@ describe('SonobiBidAdapter', function () { expect(resp.netRevenue).to.equal(prebidResponse[i].netRevenue); expect(resp.currency).to.equal(prebidResponse[i].currency); expect(resp.aid).to.equal(prebidResponse[i].aid); - if (resp.mediaType === 'video') { + if (resp.mediaType === 'video' && resp.renderer) { + expect(resp.vastUrl.indexOf('vast.xml')).to.be.greaterThan(0); + expect(resp.width).to.equal(prebidResponse[i].width); + expect(resp.height).to.equal(prebidResponse[i].height); + expect(resp.renderer).to.be.ok; + } else if (resp.mediaType === 'video') { expect(resp.vastUrl.indexOf('vast.xml')).to.be.greaterThan(0); expect(resp.ad).to.be.undefined; expect(resp.width).to.be.undefined; From c050c24e76d27849666b56b637718f27fa1d2507 Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Wed, 13 Feb 2019 14:49:09 -0500 Subject: [PATCH 09/12] mediaType is video if there is no mediaType context and sbi_ct is video --- modules/sonobiBidAdapter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index f4e64d3d135..87c65df39e9 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -126,6 +126,8 @@ export const spec = { } else { mediaType = 'video'; } + } else { + mediaType = 'video'; } } From 22dc64c5ce4414635f3aa918680c22bae7a85331 Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Wed, 13 Feb 2019 14:50:14 -0500 Subject: [PATCH 10/12] simplify if else conditions around video mediaTypes --- modules/sonobiBidAdapter.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 87c65df39e9..401dfb9c688 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -119,15 +119,10 @@ export const spec = { const bidRequest = bidderRequest.bidderRequests.find(bid => bid.bidId === bidId); let mediaType = null; if (bid.sbi_ct === 'video') { + mediaType = 'video'; const context = deepAccess(bidRequest, 'mediaTypes.video.context'); - if (context) { - if (context === 'outstream') { - mediaType = 'outstream'; - } else { - mediaType = 'video'; - } - } else { - mediaType = 'video'; + if (context === 'outstream') { + mediaType = 'outstream'; } } From 498d1bc499397412f5ec504bed2cdb9444f5fd10 Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Wed, 13 Feb 2019 15:12:24 -0500 Subject: [PATCH 11/12] fixed issue when calling Array.find in IE11 --- modules/sonobiBidAdapter.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 401dfb9c688..47d4b120bd1 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -116,7 +116,7 @@ export const spec = { Object.keys(bidResponse.slots).forEach(slot => { const bid = bidResponse.slots[slot]; const bidId = _getBidIdFromTrinityKey(slot); - const bidRequest = bidderRequest.bidderRequests.find(bid => bid.bidId === bidId); + const bidRequest = _findBidderRequest(bidderRequest.bidderRequests, bidId); let mediaType = null; if (bid.sbi_ct === 'video') { mediaType = 'video'; @@ -195,6 +195,16 @@ export const spec = { } }; +function _findBidderRequest(bidderRequests, bidId) { + + for(const bidderRequest of bidderRequests) { + if(bidderRequest.bidId === bidId) { + return bidderRequest + } + } + +} + function _validateSize (bid) { if (bid.params.sizes) { return parseSizesInput(bid.params.sizes).join(','); From 9b4159c2432bec3daf2587123052c7372059d691 Mon Sep 17 00:00:00 2001 From: Jonathan Go Date: Wed, 13 Feb 2019 15:20:27 -0500 Subject: [PATCH 12/12] fixed issue in IE11 and mac when using for of... --- modules/sonobiBidAdapter.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 47d4b120bd1..ab4058b1978 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -196,13 +196,11 @@ export const spec = { }; function _findBidderRequest(bidderRequests, bidId) { - - for(const bidderRequest of bidderRequests) { - if(bidderRequest.bidId === bidId) { - return bidderRequest + for (let i = 0; i < bidderRequests.length; i++) { + if (bidderRequests[i].bidId === bidId) { + return bidderRequests[i]; } } - } function _validateSize (bid) {