Giter Site home page Giter Site logo

lavalink.kt's Introduction

Lavalink.kt

Lavakord is a coroutine based client for LavaLink mainly designed to work with Kord

Support discord: https://discord.gg/ZbmrRVpDwR

Both Kord and Lavalink.kt are still in an experimental stage, as such we can't guarantee API stability between releases. While we'd love for you to try out our library, we don't recommend you use this in production just yet.

Lavalink download: https://github.com/freyacodes/Lavalink

Download

For now you also need this repo: https://maven.arbjerg.dev/snapshots You can get Lavakord from here: https://central.sonatype.com/search?namespace=dev.schlaubi.lavakord

Usage

You can create a Lavalink object like this

val lavalink = kord.lavakord()

// or    

val lavalink = kord.lavakord {
    link {
        autoReconnect = false
        retry = linear(2.seconds, 60.seconds, 10)
    }
}

You can obtain and use a Link like this

val link = guild.getLink(lavalink)

link.connect(channel)

// use lavalink stuff like player

link.disconnect()

Playing: https://github.com/DRSchlaubi/Lavalink.kt/blob/main/example/src/main/kotlin/me/schlaubi/lavakord/example/Lavakord.kt#L82

Track loading

Lavakord provides a wrapper for the Lavalink Track loading API

You can load a Track by using Link.loadItem(query: String)

Events

Since 0.3 Lavakord provides a Flow based way to listen for events.

val link: KordLink // = .../

val player = link.player

player.on<TrackStartEvent> {
    channel.createMessage(track.info.asString())
}

Documentation

For more info please use the example or Dokka docs

Multiplatform

Since Lavakord 1.0 we use only Multiplatform Kotlin libraries but Ktor doesn't support Websockets when using Kotlin native yet see kordlib/kord#69 and ktorio/ktor#1215 for reference. Kord doesn't support Multiplatform because of the same issue as well

Since 2.0 JS is officially supported

Other Discord API wrappers

Since 1.0 it should be possible to implement your own version of lavakord by implementing your own versions of the LavaKord and Link classes you can see a reference implementation in the kord package

Using with Kord

Add the kord artifact

Using with JDA

Apart from Kord there also is a JDA implementation. You can use it like the following. (Requires jda artifact)

var (lavakord, jda) = JDABuilder.createDefault("token").buildWithLavakord()
class Javakord {
    var container = new LavakordJDABuilder(JDABuilder.createDefault("token")).build();
    var jda = container.getJda();
    var lavakord = container.getLavakord();
    JavaLavakord javaLavakord = JavaInterop.createJavaInterface(lavakord);
}

The snippets work similarly for DefaultShardManagerBuilder as well.

Using with Java

Lavakord provides a compatibility layer for coroutines based on Java 8's CompletableFuture API . To access that interface please use the JavaInterop class. For all rest related features refer to the TrackUtil and RoutePlannerUtil classes. In order to use these methods please add the java or jda-java artifact

Full example can be found here

class Javakord {
    Lavakord lavakord;// = <lavakord build mechanism>
    JavaLavakord javaLavakord = JavaInterop.createJavaInterface(lavakord);
}

lavalink.kt's People

Contributors

bytealex avatar drschlaubi avatar emmaboecker avatar freyacodes avatar mooner1022 avatar nycodeghg avatar toxicmushroom avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

lavalink.kt's Issues

Error when loading track

