diff --git a/bot/src/classes/LavalinkManager.ts b/bot/src/classes/LavalinkManager.ts index af71070..19d3634 100644 --- a/bot/src/classes/LavalinkManager.ts +++ b/bot/src/classes/LavalinkManager.ts @@ -121,10 +121,22 @@ export class LavalinkManager { // 기본: 유튜브뮤직(YoutubeMusic.getSearchUrl) 우선 → 결과가 없거나 애매(커버/방송/무관)하면 // getSearchUrl이 null을 주고, 공식 오디오를 잘 잡는 `ytsearch:... Topic`로 폴백한다. // ('-p' 플래그를 붙이면 스포티파이 우선 검색) + // 기본 경로는 YTM 검색과 ytsearch 폴백을 '동시에' 출발시킨다. + // YTM 적중률이 약 60%라, 빗나가는 40%에서는 YTM(~0.5초)을 기다린 뒤 다시 ytsearch(~0.5초)를 + // 도는 순차 대기가 통째로 낭비된다. 미리 같이 돌려두면 빗나가도 추가 대기가 없다. + // (적중 시에는 폴백 결과를 버리므로 Lavalink 검색 1회가 헛돌지만 비용이 작다.) let searchText: string; + let pendingFallback: ReturnType | null = null; if (isUrl) searchText = text; else if (flags.has('p')) searchText = (await Spotify.getSearchUrl(text)) ?? (await YoutubeMusic.getSearchUrl(text)) ?? `ytsearch:${text}`; - else searchText = (await YoutubeMusic.getSearchUrl(text)) ?? `ytsearch:${text}`; + else { + const fallbackText = `ytsearch:${text}` + (flags.has('o') ? "" : " Topic"); + pendingFallback = node.rest.resolve(fallbackText); + pendingFallback.catch(() => {}); // 적중해서 버려질 때 unhandledRejection 방지 + const ytm = await YoutubeMusic.getSearchUrl(text).catch(() => null); + searchText = ytm ?? fallbackText; + if (ytm) pendingFallback = null; // YTM 적중 → 폴백 결과는 사용하지 않음 + } // 스포티파이 트랙 URL은 Lavalink가 유튜브 '영상(뮤비)'으로 폴백한다(유튜브뮤직 연결돼 있어도). // 대시보드에서 고른 스포티파이 곡이나 `-p` 결과가 트랙 URL이면, 메타데이터(제목+아티스트)로 // 유튜브뮤직 '오디오'를 직접 찾아 대체한다(텍스트 검색 경로와 동일하게 원곡 오디오 우선). @@ -136,8 +148,9 @@ export class LavalinkManager { searchText = (await YoutubeMusic.getSearchUrl(q)) ?? `ytsearch:${q}`; } } - if (searchText.startsWith("ytsearch") && !flags.has('o')) searchText += " Topic"; - const result = await node.rest.resolve(searchText); + if (searchText.startsWith("ytsearch") && !flags.has('o') && !searchText.endsWith(" Topic")) searchText += " Topic"; + // 위에서 미리 띄워둔 폴백 검색이 있으면 그 결과를 그대로 쓴다(중복 요청 방지). + const result = pendingFallback ? await pendingFallback : await node.rest.resolve(searchText); if (!result || result.loadType === LoadType.EMPTY || result.loadType === LoadType.ERROR) { if (result?.loadType === LoadType.ERROR) Logger.error(`[LavalinkManager] loadtype ERROR: ${result.data.message}`); return null; diff --git a/docker-compose.exp.yml b/docker-compose.exp.yml index 03bab62..ba5c5b2 100644 --- a/docker-compose.exp.yml +++ b/docker-compose.exp.yml @@ -13,9 +13,9 @@ services: - SELFTEST_GUILD_ID=1352269198297923648 - SELFTEST_VOICE_CHANNEL_ID=1352269198914621465 - SELFTEST_TEXT_CHANNEL_ID=1421342055774289980 - - SELFTEST_QUERY=https://www.youtube.com/watch?v=E7EOjkGVmyo - - SELFTEST_WATCH_SEC=1920 + - SELFTEST_QUERY=aespa Supernova + - SELFTEST_WATCH_SEC=15 - YTRESOLVER_ENABLED=true - - YTRESOLVER_URL=http://192.168.10.5:8780 + - YTRESOLVER_URL=http://192.168.10.5:8779 volumes: - ./testdb:/db