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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@blendvision/player

v2.27.2

Published

Enjoy our latest update where we have fixed some bugs and improved our framework to provide you more stable playbacking experience.

Readme

Playcraft

Enjoy our latest update where we have fixed some bugs and improved our framework to provide you more stable playbacking experience.

Playcraft provides core player, premium player and premium+ player.

Playcraft also provides Google Cast Sender integration and mini controller UI.

Developer Guide

We use husky v5 to handle git hooks.

Need to setup the husky environment in first time.

yarn install:husky

Now, commitlint and eslint checking work well in every commit.

Getting Started

Install this package from git repository:

yarn add @blendvision/player

And install Shaka player:

yarn add shaka-player

Import, and compose <Video> component to your app:

import React from 'react'
import {Video} from 'playcraft/react'

const MyApp = () => {
  return (
    <MyContainer>
      <Video
        source="https://dash.akamaized.net/dash264/TestCases/1a/sony/SNE_DASH_SD_CASE1A_REVISED.mpd"
        autoplay
      />
    </MyContainer>
  )
}

Legacy Browser Support

To deliver better experience, this package provides bundles with modern syntax for smaller bundle, but legacy browser is still compatible.

If your app is required to legacy browsers, make sure @babel/preset-env is configured correctly and polyfills are installed.

Currently polyfills may be required for these features :

Low Latency Live Mode

Low latency live supports Shaka player only, to opt-in low latency mode, ensure base player is Shaka and attach latencyManager to the player once loaded:

import {latencyManager} from 'playcraft/modules'

const MyLowLatencyLivePlayer = () => {
  const videoRef = useRef()

  return (
    <PremiumPlayer
      shaka
      videoRef={videoRef}
      onPlayerLoaded={player => {
        latencyManager(player, videoRef.current).configure({enabled: true})
      }}
    />
  )
}

API Reference

Sub bundles

There's 4 sub bundles in this package, to provide player funcitons & components to different environments:

  • playcraft: Original bundle for backward compatibility at this time, will provide core functions in future breaking/major versions
  • playcraft/core: Core player functions(non-UI)
  • playcraft/react: All React based components, make sure other sub bundles have no React dependency
  • playcraft/modules: Utility functions to share across environments, such as Google Cast receivers
  • playcraft/plugins: Plugins to share across environments

loadPlayer

Load the player & return reference to player instance.

By default this loads Shaka player, you can specify shaka for Shaka player options:

import {loadPlayer} from 'playcraft/core'

const player = await loadPlayer(document.querySelector('video'), {
  shaka: shakaOptions,
})

Base player to load is determined by options, loadPlayer(videoElement, {bitmovin: bitmovinOptions}) loads Bitmovin as base player.

Plain JavaScript interface

While we can use the player object directly, this package also provides functions the works with all base players.

import {subscribePlaybackState, load, playOrPause, seek} from 'playcraft/core'

<Video>

Import with: import {Video} from 'playcraft/react'.

Basic player component as a React component, a wrapper around base player.

This component renders <video> tag only, UI is not included.

Example:

<Video
  source={[
    {
      type: 'dash',
      src: 'https://dash.akamaized.net/dash264/TestCases/1a/sony/SNE_DASH_SD_CASE1A_REVISED.mpd'
    }
  ]}
  autoplay
  ref={videoRef}

  playbackState="playing"
  currentTime={123}
  volume={0.8}
  audio={audioTrackId}
  subtitles={subTitleTrackId}
  quality={{min: '720', max: '1080'}}

  onPlaybackStateChange={(event, playbackState) => [event.type, playbackState]}
  onTimeUpdate={() => videoRef.current.currentTime}
>

Source

An object or an array of objects containing {type, src}, URL to manifests of video and type of manifests.

;[
  {
    type: 'dash',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd',
  },
  {
    type: 'hls',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths-hls/hls.m3u8',
  },
]

In iOS browsers and MacOS Safari, the player chooses first HLS manifest and plays with built-in player provided by Apple.

In other browsers the player looks for first DASH manifest and plays with MediaSource Extensions.

DRM

To play content protection endabled videos, you should specify license server URLs and options in source.drm:

