{"_id":"@boof2015/xlrc","_rev":"5-16114e3a74e21a5a668ce6099b22b786","name":"@boof2015/xlrc","dist-tags":{"latest":"0.2.1"},"versions":{"0.0.1":{"name":"@boof2015/xlrc","version":"0.0.1","keywords":["lyrics","lrc","xlrc","music"],"author":{"name":"Boof2015"},"license":"MIT","_id":"@boof2015/xlrc@0.0.1","maintainers":[{"name":"boof2015","email":"contact@novaml.ai"}],"homepage":"https://github.com/Boof2015/xlrc#readme","bugs":{"url":"https://github.com/Boof2015/xlrc/issues"},"dist":{"shasum":"20c56b6b7c189e3c1495c0620605b7b5bb96de08","tarball":"https://registry.npmjs.org/@boof2015/xlrc/-/xlrc-0.0.1.tgz","fileCount":4,"integrity":"sha512-vxB5ITTLWCHbesL6Qu3zqwYu3NzVjqCSgr+cvKyut+TTlt+zjjR/fZYmM+0N6KPwpsM9OrSgQhu2irYHJBJobg==","signatures":[{"sig":"MEQCIAqUnAPelHKTUm+N8dHZm9yyT3sF3cOHjFEu7YKFfGDoAiB7bvLT98ayLz6+eCfhCWtMhuClqVkx59bl5hmWGZ0uMQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1687},"main":"index.js","gitHead":"67bcff0db3b78dba3508d481121350ce2f76a8e6","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"boof2015","email":"contact@novaml.ai"},"repository":{"url":"git+https://github.com/Boof2015/xlrc.git","type":"git"},"_npmVersion":"10.9.0","description":"Parser and toolkit for the XLRC lyric format","directories":{},"_nodeVersion":"23.1.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/xlrc_0.0.1_1779301662580_0.19983394751785255","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@boof2015/xlrc","version":"0.1.0","keywords":["lyrics","lrc","xlrc","music"],"author":{"name":"Boof2015"},"license":"MIT","_id":"@boof2015/xlrc@0.1.0","maintainers":[{"name":"boof2015","email":"contact@novaml.ai"}],"homepage":"https://github.com/Boof2015/xlrc#readme","bugs":{"url":"https://github.com/Boof2015/xlrc/issues"},"dist":{"shasum":"84f96a2d797f3ef46b56405520ca261207c1c8da","tarball":"https://registry.npmjs.org/@boof2015/xlrc/-/xlrc-0.1.0.tgz","fileCount":8,"integrity":"sha512-s8ZJQZtwVsmnBdCmkBAGul0L65x1KXHRI/YlwRpdef5Bn4cNLktiRDEMgUG324AdEWtyKw3kpmD33YltjIgX2w==","signatures":[{"sig":"MEYCIQCcIvcmD3dMksk8qQxfCXY9nSPP/u2Jw/SXrJHWZtTHcgIhAMEu6i4TkxtpLycNb1cc7q0/mHuY+37eRTZrkh37GIgV","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":50595},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"22dd5ef9683d332d727edd8142ed6e4174e91b3a","scripts":{"test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test && npm run build"},"_npmUser":{"name":"boof2015","email":"contact@novaml.ai"},"repository":{"url":"git+https://github.com/Boof2015/xlrc.git","type":"git"},"_npmVersion":"10.9.0","description":"Parser and toolkit for the XLRC lyric format","directories":{},"_nodeVersion":"23.1.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.2","vitest":"^1.6.0","typescript":"^5.4.5","@types/node":"^20.12.12"},"_npmOperationalInternal":{"tmp":"tmp/xlrc_0.1.0_1779303728914_0.6778531577651994","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@boof2015/xlrc","version":"0.1.1","keywords":["lyrics","lrc","xlrc","music"],"author":{"name":"Boof2015"},"license":"MIT","_id":"@boof2015/xlrc@0.1.1","maintainers":[{"name":"boof2015","email":"contact@novaml.ai"}],"homepage":"https://github.com/Boof2015/xlrc#readme","bugs":{"url":"https://github.com/Boof2015/xlrc/issues"},"dist":{"shasum":"9d3a51b6a788f500d20f11ccacc0a31399c7f605","tarball":"https://registry.npmjs.org/@boof2015/xlrc/-/xlrc-0.1.1.tgz","fileCount":8,"integrity":"sha512-A/bLS8ldpbNFcsmoAdHbONtN8frX1BfBMcBiAB1USX72HEYUcVGkfZe8W7l5QDXk3peSGMJyXaiAdVWi6MxTeA==","signatures":[{"sig":"MEYCIQDoIbqAmBhCeVBIZYhqFoHDOW2Mf1cFi+xZ5RcaQrpNBQIhAILle5SEH3RzqWAeeM5r3O8Fg4Oh3F2+YMb9KukpLhy1","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51547},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"585a05cb4b95ede5726c223159ef0bd11f568381","scripts":{"test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test && npm run build"},"_npmUser":{"name":"boof2015","email":"contact@novaml.ai"},"repository":{"url":"git+https://github.com/Boof2015/xlrc.git","type":"git"},"_npmVersion":"10.9.0","description":"Parser and toolkit for the XLRC lyric format","directories":{},"_nodeVersion":"23.1.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.2","vitest":"^1.6.0","typescript":"^5.4.5","@types/node":"^20.12.12"},"_npmOperationalInternal":{"tmp":"tmp/xlrc_0.1.1_1779304780062_0.462964835450439","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@boof2015/xlrc","version":"0.2.0","keywords":["lyrics","lrc","xlrc","music"],"author":{"name":"Boof2015"},"license":"MIT","_id":"@boof2015/xlrc@0.2.0","maintainers":[{"name":"boof2015","email":"contact@novaml.ai"}],"homepage":"https://github.com/Boof2015/xlrc#readme","bugs":{"url":"https://github.com/Boof2015/xlrc/issues"},"dist":{"shasum":"d8d0222190a4ee3bbeef6e9d16f313fe08670c28","tarball":"https://registry.npmjs.org/@boof2015/xlrc/-/xlrc-0.2.0.tgz","fileCount":8,"integrity":"sha512-JlyUZSuhLFD5nRmJi1XoEFNW0Nc8fICubslP0IDbX4mQE+Tl8UjFe+re7voVCpBAzxFQ8eMnH1MLv6gvbWSmCA==","signatures":[{"sig":"MEUCIQC4SmkkpidUWrIzJDRPndJiTuXVd1HV1mZGhB2fvwNC9wIgBPvkXlmvik+0gnZgHbuN05PxoGfi3S+l4B20/E6La0I=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":56185},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"5d95306ac515c0e172175e0df1492a9786de954f","scripts":{"test":"vitest run test/parser.test.ts test/serializer.test.ts test/validator.test.ts","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit","vscode:test":"npm --prefix vscode-xlrc test","prepublishOnly":"npm run typecheck && npm test && npm run build","vscode:compile":"npm --prefix vscode-xlrc run compile","vscode:package":"npm --prefix vscode-xlrc run package"},"_npmUser":{"name":"boof2015","email":"contact@novaml.ai"},"repository":{"url":"git+https://github.com/Boof2015/xlrc.git","type":"git"},"_npmVersion":"10.9.0","description":"Parser and toolkit for the XLRC lyric format","directories":{},"_nodeVersion":"23.1.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.2","vitest":"^1.6.0","typescript":"^5.4.5","@types/node":"^20.12.12"},"_npmOperationalInternal":{"tmp":"tmp/xlrc_0.2.0_1779484292251_0.7791463775959158","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@boof2015/xlrc","version":"0.2.1","description":"Parser and toolkit for the XLRC lyric format","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"build":"tsup src/index.ts --format esm,cjs --dts --clean","test":"vitest run test/parser.test.ts test/serializer.test.ts test/validator.test.ts test/lookup.test.ts","typecheck":"tsc --noEmit","vscode:compile":"npm --prefix vscode-xlrc run compile","vscode:test":"npm --prefix vscode-xlrc test","vscode:package":"npm --prefix vscode-xlrc run package","prepublishOnly":"npm run typecheck && npm test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/Boof2015/xlrc.git"},"keywords":["lyrics","lrc","xlrc","music"],"author":{"name":"Boof2015"},"license":"MIT","devDependencies":{"@types/node":"^20.12.12","tsup":"^8.0.2","typescript":"^5.4.5","vitest":"^1.6.0"},"bugs":{"url":"https://github.com/Boof2015/xlrc/issues"},"homepage":"https://github.com/Boof2015/xlrc#readme","_id":"@boof2015/xlrc@0.2.1","gitHead":"a96126e13e740ff3562096e3aa063ac2e435134d","_nodeVersion":"23.1.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-XncWjaw+BjzG1pQXwG92RCIrBOoU1DvLRT+wEnbU18j4qKCBujep4dT55gH+vb6TTRxI5Yv3E8V7p6FipYhWqw==","shasum":"a9090625dd25194efc3cb71319a9748d7a5c4a6e","tarball":"https://registry.npmjs.org/@boof2015/xlrc/-/xlrc-0.2.1.tgz","fileCount":8,"unpackedSize":70735,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGQr1UWk1emZUoyTDhNUFqQWYb7J/7hkbAKiMA3ZCHmeAiBjnXhQ+vtV50eI6ngSQ21xSgJ9vHlXkWHQ+thxqxHKkg=="}]},"_npmUser":{"name":"boof2015","email":"contact@novaml.ai"},"directories":{},"maintainers":[{"name":"boof2015","email":"contact@novaml.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/xlrc_0.2.1_1779594181181_0.26384055815759955"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-20T18:27:42.389Z","modified":"2026-05-24T03:43:01.581Z","0.0.1":"2026-05-20T18:27:42.712Z","0.1.0":"2026-05-20T19:02:09.081Z","0.1.1":"2026-05-20T19:19:40.222Z","0.2.0":"2026-05-22T21:11:32.396Z","0.2.1":"2026-05-24T03:43:01.480Z"},"bugs":{"url":"https://github.com/Boof2015/xlrc/issues"},"author":{"name":"Boof2015"},"license":"MIT","homepage":"https://github.com/Boof2015/xlrc#readme","keywords":["lyrics","lrc","xlrc","music"],"repository":{"type":"git","url":"git+https://github.com/Boof2015/xlrc.git"},"description":"Parser and toolkit for the XLRC lyric format","maintainers":[{"name":"boof2015","email":"contact@novaml.ai"}],"readme":"# XLRC\n\nParser, serializer, and validator for the XLRC lyric format, with backwards-compatible parsing for standard LRC files.\n\nXLRC extends LRC with inline translations, furigana, word-level timing, and multi-voice attribution while staying plain-text and friendly to existing LRC tooling. `parseXLRC()` also accepts common LRC input, so music players can use this package for both XLRC and standard synced LRC without maintaining a second parser.\n\n## Install\n\n```sh\nnpm install @boof2015/xlrc\n```\n\n## Usage\n\n```ts\nimport { lookup, parseXLRC, serializeXLRC, validateXLRC } from \"@boof2015/xlrc\";\n\nconst source = `[ti:Example]\n[lang:ja]\n\n[00:12.40]私[わたし]が歌[うた]う\n[>en]I sing\n`;\n\nconst file = parseXLRC(source);\n\nconsole.log(file.lines[0]?.text);\n// \"私が歌う\"\n\nconsole.log(file.lines[0]?.furigana);\n// [{ start: 0, end: 1, base: \"私\", reading: \"わたし\", line: 4 }, ...]\n\nconst result = validateXLRC(file);\nconsole.log(result.valid);\n// true\n\nconst xlrc = serializeXLRC(file);\n```\n\nLook up lyrics from an xlrcdb-compatible static data source:\n\n```ts\nconst lookupResult = await lookup({\n  artist: \"Example Artist\",\n  title: \"Example Track\",\n  length: 222,\n  source: \"https://example.com/xlrcdb\"\n});\n\nif (lookupResult.found) {\n  console.log(lookupResult.lyrics.lines);\n}\n```\n\n## LRC Compatibility\n\n`parseXLRC()` supports standard LRC metadata and timed lyric lines alongside XLRC features. It accepts common synced LRC timestamp forms:\n\n- `[mm:ss]`\n- `[mm:ss.x]`\n- `[mm:ss.xx]`\n- `[mm:ss.xxx]`\n- repeated line timestamps, e.g. `[00:10.00][00:20.00]Same lyric`\n- matching enhanced LRC word timestamps, e.g. `<00:10>word` and `<00:10.405>word`\n\nRepeated line timestamps expand into multiple parsed lyric lines with the same lyric body. Parsed timestamps are normalized to integer milliseconds.\n\n`serializeXLRC()` still emits canonical XLRC text. It does not preserve the original spelling of LRC timestamp variants or repeated timestamp source layout.\n\n## API\n\n### `parseXLRC(input: string): XLRCFile`\n\nParses an XLRC or common LRC string into structured metadata, lyric lines, translations, word timings, furigana, and parser warnings. Malformed input is non-fatal; warnings are returned on `file.warnings`.\n\nFor each parsed lyric line:\n\n- `text` is the clean display text with word timing and furigana markup removed.\n- `sourceText` is the lyric text after word timing tags are removed, with furigana markup preserved.\n- `rawText` is the original lyric body after the line timestamp and optional voice tag.\n- `voice` is a string label or `null` when the line is unattributed.\n\nFurigana entries refer to contiguous kanji spans in `text`. Kana around the span is left as normal display text, so `食[た]べる` renders ruby over `食` and leaves `べる` untouched.\n\n### `serializeXLRC(file: XLRCFile): string`\n\nSerializes a structured XLRC object to canonical XLRC text.\n\n### `validateXLRC(file: XLRCFile): ValidationResult`\n\nValidates structured XLRC data and returns warnings for invalid metadata, timestamps, translations, furigana, and word timing data.\n\n### `lookup(options: LookupOptions): Promise<LookupResult>`\n\nLooks up and parses lyrics from an xlrcdb-compatible static deployment. The client fetches `index/aliases.json`, the matched per-artist index, then the matched `.xlrc` file.\n\nTrack matching uses normalized artist/title strings and a ±2 second duration tolerance. Pass `fetch` in `LookupOptions` to inject a custom fetch implementation for tests or non-browser runtimes.\n\nLower-level helpers are also exported: `normalizeLookupKey()`, `fetchAliasesIndex()`, `findArtist()`, `fetchArtistIndex()`, and `findTrack()`.\n\n## Development\n\n```sh\nnpm install\nnpm run typecheck\nnpm test\nnpm run build\n```\n\nThe package publishes built files from `dist/` and generated TypeScript declarations. Runtime source is browser-compatible and has no runtime dependencies.\n\n## Publishing\n\n```sh\nnpm version patch\nnpm publish --access public\n```\n\n`prepublishOnly` runs typechecking, tests, and the production build before npm publishes the package.\n","readmeFilename":"README.md"}