Skip to content

Commit

Permalink
Eskimi Bid Adapter: Added support for video
Browse files Browse the repository at this point in the history
  • Loading branch information
myDisconnect committed May 23, 2023
1 parent 4d9b28c commit 486acfe
Show file tree
Hide file tree
Showing 3 changed files with 431 additions and 168 deletions.
192 changes: 151 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,30 @@ 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'
];

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 +47,136 @@ 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) {
let sizes = bidRequest.mediaTypes.banner.sizes;

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

return { ...imp };
}

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

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: 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);
}
47 changes: 31 additions & 16 deletions modules/eskimiBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,41 @@ 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 ]]
}
}
bids: [{
bidder: 'eskimi',
params: {
placementId: 612
}
}]
}, {
code: '/19968336/prebid_video_example_1',
mediaTypes: {
video: {
context: 'outstream',
mimes: ['video/mp4'],
api: [1, 2, 4, 6],
... // Aditional ORTB video params
}
}
bids: [{
bidder: 'eskimi',
params: {
placementId: 612
}
}]
}];
```

Where:
Expand Down
Loading

0 comments on commit 486acfe

Please sign in to comment.