| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 // packages/block-library/build-module/playlist/view.mjs 2 import { store, getContext, getElement } from "@wordpress/interactivity"; 3 4 // node_modules/.store/colord@2.10.0-Qx66Amv6c9C3nDPQDizV6Q/node_modules/colord/index.mjs 5 for (r = { grad: 0.9, turn: 360, rad: 360 / (2 * Math.PI) }, t = function(r2) { 6 return "string" == typeof r2 ? r2.length > 0 : "number" == typeof r2; 7 }, n = function(r2, t2, n2) { 8 return void 0 === t2 && (t2 = 0), void 0 === n2 && (n2 = Math.pow(10, t2)), Math.round(n2 * r2) / n2 + 0; 9 }, u = function(r2, t2, n2) { 10 return void 0 === t2 && (t2 = 0), void 0 === n2 && (n2 = 1), r2 > n2 ? n2 : r2 > t2 ? r2 : t2; 11 }, e2 = function(r2) { 12 return (r2 = isFinite(r2) ? r2 % 360 : 0) < 0 ? r2 + 360 : r2; 13 }, o = function(r2, t2) { 14 return void 0 === t2 && (t2 = 0), n(r2, t2) % 360; 15 }, a = function(r2) { 16 return { r: u(r2.r, 0, 255), g: u(r2.g, 0, 255), b: u(r2.b, 0, 255), a: u(r2.a) }; 17 }, i = function(r2) { 18 return { r: n(r2.r), g: n(r2.g), b: n(r2.b), a: n(r2.a, 3) }; 19 }, s = /^#([0-9a-f]{3,8})$/i, d = function(r2, t2) { 20 var n2 = r2.charCodeAt(t2); 21 return (15 & n2) + 9 * (n2 >> 6); 22 }, h = function(r2, t2) { 23 return d(r2, t2) << 4 | d(r2, t2 + 1); 24 }, b = [], f = 0; f < 256; f++) b.push((f < 16 ? "0" : "") + f.toString(16)); 25 var r; 26 var t; 27 var n; 28 var u; 29 var e2; 30 var o; 31 var a; 32 var i; 33 var s; 34 var d; 35 var h; 36 var b; 37 var f; 38 var g = function(r) { 39 return b[u(r, 0, 255)]; 40 }; 41 var c = function(r) { 42 var t = r.r, n = r.g, u = r.b, e2 = r.a, o = Math.max(t, n, u), a = o - Math.min(t, n, u), i = a ? o === t ? (n - u) / a : o === n ? 2 + (u - t) / a : 4 + (t - n) / a : 0; 43 return { h: 60 * (i < 0 ? i + 6 : i), s: o ? a / o * 100 : 0, v: o / 255 * 100, a: e2 }; 44 }; 45 var v = function(r) { 46 var t = r.h, n = r.s, u = r.v, e2 = r.a; 47 t = t / 360 * 6, n /= 100, u /= 100; 48 var o = Math.floor(t), a = u * (1 - n), i = u * (1 - (t - o) * n), s = u * (1 - (1 - t + o) * n), d = o % 6; 49 return { r: 255 * [u, i, a, a, s, u][d], g: 255 * [s, u, u, i, a, a][d], b: 255 * [a, a, s, u, u, i][d], a: e2 }; 50 }; 51 var l = function(r) { 52 return { h: e2(r.h), s: u(r.s, 0, 100), l: u(r.l, 0, 100), a: u(r.a) }; 53 }; 54 var p = function(r) { 55 return { h: o(r.h), s: n(r.s), l: n(r.l), a: n(r.a, 3) }; 56 }; 57 var m = function(r) { 58 return v((n = (t = r).s, { h: t.h, s: (n *= ((u = t.l) < 50 ? u : 100 - u) / 100) > 0 ? 2 * n / (u + n) * 100 : 0, v: u + n, a: t.a })); 59 var t, n, u; 60 }; 61 var y = function(r) { 62 return { h: (t = c(r)).h, s: (e2 = (200 - (n = t.s)) * (u = t.v) / 100) > 0 && e2 < 200 ? n * u / 100 / (e2 <= 100 ? e2 : 200 - e2) * 100 : 0, l: e2 / 2, a: t.a }; 63 var t, n, u, e2; 64 }; 65 var N = /^hsla?\(\s*([+-]?(?:\d*\.\d+|\d+))(deg|rad|grad|turn)?\s*,\s*([+-]?(?:\d*\.\d+|\d+))%\s*,\s*([+-]?(?:\d*\.\d+|\d+))%\s*(?:,\s*([+-]?(?:\d*\.\d+|\d+))(%)?\s*)?\)$/i; 66 var x = /^hsla?\(\s*([+-]?(?:\d*\.\d+|\d+))(deg|rad|grad|turn)?\s+([+-]?(?:\d*\.\d+|\d+))%\s+([+-]?(?:\d*\.\d+|\d+))%\s*(?:\/\s*([+-]?(?:\d*\.\d+|\d+))(%)?\s*)?\)$/i; 67 var M = /^rgba?\(\s*([+-]?(?:\d*\.\d+|\d+))(%)?\s*,\s*([+-]?(?:\d*\.\d+|\d+))(%)?\s*,\s*([+-]?(?:\d*\.\d+|\d+))(%)?\s*(?:,\s*([+-]?(?:\d*\.\d+|\d+))(%)?\s*)?\)$/i; 68 var H = /^rgba?\(\s*([+-]?(?:\d*\.\d+|\d+))(%)?\s+([+-]?(?:\d*\.\d+|\d+))(%)?\s+([+-]?(?:\d*\.\d+|\d+))(%)?\s*(?:\/\s*([+-]?(?:\d*\.\d+|\d+))(%)?\s*)?\)$/i; 69 var $ = { string: [[function(r) { 70 if (!s.test(r)) return null; 71 var t = r.length; 72 return t <= 5 ? { r: 17 * d(r, 1), g: 17 * d(r, 2), b: 17 * d(r, 3), a: 5 === t ? n(17 * d(r, 4) / 255, 2) : 1 } : 7 === t || 9 === t ? { r: h(r, 1), g: h(r, 3), b: h(r, 5), a: 9 === t ? n(h(r, 7) / 255, 2) : 1 } : null; 73 }, "hex"], [function(r) { 74 var t = M.exec(r) || H.exec(r); 75 return t ? t[2] !== t[4] || t[4] !== t[6] ? null : a({ r: Number(t[1]) / (t[2] ? 100 / 255 : 1), g: Number(t[3]) / (t[4] ? 100 / 255 : 1), b: Number(t[5]) / (t[6] ? 100 / 255 : 1), a: void 0 === t[7] ? 1 : Number(t[7]) / (t[8] ? 100 : 1) }) : null; 76 }, "rgb"], [function(t) { 77 var n = N.exec(t) || x.exec(t); 78 if (!n) return null; 79 var u, e2, o = l({ h: (u = n[1], e2 = n[2], void 0 === e2 && (e2 = "deg"), Number(u) * (r[e2] || 1)), s: Number(n[3]), l: Number(n[4]), a: void 0 === n[5] ? 1 : Number(n[5]) / (n[6] ? 100 : 1) }); 80 return m(o); 81 }, "hsl"]], object: [[function(r) { 82 var n = r.r, u = r.g, e2 = r.b, o = r.a, i = void 0 === o ? 1 : o; 83 return t(n) && t(u) && t(e2) ? a({ r: Number(n), g: Number(u), b: Number(e2), a: Number(i) }) : null; 84 }, "rgb"], [function(r) { 85 var n = r.h, u = r.s, e2 = r.l, o = r.a, a = void 0 === o ? 1 : o; 86 if (!t(n) || !t(u) || !t(e2)) return null; 87 var i = l({ h: Number(n), s: Number(u), l: Number(e2), a: Number(a) }); 88 return m(i); 89 }, "hsl"], [function(r) { 90 var n = r.h, o = r.s, a = r.v, i = r.a, s = void 0 === i ? 1 : i; 91 if (!t(n) || !t(o) || !t(a)) return null; 92 var d = (function(r2) { 93 return { h: e2(r2.h), s: u(r2.s, 0, 100), v: u(r2.v, 0, 100), a: u(r2.a) }; 94 })({ h: Number(n), s: Number(o), v: Number(a), a: Number(s) }); 95 return v(d); 96 }, "hsv"]] }; 97 var j = function(r, t) { 98 for (var n = 0; n < t.length; n++) { 99 var u = t[n][0](r); 100 if (u) return [u, t[n][1]]; 101 } 102 return [null, void 0]; 103 }; 104 var w = function(r) { 105 return "string" == typeof r ? j(r.trim(), $.string) : "object" == typeof r && null !== r ? j(r, $.object) : [null, void 0]; 106 }; 107 var k = function(r, t) { 108 var n = y(r); 109 return { h: n.h, s: u(n.s + 100 * t, 0, 100), l: n.l, a: n.a }; 110 }; 111 var E = function(r) { 112 return (299 * r.r + 587 * r.g + 114 * r.b) / 1e3 / 255; 113 }; 114 var R = function(r, t) { 115 var n = y(r); 116 return { h: n.h, s: n.s, l: u(n.l + 100 * t, 0, 100), a: n.a }; 117 }; 118 var q = (function() { 119 function r(r2) { 120 this.parsed = w(r2)[0], this.rgba = this.parsed || { r: 0, g: 0, b: 0, a: 1 }; 121 } 122 return r.prototype.isValid = function() { 123 return null !== this.parsed; 124 }, r.prototype.brightness = function() { 125 return n(E(this.rgba), 2); 126 }, r.prototype.isDark = function() { 127 return E(this.rgba) < 0.5; 128 }, r.prototype.isLight = function() { 129 return E(this.rgba) >= 0.5; 130 }, r.prototype.toHex = function() { 131 return r2 = i(this.rgba), t = r2.r, u = r2.g, e2 = r2.b, a = (o = r2.a) < 1 ? g(n(255 * o)) : "", "#" + g(t) + g(u) + g(e2) + a; 132 var r2, t, u, e2, o, a; 133 }, r.prototype.toRgb = function() { 134 return i(this.rgba); 135 }, r.prototype.toRgbString = function() { 136 return r2 = i(this.rgba), t = r2.r, n = r2.g, u = r2.b, (e2 = r2.a) < 1 ? "rgba(" + t + ", " + n + ", " + u + ", " + e2 + ")" : "rgb(" + t + ", " + n + ", " + u + ")"; 137 var r2, t, n, u, e2; 138 }, r.prototype.toHsl = function() { 139 return p(y(this.rgba)); 140 }, r.prototype.toHslString = function() { 141 return r2 = p(y(this.rgba)), t = r2.h, n = r2.s, u = r2.l, (e2 = r2.a) < 1 ? "hsla(" + t + ", " + n + "%, " + u + "%, " + e2 + ")" : "hsl(" + t + ", " + n + "%, " + u + "%)"; 142 var r2, t, n, u, e2; 143 }, r.prototype.toHsv = function() { 144 return r2 = c(this.rgba), { h: o(r2.h), s: n(r2.s), v: n(r2.v), a: n(r2.a, 3) }; 145 var r2; 146 }, r.prototype.invert = function() { 147 return A({ r: 255 - (r2 = this.rgba).r, g: 255 - r2.g, b: 255 - r2.b, a: r2.a }); 148 var r2; 149 }, r.prototype.saturate = function(r2) { 150 return void 0 === r2 && (r2 = 0.1), A(k(this.rgba, r2)); 151 }, r.prototype.desaturate = function(r2) { 152 return void 0 === r2 && (r2 = 0.1), A(k(this.rgba, -r2)); 153 }, r.prototype.grayscale = function() { 154 return A(k(this.rgba, -1)); 155 }, r.prototype.lighten = function(r2) { 156 return void 0 === r2 && (r2 = 0.1), A(R(this.rgba, r2)); 157 }, r.prototype.darken = function(r2) { 158 return void 0 === r2 && (r2 = 0.1), A(R(this.rgba, -r2)); 159 }, r.prototype.rotate = function(r2) { 160 return void 0 === r2 && (r2 = 15), this.hue(y(this.rgba).h + r2); 161 }, r.prototype.alpha = function(r2) { 162 return "number" == typeof r2 ? A({ r: (t = this.rgba).r, g: t.g, b: t.b, a: r2 }) : n(this.rgba.a, 3); 163 var t; 164 }, r.prototype.hue = function(r2) { 165 var t = y(this.rgba); 166 return "number" == typeof r2 ? A({ h: r2, s: t.s, l: t.l, a: t.a }) : o(t.h); 167 }, r.prototype.isEqual = function(r2) { 168 return this.toHex() === A(r2).toHex(); 169 }, r; 170 })(); 171 var A = function(r) { 172 return r instanceof q ? r : new q(r); 173 }; 174 175 // node_modules/.store/@arraypress/waveform-player@1.27.0-5lSg0kJG4ah83J6WIqLUFw/node_modules/@arraypress/waveform-player/dist/waveform-player-no-autoinit.esm.js 176 function $2() { 177 return typeof window < "u" && typeof document < "u"; 178 } 179 function q2(e2) { 180 let t = -1 / 0; 181 for (let i = 0; i < e2.length; i++) e2[i] > t && (t = e2[i]); 182 return t; 183 } 184 function S(e2) { 185 return String(e2 ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); 186 } 187 function U(e2) { 188 return S(typeof e2 == "number" ? `$e2}px` : e2); 189 } 190 function it(e2) { 191 if (typeof e2 != "string" || e2 === "") return false; 192 try { 193 let t = new URL(e2, "http://localhost/"); 194 return t.protocol === "http:" || t.protocol === "https:"; 195 } catch { 196 return false; 197 } 198 } 199 function m2(e2, t = 0, i = 1) { 200 return Math.max(t, Math.min(e2, i)); 201 } 202 function _(e2, t = null, i = {}) { 203 let { min: s = -1 / 0, max: r = 1 / 0, integer: a = false } = i, o = typeof e2 == "number" ? e2 : typeof e2 == "string" && e2.trim() !== "" ? Number(e2) : NaN; 204 if (!Number.isFinite(o)) return t; 205 let n = m2(o, s, r); 206 return a ? Math.round(n) : n; 207 } 208 function H2(e2, t = null) { 209 if (Array.isArray(e2)) return e2; 210 if (typeof e2 == "string" && e2.trim().startsWith("[")) try { 211 let i = JSON.parse(e2); 212 if (Array.isArray(i)) return i; 213 } catch { 214 } 215 return t; 216 } 217 function D(e2, t = {}) { 218 let { min: i = -1 / 0, max: s = 1 / 0, fallback: r = null } = t, a = H2(e2); 219 if (!a && typeof e2 == "string" && e2.trim() !== "" && (a = e2.split(/[,\s]+/)), !a) return r; 220 let o = a.map((n) => _(n)).filter((n) => n !== null && n >= i && n <= s); 221 return o.length ? o : r; 222 } 223 function st(e2, t, i = null) { 224 return t.includes(e2) ? e2 : i; 225 } 226 function rt(e2) { 227 if (typeof e2 == "string") { 228 let t = e2.trim().toLowerCase(); 229 return t !== "" && t !== "false" && t !== "0"; 230 } 231 return !!e2; 232 } 233 function kt(e2) { 234 return e2 === void 0 ? void 0 : e2 === "true"; 235 } 236 function et(e2) { 237 if (typeof e2 == "string" && e2.trim().startsWith("[")) try { 238 return JSON.parse(e2); 239 } catch { 240 } 241 return e2; 242 } 243 function I(e2) { 244 let t = {}, i = (o, n = o) => { 245 let l2 = kt(e2.dataset[n]); 246 l2 !== void 0 && (t[o] = l2); 247 }, s = (o, n = o, l2 = false) => { 248 let h = e2.dataset[n]; 249 h && (t[o] = l2 ? parseFloat(h) : parseInt(h, 10)); 250 }, r = (o, n = o) => { 251 let l2 = e2.dataset[n]; 252 l2 && (t[o] = /^\d+(\.\d+)?$/.test(l2.trim()) ? parseFloat(l2) : l2); 253 }, a = (o, n = o) => { 254 let l2 = e2.dataset[n]; 255 if (!l2) return; 256 let h = H2(l2); 257 h ? t[o] = h : console.warn(`[WaveformPlayer] Invalid $n} attribute, expected a JSON array:`, l2); 258 }; 259 if (e2.dataset.src && (t.url = e2.dataset.src), e2.dataset.url && (t.url = e2.dataset.url), s("height"), s("samples"), e2.dataset.preload && (t.preload = e2.dataset.preload), e2.dataset.crossOrigin && (t.crossOrigin = e2.dataset.crossOrigin), e2.dataset.audioMode && (t.audioMode = e2.dataset.audioMode), e2.dataset.style && (t.waveformStyle = e2.dataset.style), e2.dataset.waveformStyle && (t.waveformStyle = e2.dataset.waveformStyle), e2.dataset.waveformGradient && (t.waveformGradient = e2.dataset.waveformGradient), s("barWidth"), s("barSpacing"), s("barRadius"), e2.dataset.buttonAlign && (t.buttonAlign = e2.dataset.buttonAlign), e2.dataset.layout && (t.layout = e2.dataset.layout), e2.dataset.buttonStyle && (t.buttonStyle = e2.dataset.buttonStyle), r("buttonSize"), r("buttonRadius"), e2.dataset.colorPreset && (t.colorPreset = e2.dataset.colorPreset), e2.dataset.waveformColor && (t.waveformColor = et(e2.dataset.waveformColor)), e2.dataset.progressColor && (t.progressColor = et(e2.dataset.progressColor)), e2.dataset.color && (t.waveformColor = e2.dataset.color), e2.dataset.theme && (t.colorPreset = e2.dataset.theme), i("autoplay"), i("showControls"), i("showInfo"), i("showTime"), i("showHoverTime"), i("seekHandle"), i("showBPM", "showBpm"), s("bpm"), i("singlePlay"), i("playOnSeek"), e2.dataset.title && (t.title = e2.dataset.title), e2.dataset.artist && (t.artist = e2.dataset.artist), e2.dataset.album && (t.album = e2.dataset.album), e2.dataset.artwork && (t.artwork = e2.dataset.artwork), e2.dataset.artworkPosition && (t.artworkPosition = e2.dataset.artworkPosition), e2.dataset.waveform && (t.waveform = e2.dataset.waveform), a("markers"), s("playbackRate", "playbackRate", true), i("showPlaybackSpeed"), e2.dataset.playbackRates) { 260 let o = D(e2.dataset.playbackRates); 261 o ? t.playbackRates = o : console.warn("[WaveformPlayer] Invalid playbackRates attribute:", e2.dataset.playbackRates); 262 } 263 return i("enableMediaSession"), i("showMarkers"), i("accessibleSeek"), e2.dataset.seekLabel && (t.seekLabel = e2.dataset.seekLabel), e2.dataset.seekValueText && (t.seekValueText = e2.dataset.seekValueText), e2.dataset.errorText && (t.errorText = e2.dataset.errorText), e2.dataset.playPauseLabel && (t.playPauseLabel = e2.dataset.playPauseLabel), e2.dataset.speedLabel && (t.speedLabel = e2.dataset.speedLabel), e2.dataset.artworkAlt && (t.artworkAlt = e2.dataset.artworkAlt), e2.dataset.unknownTrackText && (t.unknownTrackText = e2.dataset.unknownTrackText), e2.dataset.playIcon && (t.playIcon = e2.dataset.playIcon), e2.dataset.pauseIcon && (t.pauseIcon = e2.dataset.pauseIcon), t; 264 } 265 function at(e2, ...t) { 266 let i = 0; 267 return e2.replace(/%(?:(\d+)\$)?s/g, (s, r) => { 268 let a = r ? Number(r) - 1 : i++; 269 return t[a] ?? s; 270 }); 271 } 272 function E2(e2) { 273 let t = Number(e2); 274 if (!t || !Number.isFinite(t) || t < 0) return "0:00"; 275 let i = Math.floor(t / 3600), s = Math.floor(t % 3600 / 60), r = Math.floor(t % 60); 276 return i > 0 ? `$i}:$s.toString().padStart(2, "0")}:$r.toString().padStart(2, "0")}` : `$s}:$r.toString().padStart(2, "0")}`; 277 } 278 var vt = 0; 279 function ot(e2) { 280 let t = e2 || "audio", i = 5381; 281 for (let s = 0; s < t.length; s++) i = (i << 5) + i + t.charCodeAt(s) | 0; 282 return `wp_${(i >>> 0).toString(36)}_${(vt++).toString(36)}`; 283 } 284 function O(e2) { 285 if (!e2) return "Audio"; 286 let t = e2.split("/"); 287 return t[t.length - 1].split(".")[0].replace(/[-_]/g, " ").replace(/\b\w/g, (r) => r.toUpperCase()); 288 } 289 function j2(e2) { 290 if (typeof e2 != "string") return null; 291 let t = e2.match(/rgba?\(\s*([\d.]+)\s*[,\s]\s*([\d.]+)\s*[,\s]\s*([\d.]+)\s*(?:[,/]\s*([\d.]+)(%?))?/i); 292 if (!t) return null; 293 let i = Number(t[1]), s = Number(t[2]), r = Number(t[3]); 294 if (!Number.isFinite(i) || !Number.isFinite(s) || !Number.isFinite(r)) return null; 295 let a = t[4] === void 0 ? 1 : Number(t[4]); 296 return Number.isFinite(a) ? (t[5] === "%" && (a /= 100), { r: i, g: s, b: r, a: m2(a, 0, 1) }) : null; 297 } 298 function nt(e2) { 299 let t = j2(e2); 300 return !t || t.a <= 0 ? null : (t.r * 299 + t.g * 587 + t.b * 114) / 1e3; 301 } 302 function V(...e2) { 303 let t = {}; 304 for (let i of e2) for (let s in i) i[s] !== null && i[s] !== void 0 && (t[s] = i[s]); 305 return t; 306 } 307 function lt(e2, t) { 308 let i; 309 return function(...r) { 310 let a = () => { 311 clearTimeout(i), e2(...r); 312 }; 313 clearTimeout(i), i = setTimeout(a, t); 314 }; 315 } 316 function B(e2, t) { 317 if (e2.length === t) return e2; 318 if (e2.length === 0 || t === 0) return []; 319 let i = []; 320 if (t > e2.length) { 321 let s = (e2.length - 1) / (t - 1); 322 for (let r = 0; r < t; r++) { 323 let a = r * s, o = Math.floor(a), n = Math.ceil(a), l2 = a - o; 324 if (n >= e2.length) i.push(e2[e2.length - 1]); 325 else if (o === n) i.push(e2[o]); 326 else { 327 let h = e2[o] * (1 - l2) + e2[n] * l2; 328 i.push(h); 329 } 330 } 331 } else { 332 let s = e2.length / t; 333 for (let r = 0; r < t; r++) { 334 let a = Math.floor(r * s), o = Math.floor((r + 1) * s), n = 0, l2 = 0; 335 for (let h = a; h <= o && h < e2.length; h++) e2[h] > n && (n = e2[h]), l2++; 336 if (l2 === 0) { 337 let h = Math.min(Math.round(r * s), e2.length - 1); 338 n = e2[h]; 339 } 340 i.push(n); 341 } 342 } 343 return i; 344 } 345 function P(e2, t, i, s) { 346 if (!Array.isArray(t)) return t; 347 if (t.length < 2) return t[0]; 348 let r = i.width, a = i.height, o = s && s.waveformGradient, [n, l2, h, c2] = o === "horizontal" ? [0, 0, r, 0] : o === "diagonal" ? [0, 0, r, a] : [0, 0, 0, a]; 349 try { 350 let d = e2.createLinearGradient(n, l2, h, c2); 351 return t.forEach((w2, y2) => d.addColorStop(y2 / (t.length - 1), w2)), d; 352 } catch { 353 return t[0]; 354 } 355 } 356 function x2(e2, t, i, s, r, a) { 357 if ((Array.isArray(a) ? a.some((n) => n > 0) : a > 0) && typeof e2.roundRect == "function") { 358 let n = Math.min(s / 2, Math.abs(r) / 2), l2 = (h) => m2(h, 0, n); 359 e2.beginPath(), e2.roundRect(t, i, s, r, Array.isArray(a) ? a.map(l2) : l2(a)), e2.fill(); 360 } else e2.fillRect(t, i, s, r); 361 } 362 function dt(e2, t) { 363 return (e2.barRadius || 0) * t; 364 } 365 function St(e2, t) { 366 let i = dt(e2, t); 367 return [i, i, 0, 0]; 368 } 369 function ht(e2, t, i, s, r) { 370 let a = r / 2; 371 e2.beginPath(), e2.moveTo(t, s - a), e2.lineTo(i - a, s - a), e2.arc(i - a, s, a, -Math.PI / 2, Math.PI / 2), e2.lineTo(t, s + a), e2.arc(t, s, a, Math.PI / 2, -Math.PI / 2), e2.closePath(); 372 } 373 function G(e2, t, i, s, r) { 374 let a = window.devicePixelRatio || 1, o = r.barWidth * a, n = r.barSpacing * a, l2 = Math.floor(t.width / (o + n)), h = B(i, l2), c2 = t.height, d = s * t.width, w2 = St(r, a), y2 = P(e2, r.color, t, r), b = P(e2, r.progressColor, t, r); 375 e2.clearRect(0, 0, t.width, t.height), e2.fillStyle = y2; 376 for (let f = 0; f < h.length; f++) { 377 let p2 = f * (o + n); 378 if (p2 + o > t.width) break; 379 let g2 = h[f] * c2 * 0.9, u = c2 - g2; 380 x2(e2, p2, u, o, g2, w2); 381 } 382 e2.save(), e2.beginPath(), e2.rect(0, 0, d, c2), e2.clip(), e2.fillStyle = b; 383 for (let f = 0; f < h.length; f++) { 384 let p2 = f * (o + n); 385 if (p2 > d) break; 386 let g2 = h[f] * c2 * 0.9, u = c2 - g2; 387 x2(e2, p2, u, o, g2, w2); 388 } 389 e2.restore(); 390 } 391 function Et(e2, t, i, s, r) { 392 let a = window.devicePixelRatio || 1, o = r.barWidth * a, n = r.barSpacing * a, l2 = Math.floor(t.width / (o + n)), h = B(i, l2), c2 = t.height, d = c2 / 2, w2 = s * t.width, y2 = dt(r, a), b = [y2, y2, 0, 0], f = [0, 0, y2, y2], p2 = P(e2, r.color, t, r), g2 = P(e2, r.progressColor, t, r); 393 e2.clearRect(0, 0, t.width, t.height), e2.fillStyle = p2; 394 for (let u = 0; u < h.length; u++) { 395 let k2 = u * (o + n); 396 if (k2 + o > t.width) break; 397 let v2 = h[u] * c2 * 0.45; 398 x2(e2, k2, d - v2, o, v2, b), x2(e2, k2, d, o, v2, f); 399 } 400 e2.save(), e2.beginPath(), e2.rect(0, 0, w2, c2), e2.clip(), e2.fillStyle = g2; 401 for (let u = 0; u < h.length; u++) { 402 let k2 = u * (o + n); 403 if (k2 > w2) break; 404 let v2 = h[u] * c2 * 0.45; 405 x2(e2, k2, d - v2, o, v2, b), x2(e2, k2, d, o, v2, f); 406 } 407 e2.restore(); 408 } 409 function Pt(e2, t, i, s, r) { 410 let a = t.width, o = t.height, n = o / 2, l2 = o * 0.35; 411 e2.clearRect(0, 0, a, o); 412 let h = (c2, d, w2 = 1, y2 = false) => { 413 let b = P(e2, c2, t, r), f = Array.isArray(c2) ? c2[c2.length - 1] : c2; 414 y2 && (e2.shadowBlur = 12, e2.shadowColor = f), e2.strokeStyle = b, e2.lineWidth = d, e2.lineCap = "round", e2.lineJoin = "round", e2.beginPath(), e2.moveTo(0, n); 415 let p2 = [], g2 = Math.floor(i.length * w2); 416 for (let u = 0; u < g2; u++) { 417 let k2 = u / (i.length - 1) * a, v2 = i[u], A2 = Math.sin(u * 0.1) * v2, L = n + A2 * l2; 418 p2.push({ x: k2, y: L }); 419 } 420 for (let u = 0; u < p2.length - 1; u++) { 421 let k2 = p2[u].x + (p2[u + 1].x - p2[u].x) * 0.5, v2 = p2[u].y, A2 = p2[u + 1].x - (p2[u + 1].x - p2[u].x) * 0.5, L = p2[u + 1].y; 422 e2.bezierCurveTo(k2, v2, A2, L, p2[u + 1].x, p2[u + 1].y); 423 } 424 e2.stroke(), y2 && (e2.shadowBlur = 0); 425 }; 426 e2.strokeStyle = "rgba(255, 255, 255, 0.03)", e2.lineWidth = 0.5, e2.beginPath(), e2.moveTo(0, n), e2.lineTo(a, n), e2.stroke(); 427 for (let c2 = 0; c2 <= 10; c2++) { 428 let d = a / 10 * c2; 429 e2.beginPath(), e2.moveTo(d, 0), e2.lineTo(d, o), e2.stroke(); 430 } 431 h(r.color, 2, 1, false), s > 0 && h(r.progressColor, 3, s, true); 432 } 433 function ct(e2, t, i, s, r) { 434 let a = window.devicePixelRatio || 1, o = (r.barWidth || 3) * a, n = (r.barSpacing || 1) * a, l2 = Math.floor(t.width / (o + n)), h = B(i, l2), c2 = t.height, d = 4 * a, w2 = 2 * a, y2 = s * t.width, b = c2 / 2, f = P(e2, r.color, t, r), p2 = P(e2, r.progressColor, t, r); 435 e2.clearRect(0, 0, t.width, t.height); 436 for (let g2 = 0; g2 < h.length; g2++) { 437 let u = g2 * (o + n); 438 if (u + o > t.width) break; 439 let k2 = h[g2] * c2 * 0.9, v2 = Math.floor(k2 / (d + w2)); 440 e2.fillStyle = u < y2 ? p2 : f; 441 for (let A2 = 0; A2 < v2; A2++) { 442 let L = A2 * (d + w2); 443 e2.fillRect(u, b - L - d, o, d), A2 > 0 && e2.fillRect(u, b + L, o, d); 444 } 445 } 446 } 447 function ut(e2, t, i, s, r) { 448 let a = window.devicePixelRatio || 1, o = (r.barWidth || 2) * a, n = (r.barSpacing || 3) * a, l2 = Math.floor(t.width / (o + n)), h = B(i, l2), c2 = t.height, d = Math.max(1.5 * a, o / 2), w2 = s * t.width, y2 = c2 / 2, b = P(e2, r.color, t, r), f = P(e2, r.progressColor, t, r); 449 e2.clearRect(0, 0, t.width, t.height); 450 for (let p2 = 0; p2 < h.length; p2++) { 451 let g2 = p2 * (o + n) + o / 2; 452 if (g2 > t.width) break; 453 let u = h[p2] * c2 * 0.9; 454 e2.fillStyle = g2 < w2 ? f : b, e2.beginPath(), e2.arc(g2, y2 - u / 2, d, 0, Math.PI * 2), e2.fill(), e2.beginPath(), e2.arc(g2, y2 + u / 2, d, 0, Math.PI * 2), e2.fill(); 455 } 456 } 457 function Tt(e2, t, i, s, r) { 458 let a = t.width, o = t.height, n = o / 2, l2 = 4, h = l2 / 2, c2 = !!r.seekActive; 459 if (e2.clearRect(0, 0, a, o), e2.fillStyle = P(e2, r.color, t, r) || "rgba(255, 255, 255, 0.2)", ht(e2, h, a, n, l2), e2.fill(), s > 0) { 460 let d = Math.max(h * 2, s * a); 461 e2.save(), e2.globalAlpha = r.seekHandle && !c2 ? 0.7 : 1, e2.fillStyle = P(e2, r.progressColor, t, r) || "rgba(255, 255, 255, 0.9)", ht(e2, h, d, n, l2), e2.fill(), e2.restore(); 462 } 463 } 464 var At = { bars: G, bar: G, mirror: Et, line: Pt, blocks: ct, block: ct, dots: ut, dot: ut, seekbar: Tt }; 465 function pt(e2, t, i, s, r) { 466 (At[r.waveformStyle] || G)(e2, t, i, s, r); 467 } 468 function ft(e2) { 469 try { 470 let t = e2.getChannelData(0), i = e2.sampleRate, s = Mt(t, i); 471 if (s.length < 2) return 120; 472 let r = []; 473 for (let l2 = 1; l2 < s.length; l2++) r.push((s[l2] - s[l2 - 1]) / i); 474 let a = {}; 475 r.forEach((l2) => { 476 let h = 60 / l2, c2 = Math.round(h / 3) * 3; 477 c2 > 60 && c2 < 200 && (a[c2] = (a[c2] || 0) + 1); 478 }); 479 let o = 0, n = 120; 480 for (let [l2, h] of Object.entries(a)) h > o && (o = h, n = parseInt(l2)); 481 return n < 70 && a[n * 2] ? n *= 2 : n > 160 && a[Math.round(n / 2)] && (n = Math.round(n / 2)), n - 1; 482 } catch (t) { 483 return console.warn("[WaveformPlayer] BPM detection failed:", t), null; 484 } 485 } 486 function Mt(e2, t) { 487 let r = [], a = 0; 488 for (let o = 0; o < e2.length - 2048; o += 1024) { 489 let n = 0; 490 for (let c2 = o; c2 < o + 2048; c2++) n += e2[c2] * e2[c2]; 491 n = n / 2048; 492 let l2 = n - a, h = a * 1.8 + 0.01; 493 if (l2 > h && n > 0.01) { 494 let c2 = r[r.length - 1] || 0, d = t * 0.15; 495 o - c2 > d && r.push(o); 496 } 497 a = n * 0.8 + a * 0.2; 498 } 499 return r; 500 } 501 function Ct(e2, t = 1800) { 502 let i = e2.length / t, s = e2.numberOfChannels, r = []; 503 for (let o = 0; o < s; o++) { 504 let n = e2.getChannelData(o); 505 for (let l2 = 0; l2 < t; l2++) { 506 let h = ~~(l2 * i), c2 = ~~(h + i), d = 0, w2 = 0; 507 for (let b = h; b < c2; b++) { 508 let f = n[b]; 509 f > w2 && (w2 = f), f < d && (d = f); 510 } 511 let y2 = Math.max(Math.abs(w2), Math.abs(d)); 512 (o === 0 || y2 > r[l2]) && (r[l2] = y2); 513 } 514 } 515 let a = q2(r); 516 return a > 0 ? r.map((o) => o / a) : r; 517 } 518 async function K(e2, t = 1800, i = false) { 519 let s; 520 try { 521 let r = window.AudioContext || window.webkitAudioContext; 522 s = new r(); 523 let o = await (await fetch(e2)).arrayBuffer(), n = await s.decodeAudioData(o), l2 = Ct(n, t); 524 l2 = Lt(l2); 525 let h = null; 526 return i && (h = ft(n)), { peaks: l2, bpm: h }; 527 } finally { 528 s && s.close(); 529 } 530 } 531 function mt(e2 = 1800) { 532 let t = []; 533 for (let i = 0; i < e2; i++) { 534 let s = Math.random() * 0.5 + 0.3, r = Math.sin(i / e2 * Math.PI * 4) * 0.2; 535 t.push(m2(s + r, 0.1, 1)); 536 } 537 return t; 538 } 539 function Lt(e2, t = 0.95) { 540 let i = q2(e2); 541 if (i === 0 || i > t) return e2; 542 let s = t / i; 543 return e2.map((r) => r * s); 544 } 545 var Y = 128; 546 function yt(e2) { 547 let t = document.documentElement, i = document.body; 548 return t.classList.contains(e2) || t.classList.contains(`$e2}-mode`) || t.classList.contains(`theme-$e2}`) || t.getAttribute("data-theme") === e2 || t.getAttribute("data-color-scheme") === e2 || i.classList.contains(e2) || i.classList.contains(`$e2}-mode`) || i.getAttribute("data-theme") === e2; 549 } 550 function _t(e2) { 551 let t = 0, i = 0; 552 for (let s = e2; s && s.nodeType === 1 && i < 0.995; s = s.parentElement) { 553 let r = j2(getComputedStyle(s).backgroundColor); 554 if (!r || r.a <= 0) continue; 555 let a = r.a * (1 - i); 556 t += (r.r * 299 + r.g * 587 + r.b * 114) / 1e3 * a, i += a; 557 } 558 return { sum: t, alpha: i }; 559 } 560 function xt() { 561 let e2 = nt(getComputedStyle(document.body).color); 562 if (e2 !== null) return e2 > Y ? "dark" : "light"; 563 if (window.matchMedia) { 564 if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark"; 565 if (window.matchMedia("(prefers-color-scheme: light)").matches) return "light"; 566 } 567 return "dark"; 568 } 569 function R2(e2) { 570 if (yt("dark")) return "dark"; 571 if (yt("light")) return "light"; 572 try { 573 let t = e2 && e2.nodeType === 1 ? e2 : document.body, { sum: i, alpha: s } = _t(t), r = xt(), a = i + (r === "dark" ? 0 : 255) * (1 - s); 574 return a > Y ? "light" : a < Y ? "dark" : r; 575 } catch { 576 return "dark"; 577 } 578 } 579 var C = { dark: { waveformColor: "rgba(255, 255, 255, 0.3)", progressColor: "rgba(255, 255, 255, 0.9)" }, light: { waveformColor: "rgba(0, 0, 0, 0.2)", progressColor: "rgba(0, 0, 0, 0.8)" } }; 580 function X(e2, t) { 581 if (e2 && C[e2]) return C[e2]; 582 let i = R2(t); 583 return C[i]; 584 } 585 var W = { url: "", height: 64, samples: 1800, preload: "metadata", crossOrigin: null, audioMode: "self", playbackRate: 1, showPlaybackSpeed: false, playbackRates: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], buttonAlign: "auto", layout: "default", buttonStyle: "circle", buttonSize: null, buttonRadius: null, waveformStyle: "mirror", barWidth: 2, barSpacing: 0, barRadius: 1, waveformGradient: "vertical", colorPreset: null, waveformColor: null, progressColor: null, autoplay: false, showControls: true, showInfo: true, showTime: true, showHoverTime: false, seekHandle: false, showBPM: false, bpm: null, singlePlay: true, playOnSeek: true, enableMediaSession: true, markers: [], showMarkers: true, accessibleSeek: true, seekLabel: null, seekValueText: null, title: null, artist: null, artwork: null, artworkPosition: "info", album: "", errorText: "Unable to load audio", playPauseLabel: "Play/Pause", speedLabel: "Playback speed", artworkAlt: "Album artwork", unknownTrackText: "Unknown Track", 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, onNextTrack: null, onPreviousTrack: null }; 586 var Q = { bars: { barWidth: 3, barSpacing: 1 }, mirror: { barWidth: 2, barSpacing: 2 }, line: { barWidth: 2, barSpacing: 0 }, blocks: { barWidth: 4, barSpacing: 2 }, dots: { barWidth: 3, barSpacing: 3 }, seekbar: { barWidth: 1, barSpacing: 0 } }; 587 var Z = ["auto", "top", "center", "bottom"]; 588 var N2 = 0.25; 589 var F = 4; 590 var Rt = { buttonAlign: Z, layout: ["default", "preview"], buttonStyle: ["circle", "minimal"], artworkPosition: ["info", "button"], waveformStyle: Object.keys(Q), waveformGradient: ["vertical", "horizontal", "diagonal"], audioMode: ["self", "external"], preload: ["none", "metadata", "auto"], colorPreset: Object.keys(C), crossOrigin: ["anonymous", "use-credentials"] }; 591 var Dt = { height: { min: 1, integer: true }, samples: { min: 1, integer: true }, barWidth: { min: 0 }, barSpacing: { min: 0 }, barRadius: { min: 0 }, bpm: { min: 1 }, playbackRate: { min: N2, max: F } }; 592 var Bt = ["autoplay", "showControls", "showInfo", "showTime", "showHoverTime", "seekHandle", "showBPM", "singlePlay", "playOnSeek", "enableMediaSession", "showMarkers", "accessibleSeek", "showPlaybackSpeed"]; 593 var Ht = ["onLoad", "onPlay", "onPause", "onEnd", "onError", "onTimeUpdate", "onNextTrack", "onPreviousTrack"]; 594 function J(e2, t) { 595 console.warn(`[WaveformPlayer] Invalid $e2} option, using default:`, t); 596 } 597 function z(e2) { 598 let t = H2(e2); 599 return t ? t.reduce((i, s) => { 600 let r = s && typeof s == "object" ? _(s.time, null, { min: 0 }) : null; 601 return r === null ? (J("marker", s), i) : (i.push({ ...s, time: r, label: s.label == null ? "" : s.label }), i); 602 }, []) : (e2 != null && J("markers", e2), []); 603 } 604 function tt(e2) { 605 let t = (s) => e2[s] != null, i = (s) => { 606 J(s, e2[s]), e2[s] = W[s]; 607 }; 608 for (let [s, r] of Object.entries(Dt)) { 609 if (!t(s)) continue; 610 let a = _(e2[s], null, r); 611 a === null ? i(s) : e2[s] = a; 612 } 613 for (let [s, r] of Object.entries(Rt)) t(s) && st(e2[s], r) === null && i(s); 614 for (let s of Bt) e2[s] = rt(e2[s]); 615 for (let s of Ht) t(s) && typeof e2[s] != "function" && i(s); 616 if (t("playbackRates")) { 617 let s = D(e2.playbackRates, { min: N2, max: F, fallback: null }); 618 s === null ? i("playbackRates") : e2.playbackRates = s; 619 } 620 e2.markers = z(e2.markers); 621 for (let s of ["buttonSize", "buttonRadius"]) { 622 if (!t(s)) continue; 623 let r = e2[s]; 624 (typeof r == "number" ? Number.isFinite(r) : typeof r == "string" && r.trim() !== "") || i(s); 625 } 626 for (let s of ["waveformColor", "progressColor"]) { 627 if (!t(s)) continue; 628 let r = e2[s]; 629 !(typeof r == "string" && r.trim() !== "") && !Array.isArray(r) && i(s); 630 } 631 return e2; 632 } 633 var It = "data:image/svg+xml," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect width="24" height="24" rx="4" fill="#71717a" fill-opacity="0.15"/><g fill="none" stroke="#a1a1aa" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="17" r="2.2"/><circle cx="17" cy="15" r="2.2"/><path d="M10.2 17V7l9-1.6v9"/></g></svg>'); 634 var gt = 5; 635 var wt = 10; 636 var Ot = 'button, a[href], input, [role="slider"]'; 637 var T = class e { 638 static instances = /* @__PURE__ */ new Map(); 639 static currentlyPlaying = null; 640 constructor(t, i = {}) { 641 if (this.container = typeof t == "string" ? document.querySelector(t) : t, !this.container) throw new Error("[WaveformPlayer] Container element not found"); 642 let s = I(this.container), r = { ...i }; 643 r.style && !r.waveformStyle && (r.waveformStyle = r.style), r.src && !r.url && (r.url = r.src), this.options = tt(V(W, s, r)); 644 let a = X(this.options.colorPreset, this.container); 645 this._autoTheme = this.options.colorPreset == null || !C[this.options.colorPreset], this._presetKeys = [], this._scheme = this.options.colorPreset && C[this.options.colorPreset] ? this.options.colorPreset : R2(this.container); 646 for (let [n, l2] of Object.entries(a)) (this.options[n] === null || this.options[n] === void 0) && (this.options[n] = l2, this._presetKeys.push(n)); 647 let o = Q[this.options.waveformStyle]; 648 o && (s.barWidth === void 0 && i.barWidth === void 0 && (this.options.barWidth = o.barWidth), s.barSpacing === void 0 && i.barSpacing === void 0 && (this.options.barSpacing = o.barSpacing)), this.audio = null, this.canvas = null, this.ctx = null, this.waveformData = [], this.progress = 0, this._activeMarkerIndex = -1, this._markerLabelTimer = null, this.isPlaying = false, this.isLoading = false, this.hasError = false, this.updateTimer = null, this.resizeObserver = null, this._ac = new AbortController(), this.id = this.container.id || ot(this.options.url), e.instances.set(this.id, this), e._watchTheme(); 649 try { 650 this.init(); 651 } catch (n) { 652 throw e.instances.delete(this.id), this._ac.abort(), n; 653 } 654 setTimeout(() => { 655 this._emit("waveformplayer:ready", { player: this, url: this.options.url }); 656 }, 100); 657 } 658 _emit(t, i, s = false) { 659 let r = new CustomEvent(t, { bubbles: true, cancelable: s, detail: i }); 660 return this.container.dispatchEvent(r), r; 661 } 662 _requestSeek(t) { 663 this._emit("waveformplayer:request-seek", { ...this._buildTrackDetail(), percent: t }, true).defaultPrevented || (this.progress = t, this.drawWaveform?.()); 664 } 665 init() { 666 this.createDOM(), this.createAudio(), this.initPlaybackSpeed(), this.initKeyboardControls(), this.initSeekControl(), this.bindEvents(), this.setupResizeObserver(), requestAnimationFrame(() => { 667 this.resizeCanvas(), this.options.url && this.load(this.options.url).then(() => { 668 this.options.autoplay && this.play()?.catch(() => { 669 }); 670 }).catch((t) => { 671 console.error("[WaveformPlayer] Failed to load audio:", t); 672 }); 673 }); 674 } 675 createDOM() { 676 this.container.innerHTML = "", this.container.className = "waveform-player"; 677 let t = Z.includes(this.options.buttonAlign) ? this.options.buttonAlign : "auto"; 678 t === "auto" && (this.options.waveformStyle === "bars" ? t = "bottom" : t = "center"), this.options.layout === "preview" && this.container.classList.add("waveform-layout-preview"), this.container.classList.toggle("waveform-theme-light", this._scheme === "light"); 679 let s = []; 680 this.options.buttonSize != null && s.push(`--wfp-btn-size: $U(this.options.buttonSize)}`), this.options.buttonRadius != null && s.push(`--wfp-btn-radius: $U(this.options.buttonRadius)}`); 681 let r = s.length ? ` style="$s.join("; ")};"` : "", a = this.options.artworkPosition === "button" && this.options.artwork, o = a ? `<img class="waveform-btn-artwork" src="$S(this.options.artwork)}" alt="" aria-hidden="true">` : "", n = this.options.showControls ? ` 682 <button class="waveform-btn$this.options.buttonStyle === "minimal" ? " waveform-btn-minimal" : ""}$a ? " waveform-btn-has-artwork" : ""}" aria-label="$S(this.options.playPauseLabel)}"$r}> 683 $o} 684 <span class="waveform-icon-play">$this.options.playIcon}</span> 685 <span class="waveform-icon-pause" style="display:none;">$this.options.pauseIcon}</span> 686 </button> 687 ` : "", l2 = this.options.showInfo ? ` 688 <div class="waveform-info"> 689 $this.options.artworkPosition !== "button" && this.options.artwork ? ` 690 <img class="waveform-artwork" src="$S(this.options.artwork)}" alt="$S(this.options.artworkAlt)}" style=" 691 width: 40px; 692 height: 40px; 693 border-radius: 4px; 694 object-fit: cover; 695 flex-shrink: 0; 696 "> 697 ` : ""} 698 <div class="waveform-text"> 699 <span class="waveform-title"></span> 700 $this.options.artist ? `<span class="waveform-artist">$S(this.options.artist)}</span>` : ""} 701 </div> 702 <div class="waveform-meta" style="display: flex; align-items: center; gap: 1rem;"> 703 $this.options.showBPM ? ` 704 <span class="waveform-bpm" style="display: none;"> 705 <span class="bpm-value">--</span> BPM 706 </span> 707 ` : ""} 708 $this.options.showPlaybackSpeed ? ` 709 <div class="waveform-speed"> 710 <button class="speed-btn" aria-label="$S(this.options.speedLabel)}" aria-haspopup="menu" aria-expanded="false"> 711 <span class="speed-value">1x</span> 712 </button> 713 <div class="speed-menu" role="menu" aria-label="$S(this.options.speedLabel)}" style="display: none;"> 714 $this.options.playbackRates.map((h) => `<button class="speed-option" role="menuitemradio" tabindex="-1" aria-checked="false" data-rate="$h}">$h}x</button>`).join("")} 715 </div> 716 </div> 717 ` : ""} 718 $this.options.showTime ? ` 719 <span class="waveform-time"> 720 <span class="time-current">0:00</span> / <span class="time-total">0:00</span> 721 </span> 722 ` : ""} 723 </div> 724 </div> 725 ` : ""; 726 this.container.innerHTML = ` 727 <div class="waveform-player-inner"> 728 <div class="waveform-body"> 729 <div class="waveform-track waveform-align-$t}"> 730 $n} 731 732 <div class="waveform-container"> 733 <canvas></canvas> 734 <div class="waveform-markers"></div> 735 <div class="waveform-loading" style="display:none;"></div> 736 <div class="waveform-error" style="display:none;" role="alert"> 737 <span class="waveform-error-text">$S(this.options.errorText)}</span> 738 </div> 739 </div> 740 </div> 741 742 $l2} 743 </div> 744 </div> 745 `, 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.artistEl = this.container.querySelector(".waveform-artist"), this.artworkEl = this.container.querySelector(".waveform-artwork, .waveform-btn-artwork"), this.bindArtworkFallback(this.artworkEl), 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(), this.updateBPMDisplay(); 746 } 747 bindArtworkFallback(t) { 748 t && t.addEventListener("error", () => { 749 t.src.startsWith("data:") || (t.src = It); 750 }, { signal: this._ac.signal }); 751 } 752 createArtworkElement() { 753 let t = document.createElement("img"); 754 return t.className = "waveform-artwork", t.style.width = "40px", t.style.height = "40px", t.style.borderRadius = "4px", t.style.objectFit = "cover", t.style.flexShrink = "0", this.bindArtworkFallback(t), t; 755 } 756 createButtonArtworkElement() { 757 let t = document.createElement("img"); 758 return t.className = "waveform-btn-artwork", t.alt = "", t.setAttribute("aria-hidden", "true"), this.bindArtworkFallback(t), t; 759 } 760 createArtistElement() { 761 let t = document.createElement("span"); 762 return t.className = "waveform-artist", t; 763 } 764 syncArtist(t) { 765 if (this.options.artist = t || null, !!this.options.showInfo) { 766 if (!t) { 767 this.artistEl?.remove(), this.artistEl = null; 768 return; 769 } 770 if (!this.artistEl) { 771 let i = this.container.querySelector(".waveform-title"); 772 if (!i) return; 773 this.artistEl = this.createArtistElement(), i.after(this.artistEl); 774 } 775 this.artistEl.textContent = t, this.artistEl.style.display = ""; 776 } 777 } 778 syncButtonArtwork(t) { 779 if (this.playBtn) { 780 if (!t) { 781 this.artworkEl?.remove(), this.artworkEl = null, this.playBtn.classList.remove("waveform-btn-has-artwork"); 782 return; 783 } 784 this.artworkEl || (this.artworkEl = this.createButtonArtworkElement(), this.playBtn.prepend(this.artworkEl)), this.artworkEl.src = t, this.playBtn.classList.add("waveform-btn-has-artwork"); 785 } 786 } 787 syncArtwork(t, i = "") { 788 if (this.options.artwork = t || null, this.options.artworkAlt = i || "", this.options.artworkPosition === "button") { 789 this.syncButtonArtwork(this.options.artwork); 790 return; 791 } 792 if (this.options.showInfo) { 793 if (!t) { 794 this.artworkEl?.remove(), this.artworkEl = null; 795 return; 796 } 797 if (!this.artworkEl) { 798 let s = this.container.querySelector(".waveform-text"); 799 if (!s) return; 800 this.artworkEl = this.createArtworkElement(), s.before(this.artworkEl); 801 } 802 this.artworkEl.src = t, this.artworkEl.alt = i || ""; 803 } 804 } 805 createAudio() { 806 if (this.options.audioMode === "external") { 807 this.audio = null; 808 return; 809 } 810 this.audio = new Audio(), this.audio.preload = this.options.preload || "metadata", this.options.crossOrigin && (this.audio.crossOrigin = this.options.crossOrigin); 811 } 812 initPlaybackSpeed() { 813 this.audio && this.options.playbackRate && this.options.playbackRate !== 1 && (this.audio.playbackRate = this.options.playbackRate), this.options.showPlaybackSpeed && this.initSpeedControls(); 814 } 815 initSpeedControls() { 816 let t = this.container.querySelector(".speed-btn"), i = this.container.querySelector(".speed-menu"); 817 if (!t || !i) return; 818 let s = () => Array.from(i.querySelectorAll(".speed-option")), r = () => i.style.display !== "none", a = (l2) => { 819 if (i.style.display = l2 ? "block" : "none", t.setAttribute("aria-expanded", l2 ? "true" : "false"), l2) { 820 let h = s(); 821 (h.find((c2) => c2.getAttribute("aria-checked") === "true") || h[0])?.focus(); 822 } 823 }, o = (l2) => { 824 let h = s(); 825 h.length && h[(l2 + h.length) % h.length].focus(); 826 }, n = (l2) => { 827 this.setPlaybackRate(parseFloat(l2.dataset.rate)), a(false), t.focus(); 828 }; 829 t.addEventListener("click", (l2) => { 830 l2.stopPropagation(), a(!r()); 831 }, { signal: this._ac.signal }), document.addEventListener("click", () => a(false), { signal: this._ac.signal }), i.addEventListener("click", (l2) => { 832 l2.stopPropagation(); 833 let h = l2.target.closest(".speed-option"); 834 h && n(h); 835 }, { signal: this._ac.signal }), t.closest(".waveform-speed")?.addEventListener("keydown", (l2) => { 836 let h = s(), c2 = h.indexOf(document.activeElement); 837 if (!r()) { 838 (l2.key === "ArrowDown" || l2.key === "ArrowUp") && document.activeElement === t && (l2.preventDefault(), a(true)); 839 return; 840 } 841 switch (l2.key) { 842 case "ArrowDown": 843 l2.preventDefault(), o(c2 < 0 ? 0 : c2 + 1); 844 break; 845 case "ArrowUp": 846 l2.preventDefault(), o(c2 < 0 ? h.length - 1 : c2 - 1); 847 break; 848 case "Home": 849 l2.preventDefault(), o(0); 850 break; 851 case "End": 852 l2.preventDefault(), o(h.length - 1); 853 break; 854 case "Escape": 855 l2.preventDefault(), a(false), t.focus(); 856 break; 857 case "Tab": 858 a(false); 859 break; 860 } 861 }, { signal: this._ac.signal }), this.updateSpeedUI(); 862 } 863 initKeyboardControls() { 864 this.container.setAttribute("tabindex", "-1"), this.container.addEventListener("click", (t) => { 865 t.target.closest(Ot) || (e.getAllInstances().forEach((i) => { 866 i !== this && i.container.setAttribute("tabindex", "-1"); 867 }), this.container.setAttribute("tabindex", "0"), this.container.focus()); 868 }, { signal: this._ac.signal }), this.container.addEventListener("keydown", (t) => { 869 if (document.activeElement !== this.container) return; 870 let i = t.key, s = !!this.audio, r = s ? this.audio.currentTime : 0; 871 if (s && i >= "0" && i <= "9") { 872 t.preventDefault(), this.seekToPercent(parseInt(i) / 10); 873 return; 874 } 875 let a = { " ": () => this.togglePlay() }; 876 s && (a.ArrowLeft = () => this.seekTo(m2(r - 5, 0, this.audio.duration)), a.ArrowRight = () => this.seekTo(m2(r + 5, 0, this.audio.duration)), a.ArrowUp = () => this.setVolume(m2(this.audio.volume + 0.1)), a.ArrowDown = () => this.setVolume(m2(this.audio.volume - 0.1)), a.m = a.M = () => this.audio.muted = !this.audio.muted), a[i] && (t.preventDefault(), a[i]()); 877 }, { signal: this._ac.signal }); 878 } 879 initSeekControl() { 880 this.options.accessibleSeek && (this.seekEl = this.container.querySelector(".waveform-container"), this.seekEl && (this.seekEl.setAttribute("role", "slider"), this.seekEl.setAttribute("tabindex", "0"), this.seekEl.setAttribute("aria-valuemin", "0"), this.applySeekLabel(), this.updateSeekAccessibility(), this.seekEl.addEventListener("keydown", (t) => { 881 if (t.key === " " || t.key === "Spacebar") { 882 t.preventDefault(), t.stopPropagation(), this.togglePlay(); 883 return; 884 } 885 let i = this.getSeekDuration(); 886 if (!i) return; 887 let s = this.getSeekCurrentTime(), r; 888 switch (t.key) { 889 case "ArrowLeft": 890 case "ArrowDown": 891 r = s - gt; 892 break; 893 case "ArrowRight": 894 case "ArrowUp": 895 r = s + gt; 896 break; 897 case "PageDown": 898 r = s - wt; 899 break; 900 case "PageUp": 901 r = s + wt; 902 break; 903 case "Home": 904 r = 0; 905 break; 906 case "End": 907 r = i; 908 break; 909 default: 910 return; 911 } 912 t.preventDefault(), t.stopPropagation(), this.seekToSeconds(r); 913 }, { signal: this._ac.signal }))); 914 } 915 getSeekDuration() { 916 return this.options.audioMode === "external" ? this._extDuration || 0 : this.audio && Number.isFinite(this.audio.duration) ? this.audio.duration : 0; 917 } 918 getSeekCurrentTime() { 919 return this.options.audioMode === "external" ? this.progress * (this._extDuration || 0) : this.audio && Number.isFinite(this.audio.currentTime) ? this.audio.currentTime : 0; 920 } 921 seekToSeconds(t) { 922 let i = this.getSeekDuration(); 923 if (!i) return; 924 let s = m2(t, 0, i); 925 if (this.options.audioMode === "external") { 926 this._requestSeek(s / i), this.updateSeekAccessibility(); 927 return; 928 } 929 this.seekTo(s); 930 } 931 applySeekLabel(t = this.options.title) { 932 if (!this.seekEl) return; 933 let i = this.options.seekLabel || t || "Seek"; 934 this.seekEl.setAttribute("aria-label", i); 935 } 936 updateSeekAccessibility() { 937 if (!this.seekEl) return; 938 let t = this.getSeekDuration(), i = Math.min(this.getSeekCurrentTime(), t); 939 this.seekEl.setAttribute("aria-valuemax", String(Math.round(t))), this.seekEl.setAttribute("aria-valuenow", String(Math.round(i))), this.seekEl.setAttribute("aria-valuetext", at(this.options.seekValueText || "%1$s of %2$s", E2(i), E2(t))); 940 } 941 initMediaSession() { 942 if (!("mediaSession" in navigator) || !this.options.enableMediaSession || !this.audio) return; 943 this._applyMediaMetadata(), navigator.mediaSession.setActionHandler("play", () => this.play()), navigator.mediaSession.setActionHandler("pause", () => this.pause()), navigator.mediaSession.setActionHandler("seekbackward", () => { 944 this.seekTo(m2(this.audio.currentTime - 10, 0, this.audio.duration)); 945 }), navigator.mediaSession.setActionHandler("seekforward", () => { 946 this.seekTo(m2(this.audio.currentTime + 10, 0, this.audio.duration)); 947 }), navigator.mediaSession.setActionHandler("seekto", (s) => { 948 s.seekTime !== null && this.seekTo(s.seekTime); 949 }); 950 let t = this.options.onNextTrack, i = this.options.onPreviousTrack; 951 try { 952 navigator.mediaSession.setActionHandler("nexttrack", typeof t == "function" ? () => t(this) : null); 953 } catch { 954 } 955 try { 956 navigator.mediaSession.setActionHandler("previoustrack", typeof i == "function" ? () => i(this) : null); 957 } catch { 958 } 959 } 960 _applyMediaMetadata() { 961 !("mediaSession" in navigator) || !this.options.enableMediaSession || (navigator.mediaSession.metadata = new MediaMetadata({ title: this.options.title || this.options.unknownTrackText, artist: this.options.artist || "", album: this.options.album || "", artwork: this.options.artwork ? [{ src: this.options.artwork, sizes: "512x512", type: "image/jpeg" }] : [] })); 962 } 963 _updateMediaSession(t) { 964 if (!(!("mediaSession" in navigator) || !this.options.enableMediaSession || !this.audio)) try { 965 t === "playing" && this.initMediaSession(), navigator.mediaSession.playbackState = t; 966 let i = this.audio.duration; 967 navigator.mediaSession.setPositionState && i && isFinite(i) && navigator.mediaSession.setPositionState({ duration: i, playbackRate: this.audio.playbackRate || 1, position: m2(this.audio.currentTime, 0, i) }); 968 } catch { 969 } 970 } 971 bindEvents() { 972 this.playBtn && this.playBtn.addEventListener("click", () => this.togglePlay()), this.audio && (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", (i) => this.onError(i))), this.canvas.addEventListener("click", (i) => this.handleCanvasClick(i)), this._dragging = false, this._seekHover = false, this._handleNear = false, this.canvas.addEventListener("pointerenter", () => { 973 this._seekHover = true, this.drawWaveform(), this._updateSeekHandle(); 974 }), this.canvas.addEventListener("pointerleave", () => { 975 this._seekHover = false, this._handleNear = false, this._dragging || this._hideHoverTip(), this.drawWaveform(), this._updateSeekHandle(); 976 }), this.canvas.addEventListener("pointerdown", (i) => { 977 if (!(i.pointerType === "mouse" && i.button !== 0)) { 978 this._dragging = true; 979 try { 980 this.canvas.setPointerCapture(i.pointerId); 981 } catch { 982 } 983 this._scrubTo(i.clientX); 984 } 985 }), this.canvas.addEventListener("pointermove", (i) => { 986 if (this._dragging) { 987 this._scrubTo(i.clientX); 988 return; 989 } 990 let s = this.canvas.getBoundingClientRect(); 991 s.width && (this._handleNear = Math.abs(i.clientX - s.left - this.progress * s.width) <= 10, this._updateSeekHandle()); 992 }); 993 let t = (i) => { 994 if (this._dragging) { 995 this._dragging = false, this._suppressClick = true; 996 try { 997 this.canvas.releasePointerCapture(i.pointerId); 998 } catch { 999 } 1000 this._seekFromPointer(i.clientX), !this._seekHover && !this.options.showHoverTime && this._hideHoverTip(), this._updateSeekHandle(); 1001 } 1002 }; 1003 this.canvas.addEventListener("pointerup", t), this.canvas.addEventListener("pointercancel", t), this.setupHoverTime(), this.setupSeekHandle(), this.resizeHandler = lt(() => this.resizeCanvas(), 100), window.addEventListener("resize", this.resizeHandler); 1004 } 1005 setupResizeObserver() { 1006 "ResizeObserver" in window && (this.resizeObserver = new ResizeObserver(() => { 1007 this.resizeCanvas(); 1008 }), this.canvas?.parentElement && this.resizeObserver.observe(this.canvas.parentElement)); 1009 } 1010 async load(t) { 1011 try { 1012 this.setLoading(true), this.progress = 0, this.hasError = false, this.container.classList.remove("waveform-is-placeholder"); 1013 let i = !!this.options.waveform; 1014 i && this.setWaveformData(this.options.waveform); 1015 let s = this.options.title || O(t); 1016 if (this.titleEl && (this.titleEl.textContent = s), this.applySeekLabel(s), this.audio && (this.audio.src = t, this.audio.preload !== "none" && await new Promise((r, a) => { 1017 let o = () => { 1018 this.audio.removeEventListener("loadedmetadata", o), this.audio.removeEventListener("error", n), r(); 1019 }, n = (l2) => { 1020 this.audio.removeEventListener("loadedmetadata", o), this.audio.removeEventListener("error", n), a(l2); 1021 }; 1022 this.audio.addEventListener("loadedmetadata", o), this.audio.addEventListener("error", n); 1023 })), !i) try { 1024 let r = await K(t, this.options.samples, this.options.showBPM); 1025 this.waveformData = r.peaks, r.bpm && (this.detectedBPM = r.bpm, this.updateBPMDisplay()); 1026 } catch (r) { 1027 console.warn("[WaveformPlayer] Using placeholder waveform:", r), this.waveformData = mt(this.options.samples), this.container.classList.add("waveform-is-placeholder"); 1028 } 1029 this.drawWaveform(), this.renderMarkers(), this.options.onLoad && this.options.onLoad(this); 1030 } catch (i) { 1031 this.onError(i); 1032 } finally { 1033 this.setLoading(false); 1034 } 1035 } 1036 async loadTrack(t, i = null, s = null, r = {}) { 1037 let a = Object.prototype.hasOwnProperty.call(r, "artwork"), o = Object.prototype.hasOwnProperty.call(r, "artworkAlt"); 1038 this.isPlaying && this.pause(), this.audio && (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 = tt(V(this.options, { url: t, title: i === null ? this.options.title : i, artist: s === null ? this.options.artist : s, ...r })), a && (this.options.artwork = r.artwork || null), o ? this.options.artworkAlt = r.artworkAlt || "" : a && (this.options.artworkAlt = this.options.artwork ? W.artworkAlt : ""), r.preload && this.audio && (this.audio.preload = this.options.preload), r.crossOrigin && this.audio && (this.audio.crossOrigin = this.options.crossOrigin), s !== null && this.syncArtist(s), (a || o) && this.syncArtwork(a ? r.artwork : this.options.artwork, o ? r.artworkAlt : this.options.artworkAlt), this.options.markers = r.markers ? z(r.markers) : [], this.options.waveform = r.waveform || null, await this.load(t), r.autoplay !== false && this.play()?.catch(() => { 1039 }); 1040 } 1041 setWaveformData(t) { 1042 if (typeof t == "string" && t.trim().endsWith(".json")) { 1043 fetch(t.trim()).then((i) => i.json()).then((i) => { 1044 this.waveformData = Array.isArray(i) ? i : i.peaks || [], i.markers && !this.options.markers?.length && (this.options.markers = z(i.markers), this.renderMarkers()), this.drawWaveform(); 1045 }).catch(() => { 1046 }); 1047 return; 1048 } 1049 this.waveformData = D(t, { fallback: [] }), this.drawWaveform(); 1050 } 1051 drawWaveform() { 1052 !this.ctx || this.waveformData.length === 0 || pt(this.ctx, this.canvas, this.waveformData, this.progress, { ...this.options, waveformStyle: this.options.waveformStyle || "bars", color: this.options.waveformColor, progressColor: this.options.progressColor, seekActive: this._seekHover || this._dragging }); 1053 } 1054 resizeCanvas() { 1055 if (!this.canvas || this.isDestroying) return; 1056 let t = window.devicePixelRatio || 1, i = this.canvas.parentElement.getBoundingClientRect(); 1057 this.canvas.width = i.width * t, this.canvas.height = this.options.height * t, this.canvas.parentElement.style.height = this.options.height + "px", this.drawWaveform(); 1058 } 1059 renderMarkers() { 1060 if (!this.markersContainer || (this.markersContainer.innerHTML = "", this._activeMarkerIndex = -1, clearTimeout(this._markerLabelTimer), !this.options.showMarkers || !this.options.markers?.length)) return; 1061 let t = this.getSeekDuration(); 1062 t && this.options.markers.forEach((i, s) => { 1063 if (i.time > t) { 1064 console.warn(`[WaveformPlayer] Marker "$i.label}" at $i.time}s exceeds audio duration of $t}s`); 1065 return; 1066 } 1067 let r = i.time / t * 100, a = document.createElement("button"); 1068 a.className = "waveform-marker", a.style.left = `$r}%`, a.style.backgroundColor = i.color || "rgba(255, 255, 255, 0.5)", a.setAttribute("aria-label", i.label), a.setAttribute("data-time", i.time); 1069 let o = document.createElement("span"); 1070 o.className = "waveform-marker-tooltip", o.textContent = i.label, a.appendChild(o), a.addEventListener("click", (n) => { 1071 n.stopPropagation(), this.seekTo(i.time), this.options.playOnSeek && !this.isPlaying && this.play(); 1072 }), this.markersContainer.appendChild(a); 1073 }); 1074 } 1075 setActiveMarker(t) { 1076 if (!this.markersContainer) return; 1077 this.markersContainer.querySelectorAll(".waveform-marker").forEach((s, r) => s.classList.toggle("active", r === t)); 1078 } 1079 updateActiveMarker() { 1080 if (!this.markersContainer) return; 1081 let t = this.markersContainer.querySelectorAll(".waveform-marker"); 1082 if (!t.length) return; 1083 let i = this.getSeekDuration(), s = i ? this.progress * i : 0, r = -1, a = -1 / 0; 1084 t.forEach((o, n) => { 1085 let l2 = parseFloat(o.getAttribute("data-time")); 1086 Number.isFinite(l2) && l2 <= s + 0.05 && l2 > a && (a = l2, r = n); 1087 }), r !== this._activeMarkerIndex && (this._activeMarkerIndex = r, this.setActiveMarker(r), clearTimeout(this._markerLabelTimer), t.forEach((o, n) => o.classList.toggle("show-label", n === r)), r >= 0 && (this._markerLabelTimer = setTimeout(() => { 1088 this.markersContainer?.querySelectorAll(".waveform-marker").forEach((o) => o.classList.remove("show-label")); 1089 }, 2500))); 1090 } 1091 setupHoverTime() { 1092 if (!this.seekEl) return; 1093 let t = document.createElement("div"); 1094 t.className = "waveform-hover-time", t.setAttribute("aria-hidden", "true"), this.seekEl.appendChild(t), this.hoverTimeEl = t, this.options.showHoverTime && (this.seekEl.addEventListener("pointermove", (i) => { 1095 this._dragging || this._updateHoverTip(i.clientX); 1096 }), this.seekEl.addEventListener("pointerleave", () => { 1097 this._dragging || this._hideHoverTip(); 1098 })); 1099 } 1100 _updateHoverTip(t) { 1101 let i = this.hoverTimeEl; 1102 if (!i) return; 1103 let s = this.getSeekDuration(); 1104 if (!s) { 1105 i.style.opacity = "0"; 1106 return; 1107 } 1108 let r = this.canvas.getBoundingClientRect(), a = m2((t - r.left) / r.width); 1109 i.textContent = E2(a * s), i.style.left = a * 100 + "%", i.style.opacity = "1"; 1110 } 1111 _hideHoverTip() { 1112 this.hoverTimeEl && (this.hoverTimeEl.style.opacity = "0"); 1113 } 1114 _scrubTo(t) { 1115 let i = this.canvas.getBoundingClientRect(); 1116 if (!i.width) return; 1117 this.progress = m2((t - i.left) / i.width), this.drawWaveform(), this._updateSeekHandle(); 1118 let s = this.getSeekDuration(); 1119 s && this.currentTimeEl ? (this.currentTimeEl.textContent = E2(this.progress * s), this._hideHoverTip()) : this._updateHoverTip(t); 1120 } 1121 setupSeekHandle() { 1122 if (!this.options.seekHandle || this.options.waveformStyle !== "seekbar" || !this.seekEl) return; 1123 let t = document.createElement("div"); 1124 t.className = "waveform-seek-handle", t.setAttribute("aria-hidden", "true"), this.seekEl.appendChild(t), this.seekHandleEl = t; 1125 } 1126 _updateSeekHandle() { 1127 let t = this.seekHandleEl; 1128 t && (t.style.left = this.progress * 100 + "%", t.classList.toggle("is-visible", this._seekHover || this._dragging), t.classList.toggle("is-active", this._dragging || this._handleNear)); 1129 } 1130 handleCanvasClick(t) { 1131 if (this._suppressClick) { 1132 this._suppressClick = false; 1133 return; 1134 } 1135 this._seekFromPointer(t.clientX); 1136 } 1137 _seekFromPointer(t) { 1138 let i = this.canvas.getBoundingClientRect(); 1139 if (!i.width) return; 1140 let s = m2((t - i.left) / i.width); 1141 if (this.options.audioMode === "external") { 1142 this._requestSeek(s); 1143 return; 1144 } 1145 !this.audio || !this.audio.duration || this.seekToPercent(s); 1146 } 1147 setLoading(t) { 1148 if (this.isLoading = t, this.loadingEl) { 1149 let i = t && this.waveformData.length === 0; 1150 this.loadingEl.style.display = i ? "block" : "none"; 1151 } 1152 this.seekEl && this.seekEl.setAttribute("aria-busy", t ? "true" : "false"); 1153 } 1154 onMetadataLoaded() { 1155 this.isDestroying || (this.totalTimeEl && (this.totalTimeEl.textContent = E2(this.audio.duration)), this.renderMarkers(), this.updateSeekAccessibility()); 1156 } 1157 setPlayButtonState(t) { 1158 if (!this.playBtn) return; 1159 this.playBtn.classList.toggle("playing", t); 1160 let i = this.playBtn.querySelector(".waveform-icon-play"), s = this.playBtn.querySelector(".waveform-icon-pause"); 1161 i && (i.style.display = t ? "none" : "flex"), s && (s.style.display = t ? "flex" : "none"); 1162 } 1163 onPlay() { 1164 this.isDestroying || (this.isPlaying = true, this.setPlayButtonState(true), this.startSmoothUpdate(), this._updateMediaSession("playing"), this._emit("waveformplayer:play", { player: this, url: this.options.url }), this.options.onPlay && this.options.onPlay(this)); 1165 } 1166 onPause() { 1167 this.isDestroying || (this.isPlaying = false, this.setPlayButtonState(false), this.stopSmoothUpdate(), this._updateMediaSession("paused"), this._emit("waveformplayer:pause", { player: this, url: this.options.url }), this.options.onPause && this.options.onPause(this)); 1168 } 1169 onEnded() { 1170 if (this.isDestroying) return; 1171 let t = this.audio.duration; 1172 this.progress = 0, this.audio.currentTime = 0, this.drawWaveform(), this.currentTimeEl && (this.currentTimeEl.textContent = "0:00"), this._emit("waveformplayer:ended", { player: this, url: this.options.url, currentTime: t, duration: t }), this.onPause(), this.options.onEnd && this.options.onEnd(this); 1173 } 1174 onError(t) { 1175 this.isDestroying || (console.error("[WaveformPlayer] Audio error:", t), 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(t, this)); 1176 } 1177 startSmoothUpdate() { 1178 this.stopSmoothUpdate(); 1179 let t = () => { 1180 this.isPlaying && this.audio && this.audio.duration && (this.updateProgress(), this.updateTimer = requestAnimationFrame(t)); 1181 }; 1182 this.updateTimer = requestAnimationFrame(t); 1183 } 1184 stopSmoothUpdate() { 1185 this.updateTimer && (cancelAnimationFrame(this.updateTimer), this.updateTimer = null); 1186 } 1187 updateProgress() { 1188 if (!this.audio || !this.audio.duration || this._dragging) return; 1189 let t = this.audio.currentTime / this.audio.duration; 1190 Math.abs(t - this.progress) > 1e-3 && (this.progress = t, this.drawWaveform(), this._updateSeekHandle()), this.currentTimeEl && (this.currentTimeEl.textContent = E2(this.audio.currentTime)), this._emit("waveformplayer:timeupdate", { player: this, currentTime: this.audio.currentTime, duration: this.audio.duration, progress: this.progress, url: this.options.url }), this.options.onTimeUpdate && this.options.onTimeUpdate(this.audio.currentTime, this.audio.duration, this), this.updateActiveMarker(), this.updateSeekAccessibility(); 1191 } 1192 updateBPMDisplay() { 1193 let t = this.options.bpm || this.detectedBPM; 1194 this.bpmEl && this.bpmValueEl && t && (this.bpmValueEl.textContent = Math.round(t), this.bpmEl.style.display = "inline-flex"); 1195 } 1196 refreshTheme() { 1197 if (!this._autoTheme) return; 1198 this._scheme = R2(this.container); 1199 let t = X(this.options.colorPreset, this.container); 1200 for (let i of this._presetKeys || []) i in t && (this.options[i] = t[i]); 1201 this._applyThemeColors(); 1202 } 1203 _applyThemeColors() { 1204 this.container.classList.toggle("waveform-theme-light", this._scheme === "light"), this.canvas && this.drawWaveform(); 1205 } 1206 static _watchTheme() { 1207 if (e._themeWatch || typeof document > "u") return; 1208 let t = () => requestAnimationFrame(() => { 1209 e.instances.forEach((a) => { 1210 try { 1211 a.refreshTheme(); 1212 } catch { 1213 } 1214 }); 1215 }), i = { attributes: true, attributeFilter: ["class", "data-theme", "data-color-scheme", "style"] }, s = new MutationObserver(t); 1216 s.observe(document.documentElement, i), document.body && s.observe(document.body, i); 1217 let r = null; 1218 try { 1219 r = window.matchMedia("(prefers-color-scheme: dark)"), r.addEventListener("change", t); 1220 } catch { 1221 } 1222 e._themeWatch = { obs: s, mq: r, refresh: t }; 1223 } 1224 updateSpeedUI() { 1225 if (!this.audio) return; 1226 let t = this.container.querySelector(".speed-value"); 1227 if (t) { 1228 let i = this.audio.playbackRate; 1229 t.textContent = i === 1 ? "1x" : `$i}x`; 1230 } 1231 this.container.querySelectorAll(".speed-option").forEach((i) => { 1232 let s = parseFloat(i.dataset.rate) === this.audio.playbackRate; 1233 i.classList.toggle("active", s), i.setAttribute("aria-checked", s ? "true" : "false"); 1234 }); 1235 } 1236 play() { 1237 if (this.options.singlePlay && e.currentlyPlaying && e.currentlyPlaying !== this && e.currentlyPlaying.pause(), this.options.audioMode === "external") { 1238 this._emit("waveformplayer:request-play", this._buildTrackDetail(), true).defaultPrevented || (e.currentlyPlaying = this); 1239 return; 1240 } 1241 return e.currentlyPlaying = this, this.audio.play(); 1242 } 1243 pause() { 1244 if (e.currentlyPlaying === this && (e.currentlyPlaying = null), this.options.audioMode === "external") { 1245 this._emit("waveformplayer:request-pause", this._buildTrackDetail(), true); 1246 return; 1247 } 1248 this.audio.pause(); 1249 } 1250 _buildTrackDetail() { 1251 return { url: this.options.url, title: this.options.title, artist: this.options.artist, artwork: this.options.artwork, markers: this.options.markers, waveform: this.options.waveform, id: this.id, player: this }; 1252 } 1253 setPlayingState(t) { 1254 let i = this.isPlaying; 1255 this.isPlaying = !!t, this.setPlayButtonState(this.isPlaying), this.isPlaying && !i ? (this.startSmoothUpdate?.(), this._emit("waveformplayer:play", { player: this, url: this.options.url }), this.options.onPlay && this.options.onPlay(this)) : !this.isPlaying && i && (this.stopSmoothUpdate?.(), this._emit("waveformplayer:pause", { player: this, url: this.options.url }), this.options.onPause && this.options.onPause(this)); 1256 } 1257 setProgress(t, i) { 1258 !i || i <= 0 || (this.progress = m2(t / i), this.currentTimeEl && (this.currentTimeEl.textContent = E2(t)), this._extDuration = i, this.totalTimeEl && (!this.totalTimeEl.dataset._extSet || this.totalTimeEl.dataset._extDur !== String(i)) && (this.totalTimeEl.textContent = E2(i), this.totalTimeEl.dataset._extSet = "1", this.totalTimeEl.dataset._extDur = String(i)), this.drawWaveform?.(), this.updateActiveMarker(), this._emit("waveformplayer:timeupdate", { player: this, currentTime: t, duration: i, progress: this.progress, url: this.options.url }), this.options.onTimeUpdate && this.options.onTimeUpdate(t, i, this), this.progress >= 1 ? this._extEnded || (this._extEnded = true, this._emit("waveformplayer:ended", { player: this, url: this.options.url, currentTime: i, duration: i }), this.options.onEnd && this.options.onEnd(this)) : this._extEnded = false, this.updateSeekAccessibility()); 1259 } 1260 togglePlay() { 1261 this.isPlaying ? this.pause() : this.play(); 1262 } 1263 seekTo(t) { 1264 this.audio && this.audio.duration && (this.audio.currentTime = m2(t, 0, this.audio.duration), this.updateProgress()); 1265 } 1266 seekToPercent(t) { 1267 this.audio && this.audio.duration && (this.audio.currentTime = this.audio.duration * m2(t), this.updateProgress()); 1268 } 1269 setVolume(t) { 1270 let i = Number(t); 1271 this.audio && Number.isFinite(i) && (this.audio.volume = m2(i)); 1272 } 1273 setPlaybackRate(t) { 1274 if (!this.audio) return; 1275 let i = _(t, null, { min: N2, max: F }); 1276 i !== null && (this.audio.playbackRate = i, this.options.playbackRate = i, this.updateSpeedUI()); 1277 } 1278 destroy() { 1279 this.isDestroying = true, this._emit("waveformplayer:destroy", { player: this, url: this.options.url }), this.pause(), this.stopSmoothUpdate(), clearTimeout(this._markerLabelTimer), this._ac?.abort(), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.resizeHandler && (window.removeEventListener("resize", this.resizeHandler), this.resizeHandler = null), e.instances.delete(this.id), e.currentlyPlaying === this && (e.currentlyPlaying = null), this.audio && (this.audio.pause(), this.audio.src = "", this.audio.load(), this.audio = null), this.container.innerHTML = "", delete this.container.dataset.waveformInitialized, this.canvas = null, this.ctx = null, this.playBtn = null, this.waveformData = []; 1280 } 1281 static getInstance(t) { 1282 if (typeof t == "string") { 1283 let i = this.instances.get(t); 1284 if (i) return i; 1285 let s = document.getElementById(t); 1286 if (s) return Array.from(this.instances.values()).find((r) => r.container === s); 1287 } 1288 if (t instanceof HTMLElement) return Array.from(this.instances.values()).find((i) => i.container === t); 1289 } 1290 static getAllInstances() { 1291 return Array.from(this.instances.values()); 1292 } 1293 static destroyAll() { 1294 this.instances.forEach((t) => t.destroy()), this.instances.clear(); 1295 } 1296 static async generateWaveformData(t, i = 1800) { 1297 try { 1298 return (await K(t, i)).peaks; 1299 } catch (s) { 1300 throw console.error("[WaveformPlayer] Failed to generate waveform:", s), s; 1301 } 1302 } 1303 static getPeaksUrl(t) { 1304 if (!t) return; 1305 let i = t.replace(/\.(mp3|wav|ogg|flac|m4a|aac)(\?[^#]*)?(#.*)?$/i, ".json$2$3"); 1306 return i === t ? void 0 : i; 1307 } 1308 }; 1309 T.utils = { formatTime: E2, extractTitleFromUrl: O, escapeHtml: S, isSafeHref: it, parseDataAttributes: I, detectColorScheme: R2 }; 1310 function bt(e2) { 1311 if (!(e2.dataset.waveformInitialized === "true" || T.getInstance(e2))) try { 1312 new T(e2), e2.dataset.waveformInitialized = "true"; 1313 } catch (t) { 1314 console.error("[WaveformPlayer] Failed to initialize:", t, e2); 1315 } 1316 } 1317 function Wt(e2 = document) { 1318 if (!$2()) return; 1319 let t = e2 || document; 1320 t.matches?.("[data-waveform-player]") && bt(t), t.querySelectorAll("[data-waveform-player]").forEach(bt); 1321 } 1322 T.init = Wt; 1323 $2() && (window.WaveformPlayer = T); 1324 var ie = T; 1325 1326 // packages/block-library/build-module/utils/waveform-utils.mjs 1327 var DEFAULT_WAVEFORM_HEIGHT = 100; 1328 var DEFAULT_SEEK_LABEL = "Seek"; 1329 function getComputedStyle2(element) { 1330 return element.ownerDocument.defaultView.getComputedStyle(element); 1331 } 1332 function getTopLevelGradientParts(gradientValue) { 1333 const match = gradientValue?.trim().match(/^[\w-]+-gradient\((.*)\)$/i); 1334 if (!match) { 1335 return []; 1336 } 1337 const parts = []; 1338 let depth = 0; 1339 let current = ""; 1340 for (const character of match[1]) { 1341 if (character === "(") { 1342 ++depth; 1343 } else if (character === ")") { 1344 --depth; 1345 } 1346 if (character === "," && depth === 0) { 1347 parts.push(current.trim()); 1348 current = ""; 1349 continue; 1350 } 1351 current += character; 1352 } 1353 if (current.trim()) { 1354 parts.push(current.trim()); 1355 } 1356 return parts; 1357 } 1358 function getLeadingColorFunction(value) { 1359 const match = value.match(/^([\w-]+)\(/); 1360 if (!match) { 1361 return; 1362 } 1363 const supportedFunctions = [ 1364 "color", 1365 "color-mix", 1366 "hsl", 1367 "hsla", 1368 "hwb", 1369 "lab", 1370 "lch", 1371 "oklab", 1372 "oklch", 1373 "rgb", 1374 "rgba", 1375 "var" 1376 ]; 1377 if (!supportedFunctions.includes(match[1].toLowerCase())) { 1378 return; 1379 } 1380 let depth = 0; 1381 let foundOpeningParenthesis = false; 1382 for (let index = 0; index < value.length; index++) { 1383 const character = value[index]; 1384 if (character === "(") { 1385 foundOpeningParenthesis = true; 1386 ++depth; 1387 } else if (character === ")") { 1388 --depth; 1389 } 1390 if (foundOpeningParenthesis && depth === 0) { 1391 return value.slice(0, index + 1); 1392 } 1393 } 1394 } 1395 function getColorStopValue(gradientPart) { 1396 const colorFunction = getLeadingColorFunction(gradientPart); 1397 if (colorFunction) { 1398 return colorFunction; 1399 } 1400 const [possibleColor] = gradientPart.split(/\s+/); 1401 if (A(possibleColor).isValid()) { 1402 return possibleColor; 1403 } 1404 } 1405 function getWaveformGradientDirection(gradientValue) { 1406 const parts = getTopLevelGradientParts(gradientValue); 1407 const direction = parts[0]; 1408 const angleMatch = direction?.match(/^(-?\d+(?:\.\d+)?)deg$/i); 1409 if (angleMatch) { 1410 const angle = (Number(angleMatch[1]) % 360 + 360) % 360; 1411 if (angle === 90 || angle === 270) { 1412 return "horizontal"; 1413 } 1414 if (angle === 0 || angle === 180) { 1415 return "vertical"; 1416 } 1417 return "diagonal"; 1418 } 1419 if (!direction?.startsWith("to ")) { 1420 return void 0; 1421 } 1422 const sideOrCorner = direction.toLowerCase().replace(/^to\s+/, ""); 1423 const hasHorizontalSide = sideOrCorner.includes("left") || sideOrCorner.includes("right"); 1424 const hasVerticalSide = sideOrCorner.includes("top") || sideOrCorner.includes("bottom"); 1425 if (hasHorizontalSide && hasVerticalSide) { 1426 return "diagonal"; 1427 } 1428 if (hasHorizontalSide) { 1429 return "horizontal"; 1430 } 1431 if (hasVerticalSide) { 1432 return "vertical"; 1433 } 1434 } 1435 function resolveColorValue(element, colorValue) { 1436 if (!colorValue || A(colorValue).isValid()) { 1437 return colorValue; 1438 } 1439 const colorResolver = element.ownerDocument.createElement("span"); 1440 colorResolver.style.color = colorValue; 1441 if (!colorResolver.style.color) { 1442 return colorValue; 1443 } 1444 element.appendChild(colorResolver); 1445 const resolvedColor = getComputedStyle2(colorResolver).color; 1446 colorResolver.remove(); 1447 return resolvedColor && A(resolvedColor).isValid() ? resolvedColor : colorValue; 1448 } 1449 function getResolvedGradientStops(element, gradientValue) { 1450 const stops = getWaveformGradientStops(gradientValue)?.map((colorValue) => resolveColorValue(element, colorValue)).filter((colorValue) => A(colorValue).isValid()); 1451 return stops?.length > 1 ? stops : void 0; 1452 } 1453 function applyAlpha(colorValue, alpha) { 1454 if (Array.isArray(colorValue)) { 1455 return colorValue.map( 1456 (color) => A(color).alpha(alpha).toRgbString() 1457 ); 1458 } 1459 return A(colorValue).alpha(alpha).toRgbString(); 1460 } 1461 function getRepresentativeColor(colorValue) { 1462 if (Array.isArray(colorValue)) { 1463 return colorValue[colorValue.length - 1]; 1464 } 1465 return colorValue; 1466 } 1467 function getWaveformGradientStops(gradientValue) { 1468 const stops = getTopLevelGradientParts(gradientValue).map(getColorStopValue).filter(Boolean); 1469 return stops.length > 1 ? stops : void 0; 1470 } 1471 function serializeColorValue(colorValue) { 1472 return Array.isArray(colorValue) ? JSON.stringify(colorValue) : colorValue; 1473 } 1474 function getWaveformColors(element, waveformColorValue, textColorValue, waveformGradientValue) { 1475 const textColor = textColorValue || getComputedStyle2(element).color; 1476 const waveformGradientStops = getResolvedGradientStops( 1477 element, 1478 waveformGradientValue 1479 ); 1480 const waveformBaseColor = waveformGradientStops || waveformColorValue || textColor; 1481 const waveformColor = applyAlpha(waveformBaseColor, 0.3); 1482 const progressColor = applyAlpha(waveformBaseColor, 0.6); 1483 const waveformGradient = waveformGradientStops ? getWaveformGradientDirection(waveformGradientValue) : void 0; 1484 return { 1485 textColor, 1486 waveformColor, 1487 progressColor, 1488 ...waveformGradient && { waveformGradient } 1489 }; 1490 } 1491 function createWaveformContainer({ 1492 url, 1493 title, 1494 artist, 1495 artwork, 1496 waveformColor, 1497 progressColor, 1498 waveformGradient, 1499 buttonColor, 1500 seekLabel, 1501 seekValueText, 1502 height = DEFAULT_WAVEFORM_HEIGHT, 1503 waveformStyle = "bars" 1504 }) { 1505 const container = document.createElement("div"); 1506 container.setAttribute("data-waveform-player", ""); 1507 container.setAttribute("data-url", url); 1508 container.setAttribute("data-height", String(height)); 1509 container.setAttribute("data-waveform-style", waveformStyle); 1510 container.setAttribute( 1511 "data-waveform-color", 1512 serializeColorValue(waveformColor) 1513 ); 1514 container.setAttribute( 1515 "data-progress-color", 1516 serializeColorValue(progressColor) 1517 ); 1518 if (waveformGradient) { 1519 container.setAttribute("data-waveform-gradient", waveformGradient); 1520 } 1521 container.setAttribute("data-button-color", buttonColor); 1522 container.setAttribute( 1523 "data-seek-label", 1524 getSeekControlLabel(seekLabel) 1525 ); 1526 if (seekValueText) { 1527 container.setAttribute("data-seek-value-text", seekValueText); 1528 } 1529 container.setAttribute("data-text-color", buttonColor); 1530 container.setAttribute("data-text-secondary-color", buttonColor); 1531 if (title) { 1532 container.setAttribute("data-title", title); 1533 } 1534 if (artist) { 1535 container.setAttribute("data-artist", artist); 1536 } 1537 if (artwork) { 1538 container.setAttribute("data-artwork", artwork); 1539 } 1540 return container; 1541 } 1542 function applyWaveformPlayerStyles(container, { 1543 backgroundColor, 1544 backgroundGradient, 1545 textColor, 1546 playButtonColor, 1547 playButtonGradient 1548 } = {}) { 1549 const waveformContainer = container.querySelector(".waveform-container"); 1550 const playButton = container.querySelector(".waveform-btn"); 1551 const playButtonBaseColor = getRepresentativeColor( 1552 getResolvedGradientStops(container, playButtonGradient) || playButtonColor 1553 ); 1554 if (playButtonBaseColor) { 1555 container.style.setProperty( 1556 "--wfp-button-color", 1557 playButtonBaseColor 1558 ); 1559 } else { 1560 container.style.removeProperty("--wfp-button-color"); 1561 } 1562 if (textColor) { 1563 container.style.setProperty("--wfp-text-color", textColor); 1564 container.style.setProperty("--wfp-text-secondary-color", textColor); 1565 } else { 1566 container.style.removeProperty("--wfp-text-color"); 1567 container.style.removeProperty("--wfp-text-secondary-color"); 1568 } 1569 if (playButton) { 1570 if (playButtonGradient) { 1571 playButton.style.background = playButtonGradient; 1572 } else { 1573 playButton.style.removeProperty("background"); 1574 } 1575 } 1576 if (waveformContainer) { 1577 if (backgroundGradient) { 1578 waveformContainer.style.background = backgroundGradient; 1579 } else if (backgroundColor) { 1580 waveformContainer.style.removeProperty("background"); 1581 waveformContainer.style.backgroundColor = backgroundColor; 1582 } else { 1583 waveformContainer.style.removeProperty("background"); 1584 waveformContainer.style.removeProperty("background-color"); 1585 } 1586 } 1587 } 1588 function styleSvgIcons(container, buttonColor) { 1589 const isButtonDark = A(buttonColor).isDark(); 1590 const iconColor = isButtonDark ? "#ffffff" : "#000000"; 1591 const svgPaths = container.querySelectorAll("svg path"); 1592 svgPaths.forEach((path) => { 1593 path.style.fill = iconColor; 1594 }); 1595 } 1596 function setupPlayButtonAccessibility(container, { play: playLabel = "Play", pause: pauseLabel = "Pause" } = {}) { 1597 const playBtn = container.querySelector(".waveform-btn"); 1598 if (!playBtn) { 1599 return; 1600 } 1601 playBtn.setAttribute("aria-label", playLabel); 1602 const onPlay = () => playBtn.setAttribute("aria-label", pauseLabel); 1603 const onPause = () => playBtn.setAttribute("aria-label", playLabel); 1604 container.addEventListener("waveformplayer:play", onPlay); 1605 container.addEventListener("waveformplayer:pause", onPause); 1606 container.addEventListener("waveformplayer:ended", onPause); 1607 return () => { 1608 container.removeEventListener("waveformplayer:play", onPlay); 1609 container.removeEventListener("waveformplayer:pause", onPause); 1610 container.removeEventListener("waveformplayer:ended", onPause); 1611 }; 1612 } 1613 function getSeekControlLabel(label) { 1614 return label || DEFAULT_SEEK_LABEL; 1615 } 1616 function updateSeekControlLabel(instance, label) { 1617 const seekLabel = getSeekControlLabel(label); 1618 instance.options.seekLabel = seekLabel; 1619 instance.applySeekLabel?.(seekLabel); 1620 const seekControl = instance?.container?.querySelector( 1621 ".waveform-container" 1622 ); 1623 if (seekControl) { 1624 seekControl.setAttribute("aria-label", seekLabel); 1625 } 1626 } 1627 function setupPlayButtonArtwork(container, artworkUrl) { 1628 if (!artworkUrl) { 1629 container.classList.remove("has-play-button-artwork"); 1630 container.style.removeProperty("--wp--playlist--play-button-artwork"); 1631 return; 1632 } 1633 container.classList.add("has-play-button-artwork"); 1634 container.style.setProperty( 1635 "--wp--playlist--play-button-artwork", 1636 `url($JSON.stringify(artworkUrl)})` 1637 ); 1638 } 1639 function logPlayError(error) { 1640 if (error.name === "AbortError") { 1641 return; 1642 } 1643 console.error("Playlist play error:", error); 1644 } 1645 function initWaveformPlayer(element, { 1646 src, 1647 title, 1648 artist, 1649 image, 1650 imageAlt, 1651 waveformColor: waveformColorValue, 1652 waveformGradient: waveformGradientValue, 1653 textColor: textColorValue, 1654 backgroundColor, 1655 backgroundGradient, 1656 autoPlay, 1657 onEnded, 1658 labels, 1659 waveformStyle, 1660 showPlayButtonArtwork = false 1661 }) { 1662 const playerArtwork = showPlayButtonArtwork ? void 0 : image; 1663 const { textColor, waveformColor, progressColor, waveformGradient } = getWaveformColors( 1664 element, 1665 waveformColorValue, 1666 textColorValue, 1667 waveformGradientValue 1668 ); 1669 const waveformGradientStops = getResolvedGradientStops( 1670 element, 1671 waveformGradientValue 1672 ); 1673 const waveformButtonColor = getRepresentativeColor( 1674 waveformGradientStops || waveformColorValue 1675 ); 1676 const container = createWaveformContainer({ 1677 url: src, 1678 title, 1679 artist, 1680 artwork: playerArtwork, 1681 waveformColor, 1682 progressColor, 1683 waveformGradient, 1684 buttonColor: textColor, 1685 seekLabel: title || labels?.seek, 1686 seekValueText: labels?.seekValueText, 1687 waveformStyle 1688 }); 1689 element.appendChild(container); 1690 const instance = new ie(container); 1691 if (instance.artworkEl) { 1692 instance.artworkEl.alt = imageAlt || ""; 1693 } 1694 applyWaveformPlayerStyles(container, { 1695 backgroundColor, 1696 backgroundGradient, 1697 textColor, 1698 playButtonColor: showPlayButtonArtwork ? void 0 : waveformButtonColor, 1699 playButtonGradient: showPlayButtonArtwork ? void 0 : waveformGradientValue 1700 }); 1701 let cleanupPlayButtonAccessibility; 1702 const handlers = { 1703 ready: () => { 1704 styleSvgIcons(container, waveformButtonColor || textColor); 1705 if (showPlayButtonArtwork) { 1706 setupPlayButtonArtwork(container, image); 1707 } 1708 cleanupPlayButtonAccessibility = setupPlayButtonAccessibility( 1709 container, 1710 labels 1711 ); 1712 if (autoPlay) { 1713 instance.play()?.catch(logPlayError); 1714 } 1715 }, 1716 ended: () => onEnded?.() 1717 }; 1718 container.addEventListener("waveformplayer:ready", handlers.ready); 1719 container.addEventListener("waveformplayer:ended", handlers.ended); 1720 return { 1721 instance, 1722 container, 1723 destroy: () => { 1724 cleanupPlayButtonAccessibility?.(); 1725 container.removeEventListener( 1726 "waveformplayer:ready", 1727 handlers.ready 1728 ); 1729 container.removeEventListener( 1730 "waveformplayer:ended", 1731 handlers.ended 1732 ); 1733 instance.destroy(); 1734 container.remove(); 1735 } 1736 }; 1737 } 1738 1739 // packages/block-library/build-module/playlist/view.mjs 1740 var playerState = /* @__PURE__ */ new WeakMap(); 1741 var playlistPlayerState = /* @__PURE__ */ new Map(); 1742 var { state } = store( 1743 "core/playlist", 1744 { 1745 state: { 1746 playlists: {}, 1747 get isCurrentTrack() { 1748 const { currentId, trackId } = getContext(); 1749 return currentId === trackId; 1750 }, 1751 get isCurrentTrackPlaying() { 1752 const { currentId, isPlaying, trackId } = getContext(); 1753 return currentId === trackId && !!isPlaying; 1754 }, 1755 get trackButtonActionLabel() { 1756 const { labelPauseTrack, labelSelectTrack } = getContext(); 1757 return state.isCurrentTrackPlaying ? labelPauseTrack : labelSelectTrack; 1758 } 1759 }, 1760 actions: { 1761 changeTrack() { 1762 const context = getContext(); 1763 if (context.currentId === context.trackId) { 1764 const player = playlistPlayerState.get( 1765 context.playlistId 1766 )?.instance; 1767 if (player?.isPlaying) { 1768 context.isPlaying = false; 1769 player.pause(); 1770 } else { 1771 player?.play()?.catch(logPlayError); 1772 } 1773 return; 1774 } 1775 context.isPlaying = false; 1776 context.currentId = context.trackId; 1777 } 1778 }, 1779 callbacks: { 1780 initWaveformPlayer() { 1781 const context = getContext(); 1782 const { ref } = getElement(); 1783 if (!context.currentId || !ref) { 1784 return; 1785 } 1786 const track = state.playlists[context.playlistId]?.tracks[context.currentId]; 1787 if (!track?.url) { 1788 return; 1789 } 1790 const existing = playerState.get(ref); 1791 if (existing?.url === track.url) { 1792 return; 1793 } 1794 const shouldAutoPlay = !!existing?.url; 1795 initPlayer(ref, track, shouldAutoPlay, context); 1796 } 1797 } 1798 }, 1799 { lock: true } 1800 ); 1801 function initPlayer(ref, track, shouldAutoPlay, context) { 1802 const existing = playerState.get(ref); 1803 const showPlayButtonArtwork = context.showPlayButtonArtwork === true; 1804 const playerArtwork = showPlayButtonArtwork ? "" : track.image; 1805 if (existing?.instance) { 1806 const shouldRecreatePlayer = !!existing.instance.artworkEl !== !!playerArtwork; 1807 if (shouldRecreatePlayer) { 1808 existing.destroy?.(); 1809 playerState.delete(ref); 1810 } else { 1811 playlistPlayerState.set(context.playlistId, existing); 1812 existing.instance.loadTrack(track.url, track.title, track.artist, { 1813 artwork: playerArtwork, 1814 artworkAlt: playerArtwork ? track.imageAlt : "" 1815 }).then(() => { 1816 existing.url = track.url; 1817 if (existing.instance.artworkEl) { 1818 existing.instance.artworkEl.alt = track.imageAlt || ""; 1819 } 1820 updateSeekControlLabel( 1821 existing.instance, 1822 track.title || ref.dataset.labelSeek 1823 ); 1824 if (showPlayButtonArtwork) { 1825 setupPlayButtonArtwork( 1826 existing.container, 1827 track.image 1828 ); 1829 } 1830 if (shouldAutoPlay) { 1831 existing.instance.play()?.catch(logPlayError); 1832 } 1833 }).catch(logPlayError); 1834 return; 1835 } 1836 } 1837 const labels = { 1838 play: ref.dataset.labelPlay, 1839 pause: ref.dataset.labelPause, 1840 seek: ref.dataset.labelSeek, 1841 seekValueText: ref.dataset.labelSeekValue 1842 }; 1843 const player = initWaveformPlayer(ref, { 1844 src: track.url, 1845 title: track.title, 1846 artist: track.artist, 1847 image: track.image, 1848 imageAlt: track.imageAlt, 1849 waveformColor: ref.dataset.waveformPlayerColor, 1850 waveformGradient: ref.dataset.waveformPlayerGradient, 1851 backgroundColor: ref.dataset.waveformPlayerBackgroundColor, 1852 backgroundGradient: ref.dataset.waveformPlayerBackgroundGradient, 1853 autoPlay: shouldAutoPlay, 1854 labels, 1855 waveformStyle: context.waveformStyle, 1856 showPlayButtonArtwork, 1857 onEnded: () => { 1858 const currentIndex = context.tracks.findIndex( 1859 (trackId) => trackId === context.currentId 1860 ); 1861 const nextTrack = context.tracks[currentIndex + 1]; 1862 if (nextTrack) { 1863 context.currentId = nextTrack; 1864 } 1865 } 1866 }); 1867 const setIsPlaying = (isPlaying) => { 1868 context.isPlaying = isPlaying; 1869 }; 1870 const onPlay = () => setIsPlaying(true); 1871 const onPause = () => setIsPlaying(false); 1872 player.container.addEventListener("waveformplayer:play", onPlay); 1873 player.container.addEventListener("waveformplayer:pause", onPause); 1874 player.container.addEventListener("waveformplayer:ended", onPause); 1875 const destroy = () => { 1876 player.container.removeEventListener("waveformplayer:play", onPlay); 1877 player.container.removeEventListener("waveformplayer:pause", onPause); 1878 player.container.removeEventListener("waveformplayer:ended", onPause); 1879 player.destroy(); 1880 }; 1881 const nextState = { 1882 url: track.url, 1883 instance: player.instance, 1884 container: player.container, 1885 destroy 1886 }; 1887 playerState.set(ref, nextState); 1888 playlistPlayerState.set(context.playlistId, nextState); 1889 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Nov 1 08:20:35 2026 | Cross-referenced by PHPXref |