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

Eskimi Bid Adapter: Added support for video #9985

Merged
merged 4 commits into from
Jun 6, 2023
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
212 changes: 171 additions & 41 deletions modules/eskimiBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER} from '../src/mediaTypes.js';
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import * as utils from '../src/utils.js';
import {ortbConverter} from '../libraries/ortbConverter/converter.js'

const BIDDER_CODE = 'eskimi';
// const ENDPOINT = 'https://hb.eskimi.com/bids'
Expand All @@ -12,43 +12,35 @@ const DEFAULT_CURRENCY = 'USD';
const DEFAULT_NET_REVENUE = true;
const GVLID = 814;

const VIDEO_ORTB_PARAMS = [
'mimes',
'minduration',
'maxduration',
'placement',
'protocols',
'startdelay',
'skip',
'skipafter',
'minbitrate',
'maxbitrate',
'delivery',
'playbackmethod',
'api',
'linearity',
'battr'
];

const BANNER_ORTB_PARAMS = [
'battr'
]

export const spec = {
code: BIDDER_CODE,
gvlid: GVLID,
supportedMediaTypes: [BANNER],

isBidRequestValid: function (bid) {
return !!bid.params.placementId;
},

buildRequests(bidRequests, bidderRequest) {
const data = converter.toORTB({bidRequests, bidderRequest})

let bid = bidRequests.find((b) => b.params.placementId)
if (!data.site) data.site = {}
data.site.ext = {placementId: bid.params.placementId}

if (bidderRequest.gdprConsent) {
if (!data.user) data.user = {};
if (!data.user.ext) data.user.ext = {};
if (!data.regs) data.regs = {};
if (!data.regs.ext) data.regs.ext = {};
data.user.ext.consent = bidderRequest.gdprConsent.consentString;
data.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
}

return [{
method: 'POST',
url: ENDPOINT,
data,
options: {contentType: 'application/json;charset=UTF-8', withCredentials: false}
}]
},

interpretResponse(response, request) {
return converter.fromORTB({response: response.body, request: request.data}).bids;
},

supportedMediaTypes: [BANNER, VIDEO],
isBidRequestValid,
buildRequests,
interpretResponse,
/**
* Register bidder specific code, which will execute if a bid from this bidder won the auction
* @param {Bid} bid The bid that won the auction
Expand All @@ -60,13 +52,151 @@ export const spec = {
}
}

const converter = ortbConverter({
registerBidder(spec);

const CONVERTER = ortbConverter({
context: {
netRevenue: DEFAULT_NET_REVENUE,
ttl: DEFAULT_BID_TTL,
currency: DEFAULT_CURRENCY,
mediaType: BANNER // TODO: support more types, we should set mtype on the winning bid
currency: DEFAULT_CURRENCY
},
imp(buildImp, bidRequest, context) {
let imp = buildImp(bidRequest, context);
imp.secure = Number(window.location.protocol === 'https:');
if (!imp.bidfloor && bidRequest.params.bidFloor) {
imp.bidfloor = bidRequest.params.bidFloor;
imp.bidfloorcur = utils.getBidIdParameter('bidFloorCur', bidRequest.params).toUpperCase() || 'USD'
}

if (bidRequest.mediaTypes[VIDEO]) {
imp = buildVideoImp(bidRequest, imp);
} else if (bidRequest.mediaTypes[BANNER]) {
imp = buildBannerImp(bidRequest, imp);
}

return imp;
}
});

registerBidder(spec);
function isBidRequestValid(bidRequest) {
return (isPlacementIdValid(bidRequest) && (isValidBannerRequest(bidRequest) || isValidVideoRequest(bidRequest)));
}

function isPlacementIdValid(bidRequest) {
return utils.isNumber(bidRequest.params.placementId);
}

function isValidBannerRequest(bidRequest) {
const bannerSizes = utils.deepAccess(bidRequest, `mediaTypes.${BANNER}.sizes`);
return utils.isArray(bannerSizes) && bannerSizes.length > 0 && bannerSizes.every(size => utils.isNumber(size[0]) && utils.isNumber(size[1]));
}

function isValidVideoRequest(bidRequest) {
const videoSizes = utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}.playerSize`);

return utils.isArray(videoSizes) && videoSizes.length > 0 && videoSizes.every(size => utils.isNumber(size[0]) && utils.isNumber(size[1]));
}

function buildRequests(validBids, bidderRequest) {
let videoBids = validBids.filter(bid => isVideoBid(bid));
let bannerBids = validBids.filter(bid => isBannerBid(bid));
let requests = [];

bannerBids.forEach(bid => {
requests.push(createRequest([bid], bidderRequest, BANNER));
});

videoBids.forEach(bid => {
requests.push(createRequest([bid], bidderRequest, VIDEO));
});

return requests;
}

function interpretResponse(response, request) {
return CONVERTER.fromORTB({ request: request.data, response: response.body }).bids;
}

function buildVideoImp(bidRequest, imp) {
const videoAdUnitParams = utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}`, {});
const videoBidderParams = utils.deepAccess(bidRequest, `params.${VIDEO}`, {});

const videoParams = { ...videoAdUnitParams, ...videoBidderParams };

const videoSizes = (videoAdUnitParams && videoAdUnitParams.playerSize) || [];

if (videoSizes && videoSizes.length > 0) {
utils.deepSetValue(imp, 'video.w', videoSizes[0][0]);
utils.deepSetValue(imp, 'video.h', videoSizes[0][1]);
}

VIDEO_ORTB_PARAMS.forEach((param) => {
if (videoParams.hasOwnProperty(param)) {
utils.deepSetValue(imp, `video.${param}`, videoParams[param]);
}
});

if (imp.video && videoParams?.context === 'outstream') {
imp.video.placement = imp.video.placement || 4;
}

return { ...imp };
}

function buildBannerImp(bidRequest, imp) {
const bannerAdUnitParams = utils.deepAccess(bidRequest, `mediaTypes.${BANNER}`, {});
const bannerBidderParams = utils.deepAccess(bidRequest, `params.${BANNER}`, {});

const bannerParams = { ...bannerAdUnitParams, ...bannerBidderParams };

let sizes = bidRequest.mediaTypes.banner.sizes;

if (sizes) {
utils.deepSetValue(imp, 'banner.w', sizes[0][0]);
utils.deepSetValue(imp, 'banner.h', sizes[0][1]);
}

BANNER_ORTB_PARAMS.forEach((param) => {
if (bannerParams.hasOwnProperty(param)) {
utils.deepSetValue(imp, `banner.${param}`, bannerParams[param]);
}
});

return { ...imp };
}

function createRequest(bidRequests, bidderRequest, mediaType) {
const data = CONVERTER.toORTB({ bidRequests, bidderRequest, context: { mediaType } })

const bid = bidRequests.find((b) => b.params.placementId)
if (!data.site) data.site = {}
data.site.ext = { placementId: bid.params.placementId }

if (bidderRequest.gdprConsent) {
if (!data.user) data.user = {};
if (!data.user.ext) data.user.ext = {};
if (!data.regs) data.regs = {};
if (!data.regs.ext) data.regs.ext = {};
data.user.ext.consent = bidderRequest.gdprConsent.consentString;
data.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
}

if (bid.params.bcat) data.bcat = bid.params.bcat;
if (bid.params.badv) data.badv = bid.params.badv;
if (bid.params.bapp) data.bapp = bid.params.bapp;

return {
method: 'POST',
url: ENDPOINT,
data: data,
options: { contentType: 'application/json;charset=UTF-8', withCredentials: false }
}
}

function isVideoBid(bid) {
return utils.deepAccess(bid, 'mediaTypes.video');
}

function isBannerBid(bid) {
return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid);
}
51 changes: 35 additions & 16 deletions modules/eskimiBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,48 @@ Maintainer: tech@eskimi.com

# Description

An adapter to get a bid from Eskimi DSP.
Module that connects to Eskimi demand sources to fetch bids using OpenRTB standard.
Banner and video formats are supported.

# Test Parameters
```javascript
var adUnits = [{
code: 'div-gpt-ad-1460505748561-0',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
},

bids: [{
bidder: 'eskimi',
params: {
placementId: 612
}
}]

}];
code: '/19968336/prebid_banner_example_1',
mediaTypes: {
banner: {
sizes: [[ 300, 250 ]],
... // battr
}
},
bids: [{
bidder: 'eskimi',
params: {
placementId: 612,
... // bcat, badv, bapp
}
}]
}, {
code: '/19968336/prebid_video_example_1',
mediaTypes: {
video: {
context: 'outstream',
mimes: ['video/mp4'],
api: [1, 2, 4, 6],
... // Aditional ORTB video params (including battr)
}
},
bids: [{
bidder: 'eskimi',
params: {
placementId: 612,
... // bcat, badv, bapp
}
}]
}];
```

Where:

* placementId - Placement ID of the ad unit (required)
* bcat, badv, bapp, battr - ORTB blocking parameters as specified by OpenRTB 2.5

Loading