Skip to content

[Suggestion] Implement lyrics button on player to fetch and display song lyrics #110

Description

@Wikijito7

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():
      1. Get current track from lavaPlayerService.getCurrentPlayingTrack()
      2. If nothing playing → send ephemeral "no track playing"
      3. Try lyricsService.getFormattedLyrics(track.audioTrack)
      4. If found → send ephemeral message with lyrics
      5. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsuggestionSuggestion to improve or change the bot

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions