From 3fb7ffbe09b68873567b004a70f504ae52c60299 Mon Sep 17 00:00:00 2001 From: "monis.q" Date: Fri, 10 Jul 2020 17:02:49 +0530 Subject: [PATCH] add support instream video ads for medianetAnalyticsAdapter --- modules/dfpAdServerVideo.js | 6 ++- modules/medianetAnalyticsAdapter.js | 66 ++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index 71a8471d5549..98039799a499 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -8,6 +8,8 @@ import { deepAccess, isEmpty, logError, parseSizesInput, formatQS, parseUrl, bui import { config } from '../src/config.js'; import { getHook, submodule } from '../src/hook.js'; import { auctionManager } from '../src/auctionManager.js'; +import events from '../src/events.js'; +import CONSTANTS from '../src/constants.json'; /** * @typedef {Object} DfpVideoParams @@ -253,8 +255,10 @@ function getCustParams(bid, options) { { hb_cache_id: bid && bid.videoCacheKey }, allTargetingData, adserverTargeting, - optCustParams, ); + + events.emit(CONSTANTS.EVENTS.SET_TARGETING, {[adUnit.code]: customParams}); + customParams = Object.assign(customParams, optCustParams) return encodeURIComponent(formatQS(customParams)); } diff --git a/modules/medianetAnalyticsAdapter.js b/modules/medianetAnalyticsAdapter.js index 849954fa072c..dfc6127f651d 100644 --- a/modules/medianetAnalyticsAdapter.js +++ b/modules/medianetAnalyticsAdapter.js @@ -2,6 +2,8 @@ import adapter from '../src/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import CONSTANTS from '../src/constants.json'; import * as utils from '../src/utils.js'; +import { OUTSTREAM } from '../src/video.js'; +import { VIDEO } from '../src/mediaTypes.js'; import { ajax } from '../src/ajax.js'; import { getRefererInfo } from '../src/refererDetection.js'; import { getPriceGranularity, AUCTION_IN_PROGRESS, AUCTION_COMPLETED } from '../src/auction.js' @@ -353,6 +355,64 @@ class Auction { } } +/** + * Here the idea is + * find all network entries via performance.getEntriesByType() + * filter it by video cache key in the url + * and exclude the ad server urls so that we dont match twice + * eg: + * dfp ads call: https://securepubads.g.doubleclick.net/gampad/ads?...hb_cache_id%3D55e85cd3-6ea4-4469-b890-84241816b131%26... + * prebid cache url: https://prebid.adnxs.com/pbc/v1/cache?uuid=55e85cd3-6ea4-4469-b890-84241816b131 + * + * if the entry exists, emit the BID_WON + */ +function findRenderedVideoImpressions(auction) { + // filter for video bids + const videoBids = auction.bids.filter(bid => bid.mediaType === VIDEO && bid.context !== OUTSTREAM && bid.videoCacheKey) + // check if performance api is available + if (!videoBids.length || !window.performance || !window.performance.getEntriesByType) { + return; + } + const timeLimit = 15 * 1000 * 60; + const start = Date.now(); + const bidWonMap = {}; + + let lastRead = 0; + + function poll() { + // get network entries using the last read offset + const entries = window.performance.getEntriesByType('resource').splice(lastRead); + for (const res of entries) { + const url = res.name; + videoBids.forEach((bid) => { + // match the video cache key excluding ad server call + const matches = !url.includes(CONSTANTS.TARGETING_KEYS.CACHE_ID) && url.includes(bid.videoCacheKey); + if (matches && !bidWonMap[bid.bidId]) { + // video found + bidWonMap[bid.bidId] = bid; + bid.requestId = bid.bidId; + bid.auctionId = auction.acid; + bid.adUnitCode = bid.supplyAdCode; + // log BID_WON + bidWonHandler(bid); + } + }); + } + // update offset + lastRead += entries.length; + + const lastCheckedDiff = Date.now() - start; + if (lastCheckedDiff < timeLimit && Object.keys(bidWonMap).length < auction.adSlots.length) { + setTimeout(poll, 2e3); + } + } + + // start polling for network entries + setTimeout(poll, 2e3); +} + +// --------------------- event handlers --------------------- + function auctionInitHandler({auctionId, timestamp}) { if (auctionId && auctions[auctionId] === undefined) { auctions[auctionId] = new Auction(auctionId); @@ -386,6 +446,7 @@ function bidRequestedHandler({ auctionId, auctionStart, bids, start, timeout, us ); } let bidObj = new Bid(bidId, bidder, src, start, adUnitCode); + bidObj.context = utils.deepAccess(mediaTypes, `${VIDEO}.context`) auctions[auctionId].addBid(bidObj); if (bidder === MEDIANET_BIDDER_CODE) { bidObj.crid = utils.deepAccess(bid, 'params.crid'); @@ -397,7 +458,7 @@ function bidRequestedHandler({ auctionId, auctionStart, bids, start, timeout, us function bidResponseHandler(bid) { const { width, height, mediaType, cpm, requestId, timeToRespond, auctionId, dealId } = bid; - const {originalCpm, bidderCode, creativeId, adId, currency} = bid; + const { originalCpm, bidderCode, creativeId, adId, currency, videoCacheKey } = bid; if (!(auctions[auctionId] instanceof Auction)) { return; @@ -409,7 +470,7 @@ function bidResponseHandler(bid) { Object.assign( bidObj, { cpm, width, height, mediaType, timeToRespond, dealId, creativeId }, - { adId, currency } + { adId, currency, videoCacheKey } ); bidObj.originalCpm = originalCpm || cpm; let dfpbd = utils.deepAccess(bid, 'adserverTargeting.hb_pb'); @@ -464,6 +525,7 @@ function auctionEndHandler({ auctionId, auctionEnd }) { } auctions[auctionId].status = AUCTION_COMPLETED; auctions[auctionId].auctionEndTime = auctionEnd; + findRenderedVideoImpressions(auctions[auctionId]); } function setTargetingHandler(params) {