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