@arraypress/waveform-player 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # WaveformPlayer
2
2
 
3
- A lightweight, customizable audio player with waveform visualization. Under 6KB gzipped.
3
+ A lightweight, customizable audio player with waveform visualization. Under 8KB gzipped.
4
4
 
5
- **[Live Demo](https://waveformplayer.com)** | **[Documentation](https://waveformplayer.com/#docs)** | **[NPM Package](https://www.npmjs.com/package/@arraypress/waveform-player)**
5
+ **[Live Demo](https://waveformplayer.com)** | **[Documentation](https://waveformplayer.com/#docs)** | *
6
+ *[NPM Package](https://www.npmjs.com/package/@arraypress/waveform-player)**
6
7
 
7
8
  ![Version](https://img.shields.io/npm/v/@arraypress/waveform-player)
8
9
  ![Size](https://img.shields.io/bundlephobia/minzip/@arraypress/waveform-player)
@@ -14,12 +15,45 @@ A lightweight, customizable audio player with waveform visualization. Under 6KB
14
15
  ## Why WaveformPlayer?
15
16
 
16
17
  - **Zero Config** - Just add `data-waveform-player` to any div. No JavaScript required.
17
- - **Tiny** - 8KB gzipped vs 40KB+ for alternatives
18
+ - **Tiny** - ~8KB gzipped vs 40KB+ for alternatives
18
19
  - **Real Waveforms** - Actual audio analysis, not fake waves
19
20
  - **No Dependencies** - No jQuery, no bloat, pure vanilla JS
20
21
  - **Works Everywhere** - WordPress, Shopify, React, Vue, or plain HTML
21
22
  - **Ecosystem** - Optional playlist and analytics addons available
22
23
 
24
+ ## What's New in 1.2.1
25
+
26
+ ### 🐛 Bug Fixes
27
+
28
+ - Fixed null reference error when `destroy()` is called during resize events
29
+ - Cleaned up window resize listener on destroy to prevent memory leaks
30
+ - Added destruction guards to all event handlers to prevent race conditions
31
+ - Added `bubbles: true` to all custom events for better framework integration
32
+
33
+ Thanks to [@scruffian](https://github.com/scruffian) for contributing these fixes.
34
+
35
+ ## What's New in 1.2.0
36
+
37
+ ### 🎨 Automatic Theme Detection
38
+
39
+ WaveformPlayer now automatically adapts to your website's color scheme - no configuration needed!
40
+
41
+ **Features:**
42
+
43
+ - Detects light/dark themes automatically
44
+ - Checks background brightness, theme classes, and system preferences
45
+ - Works seamlessly on WordPress, Shopify, and all platforms
46
+ - Override with explicit `data-color-preset="light"` or `"dark"` if needed
47
+
48
+ **How it works:**
49
+
50
+ 1. Checks for explicit theme classes (`.dark-mode`, `.light-mode`, etc.)
51
+ 2. Analyzes background brightness
52
+ 3. Respects system color preferences (`prefers-color-scheme`)
53
+ 4. Falls back to sensible defaults
54
+
55
+ [View live examples →](https://waveformplayer.com/modes/dark.html)
56
+
23
57
  ## Quick Start
24
58
 
25
59
  Simplest possible usage:
@@ -32,18 +66,23 @@ Simplest possible usage:
32
66
  ## Installation
33
67
 
34
68
  ### NPM
69
+
35
70
  ```bash
36
71
  npm install @arraypress/waveform-player
37
72
  ```
38
73
 
39
74
  ### CDN
75
+
40
76
  ```html
77
+
41
78
  <link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-player@latest/dist/waveform-player.css">
42
79
  <script src="https://unpkg.com/@arraypress/waveform-player@latest/dist/waveform-player.min.js"></script>
43
80
  ```
44
81
 
45
82
  ### Download
83
+
46
84
  ```html
85
+
47
86
  <link rel="stylesheet" href="waveform-player.css">
48
87
  <script src="waveform-player.js"></script>
49
88
  ```
@@ -67,29 +106,32 @@ npm install @arraypress/waveform-player
67
106
  ## Ecosystem
68
107
 
69
108
  ### WaveformPlaylist (Optional Addon)
109
+
70
110
  Add playlist and chapter support with zero JavaScript:
71
111
 
72
112
  ```html
113
+
73
114
  <div data-waveform-playlist data-continuous="true">
74
- <div data-track data-url="song1.mp3" data-title="Track 1">
75
- <div data-chapter data-time="0:00">Intro</div>
76
- <div data-chapter data-time="2:30">Verse</div>
77
- </div>
78
- <div data-track data-url="song2.mp3" data-title="Track 2"></div>
115
+ <div data-track data-url="song1.mp3" data-title="Track 1">
116
+ <div data-chapter data-time="0:00">Intro</div>
117
+ <div data-chapter data-time="2:30">Verse</div>
118
+ </div>
119
+ <div data-track data-url="song2.mp3" data-title="Track 2"></div>
79
120
  </div>
80
121
  ```
81
122
 
82
123
  [Learn more →](https://github.com/arraypress/waveform-playlist)
83
124
 
84
125
  ### WaveformTracker (Optional Addon)
126
+
85
127
  Track meaningful audio engagement:
86
128
 
87
129
  ```javascript
88
130
  WaveformTracker.init({
89
- endpoint: '/api/analytics',
90
- events: {
91
- listen: 30 // Track after 30 seconds of listening
92
- }
131
+ endpoint: '/api/analytics',
132
+ events: {
133
+ listen: 30 // Track after 30 seconds of listening
134
+ }
93
135
  });
94
136
  ```
95
137
 
@@ -97,22 +139,24 @@ WaveformTracker.init({
97
139
 
98
140
  ## Comparison
99
141
 
100
- | Feature | WaveformPlayer | WaveSurfer.js | Amplitude.js |
101
- |---------|----------------|---------------|--------------|
102
- | Size (gzipped) | 8KB | 40KB+ | 35KB+ |
103
- | Zero Config | ✅ | ❌ | ❌ |
104
- | Dependencies | None | None | None |
105
- | Waveform Styles | 6 | 3 | N/A |
106
- | Setup Time | 30 seconds | 5+ minutes | 5+ minutes |
107
- | Real Waveforms | ✅ | ✅ | ❌ |
108
- | Keyboard Controls | ✅ | ✅ | ❌ |
109
- | Media Session API | ✅ | ❌ | ❌ |
110
- | Speed Control | ✅ | ✅ | ❌ |
142
+ | Feature | WaveformPlayer | WaveSurfer.js | Amplitude.js |
143
+ |-------------------|----------------|---------------|--------------|
144
+ | Size (gzipped) | ~8KB | 40KB+ | 35KB+ |
145
+ | Zero Config | ✅ | ❌ | ❌ |
146
+ | Dependencies | None | None | None |
147
+ | Waveform Styles | 6 | 3 | N/A |
148
+ | Setup Time | 30 seconds | 5+ minutes | 5+ minutes |
149
+ | Real Waveforms | ✅ | ✅ | ❌ |
150
+ | Keyboard Controls | ✅ | ✅ | ❌ |
151
+ | Media Session API | ✅ | ❌ | ❌ |
152
+ | Speed Control | ✅ | ✅ | ❌ |
111
153
 
112
154
  ## Usage
113
155
 
114
156
  ### HTML (Zero JavaScript)
157
+
115
158
  ```html
159
+
116
160
  <div data-waveform-player
117
161
  data-url="audio.mp3"
118
162
  data-title="My Song"
@@ -124,6 +168,7 @@ WaveformTracker.init({
124
168
  ```
125
169
 
126
170
  ### JavaScript API
171
+
127
172
  ```javascript
128
173
  import WaveformPlayer from '@arraypress/waveform-player';
129
174
 
@@ -153,27 +198,27 @@ Choose from 6 built-in styles:
153
198
 
154
199
  ## Options
155
200
 
156
- | Option | Type | Default | Description |
157
- |--------|------|---------|-------------|
158
- | `url` | string | `''` | Audio file URL |
159
- | `waveformStyle` | string | `'bars'` | Visual style: bars, mirror, line, blocks, dots, seekbar |
160
- | `height` | number | `60` | Waveform height in pixels |
161
- | `barWidth` | number | `3` | Width of waveform bars |
162
- | `barSpacing` | number | `1` | Space between bars |
163
- | `samples` | number | `200` | Number of waveform samples |
164
- | `waveformColor` | string | `'rgba(255,255,255,0.3)'` | Waveform color |
165
- | `progressColor` | string | `'rgba(255,255,255,0.9)'` | Progress color |
166
- | `buttonColor` | string | `'rgba(255,255,255,0.9)'` | Play button color |
167
- | `showTime` | boolean | `true` | Show time display |
168
- | `showBPM` | boolean | `false` | Enable BPM detection |
169
- | `showPlaybackSpeed` | boolean | `false` | Show speed control menu |
170
- | `playbackRate` | number | `1` | Initial playback speed (0.5-2) |
171
- | `autoplay` | boolean | `false` | Autoplay on load |
172
- | `title` | string | `''` | Track title |
173
- | `subtitle` | string | `''` | Track subtitle |
174
- | `artwork` | string | `''` | Album artwork URL |
175
- | `markers` | array | `[]` | Chapter markers array |
176
- | `enableMediaSession` | boolean | `true` | Enable system media controls |
201
+ | Option | Type | Default | Description |
202
+ |----------------------|---------|---------------------------|---------------------------------------------------------|
203
+ | `url` | string | `''` | Audio file URL |
204
+ | `waveformStyle` | string | `'bars'` | Visual style: bars, mirror, line, blocks, dots, seekbar |
205
+ | `height` | number | `60` | Waveform height in pixels |
206
+ | `barWidth` | number | `3` | Width of waveform bars |
207
+ | `barSpacing` | number | `1` | Space between bars |
208
+ | `samples` | number | `200` | Number of waveform samples |
209
+ | `waveformColor` | string | `'rgba(255,255,255,0.3)'` | Waveform color |
210
+ | `progressColor` | string | `'rgba(255,255,255,0.9)'` | Progress color |
211
+ | `buttonColor` | string | `'rgba(255,255,255,0.9)'` | Play button color |
212
+ | `showTime` | boolean | `true` | Show time display |
213
+ | `showBPM` | boolean | `false` | Enable BPM detection |
214
+ | `showPlaybackSpeed` | boolean | `false` | Show speed control menu |
215
+ | `playbackRate` | number | `1` | Initial playback speed (0.5-2) |
216
+ | `autoplay` | boolean | `false` | Autoplay on load |
217
+ | `title` | string | `''` | Track title |
218
+ | `subtitle` | string | `''` | Track subtitle |
219
+ | `artwork` | string | `''` | Album artwork URL |
220
+ | `markers` | array | `[]` | Chapter markers array |
221
+ | `enableMediaSession` | boolean | `true` | Enable system media controls |
177
222
 
178
223
  ## API Methods
179
224
 
@@ -271,41 +316,44 @@ WaveformPlayer.destroyAll();
271
316
  ## Framework Integration
272
317
 
273
318
  ### React
319
+
274
320
  ```jsx
275
- import { useEffect, useRef } from 'react';
321
+ import {useEffect, useRef} from 'react';
276
322
  import WaveformPlayer from '@arraypress/waveform-player';
277
323
 
278
- function AudioPlayer({ url }) {
324
+ function AudioPlayer({url}) {
279
325
  const playerRef = useRef();
280
-
326
+
281
327
  useEffect(() => {
282
- const player = new WaveformPlayer(playerRef.current, { url });
328
+ const player = new WaveformPlayer(playerRef.current, {url});
283
329
  return () => player.destroy();
284
330
  }, [url]);
285
-
286
- return <div ref={playerRef} />;
331
+
332
+ return <div ref={playerRef}/>;
287
333
  }
288
334
  ```
289
335
 
290
336
  ### Vue
337
+
291
338
  ```vue
339
+
292
340
  <template>
293
341
  <div ref="player"></div>
294
342
  </template>
295
343
 
296
344
  <script>
297
- import WaveformPlayer from '@arraypress/waveform-player';
298
-
299
- export default {
300
- mounted() {
301
- this.player = new WaveformPlayer(this.$refs.player, {
302
- url: this.audioUrl
303
- });
304
- },
305
- beforeDestroy() {
306
- this.player?.destroy();
345
+ import WaveformPlayer from '@arraypress/waveform-player';
346
+
347
+ export default {
348
+ mounted() {
349
+ this.player = new WaveformPlayer(this.$refs.player, {
350
+ url: this.audioUrl
351
+ });
352
+ },
353
+ beforeDestroy() {
354
+ this.player?.destroy();
355
+ }
307
356
  }
308
- }
309
357
  </script>
310
358
  ```
311
359
 
@@ -319,6 +367,7 @@ export default {
319
367
  ## Examples
320
368
 
321
369
  See the [live demo](https://waveformplayer.com) for:
370
+
322
371
  - All visual styles
323
372
  - Custom styling examples
324
373
  - Event handling
@@ -1,4 +1,4 @@
1
- function L(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&&(e.height=parseInt(t.dataset.height)),t.dataset.samples&&(e.samples=parseInt(t.dataset.samples)),t.dataset.preload&&(e.preload=t.dataset.preload),t.dataset.waveformStyle&&(e.waveformStyle=t.dataset.waveformStyle),t.dataset.barWidth&&(e.barWidth=parseInt(t.dataset.barWidth)),t.dataset.barSpacing&&(e.barSpacing=parseInt(t.dataset.barSpacing)),t.dataset.buttonAlign&&(e.buttonAlign=t.dataset.buttonAlign),t.dataset.colorPreset&&(e.colorPreset=t.dataset.colorPreset),t.dataset.waveformColor&&(e.waveformColor=t.dataset.waveformColor),t.dataset.progressColor&&(e.progressColor=t.dataset.progressColor),t.dataset.buttonColor&&(e.buttonColor=t.dataset.buttonColor),t.dataset.buttonHoverColor&&(e.buttonHoverColor=t.dataset.buttonHoverColor),t.dataset.textColor&&(e.textColor=t.dataset.textColor),t.dataset.textSecondaryColor&&(e.textSecondaryColor=t.dataset.textSecondaryColor),t.dataset.backgroundColor&&(e.backgroundColor=t.dataset.backgroundColor),t.dataset.borderColor&&(e.borderColor=t.dataset.borderColor),t.dataset.color&&(e.waveformColor=t.dataset.color),t.dataset.theme&&(e.colorPreset=t.dataset.theme),t.dataset.autoplay&&(e.autoplay=t.dataset.autoplay==="true"),t.dataset.showTime&&(e.showTime=t.dataset.showTime==="true"),t.dataset.showHoverTime&&(e.showHoverTime=t.dataset.showHoverTime==="true"),t.dataset.showBpm&&(e.showBPM=t.dataset.showBpm==="true"),t.dataset.singlePlay&&(e.singlePlay=t.dataset.singlePlay==="true"),t.dataset.playOnSeek&&(e.playOnSeek=t.dataset.playOnSeek==="true"),t.dataset.title&&(e.title=t.dataset.title),t.dataset.subtitle&&(e.subtitle=t.dataset.subtitle),t.dataset.album&&(e.album=t.dataset.album),t.dataset.artwork&&(e.artwork=t.dataset.artwork),t.dataset.waveform&&(e.waveform=t.dataset.waveform),t.dataset.markers)try{e.markers=JSON.parse(t.dataset.markers)}catch(i){console.warn("Invalid markers JSON:",i)}if(t.dataset.playbackRate&&(e.playbackRate=parseFloat(t.dataset.playbackRate)),t.dataset.showPlaybackSpeed!==void 0&&(e.showPlaybackSpeed=t.dataset.showPlaybackSpeed==="true"),t.dataset.playbackRates)try{e.playbackRates=JSON.parse(t.dataset.playbackRates)}catch(i){console.warn("Invalid playbackRates JSON:",i)}return t.dataset.enableMediaSession!==void 0&&(e.enableMediaSession=t.dataset.enableMediaSession==="true"),e}function P(t){if(!t||isNaN(t))return"0:00";let e=Math.floor(t/60),i=Math.floor(t%60);return`${e}:${i.toString().padStart(2,"0")}`}function A(t){let e=t||Math.random().toString();return btoa(e.substring(0,10)).replace(/[^a-zA-Z0-9]/g,"")}function R(t){if(!t)return"Audio";let e=t.split("/");return e[e.length-1].split(".")[0].replace(/[-_]/g," ").replace(/\b\w/g,a=>a.toUpperCase())}function C(...t){let e={};for(let i of t)for(let o in i)i[o]!==null&&i[o]!==void 0&&(e[o]=i[o]);return e}function B(t,e){let i;return function(...a){let n=()=>{clearTimeout(i),t(...a)};clearTimeout(i),i=setTimeout(n,e)}}function S(t,e){if(t.length===e)return t;if(t.length===0||e===0)return[];let i=[];if(e>t.length){let o=(t.length-1)/(e-1);for(let a=0;a<e;a++){let n=a*o,r=Math.floor(n),s=Math.ceil(n),h=n-r;if(s>=t.length)i.push(t[t.length-1]);else if(r===s)i.push(t[r]);else{let l=t[r]*(1-h)+t[s]*h;i.push(l)}}}else{let o=t.length/e;for(let a=0;a<e;a++){let n=Math.floor(a*o),r=Math.floor((a+1)*o),s=0,h=0;for(let l=n;l<=r&&l<t.length;l++)t[l]>s&&(s=t[l]),h++;if(h===0){let l=Math.min(Math.round(a*o),t.length-1);s=t[l]}i.push(s)}}return i}function x(t,e,i,o,a){let n=window.devicePixelRatio||1,r=a.barWidth*n,s=a.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=o*e.width;t.clearRect(0,0,e.width,e.height);for(let y=0;y<l.length;y++){let f=y*(r+s);if(f+r>e.width)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=a.color,t.fillRect(f,m,r,c)}t.save(),t.beginPath(),t.rect(0,0,p,d),t.clip();for(let y=0;y<l.length;y++){let f=y*(r+s);if(f>p)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=a.progressColor,t.fillRect(f,m,r,c)}t.restore()}function q(t,e,i,o,a){let n=window.devicePixelRatio||1,r=a.barWidth*n,s=a.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=d/2,y=o*e.width;t.clearRect(0,0,e.width,e.height);for(let f=0;f<l.length;f++){let c=f*(r+s);if(c+r>e.width)break;let m=l[f]*d*.45;t.fillStyle=a.color,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.save(),t.beginPath(),t.rect(0,0,y,d),t.clip();for(let f=0;f<l.length;f++){let c=f*(r+s);if(c>y)break;let m=l[f]*d*.45;t.fillStyle=a.progressColor,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.restore()}function $(t,e,i,o,a){let n=e.width,r=e.height,s=r/2,h=r*.35;t.clearRect(0,0,n,r);let l=(d,p,y=1,f=!1)=>{f&&(t.shadowBlur=12,t.shadowColor=d),t.strokeStyle=d,t.lineWidth=p,t.lineCap="round",t.lineJoin="round",t.beginPath(),t.moveTo(0,s);let c=[],m=Math.floor(i.length*y);for(let u=0;u<m;u++){let v=u/(i.length-1)*n,k=i[u],b=Math.sin(u*.1)*k,w=s+b*h;c.push({x:v,y:w})}for(let u=0;u<c.length-1;u++){let v=c[u].x+(c[u+1].x-c[u].x)*.5,k=c[u].y,b=c[u+1].x-(c[u+1].x-c[u].x)*.5,w=c[u+1].y;t.bezierCurveTo(v,k,b,w,c[u+1].x,c[u+1].y)}t.stroke(),f&&(t.shadowBlur=0)};t.strokeStyle="rgba(255, 255, 255, 0.03)",t.lineWidth=.5,t.beginPath(),t.moveTo(0,s),t.lineTo(n,s),t.stroke();for(let d=0;d<=10;d++){let p=n/10*d;t.beginPath(),t.moveTo(p,0),t.lineTo(p,r),t.stroke()}l(a.color,2,1,!1),o>0&&l(a.progressColor,3,o,!0)}function U(t,e,i,o,a){let n=window.devicePixelRatio||1,r=(a.barWidth||3)*n,s=(a.barSpacing||1)*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=4*n,y=2*n,f=o*e.width,c=d/2;t.clearRect(0,0,e.width,e.height);for(let m=0;m<l.length;m++){let u=m*(r+s);if(u+r>e.width)break;let v=l[m]*d*.9,k=Math.floor(v/(p+y));t.fillStyle=u<f?a.progressColor:a.color;for(let b=0;b<k;b++){let w=b*(p+y);t.fillRect(u,c-w-p,r,p),b>0&&t.fillRect(u,c+w,r,p)}}}function F(t,e,i,o,a){let n=window.devicePixelRatio||1,r=(a.barWidth||2)*n,s=(a.barSpacing||3)*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=Math.max(1.5*n,r/2),y=o*e.width,f=d/2;t.clearRect(0,0,e.width,e.height);for(let c=0;c<l.length;c++){let m=c*(r+s)+r/2;if(m>e.width)break;let u=l[c]*d*.9;t.fillStyle=m<y?a.progressColor:a.color,t.beginPath(),t.arc(m,f-u/2,p,0,Math.PI*2),t.fill(),t.beginPath(),t.arc(m,f+u/2,p,0,Math.PI*2),t.fill()}}function N(t,e,i,o,a){let n=e.width,r=e.height,s=r/2,h=4,l=h/2;if(t.clearRect(0,0,n,r),t.fillStyle=a.color||"rgba(255, 255, 255, 0.2)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(n-l,s-h/2),t.arc(n-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),o>0){let d=Math.max(l*2,o*n);t.shadowBlur=8,t.shadowColor=a.progressColor,t.fillStyle=a.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(d-l,s-h/2),t.arc(d-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),t.shadowBlur=0;let p=8,y=d;t.shadowBlur=4,t.shadowColor="rgba(0, 0, 0, 0.3)",t.shadowOffsetY=2,t.fillStyle="#ffffff",t.beginPath(),t.arc(y,s,p,0,Math.PI*2),t.fill(),t.shadowBlur=0,t.shadowOffsetY=0,t.fillStyle=a.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.arc(y,s,p*.4,0,Math.PI*2),t.fill()}}var Y={bars:x,mirror:q,line:$,blocks:U,dots:F,seekbar:N};function W(t,e,i,o,a){(Y[a.waveformStyle]||x)(t,e,i,o,a)}function I(t){try{let e=t.getChannelData(0),i=t.sampleRate,o=j(e,i);if(o.length<2)return 120;let a=[];for(let h=1;h<o.length;h++)a.push((o[h]-o[h-1])/i);let n={};a.forEach(h=>{let l=60/h,d=Math.round(l/3)*3;d>60&&d<200&&(n[d]=(n[d]||0)+1)});let r=0,s=120;for(let[h,l]of Object.entries(n))l>r&&(r=l,s=parseInt(h));return s<70&&n[s*2]?s*=2:s>160&&n[Math.round(s/2)]&&(s=Math.round(s/2)),s-1}catch(e){return console.warn("BPM detection failed:",e),null}}function j(t,e){let a=[],n=0;for(let r=0;r<t.length-2048;r+=1024){let s=0;for(let d=r;d<r+2048;d++)s+=t[d]*t[d];s=s/2048;let h=s-n,l=n*1.8+.01;if(h>l&&s>.01){let d=a[a.length-1]||0,p=e*.15;r-d>p&&a.push(r)}n=s*.8+n*.2}return a}function V(t,e=200){let i=t.length/e,o=~~(i/10)||1,a=t.numberOfChannels,n=[];for(let s=0;s<a;s++){let h=t.getChannelData(s);for(let l=0;l<e;l++){let d=~~(l*i),p=~~(d+i),y=0,f=0;for(let m=d;m<p;m+=o){let u=h[m];u>f&&(f=u),u<y&&(y=u)}let c=Math.max(Math.abs(f),Math.abs(y));(s===0||c>n[l])&&(n[l]=c)}}let r=Math.max(...n);return r>0?n.map(s=>s/r):n}async function M(t,e=200,i=!1){try{let o=new(window.AudioContext||window.webkitAudioContext),n=await(await fetch(t)).arrayBuffer(),r=await o.decodeAudioData(n),s=V(r,e);s=J(s);let h=null;return i&&(h=await I(r)),o.close(),{peaks:s,bpm:h}}catch(o){throw console.error("Failed to generate waveform:",o),o}}function D(t=200){let e=[];for(let i=0;i<t;i++){let o=Math.random()*.5+.3,a=Math.sin(i/t*Math.PI*4)*.2;e.push(Math.max(.1,Math.min(1,o+a)))}return e}function J(t,e=.95){let i=Math.max(...t);if(i===0||i>e)return t;let o=e/i;return t.map(a=>a*o)}function G(){let t=document.documentElement,e=document.body;if(t.classList.contains("dark")||t.classList.contains("dark-mode")||t.classList.contains("theme-dark")||t.getAttribute("data-theme")==="dark"||t.getAttribute("data-color-scheme")==="dark"||e.classList.contains("dark")||e.classList.contains("dark-mode")||e.getAttribute("data-theme")==="dark")return"dark";if(t.classList.contains("light")||t.classList.contains("light-mode")||t.classList.contains("theme-light")||t.getAttribute("data-theme")==="light"||t.getAttribute("data-color-scheme")==="light"||e.classList.contains("light")||e.classList.contains("light-mode")||e.getAttribute("data-theme")==="light")return"light";try{let o=getComputedStyle(document.body).backgroundColor.match(/\d+/g);if(o&&o.length>=3){let[a,n,r]=o.map(Number),s=(a*299+n*587+r*114)/1e3;if(s>128)return"light";if(s<128)return"dark"}}catch{}if(window.matchMedia){if(window.matchMedia("(prefers-color-scheme: dark)").matches)return"dark";if(window.matchMedia("(prefers-color-scheme: light)").matches)return"light"}return"dark"}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)"}};function O(t){if(t&&E[t])return E[t];let e=G();return E[e]}var z={url:"",height:60,samples:200,preload:"metadata",playbackRate:1,showPlaybackSpeed:!1,playbackRates:[.5,.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:!1,showTime:!0,showHoverTime:!1,showBPM:!1,singlePlay:!0,playOnSeek:!0,enableMediaSession:!0,markers:[],showMarkers:!0,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},H={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}};var g=class t{static instances=new Map;static currentlyPlaying=null;constructor(e,i={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("WaveformPlayer: Container element not found");let o=L(this.container);this.options=C(z,o,i);let a=O(this.options.colorPreset);for(let[r,s]of Object.entries(a))(this.options[r]===null||this.options[r]===void 0)&&(this.options[r]=s);let n=H[this.options.waveformStyle];n&&(o.barWidth===void 0&&i.barWidth===void 0&&(this.options.barWidth=n.barWidth),o.barSpacing===void 0&&i.barSpacing===void 0&&(this.options.barSpacing=n.barSpacing)),this.audio=null,this.canvas=null,this.ctx=null,this.waveformData=[],this.progress=0,this.isPlaying=!1,this.isLoading=!1,this.hasError=!1,this.updateTimer=null,this.resizeObserver=null,this.id=this.container.id||A(this.options.url),t.instances.set(this.id,this),this.init(),setTimeout(()=>{this.container.dispatchEvent(new CustomEvent("waveformplayer:ready",{detail:{player:this,url:this.options.url}}))},100)}init(){this.createDOM(),this.createAudio(),this.initPlaybackSpeed(),this.initKeyboardControls(),this.bindEvents(),this.setupResizeObserver(),requestAnimationFrame(()=>{this.resizeCanvas(),this.options.url&&this.load(this.options.url).then(()=>{this.options.autoplay&&this.play()}).catch(e=>{console.error("Failed to load audio:",e)})})}createDOM(){this.container.innerHTML="",this.container.className="waveform-player";let e=this.options.buttonAlign;e==="auto"&&(this.options.waveformStyle==="bars"?e="bottom":e="center"),this.container.innerHTML=`
1
+ function L(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&&(e.height=parseInt(t.dataset.height)),t.dataset.samples&&(e.samples=parseInt(t.dataset.samples)),t.dataset.preload&&(e.preload=t.dataset.preload),t.dataset.waveformStyle&&(e.waveformStyle=t.dataset.waveformStyle),t.dataset.barWidth&&(e.barWidth=parseInt(t.dataset.barWidth)),t.dataset.barSpacing&&(e.barSpacing=parseInt(t.dataset.barSpacing)),t.dataset.buttonAlign&&(e.buttonAlign=t.dataset.buttonAlign),t.dataset.colorPreset&&(e.colorPreset=t.dataset.colorPreset),t.dataset.waveformColor&&(e.waveformColor=t.dataset.waveformColor),t.dataset.progressColor&&(e.progressColor=t.dataset.progressColor),t.dataset.buttonColor&&(e.buttonColor=t.dataset.buttonColor),t.dataset.buttonHoverColor&&(e.buttonHoverColor=t.dataset.buttonHoverColor),t.dataset.textColor&&(e.textColor=t.dataset.textColor),t.dataset.textSecondaryColor&&(e.textSecondaryColor=t.dataset.textSecondaryColor),t.dataset.backgroundColor&&(e.backgroundColor=t.dataset.backgroundColor),t.dataset.borderColor&&(e.borderColor=t.dataset.borderColor),t.dataset.color&&(e.waveformColor=t.dataset.color),t.dataset.theme&&(e.colorPreset=t.dataset.theme),t.dataset.autoplay&&(e.autoplay=t.dataset.autoplay==="true"),t.dataset.showTime&&(e.showTime=t.dataset.showTime==="true"),t.dataset.showHoverTime&&(e.showHoverTime=t.dataset.showHoverTime==="true"),t.dataset.showBpm&&(e.showBPM=t.dataset.showBpm==="true"),t.dataset.singlePlay&&(e.singlePlay=t.dataset.singlePlay==="true"),t.dataset.playOnSeek&&(e.playOnSeek=t.dataset.playOnSeek==="true"),t.dataset.title&&(e.title=t.dataset.title),t.dataset.subtitle&&(e.subtitle=t.dataset.subtitle),t.dataset.album&&(e.album=t.dataset.album),t.dataset.artwork&&(e.artwork=t.dataset.artwork),t.dataset.waveform&&(e.waveform=t.dataset.waveform),t.dataset.markers)try{e.markers=JSON.parse(t.dataset.markers)}catch(i){console.warn("Invalid markers JSON:",i)}if(t.dataset.playbackRate&&(e.playbackRate=parseFloat(t.dataset.playbackRate)),t.dataset.showPlaybackSpeed!==void 0&&(e.showPlaybackSpeed=t.dataset.showPlaybackSpeed==="true"),t.dataset.playbackRates)try{e.playbackRates=JSON.parse(t.dataset.playbackRates)}catch(i){console.warn("Invalid playbackRates JSON:",i)}return t.dataset.enableMediaSession!==void 0&&(e.enableMediaSession=t.dataset.enableMediaSession==="true"),e}function P(t){if(!t||isNaN(t))return"0:00";let e=Math.floor(t/60),i=Math.floor(t%60);return`${e}:${i.toString().padStart(2,"0")}`}function A(t){let e=t||Math.random().toString();return btoa(e.substring(0,10)).replace(/[^a-zA-Z0-9]/g,"")}function R(t){if(!t)return"Audio";let e=t.split("/");return e[e.length-1].split(".")[0].replace(/[-_]/g," ").replace(/\b\w/g,s=>s.toUpperCase())}function C(...t){let e={};for(let i of t)for(let a in i)i[a]!==null&&i[a]!==void 0&&(e[a]=i[a]);return e}function B(t,e){let i;return function(...s){let n=()=>{clearTimeout(i),t(...s)};clearTimeout(i),i=setTimeout(n,e)}}function S(t,e){if(t.length===e)return t;if(t.length===0||e===0)return[];let i=[];if(e>t.length){let a=(t.length-1)/(e-1);for(let s=0;s<e;s++){let n=s*a,r=Math.floor(n),o=Math.ceil(n),h=n-r;if(o>=t.length)i.push(t[t.length-1]);else if(r===o)i.push(t[r]);else{let l=t[r]*(1-h)+t[o]*h;i.push(l)}}}else{let a=t.length/e;for(let s=0;s<e;s++){let n=Math.floor(s*a),r=Math.floor((s+1)*a),o=0,h=0;for(let l=n;l<=r&&l<t.length;l++)t[l]>o&&(o=t[l]),h++;if(h===0){let l=Math.min(Math.round(s*a),t.length-1);o=t[l]}i.push(o)}}return i}function x(t,e,i,a,s){let n=window.devicePixelRatio||1,r=s.barWidth*n,o=s.barSpacing*n,h=Math.floor(e.width/(r+o)),l=S(i,h),d=e.height,p=a*e.width;t.clearRect(0,0,e.width,e.height);for(let y=0;y<l.length;y++){let f=y*(r+o);if(f+r>e.width)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=s.color,t.fillRect(f,m,r,c)}t.save(),t.beginPath(),t.rect(0,0,p,d),t.clip();for(let y=0;y<l.length;y++){let f=y*(r+o);if(f>p)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=s.progressColor,t.fillRect(f,m,r,c)}t.restore()}function q(t,e,i,a,s){let n=window.devicePixelRatio||1,r=s.barWidth*n,o=s.barSpacing*n,h=Math.floor(e.width/(r+o)),l=S(i,h),d=e.height,p=d/2,y=a*e.width;t.clearRect(0,0,e.width,e.height);for(let f=0;f<l.length;f++){let c=f*(r+o);if(c+r>e.width)break;let m=l[f]*d*.45;t.fillStyle=s.color,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.save(),t.beginPath(),t.rect(0,0,y,d),t.clip();for(let f=0;f<l.length;f++){let c=f*(r+o);if(c>y)break;let m=l[f]*d*.45;t.fillStyle=s.progressColor,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.restore()}function $(t,e,i,a,s){let n=e.width,r=e.height,o=r/2,h=r*.35;t.clearRect(0,0,n,r);let l=(d,p,y=1,f=!1)=>{f&&(t.shadowBlur=12,t.shadowColor=d),t.strokeStyle=d,t.lineWidth=p,t.lineCap="round",t.lineJoin="round",t.beginPath(),t.moveTo(0,o);let c=[],m=Math.floor(i.length*y);for(let u=0;u<m;u++){let v=u/(i.length-1)*n,k=i[u],b=Math.sin(u*.1)*k,w=o+b*h;c.push({x:v,y:w})}for(let u=0;u<c.length-1;u++){let v=c[u].x+(c[u+1].x-c[u].x)*.5,k=c[u].y,b=c[u+1].x-(c[u+1].x-c[u].x)*.5,w=c[u+1].y;t.bezierCurveTo(v,k,b,w,c[u+1].x,c[u+1].y)}t.stroke(),f&&(t.shadowBlur=0)};t.strokeStyle="rgba(255, 255, 255, 0.03)",t.lineWidth=.5,t.beginPath(),t.moveTo(0,o),t.lineTo(n,o),t.stroke();for(let d=0;d<=10;d++){let p=n/10*d;t.beginPath(),t.moveTo(p,0),t.lineTo(p,r),t.stroke()}l(s.color,2,1,!1),a>0&&l(s.progressColor,3,a,!0)}function U(t,e,i,a,s){let n=window.devicePixelRatio||1,r=(s.barWidth||3)*n,o=(s.barSpacing||1)*n,h=Math.floor(e.width/(r+o)),l=S(i,h),d=e.height,p=4*n,y=2*n,f=a*e.width,c=d/2;t.clearRect(0,0,e.width,e.height);for(let m=0;m<l.length;m++){let u=m*(r+o);if(u+r>e.width)break;let v=l[m]*d*.9,k=Math.floor(v/(p+y));t.fillStyle=u<f?s.progressColor:s.color;for(let b=0;b<k;b++){let w=b*(p+y);t.fillRect(u,c-w-p,r,p),b>0&&t.fillRect(u,c+w,r,p)}}}function F(t,e,i,a,s){let n=window.devicePixelRatio||1,r=(s.barWidth||2)*n,o=(s.barSpacing||3)*n,h=Math.floor(e.width/(r+o)),l=S(i,h),d=e.height,p=Math.max(1.5*n,r/2),y=a*e.width,f=d/2;t.clearRect(0,0,e.width,e.height);for(let c=0;c<l.length;c++){let m=c*(r+o)+r/2;if(m>e.width)break;let u=l[c]*d*.9;t.fillStyle=m<y?s.progressColor:s.color,t.beginPath(),t.arc(m,f-u/2,p,0,Math.PI*2),t.fill(),t.beginPath(),t.arc(m,f+u/2,p,0,Math.PI*2),t.fill()}}function N(t,e,i,a,s){let n=e.width,r=e.height,o=r/2,h=4,l=h/2;if(t.clearRect(0,0,n,r),t.fillStyle=s.color||"rgba(255, 255, 255, 0.2)",t.beginPath(),t.moveTo(l,o-h/2),t.lineTo(n-l,o-h/2),t.arc(n-l,o,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,o+h/2),t.arc(l,o,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),a>0){let d=Math.max(l*2,a*n);t.shadowBlur=8,t.shadowColor=s.progressColor,t.fillStyle=s.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.moveTo(l,o-h/2),t.lineTo(d-l,o-h/2),t.arc(d-l,o,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,o+h/2),t.arc(l,o,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),t.shadowBlur=0;let p=8,y=d;t.shadowBlur=4,t.shadowColor="rgba(0, 0, 0, 0.3)",t.shadowOffsetY=2,t.fillStyle="#ffffff",t.beginPath(),t.arc(y,o,p,0,Math.PI*2),t.fill(),t.shadowBlur=0,t.shadowOffsetY=0,t.fillStyle=s.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.arc(y,o,p*.4,0,Math.PI*2),t.fill()}}var Y={bars:x,mirror:q,line:$,blocks:U,dots:F,seekbar:N};function W(t,e,i,a,s){(Y[s.waveformStyle]||x)(t,e,i,a,s)}function I(t){try{let e=t.getChannelData(0),i=t.sampleRate,a=j(e,i);if(a.length<2)return 120;let s=[];for(let h=1;h<a.length;h++)s.push((a[h]-a[h-1])/i);let n={};s.forEach(h=>{let l=60/h,d=Math.round(l/3)*3;d>60&&d<200&&(n[d]=(n[d]||0)+1)});let r=0,o=120;for(let[h,l]of Object.entries(n))l>r&&(r=l,o=parseInt(h));return o<70&&n[o*2]?o*=2:o>160&&n[Math.round(o/2)]&&(o=Math.round(o/2)),o-1}catch(e){return console.warn("BPM detection failed:",e),null}}function j(t,e){let s=[],n=0;for(let r=0;r<t.length-2048;r+=1024){let o=0;for(let d=r;d<r+2048;d++)o+=t[d]*t[d];o=o/2048;let h=o-n,l=n*1.8+.01;if(h>l&&o>.01){let d=s[s.length-1]||0,p=e*.15;r-d>p&&s.push(r)}n=o*.8+n*.2}return s}function V(t,e=200){let i=t.length/e,a=~~(i/10)||1,s=t.numberOfChannels,n=[];for(let o=0;o<s;o++){let h=t.getChannelData(o);for(let l=0;l<e;l++){let d=~~(l*i),p=~~(d+i),y=0,f=0;for(let m=d;m<p;m+=a){let u=h[m];u>f&&(f=u),u<y&&(y=u)}let c=Math.max(Math.abs(f),Math.abs(y));(o===0||c>n[l])&&(n[l]=c)}}let r=Math.max(...n);return r>0?n.map(o=>o/r):n}async function M(t,e=200,i=!1){try{let a=new(window.AudioContext||window.webkitAudioContext),n=await(await fetch(t)).arrayBuffer(),r=await a.decodeAudioData(n),o=V(r,e);o=J(o);let h=null;return i&&(h=await I(r)),a.close(),{peaks:o,bpm:h}}catch(a){throw console.error("Failed to generate waveform:",a),a}}function D(t=200){let e=[];for(let i=0;i<t;i++){let a=Math.random()*.5+.3,s=Math.sin(i/t*Math.PI*4)*.2;e.push(Math.max(.1,Math.min(1,a+s)))}return e}function J(t,e=.95){let i=Math.max(...t);if(i===0||i>e)return t;let a=e/i;return t.map(s=>s*a)}function G(){let t=document.documentElement,e=document.body;if(t.classList.contains("dark")||t.classList.contains("dark-mode")||t.classList.contains("theme-dark")||t.getAttribute("data-theme")==="dark"||t.getAttribute("data-color-scheme")==="dark"||e.classList.contains("dark")||e.classList.contains("dark-mode")||e.getAttribute("data-theme")==="dark")return"dark";if(t.classList.contains("light")||t.classList.contains("light-mode")||t.classList.contains("theme-light")||t.getAttribute("data-theme")==="light"||t.getAttribute("data-color-scheme")==="light"||e.classList.contains("light")||e.classList.contains("light-mode")||e.getAttribute("data-theme")==="light")return"light";try{let a=getComputedStyle(document.body).backgroundColor.match(/\d+/g);if(a&&a.length>=3){let[s,n,r]=a.map(Number),o=(s*299+n*587+r*114)/1e3;if(o>128)return"light";if(o<128)return"dark"}}catch{}if(window.matchMedia){if(window.matchMedia("(prefers-color-scheme: dark)").matches)return"dark";if(window.matchMedia("(prefers-color-scheme: light)").matches)return"light"}return"dark"}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)"}};function z(t){if(t&&E[t])return E[t];let e=G();return E[e]}var O={url:"",height:60,samples:200,preload:"metadata",playbackRate:1,showPlaybackSpeed:!1,playbackRates:[.5,.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:!1,showTime:!0,showHoverTime:!1,showBPM:!1,singlePlay:!0,playOnSeek:!0,enableMediaSession:!0,markers:[],showMarkers:!0,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},H={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}};var g=class t{static instances=new Map;static currentlyPlaying=null;constructor(e,i={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("WaveformPlayer: Container element not found");let a=L(this.container);this.options=C(O,a,i);let s=z(this.options.colorPreset);for(let[r,o]of Object.entries(s))(this.options[r]===null||this.options[r]===void 0)&&(this.options[r]=o);let n=H[this.options.waveformStyle];n&&(a.barWidth===void 0&&i.barWidth===void 0&&(this.options.barWidth=n.barWidth),a.barSpacing===void 0&&i.barSpacing===void 0&&(this.options.barSpacing=n.barSpacing)),this.audio=null,this.canvas=null,this.ctx=null,this.waveformData=[],this.progress=0,this.isPlaying=!1,this.isLoading=!1,this.hasError=!1,this.updateTimer=null,this.resizeObserver=null,this.id=this.container.id||A(this.options.url),t.instances.set(this.id,this),this.init(),setTimeout(()=>{this.container.dispatchEvent(new CustomEvent("waveformplayer:ready",{bubbles:!0,detail:{player:this,url:this.options.url}}))},100)}init(){this.createDOM(),this.createAudio(),this.initPlaybackSpeed(),this.initKeyboardControls(),this.bindEvents(),this.setupResizeObserver(),requestAnimationFrame(()=>{this.resizeCanvas(),this.options.url&&this.load(this.options.url).then(()=>{this.options.autoplay&&this.play()}).catch(e=>{console.error("Failed to load audio:",e)})})}createDOM(){this.container.innerHTML="",this.container.className="waveform-player";let e=this.options.buttonAlign;e==="auto"&&(this.options.waveformStyle==="bars"?e="bottom":e="center"),this.container.innerHTML=`
2
2
  <div class="waveform-player-inner">
3
3
  <div class="waveform-body">
4
4
  <div class="waveform-track waveform-align-${e}">
@@ -59,4 +59,4 @@ function L(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&
59
59
  </div>
60
60
  </div>
61
61
  </div>
62
- `,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()}createAudio(){this.audio=new Audio,this.audio.preload=this.options.preload||"metadata",this.audio.crossOrigin="anonymous"}initPlaybackSpeed(){this.options.playbackRate&&this.options.playbackRate!==1&&(this.audio.playbackRate=this.options.playbackRate),this.options.showPlaybackSpeed&&this.initSpeedControls()}initSpeedControls(){let e=this.container.querySelector(".speed-btn"),i=this.container.querySelector(".speed-menu");!e||!i||(e.addEventListener("click",o=>{o.stopPropagation(),i.style.display=i.style.display==="none"?"block":"none"}),document.addEventListener("click",()=>{i.style.display="none"}),i.addEventListener("click",o=>{if(o.stopPropagation(),o.target.classList.contains("speed-option")){let a=parseFloat(o.target.dataset.rate);this.setPlaybackRate(a),i.style.display="none"}}),this.updateSpeedUI())}initKeyboardControls(){this.container.setAttribute("tabindex","-1"),this.container.addEventListener("click",()=>{t.getAllInstances().forEach(e=>{e!==this&&e.container.setAttribute("tabindex","-1")}),this.container.setAttribute("tabindex","0"),this.container.focus()}),this.container.addEventListener("keydown",e=>{if(document.activeElement!==this.container)return;let i=e.key,o=this.audio.currentTime;if(i>="0"&&i<="9"){e.preventDefault(),this.seekToPercent(parseInt(i)/10);return}let a={" ":()=>this.togglePlay(),ArrowLeft:()=>this.seekTo(Math.max(0,o-5)),ArrowRight:()=>this.seekTo(Math.min(this.audio.duration,o+5)),ArrowUp:()=>this.setVolume(Math.min(1,this.audio.volume+.1)),ArrowDown:()=>this.setVolume(Math.max(0,this.audio.volume-.1)),m:()=>this.audio.muted=!this.audio.muted,M:()=>this.audio.muted=!this.audio.muted};a[i]&&(e.preventDefault(),a[i]())})}initMediaSession(){!("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",()=>{this.seekTo(Math.max(0,this.audio.currentTime-10))}),navigator.mediaSession.setActionHandler("seekforward",()=>{this.seekTo(Math.min(this.audio.duration,this.audio.currentTime+10))}),navigator.mediaSession.setActionHandler("seekto",e=>{e.seekTime!==null&&this.seekTo(e.seekTime)}))}bindEvents(){this.playBtn.addEventListener("click",()=>this.togglePlay()),this.audio.addEventListener("loadstart",()=>this.setLoading(!0)),this.audio.addEventListener("loadedmetadata",()=>this.onMetadataLoaded()),this.audio.addEventListener("canplay",()=>this.setLoading(!1)),this.audio.addEventListener("play",()=>this.onPlay()),this.audio.addEventListener("pause",()=>this.onPause()),this.audio.addEventListener("ended",()=>this.onEnded()),this.audio.addEventListener("error",e=>this.onError(e)),this.canvas.addEventListener("click",e=>this.handleCanvasClick(e)),window.addEventListener("resize",B(()=>this.resizeCanvas(),100))}setupResizeObserver(){"ResizeObserver"in window&&(this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.canvas?.parentElement&&this.resizeObserver.observe(this.canvas.parentElement))}async load(e){try{this.setLoading(!0),this.progress=0,this.hasError=!1,this.audio.src=e,await new Promise((o,a)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),o()},r=s=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),a(s)};this.audio.addEventListener("loadedmetadata",n),this.audio.addEventListener("error",r)});let i=this.options.title||R(e);if(this.titleEl&&(this.titleEl.textContent=i),this.options.waveform)this.setWaveformData(this.options.waveform);else try{let o=await M(e,this.options.samples,this.options.showBPM);this.waveformData=o.peaks,o.bpm&&(this.detectedBPM=o.bpm,this.updateBPMDisplay())}catch(o){console.warn("Using placeholder waveform:",o),this.waveformData=D(this.options.samples)}this.drawWaveform(),this.renderMarkers(),this.initMediaSession(),this.options.onLoad&&this.options.onLoad(this)}catch(i){console.error("Failed to load audio:",i),this.onError(i)}finally{this.setLoading(!1)}}async loadTrack(e,i=null,o=null,a={}){this.isPlaying&&this.pause(),this.audio.src="",this.audio.load(),this.hasError=!1,this.errorEl&&(this.errorEl.style.display="none"),this.canvas&&(this.canvas.style.opacity="1"),this.playBtn&&(this.playBtn.disabled=!1),this.progress=0,this.waveformData=[],this.options=C(this.options,{url:e,title:i||this.options.title,subtitle:o||this.options.subtitle,...a}),a.preload&&(this.audio.preload=a.preload),this.subtitleEl&&(o?(this.subtitleEl.textContent=o,this.subtitleEl.style.display=""):o===""&&(this.subtitleEl.style.display="none")),a.artwork&&this.artworkEl&&(this.artworkEl.src=a.artwork),a.markers&&(this.options.markers=a.markers),await this.load(e),this.play()}setWaveformData(e){if(typeof e=="string")try{let i=JSON.parse(e);this.waveformData=Array.isArray(i)?i:[]}catch{this.waveformData=e.split(",").map(Number)}else this.waveformData=Array.isArray(e)?e:[];this.drawWaveform()}drawWaveform(){!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})}resizeCanvas(){let e=window.devicePixelRatio||1,i=this.canvas.getBoundingClientRect();this.canvas.width=i.width*e,this.canvas.height=this.options.height*e,this.canvas.style.height=this.options.height+"px",this.canvas.parentElement.style.height=this.options.height+"px",this.drawWaveform()}renderMarkers(){!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((e,i)=>{if(e.time>this.audio.duration){console.warn(`Marker "${e.label}" at ${e.time}s exceeds audio duration of ${this.audio.duration}s`);return}let o=e.time/this.audio.duration*100,a=document.createElement("button");a.className="waveform-marker",a.style.left=`${o}%`,a.style.backgroundColor=e.color||"rgba(255, 255, 255, 0.5)",a.setAttribute("aria-label",e.label),a.setAttribute("data-time",e.time);let n=document.createElement("span");n.className="waveform-marker-tooltip",n.textContent=e.label,a.appendChild(n),a.addEventListener("click",r=>{r.stopPropagation(),this.seekTo(e.time),this.options.playOnSeek&&!this.isPlaying&&this.play()}),this.markersContainer.appendChild(a)}))}handleCanvasClick(e){if(!this.audio.duration)return;let i=this.canvas.getBoundingClientRect(),o=e.clientX-i.left,a=Math.max(0,Math.min(1,o/i.width));this.seekToPercent(a)}setLoading(e){this.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none")}onMetadataLoaded(){this.totalTimeEl&&(this.totalTimeEl.textContent=P(this.audio.duration)),this.renderMarkers()}onPlay(){this.isPlaying=!0,this.playBtn.classList.add("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="none"),i&&(i.style.display="flex"),this.startSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:play",{detail:{player:this,url:this.options.url}})),this.options.onPlay&&this.options.onPlay(this)}onPause(){this.isPlaying=!1,this.playBtn.classList.remove("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="flex"),i&&(i.style.display="none"),this.stopSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:pause",{detail:{player:this,url:this.options.url}})),this.options.onPause&&this.options.onPause(this)}onEnded(){this.progress=0,this.audio.currentTime=0,this.drawWaveform(),this.currentTimeEl&&(this.currentTimeEl.textContent="0:00"),this.container.dispatchEvent(new CustomEvent("waveformplayer:ended",{detail:{player:this,url:this.options.url}})),this.onPause(),this.options.onEnd&&this.options.onEnd(this)}onError(e){this.isDestroying||(console.error("Audio error:",e),this.hasError=!0,this.setLoading(!1),this.errorEl&&(this.errorEl.style.display="flex"),this.canvas&&(this.canvas.style.opacity="0.2"),this.playBtn&&(this.playBtn.disabled=!0),this.options.onError&&this.options.onError(e,this))}startSmoothUpdate(){this.stopSmoothUpdate();let e=()=>{this.isPlaying&&this.audio.duration&&(this.updateProgress(),this.updateTimer=requestAnimationFrame(e))};this.updateTimer=requestAnimationFrame(e)}stopSmoothUpdate(){this.updateTimer&&(cancelAnimationFrame(this.updateTimer),this.updateTimer=null)}updateProgress(){if(!this.audio.duration)return;let e=this.audio.currentTime/this.audio.duration;Math.abs(e-this.progress)>.001&&(this.progress=e,this.drawWaveform()),this.currentTimeEl&&(this.currentTimeEl.textContent=P(this.audio.currentTime)),this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate",{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)}updateBPMDisplay(){this.bpmEl&&this.bpmValueEl&&this.detectedBPM&&(this.bpmValueEl.textContent=Math.round(this.detectedBPM),this.bpmEl.style.display="inline-flex")}updateSpeedUI(){let e=this.container.querySelector(".speed-value");if(e){let i=this.audio.playbackRate;e.textContent=i===1?"1x":`${i}x`}this.container.querySelectorAll(".speed-option").forEach(i=>{i.classList.toggle("active",parseFloat(i.dataset.rate)===this.audio.playbackRate)})}play(){this.options.singlePlay&&t.currentlyPlaying&&t.currentlyPlaying!==this&&t.currentlyPlaying.pause(),t.currentlyPlaying=this,this.audio.play()}pause(){t.currentlyPlaying===this&&(t.currentlyPlaying=null),this.audio.pause()}togglePlay(){this.isPlaying?this.pause():this.play()}seekTo(e){this.audio&&this.audio.duration&&(this.audio.currentTime=Math.max(0,Math.min(e,this.audio.duration)),this.updateProgress())}seekToPercent(e){this.audio&&this.audio.duration&&(this.audio.currentTime=this.audio.duration*Math.max(0,Math.min(1,e)),this.updateProgress())}setVolume(e){this.audio&&(this.audio.volume=Math.max(0,Math.min(1,e)))}setPlaybackRate(e){if(!this.audio)return;let i=Math.max(.5,Math.min(2,e));this.audio.playbackRate=i,this.options.playbackRate=i,this.updateSpeedUI()}destroy(){this.isDestroying=!0,this.pause(),this.stopSmoothUpdate(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),t.instances.delete(this.id),t.currentlyPlaying===this&&(t.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=[]}static getInstance(e){if(typeof e=="string"){let i=this.instances.get(e);if(i)return i;let o=document.getElementById(e);if(o)return Array.from(this.instances.values()).find(a=>a.container===o)}if(e instanceof HTMLElement)return Array.from(this.instances.values()).find(i=>i.container===e)}static getAllInstances(){return Array.from(this.instances.values())}static destroyAll(){this.instances.forEach(e=>e.destroy()),this.instances.clear()}static async generateWaveformData(e,i=200){try{return(await M(e,i)).peaks}catch(o){throw console.error("Failed to generate waveform:",o),o}}};function T(){if(typeof document>"u")return;document.querySelectorAll("[data-waveform-player]").forEach(e=>{if(e.dataset.waveformInitialized!=="true")try{new g(e),e.dataset.waveformInitialized="true"}catch(i){console.error("Failed to initialize WaveformPlayer:",i,e)}})}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",T):T());g.init=T;typeof window<"u"&&(window.WaveformPlayer=g);var lt=g;export{g as WaveformPlayer,lt as default};
62
+ `,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()}createAudio(){this.audio=new Audio,this.audio.preload=this.options.preload||"metadata",this.audio.crossOrigin="anonymous"}initPlaybackSpeed(){this.options.playbackRate&&this.options.playbackRate!==1&&(this.audio.playbackRate=this.options.playbackRate),this.options.showPlaybackSpeed&&this.initSpeedControls()}initSpeedControls(){let e=this.container.querySelector(".speed-btn"),i=this.container.querySelector(".speed-menu");!e||!i||(e.addEventListener("click",a=>{a.stopPropagation(),i.style.display=i.style.display==="none"?"block":"none"}),document.addEventListener("click",()=>{i.style.display="none"}),i.addEventListener("click",a=>{if(a.stopPropagation(),a.target.classList.contains("speed-option")){let s=parseFloat(a.target.dataset.rate);this.setPlaybackRate(s),i.style.display="none"}}),this.updateSpeedUI())}initKeyboardControls(){this.container.setAttribute("tabindex","-1"),this.container.addEventListener("click",()=>{t.getAllInstances().forEach(e=>{e!==this&&e.container.setAttribute("tabindex","-1")}),this.container.setAttribute("tabindex","0"),this.container.focus()}),this.container.addEventListener("keydown",e=>{if(document.activeElement!==this.container)return;let i=e.key,a=this.audio.currentTime;if(i>="0"&&i<="9"){e.preventDefault(),this.seekToPercent(parseInt(i)/10);return}let s={" ":()=>this.togglePlay(),ArrowLeft:()=>this.seekTo(Math.max(0,a-5)),ArrowRight:()=>this.seekTo(Math.min(this.audio.duration,a+5)),ArrowUp:()=>this.setVolume(Math.min(1,this.audio.volume+.1)),ArrowDown:()=>this.setVolume(Math.max(0,this.audio.volume-.1)),m:()=>this.audio.muted=!this.audio.muted,M:()=>this.audio.muted=!this.audio.muted};s[i]&&(e.preventDefault(),s[i]())})}initMediaSession(){!("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",()=>{this.seekTo(Math.max(0,this.audio.currentTime-10))}),navigator.mediaSession.setActionHandler("seekforward",()=>{this.seekTo(Math.min(this.audio.duration,this.audio.currentTime+10))}),navigator.mediaSession.setActionHandler("seekto",e=>{e.seekTime!==null&&this.seekTo(e.seekTime)}))}bindEvents(){this.playBtn.addEventListener("click",()=>this.togglePlay()),this.audio.addEventListener("loadstart",()=>this.setLoading(!0)),this.audio.addEventListener("loadedmetadata",()=>this.onMetadataLoaded()),this.audio.addEventListener("canplay",()=>this.setLoading(!1)),this.audio.addEventListener("play",()=>this.onPlay()),this.audio.addEventListener("pause",()=>this.onPause()),this.audio.addEventListener("ended",()=>this.onEnded()),this.audio.addEventListener("error",e=>this.onError(e)),this.canvas.addEventListener("click",e=>this.handleCanvasClick(e)),this.resizeHandler=B(()=>this.resizeCanvas(),100),window.addEventListener("resize",this.resizeHandler)}setupResizeObserver(){"ResizeObserver"in window&&(this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.canvas?.parentElement&&this.resizeObserver.observe(this.canvas.parentElement))}async load(e){try{this.setLoading(!0),this.progress=0,this.hasError=!1,this.audio.src=e,await new Promise((a,s)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),a()},r=o=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),s(o)};this.audio.addEventListener("loadedmetadata",n),this.audio.addEventListener("error",r)});let i=this.options.title||R(e);if(this.titleEl&&(this.titleEl.textContent=i),this.options.waveform)this.setWaveformData(this.options.waveform);else try{let a=await M(e,this.options.samples,this.options.showBPM);this.waveformData=a.peaks,a.bpm&&(this.detectedBPM=a.bpm,this.updateBPMDisplay())}catch(a){console.warn("Using placeholder waveform:",a),this.waveformData=D(this.options.samples)}this.drawWaveform(),this.renderMarkers(),this.initMediaSession(),this.options.onLoad&&this.options.onLoad(this)}catch(i){console.error("Failed to load audio:",i),this.onError(i)}finally{this.setLoading(!1)}}async loadTrack(e,i=null,a=null,s={}){this.isPlaying&&this.pause(),this.audio.src="",this.audio.load(),this.hasError=!1,this.errorEl&&(this.errorEl.style.display="none"),this.canvas&&(this.canvas.style.opacity="1"),this.playBtn&&(this.playBtn.disabled=!1),this.progress=0,this.waveformData=[],this.options=C(this.options,{url:e,title:i||this.options.title,subtitle:a||this.options.subtitle,...s}),s.preload&&(this.audio.preload=s.preload),this.subtitleEl&&(a?(this.subtitleEl.textContent=a,this.subtitleEl.style.display=""):a===""&&(this.subtitleEl.style.display="none")),s.artwork&&this.artworkEl&&(this.artworkEl.src=s.artwork),s.markers&&(this.options.markers=s.markers),await this.load(e),this.play()}setWaveformData(e){if(typeof e=="string")try{let i=JSON.parse(e);this.waveformData=Array.isArray(i)?i:[]}catch{this.waveformData=e.split(",").map(Number)}else this.waveformData=Array.isArray(e)?e:[];this.drawWaveform()}drawWaveform(){!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})}resizeCanvas(){if(!this.canvas||this.isDestroying)return;let e=window.devicePixelRatio||1,i=this.canvas.getBoundingClientRect();this.canvas.width=i.width*e,this.canvas.height=this.options.height*e,this.canvas.style.height=this.options.height+"px",this.canvas.parentElement.style.height=this.options.height+"px",this.drawWaveform()}renderMarkers(){!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((e,i)=>{if(e.time>this.audio.duration){console.warn(`Marker "${e.label}" at ${e.time}s exceeds audio duration of ${this.audio.duration}s`);return}let a=e.time/this.audio.duration*100,s=document.createElement("button");s.className="waveform-marker",s.style.left=`${a}%`,s.style.backgroundColor=e.color||"rgba(255, 255, 255, 0.5)",s.setAttribute("aria-label",e.label),s.setAttribute("data-time",e.time);let n=document.createElement("span");n.className="waveform-marker-tooltip",n.textContent=e.label,s.appendChild(n),s.addEventListener("click",r=>{r.stopPropagation(),this.seekTo(e.time),this.options.playOnSeek&&!this.isPlaying&&this.play()}),this.markersContainer.appendChild(s)}))}handleCanvasClick(e){if(!this.audio.duration)return;let i=this.canvas.getBoundingClientRect(),a=e.clientX-i.left,s=Math.max(0,Math.min(1,a/i.width));this.seekToPercent(s)}setLoading(e){this.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none")}onMetadataLoaded(){this.isDestroying||(this.totalTimeEl&&(this.totalTimeEl.textContent=P(this.audio.duration)),this.renderMarkers())}onPlay(){if(this.isDestroying)return;this.isPlaying=!0,this.playBtn.classList.add("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="none"),i&&(i.style.display="flex"),this.startSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:play",{bubbles:!0,detail:{player:this,url:this.options.url}})),this.options.onPlay&&this.options.onPlay(this)}onPause(){if(this.isDestroying)return;this.isPlaying=!1,this.playBtn.classList.remove("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="flex"),i&&(i.style.display="none"),this.stopSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:pause",{bubbles:!0,detail:{player:this,url:this.options.url}})),this.options.onPause&&this.options.onPause(this)}onEnded(){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:!0,detail:{player:this,url:this.options.url}})),this.onPause(),this.options.onEnd&&this.options.onEnd(this))}onError(e){this.isDestroying||(console.error("Audio error:",e),this.hasError=!0,this.setLoading(!1),this.errorEl&&(this.errorEl.style.display="flex"),this.canvas&&(this.canvas.style.opacity="0.2"),this.playBtn&&(this.playBtn.disabled=!0),this.options.onError&&this.options.onError(e,this))}startSmoothUpdate(){this.stopSmoothUpdate();let e=()=>{this.isPlaying&&this.audio.duration&&(this.updateProgress(),this.updateTimer=requestAnimationFrame(e))};this.updateTimer=requestAnimationFrame(e)}stopSmoothUpdate(){this.updateTimer&&(cancelAnimationFrame(this.updateTimer),this.updateTimer=null)}updateProgress(){if(!this.audio.duration)return;let e=this.audio.currentTime/this.audio.duration;Math.abs(e-this.progress)>.001&&(this.progress=e,this.drawWaveform()),this.currentTimeEl&&(this.currentTimeEl.textContent=P(this.audio.currentTime)),this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate",{bubbles:!0,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)}updateBPMDisplay(){this.bpmEl&&this.bpmValueEl&&this.detectedBPM&&(this.bpmValueEl.textContent=Math.round(this.detectedBPM),this.bpmEl.style.display="inline-flex")}updateSpeedUI(){let e=this.container.querySelector(".speed-value");if(e){let i=this.audio.playbackRate;e.textContent=i===1?"1x":`${i}x`}this.container.querySelectorAll(".speed-option").forEach(i=>{i.classList.toggle("active",parseFloat(i.dataset.rate)===this.audio.playbackRate)})}play(){return this.options.singlePlay&&t.currentlyPlaying&&t.currentlyPlaying!==this&&t.currentlyPlaying.pause(),t.currentlyPlaying=this,this.audio.play()}pause(){t.currentlyPlaying===this&&(t.currentlyPlaying=null),this.audio.pause()}togglePlay(){this.isPlaying?this.pause():this.play()}seekTo(e){this.audio&&this.audio.duration&&(this.audio.currentTime=Math.max(0,Math.min(e,this.audio.duration)),this.updateProgress())}seekToPercent(e){this.audio&&this.audio.duration&&(this.audio.currentTime=this.audio.duration*Math.max(0,Math.min(1,e)),this.updateProgress())}setVolume(e){this.audio&&(this.audio.volume=Math.max(0,Math.min(1,e)))}setPlaybackRate(e){if(!this.audio)return;let i=Math.max(.5,Math.min(2,e));this.audio.playbackRate=i,this.options.playbackRate=i,this.updateSpeedUI()}destroy(){this.isDestroying=!0,this.pause(),this.stopSmoothUpdate(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null),t.instances.delete(this.id),t.currentlyPlaying===this&&(t.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=[]}static getInstance(e){if(typeof e=="string"){let i=this.instances.get(e);if(i)return i;let a=document.getElementById(e);if(a)return Array.from(this.instances.values()).find(s=>s.container===a)}if(e instanceof HTMLElement)return Array.from(this.instances.values()).find(i=>i.container===e)}static getAllInstances(){return Array.from(this.instances.values())}static destroyAll(){this.instances.forEach(e=>e.destroy()),this.instances.clear()}static async generateWaveformData(e,i=200){try{return(await M(e,i)).peaks}catch(a){throw console.error("Failed to generate waveform:",a),a}}};function T(){if(typeof document>"u")return;document.querySelectorAll("[data-waveform-player]").forEach(e=>{if(e.dataset.waveformInitialized!=="true")try{new g(e),e.dataset.waveformInitialized="true"}catch(i){console.error("Failed to initialize WaveformPlayer:",i,e)}})}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",T):T());g.init=T;typeof window<"u"&&(window.WaveformPlayer=g);var lt=g;export{g as WaveformPlayer,lt as default};
@@ -677,6 +677,7 @@
677
677
  this.init();
678
678
  setTimeout(() => {
679
679
  this.container.dispatchEvent(new CustomEvent("waveformplayer:ready", {
680
+ bubbles: true,
680
681
  detail: { player: this, url: this.options.url }
681
682
  }));
682
683
  }, 100);
@@ -938,7 +939,8 @@
938
939
  this.audio.addEventListener("ended", () => this.onEnded());
939
940
  this.audio.addEventListener("error", (e) => this.onError(e));
940
941
  this.canvas.addEventListener("click", (e) => this.handleCanvasClick(e));
941
- window.addEventListener("resize", debounce(() => this.resizeCanvas(), 100));
942
+ this.resizeHandler = debounce(() => this.resizeCanvas(), 100);
943
+ window.addEventListener("resize", this.resizeHandler);
942
944
  }
