UNPKG

react-tuby

Version:

A React video player library with YouTube-like UI

1,200 lines (1,069 loc) 52.9 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } var ClientRender = function ClientRender(_ref) { var children = _ref.children; var _useState = React.useState(typeof window !== "undefined"), rendered = _useState[0], setRendered = _useState[1]; React.useEffect(function () { setRendered(true); }, []); if (rendered) return children; return React__default.createElement(React__default.Fragment, null); }; var ErrorBoundary = /*#__PURE__*/function (_Component) { _inheritsLoose(ErrorBoundary, _Component); function ErrorBoundary(props) { var _this; _this = _Component.call(this, props) || this; _this.state = { hasError: false }; _this.playerRef = React.createRef(); _this.videoProps = { crossOrigin: "anonymous", playsInline: true, controls: true, src: typeof _this.props.src === "string" ? _this.props.src : _this.props.src[0].url, children: React__default.createElement(React__default.Fragment, null, _this.props.subtitles && _this.props.subtitles.length > 0 && _this.props.subtitles.map(function (subtitle, index) { return React__default.createElement("track", { key: subtitle.lang, kind: "subtitles", srcLang: subtitle.lang, label: subtitle.language, src: subtitle.url, "default": index === 0 }); })) }; return _this; } ErrorBoundary.getDerivedStateFromError = function getDerivedStateFromError() { return { hasError: true }; }; var _proto = ErrorBoundary.prototype; _proto.render = function render() { if (this.state.hasError) { return React__default.createElement("div", { className: "tuby-container" }, this.props.renderer ? this.props.renderer(this.playerRef, this.videoProps) : React__default.createElement("video", Object.assign({ ref: this.playerRef }, this.videoProps))); } return this.props.children; }; return ErrorBoundary; }(React.Component); var formatVideoTime = function formatVideoTime(time) { try { var date = new Date(0); date.setSeconds(time); var timeString = date.toISOString().slice(11, 19); var result = timeString.startsWith("00:0") ? timeString.slice(4) : timeString.startsWith("00") ? timeString.slice(3) : timeString; return result; } catch (error) { return "0:00"; } }; var isMobile = function isMobile() { var _window, _window$navigator; return /iPhone|iPad|iPod|Android/i.test((_window = window) == null ? void 0 : (_window$navigator = _window.navigator) == null ? void 0 : _window$navigator.userAgent); }; var CircularProgress = function CircularProgress() { return React__default.createElement("svg", { className: "tuby-progress", viewBox: "25 25 50 50" }, React__default.createElement("circle", { cx: "50", cy: "50", r: "20" })); }; var ClickAwayListener = function ClickAwayListener(_ref) { var children = _ref.children, onClickAway = _ref.onClickAway; var childrenRef = React.useRef(null); React.useEffect(function () { var handler = function handler(e) { if (childrenRef.current && !childrenRef.current.contains(e.target)) { onClickAway(); } }; window.addEventListener("click", handler); return function () { return window.removeEventListener("click", handler); }; }, [onClickAway]); return React__default.createElement(React__default.Fragment, null, children(childrenRef)); }; var Cog = function Cog(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M44.1242 27.4467C44.2208 26.6625 44.2852 25.8469 44.2852 25C44.2852 24.1531 44.2208 23.3689 44.1242 22.5533L49.5331 18.4128C50.016 18.0364 50.1448 17.3777 49.8228 16.8131L44.6715 8.15558C44.3818 7.62233 43.6735 7.40276 43.1262 7.62233L36.7192 10.1317C35.3992 9.12798 33.9504 8.31242 32.3728 7.68507L31.4069 1.03513C31.3425 0.439147 30.7952 0 30.1513 0H19.8487C19.2048 0 18.6897 0.439147 18.5931 1.03513L17.6272 7.68507C16.0818 8.31242 14.633 9.15935 13.2808 10.1317L6.87385 7.62233C6.29432 7.40276 5.61822 7.62233 5.32846 8.15558L0.17715 16.8131C-0.144806 17.3463 0.0161725 18.0364 0.466912 18.4128L5.87578 22.5533C5.7792 23.3375 5.7148 24.1844 5.7148 25C5.7148 25.8156 5.7792 26.6311 5.87578 27.4467L0.466912 31.5872C-0.0160232 31.9636 -0.144806 32.6223 0.17715 33.187L5.32846 41.8444C5.61822 42.3777 6.32652 42.5972 6.87385 42.3777L13.2808 39.8683C14.6008 40.872 16.0496 41.6876 17.6272 42.3149L18.5931 48.9649C18.6575 49.5609 19.2048 50 19.8487 50H30.1513C30.7952 50 31.3103 49.5609 31.4069 48.9649L32.3728 42.3149C33.9182 41.6876 35.367 40.8407 36.7192 39.8683L43.1262 42.3777C43.7057 42.5972 44.3818 42.3777 44.6715 41.8444L49.8228 33.187C50.1126 32.6537 49.9838 31.9636 49.5331 31.5872L44.1242 27.4467V27.4467ZM25 33.7516C20.0419 33.7516 15.9852 29.8306 15.9852 24.9686C15.9852 20.138 20.0097 16.1857 25 16.1857C29.9581 16.1857 34.0148 20.1067 34.0148 24.9686C34.0148 29.7992 29.9903 33.7516 25 33.7516Z", fill: "white" })); }; var ExitFullScreen = function ExitFullScreen(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M12.5 12.5H0V18.75H18.75V0H12.5V12.5Z", fill: "white" }), React__default.createElement("path", { d: "M37.5 12.5V1.14441e-05H31.25V18.75H50V12.5H37.5Z", fill: "white" }), React__default.createElement("path", { d: "M31.25 50H37.5V37.5H50V31.25H31.25V50Z", fill: "white" }), React__default.createElement("path", { d: "M0 37.5H12.5V50H18.75V31.25H0V37.5Z", fill: "white" })); }; var FullScreen = function FullScreen(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M0 18.75H6.25V6.25H18.75V0H0V18.75Z", fill: "white" }), React__default.createElement("path", { d: "M31.25 0V6.25H43.75V18.75H50V0H31.25Z", fill: "white" }), React__default.createElement("path", { d: "M43.75 43.75H31.25V50H50V31.25H43.75V43.75Z", fill: "white" }), React__default.createElement("path", { d: "M6.25 31.25H0V50H18.75V43.75H6.25V31.25Z", fill: "white" })); }; var Pause = function Pause(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M5 50H17.3077V0H5V50ZM32.6923 50H45V0H32.6923V50Z", fill: "white" })); }; var PauseEffect = function PauseEffect() { return React__default.createElement("div", { className: "tuby-fade-zoom-out tuby-effect-icon" }, React__default.createElement(Pause, { className: "tuby-icon-md" })); }; var PictureInPicture = function PictureInPicture(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M40.9091 22.6667H22.7273V36.6667H40.9091V22.6667ZM50 41.3333V8.62C50 6.05333 47.9545 4 45.4545 4H4.54545C2.04545 4 0 6.05333 0 8.62V41.3333C0 43.9 2.04545 46 4.54545 46H45.4545C47.9545 46 50 43.9 50 41.3333ZM45.4545 41.38H4.54545V8.59667H45.4545V41.38Z", fill: "white" })); }; var Play = function Play(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ width: "50", height: "50", viewBox: "0 0 26 26", fill: "#FFFFFF", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M3 1V25L23 13L3 1Z" })); }; var PlayEffect = function PlayEffect() { return React__default.createElement("div", { className: "tuby-fade-zoom-out tuby-effect-icon" }, React__default.createElement(Play, { className: "tuby-icon-md" })); }; var Check = function Check(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M48.9536 8.08584C50.3488 9.53131 50.3488 11.8672 48.9536 13.3127L20.3806 42.9159C18.9854 44.3614 16.7308 44.3614 15.3357 42.9159L1.04604 28.1143C-0.34868 26.6688 -0.34868 24.3329 1.04604 22.8875C2.44098 21.442 4.70227 21.442 6.09744 22.8875L17.7577 35.0641L43.9087 8.08584C45.3039 6.63805 47.5585 6.63805 48.9536 8.08584Z", fill: "#fff" })); }; var ChevronLeft = function ChevronLeft(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M40 5.875L21.4575 25L40 44.125L34.2915 50L10 25L34.2915 0L40 5.875Z", fill: "white" })); }; var ChevronRight = function ChevronRight(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M10 44.125L28.5425 25L10 5.875L15.7085 0L40 25L15.7085 50L10 44.125Z", fill: "white" })); }; var Speed = function Speed(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M33.3333 40.5294H50V43.3529H33.3333V40.5294ZM22.2222 40.5294H0V43.3529H22.2222V49H25V43.3529V40.5294V34.8824H22.2222V40.5294ZM30.5556 15.1176H33.3333V9.47059V6.64706V1H30.5556V6.64706H0V9.47059H30.5556V15.1176ZM41.6667 6.64706V9.47059H50V6.64706H41.6667ZM8.33333 32.0588H11.1111V26.4118V23.5882V17.9412H8.33333V23.5882H0V26.4118H8.33333V32.0588ZM19.4444 26.4118H50V23.5882H19.4444V26.4118Z", fill: "white" })); }; var SelectSubtitle = function SelectSubtitle(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M8.33333 30.5556V19.4444C8.33333 17.9167 9.58333 16.6667 11.1111 16.6667H19.4444C20.9722 16.6667 22.2222 17.9167 22.2222 19.4444V22.2222H18.0556V20.8333H12.5V29.1667H18.0556V27.7778H22.2222V30.5556C22.2222 32.0833 20.9722 33.3333 19.4444 33.3333H11.1111C9.58333 33.3333 8.33333 32.0833 8.33333 30.5556ZM30.5556 33.3333H38.8889C40.4167 33.3333 41.6667 32.0833 41.6667 30.5556V27.7778H37.5V29.1667H31.9444V20.8333H37.5V22.2222H41.6667V19.4444C41.6667 17.9167 40.4167 16.6667 38.8889 16.6667H30.5556C29.0278 16.6667 27.7778 17.9167 27.7778 19.4444V30.5556C27.7778 32.0833 29.0278 33.3333 30.5556 33.3333ZM47.2222 2.77778H2.77778V47.2222H47.2222V2.77778ZM50 0V50H0V0.0277778C0 -2.58701e-08 -2.58701e-08 0 0.0277778 0H50Z", fill: "white" })); }; var Speed$1 = function Speed(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M20 15V35L35 25L20 15ZM10.75 7.5L9.25 5.5C13 2.5 17.5 0.5 22.5 0L22.75 2.5C18.25 3 14.25 4.75 10.75 7.5ZM7.5 10.75L5.5 9.25C2.5 13 0.5 17.5 0 22.5L2.5 22.75C3 18.25 4.75 14.25 7.5 10.75ZM7.5 39.25C4.75 35.75 3 31.5 2.5 27.25L0 27.5C0.5 32.5 2.5 37 5.5 41L7.5 39.25ZM22.75 47.5C18.25 47 14.25 45.25 10.75 42.5L9.25 44.5C13 47.5 17.5 49.5 22.5 50L22.75 47.5ZM50 25C50 12 40.25 1.5 27.5 0L27.25 2.5C38.75 3.75 47.5 13.25 47.5 25C47.5 36.75 38.75 46.25 27.25 47.5L27.5 50C40.5 48.75 50 38 50 25Z", fill: "white" })); }; var SettingsDialog = function SettingsDialog(_ref) { var settingsActive = _ref.settingsActive, src = _ref.src, subtitles = _ref.subtitles, playbackSpeed = _ref.playbackSpeed, setPlaybackSpeed = _ref.setPlaybackSpeed, subtitleIndex = _ref.subtitleIndex, setSubtitleIndex = _ref.setSubtitleIndex, quality = _ref.quality, setQuality = _ref.setQuality, internationalization = _ref.internationalization; var _useState = React.useState(0), height = _useState[0], setHeight = _useState[1]; var _useState2 = React.useState("main"), activeSection = _useState2[0], setActiveSection = _useState2[1]; var mainSectionRef = React.useRef(null); var speedSectionRef = React.useRef(null); var subtitlesSectionRef = React.useRef(null); var qualitySectionRef = React.useRef(null); var sections = { main: mainSectionRef, speed: speedSectionRef, subtitles: subtitlesSectionRef, quality: qualitySectionRef }; React.useEffect(function () { if (sections[activeSection].current) { var elementHeight = sections[activeSection].current.offsetHeight; setHeight(elementHeight > 250 ? 250 : elementHeight); sections[activeSection].current.scrollTo && sections[activeSection].current.scrollTo(0, 0); } // eslint-disable-next-line }, [activeSection]); return React__default.createElement("div", { className: "tuby-settings-dialog " + (settingsActive ? "tuby-show" : "") }, React__default.createElement("div", { style: { height: height }, className: "tuby-settings-outer" }, React__default.createElement("div", { ref: mainSectionRef, className: "tuby-settings-section tuby-settings-py " + (activeSection === "main" ? "tuby-settings-translate-center" : "tuby-settings-translate-left") }, React__default.createElement("div", { onClick: function onClick() { return setActiveSection("speed"); }, className: "tuby-settings-item" }, React__default.createElement("div", { className: "tuby-settings-item-left" }, React__default.createElement(Speed$1, { className: "tuby-icon-sm" }), React__default.createElement("p", null, (internationalization == null ? void 0 : internationalization.settingsPlaybackSpeed) || "Playback Speed")), React__default.createElement(ChevronRight, { className: "tuby-chevron" })), subtitles && React__default.createElement("div", { onClick: function onClick() { return setActiveSection("subtitles"); }, className: "tuby-settings-item" }, React__default.createElement("div", { className: "tuby-settings-item-left" }, React__default.createElement(SelectSubtitle, { className: "tuby-icon-sm" }), React__default.createElement("p", null, (internationalization == null ? void 0 : internationalization.settingsSubtitles) || "Subtitles")), React__default.createElement(ChevronRight, { style: { width: 15, height: 15 } })), typeof src !== "string" && React__default.createElement("div", { onClick: function onClick() { return setActiveSection("quality"); }, className: "tuby-settings-item" }, React__default.createElement("div", { className: "tuby-settings-item-left" }, React__default.createElement(Speed, { className: "tuby-icon-sm" }), React__default.createElement("p", null, (internationalization == null ? void 0 : internationalization.settingsQuality) || "Quality")), React__default.createElement(ChevronRight, { className: "tuby-chevron" }))), React__default.createElement("div", { ref: speedSectionRef, className: "tuby-settings-section " + (activeSection === "speed" ? "tuby-settings-translate-center" : "tuby-settings-translate-right") }, React__default.createElement("div", { onClick: function onClick() { return setActiveSection("main"); }, className: "tuby-settings-section-header" }, React__default.createElement(ChevronLeft, { className: "tuby-chevron" }), React__default.createElement("span", null, (internationalization == null ? void 0 : internationalization.settingsPlaybackSpeed) || "Playback speed")), React__default.createElement("div", { className: "tuby-settings-py" }, new Array(8).fill("").map(function (_, index) { return index === 3 ? (internationalization == null ? void 0 : internationalization.settingsPlaybackSpeedNormal) || "Normal" : (index + 1) / 4; }).map(function (item, index) { return React__default.createElement("div", { key: item, onClick: function onClick() { setPlaybackSpeed((index + 1) / 4); setActiveSection("main"); }, className: "tuby-settings-item-2" }, playbackSpeed === (index + 1) / 4 ? React__default.createElement(Check, { className: "tuby-chevron" }) : React__default.createElement("div", { style: { width: 15, height: 15 } }), React__default.createElement("span", null, item)); }))), subtitles && React__default.createElement("div", { ref: subtitlesSectionRef, className: "tuby-settings-section " + (activeSection === "subtitles" ? "tuby-settings-translate-center" : "tuby-settings-translate-right") }, React__default.createElement("div", { onClick: function onClick() { return setActiveSection("main"); }, className: "tuby-settings-section-header" }, React__default.createElement(ChevronLeft, { className: "tuby-chevron" }), React__default.createElement("span", null, (internationalization == null ? void 0 : internationalization.settingsSubtitles) || "Subtitles")), React__default.createElement("div", { className: "tuby-settings-py" }, React__default.createElement("div", { onClick: function onClick() { setSubtitleIndex(-1); setActiveSection("main"); }, className: "tuby-settings-item-2" }, subtitleIndex === -1 ? React__default.createElement(Check, { className: "tuby-chevron" }) : React__default.createElement("div", { style: { width: 15, height: 15 } }), React__default.createElement("span", null, (internationalization == null ? void 0 : internationalization.settingsSubtitlesOff) || "Off")), subtitles.map(function (subtitle, index) { return React__default.createElement("div", { key: subtitle.lang, onClick: function onClick() { setSubtitleIndex(index); setActiveSection("main"); }, className: "tuby-settings-item-2" }, subtitleIndex === index ? React__default.createElement(Check, { className: "tuby-chevron" }) : React__default.createElement("div", { style: { width: 15, height: 15 } }), React__default.createElement("span", null, subtitle.language)); }))), typeof src !== "string" && React__default.createElement("div", { ref: qualitySectionRef, className: "tuby-settings-section " + (activeSection === "quality" ? "tuby-settings-translate-center" : "tuby-settings-translate-right") }, React__default.createElement("div", { onClick: function onClick() { return setActiveSection("main"); }, className: "tuby-settings-section-header" }, React__default.createElement(ChevronLeft, { className: "tuby-chevron" }), React__default.createElement("span", null, (internationalization == null ? void 0 : internationalization.settingsQuality) || "Quality")), React__default.createElement("div", { className: "tuby-settings-py" }, src.map(function (source, index) { return React__default.createElement("div", { key: source.quality, onClick: function onClick() { setQuality(index); setActiveSection("main"); }, className: "tuby-settings-item-2" }, quality === index ? React__default.createElement(Check, { className: "tuby-chevron" }) : React__default.createElement("div", { style: { width: 15, height: 15 } }), React__default.createElement("span", null, typeof source.quality === "number" ? source.quality + "p" : source.quality)); }))))); }; var SettingsModal = function SettingsModal(_ref) { var settingsActive = _ref.settingsActive, setSettingsActive = _ref.setSettingsActive, src = _ref.src, subtitles = _ref.subtitles, playbackSpeed = _ref.playbackSpeed, setPlaybackSpeed = _ref.setPlaybackSpeed, subtitleIndex = _ref.subtitleIndex, setSubtitleIndex = _ref.setSubtitleIndex, quality = _ref.quality, setQuality = _ref.setQuality, internationalization = _ref.internationalization; return React__default.createElement("div", { onClick: function onClick() { return setSettingsActive(false); }, className: "tuby-backdrop " + (settingsActive ? "tuby-show" : "") }, React__default.createElement("div", { onClick: function onClick(e) { return e.stopPropagation(); }, className: "tuby-modal" }, React__default.createElement("h1", null, (internationalization == null ? void 0 : internationalization.tooltipsSettings) || "Settings"), React__default.createElement("div", null, React__default.createElement("p", null, (internationalization == null ? void 0 : internationalization.settingsPlaybackSpeed) || "Speed"), React__default.createElement("select", { value: playbackSpeed * 4 - 1, onChange: function onChange(e) { return setPlaybackSpeed((+e.target.value + 1) / 4); } }, new Array(8).fill("").map(function (_, index) { return index === 3 ? (internationalization == null ? void 0 : internationalization.settingsPlaybackSpeedNormal) || "Normal" : (index + 1) / 4; }).map(function (item, index) { return React__default.createElement("option", { key: item, value: index }, item); }))), subtitles && React__default.createElement("div", null, React__default.createElement("p", null, (internationalization == null ? void 0 : internationalization.settingsSubtitles) || "Subtitles"), React__default.createElement("select", { value: subtitleIndex, onChange: function onChange(e) { return setSubtitleIndex(+e.target.value); } }, React__default.createElement("option", { value: -1 }, (internationalization == null ? void 0 : internationalization.settingsSubtitlesOff) || "Off"), subtitles.map(function (subtitle, index) { return React__default.createElement("option", { key: subtitle.lang, onClick: function onClick() { setSubtitleIndex(index); }, value: index }, subtitle.language); }))), typeof src === "object" && React__default.createElement("div", null, React__default.createElement("p", null, (internationalization == null ? void 0 : internationalization.settingsQuality) || "Quality"), React__default.createElement("select", { value: quality, onChange: function onChange(e) { return setQuality(+e.target.value); } }, src.map(function (source, index) { return React__default.createElement("option", { key: source.quality, onClick: function onClick() { setQuality(index); }, value: index }, typeof source.quality === "number" ? source.quality + "p" : source.quality); }))), React__default.createElement("div", { className: "tuby-modal-btn-container" }, React__default.createElement("button", { style: { padding: 5 }, onClick: function onClick() { return setSettingsActive(false); } }, (internationalization == null ? void 0 : internationalization.settingsModalOff) || "OK")))); }; var Subtitle = function Subtitle(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M5.55556 5C2.47222 5 0 7.57143 0 10.7143V39.2857C0 42.4286 2.47222 45 5.55556 45H44.4444C47.5 45 50 42.4286 50 39.2857V10.7143C50 7.57143 47.5 5 44.4444 5H5.55556ZM22.2222 22.1429H18.0556V20.7143H12.5V29.2857H18.0556V27.8571H22.2222V30.7143C22.2222 32.2857 20.9722 33.5714 19.4444 33.5714H11.1111C9.58333 33.5714 8.33333 32.2857 8.33333 30.7143V19.2857C8.33333 17.7143 9.58333 16.4286 11.1111 16.4286H19.4444C20.9722 16.4286 22.2222 17.7143 22.2222 19.2857V22.1429ZM41.6667 22.1429H37.5V20.7143H31.9444V29.2857H37.5V27.8571H41.6667V30.7143C41.6667 32.2857 40.4167 33.5714 38.8889 33.5714H30.5556C29.0278 33.5714 27.7778 32.2857 27.7778 30.7143V19.2857C27.7778 17.7143 29.0278 16.4286 30.5556 16.4286H38.8889C40.4167 16.4286 41.6667 17.7143 41.6667 19.2857V22.1429Z", fill: "white" })); }; var VolumeFull = function VolumeFull(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M0 33.5519H11.1111L25 47.805V2.19498L11.1111 16.4481H0V33.5519ZM30.5556 13.5975V36.4025C34.6667 34.4641 37.5 30.0456 37.5 25C37.5 20.0399 34.6667 15.707 30.5556 13.5975ZM30.5556 5.87229C38.5833 8.32383 44.4444 15.9635 44.4444 25C44.4444 34.0365 38.5833 41.6762 30.5556 44.1277V50C41.6944 47.4059 50 37.2007 50 25C50 12.7993 41.6944 2.59407 30.5556 0V5.87229Z", fill: "white" })); }; var VolumeHalf = function VolumeHalf(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M0 34.375H14.8148L33.3333 50V0L14.8148 15.625H0V34.375ZM40.7407 12.5V37.5C46.2222 35.375 50 30.5312 50 25C50 19.5625 46.2222 14.8125 40.7407 12.5Z", fill: "white" })); }; var VolumeMuted = function VolumeMuted(_ref) { var others = _extends({}, _ref); return React__default.createElement("svg", Object.assign({ viewBox: "0 0 50 50", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, others), React__default.createElement("path", { d: "M37.5 25.0139C37.5 20.0945 34.6667 15.8699 30.5556 13.8132V19.9555L37.3611 26.7649C37.4444 26.209 37.5 25.6253 37.5 25.0139ZM44.4444 25.0139C44.4444 27.6265 43.8889 30.0723 42.9444 32.3513L47.1389 36.5481C48.9722 33.1017 50 29.1829 50 25.0139C50 13.1184 41.6944 3.16843 30.5556 0.667039V6.36465C38.5833 8.75487 44.4444 16.2034 44.4444 25.0139V25.0139ZM3.52778 0L0 3.50195L13.1111 16.6481H0V33.3241H11.1111L25 47.2207V28.5158L36.8056 40.328C34.9444 41.7732 32.8611 42.9127 30.5556 43.6076V49.333C34.3889 48.4714 37.8611 46.6926 40.8056 44.3024L46.4722 50L50 46.4703L25 21.4564L3.55556 0H3.52778ZM24.9722 2.75153L19.1667 8.53252L24.9722 14.3413V2.77932V2.75153Z", fill: "white" })); }; var useEffectUpdate = function useEffectUpdate(cb, dependencies) { var updated = React.useRef(false); React.useEffect(function () { if (!updated.current) { updated.current = true; return; } cb(); // eslint-disable-next-line }, dependencies); }; var Player = function Player(_ref) { var _seekRef$current, _seekRef$current2, _seekRef$current3, _document2; var playerKey = _ref.playerKey, src = _ref.src, subtitles = _ref.subtitles, children = _ref.children, poster = _ref.poster, _ref$seekDuration = _ref.seekDuration, seekDuration = _ref$seekDuration === void 0 ? 10 : _ref$seekDuration, internationalization = _ref.internationalization, passedDownRef = _ref.playerRef, _ref$pictureInPicture = _ref.pictureInPicture, pictureInPicture = _ref$pictureInPicture === void 0 ? false : _ref$pictureInPicture, _ref$keyboardShortcut = _ref.keyboardShortcut, keyboardShortcut = _ref$keyboardShortcut === void 0 ? true : _ref$keyboardShortcut; var _useState = React.useState(0), quality = _useState[0], setQuality = _useState[1]; var _useState2 = React.useState(Number(localStorage.getItem("tuby-speed")) || 1), playbackSpeed = _useState2[0], setPlaybackSpeed = _useState2[1]; var _useState3 = React.useState(true), paused = _useState3[0], setPaused = _useState3[1]; var _useState4 = React.useState(false), onFullScreen = _useState4[0], setOnFullScreen = _useState4[1]; var _useState5 = React.useState(false), loading = _useState5[0], setLoading = _useState5[1]; var _useState6 = React.useState(false), settingsActive = _useState6[0], setSettingsActive = _useState6[1]; var _useState7 = React.useState(0), subtitleIndex = _useState7[0], setSubtitleIndex = _useState7[1]; var _useState8 = React.useState(0), currentTime = _useState8[0], setCurrentTime = _useState8[1]; var _useState9 = React.useState(0), duration = _useState9[0], setDuration = _useState9[1]; var _useState10 = React.useState(null), seekPreview = _useState10[0], setSeekPreview = _useState10[1]; var _useState11 = React.useState(false), loadedData = _useState11[0], setLoadedData = _useState11[1]; var _useState12 = React.useState(isNaN(parseInt(localStorage.getItem("tuby-volume"))) ? 100 : Number(localStorage.getItem("tuby-volume"))), volume = _useState12[0], setVolume = _useState12[1]; var _useState13 = React.useState(Boolean(Number(localStorage.getItem("tuby-muted")))), isMuted = _useState13[0], setIsMuted = _useState13[1]; var _useState14 = React.useState(true), hoverEnabled = _useState14[0], setHoverEnabled = _useState14[1]; var _useState15 = React.useState(false), pauseDidUpdate = _useState15[0], setPauseDidUpdate = _useState15[1]; var myRef = React.useRef(null); var playerRef = passedDownRef || myRef; var containerRef = React.useRef(null); var seekRef = React.useRef(null); var mouseDownRef = React.useRef(false); var timeoutRef = React.useRef(null); var fullscreenToggleButton = React.useRef(null); var pauseButton = React.useRef(null); var volumeButtonRef = React.useRef(null); var subtitleButtonRef = React.useRef(null); var seekTime = function seekTime(amount) { playerRef.current && (playerRef.current.currentTime += amount); }; var updateHoverState = function updateHoverState() { if (timeoutRef.current) clearTimeout(timeoutRef.current); setHoverEnabled(true); timeoutRef.current = setTimeout(function () { setHoverEnabled(false); }, 2000); }; var toggleSound = function toggleSound() { setIsMuted(!isMuted); setVolume(volume === 0 ? 100 : volume); }; var handleSeeking = function handleSeeking(offsetX) { if (!playerRef.current || !seekRef.current) return; var offset = (offsetX - seekRef.current.getBoundingClientRect().left) / seekRef.current.offsetWidth; var newTime = (Math.abs(offset) === Infinity || isNaN(offset) ? 0 : offset) * playerRef.current.duration; playerRef.current.currentTime = newTime; setCurrentTime(newTime); }; var handleSeekPreview = function handleSeekPreview(offsetX) { if (!playerRef.current || !seekRef.current) return; var left = seekRef.current.getBoundingClientRect().left; var offsetInPercentage = (offsetX - left) / seekRef.current.offsetWidth; offsetInPercentage = Math.abs(offsetInPercentage) === Infinity || isNaN(offsetInPercentage) ? 0 : offsetInPercentage; var offsetInPixel = offsetInPercentage * seekRef.current.offsetWidth; var newTime = offsetInPercentage * playerRef.current.duration; if (isNaN(newTime)) setSeekPreview(null); if (newTime < 0) newTime = 0; setSeekPreview({ time: Math.round(newTime), offset: offsetInPixel }); }; var listenMouseMoveSeeking = function listenMouseMoveSeeking() { var moveHandler = function moveHandler(e) { handleSeekPreview(e.clientX); if (mouseDownRef.current) { handleSeeking(e.clientX); } }; window.addEventListener("mousemove", moveHandler); var touchMoveHandler = function touchMoveHandler(e) { var _e$touches, _e$touches$; handleSeekPreview((_e$touches = e.touches) == null ? void 0 : (_e$touches$ = _e$touches[0]) == null ? void 0 : _e$touches$.pageX); if (mouseDownRef.current) { var _e$touches2, _e$touches2$; handleSeeking((_e$touches2 = e.touches) == null ? void 0 : (_e$touches2$ = _e$touches2[0]) == null ? void 0 : _e$touches2$.pageX); } }; window.addEventListener("touchmove", touchMoveHandler); window.addEventListener("mouseup", function () { window.removeEventListener("mousemove", moveHandler); mouseDownRef.current = false; setSeekPreview(null); }); window.addEventListener("touchend", function () { window.removeEventListener("touchmove", touchMoveHandler); mouseDownRef.current = false; setSeekPreview(null); }); }; var handleScreenClicked = function handleScreenClicked(e) { if (settingsActive) { setSettingsActive(false); } else { setPaused(function (prev) { return !prev; }); } if (e.detail === 2 && !isMobile()) { setOnFullScreen(function (prev) { return !prev; }); } }; useEffectUpdate(function () { var _document, _document$activeEleme; updateHoverState(); setPauseDidUpdate(true); if (paused) { var _playerRef$current; (_playerRef$current = playerRef.current) == null ? void 0 : _playerRef$current.pause(); } else { var _playerRef$current2; (_playerRef$current2 = playerRef.current) == null ? void 0 : _playerRef$current2.play(); } (_document = document) == null ? void 0 : (_document$activeEleme = _document.activeElement) == null ? void 0 : _document$activeEleme.blur(); }, [paused]); React.useEffect(function () { if (playerRef.current) { playerRef.current.muted = isMuted; playerRef.current.volume = isMuted ? 0 : volume / 100; } localStorage.setItem("tuby-volume", String(volume)); localStorage.setItem("tuby-muted", String(+isMuted)); }, [volume, isMuted]); React.useEffect(function () { var changeHandler = function changeHandler() { var doc = document; var fullscreenElement = doc.fullscreenElement || doc.webkitFullscreenElement || doc.webkitCurrentFullScreenElement || doc.mozFullScreenElement || doc.msFullscreenElement; if (fullscreenElement) { setOnFullScreen(true); } else { setOnFullScreen(false); } }; document.addEventListener("fullscreenchange", changeHandler); document.addEventListener("webkitfullscreenchange", changeHandler); document.addEventListener("mozfullscreenchange", changeHandler); document.addEventListener("MSFullscreenChange", changeHandler); var endFullScreenHandler = function endFullScreenHandler() { changeHandler(); setPaused(true); }; var player = playerRef.current; player == null ? void 0 : player.addEventListener("webkitendfullscreen", endFullScreenHandler); return function () { document.removeEventListener("fullscreenchange", changeHandler); document.removeEventListener("webkitfullscreenchange", changeHandler); document.removeEventListener("mozfullscreenchange", changeHandler); document.removeEventListener("MSFullscreenChange", changeHandler); player == null ? void 0 : player.removeEventListener("webkitendfullscreen", endFullScreenHandler); }; }, []); useEffectUpdate(function () { try { if (onFullScreen) { if (isMobile()) { var elem = playerRef.current; var requestFullScreen = elem.requestFullscreen || elem.webkitRequestFullscreen || elem.webkitRequestFullScreen || elem.webkitEnterFullscreen || elem.mozRequestFullScreen || elem.msRequestFullscreen; requestFullScreen == null ? void 0 : requestFullScreen.call(elem)["catch"](function (err) { return console.log(err); }); } else { var _elem = containerRef.current; var _requestFullScreen = _elem.requestFullscreen || _elem.webkitRequestFullscreen || _elem.webkitRequestFullScreen || _elem.webkitEnterFullscreen || _elem.mozRequestFullScreen || _elem.msRequestFullscreen; _requestFullScreen == null ? void 0 : _requestFullScreen.call(_elem)["catch"](function (err) { return console.log(err); }); } } else { var doc = document; var exitFullScreen = doc.exitFullscreen || doc.webkitExitFullscreen || doc.webkitCancelFullScreen || doc.mozCancelFullScreen || doc.msExitFullscreen; exitFullScreen == null ? void 0 : exitFullScreen.call(document)["catch"](function (err) { return console.log(err); }); } } catch (error) {} updateHoverState(); }, [onFullScreen]); useEffectUpdate(function () { if (!playerRef.current) return; playerRef.current.addEventListener("loadeddata", function () { if (playerRef.current) { if (currentTime) { playerRef.current.currentTime = currentTime; playerRef.current.play(); } } }, { once: true }); playerRef.current.addEventListener("error", function () { var _playerRef$current3; (_playerRef$current3 = playerRef.current) == null ? void 0 : _playerRef$current3.pause(); }); }, [quality]); React.useEffect(function () { if (!playerRef.current) return; localStorage.setItem("tuby-speed", String(playbackSpeed)); playerRef.current.playbackRate = playbackSpeed; }, [playbackSpeed]); React.useEffect(function () { var keyHandler = function keyHandler(e) { var _containerRef$current, _document$activeEleme2, _pauseButton$current, _fullscreenToggleButt, _volumeButtonRef$curr, _subtitleButtonRef$cu; if (!keyboardShortcut) return; if ((_containerRef$current = containerRef.current) != null && _containerRef$current.contains(document.activeElement)) (_document$activeEleme2 = document.activeElement) == null ? void 0 : _document$activeEleme2.blur(); // Pause if ((keyboardShortcut === true || keyboardShortcut.pause) && (e.key === " " || e.key === "k")) (_pauseButton$current = pauseButton.current) == null ? void 0 : _pauseButton$current.click(); // Rewind if ((keyboardShortcut === true || keyboardShortcut.rewind) && e.key === "ArrowLeft") seekTime(-seekDuration); // Forward if ((keyboardShortcut === true || keyboardShortcut.forward) && e.key === "ArrowRight") seekTime(seekDuration); // Full screen if ((keyboardShortcut === true || keyboardShortcut.fullScreen) && e.key === "f") (_fullscreenToggleButt = fullscreenToggleButton.current) == null ? void 0 : _fullscreenToggleButt.click(); // Mute if ((keyboardShortcut === true || keyboardShortcut.mute) && e.key === "m") (_volumeButtonRef$curr = volumeButtonRef.current) == null ? void 0 : _volumeButtonRef$curr.click(); // Subtitle if ((keyboardShortcut === true || keyboardShortcut.subtitle) && e.key === "c") (_subtitleButtonRef$cu = subtitleButtonRef.current) == null ? void 0 : _subtitleButtonRef$cu.click(); }; var spacePressHandler = function spacePressHandler(e) { if (keyboardShortcut && e.key === " ") e.preventDefault(); }; window.addEventListener("keyup", keyHandler); window.addEventListener("keydown", spacePressHandler); return function () { window.removeEventListener("keyup", keyHandler); window.removeEventListener("keydown", spacePressHandler); }; }, [seekDuration, keyboardShortcut]); var videoProps = { crossOrigin: "anonymous", playsInline: true, onClickCapture: handleScreenClicked, controls: false, src: typeof src === "string" ? src : src[quality].url, onWaiting: function onWaiting() { return setLoading(true); }, onPlaying: function onPlaying() { setLoading(false); setPaused(false); }, onLoadedData: function onLoadedData() { var _playerRef$current4; setLoadedData(true); setDuration(((_playerRef$current4 = playerRef.current) == null ? void 0 : _playerRef$current4.duration) || 0); var currentTime; if (playerKey) { currentTime = Number(localStorage.getItem(playerKey + "-time")); } else currentTime = 0; setCurrentTime(currentTime); playerRef.current && (playerRef.current.currentTime = currentTime); }, onTimeUpdate: function onTimeUpdate() { var _playerRef$current5, _playerRef$current6, _playerRef$current7; if (playerKey) localStorage.setItem(playerKey + "-time", String(((_playerRef$current5 = playerRef.current) == null ? void 0 : _playerRef$current5.currentTime) || 0)); setCurrentTime(((_playerRef$current6 = playerRef.current) == null ? void 0 : _playerRef$current6.currentTime) || 0); setDuration(((_playerRef$current7 = playerRef.current) == null ? void 0 : _playerRef$current7.duration) || 0); }, onEnded: function onEnded() { setPaused(true); }, onMouseMove: function onMouseMove() { return updateHoverState(); }, children: React__default.createElement(React__default.Fragment, null, subtitles && subtitles.length > 0 && subtitleIndex >= 0 && loadedData && React__default.createElement("track", { kind: "subtitles", srcLang: subtitles[subtitleIndex].lang, label: subtitles[subtitleIndex].language, src: subtitles[subtitleIndex].url, "default": true })) }; return React__default.createElement(React__default.Fragment, null, poster && !pauseDidUpdate && React__default.createElement("img", { src: poster, className: "tuby-poster", alt: "Tuby Poster" }), React__default.createElement("div", { ref: containerRef, className: "tuby-container " + (hoverEnabled ? "tuby-controls-hovered" : "") }, children ? children(playerRef, videoProps) : React__default.createElement("video", Object.assign({ ref: playerRef }, videoProps)), (!loadedData && pauseDidUpdate || loading && !paused) && React__default.createElement("div", { className: "tuby-center" }, React__default.createElement(CircularProgress, null)), paused && pauseDidUpdate && React__default.createElement("div", { className: "tuby-center", onClickCapture: handleScreenClicked }, React__default.createElement(PauseEffect, null)), !paused && pauseDidUpdate && React__default.createElement("div", { className: "tuby-center", onClickCapture: handleScreenClicked }, React__default.createElement(PlayEffect, null)), !pauseDidUpdate && React__default.createElement("div", { className: "tuby-center", onClickCapture: handleScreenClicked }, React__default.createElement(Play, { className: "tuby-icon-md" })), React__default.createElement("div", { onTouchEnd: function onTouchEnd() { return setHoverEnabled(true); }, onClick: function onClick() { return setHoverEnabled(true); }, onMouseEnter: function onMouseEnter() { return timeoutRef.current && clearTimeout(timeoutRef.current); }, className: "tuby-controls " + (paused || settingsActive ? "tuby-show" : "") }, React__default.createElement("div", { ref: seekRef, onMouseDown: function onMouseDown(e) { mouseDownRef.current = true; handleSeeking(e.clientX); listenMouseMoveSeeking(); }, onTouchStart: function onTouchStart(e) { var _e$touches3, _e$touches3$; mouseDownRef.current = true; handleSeeking((_e$touches3 = e.touches) == null ? void 0 : (_e$touches3$ = _e$touches3[0]) == null ? void 0 : _e$touches3$.pageX); listenMouseMoveSeeking(); }, onMouseMove: function onMouseMove(e) { return handleSeekPreview(e.clientX); }, onMouseLeave: function onMouseLeave() { return setSeekPreview(null); }, className: "tuby-seek" }, React__default.createElement("div", { className: "tuby-seek-bar" }, React__default.createElement("div", { style: { width: duration !== 0 ? Math.round(currentTime / duration * 1000) / 10 + "%" : 0 }, className: "tuby-seek-left" })), seekPreview !== null && React__default.createElement("div", { className: "tuby-seek-preview", style: { left: seekPreview.offset < 16 ? 0 : seekPreview.offset > (((_seekRef$current = seekRef.current) == null ? void 0 : _seekRef$current.offsetWidth) || 0) - 16 ? "auto" : seekPreview.offset, right: seekPreview.offset > (((_seekRef$current2 = seekRef.current) == null ? void 0 : _seekRef$current2.offsetWidth) || 0) - 16 ? 0 : "auto", transform: seekPreview.offset < 16 || seekPreview.offset > (((_seekRef$current3 = seekRef.current) == null ? void 0 : _seekRef$current3.offsetWidth) || 0) - 16 ? "none" : "translateX(-50%)" } }, formatVideoTime(seekPreview.time))), React__default.createElement("div", { className: "tuby-controls-main" }, React__default.createElement("div", { className: "tuby-controls-left" }, React__default.createElement("button", { ref: pauseButton, className: "tuby-center-container tuby-tooltips-left", "data-tuby-tooltips": paused ? (internationalization == null ? void 0 : internationalization.tooltipsPlay) || "Play (k)" : (internationalization == null ? void 0 : internationalization.tooltipsPause) || "Pause (k)", onClickCapture: function onClickCapture() { return setPaused(function (prev) { return !prev; }); } }, paused ? React__default.createElement(Play, { className: "tuby-icon-sm" }) : React__default.createElement(Pause, { className: "tuby-icon-sm" })), React__default.createElement("div", { className: "tuby-volume-container" }, React__default.createElement("button", { ref: volumeButtonRef, className: "tuby-center-container", "data-tuby-tooltips": isMuted || volume === 0 ? (internationalization == null ? void 0 : internationalization.tooltipsUnmute) || "Unmute (m)" : (internationalization == null ? void 0 : internationalization.tooltipsMute) || "Mute (m)", onClickCapture: toggleSound }, isMuted || volume === 0 ? React__default.createElement(VolumeMuted, { className: "tuby-icon-sm" }) : volume === 100 ? React__default.createElement(VolumeFull, { className: "tuby-icon-sm" }) : React__default.createElement(VolumeHalf, { className: "tuby-icon-sm" })), React__default.createElement("div", { className: "tuby-volume-wrapper" }, React__default.createElement("input", { className: "tuby-volume-slider", type: "range", min: 0, max: 100, value: isMuted ? 0 : volume, onChange: function onChange(e) { setVolume(+e.target.value); setIsMuted(+e.target.value === 0); } }), React__default.createElement("div", { className: "tuby-volume-left-bar", style: { width: isMuted ? 0 : volume * 0.52 } }))), React__default.createElement("div", { className: "tuby-time" }, formatVideoTime(currentTime), " / ", formatVideoTime(duration))), React__default.createElement("div", { className: "tuby-controls-right" }, Boolean(subtitles) && React__default.createElement("button", { ref: subtitleButtonRef, className: "tuby-center-container " + (subtitleIndex >= 0 ? "tuby-icon-underline" : ""), "data-tuby-tooltips": (internationalization == null ? void 0 : internationalization.tooltipsSubtitles) || "Subtitles (c)", onClickCapture: function onClickCapture() { return subtitleIndex >= 0 ? setSubtitleIndex(-1) : setSubtitleIndex(0); } }, React__default.createElement(Subtitle, { className: "tuby-icon-sm" })), React__default.createElement(ClickAwayListener, { onClickAway: function onClickAway() { return setSettingsActive(false); } }, function (ref) { return React__default.createElement("div", { ref: ref, style: { position: "relative" } }, React__default.createElement("button", Object.assign({ className: "tuby-center-container", onClickCapture: function onClickCapture() { return setSettingsActive(function (prev) { return !prev; }); } }, !settingsActive ? { "data-tuby-tooltips": (internationalization == null ? void 0 : internationalization.tooltipsSettings) || "Settings" } : {}), React__default.createElement(Cog, { className: "tuby-icon-sm" })), !isMobile() ? React__default.createElement(SettingsDialog, { settingsActive: settingsActive, setSettingsActive: setSettingsActive, src: src, subtitles: subtitles, playbackSpeed: playbackSpeed, setPlaybackSpeed: setPlaybackSpeed, subtitleIndex: subtitleIndex, setSubtitleIndex: setSubtitleI