kashi
Version:
Singing at the top of my lungs
1 lines • 5.4 kB
JavaScript
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i=t();for(var s in i)("object"==typeof exports?exports:e)[s]=i[s]}}(self,()=>(()=>{"use strict";var e={d:(t,i)=>{for(var s in i)e.o(i,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:i[s]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{Kashi:()=>v});const i=/\[\d{2}:\d{2}.\d{2}\]/,s=/^\[\d{2}:\d{2}.\d{2}\](.*)$/;var n,r,a,o,l,f,h,c,d,u,m,p,y,w=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},b=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 v{constructor(e){if(n.add(this),r.set(this,[]),a.set(this,[]),o.set(this,void 0),l.set(this,new Map),f.set(this,void 0),h.set(this,null),c.set(this,!1),d.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&&(w(this,h,e.audioPlayer,"f"),b(this,h,"f").addEventListener("timeupdate",()=>{b(this,n,"m",y).call(this)}),b(this,h,"f").addEventListener("seeked",()=>{b(this,o,"f").querySelectorAll("div[data-ms-time]").forEach(e=>{e instanceof HTMLDivElement&&(e.dataset.ariaCurrent="false")}),b(this,n,"m",y).call(this)})),e.enableAutoScroll&&w(this,c,e.enableAutoScroll,"f"),w(this,o,e.container,"f"),this.subscribe("filesSet",b(this,n,"m",p).bind(this)),this.subscribe("emptyLineTextSet",b(this,n,"m",p).bind(this)),this.subscribe("lyricsLinesUpdated",b(this,n,"m",y).bind(this)),this.setFiles(e.files)}get files(){return b(this,r,"f")}get emptyLineText(){return b(this,f,"f")??"..."}get noLyricsText(){return b(this,d,"f")}async setFiles(e=[]){if(e.length>0){const t=e.map(e=>e?b(this,n,"m",u).call(this,e):Promise.resolve("")),i=await Promise.all(t);w(this,a,i.map(e=>b(this,n,"m",m).call(this,e)),"f")}else w(this,a,[],"f");w(this,r,e,"f"),this.notify("filesSet",{files:e})}setEmptyLineText(e){w(this,f,e,"f"),this.notify("emptyLineTextSet",{emptyLineText:e})}setNoLyricsText(e){w(this,d,e,"f"),this.notify("noLyricsTextSet",{noLyricsText:e})}subscribe(e,t){b(this,l,"f").set(e,[...b(this,l,"f").get(e)??[],t])}unsubscribe(e,t){const i=b(this,l,"f").get(e);i&&i.length>1?b(this,l,"f").set(e,[...i.filter(e=>e!==t)]):b(this,l,"f").delete(e)}notify(e,t){[...b(this,l,"f").get(e)??[]].forEach(e=>{e(t)})}}return r=new WeakMap,a=new WeakMap,o=new WeakMap,l=new WeakMap,f=new WeakMap,h=new WeakMap,c=new WeakMap,d=new WeakMap,n=new WeakSet,u=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)})},m=function(e){const t=e.split("\n").reduce((e,t)=>{const i=t.trim();return s.test(i)?[...e,i]:e},[]);if(0===t.length)throw new Error("No valid lyric lines found in the file.");return t},p=function(){const e=b(this,a,"f").length,t=b(this,a,"f")[0]?.length??0;if(!b(this,a,"f").every(e=>e.length===t))throw new Error("All lyric files must have the same number of lines.");let s="";for(let n=0;n<t;n++){const t=[],r=[];for(let s=0;s<e;s++){const e=b(this,a,"f")[s][n],o=e.replace(i,"");r.push(o);const l=e.match(i)?.[0]?.slice(1,-1);t.push(l)}if(new Set(t).size>1)throw new Error(`Timestamp mismatch at line ${n+1} across files}`);const o=t[0],l=o.split(":"),h=l[1].split("."),c=60*parseInt(l[0],10)*1e3+1e3*parseInt(h[0],10)+10*parseInt(h[1],10),d=r.every(e=>0===e.length);s+=`\n <div\n data-time="${o}"\n data-ms-time="${c}"\n data-empty="${d}"\n data-aria-current="false"\n >\n ${(d?"":r.map(e=>`<span>${e}</span>`).join("<br/>"))||(b(this,f,"f")??"...")}\n </div>\n `}b(this,o,"f").innerHTML=s.length?s:`\n <div>\n <span data-no-lyrics="true">\n ${b(this,d,"f")??""}\n </span>\n </div>\n `,this.notify("lyricsLinesUpdated",{lyricsLines:b(this,a,"f")})},y=function(){if(!b(this,h,"f")||!b(this,a,"f").length||b(this,a,"f").some(e=>0===e.length))return;const e=1e3*b(this,h,"f").currentTime,t=b(this,o,"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",b(this,c,"f")&&i.scrollIntoView({behavior:"smooth",block:"center"}))},t})());