Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a filter builder to aid users in setting filters #14

Merged
merged 2 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ Alternatively, you can use `Discord4JUtils.leave(gatewayClient, guildId);` as th
## Examples
The following examples are minimal implementations but show how the library works.
- Java examples
- JDA: [link](src/test/java/JavaJDAExample.java)
- JDA (simple): [link](src/test/java/JavaJDAExample.java)
- JDA (more complex example): [link](testbot/src/main/java/me/duncte123/testbot/Main.java)
- Kotlin examples
- JDA: [link](src/test/kotlin/testScript.kt)
- Discord4J: [link](src/test/kotlin/d4jTestScript.kt)
Expand Down
20 changes: 11 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,22 @@ group = "dev.arbjerg"
version = gitVersion
val archivesBaseName = "lavalink-client"

allprojects {
repositories {
mavenCentral()
maven("https://maven.lavalink.dev/releases")
maven("https://maven.lavalink.dev/snapshots")
maven("https://maven.topi.wtf/releases")
// Note to self: jitpack always comes last
maven("https://jitpack.io")
}
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

repositories {
mavenCentral()
maven("https://maven.lavalink.dev/releases")
maven("https://maven.lavalink.dev/snapshots")
maven("https://maven.topi.wtf/releases")
// Note to self: jitpack always comes last
maven("https://jitpack.io")
}

dependencies {
// package libraries
api(kotlin("stdlib"))
Expand Down
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ rootProject.name = "lavalink-client"

enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")

include(":testbot")

dependencyResolutionManagement {
versionCatalogs {
create("libs") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ interface IUpdatablePlayer {
* Please use [setVolume] to update the player's volume instead. Setting the volume via filters is
* float based (1.0f is 100% volume) and takes the time of your buffer size to apply.
*
* @param filters The new filters to apply to the player.
* @param filters The new filters to apply to the player. You can use the [dev.arbjerg.lavalink.client.protocol.FilterBuilder] to easily create this object.
*
* @return The updated builder, useful for chaining
*/
Expand Down
214 changes: 214 additions & 0 deletions src/main/kotlin/dev/arbjerg/lavalink/client/protocol/FilterBuilder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package dev.arbjerg.lavalink.client.protocol

import dev.arbjerg.lavalink.internal.toJsonElement
import dev.arbjerg.lavalink.protocol.v4.*
import kotlinx.serialization.json.JsonElement

/**
* Helper class fo builder [Filters].
*/
class FilterBuilder {
private var volume: Omissible<Float> = Omissible.Omitted()
private var equalizer: Omissible<List<Band>> = Omissible.Omitted()
private var karaoke: Omissible<Karaoke?> = Omissible.Omitted()
private var timescale: Omissible<Timescale?> = Omissible.Omitted()
private var tremolo: Omissible<Tremolo?> = Omissible.Omitted()
private var vibrato: Omissible<Vibrato?> = Omissible.Omitted()
private var distortion: Omissible<Distortion?> = Omissible.Omitted()
private var rotation: Omissible<Rotation?> = Omissible.Omitted()
private var channelMix: Omissible<ChannelMix?> = Omissible.Omitted()
private var lowPass: Omissible<LowPass?> = Omissible.Omitted()
private var pluginFilters: MutableMap<String, JsonElement> = mutableMapOf()

/**
* Sets the filter volume. If you just want to change the volume, it is highly recommended to use [dev.arbjerg.lavalink.client.IUpdatablePlayer.setVolume] instead.
*
* This volume takes the time of your buffer size to apply and should only be used if any other filters would increase the overall volume too much.
*
* @param volume The volume to apply to the filter.
*
* @return The updated builder, useful for chaining
*/
fun setVolume(volume: Float) = apply {
this.volume = volume.toOmissible()
}

/**
* Set the equalizer bands on the player.
*
* @param equalizer Each band to set in the equalizer. Default gain is 1.0f.
*
* @return The updated builder, useful for chaining
*/
fun setEqualizer(equalizer: List<Band>) = apply {
this.equalizer = equalizer.toOmissible()
}

/**
* Set a specific band on the equalizer.
*
* @param band The band to set.
* @param gain The gain to apply to the band. Default gain is 1.0f.
*
* @return The updated builder, useful for chaining
*/
@JvmOverloads
fun setEqualizerBand(band: Int, gain: Float = 1.0F) = apply {
val eq = this.equalizer
val bandObj = Band(band, gain)

if (eq.isPresent()) {
val currEq = eq.value.toMutableList()
val bandIndex = currEq.indexOfFirst { it.band == band }

if (bandIndex > -1) {
currEq[bandIndex] = bandObj
} else {
currEq.add(bandObj)
}

this.equalizer = currEq.toOmissible()
} else {
this.equalizer = listOf(bandObj).toOmissible()
}
}

/**
* Set the karaoke filter on the player.
*
* @param karaoke The karaoke filter to apply to the player. Set to null to disable the filter.
*
* @return The updated builder, useful for chaining
*/
fun setKaraoke(karaoke: Karaoke?) = apply {
this.karaoke = Omissible.of(karaoke)
}

/**
* Sets the timescale filter on the player.
*
* @param timescale The timescale filter to apply to the player. Set to null to disable the filter.
*
* @return The updated builder, useful for chaining
*/
fun setTimescale(timescale: Timescale?) = apply {
this.timescale = Omissible.of(timescale)
}

/**
* Sets the tremolo filter on the player.
*
* @param tremolo The tremolo filter to apply to the player. Set to null to disable the filter.
*
* @return The updated builder, useful for chaining
*/
fun setTremolo(tremolo: Tremolo?) = apply {
this.tremolo = Omissible.of(tremolo)
}

/**
* Sets the vibrato filter on the player.
*
* @param vibrato The vibrato filter to apply to the player. Set to null to disable the filter.
*
* @return The updated builder, useful for chaining
*/
fun setVibrato(vibrato: Vibrato?) = apply {
this.vibrato = Omissible.of(vibrato)
}

/**
* Sets the distortion filter on the player.
*
* @param distortion The distortion filter to apply to the player. Set to null to disable the filter.
*
* @return The updated builder, useful for chaining
*/
fun setDistortion(distortion: Distortion?) = apply {
this.distortion = Omissible.of(distortion)
}

/**
* Sets the rotation filter on the player.
*
* @param rotation The rotation filter to apply to the player. Set to null to disable the filter.
*
* @return The updated builder, useful for chaining
*/
fun setRotation(rotation: Rotation?) = apply {
this.rotation = Omissible.of(rotation)
}

/**
* Sets the channel mix filter on the player.
*
* @param channelMix The channel mix filter to apply to the player. Set to null to disable the filter.
*
* @return The updated builder, useful for chaining
*/
fun setChannelMix(channelMix: ChannelMix?) = apply {
this.channelMix = Omissible.of(channelMix)
}

/**
* Sets the low pass filter on the player.
*
* @param lowPass The low pass filter to apply to the player. Set to null to disable the filter.
*
* @return The updated builder, useful for chaining
*/
fun setLowPass(lowPass: LowPass?) = apply {
this.lowPass = Omissible.of(lowPass)
}

/**
* Set custom filter data for a plugin.
*
* @param name the name of the plugin filter
* @param filter the filter data, can be a custom class as it will be serialised to json
* @return The updated builder, useful for chaining
*/
fun setPluginFilter(name: String, filter: Any) = apply {
pluginFilters[name] = toJsonElement(filter)
}

/**
* Set custom filter data for a plugin.
*
* @param name the name of the plugin filter
* @param filter kotlin [JsonElement] that holds the filter data.
* @return The updated builder, useful for chaining
*/
fun setPluginFilter(name: String, filter: JsonElement) = apply {
pluginFilters[name] = filter
}

/**
* Removes a plugin filter with the given name.
*
* @param name the name of the plugin filter
* @return The updated builder, useful for chaining
*/
fun removePluginFilter(name: String) = apply {
pluginFilters.remove(name)
}

/**
* Builds the [Filters] object with the current configuration.
*
* @return the [Filters] object with the current configuration
*/
fun build() = Filters(
volume,
equalizer,
karaoke,
timescale,
tremolo,
vibrato,
distortion,
rotation,
channelMix,
lowPass,
pluginFilters
)
}
21 changes: 21 additions & 0 deletions testbot/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
plugins {
java
application
}

group = "me.duncte123"
version = "1.0-SNAPSHOT"

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

dependencies {
// Include the lavalink client
implementation(projects.lavalinkClient)

// other libs such as a discord client and a logger
implementation(libs.jda)
implementation(libs.logger.impl)
}
77 changes: 77 additions & 0 deletions testbot/src/main/java/me/duncte123/testbot/AudioLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package me.duncte123.testbot;

import dev.arbjerg.lavalink.client.AbstractAudioLoadResultHandler;
import dev.arbjerg.lavalink.client.Link;
import dev.arbjerg.lavalink.client.protocol.*;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.jetbrains.annotations.NotNull;

import java.util.List;

public class AudioLoader extends AbstractAudioLoadResultHandler {
private final Link link;
private final SlashCommandInteractionEvent event;

public AudioLoader(Link link, SlashCommandInteractionEvent event) {
this.link = link;
this.event = event;
}

@Override
public void ontrackLoaded(@NotNull TrackLoaded result) {
final Track track = result.getTrack();

// Inner class at the end of this file
var userData = new MyUserData(event.getUser().getIdLong());

track.setUserData(userData);

link.createOrUpdatePlayer()
.setTrack(track)
.setVolume(35)
.subscribe((player) -> {
final Track playingTrack = player.getTrack();
final var trackTitle = playingTrack.getInfo().getTitle();
final MyUserData customData = playingTrack.getUserData(MyUserData.class);

event.getHook().sendMessage("Now playing: " + trackTitle + "\nRequested by: <@" + customData.requester() + '>').queue();
});
}

@Override
public void onPlaylistLoaded(@NotNull PlaylistLoaded result) {
final int trackCount = result.getTracks().size();
event.getHook()
.sendMessage("This playlist has " + trackCount + " tracks!")
.queue();
}

@Override
public void onSearchResultLoaded(@NotNull SearchResult result) {
final List<Track> tracks = result.getTracks();

if (tracks.isEmpty()) {
event.getHook().sendMessage("No tracks found!").queue();
return;
}

final Track firstTrack = tracks.get(0);

// This is a different way of updating the player! Choose your preference!
// This method will also create a player if there is not one in the server yet
link.updatePlayer((update) -> update.setTrack(firstTrack).setVolume(35))
.subscribe((ignored) -> {
event.getHook().sendMessage("Now playing: " + firstTrack.getInfo().getTitle()).queue();
});
}

@Override
public void noMatches() {
event.getHook().sendMessage("No matches found for your input!").queue();
}

@Override
public void loadFailed(@NotNull LoadFailed result) {
event.getHook().sendMessage("Failed to load track! " + result.getException().getMessage()).queue();
}
}
Loading