Until now every TTS message was synthesized with VoiceType.가람
regardless of who spoke. This adds a user-scoped voice preference
persisted in SQLite so each member can pick their own voice and
keep it across bot restarts.
Changes
- db/schema.sql: add nullable `voice_type` column to `users`.
- src/utils/Database.ts:
- run a PRAGMA-driven ALTER TABLE migration so existing DBs gain
the column without dropping data.
- add `DB.user.setVoice(guildId, userId, name, voiceType)` that
upserts the row.
- src/classes/TTSClient.ts:
- export `DEFAULT_VOICE` (= 가람).
- resolve the speaking member's stored voice in `tts()` and
thread it through `getSource()` instead of hardcoding 가람.
- validate stored slug against `VoiceType` so stale/unknown
values silently fall back to the default.
- src/commands/voice.ts (new):
- `/목소리` slash command shows the user's current voice and a
StringSelectMenu of all `VoiceType` entries (현재 + 이전 보이스
모두). Selection writes to `users.voice_type` and confirms
ephemerally.
- defensively creates a guild row if `/tts channel register`
hasn't run yet, to satisfy the ON DELETE CASCADE FK.
Deploy
Run `npm run prod` after pulling so Discord sees the new
`/목소리` command. No env or config changes required.
23 lines
966 B
SQL
23 lines
966 B
SQL
-- 외래키 제약 조건 활성화
|
|
-- 기본적으로 SQLite는 외래키 검사 안함 그래서 켜줘야 함
|
|
PRAGMA foreign_keys = ON;
|
|
|
|
CREATE TABLE IF NOT EXISTS guilds (
|
|
id TEXT PRIMARY KEY, -- 길드 ID (전역 유일값)
|
|
name TEXT NOT NULL, -- 길드 이름 (캐싱용)
|
|
channel_id TEXT NOT NULL -- 채팅 ID
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
guild_id TEXT NOT NULL, -- 소속 길드 ID, guilds.id를 참조
|
|
id TEXT NOT NULL, -- 유저 ID
|
|
name TEXT NOT NULL, -- 유저 이름 (캐싱용)
|
|
voice_type TEXT, -- TTS 목소리 슬러그 (NULL = 기본)
|
|
|
|
-- 복합 기본키: 같은 길드 안에서 id는 중복 불가
|
|
PRIMARY KEY (guild_id, id),
|
|
|
|
-- 외래키 설정: guilds.id를 참조
|
|
-- 길드가 삭제되면 소속된 유저도 자동으로 삭제됨 (ON DELETE CASCADE)
|
|
FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE
|
|
); |