2621 lines
83 KiB
JavaScript
2621 lines
83 KiB
JavaScript
/*
|
|
* Extracted from browser-delivered Turbopack chunk: fd0220e4d10052af.701bdafa2d.js
|
|
* Module id: 169872
|
|
* For reading/searching only; this factory depends on the original Turbopack runtime.
|
|
*/
|
|
|
|
const moduleFactory = (e) => {
|
|
"use strict";
|
|
let t;
|
|
var n = e.i(462214),
|
|
i = e.i(358379);
|
|
function r(e, t, n, i) {
|
|
return new (n || (n = Promise))(function (r, a) {
|
|
function o(e) {
|
|
try {
|
|
c(i.next(e));
|
|
} catch (e) {
|
|
a(e);
|
|
}
|
|
}
|
|
function s(e) {
|
|
try {
|
|
c(i.throw(e));
|
|
} catch (e) {
|
|
a(e);
|
|
}
|
|
}
|
|
function c(e) {
|
|
var t;
|
|
e.done
|
|
? r(e.value)
|
|
: ((t = e.value) instanceof n
|
|
? t
|
|
: new n(function (e) {
|
|
e(t);
|
|
})
|
|
).then(o, s);
|
|
}
|
|
c((i = i.apply(e, t || [])).next());
|
|
});
|
|
}
|
|
"function" == typeof SuppressedError && SuppressedError;
|
|
class a {
|
|
constructor() {
|
|
this.listeners = {};
|
|
}
|
|
on(e, t, n) {
|
|
if (
|
|
(this.listeners[e] || (this.listeners[e] = new Set()),
|
|
null == n ? void 0 : n.once)
|
|
) {
|
|
let n = (...i) => {
|
|
this.un(e, n), t(...i);
|
|
};
|
|
return this.listeners[e].add(n), () => this.un(e, n);
|
|
}
|
|
return this.listeners[e].add(t), () => this.un(e, t);
|
|
}
|
|
un(e, t) {
|
|
var n;
|
|
null == (n = this.listeners[e]) || n.delete(t);
|
|
}
|
|
once(e, t) {
|
|
return this.on(e, t, { once: !0 });
|
|
}
|
|
unAll() {
|
|
this.listeners = {};
|
|
}
|
|
emit(e, ...t) {
|
|
this.listeners[e] && this.listeners[e].forEach((e) => e(...t));
|
|
}
|
|
}
|
|
let o = {
|
|
decode: function (e, t) {
|
|
return r(this, void 0, void 0, function* () {
|
|
let n = new AudioContext({ sampleRate: t });
|
|
try {
|
|
return yield n.decodeAudioData(e);
|
|
} finally {
|
|
n.close();
|
|
}
|
|
});
|
|
},
|
|
createBuffer: function (e, t) {
|
|
if (!e || 0 === e.length)
|
|
throw Error("channelData must be a non-empty array");
|
|
if (t <= 0) throw Error("duration must be greater than 0");
|
|
if (("number" == typeof e[0] && (e = [e]), !e[0] || 0 === e[0].length))
|
|
throw Error("channelData must contain non-empty channel arrays");
|
|
!(function (e) {
|
|
let t = e[0];
|
|
if (t.some((e) => e > 1 || e < -1)) {
|
|
let n = t.length,
|
|
i = 0;
|
|
for (let e = 0; e < n; e++) {
|
|
let n = Math.abs(t[e]);
|
|
n > i && (i = n);
|
|
}
|
|
for (let t of e) for (let e = 0; e < n; e++) t[e] /= i;
|
|
}
|
|
})(e);
|
|
let n = e.map((e) =>
|
|
e instanceof Float32Array ? e : Float32Array.from(e),
|
|
);
|
|
return {
|
|
duration: t,
|
|
length: n[0].length,
|
|
sampleRate: n[0].length / t,
|
|
numberOfChannels: n.length,
|
|
getChannelData: (e) => {
|
|
let t = n[e];
|
|
if (!t) throw Error(`Channel ${e} not found`);
|
|
return t;
|
|
},
|
|
copyFromChannel: AudioBuffer.prototype.copyFromChannel,
|
|
copyToChannel: AudioBuffer.prototype.copyToChannel,
|
|
};
|
|
},
|
|
};
|
|
function s(e, t, n) {
|
|
let i = (function e(t, n) {
|
|
let i = n.xmlns
|
|
? document.createElementNS(n.xmlns, t)
|
|
: document.createElement(t);
|
|
for (let [t, r] of Object.entries(n))
|
|
if ("children" === t && r)
|
|
for (let [t, n] of Object.entries(r))
|
|
n instanceof Node
|
|
? i.appendChild(n)
|
|
: "string" == typeof n
|
|
? i.appendChild(document.createTextNode(n))
|
|
: i.appendChild(e(t, n));
|
|
else
|
|
"style" === t
|
|
? Object.assign(i.style, r)
|
|
: "textContent" === t
|
|
? (i.textContent = r)
|
|
: i.setAttribute(t, r.toString());
|
|
return i;
|
|
})(e, t || {});
|
|
return null == n || n.appendChild(i), i;
|
|
}
|
|
var c = Object.freeze({ __proto__: null, createElement: s, default: s });
|
|
let l = {
|
|
fetchBlob: function (e, t, n) {
|
|
return r(this, void 0, void 0, function* () {
|
|
let i = yield fetch(e, n);
|
|
if (i.status >= 400)
|
|
throw Error(`Failed to fetch ${e}: ${i.status} (${i.statusText})`);
|
|
return (
|
|
(function (e, t) {
|
|
r(this, void 0, void 0, function* () {
|
|
if (!e.body || !e.headers) return;
|
|
let n = e.body.getReader(),
|
|
i = Number(e.headers.get("Content-Length")) || 0,
|
|
r = 0,
|
|
a = (e) => {
|
|
t(
|
|
Math.round(
|
|
((r += (null == e ? void 0 : e.length) || 0) / i) * 100,
|
|
),
|
|
);
|
|
};
|
|
try {
|
|
for (;;) {
|
|
let e = yield n.read();
|
|
if (e.done) break;
|
|
a(e.value);
|
|
}
|
|
} catch (e) {
|
|
console.warn("Progress tracking error:", e);
|
|
}
|
|
});
|
|
})(i.clone(), t),
|
|
i.blob()
|
|
);
|
|
});
|
|
},
|
|
};
|
|
function u(e) {
|
|
let t = e,
|
|
n = new Set();
|
|
return {
|
|
get value() {
|
|
return t;
|
|
},
|
|
set(e) {
|
|
Object.is(t, e) || ((t = e), n.forEach((e) => e(t)));
|
|
},
|
|
update(e) {
|
|
this.set(e(t));
|
|
},
|
|
subscribe: (e) => (n.add(e), () => n.delete(e)),
|
|
};
|
|
}
|
|
function h(e, t) {
|
|
let n = u(e());
|
|
return (
|
|
t.forEach((t) =>
|
|
t.subscribe(() => {
|
|
let t = e();
|
|
Object.is(n.value, t) || n.set(t);
|
|
}),
|
|
),
|
|
{
|
|
get value() {
|
|
return n.value;
|
|
},
|
|
subscribe: (e) => n.subscribe(e),
|
|
}
|
|
);
|
|
}
|
|
function f(e, t) {
|
|
let n,
|
|
i = () => {
|
|
n && (n(), (n = void 0)), (n = e());
|
|
},
|
|
r = t.map((e) => e.subscribe(i));
|
|
return (
|
|
i(),
|
|
() => {
|
|
n && (n(), (n = void 0)), r.forEach((e) => e());
|
|
}
|
|
);
|
|
}
|
|
class d extends a {
|
|
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(e) {
|
|
super(),
|
|
(this.isExternalMedia = !1),
|
|
(this.reactiveMediaEventCleanups = []),
|
|
e.media
|
|
? ((this.media = e.media), (this.isExternalMedia = !0))
|
|
: (this.media = document.createElement("audio")),
|
|
(this._isPlaying = u(!1)),
|
|
(this._currentTime = u(0)),
|
|
(this._duration = u(0)),
|
|
(this._volume = u(this.media.volume)),
|
|
(this._muted = u(this.media.muted)),
|
|
(this._playbackRate = u(this.media.playbackRate || 1)),
|
|
(this._seeking = u(!1)),
|
|
this.setupReactiveMediaEvents(),
|
|
e.mediaControls && (this.media.controls = !0),
|
|
e.autoplay && (this.media.autoplay = !0),
|
|
null != e.playbackRate &&
|
|
this.onMediaEvent(
|
|
"canplay",
|
|
() => {
|
|
null != e.playbackRate &&
|
|
(this.media.playbackRate = e.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(e, t, n) {
|
|
return (
|
|
this.media.addEventListener(e, t, n),
|
|
() => this.media.removeEventListener(e, t, n)
|
|
);
|
|
}
|
|
getSrc() {
|
|
return this.media.currentSrc || this.media.src || "";
|
|
}
|
|
revokeSrc() {
|
|
let e = this.getSrc();
|
|
e.startsWith("blob:") && URL.revokeObjectURL(e);
|
|
}
|
|
canPlayType(e) {
|
|
return "" !== this.media.canPlayType(e);
|
|
}
|
|
setSrc(e, t) {
|
|
let n = this.getSrc();
|
|
if (e && n === e) return;
|
|
this.revokeSrc();
|
|
let i =
|
|
t instanceof Blob && (this.canPlayType(t.type) || !e)
|
|
? URL.createObjectURL(t)
|
|
: e;
|
|
if ((n && this.media.removeAttribute("src"), i || e))
|
|
try {
|
|
this.media.src = i;
|
|
} catch (t) {
|
|
this.media.src = e;
|
|
}
|
|
}
|
|
destroy() {
|
|
this.reactiveMediaEventCleanups.forEach((e) => e()),
|
|
(this.reactiveMediaEventCleanups = []),
|
|
this.isExternalMedia ||
|
|
(this.media.pause(),
|
|
this.revokeSrc(),
|
|
this.media.removeAttribute("src"),
|
|
this.media.load(),
|
|
this.media.remove());
|
|
}
|
|
setMediaElement(e) {
|
|
this.reactiveMediaEventCleanups.forEach((e) => e()),
|
|
(this.reactiveMediaEventCleanups = []),
|
|
(this.media = e),
|
|
this.setupReactiveMediaEvents();
|
|
}
|
|
play() {
|
|
return r(this, void 0, void 0, function* () {
|
|
try {
|
|
return yield this.media.play();
|
|
} catch (e) {
|
|
if (e instanceof DOMException && "AbortError" === e.name) return;
|
|
throw e;
|
|
}
|
|
});
|
|
}
|
|
pause() {
|
|
this.media.pause();
|
|
}
|
|
isPlaying() {
|
|
return !this.media.paused && !this.media.ended;
|
|
}
|
|
setTime(e) {
|
|
this.media.currentTime = Math.max(0, Math.min(e, this.getDuration()));
|
|
}
|
|
getDuration() {
|
|
return this.media.duration;
|
|
}
|
|
getCurrentTime() {
|
|
return this.media.currentTime;
|
|
}
|
|
getVolume() {
|
|
return this.media.volume;
|
|
}
|
|
setVolume(e) {
|
|
this.media.volume = e;
|
|
}
|
|
getMuted() {
|
|
return this.media.muted;
|
|
}
|
|
setMuted(e) {
|
|
this.media.muted = e;
|
|
}
|
|
getPlaybackRate() {
|
|
return this.media.playbackRate;
|
|
}
|
|
isSeeking() {
|
|
return this.media.seeking;
|
|
}
|
|
setPlaybackRate(e, t) {
|
|
null != t && (this.media.preservesPitch = t),
|
|
(this.media.playbackRate = e);
|
|
}
|
|
getMediaElement() {
|
|
return this.media;
|
|
}
|
|
setSinkId(e) {
|
|
return this.media.setSinkId(e);
|
|
}
|
|
}
|
|
function p(e, t, n) {
|
|
let i = t - e.left,
|
|
r = n - e.top;
|
|
return [i / e.width, r / e.height];
|
|
}
|
|
function g(e) {
|
|
return !!(e.barWidth || e.barGap || e.barAlign);
|
|
}
|
|
function b(e, t) {
|
|
if (!g(t)) return e;
|
|
let n = t.barWidth || 0.5,
|
|
i = n + (t.barGap || n / 2);
|
|
return 0 === i ? e : Math.floor(e / i) * i;
|
|
}
|
|
function m({ scrollLeft: e, totalWidth: t, numCanvases: n }) {
|
|
if (0 === t) return [0];
|
|
let i = Math.floor((e / t) * n);
|
|
return [i - 1, i, i + 1];
|
|
}
|
|
function w(e) {
|
|
let t = e._cleanup;
|
|
"function" == typeof t && t();
|
|
}
|
|
class v extends a {
|
|
constructor(e, t) {
|
|
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.subscriptions = []),
|
|
(this.options = e);
|
|
const n = this.parentFromOptionsContainer(e.container);
|
|
this.parent = n;
|
|
const [i, r] = this.initHtml();
|
|
n.appendChild(i),
|
|
(this.container = i),
|
|
(this.scrollContainer = r.querySelector(".scroll")),
|
|
(this.wrapper = r.querySelector(".wrapper")),
|
|
(this.canvasWrapper = r.querySelector(".canvases")),
|
|
(this.progressWrapper = r.querySelector(".progress")),
|
|
(this.cursor = r.querySelector(".cursor")),
|
|
t && r.appendChild(t),
|
|
this.initEvents();
|
|
}
|
|
parentFromOptionsContainer(e) {
|
|
let t;
|
|
if (
|
|
("string" == typeof e
|
|
? (t = document.querySelector(e))
|
|
: e instanceof HTMLElement && (t = e),
|
|
!t)
|
|
)
|
|
throw Error("Container not found");
|
|
return t;
|
|
}
|
|
initEvents() {
|
|
var e;
|
|
let t, n, i, r;
|
|
this.wrapper.addEventListener("click", (e) => {
|
|
let [t, n] = p(
|
|
this.wrapper.getBoundingClientRect(),
|
|
e.clientX,
|
|
e.clientY,
|
|
);
|
|
this.emit("click", t, n);
|
|
}),
|
|
this.wrapper.addEventListener("dblclick", (e) => {
|
|
let [t, n] = p(
|
|
this.wrapper.getBoundingClientRect(),
|
|
e.clientX,
|
|
e.clientY,
|
|
);
|
|
this.emit("dblclick", t, n);
|
|
}),
|
|
(!0 !== this.options.dragToSeek &&
|
|
"object" != typeof this.options.dragToSeek) ||
|
|
this.initDrag(),
|
|
(this.scrollStream =
|
|
((n = h(
|
|
() =>
|
|
(function (e) {
|
|
let { scrollLeft: t, scrollWidth: n, clientWidth: i } = e;
|
|
return 0 === n
|
|
? { startX: 0, endX: 1 }
|
|
: {
|
|
startX: Math.max(0, Math.min(1, t / n)),
|
|
endX: Math.max(0, Math.min(1, (t + i) / n)),
|
|
};
|
|
})(t.value),
|
|
[
|
|
(t = u({
|
|
scrollLeft: (e = this.scrollContainer).scrollLeft,
|
|
scrollWidth: e.scrollWidth,
|
|
clientWidth: e.clientWidth,
|
|
})),
|
|
],
|
|
)),
|
|
(i = h(() => {
|
|
var e;
|
|
return {
|
|
left: (e = t.value).scrollLeft,
|
|
right: e.scrollLeft + e.clientWidth,
|
|
};
|
|
}, [t])),
|
|
(r = () => {
|
|
t.set({
|
|
scrollLeft: e.scrollLeft,
|
|
scrollWidth: e.scrollWidth,
|
|
clientWidth: e.clientWidth,
|
|
});
|
|
}),
|
|
e.addEventListener("scroll", r, { passive: !0 }),
|
|
{
|
|
scrollData: t,
|
|
percentages: n,
|
|
bounds: i,
|
|
cleanup: () => {
|
|
e.removeEventListener("scroll", r), w(t);
|
|
},
|
|
}));
|
|
let a = f(() => {
|
|
let { startX: e, endX: t } = this.scrollStream.percentages.value,
|
|
{ left: n, right: i } = this.scrollStream.bounds.value;
|
|
this.emit("scroll", e, t, n, i);
|
|
}, [this.scrollStream.percentages, this.scrollStream.bounds]);
|
|
if ((this.subscriptions.push(a), "function" == typeof ResizeObserver)) {
|
|
let e = this.createDelay(100);
|
|
(this.resizeObserver = new ResizeObserver(() => {
|
|
e()
|
|
.then(() => this.onContainerResize())
|
|
.catch(() => {});
|
|
})),
|
|
this.resizeObserver.observe(this.scrollContainer);
|
|
}
|
|
}
|
|
onContainerResize() {
|
|
let e = this.parent.clientWidth;
|
|
(e === this.lastContainerWidth && "auto" !== this.options.height) ||
|
|
((this.lastContainerWidth = e), this.reRender(), this.emit("resize"));
|
|
}
|
|
initDrag() {
|
|
if (this.dragStream) return;
|
|
this.dragStream = (function (e, t = {}) {
|
|
let { threshold: n = 3, mouseButton: i = 0, touchDelay: r = 100 } = t,
|
|
a = u(null),
|
|
o = new Map(),
|
|
s = matchMedia("(pointer: coarse)").matches,
|
|
c = () => {},
|
|
l = (t) => {
|
|
if (t.button !== i || (o.set(t.pointerId, t), o.size > 1)) return;
|
|
let l = t.clientX,
|
|
u = t.clientY,
|
|
h = !1,
|
|
f = Date.now(),
|
|
{ left: d, top: p } = e.getBoundingClientRect(),
|
|
g = (e) => {
|
|
if (
|
|
e.defaultPrevented ||
|
|
o.size > 1 ||
|
|
(s && Date.now() - f < r)
|
|
)
|
|
return;
|
|
let t = e.clientX,
|
|
i = e.clientY,
|
|
c = t - l,
|
|
g = i - u;
|
|
(h || Math.abs(c) > n || Math.abs(g) > n) &&
|
|
(e.preventDefault(),
|
|
e.stopPropagation(),
|
|
h ||
|
|
(a.set({ type: "start", x: l - d, y: u - p }), (h = !0)),
|
|
a.set({
|
|
type: "move",
|
|
x: t - d,
|
|
y: i - p,
|
|
deltaX: c,
|
|
deltaY: g,
|
|
}),
|
|
(l = t),
|
|
(u = i));
|
|
},
|
|
b = (e) => {
|
|
if ((o.delete(e.pointerId), h)) {
|
|
let t = e.clientX,
|
|
n = e.clientY;
|
|
a.set({ type: "end", x: t - d, y: n - p });
|
|
}
|
|
c();
|
|
},
|
|
m = (e) => {
|
|
o.delete(e.pointerId),
|
|
(e.relatedTarget &&
|
|
e.relatedTarget !== document.documentElement) ||
|
|
b(e);
|
|
},
|
|
w = (e) => {
|
|
h && (e.stopPropagation(), e.preventDefault());
|
|
},
|
|
v = (e) => {
|
|
e.defaultPrevented || o.size > 1 || (h && e.preventDefault());
|
|
};
|
|
document.addEventListener("pointermove", g),
|
|
document.addEventListener("pointerup", b),
|
|
document.addEventListener("pointerout", m),
|
|
document.addEventListener("pointercancel", m),
|
|
document.addEventListener("touchmove", v, { passive: !1 }),
|
|
document.addEventListener("click", w, { capture: !0 }),
|
|
(c = () => {
|
|
document.removeEventListener("pointermove", g),
|
|
document.removeEventListener("pointerup", b),
|
|
document.removeEventListener("pointerout", m),
|
|
document.removeEventListener("pointercancel", m),
|
|
document.removeEventListener("touchmove", v),
|
|
setTimeout(() => {
|
|
document.removeEventListener("click", w, { capture: !0 });
|
|
}, 10);
|
|
});
|
|
};
|
|
return (
|
|
e.addEventListener("pointerdown", l),
|
|
{
|
|
signal: a,
|
|
cleanup: () => {
|
|
c(), e.removeEventListener("pointerdown", l), o.clear(), w(a);
|
|
},
|
|
}
|
|
);
|
|
})(this.wrapper);
|
|
let e = f(() => {
|
|
var e;
|
|
let t = this.dragStream.signal.value;
|
|
if (!t) return;
|
|
let n = this.wrapper.getBoundingClientRect().width,
|
|
i = (e = t.x / n) < 0 ? 0 : e > 1 ? 1 : e;
|
|
"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(e);
|
|
}
|
|
initHtml() {
|
|
let e = document.createElement("div"),
|
|
t = e.attachShadow({ mode: "open" }),
|
|
n =
|
|
this.options.cspNonce && "string" == typeof this.options.cspNonce
|
|
? this.options.cspNonce.replace(/"/g, "")
|
|
: "";
|
|
return (
|
|
(t.innerHTML = `
|
|
<style${n ? ` nonce="${n}"` : ""}>
|
|
:host {
|
|
user-select: none;
|
|
min-width: 1px;
|
|
}
|
|
:host audio {
|
|
display: block;
|
|
width: 100%;
|
|
}
|
|
:host .scroll {
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
width: 100%;
|
|
position: relative;
|
|
}
|
|
:host .noScrollbar {
|
|
scrollbar-color: transparent;
|
|
scrollbar-width: none;
|
|
}
|
|
:host .noScrollbar::-webkit-scrollbar {
|
|
display: none;
|
|
-webkit-appearance: none;
|
|
}
|
|
:host .wrapper {
|
|
position: relative;
|
|
overflow: visible;
|
|
z-index: 2;
|
|
}
|
|
:host .canvases {
|
|
min-height: ${this.getHeight(this.options.height, this.options.splitChannels)}px;
|
|
pointer-events: none;
|
|
}
|
|
:host .canvases > div {
|
|
position: relative;
|
|
}
|
|
:host canvas {
|
|
display: block;
|
|
position: absolute;
|
|
top: 0;
|
|
image-rendering: pixelated;
|
|
}
|
|
:host .progress {
|
|
pointer-events: none;
|
|
position: absolute;
|
|
z-index: 2;
|
|
top: 0;
|
|
left: 0;
|
|
width: 0;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
}
|
|
:host .progress > div {
|
|
position: relative;
|
|
}
|
|
:host .cursor {
|
|
pointer-events: none;
|
|
position: absolute;
|
|
z-index: 5;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100%;
|
|
border-radius: 2px;
|
|
}
|
|
</style>
|
|
|
|
<div class="scroll" part="scroll">
|
|
<div class="wrapper" part="wrapper">
|
|
<div class="canvases" part="canvases"></div>
|
|
<div class="progress" part="progress"></div>
|
|
<div class="cursor" part="cursor"></div>
|
|
</div>
|
|
</div>
|
|
`),
|
|
[e, t]
|
|
);
|
|
}
|
|
setOptions(e) {
|
|
if (this.options.container !== e.container) {
|
|
let t = this.parentFromOptionsContainer(e.container);
|
|
t.appendChild(this.container), (this.parent = t);
|
|
}
|
|
(!0 !== e.dragToSeek && "object" != typeof this.options.dragToSeek) ||
|
|
this.initDrag(),
|
|
(this.options = e),
|
|
this.reRender();
|
|
}
|
|
getWrapper() {
|
|
return this.wrapper;
|
|
}
|
|
getWidth() {
|
|
return this.scrollContainer.clientWidth;
|
|
}
|
|
getScroll() {
|
|
return this.scrollContainer.scrollLeft;
|
|
}
|
|
setScroll(e) {
|
|
this.scrollContainer.scrollLeft = e;
|
|
}
|
|
setScrollPercentage(e) {
|
|
let { scrollWidth: t } = this.scrollContainer;
|
|
this.setScroll(t * e);
|
|
}
|
|
destroy() {
|
|
var e;
|
|
this.subscriptions.forEach((e) => e()),
|
|
this.container.remove(),
|
|
this.resizeObserver &&
|
|
(this.resizeObserver.disconnect(), (this.resizeObserver = null)),
|
|
null == (e = this.unsubscribeOnScroll) || e.forEach((e) => e()),
|
|
(this.unsubscribeOnScroll = []),
|
|
this.dragStream &&
|
|
(this.dragStream.cleanup(), (this.dragStream = null)),
|
|
this.scrollStream &&
|
|
(this.scrollStream.cleanup(), (this.scrollStream = null));
|
|
}
|
|
createDelay(e = 10) {
|
|
let t,
|
|
n,
|
|
i = () => {
|
|
t && (clearTimeout(t), (t = void 0)), n && (n(), (n = void 0));
|
|
};
|
|
return (
|
|
this.timeouts.push(i),
|
|
() =>
|
|
new Promise((r, a) => {
|
|
i(),
|
|
(n = a),
|
|
(t = setTimeout(() => {
|
|
(t = void 0), (n = void 0), r();
|
|
}, e));
|
|
})
|
|
);
|
|
}
|
|
getHeight(e, t) {
|
|
var n;
|
|
let i =
|
|
(null == (n = this.audioData) ? void 0 : n.numberOfChannels) || 1;
|
|
return (function ({
|
|
optionsHeight: e,
|
|
optionsSplitChannels: t,
|
|
parentHeight: n,
|
|
numberOfChannels: i,
|
|
defaultHeight: r = 128,
|
|
}) {
|
|
if (null == e) return r;
|
|
let a = Number(e);
|
|
if (!isNaN(a)) return a;
|
|
if ("auto" === e) {
|
|
let e = n || r;
|
|
return (null == t ? void 0 : t.every((e) => !e.overlay))
|
|
? e / i
|
|
: e;
|
|
}
|
|
return r;
|
|
})({
|
|
optionsHeight: e,
|
|
optionsSplitChannels: t,
|
|
parentHeight: this.parent.clientHeight,
|
|
numberOfChannels: i,
|
|
defaultHeight: 128,
|
|
});
|
|
}
|
|
convertColorValues(e, t) {
|
|
return (function (e, t, n) {
|
|
if (!Array.isArray(e)) return e || "";
|
|
if (0 === e.length) return "#999";
|
|
if (e.length < 2) return e[0] || "";
|
|
let i = document.createElement("canvas"),
|
|
r = i.getContext("2d"),
|
|
a = null != n ? n : i.height * t,
|
|
o = r.createLinearGradient(0, 0, 0, a || t),
|
|
s = 1 / (e.length - 1);
|
|
return (
|
|
e.forEach((e, t) => {
|
|
o.addColorStop(t * s, e);
|
|
}),
|
|
o
|
|
);
|
|
})(e, this.getPixelRatio(), null == t ? void 0 : t.canvas.height);
|
|
}
|
|
getPixelRatio() {
|
|
return Math.max(1, window.devicePixelRatio || 1);
|
|
}
|
|
renderBarWaveform(e, t, n, i) {
|
|
let { width: r, height: a } = n.canvas,
|
|
{
|
|
halfHeight: o,
|
|
barWidth: s,
|
|
barRadius: c,
|
|
barIndexScale: l,
|
|
barSpacing: u,
|
|
barMinHeight: h,
|
|
} = (function ({
|
|
width: e,
|
|
height: t,
|
|
length: n,
|
|
options: i,
|
|
pixelRatio: r,
|
|
}) {
|
|
let a = i.barWidth ? i.barWidth * r : 1,
|
|
o = i.barGap ? i.barGap * r : i.barWidth ? a / 2 : 0,
|
|
s = a + o || 1;
|
|
return {
|
|
halfHeight: t / 2,
|
|
barWidth: a,
|
|
barGap: o,
|
|
barRadius: i.barRadius || 0,
|
|
barMinHeight: i.barMinHeight ? i.barMinHeight * r : 0,
|
|
barIndexScale: n > 0 ? e / s / n : 0,
|
|
barSpacing: s,
|
|
};
|
|
})({
|
|
width: r,
|
|
height: a,
|
|
length: (e[0] || []).length,
|
|
options: t,
|
|
pixelRatio: this.getPixelRatio(),
|
|
}),
|
|
f = (function ({
|
|
channelData: e,
|
|
barIndexScale: t,
|
|
barSpacing: n,
|
|
barWidth: i,
|
|
halfHeight: r,
|
|
vScale: a,
|
|
canvasHeight: o,
|
|
barAlign: s,
|
|
barMinHeight: c,
|
|
}) {
|
|
let l = e[0] || [],
|
|
u = e[1] || l,
|
|
h = l.length,
|
|
f = [],
|
|
d = 0,
|
|
p = 0,
|
|
g = 0;
|
|
for (let e = 0; e <= h; e++) {
|
|
let h = Math.round(e * t);
|
|
if (h > d) {
|
|
let { topHeight: e, totalHeight: t } = (function ({
|
|
maxTop: e,
|
|
maxBottom: t,
|
|
halfHeight: n,
|
|
vScale: i,
|
|
barMinHeight: r = 0,
|
|
barAlign: a,
|
|
}) {
|
|
let o = Math.round(e * n * i),
|
|
s = o + Math.round(t * n * i) || 1;
|
|
return (
|
|
s < r && ((s = r), a || (o = s / 2)),
|
|
{ topHeight: o, totalHeight: s }
|
|
);
|
|
})({
|
|
maxTop: p,
|
|
maxBottom: g,
|
|
halfHeight: r,
|
|
vScale: a,
|
|
barMinHeight: c,
|
|
barAlign: s,
|
|
}),
|
|
l = (function ({
|
|
barAlign: e,
|
|
halfHeight: t,
|
|
topHeight: n,
|
|
totalHeight: i,
|
|
canvasHeight: r,
|
|
}) {
|
|
return "top" === e ? 0 : "bottom" === e ? r - i : t - n;
|
|
})({
|
|
barAlign: s,
|
|
halfHeight: r,
|
|
topHeight: e,
|
|
totalHeight: t,
|
|
canvasHeight: o,
|
|
});
|
|
f.push({ x: d * n, y: l, width: i, height: t }),
|
|
(d = h),
|
|
(p = 0),
|
|
(g = 0);
|
|
}
|
|
let b = Math.abs(l[e] || 0),
|
|
m = Math.abs(u[e] || 0);
|
|
b > p && (p = b), m > g && (g = m);
|
|
}
|
|
return f;
|
|
})({
|
|
channelData: e,
|
|
barIndexScale: l,
|
|
barSpacing: u,
|
|
barWidth: s,
|
|
halfHeight: o,
|
|
vScale: i,
|
|
canvasHeight: a,
|
|
barAlign: t.barAlign,
|
|
barMinHeight: h,
|
|
});
|
|
for (let e of (n.beginPath(), f))
|
|
c && "roundRect" in n
|
|
? n.roundRect(e.x, e.y, e.width, e.height, c)
|
|
: n.rect(e.x, e.y, e.width, e.height);
|
|
n.fill(), n.closePath();
|
|
}
|
|
renderLineWaveform(e, t, n, i) {
|
|
let { width: r, height: a } = n.canvas,
|
|
o = (function ({ channelData: e, width: t, height: n, vScale: i }) {
|
|
let r = n / 2,
|
|
a = e[0] || [];
|
|
return [a, e[1] || a].map((e, n) => {
|
|
let a = e.length,
|
|
o = a ? t / a : 0,
|
|
s = 0 === n ? -1 : 1,
|
|
c = [{ x: 0, y: r }],
|
|
l = 0,
|
|
u = 0;
|
|
for (let t = 0; t <= a; t++) {
|
|
let n = Math.round(t * o);
|
|
if (n > l) {
|
|
let e = r + (Math.round(u * r * i) || 1) * s;
|
|
c.push({ x: l, y: e }), (l = n), (u = 0);
|
|
}
|
|
let a = Math.abs(e[t] || 0);
|
|
a > u && (u = a);
|
|
}
|
|
return c.push({ x: l, y: r }), c;
|
|
});
|
|
})({ channelData: e, width: r, height: a, vScale: i });
|
|
for (let e of (n.beginPath(), o))
|
|
if (e.length) {
|
|
n.moveTo(e[0].x, e[0].y);
|
|
for (let t = 1; t < e.length; t++) {
|
|
let i = e[t];
|
|
n.lineTo(i.x, i.y);
|
|
}
|
|
}
|
|
n.fill(), n.closePath();
|
|
}
|
|
renderWaveform(e, t, n) {
|
|
if (
|
|
((n.fillStyle = this.convertColorValues(t.waveColor, n)),
|
|
t.renderFunction)
|
|
)
|
|
return void t.renderFunction(e, n);
|
|
let i = (function ({
|
|
channelData: e,
|
|
barHeight: t,
|
|
normalize: n,
|
|
maxPeak: i,
|
|
}) {
|
|
var r;
|
|
let a = t || 1;
|
|
if (!n) return a;
|
|
let o = e[0];
|
|
if (!o || 0 === o.length) return a;
|
|
let s = null != i ? i : 0;
|
|
if (!i)
|
|
for (let e = 0; e < o.length; e++) {
|
|
let t = Math.abs(null != (r = o[e]) ? r : 0);
|
|
t > s && (s = t);
|
|
}
|
|
return s ? a / s : a;
|
|
})({
|
|
channelData: e,
|
|
barHeight: t.barHeight,
|
|
normalize: t.normalize,
|
|
maxPeak: t.maxPeak,
|
|
});
|
|
g(t)
|
|
? this.renderBarWaveform(e, t, n, i)
|
|
: this.renderLineWaveform(e, t, n, i);
|
|
}
|
|
renderSingleCanvas(e, t, n, i, r, a, o) {
|
|
let s = this.getPixelRatio(),
|
|
c = document.createElement("canvas");
|
|
(c.width = Math.round(n * s)),
|
|
(c.height = Math.round(i * s)),
|
|
(c.style.width = `${n}px`),
|
|
(c.style.height = `${i}px`),
|
|
(c.style.left = `${Math.round(r)}px`),
|
|
a.appendChild(c);
|
|
let l = c.getContext("2d");
|
|
if (
|
|
(t.renderFunction
|
|
? ((l.fillStyle = this.convertColorValues(t.waveColor, l)),
|
|
t.renderFunction(e, l))
|
|
: this.renderWaveform(e, t, l),
|
|
c.width > 0 && c.height > 0)
|
|
) {
|
|
let e = c.cloneNode(),
|
|
n = e.getContext("2d");
|
|
n.drawImage(c, 0, 0),
|
|
(n.globalCompositeOperation = "source-in"),
|
|
(n.fillStyle = this.convertColorValues(t.progressColor, n)),
|
|
n.fillRect(0, 0, c.width, c.height),
|
|
o.appendChild(e);
|
|
}
|
|
}
|
|
renderMultiCanvas(e, t, n, i, r, a) {
|
|
let o = this.getPixelRatio(),
|
|
{ clientWidth: s } = this.scrollContainer,
|
|
c = n / o,
|
|
l = (function ({ clientWidth: e, totalWidth: t, options: n }) {
|
|
return b(Math.min(8e3, e, t), n);
|
|
})({ clientWidth: s, totalWidth: c, options: t }),
|
|
u = {};
|
|
if (0 === l) return;
|
|
let h = (n) => {
|
|
if (n < 0 || n >= f || u[n]) return;
|
|
u[n] = !0;
|
|
let o = n * l,
|
|
s = Math.min(c - o, l);
|
|
if ((s = b(s, t)) <= 0) return;
|
|
let h = (function ({
|
|
channelData: e,
|
|
offset: t,
|
|
clampedWidth: n,
|
|
totalWidth: i,
|
|
}) {
|
|
return e.map((e) => {
|
|
let r = Math.floor((t / i) * e.length),
|
|
a = Math.floor(((t + n) / i) * e.length);
|
|
return e.slice(r, a);
|
|
});
|
|
})({ channelData: e, offset: o, clampedWidth: s, totalWidth: c });
|
|
this.renderSingleCanvas(h, t, s, i, o, r, a);
|
|
},
|
|
f = Math.ceil(c / l);
|
|
if (!this.isScrollable) {
|
|
for (let e = 0; e < f; e++) h(e);
|
|
return;
|
|
}
|
|
if (
|
|
(m({
|
|
scrollLeft: this.scrollContainer.scrollLeft,
|
|
totalWidth: c,
|
|
numCanvases: f,
|
|
}).forEach((e) => h(e)),
|
|
f > 1)
|
|
) {
|
|
let e = this.on("scroll", () => {
|
|
let { scrollLeft: e } = this.scrollContainer;
|
|
Object.keys(u).length > 10 &&
|
|
((r.innerHTML = ""), (a.innerHTML = ""), (u = {})),
|
|
m({ scrollLeft: e, totalWidth: c, numCanvases: f }).forEach((e) =>
|
|
h(e),
|
|
);
|
|
});
|
|
this.unsubscribeOnScroll.push(e);
|
|
}
|
|
}
|
|
renderChannel(e, t, n, i) {
|
|
var { overlay: r } = t,
|
|
a = (function (e, t) {
|
|
var n = {};
|
|
for (var i in e)
|
|
Object.prototype.hasOwnProperty.call(e, i) &&
|
|
0 > t.indexOf(i) &&
|
|
(n[i] = e[i]);
|
|
if (
|
|
null != e &&
|
|
"function" == typeof Object.getOwnPropertySymbols
|
|
) {
|
|
var r = 0;
|
|
for (i = Object.getOwnPropertySymbols(e); r < i.length; r++)
|
|
0 > t.indexOf(i[r]) &&
|
|
Object.prototype.propertyIsEnumerable.call(e, i[r]) &&
|
|
(n[i[r]] = e[i[r]]);
|
|
}
|
|
return n;
|
|
})(t, ["overlay"]);
|
|
let o = document.createElement("div"),
|
|
s = this.getHeight(a.height, a.splitChannels);
|
|
(o.style.height = `${s}px`),
|
|
r && i > 0 && (o.style.marginTop = `-${s}px`),
|
|
(this.canvasWrapper.style.minHeight = `${s}px`),
|
|
this.canvasWrapper.appendChild(o);
|
|
let c = o.cloneNode();
|
|
this.progressWrapper.appendChild(c),
|
|
this.renderMultiCanvas(e, a, n, s, o, c);
|
|
}
|
|
render(e) {
|
|
return r(this, void 0, void 0, function* () {
|
|
var t;
|
|
this.timeouts.forEach((e) => e()),
|
|
(this.timeouts = []),
|
|
(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);
|
|
let n = this.getPixelRatio(),
|
|
i = this.scrollContainer.clientWidth,
|
|
{
|
|
scrollWidth: r,
|
|
isScrollable: a,
|
|
useParentWidth: o,
|
|
width: s,
|
|
} = (function ({
|
|
duration: e,
|
|
minPxPerSec: t = 0,
|
|
parentWidth: n,
|
|
fillParent: i,
|
|
pixelRatio: r,
|
|
}) {
|
|
let a = Math.ceil(e * t),
|
|
o = a > n,
|
|
s = !!(i && !o);
|
|
return {
|
|
scrollWidth: a,
|
|
isScrollable: o,
|
|
useParentWidth: s,
|
|
width: (s ? n : a) * r,
|
|
};
|
|
})({
|
|
duration: e.duration,
|
|
minPxPerSec: this.options.minPxPerSec || 0,
|
|
parentWidth: i,
|
|
fillParent: this.options.fillParent,
|
|
pixelRatio: n,
|
|
});
|
|
if (
|
|
((this.isScrollable = a),
|
|
(this.wrapper.style.width = o ? "100%" : `${r}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 n = 0; n < e.numberOfChannels; n++) {
|
|
let i = Object.assign(
|
|
Object.assign({}, this.options),
|
|
null == (t = this.options.splitChannels) ? void 0 : t[n],
|
|
);
|
|
this.renderChannel([e.getChannelData(n)], i, s, n);
|
|
}
|
|
else {
|
|
let t = [e.getChannelData(0)];
|
|
e.numberOfChannels > 1 && t.push(e.getChannelData(1)),
|
|
this.renderChannel(t, this.options, s, 0);
|
|
}
|
|
Promise.resolve().then(() => this.emit("rendered"));
|
|
});
|
|
}
|
|
reRender() {
|
|
if (
|
|
(this.unsubscribeOnScroll.forEach((e) => e()),
|
|
(this.unsubscribeOnScroll = []),
|
|
!this.audioData)
|
|
)
|
|
return;
|
|
let { scrollWidth: e } = this.scrollContainer,
|
|
{ right: t } = this.progressWrapper.getBoundingClientRect();
|
|
if (
|
|
(this.render(this.audioData),
|
|
this.isScrollable && e !== this.scrollContainer.scrollWidth)
|
|
) {
|
|
let e,
|
|
{ right: n } = this.progressWrapper.getBoundingClientRect(),
|
|
i = ((e = 2 * (n - t)) < 0 ? Math.floor(e) : Math.ceil(e)) / 2;
|
|
this.scrollContainer.scrollLeft += i;
|
|
}
|
|
}
|
|
zoom(e) {
|
|
(this.options.minPxPerSec = e), this.reRender();
|
|
}
|
|
scrollIntoView(e, t = !1) {
|
|
let {
|
|
scrollLeft: n,
|
|
scrollWidth: i,
|
|
clientWidth: r,
|
|
} = this.scrollContainer,
|
|
a = e * i,
|
|
o = n + r,
|
|
s = r / 2;
|
|
if (this.isDragging)
|
|
a + 30 > o
|
|
? (this.scrollContainer.scrollLeft += 30)
|
|
: a - 30 < n && (this.scrollContainer.scrollLeft -= 30);
|
|
else {
|
|
(a < n || a > o) &&
|
|
(this.scrollContainer.scrollLeft =
|
|
a - (this.options.autoCenter ? s : 0));
|
|
let e = a - n - s;
|
|
t &&
|
|
this.options.autoCenter &&
|
|
e > 0 &&
|
|
(this.scrollContainer.scrollLeft += e);
|
|
}
|
|
}
|
|
renderProgress(e, t) {
|
|
if (isNaN(e)) return;
|
|
let n = 100 * e;
|
|
(this.canvasWrapper.style.clipPath = `polygon(${n}% 0%, 100% 0%, 100% 100%, ${n}% 100%)`),
|
|
(this.progressWrapper.style.width = `${n}%`),
|
|
(this.cursor.style.left = `${n}%`),
|
|
(this.cursor.style.transform = this.options.cursorWidth
|
|
? `translateX(-${e * this.options.cursorWidth}px)`
|
|
: ""),
|
|
this.isScrollable &&
|
|
this.options.autoScroll &&
|
|
this.audioData &&
|
|
this.audioData.duration > 0 &&
|
|
this.scrollIntoView(e, t);
|
|
}
|
|
exportImage(e, t, n) {
|
|
return r(this, void 0, void 0, function* () {
|
|
let i = this.canvasWrapper.querySelectorAll("canvas");
|
|
if (!i.length) throw Error("No waveform data");
|
|
return "dataURL" === n
|
|
? Promise.resolve(Array.from(i).map((n) => n.toDataURL(e, t)))
|
|
: Promise.all(
|
|
Array.from(i).map(
|
|
(n) =>
|
|
new Promise((i, r) => {
|
|
n.toBlob(
|
|
(e) => {
|
|
e ? i(e) : r(Error("Could not export image"));
|
|
},
|
|
e,
|
|
t,
|
|
);
|
|
}),
|
|
),
|
|
);
|
|
});
|
|
}
|
|
}
|
|
class x extends a {
|
|
constructor() {
|
|
super(...arguments),
|
|
(this.animationFrameId = null),
|
|
(this.isRunning = !1);
|
|
}
|
|
start() {
|
|
if (this.isRunning) return;
|
|
this.isRunning = !0;
|
|
let e = () => {
|
|
this.isRunning &&
|
|
(this.emit("tick"),
|
|
(this.animationFrameId = requestAnimationFrame(e)));
|
|
};
|
|
e();
|
|
}
|
|
stop() {
|
|
(this.isRunning = !1),
|
|
null !== this.animationFrameId &&
|
|
(cancelAnimationFrame(this.animationFrameId),
|
|
(this.animationFrameId = null));
|
|
}
|
|
destroy() {
|
|
this.stop();
|
|
}
|
|
}
|
|
class y extends a {
|
|
constructor(e = new AudioContext()) {
|
|
super(),
|
|
(this.bufferNode = null),
|
|
(this.playStartTime = 0),
|
|
(this.playedDuration = 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.audioContext = e),
|
|
(this.gainNode = this.audioContext.createGain()),
|
|
this.gainNode.connect(this.audioContext.destination);
|
|
}
|
|
load() {
|
|
return r(this, void 0, void 0, function* () {});
|
|
}
|
|
get src() {
|
|
return this.currentSrc;
|
|
}
|
|
set src(e) {
|
|
((this.currentSrc = e), (this._duration = void 0), e)
|
|
? fetch(e)
|
|
.then((t) => {
|
|
if (t.status >= 400)
|
|
throw Error(
|
|
`Failed to fetch ${e}: ${t.status} (${t.statusText})`,
|
|
);
|
|
return t.arrayBuffer();
|
|
})
|
|
.then((t) =>
|
|
this.currentSrc !== e
|
|
? null
|
|
: this.audioContext.decodeAudioData(t),
|
|
)
|
|
.then((t) => {
|
|
this.currentSrc === e &&
|
|
((this.buffer = t),
|
|
this.emit("loadedmetadata"),
|
|
this.emit("canplay"),
|
|
this.autoplay && this.play());
|
|
})
|
|
.catch((e) => {
|
|
console.error("WebAudioPlayer load error:", e);
|
|
})
|
|
: ((this.buffer = null), this.emit("emptied"));
|
|
}
|
|
_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 e = this.playedDuration * this._playbackRate;
|
|
(e >= this.duration || e < 0) && ((e = 0), (this.playedDuration = 0)),
|
|
this.bufferNode.start(this.audioContext.currentTime, e),
|
|
(this.playStartTime = this.audioContext.currentTime),
|
|
(this.bufferNode.onended = () => {
|
|
this.currentTime >= this.duration &&
|
|
(this.pause(), this.emit("ended"));
|
|
});
|
|
}
|
|
_pause() {
|
|
var e;
|
|
(this.paused = !0),
|
|
null == (e = this.bufferNode) || e.stop(),
|
|
(this.playedDuration +=
|
|
this.audioContext.currentTime - this.playStartTime);
|
|
}
|
|
play() {
|
|
return r(this, void 0, void 0, function* () {
|
|
this.paused && (this._play(), this.emit("play"));
|
|
});
|
|
}
|
|
pause() {
|
|
this.paused || (this._pause(), this.emit("pause"));
|
|
}
|
|
stopAt(e) {
|
|
let t = e - this.currentTime,
|
|
n = this.bufferNode;
|
|
null == n || n.stop(this.audioContext.currentTime + t),
|
|
null == n ||
|
|
n.addEventListener(
|
|
"ended",
|
|
() => {
|
|
n === this.bufferNode &&
|
|
((this.bufferNode = null), this.pause());
|
|
},
|
|
{ once: !0 },
|
|
);
|
|
}
|
|
setSinkId(e) {
|
|
return r(this, void 0, void 0, function* () {
|
|
return this.audioContext.setSinkId(e);
|
|
});
|
|
}
|
|
get playbackRate() {
|
|
return this._playbackRate;
|
|
}
|
|
set playbackRate(e) {
|
|
(this._playbackRate = e),
|
|
this.bufferNode && (this.bufferNode.playbackRate.value = e);
|
|
}
|
|
get currentTime() {
|
|
return (
|
|
(this.paused
|
|
? this.playedDuration
|
|
: this.playedDuration +
|
|
(this.audioContext.currentTime - this.playStartTime)) *
|
|
this._playbackRate
|
|
);
|
|
}
|
|
set currentTime(e) {
|
|
let t = !this.paused;
|
|
t && this._pause(),
|
|
(this.playedDuration = e / this._playbackRate),
|
|
t && this._play(),
|
|
this.emit("seeking"),
|
|
this.emit("timeupdate");
|
|
}
|
|
get duration() {
|
|
var e, t;
|
|
return null != (e = this._duration)
|
|
? e
|
|
: (null == (t = this.buffer) ? void 0 : t.duration) || 0;
|
|
}
|
|
set duration(e) {
|
|
this._duration = e;
|
|
}
|
|
get volume() {
|
|
return this.gainNode.gain.value;
|
|
}
|
|
set volume(e) {
|
|
(this.gainNode.gain.value = e), this.emit("volumechange");
|
|
}
|
|
get muted() {
|
|
return this._muted;
|
|
}
|
|
set muted(e) {
|
|
this._muted !== e &&
|
|
((this._muted = e),
|
|
this._muted
|
|
? this.gainNode.disconnect()
|
|
: this.gainNode.connect(this.audioContext.destination));
|
|
}
|
|
canPlayType(e) {
|
|
return /^(audio|video)\//.test(e);
|
|
}
|
|
getGainNode() {
|
|
return this.gainNode;
|
|
}
|
|
getChannelData() {
|
|
let e = [];
|
|
if (!this.buffer) return e;
|
|
let t = this.buffer.numberOfChannels;
|
|
for (let n = 0; n < t; n++) e.push(this.buffer.getChannelData(n));
|
|
return e;
|
|
}
|
|
removeAttribute(e) {
|
|
switch (e) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
let _ = {
|
|
waveColor: "#999",
|
|
progressColor: "#555",
|
|
cursorWidth: 1,
|
|
minPxPerSec: 0,
|
|
fillParent: !0,
|
|
interact: !0,
|
|
dragToSeek: !1,
|
|
autoScroll: !0,
|
|
autoCenter: !0,
|
|
sampleRate: 8e3,
|
|
};
|
|
class S extends d {
|
|
static create(e) {
|
|
return new S(e);
|
|
}
|
|
getState() {
|
|
return this.wavesurferState;
|
|
}
|
|
getRenderer() {
|
|
return this.renderer;
|
|
}
|
|
constructor(e) {
|
|
const t = e.media || ("WebAudio" === e.backend ? new y() : void 0);
|
|
super({
|
|
media: t,
|
|
mediaControls: e.mediaControls,
|
|
autoplay: e.autoplay,
|
|
playbackRate: e.audioRate,
|
|
}),
|
|
(this.plugins = []),
|
|
(this.decodedData = null),
|
|
(this.stopAtPosition = null),
|
|
(this.subscriptions = []),
|
|
(this.mediaSubscriptions = []),
|
|
(this.abortController = null),
|
|
(this.reactiveCleanups = []),
|
|
(this.options = Object.assign({}, _, e));
|
|
const { state: n, actions: i } = (function (e) {
|
|
var t, n, i, r, a, o;
|
|
let s = null != (t = null == e ? void 0 : e.currentTime) ? t : u(0),
|
|
c = null != (n = null == e ? void 0 : e.duration) ? n : u(0),
|
|
l = null != (i = null == e ? void 0 : e.isPlaying) ? i : u(!1),
|
|
f = null != (r = null == e ? void 0 : e.isSeeking) ? r : u(!1),
|
|
d = null != (a = null == e ? void 0 : e.volume) ? a : u(1),
|
|
p = null != (o = null == e ? void 0 : e.playbackRate) ? o : u(1),
|
|
g = u(null),
|
|
b = u(null),
|
|
m = u(""),
|
|
w = u(0),
|
|
v = u(0),
|
|
x = h(() => !l.value, [l]),
|
|
y = h(() => null !== g.value, [g]),
|
|
_ = h(() => y.value && c.value > 0, [y, c]),
|
|
S = h(() => s.value, [s]),
|
|
E = h(() => (c.value > 0 ? s.value / c.value : 0), [s, c]);
|
|
return {
|
|
state: {
|
|
currentTime: s,
|
|
duration: c,
|
|
isPlaying: l,
|
|
isPaused: x,
|
|
isSeeking: f,
|
|
volume: d,
|
|
playbackRate: p,
|
|
audioBuffer: g,
|
|
peaks: b,
|
|
url: m,
|
|
zoom: w,
|
|
scrollPosition: v,
|
|
canPlay: y,
|
|
isReady: _,
|
|
progress: S,
|
|
progressPercent: E,
|
|
},
|
|
actions: {
|
|
setCurrentTime: (e) => {
|
|
let t = Math.max(0, Math.min(c.value || 1 / 0, e));
|
|
s.set(t);
|
|
},
|
|
setDuration: (e) => {
|
|
c.set(Math.max(0, e));
|
|
},
|
|
setPlaying: (e) => {
|
|
l.set(e);
|
|
},
|
|
setSeeking: (e) => {
|
|
f.set(e);
|
|
},
|
|
setVolume: (e) => {
|
|
let t = Math.max(0, Math.min(1, e));
|
|
d.set(t);
|
|
},
|
|
setPlaybackRate: (e) => {
|
|
let t = Math.max(0.1, Math.min(16, e));
|
|
p.set(t);
|
|
},
|
|
setAudioBuffer: (e) => {
|
|
g.set(e), e && c.set(e.duration);
|
|
},
|
|
setPeaks: (e) => {
|
|
b.set(e);
|
|
},
|
|
setUrl: (e) => {
|
|
m.set(e);
|
|
},
|
|
setZoom: (e) => {
|
|
w.set(Math.max(0, e));
|
|
},
|
|
setScrollPosition: (e) => {
|
|
v.set(Math.max(0, e));
|
|
},
|
|
},
|
|
};
|
|
})({
|
|
isPlaying: this.isPlayingSignal,
|
|
currentTime: this.currentTimeSignal,
|
|
duration: this.durationSignal,
|
|
volume: this.volumeSignal,
|
|
playbackRate: this.playbackRateSignal,
|
|
isSeeking: this.seekingSignal,
|
|
});
|
|
(this.wavesurferState = n),
|
|
(this.wavesurferActions = i),
|
|
(this.timer = new x());
|
|
const r = t ? void 0 : this.getMediaElement();
|
|
(this.renderer = new v(this.options, r)),
|
|
this.initPlayerEvents(),
|
|
this.initRendererEvents(),
|
|
this.initTimerEvents(),
|
|
this.initReactiveState(),
|
|
this.initPlugins();
|
|
const a = this.options.url || this.getSrc() || "";
|
|
Promise.resolve().then(() => {
|
|
this.emit("init");
|
|
let { peaks: e, duration: t } = this.options;
|
|
(a || (e && t)) &&
|
|
this.load(a, e, t).catch((e) => {
|
|
this.emit("error", e instanceof Error ? e : Error(String(e)));
|
|
});
|
|
});
|
|
}
|
|
updateProgress(e = this.getCurrentTime()) {
|
|
return (
|
|
this.renderer.renderProgress(
|
|
e / this.getDuration(),
|
|
this.isPlaying(),
|
|
),
|
|
e
|
|
);
|
|
}
|
|
initTimerEvents() {
|
|
this.subscriptions.push(
|
|
this.timer.on("tick", () => {
|
|
if (!this.isSeeking()) {
|
|
let e = this.updateProgress();
|
|
this.emit("timeupdate", e),
|
|
this.emit("audioprocess", e),
|
|
null != this.stopAtPosition &&
|
|
this.isPlaying() &&
|
|
e >= this.stopAtPosition &&
|
|
this.pause();
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
initReactiveState() {
|
|
var e, t;
|
|
let n, i, r;
|
|
this.reactiveCleanups.push(
|
|
((e = this.wavesurferState),
|
|
(t = { emit: this.emit.bind(this) }),
|
|
(n = []).push(
|
|
f(() => {
|
|
let n = e.isPlaying.value;
|
|
t.emit(n ? "play" : "pause");
|
|
}, [e.isPlaying]),
|
|
),
|
|
n.push(
|
|
f(() => {
|
|
let n = e.currentTime.value;
|
|
t.emit("timeupdate", n),
|
|
e.isPlaying.value && t.emit("audioprocess", n);
|
|
}, [e.currentTime, e.isPlaying]),
|
|
),
|
|
n.push(
|
|
f(() => {
|
|
e.isSeeking.value && t.emit("seeking", e.currentTime.value);
|
|
}, [e.isSeeking, e.currentTime]),
|
|
),
|
|
(i = !1),
|
|
n.push(
|
|
f(() => {
|
|
e.isReady.value &&
|
|
!i &&
|
|
((i = !0), t.emit("ready", e.duration.value));
|
|
}, [e.isReady, e.duration]),
|
|
),
|
|
(r = !1),
|
|
n.push(
|
|
f(() => {
|
|
let n = e.isPlaying.value,
|
|
i = e.currentTime.value,
|
|
a = e.duration.value,
|
|
o = a > 0 && i >= a;
|
|
r && !n && o && t.emit("finish"), (r = n && o);
|
|
}, [e.isPlaying, e.currentTime, e.duration]),
|
|
),
|
|
n.push(
|
|
f(() => {
|
|
let n = e.zoom.value;
|
|
n > 0 && t.emit("zoom", n);
|
|
}, [e.zoom]),
|
|
),
|
|
() => {
|
|
n.forEach((e) => e());
|
|
}),
|
|
);
|
|
}
|
|
initPlayerEvents() {
|
|
this.isPlaying() && (this.emit("play"), this.timer.start()),
|
|
this.mediaSubscriptions.push(
|
|
this.onMediaEvent("timeupdate", () => {
|
|
let e = this.updateProgress();
|
|
this.emit("timeupdate", e);
|
|
}),
|
|
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 e;
|
|
this.emit(
|
|
"error",
|
|
null != (e = this.getMediaElement().error)
|
|
? e
|
|
: Error("Media error"),
|
|
),
|
|
(this.stopAtPosition = null);
|
|
}),
|
|
);
|
|
}
|
|
initRendererEvents() {
|
|
this.subscriptions.push(
|
|
this.renderer.on("click", (e, t) => {
|
|
this.options.interact &&
|
|
(this.seekTo(e),
|
|
this.emit("interaction", e * this.getDuration()),
|
|
this.emit("click", e, t));
|
|
}),
|
|
this.renderer.on("dblclick", (e, t) => {
|
|
this.emit("dblclick", e, t);
|
|
}),
|
|
this.renderer.on("scroll", (e, t, n, i) => {
|
|
let r = this.getDuration();
|
|
this.emit("scroll", e * r, t * r, n, i);
|
|
}),
|
|
this.renderer.on("render", () => {
|
|
this.emit("redraw");
|
|
}),
|
|
this.renderer.on("rendered", () => {
|
|
this.emit("redrawcomplete");
|
|
}),
|
|
this.renderer.on("dragstart", (e) => {
|
|
this.emit("dragstart", e);
|
|
}),
|
|
this.renderer.on("dragend", (e) => {
|
|
this.emit("dragend", e);
|
|
}),
|
|
this.renderer.on("resize", () => {
|
|
this.emit("resize");
|
|
}),
|
|
);
|
|
{
|
|
let e,
|
|
t = this.renderer.on("drag", (t) => {
|
|
var n;
|
|
if (!this.options.interact) return;
|
|
this.renderer.renderProgress(t), clearTimeout(e);
|
|
let i = 0,
|
|
r = this.options.dragToSeek;
|
|
this.isPlaying()
|
|
? (i = 0)
|
|
: !0 === r
|
|
? (i = 200)
|
|
: r &&
|
|
"object" == typeof r &&
|
|
(i = null != (n = r.debounceTime) ? n : 200),
|
|
(e = setTimeout(() => {
|
|
this.seekTo(t);
|
|
}, i)),
|
|
this.emit("interaction", t * this.getDuration()),
|
|
this.emit("drag", t);
|
|
});
|
|
this.subscriptions.push(() => {
|
|
clearTimeout(e), t();
|
|
});
|
|
}
|
|
}
|
|
initPlugins() {
|
|
var e;
|
|
(null == (e = this.options.plugins) ? void 0 : e.length) &&
|
|
this.options.plugins.forEach((e) => {
|
|
this.registerPlugin(e);
|
|
});
|
|
}
|
|
unsubscribePlayerEvents() {
|
|
this.mediaSubscriptions.forEach((e) => e()),
|
|
(this.mediaSubscriptions = []);
|
|
}
|
|
setOptions(e) {
|
|
(this.options = Object.assign({}, this.options, e)),
|
|
e.duration &&
|
|
!e.peaks &&
|
|
(this.decodedData = o.createBuffer(this.exportPeaks(), e.duration)),
|
|
e.peaks &&
|
|
e.duration &&
|
|
(this.decodedData = o.createBuffer(e.peaks, e.duration)),
|
|
this.renderer.setOptions(this.options),
|
|
e.audioRate && this.setPlaybackRate(e.audioRate),
|
|
null != e.mediaControls &&
|
|
(this.getMediaElement().controls = e.mediaControls);
|
|
}
|
|
registerPlugin(e) {
|
|
if (this.plugins.includes(e)) return e;
|
|
e._init(this), this.plugins.push(e);
|
|
let t = e.once("destroy", () => {
|
|
(this.plugins = this.plugins.filter((t) => t !== e)),
|
|
(this.subscriptions = this.subscriptions.filter((e) => e !== t));
|
|
});
|
|
return this.subscriptions.push(t), e;
|
|
}
|
|
unregisterPlugin(e) {
|
|
(this.plugins = this.plugins.filter((t) => t !== e)), e.destroy();
|
|
}
|
|
getWrapper() {
|
|
return this.renderer.getWrapper();
|
|
}
|
|
getWidth() {
|
|
return this.renderer.getWidth();
|
|
}
|
|
getScroll() {
|
|
return this.renderer.getScroll();
|
|
}
|
|
setScroll(e) {
|
|
return this.renderer.setScroll(e);
|
|
}
|
|
setScrollTime(e) {
|
|
let t = e / this.getDuration();
|
|
this.renderer.setScrollPercentage(t);
|
|
}
|
|
getActivePlugins() {
|
|
return this.plugins;
|
|
}
|
|
loadAudio(e, t, n, i) {
|
|
return r(this, void 0, void 0, function* () {
|
|
var r;
|
|
if (
|
|
(this.emit("load", e),
|
|
!this.options.media && this.isPlaying() && this.pause(),
|
|
(this.decodedData = null),
|
|
(this.stopAtPosition = null),
|
|
null == (r = this.abortController) || r.abort(),
|
|
(this.abortController = null),
|
|
!t && !n)
|
|
) {
|
|
let n = this.options.fetchParams || {};
|
|
window.AbortController &&
|
|
!n.signal &&
|
|
((this.abortController = new AbortController()),
|
|
(n.signal = this.abortController.signal));
|
|
let i = (e) => this.emit("loading", e);
|
|
t = yield l.fetchBlob(e, i, n);
|
|
let r = this.options.blobMimeType;
|
|
r && (t = new Blob([t], { type: r }));
|
|
}
|
|
this.setSrc(e, t);
|
|
let a = yield new Promise((e) => {
|
|
let t = i || this.getDuration();
|
|
t
|
|
? e(t)
|
|
: this.mediaSubscriptions.push(
|
|
this.onMediaEvent(
|
|
"loadedmetadata",
|
|
() => e(this.getDuration()),
|
|
{ once: !0 },
|
|
),
|
|
);
|
|
});
|
|
if (!e && !t) {
|
|
let e = this.getMediaElement();
|
|
e instanceof y && (e.duration = a);
|
|
}
|
|
if (n) this.decodedData = o.createBuffer(n, a || 0);
|
|
else if (t) {
|
|
let e = yield t.arrayBuffer();
|
|
this.decodedData = yield o.decode(e, this.options.sampleRate);
|
|
}
|
|
this.decodedData &&
|
|
(this.emit("decode", this.getDuration()),
|
|
this.renderer.render(this.decodedData)),
|
|
this.emit("ready", this.getDuration());
|
|
});
|
|
}
|
|
load(e, t, n) {
|
|
return r(this, void 0, void 0, function* () {
|
|
try {
|
|
return yield this.loadAudio(e, void 0, t, n);
|
|
} catch (e) {
|
|
throw (this.emit("error", e), e);
|
|
}
|
|
});
|
|
}
|
|
loadBlob(e, t, n) {
|
|
return r(this, void 0, void 0, function* () {
|
|
try {
|
|
return yield this.loadAudio("", e, t, n);
|
|
} catch (e) {
|
|
throw (this.emit("error", e), e);
|
|
}
|
|
});
|
|
}
|
|
zoom(e) {
|
|
if (!this.decodedData) throw Error("No audio loaded");
|
|
this.renderer.zoom(e), this.emit("zoom", e);
|
|
}
|
|
getDecodedData() {
|
|
return this.decodedData;
|
|
}
|
|
exportPeaks({
|
|
channels: e = 2,
|
|
maxLength: t = 8e3,
|
|
precision: n = 1e4,
|
|
} = {}) {
|
|
if (!this.decodedData)
|
|
throw Error("The audio has not been decoded yet");
|
|
let i = Math.min(e, this.decodedData.numberOfChannels),
|
|
r = [];
|
|
for (let e = 0; e < i; e++) {
|
|
let i = this.decodedData.getChannelData(e),
|
|
a = [],
|
|
o = i.length / t;
|
|
for (let e = 0; e < t; e++) {
|
|
let t = i.slice(Math.floor(e * o), Math.ceil((e + 1) * o)),
|
|
r = 0;
|
|
for (let e = 0; e < t.length; e++) {
|
|
let n = t[e];
|
|
Math.abs(n) > Math.abs(r) && (r = n);
|
|
}
|
|
a.push(Math.round(r * n) / n);
|
|
}
|
|
r.push(a);
|
|
}
|
|
return r;
|
|
}
|
|
getDuration() {
|
|
let e = super.getDuration() || 0;
|
|
return (
|
|
(0 === e || e === 1 / 0) &&
|
|
this.decodedData &&
|
|
(e = this.decodedData.duration),
|
|
e
|
|
);
|
|
}
|
|
toggleInteraction(e) {
|
|
this.options.interact = e;
|
|
}
|
|
setTime(e) {
|
|
(this.stopAtPosition = null),
|
|
super.setTime(e),
|
|
this.updateProgress(e),
|
|
this.emit("timeupdate", e);
|
|
}
|
|
seekTo(e) {
|
|
let t = this.getDuration() * e;
|
|
this.setTime(t);
|
|
}
|
|
play(e, t) {
|
|
let n = Object.create(null, { play: { get: () => super.play } });
|
|
return r(this, void 0, void 0, function* () {
|
|
null != e && this.setTime(e);
|
|
let i = yield n.play.call(this);
|
|
return (
|
|
null != t &&
|
|
(this.media instanceof y
|
|
? this.media.stopAt(t)
|
|
: (this.stopAtPosition = t)),
|
|
i
|
|
);
|
|
});
|
|
}
|
|
playPause() {
|
|
return r(this, void 0, void 0, function* () {
|
|
return this.isPlaying() ? this.pause() : this.play();
|
|
});
|
|
}
|
|
stop() {
|
|
this.pause(), this.setTime(0);
|
|
}
|
|
skip(e) {
|
|
this.setTime(this.getCurrentTime() + e);
|
|
}
|
|
empty() {
|
|
this.load("", [[0]], 0.001);
|
|
}
|
|
setMediaElement(e) {
|
|
this.unsubscribePlayerEvents(),
|
|
super.setMediaElement(e),
|
|
this.initPlayerEvents();
|
|
}
|
|
exportImage() {
|
|
return r(
|
|
this,
|
|
arguments,
|
|
void 0,
|
|
function* (e = "image/png", t = 1, n = "dataURL") {
|
|
return this.renderer.exportImage(e, t, n);
|
|
},
|
|
);
|
|
}
|
|
destroy() {
|
|
var e;
|
|
this.emit("destroy"),
|
|
null == (e = this.abortController) || e.abort(),
|
|
this.plugins.forEach((e) => e.destroy()),
|
|
this.subscriptions.forEach((e) => e()),
|
|
this.unsubscribePlayerEvents(),
|
|
this.reactiveCleanups.forEach((e) => e()),
|
|
(this.reactiveCleanups = []),
|
|
this.timer.destroy(),
|
|
this.renderer.destroy(),
|
|
super.destroy();
|
|
}
|
|
}
|
|
(S.BasePlugin = class extends a {
|
|
constructor(e) {
|
|
super(),
|
|
(this.subscriptions = []),
|
|
(this.isDestroyed = !1),
|
|
(this.options = e);
|
|
}
|
|
onInit() {}
|
|
_init(e) {
|
|
this.isDestroyed &&
|
|
((this.subscriptions = []), (this.isDestroyed = !1)),
|
|
(this.wavesurfer = e),
|
|
this.onInit();
|
|
}
|
|
destroy() {
|
|
this.emit("destroy"),
|
|
this.subscriptions.forEach((e) => e()),
|
|
(this.subscriptions = []),
|
|
(this.isDestroyed = !0),
|
|
(this.wavesurfer = void 0);
|
|
}
|
|
}),
|
|
(S.dom = c);
|
|
var E = e.i(41671);
|
|
function M({ onRetry: e }) {
|
|
return (0, n.jsxs)("div", {
|
|
className:
|
|
"nodrag nopan absolute inset-0 flex flex-col items-center justify-center gap-2",
|
|
style: { zIndex: 10, background: "rgba(0, 0, 0, 0.45)" },
|
|
children: [
|
|
(0, n.jsx)("button", {
|
|
type: "button",
|
|
onClick: (t) => {
|
|
t.stopPropagation(), e();
|
|
},
|
|
className:
|
|
"flex h-10 w-10 items-center justify-center rounded-full transition-colors hover:bg-white/20",
|
|
style: {
|
|
background: "rgba(255, 255, 255, 0.1)",
|
|
border: "1px solid rgba(255, 255, 255, 0.2)",
|
|
},
|
|
children: (0, n.jsx)(E.Icons.Refresh, {
|
|
width: 20,
|
|
height: 20,
|
|
style: { color: "rgba(255, 255, 255, 0.8)" },
|
|
}),
|
|
}),
|
|
(0, n.jsx)("span", {
|
|
className: "text-xs",
|
|
style: { color: "rgba(255, 255, 255, 0.6)" },
|
|
children: "加载失败,点击重试",
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
function T(e, t) {
|
|
let { maxAutoRetry: n = 1, autoRetryDelay: r = 1500 } = t ?? {},
|
|
[a, o] = (0, i.useState)(0),
|
|
[s, c] = (0, i.useState)("idle"),
|
|
l = (0, i.useRef)(0),
|
|
u = (0, i.useRef)(!1),
|
|
h = (0, i.useRef)(!1),
|
|
f = (0, i.useRef)();
|
|
(0, i.useEffect)(() => {
|
|
(l.current = 0),
|
|
(u.current = !1),
|
|
(h.current = !1),
|
|
o(0),
|
|
c("idle"),
|
|
f.current && (clearTimeout(f.current), (f.current = void 0));
|
|
}, [e]),
|
|
(0, i.useEffect)(
|
|
() => () => {
|
|
f.current && clearTimeout(f.current);
|
|
},
|
|
[],
|
|
);
|
|
let d = (0, i.useCallback)(() => {
|
|
h.current ||
|
|
(!u.current && l.current < n
|
|
? ((h.current = !0),
|
|
c("retrying"),
|
|
(l.current += 1),
|
|
(f.current = setTimeout(() => {
|
|
(h.current = !1), o((e) => e + 1), (f.current = void 0);
|
|
}, r)))
|
|
: ((u.current = !1), c("failed")));
|
|
}, [n, r]);
|
|
return {
|
|
retryKey: a,
|
|
status: s,
|
|
showRetryButton: "failed" === s,
|
|
handleLoadError: d,
|
|
handleLoadSuccess: (0, i.useCallback)(() => {
|
|
f.current && (clearTimeout(f.current), (f.current = void 0)),
|
|
(h.current = !1),
|
|
(u.current = !1),
|
|
c("loaded");
|
|
}, []),
|
|
triggerManualRetry: (0, i.useCallback)(() => {
|
|
f.current && (clearTimeout(f.current), (f.current = void 0)),
|
|
(h.current = !1),
|
|
(u.current = !0),
|
|
c("retrying"),
|
|
o((e) => e + 1);
|
|
}, []),
|
|
};
|
|
}
|
|
e.s(["ResourceRetryOverlay", () => M], 45523),
|
|
e.s(["useResourceRetry", () => T], 606095);
|
|
var k = e.i(41114);
|
|
let C = "peaks",
|
|
A = new Map(),
|
|
N = null;
|
|
function I() {
|
|
return (
|
|
N ||
|
|
(N = new Promise((e, t) => {
|
|
let n = indexedDB.open("libtv-audio-peaks", 1);
|
|
(n.onupgradeneeded = () => {
|
|
let e = n.result;
|
|
e.objectStoreNames.contains(C) ||
|
|
e
|
|
.createObjectStore(C, { keyPath: "url" })
|
|
.createIndex("capturedAt", "capturedAt", { unique: !1 });
|
|
}),
|
|
(n.onsuccess = () => {
|
|
let t = n.result;
|
|
(t.onclose = () => {
|
|
N = null;
|
|
}),
|
|
e(t);
|
|
}),
|
|
(n.onerror = () => {
|
|
(N = null), t(n.error ?? Error("IndexedDB open failed"));
|
|
});
|
|
}))
|
|
);
|
|
}
|
|
async function P(e, t, n) {
|
|
try {
|
|
let i = (await I()).transaction(C, "readwrite"),
|
|
r = i.objectStore(C),
|
|
a = { url: e, peaks: t, duration: n, capturedAt: Date.now() };
|
|
r.put(a),
|
|
await new Promise((e, t) => {
|
|
(i.oncomplete = () => e()),
|
|
(i.onerror = () =>
|
|
t(i.error ?? Error("saveToDB transaction failed")));
|
|
});
|
|
} catch {}
|
|
}
|
|
async function R(e) {
|
|
try {
|
|
let t = (await I()).transaction(C, "readwrite");
|
|
t.objectStore(C).delete(e),
|
|
await new Promise((e, n) => {
|
|
(t.oncomplete = () => e()),
|
|
(t.onerror = () =>
|
|
n(t.error ?? Error("deleteFromDB transaction failed")));
|
|
});
|
|
} catch {}
|
|
}
|
|
async function L() {
|
|
try {
|
|
let e = (await I()).transaction(C, "readwrite"),
|
|
t = e.objectStore(C),
|
|
n = Date.now(),
|
|
i = await new Promise((e, n) => {
|
|
let i = t.getAll();
|
|
(i.onsuccess = () => e(i.result)),
|
|
(i.onerror = () =>
|
|
n(i.error ?? Error("purgeStaleEntries query failed")));
|
|
});
|
|
for (let e of i.filter((e) => n - e.capturedAt > 2592e6))
|
|
t.delete(e.url);
|
|
let r = i.filter((e) => n - e.capturedAt <= 2592e6);
|
|
if (r.length > 300)
|
|
for (let e of (r.sort((e, t) => e.capturedAt - t.capturedAt),
|
|
r.slice(0, r.length - 300)))
|
|
t.delete(e.url);
|
|
await new Promise((t, n) => {
|
|
(e.oncomplete = () => t()),
|
|
(e.onerror = () =>
|
|
n(e.error ?? Error("purgeStaleEntries transaction failed")));
|
|
});
|
|
} catch {}
|
|
}
|
|
function D(e, t, n) {
|
|
!e ||
|
|
0 === t.length ||
|
|
n <= 0 ||
|
|
(A.set(e, { peaks: t, duration: n }),
|
|
e.startsWith("blob:") || e.startsWith("data:") || P(e, t, n));
|
|
}
|
|
function j(e) {
|
|
if (e) return A.get(e);
|
|
}
|
|
function O(e) {
|
|
return !!e && A.has(e);
|
|
}
|
|
let F =
|
|
"function" == typeof requestIdleCallback
|
|
? (e) => requestIdleCallback(e, { timeout: 5e3 })
|
|
: (e) => setTimeout(e, 0);
|
|
async function U() {
|
|
try {
|
|
let e = (await I()).transaction(C, "readonly").objectStore(C),
|
|
t = Date.now();
|
|
await new Promise((n, i) => {
|
|
let r = e.openCursor(),
|
|
a = 0;
|
|
(r.onerror = () =>
|
|
i(r.error ?? Error("warmUpAudioCache cursor failed"))),
|
|
(r.onsuccess = () => {
|
|
let e = r.result;
|
|
if (!e) return void n();
|
|
let i = e.value;
|
|
i &&
|
|
t - i.capturedAt <= 2592e6 &&
|
|
A.set(i.url, { peaks: i.peaks, duration: i.duration }),
|
|
++a % 80 == 0
|
|
? F(() => {
|
|
e.continue();
|
|
})
|
|
: e.continue();
|
|
});
|
|
}),
|
|
L();
|
|
} catch {}
|
|
}
|
|
function B(e) {
|
|
!e ||
|
|
(A.delete(e), e.startsWith("blob:") || e.startsWith("data:") || R(e));
|
|
}
|
|
e.s(
|
|
[
|
|
"cachePeaks",
|
|
() => D,
|
|
"getCachedPeaks",
|
|
() => j,
|
|
"hasCachedPeaks",
|
|
() => O,
|
|
"invalidatePeaks",
|
|
() => B,
|
|
"warmUpAudioCache",
|
|
() => U,
|
|
],
|
|
979138,
|
|
);
|
|
let H = {
|
|
MIN_SIZE: 3,
|
|
MAX_CAP:
|
|
"number" == typeof (t = navigator.deviceMemory) && t <= 4 ? 8 : 15,
|
|
RATIO: 0.5,
|
|
EVICT_BATCH: 3,
|
|
SHRINK_COOLDOWN_MS: 3e4,
|
|
},
|
|
z = H.MIN_SIZE,
|
|
G = 0,
|
|
$ = new Map(),
|
|
V = new Map();
|
|
function W(e) {
|
|
let t = Math.min(Math.max(Math.ceil(e * H.RATIO), H.MIN_SIZE), H.MAX_CAP);
|
|
t >= z
|
|
? (z = t)
|
|
: Date.now() - G > H.SHRINK_COOLDOWN_MS &&
|
|
((z = t),
|
|
(G = Date.now()),
|
|
(function e() {
|
|
if (V.size <= z) return;
|
|
let t = [...V.entries()].sort(
|
|
(e, t) => e[1].returnedAt - t[1].returnedAt,
|
|
),
|
|
n = 0;
|
|
for (; V.size > z && t.length > 0 && n < H.EVICT_BATCH; ) {
|
|
let e = t.shift();
|
|
if (!e) break;
|
|
let [i, r] = e;
|
|
try {
|
|
r.ws.destroy();
|
|
} catch {}
|
|
V.delete(i), n++;
|
|
}
|
|
V.size > z && setTimeout(e, 500);
|
|
})());
|
|
}
|
|
function K(e) {
|
|
let t = $.get(e);
|
|
if (t) return { ws: t, url: "" };
|
|
let n = V.get(e);
|
|
return n ? (V.delete(e), $.set(e, n.ws), { ws: n.ws, url: n.url }) : null;
|
|
}
|
|
function q(e) {
|
|
e > 0 && e < 1 && (e = 1);
|
|
let t = Math.floor(e / 60),
|
|
n = Math.floor(e % 60);
|
|
return `${t.toString().padStart(2, "0")}:${n.toString().padStart(2, "0")}`;
|
|
}
|
|
function X({
|
|
url: e,
|
|
playbackRate: t = 1,
|
|
nodeId: r,
|
|
onDurationReady: a,
|
|
chromeVariant: o = "default",
|
|
}) {
|
|
let s = "canvasLight" === o,
|
|
c = (0, i.useRef)(null),
|
|
l = (0, i.useRef)(null),
|
|
[u, h] = (0, i.useState)(!1),
|
|
[f, d] = (0, i.useState)(0),
|
|
[p, g] = (0, i.useState)(() => {
|
|
let t = e ? j(e) : void 0;
|
|
return t ? t.duration : 0;
|
|
}),
|
|
[b, m] = (0, i.useState)(() => !!e && !!j(e)),
|
|
[w, v] = (0, i.useState)(0),
|
|
[x, y] = (0, i.useState)(!1),
|
|
_ = (0, i.useRef)(a);
|
|
_.current = a;
|
|
let {
|
|
retryKey: C,
|
|
showRetryButton: A,
|
|
handleLoadError: N,
|
|
handleLoadSuccess: I,
|
|
triggerManualRetry: P,
|
|
} = T(e);
|
|
(0, i.useEffect)(() => {
|
|
if (!c.current || !e) return;
|
|
let t = !1;
|
|
if ((y(!1), d(0), v(0), h(!1), m(!1), g(0), r)) {
|
|
let t = K(r);
|
|
if (t) {
|
|
if (!j(e) && t.url === e)
|
|
try {
|
|
let n = t.ws.exportPeaks({ maxLength: 512, precision: 4 }),
|
|
i = t.ws.getDuration();
|
|
n && i > 0 && D(e, n, i);
|
|
} catch {}
|
|
try {
|
|
t.ws.destroy();
|
|
} catch {}
|
|
}
|
|
}
|
|
let n = j(e),
|
|
i = new Audio();
|
|
(i.crossOrigin = "anonymous"), n && ((i.src = e), (i.preload = "auto"));
|
|
let a = S.create({
|
|
container: c.current,
|
|
media: i,
|
|
waveColor: s ? "#b3b3b3" : "#525252",
|
|
progressColor: s ? "#262626" : "#FFFFFF",
|
|
cursorColor: "transparent",
|
|
cursorWidth: 0,
|
|
barWidth: 2,
|
|
barGap: 3,
|
|
barRadius: 2,
|
|
height: 64,
|
|
barHeight: 0.8,
|
|
normalize: !0,
|
|
...(n ? { peaks: n.peaks, duration: n.duration } : {}),
|
|
});
|
|
return (
|
|
n
|
|
? (m(!0),
|
|
g(n.duration),
|
|
I(),
|
|
n.duration > 0 && _.current?.(n.duration))
|
|
: a.load(e).catch((e) => {
|
|
t ||
|
|
(e &&
|
|
"object" == typeof e &&
|
|
"name" in e &&
|
|
"AbortError" === e.name) ||
|
|
(console.error("[AudioWavePlayer] 音频加载失败:", e),
|
|
y(!0),
|
|
N());
|
|
}),
|
|
a.on("ready", () => {
|
|
if (t) return;
|
|
let n = a.getDuration();
|
|
if ((g(n), m(!0), I(), n > 0 && _.current?.(n), !j(e)))
|
|
try {
|
|
let t = a.exportPeaks({ maxLength: 512, precision: 4 });
|
|
D(e, t, a.getDuration());
|
|
} catch {}
|
|
}),
|
|
a.on("error", (e) => {
|
|
t ||
|
|
(console.error("[AudioWavePlayer] WaveSurfer 错误:", e),
|
|
y(!0),
|
|
N());
|
|
}),
|
|
a.on("audioprocess", () => {
|
|
if (t) return;
|
|
let e = a.getCurrentTime(),
|
|
n = a.getDuration();
|
|
d(e), v(n > 0 ? (e / n) * 100 : 0);
|
|
}),
|
|
a.on("seeking", () => {
|
|
if (t) return;
|
|
let e = a.getCurrentTime(),
|
|
n = a.getDuration();
|
|
d(e), v(n > 0 ? (e / n) * 100 : 0);
|
|
}),
|
|
a.on("play", () => !t && h(!0)),
|
|
a.on("pause", () => !t && h(!1)),
|
|
a.on("finish", () => !t && h(!1)),
|
|
(l.current = a),
|
|
() => {
|
|
(t = !0),
|
|
(l.current = null),
|
|
a.destroy(),
|
|
i.pause(),
|
|
i.removeAttribute("src"),
|
|
i.load();
|
|
}
|
|
);
|
|
}, [e, r, C, s]),
|
|
(0, i.useEffect)(() => {
|
|
let e = l.current;
|
|
if (!e || !b) return;
|
|
let n = e.getCurrentTime();
|
|
e.setPlaybackRate(t), e.setTime(n);
|
|
}, [t, b]);
|
|
let R = (0, i.useCallback)(() => {
|
|
l.current && l.current.playPause();
|
|
}, []);
|
|
return (0, n.jsxs)("div", {
|
|
className: "flex h-full flex-col p-2",
|
|
children: [
|
|
(0, n.jsxs)("div", {
|
|
className:
|
|
"relative flex min-h-0 flex-1 items-center justify-center overflow-hidden",
|
|
style: {
|
|
background: s
|
|
? "var(--bg-surface-secondary, #fafafa)"
|
|
: "#363636",
|
|
borderRadius: "8px",
|
|
padding: "38px 0",
|
|
...(s
|
|
? { border: "1px solid var(--border-muted, #f5f5f5)" }
|
|
: {}),
|
|
},
|
|
children: [
|
|
(0, n.jsx)("div", { ref: c, className: "w-full px-2" }),
|
|
(0, n.jsx)("div", {
|
|
className:
|
|
"pointer-events-none absolute bottom-[3.5px] top-[3.5px] z-[100]",
|
|
style: {
|
|
left: `calc(8px + ${w}% * (100% - 16px) / 100%)`,
|
|
width: "2px",
|
|
background: "#F54848",
|
|
},
|
|
}),
|
|
A && (0, n.jsx)(M, { onRetry: P }),
|
|
!b &&
|
|
!A &&
|
|
(0, n.jsx)("div", {
|
|
className:
|
|
"absolute inset-0 flex items-center justify-center",
|
|
children: (0, n.jsx)(E.Icons.loader2, {
|
|
width: 24,
|
|
height: 24,
|
|
className: (0, k.cn)(
|
|
"animate-spin",
|
|
s ? "text-fg-muted" : "text-white/50",
|
|
),
|
|
}),
|
|
}),
|
|
],
|
|
}),
|
|
(0, n.jsxs)("div", {
|
|
className: "mt-2 flex items-center",
|
|
children: [
|
|
(0, n.jsxs)("div", {
|
|
className: (0, k.cn)(
|
|
"text-sm",
|
|
s ? "text-fg-muted" : "text-white/70",
|
|
),
|
|
children: [q(f), " / ", q(p)],
|
|
}),
|
|
(0, n.jsx)("div", {
|
|
className: "flex flex-1 justify-center",
|
|
children: (0, n.jsx)("button", {
|
|
type: "button",
|
|
onClick: R,
|
|
disabled: !b,
|
|
className: (0, k.cn)(
|
|
"flex items-center justify-center gap-0.5 transition-opacity disabled:opacity-50",
|
|
s &&
|
|
"border-canvas-controls-border bg-canvas-controls-bg text-canvas-controls-text border border-solid shadow-[0_4px_10px_rgba(0,0,0,0.08)] backdrop-blur-md",
|
|
),
|
|
style: s
|
|
? {
|
|
width: 24,
|
|
height: 24,
|
|
padding: 0,
|
|
borderRadius: "100%",
|
|
}
|
|
: {
|
|
width: 24,
|
|
height: 24,
|
|
padding: 0,
|
|
borderRadius: "100%",
|
|
border: "0.5px solid #525252",
|
|
background: "rgba(31, 31, 31, 0.9)",
|
|
boxShadow:
|
|
"0 4px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px 0 rgba(0, 0, 0, 0.2)",
|
|
backdropFilter: "blur(16px)",
|
|
color: "rgba(255, 255, 255, 0.9)",
|
|
},
|
|
children: u
|
|
? (0, n.jsx)(E.Icons.lucidePause, { width: 14, height: 14 })
|
|
: (0, n.jsx)(E.Icons.lucidePlay, { width: 14, height: 14 }),
|
|
}),
|
|
}),
|
|
(0, n.jsxs)("div", {
|
|
className: "text-sm opacity-0",
|
|
children: [q(f), " / ", q(p)],
|
|
}),
|
|
],
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
e.s(["acquireWaveSurfer", () => K, "updateAudioPoolSize", () => W], 169872),
|
|
e.s(["default", () => X], 736317);
|
|
};
|
|
|
|
export default moduleFactory;
|