Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dailymotion Bid Adapter: accept ortb2 field #11366

Merged
merged 39 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
5b534be
Dailymotion Bid Adaptor: initial release
Jan 11, 2024
807c75b
.md file lint issue resolved
Aditi0101 Jan 22, 2024
9eb2277
Merge pull request #3 from dailymotion-oss/feat/dailymotion-adaptor
sebmil-daily Jan 22, 2024
3b3878e
Merge branch 'prebid:master' into master
kvnsw Feb 1, 2024
6c25624
Dailymotion Bid Adaptor: build bidder request based on param with fal…
Jan 31, 2024
9aab2ea
Dailymotion Bid Adaptor: support video metadata
Aditi0101 Feb 16, 2024
7ee40c4
Merge branch 'prebid:master' into master
kvnsw Mar 1, 2024
32d6391
Dailymotion Bid Adaptor: add support for sending adUnitCode
Mar 5, 2024
d5542db
Merge branch 'prebid:master' into master
kvnsw Mar 6, 2024
ce0536c
Dailymotion Bid Adaptor: add support for sending startDelay
Mar 6, 2024
9a97052
Merge branch 'prebid:master' into master
kvnsw Mar 6, 2024
3092928
feat(LEO-528): Allow multiple IAB categories in video metadata
sebmil-daily Mar 19, 2024
4b78d35
Merge pull request #10 from dailymotion-oss/LEO-528_multiple_iabcat2
sebmil-daily Mar 20, 2024
09f8e16
Dailymotion bid adapter: Clarify the video metadata to provide in eac…
sebmil-daily Mar 27, 2024
44b88d1
Merge pull request #11 from dailymotion-oss/LEO-528_fix_metadata_doc
sebmil-daily Mar 27, 2024
898d8bb
Dailymotion bid adapter: Move API key to bid params
sebmil-daily Apr 3, 2024
673f831
Dailymotion bid adapter: Verify API key is string
kvnsw Apr 3, 2024
53bd3df
Merge branch 'prebid:master' into master
kvnsw Apr 3, 2024
fbd456d
Dailymotion bid adapter: Move API key to bid params (fix tests)
sebmil-daily Apr 4, 2024
2bfbc13
Merge pull request #13 from dailymotion-oss/dailymotion_move_api_key_…
sebmil-daily Apr 4, 2024
b908269
Merge branch 'prebid:master' into master
sebmil-daily Apr 4, 2024
cc0c1bc
Dailymotion Bid Adaptor: add gpp support and get coppa from request
Apr 18, 2024
cc5f6ff
Merge branch 'prebid:master' into master
kvnsw Apr 18, 2024
fa56a41
Dailymotion Bid Adaptor: fix lint error
Apr 18, 2024
36637e0
Dailymotion Bid Adaptor: add iabcat1 and fallback to ortb2 for iabcat2
Apr 18, 2024
cff7c34
Merge pull request #16 from dailymotion-oss/dailymotion_iabcat
sebmil-daily Apr 18, 2024
50dda1f
Dailymotion Bid Adaptor: get iabcats from ortb2.site.content.data
Apr 18, 2024
2a38bac
Dailymotion Bid Adaptor: get content data from ortb2.site.content
Apr 19, 2024
bcaaa60
Dailymotion Bid Adaptor: add support for iabcat1 in videoParams and d…
Apr 19, 2024
091eec5
Dailymotion Bid Adaptor: add support for Object: App
Apr 19, 2024
7a5b070
Dailymotion Bid Adaptor: only support video adunits in context instream
Apr 19, 2024
729647b
Dailymotion bid adapter: Add standard ORTB video parameters
sebmil-daily Apr 19, 2024
c80dd13
Merge pull request #19 from dailymotion-oss/GLUE-16296_handle_ortb_vi…
sebmil-daily Apr 19, 2024
6e36b69
Dailymotion Bid Adaptor: add support for livestream and app
Apr 19, 2024
38a0079
Merge remote-tracking branch 'upstream/master' into merge_upstream
sebmil-daily Apr 19, 2024
a53f4c0
Merge pull request #21 from dailymotion-oss/merge_upstream
sebmil-daily Apr 19, 2024
5c209c0
Merge branch 'prebid:master' into master
kvnsw Apr 20, 2024
ae8de5f
Dailymotion Bid Adaptor: drop support for non standard fields in medi…
Apr 20, 2024
80b6dfe
Dailymotion Bid Adaptor: update docs examples
Apr 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 74 additions & 31 deletions modules/dailymotionBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,59 @@ import { deepAccess } from '../src/utils.js';
* @return video metadata
*/
function getVideoMetadata(bidRequest, bidderRequest) {
const videoAdUnit = deepAccess(bidRequest, 'mediaTypes.video', {});
const videoBidderParams = deepAccess(bidRequest, 'params.video', {});
const videoParams = deepAccess(bidRequest, 'params.video', {});

const videoParams = {
...videoAdUnit,
...videoBidderParams, // Bidder Specific overrides
};
// As per oRTB 2.5 spec, "A bid request must not contain both an App and a Site object."
// See section 3.2.14
// Content object is either from Object: Site or Object: App
const contentObj = deepAccess(bidderRequest, 'ortb2.site')
? deepAccess(bidderRequest, 'ortb2.site.content')
: deepAccess(bidderRequest, 'ortb2.app.content');

// Store as object keys to ensure uniqueness
const iabcat1 = {};
const iabcat2 = {};
const parsedContentData = {
// Store as object keys to ensure uniqueness
iabcat1: {},
iabcat2: {},
};

deepAccess(bidderRequest, 'ortb2.site.content.data', []).forEach((data) => {
deepAccess(contentObj, 'data', []).forEach((data) => {
if ([4, 5, 6, 7].includes(data?.ext?.segtax)) {
(Array.isArray(data.segment) ? data.segment : []).forEach((segment) => {
if (typeof segment.id === 'string') {
// See https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy
// Only take IAB cats of taxonomy V1
if (data.ext.segtax === 4) iabcat1[segment.id] = 1;
// Only take IAB cats of taxonomy V2 or higher
if ([5, 6, 7].includes(data.ext.segtax)) iabcat2[segment.id] = 1;
if (data.ext.segtax === 4) {
parsedContentData.iabcat1[segment.id] = 1;
} else {
// Only take IAB cats of taxonomy V2 or higher
parsedContentData.iabcat2[segment.id] = 1;
}
}
});
}
});

const videoMetadata = {
description: videoParams.description || '',
duration: videoParams.duration || 0,
iabcat1: Object.keys(iabcat1),
duration: videoParams.duration || deepAccess(contentObj, 'len', 0),
iabcat1: Array.isArray(videoParams.iabcat1)
patmmccann marked this conversation as resolved.
Show resolved Hide resolved
? videoParams.iabcat1
: Array.isArray(deepAccess(contentObj, 'cat'))
? contentObj.cat
: Object.keys(parsedContentData.iabcat1),
iabcat2: Array.isArray(videoParams.iabcat2)
? videoParams.iabcat2
: Object.keys(iabcat2),
id: videoParams.id || '',
lang: videoParams.lang || '',
: Object.keys(parsedContentData.iabcat2),
id: videoParams.id || deepAccess(contentObj, 'id', ''),
lang: videoParams.lang || deepAccess(contentObj, 'language', ''),
private: videoParams.private || false,
tags: videoParams.tags || '',
title: videoParams.title || '',
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;
Expand All @@ -67,7 +80,24 @@ export const spec = {
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function (bid) {
return typeof bid?.params?.apiKey === 'string' && bid.params.apiKey.length > 10;
if (bid?.params) {
// We only accept video adUnits
if (!bid?.mediaTypes?.[VIDEO]) return false;

// As `context`, `placement` & `plcmt` are optional (although recommended)
// values, we check the 3 of them to see if we are in an instream video context
const isInstream = bid.mediaTypes[VIDEO].context === 'instream' ||
bid.mediaTypes[VIDEO].placement === 1 ||
bid.mediaTypes[VIDEO].plcmt === 1;

// We only accept instream video context
if (!isInstream) return false;

// We need API key
return typeof bid.params.apiKey === 'string' && bid.params.apiKey.length > 10;
}

return false;
},

/**
Expand All @@ -83,15 +113,15 @@ export const spec = {
data: {
bidder_request: {
gdprConsent: {
apiVersion: bidderRequest?.gdprConsent?.apiVersion || 1,
consentString: bidderRequest?.gdprConsent?.consentString || '',
apiVersion: deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1),
consentString: deepAccess(bidderRequest, 'gdprConsent.consentString', ''),
// Cast boolean in any case (eg: if value is int) to ensure type
gdprApplies: !!bidderRequest?.gdprConsent?.gdprApplies,
gdprApplies: !!deepAccess(bidderRequest, 'gdprConsent.gdprApplies'),
},
refererInfo: {
page: bidderRequest?.refererInfo?.page || '',
page: deepAccess(bidderRequest, 'refererInfo.page', ''),
},
uspConsent: bidderRequest?.uspConsent || '',
uspConsent: deepAccess(bidderRequest, 'uspConsent', ''),
gppConsent: {
gppString: deepAccess(bidderRequest, 'gppConsent.gppString') ||
deepAccess(bidderRequest, 'ortb2.regs.gpp', ''),
Expand All @@ -104,15 +134,28 @@ export const spec = {
},
// Cast boolean in any case (value should be 0 or 1) to ensure type
coppa: !!deepAccess(bidderRequest, 'ortb2.regs.coppa'),
// In app context, we need to retrieve additional informations
...(!deepAccess(bidderRequest, 'ortb2.site') && !!deepAccess(bidderRequest, 'ortb2.app') ? {
appBundle: deepAccess(bidderRequest, 'ortb2.app.bundle', ''),
appStoreUrl: deepAccess(bidderRequest, 'ortb2.app.storeurl', ''),
} : {}),
request: {
adUnitCode: bid.adUnitCode || '',
auctionId: bid.auctionId || '',
bidId: bid.bidId || '',
adUnitCode: deepAccess(bid, 'adUnitCode', ''),
auctionId: deepAccess(bid, 'auctionId', ''),
bidId: deepAccess(bid, 'bidId', ''),
mediaTypes: {
video: {
playerSize: bid.mediaTypes?.[VIDEO]?.playerSize || [],
api: bid.mediaTypes?.[VIDEO]?.api || [],
startDelay: bid.mediaTypes?.[VIDEO]?.startdelay || 0,
mimes: bid.mediaTypes?.[VIDEO]?.mimes || [],
minduration: bid.mediaTypes?.[VIDEO]?.minduration || 0,
maxduration: bid.mediaTypes?.[VIDEO]?.maxduration || 0,
protocols: bid.mediaTypes?.[VIDEO]?.protocols || [],
skip: bid.mediaTypes?.[VIDEO]?.skip || 0,
skipafter: bid.mediaTypes?.[VIDEO]?.skipafter || 0,
skipmin: bid.mediaTypes?.[VIDEO]?.skipmin || 0,
startdelay: bid.mediaTypes?.[VIDEO]?.startdelay || 0,
w: bid.mediaTypes?.[VIDEO]?.w || 0,
h: bid.mediaTypes?.[VIDEO]?.h || 0,
},
},
sizes: bid.sizes || [],
Expand Down
83 changes: 57 additions & 26 deletions modules/dailymotionBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ Maintainer: ad-leo-engineering@dailymotion.com
# Description

Dailymotion prebid adapter.
Supports video ad units in instream context.

# Configuration options

Before calling this adapter, you need to set at least the API key in the bid parameters:
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:

```javascript
const adUnits = [
Expand All @@ -21,8 +22,14 @@ const adUnits = [
bidder: 'dailymotion',
params: {
apiKey: 'fake_api_key'
}
}]
},
}],
code: 'test-ad-unit',
mediaTypes: {
video: {
context: 'instream',
},
},
}
];
```
Expand All @@ -39,9 +46,15 @@ const adUnits = [
bids: [{
bidder: 'dailymotion',
params: {
apiKey: 'dailymotion-testing'
}
}]
apiKey: 'dailymotion-testing',
},
}],
code: 'test-ad-unit',
mediaTypes: {
video: {
context: 'instream',
},
},
}
];
```
Expand All @@ -51,7 +64,7 @@ Please note that failing to set these will result in the adapter not bidding at
# Sample video AdUnit

To allow better targeting, you should provide as much context about the video as possible.
There are two ways of doing this depending on if you're using Dailymotion player or a third party one.
There are three ways of doing this depending on if you're using Dailymotion player or a third party one.

If you are using the Dailymotion player, you should only provide the video `xid` in your ad unit, example:

Expand All @@ -61,17 +74,20 @@ const adUnits = [
bids: [{
bidder: 'dailymotion',
params: {
apiKey: 'dailymotion-testing'
apiKey: 'dailymotion-testing',
video: {
xid: 'x123456' // Dailymotion infrastructure unique video ID
},
}
}],
code: 'test-ad-unit',
mediaTypes: {
video: {
api: [2, 7],
context: 'instream',
playerSize: [ [1280, 720] ],
startDelay: 0,
xid: 'x123456' // Dailymotion infrastructure unique video ID
startdelay: 0,
w: 1280,
h: 720,
},
}
}
Expand All @@ -91,7 +107,17 @@ const adUnits = [
params: {
apiKey: 'dailymotion-testing',
video: {
description: 'overriden video description'
description: 'this is a video description',
duration: 556,
iabcat1: ['IAB-2'],
iabcat2: ['6', '17'],
id: '54321',
lang: 'FR',
livestream: 0,
private: false,
tags: 'tag_1,tag_2,tag_3',
title: 'test video',
topics: 'topic_1, topic_2',
}
}
}],
Expand All @@ -100,37 +126,42 @@ const adUnits = [
video: {
api: [2, 7],
context: 'instream',
description: 'this is a video description',
duration: 556,
iabcat2: ['6', '17'],
id: '54321',
lang: 'FR',
playerSize: [ [1280, 720] ],
private: false,
startDelay: 0,
tags: 'tag_1,tag_2,tag_3',
title: 'test video',
topics: 'topic_1, topic_2',
startdelay: 0,
w: 1280,
h: 720,
},
}
}
];
```

Each of the following video metadata fields can be added in mediaTypes.video or bids.params.video.
If a field exists in both places, it will be overridden by bids.params.video.
Each of the following video metadata fields can be added in bids.params.video.

patmmccann marked this conversation as resolved.
Show resolved Hide resolved
* `description` - Video description
* `duration` - Video duration in seconds
* `iabcat2` - List of IAB category IDs from the [2.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.0.tsv)
* `iabcat1` - List of IAB category IDs from the [1.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%201.0.tsv)
* `iabcat2` - List of IAB category IDs from the [2.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.0.tsv) and above
* `id` - Video unique ID in host video infrastructure
* `lang` - ISO 639-1 code for main language used in the video
* `livestream` - 0 = not live, 1 = content is live
* `private` - True if video is not publicly available
* `tags` - Tags for the video, comma separated
* `title` - Video title
* `topics` - Main topics for the video, comma separated
* `xid` - Dailymotion video identifier (only applicable if using the Dailymotion player)

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.

| From ortb2 | Metadata fields |
|---------------------------------------------------------------------------------|-----------------|
| `ortb2.site.content.cat` OR `ortb2.site.content.data` where `ext.segtax` is `4` | `iabcat1` |
| `ortb2.site.content.data` where `ext.segtax` is `5`, `6` or `7` | `iabcat2` |
| `ortb2.site.content.id` | `id` |
| `ortb2.site.content.language` | `lang` |
| `ortb2.site.content.livestream` | `livestream` |
| `ortb2.site.content.keywords` | `tags` |
| `ortb2.site.content.title` | `title` |

# 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**.
Expand Down
Loading