{"_id":"kashi","_rev":"35-9e7ca7c32305ca753410b390b3d1aaf2","name":"kashi","dist-tags":{"latest":"6.0.0"},"versions":{"1.0.0":{"name":"kashi","version":"1.0.0","keywords":["lyrics","song"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@1.0.0","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"43d795a938efe0922816a16d2bff042beab1775e","tarball":"https://registry.npmjs.org/kashi/-/kashi-1.0.0.tgz","fileCount":5,"integrity":"sha512-YwbML5Yg4IwvchzVNIQa219KS1m/UQic1Lp6+0pgQxmn4iDUpzi+kKvIXUlbGxYFQ/HAySt4Bo1/RuEMMoLl+w==","signatures":[{"sig":"MEUCIGMYHqRGpu4Ar68TslS4lQhNdUH4znCLSHRH9cs0q+/oAiEA94+1NQIDmcjHVxOegzt74NtVO4+nxCWWH5jH9fmOJ6g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48525},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"63b87185047d1c132ea93aadfd93d143ab269f81","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.4.2","description":"Making the digital world a little more animated place","directories":{},"_nodeVersion":"24.4.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.4","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.0","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.4","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_1.0.0_1752335940169_0.41654676299776083","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"kashi","version":"1.0.1","keywords":["lyrics","song"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@1.0.1","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"ffabf2c4af07358cdbfa201a587b3b9562560c3c","tarball":"https://registry.npmjs.org/kashi/-/kashi-1.0.1.tgz","fileCount":5,"integrity":"sha512-VjyMK6bMyFDsnJ6FOHm9EVpHa0T57GeQm0hiDeB1I+UM/a0+/K+L/NshoGnncnpgpOYvkM6g/neaVzT2YU7Kbg==","signatures":[{"sig":"MEQCIHcSDGvW4WnVk8jEDVNIixWdStBcPf3cVyJkOmZVX2OYAiAEs4HzI24v8qH+tx404L++iOLqpf++dGL6m4U60DEeiw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48524},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"3d76f508a8f02aa66fb4993e37fbe6b855620d69","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.4.2","description":"Making the digital world a little more animated place","directories":{},"_nodeVersion":"24.4.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.4","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.0","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.4","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_1.0.1_1752336366231_0.878859518102123","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"kashi","version":"1.0.2","keywords":["lyrics","song"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@1.0.2","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"f4976630bf2d8947733d12b911294a0263be91d6","tarball":"https://registry.npmjs.org/kashi/-/kashi-1.0.2.tgz","fileCount":5,"integrity":"sha512-MMLVdWViQWkeZ4PEOBhbhRJ1IYwFI0ZZ2QUUIhdnAwbwJWrFUIafG1ae937vyOPfeT9b+AVRqUJpmLN8sc91qg==","signatures":[{"sig":"MEUCIF4UI8Gu4D8UjY/2FRF2/fRciHPk8yBKsQznoxINXkKyAiEAuWJpl/UF9qPZCc9edhR8CFU3uJ2D2AmfrgPhLYL27tY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48501},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"5267049ea8e6329c08c6483fe94e89ceae3b68a6","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.4.2","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.4.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.4","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.0","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.4","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_1.0.2_1752337661573_0.23508356527249186","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"kashi","version":"1.1.0","keywords":["lyrics","song"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@1.1.0","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"b431eb0777748d3c3a3f872ad868edbfa3a36878","tarball":"https://registry.npmjs.org/kashi/-/kashi-1.1.0.tgz","fileCount":6,"integrity":"sha512-MpGGD4KEo2DtmlLsfBnx1HF7T4JFpR1bgml/eXpF6oSiHOsw8l7hgsbQggR9uZrarMVPVaIW2xjzx5kqwHNpvA==","signatures":[{"sig":"MEQCIC+Xqd+krCHe+1Vv5MOyOplYzw4Ynhl/yoJsjL7bPOZmAiBaiUlKjJwgmH3lByjkTrt6XL6ItkvbtAcPDekduzPwdA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":50008},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"b1c5910536209ae3e2754b931b6ccaa81ab43221","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.4.2","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.4.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.4","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.0","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.4","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_1.1.0_1753198667739_0.16721514577402585","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"kashi","version":"1.1.1","keywords":["lyrics","song"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@1.1.1","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"ce5ae0c6f1fe02b9d0de001ae7a13c2c3a6c9f86","tarball":"https://registry.npmjs.org/kashi/-/kashi-1.1.1.tgz","fileCount":6,"integrity":"sha512-B0V5B362tT7L/BuA2QLLR8KfTfqIjrm0cw9GFUw8ieaol2fzngn+5pErvjvTCGYbgqNA9YeHCQUHEyUGyB6FRQ==","signatures":[{"sig":"MEUCIH/DiOBsTX4jpihbZYdkTqWOQeE1qfVdzP9wgtSyO4LrAiEAt4LXn4fC2xNKL2VSXxMxkEYG+aT3aLdWQnQYqqb/LFg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53306},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"a5cfda492887c224c83eb33a9d9e4be3b4e43a02","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.4.2","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.4.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.4","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.0","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.4","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_1.1.1_1754687155084_0.4809343098066663","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"kashi","version":"1.1.2","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@1.1.2","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"020d3c4b85e81b0aed9dab18390fe0b30857941a","tarball":"https://registry.npmjs.org/kashi/-/kashi-1.1.2.tgz","fileCount":6,"integrity":"sha512-vG7ESLtMakQGI66Ho1EEpxTeWBuVq+xKTbmuitz55WPqwfhx5C7bsDyNnkOo+yRrrsY4gSXwsWUXeP+cLsN0CQ==","signatures":[{"sig":"MEQCIDhOUiftAsECJ6YzevyecM0RD9eqe12XZcY7BsqJsNLHAiBI0DlKeaJrPG8qslP5lS7Rw4prmpya+FA/HhelJzQqSg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53816},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"59c7fa61265b18a5e7fd50e56b29def3e092df9d","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.4.2","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.4.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.5","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.1","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.5","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_1.1.2_1755277143013_0.5515205939667764","host":"s3://npm-registry-packages-npm-production"}},"1.1.3":{"name":"kashi","version":"1.1.3","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@1.1.3","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"10c6ad5684eb77d3d64c4399b799ab1a8cedff78","tarball":"https://registry.npmjs.org/kashi/-/kashi-1.1.3.tgz","fileCount":6,"integrity":"sha512-qr+hl54Ekw4JBh9Nq3QOJFGwT764d4TJnk64cis58gh/U3OOvyHIqSXY18EYLebcWQDHNLPbZUiKAVHPTIRaJw==","signatures":[{"sig":"MEQCICMrQi7ppjqBVHaijKNlmeIDoo4dj4UVg2JQhyRIxcu1AiAmWbK55VHeoTu1hMJ65YACMCWCz+HE/uwMwtWuTjWS5w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":54170},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"8ca40e98be00c1ea9710c91b32cdf547171d8330","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.5.1","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.5","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.1","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.5","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_1.1.3_1757022623090_0.7824887569374503","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"kashi","version":"2.0.0","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@2.0.0","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"7ae1bd74ca42c26615b4fcb3d9704828065b6823","tarball":"https://registry.npmjs.org/kashi/-/kashi-2.0.0.tgz","fileCount":6,"integrity":"sha512-gBzmpkxX86X6sx7aa9iOKkBnqc4UJKQeSsWz3pvrA9yuQ/lHnfSt8AYftAPHjjrLQLwD4WWkAnoofjKx+c7wnA==","signatures":[{"sig":"MEQCIERFpuFuJUog31m4QfxYRWNxVJtUtLBWY9Uc0mciuhJUAiBSF5UPfTq8iVMLA2NRBrF94W3RP0Nv9Q4y3GkY1Iwn1Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57894},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"b4eb63a8913e22016fcb9520cfcd82422cb160e2","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.5.1","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.5","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.1","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.5","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_2.0.0_1759263142950_0.8743209380531762","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"kashi","version":"3.0.0","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@3.0.0","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"366309cec15d361018ef84a0f8298bc0a81c4ccc","tarball":"https://registry.npmjs.org/kashi/-/kashi-3.0.0.tgz","fileCount":6,"integrity":"sha512-1XT9qaiQezwPow79/TxyYeZV5Q68pLbi3DPVorEOw/zyX5kbQCh0aQAtFFh1KwujZmw3yEF2yCEr9yOe8Iw1+w==","signatures":[{"sig":"MEUCIFHPnDOjy+WgzGMSEn64cZG7UInHJEEc/XRnGlyuLZ6LAiEA80Ph3kxwARVF8BXKSigncPFysCEXVGX0yPnfS9Dsk2U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":56750},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"30c0b6356d0486c27bc941550705123ffed973ea","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.5.1","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.5","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.1","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.5","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_3.0.0_1763579256424_0.8574740672975216","host":"s3://npm-registry-packages-npm-production"}},"3.0.1":{"name":"kashi","version":"3.0.1","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@3.0.1","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"966e6021c013855bb3236d7edf3f4960ec48643e","tarball":"https://registry.npmjs.org/kashi/-/kashi-3.0.1.tgz","fileCount":6,"integrity":"sha512-zDbuVFHK3ccDynIh+OuDKEuZRrcnfpH8DQrvCKOx3SOTyJJHW7WZ1uzvFbyCqcLejWdRqZ0tXoY8Zu5n+gyGnw==","signatures":[{"sig":"MEUCIAVBvntuVKZCtzKTdmOFkCTH6eD7zgmEg//CNNYlxJMhAiEA0TZtV986Br7QmKMBz+d09COAHzGulGhlIa32Po3FYFE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57933},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"2d0ceda5d83e542aaafa7b65ed47748444f7f98a","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.5.1","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.5","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.1","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.5","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_3.0.1_1763671578507_0.19568328611295205","host":"s3://npm-registry-packages-npm-production"}},"3.0.2":{"name":"kashi","version":"3.0.2","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@3.0.2","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"575859858dcfb1da0b7c6d341b73c141a34da4c0","tarball":"https://registry.npmjs.org/kashi/-/kashi-3.0.2.tgz","fileCount":6,"integrity":"sha512-kWbdl1E7h89rsRjuFhvAgUMGatBs/FsajGPs3mancP4VQANWQjc2PC0DKB2ENU8fZjX0sSt/IgiW5p/jgPvVIA==","signatures":[{"sig":"MEYCIQDNdC6U1g70W0U2jOfbAgGOW3Bj+D0laWaUU5aG76W22wIhANSHAFyPcdBXQMDMsU3MFWHFSqMvL4qHAXU1FIm60U8y","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57933},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"7ace43d511cea59069c4a25922c5a29858190470","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.5.1","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.5","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.1","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.5","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_3.0.2_1765184249401_0.057990431025276346","host":"s3://npm-registry-packages-npm-production"}},"4.0.0":{"name":"kashi","version":"4.0.0","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@4.0.0","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"a33fb6609c57e775f073a8f217799ab5e5fc9ec5","tarball":"https://registry.npmjs.org/kashi/-/kashi-4.0.0.tgz","fileCount":6,"integrity":"sha512-c/KXOG94dyJHlDkDmFfrpsIu+EYLUvDGbeDYbaBAZYJpGHK+NJM5SdT6X45JusO0yPcL8d6va0FwDz8HmPKcoA==","signatures":[{"sig":"MEUCIQDGzGGkYniVusVuMjxRt6XKwjXdWyEYczclSbvAeHhKKgIgYaAEV2Jo82CvzXU7P0hCkKKcU4vAPnQTxrkNL8OKm80=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":59134},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"1496dba01f9a9d8af5b89b6098d2d9adfc9f4f29","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.5.1","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.5","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.1","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.5","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_4.0.0_1772842584116_0.49897540250992667","host":"s3://npm-registry-packages-npm-production"}},"5.0.0":{"name":"kashi","version":"5.0.0","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","_id":"kashi@5.0.0","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"homepage":"https://gitlab.com/lucasmc64/kashi","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"dist":{"shasum":"956ff82c0d29a80307bfc86756c756dfc113ed27","tarball":"https://registry.npmjs.org/kashi/-/kashi-5.0.0.tgz","fileCount":6,"integrity":"sha512-KPwYIA7pjUeOYD9L8nzqc1GWa/0IwEkzeIX7hb3qlwswvMGkCovrScHJIF5tcYKosMzgK26Iuubzl+eF3Cpz4w==","signatures":[{"sig":"MEYCIQDw2CRCZqJIW1D/Z/xco7RdieeC19FOhOv7y1gjAOSH4AIhANlDkMdody1g5VvKpJ0dNCf6Yjgo37bO9ROIMzon2EiF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":62494},"main":"./kashi.js","type":"module","types":"./kashi.d.ts","module":"./kashi.mjs","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs"}},"gitHead":"711e13933c34f14cedd9cf6983462c41255ca95c","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","start":"gulp watchAll","prestart":"npm run build","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"repository":{"url":"git+https://gitlab.com/lucasmc64/kashi.git","type":"git"},"_npmVersion":"11.5.1","description":"Singing at the top of my lungs","directories":{},"_nodeVersion":"24.6.0","_hasShrinkwrap":false,"devDependencies":{"gulp":"^5.0.1","jest":"^30.0.5","jsdom":"^26.1.0","eslint":"^9.30.1","ts-jest":"^29.4.1","ts-node":"^10.9.2","ts-loader":"^9.5.2","typescript":"^5.8.3","@types/jest":"^30.0.0","@jest/globals":"^30.0.4","webpack-stream":"^7.0.0","eslint-plugin-jest":"^29.0.1","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","jest-environment-jsdom":"^30.0.5","@typescript-eslint/parser":"^8.36.0","@typescript-eslint/eslint-plugin":"^8.36.0"},"_npmOperationalInternal":{"tmp":"tmp/kashi_5.0.0_1788662036116_0.6250696372584454","host":"s3://npm-registry-packages-npm-production"}},"6.0.0":{"name":"kashi","version":"6.0.0","description":"Singing at the top of my lungs","type":"module","author":{"name":"lucasmc64"},"license":"GPL-3.0-only","homepage":"https://gitlab.com/lucasmc64/kashi","repository":{"type":"git","url":"git+https://gitlab.com/lucasmc64/kashi.git"},"main":"./kashi.js","module":"./kashi.mjs","types":"./kashi.d.ts","exports":{".":{"types":"./kashi.d.ts","import":"./kashi.mjs","require":"./kashi.js"}},"keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"scripts":{"prestart":"npm run build","start":"gulp watchAll","build":"rm -rf dist && gulp compileAll && ./node_modules/.bin/dts-bundle-generator -o ./dist/kashi.d.ts ./src/index.ts && cat ./package.json | grep -v '\"private\":' > dist/package.json && \\cp LICENSE dist && \\cp README.md dist","test":"NODE_OPTIONS=--experimental-vm-modules jest","test:watch":"npm test -- --watch","test:coverage":"npm test -- --coverage"},"devDependencies":{"@jest/globals":"^30.0.4","@types/jest":"^30.0.0","@typescript-eslint/eslint-plugin":"^8.36.0","@typescript-eslint/parser":"^8.36.0","dts-bundle-generator":"^9.5.1","eslint":"^9.30.1","eslint-plugin-import":"^2.32.0","eslint-plugin-jest":"^29.0.1","gulp":"^5.0.1","jest":"^30.0.5","jest-environment-jsdom":"^30.0.5","jsdom":"^26.1.0","ts-jest":"^29.4.1","ts-loader":"^9.5.2","ts-node":"^10.9.2","typescript":"^5.8.3","webpack-stream":"^7.0.0"},"gitHead":"44539359fa1c4f3eae897426e1eaae6a107d16b2","_id":"kashi@6.0.0","bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"_nodeVersion":"26.5.1","_npmVersion":"11.17.0","dist":{"integrity":"sha512-vcWx/VqYLUrGmOK74IcbgSSZKr05YddSK515anHsXXNaWYbUO+4q+YNXZHGKzE6Z+aun5BiLsDLKwrqrIe0L/Q==","shasum":"7912898c3086ba84323ceba9dbfb864b85cd2f04","tarball":"https://registry.npmjs.org/kashi/-/kashi-6.0.0.tgz","fileCount":6,"unpackedSize":63481,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCoh9xqn49Dz+1rorD7yHHLo8ys9RiexzPJAlg59+VUsQIgRRZwTWHA0AFcQ4Gt8Zh4lPNGLNMRN6Zbf0SnN20FhDk="}]},"_npmUser":{"name":"lucasmc64","email":"lucasmc64@proton.me"},"directories":{},"maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/kashi_6.0.0_1789231257924_0.37285573549856954"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-12T15:59:00.168Z","modified":"2026-09-12T16:40:58.217Z","0.0.1":"2019-04-02T19:21:12.616Z","0.0.2":"2019-04-07T07:03:12.357Z","0.0.3":"2019-06-02T05:56:43.153Z","0.0.4":"2019-12-24T04:54:52.136Z","0.0.5":"2019-12-25T19:01:23.909Z","0.0.6":"2019-12-27T18:47:18.522Z","0.0.7":"2020-01-01T08:41:25.299Z","0.0.8":"2020-01-01T11:18:29.740Z","0.0.9":"2020-01-01T11:25:48.828Z","0.0.10":"2020-01-01T15:55:57.541Z","0.0.11":"2020-01-01T16:24:06.242Z","0.0.12":"2020-01-02T17:45:06.856Z","0.0.13":"2020-01-04T08:28:23.062Z","0.0.14":"2020-01-04T09:52:27.203Z","0.0.15":"2020-01-09T05:00:40.557Z","0.0.16":"2020-01-10T04:20:53.992Z","10.0.0":"2022-09-07T08:02:25.581Z","1.0.0":"2025-07-12T15:59:00.343Z","1.0.1":"2025-07-12T16:06:06.456Z","1.0.2":"2025-07-12T16:27:41.729Z","1.1.0":"2025-07-22T15:37:47.965Z","1.1.1":"2025-08-08T21:05:55.363Z","1.1.2":"2025-08-15T16:59:03.206Z","1.1.3":"2025-09-04T21:50:23.269Z","2.0.0":"2025-09-30T20:12:23.135Z","3.0.0":"2025-11-19T19:07:36.634Z","3.0.1":"2025-11-20T20:46:18.705Z","3.0.2":"2025-12-08T08:57:29.540Z","4.0.0":"2026-03-07T00:16:24.273Z","5.0.0":"2026-09-06T02:33:56.270Z","6.0.0":"2026-09-12T16:40:58.063Z"},"bugs":{"url":"https://gitlab.com/lucasmc64/kashi/issues"},"author":{"name":"lucasmc64"},"license":"GPL-3.0-only","homepage":"https://gitlab.com/lucasmc64/kashi","keywords":["lyrics","song","lrc","music","kashi","karaoke","singer","sing","walaoke","a2","lrc-parser","lyric-synchronization","timed-lyrics","music-player","audio-player","lrc-file","lyrics-formatter"],"repository":{"type":"git","url":"git+https://gitlab.com/lucasmc64/kashi.git"},"description":"Singing at the top of my lungs","maintainers":[{"name":"lucasmc64","email":"lucasmc64@proton.me"}],"readme":"<div align=\"center\">\n  <a href=\"https://gitlab.com/lucasmc64/kashi\">GitLab</a> • \n  <a href=\"https://www.npmjs.com/package/kashi\">NPM</a> • \n  <a href=\"https://unpkg.com/browse/kashi@latest\">CDN</a> • \n  <a href=\"https://ko-fi.com/lucasmc64\">Ko-fi</a>\n</div>\n\n![Kashi](https://gitlab.com/lucasmc64/kashi/-/raw/main/readme/cover.png)\n\n# 🎤 Kashi\n\n## 🎯 Goal\n\nThis project is a dependency-free library that aims to provide a way to correctly read, format, structure, and display song lyrics.\n\n## 📜 Features\n\n- [x] 🎵 Process and list song lyrics in .lrc files\n- [x] 💪 Easily integrates with React and other frameworks\n- [x] ✉️ Implements the Observer pattern and emits events at each step of the process whenever something changes\n- [x] ✏️ Allows you to enter custom text when the lyrics line is empty\n- [x] 🎤 Synchronizes the lyrics with the music that is playing\n- [x] 🎩 Supports multiple lyrics for the same song (useful to keep track of the original lyrics and their translation)\n- [x] 🧞 Supports the [Walaoke extension](https://en.wikipedia.org/wiki/LRC_(file_format)#Walaoke_extension)\n- [ ] 🕖️ Supports the [A2 extension](https://en.wikipedia.org/wiki/LRC_(file_format)#A2_extension_(Enhanced_LRC_format))\n\n> **Note:** Support for fetching lyrics using a URL has been removed because it only supported public URLs.\n>\n> Therefore, instead of refactoring to handle requests to private APIs, I opted to support only files. If a request is necessary, you can make it externally and then pass the returned file to Kashi!\n\n## 🎨 How to use it in my project?\n\n### <span id=\"classic-scripts\">🙌 Classic scripts</span>\n\nThe project is also exported using [UMD](https://github.com/umdjs/umd), which means that all variables and classes such as the `Kashi` class is exposed globally, and can be used in any script imported after the library.\n\n> **Note**: You should **change `X.Y.Z` to the library version number** according to your needs, this is just an example. It is recommended to always use the latest version.\n>\n> It is recommended that you pin to the latest stable version of the lib. However, if you always want to use the latest version, you can also use `latest` instead of a predefined version number. **Be careful** though, breaking changes may be introduced and your project may need to adapt to the changes.\n\n```html\n<!DOCTYPE html>\n\n<html>\n  <head>\n    <!-- ... -->\n    <script src=\"https://unpkg.com/kashi@X.Y.Z/kashi.js\" defer></script>\n    <!-- ... -->\n  </head>\n\n  <body>\n    <div id=\"kashi\"></div>\n  </body>\n</html>\n```\n\n```js\n\"use strict\";\n\nconst kashi = new Kashi({\n  container: document.getElementById(\"kashi\"),\n});\n\n// Files loaded from some input[type=\"file\"] or anywhere else\nkashi.setFiles([file]).catch(console.error);\n```\n\n### 📦️ ES6 Modules\n\nThe HTML is very similar to the classic scripts version, just change the `.js` extension to `.mjs` (and maybe will be necessary to adds a `type=\"module\"` too), which will result in something similar to this:\n\n> **Note**: Please read the [previous section](#classic-scripts) to get the details involved in importing and choosing a package version, they are the same here.\n\n```html\n<script\n  src=\"https://unpkg.com/kashi@X.Y.Z/kashi.mjs\"\n  type=\"module\"\n  defer\n></script>\n```\n\n```javascript\nimport { Kashi } from \"kashi\";\n\n// Usage is essentially the same as in the previous section\n\nconst kashi = new Kashi({\n  container: document.getElementById(\"kashi\"),\n});\n\n// Files loaded from some input[type=\"file\"] or anywhere else\nkashi.setFiles([file]).catch(console.error);\n```\n\n### ⚛️ React\n\nInstall the lib using your favorite package manager.\n\n```bash\nnpm install kashi\n```\n\nSince the library was designed primarily to be used with vanilla JS, a _helper_ component needs to be created to encapsulate Kashi's behavior and make it simple to reuse throughout the application.\n\n> **Note**: There is TypeScript support, and even if your project doesn't use the JS superset, it should help VSCode and other editors provide autocomplete/code suggestions.\n\n```tsx\nimport { memo, useEffect, useRef } from \"react\";\nimport { Kashi, KashiProps } from \"kashi\";\n\nimport { api } from \"@/services/axios\";\n\n// Example using Vite, React and TypeScript\nexport const KashiWrapper = memo(\n  (props: Omit<KashiProps, \"container\"> & { url: string }) => {\n    const ref = useRef<HTMLDivElement>(null);\n\n    useEffect(() => {\n      async function loadKashi() {\n        if (!ref.current) {\n          return;\n        }\n\n        if (!props.url) {\n          ref.current.innerHTML = \"\";\n          return;\n        }\n\n        try {\n          const { url, ...rest } = props;\n\n          const response = await api.get(url, { responseType: \"blob\" });\n\n          const kashi = new Kashi({\n            ...rest,\n            container: ref.current,\n          });\n\n          await kashi.setFiles([response.data]);\n        } catch (error) {\n          console.error(\"Error loading Kashi:\", error);\n        }\n      }\n\n      loadKashi();\n\n      return () => {\n        // Required to avoid duplication when React is in Strict Mode\n        if (ref.current) {\n          ref.current.innerHTML = \"\";\n        }\n      };\n    }, [ref.current, props]);\n\n    return <div className=\"kashi-wrapper\" ref={ref} />;\n  },\n  (prevProps, nextProps) => {\n    function compareArrays(arr1: unknown[], arr2: unknown[]) {\n      if (arr1.length !== arr2.length) {\n        return false;\n      }\n\n      return arr1.every((item, index) => item === arr2[index]);\n    }\n\n    function compareObjects(\n      obj1: Omit<KashiProps, \"container\">,\n      obj2: Omit<KashiProps, \"container\">,\n    ) {\n      const keys1 = Object.keys(obj1) as Array<\n        keyof Omit<KashiProps, \"container\">\n      >;\n      const keys2 = Object.keys(obj2) as Array<\n        keyof Omit<KashiProps, \"container\">\n      >;\n\n      if (keys1.length !== keys2.length) {\n        return false;\n      }\n\n      for (const key of keys1) {\n        const val1 = obj1[key];\n        const val2 = obj2[key];\n\n        if (Array.isArray(val1) && Array.isArray(val2)) {\n          if (!compareArrays(val1, val2)) {\n            return false;\n          }\n        } else if (val1 !== val2) {\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    return compareObjects(prevProps, nextProps);\n  },\n);\n```\n\n## 🧐 Constructor properties\n\nYou must pass some properties to Kashi to define what lyrics display and where. Here are its specifications:\n\n| Property           | Type             | Default value | Is required? | Description                                                  |\n| ------------------ | ---------------- | ------------- | ------------ | ------------------------------------------------------------ |\n| `container`        | `HTMLDivElement` | -             | Yes          | Element where the lyrics will be inserted                    |\n| `emptyLineText`    | `string`         | `...`         | No           | Custom text for empty lines of the lyrics                    |\n| `noLyricsText`     | `string`         | -             | No           | Custom text for when there are no lyrics                     |\n| `enableAutoScroll` | `boolean`        | `false`       | No           | Try to use `scrollIntoView` to center the current lyric line |\n\n> **Note:** The lyrics files are not passed to the constructor anymore. Use the `setFiles` method to load them, e.g. `await kashi.setFiles(files)`. This way, loading errors can be handled with a regular `try/catch` (or `.catch()`), since the constructor is synchronous.\n\n## 👾 Generated HTML structure\n\nThe `div#kashi` represents the `container` passed to `Kashi` where the song lyrics will be inserted.\n\nEach line of lyrics present in the lrc files will be wrapped by a `<div></div>` tag and inserted into the `container`.\n\nHere's an example:\n\n```html\n<div id=\"kashi\">\n  <div\n    data-time=\"00:17.55\"\n    data-ms-time=\"17550\"\n    data-empty=\"false\"\n    aria-current=\"true\"\n    data-walaoke=\"M\"\n    data-walaoke-full=\"Male\"\n  >\n    <span>Telling myself, \"I won't go there\"</span>\n    <br />\n    <span> Dizendo a mim mesmo, \"eu não vou lá\" </span>\n  </div>\n\n  <div\n    data-time=\"00:21.24\"\n    data-ms-time=\"21240\"\n    data-empty=\"false\"\n  >\n    <span>Oh, but I know that I won't care</span>\n    <br />\n    <span>Oh, mas eu sei que não vou me importar</span>\n  </div>\n\n  <!-- ... -->\n</div>\n```\n\n## 📂 Methods and attributes\n\nThe instance generated by `Kashi` has some public methods and attributes that can be used to query or change properties on the fly.\n\n| Name               | Type      | Description                                                  |\n| ------------------ | --------- | ------------------------------------------------------------ |\n| `files`            | Attribute | Returns the files from the current lyrics                    |\n| `emptyLineText`    | Attribute | Returns the text set for empty lines                         |\n| `noLyricsText`     | Attribute | Returns the text set for when there are no lyrics            |\n| `fileType`         | Attribute | Returns the guessed file type                                |\n| `setFiles`         | Method    | Function capable of changing the current lyrics files by passing the the new **files** |\n| `setEmptyLineText` | Method    | Function capable of changing the text defined for empty lines |\n| `setNoLyricsText`  | Method    | Function capable of changing the text defined for when there are no lyrics. Re-renders the lyrics container |\n| `subscribe`        | Method    | Function capable of defining a callback to be executed when a given event is triggered |\n| `unsubscribe`      | Method    | Function capable of making a callback to stop listening to an event |\n| `notify`           | Method    | Function capable of triggering an event                      |\n\n## 🍾 Events\n\nWhen creating a new instance using `Kashi` you will have access to the `subscribe`, `unsubscribe` and `notify` methods, these methods can be used respectively to listen for an event, stop listening for an event and manually trigger an event. Below is the list of events triggered internally:\n\n| Event               | Data                        | Trigger                                                      |\n| ------------------- | --------------------------- | ------------------------------------------------------------ |\n| `filesSet`          | `{ files: Blob[] }`         | When calling the `setFiles` method                           |\n| `emptyLineTextSet`  | `{ emptyLineText: string }` | When calling the `setEmptyLineText` method                   |\n| `noLyricsTextSet`   | `{ noLyricsText: text }`    | When calling the `setNoLyricsText` method. Also re-renders the container |\n| `lyricLinesUpdated` | `{ lyricsLines: ParsedLyricLine[] }` | When inserting/updating lyrics in HTML. Each item has `{ time, timeMs, spans, walaoke, walaokeFull, isEmpty }` |\n| `dataCleared`       | -                           | When the lyrics-related data is cleared. This occurs when an empty array is passed to `setFiles` or the audio player emits the \"emptied\" event. |\n\n## 🤔 How do I run the project on my machine?\n\nThe first step is to clone the project, either via terminal or even by downloading the compressed file (.zip). After that, go ahead.\n\n### 🛠️ Requirements\n\n- [NodeJS and NPM](https://nodejs.org)\n\n### ✨ Running the project\n\nWith the dependencies properly installed, still in the terminal, run `npm start`.\n\nCreate a simple demo project using vanilla HTML/JS and use the files in the `dist` folder for testing.\n\nYou can also create a demo project using React and use [npm link](https://docs.npmjs.com/cli/v9/commands/npm-link).\n\n### 🎉 If everything went well...\n\nNow you are running the project beautifully!\n\n## ✏️ License\n\nThis project is under the GPL v3 license. See the [LICENSE](https://gitlab.com/lucasmc64/kashi/-/blob/main/LICENSE) for more information.\n\n---\n\nMade with 💙 by lucasmc64 👋 [Get in touch!](https://www.linkedin.com/in/lucasmc64/)\n","readmeFilename":"README.md"}