prebid/Prebid.js

View on GitHub
modules/aniviewBidAdapter.js

Summary

Maintainability
F
5 days
Test Coverage
import { VIDEO, BANNER } from '../src/mediaTypes.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { Renderer } from '../src/Renderer.js';
import { logError } from '../src/utils.js';

const BIDDER_CODE = 'aniview';
const GVLID = 780;
const TTL = 600;

function avRenderer(bid) {
  bid.renderer.push(function() {
    let eventCallback = bid && bid.renderer && bid.renderer.handleVideoEvent ? bid.renderer.handleVideoEvent : null;
    window.aniviewRenderer.renderAd({
      id: bid.adUnitCode + '_' + bid.adId,
      debug: window.location.href.indexOf('pbjsDebug') >= 0,
      placement: bid.adUnitCode,
      width: bid.width,
      height: bid.height,
      vastUrl: bid.vastUrl,
      vastXml: bid.vastXml,
      config: bid.params[0].rendererConfig,
      eventsCallback: eventCallback,
      bid: bid
    });
  });
}

function newRenderer(bidRequest) {
  let playerDomain = 'player.aniview.com';
  const config = {};

  if (bidRequest && bidRequest.bidRequest && bidRequest.bidRequest.params) {
    const params = bidRequest.bidRequest.params

    if (params.playerDomain) {
      playerDomain = params.playerDomain;
    }

    if (params.AV_PUBLISHERID) {
      config.AV_PUBLISHERID = params.AV_PUBLISHERID;
    }

    if (params.AV_CHANNELID) {
      config.AV_CHANNELID = params.AV_CHANNELID;
    }
  }

  const renderer = Renderer.install({
    url: 'https://' + playerDomain + '/script/6.1/prebidRenderer.js',
    config: config,
    loaded: false,
  });

  try {
    renderer.setRender(avRenderer);
  } catch (err) {
  }

  return renderer;
}

