Skip to content

Commit

Permalink
report ophan events
Browse files Browse the repository at this point in the history
  • Loading branch information
sndrs committed Oct 21, 2024
1 parent 61c348f commit 4d1b854
Showing 1 changed file with 85 additions and 86 deletions.
171 changes: 85 additions & 86 deletions dotcom-rendering/src/components/AudioPlayer/AudioPlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { log } from '@guardian/libs';
import type { AudioEvent, TAudioEventType } from '@guardian/ophan-tracker-js';
import { useCallback, useEffect, useRef, useState } from 'react';
// import { submitComponentEvent } from '../../client/ophan/ophan';
import { getOphan } from '../../client/ophan/ophan';
import { Playback } from './components/Playback';
import { ProgressBar } from './components/ProgressBar';
import { CurrentTime, Duration } from './components/time';
Expand Down Expand Up @@ -51,23 +51,23 @@ export const AudioPlayer = ({

// we'll send listening progress reports to ophan at these percentage points
// through playback (100% is handled by the 'ended' event)
const ophanProgressEvents = useRef<Set<AudioProgressEvents>>(
const audioProgressEvents = useRef<Set<AudioProgressEvents>>(
new Set([25, 50, 75]),
);

// wrapper to send audio events to ophan

const sendToOphan = useCallback(
const reportAudioEvent = useCallback(
(eventName: AudioEvents) => {
const ophanEvent: AudioEvent = {
const audioEvent: AudioEvent = {
id: mediaId,
eventType: `audio:content:${eventName}`,
};

// TODO: figure out how to send events to ophan, for now just log them
console.log(ophanEvent);

// return submitComponentEvent(ophanEvent, 'dotcom-rendering');
void getOphan('Web').then((ophan) => {
ophan.record({
audio: audioEvent,
});
});
},
[mediaId],
);
Expand All @@ -87,22 +87,93 @@ export const AudioPlayer = ({
// ref to the <audio /> element that handles playback
const audioRef = useRef<HTMLAudioElement>(null);

// ******************** events *********************

const onWaiting = useCallback(() => {
setIsWaiting(true);
}, []);

const onCanPlay = useCallback(() => {
setIsWaiting(false);
}, []);

const onTimeupdate = useCallback(() => {
if (audioRef.current) {
const newProgress =
(audioRef.current.currentTime / audioRef.current.duration) *
100;

setCurrentTime(audioRef.current.currentTime);
setProgress(newProgress);

// Send progress events to ophan,
// but only if the audio is playing. We don't want to send these events
// just because you skipped around the audio while paused.
if (isPlaying) {
for (const stage of audioProgressEvents.current) {
if (newProgress >= stage) {
audioProgressEvents.current.delete(stage);
reportAudioEvent(String(stage) as AudioEvents);
}
}
}
}
}, [isPlaying, reportAudioEvent]);

const onPlay = useCallback(() => {
setIsPlaying(true);
}, []);

const onPlayOnce = useCallback(() => {
reportAudioEvent('play');
}, [reportAudioEvent]);

const onPause = useCallback(() => {
setIsPlaying(false);
}, []);

const onEnded = useCallback(() => {
reportAudioEvent('end');
}, [reportAudioEvent]);

const onProgress = useCallback(() => {
if (audioRef.current) {
const buffers = audioRef.current.buffered.length;
const end = audioRef.current.buffered.end(buffers - 1);
setBuffer((end / audioRef.current.duration) * 100);
}
}, []);

const onError = useCallback((event: Event) => {
window.guardian.modules.sentry.reportError(
new Error(event.type),
'audio-player',
);
log('dotcom', 'Audio player error:', event);
}, []);

// Set the duration to what we now *know* it is.
// If we already had the correct duration, this will be a no-op anyway.
const onDurationChange = useCallback(() => {
if (audioRef.current) {
setDuration(audioRef.current.duration);
}
}, []);

// ********************* interactions *********************

const boundingClientRect = useRef<DOMRect>();

const playPause = useCallback(() => {
if (audioRef.current) {
if (audioRef.current.paused) {
void audioRef.current.play().catch((error) => {
console.log(error);
});
void audioRef.current.play().catch(onError);
} else {
audioRef.current.pause();
setIsWaiting(false);
}
}
}, []);
}, [onError]);

const skipForward = useCallback(() => {
if (audioRef.current) {
Expand Down Expand Up @@ -179,78 +250,7 @@ export const AudioPlayer = ({
}
}, []);

// ******************** events *********************

const onWaiting = useCallback(() => {
setIsWaiting(true);
}, []);

const onCanPlay = useCallback(() => {
setIsWaiting(false);
}, []);

const onTimeupdate = useCallback(() => {
if (audioRef.current) {
const newProgress =
(audioRef.current.currentTime / audioRef.current.duration) *
100;

setCurrentTime(audioRef.current.currentTime);
setProgress(newProgress);

// Send progress events to ophan,
// but only if the audio is playing. We don't want to send these events
// just because you skipped around the audio while paused.
if (isPlaying) {
for (const stage of ophanProgressEvents.current) {
if (newProgress >= stage) {
ophanProgressEvents.current.delete(stage);
sendToOphan(String(stage) as AudioEvents);
}
}
}
}
}, [isPlaying, sendToOphan]);

const onPlay = useCallback(() => {
setIsPlaying(true);
}, []);

const onPlayOnce = useCallback(() => {
sendToOphan('play');
}, [sendToOphan]);

const onPause = useCallback(() => {
setIsPlaying(false);
}, []);

const onEnded = useCallback(() => {
sendToOphan('end');
}, [sendToOphan]);

const onProgress = useCallback(() => {
if (audioRef.current) {
const buffers = audioRef.current.buffered.length;
const end = audioRef.current.buffered.end(buffers - 1);
setBuffer((end / audioRef.current.duration) * 100);
}
}, []);

const onError = useCallback((event: Event) => {
window.guardian.modules.sentry.reportError(
new Error(event.type),
'audio-player',
);
log('dotcom', 'Audio player (WaveSurfer) error:', event);
}, []);

// Set the duration to what we now *know* it is.
// If we already had the correct duration, this will be a no-op anyway.
const onDurationChange = useCallback(() => {
if (audioRef.current) {
setDuration(audioRef.current.duration);
}
}, []);
// ********************* effects *********************

useEffect(() => {
if (!audioRef.current) return;
Expand All @@ -276,7 +276,6 @@ export const AudioPlayer = ({
audio.removeEventListener('seeking', onTimeupdate);
audio.removeEventListener('durationchange', onDurationChange);
audio.removeEventListener('play', onPlay);
audio.removeEventListener('play', onPlayOnce);
audio.removeEventListener('pause', onPause);
audio.removeEventListener('ended', onEnded);
audio.removeEventListener('error', onError);
Expand Down

0 comments on commit 4d1b854

Please sign in to comment.