diff --git a/modules/oneVideoBidAdapter.js b/modules/oneVideoBidAdapter.js
new file mode 100644
index 00000000000..c56669b8b0c
--- /dev/null
+++ b/modules/oneVideoBidAdapter.js
@@ -0,0 +1,189 @@
+import * as utils from 'src/utils';
+import {registerBidder} from 'src/adapters/bidderFactory';
+const BIDDER_CODE = 'oneVideo';
+export const spec = {
+ code: 'oneVideo',
+ ENDPOINT: '//ads.adaptv.advertising.com/rtb/openrtb?ext_id=',
+ SYNC_ENDPOINT1: 'https://cm.g.doubleclick.net/pixel?google_nid=adaptv_dbm&google_cm&google_sc',
+ SYNC_ENDPOINT2: 'https://pr-bh.ybp.yahoo.com/sync/adaptv_ortb/{combo_uid}',
+ SYNC_ENDPOINT3: 'https://sync-tm.everesttech.net/upi/pid/m7y5t93k?redir=https%3A%2F%2Fsync.adap.tv%2Fsync%3Ftype%3Dgif%26key%3Dtubemogul%26uid%3D%24%7BUSER_ID%7D',
+ SYNC_ENDPOINT4: 'https://match.adsrvr.org/track/cmf/generic?ttd_pid=adaptv&ttd_tpi=1',
+ supportedMediaTypes: ['video'],
+ /**
+ * Determines whether or not the given bid request is valid.
+ *
+ * @param {BidRequest} bid The bid params to validate.
+ * @return boolean True if this is a valid bid, and false otherwise.
+ */
+ isBidRequestValid: function(bid) {
+ if (bid.bidder !== BIDDER_CODE || typeof bid.params === 'undefined') {
+ return false;
+ }
+
+ // Video validations
+ if (typeof bid.params.video === 'undefined' || typeof bid.params.video.playerWidth === 'undefined' || typeof bid.params.video.playerHeight == 'undefined' || typeof bid.params.video.mimes == 'undefined') {
+ return false;
+ }
+
+ // Pub Id validation
+ if (typeof bid.params.pubId === 'undefined') {
+ return false;
+ }
+
+ return true;
+ },
+ /**
+ * Make a server request from the list of BidRequests.
+ *
+ * @param {validBidRequests[]} - an array of bids
+ * @return ServerRequest Info describing the request to the server.
+ */
+ buildRequests: function(bids) {
+ return bids.map(bid => {
+ return {
+ method: 'POST',
+ url: location.protocol + spec.ENDPOINT + bid.params.pubId,
+ data: getRequestData(bid),
+ options: {contentType: 'application/json'},
+ bidRequest: bid
+ }
+ })
+ },
+ /**
+ * Unpack the response from the server into a list of bids.
+ *
+ * @param {*} serverResponse A successful response from the server.
+ * @return {Bid[]} An array of bids which were nested inside the server.
+ */
+ interpretResponse: function(response, { bidRequest }) {
+ let bid;
+ let size;
+ let bidResponse;
+ try {
+ response = response.body;
+ bid = response.seatbid[0].bid[0];
+ } catch (e) {
+ response = null;
+ }
+ if (!response || !bid || (!bid.adm && !bid.nurl) || !bid.price) {
+ utils.logWarn(`No valid bids from ${spec.code} bidder`);
+ return [];
+ }
+ size = getSize(bidRequest.sizes);
+ bidResponse = {
+ requestId: bidRequest.bidId,
+ bidderCode: spec.code,
+ cpm: bid.price,
+ creativeId: bid.id,
+ width: size.width,
+ height: size.height,
+ mediaType: 'video',
+ currency: response.cur,
+ ttl: 100,
+ netRevenue: true
+ };
+ if (bid.nurl) {
+ bidResponse.vastUrl = bid.nurl;
+ } else if (bid.adm) {
+ bidResponse.vastXml = bid.adm;
+ }
+ return bidResponse;
+ },
+ /**
+ * Register the user sync pixels which should be dropped after the auction.
+ *
+ * @param {SyncOptions} syncOptions Which user syncs are allowed?
+ * @param {ServerResponse[]} serverResponses List of server's responses.
+ * @return {UserSync[]} The user syncs which should be dropped.
+ */
+ getUserSyncs: function(syncOptions) {
+ if (syncOptions.pixelEnabled) {
+ return [{
+ type: 'image',
+ url: spec.SYNC_ENDPOINT1
+ },
+ {
+ type: 'image',
+ url: spec.SYNC_ENDPOINT2
+ },
+ {
+ type: 'image',
+ url: spec.SYNC_ENDPOINT3
+ },
+ {
+ type: 'image',
+ url: spec.SYNC_ENDPOINT4
+ }];
+ }
+ }
+};
+
+function getSize(sizes) {
+ let parsedSizes = utils.parseSizesInput(sizes);
+ let [ width, height ] = parsedSizes.length ? parsedSizes[0].split('x') : [];
+ return {
+ width: parseInt(width, 10) || undefined,
+ height: parseInt(height, 10) || undefined
+ };
+}
+
+function getRequestData(bid) {
+ let loc = utils.getTopWindowLocation();
+ let global = (window.top) ? window.top : window;
+ let page = (bid.params.site.page) ? (bid.params.site.page) : (loc.href);
+ let ref = (bid.params.site.referrer) ? bid.params.site.referrer : utils.getTopWindowReferrer();
+ let bidData = {
+ id: utils.generateUUID(),
+ at: 2,
+ cur: bid.cur || 'USD',
+ imp: [{
+ id: '1',
+ secure: isSecure(),
+ bidfloor: bid.params.bidfloor,
+ video: {
+ mimes: bid.params.video.mimes,
+ w: bid.params.video.playerWidth,
+ h: bid.params.video.playerHeight,
+ linearity: 1,
+ protocols: bid.params.video.protocols || [2, 5]
+ }
+ }],
+ site: {
+ page: page,
+ ref: ref
+ },
+ device: {
+ ua: global.navigator.userAgent
+ },
+ tmax: 200
+ };
+
+ if (bid.params.video.maxbitrate) {
+ bidData.imp[0].video.maxbitrate = bid.params.video.maxbitrate
+ }
+ if (bid.params.video.maxduration) {
+ bidData.imp[0].video.maxduration = bid.params.video.maxduration
+ }
+ if (bid.params.video.minduration) {
+ bidData.imp[0].video.minduration = bid.params.video.minduration
+ }
+ if (bid.params.video.api) {
+ bidData.imp[0].video.api = bid.params.video.api
+ }
+ if (bid.params.video.delivery) {
+ bidData.imp[0].video.delivery = bid.params.video.delivery
+ }
+ if (bid.params.video.position) {
+ bidData.imp[0].video.pos = bid.params.video.position
+ }
+ if (bid.params.site.id) {
+ bidData.site.id = bid.params.site.id
+ }
+ return bidData;
+}
+
+function isSecure() {
+ return document.location.protocol === 'https:';
+}
+
+registerBidder(spec);
diff --git a/modules/oneVideoBidAdapter.md b/modules/oneVideoBidAdapter.md
new file mode 100755
index 00000000000..96399221315
--- /dev/null
+++ b/modules/oneVideoBidAdapter.md
@@ -0,0 +1,47 @@
+# Overview
+
+**Module Name**: One Video Bidder Adapter
+**Module Type**: Bidder Adapter
+**Maintainer**: ankur.modi@oath.com
+
+# Description
+
+Connects to One Video demand source to fetch bids.
+
+
+# Test Parameters
+```
+ var adUnits = [
+ {
+ code: 'video1',
+ sizes: [640,480],
+ mediaTypes: {
+ video: {
+ context: "instream"
+ }
+ },
+ bids: [
+ {
+ bidder: 'oneVideo',
+ params: {
+ video: {
+ playerWidth: 480,
+ playerHeight: 640,
+ mimes: ['video/mp4', 'application/javascript'],
+ protocols: [2,5],
+ api: [2],
+ position: 1,
+ delivery: [2]
+ },
+ site: {
+ id: 1,
+ page: 'http://abhi12345.com',
+ referrer: 'http://abhi12345.com'
+ },
+ pubId: 'brxd'
+ }
+ }
+ ]
+ }
+ ];
+```
diff --git a/test/spec/modules/oneVideoBidAdapter_spec.js b/test/spec/modules/oneVideoBidAdapter_spec.js
new file mode 100644
index 00000000000..3d7bba417f9
--- /dev/null
+++ b/test/spec/modules/oneVideoBidAdapter_spec.js
@@ -0,0 +1,135 @@
+import { expect } from 'chai';
+import { spec } from 'modules/oneVideoBidAdapter';
+import * as utils from 'src/utils';
+
+describe('OneVideoBidAdapter', () => {
+ let bidRequest;
+
+ beforeEach(() => {
+ bidRequest = {
+ bidder: 'oneVideo',
+ sizes: [640, 480],
+ bidId: '30b3efwfwe1e',
+ params: {
+ video: {
+ playerWidth: 640,
+ playerHeight: 480,
+ mimes: ['video/mp4', 'application/javascript'],
+ protocols: [2, 5],
+ api: [2],
+ position: 1,
+ delivery: [2]
+ },
+ site: {
+ id: 1,
+ page: 'https://news.yahoo.com/portfolios',
+ referrer: 'http://www.yahoo.com'
+ },
+ pubId: 'brxd'
+ }
+ };
+ });
+
+ describe('spec.isBidRequestValid', () => {
+ it('should return true when the required params are passed', () => {
+ expect(spec.isBidRequestValid(bidRequest)).to.equal(true);
+ });
+
+ it('should return false when the "video" param is missing', () => {
+ bidRequest.params = {
+ pubId: 'brxd'
+ };
+ expect(spec.isBidRequestValid(bidRequest)).to.equal(false);
+ });
+
+ it('should return false when the "pubId" param is missing', () => {
+ bidRequest.params = {
+ video: {
+ playerWidth: 480,
+ playerHeight: 640,
+ mimes: ['video/mp4', 'application/javascript'],
+ protocols: [2, 5],
+ api: [2],
+ position: 1,
+ delivery: [2]
+ }
+ };
+ expect(spec.isBidRequestValid(bidRequest)).to.equal(false);
+ });
+
+ it('should return false when no bid params are passed', () => {
+ bidRequest.params = {};
+ expect(spec.isBidRequestValid(bidRequest)).to.equal(false);
+ });
+ });
+
+ describe('spec.buildRequests', () => {
+ it('should create a POST request for every bid', () => {
+ const requests = spec.buildRequests([ bidRequest ]);
+ expect(requests[0].method).to.equal('POST');
+ expect(requests[0].url).to.equal(location.protocol + spec.ENDPOINT + bidRequest.params.pubId);
+ });
+
+ it('should attach the bid request object', () => {
+ const requests = spec.buildRequests([ bidRequest ]);
+ expect(requests[0].bidRequest).to.equal(bidRequest);
+ });
+
+ it('should attach request data', () => {
+ const requests = spec.buildRequests([ bidRequest ]);
+ const data = requests[0].data;
+ const [ width, height ] = bidRequest.sizes;
+ expect(data.imp[0].video.w).to.equal(width);
+ expect(data.imp[0].video.h).to.equal(height);
+ expect(data.imp[0].bidfloor).to.equal(bidRequest.params.bidfloor);
+ });
+
+ it('must parse bid size from a nested array', () => {
+ const width = 640;
+ const height = 480;
+ bidRequest.sizes = [[ width, height ]];
+ const requests = spec.buildRequests([ bidRequest ]);
+ const data = requests[0].data;
+ expect(data.imp[0].video.w).to.equal(width);
+ expect(data.imp[0].video.h).to.equal(height);
+ });
+ });
+
+ describe('spec.interpretResponse', () => {
+ it('should return no bids if the response is not valid', () => {
+ const bidResponse = spec.interpretResponse({ body: null }, { bidRequest });
+ expect(bidResponse.length).to.equal(0);
+ });
+
+ it('should return no bids if the response "nurl" and "adm" are missing', () => {
+ const serverResponse = {seatbid: [{bid: [{price: 6.01}]}]};
+ const bidResponse = spec.interpretResponse({ body: serverResponse }, { bidRequest });
+ expect(bidResponse.length).to.equal(0);
+ });
+
+ it('should return no bids if the response "price" is missing', () => {
+ const serverResponse = {seatbid: [{bid: [{adm: ''}]}]};
+ const bidResponse = spec.interpretResponse({ body: serverResponse }, { bidRequest });
+ expect(bidResponse.length).to.equal(0);
+ });
+
+ it('should return a valid bid response with just "adm"', () => {
+ const serverResponse = {seatbid: [{bid: [{id: 1, price: 6.01, adm: ''}]}], cur: 'USD'};
+ const bidResponse = spec.interpretResponse({ body: serverResponse }, { bidRequest });
+ let o = {
+ requestId: bidRequest.bidId,
+ bidderCode: spec.code,
+ cpm: serverResponse.seatbid[0].bid[0].price,
+ creativeId: serverResponse.seatbid[0].bid[0].id,
+ vastXml: serverResponse.seatbid[0].bid[0].adm,
+ width: 640,
+ height: 480,
+ mediaType: 'video',
+ currency: 'USD',
+ ttl: 100,
+ netRevenue: true
+ };
+ expect(bidResponse).to.deep.equal(o);
+ });
+ });
+});