Skip to content

Commit

Permalink
Use single config prop
Browse files Browse the repository at this point in the history
  • Loading branch information
cookpete committed Jul 30, 2017
1 parent 38e4020 commit 9dd7ab3
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 182 deletions.
61 changes: 46 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Prop | Description | Default
`style` | Add [inline styles](https://facebook.github.io/react/tips/inline-styles.html) to the root element
`progressFrequency` | The time between `onProgress` callbacks, in milliseconds | `1000`
`playsinline` | Applies the `playsinline` attribute where supported | `false`
`config` | Override options for the various players, see [config prop](#config-prop)

#### Callback props

Expand All @@ -103,24 +104,54 @@ Prop | Description
`onEnded` | Called when media finishes playing
`onError` | Called when an error occurs whilst attempting to play media

#### Config props
#### Config prop

These props allow you to override the parameters for the various players:
As of version `1.0.0`, there is a single `config` prop to override the settings for the various players. If you are migrating from `0.x`, you must move all the old config props to inside `config`:

Prop | Description
---- | -----------
`soundcloudConfig` | Configuration object for the SoundCloud player.<br />Set `clientId` to your own SoundCloud app [client ID](https://soundcloud.com/you/apps).<br />Set `showArtwork` to `false` to not load any artwork to display.
`vimeoConfig` | Configuration object for the Vimeo player.<br />Set `iframeParams` to override the [default params](https://developer.vimeo.com/player/embedding#universal-parameters).<br />Set `preload` for [preloading](#preloading).
`youtubeConfig` | Configuration object for the YouTube player.<br />Set `playerVars` to override the [default player vars](https://developers.google.com/youtube/player_parameters?playerVersion=HTML5).<br />Set `preload` for [preloading](#preloading).
`vidmeConfig` | Configuration object for the Vidme player.<br />Set `format` to use a certain quality of video, when available.<br />Possible values: `240p`, `480p`, `720p`, `1080p`, `dash`, `hls`
`wistiaConfig` | Configuration object for the Wistia player.<br />Set `options` to override the [default player options](https://wistia.com/doc/embed-options#options_list)
`dailymotionConfig` | Configuration object for the DailyMotion player.<br />Set `params` to override the [default player vars](https://developer.dailymotion.com/player#player-parameters).<br />Set `preload` for [preloading](#preloading).
`fileConfig` | Configuration object for the file player.<br />Set `attributes` to apply [element attributes](https://developer.mozilla.org/en/docs/Web/HTML/Element/video#Attributes).<br />Set `forceAudio` to always render an `<audio>` element.<br />Set `forceHLS` to use [hls.js](https://github.com/video-dev/hls.js) for HLS streams.<br />Set `forceDASH` to always use [dash.js](https://github.com/Dash-Industry-Forum/dash.js) for DASH streams.
`facebookConfig` | Configuration object for the Facebook player.<br />Set `appId` to your own [Facebook app ID](https://developers.facebook.com/docs/apps/register#app-id).
##### Version `0.x`

```js
<ReactPlayer
url={url}
youtubeConfig={{ playerVars: { showinfo: 1 } }}
facebookConfig={{ appId: '12345' }}
/>
```

The old style config props still work but will produce a console warning.

##### Version `1.x`

```js
<ReactPlayer
url={url}
config={{
youtube: {
playerVars: { showinfo: 1 }
},
facebook: {
appId: '12345'
}
}}
/>
```

Settings for each player live under different object keys:

Key | Options
--- | -------
`youtube` | Set `playerVars` to override the [default player vars](https://developers.google.com/youtube/player_parameters?playerVersion=HTML5).<br />Set `preload` for [preloading](#preloading).
`facebook` | Set `appId` to your own [Facebook app ID](https://developers.facebook.com/docs/apps/register#app-id).
`soundcloud` | Set `clientId` to your own SoundCloud app [client ID](https://soundcloud.com/you/apps).<br />Set `showArtwork` to `false` to not load any artwork to display.
`vimeo` | Set `iframeParams` to override the [default params](https://developer.vimeo.com/player/embedding#universal-parameters).<br />Set `preload` for [preloading](#preloading).
`vidme` | Set `format` to use a certain quality of video, when available.<br />Possible values: `240p`, `480p`, `720p`, `1080p`, `dash`, `hls`
`wistia` | Set `options` to override the [default player options](https://wistia.com/doc/embed-options#options_list)
`dailymotion` | Set `params` to override the [default player vars](https://developer.dailymotion.com/player#player-parameters).<br />Set `preload` for [preloading](#preloading).
`file` | Set `attributes` to apply [element attributes](https://developer.mozilla.org/en/docs/Web/HTML/Element/video#Attributes).<br />Set `forceAudio` to always render an `<audio>` element.<br />Set `forceHLS` to use [hls.js](https://github.com/video-dev/hls.js) for HLS streams.<br />Set `forceDASH` to always use [dash.js](https://github.com/Dash-Industry-Forum/dash.js) for DASH streams.

##### Preloading

Both `youtubeConfig`, `vimeoConfig`, `dailymotionConfig` props can take a `preload` value. Setting this to `true` will play a short, silent video in the background when `ReactPlayer` first mounts. This fixes a [bug](https://github.com/CookPete/react-player/issues/7) where videos would not play when loaded in a background browser tab.
When `preload` is set to `true` for players that support it, a short, silent video is played in the background when `ReactPlayer` first mounts. This fixes a [bug](https://github.com/CookPete/react-player/issues/7) where videos would not play when loaded in a background browser tab.

#### Multiple Sources and Tracks

Expand Down Expand Up @@ -148,13 +179,13 @@ You can also specify a `type` for each source by using objects with `src` and `t
<ReactPlayer
playing
url='foo.webm'
fileConfig={{
config={{ file: {
tracks: [
{kind: 'subtitles', src: 'subs/subtitles.en.vtt', srcLang: 'en', default: true},
{kind: 'subtitles', src: 'subs/subtitles.ja.vtt', srcLang: 'ja'},
{kind: 'subtitles', src: 'subs/subtitles.de.vtt', srcLang: 'de'}
]
}}
}}}
/>
```

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"dependencies": {
"fetch-jsonp": "^1.0.2",
"load-script": "^1.0.0",
"lodash.merge": "^4.6.0",
"lodash.omit": "^4.5.0",
"prop-types": "^15.5.6"
},
Expand Down
80 changes: 39 additions & 41 deletions src/ReactPlayer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { Component } from 'react'
import omit from 'lodash.omit'

import { propTypes, defaultProps } from './props'
import { propTypes, defaultProps, DEPRECATED_CONFIG_PROPS } from './props'
import { getConfig } from './utils'
import YouTube from './players/YouTube'
import SoundCloud from './players/SoundCloud'
import Vimeo from './players/Vimeo'
Expand All @@ -12,10 +13,24 @@ import Vidme from './players/Vidme'
import Wistia from './players/Wistia'
import DailyMotion from './players/DailyMotion'

const SUPPORTED_PROPS = Object.keys(propTypes)
const SUPPORTED_PLAYERS = [
YouTube,
SoundCloud,
Vimeo,
Facebook,
FilePlayer,
Streamable,
Vidme,
Wistia,
DailyMotion
]

export default class ReactPlayer extends Component {
static displayName = 'ReactPlayer'
static propTypes = propTypes
static defaultProps = defaultProps
config = getConfig(this.props, defaultProps, true)
componentDidMount () {
this.progress()
}
Expand All @@ -34,9 +49,8 @@ export default class ReactPlayer extends Component {
)
}
seekTo = fraction => {
if (this.player) {
this.player.seekTo(fraction)
}
if (!this.player) return null
this.player.seekTo(fraction)
}
getDuration = () => {
if (!this.player) return null
Expand Down Expand Up @@ -79,62 +93,46 @@ export default class ReactPlayer extends Component {
}
renderPlayers () {
// Build array of players to render based on URL and preload config
const { url, youtubeConfig, vimeoConfig, dailymotionConfig } = this.props
const players = []
if (YouTube.canPlay(url)) {
players.push(YouTube)
} else if (SoundCloud.canPlay(url)) {
players.push(SoundCloud)
} else if (Vimeo.canPlay(url)) {
players.push(Vimeo)
} else if (Facebook.canPlay(url)) {
players.push(Facebook)
} else if (DailyMotion.canPlay(url)) {
players.push(DailyMotion)
} else if (Streamable.canPlay(url)) {
players.push(Streamable)
} else if (Vidme.canPlay(url)) {
players.push(Vidme)
} else if (Wistia.canPlay(url)) {
players.push(Wistia)
} else if (url) {
// Fall back to FilePlayer if nothing else can play the URL
players.push(FilePlayer)
const { url } = this.props
const renderPlayers = []
for (let Player of SUPPORTED_PLAYERS) {
if (Player.canPlay(url)) {
renderPlayers.push(Player)
}
}
// Fall back to FilePlayer if nothing else can play the URL
if (renderPlayers.length === 0) {
renderPlayers.push(FilePlayer)
}
// Render additional players if preload config is set
if (!YouTube.canPlay(url) && youtubeConfig.preload) {
players.push(YouTube)
if (!YouTube.canPlay(url) && this.config.youtube.preload) {
renderPlayers.push(YouTube)
}
if (!Vimeo.canPlay(url) && vimeoConfig.preload) {
players.push(Vimeo)
if (!Vimeo.canPlay(url) && this.config.vimeo.preload) {
renderPlayers.push(Vimeo)
}
if (!DailyMotion.canPlay(url) && dailymotionConfig.preload) {
players.push(DailyMotion)
if (!DailyMotion.canPlay(url) && this.config.dailymotion.preload) {
renderPlayers.push(DailyMotion)
}
return players.map(this.renderPlayer)
return renderPlayers.map(this.renderPlayer)
}
ref = player => {
this.player = player
}
renderPlayer = Player => {
const active = Player.canPlay(this.props.url)
const { youtubeConfig, vimeoConfig, dailymotionConfig, ...activeProps } = this.props
const props = active ? { ...activeProps, ref: this.ref } : {}
// Only youtube and vimeo config passed to
// inactive players due to preload behaviour
const props = active ? { ...this.props, ref: this.ref } : {}
return (
<Player
key={Player.displayName}
youtubeConfig={youtubeConfig}
vimeoConfig={vimeoConfig}
dailymotionConfig={dailymotionConfig}
{...props}
key={Player.displayName}
config={this.config}
/>
)
}
render () {
const { style, width, height } = this.props
const otherProps = omit(this.props, Object.keys(propTypes))
const otherProps = omit(this.props, SUPPORTED_PROPS, DEPRECATED_CONFIG_PROPS)
const players = this.renderPlayers()
return (
<div style={{ ...style, width, height }} {...otherProps}>
Expand Down
1 change: 0 additions & 1 deletion src/demo/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export default class App extends Component {
this.setState({ volume: parseFloat(e.target.value) })
}
setPlaybackRate = e => {
console.log(parseFloat(e.target.value))
this.setState({ playbackRate: parseFloat(e.target.value) })
}
onSeekMouseDown = e => {
Expand Down
14 changes: 4 additions & 10 deletions src/players/DailyMotion.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,15 @@ const SDK_GLOBAL = 'DM'
const SDK_GLOBAL_READY = 'dmAsyncInit'
const MATCH_URL = /^.+dailymotion.com\/(video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/
const BLANK_VIDEO_URL = 'http://www.dailymotion.com/video/x522udb'
const DEFAULT_PLAYER_VARS = {
autoplay: 0,
api: 1,
'endscreen-enable': false
}

export default class DailyMotion extends Base {
static displayName = 'DailyMotion'
static canPlay (url) {
return MATCH_URL.test(url)
}
componentDidMount () {
const { url, dailymotionConfig } = this.props
if (!url && dailymotionConfig.preload) {
const { url, config } = this.props
if (!url && config.dailymotion.preload) {
this.preloading = true
this.load(BLANK_VIDEO_URL)
}
Expand Down Expand Up @@ -50,7 +45,7 @@ export default class DailyMotion extends Base {
return m[4] || m[2]
}
load (url) {
const { controls, dailymotionConfig, onError, playing } = this.props
const { controls, config, onError, playing } = this.props
const id = this.parseId(url)
if (this.player) {
this.player.load(id, {
Expand All @@ -71,12 +66,11 @@ export default class DailyMotion extends Base {
height: '100%',
video: id,
params: {
...DEFAULT_PLAYER_VARS,
controls: controls,
autoplay: this.props.playing,
start: parseStartTime(url),
origin: window.location.origin,
...dailymotionConfig.params
...config.dailymotion.params
},
events: {
apiready: () => {
Expand Down
2 changes: 1 addition & 1 deletion src/players/Facebook.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default class YouTube extends Base {
}
this.getSDK().then(FB => {
FB.init({
appId: this.props.facebookConfig.appId,
appId: this.props.config.facebook.appId,
xfbml: true,
version: 'v2.5'
})
Expand Down
14 changes: 6 additions & 8 deletions src/players/FilePlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ export default class FilePlayer extends Base {
super.componentWillUnmount()
}
shouldUseHLS (url) {
return HLS_EXTENSIONS.test(url) || this.props.fileConfig.forceHLS
return HLS_EXTENSIONS.test(url) || this.props.config.file.forceHLS
}
shouldUseDASH (url) {
return DASH_EXTENSIONS.test(url) || this.props.fileConfig.forceDASH
return DASH_EXTENSIONS.test(url) || this.props.config.file.forceDASH
}
load (url) {
if (this.shouldUseHLS(url)) {
Expand Down Expand Up @@ -111,8 +111,8 @@ export default class FilePlayer extends Base {
this.player = player
}
render () {
const { url, loop, controls, fileConfig, width, height } = this.props
const useAudio = AUDIO_EXTENSIONS.test(url) || fileConfig.forceAudio
const { url, loop, controls, config, width, height } = this.props
const useAudio = AUDIO_EXTENSIONS.test(url) || config.file.forceAudio
const useHLS = this.shouldUseHLS(url)
const useDASH = this.shouldUseDASH(url)
const Element = useAudio ? 'audio' : 'video'
Expand All @@ -130,13 +130,11 @@ export default class FilePlayer extends Base {
preload='auto'
controls={controls}
loop={loop}
{...fileConfig.attributes}>
{...config.file.attributes}>
{url instanceof Array &&
url.map(this.renderSource)
}
{fileConfig.tracks instanceof Array &&
fileConfig.tracks.map(this.renderTrack)
}
{config.file.tracks.map(this.renderTrack)}
</Element>
)
}
Expand Down
10 changes: 5 additions & 5 deletions src/players/SoundCloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ export default class SoundCloud extends FilePlayer {
state = {
image: null
}
clientId = this.props.soundcloudConfig.clientId || defaultProps.soundcloudConfig.clientId
shouldComponentUpdate (nextProps, nextState) {
return (
super.shouldComponentUpdate(nextProps, nextState) ||
this.state.image !== nextState.image
)
}
getSongData (url) {
const { config } = this.props
if (songData[url]) {
return Promise.resolve(songData[url])
}
return fetchJSONP(RESOLVE_URL + '?url=' + url + '&client_id=' + this.clientId)
return fetchJSONP(RESOLVE_URL + '?url=' + url + '&client_id=' + config.soundcloud.clientId)
.then(response => {
if (response.ok) {
songData[url] = response.json()
Expand All @@ -39,7 +39,7 @@ export default class SoundCloud extends FilePlayer {
})
}
load (url) {
const { soundcloudConfig, onError } = this.props
const { config, onError } = this.props
this.stop()
this.getSongData(url).then(data => {
if (!this.mounted) return
Expand All @@ -48,10 +48,10 @@ export default class SoundCloud extends FilePlayer {
return
}
const image = data.artwork_url || data.user.avatar_url
if (image && soundcloudConfig.showArtwork) {
if (image && config.soundcloud.showArtwork) {
this.setState({ image: image.replace('-large', '-t500x500') })
}
this.player.src = data.stream_url + '?client_id=' + this.clientId
this.player.src = data.stream_url + '?client_id=' + config.soundcloud.clientId
}, onError)
}
ref = player => {
Expand Down
8 changes: 4 additions & 4 deletions src/players/Vidme.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ export default class Vidme extends FilePlayer {
})
}
getURL ({ video }) {
const { vidmeConfig } = this.props
if (vidmeConfig.format && video.formats && video.formats.length !== 0) {
const index = video.formats.findIndex(f => f.type === vidmeConfig.format)
const { config } = this.props
if (config.vidme.format && video.formats && video.formats.length !== 0) {
const index = video.formats.findIndex(f => f.type === config.vidme.format)
if (index !== -1) {
return video.formats[index].uri
} else {
console.warn(`Vidme format "${vidmeConfig.format}" was not found for ${video.full_url}`)
console.warn(`Vidme format "${config.vidme.format}" was not found for ${video.full_url}`)
}
}
return video.complete_url
Expand Down
Loading

0 comments on commit 9dd7ab3

Please sign in to comment.