2024-01-19 18:47:33.142 [DefaultDispatcher-worker-15] TRACE i.k.client.plugins.HttpCallValidator - Processing exception io.ktor.serialization.JsonConvertException: Illegal input: Fields [pluginInfo, userData] are required for type with serial name 'dev.arbjerg.lavalink.protocol.v4.Track', but they were missing at path: $ for request http://82.67.2.160:2333/v4/loadtracks?identifier=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DQloMdg2bapw
2024-01-19 18:47:33.143 [DefaultDispatcher-worker-15] ERROR dev.kord.core.Kord - catching
io.ktor.serialization.JsonConvertException: Illegal input: Fields [pluginInfo, userData] are required for type with serial name 'dev.arbjerg.lavalink.protocol.v4.Track', but they were missing at path: $
	at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:90)
	at io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1$2.emit(Emitters.kt:224)
	at kotlinx.coroutines.flow.FlowKt__BuildersKt$asFlow$$inlined$unsafeFlow$3.collect(SafeCollector.common.kt:118)
	at io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1.collect(SafeCollector.common.kt:113)
	at kotlinx.coroutines.flow.FlowKt__ReduceKt.firstOrNull(Reduce.kt:243)
	at kotlinx.coroutines.flow.FlowKt.firstOrNull(Unknown Source)
	at io.ktor.serialization.ContentConverterKt.deserialize(ContentConverter.kt:123)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation.convertResponse$ktor_client_content_negotiation(ContentNegotiation.kt:230)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invokeSuspend(ContentNegotiation.kt:262)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invoke(ContentNegotiation.kt)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invoke(ContentNegotiation.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:177)
	at io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
	at io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.client.plugins.logging.Logging$setupResponseLogging$2.invokeSuspend(Logging.kt:201)
	at io.ktor.client.plugins.logging.Logging$setupResponseLogging$2.invoke(Logging.kt)
	at io.ktor.client.plugins.logging.Logging$setupResponseLogging$2.invoke(Logging.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:88)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:142)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(HttpCallValidator.kt)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(HttpCallValidator.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
	at io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:89)
	at dev.schlaubi.lavakord.rest.LinkTrackExtensionsKt.loadItem(LinkTrackExtensions.kt:80)
	at dev.schlaubi.lavakord.rest.LinkTrackExtensionsKt$loadItem$2.invokeSuspend(LinkTrackExtensions.kt)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:589)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:806)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:710)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:697)
Caused by: kotlinx.serialization.MissingFieldException: Fields [pluginInfo, userData] are required for type with serial name 'dev.arbjerg.lavalink.protocol.v4.Track', but they were missing at path: $
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:95)
	at kotlinx.serialization.json.Json.decodeFromString(Json.kt:107)
	at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:82)
	... 39 common frames omitted
Caused by: kotlinx.serialization.MissingFieldException: Fields [pluginInfo, userData] are required for type with serial name 'dev.arbjerg.lavalink.protocol.v4.Track', but they were missing
	at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20)
	at dev.arbjerg.lavalink.protocol.v4.Track.<init>(player.kt:30)
	at dev.arbjerg.lavalink.protocol.v4.Track$$serializer.deserialize(player.kt:30)
	at dev.arbjerg.lavalink.protocol.v4.Track$$serializer.deserialize(player.kt:30)
	at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:61)
	at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeSerializableValue(TreeJsonDecoder.kt:52)
	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableValue(Tagged.kt:207)
	at kotlinx.serialization.internal.TaggedDecoder$decodeSerializableElement$1.invoke(Tagged.kt:279)
	at kotlinx.serialization.internal.TaggedDecoder.tagBlock(Tagged.kt:294)
	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableElement(Tagged.kt:279)
	at dev.arbjerg.lavalink.protocol.v4.LoadResult$TrackLoaded$$serializer.deserialize(loadResult.kt:29)
	at dev.arbjerg.lavalink.protocol.v4.LoadResult$TrackLoaded$$serializer.deserialize(loadResult.kt:29)
	at dev.arbjerg.lavalink.protocol.v4.LoadResult$Serializer$selectDeserializer$$inlined$asPolymorphicDeserializer$1.deserialize(PolymorphicSerializer.kt:26)
	at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:61)
	at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeSerializableValue(TreeJsonDecoder.kt:52)
	at kotlinx.serialization.json.internal.TreeJsonDecoderKt.readJson(TreeJsonDecoder.kt:25)
	at kotlinx.serialization.json.Json.decodeFromJsonElement(Json.kt:127)
	at kotlinx.serialization.json.JsonContentPolymorphicSerializer.deserialize(JsonContentPolymorphicSerializer.kt:94)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:69)
	... 41 common frames omitted
2024-01-19 18:47:33.166 [DefaultDispatcher-worker-5] DEBUG d.s.lavakord.audio.internal.NodeImpl - RESPONSE: 200 OK

Cannot use polymorphic serializers on JS (Required by Gateway and RoutePlanner API)

