ps-hackathon-video-player
TypeScript icon, indicating that this package has built-in type declarations

0.0.1-test • Public • Published

Video Player

Install

yarn add @a-cloud-guru/video-player

Usage

There's a few examples of usage:

  • examples/create-react-app
  • src/__stories__/Player.stories.js

The player is made of two components: PlayerProvider and Player, the idea being to wrap the Player in a PlayerProvider:

const Component = () => (
  <PlayerProvider sources={sources}>
    <Player />
  </PlayerProvider>
)

where sources looks like:

const sources = {
  '360p': "http://source",
  '720p': "http://source",
  // whatever you want here
  'quality': "src",
}

We also expose a usePlayer hook, allowing a component to access the player state and a few actions:

// player-info.js
export const PlayerInfo = () => {
  const [{ playing }, { play, pause }] = usePlayer();
  return (
    <div>
      <p>Player is {playing ? 'playing' : 'paused'}.</p>
      <button onClick={playing ? pause : play}>{playing ? 'Pause' : 'Play'}</button>
    </div>
  )
}

// another-component.js
import { PlayerInfo } from './player-info';

<PlayerProvider sources={sources}>
  <Player />
  <PlayerInfo />
</PlayerProvider>

List of properties accessible through usePlayer

const [state, actions] = usePlayer();

--STATE--

property default value description
pip false is picture in picture enabled?
muted false is the audio muted?
controlBarVisible false is the control bar visible?
settingsVisible false are the settings visibile?
autoplay true is autoplay on?
volume 1 current volume value
playing false is the video playing?
loading true is the video still loading?
seeking false are we currently seeking forward/backward?
durationSeconds 0 total length of the video
playedSeconds 0 current position in the video
interval { back:15, forward:15, } number of seconds to seek backward/forward
subtitleEnabled false are subtitles enabled?
quality '720p' current quality
playbackRate 1 current playback rate
completedTimerCallbacks [] list of timer callbacks we've already called; avoids triggering them twice
fullscreen false is the player fullscreen?
sources undefined array of sources; refer to the next section for details
subtitle undefined subtitle url; refer to the next section for details
currentCueText '' current subtitle text
url sources[quality] || sources.Auto current url
compact false is the player in "compact" mode? more on that in the next section
hidden false is the player "hidden"? more on that in the next section

--ACTIONS--

property type description
reset function reset the video player to its initial state
play function play the video
pause function pause the video
togglePlay function play/pause helper
prev function trigger the "onPrevious" callback
next function trigger the "onNext" callback
playAgain function seek back to the beginning of the video
mute function mute the audio
unmute function unmute the audio
toggleMute function mute/unmute helper
updateVolume function update the volume to a new value
seekTo function move to a specific second in the video
forward function seek forward state.interval.forward seconds
backward function seek backward state.interval.backward seconds
fullScreen function enables fullscreen
exitFullScreen function disables fullscreen
updatePlaybackRate function change the playback rate
updateSeekInterval function call it with an object containing {forward:seconds} or {backward:seconds} to update the seek interval
updateQuality function update the quality of the video; effectively switches the source
toggleAutoplay function enable/disable autoplay
togglePiP function enable/disable picture in picture
canEnablePiP function is PiP supported by the browser? call it with the url for the current source
toggleSubtitle function turn subtitles on/off
canEnableSubtitle boolean do we have subtitles?
player React ref react reference to the video player element

List of properties on the PlayerProvider

property type description
sources object as described above, this contains a list of quality/source pairs. This is the only actually required field. const sources = { '360p': "http://source", '720p': "http://source", 'quality': "src", }
subtitle string an url to a subtitles file.
getPlayerContainer function used to get a reference to the container parent. Used to handle onClick events for example. Example: () => document.body.
hidden boolean because mounting the player on the page starts loading the video, it's sometimes useful to put the player on the page before it's actually visibile. Using this parameter, we can mount the component, but hide the player and disable a few things which would be disruptive, like the keyboard bindings for example.
compact boolean used to display a smaller version of the video player – currently unstable
showFullControls boolean whether to display "next" and "previous" buttons in the control bar
onPrevious function triggered when prev() is called.
onError function triggered when there's an error trying to play the video, as defined by react-player here.
onNext function triggered when next() is called.
keyProp string a value that is used as a key on the underlying component. Useful to re-render the whole player when changing videos for example. Example: ${courseId}-${lessonId}.
onUpdateProgress function called by onProgress, as defined by react-player here
onControlBar object contains a list of callbacks (functions), triggered in various occasions. More on that later.
timerCallbacks array a list of callbacks to be called at very specific time points in the video. It's been designed to be as flexible as possible, more on that later.
trackFnRef React ref a react reference to a function; essentially a reference where current is a function, called every time the player wants to track a "watched" event.
maxTimeOfNoActivity number, milliseconds Defaults to 5000 (5 seconds). When a user pauses the video, this is the delay after which we send the event through the track function.
maxTimeThreshold number, milliseconds Defaults to 270000 (270 seconds, or 4m30s). While the video is still playing, this is the delay after which we send an event through the track function

