build/modules/block-library/playlist
view.js
49.3 KB
6 months ago
view.js.map
88.1 KB
6 months ago
view.min.asset.php
180 B
6 months ago
view.min.js
36.9 KB
6 months ago
view.min.js.map
87.4 KB
6 months ago
view.js in Gutenberg 23.2.0, at build/modules/block-library/playlist/view.js
| 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, t3, n2) { |
| 10 | return void 0 === t3 && (t3 = 0), void 0 === n2 && (n2 = Math.pow(10, t3)), Math.round(n2 * r2) / n2 + 0; |
| 11 | }; |
| 12 | var e = function(r2, t3, n2) { |
| 13 | return void 0 === t3 && (t3 = 0), void 0 === n2 && (n2 = 1), r2 > n2 ? n2 : r2 > t3 ? r2 : t3; |
| 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 t3 = r2.toString(16); |
| 27 | return t3.length < 2 ? "0" + t3 : t3; |
| 28 | }; |
| 29 | var h = function(r2) { |
| 30 | var t3 = r2.r, n2 = r2.g, e2 = r2.b, u2 = r2.a, a2 = Math.max(t3, n2, e2), o2 = a2 - Math.min(t3, n2, e2), i2 = o2 ? a2 === t3 ? (n2 - e2) / o2 : a2 === n2 ? 2 + (e2 - t3) / o2 : 4 + (t3 - 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 t3 = r2.h, n2 = r2.s, e2 = r2.v, u2 = r2.a; |
| 35 | t3 = t3 / 360 * 6, n2 /= 100, e2 /= 100; |
| 36 | var a2 = Math.floor(t3), o2 = e2 * (1 - n2), i2 = e2 * (1 - (t3 - a2) * n2), s2 = e2 * (1 - (1 - t3 + a2) * n2), h2 = a2 % 6; |
| 37 | return { r: 255 * [e2, i2, o2, o2, s2, e2][h2], g: 255 * [s2, e2, e2, i2, o2, o2][h2], b: 255 * [o2, o2, s2, e2, e2, 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 = (t3 = r2).s, { h: t3.h, s: (n2 *= ((e2 = t3.l) < 50 ? e2 : 100 - e2) / 100) > 0 ? 2 * n2 / (e2 + n2) * 100 : 0, v: e2 + n2, a: t3.a })); |
| 47 | var t3, n2, e2; |
| 48 | }; |
| 49 | var c = function(r2) { |
| 50 | return { h: (t3 = h(r2)).h, s: (u2 = (200 - (n2 = t3.s)) * (e2 = t3.v) / 100) > 0 && u2 < 200 ? n2 * e2 / 100 / (u2 <= 100 ? u2 : 200 - u2) * 100 : 0, l: u2 / 2, a: t3.a }; |
| 51 | var t3, n2, e2, 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 t3 = i.exec(r2); |
| 59 | return t3 ? (r2 = t3[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 t3 = v.exec(r2) || m.exec(r2); |
| 62 | return t3 ? t3[2] !== t3[4] || t3[4] !== t3[6] ? null : a({ r: Number(t3[1]) / (t3[2] ? 100 / 255 : 1), g: Number(t3[3]) / (t3[4] ? 100 / 255 : 1), b: Number(t3[5]) / (t3[6] ? 100 / 255 : 1), a: void 0 === t3[7] ? 1 : Number(t3[7]) / (t3[8] ? 100 : 1) }) : null; |
| 63 | }, "rgb"], [function(t3) { |
| 64 | var n2 = l.exec(t3) || p.exec(t3); |
| 65 | if (!n2) return null; |
| 66 | var e2, u2, a2 = g({ h: (e2 = n2[1], u2 = n2[2], void 0 === u2 && (u2 = "deg"), Number(e2) * (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, e2 = r2.g, u2 = r2.b, o2 = r2.a, i2 = void 0 === o2 ? 1 : o2; |
| 70 | return t(n2) && t(e2) && t(u2) ? a({ r: Number(n2), g: Number(e2), b: Number(u2), a: Number(i2) }) : null; |
| 71 | }, "rgb"], [function(r2) { |
| 72 | var n2 = r2.h, e2 = r2.s, u2 = r2.l, a2 = r2.a, o2 = void 0 === a2 ? 1 : a2; |
| 73 | if (!t(n2) || !t(e2) || !t(u2)) return null; |
| 74 | var i2 = g({ h: Number(n2), s: Number(e2), 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, t3) { |
| 85 | for (var n2 = 0; n2 < t3.length; n2++) { |
| 86 | var e2 = t3[n2][0](r2); |
| 87 | if (e2) return [e2, t3[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, t3) { |
| 95 | var n2 = c(r2); |
| 96 | return { h: n2.h, s: e(n2.s + 100 * t3, 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, t3) { |
| 102 | var n2 = c(r2); |
| 103 | return { h: n2.h, s: n2.s, l: e(n2.l + 100 * t3, 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), t3 = r3.r, e2 = r3.g, u2 = r3.b, i2 = (a2 = r3.a) < 1 ? s(n(255 * a2)) : "", "#" + s(t3) + s(e2) + s(u2) + i2; |
| 119 | var r3, t3, e2, u2, a2, i2; |
| 120 | }, r2.prototype.toRgb = function() { |
| 121 | return o(this.rgba); |
| 122 | }, r2.prototype.toRgbString = function() { |
| 123 | return r3 = o(this.rgba), t3 = r3.r, n2 = r3.g, e2 = r3.b, (u2 = r3.a) < 1 ? "rgba(" + t3 + ", " + n2 + ", " + e2 + ", " + u2 + ")" : "rgb(" + t3 + ", " + n2 + ", " + e2 + ")"; |
| 124 | var r3, t3, n2, e2, u2; |
| 125 | }, r2.prototype.toHsl = function() { |
| 126 | return d(c(this.rgba)); |
| 127 | }, r2.prototype.toHslString = function() { |
| 128 | return r3 = d(c(this.rgba)), t3 = r3.h, n2 = r3.s, e2 = r3.l, (u2 = r3.a) < 1 ? "hsla(" + t3 + ", " + n2 + "%, " + e2 + "%, " + u2 + ")" : "hsl(" + t3 + ", " + n2 + "%, " + e2 + "%)"; |
| 129 | var r3, t3, n2, e2, 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: (t3 = this.rgba).r, g: t3.g, b: t3.b, a: r3 }) : n(this.rgba.a, 3); |
| 150 | var t3; |
| 151 | }, r2.prototype.hue = function(r3) { |
| 152 | var t3 = c(this.rgba); |
| 153 | return "number" == typeof r3 ? w({ h: r3, s: t3.s, l: t3.l, a: t3.a }) : n(t3.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 | // packages/block-library/node_modules/@arraypress/waveform-player/dist/waveform-player.esm.js |
| 163 | function L(t3) { |
| 164 | let e2 = {}; |
| 165 | if (t3.dataset.url && (e2.url = t3.dataset.url), t3.dataset.height && (e2.height = parseInt(t3.dataset.height)), t3.dataset.samples && (e2.samples = parseInt(t3.dataset.samples)), t3.dataset.preload && (e2.preload = t3.dataset.preload), t3.dataset.waveformStyle && (e2.waveformStyle = t3.dataset.waveformStyle), t3.dataset.barWidth && (e2.barWidth = parseInt(t3.dataset.barWidth)), t3.dataset.barSpacing && (e2.barSpacing = parseInt(t3.dataset.barSpacing)), t3.dataset.buttonAlign && (e2.buttonAlign = t3.dataset.buttonAlign), t3.dataset.colorPreset && (e2.colorPreset = t3.dataset.colorPreset), t3.dataset.waveformColor && (e2.waveformColor = t3.dataset.waveformColor), t3.dataset.progressColor && (e2.progressColor = t3.dataset.progressColor), t3.dataset.buttonColor && (e2.buttonColor = t3.dataset.buttonColor), t3.dataset.buttonHoverColor && (e2.buttonHoverColor = t3.dataset.buttonHoverColor), t3.dataset.textColor && (e2.textColor = t3.dataset.textColor), t3.dataset.textSecondaryColor && (e2.textSecondaryColor = t3.dataset.textSecondaryColor), t3.dataset.backgroundColor && (e2.backgroundColor = t3.dataset.backgroundColor), t3.dataset.borderColor && (e2.borderColor = t3.dataset.borderColor), t3.dataset.color && (e2.waveformColor = t3.dataset.color), t3.dataset.theme && (e2.colorPreset = t3.dataset.theme), t3.dataset.autoplay && (e2.autoplay = t3.dataset.autoplay === "true"), t3.dataset.showTime && (e2.showTime = t3.dataset.showTime === "true"), t3.dataset.showHoverTime && (e2.showHoverTime = t3.dataset.showHoverTime === "true"), t3.dataset.showBpm && (e2.showBPM = t3.dataset.showBpm === "true"), t3.dataset.singlePlay && (e2.singlePlay = t3.dataset.singlePlay === "true"), t3.dataset.playOnSeek && (e2.playOnSeek = t3.dataset.playOnSeek === "true"), t3.dataset.title && (e2.title = t3.dataset.title), t3.dataset.subtitle && (e2.subtitle = t3.dataset.subtitle), t3.dataset.album && (e2.album = t3.dataset.album), t3.dataset.artwork && (e2.artwork = t3.dataset.artwork), t3.dataset.waveform && (e2.waveform = t3.dataset.waveform), t3.dataset.markers) try { |
| 166 | e2.markers = JSON.parse(t3.dataset.markers); |
| 167 | } catch (i2) { |
| 168 | console.warn("Invalid markers JSON:", i2); |
| 169 | } |
| 170 | if (t3.dataset.playbackRate && (e2.playbackRate = parseFloat(t3.dataset.playbackRate)), t3.dataset.showPlaybackSpeed !== void 0 && (e2.showPlaybackSpeed = t3.dataset.showPlaybackSpeed === "true"), t3.dataset.playbackRates) try { |
| 171 | e2.playbackRates = JSON.parse(t3.dataset.playbackRates); |
| 172 | } catch (i2) { |
| 173 | console.warn("Invalid playbackRates JSON:", i2); |
| 174 | } |
| 175 | return t3.dataset.enableMediaSession !== void 0 && (e2.enableMediaSession = t3.dataset.enableMediaSession === "true"), e2; |
| 176 | } |
| 177 | function P(t3) { |
| 178 | if (!t3 || isNaN(t3)) return "0:00"; |
| 179 | let e2 = Math.floor(t3 / 60), i2 = Math.floor(t3 % 60); |
| 180 | return `${e2}:${i2.toString().padStart(2, "0")}`; |
| 181 | } |
| 182 | function A(t3) { |
| 183 | let e2 = t3 || Math.random().toString(); |
| 184 | return btoa(e2.substring(0, 10)).replace(/[^a-zA-Z0-9]/g, ""); |
| 185 | } |
| 186 | function R(t3) { |
| 187 | if (!t3) return "Audio"; |
| 188 | let e2 = t3.split("/"); |
| 189 | return e2[e2.length - 1].split(".")[0].replace(/[-_]/g, " ").replace(/\b\w/g, (s2) => s2.toUpperCase()); |
| 190 | } |
| 191 | function C(...t3) { |
| 192 | let e2 = {}; |
| 193 | for (let i2 of t3) for (let a2 in i2) i2[a2] !== null && i2[a2] !== void 0 && (e2[a2] = i2[a2]); |
| 194 | return e2; |
| 195 | } |
| 196 | function B(t3, e2) { |
| 197 | let i2; |
| 198 | return function(...s2) { |
| 199 | let n2 = () => { |
| 200 | clearTimeout(i2), t3(...s2); |
| 201 | }; |
| 202 | clearTimeout(i2), i2 = setTimeout(n2, e2); |
| 203 | }; |
| 204 | } |
| 205 | function S(t3, e2) { |
| 206 | if (t3.length === e2) return t3; |
| 207 | if (t3.length === 0 || e2 === 0) return []; |
| 208 | let i2 = []; |
| 209 | if (e2 > t3.length) { |
| 210 | let a2 = (t3.length - 1) / (e2 - 1); |
| 211 | for (let s2 = 0; s2 < e2; s2++) { |
| 212 | let n2 = s2 * a2, r2 = Math.floor(n2), o2 = Math.ceil(n2), h2 = n2 - r2; |
| 213 | if (o2 >= t3.length) i2.push(t3[t3.length - 1]); |
| 214 | else if (r2 === o2) i2.push(t3[r2]); |
| 215 | else { |
| 216 | let l2 = t3[r2] * (1 - h2) + t3[o2] * h2; |
| 217 | i2.push(l2); |
| 218 | } |
| 219 | } |
| 220 | } else { |
| 221 | let a2 = t3.length / e2; |
| 222 | for (let s2 = 0; s2 < e2; s2++) { |
| 223 | let n2 = Math.floor(s2 * a2), r2 = Math.floor((s2 + 1) * a2), o2 = 0, h2 = 0; |
| 224 | for (let l2 = n2; l2 <= r2 && l2 < t3.length; l2++) t3[l2] > o2 && (o2 = t3[l2]), h2++; |
| 225 | if (h2 === 0) { |
| 226 | let l2 = Math.min(Math.round(s2 * a2), t3.length - 1); |
| 227 | o2 = t3[l2]; |
| 228 | } |
| 229 | i2.push(o2); |
| 230 | } |
| 231 | } |
| 232 | return i2; |
| 233 | } |
| 234 | function x2(t3, e2, i2, a2, s2) { |
| 235 | let n2 = window.devicePixelRatio || 1, r2 = s2.barWidth * n2, o2 = s2.barSpacing * n2, h2 = Math.floor(e2.width / (r2 + o2)), l2 = S(i2, h2), d2 = e2.height, p2 = a2 * e2.width; |
| 236 | t3.clearRect(0, 0, e2.width, e2.height); |
| 237 | for (let y2 = 0; y2 < l2.length; y2++) { |
| 238 | let f2 = y2 * (r2 + o2); |
| 239 | if (f2 + r2 > e2.width) break; |
| 240 | let c2 = l2[y2] * d2 * 0.9, m2 = d2 - c2; |
| 241 | t3.fillStyle = s2.color, t3.fillRect(f2, m2, r2, c2); |
| 242 | } |
| 243 | t3.save(), t3.beginPath(), t3.rect(0, 0, p2, d2), t3.clip(); |
| 244 | for (let y2 = 0; y2 < l2.length; y2++) { |
| 245 | let f2 = y2 * (r2 + o2); |
| 246 | if (f2 > p2) break; |
| 247 | let c2 = l2[y2] * d2 * 0.9, m2 = d2 - c2; |
| 248 | t3.fillStyle = s2.progressColor, t3.fillRect(f2, m2, r2, c2); |
| 249 | } |
| 250 | t3.restore(); |
| 251 | } |
| 252 | function q(t3, e2, i2, a2, s2) { |
| 253 | let n2 = window.devicePixelRatio || 1, r2 = s2.barWidth * n2, o2 = s2.barSpacing * n2, h2 = Math.floor(e2.width / (r2 + o2)), l2 = S(i2, h2), d2 = e2.height, p2 = d2 / 2, y2 = a2 * e2.width; |
| 254 | t3.clearRect(0, 0, e2.width, e2.height); |
| 255 | for (let f2 = 0; f2 < l2.length; f2++) { |
| 256 | let c2 = f2 * (r2 + o2); |
| 257 | if (c2 + r2 > e2.width) break; |
| 258 | let m2 = l2[f2] * d2 * 0.45; |
| 259 | t3.fillStyle = s2.color, t3.fillRect(c2, p2 - m2, r2, m2), t3.fillRect(c2, p2, r2, m2); |
| 260 | } |
| 261 | t3.save(), t3.beginPath(), t3.rect(0, 0, y2, d2), t3.clip(); |
| 262 | for (let f2 = 0; f2 < l2.length; f2++) { |
| 263 | let c2 = f2 * (r2 + o2); |
| 264 | if (c2 > y2) break; |
| 265 | let m2 = l2[f2] * d2 * 0.45; |
| 266 | t3.fillStyle = s2.progressColor, t3.fillRect(c2, p2 - m2, r2, m2), t3.fillRect(c2, p2, r2, m2); |
| 267 | } |
| 268 | t3.restore(); |
| 269 | } |
| 270 | function $2(t3, e2, i2, a2, s2) { |
| 271 | let n2 = e2.width, r2 = e2.height, o2 = r2 / 2, h2 = r2 * 0.35; |
| 272 | t3.clearRect(0, 0, n2, r2); |
| 273 | let l2 = (d2, p2, y2 = 1, f2 = false) => { |
| 274 | f2 && (t3.shadowBlur = 12, t3.shadowColor = d2), t3.strokeStyle = d2, t3.lineWidth = p2, t3.lineCap = "round", t3.lineJoin = "round", t3.beginPath(), t3.moveTo(0, o2); |
| 275 | let c2 = [], m2 = Math.floor(i2.length * y2); |
| 276 | for (let u2 = 0; u2 < m2; u2++) { |
| 277 | let v2 = u2 / (i2.length - 1) * n2, k = i2[u2], b2 = Math.sin(u2 * 0.1) * k, w2 = o2 + b2 * h2; |
| 278 | c2.push({ x: v2, y: w2 }); |
| 279 | } |
| 280 | for (let u2 = 0; u2 < c2.length - 1; u2++) { |
| 281 | let v2 = c2[u2].x + (c2[u2 + 1].x - c2[u2].x) * 0.5, k = c2[u2].y, b2 = c2[u2 + 1].x - (c2[u2 + 1].x - c2[u2].x) * 0.5, w2 = c2[u2 + 1].y; |
| 282 | t3.bezierCurveTo(v2, k, b2, w2, c2[u2 + 1].x, c2[u2 + 1].y); |
| 283 | } |
| 284 | t3.stroke(), f2 && (t3.shadowBlur = 0); |
| 285 | }; |
| 286 | t3.strokeStyle = "rgba(255, 255, 255, 0.03)", t3.lineWidth = 0.5, t3.beginPath(), t3.moveTo(0, o2), t3.lineTo(n2, o2), t3.stroke(); |
| 287 | for (let d2 = 0; d2 <= 10; d2++) { |
| 288 | let p2 = n2 / 10 * d2; |
| 289 | t3.beginPath(), t3.moveTo(p2, 0), t3.lineTo(p2, r2), t3.stroke(); |
| 290 | } |
| 291 | l2(s2.color, 2, 1, false), a2 > 0 && l2(s2.progressColor, 3, a2, true); |
| 292 | } |
| 293 | function U(t3, e2, i2, a2, s2) { |
| 294 | let n2 = window.devicePixelRatio || 1, r2 = (s2.barWidth || 3) * n2, o2 = (s2.barSpacing || 1) * n2, h2 = Math.floor(e2.width / (r2 + o2)), l2 = S(i2, h2), d2 = e2.height, p2 = 4 * n2, y2 = 2 * n2, f2 = a2 * e2.width, c2 = d2 / 2; |
| 295 | t3.clearRect(0, 0, e2.width, e2.height); |
| 296 | for (let m2 = 0; m2 < l2.length; m2++) { |
| 297 | let u2 = m2 * (r2 + o2); |
| 298 | if (u2 + r2 > e2.width) break; |
| 299 | let v2 = l2[m2] * d2 * 0.9, k = Math.floor(v2 / (p2 + y2)); |
| 300 | t3.fillStyle = u2 < f2 ? s2.progressColor : s2.color; |
| 301 | for (let b2 = 0; b2 < k; b2++) { |
| 302 | let w2 = b2 * (p2 + y2); |
| 303 | t3.fillRect(u2, c2 - w2 - p2, r2, p2), b2 > 0 && t3.fillRect(u2, c2 + w2, r2, p2); |
| 304 | } |
| 305 | } |
| 306 | } |
| 307 | function F(t3, e2, i2, a2, s2) { |
| 308 | let n2 = window.devicePixelRatio || 1, r2 = (s2.barWidth || 2) * n2, o2 = (s2.barSpacing || 3) * n2, h2 = Math.floor(e2.width / (r2 + o2)), l2 = S(i2, h2), d2 = e2.height, p2 = Math.max(1.5 * n2, r2 / 2), y2 = a2 * e2.width, f2 = d2 / 2; |
| 309 | t3.clearRect(0, 0, e2.width, e2.height); |
| 310 | for (let c2 = 0; c2 < l2.length; c2++) { |
| 311 | let m2 = c2 * (r2 + o2) + r2 / 2; |
| 312 | if (m2 > e2.width) break; |
| 313 | let u2 = l2[c2] * d2 * 0.9; |
| 314 | t3.fillStyle = m2 < y2 ? s2.progressColor : s2.color, t3.beginPath(), t3.arc(m2, f2 - u2 / 2, p2, 0, Math.PI * 2), t3.fill(), t3.beginPath(), t3.arc(m2, f2 + u2 / 2, p2, 0, Math.PI * 2), t3.fill(); |
| 315 | } |
| 316 | } |
| 317 | function N2(t3, e2, i2, a2, s2) { |
| 318 | let n2 = e2.width, r2 = e2.height, o2 = r2 / 2, h2 = 4, l2 = h2 / 2; |
| 319 | if (t3.clearRect(0, 0, n2, r2), t3.fillStyle = s2.color || "rgba(255, 255, 255, 0.2)", t3.beginPath(), t3.moveTo(l2, o2 - h2 / 2), t3.lineTo(n2 - l2, o2 - h2 / 2), t3.arc(n2 - l2, o2, h2 / 2, -Math.PI / 2, Math.PI / 2), t3.lineTo(l2, o2 + h2 / 2), t3.arc(l2, o2, h2 / 2, Math.PI / 2, -Math.PI / 2), t3.closePath(), t3.fill(), a2 > 0) { |
| 320 | let d2 = Math.max(l2 * 2, a2 * n2); |
| 321 | t3.shadowBlur = 8, t3.shadowColor = s2.progressColor, t3.fillStyle = s2.progressColor || "rgba(255, 255, 255, 0.9)", t3.beginPath(), t3.moveTo(l2, o2 - h2 / 2), t3.lineTo(d2 - l2, o2 - h2 / 2), t3.arc(d2 - l2, o2, h2 / 2, -Math.PI / 2, Math.PI / 2), t3.lineTo(l2, o2 + h2 / 2), t3.arc(l2, o2, h2 / 2, Math.PI / 2, -Math.PI / 2), t3.closePath(), t3.fill(), t3.shadowBlur = 0; |
| 322 | let p2 = 8, y2 = d2; |
| 323 | t3.shadowBlur = 4, t3.shadowColor = "rgba(0, 0, 0, 0.3)", t3.shadowOffsetY = 2, t3.fillStyle = "#ffffff", t3.beginPath(), t3.arc(y2, o2, p2, 0, Math.PI * 2), t3.fill(), t3.shadowBlur = 0, t3.shadowOffsetY = 0, t3.fillStyle = s2.progressColor || "rgba(255, 255, 255, 0.9)", t3.beginPath(), t3.arc(y2, o2, p2 * 0.4, 0, Math.PI * 2), t3.fill(); |
| 324 | } |
| 325 | } |
| 326 | var Y = { bars: x2, mirror: q, line: $2, blocks: U, dots: F, seekbar: N2 }; |
| 327 | function W(t3, e2, i2, a2, s2) { |
| 328 | (Y[s2.waveformStyle] || x2)(t3, e2, i2, a2, s2); |
| 329 | } |
| 330 | function I(t3) { |
| 331 | try { |
| 332 | let e2 = t3.getChannelData(0), i2 = t3.sampleRate, a2 = j2(e2, i2); |
| 333 | if (a2.length < 2) return 120; |
| 334 | let s2 = []; |
| 335 | for (let h2 = 1; h2 < a2.length; h2++) s2.push((a2[h2] - a2[h2 - 1]) / i2); |
| 336 | let n2 = {}; |
| 337 | s2.forEach((h2) => { |
| 338 | let l2 = 60 / h2, d2 = Math.round(l2 / 3) * 3; |
| 339 | d2 > 60 && d2 < 200 && (n2[d2] = (n2[d2] || 0) + 1); |
| 340 | }); |
| 341 | let r2 = 0, o2 = 120; |
| 342 | for (let [h2, l2] of Object.entries(n2)) l2 > r2 && (r2 = l2, o2 = parseInt(h2)); |
| 343 | return o2 < 70 && n2[o2 * 2] ? o2 *= 2 : o2 > 160 && n2[Math.round(o2 / 2)] && (o2 = Math.round(o2 / 2)), o2 - 1; |
| 344 | } catch (e2) { |
| 345 | return console.warn("BPM detection failed:", e2), null; |
| 346 | } |
| 347 | } |
| 348 | function j2(t3, e2) { |
| 349 | let s2 = [], n2 = 0; |
| 350 | for (let r2 = 0; r2 < t3.length - 2048; r2 += 1024) { |
| 351 | let o2 = 0; |
| 352 | for (let d2 = r2; d2 < r2 + 2048; d2++) o2 += t3[d2] * t3[d2]; |
| 353 | o2 = o2 / 2048; |
| 354 | let h2 = o2 - n2, l2 = n2 * 1.8 + 0.01; |
| 355 | if (h2 > l2 && o2 > 0.01) { |
| 356 | let d2 = s2[s2.length - 1] || 0, p2 = e2 * 0.15; |
| 357 | r2 - d2 > p2 && s2.push(r2); |
| 358 | } |
| 359 | n2 = o2 * 0.8 + n2 * 0.2; |
| 360 | } |
| 361 | return s2; |
| 362 | } |
| 363 | function V(t3, e2 = 200) { |
| 364 | let i2 = t3.length / e2, a2 = ~~(i2 / 10) || 1, s2 = t3.numberOfChannels, n2 = []; |
| 365 | for (let o2 = 0; o2 < s2; o2++) { |
| 366 | let h2 = t3.getChannelData(o2); |
| 367 | for (let l2 = 0; l2 < e2; l2++) { |
| 368 | let d2 = ~~(l2 * i2), p2 = ~~(d2 + i2), y2 = 0, f2 = 0; |
| 369 | for (let m2 = d2; m2 < p2; m2 += a2) { |
| 370 | let u2 = h2[m2]; |
| 371 | u2 > f2 && (f2 = u2), u2 < y2 && (y2 = u2); |
| 372 | } |
| 373 | let c2 = Math.max(Math.abs(f2), Math.abs(y2)); |
| 374 | (o2 === 0 || c2 > n2[l2]) && (n2[l2] = c2); |
| 375 | } |
| 376 | } |
| 377 | let r2 = Math.max(...n2); |
| 378 | return r2 > 0 ? n2.map((o2) => o2 / r2) : n2; |
| 379 | } |
| 380 | async function M2(t3, e2 = 200, i2 = false) { |
| 381 | try { |
| 382 | let a2 = new (window.AudioContext || window.webkitAudioContext)(), n2 = await (await fetch(t3)).arrayBuffer(), r2 = await a2.decodeAudioData(n2), o2 = V(r2, e2); |
| 383 | o2 = J(o2); |
| 384 | let h2 = null; |
| 385 | return i2 && (h2 = await I(r2)), a2.close(), { peaks: o2, bpm: h2 }; |
| 386 | } catch (a2) { |
| 387 | throw console.error("Failed to generate waveform:", a2), a2; |
| 388 | } |
| 389 | } |
| 390 | function D(t3 = 200) { |
| 391 | let e2 = []; |
| 392 | for (let i2 = 0; i2 < t3; i2++) { |
| 393 | let a2 = Math.random() * 0.5 + 0.3, s2 = Math.sin(i2 / t3 * Math.PI * 4) * 0.2; |
| 394 | e2.push(Math.max(0.1, Math.min(1, a2 + s2))); |
| 395 | } |
| 396 | return e2; |
| 397 | } |
| 398 | function J(t3, e2 = 0.95) { |
| 399 | let i2 = Math.max(...t3); |
| 400 | if (i2 === 0 || i2 > e2) return t3; |
| 401 | let a2 = e2 / i2; |
| 402 | return t3.map((s2) => s2 * a2); |
| 403 | } |
| 404 | function G() { |
| 405 | let t3 = document.documentElement, e2 = document.body; |
| 406 | if (t3.classList.contains("dark") || t3.classList.contains("dark-mode") || t3.classList.contains("theme-dark") || t3.getAttribute("data-theme") === "dark" || t3.getAttribute("data-color-scheme") === "dark" || e2.classList.contains("dark") || e2.classList.contains("dark-mode") || e2.getAttribute("data-theme") === "dark") return "dark"; |
| 407 | if (t3.classList.contains("light") || t3.classList.contains("light-mode") || t3.classList.contains("theme-light") || t3.getAttribute("data-theme") === "light" || t3.getAttribute("data-color-scheme") === "light" || e2.classList.contains("light") || e2.classList.contains("light-mode") || e2.getAttribute("data-theme") === "light") return "light"; |
| 408 | try { |
| 409 | let a2 = getComputedStyle(document.body).backgroundColor.match(/\d+/g); |
| 410 | if (a2 && a2.length >= 3) { |
| 411 | let [s2, n2, r2] = a2.map(Number), o2 = (s2 * 299 + n2 * 587 + r2 * 114) / 1e3; |
| 412 | if (o2 > 128) return "light"; |
| 413 | if (o2 < 128) return "dark"; |
| 414 | } |
| 415 | } catch { |
| 416 | } |
| 417 | if (window.matchMedia) { |
| 418 | if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark"; |
| 419 | if (window.matchMedia("(prefers-color-scheme: light)").matches) return "light"; |
| 420 | } |
| 421 | return "dark"; |
| 422 | } |
| 423 | var E = { dark: { waveformColor: "rgba(255, 255, 255, 0.3)", progressColor: "rgba(255, 255, 255, 0.9)", buttonColor: "rgba(255, 255, 255, 0.9)", buttonHoverColor: "rgba(255, 255, 255, 1)", textColor: "#ffffff", textSecondaryColor: "rgba(255, 255, 255, 0.6)", backgroundColor: "rgba(255, 255, 255, 0.03)", borderColor: "rgba(255, 255, 255, 0.1)" }, light: { waveformColor: "rgba(0, 0, 0, 0.2)", progressColor: "rgba(0, 0, 0, 0.8)", buttonColor: "rgba(0, 0, 0, 0.8)", buttonHoverColor: "rgba(0, 0, 0, 0.9)", textColor: "#333333", textSecondaryColor: "rgba(0, 0, 0, 0.6)", backgroundColor: "rgba(0, 0, 0, 0.02)", borderColor: "rgba(0, 0, 0, 0.1)" } }; |
| 424 | function z(t3) { |
| 425 | if (t3 && E[t3]) return E[t3]; |
| 426 | let e2 = G(); |
| 427 | return E[e2]; |
| 428 | } |
| 429 | var O = { url: "", height: 60, samples: 200, preload: "metadata", playbackRate: 1, showPlaybackSpeed: false, playbackRates: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], buttonAlign: "auto", waveformStyle: "mirror", barWidth: 2, barSpacing: 0, colorPreset: null, waveformColor: null, progressColor: null, buttonColor: null, buttonHoverColor: null, textColor: null, textSecondaryColor: null, backgroundColor: null, borderColor: null, autoplay: false, showTime: true, showHoverTime: false, showBPM: false, singlePlay: true, playOnSeek: true, enableMediaSession: true, markers: [], showMarkers: true, title: null, subtitle: null, artwork: null, album: "", 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 }; |
| 430 | var H2 = { bars: { barWidth: 3, barSpacing: 1 }, mirror: { barWidth: 2, barSpacing: 0 }, line: { barWidth: 2, barSpacing: 0 }, blocks: { barWidth: 4, barSpacing: 2 }, dots: { barWidth: 3, barSpacing: 3 }, seekbar: { barWidth: 1, barSpacing: 0 } }; |
| 431 | var g2 = class t2 { |
| 432 | static instances = /* @__PURE__ */ new Map(); |
| 433 | static currentlyPlaying = null; |
| 434 | constructor(e2, i2 = {}) { |
| 435 | if (this.container = typeof e2 == "string" ? document.querySelector(e2) : e2, !this.container) throw new Error("WaveformPlayer: Container element not found"); |
| 436 | let a2 = L(this.container); |
| 437 | this.options = C(O, a2, i2); |
| 438 | let s2 = z(this.options.colorPreset); |
| 439 | for (let [r2, o2] of Object.entries(s2)) (this.options[r2] === null || this.options[r2] === void 0) && (this.options[r2] = o2); |
| 440 | let n2 = H2[this.options.waveformStyle]; |
| 441 | n2 && (a2.barWidth === void 0 && i2.barWidth === void 0 && (this.options.barWidth = n2.barWidth), a2.barSpacing === void 0 && i2.barSpacing === void 0 && (this.options.barSpacing = n2.barSpacing)), this.audio = null, this.canvas = null, this.ctx = null, this.waveformData = [], this.progress = 0, this.isPlaying = false, this.isLoading = false, this.hasError = false, this.updateTimer = null, this.resizeObserver = null, this.id = this.container.id || A(this.options.url), t2.instances.set(this.id, this), this.init(), setTimeout(() => { |
| 442 | this.container.dispatchEvent(new CustomEvent("waveformplayer:ready", { bubbles: true, detail: { player: this, url: this.options.url } })); |
| 443 | }, 100); |
| 444 | } |
| 445 | init() { |
| 446 | this.createDOM(), this.createAudio(), this.initPlaybackSpeed(), this.initKeyboardControls(), this.bindEvents(), this.setupResizeObserver(), requestAnimationFrame(() => { |
| 447 | this.resizeCanvas(), this.options.url && this.load(this.options.url).then(() => { |
| 448 | this.options.autoplay && this.play(); |
| 449 | }).catch((e2) => { |
| 450 | console.error("Failed to load audio:", e2); |
| 451 | }); |
| 452 | }); |
| 453 | } |
| 454 | createDOM() { |
| 455 | this.container.innerHTML = "", this.container.className = "waveform-player"; |
| 456 | let e2 = this.options.buttonAlign; |
| 457 | e2 === "auto" && (this.options.waveformStyle === "bars" ? e2 = "bottom" : e2 = "center"), this.container.innerHTML = ` |
| 458 | <div class="waveform-player-inner"> |
| 459 | <div class="waveform-body"> |
| 460 | <div class="waveform-track waveform-align-${e2}"> |
| 461 | <button class="waveform-btn" aria-label="Play/Pause" style=" |
| 462 | border-color: ${this.options.buttonColor}; |
| 463 | color: ${this.options.buttonColor}; |
| 464 | "> |
| 465 | <span class="waveform-icon-play">${this.options.playIcon}</span> |
| 466 | <span class="waveform-icon-pause" style="display:none;">${this.options.pauseIcon}</span> |
| 467 | </button> |
| 468 | |
| 469 | <div class="waveform-container"> |
| 470 | <canvas></canvas> |
| 471 | <div class="waveform-markers"></div> |
| 472 | <div class="waveform-loading" style="display:none;"></div> |
| 473 | <div class="waveform-error" style="display:none;"> |
| 474 | <span class="waveform-error-text">Unable to load audio</span> |
| 475 | </div> |
| 476 | </div> |
| 477 | </div> |
| 478 | |
| 479 | <div class="waveform-info"> |
| 480 | ${this.options.artwork ? ` |
| 481 | <img class="waveform-artwork" src="${this.options.artwork}" alt="Album artwork" style=" |
| 482 | width: 40px; |
| 483 | height: 40px; |
| 484 | border-radius: 4px; |
| 485 | object-fit: cover; |
| 486 | flex-shrink: 0; |
| 487 | "> |
| 488 | ` : ""} |
| 489 | <div class="waveform-text"> |
| 490 | <span class="waveform-title" style="color: ${this.options.textColor};"></span> |
| 491 | ${this.options.subtitle ? `<span class="waveform-subtitle" style="color: ${this.options.textSecondaryColor};">${this.options.subtitle}</span>` : ""} |
| 492 | </div> |
| 493 | <div style="display: flex; align-items: center; gap: 1rem;"> |
| 494 | ${this.options.showBPM ? ` |
| 495 | <span class="waveform-bpm" style="color: ${this.options.textSecondaryColor}; display: none;"> |
| 496 | <span class="bpm-value">--</span> BPM |
| 497 | </span> |
| 498 | ` : ""} |
| 499 | ${this.options.showPlaybackSpeed ? ` |
| 500 | <div class="waveform-speed"> |
| 501 | <button class="speed-btn" aria-label="Playback speed"> |
| 502 | <span class="speed-value">1x</span> |
| 503 | </button> |
| 504 | <div class="speed-menu" style="display: none;"> |
| 505 | ${this.options.playbackRates.map((i2) => `<button class="speed-option" data-rate="${i2}">${i2}x</button>`).join("")} |
| 506 | </div> |
| 507 | </div> |
| 508 | ` : ""} |
| 509 | ${this.options.showTime ? ` |
| 510 | <span class="waveform-time" style="color: ${this.options.textSecondaryColor};"> |
| 511 | <span class="time-current">0:00</span> / <span class="time-total">0:00</span> |
| 512 | </span> |
| 513 | ` : ""} |
| 514 | </div> |
| 515 | </div> |
| 516 | </div> |
| 517 | </div> |
| 518 | `, 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.subtitleEl = this.container.querySelector(".waveform-subtitle"), this.artworkEl = this.container.querySelector(".waveform-artwork"), 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(); |
| 519 | } |
| 520 | createAudio() { |
| 521 | this.audio = new Audio(), this.audio.preload = this.options.preload || "metadata", this.audio.crossOrigin = "anonymous"; |
| 522 | } |
| 523 | initPlaybackSpeed() { |
| 524 | this.options.playbackRate && this.options.playbackRate !== 1 && (this.audio.playbackRate = this.options.playbackRate), this.options.showPlaybackSpeed && this.initSpeedControls(); |
| 525 | } |
| 526 | initSpeedControls() { |
| 527 | let e2 = this.container.querySelector(".speed-btn"), i2 = this.container.querySelector(".speed-menu"); |
| 528 | !e2 || !i2 || (e2.addEventListener("click", (a2) => { |
| 529 | a2.stopPropagation(), i2.style.display = i2.style.display === "none" ? "block" : "none"; |
| 530 | }), document.addEventListener("click", () => { |
| 531 | i2.style.display = "none"; |
| 532 | }), i2.addEventListener("click", (a2) => { |
| 533 | if (a2.stopPropagation(), a2.target.classList.contains("speed-option")) { |
| 534 | let s2 = parseFloat(a2.target.dataset.rate); |
| 535 | this.setPlaybackRate(s2), i2.style.display = "none"; |
| 536 | } |
| 537 | }), this.updateSpeedUI()); |
| 538 | } |
| 539 | initKeyboardControls() { |
| 540 | this.container.setAttribute("tabindex", "-1"), this.container.addEventListener("click", () => { |
| 541 | t2.getAllInstances().forEach((e2) => { |
| 542 | e2 !== this && e2.container.setAttribute("tabindex", "-1"); |
| 543 | }), this.container.setAttribute("tabindex", "0"), this.container.focus(); |
| 544 | }), this.container.addEventListener("keydown", (e2) => { |
| 545 | if (document.activeElement !== this.container) return; |
| 546 | let i2 = e2.key, a2 = this.audio.currentTime; |
| 547 | if (i2 >= "0" && i2 <= "9") { |
| 548 | e2.preventDefault(), this.seekToPercent(parseInt(i2) / 10); |
| 549 | return; |
| 550 | } |
| 551 | let s2 = { " ": () => this.togglePlay(), ArrowLeft: () => this.seekTo(Math.max(0, a2 - 5)), ArrowRight: () => this.seekTo(Math.min(this.audio.duration, a2 + 5)), ArrowUp: () => this.setVolume(Math.min(1, this.audio.volume + 0.1)), ArrowDown: () => this.setVolume(Math.max(0, this.audio.volume - 0.1)), m: () => this.audio.muted = !this.audio.muted, M: () => this.audio.muted = !this.audio.muted }; |
| 552 | s2[i2] && (e2.preventDefault(), s2[i2]()); |
| 553 | }); |
| 554 | } |
| 555 | initMediaSession() { |
| 556 | !("mediaSession" in navigator) || !this.options.enableMediaSession || (navigator.mediaSession.metadata = new MediaMetadata({ title: this.options.title || "Unknown Track", artist: this.options.subtitle || "", album: this.options.album || "", artwork: this.options.artwork ? [{ src: this.options.artwork, sizes: "512x512", type: "image/jpeg" }] : [] }), navigator.mediaSession.setActionHandler("play", () => this.play()), navigator.mediaSession.setActionHandler("pause", () => this.pause()), navigator.mediaSession.setActionHandler("seekbackward", () => { |
| 557 | this.seekTo(Math.max(0, this.audio.currentTime - 10)); |
| 558 | }), navigator.mediaSession.setActionHandler("seekforward", () => { |
| 559 | this.seekTo(Math.min(this.audio.duration, this.audio.currentTime + 10)); |
| 560 | }), navigator.mediaSession.setActionHandler("seekto", (e2) => { |
| 561 | e2.seekTime !== null && this.seekTo(e2.seekTime); |
| 562 | })); |
| 563 | } |
| 564 | bindEvents() { |
| 565 | this.playBtn.addEventListener("click", () => this.togglePlay()), 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", (e2) => this.onError(e2)), this.canvas.addEventListener("click", (e2) => this.handleCanvasClick(e2)), this.resizeHandler = B(() => this.resizeCanvas(), 100), window.addEventListener("resize", this.resizeHandler); |
| 566 | } |
| 567 | setupResizeObserver() { |
| 568 | "ResizeObserver" in window && (this.resizeObserver = new ResizeObserver(() => { |
| 569 | this.resizeCanvas(); |
| 570 | }), this.canvas?.parentElement && this.resizeObserver.observe(this.canvas.parentElement)); |
| 571 | } |
| 572 | async load(e2) { |
| 573 | try { |
| 574 | this.setLoading(true), this.progress = 0, this.hasError = false, this.audio.src = e2, await new Promise((a2, s2) => { |
| 575 | let n2 = () => { |
| 576 | this.audio.removeEventListener("loadedmetadata", n2), this.audio.removeEventListener("error", r2), a2(); |
| 577 | }, r2 = (o2) => { |
| 578 | this.audio.removeEventListener("loadedmetadata", n2), this.audio.removeEventListener("error", r2), s2(o2); |
| 579 | }; |
| 580 | this.audio.addEventListener("loadedmetadata", n2), this.audio.addEventListener("error", r2); |
| 581 | }); |
| 582 | let i2 = this.options.title || R(e2); |
| 583 | if (this.titleEl && (this.titleEl.textContent = i2), this.options.waveform) this.setWaveformData(this.options.waveform); |
| 584 | else try { |
| 585 | let a2 = await M2(e2, this.options.samples, this.options.showBPM); |
| 586 | this.waveformData = a2.peaks, a2.bpm && (this.detectedBPM = a2.bpm, this.updateBPMDisplay()); |
| 587 | } catch (a2) { |
| 588 | console.warn("Using placeholder waveform:", a2), this.waveformData = D(this.options.samples); |
| 589 | } |
| 590 | this.drawWaveform(), this.renderMarkers(), this.initMediaSession(), this.options.onLoad && this.options.onLoad(this); |
| 591 | } catch (i2) { |
| 592 | console.error("Failed to load audio:", i2), this.onError(i2); |
| 593 | } finally { |
| 594 | this.setLoading(false); |
| 595 | } |
| 596 | } |
| 597 | async loadTrack(e2, i2 = null, a2 = null, s2 = {}) { |
| 598 | this.isPlaying && this.pause(), 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 = C(this.options, { url: e2, title: i2 || this.options.title, subtitle: a2 || this.options.subtitle, ...s2 }), s2.preload && (this.audio.preload = s2.preload), this.subtitleEl && (a2 ? (this.subtitleEl.textContent = a2, this.subtitleEl.style.display = "") : a2 === "" && (this.subtitleEl.style.display = "none")), s2.artwork && this.artworkEl && (this.artworkEl.src = s2.artwork), s2.markers && (this.options.markers = s2.markers), await this.load(e2), this.play(); |
| 599 | } |
| 600 | setWaveformData(e2) { |
| 601 | if (typeof e2 == "string") try { |
| 602 | let i2 = JSON.parse(e2); |
| 603 | this.waveformData = Array.isArray(i2) ? i2 : []; |
| 604 | } catch { |
| 605 | this.waveformData = e2.split(",").map(Number); |
| 606 | } |
| 607 | else this.waveformData = Array.isArray(e2) ? e2 : []; |
| 608 | this.drawWaveform(); |
| 609 | } |
| 610 | drawWaveform() { |
| 611 | !this.ctx || this.waveformData.length === 0 || W(this.ctx, this.canvas, this.waveformData, this.progress, { ...this.options, waveformStyle: this.options.waveformStyle || "bars", color: this.options.waveformColor, progressColor: this.options.progressColor }); |
| 612 | } |
| 613 | resizeCanvas() { |
| 614 | if (!this.canvas || this.isDestroying) return; |
| 615 | let e2 = window.devicePixelRatio || 1, i2 = this.canvas.getBoundingClientRect(); |
| 616 | this.canvas.width = i2.width * e2, this.canvas.height = this.options.height * e2, this.canvas.style.height = this.options.height + "px", this.canvas.parentElement.style.height = this.options.height + "px", this.drawWaveform(); |
| 617 | } |
| 618 | renderMarkers() { |
| 619 | !this.options.showMarkers || !this.options.markers?.length || !this.markersContainer || (this.markersContainer.innerHTML = "", !(!this.audio || !this.audio.duration || this.audio.duration === 0) && this.options.markers.forEach((e2, i2) => { |
| 620 | if (e2.time > this.audio.duration) { |
| 621 | console.warn(`Marker "${e2.label}" at ${e2.time}s exceeds audio duration of ${this.audio.duration}s`); |
| 622 | return; |
| 623 | } |
| 624 | let a2 = e2.time / this.audio.duration * 100, s2 = document.createElement("button"); |
| 625 | s2.className = "waveform-marker", s2.style.left = `${a2}%`, s2.style.backgroundColor = e2.color || "rgba(255, 255, 255, 0.5)", s2.setAttribute("aria-label", e2.label), s2.setAttribute("data-time", e2.time); |
| 626 | let n2 = document.createElement("span"); |
| 627 | n2.className = "waveform-marker-tooltip", n2.textContent = e2.label, s2.appendChild(n2), s2.addEventListener("click", (r2) => { |
| 628 | r2.stopPropagation(), this.seekTo(e2.time), this.options.playOnSeek && !this.isPlaying && this.play(); |
| 629 | }), this.markersContainer.appendChild(s2); |
| 630 | })); |
| 631 | } |
| 632 | handleCanvasClick(e2) { |
| 633 | if (!this.audio.duration) return; |
| 634 | let i2 = this.canvas.getBoundingClientRect(), a2 = e2.clientX - i2.left, s2 = Math.max(0, Math.min(1, a2 / i2.width)); |
| 635 | this.seekToPercent(s2); |
| 636 | } |
| 637 | setLoading(e2) { |
| 638 | this.isLoading = e2, this.loadingEl && (this.loadingEl.style.display = e2 ? "block" : "none"); |
| 639 | } |
| 640 | onMetadataLoaded() { |
| 641 | this.isDestroying || (this.totalTimeEl && (this.totalTimeEl.textContent = P(this.audio.duration)), this.renderMarkers()); |
| 642 | } |
| 643 | onPlay() { |
| 644 | if (this.isDestroying) return; |
| 645 | this.isPlaying = true, this.playBtn.classList.add("playing"); |
| 646 | let e2 = this.playBtn.querySelector(".waveform-icon-play"), i2 = this.playBtn.querySelector(".waveform-icon-pause"); |
| 647 | e2 && (e2.style.display = "none"), i2 && (i2.style.display = "flex"), this.startSmoothUpdate(), this.container.dispatchEvent(new CustomEvent("waveformplayer:play", { bubbles: true, detail: { player: this, url: this.options.url } })), this.options.onPlay && this.options.onPlay(this); |
| 648 | } |
| 649 | onPause() { |
| 650 | if (this.isDestroying) return; |
| 651 | this.isPlaying = false, this.playBtn.classList.remove("playing"); |
| 652 | let e2 = this.playBtn.querySelector(".waveform-icon-play"), i2 = this.playBtn.querySelector(".waveform-icon-pause"); |
| 653 | e2 && (e2.style.display = "flex"), i2 && (i2.style.display = "none"), this.stopSmoothUpdate(), this.container.dispatchEvent(new CustomEvent("waveformplayer:pause", { bubbles: true, detail: { player: this, url: this.options.url } })), this.options.onPause && this.options.onPause(this); |
| 654 | } |
| 655 | onEnded() { |
| 656 | this.isDestroying || (this.progress = 0, this.audio.currentTime = 0, this.drawWaveform(), this.currentTimeEl && (this.currentTimeEl.textContent = "0:00"), this.container.dispatchEvent(new CustomEvent("waveformplayer:ended", { bubbles: true, detail: { player: this, url: this.options.url } })), this.onPause(), this.options.onEnd && this.options.onEnd(this)); |
| 657 | } |
| 658 | onError(e2) { |
| 659 | this.isDestroying || (console.error("Audio error:", e2), 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(e2, this)); |
| 660 | } |
| 661 | startSmoothUpdate() { |
| 662 | this.stopSmoothUpdate(); |
| 663 | let e2 = () => { |
| 664 | this.isPlaying && this.audio.duration && (this.updateProgress(), this.updateTimer = requestAnimationFrame(e2)); |
| 665 | }; |
| 666 | this.updateTimer = requestAnimationFrame(e2); |
| 667 | } |
| 668 | stopSmoothUpdate() { |
| 669 | this.updateTimer && (cancelAnimationFrame(this.updateTimer), this.updateTimer = null); |
| 670 | } |
| 671 | updateProgress() { |
| 672 | if (!this.audio.duration) return; |
| 673 | let e2 = this.audio.currentTime / this.audio.duration; |
| 674 | Math.abs(e2 - this.progress) > 1e-3 && (this.progress = e2, this.drawWaveform()), this.currentTimeEl && (this.currentTimeEl.textContent = P(this.audio.currentTime)), this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate", { bubbles: true, detail: { player: this, currentTime: this.audio.currentTime, duration: this.audio.duration, url: this.options.url } })), this.options.onTimeUpdate && this.options.onTimeUpdate(this.audio.currentTime, this.audio.duration, this); |
| 675 | } |
| 676 | updateBPMDisplay() { |
| 677 | this.bpmEl && this.bpmValueEl && this.detectedBPM && (this.bpmValueEl.textContent = Math.round(this.detectedBPM), this.bpmEl.style.display = "inline-flex"); |
| 678 | } |
| 679 | updateSpeedUI() { |
| 680 | let e2 = this.container.querySelector(".speed-value"); |
| 681 | if (e2) { |
| 682 | let i2 = this.audio.playbackRate; |
| 683 | e2.textContent = i2 === 1 ? "1x" : `${i2}x`; |
| 684 | } |
| 685 | this.container.querySelectorAll(".speed-option").forEach((i2) => { |
| 686 | i2.classList.toggle("active", parseFloat(i2.dataset.rate) === this.audio.playbackRate); |
| 687 | }); |
| 688 | } |
| 689 | play() { |
| 690 | this.options.singlePlay && t2.currentlyPlaying && t2.currentlyPlaying !== this && t2.currentlyPlaying.pause(), t2.currentlyPlaying = this, this.audio.play(); |
| 691 | } |
| 692 | pause() { |
| 693 | t2.currentlyPlaying === this && (t2.currentlyPlaying = null), this.audio.pause(); |
| 694 | } |
| 695 | togglePlay() { |
| 696 | this.isPlaying ? this.pause() : this.play(); |
| 697 | } |
| 698 | seekTo(e2) { |
| 699 | this.audio && this.audio.duration && (this.audio.currentTime = Math.max(0, Math.min(e2, this.audio.duration)), this.updateProgress()); |
| 700 | } |
| 701 | seekToPercent(e2) { |
| 702 | this.audio && this.audio.duration && (this.audio.currentTime = this.audio.duration * Math.max(0, Math.min(1, e2)), this.updateProgress()); |
| 703 | } |
| 704 | setVolume(e2) { |
| 705 | this.audio && (this.audio.volume = Math.max(0, Math.min(1, e2))); |
| 706 | } |
| 707 | setPlaybackRate(e2) { |
| 708 | if (!this.audio) return; |
| 709 | let i2 = Math.max(0.5, Math.min(2, e2)); |
| 710 | this.audio.playbackRate = i2, this.options.playbackRate = i2, this.updateSpeedUI(); |
| 711 | } |
| 712 | destroy() { |
| 713 | this.isDestroying = true, this.pause(), this.stopSmoothUpdate(), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this.resizeHandler && (window.removeEventListener("resize", this.resizeHandler), this.resizeHandler = null), t2.instances.delete(this.id), t2.currentlyPlaying === this && (t2.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 = []; |
| 714 | } |
| 715 | static getInstance(e2) { |
| 716 | if (typeof e2 == "string") { |
| 717 | let i2 = this.instances.get(e2); |
| 718 | if (i2) return i2; |
| 719 | let a2 = document.getElementById(e2); |
| 720 | if (a2) return Array.from(this.instances.values()).find((s2) => s2.container === a2); |
| 721 | } |
| 722 | if (e2 instanceof HTMLElement) return Array.from(this.instances.values()).find((i2) => i2.container === e2); |
| 723 | } |
| 724 | static getAllInstances() { |
| 725 | return Array.from(this.instances.values()); |
| 726 | } |
| 727 | static destroyAll() { |
| 728 | this.instances.forEach((e2) => e2.destroy()), this.instances.clear(); |
| 729 | } |
| 730 | static async generateWaveformData(e2, i2 = 200) { |
| 731 | try { |
| 732 | return (await M2(e2, i2)).peaks; |
| 733 | } catch (a2) { |
| 734 | throw console.error("Failed to generate waveform:", a2), a2; |
| 735 | } |
| 736 | } |
| 737 | }; |
| 738 | function T() { |
| 739 | if (typeof document > "u") return; |
| 740 | document.querySelectorAll("[data-waveform-player]").forEach((e2) => { |
| 741 | if (e2.dataset.waveformInitialized !== "true") try { |
| 742 | new g2(e2), e2.dataset.waveformInitialized = "true"; |
| 743 | } catch (i2) { |
| 744 | console.error("Failed to initialize WaveformPlayer:", i2, e2); |
| 745 | } |
| 746 | }); |
| 747 | } |
| 748 | typeof document < "u" && (document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", T) : T()); |
| 749 | g2.init = T; |
| 750 | typeof window < "u" && (window.WaveformPlayer = g2); |
| 751 | var lt = g2; |
| 752 | |
| 753 | // packages/block-library/build-module/utils/waveform-utils.mjs |
| 754 | var DEFAULT_WAVEFORM_HEIGHT = 100; |
| 755 | function getComputedStyle2(element) { |
| 756 | return element.ownerDocument.defaultView.getComputedStyle(element); |
| 757 | } |
| 758 | function getWaveformColors(element) { |
| 759 | const textColor = getComputedStyle2(element).color; |
| 760 | const waveformColor = w(textColor).alpha(0.3).toRgbString(); |
| 761 | const progressColor = w(textColor).alpha(0.6).toRgbString(); |
| 762 | return { textColor, waveformColor, progressColor }; |
| 763 | } |
| 764 | function createWaveformContainer({ |
| 765 | url, |
| 766 | title, |
| 767 | artist, |
| 768 | artwork, |
| 769 | waveformColor, |
| 770 | progressColor, |
| 771 | buttonColor, |
| 772 | height = DEFAULT_WAVEFORM_HEIGHT |
| 773 | }) { |
| 774 | const container = document.createElement("div"); |
| 775 | container.setAttribute("data-waveform-player", ""); |
| 776 | container.setAttribute("data-url", url); |
| 777 | container.setAttribute("data-height", String(height)); |
| 778 | container.setAttribute("data-waveform-style", "bars"); |
| 779 | container.setAttribute("data-waveform-color", waveformColor); |
| 780 | container.setAttribute("data-progress-color", progressColor); |
| 781 | container.setAttribute("data-button-color", buttonColor); |
| 782 | container.setAttribute("data-text-color", buttonColor); |
| 783 | container.setAttribute("data-text-secondary-color", buttonColor); |
| 784 | if (title) { |
| 785 | container.setAttribute("data-title", title); |
| 786 | } |
| 787 | if (artist) { |
| 788 | container.setAttribute("data-subtitle", artist); |
| 789 | } |
| 790 | if (artwork) { |
| 791 | container.setAttribute("data-artwork", artwork); |
| 792 | } |
| 793 | return container; |
| 794 | } |
| 795 | function styleSvgIcons(container, buttonColor) { |
| 796 | const isButtonDark = w(buttonColor).isDark(); |
| 797 | const iconColor = isButtonDark ? "#ffffff" : "#000000"; |
| 798 | const svgPaths = container.querySelectorAll("svg path"); |
| 799 | svgPaths.forEach((path) => { |
| 800 | path.style.fill = iconColor; |
| 801 | }); |
| 802 | } |
| 803 | function setupPlayButtonAccessibility(container, { play: playLabel = "Play", pause: pauseLabel = "Pause" } = {}) { |
| 804 | const playBtn = container.querySelector(".waveform-btn"); |
| 805 | if (!playBtn) { |
| 806 | return; |
| 807 | } |
| 808 | playBtn.setAttribute("aria-label", playLabel); |
| 809 | const onPlay = () => playBtn.setAttribute("aria-label", pauseLabel); |
| 810 | const onPause = () => playBtn.setAttribute("aria-label", playLabel); |
| 811 | container.addEventListener("waveformplayer:play", onPlay); |
| 812 | container.addEventListener("waveformplayer:pause", onPause); |
| 813 | container.addEventListener("waveformplayer:ended", onPause); |
| 814 | return () => { |
| 815 | container.removeEventListener("waveformplayer:play", onPlay); |
| 816 | container.removeEventListener("waveformplayer:pause", onPause); |
| 817 | container.removeEventListener("waveformplayer:ended", onPause); |
| 818 | }; |
| 819 | } |
| 820 | function logPlayError(error) { |
| 821 | if (error.name === "AbortError") { |
| 822 | return; |
| 823 | } |
| 824 | console.error("Playlist play error:", error); |
| 825 | } |
| 826 | function initWaveformPlayer(element, { src, title, artist, image, autoPlay, onEnded, labels }) { |
| 827 | const { textColor, waveformColor, progressColor } = getWaveformColors(element); |
| 828 | const container = createWaveformContainer({ |
| 829 | url: src, |
| 830 | title, |
| 831 | artist, |
| 832 | artwork: image, |
| 833 | waveformColor, |
| 834 | progressColor, |
| 835 | buttonColor: textColor |
| 836 | }); |
| 837 | element.appendChild(container); |
| 838 | const instance = new lt(container); |
| 839 | let cleanupAccessibility; |
| 840 | const handlers = { |
| 841 | ready: () => { |
| 842 | styleSvgIcons(container, textColor); |
| 843 | cleanupAccessibility = setupPlayButtonAccessibility( |
| 844 | container, |
| 845 | labels |
| 846 | ); |
| 847 | if (autoPlay) { |
| 848 | instance.play()?.catch(logPlayError); |
| 849 | } |
| 850 | }, |
| 851 | ended: () => onEnded?.() |
| 852 | }; |
| 853 | container.addEventListener("waveformplayer:ready", handlers.ready); |
| 854 | container.addEventListener("waveformplayer:ended", handlers.ended); |
| 855 | return { |
| 856 | instance, |
| 857 | container, |
| 858 | destroy: () => { |
| 859 | cleanupAccessibility?.(); |
| 860 | container.removeEventListener( |
| 861 | "waveformplayer:ready", |
| 862 | handlers.ready |
| 863 | ); |
| 864 | container.removeEventListener( |
| 865 | "waveformplayer:ended", |
| 866 | handlers.ended |
| 867 | ); |
| 868 | instance.destroy(); |
| 869 | container.remove(); |
| 870 | } |
| 871 | }; |
| 872 | } |
| 873 | |
| 874 | // packages/block-library/build-module/playlist/view.mjs |
| 875 | var playerState = /* @__PURE__ */ new WeakMap(); |
| 876 | var { state } = store( |
| 877 | "core/playlist", |
| 878 | { |
| 879 | state: { |
| 880 | playlists: {}, |
| 881 | get isCurrentTrack() { |
| 882 | const { currentId, uniqueId } = getContext(); |
| 883 | return currentId === uniqueId; |
| 884 | } |
| 885 | }, |
| 886 | actions: { |
| 887 | changeTrack() { |
| 888 | const context = getContext(); |
| 889 | context.currentId = context.uniqueId; |
| 890 | } |
| 891 | }, |
| 892 | callbacks: { |
| 893 | initWaveformPlayer() { |
| 894 | const context = getContext(); |
| 895 | const { ref } = getElement(); |
| 896 | if (!context.currentId || !ref) { |
| 897 | return; |
| 898 | } |
| 899 | const track = state.playlists[context.playlistId]?.tracks[context.currentId]; |
| 900 | if (!track?.url) { |
| 901 | return; |
| 902 | } |
| 903 | const existing = playerState.get(ref); |
| 904 | if (existing?.url === track.url) { |
| 905 | return; |
| 906 | } |
| 907 | const shouldAutoPlay = !!existing?.url; |
| 908 | initPlayer(ref, track, shouldAutoPlay, context); |
| 909 | } |
| 910 | } |
| 911 | }, |
| 912 | { lock: true } |
| 913 | ); |
| 914 | function initPlayer(ref, track, shouldAutoPlay, context) { |
| 915 | const existing = playerState.get(ref); |
| 916 | if (existing?.instance) { |
| 917 | existing.instance.loadTrack(track.url, track.title, track.artist, { |
| 918 | artwork: track.image |
| 919 | }).then(() => { |
| 920 | existing.url = track.url; |
| 921 | if (shouldAutoPlay) { |
| 922 | existing.instance.play()?.catch(logPlayError); |
| 923 | } |
| 924 | }).catch(logPlayError); |
| 925 | return; |
| 926 | } |
| 927 | const labels = { |
| 928 | play: ref.dataset.labelPlay, |
| 929 | pause: ref.dataset.labelPause |
| 930 | }; |
| 931 | const player = initWaveformPlayer(ref, { |
| 932 | src: track.url, |
| 933 | title: track.title, |
| 934 | artist: track.artist, |
| 935 | image: track.image, |
| 936 | autoPlay: shouldAutoPlay, |
| 937 | labels, |
| 938 | onEnded: () => { |
| 939 | const currentIndex = context.tracks.findIndex( |
| 940 | (uniqueId) => uniqueId === context.currentId |
| 941 | ); |
| 942 | const nextTrack = context.tracks[currentIndex + 1]; |
| 943 | if (nextTrack) { |
| 944 | context.currentId = nextTrack; |
| 945 | } |
| 946 | } |
| 947 | }); |
| 948 | playerState.set(ref, { |
| 949 | url: track.url, |
| 950 | instance: player.instance, |
| 951 | destroy: player.destroy |
| 952 | }); |
| 953 | } |
| 954 | //# sourceMappingURL=view.js.map |
| 955 |