Skip to content

Commit

Permalink
Fix options.boundaries not being respected (close #1044)
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-el committed Jan 31, 2022
1 parent 6bc1841 commit 6ef2792
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 77 deletions.
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@snowplow/browser-plugin-youtube-tracking",
"comment": "Fix options.boundaries not being respected (#1044)",
"type": "none"
}
],
"packageName": "@snowplow/browser-plugin-youtube-tracking"
}
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@snowplow/javascript-tracker",
"comment": "Fix options.boundaries not being respected (#1044)",
"type": "none"
}
],
"packageName": "@snowplow/javascript-tracker"
}
59 changes: 0 additions & 59 deletions plugins/browser-plugin-youtube-tracking/src/helperFunctions.ts
@@ -1,69 +1,10 @@
import { AllEvents, DefaultEvents, EventGroups } from './eventGroups';
import { SnowplowEvent } from './snowplowEvents';
import { EventGroup, MediaTrackingOptions, TrackingOptions } from './types';
import { CaptureEventToYouTubeEvent, YTPlayerEvent } from './constants';

export function isElementFullScreen(mediaId: string): boolean {
if (document.fullscreenElement) {
return document.fullscreenElement.id === mediaId;
}
return false;
}

export function trackingOptionsParser(mediaId: string, conf?: MediaTrackingOptions): TrackingOptions {
const defaults: TrackingOptions = {
mediaId: mediaId,
captureEvents: DefaultEvents,
youtubeEvents: [
YTPlayerEvent.ONSTATECHANGE,
YTPlayerEvent.ONPLAYBACKQUALITYCHANGE,
YTPlayerEvent.ONERROR,
YTPlayerEvent.ONPLAYBACKRATECHANGE,
],
updateRate: 500,
progress: {
boundaries: [10, 25, 50, 75],
boundaryTimeoutIds: [],
},
};

if (!conf) return defaults;

if (conf.updateRate) defaults.updateRate = conf.updateRate;

if (conf.captureEvents) {
let parsedEvents: EventGroup = [];
for (let ev of conf.captureEvents) {
// If an event is an EventGroup, get the events from that group
if (EventGroups.hasOwnProperty(ev)) {
parsedEvents = parsedEvents.concat(EventGroups[ev]);
} else if (!Object.keys(AllEvents).filter((k) => k === ev)) {
console.warn(`'${ev}' is not a valid event.`);
} else {
parsedEvents.push(ev);
}
}

conf.captureEvents = parsedEvents;

for (let ev of conf.captureEvents) {
const youtubeEvent = CaptureEventToYouTubeEvent[ev];
if (CaptureEventToYouTubeEvent.hasOwnProperty(ev) && defaults.youtubeEvents.indexOf(youtubeEvent) === -1) {
defaults.youtubeEvents.push(youtubeEvent);
}
}

if (conf.captureEvents.indexOf(SnowplowEvent.PERCENTPROGRESS) !== -1) {
defaults.progress = {
boundaries: conf?.boundaries || defaults.progress!.boundaries,
boundaryTimeoutIds: [],
};
}
}

return { ...defaults, ...conf };
}

// URLSearchParams is not supported in IE
// https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

Expand Down
89 changes: 76 additions & 13 deletions plugins/browser-plugin-youtube-tracking/src/index.ts
Expand Up @@ -27,15 +27,23 @@
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import { trackingOptionsParser, addUrlParam, parseUrlParams } from './helperFunctions';
import { YouTubeIFrameAPIURL, YTError, YTPlayerEvent, YTState, YTStateEvent } from './constants';
import { EventData, MediaTrackingOptions, TrackedPlayer, TrackingOptions } from './types';
import { addUrlParam, parseUrlParams } from './helperFunctions';
import {
CaptureEventToYouTubeEvent,
YouTubeIFrameAPIURL,
YTError,
YTPlayerEvent,
YTState,
YTStateEvent,
} from './constants';
import { EventData, EventGroup, MediaTrackingOptions, TrackedPlayer, TrackingOptions } from './types';
import { BrowserPlugin, BrowserTracker, dispatchToTrackersInCollection } from '@snowplow/browser-tracker-core';
import { buildSelfDescribingEvent, CommonEventProperties, Logger, SelfDescribingJson } from '@snowplow/tracker-core';
import { SnowplowEvent } from './snowplowEvents';
import { MediaPlayerEvent } from './contexts';
import { buildYouTubeEvent } from './buildYouTubeEvent';
import { YTEvent } from './youtubeEvents';
import { DefaultEvents, EventGroups, AllEvents } from './eventGroups';

const _trackers: Record<string, BrowserTracker> = {};
const trackedPlayers: Record<string, TrackedPlayer> = {};
Expand All @@ -62,6 +70,61 @@ function trackEvent(
});
}

