315 lines
8.4 KiB
Markdown
315 lines
8.4 KiB
Markdown
# Kord - YouTube 음악 재생 기능 기획안 (YouTube Music Playback)
|
|
|
|
## 체인지로그 (Changelog)
|
|
- **2026-03-30**: 최초 기획안 작성
|
|
|
|
---
|
|
|
|
## 1. 개요
|
|
|
|
YouTube 음악 재생 기능은 사용자가 텍스트 기반 명령으로 음악을 검색하거나 YouTube 링크를 입력하면,
|
|
현재 참여 중인 음성 채팅방에 봇이 입장하여 재생 목록(플레이리스트)을 관리하고 오디오를 재생하는 기능입니다.
|
|
|
|
이 기능은 서버 유틸리티를 넘어서 실시간 상호작용 기능으로 확장되는 첫 사례이며,
|
|
음성 연결, 큐 관리, UI 컨트롤, 외부 미디어 소스 처리까지 포함하는 비교적 큰 범위의 기능입니다.
|
|
|
|
### 목표
|
|
|
|
- 문자열 검색으로 YouTube 영상을 찾아 재생 목록에 추가할 수 있어야 함
|
|
- YouTube 링크를 입력해 직접 재생 목록에 추가할 수 있어야 함
|
|
- 현재 재생 목록을 조회할 수 있어야 함
|
|
- 인덱스 기반으로 재생 목록 항목을 삭제할 수 있어야 함
|
|
- 재생 중지 / 스킵 / 일시정지 / 재개 등 기본 컨트롤을 버튼 또는 이모지 기반 UI로 제공해야 함
|
|
- 음악 추가 요청 시, 요청자가 있는 음성 채팅방에 봇이 자동 입장하고 재생을 시작해야 함
|
|
- 마지막에 봇을 음성 채팅방에서 내보내는 기능이 있어야 함
|
|
|
|
---
|
|
|
|
## 2. 지원 범위 (MVP)
|
|
|
|
### 포함
|
|
|
|
- `/music add query:<문자열>`
|
|
- `/music add url:<YouTube 링크>`
|
|
- `/music queue`
|
|
- `/music remove index:<번호>`
|
|
- `/music skip`
|
|
- `/music stop`
|
|
- `/music leave`
|
|
- 재생 컨트롤 메시지 (버튼 또는 이모지 라벨 기반)
|
|
- 음성 채널 자동 입장 및 큐 기반 연속 재생
|
|
|
|
### 제외 (초기 범위 외)
|
|
|
|
- Spotify, SoundCloud 등 타 플랫폼 연동
|
|
- 반복 재생 / 셔플 / 볼륨 조절
|
|
- 길드별 DJ 역할 분리
|
|
- 재생 이력 저장
|
|
- 노래 가사 표시
|
|
|
|
---
|
|
|
|
## 3. 사용자 시나리오
|
|
|
|
### 시나리오 A: 검색어로 곡 추가
|
|
|
|
1. 사용자가 음성 채널에 입장한 상태에서 `/music add query:아이유 좋은날` 실행
|
|
2. 봇이 검색 결과 1위를 선택하거나 선택 UI를 제공
|
|
3. 재생 목록에 곡을 추가
|
|
4. 봇이 음성 채널에 자동 입장
|
|
5. 현재 재생 중이 없다면 즉시 재생 시작
|
|
|
|
### 시나리오 B: 링크로 곡 추가
|
|
|
|
1. 사용자가 `/music add url:https://www.youtube.com/watch?v=...` 실행
|
|
2. 봇이 링크 메타데이터를 파싱
|
|
3. 재생 목록에 항목 추가
|
|
4. 이미 재생 중이면 큐 뒤에 대기
|
|
|
|
### 시나리오 C: 큐 조회 및 삭제
|
|
|
|
1. 사용자가 `/music queue` 실행
|
|
2. 봇이 현재 재생곡과 대기열을 인덱스와 함께 Embed로 표시
|
|
3. 사용자가 `/music remove index:3` 실행
|
|
4. 3번 항목이 큐에서 제거됨
|
|
|
|
### 시나리오 D: 컨트롤 UI 사용
|
|
|
|
1. 재생 시작 시 봇이 "지금 재생 중" 메시지를 게시
|
|
2. 메시지에는 ⏸️, ▶️, ⏭️, ⏹️ 같은 버튼이 포함됨
|
|
3. 사용자가 버튼을 눌러 재생 상태를 제어
|
|
|
|
---
|
|
|
|
## 4. 명령 구조 제안
|
|
|
|
### `/music add`
|
|
|
|
입력 방식:
|
|
|
|
- `query`: YouTube 검색 문자열
|
|
- `url`: YouTube 링크
|
|
|
|
규칙:
|
|
|
|
- 두 옵션 중 하나만 입력
|
|
- 사용자는 반드시 음성 채널에 있어야 함
|
|
|
|
### `/music queue`
|
|
|
|
출력:
|
|
|
|
- 현재 재생 중 항목
|
|
- 대기열 목록
|
|
- 각 곡의 인덱스, 제목, 길이, 요청자
|
|
|
|
### `/music remove`
|
|
|
|
입력:
|
|
|
|
- `index`: 큐에서 제거할 번호
|
|
|
|
### `/music skip`
|
|
|
|
- 현재 곡을 스킵하고 다음 곡 재생
|
|
|
|
### `/music stop`
|
|
|
|
- 재생 중지
|
|
- 현재 곡 정지 및 대기열 비움 여부는 정책 선택 필요
|
|
|
|
### `/music leave`
|
|
|
|
- 봇을 음성 채널에서 퇴장시킴
|
|
- 기본 정책은 큐도 함께 정리
|
|
|
|
---
|
|
|
|
## 5. 재생 컨트롤 UI
|
|
|
|
### 컨트롤 메시지 구성
|
|
|
|
재생 시작 시 텍스트 채널에 Embed + 버튼 메시지 생성
|
|
|
|
권장 버튼:
|
|
|
|
- `⏸️` 일시정지
|
|
- `▶️` 재개
|
|
- `⏭️` 스킵
|
|
- `⏹️` 정지
|
|
- `📜` 큐 보기
|
|
|
|
### 정책
|
|
|
|
- 한 길드당 활성 컨트롤 메시지 1개 유지
|
|
- 곡이 바뀔 때 동일 메시지를 업데이트하거나 새 메시지를 생성할지 결정 필요
|
|
- MVP에서는 새 메시지 생성보다 기존 메시지 업데이트가 로그 노이즈를 줄이는 데 유리
|
|
|
|
---
|
|
|
|
## 6. 큐 및 재생 상태 설계
|
|
|
|
### 핵심 개념
|
|
|
|
- 재생 상태는 길드 단위로 분리
|
|
- 각 길드는 하나의 음성 연결과 하나의 큐를 가짐
|
|
- 큐는 메모리 기반으로 시작하고, 필요 시 DB 영속화 확장 가능
|
|
|
|
### 추천 구조
|
|
|
|
```ts
|
|
interface MusicQueueItem {
|
|
id: string;
|
|
title: string;
|
|
url: string;
|
|
durationSec?: number;
|
|
requestedByUserId: string;
|
|
}
|
|
|
|
interface GuildMusicSession {
|
|
guildId: string;
|
|
voiceChannelId: string;
|
|
textChannelId: string;
|
|
nowPlaying: MusicQueueItem | null;
|
|
queue: MusicQueueItem[];
|
|
paused: boolean;
|
|
controlMessageId?: string;
|
|
}
|
|
```
|
|
|
|
### 초기 전략
|
|
|
|
- 메모리 기반 세션 관리
|
|
- 봇 재시작 시 큐는 초기화됨
|
|
- 안정화 이후 DB 저장 여부 검토
|
|
|
|
---
|
|
|
|
## 7. 음성 입장 및 재생 흐름
|
|
|
|
### 자동 입장
|
|
|
|
- `/music add` 실행 시 사용자의 음성 채널을 확인
|
|
- 봇이 해당 채널에 없으면 자동 입장
|
|
- 이미 다른 채널에 있으면 정책 필요
|
|
|
|
### 기본 정책 제안
|
|
|
|
- 같은 길드 내에서 봇이 이미 재생 중이면 다른 채널 요청은 거부
|
|
- "현재 다른 음성 채널에서 사용 중" 메시지 제공
|
|
|
|
### 자동 퇴장
|
|
|
|
- `/music leave`로 수동 퇴장 가능
|
|
- 추가 정책 후보:
|
|
- 큐가 끝나고 1분 뒤 자동 퇴장
|
|
- 음성 채널에 봇만 남으면 자동 퇴장
|
|
|
|
---
|
|
|
|
## 8. YouTube 검색 및 스트리밍 전략
|
|
|
|
> [!IMPORTANT]
|
|
> YouTube 관련 기능은 라이브러리 안정성, 차단 이슈, 서비스 정책을 반드시 검토해야 합니다.
|
|
|
|
### 검색
|
|
|
|
가능한 접근:
|
|
|
|
- YouTube 공식 API 사용
|
|
- 서드파티 검색 라이브러리 사용
|
|
|
|
### 오디오 스트리밍
|
|
|
|
가능한 접근:
|
|
|
|
- `@discordjs/voice` 기반 음성 재생
|
|
- YouTube 스트림 추출 라이브러리 사용
|
|
|
|
### 기술 리스크
|
|
|
|
- YouTube 구조 변경 시 스트림 추출 라이브러리 고장 가능
|
|
- 지역 제한 / 연령 제한 / 라이브 영상 처리 문제
|
|
- 긴 재생 목록에서 메모리 및 연결 안정성 문제
|
|
|
|
---
|
|
|
|
## 9. 권한 및 운영 정책
|
|
|
|
### 봇 권한
|
|
|
|
- `Connect`
|
|
- `Speak`
|
|
- `View Channel`
|
|
- 텍스트 채널의 `Send Messages`, `Embed Links`
|
|
|
|
### 사용자 권한
|
|
|
|
- 기본적으로 일반 사용자도 곡 추가 가능
|
|
- `skip`, `stop`, `leave`, `remove`는 다음 중 하나로 제한 가능
|
|
- 관리자 전용
|
|
- 요청자 또는 관리자
|
|
- 같은 음성 채널 참여자 전원 허용
|
|
|
|
### 추천 MVP 정책
|
|
|
|
- `add`, `queue`: 같은 음성 채널 참여자 누구나 가능
|
|
- `skip`, `stop`, `remove`, `leave`: 관리자 또는 같은 음성 채널 참여자 허용
|
|
|
|
---
|
|
|
|
## 10. 에러 처리
|
|
|
|
필수 안내 케이스:
|
|
|
|
- 사용자가 음성 채널에 없음
|
|
- 유효하지 않은 YouTube 링크
|
|
- 검색 결과 없음
|
|
- 재생 목록 인덱스 범위 오류
|
|
- 봇 음성 권한 부족
|
|
- 스트림 로드 실패
|
|
|
|
에러 메시지는 기존 Error Guidance 체계와 연결하는 것이 좋습니다.
|
|
|
|
---
|
|
|
|
## 11. 구현 단계 (Phased Implementation)
|
|
|
|
| 단계 | 내용 |
|
|
|------|------|
|
|
| **Phase 1** | `@discordjs/voice` 기반 음성 연결, 메모리 큐, `/music add`, `/music queue`, `/music skip`, `/music leave` |
|
|
| **Phase 2** | 링크 기반 추가 + 검색 기반 추가 분리, `/music remove`, `/music stop` |
|
|
| **Phase 3** | 컨트롤 메시지(⏸️ ▶️ ⏭️ ⏹️) 및 상호작용 처리 |
|
|
| **Phase 4** | 자동 퇴장, 권한 정책 세분화, 예외 처리 고도화 |
|
|
| **Phase 5** | 반복 재생, 셔플, DJ 역할, 재생 이력 등 확장 기능 |
|
|
|
|
---
|
|
|
|
## 12. 검증 계획
|
|
|
|
### 수동 테스트
|
|
|
|
1. 음성 채널 입장 후 검색어로 곡 추가
|
|
2. 링크로 곡 추가
|
|
3. 큐 조회 및 인덱스 삭제
|
|
4. 스킵 / 정지 / 퇴장 동작 확인
|
|
5. 곡 종료 후 다음 곡 자동 재생 확인
|
|
6. 권한 부족 환경에서 적절한 에러 표시 확인
|
|
|
|
### 자동 테스트
|
|
|
|
- 큐 삽입 / 삭제 / 스킵 로직 단위 테스트
|
|
- 길드별 세션 분리 테스트
|
|
- 인덱스 유효성 검사 테스트
|
|
- 컨트롤 인터랙션 핸들러 테스트
|
|
|
|
---
|
|
|
|
## 13. 관련 문서
|
|
|
|
| 문서 | 링크 |
|
|
|------|------|
|
|
| 기능 로드맵 | [`Feature_Roadmap.md`](./Feature_Roadmap.md) |
|
|
| 임시 음성 채널 기획 | [`Temp_Voice_Channel_Plan.md`](./Temp_Voice_Channel_Plan.md) |
|
|
| 에러 안내 기획 | [`Error_Guidance_Plan.md`](./Error_Guidance_Plan.md) |
|