From d39cab9002dd46a806e7d7d860f56ef39ea1dcc6 Mon Sep 17 00:00:00 2001 From: Travis Arnold Date: Tue, 20 Oct 2015 23:26:58 -0700 Subject: [PATCH] 0.1.0 release --- README.md | 10 +- bower.json | 2 +- dist/react-media-player.js | 1563 ++++++++++++++++++++++++++++++++ dist/react-media-player.min.js | 1 + example/index.jsx | 2 +- package.json | 2 +- src/Media.jsx | 13 +- src/get-media-tag.js | 7 +- 8 files changed, 1584 insertions(+), 16 deletions(-) create mode 100644 dist/react-media-player.js create mode 100644 dist/react-media-player.min.js diff --git a/README.md b/README.md index 5d2db18..31ef790 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,18 @@ -## React Media Player 0.0.2 +## React Media Player 0.1.0 React media container component to help build video & audio players. ## TODOS -- [x] Fix Progress component -- [x] Fix Volume getting locked up when player is muted -- [x] SeekBar crashes Safari -- [x] Playlist feature +- [ ] Loading new videos for Youtube/Vimeo - [ ] Loading state to allow loaders for loading big/new media - [ ] Show time/thumbnail preview when hovering seekbar - [ ] Subtitle support -- [ ] Forward / Rewind +- [ ] Forward / Rewind public methods - [ ] Playback speed option - [ ] Keyboard friendly - [ ] ARIA a11y ready - [ ] Move controls into addons -- [x] Fullscreen control example - [ ] Add tests - [ ] Check browser support - [ ] Add SoundCloud API support \ No newline at end of file diff --git a/bower.json b/bower.json index e5ec470..55770a0 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "react-media-player", - "version": "0.0.2", + "version": "0.1.0", "homepage": "https://github.com/souporserious/react-media-player", "authors": [ "Travis Arnold " diff --git a/dist/react-media-player.js b/dist/react-media-player.js new file mode 100644 index 0000000..b9d311b --- /dev/null +++ b/dist/react-media-player.js @@ -0,0 +1,1563 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("React"), require("ReactDOM")); + else if(typeof define === 'function' && define.amd) + define(["React", "ReactDOM"], factory); + else if(typeof exports === 'object') + exports["ReactMediaPlayer"] = factory(require("React"), require("ReactDOM")); + else + root["ReactMediaPlayer"] = factory(root["React"], root["ReactDOM"]); +})(this, function(__WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_5__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = "dist/"; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + + 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 _formatTime = __webpack_require__(1); + + var _formatTime2 = _interopRequireDefault(_formatTime); + + var _Media2 = __webpack_require__(2); + + var _Media3 = _interopRequireDefault(_Media2); + + exports.Media = _Media3['default']; + + var _controlsControlsJs = __webpack_require__(13); + + var _controls = _interopRequireWildcard(_controlsControlsJs); + + exports.controls = _controls; + var utils = { + formatTime: _formatTime2['default'] + }; + exports.utils = utils; + +/***/ }, +/* 1 */ +/***/ function(module, exports) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + exports['default'] = formatTime; + + function formatTime(current) { + var minutes = Math.floor(current / 60); + var seconds = Math.floor(current % 60); + + seconds = seconds >= 10 ? seconds : '0' + seconds; + minutes = minutes >= 10 ? minutes : minutes; + + return minutes + ':' + seconds; + } + + module.exports = exports['default']; + +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + + var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; } + + var _react = __webpack_require__(4); + + var _react2 = _interopRequireDefault(_react); + + var _reactDom = __webpack_require__(5); + + var _reactDom2 = _interopRequireDefault(_reactDom); + + var _reactLibShallowCompare = __webpack_require__(6); + + var _reactLibShallowCompare2 = _interopRequireDefault(_reactLibShallowCompare); + + var _loadApi = __webpack_require__(8); + + var _loadApi2 = _interopRequireDefault(_loadApi); + + var _getVendor = __webpack_require__(3); + + var _getVendor2 = _interopRequireDefault(_getVendor); + + var _getYoutubeId = __webpack_require__(9); + + var _getYoutubeId2 = _interopRequireDefault(_getYoutubeId); + + var _getVimeoId = __webpack_require__(10); + + var _getVimeoId2 = _interopRequireDefault(_getVimeoId); + + var _Player = __webpack_require__(11); + + var _Player2 = _interopRequireDefault(_Player); + + var apiFlags = { + youtube: false, + vimeo: false + }; + + var Media = (function (_Component) { + _inherits(Media, _Component); + + function Media() { + var _this = this; + + _classCallCheck(this, Media); + + _get(Object.getPrototypeOf(Media.prototype), 'constructor', this).apply(this, arguments); + + this.state = { + player: null, + vendor: null, + playing: false, + duration: 0, + current: 0, + progress: 0, + muted: false, + volume: 1, + fullscreen: false + }; + this._src = null; + this._currentProgressID = null; + this._currentYTProgressID = null; + this._currentTimeID = null; + this._lastVolume = 0; + + this.play = function () { + var _state = _this.state; + var player = _state.player; + var vendor = _state.vendor; + + switch (vendor) { + case 'youtube': + player.playVideo(); + _this._currentTimeID = requestAnimationFrame(_this._getCurrentTime); + break; + case 'vimeo': + player.api('play'); + break; + default: + player.play(); + } + }; + + this.pause = function () { + var _state2 = _this.state; + var player = _state2.player; + var vendor = _state2.vendor; + + switch (vendor) { + case 'youtube': + player.pauseVideo(); + cancelAnimationFrame(_this._currentTimeID); + break; + case 'vimeo': + player.api('pause'); + break; + default: + player.pause(); + } + }; + + this.playPause = function () { + var playing = _this.state.playing; + + if (!playing) { + _this.play(); + } else { + _this.pause(); + } + }; + + this.stop = function () { + var player = _this.state.player; + + player.pause(); + player.currentTime = 0; + }; + + this.setCurrentTime = function (current) { + var _state3 = _this.state; + var player = _state3.player; + var vendor = _state3.vendor; + + if (vendor === 'youtube') { + player.seekTo(current); + } else if (vendor === 'vimeo') { + player.api('seekTo', current); + } else { + player.currentTime = current; + } + + _this._setCurrentTime(current); + }; + + this.muteUnmute = function () { + var _state4 = _this.state; + var player = _state4.player; + var vendor = _state4.vendor; + var muted = _state4.muted; + var volume = _state4.volume; + + if (!muted) { + switch (vendor) { + case 'youtube': + player.mute(); + break; + default: + player.muted = true; + } + + // store volume for un-mute + _this._lastVolume = volume; + + // if muted the volume should be set to 0 + _this.setVolume(0); + + _this._setMute(true); + } else { + + switch (vendor) { + case 'youtube': + player.unMute(); + break; + default: + player.muted = false; + } + + // if unmuted set to last volume + _this.setVolume(_this._lastVolume); + + _this._setMute(false); + } + }; + + this.setVolume = function (volume) { + var _state5 = _this.state; + var player = _state5.player; + var vendor = _state5.vendor; + + var muted = false; + + if (volume <= 0) { + muted = true; + } + + if (vendor === 'youtube') { + player.setVolume(volume * 100); + } else if (vendor === 'vimeo') { + player.api('setVolume', volume); + } else { + player.volume = volume; + } + + _this._setVolume(volume); + _this._setMute(muted); + + if (muted) { + switch (vendor) { + case 'youtube': + player.mute(); + break; + default: + player.muted = true; + } + } else { + switch (vendor) { + case 'youtube': + player.unMute(); + break; + default: + player.muted = false; + } + } + }; + + this.toggleFullscreen = function () { + if (!_this.state.fullscreen) { + var n = _this.state.playerNode; + + if (n.requestFullscreen) { + n.requestFullscreen(); + } else if (n.webkitRequestFullscreen) { + n.webkitRequestFullscreen(); + } else if (n.mozRequestFullScreen) { + n.mozRequestFullScreen(); + } else if (n.msRequestFullscreen) { + n.msRequestFullscreen(); + } + } else { + var d = document; + + if (d.exitFullscreen) { + d.exitFullscreen(); + } else if (d.webkitExitFullscreen) { + d.webkitExitFullscreen(); + } else if (d.mozCancelFullScreen) { + d.mozCancelFullScreen(); + } else if (d.msExitFullscreen) { + d.msExitFullscreen(); + } + } + }; + + this.load = function (src) { + var player = _this.state.player; + + var vendor = (0, _getVendor2['default'])(src); + + if (['youtube', 'vimeo'].indexOf(vendor)) { + console.log('fug'); + } + + // pause player + player.pause(); + + // test support + // !!!! need to check canPlayType on init + if (player.canPlayType('video/mp4')) { + player.setAttribute('src', src); + } else if (player.canPlayType('video/webm')) { + player.setAttribute('src', setupURL(src, 'webm')); + } else if (player.canPlayType('video/ogg')) { + player.setAttribute('src', setupURL(src, 'ogv')); + } + + // load new media + player.load(); + + // play new media + player.play(); + }; + + this._getCurrentProgress = function () { + var player = _this.state.player; + + var progress = 0; + + if (player.buffered.length > 0) { + progress = player.buffered.end(0) / player.duration; + } + + _this._setProgress(progress); + + if (progress < 1) { + _this._currentProgressID = requestAnimationFrame(_this._getCurrentProgress); + } + }; + + this._getCurrentYTProgress = function () { + var player = _this.state.player; + + var progress = player.getVideoLoadedFraction(); + + _this._setProgress(progress); + + if (progress < 1) { + _this._currentYTProgressID = requestAnimationFrame(_this._getCurrentYTProgress); + } + }; + + this._getCurrentTime = function () { + var player = _this.state.player; + + _this._setCurrentTime(player.getCurrentTime()); + + _this._currentTimeID = requestAnimationFrame(_this._getCurrentTime); + }; + } + + _createClass(Media, [{ + key: 'componentDidMount', + value: function componentDidMount() { + this._setPlayer(this._setupAPI); + } + }, { + key: 'shouldComponentUpdate', + value: function shouldComponentUpdate(nextProps, nextState) { + return (0, _reactLibShallowCompare2['default'])(this, nextProps, nextState); + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() {} + }, { + key: '_setPlaying', + + // Props API + value: function _setPlaying(playing) { + var _this2 = this; + + if (playing === this.state.playing) return; + this.setState({ playing: playing }, function () { + _this2.props.onPlaying(playing); + }); + } + }, { + key: '_setProgress', + value: function _setProgress(progress) { + var _this3 = this; + + if (progress === this.state.progress) return; + this.setState({ progress: progress }, function () { + _this3.props.getProgress(progress); + }); + } + }, { + key: '_setCurrentTime', + value: function _setCurrentTime(current) { + var _this4 = this; + + if (current === this.state.current) return; + this.setState({ current: current }, function () { + _this4.props.getCurrentTime(current); + }); + } + }, { + key: '_setDuration', + value: function _setDuration(duration) { + var _this5 = this; + + if (duration === this.state.duration) return; + this.setState({ duration: duration }, function () { + _this5.props.getDuration(duration); + }); + } + }, { + key: '_setMute', + value: function _setMute(muted) { + var _this6 = this; + + if (muted === this.state.muted) return; + this.setState({ muted: muted }, function () { + _this6.props.onMute(muted); + }); + } + }, { + key: '_setVolume', + value: function _setVolume(volume) { + var _this7 = this; + + if (volume === this.state.volume) return; + this.setState({ volume: volume }, function () { + _this7.props.onVolumeChange(volume); + }); + } + }, { + key: '_setFullscreen', + value: function _setFullscreen(fullscreen) { + var _this8 = this; + + if (fullscreen === this.state.fullscreen) return; + this.setState({ fullscreen: fullscreen }, function () { + _this8.props.onFullscreen(fullscreen); + }); + } + }, { + key: '_handleLoad', + + // need todo + value: function _handleLoad(src) { + var _this9 = this; + + this.setState({ src: src }, function () { + _this9.props.onChange(src); + }); + } + }, { + key: '_setupYoutubeAPI', + + // Private Methods + value: function _setupYoutubeAPI() { + var _this10 = this; + + var vendor = 'youtube'; + var api = 'http://www.youtube.com/player_api'; + + // load the api if it hasn't been yet + if (!apiFlags[vendor]) { + (0, _loadApi2['default'])(api); + + // update flag + apiFlags[vendor] = true; + } + + // create player when API is ready + window.onYouTubeIframeAPIReady = function () { + return _this10._createYoutubePlayer(); + }; + } + }, { + key: '_createYoutubePlayer', + + // use youtube api to create player + value: function _createYoutubePlayer() { + var _this11 = this; + + var videoId = (0, _getYoutubeId2['default'])(this._src); + var player = new YT.Player(this.state.player, { + videoId: videoId, + playerVars: { + controls: 0, + showinfo: 0, + modestbranding: 1 + } + }); + + this.setState({ player: player }, function () { + _this11._init(); + }); + } + }, { + key: '_setupVimeoAPI', + value: function _setupVimeoAPI() { + var vendor = 'vimeo'; + var api = 'https://f.vimeocdn.com/js/froogaloop2.min.js'; + + // load the api if it hasn't been yet + if (!apiFlags[vendor]) { + (0, _loadApi2['default'])(api, vendor); + + // update flag + apiFlags[vendor] = true; + } + + // create player when API is ready + this._createVimeoPlayer(); + } + }, { + key: '_getVimeoPlayer', + value: function _getVimeoPlayer(id, cb) { + var request = new XMLHttpRequest(); + + request.open('GET', 'https://vimeo.com/api/oembed.json?url=https%3A//vimeo.com/' + id, true); + + request.onload = function () { + if (request.status >= 200 && request.status < 400) { + cb(JSON.parse(request.responseText)); + } + }; + + request.send(); + } + }, { + key: '_createVimeoPlayer', + value: function _createVimeoPlayer() { + var _this12 = this; + + var player = this.state.player; + + var videoId = (0, _getVimeoId2['default'])(this._src); + + this._getVimeoPlayer(videoId, function (data) { + var parentNode = player.parentNode; + + // enable javascirpt API on the data html + data.html = data.html.replace(/(