From 6eceed8af0690d358238cf41929cc018e7c9f1e7 Mon Sep 17 00:00:00 2001 From: Kevin Siow Date: Wed, 22 May 2024 09:39:48 +0200 Subject: [PATCH 1/7] Dailymotion Bid Adapter: add support for playbackmethod & plcmt --- modules/dailymotionBidAdapter.js | 8 ++-- modules/dailymotionBidAdapter.md | 6 +++ .../modules/dailymotionBidAdapter_spec.js | 44 ++++++++++++------- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js index afded538fd0..90a0cd83a5b 100644 --- a/modules/dailymotionBidAdapter.js +++ b/modules/dailymotionBidAdapter.js @@ -54,14 +54,14 @@ function getVideoMetadata(bidRequest, bidderRequest) { : Object.keys(parsedContentData.iabcat2), id: videoParams.id || deepAccess(contentObj, 'id', ''), lang: videoParams.lang || deepAccess(contentObj, 'language', ''), + livestream: typeof videoParams.livestream === 'number' + ? !!videoParams.livestream + : !!deepAccess(contentObj, 'livestream', 0), private: videoParams.private || false, tags: videoParams.tags || deepAccess(contentObj, 'keywords', ''), title: videoParams.title || deepAccess(contentObj, 'title', ''), topics: videoParams.topics || '', xid: videoParams.xid || '', - livestream: typeof videoParams.livestream === 'number' - ? !!videoParams.livestream - : !!deepAccess(contentObj, 'livestream', 0), }; return videoMetadata; @@ -149,6 +149,8 @@ export const spec = { mimes: bid.mediaTypes?.[VIDEO]?.mimes || [], minduration: bid.mediaTypes?.[VIDEO]?.minduration || 0, maxduration: bid.mediaTypes?.[VIDEO]?.maxduration || 0, + playbackmethod: bid.mediaTypes?.[VIDEO]?.playbackmethod || [], + plcmt: bid.mediaTypes?.[VIDEO]?.plcmt || 1, // Fallback to instream considering logic of `isBidRequestValid` protocols: bid.mediaTypes?.[VIDEO]?.protocols || [], skip: bid.mediaTypes?.[VIDEO]?.skip || 0, skipafter: bid.mediaTypes?.[VIDEO]?.skipafter || 0, diff --git a/modules/dailymotionBidAdapter.md b/modules/dailymotionBidAdapter.md index 7c871b0d536..28372f26806 100644 --- a/modules/dailymotionBidAdapter.md +++ b/modules/dailymotionBidAdapter.md @@ -126,6 +126,12 @@ const adUnits = [ video: { api: [2, 7], context: 'instream', + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + playbackmethod: [3], + plcmt: 1, + protocols: [7, 8, 11, 12, 13, 14] startdelay: 0, w: 1280, h: 720, diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index fe9484b2814..df8298d5036 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -90,6 +90,8 @@ describe('dailymotionBidAdapterTests', () => { mimes: ['video/mp4'], minduration: 5, maxduration: 30, + playbackmethod: [3], + plcmt: 1, protocols: [1, 2, 3, 4, 5, 6, 7, 8], skip: 1, skipafter: 5, @@ -170,9 +172,8 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.coppa).to.be.true; expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); - expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); - expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); - expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + + expect(reqData.request.mediaTypes.video).to.eql(bidRequestData[0].mediaTypes.video); expect(reqData.video_metadata).to.eql({ description: bidRequestData[0].params.video.description, iabcat1: ['IAB-1'], @@ -200,6 +201,8 @@ describe('dailymotionBidAdapterTests', () => { mimes: ['video/mp4'], minduration: 5, maxduration: 30, + playbackmethod: [3], + plcmt: 1, protocols: [1, 2, 3, 4, 5, 6, 7, 8], skip: 1, skipafter: 5, @@ -288,17 +291,9 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.appStoreUrl).to.eql(bidderRequestData.ortb2.app.storeurl); expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); - expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); - expect(reqData.request.mediaTypes.video.mimes).to.eql(bidRequestData[0].mediaTypes.video.mimes); - expect(reqData.request.mediaTypes.video.minduration).to.eql(bidRequestData[0].mediaTypes.video.minduration); - expect(reqData.request.mediaTypes.video.maxduration).to.eql(bidRequestData[0].mediaTypes.video.maxduration); - expect(reqData.request.mediaTypes.video.protocols).to.eql(bidRequestData[0].mediaTypes.video.protocols); - expect(reqData.request.mediaTypes.video.skip).to.eql(bidRequestData[0].mediaTypes.video.skip); - expect(reqData.request.mediaTypes.video.skipafter).to.eql(bidRequestData[0].mediaTypes.video.skipafter); - expect(reqData.request.mediaTypes.video.skipmin).to.eql(bidRequestData[0].mediaTypes.video.skipmin); - expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); - expect(reqData.request.mediaTypes.video.w).to.eql(bidRequestData[0].mediaTypes.video.w); - expect(reqData.request.mediaTypes.video.h).to.eql(bidRequestData[0].mediaTypes.video.h); + + expect(reqData.request.mediaTypes.video).to.eql(bidRequestData[0].mediaTypes.video); + expect(reqData.video_metadata).to.eql({ description: bidRequestData[0].params.video.description, iabcat1: ['IAB-1'], @@ -432,9 +427,22 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.coppa).to.be.false; expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); - expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); - expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); - expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + + expect(reqData.request.mediaTypes.video).to.eql({ + ...bidRequestData[0].mediaTypes.video, + mimes: [], + minduration: 0, + maxduration: 0, + playbackmethod: [], + plcmt: 1, + protocols: [], + skip: 0, + skipafter: 0, + skipmin: 0, + w: 0, + h: 0, + }); + expect(reqData.video_metadata).to.eql({ description: bidRequestData[0].params.video.description, iabcat1: ['IAB-2'], @@ -496,6 +504,8 @@ describe('dailymotionBidAdapterTests', () => { mimes: [], minduration: 0, maxduration: 0, + playbackmethod: [], + plcmt: 1, protocols: [], skip: 0, skipafter: 0, From b6037b7e9c6351b64aed136c570f55790a0b7b42 Mon Sep 17 00:00:00 2001 From: Kevin Siow Date: Wed, 22 May 2024 10:06:12 +0200 Subject: [PATCH 2/7] Dailymotion Bid Adapter: add support for user syncs --- modules/dailymotionBidAdapter.js | 31 ++++++++ modules/dailymotionBidAdapter.md | 22 ++++++ .../modules/dailymotionBidAdapter_spec.js | 79 +++++++++++++++++++ 3 files changed, 132 insertions(+) diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js index 90a0cd83a5b..d7e98782227 100644 --- a/modules/dailymotionBidAdapter.js +++ b/modules/dailymotionBidAdapter.js @@ -179,6 +179,37 @@ export const spec = { * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: serverResponse => serverResponse?.body ? [serverResponse.body] : [], + + /** + * Retrieves user synchronization URLs based on provided options and consents. + * + * @param {object} syncOptions - Options for synchronization. + * @param {object[]} serverResponses - Array of server responses. + * @returns {object[]} - Array of synchronization URLs. + */ + getUserSyncs: (syncOptions, serverResponses) => { + if (!!serverResponses?.length && (syncOptions.iframeEnabled || syncOptions.pixelEnabled)) { + const iframeSyncs = []; + const pixelSyncs = []; + + serverResponses.forEach((response) => { + (response.user_syncs || []).forEach((syncUrl) => { + if (syncUrl.type === 'image') { + pixelSyncs.push({ url: syncUrl.url, type: 'image' }); + } + + if (syncUrl.type === 'iframe') { + iframeSyncs.push({ url: syncUrl.url, type: 'iframe' }); + } + }); + }); + + if (syncOptions.iframeEnabled) return iframeSyncs; + return pixelSyncs; + } + + return []; + }, }; registerBidder(spec); diff --git a/modules/dailymotionBidAdapter.md b/modules/dailymotionBidAdapter.md index 28372f26806..4b5ae40d0a2 100644 --- a/modules/dailymotionBidAdapter.md +++ b/modules/dailymotionBidAdapter.md @@ -36,6 +36,28 @@ const adUnits = [ `apiKey` is your publisher API key. For testing purpose, you can use "dailymotion-testing". +## User Sync + +To enable user synchronization, add the following code. Dailymotion highly recommends using iframes and/or pixels for user syncing. This feature enhances DSP user match rates, resulting in higher bid rates and bid prices. Ensure that `pbjs.setConfig()` is called only once. + +```javascript +pbjs.setConfig({ + userSync: { + syncEnabled: true, + filterSettings: { + iframe: { + bidders: '*', // Or add dailymotion to your list included bidders + filter: 'include' + }, + image: { + bidders: '*', // Or add dailymotion to your list of included bidders + filter: 'include' + }, + }, + }, +}); +``` + # Test Parameters By setting the following bid parameters, you'll get a constant response to any request, to validate your adapter integration: diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index df8298d5036..ed0bcb6af31 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -567,4 +567,83 @@ describe('dailymotionBidAdapterTests', () => { expect(spec.interpretResponse(undefined)).to.have.lengthOf(0); }); + + it('validates getUserSyncs', () => { + // Nothing sent in getUserSyncs + expect(config.runWithBidder('dailymotion', () => spec.getUserSyncs())).to.eql([]); + + // No server response + { + const responses = []; + const syncOptions = { iframeEnabled: true, pixelEnabled: true }; + + expect(config.runWithBidder( + 'dailymotion', + () => spec.getUserSyncs(syncOptions, responses), + )).to.eql([]); + } + + // No permissions + { + const responses = [{ user_syncs: [{ url: 'https://usersyncurl.com', type: 'image' }] }]; + const syncOptions = { iframeEnabled: false, pixelEnabled: false }; + + expect(config.runWithBidder( + 'dailymotion', + () => spec.getUserSyncs(syncOptions, responses), + )).to.eql([]); + } + + // Has permissions but no user_syncs urls + { + const responses = [{}]; + const syncOptions = { iframeEnabled: false, pixelEnabled: true }; + + expect(config.runWithBidder( + 'dailymotion', + () => spec.getUserSyncs(syncOptions, responses), + )).to.eql([]); + } + + // Return user_syncs urls for pixels + { + const responses = [{ + user_syncs: [ + { url: 'https://usersyncurl.com', type: 'image' }, + { url: 'https://usersyncurl2.com', type: 'image' }, + { url: 'https://usersyncurl3.com', type: 'iframe' } + ], + }]; + + const syncOptions = { iframeEnabled: false, pixelEnabled: true }; + + expect(config.runWithBidder( + 'dailymotion', + () => spec.getUserSyncs(syncOptions, responses), + )).to.eql([ + { type: 'image', url: 'https://usersyncurl.com' }, + { type: 'image', url: 'https://usersyncurl2.com' }, + ]); + } + + // Return user_syncs urls for iframes + { + const responses = [{ + user_syncs: [ + { url: 'https://usersyncurl.com', type: 'image' }, + { url: 'https://usersyncurl2.com', type: 'image' }, + { url: 'https://usersyncurl3.com', type: 'iframe' } + ], + }]; + + const syncOptions = { iframeEnabled: true, pixelEnabled: true }; + + expect(config.runWithBidder( + 'dailymotion', + () => spec.getUserSyncs(syncOptions, responses), + )).to.eql([ + { type: 'iframe', url: 'https://usersyncurl3.com' }, + ]); + } + }); }); From 71219c0dc50f47a91c79347d93033c66c8fbad16 Mon Sep 17 00:00:00 2001 From: Kevin Siow Date: Wed, 29 May 2024 11:19:06 +0200 Subject: [PATCH 3/7] Dailymotion Bid Adapter: Add support for ortb2 device, and contextual informations --- modules/dailymotionBidAdapter.js | 27 +++++++++++ modules/dailymotionBidAdapter.md | 17 ++++++- .../modules/dailymotionBidAdapter_spec.js | 45 ++++++++++++++++++- 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js index d7e98782227..dab844ee1f9 100644 --- a/modules/dailymotionBidAdapter.js +++ b/modules/dailymotionBidAdapter.js @@ -62,6 +62,27 @@ function getVideoMetadata(bidRequest, bidderRequest) { title: videoParams.title || deepAccess(contentObj, 'title', ''), topics: videoParams.topics || '', xid: videoParams.xid || '', + isCreatedForKids: typeof videoParams.isCreatedForKids === 'boolean' + ? videoParams.isCreatedForKids + : null, + context: { + videoViewsInSession: ( + typeof videoParams.videoViewsInSession === 'number' && + videoParams.videoViewsInSession >= 0 + ) + ? videoParams.videoViewsInSession + : null, + autoplay: typeof videoParams.autoplay === 'boolean' + ? videoParams.autoplay + : null, + playerVolume: ( + typeof videoParams.playerVolume === 'number' && + videoParams.playerVolume >= 0 && + videoParams.playerVolume <= 10 + ) + ? videoParams.playerVolume + : null, + }, }; return videoMetadata; @@ -139,6 +160,12 @@ export const spec = { appBundle: deepAccess(bidderRequest, 'ortb2.app.bundle', ''), appStoreUrl: deepAccess(bidderRequest, 'ortb2.app.storeurl', ''), } : {}), + ...(deepAccess(bidderRequest, 'ortb2.device') ? { + device: { + lmt: deepAccess(bidderRequest, 'ortb2.device.lmt', null), + ifa: deepAccess(bidderRequest, 'ortb2.device.ifa', ''), + }, + } : {}), request: { adUnitCode: deepAccess(bid, 'adUnitCode', ''), auctionId: deepAccess(bid, 'auctionId', ''), diff --git a/modules/dailymotionBidAdapter.md b/modules/dailymotionBidAdapter.md index 4b5ae40d0a2..c584cc57884 100644 --- a/modules/dailymotionBidAdapter.md +++ b/modules/dailymotionBidAdapter.md @@ -140,6 +140,10 @@ const adUnits = [ tags: 'tag_1,tag_2,tag_3', title: 'test video', topics: 'topic_1, topic_2', + isCreatedForKids: false, + videoViewsInSession: 1, + autoplay: false, + playerVolume: 8 } } }], @@ -177,8 +181,15 @@ Each of the following video metadata fields can be added in bids.params.video. * `title` - Video title * `topics` - Main topics for the video, comma separated * `xid` - Dailymotion video identifier (only applicable if using the Dailymotion player) +* `isCreatedForKids` - [The content is created for children as primary audience](https://faq.dailymotion.com/hc/en-us/articles/360020920159-Content-created-for-kids) -If you already specify [First-Party data](https://docs.prebid.org/features/firstPartyData.html) through the `ortb2` object when calling [`pbjs.requestBids(requestObj)`](https://docs.prebid.org/dev-docs/publisher-api-reference/requestBids.html), we will fallback to those values when possible. See the mapping below. +The following contextual informations can also be added in bids.params.video. + +* `videoViewsInSession` - Number of videos viewed within the current user session +* `autoplay` - Playback was launched without user interaction +* `playerVolume` - Player volume between 0 (muted, 0%) and 10 (100%) + +If you already specify [First-Party data](https://docs.prebid.org/features/firstPartyData.html) through the `ortb2` object when calling [`pbjs.requestBids(requestObj)`](https://docs.prebid.org/dev-docs/publisher-api-reference/requestBids.html), we will collect the following values and fallback to bids.params.video values when applicable. See the mapping below. | From ortb2 | Metadata fields | |---------------------------------------------------------------------------------|-----------------| @@ -189,6 +200,10 @@ If you already specify [First-Party data](https://docs.prebid.org/features/first | `ortb2.site.content.livestream` | `livestream` | | `ortb2.site.content.keywords` | `tags` | | `ortb2.site.content.title` | `title` | +| `ortb2.app.bundle` | N/A | +| `ortb2.app.storeurl` | N/A | +| `ortb2.device.lmt` | N/A | +| `ortb2.device.ifa` | N/A | # Integrating the adapter diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index ed0bcb6af31..6ad4516e468 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -98,7 +98,11 @@ describe('dailymotionBidAdapterTests', () => { skipmin: 10, startdelay: 0, w: 1280, - h: 720 + h: 720, + isCreatedForKids: true, + videoViewsInSession: 2, + autoplay: true, + playerVolume: 8, }, }, sizes: [[1920, 1080]], @@ -187,6 +191,12 @@ describe('dailymotionBidAdapterTests', () => { xid: bidRequestData[0].params.video.xid, duration: bidRequestData[0].params.video.duration, livestream: !!bidRequestData[0].params.video.livestream, + isCreatedForKids: bidRequestData[0].params.video.isCreatedForKids, + context: { + videoViewsInSession: bidRequestData[0].params.video.videoViewsInSession, + autoplay: bidRequestData[0].params.video.autoplay, + playerVolume: bidRequestData[0].params.video.playerVolume, + }, }); }); @@ -210,6 +220,11 @@ describe('dailymotionBidAdapterTests', () => { startdelay: 0, w: 1280, h: 720, + // Test invalid values + isCreatedForKids: 'false', + videoViewsInSession: -1, + autoplay: 'true', + playerVolume: 12, }, }, sizes: [[1920, 1080]], @@ -248,6 +263,10 @@ describe('dailymotionBidAdapterTests', () => { regs: { coppa: 1, }, + device: { + lmt: 1, + ifa: 'xxx', + }, app: { bundle: 'app-bundle', storeurl: 'https://play.google.com/store/apps/details?id=app-bundle', @@ -289,6 +308,8 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.coppa).to.be.true; expect(reqData.appBundle).to.eql(bidderRequestData.ortb2.app.bundle); expect(reqData.appStoreUrl).to.eql(bidderRequestData.ortb2.app.storeurl); + expect(reqData.device.lmt).to.eql(bidderRequestData.ortb2.device.lmt); + expect(reqData.device.ifa).to.eql(bidderRequestData.ortb2.device.ifa); expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); @@ -308,6 +329,12 @@ describe('dailymotionBidAdapterTests', () => { // Overriden through bidder params duration: bidderRequestData.ortb2.app.content.len, livestream: !!bidRequestData[0].params.video.livestream, + isCreatedForKids: null, + context: { + videoViewsInSession: null, + autoplay: null, + playerVolume: null, + }, }); }); @@ -332,6 +359,10 @@ describe('dailymotionBidAdapterTests', () => { title: 'test video', topics: 'topic_1, topic_2', xid: 'x123456', + isCreatedForKids: false, + videoViewsInSession: 10, + autoplay: false, + playerVolume: 0, }, }, }]; @@ -456,6 +487,12 @@ describe('dailymotionBidAdapterTests', () => { xid: bidRequestData[0].params.video.xid, duration: bidRequestData[0].params.video.duration, livestream: !!bidderRequestData.ortb2.site.content.livestream, + isCreatedForKids: bidRequestData[0].params.video.isCreatedForKids, + context: { + videoViewsInSession: bidRequestData[0].params.video.isCreatedForKids, + autoplay: bidRequestData[0].params.video.isCreatedForKids, + playerVolume: bidRequestData[0].params.video.isCreatedForKids, + }, }); }); @@ -531,6 +568,12 @@ describe('dailymotionBidAdapterTests', () => { topics: '', xid: '', livestream: false, + isCreatedForKids: null, + context: { + videoViewsInSession: null, + autoplay: null, + playerVolume: null, + }, }); }); From a491287399b6df35b221fa3473294a05c05aac10 Mon Sep 17 00:00:00 2001 From: Kevin Siow Date: Wed, 29 May 2024 15:13:08 +0200 Subject: [PATCH 4/7] Dailymotion Bid Adapter: Fix tests --- .../modules/dailymotionBidAdapter_spec.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index 6ad4516e468..286de67904a 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -99,10 +99,6 @@ describe('dailymotionBidAdapterTests', () => { startdelay: 0, w: 1280, h: 720, - isCreatedForKids: true, - videoViewsInSession: 2, - autoplay: true, - playerVolume: 8, }, }, sizes: [[1920, 1080]], @@ -121,6 +117,10 @@ describe('dailymotionBidAdapterTests', () => { topics: 'topic_1, topic_2', xid: 'x123456', livestream: 1, + isCreatedForKids: true, + videoViewsInSession: 2, + autoplay: true, + playerVolume: 8, }, }, }]; @@ -220,11 +220,6 @@ describe('dailymotionBidAdapterTests', () => { startdelay: 0, w: 1280, h: 720, - // Test invalid values - isCreatedForKids: 'false', - videoViewsInSession: -1, - autoplay: 'true', - playerVolume: 12, }, }, sizes: [[1920, 1080]], @@ -241,6 +236,11 @@ describe('dailymotionBidAdapterTests', () => { topics: 'topic_1, topic_2', xid: 'x123456', livestream: 1, + // Test invalid values + isCreatedForKids: 'false', + videoViewsInSession: -1, + autoplay: 'true', + playerVolume: 12, }, }, }]; @@ -489,9 +489,9 @@ describe('dailymotionBidAdapterTests', () => { livestream: !!bidderRequestData.ortb2.site.content.livestream, isCreatedForKids: bidRequestData[0].params.video.isCreatedForKids, context: { - videoViewsInSession: bidRequestData[0].params.video.isCreatedForKids, - autoplay: bidRequestData[0].params.video.isCreatedForKids, - playerVolume: bidRequestData[0].params.video.isCreatedForKids, + videoViewsInSession: bidRequestData[0].params.video.videoViewsInSession, + autoplay: bidRequestData[0].params.video.autoplay, + playerVolume: bidRequestData[0].params.video.playerVolume, }, }); }); From 8762f04cfceaec09f4303446aa574dc84e62facf Mon Sep 17 00:00:00 2001 From: Kevin Siow Date: Thu, 30 May 2024 10:22:53 +0200 Subject: [PATCH 5/7] Dailymotion Bid Adapter: add support for content.url & device.ext.atts --- modules/dailymotionBidAdapter.js | 3 +++ modules/dailymotionBidAdapter.md | 3 +++ test/spec/modules/dailymotionBidAdapter_spec.js | 15 +++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js index dab844ee1f9..f8026b6821c 100644 --- a/modules/dailymotionBidAdapter.js +++ b/modules/dailymotionBidAdapter.js @@ -60,12 +60,14 @@ function getVideoMetadata(bidRequest, bidderRequest) { private: videoParams.private || false, tags: videoParams.tags || deepAccess(contentObj, 'keywords', ''), title: videoParams.title || deepAccess(contentObj, 'title', ''), + url: videoParams.url || deepAccess(contentObj, 'url', ''), topics: videoParams.topics || '', xid: videoParams.xid || '', isCreatedForKids: typeof videoParams.isCreatedForKids === 'boolean' ? videoParams.isCreatedForKids : null, context: { + siteOrAppCat: deepAccess(contentObj, 'cat', ''), videoViewsInSession: ( typeof videoParams.videoViewsInSession === 'number' && videoParams.videoViewsInSession >= 0 @@ -164,6 +166,7 @@ export const spec = { device: { lmt: deepAccess(bidderRequest, 'ortb2.device.lmt', null), ifa: deepAccess(bidderRequest, 'ortb2.device.ifa', ''), + atts: deepAccess(bidderRequest, 'ortb2.device.ext.atts', 0), }, } : {}), request: { diff --git a/modules/dailymotionBidAdapter.md b/modules/dailymotionBidAdapter.md index c584cc57884..36a6032c675 100644 --- a/modules/dailymotionBidAdapter.md +++ b/modules/dailymotionBidAdapter.md @@ -179,6 +179,7 @@ Each of the following video metadata fields can be added in bids.params.video. * `private` - True if video is not publicly available * `tags` - Tags for the video, comma separated * `title` - Video title +* `url` - URL of the content * `topics` - Main topics for the video, comma separated * `xid` - Dailymotion video identifier (only applicable if using the Dailymotion player) * `isCreatedForKids` - [The content is created for children as primary audience](https://faq.dailymotion.com/hc/en-us/articles/360020920159-Content-created-for-kids) @@ -200,10 +201,12 @@ If you already specify [First-Party data](https://docs.prebid.org/features/first | `ortb2.site.content.livestream` | `livestream` | | `ortb2.site.content.keywords` | `tags` | | `ortb2.site.content.title` | `title` | +| `ortb2.site.content.url` | `url` | | `ortb2.app.bundle` | N/A | | `ortb2.app.storeurl` | N/A | | `ortb2.device.lmt` | N/A | | `ortb2.device.ifa` | N/A | +| `ortb2.device.ext.atts` | N/A | # Integrating the adapter diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index 286de67904a..aa217e22b60 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -114,6 +114,7 @@ describe('dailymotionBidAdapterTests', () => { private: false, tags: 'tag_1,tag_2,tag_3', title: 'test video', + url: 'https://test.com/test', topics: 'topic_1, topic_2', xid: 'x123456', livestream: 1, @@ -187,12 +188,14 @@ describe('dailymotionBidAdapterTests', () => { private: bidRequestData[0].params.video.private, tags: bidRequestData[0].params.video.tags, title: bidRequestData[0].params.video.title, + url: bidRequestData[0].params.video.url, topics: bidRequestData[0].params.video.topics, xid: bidRequestData[0].params.video.xid, duration: bidRequestData[0].params.video.duration, livestream: !!bidRequestData[0].params.video.livestream, isCreatedForKids: bidRequestData[0].params.video.isCreatedForKids, context: { + siteOrAppCat: '', videoViewsInSession: bidRequestData[0].params.video.videoViewsInSession, autoplay: bidRequestData[0].params.video.autoplay, playerVolume: bidRequestData[0].params.video.playerVolume, @@ -233,6 +236,7 @@ describe('dailymotionBidAdapterTests', () => { private: false, tags: 'tag_1,tag_2,tag_3', title: 'test video', + url: 'https://test.com/test', topics: 'topic_1, topic_2', xid: 'x123456', livestream: 1, @@ -266,6 +270,9 @@ describe('dailymotionBidAdapterTests', () => { device: { lmt: 1, ifa: 'xxx', + ext: { + atts: 2, + }, }, app: { bundle: 'app-bundle', @@ -310,6 +317,7 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.appStoreUrl).to.eql(bidderRequestData.ortb2.app.storeurl); expect(reqData.device.lmt).to.eql(bidderRequestData.ortb2.device.lmt); expect(reqData.device.ifa).to.eql(bidderRequestData.ortb2.device.ifa); + expect(reqData.device.atts).to.eql(bidderRequestData.ortb2.device.ext.atts); expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); @@ -324,6 +332,7 @@ describe('dailymotionBidAdapterTests', () => { private: bidRequestData[0].params.video.private, tags: bidRequestData[0].params.video.tags, title: bidRequestData[0].params.video.title, + url: bidRequestData[0].params.video.url, topics: bidRequestData[0].params.video.topics, xid: bidRequestData[0].params.video.xid, // Overriden through bidder params @@ -331,6 +340,7 @@ describe('dailymotionBidAdapterTests', () => { livestream: !!bidRequestData[0].params.video.livestream, isCreatedForKids: null, context: { + siteOrAppCat: '', videoViewsInSession: null, autoplay: null, playerVolume: null, @@ -389,6 +399,7 @@ describe('dailymotionBidAdapterTests', () => { language: 'FR', keywords: 'tag_1,tag_2,tag_3', title: 'test video', + url: 'https://test.com/test', livestream: 1, cat: ['IAB-2'], data: [ @@ -483,12 +494,14 @@ describe('dailymotionBidAdapterTests', () => { private: bidRequestData[0].params.video.private, tags: bidderRequestData.ortb2.site.content.keywords, title: bidderRequestData.ortb2.site.content.title, + url: bidderRequestData.ortb2.site.content.url, topics: bidRequestData[0].params.video.topics, xid: bidRequestData[0].params.video.xid, duration: bidRequestData[0].params.video.duration, livestream: !!bidderRequestData.ortb2.site.content.livestream, isCreatedForKids: bidRequestData[0].params.video.isCreatedForKids, context: { + siteOrAppCat: bidderRequestData.ortb2.site.content.cat, videoViewsInSession: bidRequestData[0].params.video.videoViewsInSession, autoplay: bidRequestData[0].params.video.autoplay, playerVolume: bidRequestData[0].params.video.playerVolume, @@ -565,11 +578,13 @@ describe('dailymotionBidAdapterTests', () => { private: false, tags: '', title: '', + url: '', topics: '', xid: '', livestream: false, isCreatedForKids: null, context: { + siteOrAppCat: '', videoViewsInSession: null, autoplay: null, playerVolume: null, From 391ce7dbc3ddb52ef2f811e26049bd2cbe67e726 Mon Sep 17 00:00:00 2001 From: Kevin Siow Date: Thu, 30 May 2024 12:53:03 +0200 Subject: [PATCH 6/7] Dailymotion Bid Adapter: change markdown header levels --- modules/dailymotionBidAdapter.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/dailymotionBidAdapter.md b/modules/dailymotionBidAdapter.md index 36a6032c675..7ff3fd47d74 100644 --- a/modules/dailymotionBidAdapter.md +++ b/modules/dailymotionBidAdapter.md @@ -1,4 +1,4 @@ -# Overview +### Overview ``` Module Name: Dailymotion Bid Adapter @@ -6,12 +6,12 @@ Module Type: Bidder Adapter Maintainer: ad-leo-engineering@dailymotion.com ``` -# Description +### Description Dailymotion prebid adapter. Supports video ad units in instream context. -# Configuration options +### Configuration options Before calling this adapter, you need to at least set a video adUnit in an instream context and the API key in the bid parameters: @@ -36,7 +36,7 @@ const adUnits = [ `apiKey` is your publisher API key. For testing purpose, you can use "dailymotion-testing". -## User Sync +#### User Sync To enable user synchronization, add the following code. Dailymotion highly recommends using iframes and/or pixels for user syncing. This feature enhances DSP user match rates, resulting in higher bid rates and bid prices. Ensure that `pbjs.setConfig()` is called only once. @@ -58,7 +58,7 @@ pbjs.setConfig({ }); ``` -# Test Parameters +### Test Parameters By setting the following bid parameters, you'll get a constant response to any request, to validate your adapter integration: @@ -83,7 +83,7 @@ const adUnits = [ Please note that failing to set these will result in the adapter not bidding at all. -# Sample video AdUnit +### Sample video AdUnit To allow better targeting, you should provide as much context about the video as possible. There are three ways of doing this depending on if you're using Dailymotion player or a third party one. @@ -208,7 +208,7 @@ If you already specify [First-Party data](https://docs.prebid.org/features/first | `ortb2.device.ifa` | N/A | | `ortb2.device.ext.atts` | N/A | -# Integrating the adapter +### Integrating the adapter To use the adapter with any non-test request, you first need to ask an API key from Dailymotion. Please contact us through **DailymotionPrebid.js@dailymotion.com**. From 8fb8ecdb1bb383f11f77ed9997fb6e03fe71715b Mon Sep 17 00:00:00 2001 From: Kevin Siow Date: Fri, 31 May 2024 11:44:39 +0200 Subject: [PATCH 7/7] Dailymotion Bid Adapter: collect prebid.version --- modules/dailymotionBidAdapter.js | 1 + test/spec/modules/dailymotionBidAdapter_spec.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js index f8026b6821c..bf8eaaebb55 100644 --- a/modules/dailymotionBidAdapter.js +++ b/modules/dailymotionBidAdapter.js @@ -134,6 +134,7 @@ export const spec = { method: 'POST', url: 'https://pb.dmxleo.com', data: { + pbv: '$prebid.version$', bidder_request: { gdprConsent: { apiVersion: deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1), diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index aa217e22b60..0fa199ed034 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -167,6 +167,7 @@ describe('dailymotionBidAdapterTests', () => { expect(request.url).to.equal('https://pb.dmxleo.com'); + expect(reqData.pbv).to.eql('$prebid.version$'); expect(reqData.bidder_request).to.eql({ refererInfo: bidderRequestData.refererInfo, uspConsent: bidderRequestData.uspConsent, @@ -305,6 +306,7 @@ describe('dailymotionBidAdapterTests', () => { expect(request.url).to.equal('https://pb.dmxleo.com'); + expect(reqData.pbv).to.eql('$prebid.version$'); expect(reqData.bidder_request).to.eql({ refererInfo: bidderRequestData.refererInfo, uspConsent: bidderRequestData.uspConsent, @@ -456,6 +458,7 @@ describe('dailymotionBidAdapterTests', () => { expect(request.url).to.equal('https://pb.dmxleo.com'); + expect(reqData.pbv).to.eql('$prebid.version$'); expect(reqData.bidder_request).to.eql({ refererInfo: bidderRequestData.refererInfo, uspConsent: bidderRequestData.uspConsent, @@ -528,6 +531,7 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.config.api_key).to.eql(bidRequestDataWithApi[0].params.apiKey); expect(reqData.coppa).to.be.false; + expect(reqData.pbv).to.eql('$prebid.version$'); expect(reqData.bidder_request).to.eql({ gdprConsent: { apiVersion: 1,