@arraypress/waveform-player 1.2.1 → 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 +91 -62
- package/dist/waveform-player.esm.js +1 -1
- package/dist/waveform-player.js +2 -1
- package/dist/waveform-player.min.js +1 -1
- package/package.json +1 -1
- package/src/js/core.js +2 -1
package/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# WaveformPlayer
|
|
2
2
|
|
|
3
|
-
A lightweight, customizable audio player with waveform visualization. Under
|
|
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)** |
|
|
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
|

|
|
8
9
|

|
|
@@ -14,12 +15,23 @@ 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
|
+
|
|
23
35
|
## What's New in 1.2.0
|
|
24
36
|
|
|
25
37
|
### 🎨 Automatic Theme Detection
|
|
@@ -27,12 +39,14 @@ A lightweight, customizable audio player with waveform visualization. Under 6KB
|
|
|
27
39
|
WaveformPlayer now automatically adapts to your website's color scheme - no configuration needed!
|
|
28
40
|
|
|
29
41
|
**Features:**
|
|
42
|
+
|
|
30
43
|
- Detects light/dark themes automatically
|
|
31
44
|
- Checks background brightness, theme classes, and system preferences
|
|
32
45
|
- Works seamlessly on WordPress, Shopify, and all platforms
|
|
33
46
|
- Override with explicit `data-color-preset="light"` or `"dark"` if needed
|
|
34
47
|
|
|
35
48
|
**How it works:**
|
|
49
|
+
|
|
36
50
|
1. Checks for explicit theme classes (`.dark-mode`, `.light-mode`, etc.)
|
|
37
51
|
2. Analyzes background brightness
|
|
38
52
|
3. Respects system color preferences (`prefers-color-scheme`)
|
|
@@ -52,18 +66,23 @@ Simplest possible usage:
|
|
|
52
66
|
## Installation
|
|
53
67
|
|
|
54
68
|
### NPM
|
|
69
|
+
|
|
55
70
|
```bash
|
|
56
71
|
npm install @arraypress/waveform-player
|
|
57
72
|
```
|
|
58
73
|
|
|
59
74
|
### CDN
|
|
75
|
+
|
|
60
76
|
```html
|
|
77
|
+
|
|
61
78
|
<link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-player@latest/dist/waveform-player.css">
|
|
62
79
|
<script src="https://unpkg.com/@arraypress/waveform-player@latest/dist/waveform-player.min.js"></script>
|
|
63
80
|
```
|
|
64
81
|
|
|
65
82
|
### Download
|
|
83
|
+
|
|
66
84
|
```html
|
|
85
|
+
|
|
67
86
|
<link rel="stylesheet" href="waveform-player.css">
|
|
68
87
|
<script src="waveform-player.js"></script>
|
|
69
88
|
```
|
|
@@ -87,29 +106,32 @@ npm install @arraypress/waveform-player
|
|
|
87
106
|
## Ecosystem
|
|
88
107
|
|
|
89
108
|
### WaveformPlaylist (Optional Addon)
|
|
109
|
+
|
|
90
110
|
Add playlist and chapter support with zero JavaScript:
|
|
91
111
|
|
|
92
112
|
```html
|
|
113
|
+
|
|
93
114
|
<div data-waveform-playlist data-continuous="true">
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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>
|
|
99
120
|
</div>
|
|
100
121
|
```
|
|
101
122
|
|
|
102
123
|
[Learn more →](https://github.com/arraypress/waveform-playlist)
|
|
103
124
|
|
|
104
125
|
### WaveformTracker (Optional Addon)
|
|
126
|
+
|
|
105
127
|
Track meaningful audio engagement:
|
|
106
128
|
|
|
107
129
|
```javascript
|
|
108
130
|
WaveformTracker.init({
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
131
|
+
endpoint: '/api/analytics',
|
|
132
|
+
events: {
|
|
133
|
+
listen: 30 // Track after 30 seconds of listening
|
|
134
|
+
}
|
|
113
135
|
});
|
|
114
136
|
```
|
|
115
137
|
|
|
@@ -117,22 +139,24 @@ WaveformTracker.init({
|
|
|
117
139
|
|
|
118
140
|
## Comparison
|
|
119
141
|
|
|
120
|
-
| Feature
|
|
121
|
-
|
|
122
|
-
| Size (gzipped)
|
|
123
|
-
| Zero Config
|
|
124
|
-
| Dependencies
|
|
125
|
-
| Waveform Styles
|
|
126
|
-
| Setup Time
|
|
127
|
-
| Real Waveforms
|
|
128
|
-
| Keyboard Controls | ✅ | ✅
|
|
129
|
-
| Media Session API | ✅ | ❌
|
|
130
|
-
| 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 | ✅ | ✅ | ❌ |
|
|
131
153
|
|
|
132
154
|
## Usage
|
|
133
155
|
|
|
134
156
|
### HTML (Zero JavaScript)
|
|
157
|
+
|
|
135
158
|
```html
|
|
159
|
+
|
|
136
160
|
<div data-waveform-player
|
|
137
161
|
data-url="audio.mp3"
|
|
138
162
|
data-title="My Song"
|
|
@@ -144,6 +168,7 @@ WaveformTracker.init({
|
|
|
144
168
|
```
|
|
145
169
|
|
|
146
170
|
### JavaScript API
|
|
171
|
+
|
|
147
172
|
```javascript
|
|
148
173
|
import WaveformPlayer from '@arraypress/waveform-player';
|
|
149
174
|
|
|
@@ -173,27 +198,27 @@ Choose from 6 built-in styles:
|
|
|
173
198
|
|
|
174
199
|
## Options
|
|
175
200
|
|
|
176
|
-
| Option
|
|
177
|
-
|
|
178
|
-
| `url`
|
|
179
|
-
| `waveformStyle`
|
|
180
|
-
| `height`
|
|
181
|
-
| `barWidth`
|
|
182
|
-
| `barSpacing`
|
|
183
|
-
| `samples`
|
|
184
|
-
| `waveformColor`
|
|
185
|
-
| `progressColor`
|
|
186
|
-
| `buttonColor`
|
|
187
|
-
| `showTime`
|
|
188
|
-
| `showBPM`
|
|
189
|
-
| `showPlaybackSpeed`
|
|
190
|
-
| `playbackRate`
|
|
191
|
-
| `autoplay`
|
|
192
|
-
| `title`
|
|
193
|
-
| `subtitle`
|
|
194
|
-
| `artwork`
|
|
195
|
-
| `markers`
|
|
196
|
-
| `enableMediaSession` | boolean | `true`
|
|
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 |
|
|
197
222
|
|
|
198
223
|
## API Methods
|
|
199
224
|
|
|
@@ -291,41 +316,44 @@ WaveformPlayer.destroyAll();
|
|
|
291
316
|
## Framework Integration
|
|
292
317
|
|
|
293
318
|
### React
|
|
319
|
+
|
|
294
320
|
```jsx
|
|
295
|
-
import {
|
|
321
|
+
import {useEffect, useRef} from 'react';
|
|
296
322
|
import WaveformPlayer from '@arraypress/waveform-player';
|
|
297
323
|
|
|
298
|
-
function AudioPlayer({
|
|
324
|
+
function AudioPlayer({url}) {
|
|
299
325
|
const playerRef = useRef();
|
|
300
|
-
|
|
326
|
+
|
|
301
327
|
useEffect(() => {
|
|
302
|
-
const player = new WaveformPlayer(playerRef.current, {
|
|
328
|
+
const player = new WaveformPlayer(playerRef.current, {url});
|
|
303
329
|
return () => player.destroy();
|
|
304
330
|
}, [url]);
|
|
305
|
-
|
|
306
|
-
return <div ref={playerRef}
|
|
331
|
+
|
|
332
|
+
return <div ref={playerRef}/>;
|
|
307
333
|
}
|
|
308
334
|
```
|
|
309
335
|
|
|
310
336
|
### Vue
|
|
337
|
+
|
|
311
338
|
```vue
|
|
339
|
+
|
|
312
340
|
<template>
|
|
313
341
|
<div ref="player"></div>
|
|
314
342
|
</template>
|
|
315
343
|
|
|
316
344
|
<script>
|
|
317
|
-
import WaveformPlayer from '@arraypress/waveform-player';
|
|
318
|
-
|
|
319
|
-
export default {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
+
}
|
|
327
356
|
}
|
|
328
|
-
}
|
|
329
357
|
</script>
|
|
330
358
|
```
|
|
331
359
|
|
|
@@ -339,6 +367,7 @@ export default {
|
|
|
339
367
|
## Examples
|
|
340
368
|
|
|
341
369
|
See the [live demo](https://waveformplayer.com) for:
|
|
370
|
+
|
|
342
371
|
- All visual styles
|
|
343
372
|
- Custom styling examples
|
|
344
373
|
- Event handling
|
|
@@ -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",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(){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};
|
|
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};
|
package/dist/waveform-player.js
CHANGED
|
@@ -1359,13 +1359,14 @@
|
|
|
1359
1359
|
// ============================================
|
|
1360
1360
|
/**
|
|
1361
1361
|
* Play audio
|
|
1362
|
+
* @return {Promise} The promise returned by HTMLMediaElement.play()
|
|
1362
1363
|
*/
|
|
1363
1364
|
play() {
|
|
1364
1365
|
if (this.options.singlePlay && _WaveformPlayer.currentlyPlaying && _WaveformPlayer.currentlyPlaying !== this) {
|
|
1365
1366
|
_WaveformPlayer.currentlyPlaying.pause();
|
|
1366
1367
|
}
|
|
1367
1368
|
_WaveformPlayer.currentlyPlaying = this;
|
|
1368
|
-
this.audio.play();
|
|
1369
|
+
return this.audio.play();
|
|
1369
1370
|
}
|
|
1370
1371
|
/**
|
|
1371
1372
|
* Pause audio
|
|
@@ -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",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(){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;})();
|
|
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
package/src/js/core.js
CHANGED
|
@@ -961,6 +961,7 @@ export class WaveformPlayer {
|
|
|
961
961
|
|
|
962
962
|
/**
|
|
963
963
|
* Play audio
|
|
964
|
+
* @return {Promise} The promise returned by HTMLMediaElement.play()
|
|
964
965
|
*/
|
|
965
966
|
play() {
|
|
966
967
|
if (this.options.singlePlay && WaveformPlayer.currentlyPlaying &&
|
|
@@ -969,7 +970,7 @@ export class WaveformPlayer {
|
|
|
969
970
|
}
|
|
970
971
|
|
|
971
972
|
WaveformPlayer.currentlyPlaying = this;
|
|
972
|
-
this.audio.play();
|
|
973
|
+
return this.audio.play();
|
|
973
974
|
}
|
|
974
975
|
|
|
975
976
|
/**
|