;[
  {
    type: 'dash',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd',
    drm: {
      widevine: 'https://drm.ex.com/portal',
      playready: 'https://drm.ex.com/portal',
    },
  },
  {
    type: 'hls',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths-hls/hls.m3u8',
    drm: {
      fairplay: {
        licenseUri: 'https://drm.ex.com/portal',
        certificateUri: 'https://drm.ex.com/portal/certificate',
      },
    },
  },
]

Extranal text track / subtitles

To add external text track, specify another source object with type: 'text/vtt' or type: 'text/srt':

;[
  {
    type: 'dash',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd',
  },
  {
    type: 'text/vtt',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/text_ex.vtt',
  },
  {
    type: 'text/srt',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/text_ex.srt',
  }

Props for Player Options

shaka

Shaka player config

autoplay

Start playback when player component is mounted.

Defaults to false.

loop

Loop the current video. Check HTMLMediaElement.loop

Defaults to false.

videoRef

Ref to html video element, use this for custom integrations.

playerRef

Ref to base player instance, use this for custom integrations.

Props for Playback

These props describe target state of playback, detailed design explaination can be found here.

playbackState

Defines target state of the video, possible options are playing / paused.

Play button update with this prop immediately, for video playback, paused also takes effect instantly in most situations, but playing can only be applied when the video is ready to play.

Imperative player.play() is not recommended, since not all situations are safe to play(), requires extra checking or error handling, declarative prop playbackState handles these cases.

Example:

const MyApp = () => {
  const [playbackState, setPlaybackState] = useState('paused')
  const play = () => {
    setPlaybackState('playing')
  }
  const pause = () => {
    setPlaybackState('paused')
  }

  return (
    <div>
      <Video playbackState={playbackState} />
      <button onClick={pause}>Pause</button>
      <button onClick={play}>Play</button>
    </div>
  )
}

onPlaybackStateChange

Convenient event wrapper for playback state change.

States are: loading, buffering, playing, paused, error.

currentTime

Defines target time of the video, the video seeks to defined time when this prop is changed, no need to update this prop with playback time update, it only seeks when the prop updates.

User can also seek with seekbar when this props is set, whatever updates last takes effect.

onTimeUpdate

quality

Defines constraints on what streams/tracks should be selected in ABR, if nothing meets specified constriant, player fallbacks to base player decision.

{
  minHeight: 480,
  maxHeight: 1080,
}

volume

Defines target volume of the video, the video updates to defined volume when this prop is changed.

If not specified, volume will be saved to local storage on change if available, and restore next time.

muted

Defines muted state of the video.

playbackRate

Defines target playback rate of the video, the video updates to defined rate when this prop is changed.

audioTrack

onPlayerLoaded

Called when the player is loaded.

onError

Called when an error is occurred.

event.error.name is typically source of the error, please refer to the documentation of base player, lookup with event.error.code.

Other Props

Additional props will be passed to video element.

<PremiumPlayer>

Import with : import {PremiumPlayer} from 'playcraft/react'

Example

const [source, setSource] = useState([
  {
    type: 'dash',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd',
  },
  {
    type: 'hls',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths-hls/hls.m3u8',
  }
], [])

<PremiumPlayer
  source={source}
  onChangeNext={() => {
    // somthing like: setSource(nextSource)
  }}
  onChangePrevious={() => {}}
/>

Source

source prop format is the same as <Video>, with some extensions.

Thumbnails

;[
  {
    type: 'dash',
    src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd',
  },
  {
    type: 'thumbnail',
    src: 'https://ex.com/thumbnails.vtt',
  },
]

Specify a source object with url to thumbnails data for thumbnail seeking feature.

Quality

The player gets the available qualities/profiles/resolutions/variants from the manifest as default and offer quality settings automatically, list of setting options can be overridden by specifying source.qualityOptions:

{
  type: 'dash',
  src: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd',
  qualityOptions: [
    {label: '1080', value: 1080, options: {maxHeight: 1080}},
    {label: '720', value: 720, options: {maxHeight: 720}},
  ],
},

Props

All props of <Video> are supported.

autoplay

Whether the player starts playing after loading a source or not. Unmuted autoplay is blocked on major browsers, detect with isAutoplayBlocked of pause event.

Takes no effect when playbackState prop is given.

quality

When playing with Safari native HLS support, player can't set ABR constraints and quality selection is disabled.

To enable quality selection in Safari, specify quality.rewriteManifest to let player apply ABR constriants by manifest rewrite.

import {selectHlsQualities} from 'playcraft/modules'
<PremiumPlayer
  quality={{
    rewriteManifest: selectHlsQualities,
  }}
/>

controls

Defines that player show UI or not.
Also support advanced option autohide object prop.

<PremiumPlayer controls={true | false | autohide} />

Use autohide with 3 seconds:

<PremiumPlayer controls={{autohide: 3000}} />

To show only title use title-only:

<PremiumPlayer controls="title-only" />

To display a custom overlay, and temporarily disable built-in settings UI, use no-panel.

<PremiumPlayer controls="no-panel" />

Default value is true.

loop='disabled'

In addition to true | false for HTML video loop, you may also specify 'disabled' to disable built-in loop menu item in settings UI.

chapters

Show chapters related UI: SeekBar and SideBar.

const chapters = [
  {
    startTime: 0,
    displayName: 'OP',
  },
  {
    startTime: 30,
    displayName: 'Content',
  },
  {
    startTime: 190,
    displayName: 'Ending',
  },
]

<PremiumPlayer chapters={chapters} />

intl.locale

Language of settings UI & error messages.

intl.messages

Custom translations.

title, channelTitle

Video title text to be displayed at top.

onBack

A function that will be called when back button is clicked, back button is rendered at left of title, only if specified.

onChangeNext, onChangePrevious

Click handler for next / previous episode buttons. If not specified, buttons will be disabled in mobile UI (or hidden in desktop UI).

onError

Premium player has built-in error UI, when an error is encountered, it stops playback and displays a overlay error message.

To opt-out error message for some specific error, use event.preventDefault(), you can unmount player component then re-mount it to restart silently.

Example:

const MyVideoApp = () => {
  const [playerSwitch, setPlayerSwitch] = useState('open')
  const remount = () => {
    flushSync(() => {
      setPlayerSwitch('closed')
    })
    flushSync(() => {
      setPlayerSwitch('open')
    })
  }

  return playerSwitch === 'open' && (
    <PremiumPlayer
      event => {
        if (/PlayerError/.test(event.error.name) && event.error.code == 1000) {
          event.preventDefault()
          remount()
        }
      }
    >
  )
}

modulesConfig

The common configuration for all modules.
Each module config is distinguished by the key prefix name:

const modulesConfig = {
  'moduleA.name': 'moduleA',
  'moduleB.name': 'moduleB',
}

Currently, only support analytics module:

const modulesConfig = {
  'analytics.token': 'token',
  'analytics.session_id': 'sessionId',
}

<PremiumPlayer
  modulesConfig={modulesConfig}
/>

normalizeTabSwitch

This property controls the default behavior of our PremiumPlayer when switching tabs on various versions of Safari and across different devices

  • If normalizeTabSwitch doesn't be set, the video will pause when the tab is not visible and resume when the tab becomes visible again. This is the default behavior.

  • If normalizeTabSwitch is set to false, the video will not pause when the tab is not visible.

Here's an example of how to use the normalizeTabSwitch property:

<PremiumPlayer
  modulesConfig={{
    normalizeTabSwitch: false,
  }}
/>

keyboardControls

The default behavior of keyboardControls is below:

  • Play/Pause: Spacebar or 'K'
  • Rewind: Left Arrow
  • Forward: Right Arrow
  • Volume Up: Up Arrow
  • Volume Down: Down Arrow
  • Mute/Unmute: 'M'
  • Volume scroll: mouse scroll / gesture upward or downward

Focus Mode: Set mode to "focus-enable" to make the player respond to keyboard events only when focused.

Example of focus mode:

const customKeyboardControls = {
  mode: "focus-enable"
};

<PremiumPlayer keyboardControls={customKeyboardControls} />

onOpenSettings

Called when settings UI is open, by default, playback is paused when using mobile UI, you can opt-out with event.preventDefault():

<PremiumPlayer onOpenSettings={event => event.preventDefault()}>

slots

An object that contains the slots for a component. You can use it to define additional custom slots for a component's interior elements.

For example, the code snippet below shows how to replace the volume control with a custom component:

const MyVolumeControl = () => {
  return <div>My Custom Volume Control</div>
}

<PremiumPlayer slots={{VolumeControl: MyCustomVolumeControl}} />

Here are some possible slots that can be used in the <PremiumPlayer> component:

  • PlayButton: Used to display the play button, make sure to enable autoplay if you want to hide the play button, or add a custom play button.
  • RewindButton / ForwardButton: Used to display the rewind/forward buttons.
  • Seekbar: Used to display the seekbar of the video.
  • VolumeControl: Used to control the volume of the video.
  • DisplayTime: Used to display the current time of the video.
  • Settings: Used to display the settings UI.
  • FullscreenButton: Used to display the fullscreen button.

You can also define custom slots and slotProps to further customize the UI components of the player.

slotProps

An object that contains the props for all slots within a component. You can use it to define additional custom props for a component's interior elements.

You may also use slotProps even if you don't use slots to override the default UI components.

For example, the code snippet below shows how to make the volume control horizontal:

<PremiumPlayer slotProps={{volumeControl: {slider: 'horizontal'}}}>

uiElements (deprecated)

Deprecated, use slots and slotProps instead.

Inner UI Components

List of component props available for slots, slotProps override.

Seekbar

In case you need custom seekbar, replace it by slots.Seekbar like a whole red bar for classic live UI:

const Seekbar = () => (<div style={{height: '0.3em', background: 'red'}} />)

<PremiumPlayer slots={{
  Seekbar,
}} />

DisplayTime

VolumeControl

  • slider: 'vertical'(default) | 'horizontal'

Settings

  • slots.root: Root element of Settings UI, you may replace with ClassicSettingsContainer for classic settings UI look.
  • closeBy: 'swipeDown'(default) | 'button'
  • buttonPosition: 'top-right' | 'bottom-right'
<PremiumPlayer
  slotProps={{
    closeBy: 'button',
    slots: {root: ClassicSettingsContainer},
  }}
/>

UI Component Composition

children

All children will be rendered as children of player UI, use position: absolute to stack custom UI on player UI.

Import with : import {FunctionBarExtension} from 'playcraft/react'

In addition to children, you can also attach buttons or custom UI, at right of built-in buttons, or other specific places.

Internal layout component provides ref to the function bar container, the button is rendered at left of settings button, with React portal.

<PremiumPlayer>
  <FunctionBarExtension>
    <MyCustomButton />
  </FunctionBarExtension>
  <MyOverlayUI />
</PremiumPlayer>

Add UI elements to the right or left of the title, position defaults to 'left'.

Import with : import {TitleBarExtension} from 'playcraft/react'

You can add an empty container with a width of 1 ~ 3rem to shift the title position.

<PremiumPlayer>
  <TitleBarExtension position="left">
    <div style={{width: '2rem'}} />
  </TitleBarExtension>
</PremiumPlayer>

UI Addons

Clips & Tags

This example shows how to enable clips & tags.

  • Specify metadata.clips
  • Use SeekbarClipsTrack as SeekbarTrack slot
  • Other components are included in Addons
import {SeekbarClipsTrack, usePlayerUiAddon} from 'playcraft/react'


const MyComponent = () => {
  const {addonProps, addonPlayerProps} = usePlayerUiAddon({title, metadata, playlist})

  // In case you need to sync displayed tags on the seekbar, use `onChangeTagFilter`
  useEffect(() => {
    if (0) {
      addonProps.onChangeTagFilter({green: true, tagName1: true})
    }  
  }, [])

  return (
    <PremiumPlayer
      metadata={{
        clips: [
          {
            name: 'Clip 1',
            startTime: 0,
            duration: 30,
            tags: [{color: 'green'}],
          }
        ]
      }}
      slotProps={{seekbar: {slots: {SeekbarTrack: SeekbarClipsTrack}}}}
      {...addonPlayerProps}
    >
      <Addons title={eventTitle} {...metadata} activePanel={activePanel} onOpen={setActivePanel} {...addonProps} />
    </PremiumPlayer>
  )
}

To replace the panel with a custom component, use Addons slot:

<Addons slots={{ChapterList: () => 'My Component'}}>

<PremiumPlusPlayer>

This component is moved to another package and left here for backward compatibility, no futher updates/fixes will be made.

Import with : import {PremiumPlusPlayer} from 'playcraft/react'

Premium+ player is premium player with integrated playback API support, and full set of enterprise features, good for fast OTT platform player integration.

All props of <PremiumPlayer> and <Video> are also available.

Props for enterprise features

preload

Default is 'auto', player starts playback session automatically. If none is specified, player starts playback session when load() is called.

quality

In addition to quality prop supported in premium, quality.getSettingOptions is available to define quality setting options with resolution list provided by API.

{
  getSettingOptions: fixedQualityOptions // or abrLimitQualityOptions
}

Props for playback API

Updating host, accessToken, deviceId, headers or params doesn't restart existing playback session, sub subseqent requests will be send with new prop values.

To restart a session, please update contentKey instead.

host

URL of playback API.

accessToken

Access token of current user, this is optional if access control is not needed.

This will be added to header Authorization of playback API requests, and headers of DRM portal requests.

deviceId

Unique identifier of current device, needed for concurrent device count limit.

headers

Additional headers for playback API requests.

params

Additional query parameters for playback API requests.

contentType, contentId

Content to request from playback API, types are videos / lives.

contentKey

By default API requests are cached with key ${contentType}/${contentId}, when the backend provides different by headers or queries, you can also provide custom key for cache.

<PremiumPlusPlayer
  contentKey="linear/1"
  contentType="live"
  contentId="1"
  preloadList={[
    params={{playback_type: 'linear'}}
    preloadList{[
      {contentType: 'lives', contentId: '1', contentKey: 'whatever/1', params: {playback_type: 'whatever'},
      {contentType: 'lives', contentId: '2', contentKey: 'linear/2', params: {playback_type: 'linear'},
    ]}
  ]}
/>

preloadList

A list of content to pre-request the playback info and the content data. The data format should be like:

type PreloadList = {
  contentId
  contentType
}[]

Note that the array reference should keep the same if the content doesn't change. We suggest using useMemo to wrap the preloadList:

const preloadList = useMemo(
  () => [
    {contentId: '1', contentType: 'videos'},
    {contentId: '2', contentType: 'videos'},
  ],
  [],
)

return <PremiumPlusPlayer preloadList={preloadList} />

onApiError(error, {retry, retryTimes})

Handler for API request errors, error is error object of axios, you may resend request with retry.

Default behavior is:

  • For temporarily server or network error, wait 3 seconds and retry 3 times
  • For critical API /start and /info, pass error back
  • Ignore errors for other API errors by return a pending promise

Example:

const ignoreMinorError = async (error, {retry, retryTimes} = {}) => {
  if (
    (error.response.message === 'Network Error' ||
      /502|503/.test(error.response.status)) &&
    retryTimes < 3
  ) {
    await waitMs(3000)
    return retry()
  }
  if (/start$|info$/.test(error.config.url)) {
    return Promise.reject(error)
  }
  console.log('Ignore non-critical playback API fail', error)
  return new Promise(() => {})
}

Plugins

Import from playcraft/plugins.

While this library provides common features, some of features are not required in all use cases, these features are implemented as plguins, to make app package dependencies clean, and bundle size won't increace with unused features.

⚠️ When using plugins with React UI, make sure the plugins are stored with a reference and are not initialized on re-render(see React example below).

Since main bundle is not side-effect-free yet, plugins are in sub bundle playcraft/plugins.

MediaTailorPlugin

This plugin loads streams with server-side stitched ad from MediaTailor, and provides ad related functionalies.

Ad UI is not included in this plugin.

adParams

⚠️ Warning: this prop is experimental.

Set personalized ads for MediaTailor.

This props should be inserted with MediaTailorPlugin contructor.

Default is empty JSON.

const adParams = {user: 'tim'}
const plugin = MediaTailorPlugin({adParams})

Features

  • Load ad stitched streams from MediaTailor
  • Load ad tracking event data & send tracking events(beacons)
  • Snapback
  • Provide playback time of original content
  • Provide ad playback status
  • Provide ad events
  • Provide skip ad function

Example for React

To avoid re-initializing plugins on re-render, please wrap it with useMemo.

import {Player} from 'playcraft'
import {MediaTailorPlugin} from 'playcraft/plugins'

const MyPlayerView = () => {
  const plugins = useMemo(() => [MediaTailorPlugin()], [])

  return (
    <MyContainer>
      <Player plugins={plugins} />
    </MyContainer>
  )
}

Example for Cast receiver

This plugin can also integrate with Playcraft Cast receiver.

import {MediaTailorPlugin} from 'playcraft/plugins'
import {castService} from 'playcraft-google-cast'

castService.start({
  plugins: [MediaTailorPlugin()],
})

ImaDaiPlugin

This plugin enable the playcraft integration with ImaDai SDK for HTML5. You can use it as follow:

import {ImaDaiPlugin} from 'playcraft/plugins'

function ContainerComponent(props) {
  const plugins = useMemo(() => [ImaDaiPlugin()], [])
  return <PremiumPlusPlayer plugins={plugins} />
}

requestOptionOverrides

Accept an object to overrides the default StreamRequest:

const plugins = useMemo(
  () => [
    ImaDaiPlugin({
      requestOptionsOverrides: {adTagParameters: {tfcd: 1}},
    }),
  ],
  [],
)
return <PremiumPlusPlayer plugins={plugins} />

Modules

Import with: import {mapLogEvents} from 'playcraft/modules

This sub bundle contains building blocks unplugged from enterprise player, for crafting a player from the super flexible minimal player or other players.

mapLogEvents

A observer operator-like funciton, take video element, generates playback log events to be sent to amplitude.

Cast receiver also handle playlog with this function.

Premium+ already integrated playlog in it, no need to use this function.

For premium player or other players, simply pass video element and pass additional events with logTarget.emit:

const MyApp = () => {
  const videoRef = useRef()
  const logTarget = useRef()
  useEffect(() => {
    logTarget.current = mapLogEvents({
      playerName: 'shaka',
      version: process.env.VERSION,
      video: videoRef.current,
    })
  }, [])

  return (
    <PremiumPlayer
      videoRef={videoRef}
      sendLog={(name, data) => logTarget.current.emit(name, data)}
    />
  )
}

enableTsSupport

Enable TS playback support, this needs mux.js to be installed, the effect applies glaboally, and only needs to be called once.

This is required for TS playback in non-Safari browsers.

yarn add mux.js
import {enableTsSupport} from 'playcraft/modules'

enableTsSupport()

Google Cast Sender Integration

For plain JS integration, sender integration & mini control UI comes with player UI automatically, just specify castReceiverAppId and it will handle the rest, including initialization of Google Cast sender SDK.

React integration

For React integration, enable Cast by adding initSender and <CastSender> to your app.

<PremiumPlayer> have a Cast button, which will display automatically when Google Cast sender is initialized and there's some available receiver ready for connection.

import {CastSessionControl} from 'playcraft/react'

useEffect(() => {
  initSender({appId: "XXXXXX"});
},[])

<CastSessionControl intl={{locale: 'ja'}} />

To add customData for your own custom logic, use cast.customData prop of <PremiumPlayer>:

<PremiumPlayer cast={{
  contentId: '1',
  customData: {
    host: 'https://example.com',
    accessToken: '1234567890',
    customHeader: {},
    customQuery: {},
  },
  onChange: handleCastChange,
}}>

You may also handle Cast connection state change with cast.onChange.

Disabling Airplay Support

Disabling Airplay Support Airplay support can be controlled using the x-webkit-wirelessvideoplaybackdisabled attribute. This attribute is specific to WebKit-based browsers and can be used to disable wireless video playback, effectively disabling Airplay.

In JavaScript, you can disable Airplay on a media element by setting the x-webkit-wirelessvideoplaybackdisabled attribute to 'true'. Here's how you can do it:

// Get a reference to your media element
const media = document.querySelector('your-media-selector');

// Set the attribute to 'true' to disable Airplay
media.setAttribute('x-webkit-wirelessvideoplaybackdisabled', 'true');

In a React, you can pass this attribute through a prop to your video player component. Here's an example using a hypothetical PremiumPlayer component:

// Define your video attributes
const videoAttributes = {
  'x-webkit-wirelessvideoplaybackdisabled': 'true',
};

// Pass the attributes to your player component
<PremiumPlayer {...videoAttributes} />

Workarounds

Pause when Unplugging Headphones in iOS

Mobile web video will be paused by OS when unplugging headphones, but in some iOS versions, video is paused without an event, and cause UI state inconsistent.

A function handleIOSHeadphonesDisconnection is provided to workaround this.

Example

import React, {useEffect} from 'react'
import {Player} from 'playcraft'
import {handleIOSHeadphonesDisconnection} from 'playcraft/modules'

const MyVideoComponent = () => {
  useEffect(() => {
    handleIOSHeadphonesDisconnection()
  }, [])

  return <Player />
}