npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ps-hackathon-video-player

v0.0.1-test

Published

## Install

Downloads

5

Readme

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