UNPKG

vnetwork-player

Version:

A React component custom player support video m3u8, mp4

1,248 lines (1,221 loc) 50.1 kB
import React__default, { Component, createElement, useRef, useState, useEffect } from 'react'; function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } var ErrorBoundary = /*#__PURE__*/function (_Component) { _inheritsLoose(ErrorBoundary, _Component); function ErrorBoundary() { var _this; _this = _Component.apply(this, arguments) || this; _this.state = { hasError: false, message: "" }; return _this; } ErrorBoundary.getDerivedStateFromError = function getDerivedStateFromError(_) { // Update state so the next render will show the fallback UI. return { message: _.message, hasError: true }; }; var _proto = ErrorBoundary.prototype; _proto.componentDidCatch = function componentDidCatch(error, errorInfo) { console.error("Uncaught error:", error, errorInfo); }; _proto.render = function render() { if (this.state.hasError) { return React__default.createElement("div", { className: "video-container error-container" }, React__default.createElement("img", { className: "error-image", src: "https://raw.githubusercontent.com/an678-mhg/tiktok-clone/main/public/error.png" }), React__default.createElement("h1", { className: "text-sm font-semibold error-message line-clamp-1" }, React__default.createElement("span", { style: { color: "#fff" } }, "Error: "), " ", this.state.message)); } return this.props.children; }; return ErrorBoundary; }(Component); var VOLUME_KEY = "vnetwork-player-volume"; var MUTED_KEY = "vnetwork-player-muted"; var formatVideoTime = function formatVideoTime(seconds) { try { var date = new Date(0); date.setSeconds(seconds); var time = date.toISOString().slice(11, 19); var result = time.startsWith("00:0") ? time.slice(4) : time.startsWith("00") ? time.slice(3) : time.length === 8 && time.startsWith("0") ? time.slice(1) : time; return result; } catch (error) { return "0:00"; } }; var playSpeedOptions = [{ label: "0.25x", value: 0.25 }, { label: "0.5x", value: 0.5 }, { label: "0.75x", value: 0.75 }, { label: "1x", value: 1 }, { label: "1.25x", value: 1.25 }, { label: "1.5x", value: 1.5 }, { label: "2x", value: 2 }]; var removeSearchParams = function removeSearchParams(url) { var _url$split; return (_url$split = url.split("?")) == null ? void 0 : _url$split[0]; }; // icon:play | Entypo http://entypo.com/ | Daniel Bruce function IconPlay(props) { return createElement("svg", Object.assign({ viewBox: "0 0 500 1000", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M486 474c9.333 6.667 14 15.333 14 26 0 9.333-4.667 17.333-14 24L58 790c-16 10.667-29.667 12.667-41 6-11.333-6.667-17-20-17-40V242c0-20 5.667-33.333 17-40 11.333-6.667 25-4.667 41 6l428 266" })); } // icon:bx-fullscreen | Boxicons https://boxicons.com/ | Atisa function IconFullscreen(props) { return createElement("svg", Object.assign({ viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M5 5h5V3H3v7h2zm5 14H5v-5H3v7h7zm11-5h-2v5h-5v2h7zm-2-4h2V3h-7v2h5z" })); } // icon:fullscreen-exit | Material Design Icons https://materialdesignicons.com/ | Austin Andrews function IconFullscreenExit(props) { return createElement("svg", Object.assign({ viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M14 14h5v2h-3v3h-2v-5m-9 0h5v5H8v-3H5v-2m3-9h2v5H5V8h3V5m11 3v2h-5V5h2v3h3z" })); } // icon:pause | Material Design Icons https://materialdesignicons.com/ | Austin Andrews function IconPause(props) { return createElement("svg", Object.assign({ viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M14 19h4V5h-4M6 19h4V5H6v14z" })); } // icon:settings-sharp | Ionicons https://ionicons.com/ | Ionic Framework function IconSettingsSharp(props) { return createElement("svg", Object.assign({ viewBox: "0 0 512 512", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M256 176a80 80 0 1080 80 80.24 80.24 0 00-80-80zm172.72 80a165.53 165.53 0 01-1.64 22.34l48.69 38.12a11.59 11.59 0 012.63 14.78l-46.06 79.52a11.64 11.64 0 01-14.14 4.93l-57.25-23a176.56 176.56 0 01-38.82 22.67l-8.56 60.78a11.93 11.93 0 01-11.51 9.86h-92.12a12 12 0 01-11.51-9.53l-8.56-60.78A169.3 169.3 0 01151.05 393L93.8 416a11.64 11.64 0 01-14.14-4.92L33.6 331.57a11.59 11.59 0 012.63-14.78l48.69-38.12A174.58 174.58 0 0183.28 256a165.53 165.53 0 011.64-22.34l-48.69-38.12a11.59 11.59 0 01-2.63-14.78l46.06-79.52a11.64 11.64 0 0114.14-4.93l57.25 23a176.56 176.56 0 0138.82-22.67l8.56-60.78A11.93 11.93 0 01209.94 26h92.12a12 12 0 0111.51 9.53l8.56 60.78A169.3 169.3 0 01361 119l57.2-23a11.64 11.64 0 0114.14 4.92l46.06 79.52a11.59 11.59 0 01-2.63 14.78l-48.69 38.12a174.58 174.58 0 011.64 22.66z" })); } // icon:volume-high | Ionicons https://ionicons.com/ | Ionic Framework function IconVolumeHigh(props) { return createElement("svg", Object.assign({ viewBox: "0 0 512 512", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M232 416a23.88 23.88 0 01-14.2-4.68 8.27 8.27 0 01-.66-.51L125.76 336H56a24 24 0 01-24-24V200a24 24 0 0124-24h69.75l91.37-74.81a8.27 8.27 0 01.66-.51A24 24 0 01256 120v272a24 24 0 01-24 24zm-106.18-80zm-.27-159.86zM320 336a16 16 0 01-14.29-23.19c9.49-18.87 14.3-38 14.3-56.81 0-19.38-4.66-37.94-14.25-56.73a16 16 0 0128.5-14.54C346.19 208.12 352 231.44 352 256c0 23.86-6 47.81-17.7 71.19A16 16 0 01320 336z" }), createElement("path", { d: "M368 384a16 16 0 01-13.86-24C373.05 327.09 384 299.51 384 256c0-44.17-10.93-71.56-29.82-103.94a16 16 0 0127.64-16.12C402.92 172.11 416 204.81 416 256c0 50.43-13.06 83.29-34.13 120a16 16 0 01-13.87 8z" }), createElement("path", { d: "M416 432a16 16 0 01-13.39-24.74C429.85 365.47 448 323.76 448 256c0-66.5-18.18-108.62-45.49-151.39a16 16 0 1127-17.22C459.81 134.89 480 181.74 480 256c0 64.75-14.66 113.63-50.6 168.74A16 16 0 01416 432z" })); } // icon:volume-mute | Ionicons https://ionicons.com/ | Ionic Framework function IconVolumeMute(props) { return createElement("svg", Object.assign({ viewBox: "0 0 512 512", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeMiterlimit: 10, strokeWidth: 32, d: "M416 432L64 80" }), createElement("path", { d: "M243.33 98.86a23.89 23.89 0 00-25.55 1.82l-.66.51-28.52 23.35a8 8 0 00-.59 11.85l54.33 54.33a8 8 0 0013.66-5.66v-64.49a24.51 24.51 0 00-12.67-21.71zM251.33 335.29L96.69 180.69A16 16 0 0085.38 176H56a24 24 0 00-24 24v112a24 24 0 0024 24h69.76l92 75.31a23.9 23.9 0 0025.87 1.69A24.51 24.51 0 00256 391.45v-44.86a16 16 0 00-4.67-11.3zM352 256c0-24.56-5.81-47.87-17.75-71.27a16 16 0 10-28.5 14.55C315.34 218.06 320 236.62 320 256q0 4-.31 8.13a8 8 0 002.32 6.25l14.36 14.36a8 8 0 0013.55-4.31A146 146 0 00352 256zM416 256c0-51.18-13.08-83.89-34.18-120.06a16 16 0 00-27.64 16.12C373.07 184.44 384 211.83 384 256c0 23.83-3.29 42.88-9.37 60.65a8 8 0 001.9 8.26L389 337.4a8 8 0 0013.13-2.79C411 311.76 416 287.26 416 256z" }), createElement("path", { d: "M480 256c0-74.25-20.19-121.11-50.51-168.61a16 16 0 10-27 17.22C429.82 147.38 448 189.5 448 256c0 46.19-8.43 80.27-22.43 110.53a8 8 0 001.59 9l11.92 11.92a8 8 0 0012.92-2.16C471.6 344.9 480 305 480 256z" })); } // icon:picture-in-picture-fill | Remix Icon https://remixicon.com/ | Remix Design function IconPictureInPictureFill(props) { return createElement("svg", Object.assign({ viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { fill: "none", d: "M0 0h24v24H0z" }), createElement("path", { d: "M21 3a1 1 0 011 1v7h-2V5H4v14h6v2H3a1 1 0 01-1-1V4a1 1 0 011-1h18zm0 10a1 1 0 011 1v6a1 1 0 01-1 1h-8a1 1 0 01-1-1v-6a1 1 0 011-1h8z" })); } // icon:chevron-left | Bootstrap https://icons.getbootstrap.com/ | Bootstrap function IconChevronLeft(props) { return createElement("svg", Object.assign({ fill: "currentColor", viewBox: "0 0 16 16", height: "1em", width: "1em" }, props), createElement("path", { fillRule: "evenodd", d: "M11.354 1.646a.5.5 0 010 .708L5.707 8l5.647 5.646a.5.5 0 01-.708.708l-6-6a.5.5 0 010-.708l6-6a.5.5 0 01.708 0z" })); } // icon:chevron-right | Bootstrap https://icons.getbootstrap.com/ | Bootstrap function IconChevronRight(props) { return createElement("svg", Object.assign({ fill: "currentColor", viewBox: "0 0 16 16", height: "1em", width: "1em" }, props), createElement("path", { fillRule: "evenodd", d: "M4.646 1.646a.5.5 0 01.708 0l6 6a.5.5 0 010 .708l-6 6a.5.5 0 01-.708-.708L10.293 8 4.646 2.354a.5.5 0 010-.708z" })); } // icon:speedtest | Simple Icons https://simpleicons.org | SimpleIcons.org function IconSpeedtest(props) { return createElement("svg", Object.assign({ viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M11.628 16.186l-2.047-2.14 6.791-5.953 1.21 1.302zm8.837 6.047c2.14-2.14 3.535-5.117 3.535-8.466 0-6.604-5.395-12-12-12s-12 5.396-12 12c0 3.35 1.302 6.326 3.535 8.466l1.674-1.675c-1.767-1.767-2.79-4.093-2.79-6.79A9.568 9.568 0 0112 4.185a9.568 9.568 0 019.581 9.581c0 2.605-1.116 5.024-2.79 6.791z" })); } // icon:quality-high | Material Design Icons https://materialdesignicons.com/ | Austin Andrews function IconQualityHigh(props) { return createElement("svg", Object.assign({ viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M14.5 13.5h2v-3h-2M18 14a1 1 0 01-1 1h-.75v1.5h-1.5V15H14a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1m-7 5H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11m8-5H5c-1.11 0-2 .89-2 2v12a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2z" })); } // icon:subtitles | Material Design Icons https://materialdesignicons.com/ | Austin Andrews function IconSubtitles(props) { return createElement("svg", Object.assign({ viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em" }, props), createElement("path", { d: "M20 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V6a2 2 0 00-2-2M4 12h4v2H4v-2m10 6H4v-2h10v2m6 0h-4v-2h4v2m0-4H10v-2h10v2z" })); } // icon:check-lg | Bootstrap https://icons.getbootstrap.com/ | Bootstrap function IconCheckLg(props) { return createElement("svg", Object.assign({ fill: "currentColor", viewBox: "0 0 16 16", height: "1em", width: "1em" }, props), createElement("path", { d: "M12.736 3.97a.733.733 0 011.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 01-1.065.02L3.217 8.384a.757.757 0 010-1.06.733.733 0 011.047 0l3.052 3.093 5.4-6.425a.247.247 0 01.02-.022z" })); } var MainSettings = function MainSettings(_ref) { var setSettingsType = _ref.setSettingsType, currentQuality = _ref.currentQuality, currentSpeed = _ref.currentSpeed, currentSubtitle = _ref.currentSubtitle, haveQuality = _ref.haveQuality, haveSubtitle = _ref.haveSubtitle; return React__default.createElement("div", { className: "opacity-animation settings-content scale-in-bl w-full" }, React__default.createElement("div", { onClick: function onClick() { return setSettingsType("playspeed"); }, className: "main-settings cursor-pointer " }, React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement(IconSpeedtest, { fontSize: 20, className: "mr-3" }), React__default.createElement("p", { className: "text-sm font-semibold" }, "Play speed")), React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement("p", { className: "text-sm font-semibold line-clamp-1 mr-3" }, currentSpeed), React__default.createElement(IconChevronRight, { fontSize: 20 }))), haveQuality && React__default.createElement("div", { onClick: function onClick() { return setSettingsType("quality"); }, className: "main-settings-content justify-between cursor-pointer p-2 " }, React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement(IconQualityHigh, { fontSize: 22, className: "mr-3" }), React__default.createElement("p", { className: "text-sm font-semibold" }, "Quality")), React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement("p", { className: "text-sm font-semibold line-clamp-1 mr-3" }, currentQuality), React__default.createElement(IconChevronRight, { fontSize: 20 }))), haveSubtitle && React__default.createElement("div", { onClick: function onClick() { return setSettingsType("subtitle"); }, className: "main-settings-content justify-between cursor-pointer p-2" }, React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement(IconSubtitles, { fontSize: 22, className: "mr-3" }), React__default.createElement("p", { className: "text-sm font-semibold" }, "Subtitle")), React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement("p", { className: "text-sm font-semibold line-clamp-1 mr-3" }, currentSubtitle), React__default.createElement(IconChevronRight, { fontSize: 20 })))); }; var PlaySpeedSettings = function PlaySpeedSettings(_ref) { var setSettingsType = _ref.setSettingsType, currentPlaySpeed = _ref.currentPlaySpeed, handleChangePlaySpeed = _ref.handleChangePlaySpeed; return React__default.createElement("div", { className: "opacity-animation settings-content scale-in-bl w-full" }, React__default.createElement("div", { onClick: function onClick() { return setSettingsType("main"); }, className: "main-settings-content p-2 cursor-pointer" }, React__default.createElement(IconChevronLeft, { fontSize: 20, className: "mr-3" }), React__default.createElement("p", { className: "text-sm font-semibold" }, "Play speed")), React__default.createElement("div", null, playSpeedOptions == null ? void 0 : playSpeedOptions.map(function (item, index) { return React__default.createElement("div", { className: "p-2 text-sm font-semibold main-settings-content cursor-pointer", key: item == null ? void 0 : item.value, onClick: function onClick() { return handleChangePlaySpeed(index, item == null ? void 0 : item.value); } }, React__default.createElement("div", { className: "icon-20px mr-3" }, currentPlaySpeed === index && React__default.createElement(IconCheckLg, { fontSize: 20 })), React__default.createElement("p", null, item == null ? void 0 : item.label)); }))); }; var QualitySettings = function QualitySettings(_ref) { var setSettingsType = _ref.setSettingsType, source = _ref.source, currentSource = _ref.currentSource, handleChangeSource = _ref.handleChangeSource; return React__default.createElement("div", { className: "overflow-y-auto opacity-animation settings-content scale-in-bl w-full" }, React__default.createElement("div", { onClick: function onClick() { return setSettingsType("main"); }, className: "main-settings-content p-2 cursor-pointer" }, React__default.createElement(IconChevronLeft, { fontSize: 20, className: "mr-3" }), React__default.createElement("p", { className: "text-sm font-semibold" }, "Quality")), React__default.createElement("div", null, source == null ? void 0 : source.map(function (item, index) { return React__default.createElement("div", { onClick: function onClick() { return handleChangeSource(index); }, className: "p-2 text-sm font-semibold main-settings-content cursor-pointer", key: item == null ? void 0 : item.url }, React__default.createElement("div", { className: "icon-20px mr-3" }, currentSource === index && React__default.createElement(IconCheckLg, { fontSize: 20 })), React__default.createElement("p", null, item == null ? void 0 : item.label)); }))); }; var SubtitleSettings = function SubtitleSettings(_ref) { var currentSubtitle = _ref.currentSubtitle, handleChangeSubtitle = _ref.handleChangeSubtitle, setSettingsType = _ref.setSettingsType, subtitle = _ref.subtitle, handleTurnOffSubtitle = _ref.handleTurnOffSubtitle; return React__default.createElement("div", { className: "overflow-y-auto opacity-animation settings-content scale-in-bl w-full" }, React__default.createElement("div", { onClick: function onClick() { return setSettingsType("main"); }, className: "main-settings-content p-2 cursor-pointer" }, React__default.createElement(IconChevronLeft, { fontSize: 20, className: "mr-3" }), React__default.createElement("p", { className: "text-sm font-semibold" }, "Subtitle")), React__default.createElement("div", null, React__default.createElement("div", { onClick: handleTurnOffSubtitle, className: "p-2 text-sm font-semibold main-settings-content cursor-pointer" }, React__default.createElement("div", { className: "icon-20px mr-3" }, currentSubtitle === null && React__default.createElement(IconCheckLg, { fontSize: 20 })), React__default.createElement("p", null, "Off")), subtitle == null ? void 0 : subtitle.map(function (item, index) { return React__default.createElement("div", { onClick: function onClick() { return handleChangeSubtitle(index); }, className: "p-2 text-sm font-semibold main-settings-content cursor-pointer", key: item == null ? void 0 : item.url }, React__default.createElement("div", { className: "icon-20px mr-3" }, currentSubtitle === index && React__default.createElement(IconCheckLg, { fontSize: 20 })), React__default.createElement("p", null, item == null ? void 0 : item.lang)); }))); }; var CircularProgress = function CircularProgress() { return React__default.createElement("svg", { viewBox: "25 25 50 50", className: "loading" }, React__default.createElement("circle", { cx: "50", cy: "50", r: "20" })); }; var Slider = function Slider(_ref) { var value = _ref.value, onChange = _ref.onChange, _ref$min = _ref.min, min = _ref$min === void 0 ? 0 : _ref$min, _ref$max = _ref.max, max = _ref$max === void 0 ? 100 : _ref$max, _ref$className = _ref.className, className = _ref$className === void 0 ? "" : _ref$className, _ref$color = _ref.color, color = _ref$color === void 0 ? "#ef4444" : _ref$color, _ref$live = _ref.live, live = _ref$live === void 0 ? false : _ref$live, onDragEnd = _ref.onDragEnd, onPreview = _ref.onPreview, _ref$children = _ref.children, children = _ref$children === void 0 ? React__default.createElement(React__default.Fragment, null) : _ref$children; var sliderRef = useRef(null); var _useState = useState(false), isDragging = _useState[0], setIsDragging = _useState[1]; var handleCalculateValue = function handleCalculateValue(clientX) { if (!sliderRef.current || live) return; var rect = sliderRef.current.getBoundingClientRect(); var percent = (clientX - rect.left) / rect.width; var newValue = Math.min(Math.max(percent * (max - min) + min, min), max); return newValue; }; var handleSliderChange = function handleSliderChange(clientX) { var newValue = handleCalculateValue(clientX); onChange(newValue); }; var handlePreview = function handlePreview(clientX) { var _sliderRef$current; var newValue = handleCalculateValue(clientX); var rect = (_sliderRef$current = sliderRef.current) == null ? void 0 : _sliderRef$current.getBoundingClientRect(); var left = rect == null ? void 0 : rect.left; var width = rect == null ? void 0 : rect.width; var percent = (clientX - left) / width; onPreview && onPreview(newValue, percent); }; var handleMove = function handleMove(clientX) { if (isDragging) handleSliderChange(clientX); }; var handleMoveEnd = function handleMoveEnd() { setIsDragging(false); onDragEnd && onDragEnd(); document.body.style.userSelect = "auto"; }; var handleStart = function handleStart(clientX) { if (!live) { setIsDragging(true); handleSliderChange(clientX); } document.body.style.userSelect = "none"; }; useEffect(function () { if (!isDragging) return; var handleMouseMove = function handleMouseMove(e) { return handleMove(e.clientX); }; var handleTouchMove = function handleTouchMove(e) { return handleMove(e.touches[0].clientX); }; document.addEventListener("mousemove", handleMouseMove); document.addEventListener("touchmove", handleTouchMove); document.addEventListener("mouseup", handleMoveEnd); document.addEventListener("touchend", handleMoveEnd); return function () { document.removeEventListener("mousemove", handleMouseMove); document.removeEventListener("touchmove", handleTouchMove); document.removeEventListener("mouseup", handleMoveEnd); document.removeEventListener("touchend", handleMoveEnd); onDragEnd && onDragEnd(); }; }, [isDragging]); var percentValue = (value - min) / (max - min) * 100; return React__default.createElement("div", { ref: sliderRef, className: "progress-vnet " + className, onClick: function onClick(e) { return handleSliderChange(e.clientX); }, onMouseDown: function onMouseDown(e) { return handleStart(e.clientX); }, onTouchStart: function onTouchStart(e) { return handleStart(e.touches[0].clientX); }, onMouseMove: function onMouseMove(e) { return handlePreview(e.clientX); }, onMouseLeave: function onMouseLeave() { onPreview && onPreview(null, null); onDragEnd && onDragEnd(); } }, React__default.createElement("div", { className: "progress-gray" }, React__default.createElement("div", { className: "progress-main", style: { width: live ? "100%" : percentValue + "%", backgroundColor: color } })), children, !live && React__default.createElement("div", { className: "progress-dot", style: { backgroundColor: color, left: "calc(" + percentValue + "% - 5px)" } })); }; var _excluded = ["color", "subtitle", "playerRef", "className", "poster", "source", "live", "autoPlay", "Hls"]; var Player = function Player(_ref) { var _sourceMulti$currentS, _playSpeedOptions$cur, _subtitle$currentSubt3, _playerRef$current11, _playerRef$current12; var color = _ref.color, subtitle = _ref.subtitle, passedRef = _ref.playerRef, className = _ref.className, poster = _ref.poster, src = _ref.source, live = _ref.live, autoPlay = _ref.autoPlay, Hls = _ref.Hls, props = _objectWithoutPropertiesLoose(_ref, _excluded); // @ts-ignore var hlsRef = useRef(null); if (!src) { var _hlsRef$current; if (hlsRef.current) (_hlsRef$current = hlsRef.current) == null || _hlsRef$current.destroy(); throw new Error("Missing src props"); } var source = src; var videoContainerRef = useRef(null); var myRef = useRef(null); var timeoutSeek = useRef(null); var _useState = useState(0), currentSource = _useState[0], setCurrentSource = _useState[1]; var _useState2 = useState([]), sourceMulti = _useState2[0], setSourceMulti = _useState2[1]; var _useState3 = useState(3), currentPlaySpeed = _useState3[0], setCurrePlaySpeed = _useState3[1]; var _useState4 = useState(true), showControl = _useState4[0], setShowControl = _useState4[1]; var _useState5 = useState(false), play = _useState5[0], setPlay = _useState5[1]; var _useState6 = useState(0), currentTime = _useState6[0], setCurrentTime = _useState6[1]; var _useState7 = useState(false), fullScreen = _useState7[0], setFullScreen = _useState7[1]; var _useState8 = useState(JSON.parse(localStorage.getItem(MUTED_KEY)) || false), muted = _useState8[0], setMuted = _useState8[1]; var _useState9 = useState(true), loading = _useState9[0], setLoading = _useState9[1]; var _useState10 = useState(false), showSettings = _useState10[0], setShowSettings = _useState10[1]; var _useState11 = useState("main"), settingsType = _useState11[0], setSettingsType = _useState11[1]; var _useState12 = useState(0), currentSubtitle = _useState12[0], setCurrentSubtitle = _useState12[1]; var _useState13 = useState(Number(localStorage.getItem(VOLUME_KEY)) || 100), volume = _useState13[0], setVolume = _useState13[1]; var _useState14 = useState(false), seeking = _useState14[0], setSeeking = _useState14[1]; var _useState15 = useState({ time: null, left: null }), previewTime = _useState15[0], setPreviewTime = _useState15[1]; var defaultColor = color || "#ef4444"; var playerRef = passedRef || myRef; var handlePlayPause = function handlePlayPause() { setPlay(function (prev) { return !prev; }); }; var handleFullScreen = function handleFullScreen() { var _document; if (!(videoContainerRef != null && videoContainerRef.current)) return; var element = videoContainerRef.current; // Thoát khỏi chế độ PiP nếu đang bật if ((_document = document) != null && _document.pictureInPictureElement) { var _document2; (_document2 = document) == null || _document2.exitPictureInPicture()["catch"](console.error); } // Kiểm tra và xử lý chế độ toàn màn hình if (!document.fullscreenElement && // @ts-ignore !document.mozFullScreenElement && // @ts-ignore !document.webkitFullscreenElement && // @ts-ignore !document.msFullscreenElement) { // Bật chế độ toàn màn hình if (element.requestFullscreen) { element.requestFullscreen(); // @ts-ignore } else if (element.mozRequestFullScreen) { // Firefox // @ts-ignore element.mozRequestFullScreen(); // @ts-ignore } else if (element.webkitRequestFullscreen) { // Chrome, Safari và Opera // @ts-ignore element.webkitRequestFullscreen(); // @ts-ignore } else if (element.msRequestFullscreen) { // Internet Explorer/Edge // @ts-ignore element.msRequestFullscreen(); } } else { // Thoát chế độ toàn màn hình if (document.exitFullscreen) { document.exitFullscreen(); // @ts-ignore } else if (document.mozCancelFullScreen) { // Firefox // @ts-ignore document.mozCancelFullScreen(); // @ts-ignore } else if (document.webkitExitFullscreen) { // Chrome, Safari và Opera // @ts-ignore document.webkitExitFullscreen(); // @ts-ignore } else if (document.msExitFullscreen) { // Internet Explorer/Edge // @ts-ignore document.msExitFullscreen(); } } }; var handleTimeUpdate = function handleTimeUpdate() { var _playerRef$current; if (seeking) return; setCurrentTime((playerRef == null || (_playerRef$current = playerRef.current) == null ? void 0 : _playerRef$current.currentTime) || 0); }; var handleToggleMuted = function handleToggleMuted() { setMuted(function (prev) { return !prev; }); localStorage.setItem(MUTED_KEY, JSON.stringify(!muted)); }; var handleChangePlaySpeed = function handleChangePlaySpeed(index, value) { setCurrePlaySpeed(index); if (playerRef !== null && (playerRef == null ? void 0 : playerRef.current) !== null) { playerRef.current.playbackRate = value; } setShowSettings(false); setSettingsType("main"); }; var handleChangeSource = function handleChangeSource(index) { var _playerRef$current2; if (!(playerRef != null && playerRef.current)) return; if (currentSource === index) return; setCurrentSource(index); var existTrack = playerRef == null || (_playerRef$current2 = playerRef.current) == null ? void 0 : _playerRef$current2.querySelector("track"); if (existTrack) existTrack.remove(); if (hlsRef != null && hlsRef.current) { var _sourceMulti$index; var hls = hlsRef == null ? void 0 : hlsRef.current; hls.startLevel = index; hls.loadSource(sourceMulti == null || (_sourceMulti$index = sourceMulti[index]) == null ? void 0 : _sourceMulti$index.url); hls.startLoad(); } else { var _playerRef$current3, _sourceMulti$index2; playerRef == null || (_playerRef$current3 = playerRef.current) == null || _playerRef$current3.setAttribute("src", sourceMulti == null || (_sourceMulti$index2 = sourceMulti[index]) == null ? void 0 : _sourceMulti$index2.url); } var tmpCurrentTime = currentTime; setCurrentTime(tmpCurrentTime); if (playerRef !== null && (playerRef == null ? void 0 : playerRef.current) !== null) { playerRef.current.currentTime = tmpCurrentTime; playerRef.current.play(); } setShowSettings(false); setSettingsType("main"); }; var handleLoadVideoMp4 = function handleLoadVideoMp4() { var _hlsRef$current2; if (hlsRef != null && hlsRef.current) hlsRef == null || (_hlsRef$current2 = hlsRef.current) == null || _hlsRef$current2.destroy(); setSourceMulti(typeof source === "string" ? [{ label: "Default", url: source }] : source); if (typeof source === "string") { var _playerRef$current4; playerRef == null || (_playerRef$current4 = playerRef.current) == null || _playerRef$current4.setAttribute("src", source); } else { var _playerRef$current5, _source; // @ts-ignore setCurrentSource((source == null ? void 0 : source.length) - 1); playerRef == null || (_playerRef$current5 = playerRef.current) == null || _playerRef$current5.setAttribute("src", // @ts-ignore source == null || (_source = source[(source == null ? void 0 : source.length) - 1]) == null ? void 0 : _source.url); } }; var handleLoadVideoM3u8 = function handleLoadVideoM3u8() { if (!Hls) throw Error("To use video type m3u8 try install `npm i hls.js` and pass props Hls"); if (!(playerRef != null && playerRef.current)) return; // @ts-ignore if (!Hls.isSupported()) throw Error("Not support hls"); if (hlsRef != null && hlsRef.current) { var _hlsRef$current3; hlsRef == null || (_hlsRef$current3 = hlsRef.current) == null || _hlsRef$current3.destroy(); } // @ts-ignore hlsRef.current = new Hls(); var hls = hlsRef == null ? void 0 : hlsRef.current; // @ts-ignore hls.on(Hls.Events.MANIFEST_PARSED, function (_, data) { var _data$levels, _data$levels2, _data$levels3, _data$levels4; if (typeof source !== "string") { // @ts-ignore return setSourceMulti(source); } if ((data == null || (_data$levels = data.levels) == null ? void 0 : _data$levels.length) !== (sourceMulti == null ? void 0 : sourceMulti.length) && (sourceMulti == null ? void 0 : sourceMulti.length) !== 0) return; setSourceMulti( // @ts-ignore data == null || (_data$levels2 = data.levels) == null ? void 0 : _data$levels2.map(function (item) { var _item$url; return { label: (item == null ? void 0 : item.height) + "p", url: item == null || (_item$url = item.url) == null ? void 0 : _item$url[0] }; })); setCurrentSource((data == null || (_data$levels3 = data.levels) == null ? void 0 : _data$levels3.length) - 1); hls.startLevel = (data == null || (_data$levels4 = data.levels) == null ? void 0 : _data$levels4.length) - 1; }); hls.attachMedia(playerRef == null ? void 0 : playerRef.current); if (typeof source === "string") { hls.loadSource(source); } else { var _source$currentSource; // @ts-ignore hls.loadSource(source == null || (_source$currentSource = source[currentSource]) == null ? void 0 : _source$currentSource.url); } hls.startLoad(); }; var handleChangeSubtitle = function handleChangeSubtitle(index) { setCurrentSubtitle(index); setShowSettings(false); setSettingsType("main"); }; var handleVideoPicture = function handleVideoPicture() { if (!playerRef.current) return; // Kiểm tra hỗ trợ PiP var videoElement = playerRef.current; if (!document.pictureInPictureEnabled && !("webkitSetPresentationMode" in videoElement) && !("mozRequestPictureInPicture" in videoElement)) { console.warn("Picture-in-Picture không được hỗ trợ trong trình duyệt này."); return; } // Xử lý PiP cho các trình duyệt khác nhau if (document.pictureInPictureElement) { document.exitPictureInPicture()["catch"](console.error); } else if (document.pictureInPictureEnabled) { videoElement.requestPictureInPicture()["catch"](console.error); } else if ("webkitSetPresentationMode" in videoElement) { // Safari var safariVideo = videoElement; if (safariVideo.webkitPresentationMode === "picture-in-picture") { safariVideo.webkitSetPresentationMode("inline"); } else { safariVideo.webkitSetPresentationMode("picture-in-picture"); } } else if ("mozRequestPictureInPicture" in videoElement) { // Firefox var firefoxVideo = videoElement; firefoxVideo.mozRequestPictureInPicture()["catch"](console.error); } }; var handleVolumeChange = function handleVolumeChange(volume) { if (playerRef !== null && (playerRef == null ? void 0 : playerRef.current) !== null) { setSeeking(true); setVolume(volume); localStorage.setItem(VOLUME_KEY, JSON.stringify(volume)); playerRef.current.volume = volume / 100; } }; var handleTurnOffSubtitle = function handleTurnOffSubtitle() { var _playerRef$current6; setCurrentSubtitle(null); var track = playerRef == null || (_playerRef$current6 = playerRef.current) == null ? void 0 : _playerRef$current6.querySelector("track"); if (track) { track.remove(); } setShowSettings(false); setSettingsType("main"); }; var handleChangeTime = function handleChangeTime(time) { if (playerRef !== null && (playerRef == null ? void 0 : playerRef.current) !== null) { setSeeking(true); setCurrentTime(time); if (timeoutSeek.current) { clearTimeout(timeoutSeek.current); } timeoutSeek.current = setTimeout(function () { // @ts-ignore playerRef.current.currentTime = time; }, 100); } }; var handleDragEnd = function handleDragEnd() { setPreviewTime({ time: null, left: null }); setSeeking(false); }; useEffect(function () { if (playerRef !== null && (playerRef == null ? void 0 : playerRef.current) !== null) { playerRef.current.volume = (volume <= 0 ? 0 : volume) / 100; } }, [volume]); useEffect(function () { var timeout; if (!play || !showControl || showSettings || seeking || previewTime != null && previewTime.left) { return; } timeout = setTimeout(function () { setShowControl(false); }, 3000); return function () { timeout && clearTimeout(timeout); }; }, [showControl, play, showSettings, seeking]); useEffect(function () { var handleFullScreenChange = function handleFullScreenChange() { setFullScreen(function (prev) { return !prev; }); }; document.addEventListener("fullscreenchange", handleFullScreenChange); return function () { document.removeEventListener("fullscreenchange", handleFullScreenChange); }; }, []); useEffect(function () { if (subtitle && subtitle.length > 0) { var _playerRef$current7, _subtitle$currentSubt, _subtitle$currentSubt2, _playerRef$current8; if (currentSubtitle === null) { return; } var oldTrack = playerRef == null || (_playerRef$current7 = playerRef.current) == null ? void 0 : _playerRef$current7.querySelector("track"); if (oldTrack) { oldTrack.remove(); } var track = document.createElement("track"); track.src = subtitle == null || (_subtitle$currentSubt = subtitle[currentSubtitle]) == null ? void 0 : _subtitle$currentSubt.url; track.label = subtitle == null || (_subtitle$currentSubt2 = subtitle[currentSubtitle]) == null ? void 0 : _subtitle$currentSubt2.lang; track["default"] = true; playerRef == null || (_playerRef$current8 = playerRef.current) == null || _playerRef$current8.appendChild(track); } }, [currentSubtitle, currentSource]); useEffect(function () { var _removeSearchParams, _source$split, _removeSearchParams2, _source$, _source$2; var type = typeof source === "string" ? (_removeSearchParams = removeSearchParams(source)) == null ? void 0 : _removeSearchParams.split(".")[(source == null || (_source$split = source.split(".")) == null ? void 0 : _source$split.length) - 1] : // @ts-ignore (_removeSearchParams2 = removeSearchParams(source == null || (_source$ = source[0]) == null ? void 0 : _source$.url)) == null ? void 0 : _removeSearchParams2.split(".")[ // @ts-ignore (source == null || (_source$2 = source[0]) == null || (_source$2 = _source$2.url) == null || (_source$2 = _source$2.split(".")) == null ? void 0 : _source$2.length) - 1]; if (type === "mp4") { handleLoadVideoMp4(); } else if (type === "m3u8") { handleLoadVideoM3u8(); } else { handleLoadVideoMp4(); } return function () { if (hlsRef != null && hlsRef.current) { var _hlsRef$current4; hlsRef == null || (_hlsRef$current4 = hlsRef.current) == null || _hlsRef$current4.destroy(); } }; }, [source, sourceMulti == null ? void 0 : sourceMulti.length, hlsRef == null ? void 0 : hlsRef.current]); useEffect(function () { if (playerRef !== null && (playerRef == null ? void 0 : playerRef.current) !== null) { playerRef.current.muted = muted; } }, [muted]); useEffect(function () { if (!autoPlay) return; if (playerRef !== null && (playerRef == null ? void 0 : playerRef.current) !== null) { playerRef.current.muted = true; playerRef.current.addEventListener("loadedmetadata", function () { // @ts-ignore playerRef.current.play(); }); setMuted(true); } }, [autoPlay]); useEffect(function () { var handleKeyDown = function handleKeyDown(e) { // Ngăn chặn các hành động mặc định của trình duyệt var target = e.target; var isInputField = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable; if (isInputField) { return; } if (["Space", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "f", "m"].includes(e.code)) { e.preventDefault(); } switch (e.code) { case "Space": handlePlayPause(); break; case "ArrowLeft": // Tua lùi 5 giây if (playerRef.current) { playerRef.current.currentTime -= 5; } break; case "ArrowRight": // Tua tới 5 giây if (playerRef.current) { playerRef.current.currentTime += 5; } break; case "ArrowUp": // Tăng âm lượng handleVolumeChange(Math.min(volume + 5, 100)); break; case "ArrowDown": // Giảm âm lượng handleVolumeChange(Math.max(volume - 5, 0)); break; case "KeyF": // Bật/tắt chế độ toàn màn hình handleFullScreen(); break; case "KeyM": // Bật/tắt âm thanh handleToggleMuted(); break; } }; document.addEventListener("keydown", handleKeyDown); return function () { document.removeEventListener("keydown", handleKeyDown); }; }, [play, volume, handlePlayPause, handleVolumeChange, handleFullScreen, handleToggleMuted]); useEffect(function () { var _playerRef$current9, _playerRef$current10; if (!play) setShowControl(true); play ? playerRef == null || (_playerRef$current9 = playerRef.current) == null ? void 0 : _playerRef$current9.play() : playerRef == null || (_playerRef$current10 = playerRef.current) == null ? void 0 : _playerRef$current10.pause(); }, [play]); useEffect(function () { return function () { var _hlsRef$current5; if (hlsRef != null && hlsRef.current) hlsRef == null || (_hlsRef$current5 = hlsRef.current) == null || _hlsRef$current5.destroy(); }; }, []); return React__default.createElement("div", { ref: videoContainerRef, onMouseMove: function onMouseMove() { return setShowControl(true); }, onMouseLeave: function onMouseLeave() { if (seeking) return; setShowControl(false); }, onClick: function onClick() { return setShowControl(true); }, className: "video-container" }, React__default.createElement("video", Object.assign({ ref: playerRef, className: "video " + (className || ""), poster: poster || "", onPlay: function onPlay() { return setPlay(true); }, onPause: function onPause() { return setPlay(false); }, onTimeUpdate: handleTimeUpdate, onCanPlay: function onCanPlay() { return setLoading(false); }, onWaiting: function onWaiting() { return setLoading(true); }, onLoad: function onLoad() { return setLoading(true); }, onLoadedMetadata: function onLoadedMetadata() { return setLoading(true); } }, props)), loading && React__default.createElement("div", { className: "center-item-absolute" }, React__default.createElement(CircularProgress, null)), React__default.createElement("div", { onClick: function onClick(e) { e.stopPropagation(); setShowSettings(false); setShowControl(false); }, style: { display: showControl ? "flex" : "none" }, className: "control-container opacity-animation" }, !loading && React__default.createElement("div", { onClick: handlePlayPause, className: "center-item-absolute cursor-pointer" }, play ? React__default.createElement(IconPause, { fontSize: 60 }) : React__default.createElement(IconPlay, { fontSize: 60 })), showSettings && React__default.createElement("div", { onClick: function onClick(e) { return setShowSettings(false); }, className: "settings-container" }, React__default.createElement("div", { className: "w-full", onClick: function onClick(e) { return e.stopPropagation(); } }, settingsType === "main" ? React__default.createElement(MainSettings, { currentQuality: sourceMulti == null || (_sourceMulti$currentS = sourceMulti[currentSource]) == null ? void 0 : _sourceMulti$currentS.label, currentSpeed: playSpeedOptions == null || (_playSpeedOptions$cur = playSpeedOptions[currentPlaySpeed]) == null ? void 0 : _playSpeedOptions$cur.label, setSettingsType: setSettingsType, currentSubtitle: typeof currentSubtitle === "number" ? subtitle == null || (_subtitle$currentSubt3 = subtitle[currentSubtitle]) == null ? void 0 : _subtitle$currentSubt3.lang : "Off", haveSubtitle: Boolean(subtitle), haveQuality: (source == null ? void 0 : source.length) > 0 }) : settingsType === "playspeed" ? React__default.createElement(PlaySpeedSettings, { handleChangePlaySpeed: handleChangePlaySpeed, currentPlaySpeed: currentPlaySpeed, setSettingsType: setSettingsType }) : settingsType === "quality" ? React__default.createElement(QualitySettings, { handleChangeSource: handleChangeSource, currentSource: currentSource, setSettingsType: setSettingsType, source: sourceMulti }) : React__default.createElement(SubtitleSettings, { currentSubtitle: currentSubtitle, setSettingsType: setSettingsType, handleChangeSubtitle: handleChangeSubtitle, subtitle: subtitle, handleTurnOffSubtitle: handleTurnOffSubtitle }))), React__default.createElement("div", { onClick: function onClick(e) { return e.stopPropagation(); }, className: "w-full" }, React__default.createElement(Slider, { onDragEnd: handleDragEnd, value: currentTime, onChange: handleChangeTime, min: 0, max: playerRef == null || (_playerRef$current11 = playerRef.current) == null ? void 0 : _playerRef$current11.duration, live: live, color: defaultColor, onPreview: function onPreview(value, percentValue) { setPreviewTime({ time: value, left: percentValue }); }, className: "tooltip-container" }, !live && Number(previewTime == null ? void 0 : previewTime.time) && previewTime != null && previewTime.left ? React__default.createElement("div", { style: { left: (previewTime == null ? void 0 : previewTime.left) * 100 + "%", top: -30 }, className: "tooltip" }, React__default.createElement("p", null, formatVideoTime(Number(previewTime == null ? void 0 : previewTime.time)))) : ""), React__default.createElement("div", { onMouseDown: function onMouseDown(e) { return e.stopPropagation(); }, className: "main-control-container" }, React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement("div", { onClick: handlePlayPause, className: "cursor-pointer mr-3 main-settings-content tooltip-container" }, play ? React__default.createElement(IconPause, { fontSize: 28 }) : React__default.createElement(IconPlay, { fontSize: 28 }), React__default.createElement("div", { className: "tooltip opacity-animation" }, "Play")), React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement("div", { className: "main-settings-content volume-container" }, React__default.createElement("div", { onClick: handleToggleMuted, className: "cursor-pointer mr-3 main-settings-content tooltip-container" }, muted ? React__default.createElement(IconVolumeMute, { fontSize: 25 }) : React__default.createElement(IconVolumeHigh, { fontSize: 25 }), React__default.createElement("div", { className: "tooltip" }, "Volume")), React__default.createElement(Slider, { onDragEnd: handleDragEnd, value: volume, onChange: handleVolumeChange, min: 0, max: 100, live: false, color: defaultColor, className: "volume mr-3 width-animation" })), !live ? React__default.createElement("div", { className: "time" }, formatVideoTime(currentTime), " / ", formatVideoTime(playerRef == null || (_playerRef$current12 = playerRef.current) == null ? void 0 : _playerRef$current12.duration)) : React__default.createElement("div", { className: "text-sm font-semibold cursor-pointer live-button" }, "Live"))), React__default.createElement("div", { className: "main-settings-content" }, React__default.createElement("div", { className: "tooltip-container main-settings-content" }, React__default.createElement(IconSettingsSharp, { onClick: function onClick() { return setShowSettings(!showSettings); }, className: "cursor-pointer mr-3", fontSize: 23 }), React__default.createElement("div", { className: "tooltip" }, "Settings")), React__default.createElement("div", { className: "tooltip-container main-settings-content" }, React__default.createElement(IconPictureInPictureFill, { onClick: handleVideoPicture, className: "cursor-pointer mr-3", fontSize: 23 }), React__default.createElement("div", { className: "tooltip" }, "PIP")), React__default.createElement("div", { onClick: handleFullScreen, className: "cursor-pointer main-settings-content tooltip-container" }, fullScreen ? React__default.createElement(IconFullscreenExit, { fontSize: 30 }) : React__default.createElement(IconFullscreen, { fontSize: 23 }), React__default.createElement("div", { className: "tooltip" }, "Fullscreen"))))))); }; var ClientRender = function ClientRender(_ref) { var children = _ref.children; var _useState = useState(typeof window !== "undefined"), rendered = _useState[0], setRendered = _useState[1]; useEffect(function () { setRendered(true); }, []); if (rendered) return children; return React__default.createElement(React__default.Fragment, null); }; var VPlayer = function VPlayer(props) { return React__default.createElement("div", { id: "vnetwork-player" }, React__default.createElement(ErrorBoundary, null, React__default.createElement(ClientRender, null, React__default.createElement(Player, Object.assign({}, props))))); }; export default VPlayer; //# sourceMappingURL=vnetwor