Music System
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The Music System in Amina allows users to play audio in Discord voice channels from various sources. It is built upon the Lavalink audio server, which handles the complexities of audio streaming and processing, allowing the bot to remain lightweight and efficient. The system is managed through a series of slash commands, primarily /play and /queue.
The architecture separates the bot's command logic from the audio player management. A central MusicManager class acts as an interface to the Lavalink server, handling player creation, track searching, and queue management. Events are used to communicate state changes, such as when a new track starts playing, ensuring a responsive user experience.
Architecture
The music system is composed of three main parts: the Amina bot, the lavalink-client library, and the Lavalink server.
- Amina Bot: Handles user interactions (slash commands), permission checks, and sending messages to Discord.
lavalink-client: A Node.js library that acts as a wrapper around the Lavalink REST and WebSocket APIs, simplifying communication.- Lavalink Server: A standalone Java application that connects to Discord voice, fetches audio from sources like YouTube and SoundCloud, and streams it to the voice channel.
This diagram illustrates the high-level interaction between the components.
Configuration
The Music System's behavior is controlled by configuration in both the bot's main config file and the Lavalink server's application.yml.
Bot Configuration
These settings are defined in src/config/config.ts and control the bot's interaction with Lavalink and the user experience.
| Option | Type | Default Value | Description |
|---|---|---|---|
ENABLED | boolean | true | Toggles the entire music system. |
IDLE_TIME | number | 60 | Time in seconds before the bot disconnects from an idle voice channel. |
DEFAULT_VOLUME | number | 60 | The default player volume (1-100). |
MAX_SEARCH_RESULTS | number | 5 | The maximum number of search results to show for user selection. |
DEFAULT_SOURCE | string | scsearch | The default search prefix (e.g., ytsearch, scsearch). |
LAVALINK_RETRY_AMOUNT | number | 20 | Number of times to retry connecting to a Lavalink node. |
LAVALINK_RETRY_DELAY | number | 30000 | Delay in milliseconds between connection retries. |
LAVALINK_NODES | LavalinkNode[] | (from secrets) | An array of Lavalink node connection details. |
Sources: src/config/config.ts:80-96
Lavalink Server Configuration
The lavalink/application.yml file configures the Lavalink server itself, including which audio sources and plugins are enabled.
Plugins
Lavalink's functionality is extended via plugins.
| Plugin | Repository | Purpose |
|---|---|---|
youtube-plugin | dev.lavalink.youtube | Provides robust YouTube searching and playback. |
lavasrc-plugin | com.github.topi314.lavasrc | Adds support for Spotify, Apple Music, and Deezer. |
lavasearch-plugin | com.github.topi314.lavasearch | Enables advanced search functionality. |
sponsorblock-plugin | com.github.topi314.sponsorblock | Skips sponsored segments in YouTube videos. |
LavaDSPX-Plugin | com.github.Devoxin | Adds extra DSP filters like high-pass and echo. |
lavalyrics-plugin | com.github.topi314.lavalyrics | Provides a lyrics API. |
Sources: lavalink/application.yml:7-28
Sources & Filters
The configuration also specifies which native sources and filters are active.
- Enabled Sources:
bandcamp,soundcloud,twitch,vimeo,http. YouTube is handled by its plugin. - Enabled Filters:
volume,equalizer,karaoke,timescale,tremolo,vibrato,distortion,rotation,channelMix,lowPass.
Sources: lavalink/application.yml:33-46
Core Components
MusicManager (player.ts)
The MusicManager class is the central handler for all music-related operations. It is initialized once when the bot starts and is responsible for:
- Initializing and managing the
LavalinkManager: It connects to the Lavalink nodes defined in the configuration and handles connection events likeconnect,disconnect, anderror. - Creating and retrieving player instances: Each guild with an active music session has a
Playerinstance. ThecreatePlayermethod sets one up, binds it to a voice and text channel, and attaches event listeners. - Handling player events: It listens for
trackStart,trackEnd, andqueueEnd.- On
trackStart, it dispatches a custom event that is picked up bysrc/events/player/trackStart.tsto notify the user. - On
queueEnd, it starts an idle timer. If no new tracks are added within theIDLE_TIME, it disconnects the player.
- On
- Searching for tracks: The
searchAndPlaymethod uses the player'ssearch()function to query Lavalink for a track or playlist.
Sources: src/handlers/player.ts
Command Workflows
/play Command
The /play command is the entry point for starting music playback. The following sequence diagram shows the typical flow from a user's command to a track playing.
This diagram shows the process of a user initiating the /play command, the MusicManager handling the search and queueing, and the trackStart event notifying the user.
Sources: src/commands/music/play.ts, src/handlers/player.ts:46-118, src/events/player/trackStart.ts
/queue Command
The /queue command allows users to view the list of upcoming tracks.
- The command retrieves the guild's current player instance from the
MusicManager. - If a player exists and the queue is not empty, it constructs a paginated embed.
- The embed displays:
- The currently playing track.
- The total number of tracks and the total duration of the queue.
- A list of upcoming tracks for the current page.
- Navigation buttons (
previous,next) are provided to browse through the pages of the queue.
Sources: src/commands/music/queue.ts
User Responses
All user-facing text responses for the music system are stored in src/data/respMusic.json. This approach centralizes strings and allows for varied, more natural responses.
- Structure: The JSON is organized by command and event (e.g.,
play,queue,skip). Errors are grouped undererror. - Randomization: Many response keys map to an array of strings. The bot randomly selects one to send, preventing repetitive messages.
- Templating: Responses use placeholders like
{track}or{server}which are replaced with dynamic values at runtime.
Example Responses:
| Key | Example Value(s) | Purpose |
|---|---|---|
music.play | ["playing: {track}.", "now playing: {track}."] | Sent when a track starts playing immediately. |
music.queue | ["added to queue: {track}.", "queued: {track}."] | Sent when a track is added to the queue but not played immediately. |
music.error.notInVoice | ["join a voice channel first.", "you're not in a voice channel."] | Error message when the user is not in a voice channel. |
music.error.noResults | ["no results found.", "nothing found for {query}."] | Error message when a search yields no results. |
music.success.queue.title | ["queue for {server}.", "{server}'s queue."] | The title for the queue embed. |
Sources: src/data/respMusic.json