943
945
  /**
944
946
  * Setup resize observer
@@ -1104,6 +1106,9 @@
1104
1106
  * @private
1105
1107
  */
1106
1108
  resizeCanvas() {
1109
+ if (!this.canvas || this.isDestroying) {
1110
+ return;
1111
+ }
1107
1112
  const dpr = window.devicePixelRatio || 1;
1108
1113
  const rect = this.canvas.getBoundingClientRect();
1109
1114
  this.canvas.width = rect.width * dpr;
@@ -1177,6 +1182,7 @@
1177
1182
  * @private
1178
1183
  */
1179
1184
  onMetadataLoaded() {
1185
+ if (this.isDestroying) return;
1180
1186
  if (this.totalTimeEl) {
1181
1187
  this.totalTimeEl.textContent = formatTime(this.audio.duration);
1182
1188
  }
@@ -1187,6 +1193,7 @@
1187
1193
  * @private
1188
1194
  */
1189
1195
  onPlay() {
1196
+ if (this.isDestroying) return;
1190
1197
  this.isPlaying = true;
1191
1198
  this.playBtn.classList.add("playing");
1192
1199
  const playIcon = this.playBtn.querySelector(".waveform-icon-play");
@@ -1195,6 +1202,7 @@
1195
1202
  if (pauseIcon) pauseIcon.style.display = "flex";
1196
1203
  this.startSmoothUpdate();
1197
1204
  this.container.dispatchEvent(new CustomEvent("waveformplayer:play", {
1205
+ bubbles: true,
1198
1206
  detail: { player: this, url: this.options.url }
1199
1207
  }));
1200
1208
  if (this.options.onPlay) {
@@ -1206,6 +1214,7 @@
1206
1214
  * @private
1207
1215
  */
1208
1216
  onPause() {
1217
+ if (this.isDestroying) return;
1209
1218
  this.isPlaying = false;
1210
1219
  this.playBtn.classList.remove("playing");
1211
1220
  const playIcon = this.playBtn.querySelector(".waveform-icon-play");
@@ -1214,6 +1223,7 @@
1214
1223
  if (pauseIcon) pauseIcon.style.display = "none";
1215
1224
  this.stopSmoothUpdate();
1216
1225
  this.container.dispatchEvent(new CustomEvent("waveformplayer:pause", {
1226
+ bubbles: true,
1217
1227
  detail: { player: this, url: this.options.url }
1218
1228
  }));
1219
1229
  if (this.options.onPause) {
@@ -1225,6 +1235,7 @@
1225
1235
  * @private
1226
1236
  */
1227
1237
  onEnded() {
1238
+ if (this.isDestroying) return;
1228
1239
  this.progress = 0;
1229
1240
  this.audio.currentTime = 0;
1230
1241
  this.drawWaveform();
@@ -1232,6 +1243,7 @@
1232
1243
  this.currentTimeEl.textContent = "0:00";
1233
1244
  }
1234
1245
  this.container.dispatchEvent(new CustomEvent("waveformplayer:ended", {
1246
+ bubbles: true,
1235
1247
  detail: { player: this, url: this.options.url }
1236
1248
  }));
1237
1249
  this.onPause();
@@ -1303,6 +1315,7 @@
1303
1315
  this.currentTimeEl.textContent = formatTime(this.audio.currentTime);
1304
1316
  }
1305
1317
  this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate", {
1318
+ bubbles: true,
1306
1319
  detail: {
1307
1320
  player: this,
1308
1321
  currentTime: this.audio.currentTime,
@@ -1346,13 +1359,14 @@
1346
1359
  // ============================================
1347
1360
  /**
1348
1361
  * Play audio
1362
+ * @return {Promise} The promise returned by HTMLMediaElement.play()
1349
1363
  */
1350
1364
  play() {
1351
1365
  if (this.options.singlePlay && _WaveformPlayer.currentlyPlaying && _WaveformPlayer.currentlyPlaying !== this) {
1352
1366
  _WaveformPlayer.currentlyPlaying.pause();
1353
1367
  }
1354
1368
  _WaveformPlayer.currentlyPlaying = this;
1355
- this.audio.play();
1369
+ return this.audio.play();
1356
1370
  }
1357
1371
  /**
1358
1372
  * Pause audio
@@ -1424,6 +1438,10 @@
1424
1438
  this.resizeObserver.disconnect();
1425
1439
  this.resizeObserver = null;
1426
1440
  }
1441
+ if (this.resizeHandler) {
1442
+ window.removeEventListener("resize", this.resizeHandler);
1443
+ this.resizeHandler = null;
1444
+ }
1427
1445
  _WaveformPlayer.instances.delete(this.id);
1428
1446
  if (_WaveformPlayer.currentlyPlaying === this) {
1429
1447
  _WaveformPlayer.currentlyPlaying = null;
@@ -1,4 +1,4 @@
1
- (()=>{function L(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&&(e.height=parseInt(t.dataset.height)),t.dataset.samples&&(e.samples=parseInt(t.dataset.samples)),t.dataset.preload&&(e.preload=t.dataset.preload),t.dataset.waveformStyle&&(e.waveformStyle=t.dataset.waveformStyle),t.dataset.barWidth&&(e.barWidth=parseInt(t.dataset.barWidth)),t.dataset.barSpacing&&(e.barSpacing=parseInt(t.dataset.barSpacing)),t.dataset.buttonAlign&&(e.buttonAlign=t.dataset.buttonAlign),t.dataset.colorPreset&&(e.colorPreset=t.dataset.colorPreset),t.dataset.waveformColor&&(e.waveformColor=t.dataset.waveformColor),t.dataset.progressColor&&(e.progressColor=t.dataset.progressColor),t.dataset.buttonColor&&(e.buttonColor=t.dataset.buttonColor),t.dataset.buttonHoverColor&&(e.buttonHoverColor=t.dataset.buttonHoverColor),t.dataset.textColor&&(e.textColor=t.dataset.textColor),t.dataset.textSecondaryColor&&(e.textSecondaryColor=t.dataset.textSecondaryColor),t.dataset.backgroundColor&&(e.backgroundColor=t.dataset.backgroundColor),t.dataset.borderColor&&(e.borderColor=t.dataset.borderColor),t.dataset.color&&(e.waveformColor=t.dataset.color),t.dataset.theme&&(e.colorPreset=t.dataset.theme),t.dataset.autoplay&&(e.autoplay=t.dataset.autoplay==="true"),t.dataset.showTime&&(e.showTime=t.dataset.showTime==="true"),t.dataset.showHoverTime&&(e.showHoverTime=t.dataset.showHoverTime==="true"),t.dataset.showBpm&&(e.showBPM=t.dataset.showBpm==="true"),t.dataset.singlePlay&&(e.singlePlay=t.dataset.singlePlay==="true"),t.dataset.playOnSeek&&(e.playOnSeek=t.dataset.playOnSeek==="true"),t.dataset.title&&(e.title=t.dataset.title),t.dataset.subtitle&&(e.subtitle=t.dataset.subtitle),t.dataset.album&&(e.album=t.dataset.album),t.dataset.artwork&&(e.artwork=t.dataset.artwork),t.dataset.waveform&&(e.waveform=t.dataset.waveform),t.dataset.markers)try{e.markers=JSON.parse(t.dataset.markers)}catch(i){console.warn("Invalid markers JSON:",i)}if(t.dataset.playbackRate&&(e.playbackRate=parseFloat(t.dataset.playbackRate)),t.dataset.showPlaybackSpeed!==void 0&&(e.showPlaybackSpeed=t.dataset.showPlaybackSpeed==="true"),t.dataset.playbackRates)try{e.playbackRates=JSON.parse(t.dataset.playbackRates)}catch(i){console.warn("Invalid playbackRates JSON:",i)}return t.dataset.enableMediaSession!==void 0&&(e.enableMediaSession=t.dataset.enableMediaSession==="true"),e}function P(t){if(!t||isNaN(t))return"0:00";let e=Math.floor(t/60),i=Math.floor(t%60);return`${e}:${i.toString().padStart(2,"0")}`}function A(t){let e=t||Math.random().toString();return btoa(e.substring(0,10)).replace(/[^a-zA-Z0-9]/g,"")}function R(t){if(!t)return"Audio";let e=t.split("/");return e[e.length-1].split(".")[0].replace(/[-_]/g," ").replace(/\b\w/g,a=>a.toUpperCase())}function C(...t){let e={};for(let i of t)for(let o in i)i[o]!==null&&i[o]!==void 0&&(e[o]=i[o]);return e}function B(t,e){let i;return function(...a){let n=()=>{clearTimeout(i),t(...a)};clearTimeout(i),i=setTimeout(n,e)}}function S(t,e){if(t.length===e)return t;if(t.length===0||e===0)return[];let i=[];if(e>t.length){let o=(t.length-1)/(e-1);for(let a=0;a<e;a++){let n=a*o,r=Math.floor(n),s=Math.ceil(n),h=n-r;if(s>=t.length)i.push(t[t.length-1]);else if(r===s)i.push(t[r]);else{let l=t[r]*(1-h)+t[s]*h;i.push(l)}}}else{let o=t.length/e;for(let a=0;a<e;a++){let n=Math.floor(a*o),r=Math.floor((a+1)*o),s=0,h=0;for(let l=n;l<=r&&l<t.length;l++)t[l]>s&&(s=t[l]),h++;if(h===0){let l=Math.min(Math.round(a*o),t.length-1);s=t[l]}i.push(s)}}return i}function x(t,e,i,o,a){let n=window.devicePixelRatio||1,r=a.barWidth*n,s=a.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=o*e.width;t.clearRect(0,0,e.width,e.height);for(let y=0;y<l.length;y++){let f=y*(r+s);if(f+r>e.width)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=a.color,t.fillRect(f,m,r,c)}t.save(),t.beginPath(),t.rect(0,0,p,d),t.clip();for(let y=0;y<l.length;y++){let f=y*(r+s);if(f>p)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=a.progressColor,t.fillRect(f,m,r,c)}t.restore()}function q(t,e,i,o,a){let n=window.devicePixelRatio||1,r=a.barWidth*n,s=a.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=d/2,y=o*e.width;t.clearRect(0,0,e.width,e.height);for(let f=0;f<l.length;f++){let c=f*(r+s);if(c+r>e.width)break;let m=l[f]*d*.45;t.fillStyle=a.color,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.save(),t.beginPath(),t.rect(0,0,y,d),t.clip();for(let f=0;f<l.length;f++){let c=f*(r+s);if(c>y)break;let m=l[f]*d*.45;t.fillStyle=a.progressColor,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.restore()}function $(t,e,i,o,a){let n=e.width,r=e.height,s=r/2,h=r*.35;t.clearRect(0,0,n,r);let l=(d,p,y=1,f=!1)=>{f&&(t.shadowBlur=12,t.shadowColor=d),t.strokeStyle=d,t.lineWidth=p,t.lineCap="round",t.lineJoin="round",t.beginPath(),t.moveTo(0,s);let c=[],m=Math.floor(i.length*y);for(let u=0;u<m;u++){let v=u/(i.length-1)*n,k=i[u],b=Math.sin(u*.1)*k,w=s+b*h;c.push({x:v,y:w})}for(let u=0;u<c.length-1;u++){let v=c[u].x+(c[u+1].x-c[u].x)*.5,k=c[u].y,b=c[u+1].x-(c[u+1].x-c[u].x)*.5,w=c[u+1].y;t.bezierCurveTo(v,k,b,w,c[u+1].x,c[u+1].y)}t.stroke(),f&&(t.shadowBlur=0)};t.strokeStyle="rgba(255, 255, 255, 0.03)",t.lineWidth=.5,t.beginPath(),t.moveTo(0,s),t.lineTo(n,s),t.stroke();for(let d=0;d<=10;d++){let p=n/10*d;t.beginPath(),t.moveTo(p,0),t.lineTo(p,r),t.stroke()}l(a.color,2,1,!1),o>0&&l(a.progressColor,3,o,!0)}function U(t,e,i,o,a){let n=window.devicePixelRatio||1,r=(a.barWidth||3)*n,s=(a.barSpacing||1)*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=4*n,y=2*n,f=o*e.width,c=d/2;t.clearRect(0,0,e.width,e.height);for(let m=0;m<l.length;m++){let u=m*(r+s);if(u+r>e.width)break;let v=l[m]*d*.9,k=Math.floor(v/(p+y));t.fillStyle=u<f?a.progressColor:a.color;for(let b=0;b<k;b++){let w=b*(p+y);t.fillRect(u,c-w-p,r,p),b>0&&t.fillRect(u,c+w,r,p)}}}function F(t,e,i,o,a){let n=window.devicePixelRatio||1,r=(a.barWidth||2)*n,s=(a.barSpacing||3)*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=Math.max(1.5*n,r/2),y=o*e.width,f=d/2;t.clearRect(0,0,e.width,e.height);for(let c=0;c<l.length;c++){let m=c*(r+s)+r/2;if(m>e.width)break;let u=l[c]*d*.9;t.fillStyle=m<y?a.progressColor:a.color,t.beginPath(),t.arc(m,f-u/2,p,0,Math.PI*2),t.fill(),t.beginPath(),t.arc(m,f+u/2,p,0,Math.PI*2),t.fill()}}function N(t,e,i,o,a){let n=e.width,r=e.height,s=r/2,h=4,l=h/2;if(t.clearRect(0,0,n,r),t.fillStyle=a.color||"rgba(255, 255, 255, 0.2)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(n-l,s-h/2),t.arc(n-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),o>0){let d=Math.max(l*2,o*n);t.shadowBlur=8,t.shadowColor=a.progressColor,t.fillStyle=a.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(d-l,s-h/2),t.arc(d-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),t.shadowBlur=0;let p=8,y=d;t.shadowBlur=4,t.shadowColor="rgba(0, 0, 0, 0.3)",t.shadowOffsetY=2,t.fillStyle="#ffffff",t.beginPath(),t.arc(y,s,p,0,Math.PI*2),t.fill(),t.shadowBlur=0,t.shadowOffsetY=0,t.fillStyle=a.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.arc(y,s,p*.4,0,Math.PI*2),t.fill()}}var Y={bars:x,mirror:q,line:$,blocks:U,dots:F,seekbar:N};function W(t,e,i,o,a){(Y[a.waveformStyle]||x)(t,e,i,o,a)}function I(t){try{let e=t.getChannelData(0),i=t.sampleRate,o=j(e,i);if(o.length<2)return 120;let a=[];for(let h=1;h<o.length;h++)a.push((o[h]-o[h-1])/i);let n={};a.forEach(h=>{let l=60/h,d=Math.round(l/3)*3;d>60&&d<200&&(n[d]=(n[d]||0)+1)});let r=0,s=120;for(let[h,l]of Object.entries(n))l>r&&(r=l,s=parseInt(h));return s<70&&n[s*2]?s*=2:s>160&&n[Math.round(s/2)]&&(s=Math.round(s/2)),s-1}catch(e){return console.warn("BPM detection failed:",e),null}}function j(t,e){let a=[],n=0;for(let r=0;r<t.length-2048;r+=1024){let s=0;for(let d=r;d<r+2048;d++)s+=t[d]*t[d];s=s/2048;let h=s-n,l=n*1.8+.01;if(h>l&&s>.01){let d=a[a.length-1]||0,p=e*.15;r-d>p&&a.push(r)}n=s*.8+n*.2}return a}function V(t,e=200){let i=t.length/e,o=~~(i/10)||1,a=t.numberOfChannels,n=[];for(let s=0;s<a;s++){let h=t.getChannelData(s);for(let l=0;l<e;l++){let d=~~(l*i),p=~~(d+i),y=0,f=0;for(let m=d;m<p;m+=o){let u=h[m];u>f&&(f=u),u<y&&(y=u)}let c=Math.max(Math.abs(f),Math.abs(y));(s===0||c>n[l])&&(n[l]=c)}}let r=Math.max(...n);return r>0?n.map(s=>s/r):n}async function M(t,e=200,i=!1){try{let o=new(window.AudioContext||window.webkitAudioContext),n=await(await fetch(t)).arrayBuffer(),r=await o.decodeAudioData(n),s=V(r,e);s=J(s);let h=null;return i&&(h=await I(r)),o.close(),{peaks:s,bpm:h}}catch(o){throw console.error("Failed to generate waveform:",o),o}}function D(t=200){let e=[];for(let i=0;i<t;i++){let o=Math.random()*.5+.3,a=Math.sin(i/t*Math.PI*4)*.2;e.push(Math.max(.1,Math.min(1,o+a)))}return e}function J(t,e=.95){let i=Math.max(...t);if(i===0||i>e)return t;let o=e/i;return t.map(a=>a*o)}function G(){let t=document.documentElement,e=document.body;if(t.classList.contains("dark")||t.classList.contains("dark-mode")||t.classList.contains("theme-dark")||t.getAttribute("data-theme")==="dark"||t.getAttribute("data-color-scheme")==="dark"||e.classList.contains("dark")||e.classList.contains("dark-mode")||e.getAttribute("data-theme")==="dark")return"dark";if(t.classList.contains("light")||t.classList.contains("light-mode")||t.classList.contains("theme-light")||t.getAttribute("data-theme")==="light"||t.getAttribute("data-color-scheme")==="light"||e.classList.contains("light")||e.classList.contains("light-mode")||e.getAttribute("data-theme")==="light")return"light";try{let o=getComputedStyle(document.body).backgroundColor.match(/\d+/g);if(o&&o.length>=3){let[a,n,r]=o.map(Number),s=(a*299+n*587+r*114)/1e3;if(s>128)return"light";if(s<128)return"dark"}}catch{}if(window.matchMedia){if(window.matchMedia("(prefers-color-scheme: dark)").matches)return"dark";if(window.matchMedia("(prefers-color-scheme: light)").matches)return"light"}return"dark"}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)"}};function O(t){if(t&&E[t])return E[t];let e=G();return E[e]}var z={url:"",height:60,samples:200,preload:"metadata",playbackRate:1,showPlaybackSpeed:!1,playbackRates:[.5,.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:!1,showTime:!0,showHoverTime:!1,showBPM:!1,singlePlay:!0,playOnSeek:!0,enableMediaSession:!0,markers:[],showMarkers:!0,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},H={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}};var g=class t{static instances=new Map;static currentlyPlaying=null;constructor(e,i={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("WaveformPlayer: Container element not found");let o=L(this.container);this.options=C(z,o,i);let a=O(this.options.colorPreset);for(let[r,s]of Object.entries(a))(this.options[r]===null||this.options[r]===void 0)&&(this.options[r]=s);let n=H[this.options.waveformStyle];n&&(o.barWidth===void 0&&i.barWidth===void 0&&(this.options.barWidth=n.barWidth),o.barSpacing===void 0&&i.barSpacing===void 0&&(this.options.barSpacing=n.barSpacing)),this.audio=null,this.canvas=null,this.ctx=null,this.waveformData=[],this.progress=0,this.isPlaying=!1,this.isLoading=!1,this.hasError=!1,this.updateTimer=null,this.resizeObserver=null,this.id=this.container.id||A(this.options.url),t.instances.set(this.id,this),this.init(),setTimeout(()=>{this.container.dispatchEvent(new CustomEvent("waveformplayer:ready",{detail:{player:this,url:this.options.url}}))},100)}init(){this.createDOM(),this.createAudio(),this.initPlaybackSpeed(),this.initKeyboardControls(),this.bindEvents(),this.setupResizeObserver(),requestAnimationFrame(()=>{this.resizeCanvas(),this.options.url&&this.load(this.options.url).then(()=>{this.options.autoplay&&this.play()}).catch(e=>{console.error("Failed to load audio:",e)})})}createDOM(){this.container.innerHTML="",this.container.className="waveform-player";let e=this.options.buttonAlign;e==="auto"&&(this.options.waveformStyle==="bars"?e="bottom":e="center"),this.container.innerHTML=`
1
+ (()=>{function L(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&&(e.height=parseInt(t.dataset.height)),t.dataset.samples&&(e.samples=parseInt(t.dataset.samples)),t.dataset.preload&&(e.preload=t.dataset.preload),t.dataset.waveformStyle&&(e.waveformStyle=t.dataset.waveformStyle),t.dataset.barWidth&&(e.barWidth=parseInt(t.dataset.barWidth)),t.dataset.barSpacing&&(e.barSpacing=parseInt(t.dataset.barSpacing)),t.dataset.buttonAlign&&(e.buttonAlign=t.dataset.buttonAlign),t.dataset.colorPreset&&(e.colorPreset=t.dataset.colorPreset),t.dataset.waveformColor&&(e.waveformColor=t.dataset.waveformColor),t.dataset.progressColor&&(e.progressColor=t.dataset.progressColor),t.dataset.buttonColor&&(e.buttonColor=t.dataset.buttonColor),t.dataset.buttonHoverColor&&(e.buttonHoverColor=t.dataset.buttonHoverColor),t.dataset.textColor&&(e.textColor=t.dataset.textColor),t.dataset.textSecondaryColor&&(e.textSecondaryColor=t.dataset.textSecondaryColor),t.dataset.backgroundColor&&(e.backgroundColor=t.dataset.backgroundColor),t.dataset.borderColor&&(e.borderColor=t.dataset.borderColor),t.dataset.color&&(e.waveformColor=t.dataset.color),t.dataset.theme&&(e.colorPreset=t.dataset.theme),t.dataset.autoplay&&(e.autoplay=t.dataset.autoplay==="true"),t.dataset.showTime&&(e.showTime=t.dataset.showTime==="true"),t.dataset.showHoverTime&&(e.showHoverTime=t.dataset.showHoverTime==="true"),t.dataset.showBpm&&(e.showBPM=t.dataset.showBpm==="true"),t.dataset.singlePlay&&(e.singlePlay=t.dataset.singlePlay==="true"),t.dataset.playOnSeek&&(e.playOnSeek=t.dataset.playOnSeek==="true"),t.dataset.title&&(e.title=t.dataset.title),t.dataset.subtitle&&(e.subtitle=t.dataset.subtitle),t.dataset.album&&(e.album=t.dataset.album),t.dataset.artwork&&(e.artwork=t.dataset.artwork),t.dataset.waveform&&(e.waveform=t.dataset.waveform),t.dataset.markers)try{e.markers=JSON.parse(t.dataset.markers)}catch(i){console.warn("Invalid markers JSON:",i)}if(t.dataset.playbackRate&&(e.playbackRate=parseFloat(t.dataset.playbackRate)),t.dataset.showPlaybackSpeed!==void 0&&(e.showPlaybackSpeed=t.dataset.showPlaybackSpeed==="true"),t.dataset.playbackRates)try{e.playbackRates=JSON.parse(t.dataset.playbackRates)}catch(i){console.warn("Invalid playbackRates JSON:",i)}return t.dataset.enableMediaSession!==void 0&&(e.enableMediaSession=t.dataset.enableMediaSession==="true"),e}function P(t){if(!t||isNaN(t))return"0:00";let e=Math.floor(t/60),i=Math.floor(t%60);return`${e}:${i.toString().padStart(2,"0")}`}function A(t){let e=t||Math.random().toString();return btoa(e.substring(0,10)).replace(/[^a-zA-Z0-9]/g,"")}function R(t){if(!t)return"Audio";let e=t.split("/");return e[e.length-1].split(".")[0].replace(/[-_]/g," ").replace(/\b\w/g,s=>s.toUpperCase())}function C(...t){let e={};for(let i of t)for(let a in i)i[a]!==null&&i[a]!==void 0&&(e[a]=i[a]);return e}function B(t,e){let i;return function(...s){let n=()=>{clearTimeout(i),t(...s)};clearTimeout(i),i=setTimeout(n,e)}}function S(t,e){if(t.length===e)return t;if(t.length===0||e===0)return[];let i=[];if(e>t.length){let a=(t.length-1)/(e-1);for(let s=0;s<e;s++){let n=s*a,r=Math.floor(n),o=Math.ceil(n),h=n-r;if(o>=t.length)i.push(t[t.length-1]);else if(r===o)i.push(t[r]);else{let l=t[r]*(1-h)+t[o]*h;i.push(l)}}}else{let a=t.length/e;for(let s=0;s<e;s++){let n=Math.floor(s*a),r=Math.floor((s+1)*a),o=0,h=0;for(let l=n;l<=r&&l<t.length;l++)t[l]>o&&(o=t[l]),h++;if(h===0){let l=Math.min(Math.round(s*a),t.length-1);o=t[l]}i.push(o)}}return i}function x(t,e,i,a,s){let n=window.devicePixelRatio||1,r=s.barWidth*n,o=s.barSpacing*n,h=Math.floor(e.width/(r+o)),l=S(i,h),d=e.height,p=a*e.width;t.clearRect(0,0,e.width,e.height);for(let y=0;y<l.length;y++){let f=y*(r+o);if(f+r>e.width)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=s.color,t.fillRect(f,m,r,c)}t.save(),t.beginPath(),t.rect(0,0,p,d),t.clip();for(let y=0;y<l.length;y++){let f=y*(r+o);if(f>p)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=s.progressColor,t.fillRect(f,m,r,c)}t.restore()}function q(t,e,i,a,s){let n=window.devicePixelRatio||1,r=s.barWidth*n,o=s.barSpacing*n,h=Math.floor(e.width/(r+o)),l=S(i,h),d=e.height,p=d/2,y=a*e.width;t.clearRect(0,0,e.width,e.height);for(let f=0;f<l.length;f++){let c=f*(r+o);if(c+r>e.width)break;let m=l[f]*d*.45;t.fillStyle=s.color,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.save(),t.beginPath(),t.rect(0,0,y,d),t.clip();for(let f=0;f<l.length;f++){let c=f*(r+o);if(c>y)break;let m=l[f]*d*.45;t.fillStyle=s.progressColor,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.restore()}function $(t,e,i,a,s){let n=e.width,r=e.height,o=r/2,h=r*.35;t.clearRect(0,0,n,r);let l=(d,p,y=1,f=!1)=>{f&&(t.shadowBlur=12,t.shadowColor=d),t.strokeStyle=d,t.lineWidth=p,t.lineCap="round",t.lineJoin="round",t.beginPath(),t.moveTo(0,o);let c=[],m=Math.floor(i.length*y);for(let u=0;u<m;u++){let v=u/(i.length-1)*n,k=i[u],b=Math.sin(u*.1)*k,w=o+b*h;c.push({x:v,y:w})}for(let u=0;u<c.length-1;u++){let v=c[u].x+(c[u+1].x-c[u].x)*.5,k=c[u].y,b=c[u+1].x-(c[u+1].x-c[u].x)*.5,w=c[u+1].y;t.bezierCurveTo(v,k,b,w,c[u+1].x,c[u+1].y)}t.stroke(),f&&(t.shadowBlur=0)};t.strokeStyle="rgba(255, 255, 255, 0.03)",t.lineWidth=.5,t.beginPath(),t.moveTo(0,o),t.lineTo(n,o),t.stroke();for(let d=0;d<=10;d++){let p=n/10*d;t.beginPath(),t.moveTo(p,0),t.lineTo(p,r),t.stroke()}l(s.color,2,1,!1),a>0&&l(s.progressColor,3,a,!0)}function U(t,e,i,a,s){let n=window.devicePixelRatio||1,r=(s.barWidth||3)*n,o=(s.barSpacing||1)*n,h=Math.floor(e.width/(r+o)),l=S(i,h),d=e.height,p=4*n,y=2*n,f=a*e.width,c=d/2;t.clearRect(0,0,e.width,e.height);for(let m=0;m<l.length;m++){let u=m*(r+o);if(u+r>e.width)break;let v=l[m]*d*.9,k=Math.floor(v/(p+y));t.fillStyle=u<f?s.progressColor:s.color;for(let b=0;b<k;b++){let w=b*(p+y);t.fillRect(u,c-w-p,r,p),b>0&&t.fillRect(u,c+w,r,p)}}}function F(t,e,i,a,s){let n=window.devicePixelRatio||1,r=(s.barWidth||2)*n,o=(s.barSpacing||3)*n,h=Math.floor(e.width/(r+o)),l=S(i,h),d=e.height,p=Math.max(1.5*n,r/2),y=a*e.width,f=d/2;t.clearRect(0,0,e.width,e.height);for(let c=0;c<l.length;c++){let m=c*(r+o)+r/2;if(m>e.width)break;let u=l[c]*d*.9;t.fillStyle=m<y?s.progressColor:s.color,t.beginPath(),t.arc(m,f-u/2,p,0,Math.PI*2),t.fill(),t.beginPath(),t.arc(m,f+u/2,p,0,Math.PI*2),t.fill()}}function N(t,e,i,a,s){let n=e.width,r=e.height,o=r/2,h=4,l=h/2;if(t.clearRect(0,0,n,r),t.fillStyle=s.color||"rgba(255, 255, 255, 0.2)",t.beginPath(),t.moveTo(l,o-h/2),t.lineTo(n-l,o-h/2),t.arc(n-l,o,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,o+h/2),t.arc(l,o,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),a>0){let d=Math.max(l*2,a*n);t.shadowBlur=8,t.shadowColor=s.progressColor,t.fillStyle=s.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.moveTo(l,o-h/2),t.lineTo(d-l,o-h/2),t.arc(d-l,o,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,o+h/2),t.arc(l,o,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),t.shadowBlur=0;let p=8,y=d;t.shadowBlur=4,t.shadowColor="rgba(0, 0, 0, 0.3)",t.shadowOffsetY=2,t.fillStyle="#ffffff",t.beginPath(),t.arc(y,o,p,0,Math.PI*2),t.fill(),t.shadowBlur=0,t.shadowOffsetY=0,t.fillStyle=s.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.arc(y,o,p*.4,0,Math.PI*2),t.fill()}}var Y={bars:x,mirror:q,line:$,blocks:U,dots:F,seekbar:N};function W(t,e,i,a,s){(Y[s.waveformStyle]||x)(t,e,i,a,s)}function I(t){try{let e=t.getChannelData(0),i=t.sampleRate,a=j(e,i);if(a.length<2)return 120;let s=[];for(let h=1;h<a.length;h++)s.push((a[h]-a[h-1])/i);let n={};s.forEach(h=>{let l=60/h,d=Math.round(l/3)*3;d>60&&d<200&&(n[d]=(n[d]||0)+1)});let r=0,o=120;for(let[h,l]of Object.entries(n))l>r&&(r=l,o=parseInt(h));return o<70&&n[o*2]?o*=2:o>160&&n[Math.round(o/2)]&&(o=Math.round(o/2)),o-1}catch(e){return console.warn("BPM detection failed:",e),null}}function j(t,e){let s=[],n=0;for(let r=0;r<t.length-2048;r+=1024){let o=0;for(let d=r;d<r+2048;d++)o+=t[d]*t[d];o=o/2048;let h=o-n,l=n*1.8+.01;if(h>l&&o>.01){let d=s[s.length-1]||0,p=e*.15;r-d>p&&s.push(r)}n=o*.8+n*.2}return s}function V(t,e=200){let i=t.length/e,a=~~(i/10)||1,s=t.numberOfChannels,n=[];for(let o=0;o<s;o++){let h=t.getChannelData(o);for(let l=0;l<e;l++){let d=~~(l*i),p=~~(d+i),y=0,f=0;for(let m=d;m<p;m+=a){let u=h[m];u>f&&(f=u),u<y&&(y=u)}let c=Math.max(Math.abs(f),Math.abs(y));(o===0||c>n[l])&&(n[l]=c)}}let r=Math.max(...n);return r>0?n.map(o=>o/r):n}async function M(t,e=200,i=!1){try{let a=new(window.AudioContext||window.webkitAudioContext),n=await(await fetch(t)).arrayBuffer(),r=await a.decodeAudioData(n),o=V(r,e);o=J(o);let h=null;return i&&(h=await I(r)),a.close(),{peaks:o,bpm:h}}catch(a){throw console.error("Failed to generate waveform:",a),a}}function D(t=200){let e=[];for(let i=0;i<t;i++){let a=Math.random()*.5+.3,s=Math.sin(i/t*Math.PI*4)*.2;e.push(Math.max(.1,Math.min(1,a+s)))}return e}function J(t,e=.95){let i=Math.max(...t);if(i===0||i>e)return t;let a=e/i;return t.map(s=>s*a)}function G(){let t=document.documentElement,e=document.body;if(t.classList.contains("dark")||t.classList.contains("dark-mode")||t.classList.contains("theme-dark")||t.getAttribute("data-theme")==="dark"||t.getAttribute("data-color-scheme")==="dark"||e.classList.contains("dark")||e.classList.contains("dark-mode")||e.getAttribute("data-theme")==="dark")return"dark";if(t.classList.contains("light")||t.classList.contains("light-mode")||t.classList.contains("theme-light")||t.getAttribute("data-theme")==="light"||t.getAttribute("data-color-scheme")==="light"||e.classList.contains("light")||e.classList.contains("light-mode")||e.getAttribute("data-theme")==="light")return"light";try{let a=getComputedStyle(document.body).backgroundColor.match(/\d+/g);if(a&&a.length>=3){let[s,n,r]=a.map(Number),o=(s*299+n*587+r*114)/1e3;if(o>128)return"light";if(o<128)return"dark"}}catch{}if(window.matchMedia){if(window.matchMedia("(prefers-color-scheme: dark)").matches)return"dark";if(window.matchMedia("(prefers-color-scheme: light)").matches)return"light"}return"dark"}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)"}};function z(t){if(t&&E[t])return E[t];let e=G();return E[e]}var O={url:"",height:60,samples:200,preload:"metadata",playbackRate:1,showPlaybackSpeed:!1,playbackRates:[.5,.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:!1,showTime:!0,showHoverTime:!1,showBPM:!1,singlePlay:!0,playOnSeek:!0,enableMediaSession:!0,markers:[],showMarkers:!0,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},H={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}};var g=class t{static instances=new Map;static currentlyPlaying=null;constructor(e,i={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("WaveformPlayer: Container element not found");let a=L(this.container);this.options=C(O,a,i);let s=z(this.options.colorPreset);for(let[r,o]of Object.entries(s))(this.options[r]===null||this.options[r]===void 0)&&(this.options[r]=o);let n=H[this.options.waveformStyle];n&&(a.barWidth===void 0&&i.barWidth===void 0&&(this.options.barWidth=n.barWidth),a.barSpacing===void 0&&i.barSpacing===void 0&&(this.options.barSpacing=n.barSpacing)),this.audio=null,this.canvas=null,this.ctx=null,this.waveformData=[],this.progress=0,this.isPlaying=!1,this.isLoading=!1,this.hasError=!1,this.updateTimer=null,this.resizeObserver=null,this.id=this.container.id||A(this.options.url),t.instances.set(this.id,this),this.init(),setTimeout(()=>{this.container.dispatchEvent(new CustomEvent("waveformplayer:ready",{bubbles:!0,detail:{player:this,url:this.options.url}}))},100)}init(){this.createDOM(),this.createAudio(),this.initPlaybackSpeed(),this.initKeyboardControls(),this.bindEvents(),this.setupResizeObserver(),requestAnimationFrame(()=>{this.resizeCanvas(),this.options.url&&this.load(this.options.url).then(()=>{this.options.autoplay&&this.play()}).catch(e=>{console.error("Failed to load audio:",e)})})}createDOM(){this.container.innerHTML="",this.container.className="waveform-player";let e=this.options.buttonAlign;e==="auto"&&(this.options.waveformStyle==="bars"?e="bottom":e="center"),this.container.innerHTML=`
2
2
  <div class="waveform-player-inner">
3
3
  <div class="waveform-body">
4
4
  <div class="waveform-track waveform-align-${e}">
@@ -59,4 +59,4 @@
59
59
  </div>
60
60
  </div>
61
61
  </div>
62
- `,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()}createAudio(){this.audio=new Audio,this.audio.preload=this.options.preload||"metadata",this.audio.crossOrigin="anonymous"}initPlaybackSpeed(){this.options.playbackRate&&this.options.playbackRate!==1&&(this.audio.playbackRate=this.options.playbackRate),this.options.showPlaybackSpeed&&this.initSpeedControls()}initSpeedControls(){let e=this.container.querySelector(".speed-btn"),i=this.container.querySelector(".speed-menu");!e||!i||(e.addEventListener("click",o=>{o.stopPropagation(),i.style.display=i.style.display==="none"?"block":"none"}),document.addEventListener("click",()=>{i.style.display="none"}),i.addEventListener("click",o=>{if(o.stopPropagation(),o.target.classList.contains("speed-option")){let a=parseFloat(o.target.dataset.rate);this.setPlaybackRate(a),i.style.display="none"}}),this.updateSpeedUI())}initKeyboardControls(){this.container.setAttribute("tabindex","-1"),this.container.addEventListener("click",()=>{t.getAllInstances().forEach(e=>{e!==this&&e.container.setAttribute("tabindex","-1")}),this.container.setAttribute("tabindex","0"),this.container.focus()}),this.container.addEventListener("keydown",e=>{if(document.activeElement!==this.container)return;let i=e.key,o=this.audio.currentTime;if(i>="0"&&i<="9"){e.preventDefault(),this.seekToPercent(parseInt(i)/10);return}let a={" ":()=>this.togglePlay(),ArrowLeft:()=>this.seekTo(Math.max(0,o-5)),ArrowRight:()=>this.seekTo(Math.min(this.audio.duration,o+5)),ArrowUp:()=>this.setVolume(Math.min(1,this.audio.volume+.1)),ArrowDown:()=>this.setVolume(Math.max(0,this.audio.volume-.1)),m:()=>this.audio.muted=!this.audio.muted,M:()=>this.audio.muted=!this.audio.muted};a[i]&&(e.preventDefault(),a[i]())})}initMediaSession(){!("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",()=>{this.seekTo(Math.max(0,this.audio.currentTime-10))}),navigator.mediaSession.setActionHandler("seekforward",()=>{this.seekTo(Math.min(this.audio.duration,this.audio.currentTime+10))}),navigator.mediaSession.setActionHandler("seekto",e=>{e.seekTime!==null&&this.seekTo(e.seekTime)}))}bindEvents(){this.playBtn.addEventListener("click",()=>this.togglePlay()),this.audio.addEventListener("loadstart",()=>this.setLoading(!0)),this.audio.addEventListener("loadedmetadata",()=>this.onMetadataLoaded()),this.audio.addEventListener("canplay",()=>this.setLoading(!1)),this.audio.addEventListener("play",()=>this.onPlay()),this.audio.addEventListener("pause",()=>this.onPause()),this.audio.addEventListener("ended",()=>this.onEnded()),this.audio.addEventListener("error",e=>this.onError(e)),this.canvas.addEventListener("click",e=>this.handleCanvasClick(e)),window.addEventListener("resize",B(()=>this.resizeCanvas(),100))}setupResizeObserver(){"ResizeObserver"in window&&(this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.canvas?.parentElement&&this.resizeObserver.observe(this.canvas.parentElement))}async load(e){try{this.setLoading(!0),this.progress=0,this.hasError=!1,this.audio.src=e,await new Promise((o,a)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),o()},r=s=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),a(s)};this.audio.addEventListener("loadedmetadata",n),this.audio.addEventListener("error",r)});let i=this.options.title||R(e);if(this.titleEl&&(this.titleEl.textContent=i),this.options.waveform)this.setWaveformData(this.options.waveform);else try{let o=await M(e,this.options.samples,this.options.showBPM);this.waveformData=o.peaks,o.bpm&&(this.detectedBPM=o.bpm,this.updateBPMDisplay())}catch(o){console.warn("Using placeholder waveform:",o),this.waveformData=D(this.options.samples)}this.drawWaveform(),this.renderMarkers(),this.initMediaSession(),this.options.onLoad&&this.options.onLoad(this)}catch(i){console.error("Failed to load audio:",i),this.onError(i)}finally{this.setLoading(!1)}}async loadTrack(e,i=null,o=null,a={}){this.isPlaying&&this.pause(),this.audio.src="",this.audio.load(),this.hasError=!1,this.errorEl&&(this.errorEl.style.display="none"),this.canvas&&(this.canvas.style.opacity="1"),this.playBtn&&(this.playBtn.disabled=!1),this.progress=0,this.waveformData=[],this.options=C(this.options,{url:e,title:i||this.options.title,subtitle:o||this.options.subtitle,...a}),a.preload&&(this.audio.preload=a.preload),this.subtitleEl&&(o?(this.subtitleEl.textContent=o,this.subtitleEl.style.display=""):o===""&&(this.subtitleEl.style.display="none")),a.artwork&&this.artworkEl&&(this.artworkEl.src=a.artwork),a.markers&&(this.options.markers=a.markers),await this.load(e),this.play()}setWaveformData(e){if(typeof e=="string")try{let i=JSON.parse(e);this.waveformData=Array.isArray(i)?i:[]}catch{this.waveformData=e.split(",").map(Number)}else this.waveformData=Array.isArray(e)?e:[];this.drawWaveform()}drawWaveform(){!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})}resizeCanvas(){let e=window.devicePixelRatio||1,i=this.canvas.getBoundingClientRect();this.canvas.width=i.width*e,this.canvas.height=this.options.height*e,this.canvas.style.height=this.options.height+"px",this.canvas.parentElement.style.height=this.options.height+"px",this.drawWaveform()}renderMarkers(){!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((e,i)=>{if(e.time>this.audio.duration){console.warn(`Marker "${e.label}" at ${e.time}s exceeds audio duration of ${this.audio.duration}s`);return}let o=e.time/this.audio.duration*100,a=document.createElement("button");a.className="waveform-marker",a.style.left=`${o}%`,a.style.backgroundColor=e.color||"rgba(255, 255, 255, 0.5)",a.setAttribute("aria-label",e.label),a.setAttribute("data-time",e.time);let n=document.createElement("span");n.className="waveform-marker-tooltip",n.textContent=e.label,a.appendChild(n),a.addEventListener("click",r=>{r.stopPropagation(),this.seekTo(e.time),this.options.playOnSeek&&!this.isPlaying&&this.play()}),this.markersContainer.appendChild(a)}))}handleCanvasClick(e){if(!this.audio.duration)return;let i=this.canvas.getBoundingClientRect(),o=e.clientX-i.left,a=Math.max(0,Math.min(1,o/i.width));this.seekToPercent(a)}setLoading(e){this.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none")}onMetadataLoaded(){this.totalTimeEl&&(this.totalTimeEl.textContent=P(this.audio.duration)),this.renderMarkers()}onPlay(){this.isPlaying=!0,this.playBtn.classList.add("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="none"),i&&(i.style.display="flex"),this.startSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:play",{detail:{player:this,url:this.options.url}})),this.options.onPlay&&this.options.onPlay(this)}onPause(){this.isPlaying=!1,this.playBtn.classList.remove("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="flex"),i&&(i.style.display="none"),this.stopSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:pause",{detail:{player:this,url:this.options.url}})),this.options.onPause&&this.options.onPause(this)}onEnded(){this.progress=0,this.audio.currentTime=0,this.drawWaveform(),this.currentTimeEl&&(this.currentTimeEl.textContent="0:00"),this.container.dispatchEvent(new CustomEvent("waveformplayer:ended",{detail:{player:this,url:this.options.url}})),this.onPause(),this.options.onEnd&&this.options.onEnd(this)}onError(e){this.isDestroying||(console.error("Audio error:",e),this.hasError=!0,this.setLoading(!1),this.errorEl&&(this.errorEl.style.display="flex"),this.canvas&&(this.canvas.style.opacity="0.2"),this.playBtn&&(this.playBtn.disabled=!0),this.options.onError&&this.options.onError(e,this))}startSmoothUpdate(){this.stopSmoothUpdate();let e=()=>{this.isPlaying&&this.audio.duration&&(this.updateProgress(),this.updateTimer=requestAnimationFrame(e))};this.updateTimer=requestAnimationFrame(e)}stopSmoothUpdate(){this.updateTimer&&(cancelAnimationFrame(this.updateTimer),this.updateTimer=null)}updateProgress(){if(!this.audio.duration)return;let e=this.audio.currentTime/this.audio.duration;Math.abs(e-this.progress)>.001&&(this.progress=e,this.drawWaveform()),this.currentTimeEl&&(this.currentTimeEl.textContent=P(this.audio.currentTime)),this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate",{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)}updateBPMDisplay(){this.bpmEl&&this.bpmValueEl&&this.detectedBPM&&(this.bpmValueEl.textContent=Math.round(this.detectedBPM),this.bpmEl.style.display="inline-flex")}updateSpeedUI(){let e=this.container.querySelector(".speed-value");if(e){let i=this.audio.playbackRate;e.textContent=i===1?"1x":`${i}x`}this.container.querySelectorAll(".speed-option").forEach(i=>{i.classList.toggle("active",parseFloat(i.dataset.rate)===this.audio.playbackRate)})}play(){this.options.singlePlay&&t.currentlyPlaying&&t.currentlyPlaying!==this&&t.currentlyPlaying.pause(),t.currentlyPlaying=this,this.audio.play()}pause(){t.currentlyPlaying===this&&(t.currentlyPlaying=null),this.audio.pause()}togglePlay(){this.isPlaying?this.pause():this.play()}seekTo(e){this.audio&&this.audio.duration&&(this.audio.currentTime=Math.max(0,Math.min(e,this.audio.duration)),this.updateProgress())}seekToPercent(e){this.audio&&this.audio.duration&&(this.audio.currentTime=this.audio.duration*Math.max(0,Math.min(1,e)),this.updateProgress())}setVolume(e){this.audio&&(this.audio.volume=Math.max(0,Math.min(1,e)))}setPlaybackRate(e){if(!this.audio)return;let i=Math.max(.5,Math.min(2,e));this.audio.playbackRate=i,this.options.playbackRate=i,this.updateSpeedUI()}destroy(){this.isDestroying=!0,this.pause(),this.stopSmoothUpdate(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),t.instances.delete(this.id),t.currentlyPlaying===this&&(t.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=[]}static getInstance(e){if(typeof e=="string"){let i=this.instances.get(e);if(i)return i;let o=document.getElementById(e);if(o)return Array.from(this.instances.values()).find(a=>a.container===o)}if(e instanceof HTMLElement)return Array.from(this.instances.values()).find(i=>i.container===e)}static getAllInstances(){return Array.from(this.instances.values())}static destroyAll(){this.instances.forEach(e=>e.destroy()),this.instances.clear()}static async generateWaveformData(e,i=200){try{return(await M(e,i)).peaks}catch(o){throw console.error("Failed to generate waveform:",o),o}}};function T(){if(typeof document>"u")return;document.querySelectorAll("[data-waveform-player]").forEach(e=>{if(e.dataset.waveformInitialized!=="true")try{new g(e),e.dataset.waveformInitialized="true"}catch(i){console.error("Failed to initialize WaveformPlayer:",i,e)}})}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",T):T());g.init=T;typeof window<"u"&&(window.WaveformPlayer=g);var lt=g;})();
62
+ `,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()}createAudio(){this.audio=new Audio,this.audio.preload=this.options.preload||"metadata",this.audio.crossOrigin="anonymous"}initPlaybackSpeed(){this.options.playbackRate&&this.options.playbackRate!==1&&(this.audio.playbackRate=this.options.playbackRate),this.options.showPlaybackSpeed&&this.initSpeedControls()}initSpeedControls(){let e=this.container.querySelector(".speed-btn"),i=this.container.querySelector(".speed-menu");!e||!i||(e.addEventListener("click",a=>{a.stopPropagation(),i.style.display=i.style.display==="none"?"block":"none"}),document.addEventListener("click",()=>{i.style.display="none"}),i.addEventListener("click",a=>{if(a.stopPropagation(),a.target.classList.contains("speed-option")){let s=parseFloat(a.target.dataset.rate);this.setPlaybackRate(s),i.style.display="none"}}),this.updateSpeedUI())}initKeyboardControls(){this.container.setAttribute("tabindex","-1"),this.container.addEventListener("click",()=>{t.getAllInstances().forEach(e=>{e!==this&&e.container.setAttribute("tabindex","-1")}),this.container.setAttribute("tabindex","0"),this.container.focus()}),this.container.addEventListener("keydown",e=>{if(document.activeElement!==this.container)return;let i=e.key,a=this.audio.currentTime;if(i>="0"&&i<="9"){e.preventDefault(),this.seekToPercent(parseInt(i)/10);return}let s={" ":()=>this.togglePlay(),ArrowLeft:()=>this.seekTo(Math.max(0,a-5)),ArrowRight:()=>this.seekTo(Math.min(this.audio.duration,a+5)),ArrowUp:()=>this.setVolume(Math.min(1,this.audio.volume+.1)),ArrowDown:()=>this.setVolume(Math.max(0,this.audio.volume-.1)),m:()=>this.audio.muted=!this.audio.muted,M:()=>this.audio.muted=!this.audio.muted};s[i]&&(e.preventDefault(),s[i]())})}initMediaSession(){!("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",()=>{this.seekTo(Math.max(0,this.audio.currentTime-10))}),navigator.mediaSession.setActionHandler("seekforward",()=>{this.seekTo(Math.min(this.audio.duration,this.audio.currentTime+10))}),navigator.mediaSession.setActionHandler("seekto",e=>{e.seekTime!==null&&this.seekTo(e.seekTime)}))}bindEvents(){this.playBtn.addEventListener("click",()=>this.togglePlay()),this.audio.addEventListener("loadstart",()=>this.setLoading(!0)),this.audio.addEventListener("loadedmetadata",()=>this.onMetadataLoaded()),this.audio.addEventListener("canplay",()=>this.setLoading(!1)),this.audio.addEventListener("play",()=>this.onPlay()),this.audio.addEventListener("pause",()=>this.onPause()),this.audio.addEventListener("ended",()=>this.onEnded()),this.audio.addEventListener("error",e=>this.onError(e)),this.canvas.addEventListener("click",e=>this.handleCanvasClick(e)),this.resizeHandler=B(()=>this.resizeCanvas(),100),window.addEventListener("resize",this.resizeHandler)}setupResizeObserver(){"ResizeObserver"in window&&(this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.canvas?.parentElement&&this.resizeObserver.observe(this.canvas.parentElement))}async load(e){try{this.setLoading(!0),this.progress=0,this.hasError=!1,this.audio.src=e,await new Promise((a,s)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),a()},r=o=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),s(o)};this.audio.addEventListener("loadedmetadata",n),this.audio.addEventListener("error",r)});let i=this.options.title||R(e);if(this.titleEl&&(this.titleEl.textContent=i),this.options.waveform)this.setWaveformData(this.options.waveform);else try{let a=await M(e,this.options.samples,this.options.showBPM);this.waveformData=a.peaks,a.bpm&&(this.detectedBPM=a.bpm,this.updateBPMDisplay())}catch(a){console.warn("Using placeholder waveform:",a),this.waveformData=D(this.options.samples)}this.drawWaveform(),this.renderMarkers(),this.initMediaSession(),this.options.onLoad&&this.options.onLoad(this)}catch(i){console.error("Failed to load audio:",i),this.onError(i)}finally{this.setLoading(!1)}}async loadTrack(e,i=null,a=null,s={}){this.isPlaying&&this.pause(),this.audio.src="",this.audio.load(),this.hasError=!1,this.errorEl&&(this.errorEl.style.display="none"),this.canvas&&(this.canvas.style.opacity="1"),this.playBtn&&(this.playBtn.disabled=!1),this.progress=0,this.waveformData=[],this.options=C(this.options,{url:e,title:i||this.options.title,subtitle:a||this.options.subtitle,...s}),s.preload&&(this.audio.preload=s.preload),this.subtitleEl&&(a?(this.subtitleEl.textContent=a,this.subtitleEl.style.display=""):a===""&&(this.subtitleEl.style.display="none")),s.artwork&&this.artworkEl&&(this.artworkEl.src=s.artwork),s.markers&&(this.options.markers=s.markers),await this.load(e),this.play()}setWaveformData(e){if(typeof e=="string")try{let i=JSON.parse(e);this.waveformData=Array.isArray(i)?i:[]}catch{this.waveformData=e.split(",").map(Number)}else this.waveformData=Array.isArray(e)?e:[];this.drawWaveform()}drawWaveform(){!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})}resizeCanvas(){if(!this.canvas||this.isDestroying)return;let e=window.devicePixelRatio||1,i=this.canvas.getBoundingClientRect();this.canvas.width=i.width*e,this.canvas.height=this.options.height*e,this.canvas.style.height=this.options.height+"px",this.canvas.parentElement.style.height=this.options.height+"px",this.drawWaveform()}renderMarkers(){!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((e,i)=>{if(e.time>this.audio.duration){console.warn(`Marker "${e.label}" at ${e.time}s exceeds audio duration of ${this.audio.duration}s`);return}let a=e.time/this.audio.duration*100,s=document.createElement("button");s.className="waveform-marker",s.style.left=`${a}%`,s.style.backgroundColor=e.color||"rgba(255, 255, 255, 0.5)",s.setAttribute("aria-label",e.label),s.setAttribute("data-time",e.time);let n=document.createElement("span");n.className="waveform-marker-tooltip",n.textContent=e.label,s.appendChild(n),s.addEventListener("click",r=>{r.stopPropagation(),this.seekTo(e.time),this.options.playOnSeek&&!this.isPlaying&&this.play()}),this.markersContainer.appendChild(s)}))}handleCanvasClick(e){if(!this.audio.duration)return;let i=this.canvas.getBoundingClientRect(),a=e.clientX-i.left,s=Math.max(0,Math.min(1,a/i.width));this.seekToPercent(s)}setLoading(e){this.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none")}onMetadataLoaded(){this.isDestroying||(this.totalTimeEl&&(this.totalTimeEl.textContent=P(this.audio.duration)),this.renderMarkers())}onPlay(){if(this.isDestroying)return;this.isPlaying=!0,this.playBtn.classList.add("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="none"),i&&(i.style.display="flex"),this.startSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:play",{bubbles:!0,detail:{player:this,url:this.options.url}})),this.options.onPlay&&this.options.onPlay(this)}onPause(){if(this.isDestroying)return;this.isPlaying=!1,this.playBtn.classList.remove("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="flex"),i&&(i.style.display="none"),this.stopSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:pause",{bubbles:!0,detail:{player:this,url:this.options.url}})),this.options.onPause&&this.options.onPause(this)}onEnded(){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:!0,detail:{player:this,url:this.options.url}})),this.onPause(),this.options.onEnd&&this.options.onEnd(this))}onError(e){this.isDestroying||(console.error("Audio error:",e),this.hasError=!0,this.setLoading(!1),this.errorEl&&(this.errorEl.style.display="flex"),this.canvas&&(this.canvas.style.opacity="0.2"),this.playBtn&&(this.playBtn.disabled=!0),this.options.onError&&this.options.onError(e,this))}startSmoothUpdate(){this.stopSmoothUpdate();let e=()=>{this.isPlaying&&this.audio.duration&&(this.updateProgress(),this.updateTimer=requestAnimationFrame(e))};this.updateTimer=requestAnimationFrame(e)}stopSmoothUpdate(){this.updateTimer&&(cancelAnimationFrame(this.updateTimer),this.updateTimer=null)}updateProgress(){if(!this.audio.duration)return;let e=this.audio.currentTime/this.audio.duration;Math.abs(e-this.progress)>.001&&(this.progress=e,this.drawWaveform()),this.currentTimeEl&&(this.currentTimeEl.textContent=P(this.audio.currentTime)),this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate",{bubbles:!0,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)}updateBPMDisplay(){this.bpmEl&&this.bpmValueEl&&this.detectedBPM&&(this.bpmValueEl.textContent=Math.round(this.detectedBPM),this.bpmEl.style.display="inline-flex")}updateSpeedUI(){let e=this.container.querySelector(".speed-value");if(e){let i=this.audio.playbackRate;e.textContent=i===1?"1x":`${i}x`}this.container.querySelectorAll(".speed-option").forEach(i=>{i.classList.toggle("active",parseFloat(i.dataset.rate)===this.audio.playbackRate)})}play(){return this.options.singlePlay&&t.currentlyPlaying&&t.currentlyPlaying!==this&&t.currentlyPlaying.pause(),t.currentlyPlaying=this,this.audio.play()}pause(){t.currentlyPlaying===this&&(t.currentlyPlaying=null),this.audio.pause()}togglePlay(){this.isPlaying?this.pause():this.play()}seekTo(e){this.audio&&this.audio.duration&&(this.audio.currentTime=Math.max(0,Math.min(e,this.audio.duration)),this.updateProgress())}seekToPercent(e){this.audio&&this.audio.duration&&(this.audio.currentTime=this.audio.duration*Math.max(0,Math.min(1,e)),this.updateProgress())}setVolume(e){this.audio&&(this.audio.volume=Math.max(0,Math.min(1,e)))}setPlaybackRate(e){if(!this.audio)return;let i=Math.max(.5,Math.min(2,e));this.audio.playbackRate=i,this.options.playbackRate=i,this.updateSpeedUI()}destroy(){this.isDestroying=!0,this.pause(),this.stopSmoothUpdate(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null),t.instances.delete(this.id),t.currentlyPlaying===this&&(t.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=[]}static getInstance(e){if(typeof e=="string"){let i=this.instances.get(e);if(i)return i;let a=document.getElementById(e);if(a)return Array.from(this.instances.values()).find(s=>s.container===a)}if(e instanceof HTMLElement)return Array.from(this.instances.values()).find(i=>i.container===e)}static getAllInstances(){return Array.from(this.instances.values())}static destroyAll(){this.instances.forEach(e=>e.destroy()),this.instances.clear()}static async generateWaveformData(e,i=200){try{return(await M(e,i)).peaks}catch(a){throw console.error("Failed to generate waveform:",a),a}}};function T(){if(typeof document>"u")return;document.querySelectorAll("[data-waveform-player]").forEach(e=>{if(e.dataset.waveformInitialized!=="true")try{new g(e),e.dataset.waveformInitialized="true"}catch(i){console.error("Failed to initialize WaveformPlayer:",i,e)}})}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",T):T());g.init=T;typeof window<"u"&&(window.WaveformPlayer=g);var lt=g;})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arraypress/waveform-player",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Lightweight, customizable audio player with waveform visualization",
5
5
  "main": "dist/waveform-player.js",
6
6
  "module": "dist/waveform-player.esm.js",
package/src/js/core.js CHANGED
@@ -93,6 +93,7 @@ export class WaveformPlayer {
93
93
  // Dispatch ready event after initialization
94
94
  setTimeout(() => {
95
95
  this.container.dispatchEvent(new CustomEvent('waveformplayer:ready', {
96
+ bubbles: true,
96
97
  detail: {player: this, url: this.options.url}
97
98
  }));
98
99
  }, 100);
@@ -415,8 +416,9 @@ export class WaveformPlayer {
415
416
  // Canvas interactions
416
417
  this.canvas.addEventListener('click', (e) => this.handleCanvasClick(e));
417
418
 
418
- // Window resize
419
- window.addEventListener('resize', debounce(() => this.resizeCanvas(), 100));
419
+ // Window resize - store handler for cleanup
420
+ this.resizeHandler = debounce(() => this.resizeCanvas(), 100);
421
+ window.addEventListener('resize', this.resizeHandler);
420
422
  }
421
423
 
422
424
  /**
@@ -627,6 +629,11 @@ export class WaveformPlayer {
627
629
  * @private
628
630
  */
629
631
  resizeCanvas() {
632
+ // Guard against calls after destruction
633
+ if (!this.canvas || this.isDestroying) {
634
+ return;
635
+ }
636
+
630
637
  const dpr = window.devicePixelRatio || 1;
631
638
  const rect = this.canvas.getBoundingClientRect();
632
639
 
@@ -723,6 +730,9 @@ export class WaveformPlayer {
723
730
  * @private
724
731
  */
725
732
  onMetadataLoaded() {
733
+ // Ignore during destruction
734
+ if (this.isDestroying) return;
735
+
726
736
  if (this.totalTimeEl) {
727
737
  this.totalTimeEl.textContent = formatTime(this.audio.duration);
728
738
  }
@@ -735,6 +745,9 @@ export class WaveformPlayer {
735
745
  * @private
736
746
  */
737
747
  onPlay() {
748
+ // Ignore during destruction
749
+ if (this.isDestroying) return;
750
+
738
751
  this.isPlaying = true;
739
752
  this.playBtn.classList.add('playing');
740
753
 
@@ -747,6 +760,7 @@ export class WaveformPlayer {
747
760
 
748
761
  // Dispatch play event
749
762
  this.container.dispatchEvent(new CustomEvent('waveformplayer:play', {
763
+ bubbles: true,
750
764
  detail: {player: this, url: this.options.url}
751
765
  }));
752
766
 
@@ -760,6 +774,9 @@ export class WaveformPlayer {
760
774
  * @private
761
775
  */
762
776
  onPause() {
777
+ // Ignore during destruction
778
+ if (this.isDestroying) return;
779
+
763
780
  this.isPlaying = false;
764
781
  this.playBtn.classList.remove('playing');
765
782
 
@@ -772,6 +789,7 @@ export class WaveformPlayer {
772
789
 
773
790
  // Dispatch pause event
774
791
  this.container.dispatchEvent(new CustomEvent('waveformplayer:pause', {
792
+ bubbles: true,
775
793
  detail: {player: this, url: this.options.url}
776
794
  }));
777
795
 
@@ -785,6 +803,9 @@ export class WaveformPlayer {
785
803
  * @private
786
804
  */
787
805
  onEnded() {
806
+ // Ignore during destruction
807
+ if (this.isDestroying) return;
808
+
788
809
  this.progress = 0;
789
810
  this.audio.currentTime = 0;
790
811
  this.drawWaveform();
@@ -796,6 +817,7 @@ export class WaveformPlayer {
796
817
 
797
818
  // Dispatch ended event
798
819
  this.container.dispatchEvent(new CustomEvent('waveformplayer:ended', {
820
+ bubbles: true,
799
821
  detail: {player: this, url: this.options.url}
800
822
  }));
801
823
 
@@ -887,6 +909,7 @@ export class WaveformPlayer {
887
909
 
888
910
  // Dispatch timeupdate event
889
911
  this.container.dispatchEvent(new CustomEvent('waveformplayer:timeupdate', {
912
+ bubbles: true,
890
913
  detail: {
891
914
  player: this,
892
915
  currentTime: this.audio.currentTime,
@@ -938,6 +961,7 @@ export class WaveformPlayer {
938
961
 
939
962
  /**
940
963
  * Play audio
964
+ * @return {Promise} The promise returned by HTMLMediaElement.play()
941
965
  */
942
966
  play() {
943
967
  if (this.options.singlePlay && WaveformPlayer.currentlyPlaying &&
@@ -946,7 +970,7 @@ export class WaveformPlayer {
946
970
  }
947
971
 
948
972
  WaveformPlayer.currentlyPlaying = this;
949
- this.audio.play();
973
+ return this.audio.play();
950
974
  }
951
975
 
952
976
  /**
@@ -1033,6 +1057,12 @@ export class WaveformPlayer {
1033
1057
  this.resizeObserver = null;
1034
1058
  }
1035
1059
 
1060
+ // Remove window resize listener
1061
+ if (this.resizeHandler) {
1062
+ window.removeEventListener('resize', this.resizeHandler);
1063
+ this.resizeHandler = null;
1064
+ }
1065
+
1036
1066
  // Remove from instances map
1037
1067
  WaveformPlayer.instances.delete(this.id);
1038
1068