simple youtube player implemted

This commit is contained in:
NikolaBorislavovHristov 2018-11-14 14:40:27 +02:00
parent 30bce1ba11
commit d653e35796
4 changed files with 255 additions and 3 deletions

View file

@ -8,6 +8,7 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<script src="https://www.youtube.com/iframe_api"></script>
</body> </body>
</html> </html>

View file

@ -1,6 +1,7 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import ReactHTMLVideo from './stremio-video/ReactHTMLVideo'; import ReactHTMLVideo from './stremio-video/ReactHTMLVideo';
import ReactYouTubeVideo from './stremio-video/ReactYouTubeVideo';
import ControlBar from './ControlBar'; import ControlBar from './ControlBar';
import styles from './styles'; import styles from './styles';
@ -42,9 +43,13 @@ class Player extends Component {
} }
prepareStream = () => { prepareStream = () => {
return Promise.resolve({ return new Promise((resolve, reject) => {
source: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', YT.ready(() => {
videoComponent: ReactHTMLVideo resolve({
source: 'SEL97pn5aS0',
videoComponent: ReactYouTubeVideo
});
});
}); });
} }

View file

@ -0,0 +1,57 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import YouTubeVideo from './YouTubeVideo';
class ReactYouTubeVideo extends Component {
constructor(props) {
super(props);
this.videoContainerRef = React.createRef();
}
componentDidMount() {
this.video = new YouTubeVideo(this.videoContainerRef.current);
this.video.on('ended', this.props.onEnded);
this.video.on('error', this.props.onError);
this.video.on('propValue', this.props.onPropValue);
this.video.on('propChanged', this.props.onPropChanged);
this.props.observedProps.forEach((propName) => {
this.dispatch('observeProp', propName);
});
}
componentWillUnmount() {
this.dispatch('stop');
}
shouldComponentUpdate() {
return false;
}
dispatch = (...args) => {
try {
this.video && this.video.dispatch(...args);
} catch (e) {
console.error('YouTubeVideo', e);
}
}
render() {
return (
<div ref={this.videoContainerRef} className={this.props.className} />
);
}
}
ReactYouTubeVideo.manifest = YouTubeVideo.manifest;
ReactYouTubeVideo.propTypes = {
className: PropTypes.string,
onEnded: PropTypes.func.isRequired,
onError: PropTypes.func.isRequired,
onPropValue: PropTypes.func.isRequired,
onPropChanged: PropTypes.func.isRequired,
observedProps: PropTypes.arrayOf(PropTypes.string).isRequired
};
export default ReactYouTubeVideo;

View file

@ -0,0 +1,189 @@
var EventEmitter = require('events');
var YouTubeVideo = function(containerElement) {
var events = new EventEmitter();
var ready = false;
var observedProps = {};
var timeIntervalId = null;
var durationIntervalId = null;
var dispatchArgsQueue = [];
var onEnded = function() {
events.emit('ended');
};
var onError = function(event) {
var message;
var critical;
switch (event.data) {
case 2:
message = 'Invalid request';
critical = true;
break;
case 5:
message = 'The requested content cannot be played';
critical = true;
break;
case 100:
message = 'The video has been removed or marked as private';
critical = true;
break;
case 101:
case 150:
message = 'The video cannot be played in embedded players';
critical = true;
break;
default:
message = 'Unknown error';
critical = true;
}
events.emit('error', {
code: event.data,
message: message,
critical: critical
});
};
var onPausedChanged = function() {
events.emit('propChanged', 'paused', video.getPlayerState() === YT.PlayerState.PAUSED);
};
var onTimeChanged = function() {
events.emit('propChanged', 'time', video.getCurrentTime() * 1000);
};
var onDurationChanged = function() {
events.emit('propChanged', 'duration', video.getDuration() !== 0 ? video.getDuration() * 1000 : null);
};
var onReady = function() {
ready = true;
dispatchArgsQueue.forEach(function(args) {
this.dispatch.apply(this, args);
}, this);
dispatchArgsQueue = [];
};
var onStateChange = function(event) {
switch (event.data) {
case YT.PlayerState.ENDED:
onEnded();
break;
case YT.PlayerState.PLAYING:
if (observedProps.paused) {
onPausedChanged();
}
if (observedProps.duration) {
onDurationChanged();
}
break;
case YT.PlayerState.PAUSED:
if (observedProps.paused) {
onPausedChanged();
}
break;
}
};
var video = new YT.Player(containerElement, {
height: '100%',
width: '100%',
playerVars: {
autoplay: 1,
cc_load_policy: 0,
controls: 0,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
loop: 0,
modestbranding: 1,
playsinline: 1,
rel: 0
},
events: {
onError: onError.bind(this),
onReady: onReady.bind(this),
onStateChange: onStateChange.bind(this)
}
});
this.on = function(eventName, listener) {
events.on(eventName, listener);
};
this.dispatch = function() {
if (arguments[0] === 'observeProp') {
switch (arguments[1]) {
case 'paused':
if (ready) {
events.emit('propValue', 'paused', video.getPlayerState() === YT.PlayerState.PAUSED);
observedProps.paused = true;
}
break;
case 'time':
if (ready) {
events.emit('propValue', 'time', video.getCurrentTime() * 1000);
if (timeIntervalId === null) {
timeIntervalId = window.setInterval(onTimeChanged, 100);
}
}
break;
case 'duration':
if (ready) {
events.emit('propValue', 'duration', video.getDuration() !== 0 ? video.getDuration() * 1000 : null);
observedProps.duration = true;
if (durationIntervalId === null) {
durationIntervalId = window.setInterval(onDurationChanged, 5000);
}
}
break;
default:
throw new Error('observeProp not supported: ' + arguments[1]);
}
} else if (arguments[0] === 'setProp') {
switch (arguments[1]) {
case 'paused':
if (ready) {
arguments[2] ? video.pauseVideo() : video.playVideo();
}
break;
case 'time':
if (ready) {
video.seekTo(arguments[2] / 1000);
}
break;
default:
throw new Error('setProp not supported: ' + arguments[1]);
}
} else if (arguments[0] === 'command') {
switch (arguments[1]) {
case 'load':
if (ready) {
video.loadVideoById({
videoId: arguments[2].source,
startSeconds: isNaN(arguments[2].time) ? 0 : arguments[2].time / 1000
});
}
break;
case 'stop':
if (ready) {
events.removeAllListeners();
observedProps = {};
clearInterval(timeIntervalId);
clearInterval(durationIntervalId);
video.pauseVideo();
}
break;
default:
throw new Error('command not supported: ' + arguments[1]);
}
}
if (!ready) {
dispatchArgsQueue.push(Array.from(arguments));
}
};
};
YouTubeVideo.manifest = {
name: 'YouTubeVideo',
embedded: true,
props: ['paused', 'time', 'duration', 'volume']
};
module.exports = YouTubeVideo;