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