function isBidRequestValid(bid) {
  if (!bid.params || !bid.params.AV_PUBLISHERID || !bid.params.AV_CHANNELID) { return false; }

  return true;
}
let irc = 0;
function buildRequests(validBidRequests, bidderRequest) {
  let bidRequests = [];

  for (let i = 0; i < validBidRequests.length; i++) {
    let bidRequest = validBidRequests[i];
    var sizes = [[640, 480]];

    if (bidRequest.mediaTypes && bidRequest.mediaTypes.video && bidRequest.mediaTypes.video.playerSize) {
      sizes = bidRequest.mediaTypes.video.playerSize;
    } else {
      if (bidRequest.sizes) {
        sizes = bidRequest.sizes;
      }
    }
    if (sizes.length === 2 && typeof sizes[0] === 'number') {
      sizes = [[sizes[0], sizes[1]]];
    }

    for (let j = 0; j < sizes.length; j++) {
      let size = sizes[j];
      let playerWidth;
      let playerHeight;

      if (size && size.length == 2) {
        playerWidth = size[0];
        playerHeight = size[1];
      } else {
        playerWidth = 640;
        playerHeight = 480;
      }

      let s2sParams = {};

      for (var attrname in bidRequest.params) {
        if (bidRequest.params.hasOwnProperty(attrname) && attrname.indexOf('AV_') == 0) {
          s2sParams[attrname] = bidRequest.params[attrname];
        }
      };

      if (s2sParams.AV_APPPKGNAME && !s2sParams.AV_URL) { s2sParams.AV_URL = s2sParams.AV_APPPKGNAME; }
      if (!s2sParams.AV_IDFA && !s2sParams.AV_URL) {
        // TODO: does it make sense to fall back to window.location here?
        s2sParams.AV_URL = bidderRequest?.refererInfo?.page || window.location.href;
      }
      if (s2sParams.AV_IDFA && !s2sParams.AV_AID) { s2sParams.AV_AID = s2sParams.AV_IDFA; }
      if (s2sParams.AV_AID && !s2sParams.AV_IDFA) { s2sParams.AV_IDFA = s2sParams.AV_AID; }

      s2sParams.cb = Math.floor(Math.random() * 999999999);
      s2sParams.AV_WIDTH = playerWidth;
      s2sParams.AV_HEIGHT = playerHeight;
      s2sParams.bidWidth = playerWidth;
      s2sParams.bidHeight = playerHeight;
      s2sParams.bidId = bidRequest.bidId;
      s2sParams.pbjs = 1;
      s2sParams.tgt = 10;
      s2sParams.s2s = '1';
      s2sParams.irc = irc;
      irc++;
      s2sParams.wpm = 1;

      if (bidderRequest && bidderRequest.gdprConsent) {
        if (bidderRequest.gdprConsent.gdprApplies) {
          s2sParams.AV_GDPR = 1;
          s2sParams.AV_CONSENT = bidderRequest.gdprConsent.consentString;
        }
      }
      if (bidderRequest && bidderRequest.uspConsent) {
        s2sParams.AV_CCPA = bidderRequest.uspConsent;
      }

      let serverDomain = bidRequest.params && bidRequest.params.serverDomain ? bidRequest.params.serverDomain : 'gov.aniview.com';
      let servingUrl = 'https://' + serverDomain + '/api/adserver/vast3/';

      bidRequests.push({
        method: 'GET',
        url: servingUrl,
        data: s2sParams,
        bidRequest
      });
    }
  }

  return bidRequests;
}
function getCpmData(xml) {
  let ret = {cpm: 0, currency: 'USD'};
  if (xml) {
    let ext = xml.getElementsByTagName('Extensions');
    if (ext && ext.length > 0) {
      ext = ext[0].getElementsByTagName('Extension');
      if (ext && ext.length > 0) {
        for (var i = 0; i < ext.length; i++) {
          if (ext[i].getAttribute('type') == 'ANIVIEW') {
            let price = ext[i].getElementsByTagName('Cpm');
            if (price && price.length == 1) {
              ret.cpm = price[0].textContent;
            }
            break;
          }
        }
      }
    }
  }
  return ret;
}
function buildBanner(xmlStr, bidRequest, bidResponse) {
  var rendererData = JSON.stringify({
    id: bidRequest.adUnitCode,
    debug: window.location.href.indexOf('pbjsDebug') >= 0,
    placement: bidRequest.bidRequest.adUnitCode,
    width: bidResponse.width,
    height: bidResponse.height,
    vastXml: xmlStr,
    bid: bidResponse,
    config: bidRequest.bidRequest.params.rendererConfig
  });
  var playerDomain = bidRequest.bidRequest.params.playerDomain || 'player.aniview.com';
  var ad = '<script src="https://' + playerDomain + '/script/6.1/prebidRenderer.js"></script>';
  ad += '<script> window.aniviewRenderer.renderAd(' + rendererData + ') </script>'
  return ad;
}
function interpretResponse(serverResponse, bidRequest) {
  let bidResponses = [];
  if (serverResponse && serverResponse.body) {
    if (serverResponse.error) {
      return bidResponses;
    } else {
      try {
        let bidResponse = {};
        if (bidRequest && bidRequest.data && bidRequest.data.bidId && bidRequest.data.bidId !== '') {
          let mediaType = VIDEO;
          if (bidRequest.bidRequest && bidRequest.bidRequest.mediaTypes && !bidRequest.bidRequest.mediaTypes[VIDEO]) {
            mediaType = BANNER;
          }
          let xmlStr = serverResponse.body;
          let xml = new window.DOMParser().parseFromString(xmlStr, 'text/xml');
          if (xml && xml.getElementsByTagName('parsererror').length == 0) {
            let cpmData = getCpmData(xml);
            if (cpmData.cpm > 0) {
              bidResponse.requestId = bidRequest.data.bidId;
              bidResponse.ad = '';
              bidResponse.cpm = cpmData.cpm;
              bidResponse.width = bidRequest.data.AV_WIDTH;
              bidResponse.height = bidRequest.data.AV_HEIGHT;
              bidResponse.ttl = TTL;
              bidResponse.creativeId = xml.getElementsByTagName('Ad') && xml.getElementsByTagName('Ad')[0] && xml.getElementsByTagName('Ad')[0].getAttribute('id') ? xml.getElementsByTagName('Ad')[0].getAttribute('id') : 'creativeId';
              bidResponse.currency = cpmData.currency;
              bidResponse.netRevenue = true;
              bidResponse.mediaType = mediaType;
              if (mediaType === VIDEO) {
                try {
                  var blob = new Blob([xmlStr], {
                    type: 'application/xml'
                  });
                  bidResponse.vastUrl = window.URL.createObjectURL(blob);
                } catch (ex) {
                  logError('Aniview Debug create vastXml error:\n\n' + ex);
                }
                bidResponse.vastXml = xmlStr;
                if (bidRequest.bidRequest && bidRequest.bidRequest.mediaTypes && bidRequest.bidRequest.mediaTypes.video && bidRequest.bidRequest.mediaTypes.video.context === 'outstream') {
                  bidResponse.renderer = newRenderer(bidRequest);
                }
              } else {
                bidResponse.ad = buildBanner(xmlStr, bidRequest, bidResponse);
              }
              bidResponse.meta = {
                advertiserDomains: []
              };

              bidResponses.push(bidResponse);
            }
          } else {}
        } else {}
      } catch (e) {}
    }
  } else {}

  return bidResponses;
}

