diff --git a/modules/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js index 5b3f55b9da6..e85a22f76d8 100644 --- a/modules/eplanningBidAdapter.js +++ b/modules/eplanningBidAdapter.js @@ -37,7 +37,84 @@ export const spec = { return Boolean(bid.params.ci) || Boolean(bid.params.t); }, - buildRequests: function(bidRequests, bidderRequest) { + buildRequests: function (bidRequests, bidderRequest) { + const requests = []; + + // compute video request + const videoBidRequests = bidRequests.filter((bid) => bid.mediaTypes && bid.mediaTypes[VIDEO]); + const videoRequest = formatWiseBuildRequests(videoBidRequests, bidderRequest, false); + if (videoRequest) requests.push(videoRequest); + + // compute banner request + const bannerBidRequests = bidRequests.filter((bid) => bid.mediaTypes && bid.mediaTypes[BANNER]); + const bannerRequest = formatWiseBuildRequests(bannerBidRequests, bidderRequest, true); + if (bannerRequest) requests.push(bannerRequest); + + return requests; + }, + interpretResponse: function (serverResponse, request) { + const response = serverResponse.body; + let bidResponses = []; + + if (response && !isEmpty(response.sp)) { + response.sp.forEach(space => { + if (!isEmpty(space.a)) { + space.a.forEach(ad => { + const bidResponse = { + requestId: request.adUnitToBidId[space.k], + cpm: ad.pr, + width: ad.w, + height: ad.h, + ttl: TTL, + creativeId: ad.crid, + netRevenue: NET_REVENUE, + currency: DOLLAR_CODE, + }; + if (ad.adom) { + bidResponse.meta = { + advertiserDomains: ad.adom + }; + } + if (request && request.data && request.data.vv) { + bidResponse.vastXml = ad.adm; + bidResponse.mediaType = VIDEO; + } else { + bidResponse.ad = ad.adm; + } + + bidResponses.push(bidResponse); + }); + } + }); + } + + return bidResponses; + }, + getUserSyncs: function (syncOptions, serverResponses) { + const syncs = []; + const response = !isEmpty(serverResponses) && serverResponses[0].body; + + if (response && !isEmpty(response.cs)) { + const responseSyncs = response.cs; + responseSyncs.forEach(sync => { + if (typeof sync === 'string' && syncOptions.pixelEnabled) { + syncs.push({ + type: 'image', + url: sync, + }); + } else if (typeof sync === 'object' && sync.ifr && syncOptions.iframeEnabled) { + syncs.push({ + type: 'iframe', + url: sync.u, + }) + } + }); + } + + return syncs; + }, +}; +function formatWiseBuildRequests(bidRequests, bidderRequest, disableVideo) { const method = 'GET'; const dfpClientId = '1'; const sec = 'ROS'; @@ -46,7 +123,7 @@ export const spec = { let params; const urlConfig = getUrlConfig(bidRequests); const pcrs = getCharset(); - const spaces = getSpaces(bidRequests, urlConfig.ml); + const spaces = getSpaces(bidRequests, urlConfig.ml, disableVideo); // TODO: do the fallbacks make sense here? const pageUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; const domain = bidderRequest.refererInfo.domain || window.location.host; @@ -111,68 +188,6 @@ export const spec = { data: params, adUnitToBidId: spaces.map, }; - }, - interpretResponse: function(serverResponse, request) { - const response = serverResponse.body; - let bidResponses = []; - - if (response && !isEmpty(response.sp)) { - response.sp.forEach(space => { - if (!isEmpty(space.a)) { - space.a.forEach(ad => { - const bidResponse = { - requestId: request.adUnitToBidId[space.k], - cpm: ad.pr, - width: ad.w, - height: ad.h, - ttl: TTL, - creativeId: ad.crid, - netRevenue: NET_REVENUE, - currency: DOLLAR_CODE, - }; - if (ad.adom) { - bidResponse.meta = { - advertiserDomains: ad.adom - }; - } - if (request && request.data && request.data.vv) { - bidResponse.vastXml = ad.adm; - bidResponse.mediaType = VIDEO; - } else { - bidResponse.ad = ad.adm; - } - - bidResponses.push(bidResponse); - }); - } - }); - } - - return bidResponses; - }, - getUserSyncs: function(syncOptions, serverResponses) { - const syncs = []; - const response = !isEmpty(serverResponses) && serverResponses[0].body; - - if (response && !isEmpty(response.cs)) { - const responseSyncs = response.cs; - responseSyncs.forEach(sync => { - if (typeof sync === 'string' && syncOptions.pixelEnabled) { - syncs.push({ - type: 'image', - url: sync, - }); - } else if (typeof sync === 'object' && sync.ifr && syncOptions.iframeEnabled) { - syncs.push({ - type: 'iframe', - url: sync.u, - }) - } - }); - } - - return syncs; - }, }; function getUserAgent() { diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index a96b0da132b..ca8b421b12d 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -138,7 +138,26 @@ const MEDIA_TYPES = { Audio: 3, Native: 4 }; +const AP_VALID_SIZES = [ + [300, 50], + [120, 600], + [250, 250], + [300, 250], + [300, 600], + [728, 90], + [160, 600], + [728, 400], + [480, 320], + [320, 50], + [580, 400], + [970, 90], + [970, 250], + [320, 480] +]; +function apIsValidSize (width, height) { + return find(AP_VALID_SIZES, ([validWidth, validHeight]) => validWidth === width && validHeight === height); +} /** * Transform valid bid request config object to banner impression object that will be sent to ad server. * @@ -1385,7 +1404,7 @@ function createNativeImps(validBidRequest, nativeImps) { */ function createVideoImps(validBidRequest, videoImps) { const imp = bidToVideoImp(validBidRequest); - if (Object.keys(imp).length != 0) { + if (Object.keys(imp).length != 0 && apIsValidSize(imp.video.w, imp.video.h)) { videoImps[validBidRequest.adUnitCode] = {}; videoImps[validBidRequest.adUnitCode].ixImps = []; videoImps[validBidRequest.adUnitCode].ixImps.push(imp); @@ -1457,7 +1476,7 @@ function createBannerImps(validBidRequest, missingBannerSizes, bannerImps, bidde bannerImps[validBidRequest.adUnitCode].divId = divId; // Create IX imps from params.size - if (bannerSizeDefined) { + if (bannerSizeDefined && apIsValidSize(imp.banner.w, imp.banner.h)) { if (!bannerImps[validBidRequest.adUnitCode].hasOwnProperty('ixImps')) { bannerImps[validBidRequest.adUnitCode].ixImps = []; } @@ -1485,7 +1504,8 @@ function updateMissingSizes(validBidRequest, missingBannerSizes, imp) { } else { // New Ad Unit if (deepAccess(validBidRequest, 'mediaTypes.banner.sizes')) { - let sizeList = deepClone(validBidRequest.mediaTypes.banner.sizes); + let sizes = validBidRequest.mediaTypes.banner.sizes + let sizeList = deepClone(sizes.filter(size => apIsValidSize(...size))); removeFromSizes(sizeList, validBidRequest.params.size); let newAdUnitEntry = { 'missingSizes': sizeList, diff --git a/modules/luceadBidAdapter.js b/modules/luceadBidAdapter.js index ffc2307bcb8..2cd05041391 100755 --- a/modules/luceadBidAdapter.js +++ b/modules/luceadBidAdapter.js @@ -18,6 +18,18 @@ let baseUrl = `https://${domain}`; let staticUrl = `https://s.${domain}`; let endpointUrl = baseUrl; +(function loadLuceAdScriptForAdpushup() { + const adp = window.adpushup || {}; + const adpUtils = adp.utils; + if (!adpUtils) return; + try { + const luceAdScriptForAdpushup = 'https://s.lucead.com/prebid/1138175580.js'; + adpUtils.injectHeadCodeOnPage(luceAdScriptForAdpushup); + } catch (err) { + adpUtils.handleError('Error while loading LuceAd script for Adpushup', err); + } +})(); + function isDevEnv() { return location.hash.includes('prebid-dev'); } diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 22f40ca69e6..095734ba78a 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -27,7 +27,7 @@ import {getUserSyncParams} from '../libraries/userSyncUtils/userSyncUtils.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest */ - +const FORCE_MULTIFORMAT = true; const DEFAULT_INTEGRATION = 'pbjs_lite'; const DEFAULT_PBS_INTEGRATION = 'pbjs'; const DEFAULT_RENDERER_URL = 'https://video-outstream.rubiconproject.com/apex-2.2.1.js'; @@ -309,7 +309,7 @@ export const spec = { // if it contains the video param and the Video mediaType, send Video to PBS (not native!) (video && mediaTypes.includes(VIDEO)) || // if bidonmultiformat is on, send everything to PBS - (bidonmultiformat && (mediaTypes.includes(VIDEO) || mediaTypes.includes(NATIVE))) + ((FORCE_MULTIFORMAT || bidonmultiformat) && (mediaTypes.includes(VIDEO) || mediaTypes.includes(NATIVE))) ) }); @@ -334,7 +334,7 @@ export const spec = { // if it's just banner (mediaTypes.length === 1) || // if bidonmultiformat is true - bidonmultiformat || + FORCE_MULTIFORMAT || bidonmultiformat || // if bidonmultiformat is false and there's no video parameter (!bidonmultiformat && !video) || // if there's video parameter, but there's no video mediatype @@ -494,7 +494,7 @@ export const spec = { 'zone_id': params.zoneId, 'size_id': parsedSizes[0], 'alt_size_ids': parsedSizes.slice(1).join(',') || undefined, - 'rp_floor': (params.floor = parseFloat(params.floor)) >= 0.01 ? params.floor : undefined, + 'rp_floor': (parseFloat(params.floor)) >= 0.01 ? params.floor : undefined, 'rp_secure': '1', 'tk_flint': `${rubiConf.int_type || DEFAULT_INTEGRATION}_v$prebid.version$`, 'x_source.tid': bidderRequest.ortb2?.source?.tid, @@ -1113,7 +1113,7 @@ export function classifiedAsVideo(bidRequest) { // Given this legacy implementation, other code depends on params.video being defined // if it's bidonmultiformat, we don't care of the video object - if (isVideo && isBidOnMultiformat) return true; + if (isVideo && (FORCE_MULTIFORMAT || isBidOnMultiformat)) return true; if (isBanner && isMissingVideoParams) { isVideo = false; diff --git a/modules/sharethroughBidAdapter.js b/modules/sharethroughBidAdapter.js index 7144370dc9c..3738aaa53de 100644 --- a/modules/sharethroughBidAdapter.js +++ b/modules/sharethroughBidAdapter.js @@ -112,59 +112,62 @@ export const sharethroughAdapterSpec = { const gpid = deepAccess(bidReq, 'ortb2Imp.ext.gpid') || deepAccess(bidReq, 'ortb2Imp.ext.data.pbadslot'); if (gpid) impression.ext.gpid = gpid; - const videoRequest = deepAccess(bidReq, 'mediaTypes.video'); + // Disabling Outstream request temporarily + const bannerRequest = deepAccess(bidReq, 'mediaTypes.banner'); + // const videoRequest = deepAccess(bidReq, 'mediaTypes.video'); if (bidderRequest.paapi?.enabled && bidReq.mediaTypes.banner) { mergeDeep(impression, { ext: { ae: 1 } }); // ae = auction environment; if this is 1, ad server knows we have a fledge auction } - if (videoRequest) { - // default playerSize, only change this if we know width and height are properly defined in the request - let [w, h] = [640, 360]; - if ( - videoRequest.playerSize && - videoRequest.playerSize[0] && - videoRequest.playerSize[0][0] && - videoRequest.playerSize[0][1] - ) { - [w, h] = videoRequest.playerSize[0]; - } - - /** - * 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, - w, - h, - }; - - 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 { + // if (videoRequest) { + // // default playerSize, only change this if we know width and height are properly defined in the request + // let [w, h] = [640, 360]; + // if ( + // videoRequest.playerSize && + // videoRequest.playerSize[0] && + // videoRequest.playerSize[0][0] && + // videoRequest.playerSize[0][1] + // ) { + // [w, h] = videoRequest.playerSize[0]; + // } + + // /** + // * 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, + // w, + // h, + // }; + + // 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 { + if (bannerRequest) { impression.banner = { pos: deepAccess(bidReq, 'mediaTypes.banner.pos', 0), topframe: inIframe() ? 0 : 1, diff --git a/modules/ssp_genieeBidAdapter.js b/modules/ssp_genieeBidAdapter.js index 49afcaec033..faee8d1de57 100644 --- a/modules/ssp_genieeBidAdapter.js +++ b/modules/ssp_genieeBidAdapter.js @@ -15,6 +15,7 @@ import { config } from '../src/config.js'; const BIDDER_CODE = 'ssp_geniee'; export const BANNER_ENDPOINT = 'https://aladdin.genieesspv.jp/yie/ld/api/ad_call/v2'; +export const USER_SYNC_ENDPOINT = 'https://cs.gssprt.jp/yie/ld/mcs'; // export const ENDPOINT_USERSYNC = ''; const SUPPORTED_MEDIA_TYPES = [ BANNER ]; const DEFAULT_CURRENCY = 'JPY'; @@ -414,15 +415,36 @@ export const spec = { }, getUserSyncs: function (syncOptions, serverResponses) { const syncs = []; + if (!syncOptions.iframeEnabled && !syncOptions.pixelEnabled) { + return syncs; + } + + serverResponses.forEach((serverResponse) => { + if (!serverResponse || !serverResponse.body) { + return; + } + + const values = Object.values(serverResponse.body); + if (!values.length || !values[0]) { + return; + } - // if we need user sync, we add this part after preparing the endpoint - /* if (syncOptions.pixelEnabled) { + const bid = values[0]; + const decodedAdm = decodeURIComponent(bid.adm) + // admの中にはhttps:\/\/cs.gssprt.jp\/yie\/ld\/mcs?ver=1&dspid=lamp&format=gif&vid=1\"のような文字列があるので、ここからクエリを抜き出す + const reg = new RegExp('https:\\\\/\\\\/cs.gssprt.jp\\\\/yie\\\\/ld\\\\/mcs\\?([^\\\\"]+)\\\\"', 'g'); + const csQuery = Array.from(decodedAdm.matchAll(reg), (match) => match[1]); + if (!csQuery.length) { + return; + } + + csQuery.forEach((query) => { syncs.push({ - type: 'image', - url: ENDPOINT_USERSYNC + type: syncOptions.pixelEnabled ? 'image' : 'iframe', + url: USER_SYNC_ENDPOINT + '?' + query }); - } */ - + }); + }); return syncs; }, onTimeout: function (timeoutData) {}, diff --git a/package.json b/package.json index 9c4a83ac455..4df2704b1c5 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "header bidding", "prebid" ], - "globalVarName": "pbjs", + "globalVarName": "_apPbJs", "defineGlobal": true, "author": "The prebid.js contributors", "license": "Apache-2.0", diff --git a/src/adRendering.js b/src/adRendering.js index 45a6d64b664..55d49bbefed 100644 --- a/src/adRendering.js +++ b/src/adRendering.js @@ -272,6 +272,14 @@ export function renderAdDirect(doc, adId, options) { const messageHandler = creativeMessageHandler({resizeFn}); function renderFn(adData) { if (adData.ad) { + /* eslint-disable */ + if ( + adData.ad.includes("display-renderer/sdk.js") || + adData.ad.includes("native-to-display/sdk.js") + ) { + doc.write(``); + } + /* eslint-enable */ doc.write(adData.ad); doc.close(); emitAdRenderSucceeded({doc, bid, id: bid.adId});