UNPKG

kashi

Version:

Singing at the top of my lungs

1 lines 4.8 kB
const e=/\[\d{2}:\d{2}.\d{2}\]/,t=/^\[\d{2}:\d{2}.\d{2}\](.*)$/;var i,s,n,r,a,o,l,h,f,c,d,u,m,p=function(e,t,i,s,n){if("m"===s)throw new TypeError("Private method is not writable");if("a"===s&&!n)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!n:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===s?n.call(e,i):n?n.value=i:t.set(e,i),i},w=function(e,t,i,s){if("a"===i&&!s)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!s:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===i?s:"a"===i?s.call(e):s?s.value:t.get(e)};class y{constructor(e){if(i.add(this),s.set(this,[]),n.set(this,[]),r.set(this,void 0),a.set(this,new Map),o.set(this,void 0),l.set(this,null),h.set(this,!1),f.set(this,void 0),!(e.container&&e.container instanceof HTMLDivElement))throw new Error("Container must be an instance of HTMLDivElement.");if(e.emptyLineText&&this.setEmptyLineText(e.emptyLineText),e.audioPlayer&&!(e.audioPlayer instanceof HTMLAudioElement))throw new Error("Audio player must be an instance of HTMLAudioElement.");e.audioPlayer&&(p(this,l,e.audioPlayer,"f"),w(this,l,"f").addEventListener("timeupdate",()=>{w(this,i,"m",m).call(this)}),w(this,l,"f").addEventListener("seeked",()=>{w(this,r,"f").querySelectorAll("div[data-ms-time]").forEach(e=>{e instanceof HTMLDivElement&&(e.dataset.ariaCurrent="false")}),w(this,i,"m",m).call(this)})),e.enableAutoScroll&&p(this,h,e.enableAutoScroll,"f"),p(this,r,e.container,"f"),this.subscribe("filesSet",w(this,i,"m",u).bind(this)),this.subscribe("emptyLineTextSet",w(this,i,"m",u).bind(this)),this.subscribe("lyricsLinesUpdated",w(this,i,"m",m).bind(this)),this.setFiles(e.files)}get files(){return w(this,s,"f")}get emptyLineText(){return w(this,o,"f")??"..."}get noLyricsText(){return w(this,f,"f")}async setFiles(e=[]){if(e.length>0){const t=e.map(e=>e?w(this,i,"m",c).call(this,e):Promise.resolve("")),s=await Promise.all(t);p(this,n,s.map(e=>w(this,i,"m",d).call(this,e)),"f")}else p(this,n,[],"f");p(this,s,e,"f"),this.notify("filesSet",{files:e})}setEmptyLineText(e){p(this,o,e,"f"),this.notify("emptyLineTextSet",{emptyLineText:e})}setNoLyricsText(e){p(this,f,e,"f"),this.notify("noLyricsTextSet",{noLyricsText:e})}subscribe(e,t){w(this,a,"f").set(e,[...w(this,a,"f").get(e)??[],t])}unsubscribe(e,t){const i=w(this,a,"f").get(e);i&&i.length>1?w(this,a,"f").set(e,[...i.filter(e=>e!==t)]):w(this,a,"f").delete(e)}notify(e,t){[...w(this,a,"f").get(e)??[]].forEach(e=>{e(t)})}}s=new WeakMap,n=new WeakMap,r=new WeakMap,a=new WeakMap,o=new WeakMap,l=new WeakMap,h=new WeakMap,f=new WeakMap,i=new WeakSet,c=async function(e){return new Promise((t,i)=>{const s=new FileReader;s.onload=e=>{"string"==typeof e.target?.result&&e.target?.result.trim().length?t(e.target.result):i(new Error("Failed to read file content."))},s.onerror=()=>i(new Error("Error reading file.")),s.readAsText(e)})},d=function(e){const i=e.split("\n").reduce((e,i)=>{const s=i.trim();return t.test(s)?[...e,s]:e},[]);if(0===i.length)throw new Error("No valid lyric lines found in the file.");return i},u=function(){const t=w(this,n,"f").length,i=w(this,n,"f")[0]?.length??0;if(!w(this,n,"f").every(e=>e.length===i))throw new Error("All lyric files must have the same number of lines.");let s="";for(let r=0;r<i;r++){const i=[],a=[];for(let s=0;s<t;s++){const t=w(this,n,"f")[s][r],o=t.replace(e,"");a.push(o);const l=t.match(e)?.[0]?.slice(1,-1);i.push(l)}if(new Set(i).size>1)throw new Error(`Timestamp mismatch at line ${r+1} across files}`);const l=i[0],h=l.split(":"),f=h[1].split("."),c=60*parseInt(h[0],10)*1e3+1e3*parseInt(f[0],10)+10*parseInt(f[1],10),d=a.every(e=>0===e.length);s+=`\n <div\n data-time="${l}"\n data-ms-time="${c}"\n data-empty="${d}"\n data-aria-current="false"\n >\n ${(d?"":a.map(e=>`<span>${e}</span>`).join("<br/>"))||(w(this,o,"f")??"...")}\n </div>\n `}w(this,r,"f").innerHTML=s.length?s:`\n <div>\n <span data-no-lyrics="true">\n ${w(this,f,"f")??""}\n </span>\n </div>\n `,this.notify("lyricsLinesUpdated",{lyricsLines:w(this,n,"f")})},m=function(){if(!w(this,l,"f")||!w(this,n,"f").length||w(this,n,"f").some(e=>0===e.length))return;const e=1e3*w(this,l,"f").currentTime,t=w(this,r,"f").querySelectorAll("div[data-ms-time]");let i=null;for(let s=0;s<t.length;s++){const n=t[s],r=parseInt(n.getAttribute("data-ms-time")||"0",10);if(n.dataset.ariaCurrent="false",!(e>=r))break;i=n}i&&(i.dataset.ariaCurrent="true",w(this,h,"f")&&i.scrollIntoView({behavior:"smooth",block:"center"}))};export{y as Kashi};