diff --git a/bot/src/classes/GuildPlayer.ts b/bot/src/classes/GuildPlayer.ts index c40083b..e65bfc6 100644 --- a/bot/src/classes/GuildPlayer.ts +++ b/bot/src/classes/GuildPlayer.ts @@ -103,8 +103,11 @@ export class GuildPlayer { this.player.on("exception", async (data) => { try { - Logger.error(`[Lavalink] 재생 중 에러 발생: ${data.exception?.message}`); - await this.errMsg("유튜브 차단 또는 재생 오류로 인해 이 곡을 건너뜁니다."); + Logger.error(`[Lavalink] 재생 중 에러 발생: ${data.exception?.message}. 다음 곡으로 넘어갑니다.`); + // Lavalink는 exception 직후 TrackEndEvent(loadFailed)를 보내므로 end 핸들러가 다음 곡을 + // 진행시킨다. 여기서 stopTrack을 부르면 end가 중복 발생해 곡을 하나 더 건너뛰므로, + // 안내만 하고 errMsg의 5초 재시도 타이머는 끈다(retry=false). + await this.errMsg("유튜브 차단 또는 재생 오류로 인해 이 곡을 건너뜁니다.", false); } catch (err) { Logger.error(`[GuildPlayer] exception 이벤트 처리 중 에러: ${String(err)}`); } @@ -537,7 +540,7 @@ export class GuildPlayer { }); } - public async errMsg(reason: string) { + public async errMsg(reason: string, retry: boolean = true) { if (!this.msg) return null; await this.msg.edit({ content: this.msg.content, @@ -553,10 +556,14 @@ export class GuildPlayer { this.queue.length > 1, ) ] }); - this.errorTimer = setTimeout(() => { - this.errorTimer = undefined; - this.playNext(); - }, DelayAfterErrMs); + // retry=true일 때만 5초 뒤 현재 queue[0]을 재생. 재생 실패(exception)처럼 Lavalink가 + // 이미 end 이벤트로 다음 곡을 진행시키는 경우엔 retry=false로 호출해 중복 진행을 막는다. + if (retry) { + this.errorTimer = setTimeout(() => { + this.errorTimer = undefined; + this.playNext(); + }, DelayAfterErrMs); + } return null; } } \ No newline at end of file