@arraypress/waveform-player 1.3.2 → 1.3.4
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.
|
@@ -63,4 +63,4 @@ function L(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&
|
|
|
63
63
|
${o}
|
|
64
64
|
</div>
|
|
65
65
|
</div>
|
|
66
|
-
`,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 s=parseFloat(o.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,o=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,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};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&&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((o,s)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),o()},r=a=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),s(a)};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,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=P(this.options,{url:e,title:i||this.options.title,subtitle:o||this.options.subtitle,...s}),s.preload&&(this.audio.preload=s.preload),this.subtitleEl&&(o?(this.subtitleEl.textContent=o,this.subtitleEl.style.display=""):o===""&&(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().catch(()=>{})}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||x(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.parentElement.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,s=document.createElement("button");s.className="waveform-marker",s.style.left=`${o}%`,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(),o=e.clientX-i.left,s=Math.max(0,Math.min(1,o/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=C(this.audio.duration)),this.renderMarkers())}onPlay(){if(!this.isDestroying){if(this.isPlaying=!0,this.playBtn){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){if(this.isPlaying=!1,this.playBtn){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=C(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 o=document.getElementById(e);if(o)return Array.from(this.instances.values()).find(s=>s.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};
|
|
66
|
+
`,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 s=parseFloat(o.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,o=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,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};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&&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((o,s)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),o()},r=a=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),s(a)};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,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=P(this.options,{url:e,title:i||this.options.title,subtitle:o||this.options.subtitle,...s}),s.preload&&(this.audio.preload=s.preload),this.subtitleEl&&(o?(this.subtitleEl.textContent=o,this.subtitleEl.style.display=""):o===""&&(this.subtitleEl.style.display="none")),s.artwork&&this.artworkEl&&(this.artworkEl.src=s.artwork),this.options.markers=s.markers||[],await this.load(e),this.play().catch(()=>{})}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||x(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.parentElement.getBoundingClientRect();this.canvas.width=i.width*e,this.canvas.height=this.options.height*e,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,s=document.createElement("button");s.className="waveform-marker",s.style.left=`${o}%`,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(),o=e.clientX-i.left,s=Math.max(0,Math.min(1,o/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=C(this.audio.duration)),this.renderMarkers())}onPlay(){if(!this.isDestroying){if(this.isPlaying=!0,this.playBtn){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){if(this.isPlaying=!1,this.playBtn){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=C(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 o=document.getElementById(e);if(o)return Array.from(this.instances.values()).find(s=>s.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};
|
package/dist/waveform-player.js
CHANGED
|
@@ -1074,9 +1074,7 @@
|
|
|
1074
1074
|
if (options.artwork && this.artworkEl) {
|
|
1075
1075
|
this.artworkEl.src = options.artwork;
|
|
1076
1076
|
}
|
|
1077
|
-
|
|
1078
|
-
this.options.markers = options.markers;
|
|
1079
|
-
}
|
|
1077
|
+
this.options.markers = options.markers || [];
|
|
1080
1078
|
await this.load(url);
|
|
1081
1079
|
this.play().catch(() => {
|
|
1082
1080
|
});
|
|
@@ -1126,7 +1124,6 @@
|
|
|
1126
1124
|
const rect = this.canvas.parentElement.getBoundingClientRect();
|
|
1127
1125
|
this.canvas.width = rect.width * dpr;
|
|
1128
1126
|
this.canvas.height = this.options.height * dpr;
|
|
1129
|
-
this.canvas.style.height = this.options.height + "px";
|
|
1130
1127
|
this.canvas.parentElement.style.height = this.options.height + "px";
|
|
1131
1128
|
this.drawWaveform();
|
|
1132
1129
|
}
|
|
@@ -63,4 +63,4 @@
|
|
|
63
63
|
${o}
|
|
64
64
|
</div>
|
|
65
65
|
</div>
|
|
66
|
-
`,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 s=parseFloat(o.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,o=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,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};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&&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((o,s)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),o()},r=a=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),s(a)};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,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=P(this.options,{url:e,title:i||this.options.title,subtitle:o||this.options.subtitle,...s}),s.preload&&(this.audio.preload=s.preload),this.subtitleEl&&(o?(this.subtitleEl.textContent=o,this.subtitleEl.style.display=""):o===""&&(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().catch(()=>{})}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||x(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.parentElement.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,s=document.createElement("button");s.className="waveform-marker",s.style.left=`${o}%`,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(),o=e.clientX-i.left,s=Math.max(0,Math.min(1,o/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=C(this.audio.duration)),this.renderMarkers())}onPlay(){if(!this.isDestroying){if(this.isPlaying=!0,this.playBtn){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){if(this.isPlaying=!1,this.playBtn){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=C(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 o=document.getElementById(e);if(o)return Array.from(this.instances.values()).find(s=>s.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;})();
|
|
66
|
+
`,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 s=parseFloat(o.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,o=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,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};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&&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((o,s)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),o()},r=a=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),s(a)};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,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=P(this.options,{url:e,title:i||this.options.title,subtitle:o||this.options.subtitle,...s}),s.preload&&(this.audio.preload=s.preload),this.subtitleEl&&(o?(this.subtitleEl.textContent=o,this.subtitleEl.style.display=""):o===""&&(this.subtitleEl.style.display="none")),s.artwork&&this.artworkEl&&(this.artworkEl.src=s.artwork),this.options.markers=s.markers||[],await this.load(e),this.play().catch(()=>{})}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||x(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.parentElement.getBoundingClientRect();this.canvas.width=i.width*e,this.canvas.height=this.options.height*e,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,s=document.createElement("button");s.className="waveform-marker",s.style.left=`${o}%`,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(),o=e.clientX-i.left,s=Math.max(0,Math.min(1,o/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=C(this.audio.duration)),this.renderMarkers())}onPlay(){if(!this.isDestroying){if(this.isPlaying=!0,this.playBtn){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){if(this.isPlaying=!1,this.playBtn){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=C(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 o=document.getElementById(e);if(o)return Array.from(this.instances.values()).find(s=>s.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;})();
|
package/package.json
CHANGED
package/src/js/core.js
CHANGED
|
@@ -586,10 +586,8 @@ export class WaveformPlayer {
|
|
|
586
586
|
this.artworkEl.src = options.artwork;
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
-
// Clear
|
|
590
|
-
|
|
591
|
-
this.options.markers = options.markers;
|
|
592
|
-
}
|
|
589
|
+
// Clear or update markers
|
|
590
|
+
this.options.markers = options.markers || [];
|
|
593
591
|
|
|
594
592
|
// Load the new track
|
|
595
593
|
await this.load(url);
|
|
@@ -650,7 +648,6 @@ export class WaveformPlayer {
|
|
|
650
648
|
|
|
651
649
|
this.canvas.width = rect.width * dpr;
|
|
652
650
|
this.canvas.height = this.options.height * dpr;
|
|
653
|
-
this.canvas.style.height = this.options.height + 'px';
|
|
654
651
|
this.canvas.parentElement.style.height = this.options.height + 'px';
|
|
655
652
|
|
|
656
653
|
this.drawWaveform();
|