From 11058c4a543ba55052b2869f7d5216af2ba8e808 Mon Sep 17 00:00:00 2001 From: philip-luther Date: Thu, 20 Apr 2017 13:51:41 +0100 Subject: [PATCH] Add Facebook player Fixes https://github.com/CookPete/react-player/issues/109 --- README.md | 1 + src/ReactPlayer.js | 3 + src/demo/App.js | 7 +++ src/players/Facebook.js | 120 ++++++++++++++++++++++++++++++++++++++++ src/props.js | 6 ++ 5 files changed, 137 insertions(+) create mode 100644 src/players/Facebook.js diff --git a/README.md b/README.md index 673357c..ac35acd 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ Prop | Description `youtubeConfig` | Configuration object for the YouTube player.
Set `playerVars` to override the [default player vars](https://developers.google.com/youtube/player_parameters?playerVersion=HTML5).
Set `preload` for [preloading](#preloading). `vidmeConfig` | Configuration object for the Vidme player.
Set `format` to use a certain quality of video, when available.
Possible values: `240p`, `480p`, `720p`, `1080p`, `dash`, `hls` `fileConfig` | Configuration object for the file player.
Set `attributes` to apply [element attributes](https://developer.mozilla.org/en/docs/Web/HTML/Element/video#Attributes). +`facebookConfig` | Configuration object for the Facebook player.
Set `appId` to your own [Facebook app ID](https://developers.facebook.com/docs/apps/register#app-id). ##### Preloading diff --git a/src/ReactPlayer.js b/src/ReactPlayer.js index 14d9d41..15d7e7d 100644 --- a/src/ReactPlayer.js +++ b/src/ReactPlayer.js @@ -5,6 +5,7 @@ import { propTypes, defaultProps } from './props' import YouTube from './players/YouTube' import SoundCloud from './players/SoundCloud' import Vimeo from './players/Vimeo' +import Facebook from './players/Facebook' import FilePlayer from './players/FilePlayer' import Streamable from './players/Streamable' import Vidme from './players/Vidme' @@ -85,6 +86,8 @@ export default class ReactPlayer extends Component { players.push(SoundCloud) } else if (Vimeo.canPlay(url)) { players.push(Vimeo) + } else if (Facebook.canPlay(url)) { + players.push(Facebook) } else if (Streamable.canPlay(url)) { players.push(Streamable) } else if (Vidme.canPlay(url)) { diff --git a/src/demo/App.js b/src/demo/App.js index 2dd36f4..c30d771 100644 --- a/src/demo/App.js +++ b/src/demo/App.js @@ -175,6 +175,13 @@ export default class App extends Component { {this.renderLoadButton('https://soundcloud.com/tycho/tycho-awake', 'Test B')} + + Facebook + + {this.renderLoadButton('https://www.facebook.com/facebook/videos/10153231379946729/', 'Test A')} + {this.renderLoadButton('https://www.facebook.com/FacebookDevelopers/videos/10152454700553553/', 'Test B')} + + Vimeo diff --git a/src/players/Facebook.js b/src/players/Facebook.js new file mode 100644 index 0000000..326ddac --- /dev/null +++ b/src/players/Facebook.js @@ -0,0 +1,120 @@ +import React from 'react' +import loadScript from 'load-script' + +import Base from './Base' + +const SDK_URL = '//connect.facebook.net/en_US/sdk.js' +const SDK_GLOBAL = 'FB' +const SDK_GLOBAL_READY = 'fbAsyncInit' +const MATCH_URL = /^https:\/\/www\.facebook\.com\/([^/?].+\/)?video(s|\.php)[/?].*$/ +const PLAYER_ID_PREFIX = 'facebook-player-' + +export default class YouTube extends Base { + static displayName = 'Facebook' + static canPlay (url) { + return MATCH_URL.test(url) + } + playerID = PLAYER_ID_PREFIX + randomString() + getSDK () { + if (window[SDK_GLOBAL]) { + return Promise.resolve(window[SDK_GLOBAL]) + } + return new Promise((resolve, reject) => { + const previousOnReady = window[SDK_GLOBAL_READY] + window[SDK_GLOBAL_READY] = function () { + if (previousOnReady) previousOnReady() + resolve(window[SDK_GLOBAL]) + } + loadScript(SDK_URL, err => { + if (err) reject(err) + }) + }) + } + load (url) { + if (this.isReady) { + this.getSDK().then(FB => FB.XFBML.parse()) + return + } + this.getSDK().then(FB => { + FB.init({ + appId: this.props.facebookConfig.appId, + xfbml: true, + version: 'v2.5' + }) + FB.Event.subscribe('xfbml.ready', msg => { + if (msg.type === 'video' && msg.id === this.playerID) { + this.player = msg.instance + this.player.subscribe('startedPlaying', this.onPlay) + this.player.subscribe('paused', this.props.onPause) + this.player.subscribe('finishedPlaying', this.onEnded) + this.player.subscribe('startedBuffering', this.props.onBuffer) + this.player.subscribe('error', this.props.onError) + this.onReady() + } + }) + }) + } + onEnded = () => { + const { loop, onEnded } = this.props + if (loop) { + this.seekTo(0) + } + onEnded() + } + play () { + if (!this.isReady) return + this.player.play() + } + pause () { + if (!this.isReady) return + this.player.pause() + } + stop () { + // No need to stop + } + seekTo (fraction) { + super.seekTo(fraction) + if (!this.isReady) return + this.player.seek(this.getDuration() * fraction) + } + setVolume (fraction) { + if (!this.isReady) return + this.player.setVolume(fraction) + } + setPlaybackRate () { + return null + } + getDuration () { + if (!this.isReady) return null + return this.player.getDuration() + } + getFractionPlayed () { + if (!this.isReady || !this.getDuration()) return null + return this.player.getCurrentPosition() / this.getDuration() + } + getFractionLoaded () { + return null + } + render () { + const style = { + width: '100%', + height: '100%', + backgroundColor: 'black' + } + return ( +
+ ) + } +} + +// http://stackoverflow.com/a/38622545 +function randomString () { + return Math.random().toString(36).substr(2, 5) +} diff --git a/src/props.js b/src/props.js index 26aa68f..479fcc6 100644 --- a/src/props.js +++ b/src/props.js @@ -22,6 +22,9 @@ export const propTypes = { playerVars: object, preload: bool }), + facebookConfig: shape({ + appId: string + }), vimeoConfig: shape({ iframeParams: object, preload: bool @@ -62,6 +65,9 @@ export const defaultProps = { playerVars: {}, preload: false }, + facebookConfig: { + appId: '1309697205772819' + }, vimeoConfig: { iframeParams: {}, preload: false