lbry-desktop/ui/component/viewers/videoViewer/internal/videojs-events.jsx

294 lines
8.1 KiB
React
Raw Normal View History

// @flow
import { useEffect } from 'react';
import analytics from 'analytics';
const isDev = process.env.NODE_ENV !== 'production';
const TAP = {
NONE: 'NONE',
UNMUTE: 'UNMUTE',
RETRY: 'RETRY',
};
const VideoJsEvents = ({
tapToUnmuteRef,
tapToRetryRef,
setReload,
playerRef,
replay,
claimId,
userId,
claimValues,
2022-05-29 11:54:47 +02:00
channelTitle,
embedded,
uri,
doAnalyticsView,
doAnalyticsBuffer,
claimRewards,
playerServerRef,
2022-03-15 17:18:08 +01:00
isLivestreamClaim,
}: {
tapToUnmuteRef: any, // DOM element
tapToRetryRef: any, // DOM element
setReload: any, // react hook
playerRef: any, // DOM element
replay: boolean,
claimId: ?string,
userId: ?number,
claimValues: any,
2022-05-29 11:54:47 +02:00
channelTitle: string,
embedded: boolean,
uri: string,
doAnalyticsView: (string, number) => any,
doAnalyticsBuffer: (string, any) => void,
claimRewards: () => void,
playerServerRef: any,
2022-03-15 17:18:08 +01:00
isLivestreamClaim: boolean,
}) => {
function doTrackingBuffered(e: Event, data: any) {
const playerPoweredBy = isLivestreamClaim ? 'lvs' : playerServerRef.current;
data.playPoweredBy = playerPoweredBy;
data.isLivestream = isLivestreamClaim;
// $FlowFixMe
data.bitrateAsBitsPerSecond = this.tech(true).vhs?.playlists?.media?.().attributes?.BANDWIDTH;
doAnalyticsBuffer(uri, data);
}
/**
* Analytics functionality that is run on first video start
* @param e - event from videojs (from the plugin?)
* @param data - only has secondsToLoad property
*/
function doTrackingFirstPlay(e: Event, data: any) {
const playerPoweredBy = isLivestreamClaim ? 'lvs' : playerServerRef.current;
// how long until the video starts
let timeToStartVideo = data.secondsToLoad;
analytics.playerVideoStartedEvent(embedded);
2022-03-15 17:18:08 +01:00
// don't send this data on livestream
if (!isLivestreamClaim) {
// convert bytes to bits, and then divide by seconds
const contentInBits = Number(claimValues.source.size) * 8;
const durationInSeconds = claimValues.video && claimValues.video.duration;
let bitrateAsBitsPerSecond;
if (durationInSeconds) {
bitrateAsBitsPerSecond = Math.round(contentInBits / durationInSeconds);
}
2022-03-15 17:18:08 +01:00
// populates data for watchman, sends prom and matomo event
analytics.videoStartEvent(
claimId,
timeToStartVideo,
playerPoweredBy,
userId,
uri,
this, // pass the player
bitrateAsBitsPerSecond,
isLivestreamClaim
);
} else {
// populates data for watchman, sends prom and matomo event
analytics.videoStartEvent(
claimId,
0,
playerPoweredBy,
userId,
uri,
this, // pass the player
// $FlowFixMe
this.tech(true).vhs?.playlists?.media?.().attributes?.BANDWIDTH,
isLivestreamClaim
2022-03-15 17:18:08 +01:00
);
}
// hit backend to mark a view
doAnalyticsView(uri, timeToStartVideo).then(() => {
claimRewards();
});
}
function onInitialPlay() {
const player = playerRef.current;
2022-05-29 11:54:47 +02:00
updateMediaSession();
Reuse videojs instance between video reload, return mobile UI plugin for iOS (#1512) * add mobile plugin back on ios * further touchups and fix ios * finish mobile functionality * dont show big play button on mobile * remove logs * proof of concept * dont go full screen on rotate * add back functionality * replace dispose event with navigate away * bugfix * turn off show if you liked button and nag only on homepage * add back old functionality * ending event not working * test here * working but needs cleanup * more player touchups * bugfix * add settings button on mobile * more touchups * more cleanups * touchup loading functionality * fix hover thumbnails * touchup and eslint fix * fix repopulation bug * change recsys event name * bugfix events * change the way buttons are removed and added * finish chapters button * refactor to use videojs methods * refactor to fix autoplay next * ux touchups * seems to be behaving properly * control bar behaving how it should * fix control bar on ios * working on flow and eslint errors * bugfix and flow fixes * bring back nudge * fix playlist button bug * remove chapter markers properly * show big play button * bugfix recsys closed event * fix analytics bug * fix embeds * bugfix * possible bugfix for kp * bugfix playlist buttons * fix issue with mobile ui plugin * fix firefox autoplay issue * fix bug for play on floating player closed * bugfix volume control for ios * instantiate new player if switching between claim types * fix flow and lint errors * fix control bar not showing up when switching sources * dispose old player if recreating * bugfix save position * reset recsys data between videos * fix audio upload posters * clear claimSrcVhs on reload * bugfix errant image previews showing up * reset player value of having already switched quality * fix watch position not being used * bugfix switching between sources not perserving position * fix save position bug * fix playlist buttons * bugfix * code cleanup and add back 5 second feature
2022-06-10 18:18:58 +02:00
// $FlowIssue
player.bigPlayButton?.hide();
if (player && (player.muted() || player.volume() === 0)) {
// The css starts as "hidden". We make it visible here without
// re-rendering the whole thing.
showTapButton(TAP.UNMUTE);
} else {
showTapButton(TAP.NONE);
}
}
function onVolumeChange() {
const player = playerRef.current;
if (player && !player.muted()) {
showTapButton(TAP.NONE);
}
}
function onError() {
const player = playerRef.current;
showTapButton(TAP.RETRY);
// reattach initial play listener in case we recover from error successfully
// $FlowFixMe
player.one('play', onInitialPlay);
if (player && player.loadingSpinner) {
player.loadingSpinner.hide();
}
}
// const onEnded = React.useCallback(() => {
// if (!adUrl) {
// showTapButton(TAP.NONE);
// }
// }, [adUrl]);
// when user clicks 'Unmute' button, turn audio on and hide unmute button
function unmuteAndHideHint() {
const player = playerRef.current;
if (player) {
player.muted(false);
if (player.volume() === 0) {
player.volume(1.0);
}
}
showTapButton(TAP.NONE);
}
function retryVideoAfterFailure() {
const player = playerRef.current;
if (player) {
setReload(Date.now());
showTapButton(TAP.NONE);
}
}
function showTapButton(tapButton) {
const setButtonVisibility = (theRef, newState) => {
// Use the DOM to control the state of the button to prevent re-renders.
if (theRef.current) {
const curState = theRef.current.style.visibility === 'visible';
if (newState !== curState) {
theRef.current.style.visibility = newState ? 'visible' : 'hidden';
}
}
};
switch (tapButton) {
case TAP.NONE:
setButtonVisibility(tapToUnmuteRef, false);
setButtonVisibility(tapToRetryRef, false);
break;
case TAP.UNMUTE:
setButtonVisibility(tapToUnmuteRef, true);
setButtonVisibility(tapToRetryRef, false);
break;
case TAP.RETRY:
setButtonVisibility(tapToUnmuteRef, false);
setButtonVisibility(tapToRetryRef, true);
break;
default:
if (isDev) throw new Error('showTapButton: unexpected ref');
break;
}
}
2022-05-29 11:54:47 +02:00
function updateMediaSession() {
if ('mediaSession' in navigator) {
const player = playerRef.current;
// $FlowFixMe
navigator.mediaSession.metadata = new window.MediaMetadata({
title: claimValues.title,
artist: channelTitle,
artwork: claimValues?.thumbnail?.url ? [{ src: claimValues.thumbnail.url }] : undefined,
2022-05-29 11:54:47 +02:00
});
// $FlowFixMe
navigator.mediaSession.setActionHandler('seekbackward', function () {
player.currentTime(Math.max(0, player.currentTime() - 10));
});
// $FlowFixMe
navigator.mediaSession.setActionHandler('seekforward', function () {
player.currentTime(Math.max(0, player.currentTime() + 10));
});
}
}
Reuse videojs instance between video reload, return mobile UI plugin for iOS (#1512) * add mobile plugin back on ios * further touchups and fix ios * finish mobile functionality * dont show big play button on mobile * remove logs * proof of concept * dont go full screen on rotate * add back functionality * replace dispose event with navigate away * bugfix * turn off show if you liked button and nag only on homepage * add back old functionality * ending event not working * test here * working but needs cleanup * more player touchups * bugfix * add settings button on mobile * more touchups * more cleanups * touchup loading functionality * fix hover thumbnails * touchup and eslint fix * fix repopulation bug * change recsys event name * bugfix events * change the way buttons are removed and added * finish chapters button * refactor to use videojs methods * refactor to fix autoplay next * ux touchups * seems to be behaving properly * control bar behaving how it should * fix control bar on ios * working on flow and eslint errors * bugfix and flow fixes * bring back nudge * fix playlist button bug * remove chapter markers properly * show big play button * bugfix recsys closed event * fix analytics bug * fix embeds * bugfix * possible bugfix for kp * bugfix playlist buttons * fix issue with mobile ui plugin * fix firefox autoplay issue * fix bug for play on floating player closed * bugfix volume control for ios * instantiate new player if switching between claim types * fix flow and lint errors * fix control bar not showing up when switching sources * dispose old player if recreating * bugfix save position * reset recsys data between videos * fix audio upload posters * clear claimSrcVhs on reload * bugfix errant image previews showing up * reset player value of having already switched quality * fix watch position not being used * bugfix switching between sources not perserving position * fix save position bug * fix playlist buttons * bugfix * code cleanup and add back 5 second feature
2022-06-10 18:18:58 +02:00
function removeControlBar() {
setTimeout(function () {
window.player.controlBar.el().classList.remove('vjs-transitioning-video');
window.player.controlBar.show();
}, 1000 * 2); // wait 2 seconds to hide control bar
}
useEffect(() => {
const player = playerRef.current;
if (replay && player) {
player.play();
}
}, [replay]);
function initializeEvents() {
const player = playerRef.current;
player.one('play', onInitialPlay);
player.on('volumechange', onVolumeChange);
player.on('error', onError);
// custom tracking plugin, event used for watchman data, and marking view/getting rewards
player.on('tracking:firstplay', doTrackingFirstPlay);
// used for tracking buffering for watchman
player.on('tracking:buffered', doTrackingBuffered);
Reuse videojs instance between video reload, return mobile UI plugin for iOS (#1512) * add mobile plugin back on ios * further touchups and fix ios * finish mobile functionality * dont show big play button on mobile * remove logs * proof of concept * dont go full screen on rotate * add back functionality * replace dispose event with navigate away * bugfix * turn off show if you liked button and nag only on homepage * add back old functionality * ending event not working * test here * working but needs cleanup * more player touchups * bugfix * add settings button on mobile * more touchups * more cleanups * touchup loading functionality * fix hover thumbnails * touchup and eslint fix * fix repopulation bug * change recsys event name * bugfix events * change the way buttons are removed and added * finish chapters button * refactor to use videojs methods * refactor to fix autoplay next * ux touchups * seems to be behaving properly * control bar behaving how it should * fix control bar on ios * working on flow and eslint errors * bugfix and flow fixes * bring back nudge * fix playlist button bug * remove chapter markers properly * show big play button * bugfix recsys closed event * fix analytics bug * fix embeds * bugfix * possible bugfix for kp * bugfix playlist buttons * fix issue with mobile ui plugin * fix firefox autoplay issue * fix bug for play on floating player closed * bugfix volume control for ios * instantiate new player if switching between claim types * fix flow and lint errors * fix control bar not showing up when switching sources * dispose old player if recreating * bugfix save position * reset recsys data between videos * fix audio upload posters * clear claimSrcVhs on reload * bugfix errant image previews showing up * reset player value of having already switched quality * fix watch position not being used * bugfix switching between sources not perserving position * fix save position bug * fix playlist buttons * bugfix * code cleanup and add back 5 second feature
2022-06-10 18:18:58 +02:00
player.on('loadstart', function () {
if (embedded) {
// $FlowIssue
player.bigPlayButton?.show();
}
});
Reuse videojs instance between video reload, return mobile UI plugin for iOS (#1512) * add mobile plugin back on ios * further touchups and fix ios * finish mobile functionality * dont show big play button on mobile * remove logs * proof of concept * dont go full screen on rotate * add back functionality * replace dispose event with navigate away * bugfix * turn off show if you liked button and nag only on homepage * add back old functionality * ending event not working * test here * working but needs cleanup * more player touchups * bugfix * add settings button on mobile * more touchups * more cleanups * touchup loading functionality * fix hover thumbnails * touchup and eslint fix * fix repopulation bug * change recsys event name * bugfix events * change the way buttons are removed and added * finish chapters button * refactor to use videojs methods * refactor to fix autoplay next * ux touchups * seems to be behaving properly * control bar behaving how it should * fix control bar on ios * working on flow and eslint errors * bugfix and flow fixes * bring back nudge * fix playlist button bug * remove chapter markers properly * show big play button * bugfix recsys closed event * fix analytics bug * fix embeds * bugfix * possible bugfix for kp * bugfix playlist buttons * fix issue with mobile ui plugin * fix firefox autoplay issue * fix bug for play on floating player closed * bugfix volume control for ios * instantiate new player if switching between claim types * fix flow and lint errors * fix control bar not showing up when switching sources * dispose old player if recreating * bugfix save position * reset recsys data between videos * fix audio upload posters * clear claimSrcVhs on reload * bugfix errant image previews showing up * reset player value of having already switched quality * fix watch position not being used * bugfix switching between sources not perserving position * fix save position bug * fix playlist buttons * bugfix * code cleanup and add back 5 second feature
2022-06-10 18:18:58 +02:00
player.on('playing', removeControlBar);
player.on('playerClosed', () => {
player.off('play', onInitialPlay);
player.off('volumechange', onVolumeChange);
player.off('error', onError);
// custom tracking plugin, event used for watchman data, and marking view/getting rewards
player.off('tracking:firstplay', doTrackingFirstPlay);
// used for tracking buffering for watchman
player.off('tracking:buffered', doTrackingBuffered);
player.off('playing', removeControlBar);
});
// player.on('ended', onEnded);
2022-03-15 17:18:08 +01:00
2022-03-16 03:45:16 +01:00
if (isLivestreamClaim && player) {
2022-03-15 17:18:08 +01:00
player.liveTracker.on('liveedgechange', async () => {
// Only respond to when we fall behind
if (player.liveTracker.atLiveEdge()) return;
// Don't respond to when user has paused the player
if (player.paused()) return;
setTimeout(() => {
// Do not jump ahead if user has paused the player
if (player.paused()) return;
player.liveTracker.seekToLiveEdge();
}, 5 * 1000);
});
}
}
return {
retryVideoAfterFailure,
unmuteAndHideHint,
initializeEvents,
};
};
export default VideoJsEvents;