fix: rewrite radio voice connection — no thread blocking, no abort, no URL loss
- 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
This commit is contained in:
parent
37d50ab240
commit
25cf66aea2
3 changed files with 17 additions and 41 deletions
|
|
@ -91,7 +91,7 @@ public class RadioBotListener extends ListenerAdapter {
|
||||||
radioManager.setRadio(guild.getIdLong(), url);
|
radioManager.setRadio(guild.getIdLong(), url);
|
||||||
|
|
||||||
VoiceChannel vc = member.getVoiceState().getChannel().asVoiceChannel();
|
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();
|
event.getChannel().sendMessage("📻 Радио запущено: **" + url + "**").queue();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package creator.loki.feature.radio;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
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.manage.GuildMusicManager;
|
||||||
import creator.loki.feature.music.repository.QueueRepository;
|
import creator.loki.feature.music.repository.QueueRepository;
|
||||||
import creator.loki.util.LoggerDecorator;
|
import creator.loki.util.LoggerDecorator;
|
||||||
import creator.loki.util.VoiceHelper;
|
|
||||||
import dev.arbjerg.lavalink.client.AbstractAudioLoadResultHandler;
|
import dev.arbjerg.lavalink.client.AbstractAudioLoadResultHandler;
|
||||||
import dev.arbjerg.lavalink.client.Link;
|
import dev.arbjerg.lavalink.client.Link;
|
||||||
import dev.arbjerg.lavalink.client.player.TrackLoaded;
|
import dev.arbjerg.lavalink.client.player.TrackLoaded;
|
||||||
|
|
@ -22,7 +20,6 @@ import org.slf4j.LoggerFactory;
|
||||||
@Singleton
|
@Singleton
|
||||||
public class RadioManager {
|
public class RadioManager {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(RadioManager.class);
|
private static final Logger logger = LoggerFactory.getLogger(RadioManager.class);
|
||||||
private static final long CONNECT_TIMEOUT_MS = 30000;
|
|
||||||
|
|
||||||
private final Map<Long, GuildRadioState> radioStates = new ConcurrentHashMap<>();
|
private final Map<Long, GuildRadioState> radioStates = new ConcurrentHashMap<>();
|
||||||
private final QueueRepository queueRepository;
|
private final QueueRepository queueRepository;
|
||||||
|
|
@ -62,11 +59,15 @@ public class RadioManager {
|
||||||
GuildRadioState state = radioStates.get(guildId);
|
GuildRadioState state = radioStates.get(guildId);
|
||||||
if (state == null || state.streamUrl == null || state.streamUrl.isBlank()) return;
|
if (state == null || state.streamUrl == null || state.streamUrl.isBlank()) return;
|
||||||
if (radioJda == null || lavalinkManager == null) return;
|
if (radioJda == null || lavalinkManager == null) return;
|
||||||
if (isRadioActive(guildId) && state.musicManager != null) {
|
|
||||||
stopRadio(guildId);
|
String url = state.streamUrl;
|
||||||
}
|
int vol = state.volume;
|
||||||
var finalState = radioStates.computeIfAbsent(guildId, id -> new GuildRadioState());
|
if (state.musicManager != null) stopRadio(guildId);
|
||||||
finalState.streamUrl = getRadioUrl(guildId);
|
|
||||||
|
GuildRadioState finalState = radioStates.computeIfAbsent(guildId, id -> new GuildRadioState());
|
||||||
|
finalState.streamUrl = url;
|
||||||
|
finalState.volume = vol;
|
||||||
|
|
||||||
Guild guild = radioJda.getGuildById(guildId);
|
Guild guild = radioJda.getGuildById(guildId);
|
||||||
if (guild == null) {
|
if (guild == null) {
|
||||||
logger.warn("Radio: guild {} not found in radio bot cache", guildId);
|
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);
|
logger.warn("Radio: voice channel {} not found in guild {}", channelId, guildId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug("Radio: connecting to channel {}/{} in guild {}", vc.getName(), channelId, guildId);
|
|
||||||
var self = guild.getMember(guild.getJDA().getSelfUser());
|
var self = guild.getMember(guild.getJDA().getSelfUser());
|
||||||
if (self == null) {
|
if (self == null) {
|
||||||
logger.warn("Radio: self member is null for guild {}", guildId);
|
logger.warn("Radio: self member is null for guild {}", guildId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug(
|
if (!self.hasPermission(vc, net.dv8tion.jda.api.Permission.VOICE_CONNECT)) {
|
||||||
"Radio: bot has CONNECT permission: {}",
|
logger.warn("Radio: no CONNECT permission in channel {}/{}", channelId, guildId);
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mm = new GuildMusicManager(guildId, lavalinkManager, queueRepository);
|
var link = lavalinkManager.getOrCreateLink(guildId);
|
||||||
int vol = finalState.volume;
|
guild.getJDA().getDirectAudioController().connect(vc);
|
||||||
var url = finalState.streamUrl;
|
|
||||||
|
var mm = new GuildMusicManager(guildId, lavalinkManager, null);
|
||||||
finalState.musicManager = mm;
|
finalState.musicManager = mm;
|
||||||
lavalinkManager
|
lavalinkManager
|
||||||
.getOrCreateLink(guildId)
|
.getOrCreateLink(guildId)
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ public class RadioCommand implements Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
long channelId = member.getVoiceState().getChannel().getIdLong();
|
long channelId = member.getVoiceState().getChannel().getIdLong();
|
||||||
radioManager.startRadio(guildId, channelId);
|
Thread.startVirtualThread(() -> radioManager.startRadio(guildId, channelId));
|
||||||
context
|
context
|
||||||
.getChannel()
|
.getChannel()
|
||||||
.sendMessageEmbeds(
|
.sendMessageEmbeds(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue