From 25cf66aea2ba05ef3ed84c53b060666e97fcb8f3 Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Mon, 13 Jul 2026 11:20:55 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20rewrite=20radio=20voice=20connection=20?= =?UTF-8?q?=E2=80=94=20no=20thread=20blocking,=20no=20abort,=20no=20URL=20?= =?UTF-8?q?loss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - remove 30s+30s VoiceHelper.waitForCondition that blocked JDA event thread - remove abort on voice/player timeout (TrackScheduler retries sendTrack itself) - remove openAudioConnection() that conflicted with Lavalink voice interceptor - preserve stream URL across stopRadio/restart instead of losing it - pass null queueRepository to GuildMusicManager (radio has no queue persistence) - run startRadio in virtual thread from RadioBotListener/RadioCommand --- .../loki/feature/radio/RadioBotListener.java | 2 +- .../loki/feature/radio/RadioManager.java | 54 ++++++------------- .../feature/radio/commands/RadioCommand.java | 2 +- 3 files changed, 17 insertions(+), 41 deletions(-) diff --git a/src/main/java/creator/loki/feature/radio/RadioBotListener.java b/src/main/java/creator/loki/feature/radio/RadioBotListener.java index 44beaa0..3355042 100644 --- a/src/main/java/creator/loki/feature/radio/RadioBotListener.java +++ b/src/main/java/creator/loki/feature/radio/RadioBotListener.java @@ -91,7 +91,7 @@ public class RadioBotListener extends ListenerAdapter { radioManager.setRadio(guild.getIdLong(), url); VoiceChannel vc = member.getVoiceState().getChannel().asVoiceChannel(); - radioManager.startRadio(guild.getIdLong(), vc.getIdLong()); + Thread.startVirtualThread(() -> radioManager.startRadio(guild.getIdLong(), vc.getIdLong())); event.getChannel().sendMessage("📻 Радио запущено: **" + url + "**").queue(); } diff --git a/src/main/java/creator/loki/feature/radio/RadioManager.java b/src/main/java/creator/loki/feature/radio/RadioManager.java index 86d1642..56d251a 100644 --- a/src/main/java/creator/loki/feature/radio/RadioManager.java +++ b/src/main/java/creator/loki/feature/radio/RadioManager.java @@ -2,7 +2,6 @@ package creator.loki.feature.radio; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -10,7 +9,6 @@ import creator.loki.feature.music.core.LavalinkManager; import creator.loki.feature.music.manage.GuildMusicManager; import creator.loki.feature.music.repository.QueueRepository; import creator.loki.util.LoggerDecorator; -import creator.loki.util.VoiceHelper; import dev.arbjerg.lavalink.client.AbstractAudioLoadResultHandler; import dev.arbjerg.lavalink.client.Link; import dev.arbjerg.lavalink.client.player.TrackLoaded; @@ -22,7 +20,6 @@ import org.slf4j.LoggerFactory; @Singleton public class RadioManager { private static final Logger logger = LoggerFactory.getLogger(RadioManager.class); - private static final long CONNECT_TIMEOUT_MS = 30000; private final Map radioStates = new ConcurrentHashMap<>(); private final QueueRepository queueRepository; @@ -62,11 +59,15 @@ public class RadioManager { GuildRadioState state = radioStates.get(guildId); if (state == null || state.streamUrl == null || state.streamUrl.isBlank()) return; if (radioJda == null || lavalinkManager == null) return; - if (isRadioActive(guildId) && state.musicManager != null) { - stopRadio(guildId); - } - var finalState = radioStates.computeIfAbsent(guildId, id -> new GuildRadioState()); - finalState.streamUrl = getRadioUrl(guildId); + + String url = state.streamUrl; + int vol = state.volume; + if (state.musicManager != null) stopRadio(guildId); + + GuildRadioState finalState = radioStates.computeIfAbsent(guildId, id -> new GuildRadioState()); + finalState.streamUrl = url; + finalState.volume = vol; + Guild guild = radioJda.getGuildById(guildId); if (guild == null) { logger.warn("Radio: guild {} not found in radio bot cache", guildId); @@ -77,45 +78,20 @@ public class RadioManager { logger.warn("Radio: voice channel {} not found in guild {}", channelId, guildId); return; } - logger.debug("Radio: connecting to channel {}/{} in guild {}", vc.getName(), channelId, guildId); var self = guild.getMember(guild.getJDA().getSelfUser()); if (self == null) { logger.warn("Radio: self member is null for guild {}", guildId); return; } - logger.debug( - "Radio: bot has CONNECT permission: {}", - self.hasPermission(vc, net.dv8tion.jda.api.Permission.VOICE_CONNECT)); - guild.getJDA().getDirectAudioController().connect(vc); - if (!guild.getAudioManager().isConnected()) { - guild.getAudioManager().openAudioConnection(vc); - } - var link = lavalinkManager.getOrCreateLink(guildId); - - VoiceHelper.waitForCondition( - () -> self.getVoiceState().inAudioChannel(), CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS); - if (self.getVoiceState().inAudioChannel()) { - logger.info("Radio: voice connected for guild {}", guildId); - } else { - logger.warn("Radio: voice not connected after {}ms for guild {}", CONNECT_TIMEOUT_MS, guildId); - } - - VoiceHelper.waitForCondition( - () -> link.getCachedPlayer() != null, CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS); - if (link.getCachedPlayer() != null) { - logger.info("Radio: player created for guild {}", guildId); - } else { - logger.warn("Radio: no player after {}ms for guild {}", CONNECT_TIMEOUT_MS, guildId); - } - - if (!self.getVoiceState().inAudioChannel() || link.getCachedPlayer() == null) { - LoggerDecorator.warn(logger, "Radio: skipping — no voice or player for guild " + guildId); + if (!self.hasPermission(vc, net.dv8tion.jda.api.Permission.VOICE_CONNECT)) { + logger.warn("Radio: no CONNECT permission in channel {}/{}", channelId, guildId); return; } - var mm = new GuildMusicManager(guildId, lavalinkManager, queueRepository); - int vol = finalState.volume; - var url = finalState.streamUrl; + var link = lavalinkManager.getOrCreateLink(guildId); + guild.getJDA().getDirectAudioController().connect(vc); + + var mm = new GuildMusicManager(guildId, lavalinkManager, null); finalState.musicManager = mm; lavalinkManager .getOrCreateLink(guildId) diff --git a/src/main/java/creator/loki/feature/radio/commands/RadioCommand.java b/src/main/java/creator/loki/feature/radio/commands/RadioCommand.java index a9b14a0..903bbaf 100644 --- a/src/main/java/creator/loki/feature/radio/commands/RadioCommand.java +++ b/src/main/java/creator/loki/feature/radio/commands/RadioCommand.java @@ -132,7 +132,7 @@ public class RadioCommand implements Command { } long channelId = member.getVoiceState().getChannel().getIdLong(); - radioManager.startRadio(guildId, channelId); + Thread.startVirtualThread(() -> radioManager.startRadio(guildId, channelId)); context .getChannel() .sendMessageEmbeds(