| [ 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/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/@arraypress/waveform-player/dist/waveform-player.esm.js 176 function $2(e2) { 177 let t = -1 / 0; 178 for (let i = 0; i < e2.length; i++) e2[i] > t && (t = e2[i]); 179 return t; 180 } 181 function S(e2) { 182 return String(e2 ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); 183 } 184 function q2(e2) { 185 return S(typeof e2 == "number" ? `$e2}px` : e2); 186 } 187 function st(e2) { 188 if (typeof e2 != "string" || e2 === "") return false; 189 try { 190 let t = new URL(e2, "http://localhost/"); 191 return t.protocol === "http:" || t.protocol === "https:"; 192 } catch { 193 return false; 194 } 195 } 196 function m2(e2, t = 0, i = 1) { 197 return Math.max(t, Math.min(e2, i)); 198 } 199 function _(e2, t = null, i = {}) { 200 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; 201 if (!Number.isFinite(o)) return t; 202 let n = m2(o, s, r); 203 return a ? Math.round(n) : n; 204 } 205 function H2(e2, t = null) { 206 if (Array.isArray(e2)) return e2; 207 if (typeof e2 == "string" && e2.trim().startsWith("[")) try { 208 let i = JSON.parse(e2); 209 if (Array.isArray(i)) return i; 210 } catch { 211 } 212 return t; 213 } 214 function D(e2, t = {}) { 215 let { min: i = -1 / 0, max: s = 1 / 0, fallback: r = null } = t, a = H2(e2); 216 if (!a && typeof e2 == "string" && e2.trim() !== "" && (a = e2.split(/[,\s]+/)), !a) return r; 217 let o = a.map((n) => _(n)).filter((n) => n !== null && n >= i && n <= s); 218 return o.length ? o : r; 219 } 220 function rt(e2, t, i = null) { 221 return t.includes(e2) ? e2 : i; 222 } 223 function at(e2) { 224 if (typeof e2 == "string") { 225 let t = e2.trim().toLowerCase(); 226 return t !== "" && t !== "false" && t !== "0"; 227 } 228 return !!e2; 229 } 230 function vt(e2) { 231 return e2 === void 0 ? void 0 : e2 === "true"; 232 } 233 function it(e2) { 234 if (typeof e2 == "string" && e2.trim().startsWith("[")) try { 235 return JSON.parse(e2); 236 } catch { 237 } 238 return e2; 239 } 240 function O(e2) { 241 let t = {}, i = (o, n = o) => { 242 let l2 = vt(e2.dataset[n]); 243 l2 !== void 0 && (t[o] = l2); 244 }, s = (o, n = o, l2 = false) => { 245 let h = e2.dataset[n]; 246 h && (t[o] = l2 ? parseFloat(h) : parseInt(h, 10)); 247 }, r = (o, n = o) => { 248 let l2 = e2.dataset[n]; 249 l2 && (t[o] = /^\d+(\.\d+)?$/.test(l2.trim()) ? parseFloat(l2) : l2); 250 }, a = (o, n = o) => { 251 let l2 = e2.dataset[n]; 252 if (!l2) return; 253 let h = H2(l2); 254 h ? t[o] = h : console.warn(`[WaveformPlayer] Invalid $n} attribute, expected a JSON array:`, l2); 255 }; 256 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 = it(e2.dataset.waveformColor)), e2.dataset.progressColor && (t.progressColor = it(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) { 257 let o = D(e2.dataset.playbackRates); 258 o ? t.playbackRates = o : console.warn("[WaveformPlayer] Invalid playbackRates attribute:", e2.dataset.playbackRates); 259 } 260 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), t; 261 } 262 function ot(e2, ...t) { 263 let i = 0; 264 return e2.replace(/%(?:(\d+)\$)?s/g, (s, r) => { 265 let a = r ? Number(r) - 1 : i++; 266 return t[a] ?? s; 267 }); 268 } 269 function E2(e2) { 270 let t = Number(e2); 271 if (!t || !Number.isFinite(t) || t < 0) return "0:00"; 272 let i = Math.floor(t / 3600), s = Math.floor(t % 3600 / 60), r = Math.floor(t % 60); 273 return i > 0 ? `$i}:$s.toString().padStart(2, "0")}:$r.toString().padStart(2, "0")}` : `$s}:$r.toString().padStart(2, "0")}`; 274 } 275 var St = 0; 276 function nt(e2) { 277 let t = e2 || "audio", i = 5381; 278 for (let s = 0; s < t.length; s++) i = (i << 5) + i + t.charCodeAt(s) | 0; 279 return `wp_${(i >>> 0).toString(36)}_${(St++).toString(36)}`; 280 } 281 function I(e2) { 282 if (!e2) return "Audio"; 283 let t = e2.split("/"); 284 return t[t.length - 1].split(".")[0].replace(/[-_]/g, " ").replace(/\b\w/g, (r) => r.toUpperCase()); 285 } 286 function U(e2) { 287 if (typeof e2 != "string") return null; 288 let t = e2.match(/rgba?\(\s*([\d.]+)\s*[,\s]\s*([\d.]+)\s*[,\s]\s*([\d.]+)\s*(?:[,/]\s*([\d.]+)(%?))?/i); 289 if (!t) return null; 290 let i = Number(t[1]), s = Number(t[2]), r = Number(t[3]); 291 if (!Number.isFinite(i) || !Number.isFinite(s) || !Number.isFinite(r)) return null; 292 let a = t[4] === void 0 ? 1 : Number(t[4]); 293 return Number.isFinite(a) ? (t[5] === "%" && (a /= 100), { r: i, g: s, b: r, a: m2(a, 0, 1) }) : null; 294 } 295 function lt(e2) { 296 let t = U(e2); 297 return !t || t.a <= 0 ? null : (t.r * 299 + t.g * 587 + t.b * 114) / 1e3; 298 } 299 function j2(...e2) { 300 let t = {}; 301 for (let i of e2) for (let s in i) i[s] !== null && i[s] !== void 0 && (t[s] = i[s]); 302 return t; 303 } 304 function ht(e2, t) { 305 let i; 306 return function(...r) { 307 let a = () => { 308 clearTimeout(i), e2(...r); 309 }; 310 clearTimeout(i), i = setTimeout(a, t); 311 }; 312 } 313 function B(e2, t) { 314 if (e2.length === t) return e2; 315 if (e2.length === 0 || t === 0) return []; 316 let i = []; 317 if (t > e2.length) { 318 let s = (e2.length - 1) / (t - 1); 319 for (let r = 0; r < t; r++) { 320 let a = r * s, o = Math.floor(a), n = Math.ceil(a), l2 = a - o; 321 if (n >= e2.length) i.push(e2[e2.length - 1]); 322 else if (o === n) i.push(e2[o]); 323 else { 324 let h = e2[o] * (1 - l2) + e2[n] * l2; 325 i.push(h); 326 } 327 } 328 } else { 329 let s = e2.length / t; 330 for (let r = 0; r < t; r++) { 331 let a = Math.floor(r * s), o = Math.floor((r + 1) * s), n = 0, l2 = 0; 332 for (let h = a; h <= o && h < e2.length; h++) e2[h] > n && (n = e2[h]), l2++; 333 if (l2 === 0) { 334 let h = Math.min(Math.round(r * s), e2.length - 1); 335 n = e2[h]; 336 } 337 i.push(n); 338 } 339 } 340 return i; 341 } 342 function P(e2, t, i, s) { 343 if (!Array.isArray(t)) return t; 344 if (t.length < 2) return t[0]; 345 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]; 346 try { 347 let d = e2.createLinearGradient(n, l2, h, c2); 348 return t.forEach((b, y2) => d.addColorStop(y2 / (t.length - 1), b)), d; 349 } catch { 350 return t[0]; 351 } 352 } 353 function x2(e2, t, i, s, r, a) { 354 if ((Array.isArray(a) ? a.some((n) => n > 0) : a > 0) && typeof e2.roundRect == "function") { 355 let n = Math.min(s / 2, Math.abs(r) / 2), l2 = (h) => m2(h, 0, n); 356 e2.beginPath(), e2.roundRect(t, i, s, r, Array.isArray(a) ? a.map(l2) : l2(a)), e2.fill(); 357 } else e2.fillRect(t, i, s, r); 358 } 359 function pt(e2, t) { 360 return (e2.barRadius || 0) * t; 361 } 362 function Et(e2, t) { 363 let i = pt(e2, t); 364 return [i, i, 0, 0]; 365 } 366 function ct(e2, t, i, s, r) { 367 let a = r / 2; 368 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(); 369 } 370 function V(e2, t, i, s, r) { 371 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, b = Et(r, a), y2 = P(e2, r.color, t, r), w2 = P(e2, r.progressColor, t, r); 372 e2.clearRect(0, 0, t.width, t.height), e2.fillStyle = y2; 373 for (let f = 0; f < h.length; f++) { 374 let p2 = f * (o + n); 375 if (p2 + o > t.width) break; 376 let g2 = h[f] * c2 * 0.9, u = c2 - g2; 377 x2(e2, p2, u, o, g2, b); 378 } 379 e2.save(), e2.beginPath(), e2.rect(0, 0, d, c2), e2.clip(), e2.fillStyle = w2; 380 for (let f = 0; f < h.length; f++) { 381 let p2 = f * (o + n); 382 if (p2 > d) break; 383 let g2 = h[f] * c2 * 0.9, u = c2 - g2; 384 x2(e2, p2, u, o, g2, b); 385 } 386 e2.restore(); 387 } 388 function Pt(e2, t, i, s, r) { 389 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, b = s * t.width, y2 = pt(r, a), w2 = [y2, y2, 0, 0], f = [0, 0, y2, y2], p2 = P(e2, r.color, t, r), g2 = P(e2, r.progressColor, t, r); 390 e2.clearRect(0, 0, t.width, t.height), e2.fillStyle = p2; 391 for (let u = 0; u < h.length; u++) { 392 let k2 = u * (o + n); 393 if (k2 + o > t.width) break; 394 let v2 = h[u] * c2 * 0.45; 395 x2(e2, k2, d - v2, o, v2, w2), x2(e2, k2, d, o, v2, f); 396 } 397 e2.save(), e2.beginPath(), e2.rect(0, 0, b, c2), e2.clip(), e2.fillStyle = g2; 398 for (let u = 0; u < h.length; u++) { 399 let k2 = u * (o + n); 400 if (k2 > b) break; 401 let v2 = h[u] * c2 * 0.45; 402 x2(e2, k2, d - v2, o, v2, w2), x2(e2, k2, d, o, v2, f); 403 } 404 e2.restore(); 405 } 406 function Tt(e2, t, i, s, r) { 407 let a = t.width, o = t.height, n = o / 2, l2 = o * 0.35; 408 e2.clearRect(0, 0, a, o); 409 let h = (c2, d, b = 1, y2 = false) => { 410 let w2 = P(e2, c2, t, r), f = Array.isArray(c2) ? c2[c2.length - 1] : c2; 411 y2 && (e2.shadowBlur = 12, e2.shadowColor = f), e2.strokeStyle = w2, e2.lineWidth = d, e2.lineCap = "round", e2.lineJoin = "round", e2.beginPath(), e2.moveTo(0, n); 412 let p2 = [], g2 = Math.floor(i.length * b); 413 for (let u = 0; u < g2; u++) { 414 let k2 = u / (i.length - 1) * a, v2 = i[u], A2 = Math.sin(u * 0.1) * v2, L = n + A2 * l2; 415 p2.push({ x: k2, y: L }); 416 } 417 for (let u = 0; u < p2.length - 1; u++) { 418 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; 419 e2.bezierCurveTo(k2, v2, A2, L, p2[u + 1].x, p2[u + 1].y); 420 } 421 e2.stroke(), y2 && (e2.shadowBlur = 0); 422 }; 423 e2.strokeStyle = "rgba(255, 255, 255, 0.03)", e2.lineWidth = 0.5, e2.beginPath(), e2.moveTo(0, n), e2.lineTo(a, n), e2.stroke(); 424 for (let c2 = 0; c2 <= 10; c2++) { 425 let d = a / 10 * c2; 426 e2.beginPath(), e2.moveTo(d, 0), e2.lineTo(d, o), e2.stroke(); 427 } 428 h(r.color, 2, 1, false), s > 0 && h(r.progressColor, 3, s, true); 429 } 430 function ut(e2, t, i, s, r) { 431 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, b = 2 * a, y2 = s * t.width, w2 = c2 / 2, f = P(e2, r.color, t, r), p2 = P(e2, r.progressColor, t, r); 432 e2.clearRect(0, 0, t.width, t.height); 433 for (let g2 = 0; g2 < h.length; g2++) { 434 let u = g2 * (o + n); 435 if (u + o > t.width) break; 436 let k2 = h[g2] * c2 * 0.9, v2 = Math.floor(k2 / (d + b)); 437 e2.fillStyle = u < y2 ? p2 : f; 438 for (let A2 = 0; A2 < v2; A2++) { 439 let L = A2 * (d + b); 440 e2.fillRect(u, w2 - L - d, o, d), A2 > 0 && e2.fillRect(u, w2 + L, o, d); 441 } 442 } 443 } 444 function dt(e2, t, i, s, r) { 445 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), b = s * t.width, y2 = c2 / 2, w2 = P(e2, r.color, t, r), f = P(e2, r.progressColor, t, r); 446 e2.clearRect(0, 0, t.width, t.height); 447 for (let p2 = 0; p2 < h.length; p2++) { 448 let g2 = p2 * (o + n) + o / 2; 449 if (g2 > t.width) break; 450 let u = h[p2] * c2 * 0.9; 451 e2.fillStyle = g2 < b ? f : w2, 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(); 452 } 453 } 454 function At(e2, t, i, s, r) { 455 let a = t.width, o = t.height, n = o / 2, l2 = 4, h = l2 / 2, c2 = !!r.seekActive; 456 if (e2.clearRect(0, 0, a, o), e2.fillStyle = P(e2, r.color, t, r) || "rgba(255, 255, 255, 0.2)", ct(e2, h, a, n, l2), e2.fill(), s > 0) { 457 let d = Math.max(h * 2, s * a); 458 e2.save(), e2.globalAlpha = r.seekHandle && !c2 ? 0.7 : 1, e2.fillStyle = P(e2, r.progressColor, t, r) || "rgba(255, 255, 255, 0.9)", ct(e2, h, d, n, l2), e2.fill(), e2.restore(); 459 } 460 } 461 var Mt = { bars: V, bar: V, mirror: Pt, line: Tt, blocks: ut, block: ut, dots: dt, dot: dt, seekbar: At }; 462 function ft(e2, t, i, s, r) { 463 (Mt[r.waveformStyle] || V)(e2, t, i, s, r); 464 } 465 function mt(e2) { 466 try { 467 let t = e2.getChannelData(0), i = e2.sampleRate, s = Ct(t, i); 468 if (s.length < 2) return 120; 469 let r = []; 470 for (let l2 = 1; l2 < s.length; l2++) r.push((s[l2] - s[l2 - 1]) / i); 471 let a = {}; 472 r.forEach((l2) => { 473 let h = 60 / l2, c2 = Math.round(h / 3) * 3; 474 c2 > 60 && c2 < 200 && (a[c2] = (a[c2] || 0) + 1); 475 }); 476 let o = 0, n = 120; 477 for (let [l2, h] of Object.entries(a)) h > o && (o = h, n = parseInt(l2)); 478 return n < 70 && a[n * 2] ? n *= 2 : n > 160 && a[Math.round(n / 2)] && (n = Math.round(n / 2)), n - 1; 479 } catch (t) { 480 return console.warn("[WaveformPlayer] BPM detection failed:", t), null; 481 } 482 } 483 function Ct(e2, t) { 484 let r = [], a = 0; 485 for (let o = 0; o < e2.length - 2048; o += 1024) { 486 let n = 0; 487 for (let c2 = o; c2 < o + 2048; c2++) n += e2[c2] * e2[c2]; 488 n = n / 2048; 489 let l2 = n - a, h = a * 1.8 + 0.01; 490 if (l2 > h && n > 0.01) { 491 let c2 = r[r.length - 1] || 0, d = t * 0.15; 492 o - c2 > d && r.push(o); 493 } 494 a = n * 0.8 + a * 0.2; 495 } 496 return r; 497 } 498 function Lt(e2, t = 1800) { 499 let i = e2.length / t, s = e2.numberOfChannels, r = []; 500 for (let o = 0; o < s; o++) { 501 let n = e2.getChannelData(o); 502 for (let l2 = 0; l2 < t; l2++) { 503 let h = ~~(l2 * i), c2 = ~~(h + i), d = 0, b = 0; 504 for (let w2 = h; w2 < c2; w2++) { 505 let f = n[w2]; 506 f > b && (b = f), f < d && (d = f); 507 } 508 let y2 = Math.max(Math.abs(b), Math.abs(d)); 509 (o === 0 || y2 > r[l2]) && (r[l2] = y2); 510 } 511 } 512 let a = $2(r); 513 return a > 0 ? r.map((o) => o / a) : r; 514 } 515 async function G(e2, t = 1800, i = false) { 516 let s; 517 try { 518 let r = window.AudioContext || window.webkitAudioContext; 519 s = new r(); 520 let o = await (await fetch(e2)).arrayBuffer(), n = await s.decodeAudioData(o), l2 = Lt(n, t); 521 l2 = _t(l2); 522 let h = null; 523 return i && (h = mt(n)), { peaks: l2, bpm: h }; 524 } finally { 525 s && s.close(); 526 } 527 } 528 function yt(e2 = 1800) { 529 let t = []; 530 for (let i = 0; i < e2; i++) { 531 let s = Math.random() * 0.5 + 0.3, r = Math.sin(i / e2 * Math.PI * 4) * 0.2; 532 t.push(m2(s + r, 0.1, 1)); 533 } 534 return t; 535 } 536 function _t(e2, t = 0.95) { 537 let i = $2(e2); 538 if (i === 0 || i > t) return e2; 539 let s = t / i; 540 return e2.map((r) => r * s); 541 } 542 var K = 128; 543 function gt(e2) { 544 let t = document.documentElement, i = document.body; 545 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; 546 } 547 function xt(e2) { 548 let t = 0, i = 0; 549 for (let s = e2; s && s.nodeType === 1 && i < 0.995; s = s.parentElement) { 550 let r = U(getComputedStyle(s).backgroundColor); 551 if (!r || r.a <= 0) continue; 552 let a = r.a * (1 - i); 553 t += (r.r * 299 + r.g * 587 + r.b * 114) / 1e3 * a, i += a; 554 } 555 return { sum: t, alpha: i }; 556 } 557 function Rt() { 558 let e2 = lt(getComputedStyle(document.body).color); 559 if (e2 !== null) return e2 > K ? "dark" : "light"; 560 if (window.matchMedia) { 561 if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark"; 562 if (window.matchMedia("(prefers-color-scheme: light)").matches) return "light"; 563 } 564 return "dark"; 565 } 566 function R2(e2) { 567 if (gt("dark")) return "dark"; 568 if (gt("light")) return "light"; 569 try { 570 let t = e2 && e2.nodeType === 1 ? e2 : document.body, { sum: i, alpha: s } = xt(t), r = Rt(), a = i + (r === "dark" ? 0 : 255) * (1 - s); 571 return a > K ? "light" : a < K ? "dark" : r; 572 } catch { 573 return "dark"; 574 } 575 } 576 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)" } }; 577 function J(e2, t) { 578 if (e2 && C[e2]) return C[e2]; 579 let i = R2(t); 580 return C[i]; 581 } 582 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 }; 583 var X = { 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 } }; 584 var Q = ["auto", "top", "center", "bottom"]; 585 var N2 = 0.25; 586 var F = 4; 587 var Dt = { buttonAlign: Q, layout: ["default", "preview"], buttonStyle: ["circle", "minimal"], artworkPosition: ["info", "button"], waveformStyle: Object.keys(X), waveformGradient: ["vertical", "horizontal", "diagonal"], audioMode: ["self", "external"], preload: ["none", "metadata", "auto"], colorPreset: Object.keys(C), crossOrigin: ["anonymous", "use-credentials"] }; 588 var Bt = { 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 } }; 589 var Ht = ["autoplay", "showControls", "showInfo", "showTime", "showHoverTime", "seekHandle", "showBPM", "singlePlay", "playOnSeek", "enableMediaSession", "showMarkers", "accessibleSeek", "showPlaybackSpeed"]; 590 var Ot = ["onLoad", "onPlay", "onPause", "onEnd", "onError", "onTimeUpdate", "onNextTrack", "onPreviousTrack"]; 591 function Y(e2, t) { 592 console.warn(`[WaveformPlayer] Invalid $e2} option, using default:`, t); 593 } 594 function z(e2) { 595 let t = H2(e2); 596 return t ? t.reduce((i, s) => { 597 let r = s && typeof s == "object" ? _(s.time, null, { min: 0 }) : null; 598 return r === null ? (Y("marker", s), i) : (i.push({ ...s, time: r, label: s.label == null ? "" : s.label }), i); 599 }, []) : (e2 != null && Y("markers", e2), []); 600 } 601 function Z(e2) { 602 let t = (s) => e2[s] != null, i = (s) => { 603 Y(s, e2[s]), e2[s] = W[s]; 604 }; 605 for (let [s, r] of Object.entries(Bt)) { 606 if (!t(s)) continue; 607 let a = _(e2[s], null, r); 608 a === null ? i(s) : e2[s] = a; 609 } 610 for (let [s, r] of Object.entries(Dt)) t(s) && rt(e2[s], r) === null && i(s); 611 for (let s of Ht) e2[s] = at(e2[s]); 612 for (let s of Ot) t(s) && typeof e2[s] != "function" && i(s); 613 if (t("playbackRates")) { 614 let s = D(e2.playbackRates, { min: N2, max: F, fallback: null }); 615 s === null ? i("playbackRates") : e2.playbackRates = s; 616 } 617 e2.markers = z(e2.markers); 618 for (let s of ["buttonSize", "buttonRadius"]) { 619 if (!t(s)) continue; 620 let r = e2[s]; 621 (typeof r == "number" ? Number.isFinite(r) : typeof r == "string" && r.trim() !== "") || i(s); 622 } 623 for (let s of ["waveformColor", "progressColor"]) { 624 if (!t(s)) continue; 625 let r = e2[s]; 626 !(typeof r == "string" && r.trim() !== "") && !Array.isArray(r) && i(s); 627 } 628 return e2; 629 } 630 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>'); 631 var bt = 5; 632 var wt = 10; 633 var Wt = 'button, a[href], input, [role="slider"]'; 634 var T = class e { 635 static instances = /* @__PURE__ */ new Map(); 636 static currentlyPlaying = null; 637 constructor(t, i = {}) { 638 if (this.container = typeof t == "string" ? document.querySelector(t) : t, !this.container) throw new Error("[WaveformPlayer] Container element not found"); 639 let s = O(this.container), r = { ...i }; 640 r.style && !r.waveformStyle && (r.waveformStyle = r.style), r.src && !r.url && (r.url = r.src), this.options = Z(j2(W, s, r)); 641 let a = J(this.options.colorPreset, this.container); 642 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); 643 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)); 644 let o = X[this.options.waveformStyle]; 645 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 || nt(this.options.url), e.instances.set(this.id, this), e._watchTheme(); 646 try { 647 this.init(); 648 } catch (n) { 649 throw e.instances.delete(this.id), this._ac.abort(), n; 650 } 651 setTimeout(() => { 652 this._emit("waveformplayer:ready", { player: this, url: this.options.url }); 653 }, 100); 654 } 655 _emit(t, i, s = false) { 656 let r = new CustomEvent(t, { bubbles: true, cancelable: s, detail: i }); 657 return this.container.dispatchEvent(r), r; 658 } 659 _requestSeek(t) { 660 this._emit("waveformplayer:request-seek", { ...this._buildTrackDetail(), percent: t }, true).defaultPrevented || (this.progress = t, this.drawWaveform?.()); 661 } 662 init() { 663 this.createDOM(), this.createAudio(), this.initPlaybackSpeed(), this.initKeyboardControls(), this.initSeekControl(), this.bindEvents(), this.setupResizeObserver(), requestAnimationFrame(() => { 664 this.resizeCanvas(), this.options.url && this.load(this.options.url).then(() => { 665 this.options.autoplay && this.play()?.catch(() => { 666 }); 667 }).catch((t) => { 668 console.error("[WaveformPlayer] Failed to load audio:", t); 669 }); 670 }); 671 } 672 createDOM() { 673 this.container.innerHTML = "", this.container.className = "waveform-player"; 674 let t = Q.includes(this.options.buttonAlign) ? this.options.buttonAlign : "auto"; 675 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"); 676 let s = []; 677 this.options.buttonSize != null && s.push(`--wfp-btn-size: $q2(this.options.buttonSize)}`), this.options.buttonRadius != null && s.push(`--wfp-btn-radius: $q2(this.options.buttonRadius)}`); 678 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 ? ` 679 <button class="waveform-btn$this.options.buttonStyle === "minimal" ? " waveform-btn-minimal" : ""}$a ? " waveform-btn-has-artwork" : ""}" aria-label="$S(this.options.playPauseLabel)}"$r}> 680 $o} 681 <span class="waveform-icon-play">$this.options.playIcon}</span> 682 <span class="waveform-icon-pause" style="display:none;">$this.options.pauseIcon}</span> 683 </button> 684 ` : "", l2 = this.options.showInfo ? ` 685 <div class="waveform-info"> 686 $this.options.artworkPosition !== "button" && this.options.artwork ? ` 687 <img class="waveform-artwork" src="$S(this.options.artwork)}" alt="$S(this.options.artworkAlt)}" style=" 688 width: 40px; 689 height: 40px; 690 border-radius: 4px; 691 object-fit: cover; 692 flex-shrink: 0; 693 "> 694 ` : ""} 695 <div class="waveform-text"> 696 <span class="waveform-title"></span> 697 $this.options.artist ? `<span class="waveform-artist">$S(this.options.artist)}</span>` : ""} 698 </div> 699 <div class="waveform-meta" style="display: flex; align-items: center; gap: 1rem;"> 700 $this.options.showBPM ? ` 701 <span class="waveform-bpm" style="display: none;"> 702 <span class="bpm-value">--</span> BPM 703 </span> 704 ` : ""} 705 $this.options.showPlaybackSpeed ? ` 706 <div class="waveform-speed"> 707 <button class="speed-btn" aria-label="$S(this.options.speedLabel)}" aria-haspopup="menu" aria-expanded="false"> 708 <span class="speed-value">1x</span> 709 </button> 710 <div class="speed-menu" role="menu" aria-label="$S(this.options.speedLabel)}" style="display: none;"> 711 $this.options.playbackRates.map((h) => `<button class="speed-option" role="menuitemradio" tabindex="-1" aria-checked="false" data-rate="$h}">$h}x</button>`).join("")} 712 </div> 713 </div> 714 ` : ""} 715 $this.options.showTime ? ` 716 <span class="waveform-time"> 717 <span class="time-current">0:00</span> / <span class="time-total">0:00</span> 718 </span> 719 ` : ""} 720 </div> 721 </div> 722 ` : ""; 723 this.container.innerHTML = ` 724 <div class="waveform-player-inner"> 725 <div class="waveform-body"> 726 <div class="waveform-track waveform-align-$t}"> 727 $n} 728 729 <div class="waveform-container"> 730 <canvas></canvas> 731 <div class="waveform-markers"></div> 732 <div class="waveform-loading" style="display:none;"></div> 733 <div class="waveform-error" style="display:none;" role="alert"> 734 <span class="waveform-error-text">$S(this.options.errorText)}</span> 735 </div> 736 </div> 737 </div> 738 739 $l2} 740 </div> 741 </div> 742 `, 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(); 743 } 744 bindArtworkFallback(t) { 745 t && t.addEventListener("error", () => { 746 t.src.startsWith("data:") || (t.src = It); 747 }, { signal: this._ac.signal }); 748 } 749 createArtworkElement() { 750 let t = document.createElement("img"); 751 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; 752 } 753 createButtonArtworkElement() { 754 let t = document.createElement("img"); 755 return t.className = "waveform-btn-artwork", t.alt = "", t.setAttribute("aria-hidden", "true"), this.bindArtworkFallback(t), t; 756 } 757 createArtistElement() { 758 let t = document.createElement("span"); 759 return t.className = "waveform-artist", t; 760 } 761 syncArtist(t) { 762 if (this.options.artist = t || null, !!this.options.showInfo) { 763 if (!t) { 764 this.artistEl?.remove(), this.artistEl = null; 765 return; 766 } 767 if (!this.artistEl) { 768 let i = this.container.querySelector(".waveform-title"); 769 if (!i) return; 770 this.artistEl = this.createArtistElement(), i.after(this.artistEl); 771 } 772 this.artistEl.textContent = t, this.artistEl.style.display = ""; 773 } 774 } 775 syncButtonArtwork(t) { 776 if (this.playBtn) { 777 if (!t) { 778 this.artworkEl?.remove(), this.artworkEl = null, this.playBtn.classList.remove("waveform-btn-has-artwork"); 779 return; 780 } 781 this.artworkEl || (this.artworkEl = this.createButtonArtworkElement(), this.playBtn.prepend(this.artworkEl)), this.artworkEl.src = t, this.playBtn.classList.add("waveform-btn-has-artwork"); 782 } 783 } 784 syncArtwork(t, i = "") { 785 if (this.options.artwork = t || null, this.options.artworkAlt = i || "", this.options.artworkPosition === "button") { 786 this.syncButtonArtwork(this.options.artwork); 787 return; 788 } 789 if (this.options.showInfo) { 790 if (!t) { 791 this.artworkEl?.remove(), this.artworkEl = null; 792 return; 793 } 794 if (!this.artworkEl) { 795 let s = this.container.querySelector(".waveform-text"); 796 if (!s) return; 797 this.artworkEl = this.createArtworkElement(), s.before(this.artworkEl); 798 } 799 this.artworkEl.src = t, this.artworkEl.alt = i || ""; 800 } 801 } 802 createAudio() { 803 if (this.options.audioMode === "external") { 804 this.audio = null; 805 return; 806 } 807 this.audio = new Audio(), this.audio.preload = this.options.preload || "metadata", this.options.crossOrigin && (this.audio.crossOrigin = this.options.crossOrigin); 808 } 809 initPlaybackSpeed() { 810 this.audio && this.options.playbackRate && this.options.playbackRate !== 1 && (this.audio.playbackRate = this.options.playbackRate), this.options.showPlaybackSpeed && this.initSpeedControls(); 811 } 812 initSpeedControls() { 813 let t = this.container.querySelector(".speed-btn"), i = this.container.querySelector(".speed-menu"); 814 if (!t || !i) return; 815 let s = () => Array.from(i.querySelectorAll(".speed-option")), r = () => i.style.display !== "none", a = (l2) => { 816 if (i.style.display = l2 ? "block" : "none", t.setAttribute("aria-expanded", l2 ? "true" : "false"), l2) { 817 let h = s(); 818 (h.find((c2) => c2.getAttribute("aria-checked") === "true") || h[0])?.focus(); 819 } 820 }, o = (l2) => { 821 let h = s(); 822 h.length && h[(l2 + h.length) % h.length].focus(); 823 }, n = (l2) => { 824 this.setPlaybackRate(parseFloat(l2.dataset.rate)), a(false), t.focus(); 825 }; 826 t.addEventListener("click", (l2) => { 827 l2.stopPropagation(), a(!r()); 828 }, { signal: this._ac.signal }), document.addEventListener("click", () => a(false), { signal: this._ac.signal }), i.addEventListener("click", (l2) => { 829 l2.stopPropagation(); 830 let h = l2.target.closest(".speed-option"); 831 h && n(h); 832 }, { signal: this._ac.signal }), t.closest(".waveform-speed")?.addEventListener("keydown", (l2) => { 833 let h = s(), c2 = h.indexOf(document.activeElement); 834 if (!r()) { 835 (l2.key === "ArrowDown" || l2.key === "ArrowUp") && document.activeElement === t && (l2.preventDefault(), a(true)); 836 return; 837 } 838 switch (l2.key) { 839 case "ArrowDown": 840 l2.preventDefault(), o(c2 < 0 ? 0 : c2 + 1); 841 break; 842 case "ArrowUp": 843 l2.preventDefault(), o(c2 < 0 ? h.length - 1 : c2 - 1); 844 break; 845 case "Home": 846 l2.preventDefault(), o(0); 847 break; 848 case "End": 849 l2.preventDefault(), o(h.length - 1); 850 break; 851 case "Escape": 852 l2.preventDefault(), a(false), t.focus(); 853 break; 854 case "Tab": 855 a(false); 856 break; 857 } 858 }, { signal: this._ac.signal }), this.updateSpeedUI(); 859 } 860 initKeyboardControls() { 861 this.container.setAttribute("tabindex", "-1"), this.container.addEventListener("click", (t) => { 862 t.target.closest(Wt) || (e.getAllInstances().forEach((i) => { 863 i !== this && i.container.setAttribute("tabindex", "-1"); 864 }), this.container.setAttribute("tabindex", "0"), this.container.focus()); 865 }, { signal: this._ac.signal }), this.container.addEventListener("keydown", (t) => { 866 if (document.activeElement !== this.container) return; 867 let i = t.key, s = !!this.audio, r = s ? this.audio.currentTime : 0; 868 if (s && i >= "0" && i <= "9") { 869 t.preventDefault(), this.seekToPercent(parseInt(i) / 10); 870 return; 871 } 872 let a = { " ": () => this.togglePlay() }; 873 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]()); 874 }, { signal: this._ac.signal }); 875 } 876 initSeekControl() { 877 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) => { 878 if (t.key === " " || t.key === "Spacebar") { 879 t.preventDefault(), t.stopPropagation(), this.togglePlay(); 880 return; 881 } 882 let i = this.getSeekDuration(); 883 if (!i) return; 884 let s = this.getSeekCurrentTime(), r; 885 switch (t.key) { 886 case "ArrowLeft": 887 case "ArrowDown": 888 r = s - bt; 889 break; 890 case "ArrowRight": 891 case "ArrowUp": 892 r = s + bt; 893 break; 894 case "PageDown": 895 r = s - wt; 896 break; 897 case "PageUp": 898 r = s + wt; 899 break; 900 case "Home": 901 r = 0; 902 break; 903 case "End": 904 r = i; 905 break; 906 default: 907 return; 908 } 909 t.preventDefault(), t.stopPropagation(), this.seekToSeconds(r); 910 }, { signal: this._ac.signal }))); 911 } 912 getSeekDuration() { 913 return this.options.audioMode === "external" ? this._extDuration || 0 : this.audio && Number.isFinite(this.audio.duration) ? this.audio.duration : 0; 914 } 915 getSeekCurrentTime() { 916 return this.options.audioMode === "external" ? this.progress * (this._extDuration || 0) : this.audio && Number.isFinite(this.audio.currentTime) ? this.audio.currentTime : 0; 917 } 918 seekToSeconds(t) { 919 let i = this.getSeekDuration(); 920 if (!i) return; 921 let s = m2(t, 0, i); 922 if (this.options.audioMode === "external") { 923 this._requestSeek(s / i), this.updateSeekAccessibility(); 924 return; 925 } 926 this.seekTo(s); 927 } 928 applySeekLabel(t = this.options.title) { 929 if (!this.seekEl) return; 930 let i = this.options.seekLabel || t || "Seek"; 931 this.seekEl.setAttribute("aria-label", i); 932 } 933 updateSeekAccessibility() { 934 if (!this.seekEl) return; 935 let t = this.getSeekDuration(), i = Math.min(this.getSeekCurrentTime(), t); 936 this.seekEl.setAttribute("aria-valuemax", String(Math.round(t))), this.seekEl.setAttribute("aria-valuenow", String(Math.round(i))), this.seekEl.setAttribute("aria-valuetext", ot(this.options.seekValueText || "%1$s of %2$s", E2(i), E2(t))); 937 } 938 initMediaSession() { 939 if (!("mediaSession" in navigator) || !this.options.enableMediaSession || !this.audio) return; 940 this._applyMediaMetadata(), navigator.mediaSession.setActionHandler("play", () => this.play()), navigator.mediaSession.setActionHandler("pause", () => this.pause()), navigator.mediaSession.setActionHandler("seekbackward", () => { 941 this.seekTo(m2(this.audio.currentTime - 10, 0, this.audio.duration)); 942 }), navigator.mediaSession.setActionHandler("seekforward", () => { 943 this.seekTo(m2(this.audio.currentTime + 10, 0, this.audio.duration)); 944 }), navigator.mediaSession.setActionHandler("seekto", (s) => { 945 s.seekTime !== null && this.seekTo(s.seekTime); 946 }); 947 let t = this.options.onNextTrack, i = this.options.onPreviousTrack; 948 try { 949 navigator.mediaSession.setActionHandler("nexttrack", typeof t == "function" ? () => t(this) : null); 950 } catch { 951 } 952 try { 953 navigator.mediaSession.setActionHandler("previoustrack", typeof i == "function" ? () => i(this) : null); 954 } catch { 955 } 956 } 957 _applyMediaMetadata() { 958 !("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" }] : [] })); 959 } 960 _updateMediaSession(t) { 961 if (!(!("mediaSession" in navigator) || !this.options.enableMediaSession || !this.audio)) try { 962 t === "playing" && this.initMediaSession(), navigator.mediaSession.playbackState = t; 963 let i = this.audio.duration; 964 navigator.mediaSession.setPositionState && i && isFinite(i) && navigator.mediaSession.setPositionState({ duration: i, playbackRate: this.audio.playbackRate || 1, position: m2(this.audio.currentTime, 0, i) }); 965 } catch { 966 } 967 } 968 bindEvents() { 969 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", () => { 970 this._seekHover = true, this.drawWaveform(), this._updateSeekHandle(); 971 }), this.canvas.addEventListener("pointerleave", () => { 972 this._seekHover = false, this._handleNear = false, this._dragging || this._hideHoverTip(), this.drawWaveform(), this._updateSeekHandle(); 973 }), this.canvas.addEventListener("pointerdown", (i) => { 974 if (!(i.pointerType === "mouse" && i.button !== 0)) { 975 this._dragging = true; 976 try { 977 this.canvas.setPointerCapture(i.pointerId); 978 } catch { 979 } 980 this._scrubTo(i.clientX); 981 } 982 }), this.canvas.addEventListener("pointermove", (i) => { 983 if (this._dragging) { 984 this._scrubTo(i.clientX); 985 return; 986 } 987 let s = this.canvas.getBoundingClientRect(); 988 s.width && (this._handleNear = Math.abs(i.clientX - s.left - this.progress * s.width) <= 10, this._updateSeekHandle()); 989 }); 990 let t = (i) => { 991 if (this._dragging) { 992 this._dragging = false, this._suppressClick = true; 993 try { 994 this.canvas.releasePointerCapture(i.pointerId); 995 } catch { 996 } 997 this._seekFromPointer(i.clientX), !this._seekHover && !this.options.showHoverTime && this._hideHoverTip(), this._updateSeekHandle(); 998 } 999 }; 1000 this.canvas.addEventListener("pointerup", t), this.canvas.addEventListener("pointercancel", t), this.setupHoverTime(), this.setupSeekHandle(), this.resizeHandler = ht(() => this.resizeCanvas(), 100), window.addEventListener("resize", this.resizeHandler); 1001 } 1002 setupResizeObserver() { 1003 "ResizeObserver" in window && (this.resizeObserver = new ResizeObserver(() => { 1004 this.resizeCanvas(); 1005 }), this.canvas?.parentElement && this.resizeObserver.observe(this.canvas.parentElement)); 1006 } 1007 async load(t) { 1008 try { 1009 this.setLoading(true), this.progress = 0, this.hasError = false, this.container.classList.remove("waveform-is-placeholder"); 1010 let i = !!this.options.waveform; 1011 i && this.setWaveformData(this.options.waveform); 1012 let s = this.options.title || I(t); 1013 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) => { 1014 let o = () => { 1015 this.audio.removeEventListener("loadedmetadata", o), this.audio.removeEventListener("error", n), r(); 1016 }, n = (l2) => { 1017 this.audio.removeEventListener("loadedmetadata", o), this.audio.removeEventListener("error", n), a(l2); 1018 }; 1019 this.audio.addEventListener("loadedmetadata", o), this.audio.addEventListener("error", n); 1020 })), !i) try { 1021 let r = await G(t, this.options.samples, this.options.showBPM); 1022 this.waveformData = r.peaks, r.bpm && (this.detectedBPM = r.bpm, this.updateBPMDisplay()); 1023 } catch (r) { 1024 console.warn("[WaveformPlayer] Using placeholder waveform:", r), this.waveformData = yt(this.options.samples), this.container.classList.add("waveform-is-placeholder"); 1025 } 1026 this.drawWaveform(), this.renderMarkers(), this.options.onLoad && this.options.onLoad(this); 1027 } catch (i) { 1028 this.onError(i); 1029 } finally { 1030 this.setLoading(false); 1031 } 1032 } 1033 async loadTrack(t, i = null, s = null, r = {}) { 1034 let a = Object.prototype.hasOwnProperty.call(r, "artwork"), o = Object.prototype.hasOwnProperty.call(r, "artworkAlt"); 1035 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 = Z(j2(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(() => { 1036 }); 1037 } 1038 setWaveformData(t) { 1039 if (typeof t == "string" && t.trim().endsWith(".json")) { 1040 fetch(t.trim()).then((i) => i.json()).then((i) => { 1041 this.waveformData = Array.isArray(i) ? i : i.peaks || [], i.markers && !this.options.markers?.length && (this.options.markers = z(i.markers), this.renderMarkers()), this.drawWaveform(); 1042 }).catch(() => { 1043 }); 1044 return; 1045 } 1046 this.waveformData = D(t, { fallback: [] }), this.drawWaveform(); 1047 } 1048 drawWaveform() { 1049 !this.ctx || this.waveformData.length === 0 || ft(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 }); 1050 } 1051 resizeCanvas() { 1052 if (!this.canvas || this.isDestroying) return; 1053 let t = window.devicePixelRatio || 1, i = this.canvas.parentElement.getBoundingClientRect(); 1054 this.canvas.width = i.width * t, this.canvas.height = this.options.height * t, this.canvas.parentElement.style.height = this.options.height + "px", this.drawWaveform(); 1055 } 1056 renderMarkers() { 1057 if (!this.markersContainer || (this.markersContainer.innerHTML = "", this._activeMarkerIndex = -1, clearTimeout(this._markerLabelTimer), !this.options.showMarkers || !this.options.markers?.length)) return; 1058 let t = this.getSeekDuration(); 1059 t && this.options.markers.forEach((i, s) => { 1060 if (i.time > t) { 1061 console.warn(`[WaveformPlayer] Marker "$i.label}" at $i.time}s exceeds audio duration of $t}s`); 1062 return; 1063 } 1064 let r = i.time / t * 100, a = document.createElement("button"); 1065 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); 1066 let o = document.createElement("span"); 1067 o.className = "waveform-marker-tooltip", o.textContent = i.label, a.appendChild(o), a.addEventListener("click", (n) => { 1068 n.stopPropagation(), this.seekTo(i.time), this.options.playOnSeek && !this.isPlaying && this.play(); 1069 }), this.markersContainer.appendChild(a); 1070 }); 1071 } 1072 setActiveMarker(t) { 1073 if (!this.markersContainer) return; 1074 this.markersContainer.querySelectorAll(".waveform-marker").forEach((s, r) => s.classList.toggle("active", r === t)); 1075 } 1076 updateActiveMarker() { 1077 if (!this.markersContainer) return; 1078 let t = this.markersContainer.querySelectorAll(".waveform-marker"); 1079 if (!t.length) return; 1080 let i = this.getSeekDuration(), s = i ? this.progress * i : 0, r = -1, a = -1 / 0; 1081 t.forEach((o, n) => { 1082 let l2 = parseFloat(o.getAttribute("data-time")); 1083 Number.isFinite(l2) && l2 <= s + 0.05 && l2 > a && (a = l2, r = n); 1084 }), 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(() => { 1085 this.markersContainer?.querySelectorAll(".waveform-marker").forEach((o) => o.classList.remove("show-label")); 1086 }, 2500))); 1087 } 1088 setupHoverTime() { 1089 if (!this.seekEl) return; 1090 let t = document.createElement("div"); 1091 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) => { 1092 this._dragging || this._updateHoverTip(i.clientX); 1093 }), this.seekEl.addEventListener("pointerleave", () => { 1094 this._dragging || this._hideHoverTip(); 1095 })); 1096 } 1097 _updateHoverTip(t) { 1098 let i = this.hoverTimeEl; 1099 if (!i) return; 1100 let s = this.getSeekDuration(); 1101 if (!s) { 1102 i.style.opacity = "0"; 1103 return; 1104 } 1105 let r = this.canvas.getBoundingClientRect(), a = m2((t - r.left) / r.width); 1106 i.textContent = E2(a * s), i.style.left = a * 100 + "%", i.style.opacity = "1"; 1107 } 1108 _hideHoverTip() { 1109 this.hoverTimeEl && (this.hoverTimeEl.style.opacity = "0"); 1110 } 1111 _scrubTo(t) { 1112 let i = this.canvas.getBoundingClientRect(); 1113 if (!i.width) return; 1114 this.progress = m2((t - i.left) / i.width), this.drawWaveform(), this._updateSeekHandle(); 1115 let s = this.getSeekDuration(); 1116 s && this.currentTimeEl ? (this.currentTimeEl.textContent = E2(this.progress * s), this._hideHoverTip()) : this._updateHoverTip(t); 1117 } 1118 setupSeekHandle() { 1119 if (!this.options.seekHandle || this.options.waveformStyle !== "seekbar" || !this.seekEl) return; 1120 let t = document.createElement("div"); 1121 t.className = "waveform-seek-handle", t.setAttribute("aria-hidden", "true"), this.seekEl.appendChild(t), this.seekHandleEl = t; 1122 } 1123 _updateSeekHandle() { 1124 let t = this.seekHandleEl; 1125 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)); 1126 } 1127 handleCanvasClick(t) { 1128 if (this._suppressClick) { 1129 this._suppressClick = false; 1130 return; 1131 } 1132 this._seekFromPointer(t.clientX); 1133 } 1134 _seekFromPointer(t) { 1135 let i = this.canvas.getBoundingClientRect(); 1136 if (!i.width) return; 1137 let s = m2((t - i.left) / i.width); 1138 if (this.options.audioMode === "external") { 1139 this._requestSeek(s); 1140 return; 1141 } 1142 !this.audio || !this.audio.duration || this.seekToPercent(s); 1143 } 1144 setLoading(t) { 1145 if (this.isLoading = t, this.loadingEl) { 1146 let i = t && this.waveformData.length === 0; 1147 this.loadingEl.style.display = i ? "block" : "none"; 1148 } 1149 this.seekEl && this.seekEl.setAttribute("aria-busy", t ? "true" : "false"); 1150 } 1151 onMetadataLoaded() { 1152 this.isDestroying || (this.totalTimeEl && (this.totalTimeEl.textContent = E2(this.audio.duration)), this.renderMarkers(), this.updateSeekAccessibility()); 1153 } 1154 setPlayButtonState(t) { 1155 if (!this.playBtn) return; 1156 this.playBtn.classList.toggle("playing", t); 1157 let i = this.playBtn.querySelector(".waveform-icon-play"), s = this.playBtn.querySelector(".waveform-icon-pause"); 1158 i && (i.style.display = t ? "none" : "flex"), s && (s.style.display = t ? "flex" : "none"); 1159 } 1160 onPlay() { 1161 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)); 1162 } 1163 onPause() { 1164 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)); 1165 } 1166 onEnded() { 1167 if (this.isDestroying) return; 1168 let t = this.audio.duration; 1169 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); 1170 } 1171 onError(t) { 1172 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)); 1173 } 1174 startSmoothUpdate() { 1175 this.stopSmoothUpdate(); 1176 let t = () => { 1177 this.isPlaying && this.audio && this.audio.duration && (this.updateProgress(), this.updateTimer = requestAnimationFrame(t)); 1178 }; 1179 this.updateTimer = requestAnimationFrame(t); 1180 } 1181 stopSmoothUpdate() { 1182 this.updateTimer && (cancelAnimationFrame(this.updateTimer), this.updateTimer = null); 1183 } 1184 updateProgress() { 1185 if (!this.audio || !this.audio.duration || this._dragging) return; 1186 let t = this.audio.currentTime / this.audio.duration; 1187 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(); 1188 } 1189 updateBPMDisplay() { 1190 let t = this.options.bpm || this.detectedBPM; 1191 this.bpmEl && this.bpmValueEl && t && (this.bpmValueEl.textContent = Math.round(t), this.bpmEl.style.display = "inline-flex"); 1192 } 1193 refreshTheme() { 1194 if (!this._autoTheme) return; 1195 this._scheme = R2(this.container); 1196 let t = J(this.options.colorPreset, this.container); 1197 for (let i of this._presetKeys || []) i in t && (this.options[i] = t[i]); 1198 this._applyThemeColors(); 1199 } 1200 _applyThemeColors() { 1201 this.container.classList.toggle("waveform-theme-light", this._scheme === "light"), this.canvas && this.drawWaveform(); 1202 } 1203 static _watchTheme() { 1204 if (e._themeWatch || typeof document > "u") return; 1205 let t = () => requestAnimationFrame(() => { 1206 e.instances.forEach((a) => { 1207 try { 1208 a.refreshTheme(); 1209 } catch { 1210 } 1211 }); 1212 }), i = { attributes: true, attributeFilter: ["class", "data-theme", "data-color-scheme", "style"] }, s = new MutationObserver(t); 1213 s.observe(document.documentElement, i), document.body && s.observe(document.body, i); 1214 let r = null; 1215 try { 1216 r = window.matchMedia("(prefers-color-scheme: dark)"), r.addEventListener("change", t); 1217 } catch { 1218 } 1219 e._themeWatch = { obs: s, mq: r, refresh: t }; 1220 } 1221 updateSpeedUI() { 1222 if (!this.audio) return; 1223 let t = this.container.querySelector(".speed-value"); 1224 if (t) { 1225 let i = this.audio.playbackRate; 1226 t.textContent = i === 1 ? "1x" : `$i}x`; 1227 } 1228 this.container.querySelectorAll(".speed-option").forEach((i) => { 1229 let s = parseFloat(i.dataset.rate) === this.audio.playbackRate; 1230 i.classList.toggle("active", s), i.setAttribute("aria-checked", s ? "true" : "false"); 1231 }); 1232 } 1233 play() { 1234 if (this.options.singlePlay && e.currentlyPlaying && e.currentlyPlaying !== this && e.currentlyPlaying.pause(), this.options.audioMode === "external") { 1235 this._emit("waveformplayer:request-play", this._buildTrackDetail(), true).defaultPrevented || (e.currentlyPlaying = this); 1236 return; 1237 } 1238 return e.currentlyPlaying = this, this.audio.play(); 1239 } 1240 pause() { 1241 if (e.currentlyPlaying === this && (e.currentlyPlaying = null), this.options.audioMode === "external") { 1242 this._emit("waveformplayer:request-pause", this._buildTrackDetail(), true); 1243 return; 1244 } 1245 this.audio.pause(); 1246 } 1247 _buildTrackDetail() { 1248 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 }; 1249 } 1250 setPlayingState(t) { 1251 let i = this.isPlaying; 1252 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)); 1253 } 1254 setProgress(t, i) { 1255 !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()); 1256 } 1257 togglePlay() { 1258 this.isPlaying ? this.pause() : this.play(); 1259 } 1260 seekTo(t) { 1261 this.audio && this.audio.duration && (this.audio.currentTime = m2(t, 0, this.audio.duration), this.updateProgress()); 1262 } 1263 seekToPercent(t) { 1264 this.audio && this.audio.duration && (this.audio.currentTime = this.audio.duration * m2(t), this.updateProgress()); 1265 } 1266 setVolume(t) { 1267 let i = Number(t); 1268 this.audio && Number.isFinite(i) && (this.audio.volume = m2(i)); 1269 } 1270 setPlaybackRate(t) { 1271 if (!this.audio) return; 1272 let i = _(t, null, { min: N2, max: F }); 1273 i !== null && (this.audio.playbackRate = i, this.options.playbackRate = i, this.updateSpeedUI()); 1274 } 1275 destroy() { 1276 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 = []; 1277 } 1278 static getInstance(t) { 1279 if (typeof t == "string") { 1280 let i = this.instances.get(t); 1281 if (i) return i; 1282 let s = document.getElementById(t); 1283 if (s) return Array.from(this.instances.values()).find((r) => r.container === s); 1284 } 1285 if (t instanceof HTMLElement) return Array.from(this.instances.values()).find((i) => i.container === t); 1286 } 1287 static getAllInstances() { 1288 return Array.from(this.instances.values()); 1289 } 1290 static destroyAll() { 1291 this.instances.forEach((t) => t.destroy()), this.instances.clear(); 1292 } 1293 static async generateWaveformData(t, i = 1800) { 1294 try { 1295 return (await G(t, i)).peaks; 1296 } catch (s) { 1297 throw console.error("[WaveformPlayer] Failed to generate waveform:", s), s; 1298 } 1299 } 1300 static getPeaksUrl(t) { 1301 if (!t) return; 1302 let i = t.replace(/\.(mp3|wav|ogg|flac|m4a|aac)(\?[^#]*)?(#.*)?$/i, ".json$2$3"); 1303 return i === t ? void 0 : i; 1304 } 1305 }; 1306 T.utils = { formatTime: E2, extractTitleFromUrl: I, escapeHtml: S, isSafeHref: st, parseDataAttributes: O, detectColorScheme: R2 }; 1307 var et = () => typeof window < "u" && typeof document < "u"; 1308 var Nt = () => true; 1309 function kt(e2) { 1310 if (!(e2.dataset.waveformInitialized === "true" || T.getInstance(e2))) try { 1311 new T(e2), e2.dataset.waveformInitialized = "true"; 1312 } catch (t) { 1313 console.error("[WaveformPlayer] Failed to initialize:", t, e2); 1314 } 1315 } 1316 function tt(e2 = document) { 1317 if (!et()) return; 1318 let t = e2 || document; 1319 t.matches?.("[data-waveform-player]") && kt(t), t.querySelectorAll("[data-waveform-player]").forEach(kt); 1320 } 1321 et() && !Nt() && (document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", () => tt()) : tt()); 1322 T.init = tt; 1323 et() && (window.WaveformPlayer = T); 1324 var se = 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 se(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 : Mon Oct 12 08:20:33 2026 | Cross-referenced by PHPXref |