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

videoNow bid adapter #4088

Merged
merged 29 commits into from
Sep 27, 2019
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
68717af
-- first commit
sdbaron Aug 8, 2019
e49d26a
-- cors and bidder's name fixed
sdbaron Aug 8, 2019
1654ea5
-- almost ready
sdbaron Aug 9, 2019
8137975
-- added docs
sdbaron Aug 12, 2019
ed28e3c
-- added nurl tracking
sdbaron Aug 12, 2019
d3d8462
-- bid params
sdbaron Aug 13, 2019
56b0d23
-- tests added
sdbaron Aug 13, 2019
c31fbb1
-- test fixed
sdbaron Aug 14, 2019
7d1d694
Merge branch 'videoNowAdapter'
sdbaron Aug 14, 2019
615c3f3
-- replace placeholder in the onBidWon pixel's url
sdbaron Aug 21, 2019
4142f07
-- commit for restart tests
sdbaron Aug 21, 2019
36ce34a
-- change response data format for display ad
sdbaron Sep 2, 2019
7310341
-- tests updated
sdbaron Sep 3, 2019
4c659f6
-- 100% tests coverage
sdbaron Sep 4, 2019
a786ef5
-- a few clean the test's code
sdbaron Sep 4, 2019
11f54ac
-- custom urls from localStorage
sdbaron Sep 5, 2019
77691e5
-- tests updated
sdbaron Sep 5, 2019
833cc86
-- a few clean the test's code
sdbaron Sep 6, 2019
0f8c673
-- new init model
sdbaron Sep 6, 2019
dea7e2d
-- spec for new init model
sdbaron Sep 6, 2019
fbbd777
-- fix for new init model
sdbaron Sep 6, 2019
62811b7
-- code cleaned
sdbaron Sep 9, 2019
a4d0bfd
-- 100% tests coverage
sdbaron Sep 9, 2019
53a3b95
-- 100% tests coverage
sdbaron Sep 9, 2019
1fe97ef
Merge remote-tracking branch 'upstream/master'
sdbaron Sep 9, 2019
779fa64
Merge branch 'newResponseFormat'
sdbaron Sep 9, 2019
f7b2e2c
Merge remote-tracking branch 'upstream/master'
sdbaron Sep 12, 2019
5801534
-- fixed test
sdbaron Sep 12, 2019
3c1f76f
-- commit for restart tests
sdbaron Sep 12, 2019
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
211 changes: 211 additions & 0 deletions modules/videoNowBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import * as utils from '../src/utils';
import { registerBidder } from '../src/adapters/bidderFactory';
import { BANNER } from '../src/mediaTypes'

const RTB_URL = 'https://bidder.videonow.ru/prebid'

const BIDDER_CODE = 'videonow'
const TTL_SECONDS = 60 * 5;

function isBidRequestValid(bid) {
const { params } = bid || {}
return !!(params.pId);
}

function buildRequest(bid, bidderRequest) {
const { refererInfo } = bidderRequest
const { ext, bidId, params, code, sizes } = bid;
const { pId, bidFloor, cur, placementId, url: rtbUrl } = params || {}

let url = rtbUrl || RTB_URL
url = `${url}${~url.indexOf('?') ? '&' : '?'}profile_id=${pId}`

const dto = {
method: 'POST',
url,
data: {
id: bidId,
cpm: bidFloor,
code,
sizes,
cur: cur || 'RUB',
placementId,
ref: refererInfo && refererInfo.referer
}
}

ext && Object.keys(ext).forEach(key => {
dto[`ext_${key}`] = ext.key
})

return dto;
}

function buildRequests(validBidRequests, bidderRequest) {
utils.logInfo(`${BIDDER_CODE}. buildRequests`)
const requests = [];
validBidRequests.forEach(validBidRequest => {
const request = buildRequest(validBidRequest, bidderRequest);
request && requests.push(request);
});
return requests;
}

function interpretResponse(serverResponse, bidRequest) {
if (!serverResponse || !serverResponse.body) {
return [];
}
const { id: bidId } = (bidRequest && bidRequest.data) || {}
if (!bidId) return []

const { seatbid, cur, ext } = serverResponse.body;
if (!seatbid || !seatbid.length) return []

const { placementId } = ext || {}
if (!placementId) return []

const bids = []
seatbid.forEach(sb => {
const { bid } = sb
if (bid && bid.length) {
bid.forEach(b => {
const res = createResponseBid(b, bidId, cur, placementId)
res && bids.push(res)
})
}
})

return bids
}

