PluginProbe
Gutenberg / 23.2.0
Gutenberg v23.2.0
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
gutenberg / build / modules / block-library / playlist / view.js
build/modules/block-library/playlist
view.js 49.3 KB 6 months ago view.js.map 88.1 KB 6 months ago view.min.asset.php 180 B 6 months ago view.min.js 36.9 KB 6 months ago view.min.js.map 87.4 KB 6 months ago

view.js in Gutenberg 23.2.0, at build/modules/block-library/playlist/view.js

955 lines 49.3 KB Raw Download Zip
1 // packages/block-library/build-module/playlist/view.mjs
2 import { store, getContext, getElement } from "@wordpress/interactivity";
3
4 // node_modules/colord/index.mjs
5 var r = { grad: 0.9, turn: 360, rad: 360 / (2 * Math.PI) };
6 var t = function(r2) {
7 return "string" == typeof r2 ? r2.length > 0 : "number" == typeof r2;
8 };
9 var n = function(r2, t3, n2) {
10 return void 0 === t3 && (t3 = 0), void 0 === n2 && (n2 = Math.pow(10, t3)), Math.round(n2 * r2) / n2 + 0;
11 };
12 var e = function(r2, t3, n2) {
13 return void 0 === t3 && (t3 = 0), void 0 === n2 && (n2 = 1), r2 > n2 ? n2 : r2 > t3 ? r2 : t3;
14 };
15 var u = function(r2) {
16 return (r2 = isFinite(r2) ? r2 % 360 : 0) > 0 ? r2 : r2 + 360;
17 };
18 var a = function(r2) {
19 return { r: e(r2.r, 0, 255), g: e(r2.g, 0, 255), b: e(r2.b, 0, 255), a: e(r2.a) };
20 };
21 var o = function(r2) {
22 return { r: n(r2.r), g: n(r2.g), b: n(r2.b), a: n(r2.a, 3) };
23 };
24 var i = /^#([0-9a-f]{3,8})$/i;
25 var s = function(r2) {
26 var t3 = r2.toString(16);
27 return t3.length < 2 ? "0" + t3 : t3;
28 };
29 var h = function(r2) {
30 var t3 = r2.r, n2 = r2.g, e2 = r2.b, u2 = r2.a, a2 = Math.max(t3, n2, e2), o2 = a2 - Math.min(t3, n2, e2), i2 = o2 ? a2 === t3 ? (n2 - e2) / o2 : a2 === n2 ? 2 + (e2 - t3) / o2 : 4 + (t3 - n2) / o2 : 0;
31 return { h: 60 * (i2 < 0 ? i2 + 6 : i2), s: a2 ? o2 / a2 * 100 : 0, v: a2 / 255 * 100, a: u2 };
32 };
33 var b = function(r2) {
34 var t3 = r2.h, n2 = r2.s, e2 = r2.v, u2 = r2.a;
35 t3 = t3 / 360 * 6, n2 /= 100, e2 /= 100;
36 var a2 = Math.floor(t3), o2 = e2 * (1 - n2), i2 = e2 * (1 - (t3 - a2) * n2), s2 = e2 * (1 - (1 - t3 + a2) * n2), h2 = a2 % 6;
37 return { r: 255 * [e2, i2, o2, o2, s2, e2][h2], g: 255 * [s2, e2, e2, i2, o2, o2][h2], b: 255 * [o2, o2, s2, e2, e2, i2][h2], a: u2 };
38 };
39 var g = function(r2) {
40 return { h: u(r2.h), s: e(r2.s, 0, 100), l: e(r2.l, 0, 100), a: e(r2.a) };
41 };
42 var d = function(r2) {
43 return { h: n(r2.h), s: n(r2.s), l: n(r2.l), a: n(r2.a, 3) };
44 };
45 var f = function(r2) {
46 return b((n2 = (t3 = r2).s, { h: t3.h, s: (n2 *= ((e2 = t3.l) < 50 ? e2 : 100 - e2) / 100) > 0 ? 2 * n2 / (e2 + n2) * 100 : 0, v: e2 + n2, a: t3.a }));
47 var t3, n2, e2;
48 };
49 var c = function(r2) {
50 return { h: (t3 = h(r2)).h, s: (u2 = (200 - (n2 = t3.s)) * (e2 = t3.v) / 100) > 0 && u2 < 200 ? n2 * e2 / 100 / (u2 <= 100 ? u2 : 200 - u2) * 100 : 0, l: u2 / 2, a: t3.a };
51 var t3, n2, e2, u2;
52 };
53 var l = /^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s*,\s*([+-]?\d*\.?\d+)%\s*,\s*([+-]?\d*\.?\d+)%\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i;
54 var p = /^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s+([+-]?\d*\.?\d+)%\s+([+-]?\d*\.?\d+)%\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i;
55 var v = /^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i;
56 var m = /^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i;
57 var y = { string: [[function(r2) {
58 var t3 = i.exec(r2);
59 return t3 ? (r2 = t3[1]).length <= 4 ? { r: parseInt(r2[0] + r2[0], 16), g: parseInt(r2[1] + r2[1], 16), b: parseInt(r2[2] + r2[2], 16), a: 4 === r2.length ? n(parseInt(r2[3] + r2[3], 16) / 255, 2) : 1 } : 6 === r2.length || 8 === r2.length ? { r: parseInt(r2.substr(0, 2), 16), g: parseInt(r2.substr(2, 2), 16), b: parseInt(r2.substr(4, 2), 16), a: 8 === r2.length ? n(parseInt(r2.substr(6, 2), 16) / 255, 2) : 1 } : null : null;
60 }, "hex"], [function(r2) {
61 var t3 = v.exec(r2) || m.exec(r2);
62 return t3 ? t3[2] !== t3[4] || t3[4] !== t3[6] ? null : a({ r: Number(t3[1]) / (t3[2] ? 100 / 255 : 1), g: Number(t3[3]) / (t3[4] ? 100 / 255 : 1), b: Number(t3[5]) / (t3[6] ? 100 / 255 : 1), a: void 0 === t3[7] ? 1 : Number(t3[7]) / (t3[8] ? 100 : 1) }) : null;
63 }, "rgb"], [function(t3) {
64 var n2 = l.exec(t3) || p.exec(t3);
65 if (!n2) return null;
66 var e2, u2, a2 = g({ h: (e2 = n2[1], u2 = n2[2], void 0 === u2 && (u2 = "deg"), Number(e2) * (r[u2] || 1)), s: Number(n2[3]), l: Number(n2[4]), a: void 0 === n2[5] ? 1 : Number(n2[5]) / (n2[6] ? 100 : 1) });
67 return f(a2);
68 }, "hsl"]], object: [[function(r2) {
69 var n2 = r2.r, e2 = r2.g, u2 = r2.b, o2 = r2.a, i2 = void 0 === o2 ? 1 : o2;
70 return t(n2) && t(e2) && t(u2) ? a({ r: Number(n2), g: Number(e2), b: Number(u2), a: Number(i2) }) : null;
71 }, "rgb"], [function(r2) {
72 var n2 = r2.h, e2 = r2.s, u2 = r2.l, a2 = r2.a, o2 = void 0 === a2 ? 1 : a2;
73 if (!t(n2) || !t(e2) || !t(u2)) return null;
74 var i2 = g({ h: Number(n2), s: Number(e2), l: Number(u2), a: Number(o2) });
75 return f(i2);
76 }, "hsl"], [function(r2) {
77 var n2 = r2.h, a2 = r2.s, o2 = r2.v, i2 = r2.a, s2 = void 0 === i2 ? 1 : i2;
78 if (!t(n2) || !t(a2) || !t(o2)) return null;
79 var h2 = (function(r3) {
80 return { h: u(r3.h), s: e(r3.s, 0, 100), v: e(r3.v, 0, 100), a: e(r3.a) };
81 })({ h: Number(n2), s: Number(a2), v: Number(o2), a: Number(s2) });
82 return b(h2);
83 }, "hsv"]] };
84 var N = function(r2, t3) {
85 for (var n2 = 0; n2 < t3.length; n2++) {
86 var e2 = t3[n2][0](r2);
87 if (e2) return [e2, t3[n2][1]];
88 }
89 return [null, void 0];
90 };
91 var x = function(r2) {
92 return "string" == typeof r2 ? N(r2.trim(), y.string) : "object" == typeof r2 && null !== r2 ? N(r2, y.object) : [null, void 0];
93 };
94 var M = function(r2, t3) {
95 var n2 = c(r2);
96 return { h: n2.h, s: e(n2.s + 100 * t3, 0, 100), l: n2.l, a: n2.a };
97 };
98 var H = function(r2) {
99 return (299 * r2.r + 587 * r2.g + 114 * r2.b) / 1e3 / 255;
100 };
101 var $ = function(r2, t3) {
102 var n2 = c(r2);
103 return { h: n2.h, s: n2.s, l: e(n2.l + 100 * t3, 0, 100), a: n2.a };
104 };
105 var j = (function() {
106 function r2(r3) {
107 this.parsed = x(r3)[0], this.rgba = this.parsed || { r: 0, g: 0, b: 0, a: 1 };
108 }
109 return r2.prototype.isValid = function() {
110 return null !== this.parsed;
111 }, r2.prototype.brightness = function() {
112 return n(H(this.rgba), 2);
113 }, r2.prototype.isDark = function() {
114 return H(this.rgba) < 0.5;
115 }, r2.prototype.isLight = function() {
116 return H(this.rgba) >= 0.5;
117 }, r2.prototype.toHex = function() {
118 return r3 = o(this.rgba), t3 = r3.r, e2 = r3.g, u2 = r3.b, i2 = (a2 = r3.a) < 1 ? s(n(255 * a2)) : "", "#" + s(t3) + s(e2) + s(u2) + i2;
119 var r3, t3, e2, u2, a2, i2;
120 }, r2.prototype.toRgb = function() {
121 return o(this.rgba);
122 }, r2.prototype.toRgbString = function() {
123 return r3 = o(this.rgba), t3 = r3.r, n2 = r3.g, e2 = r3.b, (u2 = r3.a) < 1 ? "rgba(" + t3 + ", " + n2 + ", " + e2 + ", " + u2 + ")" : "rgb(" + t3 + ", " + n2 + ", " + e2 + ")";
124 var r3, t3, n2, e2, u2;
125 }, r2.prototype.toHsl = function() {
126 return d(c(this.rgba));
127 }, r2.prototype.toHslString = function() {
128 return r3 = d(c(this.rgba)), t3 = r3.h, n2 = r3.s, e2 = r3.l, (u2 = r3.a) < 1 ? "hsla(" + t3 + ", " + n2 + "%, " + e2 + "%, " + u2 + ")" : "hsl(" + t3 + ", " + n2 + "%, " + e2 + "%)";
129 var r3, t3, n2, e2, u2;
130 }, r2.prototype.toHsv = function() {
131 return r3 = h(this.rgba), { h: n(r3.h), s: n(r3.s), v: n(r3.v), a: n(r3.a, 3) };
132 var r3;
133 }, r2.prototype.invert = function() {
134 return w({ r: 255 - (r3 = this.rgba).r, g: 255 - r3.g, b: 255 - r3.b, a: r3.a });
135 var r3;
136 }, r2.prototype.saturate = function(r3) {
137 return void 0 === r3 && (r3 = 0.1), w(M(this.rgba, r3));
138 }, r2.prototype.desaturate = function(r3) {
139 return void 0 === r3 && (r3 = 0.1), w(M(this.rgba, -r3));
140 }, r2.prototype.grayscale = function() {
141 return w(M(this.rgba, -1));
142 }, r2.prototype.lighten = function(r3) {
143 return void 0 === r3 && (r3 = 0.1), w($(this.rgba, r3));
144 }, r2.prototype.darken = function(r3) {
145 return void 0 === r3 && (r3 = 0.1), w($(this.rgba, -r3));
146 }, r2.prototype.rotate = function(r3) {
147 return void 0 === r3 && (r3 = 15), this.hue(this.hue() + r3);
148 }, r2.prototype.alpha = function(r3) {
149 return "number" == typeof r3 ? w({ r: (t3 = this.rgba).r, g: t3.g, b: t3.b, a: r3 }) : n(this.rgba.a, 3);
150 var t3;
151 }, r2.prototype.hue = function(r3) {
152 var t3 = c(this.rgba);
153 return "number" == typeof r3 ? w({ h: r3, s: t3.s, l: t3.l, a: t3.a }) : n(t3.h);
154 }, r2.prototype.isEqual = function(r3) {
155 return this.toHex() === w(r3).toHex();
156 }, r2;
157 })();
158 var w = function(r2) {
159 return r2 instanceof j ? r2 : new j(r2);
160 };
161
162 // packages/block-library/node_modules/@arraypress/waveform-player/dist/waveform-player.esm.js
163 function L(t3) {
164 let e2 = {};
165 if (t3.dataset.url && (e2.url = t3.dataset.url), t3.dataset.height && (e2.height = parseInt(t3.dataset.height)), t3.dataset.samples && (e2.samples = parseInt(t3.dataset.samples)), t3.dataset.preload && (e2.preload = t3.dataset.preload), t3.dataset.waveformStyle && (e2.waveformStyle = t3.dataset.waveformStyle), t3.dataset.barWidth && (e2.barWidth = parseInt(t3.dataset.barWidth)), t3.dataset.barSpacing && (e2.barSpacing = parseInt(t3.dataset.barSpacing)), t3.dataset.buttonAlign && (e2.buttonAlign = t3.dataset.buttonAlign), t3.dataset.colorPreset && (e2.colorPreset = t3.dataset.colorPreset), t3.dataset.waveformColor && (e2.waveformColor = t3.dataset.waveformColor), t3.dataset.progressColor && (e2.progressColor = t3.dataset.progressColor), t3.dataset.buttonColor && (e2.buttonColor = t3.dataset.buttonColor), t3.dataset.buttonHoverColor && (e2.buttonHoverColor = t3.dataset.buttonHoverColor), t3.dataset.textColor && (e2.textColor = t3.dataset.textColor), t3.dataset.textSecondaryColor && (e2.textSecondaryColor = t3.dataset.textSecondaryColor), t3.dataset.backgroundColor && (e2.backgroundColor = t3.dataset.backgroundColor), t3.dataset.borderColor && (e2.borderColor = t3.dataset.borderColor), t3.dataset.color && (e2.waveformColor = t3.dataset.color), t3.dataset.theme && (e2.colorPreset = t3.dataset.theme), t3.dataset.autoplay && (e2.autoplay = t3.dataset.autoplay === "true"), t3.dataset.showTime && (e2.showTime = t3.dataset.showTime === "true"), t3.dataset.showHoverTime && (e2.showHoverTime = t3.dataset.showHoverTime === "true"), t3.dataset.showBpm && (e2.showBPM = t3.dataset.showBpm === "true"), t3.dataset.singlePlay && (e2.singlePlay = t3.dataset.singlePlay === "true"), t3.dataset.playOnSeek && (e2.playOnSeek = t3.dataset.playOnSeek === "true"), t3.dataset.title && (e2.title = t3.dataset.title), t3.dataset.subtitle && (e2.subtitle = t3.dataset.subtitle), t3.dataset.album && (e2.album = t3.dataset.album), t3.dataset.artwork && (e2.artwork = t3.dataset.artwork), t3.dataset.waveform && (e2.waveform = t3.dataset.waveform), t3.dataset.markers) try {
166 e2.markers = JSON.parse(t3.dataset.markers);
167 } catch (i2) {
168 console.warn("Invalid markers JSON:", i2);
169 }
170 if (t3.dataset.playbackRate && (e2.playbackRate = parseFloat(t3.dataset.playbackRate)), t3.dataset.showPlaybackSpeed !== void 0 && (e2.showPlaybackSpeed = t3.dataset.showPlaybackSpeed === "true"), t3.dataset.playbackRates) try {
171 e2.playbackRates = JSON.parse(t3.dataset.playbackRates);
172 } catch (i2) {
173 console.warn("Invalid playbackRates JSON:", i2);
174 }
175 return t3.dataset.enableMediaSession !== void 0 && (e2.enableMediaSession = t3.dataset.enableMediaSession === "true"), e2;
176 }
177 function P(t3) {
178 if (!t3 || isNaN(t3)) return "0:00";
179 let e2 = Math.floor(t3 / 60), i2 = Math.floor(t3 % 60);
180 return `${e2}:${i2.toString().padStart(2, "0")}`;
181 }
182 function A(t3) {
183 let e2 = t3 || Math.random().toString();
184 return btoa(e2.substring(0, 10)).replace(/[^a-zA-Z0-9]/g, "");
185 }
186 function R(t3) {
187 if (!t3) return "Audio";
188 let e2 = t3.split("/");
189 return e2[e2.length - 1].split(".")[0].replace(/[-_]/g, " ").replace(/\b\w/g, (s2) => s2.toUpperCase());
190 }
191 function C(...t3) {
192 let e2 = {};
193 for (let i2 of t3) for (let a2 in i2) i2[a2] !== null && i2[a2] !== void 0 && (e2[a2] = i2[a2]);
194 return e2;
195 }
196 function B(t3, e2) {
197 let i2;
198 return function(...s2) {
199 let n2 = () => {
200 clearTimeout(i2), t3(...s2);
201 };
202 clearTimeout(i2), i2 = setTimeout(n2, e2);
203 };
204 }
205 function S(t3, e2) {
206 if (t3.length === e2) return t3;
207 if (t3.length === 0 || e2 === 0) return [];
208 let i2 = [];
209 if (e2 > t3.length) {
210 let a2 = (t3.length - 1) / (e2 - 1);
211 for (let s2 = 0; s2 < e2; s2++) {
212 let n2 = s2 * a2, r2 = Math.floor(n2), o2 = Math.ceil(n2), h2 = n2 - r2;
213 if (o2 >= t3.length) i2.push(t3[t3.length - 1]);
214 else if (r2 === o2) i2.push(t3[r2]);
215 else {
216 let l2 = t3[r2] * (1 - h2) + t3[o2] * h2;
217 i2.push(l2);
218 }
219 }
220 } else {
221 let a2 = t3.length / e2;
222 for (let s2 = 0; s2 < e2; s2++) {
223 let n2 = Math.floor(s2 * a2), r2 = Math.floor((s2 + 1) * a2), o2 = 0, h2 = 0;
224 for (let l2 = n2; l2 <= r2 && l2 < t3.length; l2++) t3[l2] > o2 && (o2 = t3[l2]), h2++;
225 if (h2 === 0) {
226 let l2 = Math.min(Math.round(s2 * a2), t3.length - 1);
227 o2 = t3[l2];
228 }
229 i2.push(o2);
230 }
231 }
232 return i2;
233 }
234 function x2(t3, e2, i2, a2, s2) {
235 let n2 = window.devicePixelRatio || 1, r2 = s2.barWidth * n2, o2 = s2.barSpacing * n2, h2 = Math.floor(e2.width / (r2 + o2)), l2 = S(i2, h2), d2 = e2.height, p2 = a2 * e2.width;
236 t3.clearRect(0, 0, e2.width, e2.height);
237 for (let y2 = 0; y2 < l2.length; y2++) {
238 let f2 = y2 * (r2 + o2);
239 if (f2 + r2 > e2.width) break;
240 let c2 = l2[y2] * d2 * 0.9, m2 = d2 - c2;
241 t3.fillStyle = s2.color, t3.fillRect(f2, m2, r2, c2);
242 }
243 t3.save(), t3.beginPath(), t3.rect(0, 0, p2, d2), t3.clip();
244 for (let y2 = 0; y2 < l2.length; y2++) {
245 let f2 = y2 * (r2 + o2);
246 if (f2 > p2) break;
247 let c2 = l2[y2] * d2 * 0.9, m2 = d2 - c2;
248 t3.fillStyle = s2.progressColor, t3.fillRect(f2, m2, r2, c2);
249 }
250 t3.restore();
251 }
252 function q(t3, e2, i2, a2, s2) {
253 let n2 = window.devicePixelRatio || 1, r2 = s2.barWidth * n2, o2 = s2.barSpacing * n2, h2 = Math.floor(e2.width / (r2 + o2)), l2 = S(i2, h2), d2 = e2.height, p2 = d2 / 2, y2 = a2 * e2.width;
254 t3.clearRect(0, 0, e2.width, e2.height);
255 for (let f2 = 0; f2 < l2.length; f2++) {
256 let c2 = f2 * (r2 + o2);
257 if (c2 + r2 > e2.width) break;
258 let m2 = l2[f2] * d2 * 0.45;
259 t3.fillStyle = s2.color, t3.fillRect(c2, p2 - m2, r2, m2), t3.fillRect(c2, p2, r2, m2);
260 }
261 t3.save(), t3.beginPath(), t3.rect(0, 0, y2, d2), t3.clip();
262 for (let f2 = 0; f2 < l2.length; f2++) {
263 let c2 = f2 * (r2 + o2);
264 if (c2 > y2) break;
265 let m2 = l2[f2] * d2 * 0.45;
266 t3.fillStyle = s2.progressColor, t3.fillRect(c2, p2 - m2, r2, m2), t3.fillRect(c2, p2, r2, m2);
267 }
268 t3.restore();
269 }
270 function $2(t3, e2, i2, a2, s2) {
271 let n2 = e2.width, r2 = e2.height, o2 = r2 / 2, h2 = r2 * 0.35;
272 t3.clearRect(0, 0, n2, r2);
273 let l2 = (d2, p2, y2 = 1, f2 = false) => {
274 f2 && (t3.shadowBlur = 12, t3.shadowColor = d2), t3.strokeStyle = d2, t3.lineWidth = p2, t3.lineCap = "round", t3.lineJoin = "round", t3.beginPath(), t3.moveTo(0, o2);
275 let c2 = [], m2 = Math.floor(i2.length * y2);
276 for (let u2 = 0; u2 < m2; u2++) {
277 let v2 = u2 / (i2.length - 1) * n2, k = i2[u2], b2 = Math.sin(u2 * 0.1) * k, w2 = o2 + b2 * h2;
278 c2.push({ x: v2, y: w2 });
279 }
280 for (let u2 = 0; u2 < c2.length - 1; u2++) {
281 let v2 = c2[u2].x + (c2[u2 + 1].x - c2[u2].x) * 0.5, k = c2[u2].y, b2 = c2[u2 + 1].x - (c2[u2 + 1].x - c2[u2].x) * 0.5, w2 = c2[u2 + 1].y;
282 t3.bezierCurveTo(v2, k, b2, w2, c2[u2 + 1].x, c2[u2 + 1].y);
283 }
284 t3.stroke(), f2 && (t3.shadowBlur = 0);
285 };
286 t3.strokeStyle = "rgba(255, 255, 255, 0.03)", t3.lineWidth = 0.5, t3.beginPath(), t3.moveTo(0, o2), t3.lineTo(n2, o2), t3.stroke();
287 for (let d2 = 0; d2 <= 10; d2++) {
288 let p2 = n2 / 10 * d2;
289 t3.beginPath(), t3.moveTo(p2, 0), t3.lineTo(p2, r2), t3.stroke();
290 }
291 l2(s2.color, 2, 1, false), a2 > 0 && l2(s2.progressColor, 3, a2, true);
292 }
293 function U(t3, e2, i2, a2, s2) {
294 let n2 = window.devicePixelRatio || 1, r2 = (s2.barWidth || 3) * n2, o2 = (s2.barSpacing || 1) * n2, h2 = Math.floor(e2.width / (r2 + o2)), l2 = S(i2, h2), d2 = e2.height, p2 = 4 * n2, y2 = 2 * n2, f2 = a2 * e2.width, c2 = d2 / 2;
295 t3.clearRect(0, 0, e2.width, e2.height);
296 for (let m2 = 0; m2 < l2.length; m2++) {
297 let u2 = m2 * (r2 + o2);
298 if (u2 + r2 > e2.width) break;
299 let v2 = l2[m2] * d2 * 0.9, k = Math.floor(v2 / (p2 + y2));
300 t3.fillStyle = u2 < f2 ? s2.progressColor : s2.color;
301 for (let b2 = 0; b2 < k; b2++) {
302 let w2 = b2 * (p2 + y2);
303 t3.fillRect(u2, c2 - w2 - p2, r2, p2), b2 > 0 && t3.fillRect(u2, c2 + w2, r2, p2);
304 }
305 }
306 }
307 function F(t3, e2, i2, a2, s2) {
308 let n2 = window.devicePixelRatio || 1, r2 = (s2.barWidth || 2) * n2, o2 = (s2.barSpacing || 3) * n2, h2 = Math.floor(e2.width / (r2 + o2)), l2 = S(i2, h2), d2 = e2.height, p2 = Math.max(1.5 * n2, r2 / 2), y2 = a2 * e2.width, f2 = d2 / 2;
309 t3.clearRect(0, 0, e2.width, e2.height);
310 for (let c2 = 0; c2 < l2.length; c2++) {
311 let m2 = c2 * (r2 + o2) + r2 / 2;
312 if (m2 > e2.width) break;
313 let u2 = l2[c2] * d2 * 0.9;
314 t3.fillStyle = m2 < y2 ? s2.progressColor : s2.color, t3.beginPath(), t3.arc(m2, f2 - u2 / 2, p2, 0, Math.PI * 2), t3.fill(), t3.beginPath(), t3.arc(m2, f2 + u2 / 2, p2, 0, Math.PI * 2), t3.fill();
315 }
316 }
317 function N2(t3, e2, i2, a2, s2) {
318 let n2 = e2.width, r2 = e2.height, o2 = r2 / 2, h2 = 4, l2 = h2 / 2;
319 if (t3.clearRect(0, 0, n2, r2), t3.fillStyle = s2.color || "rgba(255, 255, 255, 0.2)", t3.beginPath(), t3.moveTo(l2, o2 - h2 / 2), t3.lineTo(n2 - l2, o2 - h2 / 2), t3.arc(n2 - l2, o2, h2 / 2, -Math.PI / 2, Math.PI / 2), t3.lineTo(l2, o2 + h2 / 2), t3.arc(l2, o2, h2 / 2, Math.PI / 2, -Math.PI / 2), t3.closePath(), t3.fill(), a2 > 0) {
320 let d2 = Math.max(l2 * 2, a2 * n2);
321 t3.shadowBlur = 8, t3.shadowColor = s2.progressColor, t3.fillStyle = s2.progressColor || "rgba(255, 255, 255, 0.9)", t3.beginPath(), t3.moveTo(l2, o2 - h2 / 2), t3.lineTo(d2 - l2, o2 - h2 / 2), t3.arc(d2 - l2, o2, h2 / 2, -Math.PI / 2, Math.PI / 2), t3.lineTo(l2, o2 + h2 / 2), t3.arc(l2, o2, h2 / 2, Math.PI / 2, -Math.PI / 2), t3.closePath(), t3.fill(), t3.shadowBlur = 0;
322 let p2 = 8, y2 = d2;
323 t3.shadowBlur = 4, t3.shadowColor = "rgba(0, 0, 0, 0.3)", t3.shadowOffsetY = 2, t3.fillStyle = "#ffffff", t3.beginPath(), t3.arc(y2, o2, p2, 0, Math.PI * 2), t3.fill(), t3.shadowBlur = 0, t3.shadowOffsetY = 0, t3.fillStyle = s2.progressColor || "rgba(255, 255, 255, 0.9)", t3.beginPath(), t3.arc(y2, o2, p2 * 0.4, 0, Math.PI * 2), t3.fill();
324 }
325 }
326 var Y = { bars: x2, mirror: q, line: $2, blocks: U, dots: F, seekbar: N2 };
327 function W(t3, e2, i2, a2, s2) {
328 (Y[s2.waveformStyle] || x2)(t3, e2, i2, a2, s2);
329 }
330 function I(t3) {
331 try {
332 let e2 = t3.getChannelData(0), i2 = t3.sampleRate, a2 = j2(e2, i2);
333 if (a2.length < 2) return 120;
334 let s2 = [];
335 for (let h2 = 1; h2 < a2.length; h2++) s2.push((a2[h2] - a2[h2 - 1]) / i2);
336 let n2 = {};
337 s2.forEach((h2) => {
338 let l2 = 60 / h2, d2 = Math.round(l2 / 3) * 3;
339 d2 > 60 && d2 < 200 && (n2[d2] = (n2[d2] || 0) + 1);
340 });
341 let r2 = 0, o2 = 120;
342 for (let [h2, l2] of Object.entries(n2)) l2 > r2 && (r2 = l2, o2 = parseInt(h2));
343 return o2 < 70 && n2[o2 * 2] ? o2 *= 2 : o2 > 160 && n2[Math.round(o2 / 2)] && (o2 = Math.round(o2 / 2)), o2 - 1;
344 } catch (e2) {
345 return console.warn("BPM detection failed:", e2), null;
346 }
347 }
348 function j2(t3, e2) {
349 let s2 = [], n2 = 0;
350 for (let r2 = 0; r2 < t3.length - 2048; r2 += 1024) {
351 let o2 = 0;
352 for (let d2 = r2; d2 < r2 + 2048; d2++) o2 += t3[d2] * t3[d2];
353 o2 = o2 / 2048;
354 let h2 = o2 - n2, l2 = n2 * 1.8 + 0.01;
355 if (h2 > l2 && o2 > 0.01) {
356 let d2 = s2[s2.length - 1] || 0, p2 = e2 * 0.15;
357 r2 - d2 > p2 && s2.push(r2);
358 }
359 n2 = o2 * 0.8 + n2 * 0.2;
360 }
361 return s2;
362 }
363 function V(t3, e2 = 200) {
364 let i2 = t3.length / e2, a2 = ~~(i2 / 10) || 1, s2 = t3.numberOfChannels, n2 = [];
365 for (let o2 = 0; o2 < s2; o2++) {
366 let h2 = t3.getChannelData(o2);
367 for (let l2 = 0; l2 < e2; l2++) {
368 let d2 = ~~(l2 * i2), p2 = ~~(d2 + i2), y2 = 0, f2 = 0;
369 for (let m2 = d2; m2 < p2; m2 += a2) {
370 let u2 = h2[m2];
371 u2 > f2 && (f2 = u2), u2 < y2 && (y2 = u2);
372 }
373 let c2 = Math.max(Math.abs(f2), Math.abs(y2));
374 (o2 === 0 || c2 > n2[l2]) && (n2[l2] = c2);
375 }
376 }
377 let r2 = Math.max(...n2);
378 return r2 > 0 ? n2.map((o2) => o2 / r2) : n2;
379 }
380 async function M2(t3, e2 = 200, i2 = false) {
381 try {
382 let a2 = new (window.AudioContext || window.webkitAudioContext)(), n2 = await (await fetch(t3)).arrayBuffer(), r2 = await a2.decodeAudioData(n2), o2 = V(r2, e2);
383 o2 = J(o2);
384 let h2 = null;
385 return i2 && (h2 = await I(r2)), a2.close(), { peaks: o2, bpm: h2 };
386 } catch (a2) {
387 throw console.error("Failed to generate waveform:", a2), a2;
388 }
389 }
390 function D(t3 = 200) {
391 let e2 = [];
392 for (let i2 = 0; i2 < t3; i2++) {
393 let a2 = Math.random() * 0.5 + 0.3, s2 = Math.sin(i2 / t3 * Math.PI * 4) * 0.2;
394 e2.push(Math.max(0.1, Math.min(1, a2 + s2)));
395 }
396 return e2;
397 }
398 function J(t3, e2 = 0.95) {
399 let i2 = Math.max(...t3);
400 if (i2 === 0 || i2 > e2) return t3;
401 let a2 = e2 / i2;
402 return t3.map((s2) => s2 * a2);
403 }
404 function G() {
405 let t3 = document.documentElement, e2 = document.body;
406 if (t3.classList.contains("dark") || t3.classList.contains("dark-mode") || t3.classList.contains("theme-dark") || t3.getAttribute("data-theme") === "dark" || t3.getAttribute("data-color-scheme") === "dark" || e2.classList.contains("dark") || e2.classList.contains("dark-mode") || e2.getAttribute("data-theme") === "dark") return "dark";
407 if (t3.classList.contains("light") || t3.classList.contains("light-mode") || t3.classList.contains("theme-light") || t3.getAttribute("data-theme") === "light" || t3.getAttribute("data-color-scheme") === "light" || e2.classList.contains("light") || e2.classList.contains("light-mode") || e2.getAttribute("data-theme") === "light") return "light";
408 try {
409 let a2 = getComputedStyle(document.body).backgroundColor.match(/\d+/g);
410 if (a2 && a2.length >= 3) {
411 let [s2, n2, r2] = a2.map(Number), o2 = (s2 * 299 + n2 * 587 + r2 * 114) / 1e3;
412 if (o2 > 128) return "light";
413 if (o2 < 128) return "dark";
414 }
415 } catch {
416 }
417 if (window.matchMedia) {
418 if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark";
419 if (window.matchMedia("(prefers-color-scheme: light)").matches) return "light";
420 }
421 return "dark";
422 }
423 var E = { dark: { waveformColor: "rgba(255, 255, 255, 0.3)", progressColor: "rgba(255, 255, 255, 0.9)", buttonColor: "rgba(255, 255, 255, 0.9)", buttonHoverColor: "rgba(255, 255, 255, 1)", textColor: "#ffffff", textSecondaryColor: "rgba(255, 255, 255, 0.6)", backgroundColor: "rgba(255, 255, 255, 0.03)", borderColor: "rgba(255, 255, 255, 0.1)" }, light: { waveformColor: "rgba(0, 0, 0, 0.2)", progressColor: "rgba(0, 0, 0, 0.8)", buttonColor: "rgba(0, 0, 0, 0.8)", buttonHoverColor: "rgba(0, 0, 0, 0.9)", textColor: "#333333", textSecondaryColor: "rgba(0, 0, 0, 0.6)", backgroundColor: "rgba(0, 0, 0, 0.02)", borderColor: "rgba(0, 0, 0, 0.1)" } };
424 function z(t3) {
425 if (t3 && E[t3]) return E[t3];
426 let e2 = G();
427 return E[e2];
428 }
429 var O = { url: "", height: 60, samples: 200, preload: "metadata", playbackRate: 1, showPlaybackSpeed: false, playbackRates: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], buttonAlign: "auto", waveformStyle: "mirror", barWidth: 2, barSpacing: 0, colorPreset: null, waveformColor: null, progressColor: null, buttonColor: null, buttonHoverColor: null, textColor: null, textSecondaryColor: null, backgroundColor: null, borderColor: null, autoplay: false, showTime: true, showHoverTime: false, showBPM: false, singlePlay: true, playOnSeek: true, enableMediaSession: true, markers: [], showMarkers: true, title: null, subtitle: null, artwork: null, album: "", playIcon: '<svg viewBox="0 0 24 24" width="16" height="16"><path d="M8 5v14l11-7z"/></svg>', pauseIcon: '<svg viewBox="0 0 24 24" width="16" height="16"><path d="M6 4h4v16H6zM14 4h4v16h-4z"/></svg>', onLoad: null, onPlay: null, onPause: null, onEnd: null, onError: null, onTimeUpdate: null };
430 var H2 = { bars: { barWidth: 3, barSpacing: 1 }, mirror: { barWidth: 2, barSpacing: 0 }, line: { barWidth: 2, barSpacing: 0 }, blocks: { barWidth: 4, barSpacing: 2 }, dots: { barWidth: 3, barSpacing: 3 }, seekbar: { barWidth: 1, barSpacing: 0 } };
431 var g2 = class t2 {
432 static instances = /* @__PURE__ */ new Map();
433 static currentlyPlaying = null;
434 constructor(e2, i2 = {}) {
435 if (this.container = typeof e2 == "string" ? document.querySelector(e2) : e2, !this.container) throw new Error("WaveformPlayer: Container element not found");
436 let a2 = L(this.container);
437 this.options = C(O, a2, i2);
438 let s2 = z(this.options.colorPreset);
439 for (let [r2, o2] of Object.entries(s2)) (this.options[r2] === null || this.options[r2] === void 0) && (this.options[r2] = o2);
440 let n2 = H2[this.options.waveformStyle];
441 n2 && (a2.barWidth === void 0 && i2.barWidth === void 0 && (this.options.barWidth = n2.barWidth), a2.barSpacing === void 0 && i2.barSpacing === void 0 && (this.options.barSpacing = n2.barSpacing)), this.audio = null, this.canvas = null, this.ctx = null, this.waveformData = [], this.progress = 0, this.isPlaying = false, this.isLoading = false, this.hasError = false, this.updateTimer = null, this.resizeObserver = null, this.id = this.container.id || A(this.options.url), t2.instances.set(this.id, this), this.init(), setTimeout(() => {
442 this.container.dispatchEvent(new CustomEvent("waveformplayer:ready", { bubbles: true, detail: { player: this, url: this.options.url } }));
443 }, 100);
444 }
445 init() {
446 this.createDOM(), this.createAudio(), this.initPlaybackSpeed(), this.initKeyboardControls(), this.bindEvents(), this.setupResizeObserver(), requestAnimationFrame(() => {
447 this.resizeCanvas(), this.options.url && this.load(this.options.url).then(() => {
448 this.options.autoplay && this.play();
449 }).catch((e2) => {
450 console.error("Failed to load audio:", e2);
451 });
452 });
453 }
454 createDOM() {
455 this.container.innerHTML = "", this.container.className = "waveform-player";
456 let e2 = this.options.buttonAlign;
457 e2 === "auto" && (this.options.waveformStyle === "bars" ? e2 = "bottom" : e2 = "center"), this.container.innerHTML = `
458 <div class="waveform-player-inner">
459 <div class="waveform-body">
460 <div class="waveform-track waveform-align-${e2}">
461 <button class="waveform-btn" aria-label="Play/Pause" style="
462 border-color: ${this.options.buttonColor};
463 color: ${this.options.buttonColor};
464 ">
465 <span class="waveform-icon-play">${this.options.playIcon}</span>
466 <span class="waveform-icon-pause" style="display:none;">${this.options.pauseIcon}</span>
467 </button>
468
469 <div class="waveform-container">
470 <canvas></canvas>
471 <div class="waveform-markers"></div>
472 <div class="waveform-loading" style="display:none;"></div>
473 <div class="waveform-error" style="display:none;">
474 <span class="waveform-error-text">Unable to load audio</span>
475 </div>
476 </div>
477 </div>
478
479 <div class="waveform-info">
480 ${this.options.artwork ? `
481 <img class="waveform-artwork" src="${this.options.artwork}" alt="Album artwork" style="
482 width: 40px;
483 height: 40px;
484 border-radius: 4px;
485 object-fit: cover;
486 flex-shrink: 0;
487 ">
488 ` : ""}
489 <div class="waveform-text">
490 <span class="waveform-title" style="color: ${this.options.textColor};"></span>
491 ${this.options.subtitle ? `<span class="waveform-subtitle" style="color: ${this.options.textSecondaryColor};">${this.options.subtitle}</span>` : ""}
492 </div>
493 <div style="display: flex; align-items: center; gap: 1rem;">
494 ${this.options.showBPM ? `
495 <span class="waveform-bpm" style="color: ${this.options.textSecondaryColor}; display: none;">
496 <span class="bpm-value">--</span> BPM
497 </span>
498 ` : ""}
499 ${this.options.showPlaybackSpeed ? `
500 <div class="waveform-speed">
501 <button class="speed-btn" aria-label="Playback speed">
502 <span class="speed-value">1x</span>
503 </button>
504 <div class="speed-menu" style="display: none;">
505 ${this.options.playbackRates.map((i2) => `<button class="speed-option" data-rate="${i2}">${i2}x</button>`).join("")}
506 </div>
507 </div>
508 ` : ""}
509 ${this.options.showTime ? `
510 <span class="waveform-time" style="color: ${this.options.textSecondaryColor};">
511 <span class="time-current">0:00</span> / <span class="time-total">0:00</span>
512 </span>
513 ` : ""}
514 </div>
515 </div>
516 </div>
517 </div>
518 `, this.playBtn = this.container.querySelector(".waveform-btn"), this.canvas = this.container.querySelector("canvas"), this.ctx = this.canvas.getContext("2d"), this.titleEl = this.container.querySelector(".waveform-title"), this.subtitleEl = this.container.querySelector(".waveform-subtitle"), this.artworkEl = this.container.querySelector(".waveform-artwork"), this.currentTimeEl = this.container.querySelector(".time-current"), this.totalTimeEl = this.container.querySelector(".time-total"), this.bpmEl = this.container.querySelector(".waveform-bpm"), this.bpmValueEl = this.container.querySelector(".bpm-value"), this.loadingEl = this.container.querySelector(".waveform-loading"), this.errorEl = this.container.querySelector(".waveform-error"), this.markersContainer = this.container.querySelector(".waveform-markers"), this.speedBtn = this.container.querySelector(".speed-btn"), this.speedMenu = this.container.querySelector(".speed-menu"), this.resizeCanvas();
519 }
520 createAudio() {
521 this.audio = new Audio(), this.audio.preload = this.options.preload || "metadata", this.audio.crossOrigin = "anonymous";
522 }
523 initPlaybackSpeed() {
524 this.options.playbackRate && this.options.playbackRate !== 1 && (this.audio.playbackRate = this.options.playbackRate), this.options.showPlaybackSpeed && this.initSpeedControls();
525 }
526 initSpeedControls() {
527 let e2 = this.container.querySelector(".speed-btn"), i2 = this.container.querySelector(".speed-menu");
528 !e2 || !i2 || (e2.addEventListener("click", (a2) => {
529 a2.stopPropagation(), i2.style.display = i2.style.display === "none" ? "block" : "none";
530 }), document.addEventListener("click", () => {
531 i2.style.display = "none";
532 }), i2.addEventListener("click", (a2) => {
533 if (a2.stopPropagation(), a2.target.classList.contains("speed-option")) {
534 let s2 = parseFloat(a2.target.dataset.rate);
535 this.setPlaybackRate(s2), i2.style.display = "none";
536 }
537 }), this.updateSpeedUI());
538 }
539 initKeyboardControls() {
540 this.container.setAttribute("tabindex", "-1"), this.container.addEventListener("click", () => {
541 t2.getAllInstances().forEach((e2) => {
542 e2 !== this && e2.container.setAttribute("tabindex", "-1");
543 }), this.container.setAttribute("tabindex", "0"), this.container.focus();
544 }), this.container.addEventListener("keydown", (e2) => {
545 if (document.activeElement !== this.container) return;
546 let i2 = e2.key, a2 = this.audio.currentTime;
547 if (i2 >= "0" && i2 <= "9") {
548 e2.preventDefault(), this.seekToPercent(parseInt(i2) / 10);
549 return;
550 }
551 let s2 = { " ": () => this.togglePlay(), ArrowLeft: () => this.seekTo(Math.max(0, a2 - 5)), ArrowRight: () => this.seekTo(Math.min(this.audio.duration, a2 + 5)), ArrowUp: () => this.setVolume(Math.min(1, this.audio.volume + 0.1)), ArrowDown: () => this.setVolume(Math.max(0, this.audio.volume - 0.1)), m: () => this.audio.muted = !this.audio.muted, M: () => this.audio.muted = !this.audio.muted };
552 s2[i2] && (e2.preventDefault(), s2[i2]());
553 });
554 }
555 initMediaSession() {
556 !("mediaSession" in navigator) || !this.options.enableMediaSession || (navigator.mediaSession.metadata = new MediaMetadata({ title: this.options.title || "Unknown Track", artist: this.options.subtitle || "", album: this.options.album || "", artwork: this.options.artwork ? [{ src: this.options.artwork, sizes: "512x512", type: "image/jpeg" }] : [] }), navigator.mediaSession.setActionHandler("play", () => this.play()), navigator.mediaSession.setActionHandler("pause", () => this.pause()), navigator.mediaSession.setActionHandler("seekbackward", () => {
557 this.seekTo(Math.max(0, this.audio.currentTime - 10));
558 }), navigator.mediaSession.setActionHandler("seekforward", () => {
559 this.seekTo(Math.min(this.audio.duration, this.audio.currentTime + 10));
560 }), navigator.mediaSession.setActionHandler("seekto", (e2) => {
561 e2.seekTime !== null && this.seekTo(e2.seekTime);
562 }));
563 }
564 bindEvents() {
565 this.playBtn.addEventListener("click", () => this.togglePlay()), this.audio.addEventListener("loadstart", () => this.setLoading(true)), this.audio.addEventListener("loadedmetadata", () => this.onMetadataLoaded()), this.audio.addEventListener("canplay", () => this.setLoading(false)), this.audio.addEventListener("play", () => this.onPlay()), this.audio.addEventListener("pause", () => this.onPause()), this.audio.addEventListener("ended", () => this.onEnded()), this.audio.addEventListener("error", (e2) => this.onError(e2)), this.canvas.addEventListener("click", (e2) => this.handleCanvasClick(e2)), this.resizeHandler = B(() => this.resizeCanvas(), 100), window.addEventListener("resize", this.resizeHandler);
566 }
567 setupResizeObserver() {
568 "ResizeObserver" in window && (this.resizeObserver = new ResizeObserver(() => {
569 this.resizeCanvas();
570 }), this.canvas?.parentElement && this.resizeObserver.observe(this.canvas.parentElement));
571 }
572 async load(e2) {
573 try {
574 this.setLoading(true), this.progress = 0, this.hasError = false, this.audio.src = e2, await new Promise((a2, s2) => {
575 let n2 = () => {
576 this.audio.removeEventListener("loadedmetadata", n2), this.audio.removeEventListener("error", r2), a2();
577 }, r2 = (o2) => {
578 this.audio.removeEventListener("loadedmetadata", n2), this.audio.removeEventListener("error", r2), s2(o2);
579 };
580 this.audio.addEventListener("loadedmetadata", n2), this.audio.addEventListener("error", r2);
581 });
582 let i2 = this.options.title || R(e2);
583 if (this.titleEl && (this.titleEl.textContent = i2), this.options.waveform) this.setWaveformData(this.options.waveform);
584 else try {
585 let a2 = await M2(e2, this.options.samples, this.options.showBPM);
586 this.waveformData = a2.peaks, a2.bpm && (this.detectedBPM = a2.bpm, this.updateBPMDisplay());
587 } catch (a2) {
588 console.warn("Using placeholder waveform:", a2), this.waveformData = D(this.options.samples);
589 }
590 this.drawWaveform(), this.renderMarkers(), this.initMediaSession(), this.options.onLoad && this.options.onLoad(this);
591 } catch (i2) {
592 console.error("Failed to load audio:", i2), this.onError(i2);
593 } finally {
594 this.setLoading(false);
595 }
596 }
597 async loadTrack(e2, i2 = null, a2 = null, s2 = {}) {
598 this.isPlaying && this.pause(), this.audio.src = "", this.audio.load(), this.hasError = false, this.errorEl && (this.errorEl.style.display = "none"), this.canvas && (this.canvas.style.opacity = "1"), this.playBtn && (this.playBtn.disabled = false), this.progress = 0, this.waveformData = [], this.options = C(this.options, { url: e2, title: i2 || this.options.title, subtitle: a2 || this.options.subtitle, ...s2 }), s2.preload && (this.audio.preload = s2.preload), this.subtitleEl && (a2 ? (this.subtitleEl.textContent = a2, this.subtitleEl.style.display = "") : a2 === "" && (this.subtitleEl.style.display = "none")), s2.artwork && this.artworkEl && (this.artworkEl.src = s2.artwork), s2.markers && (this.options.markers = s2.markers), await this.load(e2), this.play();
599 }
600 setWaveformData(e2) {
601 if (typeof e2 == "string") try {
602 let i2 = JSON.parse(e2);
603 this.waveformData = Array.isArray(i2) ? i2 : [];
604 } catch {
605 this.waveformData = e2.split(",").map(Number);
606 }
607 else this.waveformData = Array.isArray(e2) ? e2 : [];
608 this.drawWaveform();
609 }
610 drawWaveform() {
611 !this.ctx || this.waveformData.length === 0 || W(this.ctx, this.canvas, this.waveformData, this.progress, { ...this.options, waveformStyle: this.options.waveformStyle || "bars", color: this.options.waveformColor, progressColor: this.options.progressColor });
612 }
613 resizeCanvas() {
614 if (!this.canvas || this.isDestroying) return;
615 let e2 = window.devicePixelRatio || 1, i2 = this.canvas.getBoundingClientRect();
616 this.canvas.width = i2.width * e2, this.canvas.height = this.options.height * e2, this.canvas.style.height = this.options.height + "px", this.canvas.parentElement.style.height = this.options.height + "px", this.drawWaveform();
617 }
618 renderMarkers() {
619 !this.options.showMarkers || !this.options.markers?.length || !this.markersContainer || (this.markersContainer.innerHTML = "", !(!this.audio || !this.audio.duration || this.audio.duration === 0) && this.options.markers.forEach((e2, i2) => {
620 if (e2.time > this.audio.duration) {
621 console.warn(`Marker "${e2.label}" at ${e2.time}s exceeds audio duration of ${this.audio.duration}s`);
622 return;
623 }
624 let a2 = e2.time / this.audio.duration * 100, s2 = document.createElement("button");
625 s2.className = "waveform-marker", s2.style.left = `${a2}%`, s2.style.backgroundColor = e2.color || "rgba(255, 255, 255, 0.5)", s2.setAttribute("aria-label", e2.label), s2.setAttribute("data-time", e2.time);
626 let n2 = document.createElement("span");
627 n2.className = "waveform-marker-tooltip", n2.textContent = e2.label, s2.appendChild(n2), s2.addEventListener("click", (r2) => {
628 r2.stopPropagation(), this.seekTo(e2.time), this.options.playOnSeek && !this.isPlaying && this.play();
629 }), this.markersContainer.appendChild(s2);
630 }));
631 }
632 handleCanvasClick(e2) {
633 if (!this.audio.duration) return;
634 let i2 = this.canvas.getBoundingClientRect(), a2 = e2.clientX - i2.left, s2 = Math.max(0, Math.min(1, a2 / i2.width));
635 this.seekToPercent(s2);
636 }
637 setLoading(e2) {
638 this.isLoading = e2, this.loadingEl && (this.loadingEl.style.display = e2 ? "block" : "none");
639 }
640 onMetadataLoaded() {
641 this.isDestroying || (this.totalTimeEl && (this.totalTimeEl.textContent = P(this.audio.duration)), this.renderMarkers());
642 }
643 onPlay() {
644 if (this.isDestroying) return;
645 this.isPlaying = true, this.playBtn.classList.add("playing");
646 let e2 = this.playBtn.querySelector(".waveform-icon-play"), i2 = this.playBtn.querySelector(".waveform-icon-pause");
647 e2 && (e2.style.display = "none"), i2 && (i2.style.display = "flex"), this.startSmoothUpdate(), this.container.dispatchEvent(new CustomEvent("waveformplayer:play", { bubbles: true, detail: { player: this, url: this.options.url } })), this.options.onPlay && this.options.onPlay(this);
648 }
649 onPause() {
650 if (this.isDestroying) return;
651 this.isPlaying = false, this.playBtn.classList.remove("playing");
652 let e2 = this.playBtn.querySelector(".waveform-icon-play"), i2 = this.playBtn.querySelector(".waveform-icon-pause");
653 e2 && (e2.style.display = "flex"), i2 && (i2.style.display = "none"), this.stopSmoothUpdate(), this.container.dispatchEvent(new CustomEvent("waveformplayer:pause", { bubbles: true, detail: { player: this, url: this.options.url } })), this.options.onPause && this.options.onPause(this);
654 }
655 onEnded() {
656 this.isDestroying || (this.progress = 0, this.audio.currentTime = 0, this.drawWaveform(), this.currentTimeEl && (this.currentTimeEl.textContent = "0:00"), this.container.dispatchEvent(new CustomEvent("waveformplayer:ended", { bubbles: true, detail: { player: this, url: this.options.url } })), this.onPause(), this.options.onEnd && this.options.onEnd(this));
657 }
658 onError(e2) {
659 this.isDestroying || (console.error("Audio error:", e2), this.hasError = true, this.setLoading(false), this.errorEl && (this.errorEl.style.display = "flex"), this.canvas && (this.canvas.style.opacity = "0.2"), this.playBtn && (this.playBtn.disabled = true), this.options.onError && this.options.onError(e2, this));
660 }
661 startSmoothUpdate() {
662 this.stopSmoothUpdate();
663 let e2 = () => {
664 this.isPlaying && this.audio.duration && (this.updateProgress(), this.updateTimer = requestAnimationFrame(e2));
665 };
666 this.updateTimer = requestAnimationFrame(e2);
667 }
668 stopSmoothUpdate() {
669 this.updateTimer && (cancelAnimationFrame(this.updateTimer), this.updateTimer = null);
670 }
671 updateProgress() {
672 if (!this.audio.duration) return;
673 let e2 = this.audio.currentTime / this.audio.duration;
674 Math.abs(e2 - this.progress) > 1e-3 && (this.progress = e2, this.drawWaveform()), this.currentTimeEl && (this.currentTimeEl.textContent = P(this.audio.currentTime)), this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate", { bubbles: true, detail: { player: this, currentTime: this.audio.currentTime, duration: this.audio.duration, url: this.options.url } })), this.options.onTimeUpdate && this.options.onTimeUpdate(this.audio.currentTime, this.audio.duration, this);
675 }
676 updateBPMDisplay() {
677 this.bpmEl && this.bpmValueEl && this.detectedBPM && (this.bpmValueEl.textContent = Math.round(this.detectedBPM), this.bpmEl.style.display = "inline-flex");
678 }
679 updateSpeedUI() {
680 let e2 = this.container.querySelector(".speed-value");
681 if (e2) {
682 let i2 = this.audio.playbackRate;
683 e2.textContent = i2 === 1 ? "1x" : `${i2}x`;
684 }
685 this.container.querySelectorAll(".speed-option").forEach((i2) => {
686 i2.classList.toggle("active", parseFloat(i2.dataset.rate) === this.audio.playbackRate);
687 });
688 }
689 play() {
690 this.options.singlePlay && t2.currentlyPlaying && t2.currentlyPlaying !== this && t2.currentlyPlaying.pause(), t2.currentlyPlaying = this, this.audio.play();
691 }
692 pause() {
693 t2.currentlyPlaying === this && (t2.currentlyPlaying = null), this.audio.pause();
694 }
695 togglePlay() {
696 this.isPlaying ? this.pause() : this.play();
697 }
698 seekTo(e2) {
699 this.audio && this.audio.duration && (this.audio.currentTime = Math.max(0, Math.min(e2, this.audio.duration)), this.updateProgress());
700 }
701 seekToPercent(e2) {
702 this.audio && this.audio.duration && (this.audio.currentTime = this.audio.duration * Math.max(0, Math.min(1, e2)), this.updateProgress());
703 }
704 setVolume(e2) {
705 this.audio && (this.audio.volume = Math.max(0, Math.min(1, e2)));
706 }
707 setPlaybackRate(e2) {
708 if (!this.audio) return;
709 let i2 = Math.max(0.5, Math.min(2, e2));
710 this.audio.playbackRate = i2, this.options.playbackRate = i2, this.updateSpeedUI();
711 }
712 destroy() {
713 this.isDestroying = true, this.pause(), this.stopSmoothUpdate(), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.resizeHandler && (window.removeEventListener("resize", this.resizeHandler), this.resizeHandler = null), t2.instances.delete(this.id), t2.currentlyPlaying === this && (t2.currentlyPlaying = null), this.audio && (this.audio.pause(), this.audio.src = "", this.audio.load(), this.audio = null), this.container.innerHTML = "", this.canvas = null, this.ctx = null, this.playBtn = null, this.waveformData = [];
714 }
715 static getInstance(e2) {
716 if (typeof e2 == "string") {
717 let i2 = this.instances.get(e2);
718 if (i2) return i2;
719 let a2 = document.getElementById(e2);
720 if (a2) return Array.from(this.instances.values()).find((s2) => s2.container === a2);
721 }
722 if (e2 instanceof HTMLElement) return Array.from(this.instances.values()).find((i2) => i2.container === e2);
723 }
724 static getAllInstances() {
725 return Array.from(this.instances.values());
726 }
727 static destroyAll() {
728 this.instances.forEach((e2) => e2.destroy()), this.instances.clear();
729 }
730 static async generateWaveformData(e2, i2 = 200) {
731 try {
732 return (await M2(e2, i2)).peaks;
733 } catch (a2) {
734 throw console.error("Failed to generate waveform:", a2), a2;
735 }
736 }
737 };
738 function T() {
739 if (typeof document > "u") return;
740 document.querySelectorAll("[data-waveform-player]").forEach((e2) => {
741 if (e2.dataset.waveformInitialized !== "true") try {
742 new g2(e2), e2.dataset.waveformInitialized = "true";
743 } catch (i2) {
744 console.error("Failed to initialize WaveformPlayer:", i2, e2);
745 }
746 });
747 }
748 typeof document < "u" && (document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", T) : T());
749 g2.init = T;
750 typeof window < "u" && (window.WaveformPlayer = g2);
751 var lt = g2;
752
753 // packages/block-library/build-module/utils/waveform-utils.mjs
754 var DEFAULT_WAVEFORM_HEIGHT = 100;
755 function getComputedStyle2(element) {
756 return element.ownerDocument.defaultView.getComputedStyle(element);
757 }
758 function getWaveformColors(element) {
759 const textColor = getComputedStyle2(element).color;
760 const waveformColor = w(textColor).alpha(0.3).toRgbString();
761 const progressColor = w(textColor).alpha(0.6).toRgbString();
762 return { textColor, waveformColor, progressColor };
763 }
764 function createWaveformContainer({
765 url,
766 title,
767 artist,
768 artwork,
769 waveformColor,
770 progressColor,
771 buttonColor,
772 height = DEFAULT_WAVEFORM_HEIGHT
773 }) {
774 const container = document.createElement("div");
775 container.setAttribute("data-waveform-player", "");
776 container.setAttribute("data-url", url);
777 container.setAttribute("data-height", String(height));
778 container.setAttribute("data-waveform-style", "bars");
779 container.setAttribute("data-waveform-color", waveformColor);
780 container.setAttribute("data-progress-color", progressColor);
781 container.setAttribute("data-button-color", buttonColor);
782 container.setAttribute("data-text-color", buttonColor);
783 container.setAttribute("data-text-secondary-color", buttonColor);
784 if (title) {
785 container.setAttribute("data-title", title);
786 }
787 if (artist) {
788 container.setAttribute("data-subtitle", artist);
789 }
790 if (artwork) {
791 container.setAttribute("data-artwork", artwork);
792 }
793 return container;
794 }
795 function styleSvgIcons(container, buttonColor) {
796 const isButtonDark = w(buttonColor).isDark();
797 const iconColor = isButtonDark ? "#ffffff" : "#000000";
798 const svgPaths = container.querySelectorAll("svg path");
799 svgPaths.forEach((path) => {
800 path.style.fill = iconColor;
801 });
802 }
803 function setupPlayButtonAccessibility(container, { play: playLabel = "Play", pause: pauseLabel = "Pause" } = {}) {
804 const playBtn = container.querySelector(".waveform-btn");
805 if (!playBtn) {
806 return;
807 }
808 playBtn.setAttribute("aria-label", playLabel);
809 const onPlay = () => playBtn.setAttribute("aria-label", pauseLabel);
810 const onPause = () => playBtn.setAttribute("aria-label", playLabel);
811 container.addEventListener("waveformplayer:play", onPlay);
812 container.addEventListener("waveformplayer:pause", onPause);
813 container.addEventListener("waveformplayer:ended", onPause);
814 return () => {
815 container.removeEventListener("waveformplayer:play", onPlay);
816 container.removeEventListener("waveformplayer:pause", onPause);
817 container.removeEventListener("waveformplayer:ended", onPause);
818 };
819 }
820 function logPlayError(error) {
821 if (error.name === "AbortError") {
822 return;
823 }
824 console.error("Playlist play error:", error);
825 }
826 function initWaveformPlayer(element, { src, title, artist, image, autoPlay, onEnded, labels }) {
827 const { textColor, waveformColor, progressColor } = getWaveformColors(element);
828 const container = createWaveformContainer({
829 url: src,
830 title,
831 artist,
832 artwork: image,
833 waveformColor,
834 progressColor,
835 buttonColor: textColor
836 });
837 element.appendChild(container);
838 const instance = new lt(container);
839 let cleanupAccessibility;
840 const handlers = {
841 ready: () => {
842 styleSvgIcons(container, textColor);
843 cleanupAccessibility = setupPlayButtonAccessibility(
844 container,
845 labels
846 );
847 if (autoPlay) {
848 instance.play()?.catch(logPlayError);
849 }
850 },
851 ended: () => onEnded?.()
852 };
853 container.addEventListener("waveformplayer:ready", handlers.ready);
854 container.addEventListener("waveformplayer:ended", handlers.ended);
855 return {
856 instance,
857 container,
858 destroy: () => {
859 cleanupAccessibility?.();
860 container.removeEventListener(
861 "waveformplayer:ready",
862 handlers.ready
863 );
864 container.removeEventListener(
865 "waveformplayer:ended",
866 handlers.ended
867 );
868 instance.destroy();
869 container.remove();
870 }
871 };
872 }
873
874 // packages/block-library/build-module/playlist/view.mjs
875 var playerState = /* @__PURE__ */ new WeakMap();
876 var { state } = store(
877 "core/playlist",
878 {
879 state: {
880 playlists: {},
881 get isCurrentTrack() {
882 const { currentId, uniqueId } = getContext();
883 return currentId === uniqueId;
884 }
885 },
886 actions: {
887 changeTrack() {
888 const context = getContext();
889 context.currentId = context.uniqueId;
890 }
891 },
892 callbacks: {
893 initWaveformPlayer() {
894 const context = getContext();
895 const { ref } = getElement();
896 if (!context.currentId || !ref) {
897 return;
898 }
899 const track = state.playlists[context.playlistId]?.tracks[context.currentId];
900 if (!track?.url) {
901 return;
902 }
903 const existing = playerState.get(ref);
904 if (existing?.url === track.url) {
905 return;
906 }
907 const shouldAutoPlay = !!existing?.url;
908 initPlayer(ref, track, shouldAutoPlay, context);
909 }
910 }
911 },
912 { lock: true }
913 );
914 function initPlayer(ref, track, shouldAutoPlay, context) {
915 const existing = playerState.get(ref);
916 if (existing?.instance) {
917 existing.instance.loadTrack(track.url, track.title, track.artist, {
918 artwork: track.image
919 }).then(() => {
920 existing.url = track.url;
921 if (shouldAutoPlay) {
922 existing.instance.play()?.catch(logPlayError);
923 }
924 }).catch(logPlayError);
925 return;
926 }
927 const labels = {
928 play: ref.dataset.labelPlay,
929 pause: ref.dataset.labelPause
930 };
931 const player = initWaveformPlayer(ref, {
932 src: track.url,
933 title: track.title,
934 artist: track.artist,
935 image: track.image,
936 autoPlay: shouldAutoPlay,
937 labels,
938 onEnded: () => {
939 const currentIndex = context.tracks.findIndex(
940 (uniqueId) => uniqueId === context.currentId
941 );
942 const nextTrack = context.tracks[currentIndex + 1];
943 if (nextTrack) {
944 context.currentId = nextTrack;
945 }
946 }
947 });
948 playerState.set(ref, {
949 url: track.url,
950 instance: player.instance,
951 destroy: player.destroy
952 });
953 }
954 //# sourceMappingURL=view.js.map
955