page - /login(디스코드 로그인 전용), /servers(서버 선택 전용), /servers/[id](유튜브 뮤직 플레이어)로 분리 · 서버 컴포넌트에서 로그인 검사, callbackUrl 은 같은 사이트 경로만 허용 · NextAuth 로그인/오류 화면도 /login 으로 - 서버 선택: 최근 사용 서버 맨 앞 "최근" 표시, 새로고침, 8개 초과 시 이름 검색, 오류 표시 - 플레이어: 검색어를 ?q= 로 남겨 뒤로가기 지원, 탭 제목에 지금 곡, 내 서버가 아니면 안내 - 검색창: 최근 검색어 목록, 유튜브·스포티파이 주소를 붙여넣으면 곡/재생목록 바로 불러오기 - 다음 트랙: 섞기, 모두 지우기(두 번 눌러 확인), 자동재생 스위치, 곡 수·총 길이 - 재생바: 처음부터 다시(⏮), 섞기 버튼 / 서버 홈: 음성채널 표시, 사용 안내, 최근 검색 칩 - 곡 추가 중 스피너 + 중복 추가 방지, 검색 실패 시 다시 시도, play/playlist 응답 대기 15초 - 계정 전환형 프로필 메뉴와 사이드바 서버 목록 제거(프로필은 서버 변경·로그아웃만) bot - Redis 액션 queue_shuffle, player_recommend 추가 - player_now 응답에 recommend(자동재생), voiceChannelName 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { Logger } from "@/lib/Logger";
|
|
import { botRpc, errorResponse, readJsonBody, requireSession, requireString } from "@/lib/api";
|
|
|
|
interface PlayBody {
|
|
serverId?: unknown;
|
|
track?: unknown;
|
|
}
|
|
|
|
export async function POST(request: Request) {
|
|
try {
|
|
const sessionResult = await requireSession();
|
|
if (!sessionResult.ok) return sessionResult.response;
|
|
const userId = sessionResult.session.user.id;
|
|
|
|
const bodyResult = await readJsonBody<PlayBody>(request);
|
|
if (!bodyResult.ok) return bodyResult.response;
|
|
|
|
const serverIdResult = requireString(bodyResult.data.serverId, "serverId");
|
|
if (!serverIdResult.ok) return serverIdResult.response;
|
|
|
|
const track = bodyResult.data.track;
|
|
if (!track || typeof track !== "object") return errorResponse("track 정보가 필요합니다.");
|
|
|
|
const { status, body } = await botRpc({
|
|
channel: "player:play",
|
|
payload: {
|
|
action: "player_play",
|
|
serverId: serverIdResult.value,
|
|
userId,
|
|
track,
|
|
},
|
|
// 음성채널 접속 + 곡(재생목록) 해석까지 기다려야 해서 기본 3초로는 부족하다.
|
|
timeoutMs: 15000,
|
|
});
|
|
return NextResponse.json(body, { status });
|
|
} catch (error) {
|
|
Logger.error(`player/play API error: ${error instanceof Error ? error.message : String(error)}`);
|
|
return errorResponse("서버 오류가 발생했습니다.", 500);
|
|
}
|
|
}
|