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

Sharethrough Bid Adapter : update video logic #12217

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1659209
Merge pull request #1586 from prebid/master
jefftmahoney Jan 9, 2024
a49852a
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Jan 19, 2024
bc2e207
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Feb 2, 2024
25e0e24
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Mar 19, 2024
c5495ba
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney May 9, 2024
18c8328
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney May 20, 2024
7ce2843
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Jun 17, 2024
63f6967
Merge pull request #1612 from prebid/master
jefftmahoney Jun 27, 2024
ca6a30b
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Jun 27, 2024
b8d37a9
Merge pull request #1613 from prebid/master
jefftmahoney Jul 15, 2024
84da627
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Jul 15, 2024
fade8b9
Merge pull request #1614 from prebid/master
jefftmahoney Jul 18, 2024
ef82a8b
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Jul 18, 2024
7a2efee
Merge pull request #1615 from prebid/master
jefftmahoney Aug 18, 2024
198faf2
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Aug 18, 2024
b932054
Merge branch 'prebid:master' into master
jefftmahoney Aug 20, 2024
0e00795
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Aug 20, 2024
72669b9
Merge pull request #1616 from prebid/master
jefftmahoney Sep 9, 2024
6c93e66
Merge branch 'master' of https://github.com/sharethrough/Prebid.js-in…
jefftmahoney Sep 9, 2024
737c3a5
Video values, update logic concerning
jefftmahoney Sep 9, 2024
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
67 changes: 26 additions & 41 deletions modules/sharethroughBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { config } from '../src/config.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { deepAccess, generateUUID, inIframe, mergeDeep } from '../src/utils.js';
import { deepAccess, generateUUID, inIframe, logWarn, mergeDeep } from '../src/utils.js';

const VERSION = '4.3.0';
const BIDDER_CODE = 'sharethrough';
const SUPPLY_ID = 'WYu2BXv1';

const STR_ENDPOINT = `https://btlr.sharethrough.com/universal/v1?supply_id=${SUPPLY_ID}`;
const IDENTIFIER_PREFIX = 'Sharethrough:';

