UNPKG

react-h5-audio-player

Version:

A customizable React audio player. Written in TypeScript. Mobile compatible. Keyboard friendly

597 lines (512 loc) 23.1 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _react2 = require("@iconify/react"); var _playCircle = _interopRequireDefault(require("@iconify/icons-mdi/play-circle")); var _pauseCircle = _interopRequireDefault(require("@iconify/icons-mdi/pause-circle")); var _skipPrevious = _interopRequireDefault(require("@iconify/icons-mdi/skip-previous")); var _skipNext = _interopRequireDefault(require("@iconify/icons-mdi/skip-next")); var _fastForward = _interopRequireDefault(require("@iconify/icons-mdi/fast-forward")); var _rewind = _interopRequireDefault(require("@iconify/icons-mdi/rewind")); var _volumeHigh = _interopRequireDefault(require("@iconify/icons-mdi/volume-high")); var _volumeMute = _interopRequireDefault(require("@iconify/icons-mdi/volume-mute")); var _repeat = _interopRequireDefault(require("@iconify/icons-mdi/repeat")); var _repeatOff = _interopRequireDefault(require("@iconify/icons-mdi/repeat-off")); var _ProgressBar = _interopRequireDefault(require("./ProgressBar")); var _CurrentTime = _interopRequireDefault(require("./CurrentTime")); var _Duration = _interopRequireDefault(require("./Duration")); var _VolumeBar = _interopRequireDefault(require("./VolumeBar")); var _constants = require("./constants"); exports.RHAP_UI = _constants.RHAP_UI; var _utils = require("./utils"); var H5AudioPlayer = function (_Component) { (0, _inheritsLoose2.default)(H5AudioPlayer, _Component); function H5AudioPlayer() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _Component.call.apply(_Component, [this].concat(args)) || this; (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "audio", (0, _react.createRef)()); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "progressBar", (0, _react.createRef)()); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "container", (0, _react.createRef)()); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "lastVolume", _this.props.volume); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "listenTracker", void 0); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "volumeAnimationTimer", void 0); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "downloadProgressAnimationTimer", void 0); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "togglePlay", function (e) { e.stopPropagation(); var audio = _this.audio.current; if (audio.paused && audio.src) { _this.playAudioPromise(); } else if (!audio.paused) { audio.pause(); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "playAudioPromise", function () { _this.audio.current.play().then(null).catch(function (err) { var onPlayError = _this.props.onPlayError; onPlayError && onPlayError(new Error(err)); }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isPlaying", function () { var audio = _this.audio.current; if (!audio) return false; return !audio.paused && !audio.ended; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handlePlay", function (e) { _this.forceUpdate(); _this.props.onPlay && _this.props.onPlay(e); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handlePause", function (e) { if (!_this.audio) return; _this.forceUpdate(); _this.props.onPause && _this.props.onPause(e); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleAbort", function (e) { _this.props.onAbort && _this.props.onAbort(e); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleClickVolumeButton", function () { var audio = _this.audio.current; if (audio.volume > 0) { _this.lastVolume = audio.volume; audio.volume = 0; } else { audio.volume = _this.lastVolume; } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleMuteChange", function () { _this.forceUpdate(); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleClickLoopButton", function () { _this.audio.current.loop = !_this.audio.current.loop; _this.forceUpdate(); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleClickRewind", function () { var _this$props = _this.props, progressJumpSteps = _this$props.progressJumpSteps, progressJumpStep = _this$props.progressJumpStep; var jumpStep = progressJumpSteps.backward || progressJumpStep; _this.setJumpTime(-jumpStep); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleClickForward", function () { var _this$props2 = _this.props, progressJumpSteps = _this$props2.progressJumpSteps, progressJumpStep = _this$props2.progressJumpStep; var jumpStep = progressJumpSteps.forward || progressJumpStep; _this.setJumpTime(jumpStep); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "setJumpTime", function (time) { var audio = _this.audio.current; var duration = audio.duration, prevTime = audio.currentTime; if (!isFinite(duration) || !isFinite(prevTime)) return; var currentTime = prevTime + time / 1000; if (currentTime < 0) { audio.currentTime = 0; currentTime = 0; } else if (currentTime > duration) { audio.currentTime = duration; currentTime = duration; } else { audio.currentTime = currentTime; } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "setJumpVolume", function (volume) { var newVolume = _this.audio.current.volume + volume; if (newVolume < 0) newVolume = 0;else if (newVolume > 1) newVolume = 1; _this.audio.current.volume = newVolume; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleKeyDown", function (e) { switch (e.keyCode) { case 32: if (e.target === _this.container.current || e.target === _this.progressBar.current) { e.preventDefault(); _this.togglePlay(e); } break; case 37: _this.handleClickRewind(); break; case 39: _this.handleClickForward(); break; case 38: e.preventDefault(); _this.setJumpVolume(_this.props.volumeJumpStep); break; case 40: e.preventDefault(); _this.setJumpVolume(-_this.props.volumeJumpStep); break; case 76: _this.handleClickLoopButton(); break; case 77: _this.handleClickVolumeButton(); break; } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "renderUIModules", function (modules) { return modules.map(function (comp, i) { return _this.renderUIModule(comp, i); }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "renderUIModule", function (comp, key) { var _this$props3 = _this.props, defaultCurrentTime = _this$props3.defaultCurrentTime, progressUpdateInterval = _this$props3.progressUpdateInterval, showDownloadProgress = _this$props3.showDownloadProgress, showFilledProgress = _this$props3.showFilledProgress, showFilledVolume = _this$props3.showFilledVolume, defaultDuration = _this$props3.defaultDuration, customIcons = _this$props3.customIcons, showSkipControls = _this$props3.showSkipControls, onClickPrevious = _this$props3.onClickPrevious, onClickNext = _this$props3.onClickNext, showJumpControls = _this$props3.showJumpControls, customAdditionalControls = _this$props3.customAdditionalControls, customVolumeControls = _this$props3.customVolumeControls, muted = _this$props3.muted, timeFormat = _this$props3.timeFormat, volumeProp = _this$props3.volume, loopProp = _this$props3.loop, mse = _this$props3.mse; switch (comp) { case _constants.RHAP_UI.CURRENT_TIME: return _react.default.createElement("div", { key: key, id: "rhap_current-time", className: "rhap_time rhap_current-time" }, _react.default.createElement(_CurrentTime.default, { audio: _this.audio.current, isLeftTime: false, defaultCurrentTime: defaultCurrentTime, timeFormat: timeFormat })); case _constants.RHAP_UI.CURRENT_LEFT_TIME: return _react.default.createElement("div", { key: key, id: "rhap_current-left-time", className: "rhap_time rhap_current-left-time" }, _react.default.createElement(_CurrentTime.default, { audio: _this.audio.current, isLeftTime: true, defaultCurrentTime: defaultCurrentTime, timeFormat: timeFormat })); case _constants.RHAP_UI.PROGRESS_BAR: return _react.default.createElement(_ProgressBar.default, { key: key, ref: _this.progressBar, audio: _this.audio.current, progressUpdateInterval: progressUpdateInterval, showDownloadProgress: showDownloadProgress, showFilledProgress: showFilledProgress, onSeek: mse && mse.onSeek, srcDuration: mse && mse.srcDuration }); case _constants.RHAP_UI.DURATION: return _react.default.createElement("div", { key: key, className: "rhap_time rhap_total-time" }, mse && mse.srcDuration ? (0, _utils.getDisplayTimeBySeconds)(mse.srcDuration, mse.srcDuration, _this.props.timeFormat) : _react.default.createElement(_Duration.default, { audio: _this.audio.current, defaultDuration: defaultDuration, timeFormat: timeFormat })); case _constants.RHAP_UI.ADDITIONAL_CONTROLS: return _react.default.createElement("div", { key: key, className: "rhap_additional-controls" }, _this.renderUIModules(customAdditionalControls)); case _constants.RHAP_UI.MAIN_CONTROLS: { var isPlaying = _this.isPlaying(); var actionIcon; if (isPlaying) { actionIcon = customIcons.pause ? customIcons.pause : _react.default.createElement(_react2.Icon, { icon: _pauseCircle.default }); } else { actionIcon = customIcons.play ? customIcons.play : _react.default.createElement(_react2.Icon, { icon: _playCircle.default }); } return _react.default.createElement("div", { key: key, className: "rhap_main-controls" }, showSkipControls && _react.default.createElement("button", { "aria-label": "Previous", className: "rhap_button-clear rhap_main-controls-button rhap_skip-button", type: "button", onClick: onClickPrevious }, customIcons.previous ? customIcons.previous : _react.default.createElement(_react2.Icon, { icon: _skipPrevious.default })), showJumpControls && _react.default.createElement("button", { "aria-label": "Rewind", className: "rhap_button-clear rhap_main-controls-button rhap_rewind-button", type: "button", onClick: _this.handleClickRewind }, customIcons.rewind ? customIcons.rewind : _react.default.createElement(_react2.Icon, { icon: _rewind.default })), _react.default.createElement("button", { "aria-label": isPlaying ? 'Pause' : 'Play', className: "rhap_button-clear rhap_main-controls-button rhap_play-pause-button", type: "button", onClick: _this.togglePlay }, actionIcon), showJumpControls && _react.default.createElement("button", { "aria-label": "Forward", className: "rhap_button-clear rhap_main-controls-button rhap_forward-button", type: "button", onClick: _this.handleClickForward }, customIcons.forward ? customIcons.forward : _react.default.createElement(_react2.Icon, { icon: _fastForward.default })), showSkipControls && _react.default.createElement("button", { "aria-label": "Skip", className: "rhap_button-clear rhap_main-controls-button rhap_skip-button", type: "button", onClick: onClickNext }, customIcons.next ? customIcons.next : _react.default.createElement(_react2.Icon, { icon: _skipNext.default }))); } case _constants.RHAP_UI.VOLUME_CONTROLS: return _react.default.createElement("div", { key: key, className: "rhap_volume-controls" }, _this.renderUIModules(customVolumeControls)); case _constants.RHAP_UI.LOOP: { var loop = _this.audio.current ? _this.audio.current.loop : loopProp; var loopIcon; if (loop) { loopIcon = customIcons.loop ? customIcons.loop : _react.default.createElement(_react2.Icon, { icon: _repeat.default }); } else { loopIcon = customIcons.loopOff ? customIcons.loopOff : _react.default.createElement(_react2.Icon, { icon: _repeatOff.default }); } return _react.default.createElement("button", { key: key, "aria-label": loop ? 'Enable Loop' : 'Disable Loop', className: "rhap_button-clear rhap_repeat-button", type: "button", onClick: _this.handleClickLoopButton }, loopIcon); } case _constants.RHAP_UI.VOLUME: { var _ref = _this.audio.current || {}, _ref$volume = _ref.volume, volume = _ref$volume === void 0 ? muted ? 0 : volumeProp : _ref$volume; var volumeIcon; if (volume) { volumeIcon = customIcons.volume ? customIcons.volume : _react.default.createElement(_react2.Icon, { icon: _volumeHigh.default }); } else { volumeIcon = customIcons.volume ? customIcons.volumeMute : _react.default.createElement(_react2.Icon, { icon: _volumeMute.default }); } return _react.default.createElement("div", { key: key, className: "rhap_volume-container" }, _react.default.createElement("button", { "aria-label": volume ? 'Mute' : 'Unmute', onClick: _this.handleClickVolumeButton, type: "button", className: "rhap_button-clear rhap_volume-button" }, volumeIcon), _react.default.createElement(_VolumeBar.default, { audio: _this.audio.current, volume: volume, onMuteChange: _this.handleMuteChange, showFilledVolume: showFilledVolume })); } default: if (!(0, _react.isValidElement)(comp)) { return null; } return comp.key ? comp : (0, _react.cloneElement)(comp, { key: key }); } }); return _this; } var _proto = H5AudioPlayer.prototype; _proto.componentDidMount = function componentDidMount() { var _this2 = this; this.forceUpdate(); var audio = this.audio.current; if (this.props.muted) { audio.volume = 0; } else { audio.volume = this.lastVolume; } audio.addEventListener('error', function (e) { _this2.props.onError && _this2.props.onError(e); }); audio.addEventListener('canplay', function (e) { _this2.props.onCanPlay && _this2.props.onCanPlay(e); }); audio.addEventListener('canplaythrough', function (e) { _this2.props.onCanPlayThrough && _this2.props.onCanPlayThrough(e); }); audio.addEventListener('play', this.handlePlay); audio.addEventListener('abort', this.handleAbort); audio.addEventListener('ended', function (e) { _this2.props.onEnded && _this2.props.onEnded(e); }); audio.addEventListener('playing', function (e) { _this2.props.onPlaying && _this2.props.onPlaying(e); }); audio.addEventListener('seeking', function (e) { _this2.props.onSeeking && _this2.props.onSeeking(e); }); audio.addEventListener('seeked', function (e) { _this2.props.onSeeked && _this2.props.onSeeked(e); }); audio.addEventListener('waiting', function (e) { _this2.props.onWaiting && _this2.props.onWaiting(e); }); audio.addEventListener('emptied', function (e) { _this2.props.onEmptied && _this2.props.onEmptied(e); }); audio.addEventListener('stalled', function (e) { _this2.props.onStalled && _this2.props.onStalled(e); }); audio.addEventListener('suspend', function (e) { _this2.props.onSuspend && _this2.props.onSuspend(e); }); audio.addEventListener('loadstart', function (e) { _this2.props.onLoadStart && _this2.props.onLoadStart(e); }); audio.addEventListener('loadedmetadata', function (e) { _this2.props.onLoadedMetaData && _this2.props.onLoadedMetaData(e); }); audio.addEventListener('loadeddata', function (e) { _this2.props.onLoadedData && _this2.props.onLoadedData(e); }); audio.addEventListener('pause', this.handlePause); audio.addEventListener('timeupdate', (0, _utils.throttle)(function (e) { _this2.props.onListen && _this2.props.onListen(e); }, this.props.listenInterval)); audio.addEventListener('volumechange', function (e) { _this2.props.onVolumeChange && _this2.props.onVolumeChange(e); }); audio.addEventListener('encrypted', function (e) { var mse = _this2.props.mse; mse && mse.onEcrypted && mse.onEcrypted(e); }); }; _proto.componentDidUpdate = function componentDidUpdate(prevProps) { var _this$props4 = this.props, src = _this$props4.src, autoPlayAfterSrcChange = _this$props4.autoPlayAfterSrcChange; if (prevProps.src !== src) { if (autoPlayAfterSrcChange) { this.playAudioPromise(); } else { this.forceUpdate(); } } }; _proto.componentWillUnmount = function componentWillUnmount() { var audio = this.audio.current; if (audio) { audio.removeEventListener('play', this.handlePlay); audio.removeEventListener('pause', this.handlePause); audio.removeEventListener('abort', this.handleAbort); audio.removeAttribute('src'); audio.load(); } }; _proto.render = function render() { var _this$props5 = this.props, className = _this$props5.className, src = _this$props5.src, loopProp = _this$props5.loop, preload = _this$props5.preload, autoPlay = _this$props5.autoPlay, crossOrigin = _this$props5.crossOrigin, mediaGroup = _this$props5.mediaGroup, header = _this$props5.header, footer = _this$props5.footer, layout = _this$props5.layout, customProgressBarSection = _this$props5.customProgressBarSection, customControlsSection = _this$props5.customControlsSection, children = _this$props5.children, style = _this$props5.style; var loop = this.audio.current ? this.audio.current.loop : loopProp; return _react.default.createElement("div", { role: "group", tabIndex: 0, "aria-label": "Audio Player", className: "rhap_container " + className, onKeyDown: this.handleKeyDown, ref: this.container, style: style }, _react.default.createElement("audio", { src: src, controls: false, loop: loop, autoPlay: autoPlay, preload: preload, crossOrigin: crossOrigin, mediaGroup: mediaGroup, ref: this.audio }, children), header && _react.default.createElement("div", { className: "rhap_header" }, header), _react.default.createElement("div", { className: "rhap_main " + (0, _utils.getMainLayoutClassName)(layout) }, _react.default.createElement("div", { className: "rhap_progress-section" }, this.renderUIModules(customProgressBarSection)), _react.default.createElement("div", { className: "rhap_controls-section" }, this.renderUIModules(customControlsSection))), footer && _react.default.createElement("div", { className: "rhap_footer" }, footer)); }; return H5AudioPlayer; }(_react.Component); (0, _defineProperty2.default)(H5AudioPlayer, "defaultProps", { autoPlay: false, autoPlayAfterSrcChange: true, listenInterval: 1000, progressJumpStep: 5000, progressJumpSteps: {}, volumeJumpStep: 0.1, loop: false, muted: false, preload: 'auto', progressUpdateInterval: 20, defaultCurrentTime: '--:--', defaultDuration: '--:--', timeFormat: 'auto', volume: 1, className: '', showJumpControls: true, showSkipControls: false, showDownloadProgress: true, showFilledProgress: true, showFilledVolume: false, customIcons: {}, customProgressBarSection: [_constants.RHAP_UI.CURRENT_TIME, _constants.RHAP_UI.PROGRESS_BAR, _constants.RHAP_UI.DURATION], customControlsSection: [_constants.RHAP_UI.ADDITIONAL_CONTROLS, _constants.RHAP_UI.MAIN_CONTROLS, _constants.RHAP_UI.VOLUME_CONTROLS], customAdditionalControls: [_constants.RHAP_UI.LOOP], customVolumeControls: [_constants.RHAP_UI.VOLUME], layout: 'stacked' }); var _default = H5AudioPlayer; exports.default = _default;