Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Fixes twitch event logging #13834

Merged
merged 1 commit into from
Apr 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 22 additions & 3 deletions app/browser/api/ledger.js
Original file line number Diff line number Diff line change
Expand Up @@ -2687,12 +2687,30 @@ const onMediaRequest = (state, xhr, type, details) => {
return state
}

const tabId = details.get('tabId')
const parsed = ledgerUtil.getMediaData(xhr, type, details)
if (parsed == null) {
return state
}

if (Array.isArray(parsed)) {
parsed.forEach(data => {
if (data) {
state = module.exports.processMediaData(state, data, type, details)
}
})
} else {
state = module.exports.processMediaData(state, parsed, type, details)
}

return state
}

const processMediaData = (state, parsed, type, details) => {
let tabId = tabState.TAB_ID_NONE
if (details) {
tabId = details.get('tabId')
}

const mediaId = ledgerUtil.getMediaId(parsed, type)

if (clientOptions.loggingP) {
Expand Down Expand Up @@ -2774,7 +2792,7 @@ const onMediaRequest = (state, xhr, type, details) => {

if (_internal.verboseP) {
console.log('\ngetPublisherFromMediaProps mediaProps=' + JSON.stringify(mediaProps, null, 2) + '\nresponse=' +
JSON.stringify(response, null, 2))
JSON.stringify(response, null, 2))
}

appActions.onLedgerMediaPublisher(mediaKey, response, duration, revisited)
Expand Down Expand Up @@ -3061,7 +3079,8 @@ const getMethods = () => {
referralCheck,
roundtrip,
onFetchReferralHeaders,
onReferralRead
onReferralRead,
processMediaData
}

let privateMethods = {}
Expand Down
1 change: 0 additions & 1 deletion app/common/constants/twitchEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const events = {
BUFFER_EMPTY: 'buffer-empty',
BUFFER_REFILL: 'buffer-refill',
MINUTE_WATCHED: 'minute-watched',
PLAY_MANIFEST: 'video_play_master_manifest',
PLAY_PAUSE: 'video_pause',
SEEK: 'player_click_vod_seek',
START: 'video-play',
Expand Down
28 changes: 18 additions & 10 deletions app/common/lib/ledgerUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,13 +278,27 @@ const getMediaData = (xhr, type, details) => {
}
case ledgerMediaProviders.TWITCH:
{
const data = details.getIn(['uploadData', 0, 'bytes'])
if (!data) {
const uploadData = details.get('uploadData') || Immutable.List()

if (uploadData.size === 0) {
result = null
break
}

let params = uploadData.reduce((old, item) => {
const bytes = item.get('bytes')
let data = ''
if (bytes) {
data = Buffer.from(bytes).toString('utf8') || ''
}
return old + data
}, '')

if (!params || params.length === 0) {
result = null
break
}

let params = Buffer.from(data).toString('utf8') || ''
const paramQuery = queryString.parse(params)

if (!paramQuery || !paramQuery.data) {
Expand All @@ -307,13 +321,7 @@ const getMediaData = (xhr, type, details) => {
break
}

if (!Array.isArray(parsed)) {
result = null
break
}

result = parsed[0]

result = parsed
break
}
}
Expand Down
98 changes: 87 additions & 11 deletions test/unit/app/browser/api/ledgerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ describe('ledger api unit tests', function () {
let updater

// constants
const xhr = 'https://www.youtube.com/api/stats/watchtime?docid=kLiLOkzLetE&st=11.338&et=21.339'
const videoId = 'youtube_kLiLOkzLetE'
const publisherKey = 'youtube#channel:UCFNTTISby1c_H-rm5Ww5rZg'

Expand Down Expand Up @@ -562,8 +561,81 @@ describe('ledger api unit tests', function () {
})

describe('onMediaRequest', function () {
let processMediaDataSpy
const url = 'https://video-edge-f0f586.sjc01.hls.ttvnw.net/v1/segment/CuDNI7xCy5CGJ8g7G3thdHT26OW_DhnEuVw0tRGN-DKhJxrRTeGe...'

beforeEach(function () {
processMediaDataSpy = sinon.spy(ledgerApi, 'processMediaData')
})

afterEach(function () {
processMediaDataSpy.restore()
})

it('does nothing if input is null', function () {
const result = ledgerApi.onMediaRequest(defaultAppState)
assert.deepEqual(result.toJS(), defaultAppState.toJS())
assert(processMediaDataSpy.notCalled)
})

it('does nothing if input is null', function () {
const result = ledgerApi.onMediaRequest(defaultAppState, url, ledgerMediaProviders.TWITCH, Immutable.fromJS({
firstPartyUrl: 'https://www.twitch.tv/videos/241926348',
uploadData: [{
bytes: new Uint8Array([])
}]
}))
assert.deepEqual(result.toJS(), defaultAppState.toJS())
assert(processMediaDataSpy.notCalled)
})

it('parsed data is single object', function () {
const result = ledgerApi.onMediaRequest(defaultAppState, url, ledgerMediaProviders.TWITCH, Immutable.fromJS({
firstPartyUrl: 'https://www.twitch.tv/videos/241926348',
uploadData: [{
bytes: new Uint8Array([
100, 97, 116, 97, 61, 87, 51, 115, 105, 90, 88, 90, 108, 98, 110, 81, 105, 79, 105,
74, 116, 97, 87, 53, 49, 100, 71, 85, 116, 100, 50, 70, 48, 89, 50, 104, 108, 90, 67, 73, 115, 73, 110,
66, 121, 98, 51, 66, 108, 99, 110, 82, 112, 90, 88, 77, 105, 79, 110, 115, 105, 89, 50, 104, 104, 98,
109, 53, 108, 98, 67, 73, 54, 73, 110, 82, 51, 73, 110, 49, 57, 88, 81, 61, 61
])
}]
}))

assert(processMediaDataSpy.calledOnce)
assert.notDeepEqual(result.toJS(), defaultAppState.toJS())
})

it('parsed data is array of objects', function () {
const result = ledgerApi.onMediaRequest(defaultAppState, url, ledgerMediaProviders.TWITCH, Immutable.fromJS({
firstPartyUrl: 'https://www.twitch.tv/videos/241926348',
uploadData: [{
bytes: new Uint8Array([
100, 97, 116, 97, 61, 87, 51, 115, 105, 90, 88, 90, 108, 98, 110, 81, 105, 79, 105,
74, 50, 97, 87, 82, 108, 98, 121, 49, 119, 98, 71, 70, 53, 73, 105, 119, 105, 99, 72, 74, 118, 99, 71,
86, 121, 100, 71, 108, 108, 99, 121, 73, 54, 101, 121, 74, 106, 97, 71, 70, 117, 98, 109, 86, 115, 73,
106, 111, 105, 100, 72, 99, 105, 102, 88, 48, 115, 101, 121, 74, 108, 100, 109, 86, 117, 100, 67, 73, 54,
73, 110, 90, 112, 90, 71, 86, 118, 88, 50, 86, 121, 99, 109, 57, 121, 73, 105, 119, 105, 99, 72, 74, 118,
99, 71, 86, 121, 100, 71, 108, 108, 99, 121, 73, 54, 101, 121, 74, 106, 97, 71, 70, 117, 98, 109, 86,
115, 73, 106, 111, 105, 100, 72, 99, 105, 102, 88, 49, 100
])
}]
}))

assert(processMediaDataSpy.calledTwice)
assert.notDeepEqual(result.toJS(), defaultAppState.toJS())
})
})

describe('processMediaData', function () {
let mediaSpy, saveVisitSpy

const parsedData = {
docid: 'kLiLOkzLetE',
st: '11.338',
et: '21.339'
}

const cacheAppState = defaultAppState
.setIn(['cache', 'ledgerVideos', videoId], Immutable.fromJS({
publisher: publisherKey
Expand All @@ -590,7 +662,7 @@ describe('ledger api unit tests', function () {
})

it('does nothing if input is null', function () {
const result = ledgerApi.onMediaRequest(defaultAppState)
const result = ledgerApi.processMediaData(defaultAppState)
assert.deepEqual(result.toJS(), defaultAppState.toJS())
assert(mediaSpy.notCalled)
assert(saveVisitSpy.notCalled)
Expand All @@ -614,22 +686,26 @@ describe('ledger api unit tests', function () {
tabState = savedTabState
})
it('does nothing if tab is private', function () {
const xhr2 = 'https://www.youtube.com/api/stats/watchtime?docid=kLiLOkzLetE&st=20.338&et=21.339'
ledgerApi.onMediaRequest(cacheAppState, xhr2, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
const data = {
docid: 'kLiLOkzLetE',
st: '20.338',
et: '21.339'
}
ledgerApi.processMediaData(cacheAppState, data, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
assert(mediaSpy.notCalled)
assert(saveVisitSpy.notCalled)
})
})

it('set currentMediaKey when it is different than saved', function () {
ledgerApi.onMediaRequest(defaultAppState, xhr, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
ledgerApi.processMediaData(defaultAppState, parsedData, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
assert.equal(ledgerApi.getCurrentMediaKey(), videoId)
assert(mediaSpy.calledOnce)
assert(saveVisitSpy.notCalled)
})

it('get data from cache, if we have publisher in synopsis', function () {
ledgerApi.onMediaRequest(cacheAppState, xhr, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
ledgerApi.processMediaData(cacheAppState, parsedData, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
assert(mediaSpy.notCalled)
assert(saveVisitSpy.withArgs(cacheAppState, publisherKey, {
duration: 10001,
Expand All @@ -642,14 +718,14 @@ describe('ledger api unit tests', function () {
const state = defaultAppState.setIn(['cache', 'ledgerVideos', videoId], Immutable.fromJS({
publisher: publisherKey
}))
ledgerApi.onMediaRequest(state, xhr, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
ledgerApi.processMediaData(state, parsedData, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
assert(mediaSpy.calledOnce)
assert(saveVisitSpy.notCalled)
})

it('revisited if visiting the same media in the same tab', function () {
// first call, revisit false
ledgerApi.onMediaRequest(cacheAppState, xhr, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
ledgerApi.processMediaData(cacheAppState, parsedData, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
assert.equal(ledgerApi.getCurrentMediaKey(), videoId)
assert(saveVisitSpy.withArgs(cacheAppState, publisherKey, {
duration: 10001,
Expand All @@ -658,7 +734,7 @@ describe('ledger api unit tests', function () {
}).calledOnce)

// second call, revisit true
ledgerApi.onMediaRequest(cacheAppState, xhr, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
ledgerApi.processMediaData(cacheAppState, parsedData, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 1}))
assert(mediaSpy.notCalled)
assert(saveVisitSpy.withArgs(cacheAppState, publisherKey, {
duration: 10001,
Expand All @@ -670,7 +746,7 @@ describe('ledger api unit tests', function () {
it('revisited if visiting media in the background tab', function () {
// first call, revisit false
ledgerApi.setCurrentMediaKey('11')
ledgerApi.onMediaRequest(cacheAppState, xhr, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 10}))
ledgerApi.processMediaData(cacheAppState, parsedData, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 10}))
assert.equal(ledgerApi.getCurrentMediaKey(), '11')
assert(saveVisitSpy.withArgs(cacheAppState, publisherKey, {
duration: 10001,
Expand All @@ -690,7 +766,7 @@ describe('ledger api unit tests', function () {
}
}))

ledgerApi.onMediaRequest(badState, xhr, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 10}))
ledgerApi.processMediaData(badState, parsedData, ledgerMediaProviders.YOUTUBE, Immutable.fromJS({tabId: 10}))
assert(mediaSpy.calledOnce)
assert(saveVisitSpy.notCalled)
})
Expand Down
76 changes: 72 additions & 4 deletions test/unit/app/common/lib/ledgerUtilTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -558,19 +558,87 @@ describe('ledgerUtil unit test', function () {
assert.equal(result, null)
})

it('obj is parsed correctly', function () {
it('single event is parsed correctly', function () {
const result = ledgerUtil.getMediaData(url, ledgerMediaProviders.TWITCH, Immutable.fromJS({
firstPartyUrl: 'https://www.twitch.tv/videos/241926348',
uploadData: [{
bytes: new Uint8Array([100, 97, 116, 97, 61, 87, 51, 115, 105, 90, 88, 90, 108, 98, 110, 81, 105, 79, 105, 74, 116, 97, 87, 53, 49, 100, 71, 85, 116, 100, 50, 70, 48, 89, 50, 104, 108, 90, 67, 73, 115, 73, 110, 66, 121, 98, 51, 66, 108, 99, 110, 82, 112, 90, 88, 77, 105, 79, 110, 115, 105, 89, 50, 104, 104, 98, 109, 53, 108, 98, 67, 73, 54, 73, 110, 82, 51, 73, 110, 49, 57, 88, 81, 61, 61])
bytes: new Uint8Array([
100, 97, 116, 97, 61, 87, 51, 115, 105, 90, 88, 90, 108, 98, 110, 81, 105, 79, 105,
74, 116, 97, 87, 53, 49, 100, 71, 85, 116, 100, 50, 70, 48, 89, 50, 104, 108, 90, 67, 73, 115, 73, 110,
66, 121, 98, 51, 66, 108, 99, 110, 82, 112, 90, 88, 77, 105, 79, 110, 115, 105, 89, 50, 104, 104, 98,
109, 53, 108, 98, 67, 73, 54, 73, 110, 82, 51, 73, 110, 49, 57, 88, 81, 61, 61
])
}]
}))
assert.deepEqual(result, {
assert.deepEqual(result, [{
event: twitchEvents.MINUTE_WATCHED,
properties: {
channel: 'tw'
}
})
}])
})

it('multiple events are parsed correctly', function () {
const result = ledgerUtil.getMediaData(url, ledgerMediaProviders.TWITCH, Immutable.fromJS({
firstPartyUrl: 'https://www.twitch.tv/videos/241926348',
uploadData: [{
bytes: new Uint8Array([
100, 97, 116, 97, 61, 87, 51, 115, 105, 90, 88, 90, 108, 98, 110, 81, 105, 79, 105,
74, 50, 97, 87, 82, 108, 98, 121, 49, 119, 98, 71, 70, 53, 73, 105, 119, 105, 99, 72, 74, 118, 99, 71,
86, 121, 100, 71, 108, 108, 99, 121, 73, 54, 101, 121, 74, 106, 97, 71, 70, 117, 98, 109, 86, 115, 73,
106, 111, 105, 100, 72, 99, 105, 102, 88, 48, 115, 101, 121, 74, 108, 100, 109, 86, 117, 100, 67, 73, 54,
73, 110, 90, 112, 90, 71, 86, 118, 88, 50, 86, 121, 99, 109, 57, 121, 73, 105, 119, 105, 99, 72, 74, 118,
99, 71, 86, 121, 100, 71, 108, 108, 99, 121, 73, 54, 101, 121, 74, 106, 97, 71, 70, 117, 98, 109, 86,
115, 73, 106, 111, 105, 100, 72, 99, 105, 102, 88, 49, 100
])
}]
}))
assert.deepEqual(result, [{
event: twitchEvents.START,
properties: {
channel: 'tw'
}
}, {
event: twitchEvents.VIDEO_ERROR,
properties: {
channel: 'tw'
}
}])
})

it('multiple upload data', function () {
const result = ledgerUtil.getMediaData(url, ledgerMediaProviders.TWITCH, Immutable.fromJS({
firstPartyUrl: 'https://www.twitch.tv/videos/241926348',
uploadData: [
{
bytes: new Uint8Array([
100, 97, 116, 97, 61, 87, 51, 115, 105, 90, 88, 90, 108, 98, 110, 81, 105, 79, 105, 74, 50, 97, 87,
82, 108, 98, 121, 49, 119, 98, 71, 70, 53, 73, 105, 119, 105, 99
])
},
{
bytes: new Uint8Array([
72, 74, 118, 99, 71, 86, 121, 100, 71, 108, 108, 99, 121, 73, 54, 101, 121, 74,
106, 97, 71, 70, 117, 98, 109, 86, 115, 73, 106, 111, 105, 100, 72, 99, 105, 102, 88, 48, 115, 101,
121, 74, 108, 100, 109, 86, 117, 100, 67, 73, 54, 73, 110, 90, 112, 90, 71, 86, 118, 88, 50, 86, 121,
99, 109, 57, 121, 73, 105, 119, 105, 99, 72, 74, 118, 99, 71, 86, 121, 100, 71, 108, 108, 99, 121,
73, 54, 101, 121, 74, 106, 97, 71, 70, 117, 98, 109, 86, 115, 73, 106, 111, 105, 100, 72, 99, 105,
102, 88, 49, 100
])
}
]
}))
assert.deepEqual(result, [{
event: twitchEvents.START,
properties: {
channel: 'tw'
}
}, {
event: twitchEvents.VIDEO_ERROR,
properties: {
channel: 'tw'
}
}])
})
})
})
Expand Down