// this allows stubbing of utility function that is used internally by the sharethrough adapter
export const sharethroughInternal = {
Expand Down Expand Up @@ -129,38 +130,40 @@ export const sharethroughAdapterSpec = {
[w, h] = videoRequest.playerSize[0];
}

const getVideoPlacementValue = (vidReq) => {
if (vidReq.plcmt) {
return vidReq.placement;
} else {
return vidReq.context === 'instream' ? 1 : +deepAccess(vidReq, 'placement', 4);
/**
* Applies a specified property to an impression object if it is present in the video request
* @param {string} prop A property to apply to the impression object
* @param {object} vidReq A video request object from which to extract the property
* @param {object} imp A video impression object to which to apply the property
*/
const applyVideoProperty = (prop, vidReq, imp) => {
const propIsTypeArray = ['api', 'battr', 'mimes', 'playbackmethod', 'protocols'].includes(prop);
if (propIsTypeArray) {
const notAssignable = (!Array.isArray(vidReq[prop]) || vidReq[prop].length === 0) && vidReq[prop];
if (notAssignable) {
logWarn(`${IDENTIFIER_PREFIX} Invalid video request property: "${prop}" must be an array with at least 1 entry. Value supplied: "${vidReq[prop]}". This will not be added to the bid request.`);
return;
}
}
if (vidReq[prop]) {
imp.video[prop] = vidReq[prop];
}
};

impression.video = {
pos: nullish(videoRequest.pos, 0),
topframe: inIframe() ? 0 : 1,
skip: nullish(videoRequest.skip, 0),
linearity: nullish(videoRequest.linearity, 1),
minduration: nullish(videoRequest.minduration, 5),
maxduration: nullish(videoRequest.maxduration, 60),
playbackmethod: videoRequest.playbackmethod || [2],
api: getVideoApi(videoRequest),
mimes: videoRequest.mimes || ['video/mp4'],
protocols: getVideoProtocols(videoRequest),
w,
h,
startdelay: nullish(videoRequest.startdelay, 0),
skipmin: nullish(videoRequest.skipmin, 0),
skipafter: nullish(videoRequest.skipafter, 0),
placement: getVideoPlacementValue(videoRequest),
plcmt: videoRequest.plcmt ? videoRequest.plcmt : null,
};

if (videoRequest.battr) impression.video.battr = videoRequest.battr;
if (videoRequest.delivery) impression.video.delivery = videoRequest.delivery;
if (videoRequest.companiontype) impression.video.companiontype = videoRequest.companiontype;
if (videoRequest.companionad) impression.video.companionad = videoRequest.companionad;
const propertiesToConsider = [
'api', 'battr', 'companionad', 'companiontype', 'delivery', 'linearity', 'maxduration', 'mimes', 'minduration', 'placement', 'playbackmethod', 'plcmt', 'protocols', 'skip', 'skipafter', 'skipmin', 'startdelay'
]

propertiesToConsider.forEach(propertyToConsider => {
applyVideoProperty(propertyToConsider, videoRequest, impression);
});
} else {
impression.banner = {
pos: deepAccess(bidReq, 'mediaTypes.banner.pos', 0),
Expand Down Expand Up @@ -274,24 +277,6 @@ export const sharethroughAdapterSpec = {
onSetTargeting: (bid) => {},
};

function getVideoApi({ api }) {
let defaultValue = [2];
if (api && Array.isArray(api) && api.length > 0) {
return api;
} else {
return defaultValue;
}
}

function getVideoProtocols({ protocols }) {
let defaultValue = [2, 3, 5, 6, 7, 8];
if (protocols && Array.isArray(protocols) && protocols.length > 0) {
return protocols;
} else {
return defaultValue;
}
}

function getBidRequestFloor(bid) {
let floor = null;
if (typeof bid.getFloor === 'function') {
Expand Down
105 changes: 42 additions & 63 deletions test/spec/modules/sharethroughBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ describe('sharethrough adapter spec', function () {
video: {
pos: 3,
skip: 1,
linearity: 0,
linearity: 1,
minduration: 10,
maxduration: 30,
playbackmethod: [1],
Expand All @@ -233,6 +233,8 @@ describe('sharethrough adapter spec', function () {
companiontype: 'companion type',
companionad: 'companion ad',
context: 'instream',
placement: 1,
plcmt: 1,
},
},
getFloor: () => ({ currency: 'USD', floor: 42 }),
Expand Down Expand Up @@ -618,7 +620,7 @@ describe('sharethrough adapter spec', function () {
expect(videoImp.pos).to.equal(3);
expect(videoImp.topframe).to.equal(1);
expect(videoImp.skip).to.equal(1);
expect(videoImp.linearity).to.equal(0);
expect(videoImp.linearity).to.equal(1);
expect(videoImp.minduration).to.equal(10);
expect(videoImp.maxduration).to.equal(30);
expect(videoImp.playbackmethod).to.deep.equal([1]);
Expand All @@ -637,89 +639,66 @@ describe('sharethrough adapter spec', function () {
expect(videoImp.companionad).to.equal('companion ad');
});

it('should set defaults if no value provided', () => {
it('should set defaults in some circumstances if no value provided', () => {
delete bidRequests[1].mediaTypes.video.pos;
delete bidRequests[1].mediaTypes.video.skip;
delete bidRequests[1].mediaTypes.video.linearity;
delete bidRequests[1].mediaTypes.video.minduration;
delete bidRequests[1].mediaTypes.video.maxduration;
delete bidRequests[1].mediaTypes.video.playbackmethod;
delete bidRequests[1].mediaTypes.video.api;
delete bidRequests[1].mediaTypes.video.mimes;
delete bidRequests[1].mediaTypes.video.protocols;
delete bidRequests[1].mediaTypes.video.playerSize;
delete bidRequests[1].mediaTypes.video.startdelay;
delete bidRequests[1].mediaTypes.video.skipmin;
delete bidRequests[1].mediaTypes.video.skipafter;
delete bidRequests[1].mediaTypes.video.placement;
delete bidRequests[1].mediaTypes.video.delivery;
delete bidRequests[1].mediaTypes.video.battr;
delete bidRequests[1].mediaTypes.video.companiontype;
delete bidRequests[1].mediaTypes.video.companionad;

const builtRequest = spec.buildRequests(bidRequests, bidderRequest)[1];

const videoImp = builtRequest.data.imp[0].video;
expect(videoImp.pos).to.equal(0);
expect(videoImp.skip).to.equal(0);
expect(videoImp.linearity).to.equal(1);
expect(videoImp.minduration).to.equal(5);
expect(videoImp.maxduration).to.equal(60);
expect(videoImp.playbackmethod).to.deep.equal([2]);
expect(videoImp.api).to.deep.equal([2]);
expect(videoImp.mimes).to.deep.equal(['video/mp4']);
expect(videoImp.protocols).to.deep.equal([2, 3, 5, 6, 7, 8]);
expect(videoImp.w).to.equal(640);
expect(videoImp.h).to.equal(360);
expect(videoImp.startdelay).to.equal(0);
expect(videoImp.skipmin).to.equal(0);
expect(videoImp.skipafter).to.equal(0);
expect(videoImp.placement).to.equal(1);
expect(videoImp.delivery).to.be.undefined;
expect(videoImp.battr).to.be.undefined;
expect(videoImp.companiontype).to.be.undefined;
expect(videoImp.companionad).to.be.undefined;
});

describe('outstream', () => {
it('should use placement value if provided', () => {
bidRequests[1].mediaTypes.video.context = 'outstream';
bidRequests[1].mediaTypes.video.placement = 3;
it('should not set values in some circumstances when non-valid values are supplied', () => {
// arrange
bidRequests[1].mediaTypes.video.api = 1; // non-array value, will not be used
bidRequests[1].mediaTypes.video.battr = undefined; // non-array value, will not be used
bidRequests[1].mediaTypes.video.mimes = 'video/3gpp'; // non-array value, will not be used
bidRequests[1].mediaTypes.video.playbackmethod = null; // non-array value, will not be used
bidRequests[1].mediaTypes.video.protocols = []; // empty array, will not be used

const builtRequest = spec.buildRequests(bidRequests, bidderRequest)[1];
const videoImp = builtRequest.data.imp[0].video;

expect(videoImp.placement).to.equal(3);
});
// act
const builtRequest = spec.buildRequests(bidRequests, bidderRequest)[1];
const videoImp = builtRequest.data.imp[0].video;

it('should default placement to 4 if not provided', () => {
bidRequests[1].mediaTypes.video.context = 'outstream';
// assert
expect(videoImp.api).to.be.undefined;
expect(videoImp.battr).to.be.undefined;
expect(videoImp.mimes).to.be.undefined;
expect(videoImp.playbackmethod).to.be.undefined;
expect(videoImp.protocols).to.be.undefined;
});

const builtRequest = spec.buildRequests(bidRequests, bidderRequest)[1];
const videoImp = builtRequest.data.imp[0].video;
it('should not set a property if no corresponding property is detected on mediaTypes.video', () => {
// arrange
const propertiesToConsider = [
'api', 'battr', 'companionad', 'companiontype', 'delivery', 'linearity', 'maxduration', 'mimes', 'minduration', 'placement', 'playbackmethod', 'plcmt', 'protocols', 'skip', 'skipafter', 'skipmin', 'startdelay'
]

expect(videoImp.placement).to.equal(4);
// act
propertiesToConsider.forEach(propertyToConsider => {
delete bidRequests[1].mediaTypes.video[propertyToConsider];
});
const builtRequest = spec.buildRequests(bidRequests, bidderRequest)[1];
const videoImp = builtRequest.data.imp[0].video;

it('should not override "placement" value if "plcmt" prop is present', () => {
// ASSEMBLE
const ARBITRARY_PLACEMENT_VALUE = 99;
const ARBITRARY_PLCMT_VALUE = 100;

bidRequests[1].mediaTypes.video.context = 'instream';
bidRequests[1].mediaTypes.video.placement = ARBITRARY_PLACEMENT_VALUE;
// assert
propertiesToConsider.forEach(propertyToConsider => {
expect(videoImp[propertyToConsider]).to.be.undefined;
});
});

// adding "plcmt" property - this should prevent "placement" prop
// from getting overridden to 1
bidRequests[1].mediaTypes.video['plcmt'] = ARBITRARY_PLCMT_VALUE;
describe('outstream', () => {
it('should use placement value if provided', () => {
bidRequests[1].mediaTypes.video.context = 'outstream';
bidRequests[1].mediaTypes.video.placement = 3;

// ACT
const builtRequest = spec.buildRequests(bidRequests, bidderRequest)[1];
const videoImp = builtRequest.data.imp[0].video;

// ASSERT
expect(videoImp.placement).to.equal(ARBITRARY_PLACEMENT_VALUE);
expect(videoImp.plcmt).to.equal(ARBITRARY_PLCMT_VALUE);
expect(videoImp.placement).to.equal(3);
});
});
});
Expand Down