box-content-preview 3.82.0 → 3.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/lib/index.css +4 -3
- package/dist/lib/index.js +1829 -206
- package/package.json +1 -1
package/dist/lib/index.js
CHANGED
|
@@ -955,6 +955,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
955
955
|
wU: () => (/* binding */ decodeKeydown),
|
|
956
956
|
Is: () => (/* binding */ findScriptLocation),
|
|
957
957
|
kd: () => (/* binding */ getClosestPageToPinch),
|
|
958
|
+
RU: () => (/* binding */ getCurrentTimeMs),
|
|
958
959
|
Yf: () => (/* binding */ getDistance),
|
|
959
960
|
dJ: () => (/* binding */ getHeaders),
|
|
960
961
|
t9: () => (/* binding */ getMidpoint),
|
|
@@ -1009,7 +1010,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
1009
1010
|
const CLIENT_NAME = "box-content-preview"; // eslint-disable-line no-undef
|
|
1010
1011
|
const CLIENT_NAME_KEY = 'box_client_name';
|
|
1011
1012
|
const CLIENT_VERSION_KEY = 'box_client_version';
|
|
1012
|
-
const CLIENT_VERSION = "3.
|
|
1013
|
+
const CLIENT_VERSION = "3.84.0"; // eslint-disable-line no-undef
|
|
1013
1014
|
const HEADER_CLIENT_NAME = 'X-Box-Client-Name';
|
|
1014
1015
|
const HEADER_CLIENT_VERSION = 'X-Box-Client-Version';
|
|
1015
1016
|
const PROMISE_MAP = {};
|
|
@@ -1617,6 +1618,16 @@ function getDistance(x1, y1, x2, y2) {
|
|
|
1617
1618
|
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
|
1618
1619
|
}
|
|
1619
1620
|
|
|
1621
|
+
/**
|
|
1622
|
+
* Monotonic clock in milliseconds. Falls back to wall time when performance is missing.
|
|
1623
|
+
*
|
|
1624
|
+
* @public
|
|
1625
|
+
* @return {number} Current time in milliseconds
|
|
1626
|
+
*/
|
|
1627
|
+
function getCurrentTimeMs() {
|
|
1628
|
+
return typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1620
1631
|
/**
|
|
1621
1632
|
* Returns the closest visible page to a pinch event
|
|
1622
1633
|
*
|
|
@@ -3929,6 +3940,172 @@ let Menu = /*#__PURE__*/function (Menu) {
|
|
|
3929
3940
|
|
|
3930
3941
|
/***/ },
|
|
3931
3942
|
|
|
3943
|
+
/***/ 4937
|
|
3944
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
3945
|
+
|
|
3946
|
+
|
|
3947
|
+
// EXPORTS
|
|
3948
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
3949
|
+
A: () => (/* binding */ SliderControl)
|
|
3950
|
+
});
|
|
3951
|
+
|
|
3952
|
+
// EXTERNAL MODULE: external "react"
|
|
3953
|
+
var external_react_ = __webpack_require__(1649);
|
|
3954
|
+
// EXTERNAL MODULE: ./node_modules/classnames/index.js
|
|
3955
|
+
var classnames = __webpack_require__(2485);
|
|
3956
|
+
var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
|
|
3957
|
+
// EXTERNAL MODULE: ./node_modules/lodash/noop.js
|
|
3958
|
+
var noop = __webpack_require__(3950);
|
|
3959
|
+
var noop_default = /*#__PURE__*/__webpack_require__.n(noop);
|
|
3960
|
+
// EXTERNAL MODULE: ./src/lib/util.js + 1 modules
|
|
3961
|
+
var util = __webpack_require__(4410);
|
|
3962
|
+
;// ./src/lib/viewers/controls/slider/SliderControl.scss
|
|
3963
|
+
// extracted by mini-css-extract-plugin
|
|
3964
|
+
|
|
3965
|
+
;// ./src/lib/viewers/controls/slider/SliderControl.tsx
|
|
3966
|
+
const _excluded = ["className", "max", "min", "onMove", "onUpdate", "step", "title", "track", "value"];
|
|
3967
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
3968
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
3969
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
3970
|
+
|
|
3971
|
+
|
|
3972
|
+
|
|
3973
|
+
|
|
3974
|
+
|
|
3975
|
+
function SliderControl(_ref) {
|
|
3976
|
+
let {
|
|
3977
|
+
className,
|
|
3978
|
+
max = 100,
|
|
3979
|
+
min = 0,
|
|
3980
|
+
onMove = (noop_default()),
|
|
3981
|
+
onUpdate = (noop_default()),
|
|
3982
|
+
step = 1,
|
|
3983
|
+
title,
|
|
3984
|
+
track,
|
|
3985
|
+
value
|
|
3986
|
+
} = _ref,
|
|
3987
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
3988
|
+
const [isScrubbing, setIsScrubbing] = external_react_["default"].useState(false);
|
|
3989
|
+
const sliderElRef = external_react_["default"].useRef(null);
|
|
3990
|
+
const getPosition = external_react_["default"].useCallback(pageX => {
|
|
3991
|
+
const {
|
|
3992
|
+
current: sliderEl
|
|
3993
|
+
} = sliderElRef;
|
|
3994
|
+
if (!sliderEl) return 0;
|
|
3995
|
+
const {
|
|
3996
|
+
left: sliderLeft,
|
|
3997
|
+
width: sliderWidth
|
|
3998
|
+
} = sliderEl.getBoundingClientRect();
|
|
3999
|
+
return Math.max(0, Math.min(pageX - sliderLeft, sliderWidth));
|
|
4000
|
+
}, []);
|
|
4001
|
+
const getPositionValue = external_react_["default"].useCallback(pageX => {
|
|
4002
|
+
const {
|
|
4003
|
+
current: sliderEl
|
|
4004
|
+
} = sliderElRef;
|
|
4005
|
+
if (!sliderEl) return 0;
|
|
4006
|
+
const {
|
|
4007
|
+
width: sliderWidth
|
|
4008
|
+
} = sliderEl.getBoundingClientRect();
|
|
4009
|
+
const newValue = getPosition(pageX) / sliderWidth * max;
|
|
4010
|
+
return Math.max(min, Math.min(newValue, max));
|
|
4011
|
+
}, [getPosition, max, min]);
|
|
4012
|
+
const handleKeydown = event => {
|
|
4013
|
+
const key = (0,util/* decodeKeydown */.wU)(event);
|
|
4014
|
+
if (key === 'ArrowLeft') {
|
|
4015
|
+
event.stopPropagation(); // Prevents global key handling
|
|
4016
|
+
onUpdate(Math.max(min, Math.min(value - step, max)));
|
|
4017
|
+
}
|
|
4018
|
+
if (key === 'ArrowRight') {
|
|
4019
|
+
event.stopPropagation(); // Prevents global key handling
|
|
4020
|
+
onUpdate(Math.max(min, Math.min(value + step, max)));
|
|
4021
|
+
}
|
|
4022
|
+
};
|
|
4023
|
+
const handleMouseDown = ({
|
|
4024
|
+
button,
|
|
4025
|
+
ctrlKey,
|
|
4026
|
+
metaKey,
|
|
4027
|
+
pageX
|
|
4028
|
+
}) => {
|
|
4029
|
+
if (button > 1 || ctrlKey || metaKey) return;
|
|
4030
|
+
onUpdate(getPositionValue(pageX));
|
|
4031
|
+
setIsScrubbing(true);
|
|
4032
|
+
};
|
|
4033
|
+
const handleMouseMove = ({
|
|
4034
|
+
pageX
|
|
4035
|
+
}) => {
|
|
4036
|
+
const {
|
|
4037
|
+
current: sliderEl
|
|
4038
|
+
} = sliderElRef;
|
|
4039
|
+
const {
|
|
4040
|
+
width: sliderWidth
|
|
4041
|
+
} = sliderEl ? sliderEl.getBoundingClientRect() : {
|
|
4042
|
+
width: 0
|
|
4043
|
+
};
|
|
4044
|
+
onMove(getPositionValue(pageX), getPosition(pageX), sliderWidth);
|
|
4045
|
+
};
|
|
4046
|
+
const handleTouchStart = ({
|
|
4047
|
+
touches
|
|
4048
|
+
}) => {
|
|
4049
|
+
onUpdate(getPositionValue(touches[0].pageX));
|
|
4050
|
+
setIsScrubbing(true);
|
|
4051
|
+
};
|
|
4052
|
+
external_react_["default"].useEffect(() => {
|
|
4053
|
+
const handleDocumentMoveStop = () => setIsScrubbing(false);
|
|
4054
|
+
const handleDocumentMouseMove = event => {
|
|
4055
|
+
if (!isScrubbing || event.button > 1 || event.ctrlKey || event.metaKey) return;
|
|
4056
|
+
event.preventDefault();
|
|
4057
|
+
onUpdate(getPositionValue(event.pageX));
|
|
4058
|
+
};
|
|
4059
|
+
const handleDocumentTouchMove = event => {
|
|
4060
|
+
if (!isScrubbing || !event.touches || !event.touches[0]) return;
|
|
4061
|
+
event.preventDefault();
|
|
4062
|
+
onUpdate(getPositionValue(event.touches[0].pageX));
|
|
4063
|
+
};
|
|
4064
|
+
if (isScrubbing) {
|
|
4065
|
+
document.addEventListener('mousemove', handleDocumentMouseMove);
|
|
4066
|
+
document.addEventListener('mouseup', handleDocumentMoveStop);
|
|
4067
|
+
document.addEventListener('touchend', handleDocumentMoveStop);
|
|
4068
|
+
document.addEventListener('touchmove', handleDocumentTouchMove);
|
|
4069
|
+
}
|
|
4070
|
+
return () => {
|
|
4071
|
+
document.removeEventListener('mousemove', handleDocumentMouseMove);
|
|
4072
|
+
document.removeEventListener('mouseup', handleDocumentMoveStop);
|
|
4073
|
+
document.removeEventListener('touchend', handleDocumentMoveStop);
|
|
4074
|
+
document.removeEventListener('touchmove', handleDocumentTouchMove);
|
|
4075
|
+
};
|
|
4076
|
+
}, [isScrubbing, getPositionValue, onUpdate]);
|
|
4077
|
+
return /*#__PURE__*/external_react_["default"].createElement("div", _extends({
|
|
4078
|
+
ref: sliderElRef,
|
|
4079
|
+
"aria-label": title,
|
|
4080
|
+
"aria-valuemax": max,
|
|
4081
|
+
"aria-valuemin": min,
|
|
4082
|
+
"aria-valuenow": value,
|
|
4083
|
+
className: classnames_default()('bp-SliderControl', className, {
|
|
4084
|
+
'bp-is-scrubbing': isScrubbing
|
|
4085
|
+
}),
|
|
4086
|
+
onKeyDown: handleKeydown,
|
|
4087
|
+
onMouseDown: handleMouseDown,
|
|
4088
|
+
onMouseMove: handleMouseMove,
|
|
4089
|
+
onTouchStart: handleTouchStart,
|
|
4090
|
+
role: "slider",
|
|
4091
|
+
tabIndex: 0
|
|
4092
|
+
}, rest), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
4093
|
+
className: "bp-SliderControl-track",
|
|
4094
|
+
"data-testid": "bp-slider-control-track",
|
|
4095
|
+
style: {
|
|
4096
|
+
backgroundImage: track
|
|
4097
|
+
}
|
|
4098
|
+
}), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
4099
|
+
className: "bp-SliderControl-thumb",
|
|
4100
|
+
"data-testid": "bp-slider-control-thumb",
|
|
4101
|
+
style: {
|
|
4102
|
+
left: `${value / max * 100}%`
|
|
4103
|
+
}
|
|
4104
|
+
}));
|
|
4105
|
+
}
|
|
4106
|
+
|
|
4107
|
+
/***/ },
|
|
4108
|
+
|
|
3932
4109
|
/***/ 9974
|
|
3933
4110
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
3934
4111
|
|
|
@@ -3941,7 +4118,7 @@ function getPdfjsWorkerSrc() {
|
|
|
3941
4118
|
|
|
3942
4119
|
/***/ },
|
|
3943
4120
|
|
|
3944
|
-
/***/
|
|
4121
|
+
/***/ 3845
|
|
3945
4122
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
3946
4123
|
|
|
3947
4124
|
|
|
@@ -3967,6 +4144,8 @@ var TimestampControl = __webpack_require__(3904);
|
|
|
3967
4144
|
var VolumeControls = __webpack_require__(3945);
|
|
3968
4145
|
// EXTERNAL MODULE: ./src/lib/icons/play_48px.svg
|
|
3969
4146
|
var play_48px = __webpack_require__(3493);
|
|
4147
|
+
// EXTERNAL MODULE: ./src/lib/viewers/media/waveform/constants.ts
|
|
4148
|
+
var constants = __webpack_require__(4929);
|
|
3970
4149
|
;// ./src/lib/viewers/media/waveform/peaks.ts
|
|
3971
4150
|
const PLACEHOLDER_PEAK_AMPLITUDE = 0;
|
|
3972
4151
|
const PLACEHOLDER_PEAK_COUNT = 2000;
|
|
@@ -4063,10 +4242,126 @@ function morphPeaks(from, to, elapsedMs) {
|
|
|
4063
4242
|
}
|
|
4064
4243
|
return out;
|
|
4065
4244
|
}
|
|
4245
|
+
;// ./src/lib/viewers/media/waveform/viewport.ts
|
|
4246
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4247
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4248
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
4249
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
4250
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4251
|
+
|
|
4252
|
+
function createWaveformViewport({
|
|
4253
|
+
durationSec,
|
|
4254
|
+
heightPx,
|
|
4255
|
+
maxZoom,
|
|
4256
|
+
scrollLeftPx,
|
|
4257
|
+
widthPx,
|
|
4258
|
+
zoomLevel
|
|
4259
|
+
}) {
|
|
4260
|
+
const zoom = Number.isFinite(zoomLevel) && zoomLevel > 0 ? zoomLevel : constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4261
|
+
const viewDurationSec = durationSec > 0 ? durationSec / zoom : 0; // seconds visible at this zoom
|
|
4262
|
+
const pixelsPerSecond = viewDurationSec > 0 && widthPx > 0 ? widthPx / viewDurationSec : 0;
|
|
4263
|
+
const maxStartSec = Math.max(0, durationSec - viewDurationSec); // last start that still fills the window
|
|
4264
|
+
const startSec = pixelsPerSecond > 0 ? Math.min(maxStartSec, Math.max(0, scrollLeftPx / pixelsPerSecond)) : 0;
|
|
4265
|
+
return {
|
|
4266
|
+
durationSec,
|
|
4267
|
+
endSec: startSec + viewDurationSec,
|
|
4268
|
+
heightPx,
|
|
4269
|
+
maxZoom,
|
|
4270
|
+
pixelsPerSecond,
|
|
4271
|
+
scrollLeftPx,
|
|
4272
|
+
startSec,
|
|
4273
|
+
widthPx,
|
|
4274
|
+
zoomLevel: zoom
|
|
4275
|
+
};
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
/** Same viewport with a different scroll, so start/end times update. */
|
|
4279
|
+
function getViewportAtScroll(viewport, scrollLeftPx) {
|
|
4280
|
+
return createWaveformViewport(_objectSpread(_objectSpread({}, viewport), {}, {
|
|
4281
|
+
scrollLeftPx
|
|
4282
|
+
}));
|
|
4283
|
+
}
|
|
4284
|
+
|
|
4285
|
+
/** How many CSS pixels from the left of the visible window this time sits. */
|
|
4286
|
+
function positionPxFromTime(timeSec, viewport) {
|
|
4287
|
+
return (timeSec - viewport.startSec) * viewport.pixelsPerSecond;
|
|
4288
|
+
}
|
|
4289
|
+
|
|
4290
|
+
/** Media time under a point this many CSS pixels from the left of the visible window. */
|
|
4291
|
+
function timeFromPositionPx(positionPx, viewport) {
|
|
4292
|
+
if (!(viewport.pixelsPerSecond > 0)) {
|
|
4293
|
+
return viewport.startSec;
|
|
4294
|
+
}
|
|
4295
|
+
return viewport.startSec + positionPx / viewport.pixelsPerSecond;
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
/** True when this time sits inside the visible window. */
|
|
4299
|
+
function isTimeInView(timeSec, viewport) {
|
|
4300
|
+
return timeSec >= viewport.startSec && timeSec <= viewport.endSec;
|
|
4301
|
+
}
|
|
4302
|
+
|
|
4303
|
+
/** UI max zoom: 24×, ~1 peak per CSS pixel, and a minimum visible window. */
|
|
4304
|
+
function getWaveformZoomMax({
|
|
4305
|
+
durationSec,
|
|
4306
|
+
peakCount,
|
|
4307
|
+
viewWidthPx
|
|
4308
|
+
}) {
|
|
4309
|
+
if (!(peakCount > 0) || !(viewWidthPx > 0)) {
|
|
4310
|
+
return constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4311
|
+
}
|
|
4312
|
+
const peakLimitedMax = Math.floor(peakCount / viewWidthPx);
|
|
4313
|
+
const durationLimitedMax = durationSec > 0 ? durationSec / constants/* WAVEFORM_MIN_VIEW_WINDOW_SEC */.Kl : constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4314
|
+
return Math.max(constants/* WAVEFORM_ZOOM_MIN */.LW, Math.min(constants/* WAVEFORM_ZOOM_MAX */.tK, peakLimitedMax, durationLimitedMax));
|
|
4315
|
+
}
|
|
4316
|
+
|
|
4317
|
+
/** Keep zoom between 1× and this file's max. */
|
|
4318
|
+
function clampWaveformZoom(zoomLevel, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4319
|
+
const max = Math.max(constants/* WAVEFORM_ZOOM_MIN */.LW, maxZoom);
|
|
4320
|
+
if (!Number.isFinite(zoomLevel)) {
|
|
4321
|
+
return constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4322
|
+
}
|
|
4323
|
+
return Math.min(max, Math.max(constants/* WAVEFORM_ZOOM_MIN */.LW, zoomLevel));
|
|
4324
|
+
}
|
|
4325
|
+
|
|
4326
|
+
/** WaveSurfer zoom density. 0 = fit the whole file in the view. */
|
|
4327
|
+
function getZoomedPixelsPerSecond({
|
|
4328
|
+
durationSec,
|
|
4329
|
+
maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW,
|
|
4330
|
+
viewWidthPx,
|
|
4331
|
+
zoomLevel
|
|
4332
|
+
}) {
|
|
4333
|
+
const zoom = clampWaveformZoom(zoomLevel, maxZoom);
|
|
4334
|
+
if (zoom <= constants/* WAVEFORM_ZOOM_MIN */.LW || !(durationSec > 0) || !(viewWidthPx > 0)) {
|
|
4335
|
+
return 0;
|
|
4336
|
+
}
|
|
4337
|
+
return viewWidthPx / durationSec * zoom;
|
|
4338
|
+
}
|
|
4339
|
+
|
|
4340
|
+
/** Map zoom (1…max) onto the 0–100 slider. */
|
|
4341
|
+
function sliderValueFromZoom(zoomLevel, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4342
|
+
const max = Math.max(constants/* WAVEFORM_ZOOM_MIN */.LW, maxZoom);
|
|
4343
|
+
const zoom = clampWaveformZoom(zoomLevel, max);
|
|
4344
|
+
if (max <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4345
|
+
return 0;
|
|
4346
|
+
}
|
|
4347
|
+
return (zoom - constants/* WAVEFORM_ZOOM_MIN */.LW) / (max - constants/* WAVEFORM_ZOOM_MIN */.LW) * constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh;
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4350
|
+
/** Inverse of sliderValueFromZoom. */
|
|
4351
|
+
function zoomFromSliderValue(value, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4352
|
+
const max = Math.max(constants/* WAVEFORM_ZOOM_MIN */.LW, maxZoom);
|
|
4353
|
+
if (max <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4354
|
+
return constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4355
|
+
}
|
|
4356
|
+
const t = Math.min(constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh, Math.max(0, value)) / constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh;
|
|
4357
|
+
return clampWaveformZoom(constants/* WAVEFORM_ZOOM_MIN */.LW + t * (max - constants/* WAVEFORM_ZOOM_MIN */.LW), max);
|
|
4358
|
+
}
|
|
4066
4359
|
;// ./node_modules/wavesurfer.js/dist/wavesurfer.esm.js
|
|
4067
4360
|
function t(t,e,i,n){return new(i||(i=Promise))((function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(o,a)}l((n=n.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class e{constructor(){this.listeners={}}on(t,e,i){if(this.listeners[t]||(this.listeners[t]=new Set),null==i?void 0:i.once){const i=(...n)=>{this.un(t,i),e(...n)};return this.listeners[t].add(i),()=>this.un(t,i)}return this.listeners[t].add(e),()=>this.un(t,e)}un(t,e){var i;null===(i=this.listeners[t])||void 0===i||i.delete(e)}once(t,e){return this.on(t,e,{once:!0})}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach((t=>t(...e)))}}const i={decode:function(e,i){return t(this,void 0,void 0,(function*(){const t=new AudioContext({sampleRate:i});try{return yield t.decodeAudioData(e)}finally{"closed"!==t.state&&(yield t.close().catch((()=>{})))}}))},createBuffer:function(t,e){if(!t||0===t.length)throw new Error("channelData must be a non-empty array");if(e<=0)throw new Error("duration must be greater than 0");if("number"==typeof t[0]&&(t=[t]),!t[0]||0===t[0].length)throw new Error("channelData must contain non-empty channel arrays");!function(t){const e=t[0];if(e.some((t=>t>1||t<-1))){const i=e.length;let n=0;for(let t=0;t<i;t++){const i=Math.abs(e[t]);i>n&&(n=i)}for(const e of t)for(let t=0;t<i;t++)e[t]/=n}}(t);const i=t.map((t=>t instanceof Float32Array?t:Float32Array.from(t)));return{duration:e,length:i[0].length,sampleRate:i[0].length/e,numberOfChannels:i.length,getChannelData:t=>{const e=i[t];if(!e)throw new Error(`Channel ${t} not found`);return e},copyFromChannel:AudioBuffer.prototype.copyFromChannel,copyToChannel:AudioBuffer.prototype.copyToChannel}}};function n(t,e){const i=e.xmlns?document.createElementNS(e.xmlns,t):document.createElement(t);for(const[t,s]of Object.entries(e))if("children"===t&&s)for(const[t,e]of Object.entries(s))e instanceof Node?i.appendChild(e):"string"==typeof e?i.appendChild(document.createTextNode(e)):i.appendChild(n(t,e));else"style"===t?Object.assign(i.style,s):"textContent"===t?i.textContent=s:i.setAttribute(t,s.toString());return i}function s(t,e,i){const s=n(t,e||{});return null==i||i.appendChild(s),s}function r(t){return t instanceof HTMLElement||"object"==typeof t&&null!==t&&t.nodeType===Node.ELEMENT_NODE&&"object"==typeof t.style}var o=Object.freeze({__proto__:null,createElement:s,default:s,isHTMLElement:r});const a={fetchBlob:function(e,i,n){return t(this,void 0,void 0,(function*(){var s;const r=yield fetch(e,n);if(r.status>=400)throw new Error(`Failed to fetch ${e}: ${r.status} (${r.statusText})`);return function(e,i,n){t(this,void 0,void 0,(function*(){var t;if(!e.body||!e.headers)return;const s=e.body.getReader(),r=Number(e.headers.get("Content-Length"))||0;let o=0;const a=()=>{s.cancel()};if(n){if(n.aborted)return void s.cancel();n.addEventListener("abort",a,{once:!0})}try{for(;;){const e=yield s.read();if(e.done)break;if(o+=(null===(t=e.value)||void 0===t?void 0:t.length)||0,r>0){const t=Math.round(o/r*100);i(t)}}}catch(t){if(t instanceof DOMException&&"AbortError"===t.name)return;console.warn("Progress tracking error:",t)}finally{n&&n.removeEventListener("abort",a)}}))}(r.clone(),i,null!==(s=null==n?void 0:n.signal)&&void 0!==s?s:void 0),r.blob()}))}};function l(t){let e=t;const i=new Set;return{get value(){return e},set(t){Object.is(e,t)||(e=t,i.forEach((t=>t(e))))},update(t){this.set(t(e))},subscribe:t=>(i.add(t),()=>i.delete(t))}}function h(t,e){const i=l(t());return e.forEach((e=>e.subscribe((()=>{const e=t();Object.is(i.value,e)||i.set(e)})))),{get value(){return i.value},subscribe:t=>i.subscribe(t)}}function c(t,e){let i;const n=()=>{i&&(i(),i=void 0),i=t()},s=e.map((t=>t.subscribe(n)));return n(),()=>{i&&(i(),i=void 0),s.forEach((t=>t()))}}class u extends e{get isPlayingSignal(){return this._isPlaying}get currentTimeSignal(){return this._currentTime}get durationSignal(){return this._duration}get volumeSignal(){return this._volume}get mutedSignal(){return this._muted}get playbackRateSignal(){return this._playbackRate}get seekingSignal(){return this._seeking}constructor(t){super(),this.isExternalMedia=!1,this._ownBlobUrl=null,this.reactiveMediaEventCleanups=[],t.media?(this.media=t.media,this.isExternalMedia=!0):this.media=document.createElement("audio"),this._isPlaying=l(!1),this._currentTime=l(0),this._duration=l(0),this._volume=l(this.media.volume),this._muted=l(this.media.muted),this._playbackRate=l(this.media.playbackRate||1),this._seeking=l(!1),this.setupReactiveMediaEvents(),t.mediaControls&&(this.media.controls=!0),t.autoplay&&(this.media.autoplay=!0),null!=t.playbackRate&&this.onMediaEvent("canplay",(()=>{null!=t.playbackRate&&(this.media.playbackRate=t.playbackRate)}),{once:!0})}setupReactiveMediaEvents(){this.reactiveMediaEventCleanups.push(this.onMediaEvent("play",(()=>{this._isPlaying.set(!0)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("pause",(()=>{this._isPlaying.set(!1)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("ended",(()=>{this._isPlaying.set(!1)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("timeupdate",(()=>{this._currentTime.set(this.media.currentTime)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("durationchange",(()=>{this._duration.set(this.media.duration||0)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("loadedmetadata",(()=>{this._duration.set(this.media.duration||0)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("seeking",(()=>{this._seeking.set(!0)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("seeked",(()=>{this._seeking.set(!1)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("volumechange",(()=>{this._volume.set(this.media.volume),this._muted.set(this.media.muted)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("ratechange",(()=>{this._playbackRate.set(this.media.playbackRate)})))}onMediaEvent(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e,i)}getSrc(){return this.media.currentSrc||this.media.src||""}revokeSrc(){this._ownBlobUrl&&(URL.revokeObjectURL(this._ownBlobUrl),this._ownBlobUrl=null)}canPlayType(t){return""!==this.media.canPlayType(t)}setSrc(t,e){const i=this.getSrc();if(t&&i===t)return;this.revokeSrc();const n=e instanceof Blob&&(this.canPlayType(e.type)||!t)?URL.createObjectURL(e):t;if(n!==t&&(this._ownBlobUrl=n),i&&this.media.removeAttribute("src"),n||t)try{this.media.src=n}catch(e){this.media.src=t}}destroy(){this.reactiveMediaEventCleanups.forEach((t=>t())),this.reactiveMediaEventCleanups=[],this.revokeSrc(),this.unAll(),this.isExternalMedia||(this.media.pause(),this.media.removeAttribute("src"),this.media.load(),this.media.remove())}setMediaElement(t){this.reactiveMediaEventCleanups.forEach((t=>t())),this.reactiveMediaEventCleanups=[],this.media=t,this.setupReactiveMediaEvents()}play(){return t(this,void 0,void 0,(function*(){try{return yield this.media.play()}catch(t){if(t instanceof DOMException&&"AbortError"===t.name)return;throw t}}))}pause(){this.media.pause()}isPlaying(){return!this.media.paused&&!this.media.ended}setTime(t){this.media.currentTime=Math.max(0,Math.min(t,this.getDuration()))}getDuration(){return this.media.duration}getCurrentTime(){return this.media.currentTime}getVolume(){return this.media.volume}setVolume(t){this.media.volume=t}getMuted(){return this.media.muted}setMuted(t){this.media.muted=t}getPlaybackRate(){return this.media.playbackRate}isSeeking(){return this.media.seeking}setPlaybackRate(t,e){null!=e&&(this.media.preservesPitch=e),this.media.playbackRate=t}getMediaElement(){return this.media}setSinkId(t){return this.media.setSinkId(t)}}function d({maxTop:t,maxBottom:e,halfHeight:i,vScale:n,barMinHeight:s=0,barAlign:r}){let o=Math.round(t*i*n);let a=o+Math.round(e*i*n)||1;return a<s&&(a=s,r||(o=a/2)),{topHeight:o,totalHeight:a}}function p({barAlign:t,halfHeight:e,topHeight:i,totalHeight:n,canvasHeight:s}){return"top"===t?0:"bottom"===t?s-n:e-i}function m(t,e,i){const n=e-t.left,s=i-t.top;return[n/t.width,s/t.height]}function g(t){return Boolean(t.barWidth||t.barGap||t.barAlign)}function f(t,e){if(!g(e))return t;const i=e.barWidth||.5,n=i+(e.barGap||i/2);return 0===n?t:Math.floor(t/n)*n}function v({scrollLeft:t,totalWidth:e,numCanvases:i}){if(0===e)return[0];const n=t/e,s=Math.floor(n*i);return[s-1,s,s+1]}function b(t){const e=t._cleanup;"function"==typeof e&&e()}function y(t){const e=l({scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,clientWidth:t.clientWidth}),i=h((()=>function(t){const{scrollLeft:e,scrollWidth:i,clientWidth:n}=t;if(0===i)return{startX:0,endX:1};const s=e/i,r=(e+n)/i;return{startX:Math.max(0,Math.min(1,s)),endX:Math.max(0,Math.min(1,r))}}(e.value)),[e]),n=h((()=>function(t){return{left:t.scrollLeft,right:t.scrollLeft+t.clientWidth}}(e.value)),[e]),s=()=>{e.set({scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,clientWidth:t.clientWidth})};t.addEventListener("scroll",s,{passive:!0});return{scrollData:e,percentages:i,bounds:n,cleanup:()=>{t.removeEventListener("scroll",s),b(e)}}}class C extends e{constructor(t,e){super(),this.timeouts=[],this.isScrollable=!1,this.audioData=null,this.resizeObserver=null,this.lastContainerWidth=0,this.isDragging=!1,this.subscriptions=[],this.unsubscribeOnScroll=[],this.dragStream=null,this.scrollStream=null,this.containerInlinePadding=0,this.onClickWrapper=t=>{const e=this.wrapper.getBoundingClientRect(),[i,n]=m(e,t.clientX,t.clientY);this.emit("click",i,n)},this.onDblClickWrapper=t=>{const e=this.wrapper.getBoundingClientRect(),[i,n]=m(e,t.clientX,t.clientY);this.emit("dblclick",i,n)},this.subscriptions=[],this.options=t;const i=this.parentFromOptionsContainer(t.container);this.parent=i;const[n,s]=this.initHtml();i.appendChild(n),this.container=n,this.scrollContainer=s.querySelector(".scroll"),this.wrapper=s.querySelector(".wrapper"),this.canvasWrapper=s.querySelector(".canvases"),this.progressWrapper=s.querySelector(".progress"),this.cursor=s.querySelector(".cursor"),this.calculateInlinePadding(),e&&s.appendChild(e),this.initEvents()}parentFromOptionsContainer(t){let e;if("string"==typeof t?e=document.querySelector(t):r(t)&&(e=t),!e)throw new Error("Container not found");return e}initEvents(){this.wrapper.addEventListener("click",this.onClickWrapper),this.wrapper.addEventListener("dblclick",this.onDblClickWrapper),!0!==this.options.dragToSeek&&"object"!=typeof this.options.dragToSeek||this.initDrag(),this.scrollStream=y(this.scrollContainer);const t=c((()=>{const{startX:t,endX:e}=this.scrollStream.percentages.value,{left:i,right:n}=this.scrollStream.bounds.value;this.emit("scroll",t,e,i,n)}),[this.scrollStream.percentages,this.scrollStream.bounds]);if(this.subscriptions.push(t),"function"==typeof ResizeObserver){const t=this.createDelay(100);this.resizeObserver=new ResizeObserver((()=>{t().then((()=>this.onContainerResize())).catch((()=>{}))})),this.resizeObserver.observe(this.scrollContainer)}}onContainerResize(){const t=this.parent.clientWidth;this.calculateInlinePadding(),t===this.lastContainerWidth&&"auto"!==this.options.height||(this.lastContainerWidth=t,this.reRender(),this.emit("resize"))}initDrag(){if(this.dragStream)return;this.dragStream=function(t,e={}){const{threshold:i=3,mouseButton:n=0,touchDelay:s=100}=e,r=l(null),o=new Map,a=matchMedia("(pointer: coarse)").matches;let h=()=>{};const c=e=>{if(e.button!==n)return;if(o.has(e.pointerId))return;if(o.set(e.pointerId,e),o.size>1)return;const l=e.pointerId;let c=e.clientX,u=e.clientY,d=!1;const p=Date.now(),m=t.getBoundingClientRect(),{left:g,top:f}=m,v=t=>{if(t.pointerId!==l)return;if(t.defaultPrevented||o.size>1)return;if(a&&Date.now()-p<s)return;const e=t.clientX,n=t.clientY,h=e-c,m=n-u;(d||Math.abs(h)>i||Math.abs(m)>i)&&(t.preventDefault(),t.stopPropagation(),d||(r.set({type:"start",x:c-g,y:u-f}),d=!0),r.set({type:"move",x:e-g,y:n-f,deltaX:h,deltaY:m}),c=e,u=n)},b=t=>{if(o.delete(t.pointerId)){if(t.pointerId===l&&d){const e=t.clientX,i=t.clientY;r.set({type:"end",x:e-g,y:i-f})}0===o.size&&h()}},y=t=>{t.relatedTarget&&t.relatedTarget!==document.documentElement||b(t)},C=t=>{d&&(t.stopPropagation(),t.preventDefault())},S=t=>{t.defaultPrevented||o.size>1||d&&t.preventDefault()};document.addEventListener("pointermove",v),document.addEventListener("pointerup",b),document.addEventListener("pointerout",y),document.addEventListener("pointercancel",y),document.addEventListener("touchmove",S,{passive:!1}),document.addEventListener("click",C,{capture:!0}),h=()=>{document.removeEventListener("pointermove",v),document.removeEventListener("pointerup",b),document.removeEventListener("pointerout",y),document.removeEventListener("pointercancel",y),document.removeEventListener("touchmove",S),setTimeout((()=>{document.removeEventListener("click",C,{capture:!0})}),10)}};return t.addEventListener("pointerdown",c),{signal:r,cleanup:()=>{h(),t.removeEventListener("pointerdown",c),o.clear(),b(r)}}}(this.wrapper);const t=c((()=>{const t=this.dragStream.signal.value;if(!t)return;const e=this.wrapper.getBoundingClientRect().width,i=(n=t.x/e)<0?0:n>1?1:n;var n;"start"===t.type?(this.isDragging=!0,this.emit("dragstart",i)):"move"===t.type?this.emit("drag",i):"end"===t.type&&(this.isDragging=!1,this.emit("dragend",i))}),[this.dragStream.signal]);this.subscriptions.push(t)}calculateInlinePadding(){const{paddingLeft:t,paddingRight:e}=getComputedStyle(this.scrollContainer),i=parseFloat(t)+parseFloat(e);this.containerInlinePadding=Number.isNaN(i)?0:i}initHtml(){const t=document.createElement("div"),e=t.attachShadow({mode:"open"}),i=this.options.cspNonce&&"string"==typeof this.options.cspNonce?this.options.cspNonce.replace(/"/g,""):"";return e.innerHTML=`\n <style${i?` nonce="${i}"`:""}>\n :host {\n user-select: none;\n min-width: 1px;\n }\n :host audio {\n display: block;\n width: 100%;\n }\n :host .scroll {\n overflow-x: auto;\n overflow-y: hidden;\n width: 100%;\n position: relative;\n }\n :host .noScrollbar {\n scrollbar-color: transparent;\n scrollbar-width: none;\n }\n :host .noScrollbar::-webkit-scrollbar {\n display: none;\n -webkit-appearance: none;\n }\n :host .wrapper {\n position: relative;\n overflow: visible;\n z-index: 2;\n }\n :host .canvases {\n min-height: ${this.getHeight(this.options.height,this.options.splitChannels)}px;\n pointer-events: none;\n }\n :host .canvases > div {\n position: relative;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n image-rendering: pixelated;\n }\n :host .progress {\n pointer-events: none;\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n overflow: hidden;\n }\n :host .progress > div {\n position: relative;\n }\n :host .cursor {\n pointer-events: none;\n position: absolute;\n z-index: 5;\n top: 0;\n left: 0;\n height: 100%;\n border-radius: 2px;\n }\n </style>\n\n <div class="scroll" part="scroll">\n <div class="wrapper" part="wrapper">\n <div class="canvases" part="canvases"></div>\n <div class="progress" part="progress"></div>\n <div class="cursor" part="cursor"></div>\n </div>\n </div>\n `,[t,e]}setOptions(t){var e;if(this.options.container!==t.container){const e=this.parentFromOptionsContainer(t.container);e.appendChild(this.container),this.parent=e}!0===t.dragToSeek||"object"==typeof this.options.dragToSeek?this.initDrag():(null===(e=this.dragStream)||void 0===e||e.cleanup(),this.dragStream=null),this.options=t,this.reRender()}getWrapper(){return this.wrapper}getWidth(){return this.scrollContainer.clientWidth-this.containerInlinePadding}getScroll(){return this.scrollContainer.scrollLeft}setScroll(t){this.scrollContainer.scrollLeft=t}setScrollPercentage(t){const{scrollWidth:e}=this.scrollContainer,i=e*t;this.setScroll(i)}destroy(){var t;this.wrapper.removeEventListener("click",this.onClickWrapper),this.wrapper.removeEventListener("dblclick",this.onDblClickWrapper),this.timeouts.forEach((t=>t())),this.timeouts=[],this.subscriptions.forEach((t=>t())),this.container.remove(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),null===(t=this.unsubscribeOnScroll)||void 0===t||t.forEach((t=>t())),this.unsubscribeOnScroll=[],this.dragStream&&(this.dragStream.cleanup(),this.dragStream=null),this.scrollStream&&(this.scrollStream.cleanup(),this.scrollStream=null)}createDelay(t=10){let e,i;const n=()=>{e&&(clearTimeout(e),e=void 0),i&&(i(),i=void 0)};return this.timeouts.push(n),()=>new Promise(((s,r)=>{n(),i=r,e=setTimeout((()=>{e=void 0,i=void 0,s()}),t)}))}getHeight(t,e){var i;const n=(null===(i=this.audioData)||void 0===i?void 0:i.numberOfChannels)||1;return function({optionsHeight:t,optionsSplitChannels:e,parentHeight:i,numberOfChannels:n,defaultHeight:s=128}){if(null==t)return s;const r=Number(t);if(!isNaN(r))return r;if("auto"===t){const t=i||s;return(null==e?void 0:e.every((t=>!t.overlay)))?t/n:t}return s}({optionsHeight:t,optionsSplitChannels:e,parentHeight:this.parent.clientHeight,numberOfChannels:n,defaultHeight:128})}convertColorValues(t,e){return function(t,e,i){if(!Array.isArray(t))return t||"";if(0===t.length)return"#999";if(t.length<2)return t[0]||"";const n=document.createElement("canvas"),s=n.getContext("2d");if(!s)return t[0]||"";const r=i||n.height*e,o=s.createLinearGradient(0,0,0,r),a=1/(t.length-1);return t.forEach(((t,e)=>{o.addColorStop(e*a,t)})),o}(t,this.getPixelRatio(),null==e?void 0:e.canvas.height)}getPixelRatio(){return t=window.devicePixelRatio,Math.max(1,t||1);// removed by dead control flow
|
|
4068
4361
|
var t; }renderBarWaveform(t,e,i,n){const{width:s,height:r}=i.canvas,{halfHeight:o,barWidth:a,barRadius:l,barIndexScale:h,barSpacing:c,barMinHeight:u}=function({width:t,height:e,length:i,options:n,pixelRatio:s}){const r=e/2,o=n.barWidth?n.barWidth*s:1,a=n.barGap?n.barGap*s:n.barWidth?o/2:0,l=o+a||1;return{halfHeight:r,barWidth:o,barGap:a,barRadius:n.barRadius||0,barMinHeight:n.barMinHeight?n.barMinHeight*s:0,barIndexScale:i>0?t/l/i:0,barSpacing:l}}({width:s,height:r,length:(t[0]||[]).length,options:e,pixelRatio:this.getPixelRatio()}),m=function({channelData:t,barIndexScale:e,barSpacing:i,barWidth:n,halfHeight:s,vScale:r,canvasHeight:o,barAlign:a,barMinHeight:l}){const h=t[0]||[],c=t[1]||h,u=h.length,m=[];let g=0,f=0,v=0;for(let t=0;t<=u;t++){const u=Math.round(t*e);if(u>g){const{topHeight:t,totalHeight:e}=d({maxTop:f,maxBottom:v,halfHeight:s,vScale:r,barMinHeight:l,barAlign:a}),h=p({barAlign:a,halfHeight:s,topHeight:t,totalHeight:e,canvasHeight:o});m.push({x:g*i,y:h,width:n,height:e}),g=u,f=0,v=0}const b=Math.abs(h[t]||0),y=Math.abs(c[t]||0);b>f&&(f=b),y>v&&(v=y)}return m}({channelData:t,barIndexScale:h,barSpacing:c,barWidth:a,halfHeight:o,vScale:n,canvasHeight:r,barAlign:e.barAlign,barMinHeight:u});i.beginPath();for(const t of m)l&&"roundRect"in i?i.roundRect(t.x,t.y,t.width,t.height,l):i.rect(t.x,t.y,t.width,t.height);i.fill(),i.closePath()}renderLineWaveform(t,e,i,n){const{width:s,height:r}=i.canvas,o=function({channelData:t,width:e,height:i,vScale:n}){const s=i/2,r=t[0]||[];return[r,t[1]||r].map(((t,i)=>{const r=t.length,o=r?e/r:0,a=s,l=0===i?-1:1,h=[{x:0,y:a}];let c=0,u=0;for(let e=0;e<=r;e++){const i=Math.round(e*o);if(i>c){const t=a+(Math.round(u*s*n)||1)*l;h.push({x:c,y:t}),c=i,u=0}const r=Math.abs(t[e]||0);r>u&&(u=r)}return h.push({x:c,y:a}),h}))}({channelData:t,width:s,height:r,vScale:n});i.beginPath();for(const t of o)if(t.length){i.moveTo(t[0].x,t[0].y);for(let e=1;e<t.length;e++){const n=t[e];i.lineTo(n.x,n.y)}}i.fill(),i.closePath()}renderWaveform(t,e,i){if(i.fillStyle=this.convertColorValues(e.waveColor,i),e.renderFunction)return void e.renderFunction(t,i);const n=function({channelData:t,barHeight:e,normalize:i,maxPeak:n}){var s;const r=e||1;if(!i)return r;const o=t[0];if(!o||0===o.length)return r;let a=null!=n?n:0;if(!n)for(let t=0;t<o.length;t++){const e=null!==(s=o[t])&&void 0!==s?s:0,i=Math.abs(e);i>a&&(a=i)}return a?r/a:r}({channelData:t,barHeight:e.barHeight,normalize:e.normalize,maxPeak:e.maxPeak});g(e)?this.renderBarWaveform(t,e,i,n):this.renderLineWaveform(t,e,i,n)}renderSingleCanvas(t,e,i,n,s,r,o){const a=this.getPixelRatio(),l=document.createElement("canvas");l.width=Math.round(i*a),l.height=Math.round(n*a),l.style.width=`${i}px`,l.style.height=`${n}px`,l.style.left=`${Math.round(s)}px`,r.appendChild(l);const h=l.getContext("2d");if(e.renderFunction?(h.fillStyle=this.convertColorValues(e.waveColor,h),e.renderFunction(t,h)):this.renderWaveform(t,e,h),l.width>0&&l.height>0){const t=l.cloneNode(),i=t.getContext("2d");i.drawImage(l,0,0),i.globalCompositeOperation="source-in",i.fillStyle=this.convertColorValues(e.progressColor,i),i.fillRect(0,0,l.width,l.height),o.appendChild(t)}}renderMultiCanvas(t,e,i,n,s,r){const o=this.getPixelRatio(),{clientWidth:a}=this.scrollContainer,l=i/o,h=function({clientWidth:t,totalWidth:e,options:i}){return f(Math.min(8e3,t,e),i)}({clientWidth:a,totalWidth:l,options:e});let c={};if(0===h)return;const u=i=>{if(i<0||i>=d)return;if(c[i])return;c[i]=!0;const o=i*h;let a=Math.min(l-o,h);if(a=f(a,e),a<=0)return;const u=function({channelData:t,offset:e,clampedWidth:i,totalWidth:n}){return t.map((t=>{const s=Math.floor(e/n*t.length),r=Math.floor((e+i)/n*t.length);return t.slice(s,r)}))}({channelData:t,offset:o,clampedWidth:a,totalWidth:l});this.renderSingleCanvas(u,e,a,n,o,s,r)},d=Math.ceil(l/h);if(!this.isScrollable){for(let t=0;t<d;t++)u(t);return}if(v({scrollLeft:this.scrollContainer.scrollLeft,totalWidth:l,numCanvases:d}).forEach((t=>u(t))),d>1){const t=this.on("scroll",(()=>{const{scrollLeft:t}=this.scrollContainer;Object.keys(c).length>10&&(s.innerHTML="",r.innerHTML="",c={}),v({scrollLeft:t,totalWidth:l,numCanvases:d}).forEach((t=>u(t)))}));this.unsubscribeOnScroll.push(t)}}renderChannel(t,e,i,n){var{overlay:s}=e,r=function(t,e){var i={};for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&e.indexOf(n)<0&&(i[n]=t[n]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var s=0;for(n=Object.getOwnPropertySymbols(t);s<n.length;s++)e.indexOf(n[s])<0&&Object.prototype.propertyIsEnumerable.call(t,n[s])&&(i[n[s]]=t[n[s]])}return i}(e,["overlay"]);const o=document.createElement("div"),a=this.getHeight(r.height,r.splitChannels);o.style.height=`${a}px`,s&&n>0&&(o.style.marginTop=`-${a}px`),this.canvasWrapper.style.minHeight=`${a}px`,this.canvasWrapper.appendChild(o);const l=o.cloneNode();this.progressWrapper.appendChild(l),this.renderMultiCanvas(t,r,i,a,o,l)}render(e){return t(this,void 0,void 0,(function*(){var t;this.timeouts.forEach((t=>t())),this.timeouts=[],this.unsubscribeOnScroll.forEach((t=>t())),this.unsubscribeOnScroll=[],this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="",null!=this.options.width&&(this.scrollContainer.style.width="number"==typeof this.options.width?`${this.options.width}px`:this.options.width);const i=this.getPixelRatio(),n=this.scrollContainer.clientWidth-this.containerInlinePadding,{scrollWidth:s,isScrollable:r,useParentWidth:o,width:a}=function({duration:t,minPxPerSec:e=0,parentWidth:i,fillParent:n,pixelRatio:s}){const r=Math.ceil(t*e),o=r>i,a=Boolean(n&&!o);return{scrollWidth:r,isScrollable:o,useParentWidth:a,width:(a?i:r)*s}}({duration:e.duration,minPxPerSec:this.options.minPxPerSec||0,parentWidth:n,fillParent:this.options.fillParent,pixelRatio:i});if(this.isScrollable=r,this.wrapper.style.width=o?"100%":`${s}px`,this.scrollContainer.style.overflowX=this.isScrollable?"auto":"hidden",this.scrollContainer.classList.toggle("noScrollbar",!!this.options.hideScrollbar),this.cursor.style.backgroundColor=`${this.options.cursorColor||this.options.progressColor}`,this.cursor.style.width=`${this.options.cursorWidth}px`,this.audioData=e,this.emit("render"),this.options.splitChannels)for(let i=0;i<e.numberOfChannels;i++){const n=Object.assign(Object.assign({},this.options),null===(t=this.options.splitChannels)||void 0===t?void 0:t[i]);this.renderChannel([e.getChannelData(i)],n,a,i)}else{const t=[e.getChannelData(0)];e.numberOfChannels>1&&t.push(e.getChannelData(1)),this.renderChannel(t,this.options,a,0)}Promise.resolve().then((()=>this.emit("rendered")))}))}reRender(){if(this.unsubscribeOnScroll.forEach((t=>t())),this.unsubscribeOnScroll=[],!this.audioData)return;const{scrollWidth:t}=this.scrollContainer,{right:e}=this.progressWrapper.getBoundingClientRect();if(this.render(this.audioData),!this.isScrollable&&this.scrollContainer.scrollLeft)this.scrollContainer.scrollLeft=0;else if(this.isScrollable&&t!==this.scrollContainer.scrollWidth){const{right:t}=this.progressWrapper.getBoundingClientRect(),i=function(t){const e=2*t;return(e<0?Math.floor(e):Math.ceil(e))/2}(t-e);this.scrollContainer.scrollLeft+=i}}zoom(t){this.options.minPxPerSec=t,this.reRender()}scrollIntoView(t,e=!1){var i;const{scrollLeft:n,scrollWidth:s,clientWidth:r}=this.scrollContainer,o=t*s,a=n,l=n+r,h=r/2;if(this.isDragging){const t=30;o+t>l?this.scrollContainer.scrollLeft+=t:o-t<a&&(this.scrollContainer.scrollLeft-=t)}else{(o<a||o>l)&&(this.scrollContainer.scrollLeft=o-(this.options.autoCenter?h:0));const t=o-n-h;if(e&&this.options.autoCenter&&t>0){const e=null===(i=this.audioData)||void 0===i?void 0:i.duration;if(void 0===e||e<=0)return void(this.scrollContainer.scrollLeft+=t);const n=s/e;this.scrollContainer.scrollLeft+=n<=600?Math.min(t,10):t}}}renderProgress(t,e){if(isNaN(t))return;const i=100*t;this.canvasWrapper.style.clipPath=`polygon(${i}% 0%, 100% 0%, 100% 100%, ${i}% 100%)`,this.progressWrapper.style.width=`${i}%`,this.cursor.style.left=`${i}%`,this.cursor.style.transform=this.options.cursorWidth?`translateX(-${t*this.options.cursorWidth}px)`:"",this.isScrollable&&this.options.autoScroll&&this.audioData&&this.audioData.duration>0&&this.scrollIntoView(t,e)}exportImage(e,i,n){return t(this,void 0,void 0,(function*(){const t=this.canvasWrapper.querySelectorAll("canvas");if(!t.length)throw new Error("No waveform data");if("dataURL"===n){const n=Array.from(t).map((t=>t.toDataURL(e,i)));return Promise.resolve(n)}return Promise.all(Array.from(t).map((t=>new Promise(((n,s)=>{t.toBlob((t=>{t?n(t):s(new Error("Could not export image"))}),e,i)})))))}))}}class S extends e{constructor(){super(...arguments),this.animationFrameId=null,this.isRunning=!1}start(){if(this.isRunning)return;this.isRunning=!0;const t=()=>{this.isRunning&&(this.emit("tick"),this.animationFrameId=requestAnimationFrame(t))};t()}stop(){this.isRunning=!1,null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}destroy(){this.stop(),this.unAll()}}class E extends e{constructor(t){super(),this.bufferNode=null,this.playStartTime=0,this.playbackPosition=0,this._muted=!1,this._playbackRate=1,this._duration=void 0,this.buffer=null,this.currentSrc="",this.paused=!0,this.crossOrigin=null,this.seeking=!1,this.autoplay=!1,this.addEventListener=this.on,this.removeEventListener=this.un,this._destroyed=!1,function(){const t=globalThis.navigator;if(null==t?void 0:t.audioSession)try{t.audioSession.type="playback"}catch(t){console.warn("Setting navigator.audioSession.type failed:",t)}}(),this.audioContext=t||new AudioContext,this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination)}load(){return t(this,void 0,void 0,(function*(){}))}remove(){this.destroy()}destroy(){if(!this._destroyed){if(this._destroyed=!0,this.currentSrc="",this.bufferNode){this.bufferNode.onended=null;try{this.bufferNode.stop()}catch(t){}this.bufferNode.disconnect(),this.bufferNode=null}this.gainNode.disconnect(),"function"==typeof this.audioContext.close&&Promise.resolve(this.audioContext.close.call(this.audioContext)).catch((()=>{})),this.buffer=null,this.unAll()}}get src(){return this.currentSrc}set src(t){if(this.currentSrc=t,this._duration=void 0,!t)return this.buffer=null,void this.emit("emptied");fetch(t).then((e=>{if(e.status>=400)throw new Error(`Failed to fetch ${t}: ${e.status} (${e.statusText})`);return e.arrayBuffer()})).then((e=>this.currentSrc!==t?null:this.audioContext.decodeAudioData(e))).then((e=>{this.currentSrc===t&&(this.buffer=e,this.emit("loadedmetadata"),this.emit("canplay"),this.autoplay&&this.play())})).catch((t=>{console.error("WebAudioPlayer load error:",t)}))}_play(){if(!this.paused)return;this.paused=!1,this.bufferNode&&(this.bufferNode.onended=null,this.bufferNode.disconnect()),this.bufferNode=this.audioContext.createBufferSource(),this.buffer&&(this.bufferNode.buffer=this.buffer),this.bufferNode.playbackRate.value=this._playbackRate,this.bufferNode.connect(this.gainNode);let t=this.playbackPosition;(t>=this.duration||t<0)&&(t=0,this.playbackPosition=0),this.bufferNode.start(this.audioContext.currentTime,t),this.playStartTime=this.audioContext.currentTime,this.bufferNode.onended=()=>{!this.paused&&this.duration-this.currentTime<.01&&(this.pause(),this.emit("ended"))}}_pause(){if(this.paused=!0,this.bufferNode){this.bufferNode.onended=null;try{this.bufferNode.stop()}catch(t){}}this.playbackPosition+=(this.audioContext.currentTime-this.playStartTime)*this._playbackRate}play(){return t(this,void 0,void 0,(function*(){this.paused&&(this._play(),this.emit("play"))}))}pause(){this.paused||(this._pause(),this.emit("pause"))}stopAt(t){const e=(t-this.currentTime)/this._playbackRate,i=this.bufferNode;null==i||i.stop(this.audioContext.currentTime+e),null==i||i.addEventListener("ended",(()=>{i===this.bufferNode&&(this.bufferNode=null,this.pause(),this.playbackPosition=Math.min(t,this.duration),this.emit("timeupdate"))}),{once:!0})}setSinkId(e){return t(this,void 0,void 0,(function*(){return this.audioContext.setSinkId(e)}))}get playbackRate(){return this._playbackRate}set playbackRate(t){const e=!this.paused;e&&this._pause(),this._playbackRate=t,e&&this._play(),this.bufferNode&&(this.bufferNode.playbackRate.value=t)}get currentTime(){return this.paused?this.playbackPosition:this.playbackPosition+(this.audioContext.currentTime-this.playStartTime)*this._playbackRate}set currentTime(t){const e=!this.paused;e&&this._pause(),this.playbackPosition=t,e&&this._play(),this.emit("seeking"),this.emit("timeupdate")}get duration(){var t,e;return null!==(t=this._duration)&&void 0!==t?t:(null===(e=this.buffer)||void 0===e?void 0:e.duration)||0}set duration(t){this._duration=t}get volume(){return this.gainNode.gain.value}set volume(t){this.gainNode.gain.value=t,this.emit("volumechange")}get muted(){return this._muted}set muted(t){this._muted!==t&&(this._muted=t,this._muted?this.gainNode.disconnect():this.gainNode.connect(this.audioContext.destination))}canPlayType(t){return/^(audio|video)\//.test(t)}getGainNode(){return this.gainNode}getChannelData(){const t=[];if(!this.buffer)return t;const e=this.buffer.numberOfChannels;for(let i=0;i<e;i++)t.push(this.buffer.getChannelData(i));return t}removeAttribute(t){switch(t){case"src":this.src="";break;case"playbackRate":this.playbackRate=0;break;case"currentTime":this.currentTime=0;break;case"duration":this.duration=0;break;case"volume":this.volume=0;break;case"muted":this.muted=!1}}}const P={waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,dragToSeek:!1,autoScroll:!0,autoCenter:!0,sampleRate:8e3};class w extends u{static create(t){return new w(t)}getState(){return this.wavesurferState}getRenderer(){return this.renderer}constructor(t){const e=t.media||("WebAudio"===t.backend?new E:void 0);super({media:e,mediaControls:t.mediaControls,autoplay:t.autoplay,playbackRate:t.audioRate}),this.plugins=[],this.decodedData=null,this.stopAtPosition=null,this.subscriptions=[],this.mediaSubscriptions=[],this.abortController=null,this._isDestroyed=!1,this._loadVersion=0,this.reactiveCleanups=[],this.options=Object.assign({},P,t);const{state:i,actions:n}=function(t){var e,i,n,s,r,o;const a=null!==(e=null==t?void 0:t.currentTime)&&void 0!==e?e:l(0),c=null!==(i=null==t?void 0:t.duration)&&void 0!==i?i:l(0),u=null!==(n=null==t?void 0:t.isPlaying)&&void 0!==n?n:l(!1),d=null!==(s=null==t?void 0:t.isSeeking)&&void 0!==s?s:l(!1),p=null!==(r=null==t?void 0:t.volume)&&void 0!==r?r:l(1),m=null!==(o=null==t?void 0:t.playbackRate)&&void 0!==o?o:l(1),g=l(null),f=l(null),v=l(""),b=l(0),y=l(0),C=h((()=>!u.value),[u]),S=h((()=>null!==g.value),[g]),E=h((()=>S.value&&c.value>0),[S,c]),P=h((()=>a.value),[a]),w=h((()=>c.value>0?a.value/c.value:0),[a,c]);return{state:{currentTime:a,duration:c,isPlaying:u,isPaused:C,isSeeking:d,volume:p,playbackRate:m,audioBuffer:g,peaks:f,url:v,zoom:b,scrollPosition:y,canPlay:S,isReady:E,progress:P,progressPercent:w},actions:{setCurrentTime:t=>{const e=Math.max(0,Math.min(c.value||1/0,t));a.set(e)},setDuration:t=>{c.set(Math.max(0,t))},setPlaying:t=>{u.set(t)},setSeeking:t=>{d.set(t)},setVolume:t=>{const e=Math.max(0,Math.min(1,t));p.set(e)},setPlaybackRate:t=>{const e=Math.max(.1,Math.min(16,t));m.set(e)},setAudioBuffer:t=>{g.set(t),t&&c.set(t.duration)},setPeaks:t=>{f.set(t)},setUrl:t=>{v.set(t)},setZoom:t=>{b.set(Math.max(0,t))},setScrollPosition:t=>{y.set(Math.max(0,t))}}}}({isPlaying:this.isPlayingSignal,currentTime:this.currentTimeSignal,duration:this.durationSignal,volume:this.volumeSignal,playbackRate:this.playbackRateSignal,isSeeking:this.seekingSignal});this.wavesurferState=i,this.wavesurferActions=n,this.timer=new S;const s=e?void 0:this.getMediaElement();this.renderer=new C(this.options,s),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReactiveState(),this.initPlugins();const r=this.options.url||this.getSrc()||"";Promise.resolve().then((()=>{this.emit("init");const{peaks:t,duration:e}=this.options;(r||t&&e)&&this.load(r,t,e).catch((()=>{}))}))}updateProgress(t=this.getCurrentTime()){return this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),t}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{if(!this.isSeeking()){const t=this.updateProgress();if(this.emit("timeupdate",t),this.emit("audioprocess",t),null!=this.stopAtPosition&&this.isPlaying()&&t>=this.stopAtPosition){const t=this.stopAtPosition;this.pause(),this.setTime(t)}}})))}initReactiveState(){this.reactiveCleanups.push(function(t,e){const i=[];i.push(c((()=>{const i=t.isPlaying.value;e.emit(i?"play":"pause")}),[t.isPlaying])),i.push(c((()=>{const i=t.currentTime.value;e.emit("timeupdate",i),t.isPlaying.value&&e.emit("audioprocess",i)}),[t.currentTime,t.isPlaying])),i.push(c((()=>{t.isSeeking.value&&e.emit("seeking",t.currentTime.value)}),[t.isSeeking,t.currentTime]));let n=!1;i.push(c((()=>{t.isReady.value&&!n&&(n=!0,e.emit("ready",t.duration.value))}),[t.isReady,t.duration])),i.push(c((()=>{null===t.audioBuffer.value&&(n=!1)}),[t.audioBuffer]));let s=!1;return i.push(c((()=>{const i=t.isPlaying.value,n=t.currentTime.value,r=t.duration.value,o=r>0&&n>=r;s&&!i&&o&&e.emit("finish"),s=i&&o}),[t.isPlaying,t.currentTime,t.duration])),i.push(c((()=>{const i=t.zoom.value;i>0&&e.emit("zoom",i)}),[t.zoom])),()=>{i.forEach((t=>t()))}}(this.wavesurferState,{emit:this.emit.bind(this)}))}initPlayerEvents(){this.isPlaying()&&(this.emit("play"),this.timer.start()),this.mediaSubscriptions.push(this.onMediaEvent("timeupdate",(()=>{const t=this.updateProgress();this.emit("timeupdate",t)})),this.onMediaEvent("play",(()=>{this.emit("play"),this.timer.start()})),this.onMediaEvent("pause",(()=>{this.emit("pause"),this.timer.stop(),this.stopAtPosition=null})),this.onMediaEvent("emptied",(()=>{this.timer.stop(),this.stopAtPosition=null})),this.onMediaEvent("ended",(()=>{this.emit("timeupdate",this.getDuration()),this.emit("finish"),this.stopAtPosition=null})),this.onMediaEvent("seeking",(()=>{this.emit("seeking",this.getCurrentTime())})),this.onMediaEvent("error",(()=>{var t;this.emit("error",null!==(t=this.getMediaElement().error)&&void 0!==t?t:new Error("Media error")),this.stopAtPosition=null})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",((t,e)=>{this.options.interact&&(this.seekTo(t),this.emit("interaction",t*this.getDuration()),this.emit("click",t,e))})),this.renderer.on("dblclick",((t,e)=>{this.emit("dblclick",t,e)})),this.renderer.on("scroll",((t,e,i,n)=>{const s=this.getDuration();this.emit("scroll",t*s,e*s,i,n)})),this.renderer.on("render",(()=>{this.emit("redraw")})),this.renderer.on("rendered",(()=>{this.emit("redrawcomplete")})),this.renderer.on("dragstart",(t=>{this.emit("dragstart",t)})),this.renderer.on("dragend",(t=>{this.emit("dragend",t)})),this.renderer.on("resize",(()=>{this.emit("resize")})));{let t;const e=this.renderer.on("drag",(e=>{var i;if(!this.options.interact)return;this.renderer.renderProgress(e),clearTimeout(t);let n=0;const s=this.options.dragToSeek;this.isPlaying()?n=0:!0===s?n=200:s&&"object"==typeof s&&(n=null!==(i=s.debounceTime)&&void 0!==i?i:200),t=setTimeout((()=>{this.seekTo(e)}),n),this.emit("interaction",e*this.getDuration()),this.emit("drag",e)}));this.subscriptions.push((()=>{clearTimeout(t),e()}))}}initPlugins(){var t;(null===(t=this.options.plugins)||void 0===t?void 0:t.length)&&this.options.plugins.forEach((t=>{this.registerPlugin(t)}))}unsubscribePlayerEvents(){this.mediaSubscriptions.forEach((t=>t())),this.mediaSubscriptions=[]}setOptions(t){this.options=Object.assign({},this.options,t),t.duration&&!t.peaks&&(this.decodedData=i.createBuffer(this.exportPeaks(),t.duration)),t.peaks&&t.duration&&(this.decodedData=i.createBuffer(t.peaks,t.duration)),this.renderer.setOptions(this.options),t.audioRate&&this.setPlaybackRate(t.audioRate),null!=t.mediaControls&&(this.getMediaElement().controls=t.mediaControls)}registerPlugin(t){if(this.plugins.includes(t))return t;t._init(this),this.plugins.push(t);const e=t.once("destroy",(()=>{this.plugins=this.plugins.filter((e=>e!==t)),this.subscriptions=this.subscriptions.filter((t=>t!==e))}));return this.subscriptions.push(e),t}unregisterPlugin(t){this.plugins=this.plugins.filter((e=>e!==t)),t.destroy()}getWrapper(){return this.renderer.getWrapper()}getWidth(){return this.renderer.getWidth()}getScroll(){return this.renderer.getScroll()}setScroll(t){return this.renderer.setScroll(t)}setScrollTime(t){const e=t/this.getDuration();this.renderer.setScrollPercentage(e)}getActivePlugins(){return this.plugins}loadAudio(e,n,s,r){return t(this,void 0,void 0,(function*(){var t;const o=++this._loadVersion;if(this._isDestroyed=!1,this.emit("load",e),!this.options.media&&this.isPlaying()&&this.pause(),this.decodedData=null,this.stopAtPosition=null,null===(t=this.abortController)||void 0===t||t.abort(),this.abortController=null,!n&&!s){const t=this.options.fetchParams||{};window.AbortController&&!t.signal&&(this.abortController=new AbortController,t.signal=this.abortController.signal);const i=t=>this.emit("loading",t);if(n=yield a.fetchBlob(e,i,t),this._isDestroyed||o!==this._loadVersion)return;const s=this.options.blobMimeType;s&&(n=new Blob([n],{type:s}))}if(this._isDestroyed||o!==this._loadVersion)return;this.setSrc(e,n);const l=yield new Promise((t=>{const e=r||this.getDuration();e?t(e):this.mediaSubscriptions.push(this.onMediaEvent("loadedmetadata",(()=>t(this.getDuration())),{once:!0}))}));if(!this._isDestroyed&&o===this._loadVersion){if(!e&&!n){const t=this.getMediaElement();t instanceof E&&(t.duration=l)}if(s)this.decodedData=i.createBuffer(s,l||0);else if(n){const t=yield n.arrayBuffer();if(this._isDestroyed||o!==this._loadVersion)return;this.decodedData=yield i.decode(t,this.options.sampleRate)}this._isDestroyed||o!==this._loadVersion||(this.decodedData&&(this.emit("decode",this.getDuration()),this.renderer.render(this.decodedData)),this.emit("ready",this.getDuration()))}}))}load(e,i,n){return t(this,void 0,void 0,(function*(){try{return yield this.loadAudio(e,void 0,i,n)}catch(t){throw this.emit("error",t),t}}))}loadBlob(e,i,n){return t(this,void 0,void 0,(function*(){try{return yield this.loadAudio("",e,i,n)}catch(t){throw this.emit("error",t),t}}))}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(t),this.emit("zoom",t)}getDecodedData(){return this.decodedData}exportPeaks({channels:t=2,maxLength:e=8e3,precision:i=1e4}={}){if(!this.decodedData)throw new Error("The audio has not been decoded yet");const n=Math.min(t,this.decodedData.numberOfChannels),s=[];for(let t=0;t<n;t++){const n=this.decodedData.getChannelData(t),r=[],o=n.length/e;for(let t=0;t<e;t++){const e=n.slice(Math.floor(t*o),Math.ceil((t+1)*o));let s=0;for(let t=0;t<e.length;t++){const i=e[t];Math.abs(i)>Math.abs(s)&&(s=i)}r.push(Math.round(s*i)/i)}s.push(r)}return s}getDuration(){let t=super.getDuration()||0;return 0!==t&&t!==1/0||!this.decodedData||(t=this.decodedData.duration),t}toggleInteraction(t){this.options.interact=t}setTime(t){this.stopAtPosition=null,super.setTime(t),this.updateProgress(t),this.emit("timeupdate",t)}seekTo(t){const e=this.getDuration()*t;this.setTime(e)}play(e,i){const n=Object.create(null,{play:{get:()=>super.play}});return t(this,void 0,void 0,(function*(){null!=e&&this.setTime(e);const t=yield n.play.call(this);return null!=i&&(this.media instanceof E?this.media.stopAt(i):this.stopAtPosition=i),t}))}playPause(){return t(this,void 0,void 0,(function*(){return this.isPlaying()?this.pause():this.play()}))}stop(){this.pause(),this.setTime(0)}skip(t){this.setTime(this.getCurrentTime()+t)}empty(){this.load("",[[0]],.001)}setMediaElement(t){this.unsubscribePlayerEvents(),super.setMediaElement(t),this.initPlayerEvents()}exportImage(){return t(this,arguments,void 0,(function*(t="image/png",e=1,i="dataURL"){return this.renderer.exportImage(t,e,i)}))}destroy(){var t;this._isDestroyed=!0,this.emit("destroy"),null===(t=this.abortController)||void 0===t||t.abort(),this.plugins.forEach((t=>t.destroy())),this.subscriptions.forEach((t=>t())),this.unsubscribePlayerEvents(),this.reactiveCleanups.forEach((t=>t())),this.reactiveCleanups=[],this.timer.destroy(),this.renderer.destroy(),super.destroy()}}w.BasePlugin=class extends e{constructor(t){super(),this.subscriptions=[],this.isDestroyed=!1,this.options=t}onInit(){}_init(t){this.isDestroyed&&(this.subscriptions=[],this.isDestroyed=!1),this.wavesurfer=t,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t())),this.subscriptions=[],this.isDestroyed=!0,this.wavesurfer=void 0}},w.dom=o;
|
|
4069
4362
|
|
|
4363
|
+
// EXTERNAL MODULE: ./src/lib/util.js + 1 modules
|
|
4364
|
+
var util = __webpack_require__(4410);
|
|
4070
4365
|
;// ./src/lib/viewers/media/waveform/colors.ts
|
|
4071
4366
|
/**
|
|
4072
4367
|
* Figma Audio Player waveform tokens as opaque fills.
|
|
@@ -4085,14 +4380,6 @@ const WAVEFORM_COLOR_HOVER_PLAYED = whiteOnBlack(0.9);
|
|
|
4085
4380
|
const WAVEFORM_COLOR_HOVER_AREA = whiteOnBlack(0.6);
|
|
4086
4381
|
const WAVEFORM_COLOR_HOVER_UNPLAYED = whiteOnBlack(0.3);
|
|
4087
4382
|
const WAVEFORM_COLOR_HOVER_BUFFER = whiteOnBlack(0.16);
|
|
4088
|
-
|
|
4089
|
-
/** One canvas linear-gradient stop. `offset` is 0–1 along the bar. */
|
|
4090
|
-
|
|
4091
|
-
/**
|
|
4092
|
-
* Wavesurfer's two paints: left of the playhead (`progressColor`) and right of it (`waveColor`).
|
|
4093
|
-
* A string is a solid fill; a stop list is a left-to-right step gradient.
|
|
4094
|
-
*/
|
|
4095
|
-
|
|
4096
4383
|
/** Pin a value to the closed interval [0, 1]. */
|
|
4097
4384
|
function clampTo0And1(value) {
|
|
4098
4385
|
if (!Number.isFinite(value) || value < 0) {
|
|
@@ -4227,29 +4514,144 @@ function toCanvasFill(color, widthPx) {
|
|
|
4227
4514
|
});
|
|
4228
4515
|
return gradient;
|
|
4229
4516
|
}
|
|
4517
|
+
|
|
4518
|
+
/** Untinted bar pixels for each WaveSurfer tile, so hover can re-tint without stacking. */
|
|
4519
|
+
const tileBarSnapshots = new WeakMap();
|
|
4520
|
+
|
|
4521
|
+
/** Restore the last bar snapshot, or take a new one after WaveSurfer redraws. */
|
|
4522
|
+
function restoreOrSnapshotTile(canvas, context, replaceSnapshot) {
|
|
4523
|
+
if (!(canvas.width > 0) || !(canvas.height > 0) || !context.getImageData) {
|
|
4524
|
+
return;
|
|
4525
|
+
}
|
|
4526
|
+
const stored = tileBarSnapshots.get(canvas);
|
|
4527
|
+
if (!replaceSnapshot && stored && context.putImageData) {
|
|
4528
|
+
context.putImageData(stored, 0, 0);
|
|
4529
|
+
return;
|
|
4530
|
+
}
|
|
4531
|
+
try {
|
|
4532
|
+
tileBarSnapshots.set(canvas, context.getImageData(0, 0, canvas.width, canvas.height));
|
|
4533
|
+
} catch {
|
|
4534
|
+
// Tainted or zero-size canvases cannot snapshot; tint in place.
|
|
4535
|
+
}
|
|
4536
|
+
}
|
|
4537
|
+
|
|
4538
|
+
/** CSS width of a tile canvas (style.width, then clientWidth, then bitmap width). */
|
|
4539
|
+
function tileWidthCss(canvas) {
|
|
4540
|
+
const styled = parseFloat(canvas.style.width);
|
|
4541
|
+
if (styled > 0) {
|
|
4542
|
+
return styled;
|
|
4543
|
+
}
|
|
4544
|
+
if (canvas.clientWidth > 0) {
|
|
4545
|
+
return canvas.clientWidth;
|
|
4546
|
+
}
|
|
4547
|
+
return canvas.width;
|
|
4548
|
+
}
|
|
4549
|
+
|
|
4550
|
+
/** Solid color, or a gradient aligned to the full waveform and shifted to this tile. */
|
|
4551
|
+
function fillForTile(context, color, totalWidthCss, offsetCss, canvas) {
|
|
4552
|
+
if (typeof color === 'string') {
|
|
4553
|
+
return color;
|
|
4554
|
+
}
|
|
4555
|
+
const cssWidth = tileWidthCss(canvas);
|
|
4556
|
+
const scale = cssWidth > 0 ? canvas.width / cssWidth : 1;
|
|
4557
|
+
if (!(totalWidthCss > 0) || !(scale > 0)) {
|
|
4558
|
+
return color[0] ? color[0].color : WAVEFORM_COLOR_UNPLAYED;
|
|
4559
|
+
}
|
|
4560
|
+
const x0 = -offsetCss * scale || 0;
|
|
4561
|
+
const x1 = (totalWidthCss - offsetCss) * scale;
|
|
4562
|
+
const gradient = context.createLinearGradient(x0, 0, x1, 0);
|
|
4563
|
+
let lastOffset = -1;
|
|
4564
|
+
color.forEach(stop => {
|
|
4565
|
+
let offset = clampTo0And1(stop.offset);
|
|
4566
|
+
if (offset <= lastOffset) {
|
|
4567
|
+
offset = Math.min(1, lastOffset + 1e-6);
|
|
4568
|
+
}
|
|
4569
|
+
lastOffset = offset;
|
|
4570
|
+
gradient.addColorStop(offset, stop.color);
|
|
4571
|
+
});
|
|
4572
|
+
return gradient;
|
|
4573
|
+
}
|
|
4574
|
+
|
|
4575
|
+
/**
|
|
4576
|
+
* Wavesurfer splits a zoomed waveform into viewport-sized tiles and paints each
|
|
4577
|
+
* from x=0. Re-tint with a gradient in global waveform space so hover/buffer
|
|
4578
|
+
* colors do not repeat on the last tile.
|
|
4579
|
+
*/
|
|
4580
|
+
function tintWaveformTiles({
|
|
4581
|
+
fills,
|
|
4582
|
+
host,
|
|
4583
|
+
replaceSnapshot = false,
|
|
4584
|
+
totalWidthCss
|
|
4585
|
+
}) {
|
|
4586
|
+
if (!(totalWidthCss > 0) || !host.querySelectorAll) {
|
|
4587
|
+
return;
|
|
4588
|
+
}
|
|
4589
|
+
const groups = [{
|
|
4590
|
+
canvases: host.querySelectorAll('.canvases canvas'),
|
|
4591
|
+
color: fills.waveColor
|
|
4592
|
+
}, {
|
|
4593
|
+
canvases: host.querySelectorAll('.progress canvas'),
|
|
4594
|
+
color: fills.progressColor
|
|
4595
|
+
}];
|
|
4596
|
+
groups.forEach(({
|
|
4597
|
+
canvases,
|
|
4598
|
+
color
|
|
4599
|
+
}) => {
|
|
4600
|
+
canvases.forEach(canvas => {
|
|
4601
|
+
const context = canvas.getContext('2d');
|
|
4602
|
+
if (!context) {
|
|
4603
|
+
return;
|
|
4604
|
+
}
|
|
4605
|
+
restoreOrSnapshotTile(canvas, context, replaceSnapshot);
|
|
4606
|
+
const offsetCss = parseFloat(canvas.style.left) || 0;
|
|
4607
|
+
context.save();
|
|
4608
|
+
context.globalCompositeOperation = 'source-in';
|
|
4609
|
+
context.fillStyle = fillForTile(context, color, totalWidthCss, offsetCss, canvas);
|
|
4610
|
+
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
4611
|
+
context.restore();
|
|
4612
|
+
});
|
|
4613
|
+
});
|
|
4614
|
+
}
|
|
4230
4615
|
;// ./src/lib/viewers/media/waveform/WaveformView.scss
|
|
4231
4616
|
// extracted by mini-css-extract-plugin
|
|
4232
4617
|
|
|
4233
4618
|
;// ./src/lib/viewers/media/waveform/WaveformView.tsx
|
|
4619
|
+
function WaveformView_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4620
|
+
function WaveformView_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? WaveformView_ownKeys(Object(t), !0).forEach(function (r) { WaveformView_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : WaveformView_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4621
|
+
function WaveformView_defineProperty(e, r, t) { return (r = WaveformView_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
4622
|
+
function WaveformView_toPropertyKey(t) { var i = WaveformView_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
4623
|
+
function WaveformView_toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4234
4624
|
|
|
4235
4625
|
|
|
4236
4626
|
|
|
4237
4627
|
|
|
4238
4628
|
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
return `${progress * 100}%`;
|
|
4248
|
-
}
|
|
4249
|
-
function fillWidth(widthCssPx) {
|
|
4629
|
+
|
|
4630
|
+
|
|
4631
|
+
|
|
4632
|
+
|
|
4633
|
+
/** Pointer X in the view and the media time under it; zoom keeps this point fixed. */
|
|
4634
|
+
|
|
4635
|
+
/** CSS width × devicePixelRatio, for canvas gradient fills. */
|
|
4636
|
+
function devicePixelWidth(widthCssPx) {
|
|
4250
4637
|
const pixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;
|
|
4251
4638
|
return widthCssPx * pixelRatio;
|
|
4252
4639
|
}
|
|
4640
|
+
function prefersReducedMotion() {
|
|
4641
|
+
return typeof window !== 'undefined' && typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
4642
|
+
}
|
|
4643
|
+
function getScrollLeft(wavesurfer, fallback = 0) {
|
|
4644
|
+
return wavesurfer && wavesurfer.getScroll ? wavesurfer.getScroll() : fallback;
|
|
4645
|
+
}
|
|
4646
|
+
|
|
4647
|
+
/** CSS left % of the playhead from the left of the visible window. */
|
|
4648
|
+
function timeLeftPercent(timeSec, durationSec, viewport) {
|
|
4649
|
+
if (viewport.widthPx > 0 && viewport.pixelsPerSecond > 0) {
|
|
4650
|
+
return `${positionPxFromTime(timeSec, viewport) / viewport.widthPx * 100}%`;
|
|
4651
|
+
}
|
|
4652
|
+
const progress = durationSec > 0 ? Math.min(1, Math.max(0, timeSec / durationSec)) : 0;
|
|
4653
|
+
return `${progress * 100}%`;
|
|
4654
|
+
}
|
|
4253
4655
|
function applyPeaks(wavesurfer, peaks, durationSec) {
|
|
4254
4656
|
if (!wavesurfer.load) {
|
|
4255
4657
|
return;
|
|
@@ -4257,6 +4659,44 @@ function applyPeaks(wavesurfer, peaks, durationSec) {
|
|
|
4257
4659
|
wavesurfer.load('', toChannels(peaks), durationSec);
|
|
4258
4660
|
}
|
|
4259
4661
|
|
|
4662
|
+
/** Tint WaveSurfer's zoomed tiles with played/unplayed/hover/buffer colors. */
|
|
4663
|
+
function tintZoomedWaveform(wavesurfer, fills, replaceSnapshot = false) {
|
|
4664
|
+
const wrapper = wavesurfer.getWrapper ? wavesurfer.getWrapper() : null;
|
|
4665
|
+
if (!wrapper || !(wrapper.clientWidth > 0)) {
|
|
4666
|
+
return;
|
|
4667
|
+
}
|
|
4668
|
+
tintWaveformTiles({
|
|
4669
|
+
fills,
|
|
4670
|
+
host: wrapper,
|
|
4671
|
+
replaceSnapshot,
|
|
4672
|
+
totalWidthCss: wrapper.clientWidth
|
|
4673
|
+
});
|
|
4674
|
+
}
|
|
4675
|
+
function touchDistance(touches) {
|
|
4676
|
+
if (touches.length < 2) {
|
|
4677
|
+
return 0;
|
|
4678
|
+
}
|
|
4679
|
+
const dx = touches[0].clientX - touches[1].clientX;
|
|
4680
|
+
const dy = touches[0].clientY - touches[1].clientY;
|
|
4681
|
+
return Math.hypot(dx, dy);
|
|
4682
|
+
}
|
|
4683
|
+
|
|
4684
|
+
/** Time under the pointer, plus its X in the view, so zoom can keep that point fixed. */
|
|
4685
|
+
function zoomOriginAtPointer(pointerX, wavesurfer, durationSec, fallbackWidth) {
|
|
4686
|
+
if (!(fallbackWidth > 0) || !(durationSec > 0) || !Number.isFinite(pointerX)) {
|
|
4687
|
+
return null;
|
|
4688
|
+
}
|
|
4689
|
+
const wrapper = wavesurfer && wavesurfer.getWrapper ? wavesurfer.getWrapper() : null;
|
|
4690
|
+
const fullWidth = wrapper && wrapper.clientWidth ? wrapper.clientWidth : fallbackWidth;
|
|
4691
|
+
if (!(fullWidth > 0)) {
|
|
4692
|
+
return null;
|
|
4693
|
+
}
|
|
4694
|
+
return {
|
|
4695
|
+
pointerX,
|
|
4696
|
+
timeSec: (getScrollLeft(wavesurfer) + pointerX) / fullWidth * durationSec
|
|
4697
|
+
};
|
|
4698
|
+
}
|
|
4699
|
+
|
|
4260
4700
|
/**
|
|
4261
4701
|
* Renders V1 peaks with wavesurfer. Does not fetch audio or attach a media element.
|
|
4262
4702
|
*/
|
|
@@ -4264,42 +4704,114 @@ function WaveformView({
|
|
|
4264
4704
|
bufferedRange,
|
|
4265
4705
|
currentTime = 0,
|
|
4266
4706
|
durationSec,
|
|
4267
|
-
height = WAVEFORM_HEIGHT,
|
|
4707
|
+
height = constants/* WAVEFORM_HEIGHT */.oN,
|
|
4268
4708
|
interactive = true,
|
|
4269
4709
|
mediaEl,
|
|
4270
4710
|
onSeek,
|
|
4271
|
-
|
|
4711
|
+
onViewportChange,
|
|
4712
|
+
onZoomChange,
|
|
4713
|
+
peaks,
|
|
4714
|
+
zoomLevel: zoomLevelProp
|
|
4272
4715
|
}) {
|
|
4273
4716
|
const containerRef = (0,external_react_.useRef)(null);
|
|
4717
|
+
const trackRef = (0,external_react_.useRef)(null);
|
|
4274
4718
|
const playheadRef = (0,external_react_.useRef)(null);
|
|
4275
|
-
const
|
|
4719
|
+
const playheadAnimationRef = (0,external_react_.useRef)(0);
|
|
4276
4720
|
const wavesurferRef = (0,external_react_.useRef)(null);
|
|
4277
4721
|
const onSeekRef = (0,external_react_.useRef)(onSeek);
|
|
4278
4722
|
const interactiveRef = (0,external_react_.useRef)(interactive);
|
|
4723
|
+
const hasZoomHandlersRef = (0,external_react_.useRef)(false);
|
|
4279
4724
|
const currentTimeRef = (0,external_react_.useRef)(currentTime);
|
|
4280
4725
|
const peaksRef = (0,external_react_.useRef)(peaks);
|
|
4281
4726
|
const displayedPeaksRef = (0,external_react_.useRef)(null);
|
|
4282
|
-
const
|
|
4727
|
+
const peakTransitionAnimationRef = (0,external_react_.useRef)(0);
|
|
4283
4728
|
const durationSecRef = (0,external_react_.useRef)(durationSec);
|
|
4729
|
+
const zoomOriginRef = (0,external_react_.useRef)(null);
|
|
4730
|
+
const pinchStartRef = (0,external_react_.useRef)(null);
|
|
4731
|
+
const bufferProgressRef = (0,external_react_.useRef)(0);
|
|
4732
|
+
const hoverProgressRef = (0,external_react_.useRef)(null);
|
|
4733
|
+
const programmaticScrollRef = (0,external_react_.useRef)(false);
|
|
4734
|
+
const onViewportChangeRef = (0,external_react_.useRef)(onViewportChange);
|
|
4284
4735
|
onSeekRef.current = onSeek;
|
|
4285
4736
|
interactiveRef.current = interactive;
|
|
4286
4737
|
currentTimeRef.current = currentTime;
|
|
4287
4738
|
peaksRef.current = peaks;
|
|
4288
4739
|
durationSecRef.current = durationSec;
|
|
4740
|
+
onViewportChangeRef.current = onViewportChange;
|
|
4741
|
+
const [internalZoom, setInternalZoom] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
4289
4742
|
const [hoverProgress, setHoverProgress] = (0,external_react_.useState)(null);
|
|
4290
4743
|
const [canvasWidthPx, setCanvasWidthPx] = (0,external_react_.useState)(0);
|
|
4744
|
+
const [scrollLeft, setScrollLeft] = (0,external_react_.useState)(0);
|
|
4745
|
+
const isControlled = typeof zoomLevelProp === 'number';
|
|
4746
|
+
const maxZoom = getWaveformZoomMax({
|
|
4747
|
+
durationSec,
|
|
4748
|
+
peakCount: peaks.length,
|
|
4749
|
+
viewWidthPx: canvasWidthPx
|
|
4750
|
+
});
|
|
4751
|
+
hasZoomHandlersRef.current = maxZoom > constants/* WAVEFORM_ZOOM_MIN */.LW && (typeof onZoomChange === 'function' || typeof zoomLevelProp !== 'number');
|
|
4752
|
+
const zoomLevel = clampWaveformZoom(isControlled ? zoomLevelProp : internalZoom, maxZoom);
|
|
4753
|
+
const zoomRef = (0,external_react_.useRef)(zoomLevel);
|
|
4754
|
+
zoomRef.current = zoomLevel;
|
|
4755
|
+
const prevZoomRef = (0,external_react_.useRef)(null);
|
|
4756
|
+
const isZoomed = zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4291
4757
|
const bufferProgress = getBufferedProgress(bufferedRange, durationSec);
|
|
4758
|
+
bufferProgressRef.current = bufferProgress;
|
|
4759
|
+
hoverProgressRef.current = hoverProgress;
|
|
4760
|
+
const viewport = (0,external_react_.useMemo)(() => createWaveformViewport({
|
|
4761
|
+
durationSec,
|
|
4762
|
+
heightPx: height,
|
|
4763
|
+
maxZoom,
|
|
4764
|
+
scrollLeftPx: scrollLeft,
|
|
4765
|
+
widthPx: canvasWidthPx,
|
|
4766
|
+
zoomLevel
|
|
4767
|
+
}), [canvasWidthPx, durationSec, height, maxZoom, scrollLeft, zoomLevel]);
|
|
4768
|
+
const viewportRef = (0,external_react_.useRef)(viewport);
|
|
4769
|
+
viewportRef.current = viewport;
|
|
4770
|
+
const setZoomLevel = (0,external_react_.useCallback)(nextZoom => {
|
|
4771
|
+
const zoom = clampWaveformZoom(nextZoom, maxZoom);
|
|
4772
|
+
if (!isControlled) {
|
|
4773
|
+
setInternalZoom(zoom);
|
|
4774
|
+
}
|
|
4775
|
+
onZoomChange?.(zoom);
|
|
4776
|
+
}, [isControlled, maxZoom, onZoomChange]);
|
|
4777
|
+
const syncViewport = (0,external_react_.useCallback)(() => {
|
|
4778
|
+
const wavesurfer = wavesurferRef.current;
|
|
4779
|
+
if (!wavesurfer) {
|
|
4780
|
+
return;
|
|
4781
|
+
}
|
|
4782
|
+
const scrollLeftPx = getScrollLeft(wavesurfer);
|
|
4783
|
+
viewportRef.current = getViewportAtScroll(viewportRef.current, scrollLeftPx);
|
|
4784
|
+
onViewportChangeRef.current?.(viewportRef.current);
|
|
4785
|
+
setScrollLeft(scrollLeftPx);
|
|
4786
|
+
}, []);
|
|
4292
4787
|
const updatePlayheadPosition = (0,external_react_.useCallback)(timeSec => {
|
|
4293
4788
|
const playhead = playheadRef.current;
|
|
4294
4789
|
if (!playhead) {
|
|
4295
4790
|
return;
|
|
4296
4791
|
}
|
|
4297
|
-
playhead.style.left =
|
|
4792
|
+
playhead.style.left = timeLeftPercent(timeSec, durationSecRef.current, viewportRef.current);
|
|
4298
4793
|
const wavesurfer = wavesurferRef.current;
|
|
4299
4794
|
if (wavesurfer && wavesurfer.setTime) {
|
|
4300
4795
|
wavesurfer.setTime(timeSec);
|
|
4301
4796
|
}
|
|
4302
4797
|
}, []);
|
|
4798
|
+
const applyScrollLeft = (0,external_react_.useCallback)((scrollLeftPx, shouldCommitState) => {
|
|
4799
|
+
const wavesurfer = wavesurferRef.current;
|
|
4800
|
+
if (!wavesurfer || !wavesurfer.setScroll) {
|
|
4801
|
+
return;
|
|
4802
|
+
}
|
|
4803
|
+
programmaticScrollRef.current = true;
|
|
4804
|
+
wavesurfer.setScroll(scrollLeftPx);
|
|
4805
|
+
viewportRef.current = getViewportAtScroll(viewportRef.current, getScrollLeft(wavesurfer, scrollLeftPx));
|
|
4806
|
+
window.requestAnimationFrame(() => {
|
|
4807
|
+
// Keep the flag through delayed `scroll` after a zoom setScroll.
|
|
4808
|
+
programmaticScrollRef.current = false;
|
|
4809
|
+
});
|
|
4810
|
+
if (shouldCommitState) {
|
|
4811
|
+
onViewportChangeRef.current?.(viewportRef.current);
|
|
4812
|
+
setScrollLeft(getScrollLeft(wavesurfer, scrollLeftPx));
|
|
4813
|
+
}
|
|
4814
|
+
}, []);
|
|
4303
4815
|
(0,external_react_.useEffect)(() => {
|
|
4304
4816
|
const container = containerRef.current;
|
|
4305
4817
|
if (!container) {
|
|
@@ -4307,10 +4819,10 @@ function WaveformView({
|
|
|
4307
4819
|
}
|
|
4308
4820
|
const wavesurfer = w.create({
|
|
4309
4821
|
autoScroll: false,
|
|
4310
|
-
barGap: WAVEFORM_BAR_GAP,
|
|
4311
|
-
barMinHeight: WAVEFORM_BAR_MIN_HEIGHT,
|
|
4312
|
-
barRadius: WAVEFORM_BAR_RADIUS,
|
|
4313
|
-
barWidth: WAVEFORM_BAR_WIDTH,
|
|
4822
|
+
barGap: constants/* WAVEFORM_BAR_GAP */.Lu,
|
|
4823
|
+
barMinHeight: constants/* WAVEFORM_BAR_MIN_HEIGHT */.XS,
|
|
4824
|
+
barRadius: constants/* WAVEFORM_BAR_RADIUS */.DY,
|
|
4825
|
+
barWidth: constants/* WAVEFORM_BAR_WIDTH */.zo,
|
|
4314
4826
|
container,
|
|
4315
4827
|
cursorWidth: 0,
|
|
4316
4828
|
duration: durationSecRef.current,
|
|
@@ -4329,16 +4841,39 @@ function WaveformView({
|
|
|
4329
4841
|
}
|
|
4330
4842
|
onSeekRef.current?.(relativeX * durationSecRef.current);
|
|
4331
4843
|
});
|
|
4844
|
+
const unsubscribeScroll = wavesurfer.on('scroll', () => {
|
|
4845
|
+
if (programmaticScrollRef.current) {
|
|
4846
|
+
viewportRef.current = getViewportAtScroll(viewportRef.current, getScrollLeft(wavesurfer));
|
|
4847
|
+
return;
|
|
4848
|
+
}
|
|
4849
|
+
syncViewport();
|
|
4850
|
+
});
|
|
4851
|
+
const unsubscribeZoom = wavesurfer.on('zoom', () => {
|
|
4852
|
+
syncViewport();
|
|
4853
|
+
});
|
|
4854
|
+
const unsubscribeRedraw = wavesurfer.on('redrawcomplete', () => {
|
|
4855
|
+
if (!(zoomRef.current > constants/* WAVEFORM_ZOOM_MIN */.LW)) {
|
|
4856
|
+
return;
|
|
4857
|
+
}
|
|
4858
|
+
tintZoomedWaveform(wavesurfer, getWaveformFills({
|
|
4859
|
+
bufferProgress: bufferProgressRef.current,
|
|
4860
|
+
hoverProgress: hoverProgressRef.current
|
|
4861
|
+
}), true);
|
|
4862
|
+
});
|
|
4332
4863
|
wavesurferRef.current = wavesurfer;
|
|
4333
4864
|
displayedPeaksRef.current = peaksRef.current;
|
|
4865
|
+
syncViewport();
|
|
4334
4866
|
return () => {
|
|
4335
|
-
window.cancelAnimationFrame(
|
|
4867
|
+
window.cancelAnimationFrame(peakTransitionAnimationRef.current);
|
|
4336
4868
|
unsubscribeClick();
|
|
4869
|
+
unsubscribeScroll();
|
|
4870
|
+
unsubscribeZoom();
|
|
4871
|
+
unsubscribeRedraw();
|
|
4337
4872
|
wavesurfer.destroy();
|
|
4338
4873
|
wavesurferRef.current = null;
|
|
4339
4874
|
displayedPeaksRef.current = null;
|
|
4340
4875
|
};
|
|
4341
|
-
}, [height]);
|
|
4876
|
+
}, [height, syncViewport]);
|
|
4342
4877
|
(0,external_react_.useLayoutEffect)(() => {
|
|
4343
4878
|
const el = containerRef.current;
|
|
4344
4879
|
if (!el) {
|
|
@@ -4349,10 +4884,24 @@ function WaveformView({
|
|
|
4349
4884
|
entries.forEach(entry => {
|
|
4350
4885
|
setCanvasWidthPx(entry.contentRect.width);
|
|
4351
4886
|
});
|
|
4887
|
+
syncViewport();
|
|
4352
4888
|
});
|
|
4353
4889
|
observer.observe(el);
|
|
4354
4890
|
return () => observer.disconnect();
|
|
4355
|
-
}, []);
|
|
4891
|
+
}, [syncViewport]);
|
|
4892
|
+
(0,external_react_.useEffect)(() => {
|
|
4893
|
+
const rawZoom = isControlled ? zoomLevelProp : internalZoom;
|
|
4894
|
+
const clamped = clampWaveformZoom(typeof rawZoom === 'number' ? rawZoom : constants/* WAVEFORM_ZOOM_MIN */.LW, maxZoom);
|
|
4895
|
+
if (clamped === rawZoom) {
|
|
4896
|
+
return;
|
|
4897
|
+
}
|
|
4898
|
+
if (!isControlled) {
|
|
4899
|
+
setInternalZoom(clamped);
|
|
4900
|
+
}
|
|
4901
|
+
}, [internalZoom, isControlled, maxZoom, zoomLevelProp]);
|
|
4902
|
+
(0,external_react_.useEffect)(() => {
|
|
4903
|
+
onViewportChange?.(viewport);
|
|
4904
|
+
}, [onViewportChange, viewport]);
|
|
4356
4905
|
(0,external_react_.useEffect)(() => {
|
|
4357
4906
|
const wavesurfer = wavesurferRef.current;
|
|
4358
4907
|
if (!wavesurfer || !wavesurfer.setOptions) {
|
|
@@ -4362,13 +4911,48 @@ function WaveformView({
|
|
|
4362
4911
|
interact: interactive
|
|
4363
4912
|
});
|
|
4364
4913
|
}, [interactive]);
|
|
4914
|
+
(0,external_react_.useEffect)(() => {
|
|
4915
|
+
const wavesurfer = wavesurferRef.current;
|
|
4916
|
+
const container = containerRef.current;
|
|
4917
|
+
if (!wavesurfer || !wavesurfer.setOptions || !container) {
|
|
4918
|
+
return;
|
|
4919
|
+
}
|
|
4920
|
+
const viewWidthPx = wavesurfer.getWidth ? wavesurfer.getWidth() : container.clientWidth;
|
|
4921
|
+
const minPxPerSec = getZoomedPixelsPerSecond({
|
|
4922
|
+
durationSec,
|
|
4923
|
+
maxZoom,
|
|
4924
|
+
viewWidthPx,
|
|
4925
|
+
zoomLevel
|
|
4926
|
+
});
|
|
4927
|
+
wavesurfer.setOptions(WaveformView_objectSpread({
|
|
4928
|
+
autoScroll: false,
|
|
4929
|
+
minPxPerSec
|
|
4930
|
+
}, zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW ? {
|
|
4931
|
+
progressColor: WAVEFORM_COLOR_PLAYED,
|
|
4932
|
+
waveColor: WAVEFORM_COLOR_UNPLAYED
|
|
4933
|
+
} : {}));
|
|
4934
|
+
const origin = zoomOriginRef.current;
|
|
4935
|
+
zoomOriginRef.current = null;
|
|
4936
|
+
const didZoomChange = prevZoomRef.current !== zoomLevel;
|
|
4937
|
+
prevZoomRef.current = zoomLevel;
|
|
4938
|
+
if (minPxPerSec > 0) {
|
|
4939
|
+
if (origin) {
|
|
4940
|
+
applyScrollLeft(origin.timeSec * minPxPerSec - origin.pointerX, true);
|
|
4941
|
+
} else if (didZoomChange) {
|
|
4942
|
+
const maxScroll = Math.max(0, durationSec * minPxPerSec - viewWidthPx);
|
|
4943
|
+
applyScrollLeft(Math.min(maxScroll, Math.max(0, currentTimeRef.current * minPxPerSec - viewWidthPx / 2)), true);
|
|
4944
|
+
}
|
|
4945
|
+
}
|
|
4946
|
+
wavesurfer.setTime(currentTimeRef.current);
|
|
4947
|
+
syncViewport();
|
|
4948
|
+
}, [applyScrollLeft, durationSec, maxZoom, syncViewport, zoomLevel]);
|
|
4365
4949
|
(0,external_react_.useLayoutEffect)(() => {
|
|
4366
4950
|
if (mediaEl && !mediaEl.paused) {
|
|
4367
4951
|
updatePlayheadPosition(mediaEl.currentTime);
|
|
4368
4952
|
return;
|
|
4369
4953
|
}
|
|
4370
4954
|
updatePlayheadPosition(currentTime);
|
|
4371
|
-
}, [currentTime, durationSec, mediaEl, updatePlayheadPosition]);
|
|
4955
|
+
}, [currentTime, durationSec, mediaEl, updatePlayheadPosition, viewport]);
|
|
4372
4956
|
(0,external_react_.useEffect)(() => {
|
|
4373
4957
|
const media = mediaEl;
|
|
4374
4958
|
if (!media) {
|
|
@@ -4378,14 +4962,14 @@ function WaveformView({
|
|
|
4378
4962
|
if (!media.paused) {
|
|
4379
4963
|
updatePlayheadPosition(media.currentTime);
|
|
4380
4964
|
}
|
|
4381
|
-
|
|
4965
|
+
playheadAnimationRef.current = window.requestAnimationFrame(tick);
|
|
4382
4966
|
};
|
|
4383
4967
|
const startLoop = () => {
|
|
4384
|
-
window.cancelAnimationFrame(
|
|
4385
|
-
|
|
4968
|
+
window.cancelAnimationFrame(playheadAnimationRef.current);
|
|
4969
|
+
playheadAnimationRef.current = window.requestAnimationFrame(tick);
|
|
4386
4970
|
};
|
|
4387
4971
|
const stopLoop = () => {
|
|
4388
|
-
window.cancelAnimationFrame(
|
|
4972
|
+
window.cancelAnimationFrame(playheadAnimationRef.current);
|
|
4389
4973
|
updatePlayheadPosition(media.currentTime);
|
|
4390
4974
|
};
|
|
4391
4975
|
const handleSeeked = () => {
|
|
@@ -4395,11 +4979,13 @@ function WaveformView({
|
|
|
4395
4979
|
startLoop();
|
|
4396
4980
|
}
|
|
4397
4981
|
media.addEventListener('play', startLoop);
|
|
4982
|
+
media.addEventListener('playing', startLoop);
|
|
4398
4983
|
media.addEventListener('pause', stopLoop);
|
|
4399
4984
|
media.addEventListener('seeked', handleSeeked);
|
|
4400
4985
|
return () => {
|
|
4401
|
-
window.cancelAnimationFrame(
|
|
4986
|
+
window.cancelAnimationFrame(playheadAnimationRef.current);
|
|
4402
4987
|
media.removeEventListener('play', startLoop);
|
|
4988
|
+
media.removeEventListener('playing', startLoop);
|
|
4403
4989
|
media.removeEventListener('pause', stopLoop);
|
|
4404
4990
|
media.removeEventListener('seeked', handleSeeked);
|
|
4405
4991
|
};
|
|
@@ -4409,28 +4995,27 @@ function WaveformView({
|
|
|
4409
4995
|
if (!wavesurfer || !wavesurfer.setOptions || !(durationSec > 0)) {
|
|
4410
4996
|
return undefined;
|
|
4411
4997
|
}
|
|
4998
|
+
window.cancelAnimationFrame(peakTransitionAnimationRef.current);
|
|
4412
4999
|
const fromPeaks = displayedPeaksRef.current;
|
|
4413
|
-
|
|
4414
|
-
window.cancelAnimationFrame(peakTransitionRafRef.current);
|
|
4415
|
-
if (!fromPeaks || fromPeaks === peaks || reduceMotion) {
|
|
5000
|
+
if (!fromPeaks || fromPeaks === peaks || prefersReducedMotion()) {
|
|
4416
5001
|
displayedPeaksRef.current = peaks;
|
|
4417
5002
|
applyPeaks(wavesurfer, peaks, durationSec);
|
|
4418
5003
|
return undefined;
|
|
4419
5004
|
}
|
|
4420
|
-
const start =
|
|
5005
|
+
const start = (0,util/* getCurrentTimeMs */.RU)();
|
|
4421
5006
|
const tick = now => {
|
|
4422
5007
|
const elapsedMs = now - start;
|
|
4423
5008
|
const framePeaks = morphPeaks(fromPeaks, peaks, elapsedMs);
|
|
4424
5009
|
displayedPeaksRef.current = framePeaks;
|
|
4425
5010
|
applyPeaks(wavesurfer, framePeaks, durationSec);
|
|
4426
5011
|
if (elapsedMs < WAVEFORM_PEAK_TRANSITION_MS) {
|
|
4427
|
-
|
|
5012
|
+
peakTransitionAnimationRef.current = window.requestAnimationFrame(tick);
|
|
4428
5013
|
} else {
|
|
4429
5014
|
displayedPeaksRef.current = peaks;
|
|
4430
5015
|
}
|
|
4431
5016
|
};
|
|
4432
|
-
|
|
4433
|
-
return () => window.cancelAnimationFrame(
|
|
5017
|
+
peakTransitionAnimationRef.current = window.requestAnimationFrame(tick);
|
|
5018
|
+
return () => window.cancelAnimationFrame(peakTransitionAnimationRef.current);
|
|
4434
5019
|
}, [durationSec, peaks]);
|
|
4435
5020
|
(0,external_react_.useEffect)(() => {
|
|
4436
5021
|
const wavesurfer = wavesurferRef.current;
|
|
@@ -4441,12 +5026,91 @@ function WaveformView({
|
|
|
4441
5026
|
bufferProgress,
|
|
4442
5027
|
hoverProgress
|
|
4443
5028
|
});
|
|
5029
|
+
if (isZoomed) {
|
|
5030
|
+
tintZoomedWaveform(wavesurfer, fills);
|
|
5031
|
+
return;
|
|
5032
|
+
}
|
|
4444
5033
|
wavesurfer.setOptions({
|
|
4445
|
-
progressColor: toCanvasFill(fills.progressColor,
|
|
4446
|
-
waveColor: toCanvasFill(fills.waveColor,
|
|
5034
|
+
progressColor: toCanvasFill(fills.progressColor, devicePixelWidth(canvasWidthPx)),
|
|
5035
|
+
waveColor: toCanvasFill(fills.waveColor, devicePixelWidth(canvasWidthPx))
|
|
4447
5036
|
});
|
|
4448
5037
|
wavesurfer.setTime(currentTimeRef.current);
|
|
4449
|
-
}, [bufferProgress, canvasWidthPx, hoverProgress]);
|
|
5038
|
+
}, [bufferProgress, canvasWidthPx, hoverProgress, isZoomed]);
|
|
5039
|
+
(0,external_react_.useEffect)(() => {
|
|
5040
|
+
const track = trackRef.current;
|
|
5041
|
+
if (!track) {
|
|
5042
|
+
return undefined;
|
|
5043
|
+
}
|
|
5044
|
+
|
|
5045
|
+
/** Remember the time under this pointer so pinch/wheel zoom stays anchored. */
|
|
5046
|
+
const captureZoomOrigin = clientX => {
|
|
5047
|
+
const rect = track.getBoundingClientRect();
|
|
5048
|
+
zoomOriginRef.current = zoomOriginAtPointer(clientX - rect.left, wavesurferRef.current, durationSec, rect.width);
|
|
5049
|
+
};
|
|
5050
|
+
|
|
5051
|
+
/** Zoom origin at the midpoint of a two-finger pinch. */
|
|
5052
|
+
const zoomOriginFromPinch = touches => {
|
|
5053
|
+
if (touches.length < 2) {
|
|
5054
|
+
return null;
|
|
5055
|
+
}
|
|
5056
|
+
const rect = track.getBoundingClientRect();
|
|
5057
|
+
const pointerX = (touches[0].clientX + touches[1].clientX) / 2 - rect.left;
|
|
5058
|
+
return zoomOriginAtPointer(pointerX, wavesurferRef.current, durationSec, rect.width);
|
|
5059
|
+
};
|
|
5060
|
+
|
|
5061
|
+
/** Ctrl/meta + wheel zooms around the pointer. */
|
|
5062
|
+
const onZoomWheel = event => {
|
|
5063
|
+
if (!interactiveRef.current || !hasZoomHandlersRef.current || !event.ctrlKey && !event.metaKey) {
|
|
5064
|
+
return;
|
|
5065
|
+
}
|
|
5066
|
+
event.preventDefault();
|
|
5067
|
+
captureZoomOrigin(event.clientX);
|
|
5068
|
+
setZoomLevel(zoomRef.current * Math.exp(-event.deltaY * 0.01));
|
|
5069
|
+
};
|
|
5070
|
+
const onTouchStart = event => {
|
|
5071
|
+
if (!interactiveRef.current || !hasZoomHandlersRef.current || event.touches.length !== 2) {
|
|
5072
|
+
pinchStartRef.current = null;
|
|
5073
|
+
return;
|
|
5074
|
+
}
|
|
5075
|
+
zoomOriginRef.current = zoomOriginFromPinch(event.touches);
|
|
5076
|
+
pinchStartRef.current = {
|
|
5077
|
+
distance: touchDistance(event.touches),
|
|
5078
|
+
zoom: zoomRef.current
|
|
5079
|
+
};
|
|
5080
|
+
};
|
|
5081
|
+
const onTouchMove = event => {
|
|
5082
|
+
const pinch = pinchStartRef.current;
|
|
5083
|
+
if (!interactiveRef.current || !hasZoomHandlersRef.current || !pinch || event.touches.length !== 2 || !(pinch.distance > 0)) {
|
|
5084
|
+
return;
|
|
5085
|
+
}
|
|
5086
|
+
event.preventDefault();
|
|
5087
|
+
zoomOriginRef.current = zoomOriginFromPinch(event.touches);
|
|
5088
|
+
setZoomLevel(pinch.zoom * (touchDistance(event.touches) / pinch.distance));
|
|
5089
|
+
};
|
|
5090
|
+
const onTouchEnd = event => {
|
|
5091
|
+
if (event.touches.length < 2) {
|
|
5092
|
+
pinchStartRef.current = null;
|
|
5093
|
+
}
|
|
5094
|
+
};
|
|
5095
|
+
track.addEventListener('wheel', onZoomWheel, {
|
|
5096
|
+
passive: false
|
|
5097
|
+
});
|
|
5098
|
+
track.addEventListener('touchstart', onTouchStart, {
|
|
5099
|
+
passive: true
|
|
5100
|
+
});
|
|
5101
|
+
track.addEventListener('touchmove', onTouchMove, {
|
|
5102
|
+
passive: false
|
|
5103
|
+
});
|
|
5104
|
+
track.addEventListener('touchend', onTouchEnd);
|
|
5105
|
+
track.addEventListener('touchcancel', onTouchEnd);
|
|
5106
|
+
return () => {
|
|
5107
|
+
track.removeEventListener('wheel', onZoomWheel);
|
|
5108
|
+
track.removeEventListener('touchstart', onTouchStart);
|
|
5109
|
+
track.removeEventListener('touchmove', onTouchMove);
|
|
5110
|
+
track.removeEventListener('touchend', onTouchEnd);
|
|
5111
|
+
track.removeEventListener('touchcancel', onTouchEnd);
|
|
5112
|
+
};
|
|
5113
|
+
}, [durationSec, setZoomLevel]);
|
|
4450
5114
|
const onHoverMove = (0,external_react_.useCallback)(event => {
|
|
4451
5115
|
if (!interactive) {
|
|
4452
5116
|
return;
|
|
@@ -4455,20 +5119,26 @@ function WaveformView({
|
|
|
4455
5119
|
if (!(rect.width > 0) || !(durationSec > 0)) {
|
|
4456
5120
|
return;
|
|
4457
5121
|
}
|
|
4458
|
-
const
|
|
4459
|
-
if (!Number.isFinite(
|
|
5122
|
+
const pointerX = event.clientX - rect.left;
|
|
5123
|
+
if (!Number.isFinite(pointerX)) {
|
|
4460
5124
|
return;
|
|
4461
5125
|
}
|
|
4462
|
-
|
|
5126
|
+
const vp = viewportRef.current;
|
|
5127
|
+
if (vp.pixelsPerSecond > 0) {
|
|
5128
|
+
setHoverProgress(Math.min(1, Math.max(0, timeFromPositionPx(pointerX, vp) / durationSec)));
|
|
5129
|
+
return;
|
|
5130
|
+
}
|
|
5131
|
+
setHoverProgress(Math.min(1, Math.max(0, pointerX / rect.width)));
|
|
4463
5132
|
}, [durationSec, interactive]);
|
|
4464
5133
|
const onHoverLeave = (0,external_react_.useCallback)(() => {
|
|
4465
5134
|
setHoverProgress(null);
|
|
4466
5135
|
}, []);
|
|
4467
|
-
const hoverLeft = hoverProgress == null ? null :
|
|
5136
|
+
const hoverLeft = hoverProgress == null ? null : timeLeftPercent(hoverProgress * durationSec, durationSec, viewportRef.current);
|
|
4468
5137
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
4469
|
-
className: `bp-WaveformView${interactive ? '' : ' bp-WaveformView--inert'}`,
|
|
5138
|
+
className: `bp-WaveformView${interactive ? '' : ' bp-WaveformView--inert'}${isZoomed ? ' bp-WaveformView--zoomed' : ''}`,
|
|
4470
5139
|
"data-testid": "bp-waveform-view"
|
|
4471
5140
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
5141
|
+
ref: trackRef,
|
|
4472
5142
|
className: "bp-WaveformView-track",
|
|
4473
5143
|
onMouseLeave: interactive ? onHoverLeave : undefined,
|
|
4474
5144
|
onMouseMove: interactive ? onHoverMove : undefined
|
|
@@ -4491,6 +5161,139 @@ function WaveformView({
|
|
|
4491
5161
|
"data-testid": "bp-waveform-hover-time"
|
|
4492
5162
|
}, formatTime(hoverProgress * durationSec)))));
|
|
4493
5163
|
}
|
|
5164
|
+
// EXTERNAL MODULE: ./node_modules/classnames/index.js
|
|
5165
|
+
var classnames = __webpack_require__(2485);
|
|
5166
|
+
var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
|
|
5167
|
+
;// ./src/lib/viewers/controls/icons/IconZoom24.tsx
|
|
5168
|
+
|
|
5169
|
+
function IconZoom24() {
|
|
5170
|
+
return /*#__PURE__*/external_react_.createElement("svg", {
|
|
5171
|
+
focusable: false,
|
|
5172
|
+
height: 24,
|
|
5173
|
+
viewBox: "0 0 24 24",
|
|
5174
|
+
width: 24
|
|
5175
|
+
}, /*#__PURE__*/external_react_.createElement("path", {
|
|
5176
|
+
d: "M2 12h20M6 8l-4 4 4 4M18 8l4 4-4 4",
|
|
5177
|
+
fill: "none",
|
|
5178
|
+
stroke: "currentColor",
|
|
5179
|
+
strokeLinecap: "round",
|
|
5180
|
+
strokeLinejoin: "round",
|
|
5181
|
+
strokeWidth: "2"
|
|
5182
|
+
}));
|
|
5183
|
+
}
|
|
5184
|
+
/* harmony default export */ const icons_IconZoom24 = (IconZoom24);
|
|
5185
|
+
// EXTERNAL MODULE: ./src/lib/viewers/controls/media/MediaToggle.tsx
|
|
5186
|
+
var MediaToggle = __webpack_require__(8997);
|
|
5187
|
+
// EXTERNAL MODULE: ./src/lib/viewers/controls/slider/SliderControl.tsx + 1 modules
|
|
5188
|
+
var SliderControl = __webpack_require__(4937);
|
|
5189
|
+
;// ./src/lib/viewers/media/waveform/WaveformZoomControl.scss
|
|
5190
|
+
// extracted by mini-css-extract-plugin
|
|
5191
|
+
|
|
5192
|
+
;// ./src/lib/viewers/media/waveform/WaveformZoomControl.tsx
|
|
5193
|
+
|
|
5194
|
+
|
|
5195
|
+
|
|
5196
|
+
|
|
5197
|
+
|
|
5198
|
+
|
|
5199
|
+
|
|
5200
|
+
|
|
5201
|
+
function WaveformZoomControl({
|
|
5202
|
+
isRevealed = false,
|
|
5203
|
+
maxZoom,
|
|
5204
|
+
onZoomChange,
|
|
5205
|
+
zoomLevel
|
|
5206
|
+
}) {
|
|
5207
|
+
const [isHovered, setHovered] = (0,external_react_.useState)(false);
|
|
5208
|
+
const [isFocused, setFocused] = (0,external_react_.useState)(false);
|
|
5209
|
+
const dismissTimerRef = (0,external_react_.useRef)(0);
|
|
5210
|
+
const flyoutRef = (0,external_react_.useRef)(null);
|
|
5211
|
+
const shouldFocusSliderRef = (0,external_react_.useRef)(false);
|
|
5212
|
+
const sliderId = `bp-waveform-zoom-slider${(0,external_react_.useId)()}`;
|
|
5213
|
+
const zoom = clampWaveformZoom(zoomLevel, maxZoom);
|
|
5214
|
+
const zoomValue = Math.round(sliderValueFromZoom(zoom, maxZoom));
|
|
5215
|
+
const isOpen = isHovered || isFocused || isRevealed;
|
|
5216
|
+
const clearDismiss = (0,external_react_.useCallback)(() => {
|
|
5217
|
+
window.clearTimeout(dismissTimerRef.current);
|
|
5218
|
+
dismissTimerRef.current = 0;
|
|
5219
|
+
}, []);
|
|
5220
|
+
(0,external_react_.useEffect)(() => () => window.clearTimeout(dismissTimerRef.current), []);
|
|
5221
|
+
(0,external_react_.useLayoutEffect)(() => {
|
|
5222
|
+
if (!isOpen || !shouldFocusSliderRef.current) {
|
|
5223
|
+
return;
|
|
5224
|
+
}
|
|
5225
|
+
shouldFocusSliderRef.current = false;
|
|
5226
|
+
flyoutRef.current?.querySelector('[role="slider"]')?.focus();
|
|
5227
|
+
}, [isOpen]);
|
|
5228
|
+
const handleSlider = (0,external_react_.useCallback)(newValue => {
|
|
5229
|
+
onZoomChange(zoomFromSliderValue(newValue, maxZoom));
|
|
5230
|
+
}, [maxZoom, onZoomChange]);
|
|
5231
|
+
const handleToggleClick = (0,external_react_.useCallback)(() => {
|
|
5232
|
+
clearDismiss();
|
|
5233
|
+
if (isOpen) {
|
|
5234
|
+
shouldFocusSliderRef.current = false;
|
|
5235
|
+
setFocused(false);
|
|
5236
|
+
setHovered(false);
|
|
5237
|
+
return;
|
|
5238
|
+
}
|
|
5239
|
+
shouldFocusSliderRef.current = true;
|
|
5240
|
+
setFocused(true);
|
|
5241
|
+
}, [clearDismiss, isOpen]);
|
|
5242
|
+
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
5243
|
+
className: classnames_default()('bp-WaveformZoomControl', {
|
|
5244
|
+
'bp-is-open': isOpen
|
|
5245
|
+
}),
|
|
5246
|
+
"data-testid": "bp-waveform-zoom",
|
|
5247
|
+
onBlur: event => {
|
|
5248
|
+
if (event.currentTarget.contains(event.relatedTarget)) {
|
|
5249
|
+
return;
|
|
5250
|
+
}
|
|
5251
|
+
setFocused(false);
|
|
5252
|
+
},
|
|
5253
|
+
onFocus: () => {
|
|
5254
|
+
clearDismiss();
|
|
5255
|
+
setFocused(true);
|
|
5256
|
+
},
|
|
5257
|
+
onMouseEnter: () => {
|
|
5258
|
+
clearDismiss();
|
|
5259
|
+
setHovered(true);
|
|
5260
|
+
},
|
|
5261
|
+
onMouseLeave: () => {
|
|
5262
|
+
clearDismiss();
|
|
5263
|
+
dismissTimerRef.current = window.setTimeout(() => {
|
|
5264
|
+
setHovered(false);
|
|
5265
|
+
}, constants/* WAVEFORM_ZOOM_DISMISS_MS */.m6);
|
|
5266
|
+
}
|
|
5267
|
+
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
5268
|
+
ref: flyoutRef,
|
|
5269
|
+
"aria-hidden": !isOpen,
|
|
5270
|
+
className: classnames_default()('bp-WaveformZoomControl-flyout', {
|
|
5271
|
+
'bp-is-open': isOpen
|
|
5272
|
+
})
|
|
5273
|
+
}, /*#__PURE__*/external_react_["default"].createElement(SliderControl/* default */.A, {
|
|
5274
|
+
"aria-hidden": !isOpen,
|
|
5275
|
+
className: "bp-WaveformZoomControl-slider",
|
|
5276
|
+
"data-resin-target": "waveformZoomSlider",
|
|
5277
|
+
id: sliderId,
|
|
5278
|
+
max: constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh,
|
|
5279
|
+
min: 0,
|
|
5280
|
+
onUpdate: handleSlider,
|
|
5281
|
+
step: 1,
|
|
5282
|
+
style: {
|
|
5283
|
+
'--bp-zoom-t': zoomValue / constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh
|
|
5284
|
+
},
|
|
5285
|
+
tabIndex: isOpen ? 0 : -1,
|
|
5286
|
+
title: "Zoom Slider",
|
|
5287
|
+
value: zoomValue
|
|
5288
|
+
})), /*#__PURE__*/external_react_["default"].createElement(MediaToggle/* default */.A, {
|
|
5289
|
+
"aria-controls": sliderId,
|
|
5290
|
+
"aria-expanded": isOpen,
|
|
5291
|
+
className: "bp-WaveformZoomControl-toggle",
|
|
5292
|
+
"data-resin-target": "waveformZoom",
|
|
5293
|
+
onClick: handleToggleClick,
|
|
5294
|
+
title: "Zoom"
|
|
5295
|
+
}, /*#__PURE__*/external_react_["default"].createElement(icons_IconZoom24, null)));
|
|
5296
|
+
}
|
|
4494
5297
|
;// ./src/lib/viewers/media/MP3ControlsV2.scss
|
|
4495
5298
|
// extracted by mini-css-extract-plugin
|
|
4496
5299
|
|
|
@@ -4505,6 +5308,9 @@ function WaveformView({
|
|
|
4505
5308
|
|
|
4506
5309
|
|
|
4507
5310
|
|
|
5311
|
+
|
|
5312
|
+
|
|
5313
|
+
|
|
4508
5314
|
const PLACEHOLDER_PEAKS = placeholderPeaks();
|
|
4509
5315
|
function MP3ControlsV2({
|
|
4510
5316
|
autoplay,
|
|
@@ -4524,11 +5330,34 @@ function MP3ControlsV2({
|
|
|
4524
5330
|
volume
|
|
4525
5331
|
}) {
|
|
4526
5332
|
const durationValue = typeof durationTime === 'number' && isFinite_default()(durationTime) ? durationTime : 0;
|
|
5333
|
+
const [zoomLevel, setZoomLevel] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
5334
|
+
const [maxZoom, setMaxZoom] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
5335
|
+
const [isZoomRevealed, setIsZoomRevealed] = (0,external_react_.useState)(false);
|
|
5336
|
+
const zoomRevealTimerRef = (0,external_react_.useRef)(0);
|
|
4527
5337
|
const hasRealPeaks = !!(peaks && peaks.length);
|
|
4528
5338
|
const waveformPeaks = hasRealPeaks ? peaks : PLACEHOLDER_PEAKS;
|
|
4529
5339
|
const hasMetadata = durationValue > 0;
|
|
4530
5340
|
const waveformDurationSec = hasMetadata ? durationValue : PLACEHOLDER_DURATION_SEC;
|
|
4531
5341
|
const [playRequested, setPlayRequested] = (0,external_react_.useState)(false);
|
|
5342
|
+
const handleViewportChange = (0,external_react_.useCallback)(viewport => {
|
|
5343
|
+
setMaxZoom(viewport.maxZoom);
|
|
5344
|
+
}, []);
|
|
5345
|
+
const revealZoomControl = (0,external_react_.useCallback)(() => {
|
|
5346
|
+
setIsZoomRevealed(true);
|
|
5347
|
+
window.clearTimeout(zoomRevealTimerRef.current);
|
|
5348
|
+
zoomRevealTimerRef.current = window.setTimeout(() => {
|
|
5349
|
+
setIsZoomRevealed(false);
|
|
5350
|
+
zoomRevealTimerRef.current = 0;
|
|
5351
|
+
}, constants/* WAVEFORM_ZOOM_DISMISS_MS */.m6);
|
|
5352
|
+
}, []);
|
|
5353
|
+
const handleWaveformZoom = (0,external_react_.useCallback)(nextZoom => {
|
|
5354
|
+
setZoomLevel(nextZoom);
|
|
5355
|
+
revealZoomControl();
|
|
5356
|
+
}, [revealZoomControl]);
|
|
5357
|
+
(0,external_react_.useEffect)(() => {
|
|
5358
|
+
setZoomLevel(prev => clampWaveformZoom(prev, maxZoom));
|
|
5359
|
+
}, [maxZoom]);
|
|
5360
|
+
(0,external_react_.useEffect)(() => () => window.clearTimeout(zoomRevealTimerRef.current), []);
|
|
4532
5361
|
(0,external_react_.useEffect)(() => {
|
|
4533
5362
|
if (isPlaying) {
|
|
4534
5363
|
setPlayRequested(true);
|
|
@@ -4541,6 +5370,8 @@ function MP3ControlsV2({
|
|
|
4541
5370
|
const isWaveformInteractive = playRequested && hasMetadata;
|
|
4542
5371
|
const isWaitingToPlay = playRequested && !hasMetadata;
|
|
4543
5372
|
const showPlayOverlay = !playRequested && !isPlaying;
|
|
5373
|
+
const hasZoomHandlers = hasRealPeaks && !showPlayOverlay;
|
|
5374
|
+
const hasZoomControl = hasZoomHandlers && hasMetadata && maxZoom > constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4544
5375
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
4545
5376
|
className: "bp-MP3ControlsV2",
|
|
4546
5377
|
"data-testid": "media-controls-wrapper-v2"
|
|
@@ -4553,8 +5384,18 @@ function MP3ControlsV2({
|
|
|
4553
5384
|
interactive: isWaveformInteractive,
|
|
4554
5385
|
mediaEl: mediaEl,
|
|
4555
5386
|
onSeek: isWaveformInteractive ? onTimeChange : undefined,
|
|
4556
|
-
|
|
4557
|
-
|
|
5387
|
+
onViewportChange: hasRealPeaks ? handleViewportChange : undefined,
|
|
5388
|
+
onZoomChange: hasZoomHandlers ? handleWaveformZoom : undefined,
|
|
5389
|
+
peaks: waveformPeaks,
|
|
5390
|
+
zoomLevel: hasZoomHandlers ? zoomLevel : constants/* WAVEFORM_ZOOM_MIN */.LW
|
|
5391
|
+
}), hasZoomControl && /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
5392
|
+
className: "bp-MP3ControlsV2-waveformZoom"
|
|
5393
|
+
}, /*#__PURE__*/external_react_["default"].createElement(WaveformZoomControl, {
|
|
5394
|
+
isRevealed: isZoomRevealed,
|
|
5395
|
+
maxZoom: maxZoom,
|
|
5396
|
+
onZoomChange: setZoomLevel,
|
|
5397
|
+
zoomLevel: zoomLevel
|
|
5398
|
+
})), showPlayOverlay && /*#__PURE__*/external_react_["default"].createElement("button", {
|
|
4558
5399
|
className: "bp-MP3ControlsV2-playOverlay"
|
|
4559
5400
|
// Static SVG from the icons module, same asset video uses for the overlay.
|
|
4560
5401
|
// eslint-disable-next-line react/no-danger
|
|
@@ -4667,6 +5508,780 @@ function isFpsAvailable(player) {
|
|
|
4667
5508
|
|
|
4668
5509
|
/***/ },
|
|
4669
5510
|
|
|
5511
|
+
/***/ 4929
|
|
5512
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
5513
|
+
|
|
5514
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
5515
|
+
/* harmony export */ DY: () => (/* binding */ WAVEFORM_BAR_RADIUS),
|
|
5516
|
+
/* harmony export */ EB: () => (/* binding */ CLIENT_DECODE_MAX_COMPRESSED_BYTES),
|
|
5517
|
+
/* harmony export */ FY: () => (/* binding */ MAX_PEAK_COUNT),
|
|
5518
|
+
/* harmony export */ GQ: () => (/* binding */ DURATION_MISMATCH_TOLERANCE_SEC),
|
|
5519
|
+
/* harmony export */ Kl: () => (/* binding */ WAVEFORM_MIN_VIEW_WINDOW_SEC),
|
|
5520
|
+
/* harmony export */ LW: () => (/* binding */ WAVEFORM_ZOOM_MIN),
|
|
5521
|
+
/* harmony export */ Lu: () => (/* binding */ WAVEFORM_BAR_GAP),
|
|
5522
|
+
/* harmony export */ XS: () => (/* binding */ WAVEFORM_BAR_MIN_HEIGHT),
|
|
5523
|
+
/* harmony export */ f3: () => (/* binding */ CLIENT_DECODE_PEAK_COUNT),
|
|
5524
|
+
/* harmony export */ i8: () => (/* binding */ PEAK_UNIT_MAX),
|
|
5525
|
+
/* harmony export */ m6: () => (/* binding */ WAVEFORM_ZOOM_DISMISS_MS),
|
|
5526
|
+
/* harmony export */ mJ: () => (/* binding */ PEAK_UNIT_MIN),
|
|
5527
|
+
/* harmony export */ nG: () => (/* binding */ CLIENT_DECODE_MAX_DURATION_SEC),
|
|
5528
|
+
/* harmony export */ nh: () => (/* binding */ WAVEFORM_ZOOM_SLIDER_MAX),
|
|
5529
|
+
/* harmony export */ oN: () => (/* binding */ WAVEFORM_HEIGHT),
|
|
5530
|
+
/* harmony export */ qY: () => (/* binding */ MAX_PAYLOAD_BYTES),
|
|
5531
|
+
/* harmony export */ sh: () => (/* binding */ WAVEFORM_PAYLOAD_VERSION),
|
|
5532
|
+
/* harmony export */ tK: () => (/* binding */ WAVEFORM_ZOOM_MAX),
|
|
5533
|
+
/* harmony export */ zo: () => (/* binding */ WAVEFORM_BAR_WIDTH)
|
|
5534
|
+
/* harmony export */ });
|
|
5535
|
+
/** Current waveform payload schema version. Bump only with a migration path. */
|
|
5536
|
+
const WAVEFORM_PAYLOAD_VERSION = 1;
|
|
5537
|
+
|
|
5538
|
+
/** Maximum peaks in a single tier (overview or detail). */
|
|
5539
|
+
const MAX_PEAK_COUNT = 16384;
|
|
5540
|
+
|
|
5541
|
+
/** Hard limit on serialized JSON body size for a waveform payload (bytes). */
|
|
5542
|
+
const MAX_PAYLOAD_BYTES = 512 * 1024;
|
|
5543
|
+
|
|
5544
|
+
/** Allowed delta between payload duration and caller-supplied media duration (seconds). */
|
|
5545
|
+
const DURATION_MISMATCH_TOLERANCE_SEC = 1;
|
|
5546
|
+
|
|
5547
|
+
/** Peak values must live in this closed interval when peakScale is "unit". */
|
|
5548
|
+
const PEAK_UNIT_MIN = 0;
|
|
5549
|
+
const PEAK_UNIT_MAX = 1;
|
|
5550
|
+
|
|
5551
|
+
/** Skip client decode when the compressed file is larger than this. */
|
|
5552
|
+
const CLIENT_DECODE_MAX_COMPRESSED_BYTES = 6 * 1024 * 1024;
|
|
5553
|
+
|
|
5554
|
+
/** Skip client decode when media duration is longer than this. */
|
|
5555
|
+
const CLIENT_DECODE_MAX_DURATION_SEC = 5 * 60;
|
|
5556
|
+
|
|
5557
|
+
/** Default overview resolution for client-generated peaks. */
|
|
5558
|
+
const CLIENT_DECODE_PEAK_COUNT = 16384;
|
|
5559
|
+
const WAVEFORM_ZOOM_MIN = 1;
|
|
5560
|
+
const WAVEFORM_ZOOM_MAX = 24;
|
|
5561
|
+
/** Visible window never shorter than this. */
|
|
5562
|
+
const WAVEFORM_MIN_VIEW_WINDOW_SEC = 4;
|
|
5563
|
+
const WAVEFORM_ZOOM_SLIDER_MAX = 100;
|
|
5564
|
+
const WAVEFORM_ZOOM_DISMISS_MS = 250;
|
|
5565
|
+
const WAVEFORM_BAR_GAP = 2;
|
|
5566
|
+
const WAVEFORM_BAR_WIDTH = 2;
|
|
5567
|
+
const WAVEFORM_BAR_RADIUS = WAVEFORM_BAR_WIDTH / 2;
|
|
5568
|
+
/** Total bar height so the top and bottom radii meet as a circle on the mirror. */
|
|
5569
|
+
const WAVEFORM_BAR_MIN_HEIGHT = WAVEFORM_BAR_WIDTH;
|
|
5570
|
+
const WAVEFORM_HEIGHT = 140;
|
|
5571
|
+
|
|
5572
|
+
/***/ },
|
|
5573
|
+
|
|
5574
|
+
/***/ 546
|
|
5575
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
5576
|
+
|
|
5577
|
+
|
|
5578
|
+
// EXPORTS
|
|
5579
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
5580
|
+
decodeToPeaks: () => (/* binding */ decodeToPeaks),
|
|
5581
|
+
extractPeaks: () => (/* binding */ extractPeaks),
|
|
5582
|
+
getDecodeDecision: () => (/* binding */ getDecodeDecision),
|
|
5583
|
+
loadPeaks: () => (/* binding */ loadPeaks),
|
|
5584
|
+
runClientDecode: () => (/* binding */ runClientDecode)
|
|
5585
|
+
});
|
|
5586
|
+
// ESM COMPAT FLAG
|
|
5587
|
+
__webpack_require__.r(__webpack_exports__);
|
|
5588
|
+
|
|
5589
|
+
// EXTERNAL MODULE: ./src/lib/util.js + 1 modules
|
|
5590
|
+
var util = __webpack_require__(4410);
|
|
5591
|
+
// EXTERNAL MODULE: ./src/lib/viewers/media/waveform/constants.ts
|
|
5592
|
+
var constants = __webpack_require__(4929);
|
|
5593
|
+
;// ./src/lib/viewers/media/waveform/types.ts
|
|
5594
|
+
/**
|
|
5595
|
+
* Box V1 is the in-viewer form: unsigned mono peaks in [0, 1] (peak envelope, mono_max).
|
|
5596
|
+
* Wire JSON only requires version, durationSec, and peaks. Policy fields default.
|
|
5597
|
+
* Conversion or wavesurfer payloads should be adapted at the edge, not stored as-is.
|
|
5598
|
+
*/
|
|
5599
|
+
|
|
5600
|
+
/** Who produced peaks */
|
|
5601
|
+
|
|
5602
|
+
/**
|
|
5603
|
+
* Viewer-normalized waveform JSON (version 1).
|
|
5604
|
+
* Required: version, durationSec, peaks. Everything else is optional and defaulted.
|
|
5605
|
+
*/
|
|
5606
|
+
|
|
5607
|
+
/** Validated, runtime-friendly peak data passed to renderers. */
|
|
5608
|
+
|
|
5609
|
+
const WAVEFORM_ERROR_CODES = ['INVALID_PAYLOAD', 'UNSUPPORTED_VERSION', 'INVALID_DURATION', 'DURATION_MISMATCH', 'PEAK_COUNT_EXCEEDED', 'PAYLOAD_TOO_LARGE', 'NON_FINITE_PEAK', 'PEAK_OUT_OF_RANGE', 'EMPTY_PEAKS', 'CAP_EXCEEDED', 'LOAD_FAILED', 'DECODE_FAILED', 'CANCELLED', 'UNAVAILABLE'];
|
|
5610
|
+
const WAVEFORM_ERROR_CODE_SET = new Set(WAVEFORM_ERROR_CODES);
|
|
5611
|
+
function isWaveformErrorCode(value) {
|
|
5612
|
+
return WAVEFORM_ERROR_CODE_SET.has(value);
|
|
5613
|
+
}
|
|
5614
|
+
|
|
5615
|
+
/**
|
|
5616
|
+
* Async boundary for waveform data. Implementations may fetch fixtures, decode client-side,
|
|
5617
|
+
* or load Conversion reps — callers only observe WaveformLoadState.
|
|
5618
|
+
*/
|
|
5619
|
+
|
|
5620
|
+
/** Visible slice of the timeline. Emitted whenever zoom, scroll, or width changes. */
|
|
5621
|
+
|
|
5622
|
+
/** One canvas linear-gradient stop. `offset` is 0–1 along the bar. */
|
|
5623
|
+
|
|
5624
|
+
/**
|
|
5625
|
+
* Wavesurfer's two paints: left of the playhead (`progressColor`) and right of it (`waveColor`).
|
|
5626
|
+
* A string is a solid fill; a stop list is a left-to-right step gradient.
|
|
5627
|
+
*/
|
|
5628
|
+
;// ./src/lib/viewers/media/waveform/createWaveformLoader.ts
|
|
5629
|
+
/* unused harmony import specifier */ var isRetryableWaveformError;
|
|
5630
|
+
/* unused harmony import specifier */ var validateWaveformPayload;
|
|
5631
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5632
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
5633
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5634
|
+
|
|
5635
|
+
|
|
5636
|
+
/** Typed throw from fetchPayload (e.g. client decode). `error.name` fallback still works. */
|
|
5637
|
+
class WaveformLoadError extends Error {
|
|
5638
|
+
constructor(code, message) {
|
|
5639
|
+
super(message);
|
|
5640
|
+
_defineProperty(this, "code", void 0);
|
|
5641
|
+
this.name = code;
|
|
5642
|
+
this.code = code;
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
function isAbortError(error) {
|
|
5646
|
+
return typeof DOMException !== 'undefined' && error instanceof DOMException && error.name === 'AbortError' || error instanceof Error && error.name === 'AbortError';
|
|
5647
|
+
}
|
|
5648
|
+
function errorFromUnknown(error, fallbackCode = 'LOAD_FAILED') {
|
|
5649
|
+
if (error instanceof WaveformLoadError) {
|
|
5650
|
+
return {
|
|
5651
|
+
code: error.code,
|
|
5652
|
+
message: error.message
|
|
5653
|
+
};
|
|
5654
|
+
}
|
|
5655
|
+
if (error instanceof SyntaxError) {
|
|
5656
|
+
return {
|
|
5657
|
+
code: 'INVALID_PAYLOAD',
|
|
5658
|
+
message: error.message
|
|
5659
|
+
};
|
|
5660
|
+
}
|
|
5661
|
+
if (error instanceof Error && isWaveformErrorCode(error.name)) {
|
|
5662
|
+
return {
|
|
5663
|
+
code: error.name,
|
|
5664
|
+
message: error.message
|
|
5665
|
+
};
|
|
5666
|
+
}
|
|
5667
|
+
const message = error instanceof Error ? error.message : 'Waveform load failed';
|
|
5668
|
+
return {
|
|
5669
|
+
code: fallbackCode,
|
|
5670
|
+
message
|
|
5671
|
+
};
|
|
5672
|
+
}
|
|
5673
|
+
function failedLoadState(error) {
|
|
5674
|
+
return {
|
|
5675
|
+
status: 'failed',
|
|
5676
|
+
error,
|
|
5677
|
+
retryable: isRetryableWaveformError(error.code)
|
|
5678
|
+
};
|
|
5679
|
+
}
|
|
5680
|
+
function readyLoadState(payload) {
|
|
5681
|
+
return {
|
|
5682
|
+
status: 'ready',
|
|
5683
|
+
payload
|
|
5684
|
+
};
|
|
5685
|
+
}
|
|
5686
|
+
|
|
5687
|
+
/**
|
|
5688
|
+
* Wraps an async payload fetch with abort + stale-result suppression.
|
|
5689
|
+
* Playback must not depend on this completing — callers treat unavailable/failed as degrade paths.
|
|
5690
|
+
* abort() cancels an in-flight load only; a successful ready state is left intact.
|
|
5691
|
+
*/
|
|
5692
|
+
function createWaveformLoader(fetchPayload, options = {}) {
|
|
5693
|
+
let state = {
|
|
5694
|
+
status: 'unavailable'
|
|
5695
|
+
};
|
|
5696
|
+
let generation = 0;
|
|
5697
|
+
let abortController = null;
|
|
5698
|
+
const setState = next => {
|
|
5699
|
+
state = next;
|
|
5700
|
+
};
|
|
5701
|
+
const settle = next => {
|
|
5702
|
+
setState(next);
|
|
5703
|
+
return next;
|
|
5704
|
+
};
|
|
5705
|
+
const startLoad = () => {
|
|
5706
|
+
if (abortController) {
|
|
5707
|
+
abortController.abort();
|
|
5708
|
+
}
|
|
5709
|
+
generation += 1;
|
|
5710
|
+
abortController = new AbortController();
|
|
5711
|
+
setState({
|
|
5712
|
+
status: 'pending'
|
|
5713
|
+
});
|
|
5714
|
+
return {
|
|
5715
|
+
id: generation,
|
|
5716
|
+
signal: abortController.signal
|
|
5717
|
+
};
|
|
5718
|
+
};
|
|
5719
|
+
const cancelledIfStale = request => {
|
|
5720
|
+
if (!request.signal.aborted && generation === request.id) {
|
|
5721
|
+
return null;
|
|
5722
|
+
}
|
|
5723
|
+
if (generation === request.id) {
|
|
5724
|
+
setState({
|
|
5725
|
+
status: 'cancelled'
|
|
5726
|
+
});
|
|
5727
|
+
}
|
|
5728
|
+
return {
|
|
5729
|
+
status: 'cancelled'
|
|
5730
|
+
};
|
|
5731
|
+
};
|
|
5732
|
+
const settleValidation = validation => {
|
|
5733
|
+
if (!validation.ok) {
|
|
5734
|
+
return settle(failedLoadState(validation.error));
|
|
5735
|
+
}
|
|
5736
|
+
return settle(readyLoadState(validation.payload));
|
|
5737
|
+
};
|
|
5738
|
+
const settleFetchError = (error, request) => {
|
|
5739
|
+
if (request.signal.aborted || generation !== request.id || isAbortError(error)) {
|
|
5740
|
+
if (generation === request.id) {
|
|
5741
|
+
return settle({
|
|
5742
|
+
status: 'cancelled'
|
|
5743
|
+
});
|
|
5744
|
+
}
|
|
5745
|
+
return {
|
|
5746
|
+
status: 'cancelled'
|
|
5747
|
+
};
|
|
5748
|
+
}
|
|
5749
|
+
return settle(failedLoadState(errorFromUnknown(error)));
|
|
5750
|
+
};
|
|
5751
|
+
const load = async () => {
|
|
5752
|
+
const request = startLoad();
|
|
5753
|
+
try {
|
|
5754
|
+
const raw = await fetchPayload(request.signal);
|
|
5755
|
+
const staleAfterFetch = cancelledIfStale(request);
|
|
5756
|
+
if (staleAfterFetch) {
|
|
5757
|
+
return staleAfterFetch;
|
|
5758
|
+
}
|
|
5759
|
+
const validation = validateWaveformPayload(raw, options);
|
|
5760
|
+
const staleAfterValidate = cancelledIfStale(request);
|
|
5761
|
+
if (staleAfterValidate) {
|
|
5762
|
+
return staleAfterValidate;
|
|
5763
|
+
}
|
|
5764
|
+
return settleValidation(validation);
|
|
5765
|
+
} catch (error) {
|
|
5766
|
+
return settleFetchError(error, request);
|
|
5767
|
+
} finally {
|
|
5768
|
+
if (generation === request.id) {
|
|
5769
|
+
abortController = null;
|
|
5770
|
+
}
|
|
5771
|
+
}
|
|
5772
|
+
};
|
|
5773
|
+
const abort = () => {
|
|
5774
|
+
if (!abortController) {
|
|
5775
|
+
return;
|
|
5776
|
+
}
|
|
5777
|
+
generation += 1;
|
|
5778
|
+
abortController.abort();
|
|
5779
|
+
abortController = null;
|
|
5780
|
+
setState({
|
|
5781
|
+
status: 'cancelled'
|
|
5782
|
+
});
|
|
5783
|
+
};
|
|
5784
|
+
return {
|
|
5785
|
+
load,
|
|
5786
|
+
abort,
|
|
5787
|
+
getState: () => state
|
|
5788
|
+
};
|
|
5789
|
+
}
|
|
5790
|
+
|
|
5791
|
+
/** Returns capped state when media exceeds client decode size or duration limits. */
|
|
5792
|
+
function createCappedWaveformState(message) {
|
|
5793
|
+
return {
|
|
5794
|
+
status: 'capped',
|
|
5795
|
+
error: {
|
|
5796
|
+
code: 'CAP_EXCEEDED',
|
|
5797
|
+
message
|
|
5798
|
+
}
|
|
5799
|
+
};
|
|
5800
|
+
}
|
|
5801
|
+
;// ./src/lib/viewers/media/waveform/validateWaveformPayload.ts
|
|
5802
|
+
|
|
5803
|
+
const DEFAULT_PEAK_SCALE = 'unit';
|
|
5804
|
+
const DEFAULT_CHANNEL_POLICY = 'mono_max';
|
|
5805
|
+
const DEFAULT_ENVELOPE = 'peak';
|
|
5806
|
+
function fail(code, message, retryable = false) {
|
|
5807
|
+
return {
|
|
5808
|
+
ok: false,
|
|
5809
|
+
error: {
|
|
5810
|
+
code,
|
|
5811
|
+
message
|
|
5812
|
+
},
|
|
5813
|
+
retryable
|
|
5814
|
+
};
|
|
5815
|
+
}
|
|
5816
|
+
function isPlainObject(value) {
|
|
5817
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
5818
|
+
}
|
|
5819
|
+
function payloadByteLength(raw) {
|
|
5820
|
+
try {
|
|
5821
|
+
const serialized = JSON.stringify(raw);
|
|
5822
|
+
if (typeof Buffer !== 'undefined') {
|
|
5823
|
+
return Buffer.byteLength(serialized, 'utf8');
|
|
5824
|
+
}
|
|
5825
|
+
if (typeof TextEncoder !== 'undefined') {
|
|
5826
|
+
return new TextEncoder().encode(serialized).length;
|
|
5827
|
+
}
|
|
5828
|
+
return serialized.length;
|
|
5829
|
+
} catch {
|
|
5830
|
+
return Number.MAX_SAFE_INTEGER;
|
|
5831
|
+
}
|
|
5832
|
+
}
|
|
5833
|
+
function readOptionalPolicy(raw, key, allowed) {
|
|
5834
|
+
if (!(key in raw) || raw[key] === undefined) {
|
|
5835
|
+
return undefined;
|
|
5836
|
+
}
|
|
5837
|
+
return raw[key] === allowed ? allowed : null;
|
|
5838
|
+
}
|
|
5839
|
+
function asWaveformPayloadV1(raw) {
|
|
5840
|
+
const {
|
|
5841
|
+
version,
|
|
5842
|
+
durationSec,
|
|
5843
|
+
peaks
|
|
5844
|
+
} = raw;
|
|
5845
|
+
if (version !== constants/* WAVEFORM_PAYLOAD_VERSION */.sh || typeof durationSec !== 'number' || !Array.isArray(peaks)) {
|
|
5846
|
+
return null;
|
|
5847
|
+
}
|
|
5848
|
+
const peakScale = readOptionalPolicy(raw, 'peakScale', DEFAULT_PEAK_SCALE);
|
|
5849
|
+
const channelPolicy = readOptionalPolicy(raw, 'channelPolicy', DEFAULT_CHANNEL_POLICY);
|
|
5850
|
+
const envelope = readOptionalPolicy(raw, 'envelope', DEFAULT_ENVELOPE);
|
|
5851
|
+
if (peakScale === null || channelPolicy === null || envelope === null) {
|
|
5852
|
+
return null;
|
|
5853
|
+
}
|
|
5854
|
+
if ('channels' in raw && raw.channels !== undefined && raw.channels !== 1) {
|
|
5855
|
+
return null;
|
|
5856
|
+
}
|
|
5857
|
+
return {
|
|
5858
|
+
version: constants/* WAVEFORM_PAYLOAD_VERSION */.sh,
|
|
5859
|
+
durationSec,
|
|
5860
|
+
peaks: peaks,
|
|
5861
|
+
peakScale: peakScale ?? DEFAULT_PEAK_SCALE,
|
|
5862
|
+
channelPolicy: channelPolicy ?? DEFAULT_CHANNEL_POLICY,
|
|
5863
|
+
envelope: envelope ?? DEFAULT_ENVELOPE,
|
|
5864
|
+
channels: 1
|
|
5865
|
+
};
|
|
5866
|
+
}
|
|
5867
|
+
function readPayloadObject(raw, maxPayloadBytes, isPayloadByteCheckSkipped = false) {
|
|
5868
|
+
if (raw === null || raw === undefined) {
|
|
5869
|
+
return fail('INVALID_PAYLOAD', 'Payload is null or undefined');
|
|
5870
|
+
}
|
|
5871
|
+
if (!isPayloadByteCheckSkipped) {
|
|
5872
|
+
const byteLength = payloadByteLength(raw);
|
|
5873
|
+
if (byteLength > maxPayloadBytes) {
|
|
5874
|
+
return fail('PAYLOAD_TOO_LARGE', `Payload size ${byteLength} exceeds limit ${maxPayloadBytes}`);
|
|
5875
|
+
}
|
|
5876
|
+
}
|
|
5877
|
+
if (!isPlainObject(raw)) {
|
|
5878
|
+
return fail('INVALID_PAYLOAD', 'Payload must be an object');
|
|
5879
|
+
}
|
|
5880
|
+
return {
|
|
5881
|
+
ok: true,
|
|
5882
|
+
value: raw
|
|
5883
|
+
};
|
|
5884
|
+
}
|
|
5885
|
+
function checkVersion(raw) {
|
|
5886
|
+
if (raw.version === constants/* WAVEFORM_PAYLOAD_VERSION */.sh) {
|
|
5887
|
+
return null;
|
|
5888
|
+
}
|
|
5889
|
+
const {
|
|
5890
|
+
version
|
|
5891
|
+
} = raw;
|
|
5892
|
+
if (typeof version === 'number' && version > constants/* WAVEFORM_PAYLOAD_VERSION */.sh) {
|
|
5893
|
+
return fail('UNSUPPORTED_VERSION', `Unsupported waveform version ${version}; max supported is ${constants/* WAVEFORM_PAYLOAD_VERSION */.sh}`);
|
|
5894
|
+
}
|
|
5895
|
+
return fail('INVALID_PAYLOAD', 'Missing or invalid version field');
|
|
5896
|
+
}
|
|
5897
|
+
function checkDuration(payload, expectedDurationSec) {
|
|
5898
|
+
if (!Number.isFinite(payload.durationSec) || payload.durationSec <= 0) {
|
|
5899
|
+
return fail('INVALID_DURATION', 'durationSec must be a positive finite number');
|
|
5900
|
+
}
|
|
5901
|
+
if (expectedDurationSec !== undefined && Number.isFinite(expectedDurationSec) && Math.abs(payload.durationSec - expectedDurationSec) > constants/* DURATION_MISMATCH_TOLERANCE_SEC */.GQ) {
|
|
5902
|
+
return fail('DURATION_MISMATCH', `Payload duration ${payload.durationSec}s differs from media duration ${expectedDurationSec}s`, true);
|
|
5903
|
+
}
|
|
5904
|
+
return null;
|
|
5905
|
+
}
|
|
5906
|
+
function normalizePeaks(peaks, maxPeakCount) {
|
|
5907
|
+
if (peaks.length === 0) {
|
|
5908
|
+
return fail('EMPTY_PEAKS', 'peaks array must not be empty');
|
|
5909
|
+
}
|
|
5910
|
+
if (peaks.length > maxPeakCount) {
|
|
5911
|
+
return fail('PEAK_COUNT_EXCEEDED', `peaks length ${peaks.length} exceeds max ${maxPeakCount}`);
|
|
5912
|
+
}
|
|
5913
|
+
const normalized = new Float32Array(peaks.length);
|
|
5914
|
+
for (let i = 0; i < peaks.length; i += 1) {
|
|
5915
|
+
const value = peaks[i];
|
|
5916
|
+
if (!Number.isFinite(value)) {
|
|
5917
|
+
return fail('NON_FINITE_PEAK', `Peak at index ${i} is not finite`);
|
|
5918
|
+
}
|
|
5919
|
+
if (value < constants/* PEAK_UNIT_MIN */.mJ || value > constants/* PEAK_UNIT_MAX */.i8) {
|
|
5920
|
+
return fail('PEAK_OUT_OF_RANGE', `Peak at index ${i} is outside [${constants/* PEAK_UNIT_MIN */.mJ}, ${constants/* PEAK_UNIT_MAX */.i8}]`);
|
|
5921
|
+
}
|
|
5922
|
+
normalized[i] = value;
|
|
5923
|
+
}
|
|
5924
|
+
return {
|
|
5925
|
+
ok: true,
|
|
5926
|
+
peaks: normalized
|
|
5927
|
+
};
|
|
5928
|
+
}
|
|
5929
|
+
|
|
5930
|
+
/**
|
|
5931
|
+
* Validates a version-1 waveform payload and returns normalized peaks for rendering.
|
|
5932
|
+
* Wire JSON requires version, durationSec, and peaks. sampleCount and source are ignored.
|
|
5933
|
+
*/
|
|
5934
|
+
function validateWaveformPayload_validateWaveformPayload(raw, options = {}) {
|
|
5935
|
+
const maxPeakCount = options.maxPeakCount ?? constants/* MAX_PEAK_COUNT */.FY;
|
|
5936
|
+
const maxPayloadBytes = options.maxPayloadBytes ?? constants/* MAX_PAYLOAD_BYTES */.qY;
|
|
5937
|
+
const objectResult = readPayloadObject(raw, maxPayloadBytes, options.isPayloadByteCheckSkipped === true);
|
|
5938
|
+
if (!objectResult.ok) {
|
|
5939
|
+
return objectResult;
|
|
5940
|
+
}
|
|
5941
|
+
const versionFailure = checkVersion(objectResult.value);
|
|
5942
|
+
if (versionFailure) {
|
|
5943
|
+
return versionFailure;
|
|
5944
|
+
}
|
|
5945
|
+
const payload = asWaveformPayloadV1(objectResult.value);
|
|
5946
|
+
if (!payload) {
|
|
5947
|
+
return fail('INVALID_PAYLOAD', 'Payload failed structural validation');
|
|
5948
|
+
}
|
|
5949
|
+
const durationFailure = checkDuration(payload, options.expectedDurationSec);
|
|
5950
|
+
if (durationFailure) {
|
|
5951
|
+
return durationFailure;
|
|
5952
|
+
}
|
|
5953
|
+
const peaksResult = normalizePeaks(payload.peaks, maxPeakCount);
|
|
5954
|
+
if (!peaksResult.ok) {
|
|
5955
|
+
return peaksResult;
|
|
5956
|
+
}
|
|
5957
|
+
return {
|
|
5958
|
+
ok: true,
|
|
5959
|
+
payload: {
|
|
5960
|
+
version: constants/* WAVEFORM_PAYLOAD_VERSION */.sh,
|
|
5961
|
+
durationSec: payload.durationSec,
|
|
5962
|
+
peaks: peaksResult.peaks,
|
|
5963
|
+
peakScale: payload.peakScale ?? DEFAULT_PEAK_SCALE,
|
|
5964
|
+
channelPolicy: payload.channelPolicy ?? DEFAULT_CHANNEL_POLICY,
|
|
5965
|
+
envelope: payload.envelope ?? DEFAULT_ENVELOPE
|
|
5966
|
+
}
|
|
5967
|
+
};
|
|
5968
|
+
}
|
|
5969
|
+
|
|
5970
|
+
/** Maps validation / load failures to retry policy for loaders. */
|
|
5971
|
+
function validateWaveformPayload_isRetryableWaveformError(code) {
|
|
5972
|
+
return code === 'DURATION_MISMATCH' || code === 'DECODE_FAILED' || code === 'LOAD_FAILED';
|
|
5973
|
+
}
|
|
5974
|
+
;// ./src/lib/viewers/media/waveform/decode.ts
|
|
5975
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
5976
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { decode_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5977
|
+
function decode_defineProperty(e, r, t) { return (r = decode_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5978
|
+
function decode_toPropertyKey(t) { var i = decode_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
5979
|
+
function decode_toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5980
|
+
|
|
5981
|
+
|
|
5982
|
+
|
|
5983
|
+
|
|
5984
|
+
const EMPTY_TIMINGS = {
|
|
5985
|
+
attemptMs: null,
|
|
5986
|
+
extractMs: null
|
|
5987
|
+
};
|
|
5988
|
+
function createAbortError() {
|
|
5989
|
+
return new DOMException('Aborted', 'AbortError');
|
|
5990
|
+
}
|
|
5991
|
+
function isPositiveFinite(value) {
|
|
5992
|
+
return typeof value === 'number' && Number.isFinite(value) && value > 0;
|
|
5993
|
+
}
|
|
5994
|
+
function getAudioContextConstructor() {
|
|
5995
|
+
if (typeof window === 'undefined') {
|
|
5996
|
+
return undefined;
|
|
5997
|
+
}
|
|
5998
|
+
const {
|
|
5999
|
+
AudioContext,
|
|
6000
|
+
webkitAudioContext
|
|
6001
|
+
} = window;
|
|
6002
|
+
return AudioContext || webkitAudioContext;
|
|
6003
|
+
}
|
|
6004
|
+
function getDecodeSkipMessage(reason) {
|
|
6005
|
+
if (reason === 'compressed_size') {
|
|
6006
|
+
return 'Compressed size exceeds client decode limit';
|
|
6007
|
+
}
|
|
6008
|
+
if (reason === 'duration') {
|
|
6009
|
+
return 'Duration exceeds client decode limit';
|
|
6010
|
+
}
|
|
6011
|
+
return 'Compressed size or duration is missing; skipping client decode';
|
|
6012
|
+
}
|
|
6013
|
+
function createSkippedDecodeResult(reason) {
|
|
6014
|
+
if (reason === 'missing_metadata') {
|
|
6015
|
+
return {
|
|
6016
|
+
status: 'unavailable',
|
|
6017
|
+
error: {
|
|
6018
|
+
code: 'UNAVAILABLE',
|
|
6019
|
+
message: getDecodeSkipMessage(reason)
|
|
6020
|
+
},
|
|
6021
|
+
isDecodeSkipped: true,
|
|
6022
|
+
timings: EMPTY_TIMINGS,
|
|
6023
|
+
reason
|
|
6024
|
+
};
|
|
6025
|
+
}
|
|
6026
|
+
return _objectSpread(_objectSpread({}, createCappedWaveformState(getDecodeSkipMessage(reason))), {}, {
|
|
6027
|
+
isDecodeSkipped: true,
|
|
6028
|
+
timings: EMPTY_TIMINGS,
|
|
6029
|
+
reason
|
|
6030
|
+
});
|
|
6031
|
+
}
|
|
6032
|
+
function decodeWithContext(context, buffer, signal) {
|
|
6033
|
+
return new Promise((resolve, reject) => {
|
|
6034
|
+
let isSettled = false;
|
|
6035
|
+
let onAbort = () => undefined;
|
|
6036
|
+
const onSuccess = decoded => {
|
|
6037
|
+
if (isSettled) {
|
|
6038
|
+
return;
|
|
6039
|
+
}
|
|
6040
|
+
isSettled = true;
|
|
6041
|
+
signal?.removeEventListener('abort', onAbort);
|
|
6042
|
+
resolve(decoded);
|
|
6043
|
+
};
|
|
6044
|
+
const onFailure = error => {
|
|
6045
|
+
if (isSettled) {
|
|
6046
|
+
return;
|
|
6047
|
+
}
|
|
6048
|
+
isSettled = true;
|
|
6049
|
+
signal?.removeEventListener('abort', onAbort);
|
|
6050
|
+
if (isAbortError(error)) {
|
|
6051
|
+
reject(error instanceof DOMException ? error : createAbortError());
|
|
6052
|
+
return;
|
|
6053
|
+
}
|
|
6054
|
+
reject(error instanceof WaveformLoadError ? error : new WaveformLoadError('DECODE_FAILED', 'decodeAudioData failed'));
|
|
6055
|
+
};
|
|
6056
|
+
onAbort = () => onFailure(createAbortError());
|
|
6057
|
+
if (signal?.aborted) {
|
|
6058
|
+
onFailure(createAbortError());
|
|
6059
|
+
return;
|
|
6060
|
+
}
|
|
6061
|
+
signal?.addEventListener('abort', onAbort, {
|
|
6062
|
+
once: true
|
|
6063
|
+
});
|
|
6064
|
+
try {
|
|
6065
|
+
const maybePromise = context.decodeAudioData(buffer, onSuccess, onFailure);
|
|
6066
|
+
if (maybePromise && typeof maybePromise.then === 'function') {
|
|
6067
|
+
maybePromise.then(onSuccess, onFailure);
|
|
6068
|
+
}
|
|
6069
|
+
} catch (error) {
|
|
6070
|
+
onFailure(error);
|
|
6071
|
+
}
|
|
6072
|
+
});
|
|
6073
|
+
}
|
|
6074
|
+
|
|
6075
|
+
/**
|
|
6076
|
+
* Decide whether to run decodeAudioData. Either cap failing, or unknown size/duration,
|
|
6077
|
+
* skips decode so playback is never blocked by expanding the full audio buffer.
|
|
6078
|
+
*/
|
|
6079
|
+
function getDecodeDecision(media, caps = {}) {
|
|
6080
|
+
const maxCompressedBytes = caps.maxCompressedBytes ?? constants/* CLIENT_DECODE_MAX_COMPRESSED_BYTES */.EB;
|
|
6081
|
+
const maxDurationSec = caps.maxDurationSec ?? constants/* CLIENT_DECODE_MAX_DURATION_SEC */.nG;
|
|
6082
|
+
const {
|
|
6083
|
+
compressedBytes,
|
|
6084
|
+
durationSec
|
|
6085
|
+
} = media;
|
|
6086
|
+
if (!isPositiveFinite(compressedBytes) || !isPositiveFinite(durationSec)) {
|
|
6087
|
+
return {
|
|
6088
|
+
isAllowed: false,
|
|
6089
|
+
reason: 'missing_metadata'
|
|
6090
|
+
};
|
|
6091
|
+
}
|
|
6092
|
+
if (compressedBytes > maxCompressedBytes) {
|
|
6093
|
+
return {
|
|
6094
|
+
isAllowed: false,
|
|
6095
|
+
reason: 'compressed_size'
|
|
6096
|
+
};
|
|
6097
|
+
}
|
|
6098
|
+
if (durationSec > maxDurationSec) {
|
|
6099
|
+
return {
|
|
6100
|
+
isAllowed: false,
|
|
6101
|
+
reason: 'duration'
|
|
6102
|
+
};
|
|
6103
|
+
}
|
|
6104
|
+
return {
|
|
6105
|
+
isAllowed: true
|
|
6106
|
+
};
|
|
6107
|
+
}
|
|
6108
|
+
|
|
6109
|
+
/**
|
|
6110
|
+
* Collapse audio channels to one unsigned peak per time bucket (max abs, then clamp to unit).
|
|
6111
|
+
* Accepts an AudioBuffer so callers can extract before closing the AudioContext.
|
|
6112
|
+
*/
|
|
6113
|
+
function extractPeaks(audio, peakCount = constants/* CLIENT_DECODE_PEAK_COUNT */.f3) {
|
|
6114
|
+
const channels = Array.isArray(audio) ? audio : Array.from({
|
|
6115
|
+
length: audio.numberOfChannels
|
|
6116
|
+
}, (_, channelIndex) => audio.getChannelData(channelIndex));
|
|
6117
|
+
if (peakCount <= 0 || channels.length === 0) {
|
|
6118
|
+
return [];
|
|
6119
|
+
}
|
|
6120
|
+
const sampleCount = channels[0].length;
|
|
6121
|
+
if (sampleCount === 0) {
|
|
6122
|
+
return [];
|
|
6123
|
+
}
|
|
6124
|
+
const peaks = new Array(peakCount);
|
|
6125
|
+
const bucketWidth = sampleCount / peakCount;
|
|
6126
|
+
for (let i = 0; i < peakCount; i += 1) {
|
|
6127
|
+
const start = Math.floor(i * bucketWidth);
|
|
6128
|
+
const end = Math.max(start + 1, Math.floor((i + 1) * bucketWidth));
|
|
6129
|
+
let maxAbs = 0;
|
|
6130
|
+
for (let sampleIndex = start; sampleIndex < end && sampleIndex < sampleCount; sampleIndex += 1) {
|
|
6131
|
+
for (let channelIndex = 0; channelIndex < channels.length; channelIndex += 1) {
|
|
6132
|
+
const value = Math.abs(channels[channelIndex][sampleIndex]);
|
|
6133
|
+
if (value > maxAbs) {
|
|
6134
|
+
maxAbs = value;
|
|
6135
|
+
}
|
|
6136
|
+
}
|
|
6137
|
+
}
|
|
6138
|
+
peaks[i] = Math.min(constants/* PEAK_UNIT_MAX */.i8, Math.max(constants/* PEAK_UNIT_MIN */.mJ, maxAbs));
|
|
6139
|
+
}
|
|
6140
|
+
return peaks;
|
|
6141
|
+
}
|
|
6142
|
+
|
|
6143
|
+
/**
|
|
6144
|
+
* Decode compressed audio and extract unit peaks while the AudioBuffer is live.
|
|
6145
|
+
* Does not attach a media element or fetch a URL. Does not copy channel data.
|
|
6146
|
+
*/
|
|
6147
|
+
async function decodeToPeaks(arrayBuffer, signal, peakCount = constants/* CLIENT_DECODE_PEAK_COUNT */.f3) {
|
|
6148
|
+
if (signal?.aborted) {
|
|
6149
|
+
throw createAbortError();
|
|
6150
|
+
}
|
|
6151
|
+
const AudioContextConstructor = getAudioContextConstructor();
|
|
6152
|
+
if (!AudioContextConstructor) {
|
|
6153
|
+
throw new WaveformLoadError('DECODE_FAILED', 'AudioContext is not available');
|
|
6154
|
+
}
|
|
6155
|
+
const context = new AudioContextConstructor();
|
|
6156
|
+
try {
|
|
6157
|
+
const audioBuffer = await decodeWithContext(context, arrayBuffer.slice(0), signal);
|
|
6158
|
+
if (signal?.aborted) {
|
|
6159
|
+
throw createAbortError();
|
|
6160
|
+
}
|
|
6161
|
+
const extractStarted = (0,util/* getCurrentTimeMs */.RU)();
|
|
6162
|
+
const peaks = extractPeaks(audioBuffer, peakCount);
|
|
6163
|
+
return {
|
|
6164
|
+
durationSec: audioBuffer.duration,
|
|
6165
|
+
peaks,
|
|
6166
|
+
extractMs: (0,util/* getCurrentTimeMs */.RU)() - extractStarted
|
|
6167
|
+
};
|
|
6168
|
+
} catch (error) {
|
|
6169
|
+
if (signal?.aborted || isAbortError(error)) {
|
|
6170
|
+
throw createAbortError();
|
|
6171
|
+
}
|
|
6172
|
+
throw error;
|
|
6173
|
+
} finally {
|
|
6174
|
+
try {
|
|
6175
|
+
await context.close();
|
|
6176
|
+
} catch {
|
|
6177
|
+
// Context may already be closed.
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
6180
|
+
}
|
|
6181
|
+
|
|
6182
|
+
/**
|
|
6183
|
+
* Run a client-decode attempt against the V1 waveform contract.
|
|
6184
|
+
* Decode is not invoked when size or duration is over the cap (or unknown).
|
|
6185
|
+
*/
|
|
6186
|
+
async function runClientDecode(options) {
|
|
6187
|
+
const decision = getDecodeDecision({
|
|
6188
|
+
compressedBytes: options.compressedBytes,
|
|
6189
|
+
durationSec: options.durationSec
|
|
6190
|
+
}, options.caps);
|
|
6191
|
+
if (!decision.isAllowed) {
|
|
6192
|
+
return createSkippedDecodeResult(decision.reason);
|
|
6193
|
+
}
|
|
6194
|
+
if (options.signal?.aborted) {
|
|
6195
|
+
return {
|
|
6196
|
+
status: 'cancelled',
|
|
6197
|
+
isDecodeSkipped: true,
|
|
6198
|
+
timings: EMPTY_TIMINGS
|
|
6199
|
+
};
|
|
6200
|
+
}
|
|
6201
|
+
const signal = options.signal ?? new AbortController().signal;
|
|
6202
|
+
const decodeStarted = (0,util/* getCurrentTimeMs */.RU)();
|
|
6203
|
+
let decodeOutput;
|
|
6204
|
+
try {
|
|
6205
|
+
decodeOutput = await options.decode(signal);
|
|
6206
|
+
} catch (error) {
|
|
6207
|
+
if (signal.aborted || isAbortError(error)) {
|
|
6208
|
+
return {
|
|
6209
|
+
status: 'cancelled',
|
|
6210
|
+
isDecodeSkipped: false,
|
|
6211
|
+
timings: EMPTY_TIMINGS
|
|
6212
|
+
};
|
|
6213
|
+
}
|
|
6214
|
+
const waveformError = errorFromUnknown(error, 'DECODE_FAILED');
|
|
6215
|
+
return {
|
|
6216
|
+
status: 'failed',
|
|
6217
|
+
error: waveformError,
|
|
6218
|
+
retryable: validateWaveformPayload_isRetryableWaveformError(waveformError.code),
|
|
6219
|
+
isDecodeSkipped: false,
|
|
6220
|
+
timings: {
|
|
6221
|
+
attemptMs: (0,util/* getCurrentTimeMs */.RU)() - decodeStarted,
|
|
6222
|
+
extractMs: null
|
|
6223
|
+
}
|
|
6224
|
+
};
|
|
6225
|
+
}
|
|
6226
|
+
const attemptMs = (0,util/* getCurrentTimeMs */.RU)() - decodeStarted;
|
|
6227
|
+
if (signal.aborted) {
|
|
6228
|
+
return {
|
|
6229
|
+
status: 'cancelled',
|
|
6230
|
+
isDecodeSkipped: false,
|
|
6231
|
+
timings: {
|
|
6232
|
+
attemptMs,
|
|
6233
|
+
extractMs: null
|
|
6234
|
+
}
|
|
6235
|
+
};
|
|
6236
|
+
}
|
|
6237
|
+
const validation = validateWaveformPayload_validateWaveformPayload({
|
|
6238
|
+
version: constants/* WAVEFORM_PAYLOAD_VERSION */.sh,
|
|
6239
|
+
durationSec: options.durationSec ?? decodeOutput.durationSec,
|
|
6240
|
+
peaks: decodeOutput.peaks
|
|
6241
|
+
}, {
|
|
6242
|
+
isPayloadByteCheckSkipped: true
|
|
6243
|
+
});
|
|
6244
|
+
if (!validation.ok) {
|
|
6245
|
+
return {
|
|
6246
|
+
status: 'failed',
|
|
6247
|
+
error: validation.error,
|
|
6248
|
+
retryable: validateWaveformPayload_isRetryableWaveformError(validation.error.code),
|
|
6249
|
+
isDecodeSkipped: false,
|
|
6250
|
+
timings: {
|
|
6251
|
+
attemptMs,
|
|
6252
|
+
extractMs: decodeOutput.extractMs
|
|
6253
|
+
}
|
|
6254
|
+
};
|
|
6255
|
+
}
|
|
6256
|
+
return {
|
|
6257
|
+
status: 'ready',
|
|
6258
|
+
payload: validation.payload,
|
|
6259
|
+
isDecodeSkipped: false,
|
|
6260
|
+
timings: {
|
|
6261
|
+
attemptMs,
|
|
6262
|
+
extractMs: decodeOutput.extractMs
|
|
6263
|
+
}
|
|
6264
|
+
};
|
|
6265
|
+
}
|
|
6266
|
+
|
|
6267
|
+
/**
|
|
6268
|
+
* Gate, fetch, decode, and extract in-viewer peaks. Skips decode when over cap.
|
|
6269
|
+
* Playback must not await this.
|
|
6270
|
+
*/
|
|
6271
|
+
function loadPeaks(request) {
|
|
6272
|
+
return runClientDecode({
|
|
6273
|
+
compressedBytes: request.compressedBytes,
|
|
6274
|
+
durationSec: request.durationSec,
|
|
6275
|
+
signal: request.signal,
|
|
6276
|
+
decode: async signal => {
|
|
6277
|
+
const arrayBuffer = await request.fetchArrayBuffer(signal);
|
|
6278
|
+
return decodeToPeaks(arrayBuffer, signal);
|
|
6279
|
+
}
|
|
6280
|
+
});
|
|
6281
|
+
}
|
|
6282
|
+
|
|
6283
|
+
/***/ },
|
|
6284
|
+
|
|
4670
6285
|
/***/ 2485
|
|
4671
6286
|
(module, exports) {
|
|
4672
6287
|
|
|
@@ -11436,7 +13051,7 @@ var x = (y) => {
|
|
|
11436
13051
|
var x = {}; __webpack_require__.d(x, y); return x
|
|
11437
13052
|
}
|
|
11438
13053
|
var y = (x) => (() => (x))
|
|
11439
|
-
module.exports = x({ ["createElement"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.createElement), ["default"]: () => (__WEBPACK_EXTERNAL_MODULE_react__["default"]), ["useCallback"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useCallback), ["useEffect"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useEffect), ["useLayoutEffect"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useLayoutEffect), ["useRef"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useRef), ["useState"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useState) });
|
|
13054
|
+
module.exports = x({ ["createElement"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.createElement), ["default"]: () => (__WEBPACK_EXTERNAL_MODULE_react__["default"]), ["useCallback"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useCallback), ["useEffect"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useEffect), ["useId"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useId), ["useLayoutEffect"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useLayoutEffect), ["useMemo"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useMemo), ["useRef"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useRef), ["useState"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useState) });
|
|
11440
13055
|
|
|
11441
13056
|
/***/ },
|
|
11442
13057
|
|
|
@@ -20330,7 +21945,7 @@ class Browser {
|
|
|
20330
21945
|
;// ./src/lib/Logger.js
|
|
20331
21946
|
/* eslint-disable no-undef */
|
|
20332
21947
|
const CLIENT_NAME = "box-content-preview";
|
|
20333
|
-
const CLIENT_VERSION = "3.
|
|
21948
|
+
const CLIENT_VERSION = "3.84.0";
|
|
20334
21949
|
/* eslint-enable no-undef */
|
|
20335
21950
|
|
|
20336
21951
|
class Logger {
|
|
@@ -32844,150 +34459,8 @@ function Filmstrip({
|
|
|
32844
34459
|
"data-testid": "bp-Filmstrip-time"
|
|
32845
34460
|
}, (0,DurationLabels/* formatTime */.f)(time)));
|
|
32846
34461
|
}
|
|
32847
|
-
|
|
32848
|
-
|
|
32849
|
-
|
|
32850
|
-
;// ./src/lib/viewers/controls/slider/SliderControl.tsx
|
|
32851
|
-
const SliderControl_excluded = ["className", "max", "min", "onMove", "onUpdate", "step", "title", "track", "value"];
|
|
32852
|
-
function SliderControl_extends() { return SliderControl_extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, SliderControl_extends.apply(null, arguments); }
|
|
32853
|
-
function SliderControl_objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = SliderControl_objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
32854
|
-
function SliderControl_objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
32855
|
-
|
|
32856
|
-
|
|
32857
|
-
|
|
32858
|
-
|
|
32859
|
-
|
|
32860
|
-
function SliderControl(_ref) {
|
|
32861
|
-
let {
|
|
32862
|
-
className,
|
|
32863
|
-
max = 100,
|
|
32864
|
-
min = 0,
|
|
32865
|
-
onMove = (noop_default()),
|
|
32866
|
-
onUpdate = (noop_default()),
|
|
32867
|
-
step = 1,
|
|
32868
|
-
title,
|
|
32869
|
-
track,
|
|
32870
|
-
value
|
|
32871
|
-
} = _ref,
|
|
32872
|
-
rest = SliderControl_objectWithoutProperties(_ref, SliderControl_excluded);
|
|
32873
|
-
const [isScrubbing, setIsScrubbing] = external_react_["default"].useState(false);
|
|
32874
|
-
const sliderElRef = external_react_["default"].useRef(null);
|
|
32875
|
-
const getPosition = external_react_["default"].useCallback(pageX => {
|
|
32876
|
-
const {
|
|
32877
|
-
current: sliderEl
|
|
32878
|
-
} = sliderElRef;
|
|
32879
|
-
if (!sliderEl) return 0;
|
|
32880
|
-
const {
|
|
32881
|
-
left: sliderLeft,
|
|
32882
|
-
width: sliderWidth
|
|
32883
|
-
} = sliderEl.getBoundingClientRect();
|
|
32884
|
-
return Math.max(0, Math.min(pageX - sliderLeft, sliderWidth));
|
|
32885
|
-
}, []);
|
|
32886
|
-
const getPositionValue = external_react_["default"].useCallback(pageX => {
|
|
32887
|
-
const {
|
|
32888
|
-
current: sliderEl
|
|
32889
|
-
} = sliderElRef;
|
|
32890
|
-
if (!sliderEl) return 0;
|
|
32891
|
-
const {
|
|
32892
|
-
width: sliderWidth
|
|
32893
|
-
} = sliderEl.getBoundingClientRect();
|
|
32894
|
-
const newValue = getPosition(pageX) / sliderWidth * max;
|
|
32895
|
-
return Math.max(min, Math.min(newValue, max));
|
|
32896
|
-
}, [getPosition, max, min]);
|
|
32897
|
-
const handleKeydown = event => {
|
|
32898
|
-
const key = (0,util/* decodeKeydown */.wU)(event);
|
|
32899
|
-
if (key === 'ArrowLeft') {
|
|
32900
|
-
event.stopPropagation(); // Prevents global key handling
|
|
32901
|
-
onUpdate(Math.max(min, Math.min(value - step, max)));
|
|
32902
|
-
}
|
|
32903
|
-
if (key === 'ArrowRight') {
|
|
32904
|
-
event.stopPropagation(); // Prevents global key handling
|
|
32905
|
-
onUpdate(Math.max(min, Math.min(value + step, max)));
|
|
32906
|
-
}
|
|
32907
|
-
};
|
|
32908
|
-
const handleMouseDown = ({
|
|
32909
|
-
button,
|
|
32910
|
-
ctrlKey,
|
|
32911
|
-
metaKey,
|
|
32912
|
-
pageX
|
|
32913
|
-
}) => {
|
|
32914
|
-
if (button > 1 || ctrlKey || metaKey) return;
|
|
32915
|
-
onUpdate(getPositionValue(pageX));
|
|
32916
|
-
setIsScrubbing(true);
|
|
32917
|
-
};
|
|
32918
|
-
const handleMouseMove = ({
|
|
32919
|
-
pageX
|
|
32920
|
-
}) => {
|
|
32921
|
-
const {
|
|
32922
|
-
current: sliderEl
|
|
32923
|
-
} = sliderElRef;
|
|
32924
|
-
const {
|
|
32925
|
-
width: sliderWidth
|
|
32926
|
-
} = sliderEl ? sliderEl.getBoundingClientRect() : {
|
|
32927
|
-
width: 0
|
|
32928
|
-
};
|
|
32929
|
-
onMove(getPositionValue(pageX), getPosition(pageX), sliderWidth);
|
|
32930
|
-
};
|
|
32931
|
-
const handleTouchStart = ({
|
|
32932
|
-
touches
|
|
32933
|
-
}) => {
|
|
32934
|
-
onUpdate(getPositionValue(touches[0].pageX));
|
|
32935
|
-
setIsScrubbing(true);
|
|
32936
|
-
};
|
|
32937
|
-
external_react_["default"].useEffect(() => {
|
|
32938
|
-
const handleDocumentMoveStop = () => setIsScrubbing(false);
|
|
32939
|
-
const handleDocumentMouseMove = event => {
|
|
32940
|
-
if (!isScrubbing || event.button > 1 || event.ctrlKey || event.metaKey) return;
|
|
32941
|
-
event.preventDefault();
|
|
32942
|
-
onUpdate(getPositionValue(event.pageX));
|
|
32943
|
-
};
|
|
32944
|
-
const handleDocumentTouchMove = event => {
|
|
32945
|
-
if (!isScrubbing || !event.touches || !event.touches[0]) return;
|
|
32946
|
-
event.preventDefault();
|
|
32947
|
-
onUpdate(getPositionValue(event.touches[0].pageX));
|
|
32948
|
-
};
|
|
32949
|
-
if (isScrubbing) {
|
|
32950
|
-
document.addEventListener('mousemove', handleDocumentMouseMove);
|
|
32951
|
-
document.addEventListener('mouseup', handleDocumentMoveStop);
|
|
32952
|
-
document.addEventListener('touchend', handleDocumentMoveStop);
|
|
32953
|
-
document.addEventListener('touchmove', handleDocumentTouchMove);
|
|
32954
|
-
}
|
|
32955
|
-
return () => {
|
|
32956
|
-
document.removeEventListener('mousemove', handleDocumentMouseMove);
|
|
32957
|
-
document.removeEventListener('mouseup', handleDocumentMoveStop);
|
|
32958
|
-
document.removeEventListener('touchend', handleDocumentMoveStop);
|
|
32959
|
-
document.removeEventListener('touchmove', handleDocumentTouchMove);
|
|
32960
|
-
};
|
|
32961
|
-
}, [isScrubbing, getPositionValue, onUpdate]);
|
|
32962
|
-
return /*#__PURE__*/external_react_["default"].createElement("div", SliderControl_extends({
|
|
32963
|
-
ref: sliderElRef,
|
|
32964
|
-
"aria-label": title,
|
|
32965
|
-
"aria-valuemax": max,
|
|
32966
|
-
"aria-valuemin": min,
|
|
32967
|
-
"aria-valuenow": value,
|
|
32968
|
-
className: classnames_default()('bp-SliderControl', className, {
|
|
32969
|
-
'bp-is-scrubbing': isScrubbing
|
|
32970
|
-
}),
|
|
32971
|
-
onKeyDown: handleKeydown,
|
|
32972
|
-
onMouseDown: handleMouseDown,
|
|
32973
|
-
onMouseMove: handleMouseMove,
|
|
32974
|
-
onTouchStart: handleTouchStart,
|
|
32975
|
-
role: "slider",
|
|
32976
|
-
tabIndex: 0
|
|
32977
|
-
}, rest), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
32978
|
-
className: "bp-SliderControl-track",
|
|
32979
|
-
"data-testid": "bp-slider-control-track",
|
|
32980
|
-
style: {
|
|
32981
|
-
backgroundImage: track
|
|
32982
|
-
}
|
|
32983
|
-
}), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
32984
|
-
className: "bp-SliderControl-thumb",
|
|
32985
|
-
"data-testid": "bp-slider-control-thumb",
|
|
32986
|
-
style: {
|
|
32987
|
-
left: `${value / max * 100}%`
|
|
32988
|
-
}
|
|
32989
|
-
}));
|
|
32990
|
-
}
|
|
34462
|
+
// EXTERNAL MODULE: ./src/lib/viewers/controls/slider/SliderControl.tsx + 1 modules
|
|
34463
|
+
var SliderControl = __webpack_require__(4937);
|
|
32991
34464
|
;// ./src/lib/viewers/controls/media/TimeControls.scss
|
|
32992
34465
|
// extracted by mini-css-extract-plugin
|
|
32993
34466
|
|
|
@@ -33047,7 +34520,7 @@ function TimeControls({
|
|
|
33047
34520
|
durationTime: durationTime,
|
|
33048
34521
|
fps: fps,
|
|
33049
34522
|
mediaEl: mediaEl
|
|
33050
|
-
}), /*#__PURE__*/external_react_["default"].createElement(SliderControl, {
|
|
34523
|
+
}), /*#__PURE__*/external_react_["default"].createElement(SliderControl/* default */.A, {
|
|
33051
34524
|
className: "bp-TimeControls-slider",
|
|
33052
34525
|
"data-resin-target": "timeScrubber",
|
|
33053
34526
|
max: durationValue,
|
|
@@ -33172,6 +34645,11 @@ function MP3Viewer_toPrimitive(t, r) { if ("object" != typeof t || !t) return t;
|
|
|
33172
34645
|
|
|
33173
34646
|
|
|
33174
34647
|
const CSS_CLASS_MP3 = 'bp-media-mp3';
|
|
34648
|
+
function createLoadFailedError(message) {
|
|
34649
|
+
const error = new Error(message);
|
|
34650
|
+
error.name = 'LOAD_FAILED';
|
|
34651
|
+
return error;
|
|
34652
|
+
}
|
|
33175
34653
|
class MP3Viewer extends media_MediaBaseViewer {
|
|
33176
34654
|
constructor(...args) {
|
|
33177
34655
|
super(...args);
|
|
@@ -33181,6 +34659,11 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
33181
34659
|
MP3Viewer_defineProperty(this, "handlePlayRequest", () => {
|
|
33182
34660
|
this.userRequestedPlay = true;
|
|
33183
34661
|
this.togglePlay();
|
|
34662
|
+
if (this.isWaveformDecodeRetryPending && !this.hasUsedWaveformDecodePlayRetry) {
|
|
34663
|
+
this.hasUsedWaveformDecodePlayRetry = true;
|
|
34664
|
+
this.isWaveformDecodeRetryPending = false;
|
|
34665
|
+
this.startClientWaveformDecode();
|
|
34666
|
+
}
|
|
33184
34667
|
});
|
|
33185
34668
|
/**
|
|
33186
34669
|
* Auto-play was prevented, pause the audio
|
|
@@ -33210,6 +34693,7 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
33210
34693
|
this.wrapperEl.classList.add('bp-media--v2');
|
|
33211
34694
|
this.mediaContainerEl.classList.add('bp-media-container--v2');
|
|
33212
34695
|
this.ensureV2Controls();
|
|
34696
|
+
this.importWaveformDecode();
|
|
33213
34697
|
}
|
|
33214
34698
|
|
|
33215
34699
|
// Audio element
|
|
@@ -33268,7 +34752,30 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
33268
34752
|
* @return {Promise<{ default: Function }>} MP3ControlsV2 module
|
|
33269
34753
|
*/
|
|
33270
34754
|
importV2Controls() {
|
|
33271
|
-
return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__,
|
|
34755
|
+
return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 3845));
|
|
34756
|
+
}
|
|
34757
|
+
|
|
34758
|
+
/**
|
|
34759
|
+
* @return {Promise<{ loadPeaks: Function }>} client-decode helpers
|
|
34760
|
+
*/
|
|
34761
|
+
async importWaveformDecode() {
|
|
34762
|
+
if (!this.waveformDecodeImport) {
|
|
34763
|
+
this.waveformDecodeImport = Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 546));
|
|
34764
|
+
}
|
|
34765
|
+
try {
|
|
34766
|
+
return await this.waveformDecodeImport;
|
|
34767
|
+
} catch (error) {
|
|
34768
|
+
this.waveformDecodeImport = null;
|
|
34769
|
+
throw error;
|
|
34770
|
+
}
|
|
34771
|
+
}
|
|
34772
|
+
|
|
34773
|
+
/**
|
|
34774
|
+
* @inheritdoc
|
|
34775
|
+
*/
|
|
34776
|
+
destroy() {
|
|
34777
|
+
this.abortClientWaveformDecode();
|
|
34778
|
+
super.destroy();
|
|
33272
34779
|
}
|
|
33273
34780
|
|
|
33274
34781
|
/**
|
|
@@ -33315,10 +34822,126 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
33315
34822
|
*/
|
|
33316
34823
|
loadeddataHandler() {
|
|
33317
34824
|
super.loadeddataHandler();
|
|
33318
|
-
if (this.isAudioPlayerV2
|
|
34825
|
+
if (!this.isAudioPlayerV2) {
|
|
34826
|
+
return;
|
|
34827
|
+
}
|
|
34828
|
+
|
|
34829
|
+
// Play first so Safari has a user gesture before AudioContext is created.
|
|
34830
|
+
if (this.userRequestedPlay) {
|
|
33319
34831
|
this.play();
|
|
33320
34832
|
}
|
|
34833
|
+
this.startClientWaveformDecode();
|
|
33321
34834
|
}
|
|
34835
|
+
/**
|
|
34836
|
+
* Fetch compressed audio bytes for client decode. Prefers an already-fetched blob URL.
|
|
34837
|
+
*
|
|
34838
|
+
* @param {AbortSignal} signal
|
|
34839
|
+
* @return {Promise<ArrayBuffer>}
|
|
34840
|
+
*/
|
|
34841
|
+
async fetchAudioArrayBuffer(signal) {
|
|
34842
|
+
if (this.mediaBlobUrl) {
|
|
34843
|
+
const response = await fetch(this.mediaBlobUrl, {
|
|
34844
|
+
signal
|
|
34845
|
+
});
|
|
34846
|
+
if (!response.ok) {
|
|
34847
|
+
throw createLoadFailedError(`Waveform fetch failed (${response.status})`);
|
|
34848
|
+
}
|
|
34849
|
+
return response.arrayBuffer();
|
|
34850
|
+
}
|
|
34851
|
+
const template = this.options.representation && this.options.representation.content && this.options.representation.content.url_template;
|
|
34852
|
+
if (!template) {
|
|
34853
|
+
throw createLoadFailedError('Waveform fetch URL is missing');
|
|
34854
|
+
}
|
|
34855
|
+
const data = await this.api.get(this.createContentUrlV2(template), {
|
|
34856
|
+
headers: this.appendAuthHeader(),
|
|
34857
|
+
signal,
|
|
34858
|
+
type: 'arraybuffer'
|
|
34859
|
+
});
|
|
34860
|
+
if (data instanceof ArrayBuffer) {
|
|
34861
|
+
return data;
|
|
34862
|
+
}
|
|
34863
|
+
throw createLoadFailedError('Waveform fetch did not return binary data');
|
|
34864
|
+
}
|
|
34865
|
+
abortClientWaveformDecode() {
|
|
34866
|
+
if (!this.waveformDecodeController) {
|
|
34867
|
+
return;
|
|
34868
|
+
}
|
|
34869
|
+
this.waveformDecodeController.abort();
|
|
34870
|
+
this.waveformDecodeController = null;
|
|
34871
|
+
}
|
|
34872
|
+
|
|
34873
|
+
/**
|
|
34874
|
+
* Decode peaks in the background when the file is under size and duration caps.
|
|
34875
|
+
* Does not block playback. Capped or failed decode keeps the placeholder waveform.
|
|
34876
|
+
*
|
|
34877
|
+
* @return {Promise<void>}
|
|
34878
|
+
*/
|
|
34879
|
+
async startClientWaveformDecode() {
|
|
34880
|
+
if (!this.isAudioPlayerV2 || this.destroyed) {
|
|
34881
|
+
return;
|
|
34882
|
+
}
|
|
34883
|
+
this.abortClientWaveformDecode();
|
|
34884
|
+
const controller = new AbortController();
|
|
34885
|
+
this.waveformDecodeController = controller;
|
|
34886
|
+
const {
|
|
34887
|
+
signal
|
|
34888
|
+
} = controller;
|
|
34889
|
+
try {
|
|
34890
|
+
const decodeModule = await this.importWaveformDecode();
|
|
34891
|
+
if (this.destroyed || signal.aborted || this.waveformDecodeController !== controller) {
|
|
34892
|
+
return;
|
|
34893
|
+
}
|
|
34894
|
+
const result = await decodeModule.loadPeaks({
|
|
34895
|
+
compressedBytes: this.options.file && this.options.file.size,
|
|
34896
|
+
durationSec: this.mediaEl && this.mediaEl.duration,
|
|
34897
|
+
fetchArrayBuffer: fetchSignal => this.fetchAudioArrayBuffer(fetchSignal),
|
|
34898
|
+
signal
|
|
34899
|
+
});
|
|
34900
|
+
this.handleClientWaveformDecodeResult(result, controller, signal);
|
|
34901
|
+
} catch (error) {
|
|
34902
|
+
if (error && error.name === 'AbortError') {
|
|
34903
|
+
this.handleClientWaveformDecodeResult({
|
|
34904
|
+
status: 'cancelled'
|
|
34905
|
+
}, controller, signal);
|
|
34906
|
+
return;
|
|
34907
|
+
}
|
|
34908
|
+
this.handleClientWaveformDecodeResult({
|
|
34909
|
+
error: {
|
|
34910
|
+
code: 'LOAD_FAILED',
|
|
34911
|
+
message: error instanceof Error ? error.message : 'Waveform decode failed'
|
|
34912
|
+
},
|
|
34913
|
+
retryable: true,
|
|
34914
|
+
status: 'failed'
|
|
34915
|
+
}, controller, signal);
|
|
34916
|
+
}
|
|
34917
|
+
}
|
|
34918
|
+
|
|
34919
|
+
/**
|
|
34920
|
+
* Apply peaks, or record a retryable failure for overlay play.
|
|
34921
|
+
*
|
|
34922
|
+
* @param {import('./waveform/types').ClientDecodeResult} result
|
|
34923
|
+
* @param {AbortController} controller in-flight controller for this attempt
|
|
34924
|
+
* @param {AbortSignal} signal
|
|
34925
|
+
* @return {void}
|
|
34926
|
+
*/
|
|
34927
|
+
handleClientWaveformDecodeResult(result, controller, signal) {
|
|
34928
|
+
if (!result || this.destroyed || signal.aborted || this.waveformDecodeController !== controller) {
|
|
34929
|
+
return;
|
|
34930
|
+
}
|
|
34931
|
+
if (result.status === 'ready') {
|
|
34932
|
+
this.waveformPeaks = result.payload.peaks;
|
|
34933
|
+
this.isWaveformDecodeRetryPending = false;
|
|
34934
|
+
this.renderUI();
|
|
34935
|
+
return;
|
|
34936
|
+
}
|
|
34937
|
+
if (result.status === 'cancelled') {
|
|
34938
|
+
return;
|
|
34939
|
+
}
|
|
34940
|
+
if (result.status === 'failed' && result.retryable && !this.hasUsedWaveformDecodePlayRetry) {
|
|
34941
|
+
this.isWaveformDecodeRetryPending = true;
|
|
34942
|
+
}
|
|
34943
|
+
}
|
|
34944
|
+
|
|
33322
34945
|
/**
|
|
33323
34946
|
* @inheritdoc
|
|
33324
34947
|
*/
|
|
@@ -35425,7 +37048,7 @@ function TimeControlsV2({
|
|
|
35425
37048
|
style: trackMask ? {
|
|
35426
37049
|
'--bp-track-mask': trackMask
|
|
35427
37050
|
} : undefined
|
|
35428
|
-
}, /*#__PURE__*/external_react_["default"].createElement(SliderControl, {
|
|
37051
|
+
}, /*#__PURE__*/external_react_["default"].createElement(SliderControl/* default */.A, {
|
|
35429
37052
|
className: "bp-TimeControlsV2-slider",
|
|
35430
37053
|
"data-resin-target": "timeScrubber",
|
|
35431
37054
|
max: durationValue,
|