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

Sync with master #12

Merged
merged 10 commits into from
May 31, 2024
4 changes: 2 additions & 2 deletions integrationExamples/gpt/cstg_example.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
function updateUID2GuiElements() {
console.log('Updating displayed values.');
const uid2 = pbjs.getUserIds().uid2;
document.querySelector('#uid2TargetedAdvertisingReady').innerText = uid2 ? 'yes' : 'no';
document.querySelector('#uid2AdvertisingToken').innerText = uid2 ? String(uid2.id) : '';
document.querySelector('#uid2TargetedAdvertisingReady').innerText = uid2 && !uid2.optout ? 'yes' : 'no';
document.querySelector('#uid2AdvertisingToken').innerText = uid2 && !uid2.optout ? String(uid2.id) : uid2 && uid2.optout ? 'Optout' : '';
if (!uid2) {
document.querySelector('#uid2LoginForm').style['display'] = 'block';
document.querySelector('#uid2ClearStorageForm').style['display'] = 'none';;
Expand Down
1 change: 1 addition & 0 deletions libraries/autoplayDetection/autoplay.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
let autoplayEnabled = null;

/**
* DEVELOPER WARNING: IMPORTING THIS LIBRARY MAY MAKE YOUR ADAPTER NO LONGER COMPATIBLE WITH APP PUBLISHERS USING WKWEBVIEW
* Note: this function returns true if detection is not done yet. This is by design: if autoplay is not allowed,
* the call to video.play() will fail immediately, otherwise it may not terminate.
* @returns true if autoplay is not forbidden
Expand Down
2 changes: 2 additions & 0 deletions modules/adfBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,15 @@ export const spec = {
const bidfloor = floorInfo.floor;
const bidfloorcur = floorInfo.currency;
const { mid, inv, mname } = bid.params;
const impExtData = bid.ortb2Imp?.ext?.data;

const imp = {
id: id + 1,
tagid: mid,
bidfloor,
bidfloorcur,
ext: {
data: impExtData,
bidder: {
inv,
mname
Expand Down
18 changes: 1 addition & 17 deletions modules/luponmediaBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {config} from '../src/config.js';
import {BANNER} from '../src/mediaTypes.js';
import {ajax} from '../src/ajax.js';

const BIDDER_CODE = 'luponmedia';
const ENDPOINT_URL = 'https://rtb.adxpremium.services/openrtb2/auction';
Expand Down Expand Up @@ -220,19 +219,6 @@ export const spec = {

hasSynced = true;
return allUserSyncs;
},
onBidWon: bid => {
const bidString = JSON.stringify(bid);
spec.sendWinningsToServer(bidString);
},
sendWinningsToServer: data => {
let mutation = `mutation {createWin(input: {win: {eventData: "${window.btoa(data)}"}}) {win {createTime } } }`;
let dataToSend = JSON.stringify({ query: mutation });

ajax('https://analytics.adxpremium.services/graphql', null, dataToSend, {
contentType: 'application/json',
method: 'POST'
});
}
};

Expand Down Expand Up @@ -469,9 +455,7 @@ function newOrtbBidRequest(bidRequest, bidderRequest, currentImps) {
deepSetValue(data, 'ext.prebid.bidderconfig.0', bidderData);
}

// TODO: bidRequest.fpd is not the right place for pbadslot - who's filling that in, if anyone?
// is this meant to be bidRequest.ortb2Imp.ext.data.pbadslot?
const pbAdSlot = deepAccess(bidRequest, 'fpd.context.pbAdSlot');
const pbAdSlot = deepAccess(bidRequest, 'ortb2Imp.ext.data.pbadslot');
if (typeof pbAdSlot === 'string' && pbAdSlot) {
deepSetValue(data.imp[0].ext, 'context.data.adslot', pbAdSlot);
}
Expand Down
2 changes: 1 addition & 1 deletion modules/outbrainBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ function getVideoAsset(bid) {
minduration: bid.mediaTypes.video.minduration,
maxduration: bid.mediaTypes.video.maxduration,
startdelay: bid.mediaTypes.video.startdelay,
placement: bid.mediaTypes.video.placement,
placement: bid.mediaTypes.video.plcmt ?? bid.mediaTypes.video.placement,
linearity: bid.mediaTypes.video.linearity
};
}
Expand Down
6 changes: 3 additions & 3 deletions modules/pubmaticBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const DEFAULT_HEIGHT = 0;
const PREBID_NATIVE_HELP_LINK = 'http://prebid.org/dev-docs/show-native-ads.html';
const PUBLICATION = 'pubmatic'; // Your publication on Blue Billywig, potentially with environment (e.g. publication.bbvms.com or publication.test.bbvms.com)
const RENDERER_URL = 'https://pubmatic.bbvms.com/r/'.concat('$RENDERER', '.js'); // URL of the renderer application
const MSG_VIDEO_PLACEMENT_MISSING = 'Video.Placement param missing';
const MSG_VIDEO_PLCMT_MISSING = 'Video.plcmt param missing';

const CUSTOM_PARAMS = {
'kadpageurl': '', // Custom page url
Expand Down Expand Up @@ -560,8 +560,8 @@ function _createBannerRequest(bid) {

export function checkVideoPlacement(videoData, adUnitCode) {
// Check for video.placement property. If property is missing display log message.
if (FEATURES.VIDEO && !deepAccess(videoData, 'placement')) {
logWarn(MSG_VIDEO_PLACEMENT_MISSING + ' for ' + adUnitCode);
if (FEATURES.VIDEO && !deepAccess(videoData, 'plcmt')) {
logWarn(MSG_VIDEO_PLCMT_MISSING + ' for ' + adUnitCode);
};
}

Expand Down
239 changes: 239 additions & 0 deletions modules/qtBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import { logMessage, logError, deepAccess } from '../src/utils.js';
import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
import { config } from '../src/config.js';

const BIDDER_CODE = 'qt';
const AD_URL = 'https://endpoint1.qt.io/pbjs';
const SYNC_URL = 'https://cs.qt.io';

function isBidResponseValid(bid) {
if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) {
return false;
}

switch (bid.mediaType) {
case BANNER:
return Boolean(bid.width && bid.height && bid.ad);
case VIDEO:
return Boolean(bid.vastUrl || bid.vastXml);
case NATIVE:
return Boolean(bid.native && bid.native.impressionTrackers && bid.native.impressionTrackers.length);
default:
return false;
}
}

function getPlacementReqData(bid) {
const { params, bidId, mediaTypes, transactionId, userIdAsEids } = bid;
const schain = bid.schain || {};
const { placementId, endpointId } = params;
const bidfloor = getBidFloor(bid);

const placement = {
bidId,
schain,
bidfloor
};

if (placementId) {
placement.placementId = placementId;
placement.type = 'publisher';
} else if (endpointId) {
placement.endpointId = endpointId;
placement.type = 'network';
}

if (mediaTypes && mediaTypes[BANNER]) {
placement.adFormat = BANNER;
placement.sizes = mediaTypes[BANNER].sizes;
} else if (mediaTypes && mediaTypes[VIDEO]) {
placement.adFormat = VIDEO;
placement.playerSize = mediaTypes[VIDEO].playerSize;
placement.minduration = mediaTypes[VIDEO].minduration;
placement.maxduration = mediaTypes[VIDEO].maxduration;
placement.mimes = mediaTypes[VIDEO].mimes;
placement.protocols = mediaTypes[VIDEO].protocols;
placement.startdelay = mediaTypes[VIDEO].startdelay;
placement.plcmt = mediaTypes[VIDEO].plcmt;
placement.skip = mediaTypes[VIDEO].skip;
placement.skipafter = mediaTypes[VIDEO].skipafter;
placement.minbitrate = mediaTypes[VIDEO].minbitrate;
placement.maxbitrate = mediaTypes[VIDEO].maxbitrate;
placement.delivery = mediaTypes[VIDEO].delivery;
placement.playbackmethod = mediaTypes[VIDEO].playbackmethod;
placement.api = mediaTypes[VIDEO].api;
placement.linearity = mediaTypes[VIDEO].linearity;
} else if (mediaTypes && mediaTypes[NATIVE]) {
placement.native = mediaTypes[NATIVE];
placement.adFormat = NATIVE;
}

if (transactionId) {
placement.ext = placement.ext || {};
placement.ext.tid = transactionId;
}

if (userIdAsEids && userIdAsEids.length) {
placement.eids = userIdAsEids;
}

return placement;
}

function getBidFloor(bid) {
try {
const bidFloor = bid.getFloor({
currency: 'USD',
mediaType: '*',
size: '*',
});
return bidFloor.floor;
} catch (err) {
logError(err);
return 0;
}
}

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER, VIDEO, NATIVE],

isBidRequestValid: (bid = {}) => {
const { params, bidId, mediaTypes } = bid;
let valid = Boolean(bidId && params && (params.placementId || params.endpointId));

if (mediaTypes && mediaTypes[BANNER]) {
valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes);
} else if (mediaTypes && mediaTypes[VIDEO]) {
valid = valid && Boolean(mediaTypes[VIDEO] && mediaTypes[VIDEO].playerSize);
} else if (mediaTypes && mediaTypes[NATIVE]) {
valid = valid && Boolean(mediaTypes[NATIVE]);
} else {
valid = false;
}
return valid;
},

buildRequests: (validBidRequests = [], bidderRequest = {}) => {
// convert Native ORTB definition to old-style prebid native definition
validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);

let deviceWidth = 0;
let deviceHeight = 0;

let winLocation;
try {
const winTop = window.top;
deviceWidth = winTop.screen.width;
deviceHeight = winTop.screen.height;
winLocation = winTop.location;
} catch (e) {
logMessage(e);
winLocation = window.location;
}

const refferUrl = bidderRequest.refererInfo && bidderRequest.refererInfo.page;
let refferLocation;
try {
refferLocation = refferUrl && new URL(refferUrl);
} catch (e) {
logMessage(e);
}

let location = refferLocation || winLocation;
const language = (navigator && navigator.language) ? navigator.language.split('-')[0] : '';
const host = location.host;
const page = location.pathname;
const secure = location.protocol === 'https:' ? 1 : 0;
const placements = [];
const request = {
deviceWidth,
deviceHeight,
language,
secure,
host,
page,
placements,
coppa: deepAccess(bidderRequest, 'ortb2.regs.coppa') ? 1 : 0,
tmax: bidderRequest.timeout
};

if (bidderRequest.uspConsent) {
request.ccpa = bidderRequest.uspConsent;
}

if (bidderRequest.gdprConsent) {
request.gdpr = {
consentString: bidderRequest.gdprConsent.consentString
};
}

if (bidderRequest.gppConsent) {
request.gpp = bidderRequest.gppConsent.gppString;
request.gpp_sid = bidderRequest.gppConsent.applicableSections;
} else if (bidderRequest.ortb2?.regs?.gpp) {
request.gpp = bidderRequest.ortb2.regs.gpp;
request.gpp_sid = bidderRequest.ortb2.regs.gpp_sid;
}

const len = validBidRequests.length;
for (let i = 0; i < len; i++) {
const bid = validBidRequests[i];
placements.push(getPlacementReqData(bid));
}

return {
method: 'POST',
url: AD_URL,
data: request
};
},

interpretResponse: (serverResponse) => {
let response = [];
for (let i = 0; i < serverResponse.body.length; i++) {
let resItem = serverResponse.body[i];
if (isBidResponseValid(resItem)) {
const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : [];
resItem.meta = { ...resItem.meta, advertiserDomains };

response.push(resItem);
}
}
return response;
},

getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => {
let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image';
let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`;

if (gdprConsent && gdprConsent.consentString) {
if (typeof gdprConsent.gdprApplies === 'boolean') {
syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
} else {
syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`;
}
}

if (uspConsent && uspConsent.consentString) {
syncUrl += `&ccpa_consent=${uspConsent.consentString}`;
}

if (gppConsent?.gppString && gppConsent?.applicableSections?.length) {
syncUrl += '&gpp=' + gppConsent.gppString;
syncUrl += '&gpp_sid=' + gppConsent.applicableSections.join(',');
}

const coppa = config.getConfig('coppa') ? 1 : 0;
syncUrl += `&coppa=${coppa}`;

return [{
type: syncType,
url: syncUrl
}];
}
};

registerBidder(spec);
Loading