RadioManager creates GuildMusicManager with null queueRepository (radio has no
queue persistence). Constructor called loadQueueAsync() which dereferenced null,
throwing NPE after voice connect — bot joined voice but track never loaded.
- 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
The local copy of JDAVoiceUpdateListener.onVoiceServerUpdate() checked
if the bot's cached voice channel was null and returned early, silently
dropping the voice server update. Discord often sends the voice server
update BEFORE the voice state update is processed by JDA, so the channel
was always null on first attempt -> Lavalink never received the update
-> voice connection never established -> timeout.
Fix: pass null channelId to Lavalink's VoiceState instead of aborting.
This matches the Kotlin original library code.
The radio bot's own LavalinkClient may not be connected yet when
startRadio() is called (async connection). Without this wait, the
voice server update is forwarded to a not-yet-connected client and
lost, causing a voice connection timeout.
Also ensure the radio bot uses its own LavalinkManager (separate
LavalinkClient with radio bot's user ID) instead of sharing the
main bot's, which caused user ID mismatch.
Radio bot is a separate Discord bot account but shared the main bot's
LavalinkManager (created with main bot's user ID). When the radio bot
connected to voice, Lavalink received voice server updates mismatched
with the expected user ID, causing voice connection timeout.
Now the radio bot creates its own LavalinkManager with its own token,
matching the pattern already used by the music bot.
- RizzCommand: 🗿 ризз-метр (харизма) с уровнями
- LuckCommand: 🍀 удача с уровнями
- AuraCommand: ✨ аура от -50 до 100 с цветами
- RatingConfig: уровни для rizz + luck
- Все зарегистрированы в EntertainmentCommandRegistrar
- LevelRoleCommand: set/remove/clear role mappings per level
- LevelRoleService: reads from ConfigRepository, falls back to defaults
- LevelCommandRegistrar: wires new command
- Создана доменная структура feature/level/ с разделением на domain/service
- ынесены классы LevelUpResult, LevelProgress, UserStats, XpFormula
- Созданы сервисы: LevelService, MessageCooldownService, LeaderboardService
- еремещены команды и листенеры в feature/level/
- далены импорты AudioManager и мертвые ссылки на TTS
- бновлены все тесты
овая функциональность:
- енератор красивых профильных карточек (RankCardGenerator)
- оманда !profile для просмотра карточки с уровнем, XP, статистикой
- оманда !stop для безопасной остановки бота (только админы)
- обавлены ассеты: фоны, иконки, бейджи
Технические улучшения:
- ерсистентный кулдаун через UserStats.lastMessageTime
- бобщенные методы лидерборда через Comparator
- Graceful shutdown с сохранением всех данных
- Fallback на заглушки если ассеты не загрузились