|
| 1 | +import { BANNER, NATIVE } from '../src/mediaTypes.js'; |
| 2 | +import { createTrackPixelHtml, inIframe } from '../src/utils.js'; |
| 3 | +import { registerBidder } from '../src/adapters/bidderFactory.js'; |
| 4 | +import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; |
| 5 | + |
| 6 | +const BIDDER_CODE = 'condorx'; |
| 7 | +const API_URL = 'https://api.condorx.io/cxb/get.json'; |
| 8 | +const REQUEST_METHOD = 'GET'; |
| 9 | +const MAX_SIZE_DEVIATION = 0.05; |
| 10 | +const SUPPORTED_AD_SIZES = [ |
| 11 | + [100, 100], [200, 200], [300, 250], [400, 200], [300, 200], [600, 600], [650, 1168], [236, 202], [1080, 1920], [300, 374] |
| 12 | +]; |
| 13 | + |
| 14 | +function getBidRequestUrl(bidRequest, bidderRequest) { |
| 15 | + if (bidRequest.params.url && bidRequest.params.url !== 'current url') { |
| 16 | + return bidRequest.params.url; |
| 17 | + } |
| 18 | + if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.page) { |
| 19 | + return bidderRequest.refererInfo.page; |
| 20 | + } |
| 21 | + const pageUrl = inIframe() && document.referrer ? document.referrer : window.location.href; |
| 22 | + return encodeURIComponent(pageUrl); |
| 23 | +} |
| 24 | + |
| 25 | +function getTileImageUrl(tile) { |
| 26 | + return tile.imageUrl.indexOf('http') === -1 ? 'https:' + tile.imageUrl : tile.imageUrl; |
| 27 | +} |
| 28 | + |
| 29 | +function collectImpressionTrackers(tile, response) { |
| 30 | + const trackers = [response.widgetViewPixel]; |
| 31 | + if (!tile.trackers) return trackers; |
| 32 | + const impressionTrackers = tile.trackers.impressionPixels || []; |
| 33 | + const viewTrackers = tile.trackers.viewPixels || []; |
| 34 | + return [...impressionTrackers, ...viewTrackers, ...trackers]; |
| 35 | +} |
| 36 | + |
| 37 | +function parseNativeAdResponse(tile, response) { |
| 38 | + return { |
| 39 | + title: tile.title, |
| 40 | + body: '', |
| 41 | + image: { |
| 42 | + url: getTileImageUrl(tile), |
| 43 | + width: response.imageWidth, |
| 44 | + height: response.imageHeight |
| 45 | + }, |
| 46 | + privacyLink: '', |
| 47 | + clickUrl: tile.clickUrl, |
| 48 | + displayUrl: tile.url, |
| 49 | + cta: '', |
| 50 | + sponsoredBy: tile.displayName, |
| 51 | + impressionTrackers: collectImpressionTrackers(tile, response), |
| 52 | + }; |
| 53 | +} |
| 54 | + |
| 55 | +function parseBannerAdResponse(tile, response) { |
| 56 | + if (tile.tag) { |
| 57 | + return tile.tag; |
| 58 | + } |
| 59 | + let style = ''; |
| 60 | + try { |
| 61 | + const config = JSON.parse(response.widget.config); |
| 62 | + const css = config.css || ''; |
| 63 | + style = css ? `<style>${css}</style>` : ''; |
| 64 | + } catch (e) { |
| 65 | + style = ''; |
| 66 | + } |
| 67 | + const title = tile.title && tile.title.trim() ? `<div class="__condorx_banner_title" style="display: none">${tile.title}</div>` : ''; |
| 68 | + const displayName = tile.displayName && title ? `<div class="__condorx_banner_branding" style="display: none">${tile.displayName}</div>` : ''; |
| 69 | + const trackers = collectImpressionTrackers(tile, response) |
| 70 | + .map((url) => createTrackPixelHtml(url)) |
| 71 | + .join(''); |
| 72 | + return `<html><body>${style}<div id="__CONDORX__BANNER"><a href="${tile.clickUrl}" target=_blank><img class="__condorx_banner_image" src="${getTileImageUrl(tile)}" style="width:${response.imageWidth}px;height:${response.imageHeight}px;" alt="${tile.title}"/>${displayName}${title}</a>${trackers}</div></body></html>`; |
| 73 | +} |
| 74 | + |
| 75 | +function getAdSize(bidRequest) { |
| 76 | + if (bidRequest.sizes && bidRequest.sizes.length > 0) { |
| 77 | + return bidRequest.sizes[0]; |
| 78 | + } else if (bidRequest.nativeParams && bidRequest.nativeParams.image && bidRequest.nativeParams.image.sizes) { |
| 79 | + return bidRequest.nativeParams.image.sizes; |
| 80 | + } |
| 81 | + return [-1, -1]; |
| 82 | +} |
| 83 | + |
| 84 | +function isValidAdSize([width, height]) { |
| 85 | + if (!width || !height) { |
| 86 | + return false; |
| 87 | + } |
| 88 | + return SUPPORTED_AD_SIZES.some(([supportedWidth, supportedHeight]) => { |
| 89 | + if (supportedWidth === width && supportedHeight === height) { |
| 90 | + return true; |
| 91 | + } |
| 92 | + const supportedRatio = supportedWidth / supportedHeight; |
| 93 | + const ratioDeviation = supportedRatio / width * height; |
| 94 | + return Math.abs(ratioDeviation - 1) <= MAX_SIZE_DEVIATION && (supportedWidth > width || (width - supportedWidth) / width <= MAX_SIZE_DEVIATION); |
| 95 | + }); |
| 96 | +} |
| 97 | + |
| 98 | +export const bidderSpec = { |
| 99 | + code: BIDDER_CODE, |
| 100 | + supportedMediaTypes: [BANNER, NATIVE], |
| 101 | + |
| 102 | + isBidRequestValid: function (bidRequest) { |
| 103 | + return bidRequest && |
| 104 | + bidRequest.params && |
| 105 | + bidRequest.params.hasOwnProperty('widget') && |
| 106 | + bidRequest.params.hasOwnProperty('website') && |
| 107 | + !isNaN(bidRequest.params.widget) && |
| 108 | + !isNaN(bidRequest.params.website) && |
| 109 | + isValidAdSize(getAdSize(bidRequest)); |
| 110 | + }, |
| 111 | + |
| 112 | + buildRequests: function (validBidRequests, bidderRequest) { |
| 113 | + validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); |
| 114 | + |
| 115 | + if (!validBidRequests) { |
| 116 | + return []; |
| 117 | + } |
| 118 | + return validBidRequests.map(bidRequest => { |
| 119 | + if (bidRequest.params) { |
| 120 | + const mediaType = bidRequest.hasOwnProperty('nativeParams') ? 1 : 2; |
| 121 | + const [imageWidth, imageHeight] = getAdSize(bidRequest); |
| 122 | + const widgetId = bidRequest.params.widget; |
| 123 | + const websiteId = bidRequest.params.website; |
| 124 | + const pageUrl = getBidRequestUrl(bidRequest, bidderRequest); |
| 125 | + const bidId = bidRequest.bidId; |
| 126 | + let apiUrl = `${API_URL}?w=${websiteId}&wg=${widgetId}&u=${pageUrl}&p=0&ireqid=${bidId}&prebid=${mediaType}&imgw=${imageWidth}&imgh=${imageHeight}`; |
| 127 | + if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprApplies && bidderRequest.consentString) { |
| 128 | + apiUrl += `&g=1&gc=${bidderRequest.consentString}`; |
| 129 | + } |
| 130 | + return { |
| 131 | + url: apiUrl, |
| 132 | + method: REQUEST_METHOD, |
| 133 | + data: '' |
| 134 | + }; |
| 135 | + } |
| 136 | + }).filter(Boolean); |
| 137 | + }, |
| 138 | + |
| 139 | + interpretResponse: function (serverResponse, bidRequest) { |
| 140 | + if (!serverResponse.body || !serverResponse.body.tiles || !serverResponse.body.tiles.length) { |
| 141 | + return []; |
| 142 | + } |
| 143 | + const response = serverResponse.body; |
| 144 | + const isNative = response.pbtypeId === 1; |
| 145 | + return response.tiles.map(tile => { |
| 146 | + let bid = { |
| 147 | + requestId: response.ireqId, |
| 148 | + width: response.imageWidth, |
| 149 | + height: response.imageHeight, |
| 150 | + creativeId: tile.postId, |
| 151 | + cpm: tile.pecpm || (tile.ecpm / 100), |
| 152 | + currency: 'USD', |
| 153 | + netRevenue: !!tile.pecpm, |
| 154 | + ttl: 360, |
| 155 | + meta: { advertiserDomains: tile.domain ? [tile.domain] : [] }, |
| 156 | + }; |
| 157 | + if (isNative) { |
| 158 | + bid.native = parseNativeAdResponse(tile, response); |
| 159 | + } else { |
| 160 | + bid.ad = parseBannerAdResponse(tile, response); |
| 161 | + } |
| 162 | + return bid; |
| 163 | + }); |
| 164 | + } |
| 165 | +}; |
| 166 | + |
| 167 | +registerBidder(bidderSpec); |
0 commit comments