function createResponseBid(bidInfo, bidId, cur, placementId) {
const { id, nurl, code, price, crid, adm, ttl, netRevenue, w, h } = bidInfo

if (!id || !price) {
return null;
}

if (!adm) {
utils.logError(`${BIDDER_CODE}. adm not exists in the response`)
return null
}

try {
return {
requestId: bidId,
cpm: price,
width: w,
height: h,
creativeId: crid,
currency: cur || 'RUB',
netRevenue: netRevenue !== undefined ? netRevenue : true,
ttl: ttl || TTL_SECONDS,
ad: code,
nurl,
renderer: {
url: nurl,
render: function() {
const d = window.document
const el = placementId && d.getElementById(placementId)
if (!el) {
console.error(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`)
Copy link
Contributor

Choose a reason for hiding this comment

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

can we use utils.logError() here?

}

el.innerHTML = adm
reInitScripts(el)
}
}
}
} catch (e) {
return null
}
}

function getUserSyncs(syncOptions, serverResponses) {
const syncs = []

if (!serverResponses || !serverResponses.length) return syncs

serverResponses.forEach(response => {
const {ext} = (response && response.body) || {}
const {pixels, iframes} = ext || {}

if (syncOptions.iframeEnabled && iframes && iframes.length) {
iframes.forEach(i => syncs.push({
type: 'iframe',
url: i
})
)
}

if (syncOptions.pixelEnabled && pixels && pixels.length) {
pixels.forEach(p => syncs.push({
type: 'image',
url: p
})
)
}
})

utils.logInfo(`${BIDDER_CODE} getUserSyncs() syncs=${syncs.length}`)
return syncs
}

function onBidWon(bid) {
const { nurl } = bid
if (nurl) {
const img = document.createElement('img')
img.src = nurl
img.style.cssText = 'display:none !important;'
document.body.appendChild(img)
}
}

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER],
isBidRequestValid,
buildRequests,
interpretResponse,
getUserSyncs,
onTimeout: function(timeoutData) {},
onBidWon
}

registerBidder(spec);

function reInitScripts(container, shouldReInitInlineScripts = true, delay = 10) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please explain what does this function do and why do we need it in the adapter?

const oldScripts = container.querySelectorAll('script')
const innerScriptsInsertActions = []

oldScripts && oldScripts.length && Array.from(oldScripts).forEach(oldScr => {
const { parentNode } = oldScr
const scriptElement = document.createElement('script')
oldScr.attributes && Array.from(oldScr.attributes).forEach(attr => {
scriptElement.setAttribute(attr.name, attr.value)
})

if (oldScr.src) {
innerScriptsInsertActions.push(() => {
((function(parent, scriptElm, src) {
scriptElm.src = src
parent.appendChild(scriptElm)
})(parentNode, scriptElement, oldScr.src))
})
}

if (oldScr.innerHTML && shouldReInitInlineScripts) {
innerScriptsInsertActions.push(() => {
((function(parent, scriptElm, scriptText) {
scriptElm.innerHTML = scriptText
parent.appendChild(scriptElm)
})(parentNode, scriptElement, oldScr.innerHTML))
})
}
parentNode.removeChild(oldScr)
})

innerScriptsInsertActions.length && setTimeout(() => {
innerScriptsInsertActions.forEach(si => si())
}, delay)
}
35 changes: 35 additions & 0 deletions modules/videoNowBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Overview

```
Module Name: Videonow Bidder Adapter
Module Type: Bidder Adapter
Maintainer: info@videonow.ru
```

# Description

Connect to Videonow for bids.

The Videonow bidder adapter requires setup and approval from the videoNow team.
Please reach out to your account team or info@videonow.ru for more information.

# Test Parameters
```javascript
var adUnits = [
// Banner adUnit
{
code: 'banner-div',
mediaTypes: {
banner: {
sizes: [[640, 480], [300, 250], [336, 280]]
}
},
bids: [{
bidder: 'videonow',
params: {
pId: 1,
placementId: '36891'
}
}]
}]
```
Loading