--ON CONTROL BAR--

These callbacks are available in the property mentioned in the previous section, called onControlBar.

property type description
onPlay function called before the playback is resumed, using play()
onPause function called before the playback is paused, using pause()
onAutoPlayChange function called before toggling the autoplay, using toggleAutoplay(). The value is a boolean representing the active state.
onPiPChange function called before toggling picture in picture, using togglePip(). The value is a boolean representing the active state.
onPlaybackRateChange function called before changing the speed of the playback, using updatePlaybackRate(). The value is the new playback rate.
onSeekForward function called before seeking forward in the video, using forward(). The value is an object of the following shape { from: where_we_were_in_seconds, to: where_we_moved_in_seconds }
onSeekBackward function called before seeking backward in the video, using backward(). The value is an object of the following shape { from: where_we_were_in_seconds, to: where_we_moved_in_seconds }
onToggleSubtitle function called before toggling the subtitles, using toggleSubtitle(). The value is a boolean representing the active state.
onSendFeedback function called when the "send feedback" button is clicked

--ABOUT TIMER CALLBACKS--

const timerCallbacks = [
  {
    type: "start",
    second: 23,
    callback: () => console.log("called at 23s from the start")
  },
  {
    type: "start",
    percent: 0.3,
    callback: () => console.log("called at 30% of the video")
  },
  {
    type: "end",
    second: 10,
    callback: () => console.log("called at 10s before the end")
  },
  {
    type: "end",
    percent: 20,
    callback: () => console.log("called at 20% from the end / 80% of the video")
  }
]

--VIDEO TRACKING--

  • when a user starts watching a video, every 270s (4min 30s), we send an event – you can think of it as some sort of heartbeat.
  • if the user pauses the video, we send the event after 5 seconds, to avoid being spammed by double clicks on the play button).
  • if a user is watching a video, doesn’t reach the 270s required to trigger the event, but closes their browser/computer/tab/etc, we just keep a record in their browser’s local storage – when they come back to our website, the event we stored here will get sent, so that we don’t lose the time they spent watching in their previous session.

--TRACKING EVENTS--

property type description
actualTime number, in milliseconds this is the actual time, as in the time that the user spends in front of the video.
contentTime number, in seconds this is the content time counterpart – the duration of video content the user has watched. Note that actualTime and contentTime can be differ because of the playback speed.
from number, in seconds when did we start tracking for the current event?
to number, in seconds when did we stop tracking for the current event?
trackedLater boolean whether it’s an event that we could not track because the user moved away from the app, so we tracked it when they came back.
originalTrackDate timestamp this is a timestamp, corresponding to when we recorded the event. If the event is tracked right away, this will be very close to when we actually register the event in Segment, but when it’s tracked after the user has left the app and come back (when trackedLater = true), this originalTrackDate will hold the date at which we recorded the event
currentPlaybackRate number the speed at which the video is played
currentSubtitleEnabled boolean whether the subtitles are on or off
currentPip boolean true if the user is watching the video in Picture-in-Picture
currentQuality string the quality the user is watching the video at

List of properties on the Player component

property type description
containerStyle object spread in the sx prop associated with the player container component (more about it here, it's essentially react styles)
controlBarStyle object spread in the sx prop associated with the control bar component
onEndedCallback function a hook allowing the caller to precisely control what to do at the end of the video.

--ON ENDED CALLBACK--

We've used this to show a popup at the end of the video, only if a set of conditions is fulfilled. Implementation details and example:

const onEndedCallback = ({defaultOnEnd}) => {
  if (Math.random() > 0.5) {
    // do something here, show a popup, etc
    // ...
  } else {
    defaultOnEnd();
  }
}

// implementation details inside Player.js
<ReactPlayer
// onEnded triggered by react-player, as described here: https://github.com/CookPete/react-player#callback-props
  onEnded={() => {
    const defaultOnEnd = () => autoplay && next() && onAutoplay();
    // if onEndedCallback is provided, call it with defaultOnEnd as a param
    return onEndedCallback
      ? onEndedCallback({ pip, fullscreen, defaultOnEnd, durationSeconds })
    // otherwise just call defaultOnEnd
      : defaultOnEnd();
  }}
/>

TODO

  • consider decoupling tracking; should it be in the base player or in a wrapper?
  • fix the disabled linting rules

Readme

Keywords

none

Package Sidebar

Install

npm i ps-hackathon-video-player

Weekly Downloads

0

Version

0.0.1-test

License

MIT

Unpacked Size

528 kB

Total Files

161

Last publish

Collaborators

  • timkinnane