@@ -22,6 +22,7 @@ var NielsenDCR = (module.exports = integration('Nielsen DCR')
2222 . option ( 'adAssetIdPropertyName' , '' )
2323 . option ( 'subbrandPropertyName' , '' )
2424 . option ( 'clientIdPropertyName' , '' )
25+ . option ( 'sendCurrentTimeLivestream' , false )
2526 . option ( 'contentLengthPropertyName' , 'total_length' )
2627 . option ( 'optout' , false )
2728 . tag (
@@ -74,6 +75,7 @@ NielsenDCR.prototype.initialize = function() {
7475 // for the currently viewing ad or content so that we can handle video switches in the same session
7576 this . currentAssetId = null ;
7677 this . currentPosition = 0 ;
78+ this . isDCRStream = false ;
7779 this . heartbeatId = null ; // reference to setTimeout
7880 this . load ( protocol , this . ready ) ;
7981} ;
@@ -135,12 +137,11 @@ NielsenDCR.prototype.heartbeat = function(assetId, position, livestream) {
135137
136138 if ( livestream ) {
137139 // for livestream events, we calculate a unix timestamp based on the current time an offset value, which should be passed in properties.position
138- this . currentPosition = getOffsetTime ( position ) ;
140+ this . currentPosition = getOffsetTime ( position , self . options ) ;
139141 } else if ( position >= 0 ) {
140142 // this.currentPosition defaults to 0 upon initialization
141143 this . currentPosition = position ;
142144 }
143-
144145 this . heartbeatId = setInterval ( function ( ) {
145146 self . _client . ggPM ( 'setPlayheadPosition' , self . currentPosition ) ;
146147 self . currentPosition ++ ;
@@ -157,6 +158,14 @@ NielsenDCR.prototype.getContentMetadata = function(track, type) {
157158 var propertiesPath = 'properties.' ;
158159 if ( type && type === 'contentEvent' ) propertiesPath = 'properties.content.' ;
159160
161+ var integrationOpts = track . options ( this . name ) ;
162+ var adLoadType = formatLoadType ( integrationOpts , track , propertiesPath ) ;
163+ // adLoadType will be falsy if the `load_type` is NOT 'dynamic' (i.e. it IS 'linear' instead)
164+ // we bubble up false to the calling content/playback method so we can early return, as
165+ // DCR should not be tracking ratings for content of `load_type` 'linear'
166+ if ( ! adLoadType ) return ;
167+ this . isDCRStream = true ;
168+
160169 var customAssetId ;
161170 if ( this . options . contentAssetIdPropertyName ) {
162171 customAssetId = track . proxy (
@@ -167,7 +176,6 @@ NielsenDCR.prototype.getContentMetadata = function(track, type) {
167176 track . proxy ( propertiesPath + 'content_asset_id' ) ||
168177 track . proxy ( propertiesPath + 'asset_id' ) ;
169178 var assetId = customAssetId || assetIdProp ;
170- var integrationOpts = track . options ( this . name ) ;
171179 var contentMetadata = {
172180 type : 'content' ,
173181 assetid : assetId ,
@@ -176,8 +184,7 @@ NielsenDCR.prototype.getContentMetadata = function(track, type) {
176184 isfullepisode : track . proxy ( propertiesPath + 'full_episode' ) ? 'y' : 'n' ,
177185 mediaURL : track . proxy ( 'context.page.url' ) ,
178186 airdate : formatAirdate ( track . proxy ( propertiesPath + 'airdate' ) ) ,
179- // `adLoadType` may be set in int opts, falling back to `load_type` property per our video spec
180- adloadtype : formatLoadType ( integrationOpts , track , propertiesPath ) ,
187+ adloadtype : adLoadType ,
181188 // below metadata fields must all be set in event's integrations opts object
182189 crossId1 : find ( integrationOpts , 'crossId1' ) ,
183190 crossId2 : find ( integrationOpts , 'crossId2' ) ,
@@ -219,8 +226,11 @@ NielsenDCR.prototype.getContentMetadata = function(track, type) {
219226 */
220227
221228NielsenDCR . prototype . getAdMetadata = function ( track ) {
222- var type = track . proxy ( 'properties.type' ) ;
229+ var integrationOpts = track . options ( this . name ) ;
230+ var adLoadType = formatLoadType ( integrationOpts , track , 'properties' ) ;
231+ if ( ! adLoadType ) return ;
223232
233+ var type = track . proxy ( 'properties.type' ) ;
224234 if ( typeof type === 'string' ) type = type . replace ( '-' , '' ) ;
225235
226236 var customAssetId ;
@@ -250,6 +260,7 @@ NielsenDCR.prototype.videoContentStarted = function(track) {
250260 clearInterval ( this . heartbeatId ) ;
251261
252262 var contentMetadata = this . getContentMetadata ( track ) ;
263+ if ( ! contentMetadata ) return ;
253264 var position = track . proxy ( 'properties.position' ) ;
254265 var livestream = track . proxy ( 'properties.livestream' ) ;
255266
@@ -276,6 +287,7 @@ NielsenDCR.prototype.videoContentStarted = function(track) {
276287
277288NielsenDCR . prototype . videoContentPlaying = function ( track ) {
278289 clearInterval ( this . heartbeatId ) ;
290+ if ( ! this . isDCRStream ) return ;
279291
280292 var assetId = this . options . contentAssetIdPropertyName
281293 ? track . proxy ( 'properties.' + this . options . contentAssetIdPropertyName )
@@ -293,12 +305,15 @@ NielsenDCR.prototype.videoContentPlaying = function(track) {
293305 */
294306
295307NielsenDCR . prototype . videoContentCompleted = function ( track ) {
308+ var self = this ;
309+
296310 clearInterval ( this . heartbeatId ) ;
311+ if ( ! this . isDCRStream ) return ;
297312
298313 var position = track . proxy ( 'properties.position' ) ;
299314 var livestream = track . proxy ( 'properties.livestream' ) ;
300315
301- if ( livestream ) position = getOffsetTime ( position ) ;
316+ if ( livestream ) position = getOffsetTime ( position , self . options ) ;
302317
303318 this . _client . ggPM ( 'setPlayheadPosition' , position ) ;
304319 this . _client . ggPM ( 'stop' , position ) ;
@@ -313,21 +328,24 @@ NielsenDCR.prototype.videoContentCompleted = function(track) {
313328NielsenDCR . prototype . videoAdStarted = function ( track ) {
314329 clearInterval ( this . heartbeatId ) ;
315330
316- var contentMetadata = { } ;
317- var adAssetId = this . options . adAssetIdPropertyName
318- ? track . proxy ( 'properties.' + this . options . adAssetIdPropertyName )
319- : track . proxy ( 'properties.asset_id' ) ;
320- var position = track . proxy ( 'properties.position' ) ;
321331 var type = track . proxy ( 'properties.type' ) ;
322-
323332 if ( typeof type === 'string' ) type = type . replace ( '-' , '' ) ;
324333 // edge case: if pre-roll, you must load the content metadata first
325334 // because nielsen ties ad attribution to the content not playback session
335+ var contentMetadata = { } ;
326336 if ( type === 'preroll' ) {
327337 contentMetadata = this . getContentMetadata ( track , 'contentEvent' ) ;
338+ if ( ! contentMetadata ) return ;
328339 this . _client . ggPM ( 'loadMetadata' , contentMetadata ) ;
329340 }
330341
342+ if ( ! this . isDCRStream ) return ;
343+
344+ var adAssetId = this . options . adAssetIdPropertyName
345+ ? track . proxy ( 'properties.' + this . options . adAssetIdPropertyName )
346+ : track . proxy ( 'properties.asset_id' ) ;
347+ var position = track . proxy ( 'properties.position' ) ;
348+
331349 var adMetadata = {
332350 assetid : adAssetId ,
333351 type : type || 'ad'
@@ -348,6 +366,7 @@ NielsenDCR.prototype.videoAdStarted = function(track) {
348366
349367NielsenDCR . prototype . videoAdPlaying = function ( track ) {
350368 clearInterval ( this . heartbeatId ) ;
369+ if ( ! this . isDCRStream ) return ;
351370
352371 var position = track . proxy ( 'properties.position' ) ;
353372 // first argument below is "null" b/c `heartbeat` doesn't need to keep track of ad asset ids
@@ -363,6 +382,7 @@ NielsenDCR.prototype.videoAdPlaying = function(track) {
363382
364383NielsenDCR . prototype . videoAdCompleted = function ( track ) {
365384 clearInterval ( this . heartbeatId ) ;
385+ if ( ! this . isDCRStream ) return ;
366386
367387 var position = track . proxy ( 'properties.position' ) ;
368388
@@ -381,12 +401,14 @@ NielsenDCR.prototype.videoAdCompleted = function(track) {
381401NielsenDCR . prototype . videoPlaybackPaused = NielsenDCR . prototype . videoPlaybackSeekStarted = NielsenDCR . prototype . videoPlaybackBufferStarted = function (
382402 track
383403) {
404+ var self = this ;
384405 clearInterval ( this . heartbeatId ) ;
406+ if ( ! this . isDCRStream ) return ;
385407
386408 var position = track . proxy ( 'properties.position' ) ;
387409 var livestream = track . proxy ( 'properties.livestream' ) ;
388410
389- if ( livestream ) position = getOffsetTime ( position ) ;
411+ if ( livestream ) position = getOffsetTime ( position , self . options ) ;
390412
391413 this . _client . ggPM ( 'stop' , position ) ;
392414} ;
@@ -403,6 +425,7 @@ NielsenDCR.prototype.videoPlaybackResumed = NielsenDCR.prototype.videoPlaybackSe
403425 track
404426) {
405427 clearInterval ( this . heartbeatId ) ;
428+ if ( ! this . isDCRStream ) return ;
406429
407430 var contentAssetId = this . options . contentAssetIdPropertyName
408431 ? track . proxy ( 'properties.' + this . options . contentAssetIdPropertyName )
@@ -422,12 +445,13 @@ NielsenDCR.prototype.videoPlaybackResumed = NielsenDCR.prototype.videoPlaybackSe
422445 this . _client . ggPM ( 'end' , this . currentPosition ) ;
423446
424447 if ( type === 'ad' ) {
425- this . _client . ggPM ( 'loadMetadata' , this . getAdMetadata ( track ) ) ;
448+ var adMetadata = this . getAdMetadata ( track ) ;
449+ if ( ! adMetadata ) return ;
450+ this . _client . ggPM ( 'loadMetadata' , adMetadata ) ;
426451 } else if ( type === 'content' ) {
427- this . _client . ggPM (
428- 'loadMetadata' ,
429- this . getContentMetadata ( track , 'contentEvent' )
430- ) ;
452+ var contentMetadata = this . getContentMetadata ( track , 'contentEvent' ) ;
453+ if ( ! contentMetadata ) return ;
454+ this . _client . ggPM ( 'loadMetadata' , contentMetadata ) ;
431455 }
432456 }
433457
@@ -438,25 +462,31 @@ NielsenDCR.prototype.videoPlaybackResumed = NielsenDCR.prototype.videoPlaybackSe
438462 * Video Playback Completed
439463 * Video Playback Interrupted
440464 *
465+ *
441466 * @api public
442467 */
443468
444469NielsenDCR . prototype . videoPlaybackCompleted = NielsenDCR . prototype . videoPlaybackInterrupted = function (
445470 track
446471) {
472+ var self = this ;
447473 clearInterval ( this . heartbeatId ) ;
474+ if ( ! this . isDCRStream ) return ;
448475
449476 var position = track . proxy ( 'properties.position' ) ;
450477 var livestream = track . proxy ( 'properties.livestream' ) ;
451478
452- if ( livestream ) position = getOffsetTime ( position ) ;
479+ if ( livestream ) position = getOffsetTime ( position , self . options ) ;
453480
454481 this . _client . ggPM ( 'setPlayheadPosition' , position ) ;
455482 this . _client . ggPM ( 'end' , position ) ;
456483
457- // reset state
484+ // reset state because "Video Playback Completed/Interrupted" are "non-recoverable events"
485+ // e.g. they should always be followed by the start of a new video session with either
486+ // "Video Content Started" or "Video Ad Started" events
458487 this . currentPosition = 0 ;
459488 this . currentAssetId = null ;
489+ this . isDCRStream = false ;
460490 this . heartbeatId = null ;
461491} ;
462492
@@ -488,10 +518,10 @@ function formatLoadType(integrationOpts, track, propertiesPath) {
488518 var loadType =
489519 find ( integrationOpts , 'ad_load_type' ) ||
490520 track . proxy ( propertiesPath + 'load_type' ) ||
491- track . proxy ( 'properties.load_type ') ;
492- // linear or dynamic
493- // linear means original ads that were broadcasted with tv airing. much less common use case
494- loadType = loadType === 'dynamic' ? '2' : '1' ;
521+ track . proxy ( propertiesPath + 'loadType ') ;
522+ // DCR is meant to track videos with ad `load_type` dynamic only
523+ // otherwise, we return `false` so we can easily early return in the calling method
524+ loadType = loadType === 'dynamic' ? '2' : false ;
495525 return loadType ;
496526}
497527
@@ -501,14 +531,15 @@ function formatLoadType(integrationOpts, track, propertiesPath) {
501531 * handles offsets for livestreams, if applicable.
502532 *
503533 * @param {* } position Should be negative int representing livestream offset
534+ * @param {* } options Integration settings
504535 * @returns {Number } Unix timestamp in seconds
505536 *
506537 * @api private
507538 */
508539
509- function getOffsetTime ( position ) {
540+ function getOffsetTime ( position , options ) {
510541 var date = Math . floor ( Date . now ( ) / 1000 ) ;
511- if ( ! position ) return date ;
542+ if ( ! position || options . sendCurrentTimeLivestream ) return date ;
512543
513544 try {
514545 if ( typeof position !== 'number' ) {
0 commit comments