Skip to content

Commit d6f9738

Browse files
kdaswaniKiara Daswani
andauthored
Update Nielsen integration mappings and add new setting to Nielsen DCR (#597)
* Update Nielsen integration mappings and add new setting to DCR * Upgrade dependencies for analytics-events * Add Nielsen DTVR integration changes and unit tests * Update Nielsen integration mappings and add new setting to DCR * Upgrade dependencies for analytics-events * Add Nielsen DTVR integration changes and unit tests * Publishing beta versions of Nielsen DCR 2.1.0 and Nielsen DTVR 1.0.2 * Fix total_length bug by checking for undefined * Hash URL for assetid and update unit tests * Update beta version for Nielsen DCR to 2.1.1 * Bump to non beta versions Co-authored-by: Kiara Daswani <kiara.daswani@Kiaras-MBP.attlocal.net>
1 parent db82313 commit d6f9738

File tree

7 files changed

+79
-100
lines changed

7 files changed

+79
-100
lines changed

integrations/nielsen-dcr/lib/index.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var integration = require('@segment/analytics.js-integration');
88
var find = require('obj-case').find;
99
var reject = require('reject');
1010
var dateformat = require('dateformat');
11+
var sha256 = require('js-sha256');
1112

1213
/**
1314
* Expose `NielsenDCR` integration.
@@ -22,6 +23,7 @@ var NielsenDCR = (module.exports = integration('Nielsen DCR')
2223
.option('adAssetIdPropertyName', '')
2324
.option('subbrandPropertyName', '')
2425
.option('clientIdPropertyName', '')
26+
.option('customSectionProperty', '')
2527
.option('sendCurrentTimeLivestream', false)
2628
.option('contentLengthPropertyName', 'total_length')
2729
.option('optout', false)
@@ -100,10 +102,22 @@ NielsenDCR.prototype.loaded = function() {
100102

101103
NielsenDCR.prototype.page = function(page) {
102104
var integrationOpts = page.options(this.name);
105+
var customSectionName;
106+
107+
//Allow customer to pick property to source section from otherwise fallback on page name
108+
if (this.options.customSectionProperty) {
109+
customSectionName = page.proxy(
110+
'properties.' + this.options.customSectionProperty
111+
);
112+
}
113+
var defaultSectionName = page.fullName() || page.name() || page.event();
114+
var sectionName = customSectionName || defaultSectionName;
115+
var url = page.url();
116+
103117
var staticMetadata = reject({
104118
type: 'static',
105-
assetid: page.url(), // *DYNAMIC METADATA*: unique ID for each article **REQUIRED**
106-
section: page.fullName() || page.name() || page.event(), // *DYNAMIC METADATA*: section of site **REQUIRED**
119+
assetid: sha256(url), // *DYNAMIC METADATA*: unique ID for each article, deterministic SHA256 hash of url since assetid cannot contain special characters **REQUIRED**
120+
section: sectionName, // *DYNAMIC METADATA*: section of site **REQUIRED**
107121
segA: integrationOpts.segA, // *DYNAMIC METADATA*: custom segment
108122
segB: integrationOpts.segB, // *DYNAMIC METADATA*: custom segment
109123
segC: integrationOpts.segC // *DYNAMIC METADATA*: custom segment
@@ -191,7 +205,7 @@ NielsenDCR.prototype.getContentMetadata = function(track, type) {
191205
hasAds: find(integrationOpts, 'hasAds') === true ? '1' : '0'
192206
};
193207

194-
if (this.options.contentLengthPropertyName !== 'total_length') {
208+
if (this.options.contentLengthPropertyName && this.options.contentLengthPropertyName !== 'total_length') {
195209
var contentLengthKey = this.options.contentLengthPropertyName;
196210
contentMetadata.length = track.proxy(propertiesPath + contentLengthKey);
197211
} else {
@@ -394,11 +408,13 @@ NielsenDCR.prototype.videoAdCompleted = function(track) {
394408
* Video Playback Paused
395409
* Video Playback Seek Started
396410
* Video Playback Buffer Started
411+
* Video Playback Interrupted
412+
* Video Playback Exited
397413
*
398414
* @api public
399415
*/
400416

401-
NielsenDCR.prototype.videoPlaybackPaused = NielsenDCR.prototype.videoPlaybackSeekStarted = NielsenDCR.prototype.videoPlaybackBufferStarted = function(
417+
NielsenDCR.prototype.videoPlaybackPaused = NielsenDCR.prototype.videoPlaybackSeekStarted = NielsenDCR.prototype.videoPlaybackBufferStarted = NielsenDCR.prototype.videoPlaybackInterrupted = NielsenDCR.prototype.videoPlaybackExited = function(
402418
track
403419
) {
404420
var self = this;
@@ -460,13 +476,12 @@ NielsenDCR.prototype.videoPlaybackResumed = NielsenDCR.prototype.videoPlaybackSe
460476

461477
/**
462478
* Video Playback Completed
463-
* Video Playback Interrupted
464479
*
465480
*
466481
* @api public
467482
*/
468483

469-
NielsenDCR.prototype.videoPlaybackCompleted = NielsenDCR.prototype.videoPlaybackInterrupted = function(
484+
NielsenDCR.prototype.videoPlaybackCompleted = function(
470485
track
471486
) {
472487
var self = this;
@@ -481,7 +496,7 @@ NielsenDCR.prototype.videoPlaybackCompleted = NielsenDCR.prototype.videoPlayback
481496
this._client.ggPM('setPlayheadPosition', position);
482497
this._client.ggPM('end', position);
483498

484-
// reset state because "Video Playback Completed/Interrupted" are "non-recoverable events"
499+
// reset state because "Video Playback Completed" are "non-recoverable events"
485500
// e.g. they should always be followed by the start of a new video session with either
486501
// "Video Content Started" or "Video Ad Started" events
487502
this.currentPosition = 0;

integrations/nielsen-dcr/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@segment/analytics.js-integration-nielsen-dcr",
33
"description": "The Nielsen DCR analytics.js integration.",
4-
"version": "2.0.2",
4+
"version": "2.1.1",
55
"keywords": [
66
"analytics.js",
77
"analytics.js-integration",

integrations/nielsen-dcr/test/index.test.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ describe('NielsenDCR', function() {
4141
.option('adAssetIdPropertyName', '')
4242
.option('subbrandPropertyName', '')
4343
.option('clientIdPropertyName', '')
44+
.option('customSectionProperty', '')
4445
.option('contentLengthPropertyName', 'total_length')
4546
.option('optout', false)
4647
.option('sendCurrentTimeLivestream', false)
@@ -90,7 +91,7 @@ describe('NielsenDCR', function() {
9091
analytics.page();
9192
var staticMetadata = {
9293
type: 'static',
93-
assetid: window.location.href,
94+
assetid: 'ff4c0efe94509b3d21872f0c0bfec92faaed5ae46d707b6ea832a74f9f1fe38d',
9495
section: 'Loaded a Page'
9596
};
9697
analytics.called(
@@ -99,6 +100,29 @@ describe('NielsenDCR', function() {
99100
staticMetadata
100101
);
101102
});
103+
104+
it('should send static metadata with custom section name', function() {
105+
var props;
106+
props = {
107+
custom_section_name_prop: 'Custom Page Name'
108+
}
109+
110+
nielsenDCR.options.customSectionProperty =
111+
'custom_section_name_prop';
112+
113+
analytics.page('Homepage', props);
114+
115+
var staticMetadata = {
116+
type: 'static',
117+
assetid: 'ff4c0efe94509b3d21872f0c0bfec92faaed5ae46d707b6ea832a74f9f1fe38d',
118+
section: 'Custom Page Name'
119+
};
120+
analytics.called(
121+
nielsenDCR._client.ggPM,
122+
'staticstart',
123+
staticMetadata
124+
);
125+
});
102126
});
103127

104128
describe('#track', function() {
@@ -183,13 +207,19 @@ describe('NielsenDCR', function() {
183207
it('video playback interrupted during content', function() {
184208
analytics.track('Video Playback Interrupted', props);
185209
analytics.called(window.clearInterval);
186-
analytics.called(nielsenDCR._client.ggPM, 'end', props.position);
210+
analytics.called(nielsenDCR._client.ggPM, 'stop', props.position);
187211
});
188212

189213
it('video playback interrupted during ad', function() {
190214
analytics.track('Video Playback Interrupted', props);
191215
analytics.called(window.clearInterval);
192-
analytics.called(nielsenDCR._client.ggPM, 'end', props.position);
216+
analytics.called(nielsenDCR._client.ggPM, 'stop', props.position);
217+
});
218+
219+
it('video playback exited', function() {
220+
analytics.track('Video Playback Exited', props);
221+
analytics.called(window.clearInterval);
222+
analytics.called(nielsenDCR._client.ggPM, 'stop', props.position);
193223
});
194224

195225
it('video playback completed', function() {

integrations/nielsen-dtvr/lib/index.js

Lines changed: 17 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -105,25 +105,15 @@ NielsenDTVR.prototype.track = function(track) {
105105
*/
106106

107107
NielsenDTVR.prototype.videoContentStarted = function(track) {
108-
var date;
109-
var time;
110108
var metadata;
111-
// Proactively ensure that we call "end" whenever new content
109+
// Proactively ensure we clear the session whenever new content
112110
// starts. Here, we'll catch it if a customer forgets to call a Segment
113-
// "Completed" event, so we'll end the video for them. `end` is also
114-
// appropriate during a video "interruption",
111+
// "Completed" event, so we'll clear the ID3 tags and stream.
115112
// e.g. if a user is alternating b/w watching two videos on the same page.
116113
if (this.previousEvent && track !== this.previousEvent) {
117-
date = this.previousEvent.timestamp();
118-
if (
119-
this.previousEvent.proxy('properties.livestream') === true &&
120-
date instanceof Date
121-
) {
122-
time = Math.floor(date.getTime() / 1000);
123-
} else if (this.previousEvent.proxy('properties.position')) {
124-
time = this.previousEvent.proxy('properties.position');
125-
}
126-
this.client.ggPM('end', time);
114+
this.ID3 = null;
115+
this.previousEvent = null;
116+
this.isDTVRStream = null;
127117
}
128118

129119
metadata = this.mapMetadata(track);
@@ -136,20 +126,28 @@ NielsenDTVR.prototype.videoContentStarted = function(track) {
136126
};
137127

138128
/**
129+
* These are considered non-recoverable completion scenarios.
130+
* Nielsen has requested we do not fire anything for these events.
131+
* We will simply reset ID3 tags and clear out the stream/session.
132+
*
139133
* Video Content Completed
140134
* Video Playback Completed
135+
* Video Playback Exited
141136
*
142137
* @api public
143138
*/
144139

145-
NielsenDTVR.prototype.videoContentCompleted = NielsenDTVR.prototype.videoPlaybackCompleted = function(
146-
track
147-
) {
140+
NielsenDTVR.prototype.videoContentCompleted = NielsenDTVR.prototype.videoPlaybackCompleted = NielsenDTVR.prototype.videoPlaybackExited = function() {
148141
if (!this.isDTVRStream) return;
149-
this.end(track);
142+
this.ID3 = null;
143+
this.previousEvent = null;
144+
this.isDTVRStream = null;
150145
};
151146

152147
/**
148+
* These are considered recoverable interruption scenarios.
149+
* Nielsen has requested we do not fire anything for these events, aside from reporting the latest ID3 tag.
150+
*
153151
* Video Playback Interrupted
154152
* Video Playback Seek Started
155153
* Video Playback Buffer Started
@@ -163,7 +161,6 @@ NielsenDTVR.prototype.videoPlaybackInterrupted = NielsenDTVR.prototype.videoPlay
163161
) {
164162
if (!this.isDTVRStream) return;
165163
this.sendID3(track);
166-
this.end(track, 'recoverable');
167164
};
168165

169166
/**
@@ -217,33 +214,6 @@ NielsenDTVR.prototype.sendID3 = function(event) {
217214
}
218215
};
219216

220-
/**
221-
* End playback
222-
*
223-
* @api private
224-
*/
225-
226-
NielsenDTVR.prototype.end = function(event, interruptType) {
227-
var livestream = event.proxy('properties.livestream');
228-
var position = event.proxy('properties.position');
229-
var time;
230-
if (livestream) {
231-
time = Math.floor(event.timestamp().getTime() / 1000);
232-
} else if (position) {
233-
time = position;
234-
}
235-
236-
if (time) {
237-
this.client.ggPM('end', time);
238-
}
239-
240-
if (interruptType !== 'recoverable') {
241-
this.ID3 = null;
242-
this.previousEvent = null;
243-
this.isDTVRStream = null;
244-
}
245-
};
246-
247217
/**
248218
* Helper to validate that metadata contains required properties, i.e.
249219
* all values are truthy Strings. We don't need to validate keys b/c

integrations/nielsen-dtvr/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@segment/analytics.js-integration-nielsen-dtvr",
33
"description": "The Nielsen DTVR analytics.js integration.",
4-
"version": "1.0.1",
4+
"version": "1.0.2",
55
"keywords": [
66
"analytics.js",
77
"analytics.js-integration",

integrations/nielsen-dtvr/test/index.test.js

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ describe('NielsenDTVR', function() {
128128

129129
analytics.track('Video Playback Interrupted', props);
130130
analytics.called(nielsenDTVR.client.ggPM, 'sendID3', props.custom);
131-
analytics.called(nielsenDTVR.client.ggPM, 'end', props.position);
132131
});
133132
});
134133

@@ -164,13 +163,11 @@ describe('NielsenDTVR', function() {
164163
it('should send video playback buffer started', function() {
165164
analytics.track('Video Playback Buffer Started', props);
166165
analytics.called(nielsenDTVR.client.ggPM, 'sendID3', props.id3);
167-
analytics.called(nielsenDTVR.client.ggPM, 'end', props.position);
168166
});
169167

170168
it('should send video playback interrupted', function() {
171169
analytics.track('Video Playback Interrupted', props);
172170
analytics.called(nielsenDTVR.client.ggPM, 'sendID3', props.id3);
173-
analytics.called(nielsenDTVR.client.ggPM, 'end', props.position);
174171
});
175172

176173
it('should send video playback resumed', function() {
@@ -186,7 +183,6 @@ describe('NielsenDTVR', function() {
186183
it('should send video playback seek started', function() {
187184
analytics.track('Video Playback Seek Started', props);
188185
analytics.called(nielsenDTVR.client.ggPM, 'sendID3', props.id3);
189-
analytics.called(nielsenDTVR.client.ggPM, 'end', props.position);
190186
});
191187

192188
it('should send video playback seek completed', function() {
@@ -201,20 +197,10 @@ describe('NielsenDTVR', function() {
201197

202198
it('should send video playback completed', function() {
203199
analytics.track('Video Playback Completed', props);
204-
analytics.called(nielsenDTVR.client.ggPM, 'end', props.position);
205200
});
206201

207-
it('should send video playback completed livestream', function() {
208-
props.livestream = true;
209-
210-
var timestamp = new Date();
211-
// when live streams end, we need to pass the Unix timestamp in seconds per Nielsen
212-
var unixTime = Math.floor(timestamp.getTime() / 1000);
213-
214-
analytics.track('Video Playback Completed', props, {
215-
timestamp: timestamp
216-
});
217-
analytics.called(nielsenDTVR.client.ggPM, 'end', unixTime);
202+
it('should send video playback exited', function() {
203+
analytics.track('Video Playback Exited', props);
218204
});
219205
});
220206

@@ -234,7 +220,6 @@ describe('NielsenDTVR', function() {
234220

235221
it('should send video content completed', function() {
236222
analytics.track('Video Content Completed', props);
237-
analytics.called(nielsenDTVR.client.ggPM, 'end', props.position);
238223
});
239224

240225
it('should send video content started', function() {
@@ -257,27 +242,6 @@ describe('NielsenDTVR', function() {
257242
});
258243
analytics.didNotCall(nielsenDTVR.client.ggPM, 'sendID3', props.id3);
259244
});
260-
261-
it('should call end before starting a new content stream if the previous stream was not ended correctly', function() {
262-
var previousEvent = {
263-
asset_id: '123',
264-
ad_asset_id: null,
265-
channel: 'segment',
266-
load_type: 'linear',
267-
position: 1,
268-
id3: '1',
269-
livestream: true
270-
};
271-
var currentEvent = props;
272-
var timestamp = new Date();
273-
// when live streams end, we need to pass the Unix timestamp in seconds per Nielsen
274-
var unixTime = Math.floor(timestamp.getTime() / 1000);
275-
analytics.track('Video Content Started', previousEvent, {
276-
timestamp: timestamp
277-
});
278-
analytics.track('Video Content Started', currentEvent);
279-
analytics.called(nielsenDTVR.client.ggPM, 'end', unixTime);
280-
});
281245
});
282246

283247
describe('#persisted data', function() {

yarn.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,9 +2854,9 @@ analytics-events@^1.2.0:
28542854
integrity sha1-sDCnqCv+tF7w2qdNIM+ai6TUvcs=
28552855

28562856
analytics-events@^2.0.2, analytics-events@^2.1.0:
2857-
version "2.2.0"
2858-
resolved "https://registry.yarnpkg.com/analytics-events/-/analytics-events-2.2.0.tgz#f00f55946940a6357809582f6fded6ab80034b84"
2859-
integrity sha1-8A9VlGlApjV4CVgvb97Wq4ADS4Q=
2857+
version "2.2.5"
2858+
resolved "https://registry.npmjs.org/analytics-events/-/analytics-events-2.2.5.tgz#7f20217a7b08d3bf719e48b62b0785064e74f71b"
2859+
integrity sha512-WuuEs52q/mxvM/wvLSdNA71iEqwTSnLodkwnPpzVUYzFuoR1YOujvN09ZMpkcaVhkTBK/rbfPiSpDEDD8FFD6Q==
28602860
dependencies:
28612861
"@ndhoule/foldl" "^2.0.1"
28622862
"@ndhoule/map" "^2.0.1"

0 commit comments

Comments
 (0)