[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/script-modules/block-library/playlist/ -> view.js (source)

   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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
 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  }


Generated : Mon Oct 12 08:20:33 2026 Cross-referenced by PHPXref