diff options
| author | Pinapelz <yukais@pinapelz.com> | 2026-04-16 03:13:31 -0700 |
|---|---|---|
| committer | Pinapelz <yukais@pinapelz.com> | 2026-04-16 03:13:31 -0700 |
| commit | 784c99aa2d5ec4d2b861b0c44e4943f89f0144ce (patch) | |
| tree | 035ba8887b6eb81424a563e1dc9acfb34f25eef0 /src/app/game/game.utils.ts | |
| parent | 30d2ca8480caea1ce76cc1ec29d454e3a669c638 (diff) | |
wip: typing tube mode
Diffstat (limited to 'src/app/game/game.utils.ts')
| -rw-r--r-- | src/app/game/game.utils.ts | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/app/game/game.utils.ts b/src/app/game/game.utils.ts new file mode 100644 index 0000000..73d2884 --- /dev/null +++ b/src/app/game/game.utils.ts @@ -0,0 +1,45 @@ +export interface GameLine { + millisecond: number; + content: string; +} + +export function parseLrcLines(lrcText: string): GameLine[] { + const result: GameLine[] = []; + const lineRegex = /\[(\d{2,3}):(\d{2})\.(\d{2,3})\]/g; + + for (const rawLine of lrcText.split("\n")) { + const timestamps: number[] = []; + let match: RegExpExecArray | null; + let lastIndex = 0; + + lineRegex.lastIndex = 0; + while ((match = lineRegex.exec(rawLine)) !== null) { + const minutes = parseInt(match[1], 10); + const seconds = parseInt(match[2], 10); + const msField = match[3]; + const ms = + msField.length === 2 + ? parseInt(msField, 10) * 10 + : parseInt(msField, 10); + timestamps.push(minutes * 60_000 + seconds * 1_000 + ms); + lastIndex = match.index + match[0].length; + } + + if (timestamps.length === 0) continue; + + const content = rawLine.slice(lastIndex).trim(); + if (!content) continue; + + for (const ms of timestamps) { + result.push({ millisecond: ms, content }); + } + } + + result.sort((a, b) => a.millisecond - b.millisecond); + return result; +} + +export function formatTime(ms: number): string { + const s = Math.max(0, Math.floor(ms / 1000)); + return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`; +}
\ No newline at end of file |
