From 499852b2a70469d275dfc09577dc30d79c371c58 Mon Sep 17 00:00:00 2001 From: Claude Owner Date: Tue, 26 May 2026 14:48:24 +0900 Subject: [PATCH] fix(tts): avoid char-by-char split when signature list is empty SignatureClient.regex returned new RegExp("()", "g") when nameSet was empty (server unreachable, list not yet synced). text.split() with that regex matches every zero-width position, so 'abc' became ['a','','b','','c',''] and TTSClient sent a separate Chzzk request per character. Two-layer fix: - SignatureClient.regex returns /$^/g (never-match) when names is empty, so split() returns the original string as a single element. - TTSClient.getSource explicitly skips split when nameSet.size === 0 so the intent is obvious at the call site. --- src/classes/SignatureClient.ts | 7 ++++++- src/classes/TTSClient.ts | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/classes/SignatureClient.ts b/src/classes/SignatureClient.ts index c7c4485..ad0de4d 100644 --- a/src/classes/SignatureClient.ts +++ b/src/classes/SignatureClient.ts @@ -35,7 +35,12 @@ export class SignatureClient { } get regex() { - const escaped = [...this.nameSet].map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); + const names = [...this.nameSet]; + // 빈 목록이면 new RegExp("()", "g")가 모든 위치에서 매칭돼 + // text.split() 결과가 글자 단위로 쪼개진다. 절대 매칭되지 않는 + // 패턴을 돌려줘 split 호출자가 원문을 그대로 받게 한다. + if (names.length === 0) return /$^/g; + const escaped = names.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); return new RegExp(`(${escaped.join("|")})`, "g"); } diff --git a/src/classes/TTSClient.ts b/src/classes/TTSClient.ts index 7e52b42..26fa809 100644 --- a/src/classes/TTSClient.ts +++ b/src/classes/TTSClient.ts @@ -92,7 +92,11 @@ export class TTSClient { private async getSource(text: string): Promise { - const parts = text.split(signature.regex); + // 시그니처 목록이 비어 있으면 split을 건너뛰고 원문을 한 번에 합성한다. + // (SignatureClient.regex가 빈 목록일 때 never-match 패턴을 돌려주지만, + // 소비자 측에서도 명시적으로 가드해 의도를 분명히 한다.) + const names = signature.nameSet; + const parts = names.size === 0 ? [text] : text.split(signature.regex); const bufferList: Buffer[] = []; for (const part of parts) {