- Dockerfile base now node:22-bookworm-slim (glibc) so better-sqlite3 uses prebuilt binaries and node-gyp/python build deps are no longer required. Also satisfies @discordjs/voice node>=22.12 engine req. - Drop redundant `mkdir -p dist` (build script handles it). - Add .env.example covering TOKEN, APPID, PREFIX, DBPATH, GUILDID, CHZZK_NID_AUT/SES, SIGNATURE_HOST, TTSPATH, DEV, DEBUG, REPLACETEXT. - README: update base image note.
118 lines
5.6 KiB
Markdown
118 lines
5.6 KiB
Markdown
# tts_bot
|
|
|
|
Discord 음성채널에서 채팅을 읽어주는 TTS 봇. TypeScript + discord.js 기반.
|
|
|
|
## 주요 기능
|
|
|
|
- 지정한 텍스트 채널의 채팅을 음성채널에서 자동 낭독 (`/tts channel register`로 채널 지정)
|
|
- 치지직(Chzzk) 알림 TTS 엔진 사용 (`utils/tts/Chzzk.ts`). 현재 코드는 `VoiceType.가람` 고정 (`VoiceType` enum에 다른 보이스도 정의돼 있어 코드 한 줄 수정으로 교체 가능)
|
|
- 대체 엔진으로 Google Translate TTS 구현체(`utils/tts/Google.ts`)가 포함돼 있으나 현재 비활성(`TTSClient.ts`에서 import 주석 처리). 사용하려면 import 교체 필요
|
|
- 시그니처(짤·효과음) 재생: 외부 시그니처 서버(`192.168.10.5:2967`)와 WebSocket으로 동기화해 채팅 중 키워드 매칭 시 mp3 삽입
|
|
- URL, 멘션, 이모지, 자주 쓰는 초성(ㄹㅇ, ㅇㅋ 등)을 자동 치환해 읽음
|
|
- 10분 idle 후 음성채널 자동 퇴장, 사용자 음성채널 이동 시 따라가기
|
|
|
|
## 명령어
|
|
|
|
| 명령어 | 설명 |
|
|
| --- | --- |
|
|
| `/tts channel make` | "TTS채널" 텍스트 채널을 새로 만들고 등록 |
|
|
| `/tts channel register [channel|channel_id]` | 기존 텍스트 채널을 TTS 입력 채널로 등록 |
|
|
| `/시그니처` (`/signature`) | 시그니처 관리 사이트 링크 |
|
|
| `/help` (`/도움말`) | 명령어 목록 |
|
|
| `/ping` (`/핑`) | 응답 지연 확인 |
|
|
|
|
메시지 prefix(`PREFIX` 환경변수)로도 `help`/`ping`/`시그니처`/`example`은 동일하게 호출된다. `tts`는 슬래시 전용이며, prefix `tts`는 현재 더미 응답("예시 명령어")만 보낸다.
|
|
|
|
## 기술 스택
|
|
|
|
- Node.js 20 (Dockerfile 기준) / TypeScript (strict 모드)
|
|
- `discord.js` v14, `@discordjs/voice`, `@discordjs/opus`
|
|
- `better-sqlite3` — 길드별 등록 채널 저장 (`db/schema.sql`)
|
|
- `fluent-ffmpeg` + `ffmpeg-static` — 시그니처 mp3 볼륨 조절, PCM 변환
|
|
- `ws` — 시그니처 서버 동기화
|
|
- `axios` — Chzzk / Google TTS HTTP 호출
|
|
|
|
## 디렉터리 구조
|
|
|
|
```
|
|
src/
|
|
index.ts # 엔트리: 싱글톤(client, handler, tts, signature) 구성
|
|
classes/
|
|
BotClient.ts # discord.js Client 확장 (embed/메시지 삭제 헬퍼)
|
|
Handler.ts # commands/ 자동 로드 및 슬래시 라우팅
|
|
TTSClient.ts # 메시지 → TTS 변환 파이프라인
|
|
VoiceSession.ts # 길드별 음성 연결/플레이어 관리
|
|
SignatureClient.ts # 시그니처 서버 WS 연결 + 파일 캐싱
|
|
commands/ # tts, signature, help, ping, example
|
|
events/ # clientReady, interactionCreate, messageCreate, voiceStateUpdate
|
|
utils/
|
|
Config.ts # 환경변수 게터 (누락 시 ReferenceError)
|
|
Database.ts # better-sqlite3 래퍼 (guild/user CRUD)
|
|
Logger.ts # colors 기반 타임스탬프 로거
|
|
Transcode.ts # mp3 Buffer → 48k/16bit/stereo PCM 스트림
|
|
Prod-commands.ts # 전역 슬래시 명령어 일괄 등록 스크립트
|
|
tts/ # Chzzk, Google, Utils(치환 사전)
|
|
db/
|
|
schema.sql # guilds, users 테이블
|
|
db.d.ts # 타입 정의
|
|
```
|
|
|
|
## 환경 변수
|
|
|
|
`.env` 또는 시스템 환경변수로 설정. 모든 값은 `Config.ts`에서 trim 후 읽음.
|
|
|
|
| 키 | 필수 | 설명 |
|
|
| --- | --- | --- |
|
|
| `APPID` | ✅ | Discord 애플리케이션 ID |
|
|
| `TOKEN` | ✅ | 봇 토큰 |
|
|
| `PREFIX` | ✅ | 메시지 명령어 prefix (예: `!`) |
|
|
| `DBPATH` | ✅ | SQLite 파일 경로 (예: `./db/data.db`) |
|
|
| `CHZZK_NID_AUT` | ✅ | 네이버 NID_AUT 쿠키 (치지직 TTS 인증) |
|
|
| `CHZZK_NID_SES` | ✅ | 네이버 NID_SES 쿠키 |
|
|
| `GUILDID` | △ | `DEV=true`일 때만 사용 (DEV 길드 한정 슬래시 등록 대상). 그 외에는 미설정이어도 무방 |
|
|
| `DEV` | 선택 | `true`면 글로벌 대신 `GUILDID`에만 슬래시 등록 |
|
|
| `DEBUG` | 선택 | `true`면 명령어 오류 스택 로깅 |
|
|
| `REPLACETEXT` | 선택 | 치환 사전(JSON 배열). 기본 사전(`def_replaceObj`)과 병합 |
|
|
| `SIGNATURE_HOST` | 선택 | 시그니처 서버 `host:port`. 미설정 시 `192.168.10.5:2967` 기본값 |
|
|
| `TTSPATH` | 선택 | `Config.ttsPath` getter만 정의돼 있고 현재 호출처 없음. 향후 사용 대비 환경변수만 받아둠 |
|
|
|
|
## 실행
|
|
|
|
```bash
|
|
# 의존성 설치
|
|
npm install
|
|
|
|
# 개발 (ts-node)
|
|
npm run dev
|
|
|
|
# 빌드 후 실행 (build 스크립트가 dist 디렉터리를 자동 생성)
|
|
npm run build
|
|
npm start
|
|
|
|
# 전역 슬래시 명령어 등록 (배포 파이프라인)
|
|
npm run prod
|
|
```
|
|
|
|
### Docker
|
|
|
|
```bash
|
|
docker build -t tts_bot .
|
|
docker run --env-file .env -v $(pwd)/db:/app/db tts_bot
|
|
```
|
|
|
|
Dockerfile은 `node:22-bookworm-slim` 기반이며 `ffmpeg`을 설치한다. (이전 `node:20-alpine` 은 musl 환경이라 `better-sqlite3` prebuilt 가 없어 node-gyp/python 빌드 의존성이 필요했고, `@discordjs/voice` 의 node>=22 요구도 충족하지 못해 변경했다.)
|
|
|
|
## 동작 흐름 요약
|
|
|
|
1. `messageCreate` → 등록된 TTS 채널이면 `TTSClient.tts()` 호출
|
|
2. 텍스트 전처리(URL/멘션/이모지 치환) → 시그니처 키워드 분할
|
|
3. 각 조각을 Chzzk TTS로 합성 또는 캐시된 시그니처 mp3 사용
|
|
4. mp3 Buffer 결합 → `Transcode`에서 PCM 변환 → `VoiceSession.player.play()`
|
|
5. 일정 시간 idle 시 세션 자동 종료, 사용자 채널 이동 시 따라감
|
|
|
|
## 참고
|
|
|
|
- 시그니처 서버 주소(`192.168.10.5:2967`)는 `SignatureClient.ts`에 하드코딩 — 환경에 맞게 수정 필요
|
|
- `commands/` 내 파일은 default export class 형태로 자동 로드되므로 새 명령어 추가 시 같은 패턴 유지
|
|
- 현재 `users` 테이블 스키마는 정의돼 있으나 코드에서 사용 흔적은 적음 (향후 확장 여지)
|