export function trackingOptionsParser(mediaId: string, conf?: MediaTrackingOptions): TrackingOptions {
const defaults: TrackingOptions = {
mediaId: mediaId,
captureEvents: DefaultEvents,
youtubeEvents: [
YTPlayerEvent.ONSTATECHANGE,
YTPlayerEvent.ONPLAYBACKQUALITYCHANGE,
YTPlayerEvent.ONERROR,
YTPlayerEvent.ONPLAYBACKRATECHANGE,
],
updateRate: 500,
progress: {
boundaries: [10, 25, 50, 75],
boundaryTimeoutIds: [],
},
};

if (!conf) return defaults;
if (conf.label) defaults.label = conf.label;
defaults.updateRate = conf.updateRate || defaults.updateRate;
defaults.captureEvents = conf.captureEvents || defaults.captureEvents;

let parsedEvents: EventGroup = [];
for (let ev of defaults.captureEvents) {
// If an event is an EventGroup, get the events from that group
if (EventGroups.hasOwnProperty(ev)) {
parsedEvents = parsedEvents.concat(EventGroups[ev]);
} else if (!Object.keys(AllEvents).filter((k) => k === ev)) {
LOG.warn(`'${ev}' is not a valid event.`);
} else {
parsedEvents.push(ev);
}
}

defaults.captureEvents = parsedEvents;

for (let ev of defaults.captureEvents) {
if (
CaptureEventToYouTubeEvent.hasOwnProperty(ev) &&
defaults.youtubeEvents.indexOf(CaptureEventToYouTubeEvent[ev]) === -1
) {
defaults.youtubeEvents.push(CaptureEventToYouTubeEvent[ev]);
}
}

if (defaults.captureEvents.indexOf(SnowplowEvent.PERCENTPROGRESS) !== -1) {
defaults.progress = {
boundaries: conf.boundaries || defaults.progress!.boundaries,
boundaryTimeoutIds: [],
};
}

return defaults;
}

export function enableYouTubeTracking(args: { id: string; options?: MediaTrackingOptions }) {
const conf: TrackingOptions = trackingOptionsParser(args.id, args.options);
const el: HTMLIFrameElement = document.getElementById(args.id) as HTMLIFrameElement;
Expand Down Expand Up @@ -175,7 +238,7 @@ function youtubeEvent(player: YT.Player, eventName: string, conf: TrackingOption
enableVolumeTracking(player, conf, eventData);
}

if (conf.hasOwnProperty('boundaries')) {
if (conf.captureEvents.indexOf(SnowplowEvent.PERCENTPROGRESS) !== -1) {
progressHandler(player, eventName, conf);
}

Expand All @@ -198,15 +261,15 @@ function progressHandler(player: YT.Player, eventName: string, conf: TrackingOpt
}

function setPercentageBoundTimeouts(player: YT.Player, conf: TrackingOptions) {
const currentTime = player.getCurrentTime();
conf.progress?.boundaries!.forEach((p) => {
let percentTime = player.getDuration() * 1000 * (p / 100);
if (currentTime !== 0) {
percentTime -= currentTime * 1000;
}
if (p < percentTime) {
conf.progress?.boundaryTimeoutIds.push(
setTimeout(() => waitAnyRemainingTimeAfterTimeout(player, conf, percentTime, p), percentTime)
conf.progress?.boundaries!.forEach((boundary) => {
const absoluteBoundaryTimeMs = player.getDuration() * (boundary / 100) * 1000;
const timeUntilBoundaryEvent = absoluteBoundaryTimeMs - player.getCurrentTime() * 1000;
if (0 < timeUntilBoundaryEvent) {
conf.progress!.boundaryTimeoutIds.push(
setTimeout(
() => waitAnyRemainingTimeAfterTimeout(player, conf, absoluteBoundaryTimeMs, boundary),
timeUntilBoundaryEvent
)
);
}
});
Expand Down
5 changes: 3 additions & 2 deletions plugins/browser-plugin-youtube-tracking/test/youtube.test.ts
Expand Up @@ -29,9 +29,10 @@
*/

import { AllEvents, DefaultEvents } from '../src/eventGroups';
import { addUrlParam, parseUrlParams, trackingOptionsParser } from '../src/helperFunctions';
import { addUrlParam, parseUrlParams } from '../src/helperFunctions';
import { MediaTrackingOptions, TrackingOptions } from '../src/types';
import { YTPlayerEvent } from '../src/constants';
import { trackingOptionsParser } from '../src';

describe('config parser', () => {
const id = 'youtube';
Expand All @@ -56,7 +57,7 @@ describe('config parser', () => {
expect(test).toEqual(default_output);
});

it('parses boundries', () => {
it('parses boundaries', () => {
let trackingOptions: MediaTrackingOptions = {
captureEvents: DefaultEvents,
boundaries: [1, 4, 7, 9, 99],
Expand Down
8 changes: 5 additions & 3 deletions trackers/javascript-tracker/test/integration/youtube.test.ts
Expand Up @@ -145,19 +145,20 @@ describe('YouTube Tracker', () => {

const player = $('#youtube');
player.click(); // emits 'playbackqualitychange' and 'play';
player.keys(Array(3).fill('ArrowRight')); // Skips to the point just before 'percentprogress' fires

browser.waitUntil(
() => {
return browser.call(() =>
fetchResults(docker.url).then((result) => {
return result.length;
return result.some((r: any) => r.event.unstruct_event.data.data.type === 'percentprogress');
})
);
},
{
interval: 5000,
timeout: 60000,
timeoutMsg: "No 'playbackqualitychange' event received",
timeout: 40000,
timeoutMsg: "No 'percentprogress' event received",
}
);

Expand Down Expand Up @@ -203,6 +204,7 @@ describe('YouTube Tracker', () => {

const expected = {
ready: { youtube: { cued: true } },
percentprogress: {},
playbackqualitychange: {},
play: {},
playbackratechange: {},
Expand Down
Expand Up @@ -35,6 +35,7 @@
options: {
label: 'test-label',
captureEvents: ['DefaultEvents'],
boundaries: [1],
},
});
</script>
Expand Down

0 comments on commit 6ef2792

Please sign in to comment.