react-player
Version:
A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Twitch, SoundCloud, Streamable, Vimeo, Wistia and DailyMotion
204 lines (181 loc) • 5.49 kB
JSX
import React, { Component } from 'react'
import { callPlayer, getSDK, parseStartTime, parseEndTime } from '../utils'
import { canPlay, MATCH_URL_YOUTUBE } from '../patterns'
const SDK_URL = 'https://www.youtube.com/iframe_api'
const SDK_GLOBAL = 'YT'
const SDK_GLOBAL_READY = 'onYouTubeIframeAPIReady'
const MATCH_PLAYLIST = /[?&](?:list|channel)=([a-zA-Z0-9_-]+)/
const MATCH_USER_UPLOADS = /user\/([a-zA-Z0-9_-]+)\/?/
const MATCH_NOCOOKIE = /youtube-nocookie\.com/
const NOCOOKIE_HOST = 'https://www.youtube-nocookie.com'
export default class YouTube extends Component {
static displayName = 'YouTube'
static canPlay = canPlay.youtube
callPlayer = callPlayer
componentDidMount () {
this.props.onMount && this.props.onMount(this)
}
getID (url) {
if (!url || url instanceof Array || MATCH_PLAYLIST.test(url)) {
return null
}
return url.match(MATCH_URL_YOUTUBE)[1]
}
load (url, isReady) {
const { playing, muted, playsinline, controls, loop, config, onError } = this.props
const { playerVars, embedOptions } = config
const id = this.getID(url)
if (isReady) {
if (MATCH_PLAYLIST.test(url) || MATCH_USER_UPLOADS.test(url) || url instanceof Array) {
this.player.loadPlaylist(this.parsePlaylist(url))
return
}
this.player.cueVideoById({
videoId: id,
startSeconds: parseStartTime(url) || playerVars.start,
endSeconds: parseEndTime(url) || playerVars.end
})
return
}
getSDK(SDK_URL, SDK_GLOBAL, SDK_GLOBAL_READY, YT => YT.loaded).then(YT => {
if (!this.container) return
this.player = new YT.Player(this.container, {
width: '100%',
height: '100%',
videoId: id,
playerVars: {
autoplay: playing ? 1 : 0,
mute: muted ? 1 : 0,
controls: controls ? 1 : 0,
start: parseStartTime(url),
end: parseEndTime(url),
origin: window.location.origin,
playsinline: playsinline ? 1 : 0,
...this.parsePlaylist(url),
...playerVars
},
events: {
onReady: () => {
if (loop) {
this.player.setLoop(true) // Enable playlist looping
}
this.props.onReady()
},
onPlaybackRateChange: event => this.props.onPlaybackRateChange(event.data),
onPlaybackQualityChange: event => this.props.onPlaybackQualityChange(event),
onStateChange: this.onStateChange,
onError: event => onError(event.data)
},
host: MATCH_NOCOOKIE.test(url) ? NOCOOKIE_HOST : undefined,
...embedOptions
})
}, onError)
if (embedOptions.events) {
console.warn('Using `embedOptions.events` will likely break things. Use ReactPlayer’s callback props instead, eg onReady, onPlay, onPause')
}
}
parsePlaylist = (url) => {
if (url instanceof Array) {
return {
listType: 'playlist',
playlist: url.map(this.getID).join(',')
}
}
if (MATCH_PLAYLIST.test(url)) {
const [, playlistId] = url.match(MATCH_PLAYLIST)
return {
listType: 'playlist',
list: playlistId.replace(/^UC/, 'UU')
}
}
if (MATCH_USER_UPLOADS.test(url)) {
const [, username] = url.match(MATCH_USER_UPLOADS)
return {
listType: 'user_uploads',
list: username
}
}
return {}
}
onStateChange = (event) => {
const { data } = event
const { onPlay, onPause, onBuffer, onBufferEnd, onEnded, onReady, loop, config: { playerVars, onUnstarted } } = this.props
const { UNSTARTED, PLAYING, PAUSED, BUFFERING, ENDED, CUED } = window[SDK_GLOBAL].PlayerState
if (data === UNSTARTED) onUnstarted()
if (data === PLAYING) {
onPlay()
onBufferEnd()
}
if (data === PAUSED) onPause()
if (data === BUFFERING) onBuffer()
if (data === ENDED) {
const isPlaylist = !!this.callPlayer('getPlaylist')
// Only loop manually if not playing a playlist
if (loop && !isPlaylist) {
if (playerVars.start) {
this.seekTo(playerVars.start)
} else {
this.play()
}
}
onEnded()
}
if (data === CUED) onReady()
}
play () {
this.callPlayer('playVideo')
}
pause () {
this.callPlayer('pauseVideo')
}
stop () {
if (!document.body.contains(this.callPlayer('getIframe'))) return
this.callPlayer('stopVideo')
}
seekTo (amount, keepPlaying = false) {
this.callPlayer('seekTo', amount)
if (!keepPlaying && !this.props.playing) {
this.pause()
}
}
setVolume (fraction) {
this.callPlayer('setVolume', fraction * 100)
}
mute = () => {
this.callPlayer('mute')
}
unmute = () => {
this.callPlayer('unMute')
}
setPlaybackRate (rate) {
this.callPlayer('setPlaybackRate', rate)
}
setLoop (loop) {
this.callPlayer('setLoop', loop)
}
getDuration () {
return this.callPlayer('getDuration')
}
getCurrentTime () {
return this.callPlayer('getCurrentTime')
}
getSecondsLoaded () {
return this.callPlayer('getVideoLoadedFraction') * this.getDuration()
}
ref = container => {
this.container = container
}
render () {
const { display } = this.props
const style = {
width: '100%',
height: '100%',
display
}
return (
<div style={style}>
<div ref={this.ref} />
</div>
)
}
}