UNPKG

@lahzenegar/video-react

Version:

Video-React is a web video player built from the ground up for an HTML5 world using React library.

652 lines (540 loc) 19.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _Manager = require('../Manager'); var _Manager2 = _interopRequireDefault(_Manager); var _LoadingSpinner = require('./LoadingSpinner'); var _LoadingSpinner2 = _interopRequireDefault(_LoadingSpinner); var _AudioVisualizer = require('./AudioVisualizer'); var _AudioVisualizer2 = _interopRequireDefault(_AudioVisualizer); var _PosterImage = require('./PosterImage'); var _PosterImage2 = _interopRequireDefault(_PosterImage); var _Video = require('./Video'); var _Video2 = _interopRequireDefault(_Video); var _Bezel = require('./Bezel'); var _Bezel2 = _interopRequireDefault(_Bezel); var _Shortcut = require('./Shortcut'); var _Shortcut2 = _interopRequireDefault(_Shortcut); var _ControlBar = require('./control-bar/ControlBar'); var _ControlBar2 = _interopRequireDefault(_ControlBar); var _utils = require('../utils'); var _fullscreen = require('../utils/fullscreen'); var _fullscreen2 = _interopRequireDefault(_fullscreen); var _browser = require('../utils/browser'); var browser = _interopRequireWildcard(_browser); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var propTypes = { children: _propTypes2.default.any, width: _propTypes2.default.number, height: _propTypes2.default.number, fluid: _propTypes2.default.bool, muted: _propTypes2.default.bool, aspectRatio: _propTypes2.default.string, className: _propTypes2.default.string, videoId: _propTypes2.default.string, startTime: _propTypes2.default.number, dvrThreshold: _propTypes2.default.number, hasAudioSrc: _propTypes2.default.bool, hasAds: _propTypes2.default.bool, targetTotalTime: _propTypes2.default.number, adsTagUrl: _propTypes2.default.string, loop: _propTypes2.default.bool, autoPlay: _propTypes2.default.bool, src: _propTypes2.default.string, poster: _propTypes2.default.string, preload: _propTypes2.default.oneOf(['auto', 'metadata', 'none']), onLoadStart: _propTypes2.default.func, onWaiting: _propTypes2.default.func, onCanPlay: _propTypes2.default.func, onCanPlayThrough: _propTypes2.default.func, onPlaying: _propTypes2.default.func, onEnded: _propTypes2.default.func, onSeeking: _propTypes2.default.func, onSeeked: _propTypes2.default.func, onPlay: _propTypes2.default.func, onPause: _propTypes2.default.func, onProgress: _propTypes2.default.func, onDurationChange: _propTypes2.default.func, onError: _propTypes2.default.func, onSuspend: _propTypes2.default.func, onAbort: _propTypes2.default.func, onEmptied: _propTypes2.default.func, onStalled: _propTypes2.default.func, onLoadedMetadata: _propTypes2.default.func, onLoadedData: _propTypes2.default.func, onTimeUpdate: _propTypes2.default.func, onRateChange: _propTypes2.default.func, onVolumeChange: _propTypes2.default.func, onStatsChange: _propTypes2.default.func, onUserActivateChange: _propTypes2.default.func, onWaitingStop: _propTypes2.default.func, onStartFirstTime: _propTypes2.default.func, onSourceChange: _propTypes2.default.func, onSecondsPlayedReached: _propTypes2.default.func, onAllAdsCompleted: _propTypes2.default.func, store: _propTypes2.default.object, sendAdsEvent: _propTypes2.default.func, onAdError: _propTypes2.default.func, onAdStart: _propTypes2.default.func, debugMode: _propTypes2.default.bool, onAdPlaying: _propTypes2.default.func, onAdStartFirstTime: _propTypes2.default.func, onVASTLoadedFirstTime: _propTypes2.default.func, onFirstPlayAttempt: _propTypes2.default.func, onStartError: _propTypes2.default.func, chapters: _propTypes2.default.array, storyboard: _propTypes2.default.object }; var defaultProps = { dvrThreshold: 300, hasAudioSrc: false, hasAds: false, fluid: true, muted: false, targetTotalTime: 10, aspectRatio: 'auto' }; var Player = function (_Component) { (0, _inherits3.default)(Player, _Component); function Player(props) { (0, _classCallCheck3.default)(this, Player); var _this = (0, _possibleConstructorReturn3.default)(this, (Player.__proto__ || (0, _getPrototypeOf2.default)(Player)).call(this, props)); _this.handleClick = function (event) { if (_this.manager && _this.manager.rootElement && event && event.target) { if (_this.manager.rootElement.contains(event.target)) { _this.handleFocus(); } else { _this.handleBlur(); } } }; _this.controlsHideTimer = null; _this.statsUpdateInterval = null; _this.lastSecondPlayed = 0; _this.lastPercentPlayed = 0; _this.lastWaitingTime = 0; _this.video = null; // the Video component _this.manager = new _Manager2.default(props.store); _this.actions = _this.manager.getActions(); _this.manager.subscribeToPlayerStateChange(_this.handleStateChange.bind(_this)); _this.getStyle = _this.getStyle.bind(_this); _this.handleResize = _this.handleResize.bind(_this); _this.getChildren = _this.getChildren.bind(_this); _this.handleMouseMove = (0, _utils.throttle)(_this.handleMouseMove.bind(_this), 250); _this.handleMouseDown = _this.handleMouseDown.bind(_this); _this.startControlsTimer = _this.startControlsTimer.bind(_this); _this.handleFullScreenChange = _this.handleFullScreenChange.bind(_this); _this.handleKeyDown = _this.handleKeyDown.bind(_this); _this.handleFocus = _this.handleFocus.bind(_this); _this.handleBlur = _this.handleBlur.bind(_this); return _this; } (0, _createClass3.default)(Player, [{ key: 'componentDidMount', value: function componentDidMount() { this.handleResize(); this.handleStatsChange(); window.addEventListener('resize', this.handleResize); document.addEventListener('mousedown', this.handleClick, false); _fullscreen2.default.addEventListener(this.handleFullScreenChange); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { // Remove event listener window.removeEventListener('resize', this.handleResize); document.removeEventListener('mousedown', this.handleClick, false); _fullscreen2.default.removeEventListener(this.handleFullScreenChange); if (this.controlsHideTimer) { window.clearTimeout(this.controlsHideTimer); } if (this.statsUpdateInterval) { clearInterval(this.statsUpdateInterval); } } }, { key: 'getDefaultChildren', value: function getDefaultChildren(props, fullProps) { var _this2 = this; return [_react2.default.createElement(_Video2.default, (0, _extends3.default)({ ref: function ref(c) { _this2.video = c; _this2.manager.video = _this2.video; }, key: 'video', order: 0.0 }, fullProps)), _react2.default.createElement(_PosterImage2.default, (0, _extends3.default)({ key: 'poster-image', order: 1.0 }, props)), _react2.default.createElement(_LoadingSpinner2.default, (0, _extends3.default)({ key: 'loading-spinner', order: 2.0 }, props)), _react2.default.createElement(_AudioVisualizer2.default, (0, _extends3.default)({ key: 'audio-visualizer', order: 3.0 }, props)), _react2.default.createElement(_Bezel2.default, (0, _extends3.default)({ key: 'bezel', order: 4.0 }, props)), _react2.default.createElement(_ControlBar2.default, (0, _extends3.default)({ key: 'control-bar', order: 6.0 }, props)), _react2.default.createElement(_Shortcut2.default, (0, _extends3.default)({ key: 'shortcut', order: 99.0 }, props))]; } }, { key: 'getChildren', value: function getChildren(props) { var propsWithoutChildren = (0, _extends3.default)({}, props, { children: null }); var children = _react2.default.Children.toArray(this.props.children).filter(function (e) { return !(0, _utils.isVideoChild)(e); }); var defaultChildren = this.getDefaultChildren(propsWithoutChildren, props); return (0, _utils.mergeAndSortChildren)(defaultChildren, children, propsWithoutChildren); } }, { key: 'getStyle', value: function getStyle() { var fluid = this.props.fluid; var _manager$getState = this.manager.getState(), player = _manager$getState.player; var style = {}; var width = void 0; var height = void 0; var aspectRatio = void 0; // The aspect ratio is either used directly or to calculate width and height. if (this.props.aspectRatio !== undefined && this.props.aspectRatio !== 'auto') { // Use any aspectRatio that's been specifically set aspectRatio = this.props.aspectRatio; } else if (player.videoWidth) { // Otherwise try to get the aspect ratio from the video metadata aspectRatio = player.videoWidth + ':' + player.videoHeight; } else { // Or use a default. The video element's is 2:1, but 16:9 is more common. aspectRatio = '16:9'; } // Get the ratio as a decimal we can use to calculate dimensions var ratioParts = aspectRatio.split(':'); var ratioMultiplier = ratioParts[1] / ratioParts[0]; if (this.props.width !== undefined) { // Use any width that's been specifically set width = this.props.width; } else if (this.props.height !== undefined) { // Or calulate the width from the aspect ratio if a height has been set width = this.props.height / ratioMultiplier; } else { // Or use the video's metadata, or use the video el's default of 300 width = player.videoWidth || 400; } if (this.props.height !== undefined) { // Use any height that's been specifically set height = this.props.height; } else { // Otherwise calculate the height from the ratio and the width height = width * ratioMultiplier; } if (fluid) { style.paddingTop = ratioMultiplier * 100 + '%'; } else { style.width = width + 'px'; style.height = height + 'px'; } return style; } // get redux state // { player, operation } }, { key: 'getState', value: function getState() { return this.manager.getState(); } // get playback rate }, { key: 'play', // play the video value: function play() { this.video.play(); } // pause the video }, { key: 'pause', value: function pause() { this.video.pause(); } // Change the video source and re-load the video: }, { key: 'load', value: function load() { this.video.load(); } // Add a new text track to the video }, { key: 'addTextTrack', value: function addTextTrack() { var _video; (_video = this.video).addTextTrack.apply(_video, arguments); } // Check if your browser can play different types of video: }, { key: 'canPlayType', value: function canPlayType() { var _video2; (_video2 = this.video).canPlayType.apply(_video2, arguments); } // seek video by time }, { key: 'seek', value: function seek(time) { this.video.seek(time); } // jump forward x seconds }, { key: 'forward', value: function forward(seconds) { this.video.forward(seconds); } // jump back x seconds }, { key: 'replay', value: function replay(seconds) { this.video.replay(seconds); } // enter or exist full screen }, { key: 'toggleFullscreen', value: function toggleFullscreen() { this.video.toggleFullscreen(); } // subscribe to player state change }, { key: 'subscribeToStateChange', value: function subscribeToStateChange(listener) { return this.manager.subscribeToPlayerStateChange(listener); } // player resize }, { key: 'handleResize', value: function handleResize() {} }, { key: 'handleFullScreenChange', value: function handleFullScreenChange() { this.actions.handleFullscreenChange(_fullscreen2.default.isFullscreen); } }, { key: 'handleMouseDown', value: function handleMouseDown() { this.startControlsTimer(); } }, { key: 'handleMouseMove', value: function handleMouseMove() { this.startControlsTimer(); } }, { key: 'handleKeyDown', value: function handleKeyDown() { this.startControlsTimer(); } }, { key: 'startControlsTimer', value: function startControlsTimer() { var _this3 = this; var onUserActivateChange = this.props.onUserActivateChange; this.actions.userActivate(true); if (onUserActivateChange) { onUserActivateChange(true); } clearTimeout(this.controlsHideTimer); this.controlsHideTimer = setTimeout(function () { _this3.actions.userActivate(false); if (onUserActivateChange) { onUserActivateChange(false); } }, 3000); } }, { key: 'handleStateChange', value: function handleStateChange(state, prevState) { if (state.isFullscreen !== prevState.isFullscreen) { this.handleResize(); } this.forceUpdate(); // re-render } }, { key: 'handleFocus', value: function handleFocus() { this.actions.activate(true); } }, { key: 'handleBlur', value: function handleBlur() { this.actions.activate(false); } }, { key: 'handleStatsChange', value: function handleStatsChange() { var _this4 = this; var onStatsChange = this.props.onStatsChange; if (this.statsUpdateInterval) { clearInterval(this.statsUpdateInterval); } this.statsUpdateInterval = setInterval(function () { var _manager$getState2 = _this4.manager.getState(), _manager$getState2$pl = _manager$getState2.player, secondsPlayed = _manager$getState2$pl.secondsPlayed, percentPlayed = _manager$getState2$pl.percentPlayed, waitingTime = _manager$getState2$pl.waitingTime, tracks = _manager$getState2$pl.tracks, realActiveTrack = _manager$getState2$pl.realActiveTrack, ads = _manager$getState2$pl.ads; if (ads) { return; } if (onStatsChange) { var realActiveTrackLabel = null; if (tracks && tracks.length > 1) { realActiveTrackLabel = tracks.filter(function (item) { return item.id === realActiveTrack; })[0].label; } onStatsChange({ percentPlayed: percentPlayed - _this4.lastPercentPlayed, waitingTime: Math.round((waitingTime - _this4.lastWaitingTime) * 100) / 100, quality: realActiveTrackLabel, secondsPlayed: Math.round((secondsPlayed - _this4.lastSecondPlayed) * 100) / 100 }); _this4.lastSecondPlayed = secondsPlayed; _this4.lastPercentPlayed = percentPlayed; _this4.lastWaitingTime = waitingTime; } }, 10000); } }, { key: 'render', value: function render() { var _this5 = this; var fluid = this.props.fluid; var _manager$getState3 = this.manager.getState(), player = _manager$getState3.player; var paused = player.paused, hasStarted = player.hasStarted, waiting = player.waiting, seeking = player.seeking, isFullscreen = player.isFullscreen, userActivity = player.userActivity, isLive = player.isLive, ads = player.ads, contentLoading = player.contentLoading; var props = (0, _extends3.default)({}, this.props, { player: player, actions: this.actions, manager: this.manager, store: this.manager.store, video: this.video ? this.video.video : null }); var children = this.getChildren(props); return _react2.default.createElement( 'div', { className: (0, _classnames2.default)({ 'video-react-controls-enabled': !browser.IS_MOBILE, 'video-react-controls-disabled': browser.IS_MOBILE, 'video-react-native-player': browser.IS_MOBILE, 'video-react-native-seek-bar-disabled': isLive, 'video-react-has-started': hasStarted, 'video-react-paused': paused, 'video-react-playing': !paused, 'video-react-waiting': waiting || contentLoading, 'video-react-seeking': seeking, 'video-react-fluid': fluid, 'video-react-ads-playing': ads, 'video-react-fullscreen': isFullscreen, 'video-react-user-inactive': !userActivity, 'video-react-user-active': userActivity, 'video-react-workinghover': true }, 'video-react', this.props.className), style: this.getStyle(), ref: function ref(c) { _this5.manager.rootElement = c; }, onTouchStart: this.handleMouseDown, onMouseDown: this.handleMouseDown, onMouseMove: this.handleMouseMove, onKeyDown: this.handleKeyDown, onFocus: this.handleFocus, onBlur: this.handleBlur, tabIndex: '-1' }, children ); } }, { key: 'playbackRate', get: function get() { return this.video.playbackRate; } // set playback rate // speed of video , set: function set(rate) { this.video.playbackRate = rate; } }, { key: 'muted', get: function get() { return this.video.muted; }, set: function set(val) { this.video.muted = val; } }, { key: 'volume', get: function get() { return this.video.volume; }, set: function set(val) { this.video.volume = val; } // video width }, { key: 'videoWidth', get: function get() { return this.video.videoWidth; } // video height }, { key: 'videoHeight', get: function get() { return this.video.videoHeight; } }]); return Player; }(_react.Component); exports.default = Player; Player.contextTypes = { store: _propTypes2.default.object }; Player.propTypes = propTypes; Player.defaultProps = defaultProps; Player.displayName = 'Player';