On Kotlin/JS explicitly declared serializer should be used for interfaces and enums without @Serializable annotation
SerializationException: Serializer for class 'GatewayPayload' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
On Kotlin/JS explicitly declared serializer should be used for interfaces and enums without @Serializable annotation
	at <global>.platformSpecificSerializerNotRegistered(kotlin\lavakord-jsIr-test.js:81560)
	at <global>.serializer(kotlin\lavakord-jsIr-test.js:76486)
	at json.CommandsTest.testPlayCommand(kotlin\lavakord-jsIr-test.js:104119)
	at _no_name_provided__471.invoke(kotlin\lavakord-jsIr-test.js:106732)
	at Context.<anonymous>(kotlin\lavakord-jsIr-test.js:106513)
	at <global>.processImmediate(internal/timers.js:456)

See: Kotlin/kotlinx.serialization#1078

Unsupported version

According to the documentation I wrote a bot using JDA and Java. After much effort, I got a message that the Lavalink 4.0.0-beta3 version was unsupported, and then the connection was no longer possible at all. "Handshake failed due to invalid Upgrade header: null"

What version of Lavalink Lavalink.kt 5.1.7 supports then?

Websocket connection errors are not being handled correctly on Kotlin/JS

Currently, whenever an error occurs in the WebSocket connection the following JS error is being printed and kills the nodejs process

      var exception = new WebSocketException(JSON.stringify(event));
                                                  ^
TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Socket'
    |     property 'parser' -> object with constructor 'HTTPParser'
    --- property 'socket' closes the circle
    at JSON.stringify (<anonymous>)
    at WebSocket.<anonymous> (D:\WORK\lavakord\build\js\node_modules\ktor-ktor-client-core-jsLegacy\ktor-ktor-client-core-jsLegacy.js:17440:51)
    at WebSocket.onError (D:\WORK\lavakord\build\js\node_modules\ws\lib\event-target.js:128:16)
    at WebSocket.emit (events.js:311:20)
    at abortHandshake (D:\WORK\lavakord\build\js\node_modules\ws\lib\websocket.js:718:15)
    at ClientRequest.<anonymous> (D:\WORK\lavakord\build\js\node_modules\ws\lib\websocket.js:595:7)
    at ClientRequest.emit (events.js:311:20)
    at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:603:27)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:119:17)
    at Socket.socketOnData (_http_client.js:476:22)```

As this error gets thrown whilst Ktor is trying to turn the JS Error into a Ktor exception Lavakord cannot catch it. This also prevents Lavakord from reconnecting and resuming the connection

I created a Ktor issue here: https://youtrack.jetbrains.com/issue/KTOR-1726

Edit 1: Reconnecting works when the client is able to reconnect on the 1st try, but as soon as an exception has to be handled KTOR throws a javascript error which kills the whole process

Missing access for reading filter values

There is currently no good way to read previously configured filter values from the player.

The current filters variable is only inside the WebsocketPlayer class and marked internal
This could be abstracted into Player and made public to allow for reading the filter values

Nodes do not attempt reconnecting after initial connection refused

After calling Lavakord.addNode() and encountering a refused connection, this exception is raised:

Exception in thread "DefaultDispatcher-worker-9" java.net.ConnectException: Connection refused
	at java.base/sun.nio.ch.Net.pollConnect(Native Method)
	at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:673)
	at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:973)
	at io.ktor.network.sockets.SocketImpl.connect$ktor_network(SocketImpl.kt:50)
	at io.ktor.network.sockets.SocketImpl$connect$1.invokeSuspend(SocketImpl.kt)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)

The coroutine then ends without retrying, as retries are only done when ReconnectException is caught.

java.net.ConnectException is JVM specific, so I am unsure how to catch it in multiplatform code

java.lang.NumberFormatException: For input string: "Snowflake(value=***)"

Lavakord is sending guild id as guildId.toString() where guildId is Snowflake, which leads to error on the lavalink node org.json.JSONException: JSONObject["guildId"] is not a long. <- java.lang.NumberFormatException: For input string: "Snowflake(value=***)"
Having a brief look into the source code, I found at least here snowflake is being sent as just string representation: LavaKordImpl.kt/KordLavaKord.class/handleVoiceServerUpdate/80 line and 82 line

Initially, issue was found when I tried to play a track and no sound was coming from a bot

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.