function getSyncData(xml, options) {
  let ret = [];
  if (xml) {
    let ext = xml.getElementsByTagName('Extensions');
    if (ext && ext.length > 0) {
      ext = ext[0].getElementsByTagName('Extension');
      if (ext && ext.length > 0) {
        for (var i = 0; i < ext.length; i++) {
          if (ext[i].getAttribute('type') == 'ANIVIEW') {
            let syncs = ext[i].getElementsByTagName('AdServingSync');
            if (syncs && syncs.length == 1) {
              try {
                let data = JSON.parse(syncs[0].textContent);
                if (data && data.trackers && data.trackers.length) {
                  data = data.trackers;
                  for (var j = 0; j < data.length; j++) {
                    if (typeof data[j] === 'object' &&
                      typeof data[j].url === 'string' &&
                      (data[j].e === 'inventory' || data[j].e === 'sync')
                    ) {
                      if (data[j].t == 1 && options.pixelEnabled) {
                        ret.push({url: data[j].url, type: 'image'});
                      } else {
                        if (data[j].t == 3 && options.iframeEnabled) {
                          ret.push({url: data[j].url, type: 'iframe'});
                        }
                      }
                    }
                  }
                }
              } catch (e) {}
            }
            break;
          }
        }
      }
    }
  }
  return ret;
}

function getUserSyncs(syncOptions, serverResponses) {
  if (serverResponses && serverResponses[0] && serverResponses[0].body) {
    if (serverResponses.error) {
      return [];
    } else {
      try {
        let xmlStr = serverResponses[0].body;
        let xml = new window.DOMParser().parseFromString(xmlStr, 'text/xml');
        if (xml && xml.getElementsByTagName('parsererror').length == 0) {
          let syncData = getSyncData(xml, syncOptions);
          return syncData;
        }
      } catch (e) {}
    }
  }
}

export const spec = {
  code: BIDDER_CODE,
  gvlid: GVLID,
  aliases: ['avantisvideo', 'selectmediavideo', 'vidcrunch', 'openwebvideo', 'didnavideo', 'ottadvisors', 'pgammedia'],
  supportedMediaTypes: [VIDEO, BANNER],
  isBidRequestValid,
  buildRequests,
  interpretResponse,
  getUserSyncs
};

registerBidder(spec);