Is your feature request related to a problem? Please describe.
Currently the player has playback control buttons (pause, skip, shuffle, etc.) but no way to view lyrics for the currently playing track. Users have to look up lyrics manually outside Discord.
Describe the solution you'd like
Add a Lyrics button (📝) to the player's action row that fetches and displays lyrics for the current track using LavaLyrics + LavaSrc's built-in lyrics providers.
Implementation Plan
🧱 1. Build Configuration
- File:
gradle/libs.versions.toml
- Add version:
lavalyrics = "1.1.0"
- Add library:
lavalyrics = { module = "com.github.topi314.lavalyrics:lavalyrics", version.ref = "lavalyrics" }
- File:
build.gradle.kts
- Add dependency:
implementation(libs.lavalyrics)
- No new repository needed —
https://maven.topi.wtf/releases is already configured.
📦 2. New Service: LyricsService
- Path:
src/main/kotlin/services/lavaplayer/LyricsService.kt
- Wraps LavaLyrics'
LyricsManager and registers LrcLibLyricsManager (from LavaSrc) as the lyrics provider.
LrcLibLyricsManager searches lrclib.net by track name + artist, works for any source (YouTube, Spotify, Deezer, etc.)
- Exposes:
getLyrics(track: AudioTrack): AudioLyrics? — fetches lyrics
getFormattedLyrics(track: AudioTrack): String? — returns formatted plain text lyrics or null
- Future enhancement: Register
SpotifySourceManager / DeezerAudioSourceManager directly into LyricsManager once they're exposed from AudioPlayerManagerProvider, for source-native higher-quality lyrics.
🔌 3. DI Registration
- File:
src/main/kotlin/di/ServicesModule.kt
- Add
singleOf(::LyricsService) (singleton)
🆕 4. Button Component
- File:
src/main/kotlin/commands/ComponentsEnum.kt
- Add
PLAYER_LYRICS("player_lyrics")
🎛️ 5. Player UI — Add Button
- File:
src/main/kotlin/commands/player/PlayerCommons.kt
- Add lyrics button (📝) to
createPlayerComponents():
interactionButton(
style = ButtonStyle.Secondary,
customId = ComponentsEnum.PLAYER_LYRICS.customId
) {
label = localizationService.getString(key = LocalizationKeys.PLAYER_LYRICS, ...)
emoji = DiscordPartialEmoji(name = "📝")
}
🕹️ 6. Button Handler
- File:
src/main/kotlin/commands/player/PlayerCommand.kt
- Inject
LyricsService
- Add
PLAYER_LYRICS case in onInteract():
- Get current track from
lavaPlayerService.getCurrentPlayingTrack()
- If nothing playing → send ephemeral "no track playing"
- Try
lyricsService.getFormattedLyrics(track.audioTrack)
- If found → send ephemeral message with lyrics
- If not → send ephemeral "lyrics not found" message
🌐 7. Localization
lang.yml:
player_lyrics: Lyrics
player_lyrics_not_found: No lyrics found for the current track
player_lyrics_title: Lyrics — %s
lang_es-ES.yml:
player_lyrics: Letra
player_lyrics_not_found: No se encontraron letras para la pista actual
player_lyrics_title: Letra — %s
LocalizationKeys.kt — auto-generated via generateLangClass Gradle task.
🧪 8. Tests
- Path:
src/test/kotlin/services/lavaplayer/LyricsServiceTest.kt
- Unit tests for
LyricsService with mocked LyricsManager:
- Returns lyrics when found
- Returns null when no lyrics available
- Handles null/empty/malformed responses
Architecture Reference
| Component |
File |
Relevant Lines |
| Player embed builder |
commands/player/PlayerCommons.kt |
23-87 embed, 102-150 buttons |
| Button handler |
commands/player/PlayerCommand.kt |
146-176 |
| Button IDs enum |
commands/ComponentsEnum.kt |
3-26 |
| Button dispatch |
services/commands/CommandHandlerService.kt |
112-137, 168-179 |
| DI ServicesModule |
di/ServicesModule.kt |
21-34 |
| LyricsManager (LavaLyrics) |
LavaLyrics repo |
LyricsManager.java, AudioLyrics.java |
| LrcLibLyricsManager (LavaSrc) |
LavaSrc repo |
lrclib/LrcLibLyricsManager.java |
Describe alternatives you've considered
- Modal popup: Discord modals have 4000-char limit and disappear after one use — unsuitable for lyrics.
- Edit player embed: Would replace the controls interface until next interaction — disruptive UX.
- Separate channel: Creates noise — ephemeral follow-up is cleaner.
- Scrolling embed: Discord embeds have field limits — synchronous lyrics in a text message is simpler.
Chosen UX: Ephemeral follow-up message (only the user who clicked sees it), showing lyrics in a code block for readability.
Additional context
- LavaSrc (
v4.8.1) already has AudioLyricsManager implementations in Spotify, Deezer, Yandex Music, and VK Music source managers.
- The
LrcLibLyricsManager from LavaSrc provides a fallback that works for any track by searching by artist+title.
- The repository
https://maven.topi.wtf/releases is already configured.
- LavaLyrics v1.1.0 requires no new infrastructure.
Media
N/A — this is a feature request.
Is your feature request related to a problem? Please describe.
Currently the player has playback control buttons (pause, skip, shuffle, etc.) but no way to view lyrics for the currently playing track. Users have to look up lyrics manually outside Discord.
Describe the solution you'd like
Add a Lyrics button (📝) to the player's action row that fetches and displays lyrics for the current track using LavaLyrics + LavaSrc's built-in lyrics providers.
Implementation Plan
🧱 1. Build Configuration
gradle/libs.versions.tomllavalyrics = "1.1.0"lavalyrics = { module = "com.github.topi314.lavalyrics:lavalyrics", version.ref = "lavalyrics" }build.gradle.ktsimplementation(libs.lavalyrics)https://maven.topi.wtf/releasesis already configured.📦 2. New Service:
LyricsServicesrc/main/kotlin/services/lavaplayer/LyricsService.ktLyricsManagerand registersLrcLibLyricsManager(from LavaSrc) as the lyrics provider.LrcLibLyricsManagersearches lrclib.net by track name + artist, works for any source (YouTube, Spotify, Deezer, etc.)getLyrics(track: AudioTrack): AudioLyrics?— fetches lyricsgetFormattedLyrics(track: AudioTrack): String?— returns formatted plain text lyrics or nullSpotifySourceManager/DeezerAudioSourceManagerdirectly intoLyricsManageronce they're exposed fromAudioPlayerManagerProvider, for source-native higher-quality lyrics.🔌 3. DI Registration
src/main/kotlin/di/ServicesModule.ktsingleOf(::LyricsService)(singleton)🆕 4. Button Component
src/main/kotlin/commands/ComponentsEnum.ktPLAYER_LYRICS("player_lyrics")🎛️ 5. Player UI — Add Button
src/main/kotlin/commands/player/PlayerCommons.ktcreatePlayerComponents():interactionButton( style = ButtonStyle.Secondary, customId = ComponentsEnum.PLAYER_LYRICS.customId ) { label = localizationService.getString(key = LocalizationKeys.PLAYER_LYRICS, ...) emoji = DiscordPartialEmoji(name = "📝") }🕹️ 6. Button Handler
src/main/kotlin/commands/player/PlayerCommand.ktLyricsServicePLAYER_LYRICScase inonInteract():lavaPlayerService.getCurrentPlayingTrack()lyricsService.getFormattedLyrics(track.audioTrack)🌐 7. Localization
lang.yml:lang_es-ES.yml:LocalizationKeys.kt— auto-generated viagenerateLangClassGradle task.🧪 8. Tests
src/test/kotlin/services/lavaplayer/LyricsServiceTest.ktLyricsServicewith mockedLyricsManager:Architecture Reference
commands/player/PlayerCommons.ktcommands/player/PlayerCommand.ktcommands/ComponentsEnum.ktservices/commands/CommandHandlerService.ktdi/ServicesModule.ktLyricsManager.java,AudioLyrics.javalrclib/LrcLibLyricsManager.javaDescribe alternatives you've considered
Chosen UX: Ephemeral follow-up message (only the user who clicked sees it), showing lyrics in a code block for readability.
Additional context
v4.8.1) already hasAudioLyricsManagerimplementations in Spotify, Deezer, Yandex Music, and VK Music source managers.LrcLibLyricsManagerfrom LavaSrc provides a fallback that works for any track by searching by artist+title.https://maven.topi.wtf/releasesis already configured.Media
N/A — this is a feature request.