diff --git a/CHANGELOG.md b/CHANGELOG.md index f685bad3..f38d9678 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [v2.6.0](https://github.com/CookPete/react-player/compare/v2.5.0...v2.6.0) + +> 23 July 2020 + +- Make force disabling PIP dependent on prop [`#964`](https://github.com/CookPete/react-player/pull/964) +- vimeo: listen for bufferring events and handle with matching callbacks [`#975`](https://github.com/CookPete/react-player/pull/975) +- Call onLoaded when file streaming SDKs have loaded [`#976`](https://github.com/CookPete/react-player/issues/976) +- yarn upgrade [`05ae217`](https://github.com/CookPete/react-player/commit/05ae21741f0963d6cb8be317b67879270de229ba) +- Add gitads banner to readme [`6840e35`](https://github.com/CookPete/react-player/commit/6840e3567339c2c5833b230919e1c639d0c6629c) + #### [v2.5.0](https://github.com/CookPete/react-player/compare/v2.4.0...v2.5.0) > 3 July 2020 @@ -1077,7 +1087,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). #### [v0.3.0](https://github.com/CookPete/react-player/compare/v0.2.1...v0.3.0) -> 24 December 2015 +> 25 December 2015 - Prime players to enable autoplay when out of focus [`#13`](https://github.com/CookPete/react-player/pull/13) - Enable multiple YouTube players [`#15`](https://github.com/CookPete/react-player/issues/15) diff --git a/dist/ReactPlayer.js b/dist/ReactPlayer.js index d382d096..6f43a100 100644 --- a/dist/ReactPlayer.js +++ b/dist/ReactPlayer.js @@ -1,2 +1,2 @@ -var ReactPlayer=function(e){function t(t){for(var n,o,i=t[0],a=t[1],u=0,c=[];ue.length)&&(t=e.length);for(var n=0,r=new Array(t);n2&&void 0!==arguments[2]?arguments[2]:null,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){return!0},i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:o.a,a=b(t);return a&&r(a)?Promise.resolve(a):new Promise((function(r,o){if(v[e])v[e].push({resolve:r,reject:o});else{v[e]=[{resolve:r,reject:o}];var a=function(t){v[e].forEach((function(e){return e.resolve(t)}))};if(n){var u=window[n];window[n]=function(){u&&u(),a(b(t))}}i(e,(function(r){r?(v[e].forEach((function(e){return e.reject(r)})),v[e]=null):n||a(b(t))}))}}))}function P(e){for(var t,n=arguments.length,r=new Array(n>1?n-1:0),o=1;o1?r-1:0),i=1;i0&&void 0!==arguments[0]?arguments[0]:document.createElement("video"),t=!1===/iPhone|iPod/.test(navigator.userAgent);return e.webkitSupportsPresentationMode&&"function"==typeof e.webkitSetPresentationMode&&t}},function(e,t,n){"use strict";n.d(t,"l",(function(){return a})),n.d(t,"g",(function(){return s})),n.d(t,"k",(function(){return f})),n.d(t,"i",(function(){return p})),n.d(t,"h",(function(){return y})),n.d(t,"e",(function(){return d})),n.d(t,"f",(function(){return h})),n.d(t,"j",(function(){return b})),n.d(t,"a",(function(){return v})),n.d(t,"d",(function(){return P})),n.d(t,"b",(function(){return g})),n.d(t,"c",(function(){return O})),n.d(t,"m",(function(){return w}));var r=n(1);function o(e,t){var n;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,u=!0,l=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return u=e.done,e},e:function(e){l=!0,a=e},f:function(){try{u||null==n.return||n.return()}finally{if(l)throw a}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&e<1){var r=this.player.getDuration();return r?void this.player.seekTo(r*e):void console.warn("ReactPlayer: could not seek using fraction – duration not yet available")}this.player.seekTo(e)}},{key:"render",value:function(){var e=this.props.activePlayer;return e?o.a.createElement(e,_({},this.props,{onMount:this.handlePlayerMount,onReady:this.handleReady,onPlay:this.handlePlay,onPause:this.handlePause,onEnded:this.handleEnded,onLoaded:this.handleLoaded,onError:this.handleError})):null}}])&&I(t.prototype,n),r&&I(t,r),a}(r.Component);function N(e){return(N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function z(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function B(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:"player";return e.player?e.player.getInternalPlayer(t):null})),X(K(e),"seekTo",(function(t,n){if(!e.player)return null;e.player.seekTo(t,n)})),X(K(e),"handleReady",(function(){e.props.onReady(K(e))})),X(K(e),"getActivePlayer",f((function(e){for(var t=0,n=[].concat(ue,$(Q));te.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0?n.end(n.length-1):t}},{key:"getCurrentTime",value:function(){return this.player?this.player.currentTime:null}},{key:"getSecondsLoaded",value:function(){if(!this.player)return null;var e=this.player.buffered;if(0===e.length)return 0;var t=e.end(e.length-1),n=this.getDuration();return t>n?n:t}},{key:"getSource",value:function(e){var t=this.shouldUseHLS(e),n=this.shouldUseDASH(e),r=this.shouldUseFLV(e);if(!(e instanceof Array||Object(i.c)(e)||t||n||r))return m.test(e)?e.replace("www.dropbox.com","dl.dropboxusercontent.com"):e}},{key:"render",value:function(){var e=this.props,t=e.url,n=e.playing,r=e.loop,i=e.controls,a=e.muted,u=e.config,c=e.width,s=e.height,f=this.shouldUseAudio(this.props)?"audio":"video",p={width:"auto"===c?c:"100%",height:"auto"===s?s:"100%"};return o.a.createElement(f,l({ref:this.ref,src:this.getSource(t),style:p,preload:"auto",autoPlay:n||void 0,controls:i,muted:a,loop:r},u.attributes),t instanceof Array&&t.map(this.renderSourceElement),u.tracks.map(this.renderTrack))}}])&&s(t.prototype,n),r&&s(t,r),y}(r.Component);b(g,"displayName","FilePlayer"),b(g,"canPlay",a.m.file)},function(e,t,n){"use strict";n.r(t),n.d(t,"default",(function(){return v}));var r=n(0),o=n.n(r);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function u(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n2&&void 0!==arguments[2]?arguments[2]:null,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){return!0},i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:o.a,a=b(t);return a&&r(a)?Promise.resolve(a):new Promise((function(r,o){if(m[e])m[e].push({resolve:r,reject:o});else{m[e]=[{resolve:r,reject:o}];var a=function(t){m[e].forEach((function(e){return e.resolve(t)}))};if(n){var u=window[n];window[n]=function(){u&&u(),a(b(t))}}i(e,(function(r){r?(m[e].forEach((function(e){return e.reject(r)})),m[e]=null):n||a(b(t))}))}}))}function P(e){for(var t,n=arguments.length,r=new Array(n>1?n-1:0),o=1;o1?r-1:0),i=1;i0&&void 0!==arguments[0]?arguments[0]:document.createElement("video"),t=!1===/iPhone|iPod/.test(navigator.userAgent);return e.webkitSupportsPresentationMode&&"function"==typeof e.webkitSetPresentationMode&&t}},function(e,t,n){"use strict";n.d(t,"l",(function(){return a})),n.d(t,"g",(function(){return s})),n.d(t,"k",(function(){return f})),n.d(t,"i",(function(){return p})),n.d(t,"h",(function(){return y})),n.d(t,"e",(function(){return d})),n.d(t,"f",(function(){return h})),n.d(t,"j",(function(){return b})),n.d(t,"a",(function(){return m})),n.d(t,"d",(function(){return P})),n.d(t,"b",(function(){return g})),n.d(t,"c",(function(){return O})),n.d(t,"m",(function(){return w}));var r=n(1);function o(e,t){var n;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,u=!0,l=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return u=e.done,e},e:function(e){l=!0,a=e},f:function(){try{u||null==n.return||n.return()}finally{if(l)throw a}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&e<1){var r=this.player.getDuration();return r?void this.player.seekTo(r*e):void console.warn("ReactPlayer: could not seek using fraction – duration not yet available")}this.player.seekTo(e)}},{key:"render",value:function(){var e=this.props.activePlayer;return e?o.a.createElement(e,_({},this.props,{onMount:this.handlePlayerMount,onReady:this.handleReady,onPlay:this.handlePlay,onPause:this.handlePause,onEnded:this.handleEnded,onLoaded:this.handleLoaded,onError:this.handleError})):null}}])&&I(t.prototype,n),r&&I(t,r),a}(r.Component);function B(e){return(B="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function N(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function z(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:"player";return e.player?e.player.getInternalPlayer(t):null})),X(K(e),"seekTo",(function(t,n){if(!e.player)return null;e.player.seekTo(t,n)})),X(K(e),"handleReady",(function(){e.props.onReady(K(e))})),X(K(e),"getActivePlayer",f((function(e){for(var t=0,n=[].concat(ue,$(Q));te.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0?n.end(n.length-1):t}},{key:"getCurrentTime",value:function(){return this.player?this.player.currentTime:null}},{key:"getSecondsLoaded",value:function(){if(!this.player)return null;var e=this.player.buffered;if(0===e.length)return 0;var t=e.end(e.length-1),n=this.getDuration();return t>n?n:t}},{key:"getSource",value:function(e){var t=this.shouldUseHLS(e),n=this.shouldUseDASH(e),r=this.shouldUseFLV(e);if(!(e instanceof Array||Object(i.c)(e)||t||n||r))return v.test(e)?e.replace("www.dropbox.com","dl.dropboxusercontent.com"):e}},{key:"render",value:function(){var e=this.props,t=e.url,n=e.playing,r=e.loop,i=e.controls,a=e.muted,u=e.config,c=e.width,s=e.height,f=this.shouldUseAudio(this.props)?"audio":"video",p={width:"auto"===c?c:"100%",height:"auto"===s?s:"100%"};return o.a.createElement(f,l({ref:this.ref,src:this.getSource(t),style:p,preload:"auto",autoPlay:n||void 0,controls:i,muted:a,loop:r},u.attributes),t instanceof Array&&t.map(this.renderSourceElement),u.tracks.map(this.renderTrack))}}])&&s(t.prototype,n),r&&s(t,r),y}(r.Component);b(g,"displayName","FilePlayer"),b(g,"canPlay",a.m.file)},function(e,t,n){"use strict";n.r(t),n.d(t,"default",(function(){return m}));var r=n(0),o=n.n(r);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function u(e){for(var t=1;t `${key}=${object[key]}`)\n .join('&')\n}\n\nfunction getGlobal (key) {\n if (window[key]) {\n return window[key]\n }\n if (window.exports && window.exports[key]) {\n return window.exports[key]\n }\n if (window.module && window.module.exports && window.module.exports[key]) {\n return window.module.exports[key]\n }\n return null\n}\n\n// Util function to load an external SDK\n// or return the SDK if it is already loaded\nconst requests = {}\nexport function getSDK (url, sdkGlobal, sdkReady = null, isLoaded = () => true, fetchScript = loadScript) {\n const existingGlobal = getGlobal(sdkGlobal)\n if (existingGlobal && isLoaded(existingGlobal)) {\n return Promise.resolve(existingGlobal)\n }\n return new Promise((resolve, reject) => {\n // If we are already loading the SDK, add the resolve and reject\n // functions to the existing array of requests\n if (requests[url]) {\n requests[url].push({ resolve, reject })\n return\n }\n requests[url] = [{ resolve, reject }]\n const onLoaded = sdk => {\n // When loaded, resolve all pending request promises\n requests[url].forEach(request => request.resolve(sdk))\n }\n if (sdkReady) {\n const previousOnReady = window[sdkReady]\n window[sdkReady] = function () {\n if (previousOnReady) previousOnReady()\n onLoaded(getGlobal(sdkGlobal))\n }\n }\n fetchScript(url, err => {\n if (err) {\n // Loading the SDK failed – reject all requests and\n // reset the array of requests for this SDK\n requests[url].forEach(request => request.reject(err))\n requests[url] = null\n } else if (!sdkReady) {\n onLoaded(getGlobal(sdkGlobal))\n }\n })\n })\n}\n\nexport function getConfig (props, defaultProps) {\n return merge(defaultProps.config, props.config)\n}\n\nexport function omit (object, ...arrays) {\n const omitKeys = [].concat(...arrays)\n const output = {}\n const keys = Object.keys(object)\n for (const key of keys) {\n if (omitKeys.indexOf(key) === -1) {\n output[key] = object[key]\n }\n }\n return output\n}\n\nexport function callPlayer (method, ...args) {\n // Util method for calling a method on this.player\n // but guard against errors and console.warn instead\n if (!this.player || !this.player[method]) {\n let message = `ReactPlayer: ${this.constructor.displayName} player could not call %c${method}%c – `\n if (!this.player) {\n message += 'The player was not available'\n } else if (!this.player[method]) {\n message += 'The method was not available'\n }\n console.warn(message, 'font-weight: bold', '')\n return null\n }\n return this.player[method](...args)\n}\n\nexport function isMediaStream (url) {\n return (\n typeof window !== 'undefined' &&\n typeof window.MediaStream !== 'undefined' &&\n url instanceof window.MediaStream\n )\n}\n\nexport function supportsWebKitPresentationMode (video = document.createElement('video')) {\n // Check if Safari supports PiP, and is not on mobile (other than iPad)\n // iPhone safari appears to \"support\" PiP through the check, however PiP does not function\n const notMobile = /iPhone|iPod/.test(navigator.userAgent) === false\n return video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === 'function' && notMobile\n}\n","import { isMediaStream } from './utils'\n\nexport const MATCH_URL_YOUTUBE = /(?:youtu\\.be\\/|youtube(?:-nocookie)?\\.com\\/(?:embed\\/|v\\/|watch\\?v=|watch\\?.+&v=))((\\w|-){11})|youtube\\.com\\/playlist\\?list=|youtube\\.com\\/user\\//\nexport const MATCH_URL_SOUNDCLOUD = /(?:soundcloud\\.com|snd\\.sc)\\/[^.]+$/\nexport const MATCH_URL_VIMEO = /vimeo\\.com\\/.+/\nexport const MATCH_URL_FACEBOOK = /^https?:\\/\\/(www\\.)?facebook\\.com.*\\/(video(s)?|watch|story)(\\.php?|\\/).+$/\nexport const MATCH_URL_STREAMABLE = /streamable\\.com\\/([a-z0-9]+)$/\nexport const MATCH_URL_WISTIA = /(?:wistia\\.com|wi\\.st)\\/(?:medias|embed)\\/(.*)$/\nexport const MATCH_URL_TWITCH_VIDEO = /(?:www\\.|go\\.)?twitch\\.tv\\/videos\\/(\\d+)($|\\?)/\nexport const MATCH_URL_TWITCH_CHANNEL = /(?:www\\.|go\\.)?twitch\\.tv\\/([a-zA-Z0-9_]+)($|\\?)/\nexport const MATCH_URL_DAILYMOTION = /^(?:(?:https?):)?(?:\\/\\/)?(?:www\\.)?(?:(?:dailymotion\\.com(?:\\/embed)?\\/video)|dai\\.ly)\\/([a-zA-Z0-9]+)(?:_[\\w_-]+)?$/\nexport const MATCH_URL_MIXCLOUD = /mixcloud\\.com\\/([^/]+\\/[^/]+)/\nexport const MATCH_URL_VIDYARD = /vidyard.com\\/(?:watch\\/)?([a-zA-Z0-9-]+)/\nexport const AUDIO_EXTENSIONS = /\\.(m4a|mp4a|mpga|mp2|mp2a|mp3|m2a|m3a|wav|weba|aac|oga|spx)($|\\?)/i\nexport const VIDEO_EXTENSIONS = /\\.(mp4|og[gv]|webm|mov|m4v)($|\\?)/i\nexport const HLS_EXTENSIONS = /\\.(m3u8)($|\\?)/i\nexport const DASH_EXTENSIONS = /\\.(mpd)($|\\?)/i\nexport const FLV_EXTENSIONS = /\\.(flv)($|\\?)/i\n\nconst canPlayFile = url => {\n if (url instanceof Array) {\n for (const item of url) {\n if (typeof item === 'string' && canPlayFile(item)) {\n return true\n }\n if (canPlayFile(item.src)) {\n return true\n }\n }\n return false\n }\n if (isMediaStream(url)) {\n return true\n }\n return (\n AUDIO_EXTENSIONS.test(url) ||\n VIDEO_EXTENSIONS.test(url) ||\n HLS_EXTENSIONS.test(url) ||\n DASH_EXTENSIONS.test(url) ||\n FLV_EXTENSIONS.test(url)\n )\n}\n\nexport const canPlay = {\n youtube: url => {\n if (url instanceof Array) {\n return url.every(item => MATCH_URL_YOUTUBE.test(item))\n }\n return MATCH_URL_YOUTUBE.test(url)\n },\n soundcloud: url => MATCH_URL_SOUNDCLOUD.test(url) && !AUDIO_EXTENSIONS.test(url),\n vimeo: url => MATCH_URL_VIMEO.test(url) && !VIDEO_EXTENSIONS.test(url) && !HLS_EXTENSIONS.test(url),\n facebook: url => MATCH_URL_FACEBOOK.test(url),\n streamable: url => MATCH_URL_STREAMABLE.test(url),\n wistia: url => MATCH_URL_WISTIA.test(url),\n twitch: url => MATCH_URL_TWITCH_VIDEO.test(url) || MATCH_URL_TWITCH_CHANNEL.test(url),\n dailymotion: url => MATCH_URL_DAILYMOTION.test(url),\n mixcloud: url => MATCH_URL_MIXCLOUD.test(url),\n vidyard: url => MATCH_URL_VIDYARD.test(url),\n file: canPlayFile\n}\n","/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nif (process.env.NODE_ENV !== 'production') {\n var ReactIs = require('react-is');\n\n // By explicitly using `prop-types` you are opting into new development behavior.\n // http://fb.me/prop-types-in-prod\n var throwOnDirectAccess = true;\n module.exports = require('./factoryWithTypeCheckers')(ReactIs.isElement, throwOnDirectAccess);\n} else {\n // By explicitly using `prop-types` you are opting into new production behavior.\n // http://fb.me/prop-types-in-prod\n module.exports = require('./factoryWithThrowingShims')();\n}\n","/* global Map:readonly, Set:readonly, ArrayBuffer:readonly */\n\nvar hasElementType = typeof Element !== 'undefined';\nvar hasMap = typeof Map === 'function';\nvar hasSet = typeof Set === 'function';\nvar hasArrayBuffer = typeof ArrayBuffer === 'function' && !!ArrayBuffer.isView;\n\n// Note: We **don't** need `envHasBigInt64Array` in fde es6/index.js\n\nfunction equal(a, b) {\n // START: fast-deep-equal es6/index.js 3.1.1\n if (a === b) return true;\n\n if (a && b && typeof a == 'object' && typeof b == 'object') {\n if (a.constructor !== b.constructor) return false;\n\n var length, i, keys;\n if (Array.isArray(a)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0;)\n if (!equal(a[i], b[i])) return false;\n return true;\n }\n\n // START: Modifications:\n // 1. Extra `has &&` helpers in initial condition allow es6 code\n // to co-exist with es5.\n // 2. Replace `for of` with es5 compliant iteration using `for`.\n // Basically, take:\n //\n // ```js\n // for (i of a.entries())\n // if (!b.has(i[0])) return false;\n // ```\n //\n // ... and convert to:\n //\n // ```js\n // it = a.entries();\n // while (!(i = it.next()).done)\n // if (!b.has(i.value[0])) return false;\n // ```\n //\n // **Note**: `i` access switches to `i.value`.\n var it;\n if (hasMap && (a instanceof Map) && (b instanceof Map)) {\n if (a.size !== b.size) return false;\n it = a.entries();\n while (!(i = it.next()).done)\n if (!b.has(i.value[0])) return false;\n it = a.entries();\n while (!(i = it.next()).done)\n if (!equal(i.value[1], b.get(i.value[0]))) return false;\n return true;\n }\n\n if (hasSet && (a instanceof Set) && (b instanceof Set)) {\n if (a.size !== b.size) return false;\n it = a.entries();\n while (!(i = it.next()).done)\n if (!b.has(i.value[0])) return false;\n return true;\n }\n // END: Modifications\n\n if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0;)\n if (a[i] !== b[i]) return false;\n return true;\n }\n\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\n\n keys = Object.keys(a);\n length = keys.length;\n if (length !== Object.keys(b).length) return false;\n\n for (i = length; i-- !== 0;)\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n // END: fast-deep-equal\n\n // START: react-fast-compare\n // custom handling for DOM elements\n if (hasElementType && a instanceof Element) return false;\n\n // custom handling for React/Preact\n for (i = length; i-- !== 0;) {\n if ((keys[i] === '_owner' || keys[i] === '__v' || keys[i] === '__o') && a.$$typeof) {\n // React-specific: avoid traversing React elements' _owner\n // Preact-specific: avoid traversing Preact elements' __v and __o\n // __v = $_original / $_vnode\n // __o = $_owner\n // These properties contain circular references and are not needed when\n // comparing the actual elements (and not their owners)\n // .$$typeof and ._store on just reasonable markers of elements\n\n continue;\n }\n\n // all other properties should be traversed as usual\n if (!equal(a[keys[i]], b[keys[i]])) return false;\n }\n // END: react-fast-compare\n\n // START: fast-deep-equal\n return true;\n }\n\n return a !== a && b !== b;\n}\n// end fast-deep-equal\n\nmodule.exports = function isEqual(a, b) {\n try {\n return equal(a, b);\n } catch (error) {\n if (((error.message || '').match(/stack|recursion/i))) {\n // warn on circular references, don't crash\n // browsers give this different errors name and messages:\n // chrome/safari: \"RangeError\", \"Maximum call stack size exceeded\"\n // firefox: \"InternalError\", too much recursion\"\n // edge: \"Error\", \"Out of stack space\"\n console.warn('react-fast-compare cannot handle circular refs');\n return false;\n }\n // some other error. we should definitely know about these\n throw error;\n }\n};\n","'use strict';\n\nvar isMergeableObject = function isMergeableObject(value) {\n\treturn isNonNullObject(value)\n\t\t&& !isSpecial(value)\n};\n\nfunction isNonNullObject(value) {\n\treturn !!value && typeof value === 'object'\n}\n\nfunction isSpecial(value) {\n\tvar stringValue = Object.prototype.toString.call(value);\n\n\treturn stringValue === '[object RegExp]'\n\t\t|| stringValue === '[object Date]'\n\t\t|| isReactElement(value)\n}\n\n// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25\nvar canUseSymbol = typeof Symbol === 'function' && Symbol.for;\nvar REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;\n\nfunction isReactElement(value) {\n\treturn value.$$typeof === REACT_ELEMENT_TYPE\n}\n\nfunction emptyTarget(val) {\n\treturn Array.isArray(val) ? [] : {}\n}\n\nfunction cloneUnlessOtherwiseSpecified(value, options) {\n\treturn (options.clone !== false && options.isMergeableObject(value))\n\t\t? deepmerge(emptyTarget(value), value, options)\n\t\t: value\n}\n\nfunction defaultArrayMerge(target, source, options) {\n\treturn target.concat(source).map(function(element) {\n\t\treturn cloneUnlessOtherwiseSpecified(element, options)\n\t})\n}\n\nfunction getMergeFunction(key, options) {\n\tif (!options.customMerge) {\n\t\treturn deepmerge\n\t}\n\tvar customMerge = options.customMerge(key);\n\treturn typeof customMerge === 'function' ? customMerge : deepmerge\n}\n\nfunction getEnumerableOwnPropertySymbols(target) {\n\treturn Object.getOwnPropertySymbols\n\t\t? Object.getOwnPropertySymbols(target).filter(function(symbol) {\n\t\t\treturn target.propertyIsEnumerable(symbol)\n\t\t})\n\t\t: []\n}\n\nfunction getKeys(target) {\n\treturn Object.keys(target).concat(getEnumerableOwnPropertySymbols(target))\n}\n\nfunction propertyIsOnObject(object, property) {\n\ttry {\n\t\treturn property in object\n\t} catch(_) {\n\t\treturn false\n\t}\n}\n\n// Protects from prototype poisoning and unexpected merging up the prototype chain.\nfunction propertyIsUnsafe(target, key) {\n\treturn propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet,\n\t\t&& !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain,\n\t\t\t&& Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.\n}\n\nfunction mergeObject(target, source, options) {\n\tvar destination = {};\n\tif (options.isMergeableObject(target)) {\n\t\tgetKeys(target).forEach(function(key) {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(target[key], options);\n\t\t});\n\t}\n\tgetKeys(source).forEach(function(key) {\n\t\tif (propertyIsUnsafe(target, key)) {\n\t\t\treturn\n\t\t}\n\n\t\tif (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {\n\t\t\tdestination[key] = getMergeFunction(key, options)(target[key], source[key], options);\n\t\t} else {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(source[key], options);\n\t\t}\n\t});\n\treturn destination\n}\n\nfunction deepmerge(target, source, options) {\n\toptions = options || {};\n\toptions.arrayMerge = options.arrayMerge || defaultArrayMerge;\n\toptions.isMergeableObject = options.isMergeableObject || isMergeableObject;\n\t// cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge()\n\t// implementations can use it. The caller may not replace it.\n\toptions.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;\n\n\tvar sourceIsArray = Array.isArray(source);\n\tvar targetIsArray = Array.isArray(target);\n\tvar sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;\n\n\tif (!sourceAndTargetTypesMatch) {\n\t\treturn cloneUnlessOtherwiseSpecified(source, options)\n\t} else if (sourceIsArray) {\n\t\treturn options.arrayMerge(target, source, options)\n\t} else {\n\t\treturn mergeObject(target, source, options)\n\t}\n}\n\ndeepmerge.all = function deepmergeAll(array, options) {\n\tif (!Array.isArray(array)) {\n\t\tthrow new Error('first argument should be an array')\n\t}\n\n\treturn array.reduce(function(prev, next) {\n\t\treturn deepmerge(prev, next, options)\n\t}, {})\n};\n\nvar deepmerge_1 = deepmerge;\n\nmodule.exports = deepmerge_1;\n","\nmodule.exports = function load (src, opts, cb) {\n var head = document.head || document.getElementsByTagName('head')[0]\n var script = document.createElement('script')\n\n if (typeof opts === 'function') {\n cb = opts\n opts = {}\n }\n\n opts = opts || {}\n cb = cb || function() {}\n\n script.type = opts.type || 'text/javascript'\n script.charset = opts.charset || 'utf8';\n script.async = 'async' in opts ? !!opts.async : true\n script.src = src\n\n if (opts.attrs) {\n setAttributes(script, opts.attrs)\n }\n\n if (opts.text) {\n script.text = '' + opts.text\n }\n\n var onend = 'onload' in script ? stdOnEnd : ieOnEnd\n onend(script, cb)\n\n // some good legacy browsers (firefox) fail the 'in' detection above\n // so as a fallback we always set onload\n // old IE will ignore this and new IE will set onload\n if (!script.onload) {\n stdOnEnd(script, cb);\n }\n\n head.appendChild(script)\n}\n\nfunction setAttributes(script, attrs) {\n for (var attr in attrs) {\n script.setAttribute(attr, attrs[attr]);\n }\n}\n\nfunction stdOnEnd (script, cb) {\n script.onload = function () {\n this.onerror = this.onload = null\n cb(null, script)\n }\n script.onerror = function () {\n // this.onload = null here is necessary\n // because even IE9 works not like others\n this.onerror = this.onload = null\n cb(new Error('Failed to load ' + this.src), script)\n }\n}\n\nfunction ieOnEnd (script, cb) {\n script.onreadystatechange = function () {\n if (this.readyState != 'complete' && this.readyState != 'loaded') return\n this.onreadystatechange = null\n cb(null, script) // there is no way to catch loading errors in IE8\n }\n}\n","/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nvar ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');\n\nfunction emptyFunction() {}\nfunction emptyFunctionWithReset() {}\nemptyFunctionWithReset.resetWarningCache = emptyFunction;\n\nmodule.exports = function() {\n function shim(props, propName, componentName, location, propFullName, secret) {\n if (secret === ReactPropTypesSecret) {\n // It is still safe when called from React.\n return;\n }\n var err = new Error(\n 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +\n 'Use PropTypes.checkPropTypes() to call them. ' +\n 'Read more at http://fb.me/use-check-prop-types'\n );\n err.name = 'Invariant Violation';\n throw err;\n };\n shim.isRequired = shim;\n function getShim() {\n return shim;\n };\n // Important!\n // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.\n var ReactPropTypes = {\n array: shim,\n bool: shim,\n func: shim,\n number: shim,\n object: shim,\n string: shim,\n symbol: shim,\n\n any: shim,\n arrayOf: getShim,\n element: shim,\n elementType: shim,\n instanceOf: getShim,\n node: shim,\n objectOf: getShim,\n oneOf: getShim,\n oneOfType: getShim,\n shape: getShim,\n exact: getShim,\n\n checkPropTypes: emptyFunctionWithReset,\n resetWarningCache: emptyFunction\n };\n\n ReactPropTypes.PropTypes = ReactPropTypes;\n\n return ReactPropTypes;\n};\n","/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nvar ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';\n\nmodule.exports = ReactPropTypesSecret;\n","import { lazy } from 'react'\nimport { supportsWebKitPresentationMode } from '../utils'\nimport { canPlay, AUDIO_EXTENSIONS } from '../patterns'\n\nexport default [\n {\n key: 'youtube',\n name: 'YouTube',\n canPlay: canPlay.youtube,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerYouTube' */'./YouTube'))\n },\n {\n key: 'soundcloud',\n name: 'SoundCloud',\n canPlay: canPlay.soundcloud,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerSoundCloud' */'./SoundCloud'))\n },\n {\n key: 'vimeo',\n name: 'Vimeo',\n canPlay: canPlay.vimeo,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerVimeo' */'./Vimeo'))\n },\n {\n key: 'facebook',\n name: 'Facebook',\n canPlay: canPlay.facebook,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerFacebook' */'./Facebook'))\n },\n {\n key: 'streamable',\n name: 'Streamable',\n canPlay: canPlay.streamable,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerStreamable' */'./Streamable'))\n },\n {\n key: 'wistia',\n name: 'Wistia',\n canPlay: canPlay.wistia,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerWistia' */'./Wistia'))\n },\n {\n key: 'twitch',\n name: 'Twitch',\n canPlay: canPlay.twitch,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerTwitch' */'./Twitch'))\n },\n {\n key: 'dailymotion',\n name: 'DailyMotion',\n canPlay: canPlay.dailymotion,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerDailyMotion' */'./DailyMotion'))\n },\n {\n key: 'mixcloud',\n name: 'Mixcloud',\n canPlay: canPlay.mixcloud,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerMixcloud' */'./Mixcloud'))\n },\n {\n key: 'vidyard',\n name: 'Vidyard',\n canPlay: canPlay.vidyard,\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerVidyard' */'./Vidyard'))\n },\n {\n key: 'file',\n name: 'FilePlayer',\n canPlay: canPlay.file,\n canEnablePIP: url => {\n return canPlay.file(url) && (document.pictureInPictureEnabled || supportsWebKitPresentationMode()) && !AUDIO_EXTENSIONS.test(url)\n },\n lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerFilePlayer' */'./FilePlayer'))\n }\n]\n","function areInputsEqual(newInputs, lastInputs) {\n if (newInputs.length !== lastInputs.length) {\n return false;\n }\n for (var i = 0; i < newInputs.length; i++) {\n if (newInputs[i] !== lastInputs[i]) {\n return false;\n }\n }\n return true;\n}\n\nfunction memoizeOne(resultFn, isEqual) {\n if (isEqual === void 0) { isEqual = areInputsEqual; }\n var lastThis;\n var lastArgs = [];\n var lastResult;\n var calledOnce = false;\n function memoized() {\n var newArgs = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n newArgs[_i] = arguments[_i];\n }\n if (calledOnce && lastThis === this && isEqual(newArgs, lastArgs)) {\n return lastResult;\n }\n lastResult = resultFn.apply(this, newArgs);\n calledOnce = true;\n lastThis = this;\n lastArgs = newArgs;\n return lastResult;\n }\n return memoized;\n}\n\nexport default memoizeOne;\n","import PropTypes from 'prop-types'\n\nconst { string, bool, number, array, oneOfType, shape, object, func, node } = PropTypes\n\nexport const propTypes = {\n url: oneOfType([string, array, object]),\n playing: bool,\n loop: bool,\n controls: bool,\n volume: number,\n muted: bool,\n playbackRate: number,\n width: oneOfType([string, number]),\n height: oneOfType([string, number]),\n style: object,\n progressInterval: number,\n playsinline: bool,\n pip: bool,\n light: oneOfType([bool, string]),\n playIcon: node,\n wrapper: oneOfType([\n string,\n func,\n shape({ render: func.isRequired })\n ]),\n config: shape({\n soundcloud: shape({\n options: object\n }),\n youtube: shape({\n playerVars: object,\n embedOptions: object,\n onUnstarted: func\n }),\n facebook: shape({\n appId: string,\n version: string,\n playerId: string\n }),\n dailymotion: shape({\n params: object\n }),\n vimeo: shape({\n playerOptions: object\n }),\n file: shape({\n attributes: object,\n tracks: array,\n forceVideo: bool,\n forceAudio: bool,\n forceHLS: bool,\n forceDASH: bool,\n forceFLV: bool,\n hlsOptions: object,\n hlsVersion: string,\n dashVersion: string,\n flvVersion: string\n }),\n wistia: shape({\n options: object,\n playerId: string\n }),\n mixcloud: shape({\n options: object\n }),\n twitch: shape({\n options: object,\n playerId: string\n }),\n vidyard: shape({\n options: object\n })\n }),\n onReady: func,\n onStart: func,\n onPlay: func,\n onPause: func,\n onBuffer: func,\n onBufferEnd: func,\n onEnded: func,\n onError: func,\n onDuration: func,\n onSeek: func,\n onProgress: func,\n onEnablePIP: func,\n onDisablePIP: func\n}\n\nconst noop = () => {}\n\nexport const defaultProps = {\n playing: false,\n loop: false,\n controls: false,\n volume: null,\n muted: false,\n playbackRate: 1,\n width: '640px',\n height: '360px',\n style: {},\n progressInterval: 1000,\n playsinline: false,\n pip: false,\n light: false,\n wrapper: 'div',\n config: {\n soundcloud: {\n options: {\n visual: true, // Undocumented, but makes player fill container and look better\n buying: false,\n liking: false,\n download: false,\n sharing: false,\n show_comments: false,\n show_playcount: false\n }\n },\n youtube: {\n playerVars: {\n playsinline: 1,\n showinfo: 0,\n rel: 0,\n iv_load_policy: 3,\n modestbranding: 1\n },\n embedOptions: {},\n onUnstarted: noop\n },\n facebook: {\n appId: '1309697205772819',\n version: 'v3.3',\n playerId: null\n },\n dailymotion: {\n params: {\n api: 1,\n 'endscreen-enable': false\n }\n },\n vimeo: {\n playerOptions: {\n autopause: false,\n byline: false,\n portrait: false,\n title: false\n }\n },\n file: {\n attributes: {},\n tracks: [],\n forceVideo: false,\n forceAudio: false,\n forceHLS: false,\n forceDASH: false,\n forceFLV: false,\n hlsOptions: {},\n hlsVersion: '0.13.1',\n dashVersion: '2.9.2',\n flvVersion: '1.5.0'\n },\n wistia: {\n options: {},\n playerId: null\n },\n mixcloud: {\n options: {\n hide_cover: 1\n }\n },\n twitch: {\n options: {},\n playerId: null\n },\n vidyard: {\n options: {}\n }\n },\n onReady: noop,\n onStart: noop,\n onPlay: noop,\n onPause: noop,\n onBuffer: noop,\n onBufferEnd: noop,\n onEnded: noop,\n onError: noop,\n onDuration: noop,\n onSeek: noop,\n onProgress: noop,\n onEnablePIP: noop,\n onDisablePIP: noop\n}\n","import React, { Component } from 'react'\nimport isEqual from 'react-fast-compare'\n\nimport { propTypes, defaultProps } from './props'\n\nconst SEEK_ON_PLAY_EXPIRY = 5000\n\nexport default class Player extends Component {\n static displayName = 'Player'\n static propTypes = propTypes\n static defaultProps = defaultProps\n\n mounted = false\n isReady = false\n isPlaying = false // Track playing state internally to prevent bugs\n isLoading = true // Use isLoading to prevent onPause when switching URL\n loadOnReady = null\n startOnPlay = true\n seekOnPlay = null\n onDurationCalled = false\n\n componentDidMount () {\n this.mounted = true\n }\n\n componentWillUnmount () {\n clearTimeout(this.progressTimeout)\n clearTimeout(this.durationCheckTimeout)\n if (this.isReady) {\n this.player.stop()\n\n if (this.player.disablePIP) {\n this.player.disablePIP()\n }\n }\n this.mounted = false\n }\n\n componentDidUpdate (prevProps) {\n // Invoke player methods based on changed props\n const { url, playing, volume, muted, playbackRate, pip, loop, activePlayer } = this.props\n if (!isEqual(prevProps.url, url)) {\n if (this.isLoading && !activePlayer.forceLoad) {\n console.warn(`ReactPlayer: the attempt to load ${url} is being deferred until the player has loaded`)\n this.loadOnReady = url\n return\n }\n this.isLoading = true\n this.startOnPlay = true\n this.onDurationCalled = false\n this.player.load(url, this.isReady)\n }\n if (!prevProps.playing && playing && !this.isPlaying) {\n this.player.play()\n }\n if (prevProps.playing && !playing && this.isPlaying) {\n this.player.pause()\n }\n if (!prevProps.pip && pip && this.player.enablePIP) {\n this.player.enablePIP()\n }\n if (prevProps.pip && !pip && this.player.disablePIP) {\n this.player.disablePIP()\n }\n if (prevProps.volume !== volume && volume !== null) {\n this.player.setVolume(volume)\n }\n if (prevProps.muted !== muted) {\n if (muted) {\n this.player.mute()\n } else {\n this.player.unmute()\n if (volume !== null) {\n // Set volume next tick to fix a bug with DailyMotion\n setTimeout(() => this.player.setVolume(volume))\n }\n }\n }\n if (prevProps.playbackRate !== playbackRate && this.player.setPlaybackRate) {\n this.player.setPlaybackRate(playbackRate)\n }\n if (prevProps.loop !== loop && this.player.setLoop) {\n this.player.setLoop(loop)\n }\n }\n\n handlePlayerMount = player => {\n this.player = player\n this.player.load(this.props.url)\n this.progress()\n }\n\n getDuration () {\n if (!this.isReady) return null\n return this.player.getDuration()\n }\n\n getCurrentTime () {\n if (!this.isReady) return null\n return this.player.getCurrentTime()\n }\n\n getSecondsLoaded () {\n if (!this.isReady) return null\n return this.player.getSecondsLoaded()\n }\n\n getInternalPlayer = (key) => {\n if (!this.player) return null\n return this.player[key]\n }\n\n progress = () => {\n if (this.props.url && this.player && this.isReady) {\n const playedSeconds = this.getCurrentTime() || 0\n const loadedSeconds = this.getSecondsLoaded()\n const duration = this.getDuration()\n if (duration) {\n const progress = {\n playedSeconds,\n played: playedSeconds / duration\n }\n if (loadedSeconds !== null) {\n progress.loadedSeconds = loadedSeconds\n progress.loaded = loadedSeconds / duration\n }\n // Only call onProgress if values have changed\n if (progress.playedSeconds !== this.prevPlayed || progress.loadedSeconds !== this.prevLoaded) {\n this.props.onProgress(progress)\n }\n this.prevPlayed = progress.playedSeconds\n this.prevLoaded = progress.loadedSeconds\n }\n }\n this.progressTimeout = setTimeout(this.progress, this.props.progressFrequency || this.props.progressInterval)\n }\n\n seekTo (amount, type) {\n // When seeking before player is ready, store value and seek later\n if (!this.isReady && amount !== 0) {\n this.seekOnPlay = amount\n setTimeout(() => { this.seekOnPlay = null }, SEEK_ON_PLAY_EXPIRY)\n return\n }\n const isFraction = !type ? (amount > 0 && amount < 1) : type === 'fraction'\n if (isFraction) {\n // Convert fraction to seconds based on duration\n const duration = this.player.getDuration()\n if (!duration) {\n console.warn('ReactPlayer: could not seek using fraction – duration not yet available')\n return\n }\n this.player.seekTo(duration * amount)\n return\n }\n this.player.seekTo(amount)\n }\n\n handleReady = () => {\n if (!this.mounted) return\n this.isReady = true\n this.isLoading = false\n const { onReady, playing, volume, muted } = this.props\n onReady()\n if (!muted && volume !== null) {\n this.player.setVolume(volume)\n }\n if (this.loadOnReady) {\n this.player.load(this.loadOnReady, true)\n this.loadOnReady = null\n } else if (playing) {\n this.player.play()\n }\n this.handleDurationCheck()\n }\n\n handlePlay = () => {\n this.isPlaying = true\n this.isLoading = false\n const { onStart, onPlay, playbackRate } = this.props\n if (this.startOnPlay) {\n if (this.player.setPlaybackRate && playbackRate !== 1) {\n this.player.setPlaybackRate(playbackRate)\n }\n onStart()\n this.startOnPlay = false\n }\n onPlay()\n if (this.seekOnPlay) {\n this.seekTo(this.seekOnPlay)\n this.seekOnPlay = null\n }\n this.handleDurationCheck()\n }\n\n handlePause = (e) => {\n this.isPlaying = false\n if (!this.isLoading) {\n this.props.onPause(e)\n }\n }\n\n handleEnded = () => {\n const { activePlayer, loop, onEnded } = this.props\n if (activePlayer.loopOnEnded && loop) {\n this.seekTo(0)\n }\n if (!loop) {\n this.isPlaying = false\n onEnded()\n }\n }\n\n handleError = (...args) => {\n this.isLoading = false\n this.props.onError(...args)\n }\n\n handleDurationCheck = () => {\n clearTimeout(this.durationCheckTimeout)\n const duration = this.getDuration()\n if (duration) {\n if (!this.onDurationCalled) {\n this.props.onDuration(duration)\n this.onDurationCalled = true\n }\n } else {\n this.durationCheckTimeout = setTimeout(this.handleDurationCheck, 100)\n }\n }\n\n handleLoaded = () => {\n // Sometimes we know loading has stopped but onReady/onPlay are never called\n // so this provides a way for players to avoid getting stuck\n this.isLoading = false\n }\n\n render () {\n const Player = this.props.activePlayer\n if (!Player) {\n return null\n }\n return (\n \n )\n }\n}\n","import React, { Component, Suspense, lazy } from 'react'\nimport merge from 'deepmerge'\nimport memoize from 'memoize-one'\nimport isEqual from 'react-fast-compare'\n\nimport { propTypes, defaultProps } from './props'\nimport { omit } from './utils'\nimport Player from './Player'\n\nconst Preview = lazy(() => import(/* webpackChunkName: 'reactPlayerPreview' */'./Preview'))\n\nconst IS_BROWSER = typeof window !== 'undefined' && window.document\nconst SUPPORTED_PROPS = Object.keys(propTypes)\n\n// Return null when rendering on the server\n// as Suspense is not supported yet\nconst UniversalSuspense = IS_BROWSER ? Suspense : () => null\n\nconst customPlayers = []\n\nexport const createReactPlayer = (players, fallback) => {\n return class ReactPlayer extends Component {\n static displayName = 'ReactPlayer'\n static propTypes = propTypes\n static defaultProps = defaultProps\n static addCustomPlayer = player => { customPlayers.push(player) }\n static removeCustomPlayers = () => { customPlayers.length = 0 }\n\n static canPlay = url => {\n for (const Player of [...customPlayers, ...players]) {\n if (Player.canPlay(url)) {\n return true\n }\n }\n return false\n }\n\n static canEnablePIP = url => {\n for (const Player of [...customPlayers, ...players]) {\n if (Player.canEnablePIP && Player.canEnablePIP(url)) {\n return true\n }\n }\n return false\n }\n\n state = {\n showPreview: !!this.props.light\n }\n\n // Use references, as refs is used by React\n references = {\n wrapper: wrapper => { this.wrapper = wrapper },\n player: player => { this.player = player }\n }\n\n shouldComponentUpdate (nextProps, nextState) {\n return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState)\n }\n\n componentDidUpdate (prevProps) {\n const { light } = this.props\n if (!prevProps.light && light) {\n this.setState({ showPreview: true })\n }\n if (prevProps.light && !light) {\n this.setState({ showPreview: false })\n }\n }\n\n handleClickPreview = () => {\n this.setState({ showPreview: false })\n }\n\n showPreview = () => {\n this.setState({ showPreview: true })\n }\n\n getDuration = () => {\n if (!this.player) return null\n return this.player.getDuration()\n }\n\n getCurrentTime = () => {\n if (!this.player) return null\n return this.player.getCurrentTime()\n }\n\n getSecondsLoaded = () => {\n if (!this.player) return null\n return this.player.getSecondsLoaded()\n }\n\n getInternalPlayer = (key = 'player') => {\n if (!this.player) return null\n return this.player.getInternalPlayer(key)\n }\n\n seekTo = (fraction, type) => {\n if (!this.player) return null\n this.player.seekTo(fraction, type)\n }\n\n handleReady = () => {\n this.props.onReady(this)\n }\n\n getActivePlayer = memoize(url => {\n for (const player of [...customPlayers, ...players]) {\n if (player.canPlay(url)) {\n return player\n }\n }\n if (fallback) {\n return fallback\n }\n return null\n })\n\n getConfig = memoize((url, key) => {\n const { config } = this.props\n return merge.all([\n defaultProps.config,\n defaultProps.config[key] || {},\n config,\n config[key] || {}\n ])\n })\n\n getAttributes = memoize(url => {\n return omit(this.props, SUPPORTED_PROPS)\n })\n\n renderPreview (url) {\n if (!url) return null\n const { light, playIcon } = this.props\n return (\n \n )\n }\n\n renderActivePlayer = url => {\n if (!url) return null\n const player = this.getActivePlayer(url)\n if (!player) return null\n const config = this.getConfig(url, player.key)\n return (\n \n )\n }\n\n render () {\n const { url, style, width, height, wrapper: Wrapper } = this.props\n const { showPreview } = this.state\n const attributes = this.getAttributes(url)\n return (\n \n \n {showPreview\n ? this.renderPreview(url)\n : this.renderActivePlayer(url)}\n \n \n )\n }\n }\n}\n","import players from './players'\nimport { createReactPlayer } from './ReactPlayer'\n\n// Fall back to FilePlayer if nothing else can play the URL\nconst fallback = players[players.length - 1]\n\nexport default createReactPlayer(players, fallback)\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK, parseStartTime, parseEndTime } from '../utils'\nimport { canPlay, MATCH_URL_YOUTUBE } from '../patterns'\n\nconst SDK_URL = 'https://www.youtube.com/iframe_api'\nconst SDK_GLOBAL = 'YT'\nconst SDK_GLOBAL_READY = 'onYouTubeIframeAPIReady'\nconst MATCH_PLAYLIST = /list=([a-zA-Z0-9_-]+)/\nconst MATCH_USER_UPLOADS = /user\\/([a-zA-Z0-9_-]+)\\/?/\nconst MATCH_NOCOOKIE = /youtube-nocookie\\.com/\nconst NOCOOKIE_HOST = 'https://www.youtube-nocookie.com'\n\nexport default class YouTube extends Component {\n static displayName = 'YouTube'\n static canPlay = canPlay.youtube\n callPlayer = callPlayer\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n getID (url) {\n if (!url || url instanceof Array) {\n return null\n }\n return url.match(MATCH_URL_YOUTUBE)[1]\n }\n\n load (url, isReady) {\n const { playing, muted, playsinline, controls, loop, config, onError } = this.props\n const { playerVars, embedOptions } = config\n const id = this.getID(url)\n if (isReady) {\n if (MATCH_PLAYLIST.test(url) || MATCH_USER_UPLOADS.test(url) || url instanceof Array) {\n this.player.loadPlaylist(this.parsePlaylist(url))\n return\n }\n this.player.cueVideoById({\n videoId: id,\n startSeconds: parseStartTime(url) || playerVars.start,\n endSeconds: parseEndTime(url) || playerVars.end\n })\n return\n }\n getSDK(SDK_URL, SDK_GLOBAL, SDK_GLOBAL_READY, YT => YT.loaded).then(YT => {\n if (!this.container) return\n this.player = new YT.Player(this.container, {\n width: '100%',\n height: '100%',\n videoId: id,\n playerVars: {\n autoplay: playing ? 1 : 0,\n mute: muted ? 1 : 0,\n controls: controls ? 1 : 0,\n start: parseStartTime(url),\n end: parseEndTime(url),\n origin: window.location.origin,\n playsinline: playsinline,\n ...this.parsePlaylist(url),\n ...playerVars\n },\n events: {\n onReady: () => {\n if (loop) {\n this.player.setLoop(true) // Enable playlist looping\n }\n this.props.onReady()\n },\n onStateChange: this.onStateChange,\n onError: event => onError(event.data)\n },\n host: MATCH_NOCOOKIE.test(url) ? NOCOOKIE_HOST : undefined,\n ...embedOptions\n })\n }, onError)\n }\n\n parsePlaylist = (url) => {\n if (url instanceof Array) {\n return {\n listType: 'playlist',\n playlist: url.map(this.getID).join(',')\n }\n }\n if (MATCH_PLAYLIST.test(url)) {\n const [, playlistId] = url.match(MATCH_PLAYLIST)\n return {\n listType: 'playlist',\n list: playlistId\n }\n } else if (MATCH_USER_UPLOADS.test(url)) {\n const [, username] = url.match(MATCH_USER_UPLOADS)\n return {\n listType: 'user_uploads',\n list: username\n }\n }\n return {}\n }\n\n onStateChange = (event) => {\n const { data } = event\n const { onPlay, onPause, onBuffer, onBufferEnd, onEnded, onReady, loop, config: { playerVars, onUnstarted } } = this.props\n const { UNSTARTED, PLAYING, PAUSED, BUFFERING, ENDED, CUED } = window[SDK_GLOBAL].PlayerState\n if (data === UNSTARTED) onUnstarted()\n if (data === PLAYING) {\n onPlay()\n onBufferEnd()\n }\n if (data === PAUSED) onPause()\n if (data === BUFFERING) onBuffer()\n if (data === ENDED) {\n const isPlaylist = !!this.callPlayer('getPlaylist')\n // Only loop manually if not playing a playlist\n if (loop && !isPlaylist) {\n if (playerVars.start) {\n this.seekTo(playerVars.start)\n } else {\n this.play()\n }\n }\n onEnded()\n }\n if (data === CUED) onReady()\n }\n\n play () {\n this.callPlayer('playVideo')\n }\n\n pause () {\n this.callPlayer('pauseVideo')\n }\n\n stop () {\n if (!document.body.contains(this.callPlayer('getIframe'))) return\n this.callPlayer('stopVideo')\n }\n\n seekTo (amount) {\n this.callPlayer('seekTo', amount)\n if (!this.props.playing) {\n this.pause()\n }\n }\n\n setVolume (fraction) {\n this.callPlayer('setVolume', fraction * 100)\n }\n\n mute = () => {\n this.callPlayer('mute')\n }\n\n unmute = () => {\n this.callPlayer('unMute')\n }\n\n setPlaybackRate (rate) {\n this.callPlayer('setPlaybackRate', rate)\n }\n\n setLoop (loop) {\n this.callPlayer('setLoop', loop)\n }\n\n getDuration () {\n return this.callPlayer('getDuration')\n }\n\n getCurrentTime () {\n return this.callPlayer('getCurrentTime')\n }\n\n getSecondsLoaded () {\n return this.callPlayer('getVideoLoadedFraction') * this.getDuration()\n }\n\n ref = container => {\n this.container = container\n }\n\n render () {\n const { display } = this.props\n const style = {\n width: '100%',\n height: '100%',\n display\n }\n return (\n
\n
\n
\n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK } from '../utils'\nimport { canPlay } from '../patterns'\n\nconst SDK_URL = 'https://w.soundcloud.com/player/api.js'\nconst SDK_GLOBAL = 'SC'\n\nexport default class SoundCloud extends Component {\n static displayName = 'SoundCloud'\n static canPlay = canPlay.soundcloud\n static loopOnEnded = true\n callPlayer = callPlayer\n duration = null\n currentTime = null\n fractionLoaded = null\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url, isReady) {\n getSDK(SDK_URL, SDK_GLOBAL).then(SC => {\n if (!this.iframe) return\n const { PLAY, PLAY_PROGRESS, PAUSE, FINISH, ERROR } = SC.Widget.Events\n if (!isReady) {\n this.player = SC.Widget(this.iframe)\n this.player.bind(PLAY, this.props.onPlay)\n this.player.bind(PAUSE, () => {\n const remaining = this.duration - this.currentTime\n if (remaining < 0.05) {\n // Prevent onPause firing right before onEnded\n return\n }\n this.props.onPause()\n })\n this.player.bind(PLAY_PROGRESS, e => {\n this.currentTime = e.currentPosition / 1000\n this.fractionLoaded = e.loadedProgress\n })\n this.player.bind(FINISH, () => this.props.onEnded())\n this.player.bind(ERROR, e => this.props.onError(e))\n }\n this.player.load(url, {\n ...this.props.config.options,\n callback: () => {\n this.player.getDuration(duration => {\n this.duration = duration / 1000\n this.props.onReady()\n })\n }\n })\n })\n }\n\n play () {\n this.callPlayer('play')\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n // Nothing to do\n }\n\n seekTo (seconds) {\n this.callPlayer('seekTo', seconds * 1000)\n }\n\n setVolume (fraction) {\n this.callPlayer('setVolume', fraction * 100)\n }\n\n mute = () => {\n this.setVolume(0)\n }\n\n unmute = () => {\n if (this.props.volume !== null) {\n this.setVolume(this.props.volume)\n }\n }\n\n getDuration () {\n return this.duration\n }\n\n getCurrentTime () {\n return this.currentTime\n }\n\n getSecondsLoaded () {\n return this.fractionLoaded * this.duration\n }\n\n ref = iframe => {\n this.iframe = iframe\n }\n\n render () {\n const { display } = this.props\n const style = {\n width: '100%',\n height: '100%',\n display\n }\n return (\n \n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK } from '../utils'\nimport { canPlay } from '../patterns'\n\nconst SDK_URL = 'https://player.vimeo.com/api/player.js'\nconst SDK_GLOBAL = 'Vimeo'\n\nexport default class Vimeo extends Component {\n static displayName = 'Vimeo'\n static canPlay = canPlay.vimeo\n static forceLoad = true // Prevent checking isLoading when URL changes\n callPlayer = callPlayer\n duration = null\n currentTime = null\n secondsLoaded = null\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url) {\n this.duration = null\n getSDK(SDK_URL, SDK_GLOBAL).then(Vimeo => {\n if (!this.container) return\n this.player = new Vimeo.Player(this.container, {\n url,\n autoplay: this.props.playing,\n muted: this.props.muted,\n loop: this.props.loop,\n playsinline: this.props.playsinline,\n controls: this.props.controls,\n ...this.props.config.playerOptions\n })\n this.player.ready().then(() => {\n const iframe = this.container.querySelector('iframe')\n iframe.style.width = '100%'\n iframe.style.height = '100%'\n }).catch(this.props.onError)\n this.player.on('loaded', () => {\n this.props.onReady()\n this.refreshDuration()\n })\n this.player.on('play', () => {\n this.props.onPlay()\n this.refreshDuration()\n })\n this.player.on('pause', this.props.onPause)\n this.player.on('seeked', e => this.props.onSeek(e.seconds))\n this.player.on('ended', this.props.onEnded)\n this.player.on('error', this.props.onError)\n this.player.on('timeupdate', ({ seconds }) => {\n this.currentTime = seconds\n })\n this.player.on('progress', ({ seconds }) => {\n this.secondsLoaded = seconds\n })\n }, this.props.onError)\n }\n\n refreshDuration () {\n this.player.getDuration().then(duration => {\n this.duration = duration\n })\n }\n\n play () {\n const promise = this.callPlayer('play')\n if (promise) {\n promise.catch(this.props.onError)\n }\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n this.callPlayer('unload')\n }\n\n seekTo (seconds) {\n this.callPlayer('setCurrentTime', seconds)\n }\n\n setVolume (fraction) {\n this.callPlayer('setVolume', fraction)\n }\n\n setLoop (loop) {\n this.callPlayer('setLoop', loop)\n }\n\n setPlaybackRate (rate) {\n this.callPlayer('setPlaybackRate', rate)\n }\n\n mute = () => {\n this.setVolume(0)\n }\n\n unmute = () => {\n if (this.props.volume !== null) {\n this.setVolume(this.props.volume)\n }\n }\n\n getDuration () {\n return this.duration\n }\n\n getCurrentTime () {\n return this.currentTime\n }\n\n getSecondsLoaded () {\n return this.secondsLoaded\n }\n\n ref = container => {\n this.container = container\n }\n\n render () {\n const { display } = this.props\n const style = {\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n display\n }\n return (\n \n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK, randomString } from '../utils'\nimport { canPlay } from '../patterns'\n\nconst SDK_URL = 'https://connect.facebook.net/en_US/sdk.js'\nconst SDK_GLOBAL = 'FB'\nconst SDK_GLOBAL_READY = 'fbAsyncInit'\nconst PLAYER_ID_PREFIX = 'facebook-player-'\n\nexport default class Facebook extends Component {\n static displayName = 'Facebook'\n static canPlay = canPlay.facebook\n static loopOnEnded = true\n callPlayer = callPlayer\n playerID = this.props.config.playerId || `${PLAYER_ID_PREFIX}${randomString()}`\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url, isReady) {\n if (isReady) {\n getSDK(SDK_URL, SDK_GLOBAL, SDK_GLOBAL_READY).then(FB => FB.XFBML.parse())\n return\n }\n getSDK(SDK_URL, SDK_GLOBAL, SDK_GLOBAL_READY).then(FB => {\n FB.init({\n appId: this.props.config.appId,\n xfbml: true,\n version: this.props.config.version\n })\n FB.Event.subscribe('xfbml.render', msg => {\n // Here we know the SDK has loaded, even if onReady/onPlay\n // is not called due to a video that cannot be embedded\n this.props.onLoaded()\n })\n FB.Event.subscribe('xfbml.ready', msg => {\n if (msg.type === 'video' && msg.id === this.playerID) {\n this.player = msg.instance\n this.player.subscribe('startedPlaying', this.props.onPlay)\n this.player.subscribe('paused', this.props.onPause)\n this.player.subscribe('finishedPlaying', this.props.onEnded)\n this.player.subscribe('startedBuffering', this.props.onBuffer)\n this.player.subscribe('finishedBuffering', this.props.onBufferEnd)\n this.player.subscribe('error', this.props.onError)\n if (!this.props.muted) {\n // Player is muted by default\n this.callPlayer('unmute')\n }\n this.props.onReady()\n\n // For some reason Facebook have added `visibility: hidden`\n // to the iframe when autoplay fails, so here we set it back\n document.getElementById(this.playerID).querySelector('iframe').style.visibility = 'visible'\n }\n })\n })\n }\n\n play () {\n this.callPlayer('play')\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n // Nothing to do\n }\n\n seekTo (seconds) {\n this.callPlayer('seek', seconds)\n }\n\n setVolume (fraction) {\n this.callPlayer('setVolume', fraction)\n }\n\n mute = () => {\n this.callPlayer('mute')\n }\n\n unmute = () => {\n this.callPlayer('unmute')\n }\n\n getDuration () {\n return this.callPlayer('getDuration')\n }\n\n getCurrentTime () {\n return this.callPlayer('getCurrentPosition')\n }\n\n getSecondsLoaded () {\n return null\n }\n\n render () {\n const style = {\n width: '100%',\n height: '100%'\n }\n return (\n \n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK } from '../utils'\nimport { canPlay, MATCH_URL_STREAMABLE } from '../patterns'\n\nconst SDK_URL = 'https://cdn.embed.ly/player-0.1.0.min.js'\nconst SDK_GLOBAL = 'playerjs'\n\nexport default class Streamable extends Component {\n static displayName = 'Streamable'\n static canPlay = canPlay.streamable\n callPlayer = callPlayer\n duration = null\n currentTime = null\n secondsLoaded = null\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url) {\n getSDK(SDK_URL, SDK_GLOBAL).then(playerjs => {\n if (!this.iframe) return\n this.player = new playerjs.Player(this.iframe)\n this.player.setLoop(this.props.loop)\n this.player.on('ready', this.props.onReady)\n this.player.on('play', this.props.onPlay)\n this.player.on('pause', this.props.onPause)\n this.player.on('seeked', this.props.onSeek)\n this.player.on('ended', this.props.onEnded)\n this.player.on('error', this.props.onError)\n this.player.on('timeupdate', ({ duration, seconds }) => {\n this.duration = duration\n this.currentTime = seconds\n })\n this.player.on('buffered', ({ percent }) => {\n if (this.duration) {\n this.secondsLoaded = this.duration * percent\n }\n })\n if (this.props.muted) {\n this.player.mute()\n }\n }, this.props.onError)\n }\n\n play () {\n this.callPlayer('play')\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n // Nothing to do\n }\n\n seekTo (seconds) {\n this.callPlayer('setCurrentTime', seconds)\n }\n\n setVolume (fraction) {\n this.callPlayer('setVolume', fraction * 100)\n }\n\n setLoop (loop) {\n this.callPlayer('setLoop', loop)\n }\n\n mute = () => {\n this.callPlayer('mute')\n }\n\n unmute = () => {\n this.callPlayer('unmute')\n }\n\n getDuration () {\n return this.duration\n }\n\n getCurrentTime () {\n return this.currentTime\n }\n\n getSecondsLoaded () {\n return this.secondsLoaded\n }\n\n ref = iframe => {\n this.iframe = iframe\n }\n\n render () {\n const id = this.props.url.match(MATCH_URL_STREAMABLE)[1]\n const style = {\n width: '100%',\n height: '100%'\n }\n return (\n \n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK, randomString } from '../utils'\nimport { canPlay, MATCH_URL_WISTIA } from '../patterns'\n\nconst SDK_URL = 'https://fast.wistia.com/assets/external/E-v1.js'\nconst SDK_GLOBAL = 'Wistia'\nconst PLAYER_ID_PREFIX = 'wistia-player-'\n\nexport default class Wistia extends Component {\n static displayName = 'Wistia'\n static canPlay = canPlay.wistia\n static loopOnEnded = true\n callPlayer = callPlayer\n playerID = this.props.config.playerId || `${PLAYER_ID_PREFIX}${randomString()}`\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url) {\n const { playing, muted, controls, onReady, config, onError } = this.props\n getSDK(SDK_URL, SDK_GLOBAL).then(() => {\n window._wq = window._wq || []\n window._wq.push({\n id: this.playerID,\n options: {\n autoPlay: playing,\n silentAutoPlay: 'allow',\n muted: muted,\n controlsVisibleOnLoad: controls,\n fullscreenButton: controls,\n playbar: controls,\n playbackRateControl: controls,\n qualityControl: controls,\n volumeControl: controls,\n settingsControl: controls,\n smallPlayButton: controls,\n ...config.options\n },\n onReady: player => {\n this.player = player\n this.unbind()\n this.player.bind('play', this.onPlay)\n this.player.bind('pause', this.onPause)\n this.player.bind('seek', this.onSeek)\n this.player.bind('end', this.onEnded)\n onReady()\n }\n })\n }, onError)\n }\n\n unbind () {\n this.player.unbind('play', this.onPlay)\n this.player.unbind('pause', this.onPause)\n this.player.unbind('seek', this.onSeek)\n this.player.unbind('end', this.onEnded)\n }\n\n // Proxy methods to prevent listener leaks\n onPlay = (...args) => this.props.onPlay(...args)\n onPause = (...args) => this.props.onPause(...args)\n onSeek = (...args) => this.props.onSeek(...args)\n onEnded = (...args) => this.props.onEnded(...args)\n\n play () {\n this.callPlayer('play')\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n this.unbind()\n this.callPlayer('remove')\n }\n\n seekTo (seconds) {\n this.callPlayer('time', seconds)\n }\n\n setVolume (fraction) {\n this.callPlayer('volume', fraction)\n }\n\n mute = () => {\n this.callPlayer('mute')\n }\n\n unmute = () => {\n this.callPlayer('unmute')\n }\n\n setPlaybackRate (rate) {\n this.callPlayer('playbackRate', rate)\n }\n\n getDuration () {\n return this.callPlayer('duration')\n }\n\n getCurrentTime () {\n return this.callPlayer('time')\n }\n\n getSecondsLoaded () {\n return null\n }\n\n render () {\n const { url } = this.props\n const videoID = url && url.match(MATCH_URL_WISTIA)[1]\n const className = `wistia_embed wistia_async_${videoID}`\n const style = {\n width: '100%',\n height: '100%'\n }\n return (\n
\n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK, randomString } from '../utils'\nimport { canPlay, MATCH_URL_TWITCH_CHANNEL, MATCH_URL_TWITCH_VIDEO } from '../patterns'\n\nconst SDK_URL = 'https://player.twitch.tv/js/embed/v1.js'\nconst SDK_GLOBAL = 'Twitch'\nconst PLAYER_ID_PREFIX = 'twitch-player-'\n\nexport default class Twitch extends Component {\n static displayName = 'Twitch'\n static canPlay = canPlay.twitch\n static loopOnEnded = true\n callPlayer = callPlayer\n playerID = this.props.config.playerId || `${PLAYER_ID_PREFIX}${randomString()}`\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url, isReady) {\n const { playsinline, onError, config, controls } = this.props\n const isChannel = MATCH_URL_TWITCH_CHANNEL.test(url)\n const id = isChannel ? url.match(MATCH_URL_TWITCH_CHANNEL)[1] : url.match(MATCH_URL_TWITCH_VIDEO)[1]\n if (isReady) {\n if (isChannel) {\n this.player.setChannel(id)\n } else {\n this.player.setVideo('v' + id)\n }\n return\n }\n getSDK(SDK_URL, SDK_GLOBAL).then(Twitch => {\n this.player = new Twitch.Player(this.playerID, {\n video: isChannel ? '' : id,\n channel: isChannel ? id : '',\n height: '100%',\n width: '100%',\n playsinline: playsinline,\n autoplay: this.props.playing,\n muted: this.props.muted,\n // https://github.com/CookPete/react-player/issues/733#issuecomment-549085859\n controls: isChannel ? true : controls,\n ...config.options\n })\n const { READY, PLAYING, PAUSE, ENDED, ONLINE, OFFLINE } = Twitch.Player\n this.player.addEventListener(READY, this.props.onReady)\n this.player.addEventListener(PLAYING, this.props.onPlay)\n this.player.addEventListener(PAUSE, this.props.onPause)\n this.player.addEventListener(ENDED, this.props.onEnded)\n\n // Prevent weird isLoading behaviour when streams are offline\n this.player.addEventListener(ONLINE, this.props.onLoaded)\n this.player.addEventListener(OFFLINE, this.props.onLoaded)\n }, onError)\n }\n\n play () {\n this.callPlayer('play')\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n this.callPlayer('pause')\n }\n\n seekTo (seconds) {\n this.callPlayer('seek', seconds)\n }\n\n setVolume (fraction) {\n this.callPlayer('setVolume', fraction)\n }\n\n mute = () => {\n this.callPlayer('setMuted', true)\n }\n\n unmute = () => {\n this.callPlayer('setMuted', false)\n }\n\n getDuration () {\n return this.callPlayer('getDuration')\n }\n\n getCurrentTime () {\n return this.callPlayer('getCurrentTime')\n }\n\n getSecondsLoaded () {\n return null\n }\n\n render () {\n const style = {\n width: '100%',\n height: '100%'\n }\n return (\n
\n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK, parseStartTime } from '../utils'\nimport { canPlay, MATCH_URL_DAILYMOTION } from '../patterns'\n\nconst SDK_URL = 'https://api.dmcdn.net/all.js'\nconst SDK_GLOBAL = 'DM'\nconst SDK_GLOBAL_READY = 'dmAsyncInit'\n\nexport default class DailyMotion extends Component {\n static displayName = 'DailyMotion'\n static canPlay = canPlay.dailymotion\n static loopOnEnded = true\n callPlayer = callPlayer\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url) {\n const { controls, config, onError, playing } = this.props\n const [, id] = url.match(MATCH_URL_DAILYMOTION)\n if (this.player) {\n this.player.load(id, {\n start: parseStartTime(url),\n autoplay: playing\n })\n return\n }\n getSDK(SDK_URL, SDK_GLOBAL, SDK_GLOBAL_READY, DM => DM.player).then(DM => {\n if (!this.container) return\n const Player = DM.player\n this.player = new Player(this.container, {\n width: '100%',\n height: '100%',\n video: id,\n params: {\n controls: controls,\n autoplay: this.props.playing,\n mute: this.props.muted,\n start: parseStartTime(url),\n origin: window.location.origin,\n ...config.params\n },\n events: {\n apiready: this.props.onReady,\n seeked: () => this.props.onSeek(this.player.currentTime),\n video_end: this.props.onEnded,\n durationchange: this.onDurationChange,\n pause: this.props.onPause,\n playing: this.props.onPlay,\n waiting: this.props.onBuffer,\n error: event => onError(event)\n }\n })\n }, onError)\n }\n\n onDurationChange = () => {\n const duration = this.getDuration()\n this.props.onDuration(duration)\n }\n\n play () {\n this.callPlayer('play')\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n // Nothing to do\n }\n\n seekTo (seconds) {\n this.callPlayer('seek', seconds)\n }\n\n setVolume (fraction) {\n this.callPlayer('setVolume', fraction)\n }\n\n mute = () => {\n this.callPlayer('setMuted', true)\n }\n\n unmute = () => {\n this.callPlayer('setMuted', false)\n }\n\n getDuration () {\n return this.player.duration || null\n }\n\n getCurrentTime () {\n return this.player.currentTime\n }\n\n getSecondsLoaded () {\n return this.player.bufferedTime\n }\n\n ref = container => {\n this.container = container\n }\n\n render () {\n const { display } = this.props\n const style = {\n width: '100%',\n height: '100%',\n display\n }\n return (\n
\n
\n
\n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK, queryString } from '../utils'\nimport { canPlay, MATCH_URL_MIXCLOUD } from '../patterns'\n\nconst SDK_URL = 'https://widget.mixcloud.com/media/js/widgetApi.js'\nconst SDK_GLOBAL = 'Mixcloud'\n\nexport default class Mixcloud extends Component {\n static displayName = 'Mixcloud'\n static canPlay = canPlay.mixcloud\n static loopOnEnded = true\n callPlayer = callPlayer\n duration = null\n currentTime = null\n secondsLoaded = null\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url) {\n getSDK(SDK_URL, SDK_GLOBAL).then(Mixcloud => {\n this.player = Mixcloud.PlayerWidget(this.iframe)\n this.player.ready.then(() => {\n this.player.events.play.on(this.props.onPlay)\n this.player.events.pause.on(this.props.onPause)\n this.player.events.ended.on(this.props.onEnded)\n this.player.events.error.on(this.props.error)\n this.player.events.progress.on((seconds, duration) => {\n this.currentTime = seconds\n this.duration = duration\n })\n this.props.onReady()\n })\n }, this.props.onError)\n }\n\n play () {\n this.callPlayer('play')\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n // Nothing to do\n }\n\n seekTo (seconds) {\n this.callPlayer('seek', seconds)\n }\n\n setVolume (fraction) {\n // No volume support\n }\n\n mute = () => {\n // No volume support\n }\n\n unmute = () => {\n // No volume support\n }\n\n getDuration () {\n return this.duration\n }\n\n getCurrentTime () {\n return this.currentTime\n }\n\n getSecondsLoaded () {\n return null\n }\n\n ref = iframe => {\n this.iframe = iframe\n }\n\n render () {\n const { url, config } = this.props\n const id = url.match(MATCH_URL_MIXCLOUD)[1]\n const style = {\n width: '100%',\n height: '100%'\n }\n const query = queryString({\n ...config.options,\n feed: `/${id}/`\n })\n // We have to give the iframe a key here to prevent a\n // weird dialog appearing when loading a new track\n return (\n \n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { callPlayer, getSDK } from '../utils'\nimport { canPlay, MATCH_URL_VIDYARD } from '../patterns'\n\nconst SDK_URL = 'https://play.vidyard.com/embed/v4.js'\nconst SDK_GLOBAL = 'VidyardV4'\nconst SDK_GLOBAL_READY = 'onVidyardAPI'\n\nexport default class Vidyard extends Component {\n static displayName = 'Vidyard'\n static canPlay = canPlay.vidyard\n callPlayer = callPlayer\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n }\n\n load (url) {\n const { playing, config, onError, onDuration } = this.props\n const id = url && url.match(MATCH_URL_VIDYARD)[1]\n if (this.player) {\n this.stop()\n }\n getSDK(SDK_URL, SDK_GLOBAL, SDK_GLOBAL_READY).then(Vidyard => {\n if (!this.container) return\n Vidyard.api.addReadyListener((data, player) => {\n this.player = player\n this.player.on('ready', this.props.onReady)\n this.player.on('play', this.props.onPlay)\n this.player.on('pause', this.props.onPause)\n this.player.on('seek', this.props.onSeek)\n this.player.on('playerComplete', this.props.onEnded)\n }, id)\n Vidyard.api.renderPlayer({\n uuid: id,\n container: this.container,\n autoplay: playing ? 1 : 0,\n ...config.options\n })\n Vidyard.api.getPlayerMetadata(id).then(meta => {\n this.duration = meta.length_in_seconds\n onDuration(meta.length_in_seconds)\n })\n }, onError)\n }\n\n play () {\n this.callPlayer('play')\n }\n\n pause () {\n this.callPlayer('pause')\n }\n\n stop () {\n window.VidyardV4.api.destroyPlayer(this.player)\n }\n\n seekTo (amount) {\n this.callPlayer('seek', amount)\n }\n\n setVolume (fraction) {\n this.callPlayer('setVolume', fraction)\n }\n\n mute = () => {\n this.setVolume(0)\n }\n\n unmute = () => {\n if (this.props.volume !== null) {\n this.setVolume(this.props.volume)\n }\n }\n\n setPlaybackRate (rate) {\n this.callPlayer('setPlaybackSpeed', rate)\n }\n\n getDuration () {\n return this.duration\n }\n\n getCurrentTime () {\n return this.callPlayer('currentTime')\n }\n\n getSecondsLoaded () {\n return null\n }\n\n ref = container => {\n this.container = container\n }\n\n render () {\n const { display } = this.props\n const style = {\n width: '100%',\n height: '100%',\n display\n }\n return (\n
\n
\n
\n )\n }\n}\n","import React, { Component } from 'react'\n\nimport { getSDK, isMediaStream, supportsWebKitPresentationMode } from '../utils'\nimport { canPlay, AUDIO_EXTENSIONS, HLS_EXTENSIONS, DASH_EXTENSIONS, FLV_EXTENSIONS } from '../patterns'\n\nconst IOS = typeof navigator !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream\nconst HLS_SDK_URL = 'https://cdn.jsdelivr.net/npm/hls.js@VERSION/dist/hls.min.js'\nconst HLS_GLOBAL = 'Hls'\nconst DASH_SDK_URL = 'https://cdnjs.cloudflare.com/ajax/libs/dashjs/VERSION/dash.all.min.js'\nconst DASH_GLOBAL = 'dashjs'\nconst FLV_SDK_URL = 'https://cdn.jsdelivr.net/npm/flv.js@VERSION/dist/flv.min.js'\nconst FLV_GLOBAL = 'flvjs'\nconst MATCH_DROPBOX_URL = /www\\.dropbox\\.com\\/.+/\nconst MATCH_CLOUDFLARE_STREAM = /https:\\/\\/watch\\.cloudflarestream\\.com\\/([a-z0-9]+)/\nconst REPLACE_CLOUDFLARE_STREAM = 'https://videodelivery.net/{id}/manifest/video.m3u8'\n\nexport default class FilePlayer extends Component {\n static displayName = 'FilePlayer'\n static canPlay = canPlay.file\n\n componentDidMount () {\n this.props.onMount && this.props.onMount(this)\n this.addListeners(this.player)\n if (IOS) {\n this.player.load()\n }\n }\n\n componentDidUpdate (prevProps) {\n if (this.shouldUseAudio(this.props) !== this.shouldUseAudio(prevProps)) {\n this.removeListeners(this.prevPlayer)\n this.addListeners(this.player)\n }\n }\n\n componentWillUnmount () {\n this.removeListeners(this.player)\n if (this.hls) {\n this.hls.destroy()\n }\n }\n\n addListeners (player) {\n const { playsinline } = this.props\n player.addEventListener('canplay', this.onReady)\n player.addEventListener('play', this.onPlay)\n player.addEventListener('waiting', this.onBuffer)\n player.addEventListener('playing', this.onBufferEnd)\n player.addEventListener('pause', this.onPause)\n player.addEventListener('seeked', this.onSeek)\n player.addEventListener('ended', this.onEnded)\n player.addEventListener('error', this.onError)\n player.addEventListener('enterpictureinpicture', this.onEnablePIP)\n player.addEventListener('leavepictureinpicture', this.onDisablePIP)\n player.addEventListener('webkitpresentationmodechanged', this.onPresentationModeChange)\n if (playsinline) {\n player.setAttribute('playsinline', '')\n player.setAttribute('webkit-playsinline', '')\n player.setAttribute('x5-playsinline', '')\n }\n }\n\n removeListeners (player) {\n player.removeEventListener('canplay', this.onReady)\n player.removeEventListener('play', this.onPlay)\n player.removeEventListener('waiting', this.onBuffer)\n player.removeEventListener('playing', this.onBufferEnd)\n player.removeEventListener('pause', this.onPause)\n player.removeEventListener('seeked', this.onSeek)\n player.removeEventListener('ended', this.onEnded)\n player.removeEventListener('error', this.onError)\n player.removeEventListener('enterpictureinpicture', this.onEnablePIP)\n player.removeEventListener('leavepictureinpicture', this.onDisablePIP)\n player.removeEventListener('webkitpresentationmodechanged', this.onPresentationModeChange)\n }\n\n // Proxy methods to prevent listener leaks\n onReady = (...args) => this.props.onReady(...args)\n onPlay = (...args) => this.props.onPlay(...args)\n onBuffer = (...args) => this.props.onBuffer(...args)\n onBufferEnd = (...args) => this.props.onBufferEnd(...args)\n onPause = (...args) => this.props.onPause(...args)\n onEnded = (...args) => this.props.onEnded(...args)\n onError = (...args) => this.props.onError(...args)\n onEnablePIP = (...args) => this.props.onEnablePIP(...args)\n\n onDisablePIP = e => {\n const { onDisablePIP, playing } = this.props\n onDisablePIP(e)\n if (playing) {\n this.play()\n }\n }\n\n onPresentationModeChange = e => {\n if (this.player && supportsWebKitPresentationMode(this.player)) {\n const { webkitPresentationMode } = this.player\n if (webkitPresentationMode === 'picture-in-picture') {\n this.onEnablePIP(e)\n } else if (webkitPresentationMode === 'inline') {\n this.onDisablePIP(e)\n }\n }\n }\n\n onSeek = e => {\n this.props.onSeek(e.target.currentTime)\n }\n\n shouldUseAudio (props) {\n if (props.config.forceVideo) {\n return false\n }\n if (props.config.attributes.poster) {\n return false // Use