@arraypress/waveform-player 1.1.1 → 1.1.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.
@@ -1,4 +1,4 @@
1
- function T(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&&(e.height=parseInt(t.dataset.height)),t.dataset.samples&&(e.samples=parseInt(t.dataset.samples)),t.dataset.preload&&(e.preload=t.dataset.preload),t.dataset.waveformStyle&&(e.waveformStyle=t.dataset.waveformStyle),t.dataset.barWidth&&(e.barWidth=parseInt(t.dataset.barWidth)),t.dataset.barSpacing&&(e.barSpacing=parseInt(t.dataset.barSpacing)),t.dataset.buttonAlign&&(e.buttonAlign=t.dataset.buttonAlign),t.dataset.colorPreset&&(e.colorPreset=t.dataset.colorPreset),t.dataset.waveformColor&&(e.waveformColor=t.dataset.waveformColor),t.dataset.progressColor&&(e.progressColor=t.dataset.progressColor),t.dataset.buttonColor&&(e.buttonColor=t.dataset.buttonColor),t.dataset.buttonHoverColor&&(e.buttonHoverColor=t.dataset.buttonHoverColor),t.dataset.textColor&&(e.textColor=t.dataset.textColor),t.dataset.textSecondaryColor&&(e.textSecondaryColor=t.dataset.textSecondaryColor),t.dataset.backgroundColor&&(e.backgroundColor=t.dataset.backgroundColor),t.dataset.borderColor&&(e.borderColor=t.dataset.borderColor),t.dataset.color&&(e.waveformColor=t.dataset.color),t.dataset.theme&&(e.colorPreset=t.dataset.theme),t.dataset.autoplay&&(e.autoplay=t.dataset.autoplay==="true"),t.dataset.showTime&&(e.showTime=t.dataset.showTime==="true"),t.dataset.showHoverTime&&(e.showHoverTime=t.dataset.showHoverTime==="true"),t.dataset.showBpm&&(e.showBPM=t.dataset.showBpm==="true"),t.dataset.singlePlay&&(e.singlePlay=t.dataset.singlePlay==="true"),t.dataset.playOnSeek&&(e.playOnSeek=t.dataset.playOnSeek==="true"),t.dataset.title&&(e.title=t.dataset.title),t.dataset.subtitle&&(e.subtitle=t.dataset.subtitle),t.dataset.album&&(e.album=t.dataset.album),t.dataset.artwork&&(e.artwork=t.dataset.artwork),t.dataset.waveform&&(e.waveform=t.dataset.waveform),t.dataset.markers)try{e.markers=JSON.parse(t.dataset.markers)}catch(o){console.warn("Invalid markers JSON:",o)}if(t.dataset.playbackRate&&(e.playbackRate=parseFloat(t.dataset.playbackRate)),t.dataset.showPlaybackSpeed!==void 0&&(e.showPlaybackSpeed=t.dataset.showPlaybackSpeed==="true"),t.dataset.playbackRates)try{e.playbackRates=JSON.parse(t.dataset.playbackRates)}catch(o){console.warn("Invalid playbackRates JSON:",o)}return t.dataset.enableMediaSession!==void 0&&(e.enableMediaSession=t.dataset.enableMediaSession==="true"),e}function C(t){if(!t||isNaN(t))return"0:00";let e=Math.floor(t/60),o=Math.floor(t%60);return`${e}:${o.toString().padStart(2,"0")}`}function R(t){let e=t||Math.random().toString();return btoa(e.substring(0,10)).replace(/[^a-zA-Z0-9]/g,"")}function A(t){if(!t)return"Audio";let e=t.split("/");return e[e.length-1].split(".")[0].replace(/[-_]/g," ").replace(/\b\w/g,i=>i.toUpperCase())}function P(...t){let e={};for(let o of t)for(let a in o)o[a]!==null&&o[a]!==void 0&&(e[a]=o[a]);return e}function L(t,e){let o;return function(...i){let n=()=>{clearTimeout(o),t(...i)};clearTimeout(o),o=setTimeout(n,e)}}function S(t,e){if(t.length===e)return t;if(t.length===0||e===0)return[];let o=[];if(e>t.length){let a=(t.length-1)/(e-1);for(let i=0;i<e;i++){let n=i*a,r=Math.floor(n),s=Math.ceil(n),h=n-r;if(s>=t.length)o.push(t[t.length-1]);else if(r===s)o.push(t[r]);else{let l=t[r]*(1-h)+t[s]*h;o.push(l)}}}else{let a=t.length/e;for(let i=0;i<e;i++){let n=Math.floor(i*a),r=Math.floor((i+1)*a),s=0,h=0;for(let l=n;l<=r&&l<t.length;l++)t[l]>s&&(s=t[l]),h++;if(h===0){let l=Math.min(Math.round(i*a),t.length-1);s=t[l]}o.push(s)}}return o}function x(t,e,o,a,i){let n=window.devicePixelRatio||1,r=i.barWidth*n,s=i.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(o,h),d=e.height,p=a*e.width;t.clearRect(0,0,e.width,e.height);for(let y=0;y<l.length;y++){let f=y*(r+s);if(f+r>e.width)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=i.color,t.fillRect(f,m,r,c)}t.save(),t.beginPath(),t.rect(0,0,p,d),t.clip();for(let y=0;y<l.length;y++){let f=y*(r+s);if(f>p)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=i.progressColor,t.fillRect(f,m,r,c)}t.restore()}function D(t,e,o,a,i){let n=window.devicePixelRatio||1,r=i.barWidth*n,s=i.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(o,h),d=e.height,p=d/2,y=a*e.width;t.clearRect(0,0,e.width,e.height);for(let f=0;f<l.length;f++){let c=f*(r+s);if(c+r>e.width)break;let m=l[f]*d*.45;t.fillStyle=i.color,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.save(),t.beginPath(),t.rect(0,0,y,d),t.clip();for(let f=0;f<l.length;f++){let c=f*(r+s);if(c>y)break;let m=l[f]*d*.45;t.fillStyle=i.progressColor,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.restore()}function H(t,e,o,a,i){let n=e.width,r=e.height,s=r/2,h=r*.35;t.clearRect(0,0,n,r);let l=(d,p,y=1,f=!1)=>{f&&(t.shadowBlur=12,t.shadowColor=d),t.strokeStyle=d,t.lineWidth=p,t.lineCap="round",t.lineJoin="round",t.beginPath(),t.moveTo(0,s);let c=[],m=Math.floor(o.length*y);for(let u=0;u<m;u++){let v=u/(o.length-1)*n,k=o[u],b=Math.sin(u*.1)*k,w=s+b*h;c.push({x:v,y:w})}for(let u=0;u<c.length-1;u++){let v=c[u].x+(c[u+1].x-c[u].x)*.5,k=c[u].y,b=c[u+1].x-(c[u+1].x-c[u].x)*.5,w=c[u+1].y;t.bezierCurveTo(v,k,b,w,c[u+1].x,c[u+1].y)}t.stroke(),f&&(t.shadowBlur=0)};t.strokeStyle="rgba(255, 255, 255, 0.03)",t.lineWidth=.5,t.beginPath(),t.moveTo(0,s),t.lineTo(n,s),t.stroke();for(let d=0;d<=10;d++){let p=n/10*d;t.beginPath(),t.moveTo(p,0),t.lineTo(p,r),t.stroke()}l(i.color,2,1,!1),a>0&&l(i.progressColor,3,a,!0)}function q(t,e,o,a,i){let n=window.devicePixelRatio||1,r=(i.barWidth||3)*n,s=(i.barSpacing||1)*n,h=Math.floor(e.width/(r+s)),l=S(o,h),d=e.height,p=4*n,y=2*n,f=a*e.width,c=d/2;t.clearRect(0,0,e.width,e.height);for(let m=0;m<l.length;m++){let u=m*(r+s);if(u+r>e.width)break;let v=l[m]*d*.9,k=Math.floor(v/(p+y));t.fillStyle=u<f?i.progressColor:i.color;for(let b=0;b<k;b++){let w=b*(p+y);t.fillRect(u,c-w-p,r,p),b>0&&t.fillRect(u,c+w,r,p)}}}function U(t,e,o,a,i){let n=window.devicePixelRatio||1,r=(i.barWidth||2)*n,s=(i.barSpacing||3)*n,h=Math.floor(e.width/(r+s)),l=S(o,h),d=e.height,p=Math.max(1.5*n,r/2),y=a*e.width,f=d/2;t.clearRect(0,0,e.width,e.height);for(let c=0;c<l.length;c++){let m=c*(r+s)+r/2;if(m>e.width)break;let u=l[c]*d*.9;t.fillStyle=m<y?i.progressColor:i.color,t.beginPath(),t.arc(m,f-u/2,p,0,Math.PI*2),t.fill(),t.beginPath(),t.arc(m,f+u/2,p,0,Math.PI*2),t.fill()}}function $(t,e,o,a,i){let n=e.width,r=e.height,s=r/2,h=4,l=h/2;if(t.clearRect(0,0,n,r),t.fillStyle=i.color||"rgba(255, 255, 255, 0.2)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(n-l,s-h/2),t.arc(n-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),a>0){let d=Math.max(l*2,a*n);t.shadowBlur=8,t.shadowColor=i.progressColor,t.fillStyle=i.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(d-l,s-h/2),t.arc(d-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),t.shadowBlur=0;let p=8,y=d;t.shadowBlur=4,t.shadowColor="rgba(0, 0, 0, 0.3)",t.shadowOffsetY=2,t.fillStyle="#ffffff",t.beginPath(),t.arc(y,s,p,0,Math.PI*2),t.fill(),t.shadowBlur=0,t.shadowOffsetY=0,t.fillStyle=i.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.arc(y,s,p*.4,0,Math.PI*2),t.fill()}}var F={bars:x,mirror:D,line:H,blocks:q,dots:U,seekbar:$};function B(t,e,o,a,i){(F[i.waveformStyle]||x)(t,e,o,a,i)}function W(t){try{let e=t.getChannelData(0),o=t.sampleRate,a=N(e,o);if(a.length<2)return 120;let i=[];for(let h=1;h<a.length;h++)i.push((a[h]-a[h-1])/o);let n={};i.forEach(h=>{let l=60/h,d=Math.round(l/3)*3;d>60&&d<200&&(n[d]=(n[d]||0)+1)});let r=0,s=120;for(let[h,l]of Object.entries(n))l>r&&(r=l,s=parseInt(h));return s<70&&n[s*2]?s*=2:s>160&&n[Math.round(s/2)]&&(s=Math.round(s/2)),s-1}catch(e){return console.warn("BPM detection failed:",e),null}}function N(t,e){let i=[],n=0;for(let r=0;r<t.length-2048;r+=1024){let s=0;for(let d=r;d<r+2048;d++)s+=t[d]*t[d];s=s/2048;let h=s-n,l=n*1.8+.01;if(h>l&&s>.01){let d=i[i.length-1]||0,p=e*.15;r-d>p&&i.push(r)}n=s*.8+n*.2}return i}function Y(t,e=200){let o=t.length/e,a=~~(o/10)||1,i=t.numberOfChannels,n=[];for(let s=0;s<i;s++){let h=t.getChannelData(s);for(let l=0;l<e;l++){let d=~~(l*o),p=~~(d+o),y=0,f=0;for(let m=d;m<p;m+=a){let u=h[m];u>f&&(f=u),u<y&&(y=u)}let c=Math.max(Math.abs(f),Math.abs(y));(s===0||c>n[l])&&(n[l]=c)}}let r=Math.max(...n);return r>0?n.map(s=>s/r):n}async function M(t,e=200,o=!1){try{let a=new(window.AudioContext||window.webkitAudioContext),n=await(await fetch(t)).arrayBuffer(),r=await a.decodeAudioData(n),s=Y(r,e);s=j(s);let h=null;return o&&(h=await W(r)),a.close(),{peaks:s,bpm:h}}catch(a){throw console.error("Failed to generate waveform:",a),a}}function I(t=200){let e=[];for(let o=0;o<t;o++){let a=Math.random()*.5+.3,i=Math.sin(o/t*Math.PI*4)*.2;e.push(Math.max(.1,Math.min(1,a+i)))}return e}function j(t,e=.95){let o=Math.max(...t);if(o===0||o>e)return t;let a=e/o;return t.map(i=>i*a)}var O={url:"",height:60,samples:200,preload:"metadata",playbackRate:1,showPlaybackSpeed:!1,playbackRates:[.5,.75,1,1.25,1.5,1.75,2],buttonAlign:"auto",waveformStyle:"mirror",barWidth:2,barSpacing:0,colorPreset:"dark",waveformColor:null,progressColor:null,buttonColor:null,buttonHoverColor:null,textColor:null,textSecondaryColor:null,backgroundColor:null,borderColor:null,autoplay:!1,showTime:!0,showHoverTime:!1,showBPM:!1,singlePlay:!0,playOnSeek:!0,enableMediaSession:!0,markers:[],showMarkers:!0,title:null,subtitle:null,artwork:null,album:"",playIcon:'<svg viewBox="0 0 24 24" width="16" height="16"><path d="M8 5v14l11-7z"/></svg>',pauseIcon:'<svg viewBox="0 0 24 24" width="16" height="16"><path d="M6 4h4v16H6zM14 4h4v16h-4z"/></svg>',onLoad:null,onPlay:null,onPause:null,onEnd:null,onError:null,onTimeUpdate:null},z={bars:{barWidth:3,barSpacing:1},mirror:{barWidth:2,barSpacing:0},line:{barWidth:2,barSpacing:0},blocks:{barWidth:4,barSpacing:2},dots:{barWidth:3,barSpacing:3},seekbar:{barWidth:1,barSpacing:0}};var g=class t{static instances=new Map;static currentlyPlaying=null;constructor(e,o={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("WaveformPlayer: Container element not found");let a=T(this.container);this.options=P(O,a,o);let i=z[this.options.waveformStyle];i&&(a.barWidth===void 0&&o.barWidth===void 0&&(this.options.barWidth=i.barWidth),a.barSpacing===void 0&&o.barSpacing===void 0&&(this.options.barSpacing=i.barSpacing)),this.options.waveformColor=this.options.waveformColor||"rgba(255, 255, 255, 0.3)",this.options.progressColor=this.options.progressColor||"rgba(255, 255, 255, 0.9)",this.options.buttonColor=this.options.buttonColor||"rgba(255, 255, 255, 0.9)",this.options.textColor=this.options.textColor||"#ffffff",this.options.textSecondaryColor=this.options.textSecondaryColor||"rgba(255, 255, 255, 0.6)",this.audio=null,this.canvas=null,this.ctx=null,this.waveformData=[],this.progress=0,this.isPlaying=!1,this.isLoading=!1,this.hasError=!1,this.updateTimer=null,this.resizeObserver=null,this.id=this.container.id||R(this.options.url),t.instances.set(this.id,this),this.init()}init(){this.createDOM(),this.createAudio(),this.initPlaybackSpeed(),this.initKeyboardControls(),this.bindEvents(),this.setupResizeObserver(),requestAnimationFrame(()=>{this.resizeCanvas(),this.options.url&&this.load(this.options.url).then(()=>{this.options.autoplay&&this.play()}).catch(e=>{console.error("Failed to load audio:",e)})})}createDOM(){this.container.innerHTML="",this.container.className="waveform-player";let e=this.options.buttonAlign;e==="auto"&&(this.options.waveformStyle==="bars"?e="bottom":e="center"),this.container.innerHTML=`
1
+ function T(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&&(e.height=parseInt(t.dataset.height)),t.dataset.samples&&(e.samples=parseInt(t.dataset.samples)),t.dataset.preload&&(e.preload=t.dataset.preload),t.dataset.waveformStyle&&(e.waveformStyle=t.dataset.waveformStyle),t.dataset.barWidth&&(e.barWidth=parseInt(t.dataset.barWidth)),t.dataset.barSpacing&&(e.barSpacing=parseInt(t.dataset.barSpacing)),t.dataset.buttonAlign&&(e.buttonAlign=t.dataset.buttonAlign),t.dataset.colorPreset&&(e.colorPreset=t.dataset.colorPreset),t.dataset.waveformColor&&(e.waveformColor=t.dataset.waveformColor),t.dataset.progressColor&&(e.progressColor=t.dataset.progressColor),t.dataset.buttonColor&&(e.buttonColor=t.dataset.buttonColor),t.dataset.buttonHoverColor&&(e.buttonHoverColor=t.dataset.buttonHoverColor),t.dataset.textColor&&(e.textColor=t.dataset.textColor),t.dataset.textSecondaryColor&&(e.textSecondaryColor=t.dataset.textSecondaryColor),t.dataset.backgroundColor&&(e.backgroundColor=t.dataset.backgroundColor),t.dataset.borderColor&&(e.borderColor=t.dataset.borderColor),t.dataset.color&&(e.waveformColor=t.dataset.color),t.dataset.theme&&(e.colorPreset=t.dataset.theme),t.dataset.autoplay&&(e.autoplay=t.dataset.autoplay==="true"),t.dataset.showTime&&(e.showTime=t.dataset.showTime==="true"),t.dataset.showHoverTime&&(e.showHoverTime=t.dataset.showHoverTime==="true"),t.dataset.showBpm&&(e.showBPM=t.dataset.showBpm==="true"),t.dataset.singlePlay&&(e.singlePlay=t.dataset.singlePlay==="true"),t.dataset.playOnSeek&&(e.playOnSeek=t.dataset.playOnSeek==="true"),t.dataset.title&&(e.title=t.dataset.title),t.dataset.subtitle&&(e.subtitle=t.dataset.subtitle),t.dataset.album&&(e.album=t.dataset.album),t.dataset.artwork&&(e.artwork=t.dataset.artwork),t.dataset.waveform&&(e.waveform=t.dataset.waveform),t.dataset.markers)try{e.markers=JSON.parse(t.dataset.markers)}catch(i){console.warn("Invalid markers JSON:",i)}if(t.dataset.playbackRate&&(e.playbackRate=parseFloat(t.dataset.playbackRate)),t.dataset.showPlaybackSpeed!==void 0&&(e.showPlaybackSpeed=t.dataset.showPlaybackSpeed==="true"),t.dataset.playbackRates)try{e.playbackRates=JSON.parse(t.dataset.playbackRates)}catch(i){console.warn("Invalid playbackRates JSON:",i)}return t.dataset.enableMediaSession!==void 0&&(e.enableMediaSession=t.dataset.enableMediaSession==="true"),e}function C(t){if(!t||isNaN(t))return"0:00";let e=Math.floor(t/60),i=Math.floor(t%60);return`${e}:${i.toString().padStart(2,"0")}`}function R(t){let e=t||Math.random().toString();return btoa(e.substring(0,10)).replace(/[^a-zA-Z0-9]/g,"")}function A(t){if(!t)return"Audio";let e=t.split("/");return e[e.length-1].split(".")[0].replace(/[-_]/g," ").replace(/\b\w/g,o=>o.toUpperCase())}function P(...t){let e={};for(let i of t)for(let a in i)i[a]!==null&&i[a]!==void 0&&(e[a]=i[a]);return e}function L(t,e){let i;return function(...o){let n=()=>{clearTimeout(i),t(...o)};clearTimeout(i),i=setTimeout(n,e)}}function S(t,e){if(t.length===e)return t;if(t.length===0||e===0)return[];let i=[];if(e>t.length){let a=(t.length-1)/(e-1);for(let o=0;o<e;o++){let n=o*a,r=Math.floor(n),s=Math.ceil(n),h=n-r;if(s>=t.length)i.push(t[t.length-1]);else if(r===s)i.push(t[r]);else{let l=t[r]*(1-h)+t[s]*h;i.push(l)}}}else{let a=t.length/e;for(let o=0;o<e;o++){let n=Math.floor(o*a),r=Math.floor((o+1)*a),s=0,h=0;for(let l=n;l<=r&&l<t.length;l++)t[l]>s&&(s=t[l]),h++;if(h===0){let l=Math.min(Math.round(o*a),t.length-1);s=t[l]}i.push(s)}}return i}function x(t,e,i,a,o){let n=window.devicePixelRatio||1,r=o.barWidth*n,s=o.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=a*e.width;t.clearRect(0,0,e.width,e.height);for(let m=0;m<l.length;m++){let f=m*(r+s);if(f+r>e.width)break;let c=l[m]*d*.9,y=d-c;t.fillStyle=o.color,t.fillRect(f,y,r,c)}t.save(),t.beginPath(),t.rect(0,0,p,d),t.clip();for(let m=0;m<l.length;m++){let f=m*(r+s);if(f>p)break;let c=l[m]*d*.9,y=d-c;t.fillStyle=o.progressColor,t.fillRect(f,y,r,c)}t.restore()}function z(t,e,i,a,o){let n=window.devicePixelRatio||1,r=o.barWidth*n,s=o.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=d/2,m=a*e.width;t.clearRect(0,0,e.width,e.height);for(let f=0;f<l.length;f++){let c=f*(r+s);if(c+r>e.width)break;let y=l[f]*d*.45;t.fillStyle=o.color,t.fillRect(c,p-y,r,y),t.fillRect(c,p,r,y)}t.save(),t.beginPath(),t.rect(0,0,m,d),t.clip();for(let f=0;f<l.length;f++){let c=f*(r+s);if(c>m)break;let y=l[f]*d*.45;t.fillStyle=o.progressColor,t.fillRect(c,p-y,r,y),t.fillRect(c,p,r,y)}t.restore()}function H(t,e,i,a,o){let n=e.width,r=e.height,s=r/2,h=r*.35;t.clearRect(0,0,n,r);let l=(d,p,m=1,f=!1)=>{f&&(t.shadowBlur=12,t.shadowColor=d),t.strokeStyle=d,t.lineWidth=p,t.lineCap="round",t.lineJoin="round",t.beginPath(),t.moveTo(0,s);let c=[],y=Math.floor(i.length*m);for(let u=0;u<y;u++){let v=u/(i.length-1)*n,k=i[u],b=Math.sin(u*.1)*k,w=s+b*h;c.push({x:v,y:w})}for(let u=0;u<c.length-1;u++){let v=c[u].x+(c[u+1].x-c[u].x)*.5,k=c[u].y,b=c[u+1].x-(c[u+1].x-c[u].x)*.5,w=c[u+1].y;t.bezierCurveTo(v,k,b,w,c[u+1].x,c[u+1].y)}t.stroke(),f&&(t.shadowBlur=0)};t.strokeStyle="rgba(255, 255, 255, 0.03)",t.lineWidth=.5,t.beginPath(),t.moveTo(0,s),t.lineTo(n,s),t.stroke();for(let d=0;d<=10;d++){let p=n/10*d;t.beginPath(),t.moveTo(p,0),t.lineTo(p,r),t.stroke()}l(o.color,2,1,!1),a>0&&l(o.progressColor,3,a,!0)}function q(t,e,i,a,o){let n=window.devicePixelRatio||1,r=(o.barWidth||3)*n,s=(o.barSpacing||1)*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=4*n,m=2*n,f=a*e.width,c=d/2;t.clearRect(0,0,e.width,e.height);for(let y=0;y<l.length;y++){let u=y*(r+s);if(u+r>e.width)break;let v=l[y]*d*.9,k=Math.floor(v/(p+m));t.fillStyle=u<f?o.progressColor:o.color;for(let b=0;b<k;b++){let w=b*(p+m);t.fillRect(u,c-w-p,r,p),b>0&&t.fillRect(u,c+w,r,p)}}}function $(t,e,i,a,o){let n=window.devicePixelRatio||1,r=(o.barWidth||2)*n,s=(o.barSpacing||3)*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=Math.max(1.5*n,r/2),m=a*e.width,f=d/2;t.clearRect(0,0,e.width,e.height);for(let c=0;c<l.length;c++){let y=c*(r+s)+r/2;if(y>e.width)break;let u=l[c]*d*.9;t.fillStyle=y<m?o.progressColor:o.color,t.beginPath(),t.arc(y,f-u/2,p,0,Math.PI*2),t.fill(),t.beginPath(),t.arc(y,f+u/2,p,0,Math.PI*2),t.fill()}}function U(t,e,i,a,o){let n=e.width,r=e.height,s=r/2,h=4,l=h/2;if(t.clearRect(0,0,n,r),t.fillStyle=o.color||"rgba(255, 255, 255, 0.2)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(n-l,s-h/2),t.arc(n-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),a>0){let d=Math.max(l*2,a*n);t.shadowBlur=8,t.shadowColor=o.progressColor,t.fillStyle=o.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(d-l,s-h/2),t.arc(d-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),t.shadowBlur=0;let p=8,m=d;t.shadowBlur=4,t.shadowColor="rgba(0, 0, 0, 0.3)",t.shadowOffsetY=2,t.fillStyle="#ffffff",t.beginPath(),t.arc(m,s,p,0,Math.PI*2),t.fill(),t.shadowBlur=0,t.shadowOffsetY=0,t.fillStyle=o.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.arc(m,s,p*.4,0,Math.PI*2),t.fill()}}var F={bars:x,mirror:z,line:H,blocks:q,dots:$,seekbar:U};function B(t,e,i,a,o){(F[o.waveformStyle]||x)(t,e,i,a,o)}function W(t){try{let e=t.getChannelData(0),i=t.sampleRate,a=N(e,i);if(a.length<2)return 120;let o=[];for(let h=1;h<a.length;h++)o.push((a[h]-a[h-1])/i);let n={};o.forEach(h=>{let l=60/h,d=Math.round(l/3)*3;d>60&&d<200&&(n[d]=(n[d]||0)+1)});let r=0,s=120;for(let[h,l]of Object.entries(n))l>r&&(r=l,s=parseInt(h));return s<70&&n[s*2]?s*=2:s>160&&n[Math.round(s/2)]&&(s=Math.round(s/2)),s-1}catch(e){return console.warn("BPM detection failed:",e),null}}function N(t,e){let o=[],n=0;for(let r=0;r<t.length-2048;r+=1024){let s=0;for(let d=r;d<r+2048;d++)s+=t[d]*t[d];s=s/2048;let h=s-n,l=n*1.8+.01;if(h>l&&s>.01){let d=o[o.length-1]||0,p=e*.15;r-d>p&&o.push(r)}n=s*.8+n*.2}return o}function Y(t,e=200){let i=t.length/e,a=~~(i/10)||1,o=t.numberOfChannels,n=[];for(let s=0;s<o;s++){let h=t.getChannelData(s);for(let l=0;l<e;l++){let d=~~(l*i),p=~~(d+i),m=0,f=0;for(let y=d;y<p;y+=a){let u=h[y];u>f&&(f=u),u<m&&(m=u)}let c=Math.max(Math.abs(f),Math.abs(m));(s===0||c>n[l])&&(n[l]=c)}}let r=Math.max(...n);return r>0?n.map(s=>s/r):n}async function M(t,e=200,i=!1){try{let a=new(window.AudioContext||window.webkitAudioContext),n=await(await fetch(t)).arrayBuffer(),r=await a.decodeAudioData(n),s=Y(r,e);s=j(s);let h=null;return i&&(h=await W(r)),a.close(),{peaks:s,bpm:h}}catch(a){throw console.error("Failed to generate waveform:",a),a}}function I(t=200){let e=[];for(let i=0;i<t;i++){let a=Math.random()*.5+.3,o=Math.sin(i/t*Math.PI*4)*.2;e.push(Math.max(.1,Math.min(1,a+o)))}return e}function j(t,e=.95){let i=Math.max(...t);if(i===0||i>e)return t;let a=e/i;return t.map(o=>o*a)}var D={url:"",height:60,samples:200,preload:"metadata",playbackRate:1,showPlaybackSpeed:!1,playbackRates:[.5,.75,1,1.25,1.5,1.75,2],buttonAlign:"auto",waveformStyle:"mirror",barWidth:2,barSpacing:0,colorPreset:"dark",waveformColor:null,progressColor:null,buttonColor:null,buttonHoverColor:null,textColor:null,textSecondaryColor:null,backgroundColor:null,borderColor:null,autoplay:!1,showTime:!0,showHoverTime:!1,showBPM:!1,singlePlay:!0,playOnSeek:!0,enableMediaSession:!0,markers:[],showMarkers:!0,title:null,subtitle:null,artwork:null,album:"",playIcon:'<svg viewBox="0 0 24 24" width="16" height="16"><path d="M8 5v14l11-7z"/></svg>',pauseIcon:'<svg viewBox="0 0 24 24" width="16" height="16"><path d="M6 4h4v16H6zM14 4h4v16h-4z"/></svg>',onLoad:null,onPlay:null,onPause:null,onEnd:null,onError:null,onTimeUpdate:null},O={bars:{barWidth:3,barSpacing:1},mirror:{barWidth:2,barSpacing:0},line:{barWidth:2,barSpacing:0},blocks:{barWidth:4,barSpacing:2},dots:{barWidth:3,barSpacing:3},seekbar:{barWidth:1,barSpacing:0}};var g=class t{static instances=new Map;static currentlyPlaying=null;constructor(e,i={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("WaveformPlayer: Container element not found");let a=T(this.container);this.options=P(D,a,i);let o=O[this.options.waveformStyle];o&&(a.barWidth===void 0&&i.barWidth===void 0&&(this.options.barWidth=o.barWidth),a.barSpacing===void 0&&i.barSpacing===void 0&&(this.options.barSpacing=o.barSpacing)),this.options.waveformColor=this.options.waveformColor||"rgba(255, 255, 255, 0.3)",this.options.progressColor=this.options.progressColor||"rgba(255, 255, 255, 0.9)",this.options.buttonColor=this.options.buttonColor||"rgba(255, 255, 255, 0.9)",this.options.textColor=this.options.textColor||"#ffffff",this.options.textSecondaryColor=this.options.textSecondaryColor||"rgba(255, 255, 255, 0.6)",this.audio=null,this.canvas=null,this.ctx=null,this.waveformData=[],this.progress=0,this.isPlaying=!1,this.isLoading=!1,this.hasError=!1,this.updateTimer=null,this.resizeObserver=null,this.id=this.container.id||R(this.options.url),t.instances.set(this.id,this),this.init(),setTimeout(()=>{this.container.dispatchEvent(new CustomEvent("waveformplayer:ready",{detail:{player:this,url:this.options.url}}))},100)}init(){this.createDOM(),this.createAudio(),this.initPlaybackSpeed(),this.initKeyboardControls(),this.bindEvents(),this.setupResizeObserver(),requestAnimationFrame(()=>{this.resizeCanvas(),this.options.url&&this.load(this.options.url).then(()=>{this.options.autoplay&&this.play()}).catch(e=>{console.error("Failed to load audio:",e)})})}createDOM(){this.container.innerHTML="",this.container.className="waveform-player";let e=this.options.buttonAlign;e==="auto"&&(this.options.waveformStyle==="bars"?e="bottom":e="center"),this.container.innerHTML=`
2
2
  <div class="waveform-player-inner">
3
3
  <div class="waveform-body">
4
4
  <div class="waveform-track waveform-align-${e}">
@@ -46,7 +46,7 @@ function T(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&
46
46
  <span class="speed-value">1x</span>
47
47
  </button>
48
48
  <div class="speed-menu" style="display: none;">
49
- ${this.options.playbackRates.map(o=>`<button class="speed-option" data-rate="${o}">${o}x</button>`).join("")}
49
+ ${this.options.playbackRates.map(i=>`<button class="speed-option" data-rate="${i}">${i}x</button>`).join("")}
50
50
  </div>
51
51
  </div>
52
52
  `:""}
@@ -59,4 +59,4 @@ function T(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"),o=this.container.querySelector(".speed-menu");!e||!o||(e.addEventListener("click",a=>{a.stopPropagation(),o.style.display=o.style.display==="none"?"block":"none"}),document.addEventListener("click",()=>{o.style.display="none"}),o.addEventListener("click",a=>{if(a.stopPropagation(),a.target.classList.contains("speed-option")){let i=parseFloat(a.target.dataset.rate);this.setPlaybackRate(i),o.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 o=e.key,a=this.audio.currentTime;if(o>="0"&&o<="9"){e.preventDefault(),this.seekToPercent(parseInt(o)/10);return}let i={" ":()=>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};i[o]&&(e.preventDefault(),i[o]())})}initMediaSession(){!("mediaSession"in navigator)||!this.options.enableMediaSession||(navigator.mediaSession.metadata=new MediaMetadata({title:this.options.title||"Unknown Track",artist:this.options.subtitle||"",album:this.options.album||"",artwork:this.options.artwork?[{src:this.options.artwork,sizes:"512x512",type:"image/jpeg"}]:[]}),navigator.mediaSession.setActionHandler("play",()=>this.play()),navigator.mediaSession.setActionHandler("pause",()=>this.pause()),navigator.mediaSession.setActionHandler("seekbackward",()=>{this.seekTo(Math.max(0,this.audio.currentTime-10))}),navigator.mediaSession.setActionHandler("seekforward",()=>{this.seekTo(Math.min(this.audio.duration,this.audio.currentTime+10))}),navigator.mediaSession.setActionHandler("seekto",e=>{e.seekTime!==null&&this.seekTo(e.seekTime)}))}bindEvents(){this.playBtn.addEventListener("click",()=>this.togglePlay()),this.audio.addEventListener("loadstart",()=>this.setLoading(!0)),this.audio.addEventListener("loadedmetadata",()=>this.onMetadataLoaded()),this.audio.addEventListener("canplay",()=>this.setLoading(!1)),this.audio.addEventListener("play",()=>this.onPlay()),this.audio.addEventListener("pause",()=>this.onPause()),this.audio.addEventListener("ended",()=>this.onEnded()),this.audio.addEventListener("error",e=>this.onError(e)),this.canvas.addEventListener("click",e=>this.handleCanvasClick(e)),window.addEventListener("resize",L(()=>this.resizeCanvas(),100))}setupResizeObserver(){"ResizeObserver"in window&&(this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.canvas?.parentElement&&this.resizeObserver.observe(this.canvas.parentElement))}async load(e){try{this.setLoading(!0),this.progress=0,this.hasError=!1,this.audio.src=e,await new Promise((a,i)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),a()},r=s=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),i(s)};this.audio.addEventListener("loadedmetadata",n),this.audio.addEventListener("error",r)});let o=this.options.title||A(e);if(this.titleEl&&(this.titleEl.textContent=o),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=I(this.options.samples)}this.drawWaveform(),this.renderMarkers(),this.initMediaSession(),this.options.onLoad&&this.options.onLoad(this)}catch(o){console.error("Failed to load audio:",o),this.onError(o)}finally{this.setLoading(!1)}}async loadTrack(e,o=null,a=null,i={}){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:o||this.options.title,subtitle:a||this.options.subtitle,...i}),i.preload&&(this.audio.preload=i.preload),this.subtitleEl&&(a?(this.subtitleEl.textContent=a,this.subtitleEl.style.display=""):a===""&&(this.subtitleEl.style.display="none")),i.artwork&&this.artworkEl&&(this.artworkEl.src=i.artwork),i.markers&&(this.options.markers=i.markers),await this.load(e),this.play()}setWaveformData(e){if(typeof e=="string")try{let o=JSON.parse(e);this.waveformData=Array.isArray(o)?o:[]}catch{this.waveformData=e.split(",").map(Number)}else this.waveformData=Array.isArray(e)?e:[];this.drawWaveform()}drawWaveform(){!this.ctx||this.waveformData.length===0||B(this.ctx,this.canvas,this.waveformData,this.progress,{...this.options,waveformStyle:this.options.waveformStyle||"bars",color:this.options.waveformColor,progressColor:this.options.progressColor})}resizeCanvas(){let e=window.devicePixelRatio||1,o=this.canvas.getBoundingClientRect();this.canvas.width=o.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,o)=>{let a=e.time/this.audio.duration*100,i=document.createElement("button");i.className="waveform-marker",i.style.left=`${a}%`,i.style.backgroundColor=e.color||"rgba(255, 255, 255, 0.5)",i.setAttribute("aria-label",e.label),i.setAttribute("data-time",e.time);let n=document.createElement("span");n.className="waveform-marker-tooltip",n.textContent=e.label,i.appendChild(n),i.addEventListener("click",r=>{r.stopPropagation(),this.seekTo(e.time),this.options.playOnSeek&&!this.isPlaying&&this.play()}),this.markersContainer.appendChild(i)}))}handleCanvasClick(e){if(!this.audio.duration)return;let o=this.canvas.getBoundingClientRect(),a=e.clientX-o.left,i=Math.max(0,Math.min(1,a/o.width));this.seekToPercent(i)}setLoading(e){this.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none")}onMetadataLoaded(){this.totalTimeEl&&(this.totalTimeEl.textContent=C(this.audio.duration)),this.renderMarkers()}onPlay(){this.isPlaying=!0,this.playBtn.classList.add("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),o=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="none"),o&&(o.style.display="flex"),this.startSmoothUpdate(),this.options.onPlay&&this.options.onPlay(this)}onPause(){this.isPlaying=!1,this.playBtn.classList.remove("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),o=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="flex"),o&&(o.style.display="none"),this.stopSmoothUpdate(),this.options.onPause&&this.options.onPause(this)}onEnded(){this.progress=0,this.audio.currentTime=0,this.drawWaveform(),this.currentTimeEl&&(this.currentTimeEl.textContent="0:00"),this.onPause(),this.options.onEnd&&this.options.onEnd(this)}onError(e){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.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 o=this.audio.playbackRate;e.textContent=o===1?"1x":`${o}x`}this.container.querySelectorAll(".speed-option").forEach(o=>{o.classList.toggle("active",parseFloat(o.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 o=Math.max(.5,Math.min(2,e));this.audio.playbackRate=o,this.options.playbackRate=o,this.updateSpeedUI()}destroy(){this.pause(),this.stopSmoothUpdate(),this.resizeObserver&&this.resizeObserver.disconnect(),t.instances.delete(this.id),this.audio&&(this.audio.src=""),this.container.innerHTML=""}static getInstance(e){if(typeof e=="string"){let o=this.instances.get(e);if(o)return o;let a=document.getElementById(e);if(a)return Array.from(this.instances.values()).find(i=>i.container===a)}if(e instanceof HTMLElement)return Array.from(this.instances.values()).find(o=>o.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,o=200){try{return(await M(e,o)).peaks}catch(a){throw console.error("Failed to generate waveform:",a),a}}};function E(){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(o){console.error("Failed to initialize WaveformPlayer:",o,e)}})}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",E):E());g.init=E;typeof window<"u"&&(window.WaveformPlayer=g);var st=g;export{g as WaveformPlayer,st 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 o=parseFloat(a.target.dataset.rate);this.setPlaybackRate(o),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 o={" ":()=>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};o[i]&&(e.preventDefault(),o[i]())})}initMediaSession(){!("mediaSession"in navigator)||!this.options.enableMediaSession||(navigator.mediaSession.metadata=new MediaMetadata({title:this.options.title||"Unknown Track",artist:this.options.subtitle||"",album:this.options.album||"",artwork:this.options.artwork?[{src:this.options.artwork,sizes:"512x512",type:"image/jpeg"}]:[]}),navigator.mediaSession.setActionHandler("play",()=>this.play()),navigator.mediaSession.setActionHandler("pause",()=>this.pause()),navigator.mediaSession.setActionHandler("seekbackward",()=>{this.seekTo(Math.max(0,this.audio.currentTime-10))}),navigator.mediaSession.setActionHandler("seekforward",()=>{this.seekTo(Math.min(this.audio.duration,this.audio.currentTime+10))}),navigator.mediaSession.setActionHandler("seekto",e=>{e.seekTime!==null&&this.seekTo(e.seekTime)}))}bindEvents(){this.playBtn.addEventListener("click",()=>this.togglePlay()),this.audio.addEventListener("loadstart",()=>this.setLoading(!0)),this.audio.addEventListener("loadedmetadata",()=>this.onMetadataLoaded()),this.audio.addEventListener("canplay",()=>this.setLoading(!1)),this.audio.addEventListener("play",()=>this.onPlay()),this.audio.addEventListener("pause",()=>this.onPause()),this.audio.addEventListener("ended",()=>this.onEnded()),this.audio.addEventListener("error",e=>this.onError(e)),this.canvas.addEventListener("click",e=>this.handleCanvasClick(e)),window.addEventListener("resize",L(()=>this.resizeCanvas(),100))}setupResizeObserver(){"ResizeObserver"in window&&(this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.canvas?.parentElement&&this.resizeObserver.observe(this.canvas.parentElement))}async load(e){try{this.setLoading(!0),this.progress=0,this.hasError=!1,this.audio.src=e,await new Promise((a,o)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),a()},r=s=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),o(s)};this.audio.addEventListener("loadedmetadata",n),this.audio.addEventListener("error",r)});let i=this.options.title||A(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=I(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,o={}){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:a||this.options.subtitle,...o}),o.preload&&(this.audio.preload=o.preload),this.subtitleEl&&(a?(this.subtitleEl.textContent=a,this.subtitleEl.style.display=""):a===""&&(this.subtitleEl.style.display="none")),o.artwork&&this.artworkEl&&(this.artworkEl.src=o.artwork),o.markers&&(this.options.markers=o.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||B(this.ctx,this.canvas,this.waveformData,this.progress,{...this.options,waveformStyle:this.options.waveformStyle||"bars",color:this.options.waveformColor,progressColor:this.options.progressColor})}resizeCanvas(){let e=window.devicePixelRatio||1,i=this.canvas.getBoundingClientRect();this.canvas.width=i.width*e,this.canvas.height=this.options.height*e,this.canvas.style.height=this.options.height+"px",this.canvas.parentElement.style.height=this.options.height+"px",this.drawWaveform()}renderMarkers(){!this.options.showMarkers||!this.options.markers?.length||!this.markersContainer||(this.markersContainer.innerHTML="",!(!this.audio||!this.audio.duration||this.audio.duration===0)&&this.options.markers.forEach((e,i)=>{if(e.time>this.audio.duration){console.warn(`Marker "${e.label}" at ${e.time}s exceeds audio duration of ${this.audio.duration}s`);return}let a=e.time/this.audio.duration*100,o=document.createElement("button");o.className="waveform-marker",o.style.left=`${a}%`,o.style.backgroundColor=e.color||"rgba(255, 255, 255, 0.5)",o.setAttribute("aria-label",e.label),o.setAttribute("data-time",e.time);let n=document.createElement("span");n.className="waveform-marker-tooltip",n.textContent=e.label,o.appendChild(n),o.addEventListener("click",r=>{r.stopPropagation(),this.seekTo(e.time),this.options.playOnSeek&&!this.isPlaying&&this.play()}),this.markersContainer.appendChild(o)}))}handleCanvasClick(e){if(!this.audio.duration)return;let i=this.canvas.getBoundingClientRect(),a=e.clientX-i.left,o=Math.max(0,Math.min(1,a/i.width));this.seekToPercent(o)}setLoading(e){this.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none")}onMetadataLoaded(){this.totalTimeEl&&(this.totalTimeEl.textContent=C(this.audio.duration)),this.renderMarkers()}onPlay(){this.isPlaying=!0,this.playBtn.classList.add("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="none"),i&&(i.style.display="flex"),this.startSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:play",{detail:{player:this,url:this.options.url}})),this.options.onPlay&&this.options.onPlay(this)}onPause(){this.isPlaying=!1,this.playBtn.classList.remove("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="flex"),i&&(i.style.display="none"),this.stopSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:pause",{detail:{player:this,url:this.options.url}})),this.options.onPause&&this.options.onPause(this)}onEnded(){this.progress=0,this.audio.currentTime=0,this.drawWaveform(),this.currentTimeEl&&(this.currentTimeEl.textContent="0:00"),this.container.dispatchEvent(new CustomEvent("waveformplayer:ended",{detail:{player:this,url:this.options.url}})),this.onPause(),this.options.onEnd&&this.options.onEnd(this)}onError(e){this.isDestroying||(console.error("Audio error:",e),this.hasError=!0,this.setLoading(!1),this.errorEl&&(this.errorEl.style.display="flex"),this.canvas&&(this.canvas.style.opacity="0.2"),this.playBtn&&(this.playBtn.disabled=!0),this.options.onError&&this.options.onError(e,this))}startSmoothUpdate(){this.stopSmoothUpdate();let e=()=>{this.isPlaying&&this.audio.duration&&(this.updateProgress(),this.updateTimer=requestAnimationFrame(e))};this.updateTimer=requestAnimationFrame(e)}stopSmoothUpdate(){this.updateTimer&&(cancelAnimationFrame(this.updateTimer),this.updateTimer=null)}updateProgress(){if(!this.audio.duration)return;let e=this.audio.currentTime/this.audio.duration;Math.abs(e-this.progress)>.001&&(this.progress=e,this.drawWaveform()),this.currentTimeEl&&(this.currentTimeEl.textContent=C(this.audio.currentTime)),this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate",{detail:{player:this,currentTime:this.audio.currentTime,duration:this.audio.duration,url:this.options.url}})),this.options.onTimeUpdate&&this.options.onTimeUpdate(this.audio.currentTime,this.audio.duration,this)}updateBPMDisplay(){this.bpmEl&&this.bpmValueEl&&this.detectedBPM&&(this.bpmValueEl.textContent=Math.round(this.detectedBPM),this.bpmEl.style.display="inline-flex")}updateSpeedUI(){let e=this.container.querySelector(".speed-value");if(e){let i=this.audio.playbackRate;e.textContent=i===1?"1x":`${i}x`}this.container.querySelectorAll(".speed-option").forEach(i=>{i.classList.toggle("active",parseFloat(i.dataset.rate)===this.audio.playbackRate)})}play(){this.options.singlePlay&&t.currentlyPlaying&&t.currentlyPlaying!==this&&t.currentlyPlaying.pause(),t.currentlyPlaying=this,this.audio.play()}pause(){t.currentlyPlaying===this&&(t.currentlyPlaying=null),this.audio.pause()}togglePlay(){this.isPlaying?this.pause():this.play()}seekTo(e){this.audio&&this.audio.duration&&(this.audio.currentTime=Math.max(0,Math.min(e,this.audio.duration)),this.updateProgress())}seekToPercent(e){this.audio&&this.audio.duration&&(this.audio.currentTime=this.audio.duration*Math.max(0,Math.min(1,e)),this.updateProgress())}setVolume(e){this.audio&&(this.audio.volume=Math.max(0,Math.min(1,e)))}setPlaybackRate(e){if(!this.audio)return;let i=Math.max(.5,Math.min(2,e));this.audio.playbackRate=i,this.options.playbackRate=i,this.updateSpeedUI()}destroy(){this.isDestroying=!0,this.pause(),this.stopSmoothUpdate(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),t.instances.delete(this.id),t.currentlyPlaying===this&&(t.currentlyPlaying=null),this.audio&&(this.audio.pause(),this.audio.src="",this.audio.load(),this.audio=null),this.container.innerHTML="",this.canvas=null,this.ctx=null,this.playBtn=null,this.waveformData=[]}static getInstance(e){if(typeof e=="string"){let i=this.instances.get(e);if(i)return i;let a=document.getElementById(e);if(a)return Array.from(this.instances.values()).find(o=>o.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 E(){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",E):E());g.init=E;typeof window<"u"&&(window.WaveformPlayer=g);var st=g;export{g as WaveformPlayer,st as default};
@@ -614,6 +614,11 @@
614
614
  this.id = this.container.id || generateId(this.options.url);
615
615
  _WaveformPlayer.instances.set(this.id, this);
616
616
  this.init();
617
+ setTimeout(() => {
618
+ this.container.dispatchEvent(new CustomEvent("waveformplayer:ready", {
619
+ detail: { player: this, url: this.options.url }
620
+ }));
621
+ }, 100);
617
622
  }
618
623
  // ============================================
619
624
  // Initialization
@@ -1057,6 +1062,10 @@
1057
1062
  return;
1058
1063
  }
1059
1064
  this.options.markers.forEach((marker, index) => {
1065
+ if (marker.time > this.audio.duration) {
1066
+ console.warn(`Marker "${marker.label}" at ${marker.time}s exceeds audio duration of ${this.audio.duration}s`);
1067
+ return;
1068
+ }
1060
1069
  const position = marker.time / this.audio.duration * 100;
1061
1070
  const markerEl = document.createElement("button");
1062
1071
  markerEl.className = "waveform-marker";
@@ -1124,6 +1133,9 @@
1124
1133
  if (playIcon) playIcon.style.display = "none";
1125
1134
  if (pauseIcon) pauseIcon.style.display = "flex";
1126
1135
  this.startSmoothUpdate();
1136
+ this.container.dispatchEvent(new CustomEvent("waveformplayer:play", {
1137
+ detail: { player: this, url: this.options.url }
1138
+ }));
1127
1139
  if (this.options.onPlay) {
1128
1140
  this.options.onPlay(this);
1129
1141
  }
@@ -1140,6 +1152,9 @@
1140
1152
  if (playIcon) playIcon.style.display = "flex";
1141
1153
  if (pauseIcon) pauseIcon.style.display = "none";
1142
1154
  this.stopSmoothUpdate();
1155
+ this.container.dispatchEvent(new CustomEvent("waveformplayer:pause", {
1156
+ detail: { player: this, url: this.options.url }
1157
+ }));
1143
1158
  if (this.options.onPause) {
1144
1159
  this.options.onPause(this);
1145
1160
  }
@@ -1155,6 +1170,9 @@
1155
1170
  if (this.currentTimeEl) {
1156
1171
  this.currentTimeEl.textContent = "0:00";
1157
1172
  }
1173
+ this.container.dispatchEvent(new CustomEvent("waveformplayer:ended", {
1174
+ detail: { player: this, url: this.options.url }
1175
+ }));
1158
1176
  this.onPause();
1159
1177
  if (this.options.onEnd) {
1160
1178
  this.options.onEnd(this);
@@ -1165,6 +1183,7 @@
1165
1183
  * @private
1166
1184
  */
1167
1185
  onError(error) {
1186
+ if (this.isDestroying) return;
1168
1187
  console.error("Audio error:", error);
1169
1188
  this.hasError = true;
1170
1189
  this.setLoading(false);
@@ -1222,6 +1241,14 @@
1222
1241
  if (this.currentTimeEl) {
1223
1242
  this.currentTimeEl.textContent = formatTime(this.audio.currentTime);
1224
1243
  }
1244
+ this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate", {
1245
+ detail: {
1246
+ player: this,
1247
+ currentTime: this.audio.currentTime,
1248
+ duration: this.audio.duration,
1249
+ url: this.options.url
1250
+ }
1251
+ }));
1225
1252
  if (this.options.onTimeUpdate) {
1226
1253
  this.options.onTimeUpdate(this.audio.currentTime, this.audio.duration, this);
1227
1254
  }
@@ -1329,16 +1356,28 @@
1329
1356
  * Destroy player instance
1330
1357
  */
1331
1358
  destroy() {
1359
+ this.isDestroying = true;
1332
1360
  this.pause();
1333
1361
  this.stopSmoothUpdate();
1334
1362
  if (this.resizeObserver) {
1335
1363
  this.resizeObserver.disconnect();
1364
+ this.resizeObserver = null;
1336
1365
  }
1337
1366
  _WaveformPlayer.instances.delete(this.id);
1367
+ if (_WaveformPlayer.currentlyPlaying === this) {
1368
+ _WaveformPlayer.currentlyPlaying = null;
1369
+ }
1338
1370
  if (this.audio) {
1371
+ this.audio.pause();
1339
1372
  this.audio.src = "";
1373
+ this.audio.load();
1374
+ this.audio = null;
1340
1375
  }
1341
1376
  this.container.innerHTML = "";
1377
+ this.canvas = null;
1378
+ this.ctx = null;
1379
+ this.playBtn = null;
1380
+ this.waveformData = [];
1342
1381
  }
1343
1382
  // ============================================
1344
1383
  // Static Methods
@@ -1,4 +1,4 @@
1
- (()=>{function T(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&&(e.height=parseInt(t.dataset.height)),t.dataset.samples&&(e.samples=parseInt(t.dataset.samples)),t.dataset.preload&&(e.preload=t.dataset.preload),t.dataset.waveformStyle&&(e.waveformStyle=t.dataset.waveformStyle),t.dataset.barWidth&&(e.barWidth=parseInt(t.dataset.barWidth)),t.dataset.barSpacing&&(e.barSpacing=parseInt(t.dataset.barSpacing)),t.dataset.buttonAlign&&(e.buttonAlign=t.dataset.buttonAlign),t.dataset.colorPreset&&(e.colorPreset=t.dataset.colorPreset),t.dataset.waveformColor&&(e.waveformColor=t.dataset.waveformColor),t.dataset.progressColor&&(e.progressColor=t.dataset.progressColor),t.dataset.buttonColor&&(e.buttonColor=t.dataset.buttonColor),t.dataset.buttonHoverColor&&(e.buttonHoverColor=t.dataset.buttonHoverColor),t.dataset.textColor&&(e.textColor=t.dataset.textColor),t.dataset.textSecondaryColor&&(e.textSecondaryColor=t.dataset.textSecondaryColor),t.dataset.backgroundColor&&(e.backgroundColor=t.dataset.backgroundColor),t.dataset.borderColor&&(e.borderColor=t.dataset.borderColor),t.dataset.color&&(e.waveformColor=t.dataset.color),t.dataset.theme&&(e.colorPreset=t.dataset.theme),t.dataset.autoplay&&(e.autoplay=t.dataset.autoplay==="true"),t.dataset.showTime&&(e.showTime=t.dataset.showTime==="true"),t.dataset.showHoverTime&&(e.showHoverTime=t.dataset.showHoverTime==="true"),t.dataset.showBpm&&(e.showBPM=t.dataset.showBpm==="true"),t.dataset.singlePlay&&(e.singlePlay=t.dataset.singlePlay==="true"),t.dataset.playOnSeek&&(e.playOnSeek=t.dataset.playOnSeek==="true"),t.dataset.title&&(e.title=t.dataset.title),t.dataset.subtitle&&(e.subtitle=t.dataset.subtitle),t.dataset.album&&(e.album=t.dataset.album),t.dataset.artwork&&(e.artwork=t.dataset.artwork),t.dataset.waveform&&(e.waveform=t.dataset.waveform),t.dataset.markers)try{e.markers=JSON.parse(t.dataset.markers)}catch(o){console.warn("Invalid markers JSON:",o)}if(t.dataset.playbackRate&&(e.playbackRate=parseFloat(t.dataset.playbackRate)),t.dataset.showPlaybackSpeed!==void 0&&(e.showPlaybackSpeed=t.dataset.showPlaybackSpeed==="true"),t.dataset.playbackRates)try{e.playbackRates=JSON.parse(t.dataset.playbackRates)}catch(o){console.warn("Invalid playbackRates JSON:",o)}return t.dataset.enableMediaSession!==void 0&&(e.enableMediaSession=t.dataset.enableMediaSession==="true"),e}function C(t){if(!t||isNaN(t))return"0:00";let e=Math.floor(t/60),o=Math.floor(t%60);return`${e}:${o.toString().padStart(2,"0")}`}function R(t){let e=t||Math.random().toString();return btoa(e.substring(0,10)).replace(/[^a-zA-Z0-9]/g,"")}function A(t){if(!t)return"Audio";let e=t.split("/");return e[e.length-1].split(".")[0].replace(/[-_]/g," ").replace(/\b\w/g,i=>i.toUpperCase())}function P(...t){let e={};for(let o of t)for(let a in o)o[a]!==null&&o[a]!==void 0&&(e[a]=o[a]);return e}function L(t,e){let o;return function(...i){let n=()=>{clearTimeout(o),t(...i)};clearTimeout(o),o=setTimeout(n,e)}}function S(t,e){if(t.length===e)return t;if(t.length===0||e===0)return[];let o=[];if(e>t.length){let a=(t.length-1)/(e-1);for(let i=0;i<e;i++){let n=i*a,r=Math.floor(n),s=Math.ceil(n),h=n-r;if(s>=t.length)o.push(t[t.length-1]);else if(r===s)o.push(t[r]);else{let l=t[r]*(1-h)+t[s]*h;o.push(l)}}}else{let a=t.length/e;for(let i=0;i<e;i++){let n=Math.floor(i*a),r=Math.floor((i+1)*a),s=0,h=0;for(let l=n;l<=r&&l<t.length;l++)t[l]>s&&(s=t[l]),h++;if(h===0){let l=Math.min(Math.round(i*a),t.length-1);s=t[l]}o.push(s)}}return o}function x(t,e,o,a,i){let n=window.devicePixelRatio||1,r=i.barWidth*n,s=i.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(o,h),d=e.height,p=a*e.width;t.clearRect(0,0,e.width,e.height);for(let y=0;y<l.length;y++){let f=y*(r+s);if(f+r>e.width)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=i.color,t.fillRect(f,m,r,c)}t.save(),t.beginPath(),t.rect(0,0,p,d),t.clip();for(let y=0;y<l.length;y++){let f=y*(r+s);if(f>p)break;let c=l[y]*d*.9,m=d-c;t.fillStyle=i.progressColor,t.fillRect(f,m,r,c)}t.restore()}function D(t,e,o,a,i){let n=window.devicePixelRatio||1,r=i.barWidth*n,s=i.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(o,h),d=e.height,p=d/2,y=a*e.width;t.clearRect(0,0,e.width,e.height);for(let f=0;f<l.length;f++){let c=f*(r+s);if(c+r>e.width)break;let m=l[f]*d*.45;t.fillStyle=i.color,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.save(),t.beginPath(),t.rect(0,0,y,d),t.clip();for(let f=0;f<l.length;f++){let c=f*(r+s);if(c>y)break;let m=l[f]*d*.45;t.fillStyle=i.progressColor,t.fillRect(c,p-m,r,m),t.fillRect(c,p,r,m)}t.restore()}function H(t,e,o,a,i){let n=e.width,r=e.height,s=r/2,h=r*.35;t.clearRect(0,0,n,r);let l=(d,p,y=1,f=!1)=>{f&&(t.shadowBlur=12,t.shadowColor=d),t.strokeStyle=d,t.lineWidth=p,t.lineCap="round",t.lineJoin="round",t.beginPath(),t.moveTo(0,s);let c=[],m=Math.floor(o.length*y);for(let u=0;u<m;u++){let v=u/(o.length-1)*n,k=o[u],b=Math.sin(u*.1)*k,w=s+b*h;c.push({x:v,y:w})}for(let u=0;u<c.length-1;u++){let v=c[u].x+(c[u+1].x-c[u].x)*.5,k=c[u].y,b=c[u+1].x-(c[u+1].x-c[u].x)*.5,w=c[u+1].y;t.bezierCurveTo(v,k,b,w,c[u+1].x,c[u+1].y)}t.stroke(),f&&(t.shadowBlur=0)};t.strokeStyle="rgba(255, 255, 255, 0.03)",t.lineWidth=.5,t.beginPath(),t.moveTo(0,s),t.lineTo(n,s),t.stroke();for(let d=0;d<=10;d++){let p=n/10*d;t.beginPath(),t.moveTo(p,0),t.lineTo(p,r),t.stroke()}l(i.color,2,1,!1),a>0&&l(i.progressColor,3,a,!0)}function q(t,e,o,a,i){let n=window.devicePixelRatio||1,r=(i.barWidth||3)*n,s=(i.barSpacing||1)*n,h=Math.floor(e.width/(r+s)),l=S(o,h),d=e.height,p=4*n,y=2*n,f=a*e.width,c=d/2;t.clearRect(0,0,e.width,e.height);for(let m=0;m<l.length;m++){let u=m*(r+s);if(u+r>e.width)break;let v=l[m]*d*.9,k=Math.floor(v/(p+y));t.fillStyle=u<f?i.progressColor:i.color;for(let b=0;b<k;b++){let w=b*(p+y);t.fillRect(u,c-w-p,r,p),b>0&&t.fillRect(u,c+w,r,p)}}}function U(t,e,o,a,i){let n=window.devicePixelRatio||1,r=(i.barWidth||2)*n,s=(i.barSpacing||3)*n,h=Math.floor(e.width/(r+s)),l=S(o,h),d=e.height,p=Math.max(1.5*n,r/2),y=a*e.width,f=d/2;t.clearRect(0,0,e.width,e.height);for(let c=0;c<l.length;c++){let m=c*(r+s)+r/2;if(m>e.width)break;let u=l[c]*d*.9;t.fillStyle=m<y?i.progressColor:i.color,t.beginPath(),t.arc(m,f-u/2,p,0,Math.PI*2),t.fill(),t.beginPath(),t.arc(m,f+u/2,p,0,Math.PI*2),t.fill()}}function $(t,e,o,a,i){let n=e.width,r=e.height,s=r/2,h=4,l=h/2;if(t.clearRect(0,0,n,r),t.fillStyle=i.color||"rgba(255, 255, 255, 0.2)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(n-l,s-h/2),t.arc(n-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),a>0){let d=Math.max(l*2,a*n);t.shadowBlur=8,t.shadowColor=i.progressColor,t.fillStyle=i.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(d-l,s-h/2),t.arc(d-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),t.shadowBlur=0;let p=8,y=d;t.shadowBlur=4,t.shadowColor="rgba(0, 0, 0, 0.3)",t.shadowOffsetY=2,t.fillStyle="#ffffff",t.beginPath(),t.arc(y,s,p,0,Math.PI*2),t.fill(),t.shadowBlur=0,t.shadowOffsetY=0,t.fillStyle=i.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.arc(y,s,p*.4,0,Math.PI*2),t.fill()}}var F={bars:x,mirror:D,line:H,blocks:q,dots:U,seekbar:$};function B(t,e,o,a,i){(F[i.waveformStyle]||x)(t,e,o,a,i)}function W(t){try{let e=t.getChannelData(0),o=t.sampleRate,a=N(e,o);if(a.length<2)return 120;let i=[];for(let h=1;h<a.length;h++)i.push((a[h]-a[h-1])/o);let n={};i.forEach(h=>{let l=60/h,d=Math.round(l/3)*3;d>60&&d<200&&(n[d]=(n[d]||0)+1)});let r=0,s=120;for(let[h,l]of Object.entries(n))l>r&&(r=l,s=parseInt(h));return s<70&&n[s*2]?s*=2:s>160&&n[Math.round(s/2)]&&(s=Math.round(s/2)),s-1}catch(e){return console.warn("BPM detection failed:",e),null}}function N(t,e){let i=[],n=0;for(let r=0;r<t.length-2048;r+=1024){let s=0;for(let d=r;d<r+2048;d++)s+=t[d]*t[d];s=s/2048;let h=s-n,l=n*1.8+.01;if(h>l&&s>.01){let d=i[i.length-1]||0,p=e*.15;r-d>p&&i.push(r)}n=s*.8+n*.2}return i}function Y(t,e=200){let o=t.length/e,a=~~(o/10)||1,i=t.numberOfChannels,n=[];for(let s=0;s<i;s++){let h=t.getChannelData(s);for(let l=0;l<e;l++){let d=~~(l*o),p=~~(d+o),y=0,f=0;for(let m=d;m<p;m+=a){let u=h[m];u>f&&(f=u),u<y&&(y=u)}let c=Math.max(Math.abs(f),Math.abs(y));(s===0||c>n[l])&&(n[l]=c)}}let r=Math.max(...n);return r>0?n.map(s=>s/r):n}async function M(t,e=200,o=!1){try{let a=new(window.AudioContext||window.webkitAudioContext),n=await(await fetch(t)).arrayBuffer(),r=await a.decodeAudioData(n),s=Y(r,e);s=j(s);let h=null;return o&&(h=await W(r)),a.close(),{peaks:s,bpm:h}}catch(a){throw console.error("Failed to generate waveform:",a),a}}function I(t=200){let e=[];for(let o=0;o<t;o++){let a=Math.random()*.5+.3,i=Math.sin(o/t*Math.PI*4)*.2;e.push(Math.max(.1,Math.min(1,a+i)))}return e}function j(t,e=.95){let o=Math.max(...t);if(o===0||o>e)return t;let a=e/o;return t.map(i=>i*a)}var O={url:"",height:60,samples:200,preload:"metadata",playbackRate:1,showPlaybackSpeed:!1,playbackRates:[.5,.75,1,1.25,1.5,1.75,2],buttonAlign:"auto",waveformStyle:"mirror",barWidth:2,barSpacing:0,colorPreset:"dark",waveformColor:null,progressColor:null,buttonColor:null,buttonHoverColor:null,textColor:null,textSecondaryColor:null,backgroundColor:null,borderColor:null,autoplay:!1,showTime:!0,showHoverTime:!1,showBPM:!1,singlePlay:!0,playOnSeek:!0,enableMediaSession:!0,markers:[],showMarkers:!0,title:null,subtitle:null,artwork:null,album:"",playIcon:'<svg viewBox="0 0 24 24" width="16" height="16"><path d="M8 5v14l11-7z"/></svg>',pauseIcon:'<svg viewBox="0 0 24 24" width="16" height="16"><path d="M6 4h4v16H6zM14 4h4v16h-4z"/></svg>',onLoad:null,onPlay:null,onPause:null,onEnd:null,onError:null,onTimeUpdate:null},z={bars:{barWidth:3,barSpacing:1},mirror:{barWidth:2,barSpacing:0},line:{barWidth:2,barSpacing:0},blocks:{barWidth:4,barSpacing:2},dots:{barWidth:3,barSpacing:3},seekbar:{barWidth:1,barSpacing:0}};var g=class t{static instances=new Map;static currentlyPlaying=null;constructor(e,o={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("WaveformPlayer: Container element not found");let a=T(this.container);this.options=P(O,a,o);let i=z[this.options.waveformStyle];i&&(a.barWidth===void 0&&o.barWidth===void 0&&(this.options.barWidth=i.barWidth),a.barSpacing===void 0&&o.barSpacing===void 0&&(this.options.barSpacing=i.barSpacing)),this.options.waveformColor=this.options.waveformColor||"rgba(255, 255, 255, 0.3)",this.options.progressColor=this.options.progressColor||"rgba(255, 255, 255, 0.9)",this.options.buttonColor=this.options.buttonColor||"rgba(255, 255, 255, 0.9)",this.options.textColor=this.options.textColor||"#ffffff",this.options.textSecondaryColor=this.options.textSecondaryColor||"rgba(255, 255, 255, 0.6)",this.audio=null,this.canvas=null,this.ctx=null,this.waveformData=[],this.progress=0,this.isPlaying=!1,this.isLoading=!1,this.hasError=!1,this.updateTimer=null,this.resizeObserver=null,this.id=this.container.id||R(this.options.url),t.instances.set(this.id,this),this.init()}init(){this.createDOM(),this.createAudio(),this.initPlaybackSpeed(),this.initKeyboardControls(),this.bindEvents(),this.setupResizeObserver(),requestAnimationFrame(()=>{this.resizeCanvas(),this.options.url&&this.load(this.options.url).then(()=>{this.options.autoplay&&this.play()}).catch(e=>{console.error("Failed to load audio:",e)})})}createDOM(){this.container.innerHTML="",this.container.className="waveform-player";let e=this.options.buttonAlign;e==="auto"&&(this.options.waveformStyle==="bars"?e="bottom":e="center"),this.container.innerHTML=`
1
+ (()=>{function T(t){let e={};if(t.dataset.url&&(e.url=t.dataset.url),t.dataset.height&&(e.height=parseInt(t.dataset.height)),t.dataset.samples&&(e.samples=parseInt(t.dataset.samples)),t.dataset.preload&&(e.preload=t.dataset.preload),t.dataset.waveformStyle&&(e.waveformStyle=t.dataset.waveformStyle),t.dataset.barWidth&&(e.barWidth=parseInt(t.dataset.barWidth)),t.dataset.barSpacing&&(e.barSpacing=parseInt(t.dataset.barSpacing)),t.dataset.buttonAlign&&(e.buttonAlign=t.dataset.buttonAlign),t.dataset.colorPreset&&(e.colorPreset=t.dataset.colorPreset),t.dataset.waveformColor&&(e.waveformColor=t.dataset.waveformColor),t.dataset.progressColor&&(e.progressColor=t.dataset.progressColor),t.dataset.buttonColor&&(e.buttonColor=t.dataset.buttonColor),t.dataset.buttonHoverColor&&(e.buttonHoverColor=t.dataset.buttonHoverColor),t.dataset.textColor&&(e.textColor=t.dataset.textColor),t.dataset.textSecondaryColor&&(e.textSecondaryColor=t.dataset.textSecondaryColor),t.dataset.backgroundColor&&(e.backgroundColor=t.dataset.backgroundColor),t.dataset.borderColor&&(e.borderColor=t.dataset.borderColor),t.dataset.color&&(e.waveformColor=t.dataset.color),t.dataset.theme&&(e.colorPreset=t.dataset.theme),t.dataset.autoplay&&(e.autoplay=t.dataset.autoplay==="true"),t.dataset.showTime&&(e.showTime=t.dataset.showTime==="true"),t.dataset.showHoverTime&&(e.showHoverTime=t.dataset.showHoverTime==="true"),t.dataset.showBpm&&(e.showBPM=t.dataset.showBpm==="true"),t.dataset.singlePlay&&(e.singlePlay=t.dataset.singlePlay==="true"),t.dataset.playOnSeek&&(e.playOnSeek=t.dataset.playOnSeek==="true"),t.dataset.title&&(e.title=t.dataset.title),t.dataset.subtitle&&(e.subtitle=t.dataset.subtitle),t.dataset.album&&(e.album=t.dataset.album),t.dataset.artwork&&(e.artwork=t.dataset.artwork),t.dataset.waveform&&(e.waveform=t.dataset.waveform),t.dataset.markers)try{e.markers=JSON.parse(t.dataset.markers)}catch(i){console.warn("Invalid markers JSON:",i)}if(t.dataset.playbackRate&&(e.playbackRate=parseFloat(t.dataset.playbackRate)),t.dataset.showPlaybackSpeed!==void 0&&(e.showPlaybackSpeed=t.dataset.showPlaybackSpeed==="true"),t.dataset.playbackRates)try{e.playbackRates=JSON.parse(t.dataset.playbackRates)}catch(i){console.warn("Invalid playbackRates JSON:",i)}return t.dataset.enableMediaSession!==void 0&&(e.enableMediaSession=t.dataset.enableMediaSession==="true"),e}function C(t){if(!t||isNaN(t))return"0:00";let e=Math.floor(t/60),i=Math.floor(t%60);return`${e}:${i.toString().padStart(2,"0")}`}function R(t){let e=t||Math.random().toString();return btoa(e.substring(0,10)).replace(/[^a-zA-Z0-9]/g,"")}function A(t){if(!t)return"Audio";let e=t.split("/");return e[e.length-1].split(".")[0].replace(/[-_]/g," ").replace(/\b\w/g,o=>o.toUpperCase())}function P(...t){let e={};for(let i of t)for(let a in i)i[a]!==null&&i[a]!==void 0&&(e[a]=i[a]);return e}function L(t,e){let i;return function(...o){let n=()=>{clearTimeout(i),t(...o)};clearTimeout(i),i=setTimeout(n,e)}}function S(t,e){if(t.length===e)return t;if(t.length===0||e===0)return[];let i=[];if(e>t.length){let a=(t.length-1)/(e-1);for(let o=0;o<e;o++){let n=o*a,r=Math.floor(n),s=Math.ceil(n),h=n-r;if(s>=t.length)i.push(t[t.length-1]);else if(r===s)i.push(t[r]);else{let l=t[r]*(1-h)+t[s]*h;i.push(l)}}}else{let a=t.length/e;for(let o=0;o<e;o++){let n=Math.floor(o*a),r=Math.floor((o+1)*a),s=0,h=0;for(let l=n;l<=r&&l<t.length;l++)t[l]>s&&(s=t[l]),h++;if(h===0){let l=Math.min(Math.round(o*a),t.length-1);s=t[l]}i.push(s)}}return i}function x(t,e,i,a,o){let n=window.devicePixelRatio||1,r=o.barWidth*n,s=o.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=a*e.width;t.clearRect(0,0,e.width,e.height);for(let m=0;m<l.length;m++){let f=m*(r+s);if(f+r>e.width)break;let c=l[m]*d*.9,y=d-c;t.fillStyle=o.color,t.fillRect(f,y,r,c)}t.save(),t.beginPath(),t.rect(0,0,p,d),t.clip();for(let m=0;m<l.length;m++){let f=m*(r+s);if(f>p)break;let c=l[m]*d*.9,y=d-c;t.fillStyle=o.progressColor,t.fillRect(f,y,r,c)}t.restore()}function z(t,e,i,a,o){let n=window.devicePixelRatio||1,r=o.barWidth*n,s=o.barSpacing*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=d/2,m=a*e.width;t.clearRect(0,0,e.width,e.height);for(let f=0;f<l.length;f++){let c=f*(r+s);if(c+r>e.width)break;let y=l[f]*d*.45;t.fillStyle=o.color,t.fillRect(c,p-y,r,y),t.fillRect(c,p,r,y)}t.save(),t.beginPath(),t.rect(0,0,m,d),t.clip();for(let f=0;f<l.length;f++){let c=f*(r+s);if(c>m)break;let y=l[f]*d*.45;t.fillStyle=o.progressColor,t.fillRect(c,p-y,r,y),t.fillRect(c,p,r,y)}t.restore()}function H(t,e,i,a,o){let n=e.width,r=e.height,s=r/2,h=r*.35;t.clearRect(0,0,n,r);let l=(d,p,m=1,f=!1)=>{f&&(t.shadowBlur=12,t.shadowColor=d),t.strokeStyle=d,t.lineWidth=p,t.lineCap="round",t.lineJoin="round",t.beginPath(),t.moveTo(0,s);let c=[],y=Math.floor(i.length*m);for(let u=0;u<y;u++){let v=u/(i.length-1)*n,k=i[u],b=Math.sin(u*.1)*k,w=s+b*h;c.push({x:v,y:w})}for(let u=0;u<c.length-1;u++){let v=c[u].x+(c[u+1].x-c[u].x)*.5,k=c[u].y,b=c[u+1].x-(c[u+1].x-c[u].x)*.5,w=c[u+1].y;t.bezierCurveTo(v,k,b,w,c[u+1].x,c[u+1].y)}t.stroke(),f&&(t.shadowBlur=0)};t.strokeStyle="rgba(255, 255, 255, 0.03)",t.lineWidth=.5,t.beginPath(),t.moveTo(0,s),t.lineTo(n,s),t.stroke();for(let d=0;d<=10;d++){let p=n/10*d;t.beginPath(),t.moveTo(p,0),t.lineTo(p,r),t.stroke()}l(o.color,2,1,!1),a>0&&l(o.progressColor,3,a,!0)}function q(t,e,i,a,o){let n=window.devicePixelRatio||1,r=(o.barWidth||3)*n,s=(o.barSpacing||1)*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=4*n,m=2*n,f=a*e.width,c=d/2;t.clearRect(0,0,e.width,e.height);for(let y=0;y<l.length;y++){let u=y*(r+s);if(u+r>e.width)break;let v=l[y]*d*.9,k=Math.floor(v/(p+m));t.fillStyle=u<f?o.progressColor:o.color;for(let b=0;b<k;b++){let w=b*(p+m);t.fillRect(u,c-w-p,r,p),b>0&&t.fillRect(u,c+w,r,p)}}}function $(t,e,i,a,o){let n=window.devicePixelRatio||1,r=(o.barWidth||2)*n,s=(o.barSpacing||3)*n,h=Math.floor(e.width/(r+s)),l=S(i,h),d=e.height,p=Math.max(1.5*n,r/2),m=a*e.width,f=d/2;t.clearRect(0,0,e.width,e.height);for(let c=0;c<l.length;c++){let y=c*(r+s)+r/2;if(y>e.width)break;let u=l[c]*d*.9;t.fillStyle=y<m?o.progressColor:o.color,t.beginPath(),t.arc(y,f-u/2,p,0,Math.PI*2),t.fill(),t.beginPath(),t.arc(y,f+u/2,p,0,Math.PI*2),t.fill()}}function U(t,e,i,a,o){let n=e.width,r=e.height,s=r/2,h=4,l=h/2;if(t.clearRect(0,0,n,r),t.fillStyle=o.color||"rgba(255, 255, 255, 0.2)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(n-l,s-h/2),t.arc(n-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),a>0){let d=Math.max(l*2,a*n);t.shadowBlur=8,t.shadowColor=o.progressColor,t.fillStyle=o.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.moveTo(l,s-h/2),t.lineTo(d-l,s-h/2),t.arc(d-l,s,h/2,-Math.PI/2,Math.PI/2),t.lineTo(l,s+h/2),t.arc(l,s,h/2,Math.PI/2,-Math.PI/2),t.closePath(),t.fill(),t.shadowBlur=0;let p=8,m=d;t.shadowBlur=4,t.shadowColor="rgba(0, 0, 0, 0.3)",t.shadowOffsetY=2,t.fillStyle="#ffffff",t.beginPath(),t.arc(m,s,p,0,Math.PI*2),t.fill(),t.shadowBlur=0,t.shadowOffsetY=0,t.fillStyle=o.progressColor||"rgba(255, 255, 255, 0.9)",t.beginPath(),t.arc(m,s,p*.4,0,Math.PI*2),t.fill()}}var F={bars:x,mirror:z,line:H,blocks:q,dots:$,seekbar:U};function B(t,e,i,a,o){(F[o.waveformStyle]||x)(t,e,i,a,o)}function W(t){try{let e=t.getChannelData(0),i=t.sampleRate,a=N(e,i);if(a.length<2)return 120;let o=[];for(let h=1;h<a.length;h++)o.push((a[h]-a[h-1])/i);let n={};o.forEach(h=>{let l=60/h,d=Math.round(l/3)*3;d>60&&d<200&&(n[d]=(n[d]||0)+1)});let r=0,s=120;for(let[h,l]of Object.entries(n))l>r&&(r=l,s=parseInt(h));return s<70&&n[s*2]?s*=2:s>160&&n[Math.round(s/2)]&&(s=Math.round(s/2)),s-1}catch(e){return console.warn("BPM detection failed:",e),null}}function N(t,e){let o=[],n=0;for(let r=0;r<t.length-2048;r+=1024){let s=0;for(let d=r;d<r+2048;d++)s+=t[d]*t[d];s=s/2048;let h=s-n,l=n*1.8+.01;if(h>l&&s>.01){let d=o[o.length-1]||0,p=e*.15;r-d>p&&o.push(r)}n=s*.8+n*.2}return o}function Y(t,e=200){let i=t.length/e,a=~~(i/10)||1,o=t.numberOfChannels,n=[];for(let s=0;s<o;s++){let h=t.getChannelData(s);for(let l=0;l<e;l++){let d=~~(l*i),p=~~(d+i),m=0,f=0;for(let y=d;y<p;y+=a){let u=h[y];u>f&&(f=u),u<m&&(m=u)}let c=Math.max(Math.abs(f),Math.abs(m));(s===0||c>n[l])&&(n[l]=c)}}let r=Math.max(...n);return r>0?n.map(s=>s/r):n}async function M(t,e=200,i=!1){try{let a=new(window.AudioContext||window.webkitAudioContext),n=await(await fetch(t)).arrayBuffer(),r=await a.decodeAudioData(n),s=Y(r,e);s=j(s);let h=null;return i&&(h=await W(r)),a.close(),{peaks:s,bpm:h}}catch(a){throw console.error("Failed to generate waveform:",a),a}}function I(t=200){let e=[];for(let i=0;i<t;i++){let a=Math.random()*.5+.3,o=Math.sin(i/t*Math.PI*4)*.2;e.push(Math.max(.1,Math.min(1,a+o)))}return e}function j(t,e=.95){let i=Math.max(...t);if(i===0||i>e)return t;let a=e/i;return t.map(o=>o*a)}var D={url:"",height:60,samples:200,preload:"metadata",playbackRate:1,showPlaybackSpeed:!1,playbackRates:[.5,.75,1,1.25,1.5,1.75,2],buttonAlign:"auto",waveformStyle:"mirror",barWidth:2,barSpacing:0,colorPreset:"dark",waveformColor:null,progressColor:null,buttonColor:null,buttonHoverColor:null,textColor:null,textSecondaryColor:null,backgroundColor:null,borderColor:null,autoplay:!1,showTime:!0,showHoverTime:!1,showBPM:!1,singlePlay:!0,playOnSeek:!0,enableMediaSession:!0,markers:[],showMarkers:!0,title:null,subtitle:null,artwork:null,album:"",playIcon:'<svg viewBox="0 0 24 24" width="16" height="16"><path d="M8 5v14l11-7z"/></svg>',pauseIcon:'<svg viewBox="0 0 24 24" width="16" height="16"><path d="M6 4h4v16H6zM14 4h4v16h-4z"/></svg>',onLoad:null,onPlay:null,onPause:null,onEnd:null,onError:null,onTimeUpdate:null},O={bars:{barWidth:3,barSpacing:1},mirror:{barWidth:2,barSpacing:0},line:{barWidth:2,barSpacing:0},blocks:{barWidth:4,barSpacing:2},dots:{barWidth:3,barSpacing:3},seekbar:{barWidth:1,barSpacing:0}};var g=class t{static instances=new Map;static currentlyPlaying=null;constructor(e,i={}){if(this.container=typeof e=="string"?document.querySelector(e):e,!this.container)throw new Error("WaveformPlayer: Container element not found");let a=T(this.container);this.options=P(D,a,i);let o=O[this.options.waveformStyle];o&&(a.barWidth===void 0&&i.barWidth===void 0&&(this.options.barWidth=o.barWidth),a.barSpacing===void 0&&i.barSpacing===void 0&&(this.options.barSpacing=o.barSpacing)),this.options.waveformColor=this.options.waveformColor||"rgba(255, 255, 255, 0.3)",this.options.progressColor=this.options.progressColor||"rgba(255, 255, 255, 0.9)",this.options.buttonColor=this.options.buttonColor||"rgba(255, 255, 255, 0.9)",this.options.textColor=this.options.textColor||"#ffffff",this.options.textSecondaryColor=this.options.textSecondaryColor||"rgba(255, 255, 255, 0.6)",this.audio=null,this.canvas=null,this.ctx=null,this.waveformData=[],this.progress=0,this.isPlaying=!1,this.isLoading=!1,this.hasError=!1,this.updateTimer=null,this.resizeObserver=null,this.id=this.container.id||R(this.options.url),t.instances.set(this.id,this),this.init(),setTimeout(()=>{this.container.dispatchEvent(new CustomEvent("waveformplayer:ready",{detail:{player:this,url:this.options.url}}))},100)}init(){this.createDOM(),this.createAudio(),this.initPlaybackSpeed(),this.initKeyboardControls(),this.bindEvents(),this.setupResizeObserver(),requestAnimationFrame(()=>{this.resizeCanvas(),this.options.url&&this.load(this.options.url).then(()=>{this.options.autoplay&&this.play()}).catch(e=>{console.error("Failed to load audio:",e)})})}createDOM(){this.container.innerHTML="",this.container.className="waveform-player";let e=this.options.buttonAlign;e==="auto"&&(this.options.waveformStyle==="bars"?e="bottom":e="center"),this.container.innerHTML=`
2
2
  <div class="waveform-player-inner">
3
3
  <div class="waveform-body">
4
4
  <div class="waveform-track waveform-align-${e}">
@@ -46,7 +46,7 @@
46
46
  <span class="speed-value">1x</span>
47
47
  </button>
48
48
  <div class="speed-menu" style="display: none;">
49
- ${this.options.playbackRates.map(o=>`<button class="speed-option" data-rate="${o}">${o}x</button>`).join("")}
49
+ ${this.options.playbackRates.map(i=>`<button class="speed-option" data-rate="${i}">${i}x</button>`).join("")}
50
50
  </div>
51
51
  </div>
52
52
  `:""}
@@ -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"),o=this.container.querySelector(".speed-menu");!e||!o||(e.addEventListener("click",a=>{a.stopPropagation(),o.style.display=o.style.display==="none"?"block":"none"}),document.addEventListener("click",()=>{o.style.display="none"}),o.addEventListener("click",a=>{if(a.stopPropagation(),a.target.classList.contains("speed-option")){let i=parseFloat(a.target.dataset.rate);this.setPlaybackRate(i),o.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 o=e.key,a=this.audio.currentTime;if(o>="0"&&o<="9"){e.preventDefault(),this.seekToPercent(parseInt(o)/10);return}let i={" ":()=>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};i[o]&&(e.preventDefault(),i[o]())})}initMediaSession(){!("mediaSession"in navigator)||!this.options.enableMediaSession||(navigator.mediaSession.metadata=new MediaMetadata({title:this.options.title||"Unknown Track",artist:this.options.subtitle||"",album:this.options.album||"",artwork:this.options.artwork?[{src:this.options.artwork,sizes:"512x512",type:"image/jpeg"}]:[]}),navigator.mediaSession.setActionHandler("play",()=>this.play()),navigator.mediaSession.setActionHandler("pause",()=>this.pause()),navigator.mediaSession.setActionHandler("seekbackward",()=>{this.seekTo(Math.max(0,this.audio.currentTime-10))}),navigator.mediaSession.setActionHandler("seekforward",()=>{this.seekTo(Math.min(this.audio.duration,this.audio.currentTime+10))}),navigator.mediaSession.setActionHandler("seekto",e=>{e.seekTime!==null&&this.seekTo(e.seekTime)}))}bindEvents(){this.playBtn.addEventListener("click",()=>this.togglePlay()),this.audio.addEventListener("loadstart",()=>this.setLoading(!0)),this.audio.addEventListener("loadedmetadata",()=>this.onMetadataLoaded()),this.audio.addEventListener("canplay",()=>this.setLoading(!1)),this.audio.addEventListener("play",()=>this.onPlay()),this.audio.addEventListener("pause",()=>this.onPause()),this.audio.addEventListener("ended",()=>this.onEnded()),this.audio.addEventListener("error",e=>this.onError(e)),this.canvas.addEventListener("click",e=>this.handleCanvasClick(e)),window.addEventListener("resize",L(()=>this.resizeCanvas(),100))}setupResizeObserver(){"ResizeObserver"in window&&(this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.canvas?.parentElement&&this.resizeObserver.observe(this.canvas.parentElement))}async load(e){try{this.setLoading(!0),this.progress=0,this.hasError=!1,this.audio.src=e,await new Promise((a,i)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),a()},r=s=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),i(s)};this.audio.addEventListener("loadedmetadata",n),this.audio.addEventListener("error",r)});let o=this.options.title||A(e);if(this.titleEl&&(this.titleEl.textContent=o),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=I(this.options.samples)}this.drawWaveform(),this.renderMarkers(),this.initMediaSession(),this.options.onLoad&&this.options.onLoad(this)}catch(o){console.error("Failed to load audio:",o),this.onError(o)}finally{this.setLoading(!1)}}async loadTrack(e,o=null,a=null,i={}){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:o||this.options.title,subtitle:a||this.options.subtitle,...i}),i.preload&&(this.audio.preload=i.preload),this.subtitleEl&&(a?(this.subtitleEl.textContent=a,this.subtitleEl.style.display=""):a===""&&(this.subtitleEl.style.display="none")),i.artwork&&this.artworkEl&&(this.artworkEl.src=i.artwork),i.markers&&(this.options.markers=i.markers),await this.load(e),this.play()}setWaveformData(e){if(typeof e=="string")try{let o=JSON.parse(e);this.waveformData=Array.isArray(o)?o:[]}catch{this.waveformData=e.split(",").map(Number)}else this.waveformData=Array.isArray(e)?e:[];this.drawWaveform()}drawWaveform(){!this.ctx||this.waveformData.length===0||B(this.ctx,this.canvas,this.waveformData,this.progress,{...this.options,waveformStyle:this.options.waveformStyle||"bars",color:this.options.waveformColor,progressColor:this.options.progressColor})}resizeCanvas(){let e=window.devicePixelRatio||1,o=this.canvas.getBoundingClientRect();this.canvas.width=o.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,o)=>{let a=e.time/this.audio.duration*100,i=document.createElement("button");i.className="waveform-marker",i.style.left=`${a}%`,i.style.backgroundColor=e.color||"rgba(255, 255, 255, 0.5)",i.setAttribute("aria-label",e.label),i.setAttribute("data-time",e.time);let n=document.createElement("span");n.className="waveform-marker-tooltip",n.textContent=e.label,i.appendChild(n),i.addEventListener("click",r=>{r.stopPropagation(),this.seekTo(e.time),this.options.playOnSeek&&!this.isPlaying&&this.play()}),this.markersContainer.appendChild(i)}))}handleCanvasClick(e){if(!this.audio.duration)return;let o=this.canvas.getBoundingClientRect(),a=e.clientX-o.left,i=Math.max(0,Math.min(1,a/o.width));this.seekToPercent(i)}setLoading(e){this.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none")}onMetadataLoaded(){this.totalTimeEl&&(this.totalTimeEl.textContent=C(this.audio.duration)),this.renderMarkers()}onPlay(){this.isPlaying=!0,this.playBtn.classList.add("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),o=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="none"),o&&(o.style.display="flex"),this.startSmoothUpdate(),this.options.onPlay&&this.options.onPlay(this)}onPause(){this.isPlaying=!1,this.playBtn.classList.remove("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),o=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="flex"),o&&(o.style.display="none"),this.stopSmoothUpdate(),this.options.onPause&&this.options.onPause(this)}onEnded(){this.progress=0,this.audio.currentTime=0,this.drawWaveform(),this.currentTimeEl&&(this.currentTimeEl.textContent="0:00"),this.onPause(),this.options.onEnd&&this.options.onEnd(this)}onError(e){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.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 o=this.audio.playbackRate;e.textContent=o===1?"1x":`${o}x`}this.container.querySelectorAll(".speed-option").forEach(o=>{o.classList.toggle("active",parseFloat(o.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 o=Math.max(.5,Math.min(2,e));this.audio.playbackRate=o,this.options.playbackRate=o,this.updateSpeedUI()}destroy(){this.pause(),this.stopSmoothUpdate(),this.resizeObserver&&this.resizeObserver.disconnect(),t.instances.delete(this.id),this.audio&&(this.audio.src=""),this.container.innerHTML=""}static getInstance(e){if(typeof e=="string"){let o=this.instances.get(e);if(o)return o;let a=document.getElementById(e);if(a)return Array.from(this.instances.values()).find(i=>i.container===a)}if(e instanceof HTMLElement)return Array.from(this.instances.values()).find(o=>o.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,o=200){try{return(await M(e,o)).peaks}catch(a){throw console.error("Failed to generate waveform:",a),a}}};function E(){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(o){console.error("Failed to initialize WaveformPlayer:",o,e)}})}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",E):E());g.init=E;typeof window<"u"&&(window.WaveformPlayer=g);var st=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 o=parseFloat(a.target.dataset.rate);this.setPlaybackRate(o),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 o={" ":()=>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};o[i]&&(e.preventDefault(),o[i]())})}initMediaSession(){!("mediaSession"in navigator)||!this.options.enableMediaSession||(navigator.mediaSession.metadata=new MediaMetadata({title:this.options.title||"Unknown Track",artist:this.options.subtitle||"",album:this.options.album||"",artwork:this.options.artwork?[{src:this.options.artwork,sizes:"512x512",type:"image/jpeg"}]:[]}),navigator.mediaSession.setActionHandler("play",()=>this.play()),navigator.mediaSession.setActionHandler("pause",()=>this.pause()),navigator.mediaSession.setActionHandler("seekbackward",()=>{this.seekTo(Math.max(0,this.audio.currentTime-10))}),navigator.mediaSession.setActionHandler("seekforward",()=>{this.seekTo(Math.min(this.audio.duration,this.audio.currentTime+10))}),navigator.mediaSession.setActionHandler("seekto",e=>{e.seekTime!==null&&this.seekTo(e.seekTime)}))}bindEvents(){this.playBtn.addEventListener("click",()=>this.togglePlay()),this.audio.addEventListener("loadstart",()=>this.setLoading(!0)),this.audio.addEventListener("loadedmetadata",()=>this.onMetadataLoaded()),this.audio.addEventListener("canplay",()=>this.setLoading(!1)),this.audio.addEventListener("play",()=>this.onPlay()),this.audio.addEventListener("pause",()=>this.onPause()),this.audio.addEventListener("ended",()=>this.onEnded()),this.audio.addEventListener("error",e=>this.onError(e)),this.canvas.addEventListener("click",e=>this.handleCanvasClick(e)),window.addEventListener("resize",L(()=>this.resizeCanvas(),100))}setupResizeObserver(){"ResizeObserver"in window&&(this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.canvas?.parentElement&&this.resizeObserver.observe(this.canvas.parentElement))}async load(e){try{this.setLoading(!0),this.progress=0,this.hasError=!1,this.audio.src=e,await new Promise((a,o)=>{let n=()=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),a()},r=s=>{this.audio.removeEventListener("loadedmetadata",n),this.audio.removeEventListener("error",r),o(s)};this.audio.addEventListener("loadedmetadata",n),this.audio.addEventListener("error",r)});let i=this.options.title||A(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=I(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,o={}){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:a||this.options.subtitle,...o}),o.preload&&(this.audio.preload=o.preload),this.subtitleEl&&(a?(this.subtitleEl.textContent=a,this.subtitleEl.style.display=""):a===""&&(this.subtitleEl.style.display="none")),o.artwork&&this.artworkEl&&(this.artworkEl.src=o.artwork),o.markers&&(this.options.markers=o.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||B(this.ctx,this.canvas,this.waveformData,this.progress,{...this.options,waveformStyle:this.options.waveformStyle||"bars",color:this.options.waveformColor,progressColor:this.options.progressColor})}resizeCanvas(){let e=window.devicePixelRatio||1,i=this.canvas.getBoundingClientRect();this.canvas.width=i.width*e,this.canvas.height=this.options.height*e,this.canvas.style.height=this.options.height+"px",this.canvas.parentElement.style.height=this.options.height+"px",this.drawWaveform()}renderMarkers(){!this.options.showMarkers||!this.options.markers?.length||!this.markersContainer||(this.markersContainer.innerHTML="",!(!this.audio||!this.audio.duration||this.audio.duration===0)&&this.options.markers.forEach((e,i)=>{if(e.time>this.audio.duration){console.warn(`Marker "${e.label}" at ${e.time}s exceeds audio duration of ${this.audio.duration}s`);return}let a=e.time/this.audio.duration*100,o=document.createElement("button");o.className="waveform-marker",o.style.left=`${a}%`,o.style.backgroundColor=e.color||"rgba(255, 255, 255, 0.5)",o.setAttribute("aria-label",e.label),o.setAttribute("data-time",e.time);let n=document.createElement("span");n.className="waveform-marker-tooltip",n.textContent=e.label,o.appendChild(n),o.addEventListener("click",r=>{r.stopPropagation(),this.seekTo(e.time),this.options.playOnSeek&&!this.isPlaying&&this.play()}),this.markersContainer.appendChild(o)}))}handleCanvasClick(e){if(!this.audio.duration)return;let i=this.canvas.getBoundingClientRect(),a=e.clientX-i.left,o=Math.max(0,Math.min(1,a/i.width));this.seekToPercent(o)}setLoading(e){this.isLoading=e,this.loadingEl&&(this.loadingEl.style.display=e?"block":"none")}onMetadataLoaded(){this.totalTimeEl&&(this.totalTimeEl.textContent=C(this.audio.duration)),this.renderMarkers()}onPlay(){this.isPlaying=!0,this.playBtn.classList.add("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="none"),i&&(i.style.display="flex"),this.startSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:play",{detail:{player:this,url:this.options.url}})),this.options.onPlay&&this.options.onPlay(this)}onPause(){this.isPlaying=!1,this.playBtn.classList.remove("playing");let e=this.playBtn.querySelector(".waveform-icon-play"),i=this.playBtn.querySelector(".waveform-icon-pause");e&&(e.style.display="flex"),i&&(i.style.display="none"),this.stopSmoothUpdate(),this.container.dispatchEvent(new CustomEvent("waveformplayer:pause",{detail:{player:this,url:this.options.url}})),this.options.onPause&&this.options.onPause(this)}onEnded(){this.progress=0,this.audio.currentTime=0,this.drawWaveform(),this.currentTimeEl&&(this.currentTimeEl.textContent="0:00"),this.container.dispatchEvent(new CustomEvent("waveformplayer:ended",{detail:{player:this,url:this.options.url}})),this.onPause(),this.options.onEnd&&this.options.onEnd(this)}onError(e){this.isDestroying||(console.error("Audio error:",e),this.hasError=!0,this.setLoading(!1),this.errorEl&&(this.errorEl.style.display="flex"),this.canvas&&(this.canvas.style.opacity="0.2"),this.playBtn&&(this.playBtn.disabled=!0),this.options.onError&&this.options.onError(e,this))}startSmoothUpdate(){this.stopSmoothUpdate();let e=()=>{this.isPlaying&&this.audio.duration&&(this.updateProgress(),this.updateTimer=requestAnimationFrame(e))};this.updateTimer=requestAnimationFrame(e)}stopSmoothUpdate(){this.updateTimer&&(cancelAnimationFrame(this.updateTimer),this.updateTimer=null)}updateProgress(){if(!this.audio.duration)return;let e=this.audio.currentTime/this.audio.duration;Math.abs(e-this.progress)>.001&&(this.progress=e,this.drawWaveform()),this.currentTimeEl&&(this.currentTimeEl.textContent=C(this.audio.currentTime)),this.container.dispatchEvent(new CustomEvent("waveformplayer:timeupdate",{detail:{player:this,currentTime:this.audio.currentTime,duration:this.audio.duration,url:this.options.url}})),this.options.onTimeUpdate&&this.options.onTimeUpdate(this.audio.currentTime,this.audio.duration,this)}updateBPMDisplay(){this.bpmEl&&this.bpmValueEl&&this.detectedBPM&&(this.bpmValueEl.textContent=Math.round(this.detectedBPM),this.bpmEl.style.display="inline-flex")}updateSpeedUI(){let e=this.container.querySelector(".speed-value");if(e){let i=this.audio.playbackRate;e.textContent=i===1?"1x":`${i}x`}this.container.querySelectorAll(".speed-option").forEach(i=>{i.classList.toggle("active",parseFloat(i.dataset.rate)===this.audio.playbackRate)})}play(){this.options.singlePlay&&t.currentlyPlaying&&t.currentlyPlaying!==this&&t.currentlyPlaying.pause(),t.currentlyPlaying=this,this.audio.play()}pause(){t.currentlyPlaying===this&&(t.currentlyPlaying=null),this.audio.pause()}togglePlay(){this.isPlaying?this.pause():this.play()}seekTo(e){this.audio&&this.audio.duration&&(this.audio.currentTime=Math.max(0,Math.min(e,this.audio.duration)),this.updateProgress())}seekToPercent(e){this.audio&&this.audio.duration&&(this.audio.currentTime=this.audio.duration*Math.max(0,Math.min(1,e)),this.updateProgress())}setVolume(e){this.audio&&(this.audio.volume=Math.max(0,Math.min(1,e)))}setPlaybackRate(e){if(!this.audio)return;let i=Math.max(.5,Math.min(2,e));this.audio.playbackRate=i,this.options.playbackRate=i,this.updateSpeedUI()}destroy(){this.isDestroying=!0,this.pause(),this.stopSmoothUpdate(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),t.instances.delete(this.id),t.currentlyPlaying===this&&(t.currentlyPlaying=null),this.audio&&(this.audio.pause(),this.audio.src="",this.audio.load(),this.audio=null),this.container.innerHTML="",this.canvas=null,this.ctx=null,this.playBtn=null,this.waveformData=[]}static getInstance(e){if(typeof e=="string"){let i=this.instances.get(e);if(i)return i;let a=document.getElementById(e);if(a)return Array.from(this.instances.values()).find(o=>o.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 E(){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",E):E());g.init=E;typeof window<"u"&&(window.WaveformPlayer=g);var st=g;})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arraypress/waveform-player",
3
- "version": "1.1.1",
3
+ "version": "1.1.4",
4
4
  "description": "Lightweight, customizable audio player with waveform visualization",
5
5
  "main": "dist/waveform-player.js",
6
6
  "module": "dist/waveform-player.esm.js",
@@ -17,11 +17,12 @@
17
17
  "build:iife": "esbuild src/js/index.js --bundle --format=iife --outfile=dist/waveform-player.js",
18
18
  "build:min": "esbuild src/js/index.js --bundle --format=iife --outfile=dist/waveform-player.min.js --minify",
19
19
  "build:esm": "esbuild src/js/index.js --bundle --format=esm --outfile=dist/waveform-player.esm.js --minify",
20
- "build:demo": "npm run build:css && mkdir -p demo/dist && cp dist/*.js demo/dist/ 2>/dev/null || true && cp dist/*.css demo/dist/",
20
+ "build:demo": "mkdir -p demo/dist && cp -r dist/* demo/dist/",
21
21
  "dev": "npm run build:css && esbuild src/js/index.js --bundle --format=iife --outfile=dist/waveform-player.js --watch",
22
22
  "dev:css": "esbuild src/css/waveform-player.css --outfile=dist/waveform-player.css --watch",
23
- "dev:all": "npm run build:css && npm run build:demo && concurrently \"npm run dev\" \"npm run dev:css\"",
23
+ "dev:demo": "npm run build:css && npm run build:demo && concurrently \"npm run dev\" \"npm run dev:css\"",
24
24
  "size": "npm run build:min && npm run build:css && echo 'JS:' && gzip -c dist/waveform-player.min.js | wc -c && echo 'CSS:' && gzip -c dist/waveform-player.css | wc -c",
25
+ "serve": "npx http-server -p 8000",
25
26
  "prepublishOnly": "npm run build"
26
27
  },
27
28
  "keywords": [
package/src/js/core.js CHANGED
@@ -86,6 +86,13 @@ export class WaveformPlayer {
86
86
 
87
87
  // Initialize
88
88
  this.init();
89
+
90
+ // Dispatch ready event after initialization
91
+ setTimeout(() => {
92
+ this.container.dispatchEvent(new CustomEvent('waveformplayer:ready', {
93
+ detail: { player: this, url: this.options.url }
94
+ }));
95
+ }, 100);
89
96
  }
90
97
 
91
98
  // ============================================
@@ -645,6 +652,12 @@ export class WaveformPlayer {
645
652
 
646
653
  // Add each marker
647
654
  this.options.markers.forEach((marker, index) => {
655
+ // Skip markers that are beyond the audio duration
656
+ if (marker.time > this.audio.duration) {
657
+ console.warn(`Marker "${marker.label}" at ${marker.time}s exceeds audio duration of ${this.audio.duration}s`);
658
+ return;
659
+ }
660
+
648
661
  const position = (marker.time / this.audio.duration) * 100;
649
662
 
650
663
  const markerEl = document.createElement('button');
@@ -729,6 +742,11 @@ export class WaveformPlayer {
729
742
 
730
743
  this.startSmoothUpdate();
731
744
 
745
+ // Dispatch play event
746
+ this.container.dispatchEvent(new CustomEvent('waveformplayer:play', {
747
+ detail: { player: this, url: this.options.url }
748
+ }));
749
+
732
750
  if (this.options.onPlay) {
733
751
  this.options.onPlay(this);
734
752
  }
@@ -749,6 +767,11 @@ export class WaveformPlayer {
749
767
 
750
768
  this.stopSmoothUpdate();
751
769
 
770
+ // Dispatch pause event
771
+ this.container.dispatchEvent(new CustomEvent('waveformplayer:pause', {
772
+ detail: { player: this, url: this.options.url }
773
+ }));
774
+
752
775
  if (this.options.onPause) {
753
776
  this.options.onPause(this);
754
777
  }
@@ -768,6 +791,11 @@ export class WaveformPlayer {
768
791
  this.currentTimeEl.textContent = '0:00';
769
792
  }
770
793
 
794
+ // Dispatch ended event
795
+ this.container.dispatchEvent(new CustomEvent('waveformplayer:ended', {
796
+ detail: { player: this, url: this.options.url }
797
+ }));
798
+
771
799
  this.onPause();
772
800
 
773
801
  if (this.options.onEnd) {
@@ -780,6 +808,9 @@ export class WaveformPlayer {
780
808
  * @private
781
809
  */
782
810
  onError(error) {
811
+ // Ignore errors during destruction
812
+ if (this.isDestroying) return;
813
+
783
814
  console.error('Audio error:', error);
784
815
  this.hasError = true;
785
816
  this.setLoading(false);
@@ -851,6 +882,16 @@ export class WaveformPlayer {
851
882
  this.currentTimeEl.textContent = formatTime(this.audio.currentTime);
852
883
  }
853
884
 
885
+ // Dispatch timeupdate event
886
+ this.container.dispatchEvent(new CustomEvent('waveformplayer:timeupdate', {
887
+ detail: {
888
+ player: this,
889
+ currentTime: this.audio.currentTime,
890
+ duration: this.audio.duration,
891
+ url: this.options.url
892
+ }
893
+ }));
894
+
854
895
  if (this.options.onTimeUpdate) {
855
896
  this.options.onTimeUpdate(this.audio.currentTime, this.audio.duration, this);
856
897
  }
@@ -976,20 +1017,43 @@ export class WaveformPlayer {
976
1017
  * Destroy player instance
977
1018
  */
978
1019
  destroy() {
1020
+ // Set a flag to indicate we're destroying
1021
+ this.isDestroying = true;
1022
+
1023
+ // Stop playback and animations
979
1024
  this.pause();
980
1025
  this.stopSmoothUpdate();
981
1026
 
1027
+ // Disconnect observer
982
1028
  if (this.resizeObserver) {
983
1029
  this.resizeObserver.disconnect();
1030
+ this.resizeObserver = null;
984
1031
  }
985
1032
 
1033
+ // Remove from instances map
986
1034
  WaveformPlayer.instances.delete(this.id);
987
1035
 
1036
+ // Clear current playing reference if it's this instance
1037
+ if (WaveformPlayer.currentlyPlaying === this) {
1038
+ WaveformPlayer.currentlyPlaying = null;
1039
+ }
1040
+
1041
+ // Properly clean up audio element
988
1042
  if (this.audio) {
1043
+ this.audio.pause();
989
1044
  this.audio.src = '';
1045
+ this.audio.load(); // Reset the audio element
1046
+ this.audio = null;
990
1047
  }
991
1048
 
1049
+ // Clear the container
992
1050
  this.container.innerHTML = '';
1051
+
1052
+ // Clear all references
1053
+ this.canvas = null;
1054
+ this.ctx = null;
1055
+ this.playBtn = null;
1056
+ this.waveformData = [];
993
1057
  }
994
1058
 
995
1059
  // ============================================
@@ -1051,4 +1115,5 @@ export class WaveformPlayer {
1051
1115
  throw error;
1052
1116
  }
1053
1117
  }
1118
+
1054
1119
  }