Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PeerTube Videos support #1544

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ Key | Options
`mixcloud` | `options`: Override the [default player options](https://www.mixcloud.com/developers/widget/#methods)
`dailymotion` | `params`: Override the [default player vars](https://developer.dailymotion.com/player#player-parameters)
`twitch` | `options`: Override the [default player options](https://dev.twitch.tv/docs/embed)<br />`playerId`: Override player ID for consistent server-side rendering (use with [`react-uid`](https://github.com/thearnica/react-uid))
`peertube` | `options`: Override the [default player options](https://docs.joinpeertube.org/api-embed-player)
`file` | `attributes`: Apply [element attributes](https://developer.mozilla.org/en/docs/Web/HTML/Element/video#Attributes)<br />`forceVideo`: Always render a `<video>` element<br />`forceAudio`: Always render an `<audio>` element<br />`forceHLS`: Use [hls.js](https://github.com/video-dev/hls.js) for HLS streams<br />`forceSafariHLS`: Use [hls.js](https://github.com/video-dev/hls.js) for HLS streams, [even on Safari](https://github.com/cookpete/react-player/pull/1560)<br />`forceDisableHLS`: Disable usage [hls.js](https://github.com/video-dev/hls.js) for HLS streams<br />`forceDASH`: Always use [dash.js](https://github.com/Dash-Industry-Forum/dash.js) for DASH streams<br />`forceFLV`: Always use [flv.js](https://github.com/Bilibili/flv.js)<br />`hlsOptions`: Override the [default `hls.js` options](https://github.com/video-dev/hls.js/blob/master/docs/API.md#fine-tuning)<br />`hlsVersion`: Override the [`hls.js`](https://github.com/video-dev/hls.js) version loaded from [`jsdelivr`](https://www.jsdelivr.com/package/npm/hls.js), default: `0.13.1`<br />`dashVersion`: Override the [`dash.js`](https://github.com/Dash-Industry-Forum/dash.js) version loaded from [`cdnjs`](https://cdnjs.com/libraries/dashjs), default: `2.9.2`<br />`flvVersion`: Override the [`flv.js`](https://github.com/Bilibili/flv.js) version loaded from [`jsdelivr`](https://www.jsdelivr.com/package/npm/flv.js), default: `1.5.0`

### Methods

#### Static Methods
Expand Down Expand Up @@ -334,6 +334,7 @@ ReactPlayer `v2.0` changes single player imports and adds lazy loading players.
* DailyMotion videos use the [DailyMotion Player API](https://developer.dailymotion.com/player)
* Vidyard videos use the [Vidyard Player API](https://knowledge.vidyard.com/hc/en-us/articles/360019034753-Using-the-Vidyard-Player-API)
* Kaltura's `react-player` implementation uses the embed.ly [`Player.js`](https://github.com/embedly/player.js) API but Kaltura specific APIs are also available, see [Kaltura Player API](http://player.kaltura.com/docs/index.php?path=kwidget)
* PeerTube videos use the [PeerTube Player API](https://docs.joinpeertube.org/api-embed-player)
* [Supported file types](https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats) are playing using [`<video>`](https://developer.mozilla.org/en/docs/Web/HTML/Element/video) or [`<audio>`](https://developer.mozilla.org/en/docs/Web/HTML/Element/audio) elements
* HLS streams are played using [`hls.js`](https://github.com/video-dev/hls.js)
* DASH streams are played using [`dash.js`](https://github.com/Dash-Industry-Forum/dash.js)
Expand Down
2 changes: 1 addition & 1 deletion dist/ReactPlayer.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions dist/ReactPlayer.js.map

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions dist/ReactPlayer.standalone.es6.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/ReactPlayer.standalone.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions dist/ReactPlayer.standalone.js.map

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions examples/react/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ class App extends Component {
onProgress={this.handleProgress}
onDuration={this.handleDuration}
onPlaybackQualityChange={e => console.log('onPlaybackQualityChange', e)}
config={{
peertube: {
controls: 0,
mode: 'p2p-media-loader'
}
}}
/>
</div>

Expand Down Expand Up @@ -356,6 +362,13 @@ class App extends Component {
{this.renderLoadButton('https://cdnapisec.kaltura.com/p/2507381/sp/250738100/embedIframeJs/uiconf_id/44372392/partner_id/2507381?iframeembed=true&playerId=kaltura_player_1605622336&entry_id=1_i1jmzcn3', 'Test B')}
</td>
</tr>
<tr>
<th>PeerTube</th>
<td>
{this.renderLoadButton('https://celluloid-media.huma-num.fr/w/5GPbYsxX97Kxo8uLviWG4i', 'Test A')}
{this.renderLoadButton('https://celluloid-media.huma-num.fr/w/ngUWp1oYed4xHCjd3xtiem', 'Test B')}
</td>
</tr>
<tr>
<th>Files</th>
<td>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"vimeo",
"wistia",
"dailymotion",
"peertube",
"hls",
"dash",
"react-component"
Expand Down
2 changes: 2 additions & 0 deletions src/patterns.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const MATCH_URL_DAILYMOTION = /^(?:(?:https?):)?(?:\/\/)?(?:www\.)?(?:(?:
export const MATCH_URL_MIXCLOUD = /mixcloud\.com\/([^/]+\/[^/]+)/
export const MATCH_URL_VIDYARD = /vidyard.com\/(?:watch\/)?([a-zA-Z0-9-_]+)/
export const MATCH_URL_KALTURA = /^https?:\/\/[a-zA-Z]+\.kaltura.(com|org)\/p\/([0-9]+)\/sp\/([0-9]+)00\/embedIframeJs\/uiconf_id\/([0-9]+)\/partner_id\/([0-9]+)(.*)entry_id.([a-zA-Z0-9-_].*)$/
export const MATCH_URL_PEERTUBE = new RegExp('(https?)://(.*)/w/(.*)')
export const AUDIO_EXTENSIONS = /\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3a|wav|weba|aac|oga|spx)($|\?)/i
export const VIDEO_EXTENSIONS = /\.(mp4|og[gv]|webm|mov|m4v)(#t=[,\d+]+)?($|\?)/i
export const HLS_EXTENSIONS = /\.(m3u8)($|\?)/i
Expand Down Expand Up @@ -62,5 +63,6 @@ export const canPlay = {
mixcloud: url => MATCH_URL_MIXCLOUD.test(url),
vidyard: url => MATCH_URL_VIDYARD.test(url),
kaltura: url => MATCH_URL_KALTURA.test(url),
peertube: url => MATCH_URL_PEERTUBE.test(url),
file: canPlayFile
}
155 changes: 155 additions & 0 deletions src/players/PeerTube.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import React, { Component } from 'react'
import { canPlay, MATCH_URL_PEERTUBE } from '../patterns'
import { callPlayer, getSDK, queryString } from '../utils'

const SDK_URL = 'https://unpkg.com/@peertube/embed-api/build/player.min.js'
const SDK_GLOBAL = 'PeerTubePlayer'


export class PeerTubePlayer extends Component {
static displayName = 'PeerTubePlayer';
static canPlay = canPlay.peertube;
callPlayer = callPlayer;

constructor (props) {
super(props)
this.currentTime = 0
this.duration = 0
this.playbackRate = 1
this.getCurrentTime = this.getCurrentTime.bind(this)
this.getEmbedUrl = this.getEmbedUrl.bind(this)
}

componentDidMount () {
this.props.onMount && this.props.onMount(this)
}

getEmbedUrl = () => {
const { config, url } = this.props
const m = MATCH_URL_PEERTUBE.exec(url)

const query = queryString({
...config.peertube,
api: 1
})

return `${m[1]}://${m[2]}/videos/embed/${m[3]}?${query}`
};

load () {
getSDK(SDK_URL, SDK_GLOBAL).then(() => {
if (!this.iframe) {
return
}
const PeerTubePlayer = window.PeerTubePlayer
this.player = new PeerTubePlayer(this.iframe)

this.player.ready.then(() => {
this.player.addEventListener('playbackStatusUpdate', (data) => {
this.currentTime = data.position
this.duration = data.duration
})
this.player.addEventListener('playbackStatusChange', (data) => {
console.log('playbackStatusChange', data)
if (data === 'playing') {
this.props.onPlay()
} else {
this.props.onPause()
}
})

this.props.onReady()
})
}, this.props.onError)
}

play () {
this.callPlayer('play')
}

pause () {
this.callPlayer('pause')
}

stop () {}

seekTo (seconds) {
this.callPlayer('seek', seconds)
}

setVolume (fraction) {
this.callPlayer('setVolume', fraction)
}

setLoop (loop) {
// console.log("SET LOOP");
}

mute () {
// console.log("SET MUTE");
}

unmute () {
// console.log("SET UNMUTE");
}

getDuration () {
return this.duration
}

getCurrentTime () {
return this.currentTime
}

getSecondsLoaded () {

}

getPlaybackRate () {
if (this.player) {
this.player.getPlaybackRate().then((rate) => {
this.playbackRate = rate
})
}

return this.playbackRate
}

setPlaybackRate (rate) {
if (this.player) {
this.player.setPlaybackRate(rate)
}
}

ref = (iframe) => {
this.iframe = iframe
};

render () {
const style = {
width: '100%',
height: '100%',
margin: 0,
padding: 0,
border: 0,
overflow: 'hidden'
}
const { url } = this.props

return (
<iframe
key={url}
ref={this.ref}
style={style}
src={this.getEmbedUrl(url)}
frameBorder='0'
scrolling='no'
id='peerTubeContainer'
allow='autoplay; fullscreen'
sandbox='allow-same-origin allow-scripts allow-popups'
/>
)
}
}

export default PeerTubePlayer
6 changes: 6 additions & 0 deletions src/players/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ export default [
canPlay: canPlay.kaltura,
lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerKaltura' */'./Kaltura'))
},
{
key: 'peertube',
name: 'PeerTube',
canPlay: canPlay.peertube,
lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerPeerTube' */'./PeerTube'))
},
{
key: 'file',
name: 'FilePlayer',
Expand Down
2 changes: 2 additions & 0 deletions types/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { VidyardConfig } from '../vidyard'
import { VimeoConfig } from '../vimeo'
import { WistiaConfig } from '../wistia'
import { YouTubeConfig } from '../youtube'
import { PeerTubeConfig } from '../peertube'

export interface Config {
soundcloud?: SoundCloudConfig
Expand All @@ -22,6 +23,7 @@ export interface Config {
mixcloud?: MixcloudConfig
vidyard?: VidyardConfig
twitch?: TwitchConfig
peertube?: PeerTubeConfig
}

export interface ReactPlayerProps extends BaseReactPlayerProps {
Expand Down
9 changes: 9 additions & 0 deletions types/peertube.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import BaseReactPlayer, { BaseReactPlayerProps } from './base'

export type PeerTubeConfig = Record<string, any>

export interface PeerTubePlayerProps extends BaseReactPlayerProps {
config?: PeerTubeConfig
}

export default class PeerTubePlayer extends BaseReactPlayer<PeerTubePlayerProps> {}