Plugin Development
Lavalink supports third-party plugins to add additional functionality such as custom audio sources, custom filters, WebSocket handling, REST endpoints, and much more.
If your plugin is developed in Kotlin, make sure you are using Kotlin v1.8.22
Getting Started
Create a new plugin from template
Use the Lavalink plugin template to bootstrap your plugin:
Click “Use this template” on GitHub
Clone your new repository
Update the plugin metadata in build.gradle.kts
Add the plugin API dependency
The plugin API is already included in the template. It provides the interfaces and classes you need: dependencies {
api ( "dev.arbjerg.lavalink:plugin-api:VERSION" )
}
Implement your plugin
Create classes that implement the plugin API interfaces using Spring annotations. See the extension points below.
Build and distribute
Build your plugin JAR and publish it to a Maven repository for distribution.
Extension Points
Adding Audio Sources
To add a new audio source (like YouTube, Spotify, etc.), simply provide an AudioSourceManager as a Spring bean:
import org.springframework.stereotype.Service;
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager;
@ Service
class MyAudioSourceManager implements AudioSourceManager {
@ Override
public String getSourceName () {
return "my-source" ;
}
@ Override
public AudioItem loadItem ( AudioPlayerManager manager , AudioReference reference ) {
// Load and return audio items
}
// ... other required methods
}
Add support for new media container formats for HTTP and local sources:
import org.springframework.stereotype.Service;
import com.sedmelluq.discord.lavaplayer.container.MediaContainerProbe;
@ Service
class MyMediaContainerProbe implements MediaContainerProbe {
@ Override
public String getName () {
return "my-container" ;
}
@ Override
public boolean matchesHints ( MediaContainerHints hints ) {
// Check if this probe should handle the content
}
// ... other required methods
}
Custom Audio Filters
Implement the AudioFilterExtension interface to add custom audio filters that can be controlled via the WebSocket filters operation:
import org.springframework.stereotype.Service
import dev.arbjerg.lavalink.api.AudioFilterExtension
import com.sedmelluq.discord.lavaplayer.filter.FloatPcmAudioFilter
import com.sedmelluq.discord.lavaplayer.format.AudioDataFormat
import kotlinx.serialization.json.JsonElement
@Service
class CustomFilterExtension : AudioFilterExtension {
override val name: String = "customFilter"
override fun isEnabled ( data : JsonElement ): Boolean {
// Check if the filter should be enabled based on client data
return data .jsonObject[ "enabled" ]?.jsonPrimitive?.boolean ?: false
}
override fun build (
data : JsonElement ,
format: AudioDataFormat ?,
output: FloatPcmAudioFilter ?
): FloatPcmAudioFilter ? {
// Create and return your custom filter
return CustomFilter (format, output)
}
}
Clients can then use your filter via the WebSocket:
{
"op" : "filters" ,
"guildId" : "..." ,
"customFilter" : {
"enabled" : true ,
"parameter" : "value"
}
}
REST Endpoint Interceptors
Intercept and modify existing REST endpoints using the RestInterceptor interface:
import org.springframework.stereotype.Service;
import dev.arbjerg.lavalink.api.RestInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ Service
class MyRestInterceptor implements RestInterceptor {
@ Override
public boolean preHandle (
HttpServletRequest request ,
HttpServletResponse response ,
Object handler
) {
// Intercept before the request is handled
// Return false to block the request
return true ;
}
@ Override
public void postHandle (
HttpServletRequest request ,
HttpServletResponse response ,
Object handler ,
ModelAndView modelAndView
) {
// Intercept after the request is handled
}
}
Custom REST Endpoints
Define custom REST endpoints using Spring Web MVC annotations:
import org.springframework.web.bind.annotation. *
@RestController
@RequestMapping ( "/v4/myplugin" )
class MyPluginController {
@GetMapping ( "/status" )
fun getStatus (): Map < String , Any > {
return mapOf (
"status" to "active" ,
"version" to "1.0.0"
)
}
@PostMapping ( "/action" )
fun performAction ( @RequestBody data : Map < String , Any >): Response {
// Handle custom action
return Response ( "success" )
}
}
See the Spring Web MVC documentation for more details.
Modifying Track and Playlist Info
Add custom fields to track and playlist JSON responses using AudioPluginInfoModifier:
import org.springframework.stereotype.Service
import dev.arbjerg.lavalink.api.AudioPluginInfoModifier
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
@Service
class MyPluginInfoModifier : AudioPluginInfoModifier {
override fun modifyAudioTrackPluginInfo (track: AudioTrack ): JsonObject ? {
// Add custom fields to track JSON
return buildJsonObject {
put ( "customField" , "customValue" )
put ( "trackMetadata" , "additional info" )
}
}
override fun modifyAudioPlaylistPluginInfo (playlist: AudioPlaylist ): JsonObject ? {
// Add custom fields to playlist JSON
return buildJsonObject {
put ( "playlistExtra" , "extra data" )
}
}
}
Configuration Properties
Define type-safe configuration properties using Spring Boot’s configuration system:
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component
@Component
@ConfigurationProperties (prefix = "plugins.myplugin" )
data class MyPluginConfig (
var enabled: Boolean = true ,
var apiKey: String = "" ,
var maxRetries: Int = 3
)
Users can then configure your plugin in application.yml:
plugins :
myplugin :
enabled : true
apiKey : "your-api-key"
maxRetries : 5
See the Spring Boot type-safe configuration documentation for more details.
Building Your Plugin
The plugin template uses Gradle for building. The key tasks are:
# Build the plugin JAR
./gradlew build
# Run Lavalink with your plugin for testing
./gradlew :runLavalink
# Publish to Maven repository
./gradlew publish
The built JAR will be in build/libs/ and includes all necessary metadata.
Plugin Manifest
Your plugin must include metadata in build.gradle.kts:
group = "com.example"
version = "1.0.0"
lavalink {
pluginName = "MyPlugin"
pluginVersion = version
serverVersion = "4.0.0"
configurePublishing = true
}
Distributing Your Plugin
Publishing to Maven
The official plugin repository is hosted at https://maven.lavalink.dev . To publish there:
Contact the Lavalink team via Discord for credentials
Configure your Maven credentials in ~/.gradle/gradle.properties
Run ./gradlew publish
Custom Repositories
Users can load plugins from custom Maven repositories by configuring application.yml:
lavalink :
plugins :
- dependency : "com.example:my-plugin:1.0.0"
repository : "https://maven.example.com/releases"
snapshot : false
Default Repository Configuration
Users can override the default repositories:
lavalink :
defaultPluginRepository : "https://maven.example.com/releases"
defaultPluginSnapshotRepository : "https://maven.example.com/snapshots"
Plugin Directory
By default, Lavalink downloads and loads plugins from the ./plugins directory. Users can customize this:
lavalink :
pluginsDir : "./lavalink-plugins"
Best Practices
Use the Plugin API, not internal APIs
Always use the official plugin API rather than accessing internal Lavalink classes. If you need functionality not exposed by the API, open an issue or pull request to extend it.
Follow semantic versioning
Version your plugin using semantic versioning (MAJOR.MINOR.PATCH) to communicate breaking changes clearly to users.
Document configuration options
Provide clear documentation for all configuration properties and their default values.
Catch and log exceptions appropriately. Don’t let plugin errors crash the Lavalink server.
Test with the latest Lavalink version
Regularly test your plugin against new Lavalink releases to ensure compatibility.
Resources
Plugin API Javadoc Complete API reference documentation
Plugin Template Start with the official template
Gradle Plugin Docs Learn about the Lavalink Gradle plugin
Discord Community Get help from the community
Next Steps
Plugin Architecture Learn about extension points and hooks in detail
Available Plugins Explore existing plugins for inspiration