From 9d4165def18cb99e24ab9c17b916748a10cff283 Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Sat, 15 Jul 2023 18:02:45 +0200 Subject: [PATCH 01/73] Add Lavalink.kt to v4 clients (#918) --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7ecbb5c7c..143f15b79 100644 --- a/README.md +++ b/README.md @@ -88,15 +88,16 @@ Version numbers can come in different combinations, depending on the release typ --- ## Client libraries: -| Client | Platform | Compatible With | Additional Information | -|--------------------------------------------------------------------|----------|--------------------------------------------|------------------------| -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | -| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | -| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | +| Client | Platform | Compatible With | Additional Information | +|-----------------------------------------------------------------|----------|--------------------------------------------|------------------------| +| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | +| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | +| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | |
v3.7 supporting Client Libraries From afbb146d3f2dddf244644dd3ab9683eb11b3666f Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Sat, 15 Jul 2023 21:14:04 +0200 Subject: [PATCH 02/73] add discatsharp to libs (#919) --- README.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 143f15b79..733338dd6 100644 --- a/README.md +++ b/README.md @@ -97,24 +97,26 @@ Version numbers can come in different combinations, depending on the release typ | [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | | [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | | [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | | [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | |
v3.7 supporting Client Libraries -| Client | Platform | Compatible With | Additional Information | -|-------------------------------------------------------------|----------|--------------------------------------------|---------------------------------| -| [Lavalink.kt](https://github.com/DRSchlaubi/lavalink.kt) | Kotlin | JDA/Kord/**Any** | Kotlin Coroutines | -| [lavaplay.py](https://github.com/HazemMeqdad/lavaplay.py) | Python | **Any\*** | *`asyncio`-based libraries only | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Wavelink](https://github.com/PythonistaGuild/Wavelink) | Python | discord.py **V2** | | -| [Pomice](https://github.com/cloudwithax/pomice) | Python | discord.py **V2** | | -| [Lavacord](https://github.com/lavacord/lavacord) | Node.js | **Any** | | -| [Poru](https://github.com/parasop/poru) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [Cosmicord.js](https://github.com/SudhanPlayz/Cosmicord.js) | Node.js | **Any** | | -| [Nomia](https://github.com/DHCPCD9/Nomia) | .NET | DSharpPlus | | -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | +| Client | Platform | Compatible With | Additional Information | +|---------------------------------------------------------------|----------|--------------------------------------------|---------------------------------| +| [Lavalink.kt](https://github.com/DRSchlaubi/lavalink.kt) | Kotlin | JDA/Kord/**Any** | Kotlin Coroutines | +| [lavaplay.py](https://github.com/HazemMeqdad/lavaplay.py) | Python | **Any\*** | *`asyncio`-based libraries only | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Wavelink](https://github.com/PythonistaGuild/Wavelink) | Python | discord.py **V2** | | +| [Pomice](https://github.com/cloudwithax/pomice) | Python | discord.py **V2** | | +| [Lavacord](https://github.com/lavacord/lavacord) | Node.js | **Any** | | +| [Poru](https://github.com/parasop/poru) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Cosmicord.js](https://github.com/SudhanPlayz/Cosmicord.js) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | Only prior v10.4.1 | +| [Nomia](https://github.com/DHCPCD9/Nomia) | .NET | DSharpPlus | | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | |
From 6ba2986fb0eb3259a2d1dca3c870ea181aeb8ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 21 Jul 2023 14:32:57 +0200 Subject: [PATCH 03/73] add jda-nas for linux musl (#920) --- LavalinkServer/build.gradle.kts | 2 +- LavalinkServer/docker/alpine.Dockerfile | 2 ++ .../main/java/lavalink/server/config/KoeConfiguration.kt | 3 +++ settings.gradle.kts | 6 +++--- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/LavalinkServer/build.gradle.kts b/LavalinkServer/build.gradle.kts index ad61565fe..fbb61ecae 100644 --- a/LavalinkServer/build.gradle.kts +++ b/LavalinkServer/build.gradle.kts @@ -137,7 +137,7 @@ tasks { archiveFileName.set("Lavalink-musl.jar") // Exclude base dependency jar exclude { - it.name.contains("lavaplayer-natives-fork") || it.name.contains("udpqueue-native-") + it.name.contains("lavaplayer-natives-fork") || (it.name.contains("udpqueue-native-") && !it.name.contains("musl")) } // Add custom jar diff --git a/LavalinkServer/docker/alpine.Dockerfile b/LavalinkServer/docker/alpine.Dockerfile index b410fadc6..e24daeed2 100644 --- a/LavalinkServer/docker/alpine.Dockerfile +++ b/LavalinkServer/docker/alpine.Dockerfile @@ -1,5 +1,7 @@ FROM azul/zulu-openjdk-alpine:17-jre-headless-latest +RUN apk add --no-cache libgcc + # Run as non-root user RUN addgroup -g 322 -S lavalink && \ adduser -u 322 -S lavalink lavalink diff --git a/LavalinkServer/src/main/java/lavalink/server/config/KoeConfiguration.kt b/LavalinkServer/src/main/java/lavalink/server/config/KoeConfiguration.kt index b7f5048e8..41397f506 100644 --- a/LavalinkServer/src/main/java/lavalink/server/config/KoeConfiguration.kt +++ b/LavalinkServer/src/main/java/lavalink/server/config/KoeConfiguration.kt @@ -20,6 +20,9 @@ class KoeConfiguration(val serverConfig: ServerConfig) { SystemType(DefaultArchitectureTypes.X86_32, DefaultOperatingSystemTypes.LINUX), SystemType(DefaultArchitectureTypes.ARMv8_64, DefaultOperatingSystemTypes.LINUX), + SystemType(DefaultArchitectureTypes.X86_64, DefaultOperatingSystemTypes.LINUX_MUSL), + SystemType(DefaultArchitectureTypes.ARMv8_64, DefaultOperatingSystemTypes.LINUX_MUSL), + SystemType(DefaultArchitectureTypes.X86_64, DefaultOperatingSystemTypes.WINDOWS), SystemType(DefaultArchitectureTypes.X86_32, DefaultOperatingSystemTypes.WINDOWS), diff --git a/settings.gradle.kts b/settings.gradle.kts index 8cce7cd49..0f12f7e6d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,7 +36,7 @@ fun VersionCatalogBuilder.spring() { } fun VersionCatalogBuilder.voice() { - version("lavaplayer", "17c75f5") + version("lavaplayer", "17c75f51f9") library("lavaplayer", "com.github.walkyst.lavaplayer-fork", "lavaplayer").versionRef("lavaplayer") library("lavaplayer-ip-rotator", "com.github.walkyst.lavaplayer-fork", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") @@ -45,8 +45,8 @@ fun VersionCatalogBuilder.voice() { library("koe", "moe.kyokobot.koe", "core").version("2.0.0-rc1") library("koe-udpqueue", "moe.kyokobot.koe", "ext-udpqueue").version("2.0.0-rc1") - version("udpqueue", "0.2.6") - val platforms = listOf("linux-x86-64", "linux-x86", "linux-aarch64", "linux-arm", "win-x86-64", "win-x86", "darwin") + version("udpqueue", "0.2.7") + val platforms = listOf("linux-x86-64", "linux-x86", "linux-aarch64", "linux-arm", "linux-musl-x86-64", "linux-musl-aarch64", "win-x86-64", "win-x86", "darwin") platforms.forEach { library("udpqueue-native-$it", "club.minnced", "udpqueue-native-$it").versionRef("udpqueue") } From 6672f0dd8932fd4000077606f73ea683e146333e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 21 Jul 2023 14:36:02 +0200 Subject: [PATCH 04/73] update lavaplayer to 08cfbc0 - Fixed ogg streaming --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 0f12f7e6d..887c8afdc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,7 +36,7 @@ fun VersionCatalogBuilder.spring() { } fun VersionCatalogBuilder.voice() { - version("lavaplayer", "17c75f51f9") + version("lavaplayer", "08cfbc0595") library("lavaplayer", "com.github.walkyst.lavaplayer-fork", "lavaplayer").versionRef("lavaplayer") library("lavaplayer-ip-rotator", "com.github.walkyst.lavaplayer-fork", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") From 9ac3eb8b7209d317fb913cf0e5018e08b8ad55b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 21 Jul 2023 14:46:49 +0200 Subject: [PATCH 05/73] add new config option to readme env vars --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 733338dd6..7b6e6b38b 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,8 @@ LAVALINK_PLUGINS_0_REPOSITORY LAVALINK_PLUGINS_1_DEPENDENCY LAVALINK_PLUGINS_1_REPOSITORY +LAVALINK_PLUGINS_DIR + LAVALINK_SERVER_PASSWORD LAVALINK_SERVER_SOURCES_YOUTUBE LAVALINK_SERVER_SOURCES_BANDCAMP From f543fa9e98e61efa6f46511ac785041777e62364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 21 Jul 2023 14:49:09 +0200 Subject: [PATCH 06/73] fixup some readme things --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b6e6b38b..68ab53e15 100644 --- a/README.md +++ b/README.md @@ -263,19 +263,20 @@ WantedBy=multi-user.target ``` To initiate the service, run + ```shell sudo systemctl daemon-reload sudo systemctl enable lavalink sudo systemctl start lavalink ``` + In addition to the usual log files, you can also view the log with `sudo journalctl -u lavalink`. + ### Docker Docker images can be found under [packages](https://github.com/lavalink-devs/Lavalink/pkgs/container/lavalink) with old builds prior to `v3.7.4` being available on [Docker Hub](https://hub.docker.com/r/fredboat/lavalink/). There are 2 image variants `Ubuntu` and `Alpine`, the `Alpine` variant is smaller and can be used with the `-alpine` suffix, for example `ghcr.io/lavalink-devs/lavalink:3-alpine`. ---- - Install [Docker](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) Create a `docker-compose.yml` with the following content: From 83d6f59a22e7b8106b00f7db906d35766b4c7b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 21 Jul 2023 15:05:47 +0200 Subject: [PATCH 07/73] readd hardware support section in readme --- README.md | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 68ab53e15..be108bf4c 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ A [basic example bot](Testbot) is available. - [Features](#features) - [Requirements](#requirements) +- [Hardware Support](#hardware-support) - [Changelog](#changelog) - [Versioning policy](#versioning-policy) - [Client libraries](#client-libraries) @@ -49,19 +50,28 @@ A [basic example bot](Testbot) is available. * Java 17 LTS or newer required. (we recommend running the latest LTS version or newer) * OpenJDK or Zulu running on Linux AMD64 is officially supported. -Support for Darwin (Mac), Windows AMD64, and Linux ARM (Raspberry Pi) is provided on a best-effort basis. This is dependent on Lavaplayer's native libraries. - -Lavaplayer currently supports following architectures: - -`Darwin (M1 & Intel)`, `Linux aarch32`, `Linux aarch64`, `Linux ARMv7+ 32/64`, `Linux ARMHF(v6) 32`, `Linux i386 32`, `Linux x86 64`, `Windows i386 32` and `Windows x86 64` - -JDA-NAS(Native Audio Buffer) & the Timescale filter are currently not supported on following architectures: - -`Linux ARMHF(v6) 32` and `Linux aarch32` - - Support for other JVMs is also best-effort. Periodic CPU utilization stats are prone not to work everywhere. +## Hardware Support + +Lavalink also runs on other hardware, but support is best-effort. +Here is a list of known working hardware: + +| Operating System | Architecture | Lavaplayer | JDA-NAS | Timescale | AVX2 | +|------------------|--------------|------------|---------|-----------|------| +| linux | x86-64 | ✅ | ✅ | ✅ | ✅ | +| linux | x86 | ✅ | ✅ | ✅ | ✅ | +| linux | arm | ✅ | ✅ | ✅ | ❌ | +| linux | armhf | ✅ | ❌ | ❌ | ❌ | +| linux | aarch32 | ✅ | ❌ | ❌ | ❌ | +| linux | aarch64 | ✅ | ✅ | ✅ | ❌ | +| linux-musl | x86-64 | ✅ | ✅ | ✅ | ✅ | +| linux-musl | aarch64 | ✅ | ✅ | ✅ | ❌ | +| windows | x86-64 | ✅ | ✅ | ✅ | ✅ | +| Windows | x86 | ✅ | ✅ | ✅ | ✅ | +| darwin | x86-64 | ✅ | ✅ | ✅ | ✅ | +| darwin | aarch64e | ✅ | ✅ | ✅ | ❌ | + ## Changelog Please see [here](CHANGELOG.md) From c79ffaace544a986356d6fc93eea0d893ac943ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 21 Jul 2023 15:12:46 +0200 Subject: [PATCH 08/73] update changelog for v4.0.0-beta.2 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cef880bbb..dc71834ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ Each release usually includes various fixes and improvements. The most noteworthy of these, as well as any features and breaking changes, are listed here. +## 4.0.0-beta.2 +* Update lavaplayer to [`08cfbc0`](https://github.com/Walkyst/lavaplayer-fork/commit/08cfbc05953128f3cf727ea3bcbe41dabcd1c7db) - Fixed ogg streaming +* Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) +* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) + ## 4.0.0-beta.1 * New Lavalink now requires Java 17 or higher to run * **Removal of all websocket messages sent by the client. Everything is now done via [REST](IMPLEMENTATION.md#rest-api)** From 30bedcafccc4145777839f78642ec16e7b843a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 21 Jul 2023 15:20:01 +0200 Subject: [PATCH 09/73] release v4.0.0-beta.2 (#923) --- CHANGELOG.md | 5 +++ LavalinkServer/build.gradle.kts | 2 +- LavalinkServer/docker/alpine.Dockerfile | 2 + .../server/config/KoeConfiguration.kt | 3 ++ README.md | 39 ++++++++++++------- settings.gradle.kts | 6 +-- 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cef880bbb..dc71834ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ Each release usually includes various fixes and improvements. The most noteworthy of these, as well as any features and breaking changes, are listed here. +## 4.0.0-beta.2 +* Update lavaplayer to [`08cfbc0`](https://github.com/Walkyst/lavaplayer-fork/commit/08cfbc05953128f3cf727ea3bcbe41dabcd1c7db) - Fixed ogg streaming +* Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) +* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) + ## 4.0.0-beta.1 * New Lavalink now requires Java 17 or higher to run * **Removal of all websocket messages sent by the client. Everything is now done via [REST](IMPLEMENTATION.md#rest-api)** diff --git a/LavalinkServer/build.gradle.kts b/LavalinkServer/build.gradle.kts index ad61565fe..fbb61ecae 100644 --- a/LavalinkServer/build.gradle.kts +++ b/LavalinkServer/build.gradle.kts @@ -137,7 +137,7 @@ tasks { archiveFileName.set("Lavalink-musl.jar") // Exclude base dependency jar exclude { - it.name.contains("lavaplayer-natives-fork") || it.name.contains("udpqueue-native-") + it.name.contains("lavaplayer-natives-fork") || (it.name.contains("udpqueue-native-") && !it.name.contains("musl")) } // Add custom jar diff --git a/LavalinkServer/docker/alpine.Dockerfile b/LavalinkServer/docker/alpine.Dockerfile index b410fadc6..e24daeed2 100644 --- a/LavalinkServer/docker/alpine.Dockerfile +++ b/LavalinkServer/docker/alpine.Dockerfile @@ -1,5 +1,7 @@ FROM azul/zulu-openjdk-alpine:17-jre-headless-latest +RUN apk add --no-cache libgcc + # Run as non-root user RUN addgroup -g 322 -S lavalink && \ adduser -u 322 -S lavalink lavalink diff --git a/LavalinkServer/src/main/java/lavalink/server/config/KoeConfiguration.kt b/LavalinkServer/src/main/java/lavalink/server/config/KoeConfiguration.kt index b7f5048e8..41397f506 100644 --- a/LavalinkServer/src/main/java/lavalink/server/config/KoeConfiguration.kt +++ b/LavalinkServer/src/main/java/lavalink/server/config/KoeConfiguration.kt @@ -20,6 +20,9 @@ class KoeConfiguration(val serverConfig: ServerConfig) { SystemType(DefaultArchitectureTypes.X86_32, DefaultOperatingSystemTypes.LINUX), SystemType(DefaultArchitectureTypes.ARMv8_64, DefaultOperatingSystemTypes.LINUX), + SystemType(DefaultArchitectureTypes.X86_64, DefaultOperatingSystemTypes.LINUX_MUSL), + SystemType(DefaultArchitectureTypes.ARMv8_64, DefaultOperatingSystemTypes.LINUX_MUSL), + SystemType(DefaultArchitectureTypes.X86_64, DefaultOperatingSystemTypes.WINDOWS), SystemType(DefaultArchitectureTypes.X86_32, DefaultOperatingSystemTypes.WINDOWS), diff --git a/README.md b/README.md index 733338dd6..be108bf4c 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ A [basic example bot](Testbot) is available. - [Features](#features) - [Requirements](#requirements) +- [Hardware Support](#hardware-support) - [Changelog](#changelog) - [Versioning policy](#versioning-policy) - [Client libraries](#client-libraries) @@ -49,19 +50,28 @@ A [basic example bot](Testbot) is available. * Java 17 LTS or newer required. (we recommend running the latest LTS version or newer) * OpenJDK or Zulu running on Linux AMD64 is officially supported. -Support for Darwin (Mac), Windows AMD64, and Linux ARM (Raspberry Pi) is provided on a best-effort basis. This is dependent on Lavaplayer's native libraries. - -Lavaplayer currently supports following architectures: - -`Darwin (M1 & Intel)`, `Linux aarch32`, `Linux aarch64`, `Linux ARMv7+ 32/64`, `Linux ARMHF(v6) 32`, `Linux i386 32`, `Linux x86 64`, `Windows i386 32` and `Windows x86 64` - -JDA-NAS(Native Audio Buffer) & the Timescale filter are currently not supported on following architectures: - -`Linux ARMHF(v6) 32` and `Linux aarch32` - - Support for other JVMs is also best-effort. Periodic CPU utilization stats are prone not to work everywhere. +## Hardware Support + +Lavalink also runs on other hardware, but support is best-effort. +Here is a list of known working hardware: + +| Operating System | Architecture | Lavaplayer | JDA-NAS | Timescale | AVX2 | +|------------------|--------------|------------|---------|-----------|------| +| linux | x86-64 | ✅ | ✅ | ✅ | ✅ | +| linux | x86 | ✅ | ✅ | ✅ | ✅ | +| linux | arm | ✅ | ✅ | ✅ | ❌ | +| linux | armhf | ✅ | ❌ | ❌ | ❌ | +| linux | aarch32 | ✅ | ❌ | ❌ | ❌ | +| linux | aarch64 | ✅ | ✅ | ✅ | ❌ | +| linux-musl | x86-64 | ✅ | ✅ | ✅ | ✅ | +| linux-musl | aarch64 | ✅ | ✅ | ✅ | ❌ | +| windows | x86-64 | ✅ | ✅ | ✅ | ✅ | +| Windows | x86 | ✅ | ✅ | ✅ | ✅ | +| darwin | x86-64 | ✅ | ✅ | ✅ | ✅ | +| darwin | aarch64e | ✅ | ✅ | ✅ | ❌ | + ## Changelog Please see [here](CHANGELOG.md) @@ -146,6 +156,8 @@ LAVALINK_PLUGINS_0_REPOSITORY LAVALINK_PLUGINS_1_DEPENDENCY LAVALINK_PLUGINS_1_REPOSITORY +LAVALINK_PLUGINS_DIR + LAVALINK_SERVER_PASSWORD LAVALINK_SERVER_SOURCES_YOUTUBE LAVALINK_SERVER_SOURCES_BANDCAMP @@ -261,19 +273,20 @@ WantedBy=multi-user.target ``` To initiate the service, run + ```shell sudo systemctl daemon-reload sudo systemctl enable lavalink sudo systemctl start lavalink ``` + In addition to the usual log files, you can also view the log with `sudo journalctl -u lavalink`. + ### Docker Docker images can be found under [packages](https://github.com/lavalink-devs/Lavalink/pkgs/container/lavalink) with old builds prior to `v3.7.4` being available on [Docker Hub](https://hub.docker.com/r/fredboat/lavalink/). There are 2 image variants `Ubuntu` and `Alpine`, the `Alpine` variant is smaller and can be used with the `-alpine` suffix, for example `ghcr.io/lavalink-devs/lavalink:3-alpine`. ---- - Install [Docker](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) Create a `docker-compose.yml` with the following content: diff --git a/settings.gradle.kts b/settings.gradle.kts index 8cce7cd49..887c8afdc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,7 +36,7 @@ fun VersionCatalogBuilder.spring() { } fun VersionCatalogBuilder.voice() { - version("lavaplayer", "17c75f5") + version("lavaplayer", "08cfbc0595") library("lavaplayer", "com.github.walkyst.lavaplayer-fork", "lavaplayer").versionRef("lavaplayer") library("lavaplayer-ip-rotator", "com.github.walkyst.lavaplayer-fork", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") @@ -45,8 +45,8 @@ fun VersionCatalogBuilder.voice() { library("koe", "moe.kyokobot.koe", "core").version("2.0.0-rc1") library("koe-udpqueue", "moe.kyokobot.koe", "ext-udpqueue").version("2.0.0-rc1") - version("udpqueue", "0.2.6") - val platforms = listOf("linux-x86-64", "linux-x86", "linux-aarch64", "linux-arm", "win-x86-64", "win-x86", "darwin") + version("udpqueue", "0.2.7") + val platforms = listOf("linux-x86-64", "linux-x86", "linux-aarch64", "linux-arm", "linux-musl-x86-64", "linux-musl-aarch64", "win-x86-64", "win-x86", "darwin") platforms.forEach { library("udpqueue-native-$it", "club.minnced", "udpqueue-native-$it").versionRef("udpqueue") } From 1bcc3df8d84b7c534644cbfa6850ca3169ba62b6 Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Thu, 27 Jul 2023 19:03:37 +0200 Subject: [PATCH 10/73] Update PLUGINS.md (#924) --- PLUGINS.md | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/PLUGINS.md b/PLUGINS.md index 1ceaf455d..f1dc92841 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -21,35 +21,20 @@ You can add your own plugin by submitting a pull-request to this file. ## Developing your own plugin > **Note:** -> If your plugin is developed in Kotlin make sure you are using **Kotlin v1.7.20** +> If your plugin is developed in Kotlin make sure you are using **Kotlin v1.8.22** -Follow these steps to quickly get started with plugin development: -1. Create a copy of https://github.com/lavalink-devs/lavalink-plugin-template -2. Rename the directories `org/example/plugin/` under `src/main/java/` to something more specific like -`io/github/yourusername/yourplugin` -3. Rename `src/main/resources/lavalink-plugins/your-plugin.properties` to the name of your plugin. The file must end -with `.properties`. This is the plugin manifest. -4. Fill out the name, path, and version properties in the manifest. The path is where your classes will be loaded from, -e.g. `io.github.yourusername.yourplugin`. +Follow [these steps](https://github.com/lavalink-devs/lavalink-plugin-template#how-to-use-this-template) to setup a new Lavalink plugin Now you can start writing your plugin. You can test your plugin against Lavalink by running Gradle with the -`:run` Gradle task. The [Gradle documentation](https://docs.gradle.org/current/userguide/userguide.html) might be helpful. +`:runLavalink` Gradle task. The [Gradle plugin documentation](https://github.com/lavalink-devs/lavalink-gradle-plugin#running-the-plugin) might be helpful. -Lavalink has a [plugin API](plugin-api/src/main/java/dev/arbjerg/lavalink/api) which you can integrate with. The API is -provided as an artifact and is used by the template. It is also possible to integrate with internal parts og Lavalink, +Lavalink has a [plugin API](https://javadoc.io/doc/dev.arbjerg.lavalink/plugin-api/latest/dev/arbjerg/lavalink/api/package-summary.html) which you can integrate with. The API is +provided [as an artifact](https://central.sonatype.com/artifact/dev.arbjerg.lavalink/plugin-api) and is used by the template. It is also possible to integrate with internal parts og Lavalink, but this is not recommended. Instead, open an issue or pull-request to change the API. -Lavalink is configured by plugins using the Spring Boot framework using Spring annotations. For instance, you could define -an extension to the WebSocket API by exposing a Spring bean like this: +Lavalink is configured by plugins using the Spring Boot framework using Spring annotations. -```java -@Service -class MyExtension implements WebSocketExtension { - // ... -} -``` - -You can also define custom REST endpoints and configuration file properties. See the Spring Boot documentation for +You can define custom REST endpoints and configuration file properties. See the Spring Boot documentation for [Spring Web MVC](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#web.servlet) and [type-safe configuration](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.external-config.typesafe-configuration-properties). From fe316404fb84e9225092d4001236dfc4a23859c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 28 Jul 2023 20:43:09 +0200 Subject: [PATCH 11/73] update lavaplayer version to 74e6c4d728 --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 887c8afdc..500068551 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,7 +36,7 @@ fun VersionCatalogBuilder.spring() { } fun VersionCatalogBuilder.voice() { - version("lavaplayer", "08cfbc0595") + version("lavaplayer", "74e6c4d728") library("lavaplayer", "com.github.walkyst.lavaplayer-fork", "lavaplayer").versionRef("lavaplayer") library("lavaplayer-ip-rotator", "com.github.walkyst.lavaplayer-fork", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") From f311e2ef885ac324b3f388e73bb7d42d6a2ca0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Wed, 2 Aug 2023 13:47:49 +0200 Subject: [PATCH 12/73] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index be108bf4c..b5e6d8d08 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ A [basic example bot](Testbot) is available. [![Lavalink Guild](https://discordapp.com/api/guilds/1082302532421943407/embed.png?style=banner2)](https://discord.gg/ZW4s47Ppw4) -> **Warning** Lavalink v4 is now in beta! -> See [here](CHANGELOG.md#400-beta1) for more information. +> [!Warning] +> Lavalink v4 is now in beta! See [here](CHANGELOG.md#400-beta1) for more information.
Table of Contents From e2281a4e9ef123484b6e714d2cf68c59e0574071 Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Wed, 2 Aug 2023 22:23:33 +0200 Subject: [PATCH 13/73] Use maven publish plugin (#930) --- LavalinkServer/build.gradle.kts | 68 +++++++----------------- Testbot/build.gradle.kts | 3 +- build.gradle.kts | 62 +++++++++++++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- plugin-api/build.gradle.kts | 64 ++++------------------ protocol/build.gradle.kts | 67 ++++------------------- repositories.gradle | 43 --------------- settings.gradle.kts | 5 ++ 8 files changed, 107 insertions(+), 207 deletions(-) delete mode 100644 repositories.gradle diff --git a/LavalinkServer/build.gradle.kts b/LavalinkServer/build.gradle.kts index fbb61ecae..7d809c7e3 100644 --- a/LavalinkServer/build.gradle.kts +++ b/LavalinkServer/build.gradle.kts @@ -1,12 +1,14 @@ +import com.vanniktech.maven.publish.JavadocJar +import com.vanniktech.maven.publish.KotlinJvm import org.apache.tools.ant.filters.ReplaceTokens import org.springframework.boot.gradle.tasks.bundling.BootJar import org.springframework.boot.gradle.tasks.run.BootRun plugins { application - `maven-publish` kotlin("jvm") id("org.jetbrains.dokka") + alias(libs.plugins.maven.publish.base) } apply(plugin = "org.springframework.boot") @@ -15,28 +17,17 @@ apply(plugin = "org.ajoberstar.grgit") apply(plugin = "com.adarshr.test-logger") apply(plugin = "kotlin") apply(plugin = "kotlin-spring") -apply(from = "../repositories.gradle") val archivesBaseName = "Lavalink" group = "dev.arbjerg.lavalink" description = "Play audio to discord voice channels" application { - mainClass.set("lavalink.server.Launcher") + mainClass = "lavalink.server.Launcher" } java { sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - withJavadocJar() - withSourcesJar() -} - -val dokkaJar by tasks.registering(Jar::class) { - group = JavaBasePlugin.DOCUMENTATION_GROUP - description = "Assembles Javadoc with Dokka" - archiveClassifier.set("javadoc") - from(tasks.dokkaJavadoc) } configurations { @@ -104,11 +95,11 @@ tasks { // https://stackoverflow.com/questions/41444916/multiple-artifacts-issue-with-deploying-zip-to-nexus named("bootDistTar") { - archiveClassifier.set("bootTar") + archiveClassifier = "bootTar" } named("bootDistZip") { - archiveClassifier.set("bootZip") + archiveClassifier = "bootZip" } named("test") { @@ -125,16 +116,16 @@ tasks { } }) - archiveBaseName.set("lavaplayer-natives") - archiveClassifier.set("musl") + archiveBaseName = "lavaplayer-natives" + archiveClassifier = "musl" } withType { - archiveFileName.set("Lavalink.jar") + archiveFileName = "Lavalink.jar" if (findProperty("targetPlatform") == "musl") { - archiveFileName.set("Lavalink-musl.jar") + archiveFileName = "Lavalink-musl.jar" // Exclude base dependency jar exclude { it.name.contains("lavaplayer-natives-fork") || (it.name.contains("udpqueue-native-") && !it.name.contains("musl")) @@ -162,39 +153,18 @@ tasks { } } +mavenPublishing { + configure(KotlinJvm(JavadocJar.Dokka("dokkaHtml"))) + pom { + name = "Lavalink Server" + description = "Lavalink Server" + } +} + publishing { publications { - create("LavalinkServer") { + named("maven") { artifact(tasks.named("bootJar")) - artifact(tasks.kotlinSourcesJar) - artifact(dokkaJar) - - pom { - name.set("Lavalink Server") - description.set("Lavalink Server") - url.set("https://github.com/lavalink-devs/lavalink") - - licenses { - license { - name.set("The MIT License") - url.set("https://github.com/lavalink-devs/Lavalink/blob/master/LICENSE") - } - } - - developers { - developer { - id.set("freyacodes") - name.set("Freya Arbjerg") - url.set("https://www.arbjerg.dev") - } - } - - scm { - connection.set("scm:git:ssh://github.com/lavalink-devs/lavalink.git") - developerConnection.set("scm:git:ssh://github.com/lavalink-devs/lavalink.git") - url.set("https://github.com/lavalink-devs/lavalink") - } - } } } } diff --git a/Testbot/build.gradle.kts b/Testbot/build.gradle.kts index 05ac3045f..9ae13f7f2 100644 --- a/Testbot/build.gradle.kts +++ b/Testbot/build.gradle.kts @@ -1,6 +1,5 @@ plugins { application - kotlin("jvm") } @@ -8,7 +7,7 @@ group = "dev.arbjerg.lavalink" version = "1.0" application { - mainClass.set("lavalink.testbot.TestbotKt") + mainClass = "lavalink.testbot.TestbotKt" } repositories { diff --git a/build.gradle.kts b/build.gradle.kts index bd5d8aa21..f83591527 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import com.vanniktech.maven.publish.MavenPublishBaseExtension +import com.vanniktech.maven.publish.SonatypeHost import org.ajoberstar.grgit.Grgit import org.jetbrains.kotlin.gradle.tasks.KotlinCompile @@ -11,6 +13,7 @@ plugins { id("org.jetbrains.kotlin.jvm") version "1.8.22" id("org.jetbrains.kotlin.plugin.allopen") version "1.8.22" id("org.jetbrains.kotlin.plugin.serialization") version "1.8.22" apply false + alias(libs.plugins.maven.publish.base) apply false } allprojects { @@ -42,6 +45,65 @@ subprojects { options.compilerArgs.add("-Xlint:unchecked") options.compilerArgs.add("-Xlint:deprecation") } + + afterEvaluate { + plugins.withId(libs.plugins.maven.publish.base.get().pluginId) { + configure { + if (findProperty("MAVEN_PASSWORD") != null && findProperty("MAVEN_USERNAME") != null) { + repositories { + val snapshots = "https://maven.arbjerg.dev/snapshots" + val releases = "https://maven.arbjerg.dev/releases" + + maven(if ((version as String).endsWith("-SNAPSHOT")) releases else snapshots) { + credentials { + password = findProperty("MAVEN_PASSWORD") as String? + username = findProperty("MAVEN_USERNAME") as String? + } + } + } + } else { + logger.lifecycle("Not publishing to maven.arbjerg.dev because credentials are not set") + } + } + configure { + coordinates(group.toString(), project.the().archivesName.get(), version.toString()) + + if (findProperty("mavenCentralUsername") != null && findProperty("mavenCentralPassword") != null) { + publishToMavenCentral(SonatypeHost.S01, false) + if (!(version as String).endsWith("-SNAPSHOT")) { + signAllPublications() + } + } else { + logger.lifecycle("Not publishing to OSSRH due to missing credentials") + } + + pom { + url = "https://github.com/lavalink-devs/Lavalink" + + licenses { + license { + name = "MIT License" + url = "https://github.com/lavalink-devs/Lavalink/blob/main/LICENSE" + } + } + + developers { + developer { + id = "freyacodes" + name = "Freya Arbjerg" + url = "https://www.arbjerg.dev" + } + } + + scm { + url = "https://github.com/lavalink-devs/Lavalink/" + connection = "scm:git:git://github.com/lavalink-devs/Lavalink.git" + developerConnection = "scm:git:ssh://git@github.com/lavalink-devs/Lavalink.git" + } + } + } + } + } } @SuppressWarnings("GrMethodMayBeStatic") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a36387743..17a8ddce2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/plugin-api/build.gradle.kts b/plugin-api/build.gradle.kts index 9937c61b2..f0fe1556c 100644 --- a/plugin-api/build.gradle.kts +++ b/plugin-api/build.gradle.kts @@ -1,15 +1,14 @@ +import com.vanniktech.maven.publish.JavadocJar +import com.vanniktech.maven.publish.KotlinJvm import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - signing - `maven-publish` kotlin("jvm") id("org.jetbrains.dokka") + alias(libs.plugins.maven.publish.base) } -apply(from = "../repositories.gradle") - val archivesBaseName = "plugin-api" group = "dev.arbjerg.lavalink" @@ -27,60 +26,15 @@ java { tasks.withType { compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) + jvmTarget = JvmTarget.JVM_17 freeCompilerArgs.add("-Xjvm-default=all") } } -val dokkaJar by tasks.registering(Jar::class) { - group = JavaBasePlugin.DOCUMENTATION_GROUP - description = "Assembles Javadoc with Dokka" - archiveClassifier.set("javadoc") - from(tasks.dokkaJavadoc) -} - -val isGpgKeyDefined = findProperty("signing.gnupg.keyName") != null - -publishing { - publications { - create("PluginApi") { - from(project.components["java"]) - artifact(tasks.kotlinSourcesJar) - artifact(dokkaJar) - - pom { - name.set("Lavalink Plugin API") - description.set("API for Lavalink plugin development") - url.set("https://github.com/lavalink-devs/lavalink") - - licenses { - license { - name.set("The MIT License") - url.set("https://github.com/lavalink-devs/Lavalink/blob/master/LICENSE") - } - } - - developers { - developer { - id.set("freyacodes") - name.set("Freya Arbjerg") - url.set("https://www.arbjerg.dev") - } - } - - scm { - connection.set("scm:git:ssh://github.com/lavalink-devs/lavalink.git") - developerConnection.set("scm:git:ssh://github.com/lavalink-devs/lavalink.git") - url.set("https://github.com/lavalink-devs/lavalink") - } - } - } - } -} - -if (isGpgKeyDefined) { - signing { - sign(publishing.publications["PluginApi"]) - useGpgCmd() +mavenPublishing { + configure(KotlinJvm(JavadocJar.Dokka("dokkaJavadoc"))) + pom { + name = "Lavalink Plugin API" + description = "API for Lavalink plugin development" } } diff --git a/protocol/build.gradle.kts b/protocol/build.gradle.kts index 19a0f2fca..74e2758ef 100644 --- a/protocol/build.gradle.kts +++ b/protocol/build.gradle.kts @@ -1,28 +1,19 @@ +import com.vanniktech.maven.publish.JavadocJar +import com.vanniktech.maven.publish.KotlinMultiplatform import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest plugins { - signing - `maven-publish` kotlin("multiplatform") kotlin("plugin.serialization") id("org.jetbrains.dokka") + alias(libs.plugins.maven.publish.base) } -apply(from = "../repositories.gradle") - val archivesBaseName = "protocol" group = "dev.arbjerg.lavalink" -fun MavenPublication.registerDokkaJar() = - tasks.register("${name}DokkaJar") { - archiveClassifier = "javadoc" - destinationDirectory = destinationDirectory.get().dir(name) - from(tasks.named("dokkaHtml")) - } - - kotlin { jvm { compilations.all { @@ -66,13 +57,13 @@ kotlin { } } - getByName("jsTest") { + named("jsTest") { dependencies { implementation(kotlin("test-js")) } } - getByName("jvmTest") { + named("jvmTest") { dependencies { implementation(kotlin("test-junit5")) } @@ -80,52 +71,14 @@ kotlin { } } -publishing { - publications { - withType { - artifact(registerDokkaJar()) - pom { - name.set("Lavalink Protocol") - description.set("Protocol for Lavalink Client development") - url.set("https://github.com/lavalink-devs/lavalink") - - licenses { - license { - name.set("The MIT License") - url.set("https://github.com/lavalink-devs/Lavalink/blob/master/LICENSE") - } - } - - developers { - developer { - id.set("freyacodes") - name.set("Freya Arbjerg") - url.set("https://www.arbjerg.dev") - } - } - - scm { - connection.set("scm:git:ssh://github.com/lavalink-devs/lavalink.git") - developerConnection.set("scm:git:ssh://github.com/lavalink-devs/lavalink.git") - url.set("https://github.com/lavalink-devs/lavalink") - } - } - } - } -} - -if (findProperty("signing.gnupg.keyName") != null) { - signing { - sign( - publishing.publications["js"], - publishing.publications["jvm"], - publishing.publications["kotlinMultiplatform"] - ) - useGpgCmd() +mavenPublishing { + configure(KotlinMultiplatform(JavadocJar.Dokka("dokkaHtml"))) + pom { + name = "Lavalink Protocol" + description = "Protocol for Lavalink Client development" } } - tasks { withType { useJUnitPlatform() diff --git a/repositories.gradle b/repositories.gradle deleted file mode 100644 index 6b52c9ec1..000000000 --- a/repositories.gradle +++ /dev/null @@ -1,43 +0,0 @@ -// Usage: apply from: 'repositories.gradle' - -publishing { - boolean isOssrhDefined = findProperty("signing.gnupg.keyName") != null && findProperty("ossrhPassword") != null && findProperty("ossrhUsername") != null - boolean isMavenDefined = findProperty('MAVEN_USERNAME') != null && findProperty("MAVEN_PASSWORD") != null - - if (!project.name.equals("Lavalink-Server")) { - if (isOssrhDefined) { - repositories { - def snapshots = "https://s01.oss.sonatype.org/content/repositories/snapshots/" - def releases = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" - - maven { - url = version.endsWith("SNAPSHOT") ? snapshots : releases - credentials { - password = findProperty("ossrhPassword") - username = findProperty("ossrhUsername") - } - } - } - } else { - println("Not capable of publishing to OSSRH because of missing GPG key or OSSRH credentials") - } - } - - if (findProperty("MAVEN_USERNAME") != null && findProperty("MAVEN_PASSWORD") != null) { - println("Publishing to Maven Repo") - repositories { - def snapshots = "https://maven.arbjerg.dev/snapshots" - def releases = "https://maven.arbjerg.dev/releases" - - maven { - url = version.endsWith("SNAPSHOT") ? snapshots : releases - credentials { - password = findProperty("MAVEN_PASSWORD") - username = findProperty("MAVEN_USERNAME") - } - } - } - } else { - println("Maven credentials not found, not publishing to Maven Repo") - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 887c8afdc..55b1d1f26 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -82,4 +82,9 @@ fun VersionCatalogBuilder.common() { fun VersionCatalogBuilder.other() { library("jda", "net.dv8tion", "JDA").version("4.1.1_135") library("lavalink-client", "com.github.FredBoat", "Lavalink-Client").version("8d9b660") + + val mavenPublishPlugin = version("maven-publish-plugin", "0.25.3") + + plugin("maven-publish", "com.vanniktech.maven.publish").versionRef(mavenPublishPlugin) + plugin("maven-publish-base", "com.vanniktech.maven.publish.base").versionRef(mavenPublishPlugin) } From 507b610b229229aefd229754407aa1abb4900308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Wed, 2 Aug 2023 22:28:46 +0200 Subject: [PATCH 14/73] add missing env variables in github workflows --- .github/workflows/build.yml | 12 ++++++++++++ .github/workflows/release.yml | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 19ee18338..347e05b67 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,6 +18,14 @@ on: required: false MAVEN_PASSWORD: required: false + ORG_GRADLE_PROJECT_mavenCentralPassword: + required: false + ORG_GRADLE_PROJECT_mavenCentralUsername: + required: false + ORG_GRADLE_PROJECT_signingInMemoryKey: + required: false + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: + required: false jobs: build: @@ -29,6 +37,10 @@ jobs: DOCKER_IMAGE: ${{ secrets.DOCKER_IMAGE }} MAVEN_USERNAME: ${{ vars.MAVEN_USERNAME }} MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.ORG_GRADLE_PROJECT_MAVENCENTRALPASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.ORG_GRADLE_PROJECT_MAVENCENTRALUSERNAME }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGINMEMORYKEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGINMEMORYKEYPASSWORD }} steps: - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b2a3107db..8ed15f640 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,10 @@ jobs: DOCKER_IMAGE: ${{ secrets.DOCKER_IMAGE }} MAVEN_USERNAME: ${{ vars.MAVEN_USERNAME }} MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.ORG_GRADLE_PROJECT_MAVENCENTRALPASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.ORG_GRADLE_PROJECT_MAVENCENTRALUSERNAME }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGINMEMORYKEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGINMEMORYKEYPASSWORD }} release: needs: build From 9d85bed0ebaa7048106c8bbf6d166dc5eaf9c457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Thu, 3 Aug 2023 17:40:31 +0200 Subject: [PATCH 15/73] use lavalink lavaplayer fork 2.0.0 (#931) --- .../src/main/java/lavalink/server/player/AudioLoader.kt | 6 +++--- .../java/lavalink/server/player/AudioLoaderRestHandler.kt | 5 ++--- settings.gradle.kts | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/LavalinkServer/src/main/java/lavalink/server/player/AudioLoader.kt b/LavalinkServer/src/main/java/lavalink/server/player/AudioLoader.kt index fcdad0e1e..5987d372a 100644 --- a/LavalinkServer/src/main/java/lavalink/server/player/AudioLoader.kt +++ b/LavalinkServer/src/main/java/lavalink/server/player/AudioLoader.kt @@ -49,12 +49,12 @@ class AudioLoader( private val loadResult = CompletableFuture() private val used = AtomicBoolean(false) - fun load(identifier: String?): CompletionStage { + fun load(identifier: String?): LoadResult { val isUsed = used.getAndSet(true) check(!isUsed) { "This loader can only be used once per instance" } log.trace("Loading item with identifier $identifier") - audioPlayerManager.loadItem(identifier, this) - return loadResult + audioPlayerManager.loadItemSync(identifier, this) + return loadResult.get() } override fun trackLoaded(audioTrack: AudioTrack) { diff --git a/LavalinkServer/src/main/java/lavalink/server/player/AudioLoaderRestHandler.kt b/LavalinkServer/src/main/java/lavalink/server/player/AudioLoaderRestHandler.kt index 6847af31d..83114fc7e 100644 --- a/LavalinkServer/src/main/java/lavalink/server/player/AudioLoaderRestHandler.kt +++ b/LavalinkServer/src/main/java/lavalink/server/player/AudioLoaderRestHandler.kt @@ -51,10 +51,9 @@ class AudioLoaderRestHandler( fun loadTracks( request: HttpServletRequest, @RequestParam identifier: String - ): CompletionStage> { + ): ResponseEntity { log.info("Got request to load for identifier \"${identifier}\"") - return AudioLoader(audioPlayerManager, pluginInfoModifiers).load(identifier) - .thenApply { ResponseEntity.ok(it) } + return ResponseEntity.ok(AudioLoader(audioPlayerManager, pluginInfoModifiers).load(identifier)) } @GetMapping("/v4/decodetrack") diff --git a/settings.gradle.kts b/settings.gradle.kts index c35dfed60..d81126fa8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,10 +36,10 @@ fun VersionCatalogBuilder.spring() { } fun VersionCatalogBuilder.voice() { - version("lavaplayer", "74e6c4d728") + version("lavaplayer", "2.0.0") - library("lavaplayer", "com.github.walkyst.lavaplayer-fork", "lavaplayer").versionRef("lavaplayer") - library("lavaplayer-ip-rotator", "com.github.walkyst.lavaplayer-fork", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") + library("lavaplayer", "dev.arbjerg", "lavaplayer").versionRef("lavaplayer") + library("lavaplayer-ip-rotator", "dev.arbjerg", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") library("lavadsp", "dev.arbjerg", "lavadsp").version("0.7.8") library("koe", "moe.kyokobot.koe", "core").version("2.0.0-rc1") From 6f37eba6d1f502f72e4d0c461959241e10ab515d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Thu, 3 Aug 2023 17:55:57 +0200 Subject: [PATCH 16/73] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc71834ae..bbe9b2c49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ Each release usually includes various fixes and improvements. The most noteworthy of these, as well as any features and breaking changes, are listed here. +## 4.0.0-beta.3 +* Update lavaplayer to [`2.0.0`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.0) - Fixed YouTube 403 errors & YouTube access token errors + ## 4.0.0-beta.2 * Update lavaplayer to [`08cfbc0`](https://github.com/Walkyst/lavaplayer-fork/commit/08cfbc05953128f3cf727ea3bcbe41dabcd1c7db) - Fixed ogg streaming * Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) From 9d6f2edb34d1fe5b5d3c6c67c55045b56b3cc847 Mon Sep 17 00:00:00 2001 From: Victoria Casasampere Fernandez Date: Fri, 4 Aug 2023 22:18:27 +0200 Subject: [PATCH 17/73] Update frame stats documentation (V4) (#934) --- IMPLEMENTATION.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index 85f271438..d92f6f1c0 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -238,7 +238,7 @@ Dispatched every x seconds (configurable in `application.yml`) with the current #### Stats OP -A collection of stats sent every minute. +A collection of statistics sent every minute. ##### Stats Object @@ -270,11 +270,13 @@ A collection of stats sent every minute. ##### Frame Stats -| Field | Type | Description | -|---------|------|----------------------------------------| -| sent | int | The amount of frames sent to Discord | -| nulled | int | The amount of frames that were nulled | -| deficit | int | The amount of frames that were deficit | +| Field | Type | Description | +|-----------|------|----------------------------------------------------------------------| +| sent | int | The amount of frames sent to Discord | +| nulled | int | The amount of frames that were nulled | +| deficit * | int | The difference between sent frames and the expected amount of frames | + +\* The expected amount of frames is 3000 (1 every 20 ms) per player. If the `deficit` is negative, too many frames were sent, and if it's positive, not enough frames got sent.
Example Payload @@ -297,9 +299,9 @@ A collection of stats sent every minute. "lavalinkLoad": 0.5 }, "frameStats": { - "sent": 123456789, - "nulled": 123456789, - "deficit": 123456789 + "sent": 6000, + "nulled": 10, + "deficit": -3010 } } ``` From b8055f3f86be6f5225d170d55afada2ccd991ef1 Mon Sep 17 00:00:00 2001 From: Freya Arbjerg Date: Sat, 5 Aug 2023 16:02:01 +0200 Subject: [PATCH 18/73] Add a change request template (#936) --- .github/ISSUE_TEMPLATE/change_request.yml | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/change_request.yml diff --git a/.github/ISSUE_TEMPLATE/change_request.yml b/.github/ISSUE_TEMPLATE/change_request.yml new file mode 100644 index 000000000..58b174a11 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/change_request.yml @@ -0,0 +1,33 @@ +name: Change Request +description: Request a feature or change +labels: ["enhancement"] +body: + - type: input + id: request + attributes: + label: Change request + description: What are you requesting? + validations: + required: true + - type: input + id: relevance + attributes: + label: Relevance + description: Is this change relevant to the greater community? + validations: + required: true + - type: input + id: plugin + attributes: + label: Could this be a plugin instead? + description: Make your case as to whether this needs to be part of Lavalink itself. + validations: + required: true + - type: checkboxes + attributes: + label: Checklist + options: + - label: I have checked for duplicate issues + required: true + - label: I have checked for existing plugins + required: true From 654be728a48bac57aaa7b768c87cc725fb028abf Mon Sep 17 00:00:00 2001 From: Freya Arbjerg Date: Sat, 5 Aug 2023 16:04:34 +0200 Subject: [PATCH 19/73] Make change request form use paragraph fields --- .github/ISSUE_TEMPLATE/change_request.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/change_request.yml b/.github/ISSUE_TEMPLATE/change_request.yml index 58b174a11..f041b83b9 100644 --- a/.github/ISSUE_TEMPLATE/change_request.yml +++ b/.github/ISSUE_TEMPLATE/change_request.yml @@ -2,21 +2,21 @@ name: Change Request description: Request a feature or change labels: ["enhancement"] body: - - type: input + - type: textarea id: request attributes: label: Change request description: What are you requesting? validations: required: true - - type: input + - type: textarea id: relevance attributes: label: Relevance description: Is this change relevant to the greater community? validations: required: true - - type: input + - type: textarea id: plugin attributes: label: Could this be a plugin instead? From 96b4d45f51440c4f5ce427067f4c2f774267c08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Tue, 8 Aug 2023 13:21:46 +0200 Subject: [PATCH 20/73] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b5e6d8d08..0ebc0e80b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Lavalink logo -A standalone audio sending node based on [Lavaplayer](https://github.com/sedmelluq/lavaplayer) and [Koe](https://github.com/KyokoBot/koe). +A standalone audio sending node based on [Lavaplayer](https://github.com/lavalink-devs/lavaplayer) and [Koe](https://github.com/KyokoBot/koe). Allows for sending audio without it ever reaching any of your shards. Being used in production by FredBoat, Dyno, LewdBot, and more. From 0f59a5a981af0dfa13cb9f51145e077e8dd89e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 13 Aug 2023 12:07:08 +0200 Subject: [PATCH 21/73] add null-check before calling List.indexOf with possible null value to avoid npe thanks to ImmutableCollections --- LavalinkServer/src/main/java/lavalink/server/util/util.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LavalinkServer/src/main/java/lavalink/server/util/util.kt b/LavalinkServer/src/main/java/lavalink/server/util/util.kt index 0cd53905b..4a093cd27 100644 --- a/LavalinkServer/src/main/java/lavalink/server/util/util.kt +++ b/LavalinkServer/src/main/java/lavalink/server/util/util.kt @@ -76,7 +76,7 @@ fun AudioTrack.toInfo(): TrackInfo { } fun AudioPlaylist.toPlaylistInfo(): PlaylistInfo { - return PlaylistInfo(this.name, this.tracks.indexOf(this.selectedTrack)) + return PlaylistInfo(this.name, if (this.selectedTrack == null) -1 else this.tracks.indexOf(this.selectedTrack)) } From c299bb6b575a0cd184117a2fe4b35d3410caaa9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Tue, 15 Aug 2023 16:45:31 +0200 Subject: [PATCH 22/73] remove outdated startTime from implementation docs --- IMPLEMENTATION.md | 1 - 1 file changed, 1 deletion(-) diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index d92f6f1c0..3fab96b91 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -809,7 +809,6 @@ When `identifier` is used, Lavalink will try to resolve the identifier as a sing { "encodedTrack": "...", "identifier": "...", - "startTime": 0, "endTime": 0, "volume": 100, "position": 32400, From fb66f585669b9711dd671ef2ae1f740acb52aeb9 Mon Sep 17 00:00:00 2001 From: Victoria Casasampere Fernandez Date: Wed, 16 Aug 2023 12:11:30 +0200 Subject: [PATCH 23/73] Add lavalink-rs to the list of V4 libraries. (#945) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0ebc0e80b..36bc5e4b9 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Version numbers can come in different combinations, depending on the release typ | [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | | [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | | [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | +| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based |
v3.7 supporting Client Libraries From 5a560409fdedd5d5b150fde0f937aa0c824c7577 Mon Sep 17 00:00:00 2001 From: Tomato6966 Date: Thu, 17 Aug 2023 18:08:52 +0200 Subject: [PATCH 24/73] add lavalink client (#947) --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 36bc5e4b9..dcb68ca76 100644 --- a/README.md +++ b/README.md @@ -98,18 +98,19 @@ Version numbers can come in different combinations, depending on the release typ --- ## Client libraries: -| Client | Platform | Compatible With | Additional Information | -|-----------------------------------------------------------------|----------|--------------------------------------------|------------------------| -| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | -| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | -| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | -| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | -| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based | +| Client | Platform | Compatible With | Additional Information | +|------------------------------------------------------------------|----------|--------------------------------------------|------------------------| +| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | +| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | +| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | +| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | +| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based |
v3.7 supporting Client Libraries From 2eaede09729793fbea72a03b1c964fab267d32a7 Mon Sep 17 00:00:00 2001 From: "Pedro.js" Date: Sat, 19 Aug 2023 18:22:25 -0300 Subject: [PATCH 25/73] Add FastLink to the clients list (#949) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dcb68ca76..d7b2fcf2e 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ Version numbers can come in different combinations, depending on the release typ | [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | | [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | | [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | +| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | | [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | | [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | | [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based | From 8a6c376407205e8208aa452c8b59443774c2e754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 20 Aug 2023 20:31:25 +0200 Subject: [PATCH 26/73] add Omissible#isPresent & Omissible#isOmitted --- .../kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt index a0ef72b5f..f3215cdcd 100644 --- a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt @@ -70,6 +70,10 @@ class OmissableSerializer(private val childSerializer: KSerializer) : KSer } } +fun Omissible.isPresent() = this is Omissible.Present + +fun Omissible.isOmitted() = this is Omissible.Omitted + fun Omissible.takeIfPresent(predicate: (T) -> Boolean = { true }) = if (this is Omissible.Present) value.takeIf(predicate) else null From a7d1c03f1c67b717fcbffc8a213daa3627a59794 Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Mon, 21 Aug 2023 20:45:37 +0200 Subject: [PATCH 27/73] Use contracts for isPresent (#950) --- .../arbjerg/lavalink/protocol/v4/omissible.kt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt index f3215cdcd..a9fbb1aaf 100644 --- a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/omissible.kt @@ -6,6 +6,8 @@ import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract import kotlin.jvm.JvmInline @Serializable(with = OmissableSerializer::class) @@ -70,9 +72,21 @@ class OmissableSerializer(private val childSerializer: KSerializer) : KSer } } -fun Omissible.isPresent() = this is Omissible.Present +@OptIn(ExperimentalContracts::class) +fun Omissible.isPresent(): Boolean { + contract { + returns(true) implies (this@isPresent is Omissible.Present) + } + return this is Omissible.Present +} -fun Omissible.isOmitted() = this is Omissible.Omitted +@OptIn(ExperimentalContracts::class) +fun Omissible.isOmitted(): Boolean { + contract { + returns(true) implies (this@isOmitted is Omissible.Omitted) + } + return this is Omissible.Omitted +} fun Omissible.takeIfPresent(predicate: (T) -> Boolean = { true }) = if (this is Omissible.Present) value.takeIf(predicate) else null From 5fa14d012431037b0a1100814ec9fc8f738968c7 Mon Sep 17 00:00:00 2001 From: Angelo Breuer <46497296+angelobreuer@users.noreply.github.com> Date: Tue, 22 Aug 2023 01:24:14 +0200 Subject: [PATCH 28/73] docs: Add Lavalink4NET to client libraries (#951) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d7b2fcf2e..9cfd87657 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ Version numbers can come in different combinations, depending on the release typ | [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | | [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | | [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | | [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | | [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based | @@ -129,6 +130,7 @@ Version numbers can come in different combinations, depending on the release typ | [Cosmicord.js](https://github.com/SudhanPlayz/Cosmicord.js) | Node.js | **Any** | | | [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | Only prior v10.4.1 | | [Nomia](https://github.com/DHCPCD9/Nomia) | .NET | DSharpPlus | | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus | < v4 | | [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | |
From 944df988b79b60d2f4377ef53ef18f2eda1a2e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Tue, 22 Aug 2023 12:47:29 +0200 Subject: [PATCH 29/73] add LavaSearch plugin --- PLUGINS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PLUGINS.md b/PLUGINS.md index f1dc92841..08e27ca5c 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -6,8 +6,9 @@ WebSocket handling, REST endpoints, and much more. List of plugins: - [Google Cloud TTS plugin](https://github.com/DuncteBot/tts-plugin) A text to speech plugin using the [google cloud tts api](https://cloud.google.com/text-to-speech/docs) -- [SponsorBlock plugin](https://github.com/TopiSenpai/Sponsorblock-Plugin) for skipping sponsor segments in YouTube videos -- [LavaSrc plugin](https://github.com/TopiSenpai/LavaSrc) adds Spotify, Apple Music & Deezer(native play) support +- [SponsorBlock plugin](https://github.com/topi314/Sponsorblock-Plugin) for skipping sponsor segments in YouTube videos +- [LavaSrc plugin](https://github.com/topi314/LavaSrc) adds Spotify, Apple Music & Deezer(native play) support +- [LavaSearch plugin](https://github.com/topi314/LavaSearch) adds advanced search functionality including playlists, albums, artists, tracks & terms - [DuncteBot plugin](https://github.com/DuncteBot/skybot-lavalink-plugin) adds additional source managers that are not widely used - [Extra Filter plugin](https://github.com/rohank05/lavalink-filter-plugin) adds additional audio filters to lavalink - [XM plugin](https://github.com/esmBot/lava-xm-plugin) adds support for various [music tracker module](https://en.wikipedia.org/wiki/Module_file) formats From d001bda1217c6a8faa3c0a5803fb5eb5d0b95bcf Mon Sep 17 00:00:00 2001 From: Tomato6966 Date: Thu, 17 Aug 2023 18:08:52 +0200 Subject: [PATCH 30/73] add lavalink client (#947) --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 36bc5e4b9..dcb68ca76 100644 --- a/README.md +++ b/README.md @@ -98,18 +98,19 @@ Version numbers can come in different combinations, depending on the release typ --- ## Client libraries: -| Client | Platform | Compatible With | Additional Information | -|-----------------------------------------------------------------|----------|--------------------------------------------|------------------------| -| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | -| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | -| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | -| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | -| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based | +| Client | Platform | Compatible With | Additional Information | +|------------------------------------------------------------------|----------|--------------------------------------------|------------------------| +| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | +| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | +| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | +| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | +| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based |
v3.7 supporting Client Libraries From 5985d32907429084fcc4b21ceceb9081ba334cc4 Mon Sep 17 00:00:00 2001 From: "Pedro.js" Date: Sat, 19 Aug 2023 18:22:25 -0300 Subject: [PATCH 31/73] Add FastLink to the clients list (#949) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dcb68ca76..d7b2fcf2e 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ Version numbers can come in different combinations, depending on the release typ | [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | | [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | | [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | +| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | | [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | | [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | | [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based | From 474a5a0fd659c14ae488f877f31a717142aa541f Mon Sep 17 00:00:00 2001 From: Angelo Breuer <46497296+angelobreuer@users.noreply.github.com> Date: Tue, 22 Aug 2023 01:24:14 +0200 Subject: [PATCH 32/73] docs: Add Lavalink4NET to client libraries (#951) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d7b2fcf2e..9cfd87657 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ Version numbers can come in different combinations, depending on the release typ | [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | | [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | | [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | | [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | | [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based | @@ -129,6 +130,7 @@ Version numbers can come in different combinations, depending on the release typ | [Cosmicord.js](https://github.com/SudhanPlayz/Cosmicord.js) | Node.js | **Any** | | | [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | Only prior v10.4.1 | | [Nomia](https://github.com/DHCPCD9/Nomia) | .NET | DSharpPlus | | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus | < v4 | | [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | |
From f90569c80db19b8af84c4e19ab010197d2ecc0c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Tue, 22 Aug 2023 12:47:29 +0200 Subject: [PATCH 33/73] add LavaSearch plugin --- PLUGINS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PLUGINS.md b/PLUGINS.md index f1dc92841..08e27ca5c 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -6,8 +6,9 @@ WebSocket handling, REST endpoints, and much more. List of plugins: - [Google Cloud TTS plugin](https://github.com/DuncteBot/tts-plugin) A text to speech plugin using the [google cloud tts api](https://cloud.google.com/text-to-speech/docs) -- [SponsorBlock plugin](https://github.com/TopiSenpai/Sponsorblock-Plugin) for skipping sponsor segments in YouTube videos -- [LavaSrc plugin](https://github.com/TopiSenpai/LavaSrc) adds Spotify, Apple Music & Deezer(native play) support +- [SponsorBlock plugin](https://github.com/topi314/Sponsorblock-Plugin) for skipping sponsor segments in YouTube videos +- [LavaSrc plugin](https://github.com/topi314/LavaSrc) adds Spotify, Apple Music & Deezer(native play) support +- [LavaSearch plugin](https://github.com/topi314/LavaSearch) adds advanced search functionality including playlists, albums, artists, tracks & terms - [DuncteBot plugin](https://github.com/DuncteBot/skybot-lavalink-plugin) adds additional source managers that are not widely used - [Extra Filter plugin](https://github.com/rohank05/lavalink-filter-plugin) adds additional audio filters to lavalink - [XM plugin](https://github.com/esmBot/lava-xm-plugin) adds support for various [music tracker module](https://en.wikipedia.org/wiki/Module_file) formats From b38b05d27ff97ed162a478cdc01d58007745c403 Mon Sep 17 00:00:00 2001 From: Emmanuel Lobo <76094069+UnschooledGamer@users.noreply.github.com> Date: Sun, 3 Sep 2023 20:11:56 +0530 Subject: [PATCH 34/73] =?UTF-8?q?docs:=20=F0=9F=93=9D=20Add=20Riffy=20to?= =?UTF-8?q?=20client=20libraries=20(#958)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: :memo: Add Riffy to client libraries * Fix spacing in README * Fix the order in README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9cfd87657..4c567afff 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Version numbers can come in different combinations, depending on the release typ | [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | | [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | | [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | +| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | | [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | | [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | | [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | From 16ca93f6469a6c3773282cce43a5b9967bc14c82 Mon Sep 17 00:00:00 2001 From: Victoria Casasampere Fernandez Date: Sat, 16 Sep 2023 21:09:07 +0200 Subject: [PATCH 35/73] Add Python support to lavalink-rs (#962) modified: README.md --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4c567afff..37d615884 100644 --- a/README.md +++ b/README.md @@ -98,22 +98,22 @@ Version numbers can come in different combinations, depending on the release typ --- ## Client libraries: -| Client | Platform | Compatible With | Additional Information | -|------------------------------------------------------------------|----------|--------------------------------------------|------------------------| -| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | -| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | -| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | -| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | -| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | -| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | -| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | -| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | -| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust | **Any** | `tokio`-based | +| Client | Platform | Compatible With | Additional Information | +|------------------------------------------------------------------|--------------|--------------------------------------------|--------------------------------| +| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | +| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | +| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | +| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | +| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | +| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | +| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust, Python | **Any** | `tokio`-based, `asyncio`-based |
v3.7 supporting Client Libraries From 64e161d74abb4135cb2caaf483ae7c722c9a9469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Wed, 27 Sep 2023 13:20:51 +0200 Subject: [PATCH 36/73] update lavaplayer to 2.0.2 --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index d81126fa8..226c802bd 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,7 +36,7 @@ fun VersionCatalogBuilder.spring() { } fun VersionCatalogBuilder.voice() { - version("lavaplayer", "2.0.0") + version("lavaplayer", "2.0.2") library("lavaplayer", "dev.arbjerg", "lavaplayer").versionRef("lavaplayer") library("lavaplayer-ip-rotator", "dev.arbjerg", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") From 839db58f475a3ab7e9e5a1aa3e2b2821af373e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Wed, 27 Sep 2023 13:25:24 +0200 Subject: [PATCH 37/73] update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbe9b2c49..2def2277d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ Each release usually includes various fixes and improvements. The most noteworthy of these, as well as any features and breaking changes, are listed here. +## 4.0.0-beta.4 +* Update lavaplayer to [`2.0.2`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Support MPEG 2.5 and fixed some requests not timing out +* Add `Omissible#isPresent` & `Omissible#isOmitted` to the `protocol` module +* Fix null pointer when a playlist has no selected track + ## 4.0.0-beta.3 * Update lavaplayer to [`2.0.0`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.0) - Fixed YouTube 403 errors & YouTube access token errors From 8df70c20fd29ee36bab44bbc7632c5e5710d9afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Tue, 10 Oct 2023 18:55:50 +0200 Subject: [PATCH 38/73] add java lavalink-client to README --- README.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 37d615884..937970703 100644 --- a/README.md +++ b/README.md @@ -98,22 +98,23 @@ Version numbers can come in different combinations, depending on the release typ --- ## Client libraries: -| Client | Platform | Compatible With | Additional Information | -|------------------------------------------------------------------|--------------|--------------------------------------------|--------------------------------| -| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | -| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | -| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | -| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | -| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | -| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | -| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | -| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | -| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust, Python | **Any** | `tokio`-based, `asyncio`-based | +| Client | Platform | Compatible With | Additional Information | +|---------------------------------------------------------------------|-----------------|--------------------------------------------|--------------------------------| +| [Lavalink-Client](https://github.com/lavalink-devs/Lavalink-Client) | Java/Kotlin/JVM | JDA/Discord4J/**Any** | Uses reactor | +| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | +| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | +| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | +| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | +| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | +| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | +| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust, Python | **Any** | `tokio`-based, `asyncio`-based |
v3.7 supporting Client Libraries From 76ef7c73cdc31767cfa0320e8b1db34367f2ed08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Thu, 12 Oct 2023 23:08:54 +0200 Subject: [PATCH 39/73] default lavalink plugin repository (#972) * implement default lavalink plugin repository * Update LavalinkServer/application.yml.example Co-authored-by: Freya Arbjerg * Update LavalinkServer/application.yml.example Co-authored-by: Freya Arbjerg * Apply suggestions from code review Co-authored-by: Freya Arbjerg --------- Co-authored-by: Freya Arbjerg --- LavalinkServer/application.yml.example | 11 +++++-- .../server/bootstrap/PluginManager.kt | 7 +++-- .../server/bootstrap/PluginsConfig.kt | 5 +++- PLUGINS.md | 30 +++++++++++++++++++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/LavalinkServer/application.yml.example b/LavalinkServer/application.yml.example index 39d2ab0d9..8b63c2e34 100644 --- a/LavalinkServer/application.yml.example +++ b/LavalinkServer/application.yml.example @@ -1,15 +1,20 @@ server: # REST and WS server port: 2333 address: 0.0.0.0 + http2: + enabled: false # Whether to enable HTTP/2 support plugins: # name: # Name of the plugin # some_key: some_value # Some key-value pair for the plugin # another_key: another_value lavalink: plugins: -# - dependency: "group:artifact:version" -# repository: "repository" - pluginsDir: "./plugins" +# - dependency: "com.github.example:example-plugin:1.0.0" # required, the coordinates of your plugin +# repository: "https://maven.example.com/releases" # optional, defaults to the Lavalink releases repository by default +# snapshot: false # optional, defaults to false, used to tell Lavalink to use the snapshot repository instead of the release repository +# pluginsDir: "./plugins" # optional, defaults to "./plugins" +# defaultPluginRepository: "https://maven.lavalink.dev/releases" # optional, defaults to the Lavalink release repository +# defaultPluginSnapshotRepository: "https://maven.lavalink.dev/snapshots" # optional, defaults to the Lavalink snapshot repository server: password: "youshallnotpass" sources: diff --git a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt index 44429644a..fc3b83ee4 100644 --- a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt +++ b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt @@ -47,10 +47,13 @@ class PluginManager(val config: PluginsConfig) { data class Declaration(val group: String, val name: String, val version: String, val repository: String) val declarations = config.plugins.map { declaration -> - if (declaration.dependency == null || declaration.repository == null) throw RuntimeException("Illegal declaration $declaration") + if (declaration.dependency == null) throw RuntimeException("Illegal dependency declaration: null") val fragments = declaration.dependency!!.split(":") if (fragments.size != 3) throw RuntimeException("Invalid dependency \"${declaration.dependency}\"") - val repository = + + var repository = declaration.repository + ?: if (declaration.snapshot) config.defaultPluginSnapshotRepository else config.defaultPluginRepository + repository = if (declaration.repository!!.endsWith("/")) declaration.repository!! else declaration.repository!! + "/" Declaration(fragments[0], fragments[1], fragments[2], repository) } diff --git a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginsConfig.kt b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginsConfig.kt index aaeac29cc..5f6bd0421 100644 --- a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginsConfig.kt +++ b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginsConfig.kt @@ -8,9 +8,12 @@ import org.springframework.stereotype.Component class PluginsConfig { var plugins: List = emptyList() var pluginsDir: String = "./plugins" + var defaultPluginRepository: String = "https://maven.lavalink.dev/releases" + var defaultPluginSnapshotRepository: String = "https://maven.lavalink.dev/snapshots" } data class PluginDeclaration( var dependency: String? = null, - var repository: String? = null + var repository: String? = null, + var snapshot: Boolean = false ) \ No newline at end of file diff --git a/PLUGINS.md b/PLUGINS.md index 08e27ca5c..d848c8a84 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -19,6 +19,36 @@ for instructions. You can add your own plugin by submitting a pull-request to this file. +## Distributing your plugin + +The official plugin repository is hosted on https://maven.lavalink.dev. If you want to publish your plugin there, please reach out to us via [Discord](https://discord.gg/ZW4s47Ppw4) for credentials. +The Lavalink team has release (https://maven.lavalink.dev/releases) and snapshot (https://maven.lavalink.dev/snapshots) repositories which you can use to publish your plugin. +By default, Lavalink will look for the plugin in the Lavalink repository, but you can also specify a custom repository for each plugin in your `application.yml` file. + +```yaml + +lavalink: + plugins: + - dependency: "com.github.example:example-plugin:1.0.0" # required, the dependency to your plugin + repository: "https://maven.example.com/releases" # optional, defaults to https://maven.lavalink.dev/releases for releases + snapshot: false # optional, defaults to false, used to tell Lavalink to use the snapshot repository instead of the release repository +``` + +The default repositories can also be overridden in your `application.yml` file. + +```yaml +lavalink: + defaultPluginRepository: "https://maven.example.com/releases" # optional, defaults to https://maven.lavalink.dev/releases + defaultPluginSnapshotRepository: "https://maven.example.com/snapshots" # optional, defaults to https://maven.lavalink.dev/snapshots +``` + +Additionally, you can override the default plugin path where Lavalink saves and loads the downloaded plugins. + +```yaml +lavalink: + pluginsDir: "./lavalink-plugins" # optional, defaults to "./plugins" +``` + ## Developing your own plugin > **Note:** From f0c93edf34fbbf6298c78af410424471745f2f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Fri, 13 Oct 2023 12:24:36 +0200 Subject: [PATCH 40/73] only seek when player is playing --- .../main/java/lavalink/server/player/PlayerRestHandler.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt b/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt index 6c875621a..18355d8a8 100644 --- a/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt +++ b/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt @@ -124,8 +124,10 @@ class PlayerRestHandler( // we handle position differently for playing new tracks playerUpdate.position.takeIfPresent { encodedTrack is Omissible.Omitted && playerUpdate.identifier is Omissible.Omitted } ?.let { - player.seekTo(it) - SocketServer.sendPlayerUpdate(context, player) + if (player.isPlaying) { + player.seekTo(it) + SocketServer.sendPlayerUpdate(context, player) + } } playerUpdate.endTime.takeIfPresent { encodedTrack is Omissible.Omitted && playerUpdate.identifier is Omissible.Omitted } From e35993d36a1ecdc0384e22f9c6dd2b6cbae033ab Mon Sep 17 00:00:00 2001 From: Freya Arbjerg Date: Mon, 16 Oct 2023 11:08:46 +0200 Subject: [PATCH 41/73] Fix GitHub-induced 404 link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 937970703..12d87b15e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ A [basic example bot](Testbot) is available. [![Lavalink Guild](https://discordapp.com/api/guilds/1082302532421943407/embed.png?style=banner2)](https://discord.gg/ZW4s47Ppw4) > [!Warning] -> Lavalink v4 is now in beta! See [here](CHANGELOG.md#400-beta1) for more information. +> Lavalink v4 is now in beta! See [the changelog](CHANGELOG.md) for more information.
Table of Contents From 380cfb5b9061034aa4a9d45d9c20e954592ef9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 5 Nov 2023 01:17:47 +0100 Subject: [PATCH 42/73] update lavaplayer to 2.0.3 --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 226c802bd..c89cb58bf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,7 +36,7 @@ fun VersionCatalogBuilder.spring() { } fun VersionCatalogBuilder.voice() { - version("lavaplayer", "2.0.2") + version("lavaplayer", "2.0.3") library("lavaplayer", "dev.arbjerg", "lavaplayer").versionRef("lavaplayer") library("lavaplayer-ip-rotator", "dev.arbjerg", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") From d0880fdbec62a1e1e98d58ef3ee31e2a19fa1726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 5 Nov 2023 01:21:18 +0100 Subject: [PATCH 43/73] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2def2277d..1cb5a9912 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ Each release usually includes various fixes and improvements. The most noteworthy of these, as well as any features and breaking changes, are listed here. +## 4.0.0-beta.5 +* Update lavaplayer to [`2.0.3`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Fixed YouTube access token errors + ## 4.0.0-beta.4 * Update lavaplayer to [`2.0.2`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Support MPEG 2.5 and fixed some requests not timing out * Add `Omissible#isPresent` & `Omissible#isOmitted` to the `protocol` module From eac987872d8e6202217f5b3d5de0fe3aabfe9abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 5 Nov 2023 01:33:00 +0100 Subject: [PATCH 44/73] add missing changes to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cb5a9912..103055a5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The most noteworthy of these, as well as any features and breaking changes, are ## 4.0.0-beta.5 * Update lavaplayer to [`2.0.3`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Fixed YouTube access token errors +* Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](https://github.com/lavalink-devs/Lavalink/blob/master/PLUGINS.md#distributing-your-plugin) +* Fixed error when seeking and player is not playing anything in ## 4.0.0-beta.4 * Update lavaplayer to [`2.0.2`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Support MPEG 2.5 and fixed some requests not timing out From cb14d44c9a0513e16a477ac139ff1925656cf16e Mon Sep 17 00:00:00 2001 From: Mysty Date: Sun, 5 Nov 2023 21:43:06 +1000 Subject: [PATCH 45/73] Add Wavelink to README (#976) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Wavelink to README Added version 3 of Wavelink to README. Update previous Wavelink information. * Change additional info * Add version to additional info. * Update README.md --------- Co-authored-by: Toπ --- README.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 12d87b15e..4b9767a89 100644 --- a/README.md +++ b/README.md @@ -98,23 +98,24 @@ Version numbers can come in different combinations, depending on the release typ --- ## Client libraries: -| Client | Platform | Compatible With | Additional Information | -|---------------------------------------------------------------------|-----------------|--------------------------------------------|--------------------------------| -| [Lavalink-Client](https://github.com/lavalink-devs/Lavalink-Client) | Java/Kotlin/JVM | JDA/Discord4J/**Any** | Uses reactor | -| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | -| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | -| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | -| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | -| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | -| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | -| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | -| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | -| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust, Python | **Any** | `tokio`-based, `asyncio`-based | +| Client | Platform | Compatible With | Additional Information | +|---------------------------------------------------------------------------|-----------------|--------------------------------------------|---------------------------------| +| [Lavalink-Client](https://github.com/lavalink-devs/Lavalink-Client) | Java/Kotlin/JVM | JDA/Discord4J/**Any** | Uses reactor | +| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Wavelink](https://github.com/PythonistaGuild/Wavelink/tree/feature/v3) | Python | discord.py **V2** | Pre-Release (Version 3+) | +| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | +| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | +| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | +| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | +| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | +| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | +| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust, Python | **Any** | `tokio`-based, `asyncio`-based |
v3.7 supporting Client Libraries @@ -124,7 +125,7 @@ Version numbers can come in different combinations, depending on the release typ | [Lavalink.kt](https://github.com/DRSchlaubi/lavalink.kt) | Kotlin | JDA/Kord/**Any** | Kotlin Coroutines | | [lavaplay.py](https://github.com/HazemMeqdad/lavaplay.py) | Python | **Any\*** | *`asyncio`-based libraries only | | [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Wavelink](https://github.com/PythonistaGuild/Wavelink) | Python | discord.py **V2** | | +| [Wavelink](https://github.com/PythonistaGuild/Wavelink) | Python | discord.py **V2** | Version >=2, <3 | | [Pomice](https://github.com/cloudwithax/pomice) | Python | discord.py **V2** | | | [Lavacord](https://github.com/lavacord/lavacord) | Node.js | **Any** | | | [Poru](https://github.com/parasop/poru) | Node.js | **Any** | | From 7655511085347df8cb9402092c6f79c40061e65e Mon Sep 17 00:00:00 2001 From: Freya Arbjerg Date: Tue, 14 Nov 2023 13:46:57 +0100 Subject: [PATCH 46/73] Clarify error message about incomplete voice state --- .../src/main/java/lavalink/server/player/PlayerRestHandler.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt b/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt index 18355d8a8..6bd043499 100644 --- a/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt +++ b/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt @@ -76,9 +76,9 @@ class PlayerRestHandler( } playerUpdate.voice.ifPresent { - //discord sometimes send a partial server update missing the endpoint, which can be ignored. + // Discord sometimes sends a partial voice server update missing the endpoint, which can be ignored. if (it.endpoint.isEmpty() || it.token.isEmpty() || it.sessionId.isEmpty()) { - throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Partial voice state update: $it") + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Partial Lavalink voice state: $it") } } From d685d986fab058d3263abd4f17167e86a5d98ca2 Mon Sep 17 00:00:00 2001 From: Freya Arbjerg Date: Tue, 14 Nov 2023 14:15:43 +0100 Subject: [PATCH 47/73] Add logging of Koe gateway errors (#982) --- .../src/main/java/lavalink/server/io/SocketContext.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/LavalinkServer/src/main/java/lavalink/server/io/SocketContext.kt b/LavalinkServer/src/main/java/lavalink/server/io/SocketContext.kt index 2f0f5a0d7..874e0d2e8 100644 --- a/LavalinkServer/src/main/java/lavalink/server/io/SocketContext.kt +++ b/LavalinkServer/src/main/java/lavalink/server/io/SocketContext.kt @@ -232,5 +232,9 @@ class SocketContext( override fun gatewayReady(target: InetSocketAddress?, ssrc: Int) { SocketServer.sendPlayerUpdate(this@SocketContext, player) } + + override fun gatewayError(cause: Throwable) { + log.error("Koe encountered a voice gateway exception for guild ${player.guildId}", cause) + } } } From 8ab4e48745013cf94b98be3d2fefc6c4937c00b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Mon, 20 Nov 2023 21:21:44 +0100 Subject: [PATCH 48/73] enable request logging by default since a lot of people are updating to lavalink v4 from v3 they don't have this setting in their application.yml these logs are an easy way to see if anything is wrong and should be enabled by default --- .../main/java/lavalink/server/config/RequestLoggingConfig.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LavalinkServer/src/main/java/lavalink/server/config/RequestLoggingConfig.kt b/LavalinkServer/src/main/java/lavalink/server/config/RequestLoggingConfig.kt index ac9e9b176..11a3dcd4c 100644 --- a/LavalinkServer/src/main/java/lavalink/server/config/RequestLoggingConfig.kt +++ b/LavalinkServer/src/main/java/lavalink/server/config/RequestLoggingConfig.kt @@ -8,9 +8,9 @@ import org.springframework.context.annotation.Configuration @Configuration @ConfigurationProperties(prefix = "logging.request") -@ConditionalOnProperty("logging.request.enabled") +@ConditionalOnProperty("logging.request.enabled", matchIfMissing = true) data class RequestLoggingConfig( - var includeClientInfo: Boolean = true, + var includeClientInfo: Boolean = false, var includeHeaders: Boolean = false, var includeQueryString: Boolean = true, var includePayload: Boolean = true, From c136802b71e62b5714f751ba37b2b0bd154d1e8d Mon Sep 17 00:00:00 2001 From: topi314 Date: Mon, 27 Nov 2023 11:30:20 +0100 Subject: [PATCH 49/73] fix NPE when omitting plugin repository --- .../src/main/java/lavalink/server/bootstrap/PluginManager.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt index fc3b83ee4..6f168a1b6 100644 --- a/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt +++ b/LavalinkServer/src/main/java/lavalink/server/bootstrap/PluginManager.kt @@ -53,8 +53,7 @@ class PluginManager(val config: PluginsConfig) { var repository = declaration.repository ?: if (declaration.snapshot) config.defaultPluginSnapshotRepository else config.defaultPluginRepository - repository = - if (declaration.repository!!.endsWith("/")) declaration.repository!! else declaration.repository!! + "/" + repository = if (repository.endsWith("/")) repository else "$repository/" Declaration(fragments[0], fragments[1], fragments[2], repository) } From 3b61c5f4fdf0f8b2fd3f13d4069858d5d5742ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Mon, 27 Nov 2023 12:47:43 +0100 Subject: [PATCH 50/73] Update to Koe 2.0.0-rc2 (#985) Co-authored-by: Freya Arbjerg --- settings.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index c89cb58bf..ab216aa19 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -42,8 +42,8 @@ fun VersionCatalogBuilder.voice() { library("lavaplayer-ip-rotator", "dev.arbjerg", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") library("lavadsp", "dev.arbjerg", "lavadsp").version("0.7.8") - library("koe", "moe.kyokobot.koe", "core").version("2.0.0-rc1") - library("koe-udpqueue", "moe.kyokobot.koe", "ext-udpqueue").version("2.0.0-rc1") + library("koe", "moe.kyokobot.koe", "core").version("2.0.0-rc2") + library("koe-udpqueue", "moe.kyokobot.koe", "ext-udpqueue").version("2.0.0-rc2") version("udpqueue", "0.2.7") val platforms = listOf("linux-x86-64", "linux-x86", "linux-aarch64", "linux-arm", "linux-musl-x86-64", "linux-musl-aarch64", "win-x86-64", "win-x86", "darwin") From 7978e9d224a6cbb0ab30029b1454b5964795c09e Mon Sep 17 00:00:00 2001 From: Mysty Date: Tue, 28 Nov 2023 08:33:44 +1000 Subject: [PATCH 51/73] Update Wavelink in README (#986) Wavelink section has been updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b9767a89..1d581d859 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ Version numbers can come in different combinations, depending on the release typ | [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | | [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | | [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Wavelink](https://github.com/PythonistaGuild/Wavelink/tree/feature/v3) | Python | discord.py **V2** | Pre-Release (Version 3+) | +| [Wavelink](https://github.com/PythonistaGuild/Wavelink) | Python | discord.py **V2** | | | [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | | [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | | [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | From b78a956c95da81226534877634aa92e13276d023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sat, 2 Dec 2023 11:47:59 +0100 Subject: [PATCH 52/73] use maven.lavalink.dev maven repo --- build.gradle.kts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f83591527..98e606842 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,7 +24,7 @@ allprojects { mavenCentral() // main maven repo mavenLocal() // useful for developing maven("https://m2.dv8tion.net/releases") - maven("https://maven.arbjerg.dev/releases") + maven("https://maven.lavalink.dev/releases") jcenter() maven("https://jitpack.io") // build projects directly from GitHub } @@ -51,8 +51,8 @@ subprojects { configure { if (findProperty("MAVEN_PASSWORD") != null && findProperty("MAVEN_USERNAME") != null) { repositories { - val snapshots = "https://maven.arbjerg.dev/snapshots" - val releases = "https://maven.arbjerg.dev/releases" + val snapshots = "https://maven.lavalink.dev/snapshots" + val releases = "https://maven.lavalink.dev/releases" maven(if ((version as String).endsWith("-SNAPSHOT")) releases else snapshots) { credentials { @@ -62,7 +62,7 @@ subprojects { } } } else { - logger.lifecycle("Not publishing to maven.arbjerg.dev because credentials are not set") + logger.lifecycle("Not publishing to maven.lavalink.dev because credentials are not set") } } configure { From 86348bd06b217528fd30df2251d971b2861d7b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sat, 2 Dec 2023 13:14:59 +0100 Subject: [PATCH 53/73] docs (#944) --- .github/workflows/build.yml | 6 +- .github/workflows/docs-pr.yml | 49 + .github/workflows/docs.yml | 49 + .gitignore | 2 + CHANGELOG.md | 7 + README.md | 243 +-- branding/lavalink-400.png | Bin 14450 -> 16484 bytes branding/lavalink.svg | 2 + docs/CNAME | 1 + .../api/Insomnia.json | 0 docs/api/index.md | 74 + PLUGINS.md => docs/api/plugins.md | 87 +- IMPLEMENTATION.md => docs/api/rest.md | 1438 +++++------------ docs/api/websocket.md | 454 ++++++ docs/assets/favicon.png | Bin 0 -> 2445 bytes docs/assets/images/lavalink.svg | 50 + docs/assets/logo.svg | 18 + docs/changelog/index.md | 119 ++ docs/changelog/v2.md | 36 + docs/changelog/v3.md | 315 ++++ docs/changelog/v4.md | 40 + docs/clients.md | 49 + docs/configuration/binary.md | 12 + docs/configuration/docker.md | 54 + docs/configuration/index.md | 115 ++ docs/configuration/systemd.md | 52 + docs/docker/Dockerfile | 9 + docs/docker/docker-compose.yml | 15 + docs/getting-started/faq.md | 46 + docs/getting-started/index.md | 33 + docs/getting-started/troubleshooting.md | 55 + docs/index.md | 60 + docs/mkdocs.yml | 127 ++ docs/overrides/home.html | 32 + docs/overrides/main.html | 5 + docs/plugins.md | 24 + docs/requirements.txt | 9 + docs/stylesheets/neoteroi-cards.css | 76 + docs/stylesheets/style.css | 51 + 39 files changed, 2503 insertions(+), 1311 deletions(-) create mode 100644 .github/workflows/docs-pr.yml create mode 100644 .github/workflows/docs.yml create mode 100644 docs/CNAME rename Lavalink-Insomnia.json => docs/api/Insomnia.json (100%) create mode 100644 docs/api/index.md rename PLUGINS.md => docs/api/plugins.md (68%) rename IMPLEMENTATION.md => docs/api/rest.md (54%) create mode 100644 docs/api/websocket.md create mode 100644 docs/assets/favicon.png create mode 100644 docs/assets/images/lavalink.svg create mode 100644 docs/assets/logo.svg create mode 100644 docs/changelog/index.md create mode 100644 docs/changelog/v2.md create mode 100644 docs/changelog/v3.md create mode 100644 docs/changelog/v4.md create mode 100644 docs/clients.md create mode 100644 docs/configuration/binary.md create mode 100644 docs/configuration/docker.md create mode 100644 docs/configuration/index.md create mode 100644 docs/configuration/systemd.md create mode 100644 docs/docker/Dockerfile create mode 100644 docs/docker/docker-compose.yml create mode 100644 docs/getting-started/faq.md create mode 100644 docs/getting-started/index.md create mode 100644 docs/getting-started/troubleshooting.md create mode 100644 docs/index.md create mode 100644 docs/mkdocs.yml create mode 100644 docs/overrides/home.html create mode 100644 docs/overrides/main.html create mode 100644 docs/plugins.md create mode 100644 docs/requirements.txt create mode 100644 docs/stylesheets/neoteroi-cards.css create mode 100644 docs/stylesheets/style.css diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 347e05b67..1db033e67 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,11 @@ name: Build on: push: branches: [ '**' ] - paths-ignore: [ '**.md' ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.github/workflows/docs.yml' + - '.github/workflows/docs-pr.yml' workflow_call: secrets: DOCKER_USERNAME: diff --git a/.github/workflows/docs-pr.yml b/.github/workflows/docs-pr.yml new file mode 100644 index 000000000..0703f9e4a --- /dev/null +++ b/.github/workflows/docs-pr.yml @@ -0,0 +1,49 @@ +name: Docs PR + +on: + pull_request_target: + branches: [ '**' ] + paths: + - 'docs/**' + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + contents: read + deployments: write + steps: + - uses: actions/checkout@v3 + with: + ref: "${{ github.event.pull_request.merge_commit_sha }}" + fetch-depth: 0 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV + - uses: actions/cache@v3 + with: + key: mkdocs-material-${{ env.cache_id }} + path: .cache + restore-keys: | + mkdocs-material- + - run: pip install -r requirements.txt + working-directory: docs +# - run: mkdocs build --verbose --strict + - run: mkdocs build --verbose + working-directory: docs + - uses: actions/upload-pages-artifact@v1 + with: + path: 'site' + - uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: ${{ vars.CLOUDFLARE_PROJECT_NAME }} + directory: site + branch: pr-${{ github.event.pull_request.number }} + gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..8cbbbf354 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,49 @@ +name: Docs Push + +on: + push: + branches: [ '**' ] + paths: + - 'docs/**' + - '.github/workflows/docs.yml' + +concurrency: + group: pages-${{ github.ref }} + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + contents: read + deployments: write + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV + - uses: actions/cache@v3 + with: + key: mkdocs-material-${{ env.cache_id }} + path: .cache + restore-keys: | + mkdocs-material- + - run: pip install -r requirements.txt + working-directory: docs +# - run: mkdocs build --verbose --strict + - run: mkdocs build --verbose + working-directory: docs + - uses: actions/upload-pages-artifact@v1 + with: + path: 'site' + - uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: ${{ vars.CLOUDFLARE_PROJECT_NAME }} + directory: site + gitHubToken: ${{ secrets.GITHUB_TOKEN }} + wranglerVersion: '3' diff --git a/.gitignore b/.gitignore index a26490138..d9ac554cd 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ build/* gradle.properties application.yml LavalinkServer/plugins +.cache/ +site/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 103055a5a..78fa3df62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,13 @@ The most noteworthy of these, as well as any features and breaking changes, are Contributors: [@topi314](https://github.com/topi314), [@freyacodes](https://github.com/freyacodes), [@DRSchlaubi](https://github.com/DRSchlaubi) and [@melike2d](https://github.com/melike2d) +## 3.7.8 +* Fix YouTube 403 errors +* Fix YouTube access token errors + +## 3.7.7 +* Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) + ## 3.7.6 * Update Lavaplayer to [`1.4.1`](https://github.com/Walkyst/lavaplayer-fork/releases/tag/1.4.1) & [`1.4.2`](https://github.com/Walkyst/lavaplayer-fork/releases/tag/1.4.2) * New support for `MUSL` based systems (most notably `alpine`) diff --git a/README.md b/README.md index 4b9767a89..1288be1cd 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,12 @@ A [basic example bot](Testbot) is available. > [!Warning] > Lavalink v4 is now in beta! See [the changelog](CHANGELOG.md) for more information. +## Getting started +* Pick one of the [up-to-date clients](https://lavalink.dev/clients). Advanced users can create their own using the [API documentation +](https://lavalink.dev/api/) +* See the [server configuration documentation](https://lavalink.dev/configuration/) for configuring your Lavalink server +* Explore [available plugins](https://lavalink.dev/plugins) for extra features +* See also our [FAQ](https://lavalink.dev/getting-started/faq)
Table of Contents @@ -22,12 +28,6 @@ A [basic example bot](Testbot) is available. - [Hardware Support](#hardware-support) - [Changelog](#changelog) - [Versioning policy](#versioning-policy) -- [Client libraries](#client-libraries) -- [Server configuration](#server-configuration) - - [Config](#config) - - [Binary](#binary) - - [Systemd Serivce](#systemd-service) - - [Docker](#docker)
@@ -95,236 +95,5 @@ Version numbers can come in different combinations, depending on the release typ `MAJOR.MINOR.PATCH-PRERELEASE` - Pre-release `MAJOR.MINOR.PATCH-PRERELEASE+BUILD` - Pre-release additional build metadata ---- -## Client libraries: -| Client | Platform | Compatible With | Additional Information | -|---------------------------------------------------------------------------|-----------------|--------------------------------------------|---------------------------------| -| [Lavalink-Client](https://github.com/lavalink-devs/Lavalink-Client) | Java/Kotlin/JVM | JDA/Discord4J/**Any** | Uses reactor | -| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Wavelink](https://github.com/PythonistaGuild/Wavelink/tree/feature/v3) | Python | discord.py **V2** | Pre-Release (Version 3+) | -| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | -| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | -| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | -| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | -| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | -| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | -| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | -| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | -| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust, Python | **Any** | `tokio`-based, `asyncio`-based | -
-v3.7 supporting Client Libraries - -| Client | Platform | Compatible With | Additional Information | -|---------------------------------------------------------------|----------|--------------------------------------------|---------------------------------| -| [Lavalink.kt](https://github.com/DRSchlaubi/lavalink.kt) | Kotlin | JDA/Kord/**Any** | Kotlin Coroutines | -| [lavaplay.py](https://github.com/HazemMeqdad/lavaplay.py) | Python | **Any\*** | *`asyncio`-based libraries only | -| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | -| [Wavelink](https://github.com/PythonistaGuild/Wavelink) | Python | discord.py **V2** | Version >=2, <3 | -| [Pomice](https://github.com/cloudwithax/pomice) | Python | discord.py **V2** | | -| [Lavacord](https://github.com/lavacord/lavacord) | Node.js | **Any** | | -| [Poru](https://github.com/parasop/poru) | Node.js | **Any** | | -| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | -| [Cosmicord.js](https://github.com/SudhanPlayz/Cosmicord.js) | Node.js | **Any** | | -| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | Only prior v10.4.1 | -| [Nomia](https://github.com/DHCPCD9/Nomia) | .NET | DSharpPlus | | -| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus | < v4 | -| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | - -
- -Or alternatively, you can create your own client library, following the [implementation documentation](IMPLEMENTATION.md). -Any client libraries marked with `Unmaintained` have been marked as such as their repositories have not received any commits for at least 1 year since time of checking, -however they are listed as they may still support Lavalink, and/or have not needed maintenance, however keep in mind that compatibility and full feature support is not guaranteed. - -## Server configuration - -### Config - -The server configuration is done in `application.yml`. You can find an example configuration [here](LavalinkServer/application.yml.example). - -Alternatively, you can also use environment variables to configure the server. The environment variables are named the same as the keys in the `application.yml` file, but in uppercase and with `.` replaced with `_`. For example, `server.port` becomes `SERVER_PORT`. -For arrays, the index is appended to the key, starting at 0. For example, `LAVALINK_PLUGINS_0_DEPENDENCY` refers to the `dependency` key of the first plugin. - -
-List of all env keys - -```env -SERVER_PORT -SERVER_ADDRESS - -LAVALINK_PLUGINS_0_DEPENDENCY -LAVALINK_PLUGINS_0_REPOSITORY - -LAVALINK_PLUGINS_1_DEPENDENCY -LAVALINK_PLUGINS_1_REPOSITORY - -LAVALINK_PLUGINS_DIR - -LAVALINK_SERVER_PASSWORD -LAVALINK_SERVER_SOURCES_YOUTUBE -LAVALINK_SERVER_SOURCES_BANDCAMP -LAVALINK_SERVER_SOURCES_SOUNDCLOUD -LAVALINK_SERVER_SOURCES_TWITCH -LAVALINK_SERVER_SOURCES_VIMEO -LAVALINK_SERVER_SOURCES_HTTP -LAVALINK_SERVER_SOURCES_LOCAL - -LAVALINK_SERVER_FILTERS_VOLUME -LAVALINK_SERVER_FILTERS_EQUALIZER -LAVALINK_SERVER_FILTERS_KARAOKE -LAVALINK_SERVER_FILTERS_TIMESCALE -LAVALINK_SERVER_FILTERS_TREMOLO -LAVALINK_SERVER_FILTERS_VIBRATO -LAVALINK_SERVER_FILTERS_DISTORTION -LAVALINK_SERVER_FILTERS_ROTATION -LAVALINK_SERVER_FILTERS_CHANNEL_MIX -LAVALINK_SERVER_FILTERS_LOW_PASS - -LAVALINK_SERVER_BUFFER_DURATION_MS -LAVALINK_SERVER_FRAME_BUFFER_DURATION_MS -LAVALINK_SERVER_OPUS_ENCODING_QUALITY -LAVALINK_SERVER_RESAMPLING_QUALITY -LAVALINK_SERVER_TRACK_STUCK_THRESHOLD_MS -LAVALINK_SERVER_USE_SEEK_GHOSTING - -LAVALINK_SERVER_PLAYER_UPDATE_INTERVAL -LAVALINK_SERVER_YOUTUBE_SEARCH_ENABLED -LAVALINK_SERVER_SOUNDCLOUD_SEARCH_ENABLED - -LAVALINK_SERVER_GC_WARNINGS - -LAVALINK_SERVER_RATELIMIT_IP_BLOCKS -LAVALINK_SERVER_RATELIMIT_EXCLUDE_IPS -LAVALINK_SERVER_RATELIMIT_STRATEGY -LAVALINK_SERVER_RATELIMIT_SEARCH_TRIGGERS_FAIK -LAVALINK_SERVER_RATELIMIT_RETRY_LIMIT - -LAVALINK_SERVER_YOUTUBE_CONFIG_EMAIL -LAVALINK_SERVER_YOUTUBE_CONFIG_PASSWORD - -LAVALINK_SERVER_HTTP_CONFIG_PROXY_HOST -LAVALINK_SERVER_HTTP_CONFIG_PROXY_PORT -LAVALINK_SERVER_HTTP_CONFIG_PROXY_USER -LAVALINK_SERVER_HTTP_CONFIG_PROXY_PASSWORD - -METRICS_PROMETHEUS_ENABLED -METRICS_PROMETHEUS_ENDPOINT - -SENTRY_DSN -SENTRY_ENVIRONMENT -SENTRY_TAGS_SOME_KEY -SENTRY_TAGS_ANOTHER_KEY - -LOGGING_FILE_PATH -LOGGING_LEVEL_ROOT -LOGGING_LEVEL_LAVALINK - -LOGGING_REQUEST_ENABLED -LOGGING_REQUEST_INCLUDE_CLIENT_INFO -LOGGING_REQUEST_INCLUDE_HEADERS -LOGGING_REQUEST_INCLUDE_QUERY_STRING -LOGGING_REQUEST_INCLUDE_PAYLOAD -LOGGING_REQUEST_MAX_PAYLOAD_LENGTH - -LOGGING_LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE -LOGGING_LOGBACK_ROLLINGPOLICY_MAX_HISTORY -``` -
- - -### Binary -Download binaries from the [Download Server](https://repo.arbjerg.dev/artifacts/lavalink/), [GitHub releases](https://github.com/lavalink-devs/Lavalink/releases) (specific versions prior to `v3.5` can be found in the [CI Server](https://ci.fredboat.com/viewLog.html?buildId=lastSuccessful&buildTypeId=Lavalink_Build&tab=artifacts&guest=1)) or [GitHub actions](https://github.com/lavalink-devs/Lavalink/actions). - -Put an `application.yml` file in your working directory. ([Example here](LavalinkServer/application.yml.example)) - -Run with `java -jar Lavalink.jar` from the same directory - -### Systemd Service - -If you're using a Systemd-based Linux distribution you may want to install Lavalink as a background service. You will need to create a `lavalink.service` file inside `/usr/lib/systemd/system`. Create the file with the following template (replacing the values inside the `<>` brackets): - ```ini -[Unit] -# Describe the service -Description=Lavalink Service - -# Configure service order -After=syslog.target network.target - -[Service] -# The user which will run Lavalink -User= - -# The group which will run Lavalink -Group= - -# Where the program should start -WorkingDirectory= - -# The command to start Lavalink -ExecStart=java -Xmx4G -jar /Lavalink.jar - -# Restart the service if it crashes -Restart=on-failure - -# Delay each restart by 5s -RestartSec=5s - -[Install] -# Start this service as part of normal system start-up -WantedBy=multi-user.target -``` - -To initiate the service, run - -```shell -sudo systemctl daemon-reload -sudo systemctl enable lavalink -sudo systemctl start lavalink -``` - -In addition to the usual log files, you can also view the log with `sudo journalctl -u lavalink`. - -### Docker - -Docker images can be found under [packages](https://github.com/lavalink-devs/Lavalink/pkgs/container/lavalink) with old builds prior to `v3.7.4` being available on [Docker Hub](https://hub.docker.com/r/fredboat/lavalink/). -There are 2 image variants `Ubuntu` and `Alpine`, the `Alpine` variant is smaller and can be used with the `-alpine` suffix, for example `ghcr.io/lavalink-devs/lavalink:3-alpine`. - -Install [Docker](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) - -Create a `docker-compose.yml` with the following content: -```yaml -version: "3.8" - -services: - lavalink: - image: ghcr.io/lavalink-devs/lavalink:4 # pin the image version to Lavalink v4 - container_name: lavalink - restart: unless-stopped - environment: - - _JAVA_OPTIONS=-Xmx6G # set Java options here - - SERVER_PORT=2333 # set lavalink server port - - LAVALINK_SERVER_PASSWORD=youshallnotpass # set password for lavalink - volumes: - - ./application.yml:/opt/Lavalink/application.yml # mount application.yml from the same directory or use environment variables - - ./plugins/:/opt/Lavalink/plugins/ # persist plugins between restarts, make sure to set the correct permissions (user: 322, group: 322) - networks: - - lavalink - expose: - - 2333 # lavalink exposes port 2333 to connect to for other containers (this is for documentation purposes only) - ports: - - 2333:2333 # you only need this if you want to make your lavalink accessible from outside of containers -networks: - lavalink: # create a lavalink network you can add other containers to, to give them access to Lavalink - name: lavalink -``` - -Run `docker compose up -d`. See [Docker Compose Up](https://docs.docker.com/engine/reference/commandline/compose_up/) - -If your bot also runs in a docker container you can make that container join the lavalink network and use `lavalink` (service name) as the hostname to connect. -See [Docker Networking](https://docs.docker.com/network/) & [Docker Compose Networking](https://docs.docker.com/compose/networking/) diff --git a/branding/lavalink-400.png b/branding/lavalink-400.png index 5e9e7ca24ff88a29a67406103714b501db0423b4..57cdf8ecbe1e1b19507f8bd49e77f00d8865187f 100644 GIT binary patch literal 16484 zcmai52{@E(_kYHy8HuqJvdoN#6e4BG7!z-#P1;Dds1(VP7$Sqo&|;LbWJ~n6*egN` zGeRj#3MrYfOBnmk|9(bq^?h%B|E{a6E1u=P&pG$+{Lb&3Cv5K?V}WIo%OD66Fxmds zJ_tfYz<<$8!A~f~ns2~Ad~VwhpM@Y@LHIA?O_DO8DnR(NrDN-1;m4`|?Ti3Hu z(nMmPNq&CGwy=l@J7H1eRQrL`_9fakSGb=}->cMiLnbWlfydo-6rrHfu%NABQwYX` z8&^|Ty^Yt|A_x_rB8yMbJ?PWPLS3AmYW#I*D0CI)Pr`=6g5^DTa;R6Rfbsn4a_ zua#i=%zHv)-wsdJGh+Nz-3j9lmxQ_OvwwD@X`QUC5=DG#n=(3nN#I%a6-S`c@5-GP zyf3bCbh^04{6$bU{pnPGQEGO_8!FTI)ZEDOk=RW&Lb#g21Co;WsyEhL^15zXGAP$I zsQSL*VM2!ndjg@oFrfM9t+US83HI>ojHu@$%ZG&1phP6+3X~WvQiGgaC4XTpo^HZw zB3*LOp1)3WpJ=%!edbk24=;(RSbgO1m)WJVopE@M5$PLg)$-lTu5g+-oN&yLECG#a zCDZBe6b@9qWvd_c>y;Eq;~DM|YJ0{rS#3AMT40Uey(gowUE%tY%CCxAt@yk7Cg`aX z&@;T*l`p4qO3-ux%;2ODjuFh^T%DL)>tc{gI6`jnG(_YCp#6-+UYcw5A8ziBsk4$( zq7=DR#fooOzUMi=$bxi<>R3qshTT=sXQ{^V7+spK+piK&452~<*yCXLc zmbVCrcq7{yN)u=UjQ9ma5{`66?B(!Ou+-(`Nq@AvzZ>(^lt(xxbVQaQIb)GaHICpK zpqJ^;E}7!1y;gSNWVYMO{-(!{Z_f~0V)WqKzfQ${K`H4kvvWT1`@3a=X|lQsczyN! zE{@A&jC8Z&#)KFp(jnKDBB_hB%9O^8Pomh6{f?5=y2LUX=e`pkT^q+pNna^6k+rf7 z88<)EHt|i=N&f^g;>gQ_G<)_5v>#Mr*K&)a7Qdz5?aPoX@zf?O6=O435g>H>9@|L`g`=he2;iE9D8vhG&z4|$+k5|7)-aXySVmAedo5>FWr(M zS804o^kL^L%dA09P>Hx{a=Oj@TjXiQzflo2m+Q?YeymmTW=I;_;e!Zv zD{)8MUX^YE`tanZr5jjUoQ#*ZBJa7bzm%&Nk>8vxM_7KZdQ-f&U#RIi z0dwY0w+`?V8vIks>exbBF7sV&vT-{j*DCC6vme{fKd5pk*Plvrot@rX_>Q~R2b-(} ze(trvkpn@p*$!$Ywpnvb>*5n3N?Z4it}2P88? z=m&R_d8gob{A@_RVb7mh)c;=BYfdrFq2*++oU-g8{pTEGi1_Y4`-z{9F}Z9?2z%B4 zr+F?g4I7sYeJmY#iOI`xOw|D)5NE!jX>`f*ScT=UsMDyP@B{Q~8p_Lm=`x zQl9XA*vL*kf5pRFFmdMNdAA9sqKgLK)e}&`;nOxc0qmM3oT~q^$5>9S-i`vE$tdmi z_qy5LwU=CsWX%Euj(N(za-kZZ5a^b{wMFh=e&FPQ(81&G?!F(zhiPF}ny{j28!h5w%JNPKt|^JU#J|Xs;L$+ zu!jR$A+E*atshTlE8S@%9n#O`d>PC7dMkSMpZu;s@WjZOU#u`P+A&nK)Vn2s=8~5g z%2PS)XxeJIym8#1?R5J_DvkX`~lF41R)8x-nNu>=O?I3U@I(ZYh1hf(Ci}j zV2xDKSSj~T&Q#=6i_aOtqrwf-*SP*#!;FPHlw?)ZD_2le}mQJ=5@y zuiH#TK}E;%m5FEeJEiz}!HK*qpbc2doA`+tN#)FZ!ayc|BN~k1v(5Qbcx;kH7lxB)ia~EcyK3K`w8D4eW~S0zA`qr zp?Dv3c&?*M3i_6QO9)%2nf%ASyrZC?ump0Sv-efob(HN&XCD4PH;4qGAiK38gV=j3 zNYsepj`-C2(0?Ue?(yCijDog@X{D_#-=1S#H!mMeUR*T zp9u^G_bXO376MxT@_~xu$|}bsuT^OJ_5We-ElV*ZdyPw?S<3kAx4LEwxp%)=W*?pa zLC*V5uV3mw5yFa=!#t?)P}wi61{m1v_07VRvmA)G4EnT;@3b62^iDDUI`A z*i*FvTQV(E*<~4dz=!MQ|NgxMma-y_|7j?=(Q^F1(&}+R40KmfLybS znO=Mwo%=+!bH52GTQ`!JewhBv8`{OTVu#~*eGt0O%^e21g zzAzl5+lOF#P9T~9V=1bDDdXY}s1-)l9yj=Y_c~#$Z?*Po;4Q$bf0h+oU!mz=o8CRm zM#Gf%U+>DMtDxyyh*T7tEj2gL#FQG9Erq-ACe>j$e4uh%g zr8nqM5q@T-b4m@7JY>6((6OK=oU=r{~0GaR8qGVEk$W63@< z1u9MHH6K=1haq8XiH) z5_SoLcTbj|=hiITfHfv-mp}CTV2q%0)VBR@KWW2WN%o^+QhPA}HiO%hgFa79w~}L4 z|NeKy^f@2A|CvAGP&fxXVCvQ8F74_THTPAW4Zoq$znJIf=B|%nUmpJv?a`PDi<_9N z9ER%G!@sE?z6S%%A^mm5hnVAvzBPZ$<#GgRhl9iy<(Kjes?+~ONML^+>g@Yqk<2H# z`<;sj@fD~k|8?vZ_c*O*eo_G(dUd|UW1;_9IsW2>$BFBG8~?Wr-kz@>Qc15h@!b`q zxT?*Nyy?F&Ko}dIv#xbd&EX`Jh^7hMgd=bGn}of%_D_8}6=n*tf6TXwvGGjLQRlV% z|6_L7;_fRcyEZ!iZ&&w@TAdQs`+pvlWK*;9Xyj-Nujximbp9*LaeZ^4P|y6>|6{89 z!2-S-q&;Y-+T^6Ij%xf?!qnP^3*A@y8;7?=+qv~UJrZNLdZ;PIVkX+vSpe$= zA6>^8-0ARy9%_XjOTFD7@m&Hfe|9XKzgu{?M{oaw<2mi(M`EnE$VR_ut)CR2;Eu#L z50oOa2mVqd02rE#p=XqJW}PjHHLgSrC_Q%?bXf1cEd+WXk6I6$AuFBK0j=C zU?I?<8G89hM6Ch=B7GyfNY(F@OQjM#ldd7rnEjuu$)sDD8>(VnC3G~9)=8gp3_LxwWj zKi`bt)PmITVP~LZyzZ6=fJU3S$pueH}~{_r|#}kyHMD7q>Yi zoRp^0j2rdH(9P~Z>aLAtRBlZD&5wbEj%du#YSBKUHakU5@?f@;tgh8HdLt@>Gh6Gm z(R67R;$#hyFZNg{A6M(yErlhS4v?Pk)~>(`tp$JU;OA8$>DnqhFxlmj+O zY&CHm4@ftb;y`%S3j&-w{Fbry%Vg;)2u0hqYhDkEV0B87ds`W+37#@+v$5fYJ-+8A z>O=?-;@g`(2mP@zYYK-m?TN#dka3~jZr@+uzmx!7TbMF8)|-+1%0O1SBCJ0xs0%XW zjL9TR@j8dyTwdbk8SqsKb7$?-|v2fCE_>#|mMM1Uf`j*7@e4V)RrXJcR5g0@!HHr}lK|z0?jiSFvy)XsV=A#wN8n5|4HeNck16on zz&0CqyLxa61U9sc!Mp+%X$BT)v7l`qAMk;PuvZxbY$hDAj^RlC3l`7ixhVrgcS%qy zl~bF$`2y~c3zpOKVH!m_#FAZ7mX--sH@$nkVn4coya9jLW;d(@VhH%Rs2##sQ9p%F zUtSDke}rCL?8JwKhIJR5>a<@ZaNJIU=-#VSt><}NR-vFY7+^y&eKu)9{mVifC~ZSO zYYM5hRM9i6K*G`|Lk$3AU=pvnVR5yEFObi-k?qtdO};McM|Q5po?p?XKH^*rBK0i{ z9Ew}Gq5T$vowHb&G1$uF{6*ZXif=r={xSzWq{L8IWp6+pU4o6EG(}BKR|r>~eI8hz8~Zi1>jYZ57gxDt!f)i3#_j`c{J!$Sr3RiT4q0n0I|TAZ<*eip17bcZGdgonlAX~D$OrX2^e_*6g}$+ z&}h4q1?gFCQLkrchPhUf)w&@q3{<1{DIxK!uQ1k~I89K2>%%HgNR*Dq!4Pm3@Xlz7E^zPfiCPyzG1 z4+~)t;DHM)1b#s`LJncO`)WpK{T>>5>}JNB4Pj&!-fj5ezSX7QS3K_{My=ol>rLX6 zT#O#In`>8;$~yA!c#ex!_NlY{qPyfq+dqkZUyH`6#D;C2RZGxxbkZ(%;ET`xS8SVj z$D9s-D@ta+dAF=Un;mnW;qZuFm1f9+sIDNOwvr{x-}=uv%+AvDoOSMv(K{ncf@u-Q zYIL3hHl3sfqO?2khAN5t*JOtPrZVw!;1lbrdr7e$rfCE}{p`Y9Hs7ywTa0HE`{=4x z+8Dh8m(eBF@Tlp9l!Wr81nVuyGOaet7GIshf!68P@d3t7d;!4!=CKjWYL^At=Rw`O z5oBW4?E)l{OKbIp1W#y(@Qb8i!h*m;Pi?U+>V+8 z2(`=r>3qxW`-$ewA1yrn-^Ox!TsLr1i?>b&ct~SoL)vrPESO z2l)T=w*@>wVJ5$5V-O1O2VqU|D?%$=0X{#Od!MQzyZt!6=p= zh?xhDsC#a7XZFrkm2TdMB;uB7xRx_|kv;!X7>g$~JoYa{o=S_VA&R%H z%sS=ZYeFUL^)*_?P6k`_g)k+bw@YZex)jB!6u>^WTsWB%^|D$Dx&~5J+qAXh;#D9c zj|A?cqR{kry8Z<-Ckvt;TP{R+Jel80?g1Xf0*0h|$28{Hww>gTMF8*l^5DJ4A!w@3 zuw;Klnh%3{r(YbPf-g4I;rdDy_BC*vuPyLQ%eL30lSV9w-F~d=Rn0LrBC;5Z@k$}A z7<_~*l2C0i$2x=HqzBO3_;Rjtrk@I4danMZ#U@jwr7(>$C8I68L4rBxQo}-Y1WY8q z@c(c|_XE+BdV0){To}BW}WYeDD)M=AP0K{c(Fq0E5#N7%Y@{-fL6? zzDN|?2}p4Q=&sE0VQyo*@p+NQ&0c@F-#Mbnqx#~>#gBJ|Q|54ZP@eWn-bq~_AL+UK z1}BDKdUNoktZgk!ikx-Q=vkC^BQ*f3capE9;0dRju}s79jsb^d;B^(|fTv(of;eiR zZKU(<({Vof>&X`-NT_W5%Dn6o>e%GCnA2gan{|WzJzH5FubdJ&_q$V`OqC$_O)i4v zf#-#`mCy5$bt0s8%NHDRiY?g(5X;pafzP8-WAWS;7|1u(fM3Oco>tcKWd-Il`n8rS zj^`#22egDluw$U$1U7)9k8Z<2>OGq|nGvO-`{LM?yxTWUxicdrk^Zg=?0=XLAtcI3 z`Fhh-)-hoI=J;5P7eKW%SG!liGl3s&j)`{xjsbdKUHq8aa7|z5NG2@{mC=K?S8+-% z+iFfn?o=*>eF@jbTHxHtex`En`yM}3DQ-iUj&vprt>ut=U-`BJzK74EXF-*7d09H5 z@a3QM$e}Slna*QyLXPZyFg&%=W851@8!-IDq41U+obvO#*u4kR*FGW7ZD#bNz~hf< za_$dRWiPfjuCDL+)~FvonHWF}pOh5U&2l9?Jz$_Zuq1@JFNE6yn=gT5wqlouwZ_nf zGyB3h=vYUvn{sjRCj3oTyI8Z7a+~R8tUJ+p>d!YB%uK6tyEHAqv?E$T8FACY$RE4j zcdNEo8z^7yK5x?^&e|@J{fg!T$60}Ih%b0{NTC-Or$De5d*gEU+&7SI9@_YbdjLlI z1dV}wT=0I=N-SecFb6$q)_j41d{-z6qR+R}w(=vgBXnwZ#C=m*PI`m>c&qO8!glhm zakJ)m2J-&mgXY%4TNFGjxc9WBgLv^W?S(t#XLl+HYU5$)b}j^UTLnHBS&1t=k{a|6 zY)V&;{a9gMa&p0Vjm~@^;6+r_ZJ3%J%$i^EsA*^mZ7bGH@5OT+a4V+v>=NzuT1ZhCB^0D5j5g$-FHz64|gaJu^4dL~c8ux*_{6bja zkxiL(fdG!^#^z{j?O0L1Imh{p@l1MIPptY#`IqH!q$M_f)g7thIF z!e%Gj^9SipSjV(oQfA$;9J!Q*>v>dy^w5X*wU%N$_KrqUgAbZgT0N%bW-bc}$S?=5h0_w$CY#D1vac zKX(yjrw4?<$`=tEzA~pP7Cw<%cz{l=Hs*o`)-(%zc$6m6IT19={a7>2{mDJ3Sa#P<+qamnt8vz!v>HeUd-JuzH8i!KsdpQ zIV{s3?z8x7BIbL?u{tMWCVPIU$@JmWEpP1Cge$}sjI)Xq9AP_n23X4(Ye^0SD1|H` zsCyOY`HrZ7$NC?*PRgKXye_-~t;T#qHYi^-B$GWK(~O~1vO4OjK^%I&hYo+h9`Z0`5vi(J>O;3Wrum%E`3Hk z(#npKW99g0l;vFki1ul`5?+KaaS23^*+Pp|F20Wd*=NaUIL*rHiF{zH zZ?*0PLpl4d!*zcnFeQGsSFp`$fPTI1m|XPSbOqZV=2=*RTXSzoLxRfNh&pXC%-5{_ zeL91a0=rc?P!U{!aK&KRBjw|Z#uqaG#-rK!c)o5d;_}YB;-r0GMa9Xl_^=dMDdA33 ztULCp$tFGE#zerC6e5Uq^P%>%V{K)8EVi+c{=J5?@cc##=vaIL!p7pfNoBatc-KJ6 zZcxfMcH~mNbVgi81+vwiCys=GR=5xM?V zXOKK6S-?Q<1qwfR;Km>kqT3_{d=LTp1E)RB)BgBMZC{waC+6IB-X)BM_6lJGK~9$? zlfLsaP%IBDY*z}GUUKMljq6i@oN|9-FeQbd;h`Z&ws60O?stxs>_TRxtCToC3DD9a)DZC@7FWDs8%oadCpIwGT8TpWC_h}n;h zS!=|K5vcp40o!o_JhC>oB?MI)sVfBFmM=6dt9{ydhnWuP8mHFb0tb5UJ^fU38*rr z5Jv9~IO|^i>CJ9rQZr-#@H=%05dCyFF3>o&Ho)TX=ZTzQ^W05ajq3MeBKCz118xax zCxRexz=xz-5vYbhn9|A58fE+)>ZG4Rza}AFl09 zM6n;U0tkmdIrEsE`6Bb`M|I0fS6%IHKIT3)4@;n^lhE|-Nq?~ei2#62TU$b>1uEun zd@org-FMN ziZS1_B@l(jdvys!T-A*jmkfVaQ@;#IaWLyY_z6JIZ9I7WnbH*fKAeh{G~)W9D~(`u zz?XOkPN5GPfYJ5bK%U%Vs_c)&!m`rl}HpHy%1b73OdyMRN8|+EI{MA3Uh7p z!U4%MlV7|gVnajD`YvgZIDh8*phwJR0<;TMgGcu{UoYQ0y|+>$1QnrAN}tj1`slW2 z!;iN59vqg!(ZiIfJ=kp0F6qCvL#G5@+ug+q-2(tGfFml+{pwP#E~>uEY4^K)Biu3{ zEQf>{B*K`cn)Ml=x=ry?csv8Bq%y{_*%1!@T__AbfWoSslhPOEN(}{L@!mxj1Q^VG zBYw~_z4$QVqI9>0Eg7m@kh0jBCraj{+f2lJ&xRP4y?K0R4ME}UR&FhKumBgyooM%-&~F;+ogt%XnF`uxPyVJRe=?$3-SMEUZuV&$1A9 zvntAB9`UAtBJh^2j2%oRT37-lV!DM3{|`#!?2wT4SZ$SHEF88QMD#zwu@mSw+ zg9WQdLfGd6Kg_7aM7m**GYlH!z=7+jnMQF1fM4vqssu^tUn?s12z!cwd<2T*88oK8 zqVwhv?kezvE6#7wTs4#bFx`_~cX^DSbgM=m#jc}qQxi9QffF`UvLnW}17+h?i}4yh zA?)9pkAMDNoy&$TDyKJtp$jN9Ar^2ofQib@Z+`P0|9Y>1h+Kc zXSCLW+VRj6s`01Xq7nnm%sK@5Sn)jK_9R2AOK(Z}llHK7i5Fw$M!@UB#8V|mA+z_x_?xTF@;o4|f%>90_f#oz!-bDMnBcmh z2;*W``Eq?QYM~0!H!Mqlo0nr*EhxE2a+@}%W9VulP^6<(3D8-&Kx@3%<7P{t{0L$L;I85Y#cB#S8QlO5qDY-uV)!wlOTFOA8QwYdBnB*~XYsBh4S% zhr43c#!+W5AM}CtMfcNegC9*$1Z75F;vuP7U+ z+y)Kq%p)LQ!o8T(3VHH%S(pJ=jbV%g)h)UAPQVZ_^rL53`((q581QC-{hX8q&-Q2C zU%_ym4+tDsF-Y#)r*y3J8ODg{KDm`4ha^LtxY+o55vhZUFyVumn}v-4yxyvtY=z87KpbK)uSg zuzWe_RkZEM3;n#8Sn=ZvH1Q}MHluD2+u!qgTjzLjS!)0pY%KkR%aHomd5O^iik!5Y*la zAiX5dXje#q#K6yCO_^UwXG|>z!J?Mi`@Jn#>mT1PfQil&Ad@%)!PiU)7o^E;58!~S zxF-b~Mim9?Wr1T(py2eJ^>~$$mCbs;en z5F}R&j(`~Q2t?hM;fkA6rO4~vc<^I5@P72^TKw3hAmH|J1I{BDrS=8YCL;|R2|djq z2MiJ=VqYeYfjBZOHmYDFPFZuCYo0C|WQaAQFX3}>guAkOFC;gyz`cdq+_!AdtxZD< z87T}+y0eDvJp_Vfa=#!rCg2#rCBr8{0=(aK;TC&XK)+}{Q;Kwh7b&4GN2cIx)rXh) zH2E#vLLxUkX$eNzap6K;mrM$Re|L%5waNn49(R*TJpAr(Z_-5^3n3Vl%1^iNx2|?ozex%v%X_9#SLx#mW%v*b#Ed(RXtn{R}U>C z$_#joJIOs;KtKccgaZk4x1&F}XEb%@(QZJu@dn8O7y?*D&0sKzo6R-qRE|NYe|58pnGy8K`T zJjTo&u{qQ^;*$R`{O91nk*uhl&VVKXu?VzVlbsh^%DGdG!v;T5VzNwu znw`z|0|@tH6mQ)5BMe;Zu?HvlFq-i-zYIm_CRl2UfimKExAlJTSnMJlctS-)iK>y}ly^S7bGttSX_~>hsR!CL%z6`ni>n8`*e@E#pw!}@=T?BJizqtNz zRcAbf(+~WE#w1~+fCD~$pQHEk0$G!$B!W#Gx;p{)XHVyIzraXxg9TTRG*QkUyF~>T zlNQ%5+KiOr{|q92WFq%g6wvl;ER(-!aOV3&hKiJGwW1>VN!?kMN$9PUPQK&x!77FC z%~b9<6o!5DuVTr}-Q@gp4}ReEhK7x|K_Rf~);;b}R2A4BrOP_dATt z04<2(*fFPm9h(`Up;%k0twlw!W<(`T(8?1K|J9zm!LiPk?#|@P^DRQl= z{FMZ_e*!lUL62;+G?+>J=j#W5?ySg;!U*nx=>eZ%oJs7v^&U)>m83frC=npg9RQt@ zU+%Vw8w9-`&I&qVMgi{0{($$~`^33%IKJ zw~y0MAwwjD(xKVlo#J>xJkcF|vINHOzN1)Fu2ppy;Hf1$5UhgRU|M!hQoc{fBmm4G zu2k)AZjzVa%xIgDSY>6uUIG*YAv|FdAm$~O;o~Mtv5?yxA?7<7H1M0K7Wk411O-rT zOGnbd32%5*qo_oNA{50sCI#h@WON$5?bG?%N%5>YqZ%-tv?;BVmDp>pQX__i@OzX= zZ67a%IbQEw;c+Zb7&vmyDPNP#Zn(=skFY|qjylELq#xI72Ar1lkw-*7ebqFhXL;WN{&3abHSsLOcK7s%5_Qmf zHT_Hg^JPD<__#_OaRkg|s1pt?Pu12ub=|9-0t_Me3+|>LuXoG@bcxNf2yEZrBO&sk z1!(P8|I3z|{#}9?yCsU|0T!%*XQq6CDS0MamhMSh3r@kW$49mMgd4%+qzW$N^W#HM z$=u}tFW`83y0~Q0 z2k$))U_?@$R_u-azC7S>H#qf0cruyJJ&TbVd1C5yIg-QWqYXJ9-u>jDe7P2K5{LAlFK&#@ND0iB8^!^ zbD0|v=1W0S&rfK+j&-K?Z8^aQQZhV6!v17Hy_;s4%wgfwFYEnS2Yt@504@I7eVAbIba&xZPheuIW1>s;C$bIMW6P?>e-Ip&69h{NR*1d2& zM8WMkH_JW-*v4SX!Xl^$z~Us+Jscra_H1X18s%sK5|LVlD>r>t%e!me4Pzm!;P(V@ zV@qlkCj!0jtj|ov8;zxuRe<6~kh0uMW?F+!I!=M`4bD(7Y+ByWImQyc-UktOU9G>I zn{I5tp=e*anXypsrL>;JQP)`!k%W#*P3DW2AB0DF5&^=CqA;00K==?NSX3RtnY~)o zxE&nb)LD82PO4ee5rw9dZl<{+%k<_=qIRuTFo8#D30(aCKD7-yLp`d6b~D4<;y}t% zm&-lv7XIBI8dsL+MM#i$|LK-LDG%GI0UPzK>4@pF6 z1-wyTzfu$tv{ONf?FX4Y;-$_{#ceSO8bwlk z{_bC88b7bb6L$eU%#P_oCUd{y{625)h{6<`GB`qQrf$PKac*y_rRu!#?G}^e?~L&; z#VfM@;0rM7Xj?kmS=<@ZQg&ZJXuA^1F@1gu#g#joS_4y*XCpE0%vD^%y!~NRH}*Ho_m^;a|#tk4a!^0s{972;86P^%y&FA@JtzLF(tnZ81mp zzPCZvWvwpblv^*XDk(lxkh$q!lm^%<0od#1y&T^uTHI%!wG)S+M_6WnTR#o&&Yzm0 zA@Xmsq8n#9z_~@^<>0dYW^mdk#APygc%gdK%))o_Lx~35*d74)7HQ)5}Rs&&32n%cmKDBbO_~^j|TFS0I!PFJbS~lL1 z5ySf-8y*Vi9J%{&XV0fM=XV{o3g(n3J0CvaQNHH&we@KOhK*r#klzDF|$I^l-8^YUurfTh$W zePN+2c=+wVnHJ#3oEiD0m_UCErmKDD_<5PfPI`Y|0QXtXV3ylFT^QV<)QSpAxe3Vg z&iNq1J1?PV?n?Xo_=MSRy)Kl{W~6Mx7mvA5 z%hYFG_=Zm07`y~au{(ZAEMZKrL04qkA>e`lhw24N4G!N)?i+{}Fq>V*`vn!&G9Ab5 z7Jrh%I!l0$~^=D#quE$`B}o- q3FyES3udqdmbfwNB1d6p0kJR0;-mG02OlBu$7I`{zcLN%g8mO-Z3Zg< literal 14450 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 mcBcT8l^9rMySzd`wmcv?b?>$p **Note:** > If your plugin is developed in Kotlin make sure you are using **Kotlin v1.8.22** -Follow [these steps](https://github.com/lavalink-devs/lavalink-plugin-template#how-to-use-this-template) to setup a new Lavalink plugin +Follow [these steps](https://github.com/lavalink-devs/lavalink-plugin-template#how-to-use-this-template) to set up a new Lavalink plugin Now you can start writing your plugin. You can test your plugin against Lavalink by running Gradle with the `:runLavalink` Gradle task. The [Gradle plugin documentation](https://github.com/lavalink-devs/lavalink-gradle-plugin#running-the-plugin) might be helpful. @@ -115,3 +68,33 @@ class TestAudioPluginInfoModifier implements AudioPluginInfoModifier { // ... } ``` + +# Distributing your plugin + +The official plugin repository is hosted on https://maven.lavalink.dev. If you want to publish your plugin there, please reach out to us via [Discord](https://discord.gg/ZW4s47Ppw4) for credentials. +The Lavalink team has release (https://maven.lavalink.dev/releases) and snapshot (https://maven.lavalink.dev/snapshots) repositories which you can use to publish your plugin. +By default, Lavalink will look for the plugin in the Lavalink repository, but you can also specify a custom repository for each plugin in your `application.yml` file. + +```yaml + +lavalink: + plugins: + - dependency: "com.github.example:example-plugin:x.y.z" # required, the dependency to your plugin + repository: "https://maven.example.com/releases" # optional, defaults to https://maven.lavalink.dev/releases for releases + snapshot: false # optional, defaults to false, used to tell Lavalink to use the snapshot repository instead of the release repository +``` + +The default repositories can also be overridden in your `application.yml` file. + +```yaml +lavalink: + defaultPluginRepository: "https://maven.example.com/releases" # optional, defaults to https://maven.lavalink.dev/releases + defaultPluginSnapshotRepository: "https://maven.example.com/snapshots" # optional, defaults to https://maven.lavalink.dev/snapshots +``` + +Additionally, you can override the default plugin path where Lavalink saves and loads the downloaded plugins. + +```yaml +lavalink: + pluginsDir: "./lavalink-plugins" # optional, defaults to "./plugins" +``` \ No newline at end of file diff --git a/IMPLEMENTATION.md b/docs/api/rest.md similarity index 54% rename from IMPLEMENTATION.md rename to docs/api/rest.md index 3fab96b91..e2c5ecb2d 100644 --- a/IMPLEMENTATION.md +++ b/docs/api/rest.md @@ -1,767 +1,265 @@ -# Implementation guidelines - -How to write your own client. - -## Requirements - -* You must be able to send messages via a shard's gateway connection. -* You must be able to intercept voice server & voice state updates from the gateway on your shard connection. - -## Significant changes v3.7.0 -> v4.0.0 - -* removed all non version `/v3` or `/v4` endpoints (except `/version`). -* `/v4/websocket` does not accept any messages anymore. -* `v4` uses the `sessionId` instead of the `resumeKey` for resuming. -* `v4` now returns the tracks `artworkUrl` and `isrc` if the source supports it. -* removal of deprecated json fields like `track`. -* addition of `artworkUrl` and `isrc` fields to the [Track Info](#track-info) object. -* addition of the full [Track](#track) object in [TrackStartEvent](#trackstartevent), [TrackEndEvent](#trackendevent), [TrackExceptionEvent](#trackexceptionevent) and [TrackStuckEvent](#trackstuckevent). -* updated capitalization of [Track End Reason](#track-end-reason) and [Severity](#severity) -* reworked [Load Result](#track-loading-result) object - -
-v4.0.0 Migration Guide - -All websocket ops are removed as of `v4.0.0` and replaced with the following endpoints and json fields: -* `play` -> [Update Player Endpoint](#update-player) `encodedTrack` or `identifier` field -* `stop` -> [Update Player Endpoint](#update-player) `encodedTrack` field with `null` -* `pause` -> [Update Player Endpoint](#update-player) `pause` field -* `seek` -> [Update Player Endpoint](#update-player) `position` field -* `volume` -> [Update Player Endpoint](#update-player) `volume` field -* `filters` -> [Update Player Endpoint](#update-player) `filters` field -* `destroy` -> [Destroy Player Endpoint](#destroy-player) -* `voiceUpdate` -> [Update Player Endpoint](#update-player) `voice` field -* `configureResuming` -> [Update Session Endpoint](#update-session) - -
- -
-Older versions - -## Significant changes v3.6.0 -> v3.7.0 - -* Moved HTTP endpoints under the new `/v3` path with `/version` as the only exception. -* Deprecation of the old HTTP paths. -* WebSocket handshakes should be done with `/v3/websocket`. Handshakes on `/` are now deprecated. -* Deprecation of all client-to-server messages (play, stop, pause, seek, volume, filters, destroy, voiceUpdate & configureResuming). -* Addition of REST endpoints intended to replace client requests. -* Addition of new WebSocket dispatch [Ready OP](#ready-op) to get `sessionId` and `resume` status. -* Addition of new [Session](#update-session)/[Player](#get-player) REST API. -* Addition of `/v3/info`, replaces `/plugins`. -* Deprecation of `Track.track` in existing endpoints. Use `Track.encoded` instead. -* Deprecation of `TrackXEvent.track` in WebSocket dispatches. Use `TrackXEvent.encodedTrack` instead. -* Player now has a `state` field which contains the same structure as returned by the `playerUpdate` OP. - -
-v3.7.0 Migration Guide - -All websocket ops are deprecated as of `v3.7.0` and replaced with the following endpoints and json fields: - -* `play` -> [Update Player Endpoint](#update-player) `track` or `identifier` field -* `stop` -> [Update Player Endpoint](#update-player) `track` field with `null` -* `pause` -> [Update Player Endpoint](#update-player) `pause` field -* `seek` -> [Update Player Endpoint](#update-player) `position` field -* `volume` -> [Update Player Endpoint](#update-player) `volume` field -* `filters` -> [Update Player Endpoint](#update-player) `filters` field -* `destroy` -> [Destroy Player Endpoint](#destroy-player) -* `voiceUpdate` -> [Update Player Endpoint](#update-player) `voice` field -* `configureResuming` -> [Update Session Endpoint](#update-session) - -
- -## Significant changes v3.3 -> v3.4 - -* Added filters -* The `error` string on the `TrackExceptionEvent` has been deprecated and replaced by - the [Exception](#exception-object) object following the same structure as the `LOAD_FAILED` error on [`/loadtracks`](#track-loading). -* Added the `connected` boolean to player updates. -* Added source name to REST api track objects -* Clients are now requested to make their name known during handshake - -## Significant changes v2.0 -> v3.0 - -* The response of `/loadtracks` has been completely changed (again since the initial v3.0 pre-release). -* Lavalink v3.0 now reports its version as a handshake response header. - `Lavalink-Major-Version` has a value of `3` for v3.0 only. It's missing for any older version. - -## Significant changes v1.3 -> v2.0 - -With the release of v2.0 many unnecessary ops were removed: - -* `connect` -* `disconnect` -* `validationRes` -* `isConnectedRes` -* `validationReq` -* `isConnectedReq` -* `sendWS` - -With Lavalink 1.x the server had the responsibility of handling Discord `VOICE_SERVER_UPDATE`s as well as its own internal ratelimiting. -This remote handling makes things unnecessarily complicated and adds a lot og points where things could go wrong. -One problem we noticed is that since JDA is unaware of ratelimits on the bot's gateway connection, it would keep adding -to the ratelimit queue to the gateway. With this update this is now the responsibility of the Lavalink client or the -Discord client. - -A voice connection is now initiated by forwarding a `voiceUpdate` (VOICE_SERVER_UPDATE) to the server. When you want to -disconnect or move to a different voice channel you must send Discord a new VOICE_STATE_UPDATE. If you want to move your -connection to a new Lavalink server you can simply send the VOICE_SERVER_UPDATE to the new node, and the other node -will be disconnected by Discord. - -Depending on your Discord library, it may be possible to take advantage of the library's OP 4 handling. For instance, -the JDA client takes advantage of JDA's websocket write thread to send OP 4s for connects, disconnects and reconnects. - -
- -## Protocol - -### Reference - -Fields marked with `?` are optional and types marked with `?` are nullable. - -### Opening a connection - -You can establish a WebSocket connection against the path `/v4/websocket`. - -When opening a websocket connection, you must supply 3 required headers: - -| Header Name | Description | -|-----------------|-------------------------------------------------| -| `Authorization` | The password you set in your Lavalink config | -| `User-Id` | The user id of the bot | -| `Client-Name` | The name of the client in `NAME/VERSION` format | -| `Session-Id`? * | The id of the previous session to resume | +--- +description: Lavalink REST API documentation. +--- -**\*For more information on resuming see [Resuming](#resuming-lavalink-sessions)** +# REST API -
-Example Headers +Lavalink exposes a REST API to allow for easy control of the players. +Most routes require the `Authorization` header with the configured password. ``` Authorization: youshallnotpass -User-Id: 170939974227541168 -Client-Name: lavalink-client/2.0.0 ``` -
- -### Websocket Messages - -Websocket messages all follow the following standard format: - -| Field | Type | Description | -|-------|----------------------|---------------------------------------| -| op | [OP Type](#op-types) | The op type | -| ... | ... | Extra fields depending on the op type | - -
-Example Payload - -```yaml -{ - "op": "...", - ... -} -``` - -
+Routes are prefixed with `/v3` as of `v3.7.0` and `/v4` as of `v4.0.0`. Routes without an API prefix were removed in v4 (except `/version`). -#### OP Types +## Insomnia Collection -| OP Type | Description | -|-----------------------------------|---------------------------------------------------------------| -| [ready](#ready-op) | Dispatched when you successfully connect to the Lavalink node | -| [playerUpdate](#player-update-op) | Dispatched every x seconds with the latest player state | -| [stats](#stats-op) | Dispatched when the node sends stats once per minute | -| [event](#event-op) | Dispatched when player or voice events occur | +You can find an [Insomnia](https://insomnia.rest/) collection in the [here](Insomnia.json) which contains all the endpoints and their respective payloads. -#### Ready OP +## Error Responses -Dispatched by Lavalink upon successful connection and authorization. Contains fields determining if resuming was successful, as well as the session id. +When Lavalink encounters an error, it will respond with a JSON object containing more information about the error. Include the `trace=true` query param to also receive the full stack trace. -| Field | Type | Description | -|-----------|--------|------------------------------------------------------------------------------------------------| -| resumed | bool | Whether this session was resumed | -| sessionId | string | The Lavalink session id of this connection. Not to be confused with a Discord voice session id | +| Field | Type | Description | +|-----------|--------|-----------------------------------------------------------------------------| +| timestamp | int | The timestamp of the error in milliseconds since the Unix epoch | +| status | int | The HTTP status code | +| error | string | The HTTP status code message | +| trace? | string | The stack trace of the error when `trace=true` as query param has been sent | +| message | string | The error message | +| path | string | The request path |
Example Payload ```json { - "op": "ready", - "resumed": false, - "sessionId": "..." + "timestamp": 1667857581613, + "status": 404, + "error": "Not Found", + "trace": "...", + "message": "Session not found", + "path": "/v4/sessions/xtaug914v9k5032f/players/817327181659111454" } ```
---- -#### Player Update OP +## Track API -Dispatched every x seconds (configurable in `application.yml`) with the current state of the player. +### Common Types ### {: #track-api-types } -| Field | Type | Description | -|---------|--------------------------------------|----------------------------| -| guildId | string | The guild id of the player | -| state | [Player State](#player-state) object | The player state | +#### Track -##### Player State +| Field | Type | Description | +|------------|----------------------------------|-----------------------------------------| +| encoded | string | The base64 encoded track data | +| info | [Track Info](#track-info) object | Info about the track | +| pluginInfo | object | Addition track info provided by plugins | -| Field | Type | Description | -|-----------|------|------------------------------------------------------------------------------------------| -| time | int | Unix timestamp in milliseconds | -| position | int | The position of the track in milliseconds | -| connected | bool | Whether Lavalink is connected to the voice gateway | -| ping | int | The ping of the node to the Discord voice server in milliseconds (`-1` if not connected) | +#### Track Info -
-Example Payload +| Field | Type | Description | +|------------|---------|---------------------------------------------------------------------------------------| +| identifier | string | The track identifier | +| isSeekable | bool | Whether the track is seekable | +| author | string | The track author | +| length | int | The track length in milliseconds | +| isStream | bool | Whether the track is a stream | +| position | int | The track position in milliseconds | +| title | string | The track title | +| uri | ?string | The track uri | +| artworkUrl | ?string | The track artwork url | +| isrc | ?string | The track [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code) | +| sourceName | string | The track source name | -```json -{ - "op": "playerUpdate", - "guildId": "...", - "state": { - "time": 1500467109, - "position": 60000, - "connected": true, - "ping": 50 - } -} -``` +#### Playlist Info -
+| Field | Type | Description | +|---------------|--------|-----------------------------------------------------------------| +| name | string | The name of the playlist | +| selectedTrack | int | The selected track of the playlist (-1 if no track is selected) | --- -#### Stats OP +### Track Loading -A collection of statistics sent every minute. - -##### Stats Object - -| Field | Type | Description | -|----------------|-------------------------------------|--------------------------------------------------------------------------------------------------| -| players | int | The amount of players connected to the node | -| playingPlayers | int | The amount of players playing a track | -| uptime | int | The uptime of the node in milliseconds | -| memory | [Memory](#memory) object | The memory stats of the node | -| cpu | [CPU](#cpu) object | The cpu stats of the node | -| frameStats | ?[Frame Stats](#frame-stats) object | The frame stats of the node. `null` if the node has no players or when retrieved via `/v4/stats` | - -##### Memory - -| Field | Type | Description | -|------------|------|------------------------------------------| -| free | int | The amount of free memory in bytes | -| used | int | The amount of used memory in bytes | -| allocated | int | The amount of allocated memory in bytes | -| reservable | int | The amount of reservable memory in bytes | - -##### CPU +This endpoint is used to resolve audio tracks for use with the [Update Player](#update-player) endpoint. -| Field | Type | Description | -|--------------|-------|----------------------------------| -| cores | int | The amount of cores the node has | -| systemLoad | float | The system load of the node | -| lavalinkLoad | float | The load of Lavalink on the node | -##### Frame Stats +!!! note + + Lavalink supports searching via YouTube, YouTube Music, and Soundcloud. To search, you must prefix your identifier with `ytsearch:`, `ytmsearch:` or `scsearch:` respectively. + + When a search prefix is used, the returned `loadType` will be `search`. Note that disabling the respective source managers renders these search prefixes useless. -| Field | Type | Description | -|-----------|------|----------------------------------------------------------------------| -| sent | int | The amount of frames sent to Discord | -| nulled | int | The amount of frames that were nulled | -| deficit * | int | The difference between sent frames and the expected amount of frames | + Plugins may also implement prefixes to allow for more search engines to be utilised. -\* The expected amount of frames is 3000 (1 every 20 ms) per player. If the `deficit` is negative, too many frames were sent, and if it's positive, not enough frames got sent. -
-Example Payload - -```json -{ - "op": "stats", - "players": 1, - "playingPlayers": 1, - "uptime": 123456789, - "memory": { - "free": 123456789, - "used": 123456789, - "allocated": 123456789, - "reservable": 123456789 - }, - "cpu": { - "cores": 4, - "systemLoad": 0.5, - "lavalinkLoad": 0.5 - }, - "frameStats": { - "sent": 6000, - "nulled": 10, - "deficit": -3010 - } -} ``` - -
- ---- - -#### Event OP - -Server dispatched an event. See the [Event Types](#event-types) section for more information. - -| Field | Type | Description | -|---------|---------------------------|-------------------------------------| -| type | [EventType](#event-types) | The type of event | -| guildId | string | The guild id | -| ... | ... | Extra fields depending on the event | - -
-Example Payload - -```yaml -{ - "op": "event", - "type": "...", - "guildId": "...", - ... -} +GET /v4/loadtracks?identifier=dQw4w9WgXcQ ``` -
- -##### Event Types - -| Event Type | Description | -|-----------------------------------------------|-----------------------------------------------------------------------------| -| [TrackStartEvent](#trackstartevent) | Dispatched when a track starts playing | -| [TrackEndEvent](#trackendevent) | Dispatched when a track ends | -| [TrackExceptionEvent](#trackexceptionevent) | Dispatched when a track throws an exception | -| [TrackStuckEvent](#trackstuckevent) | Dispatched when a track gets stuck while playing | -| [WebSocketClosedEvent](#websocketclosedevent) | Dispatched when the websocket connection to Discord voice servers is closed | - -##### TrackStartEvent - -Dispatched when a track starts playing. - -| Field | Type | Description | -|-------|------------------------|--------------------------------| -| track | [Track](#track) object | The track that started playing | +Response: -
-Example Payload +#### Track Loading Result -```json -{ - "op": "event", - "type": "TrackStartEvent", - "guildId": "...", - "track": { - "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - "info": { - "identifier": "dQw4w9WgXcQ", - "isSeekable": true, - "author": "RickAstleyVEVO", - "length": 212000, - "isStream": false, - "position": 0, - "title": "Rick Astley - Never Gonna Give You Up", - "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", - "isrc": null, - "sourceName": "youtube" - }, - "pluginInfo": {} - } -} -``` - -
- ---- +| Field | Type | Description | +|----------|-------------------------------------|------------------------| +| loadType | [LoadResultType](#load-result-type) | The type of the result | +| data | [LoadResultData](#load-result-data) | The data of the result | -##### TrackEndEvent +#### Load Result Type -Dispatched when a track ends. +| Load Result Type | Description | +|------------------|-----------------------------------------------| +| `track` | A track has been loaded | +| `playlist` | A playlist has been loaded | +| `search` | A search result has been loaded | +| `empty` | There has been no matches for your identifier | +| `error` | Loading has failed with an error | -| Field | Type | Description | -|--------|-------------------------------------|------------------------------| -| track | [Track](#track) object | The track that ended playing | -| reason | [TrackEndReason](#track-end-reason) | The reason the track ended | +#### Load Result Data -##### Track End Reason +##### Track Result Data -| Reason | Description | May Start Next | -|--------------|----------------------------|----------------| -| `finished` | The track finished playing | true | -| `loadFailed` | The track failed to load | true | -| `stopped` | The track was stopped | false | -| `replaced` | The track was replaced | false | -| `cleanup` | The track was cleaned up | false | +[Track](#track) object with the loaded track.
Example Payload -```json +```yaml { - "op": "event", - "type": "TrackEndEvent", - "guildId": "...", - "track": { - "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - "info": { - "identifier": "dQw4w9WgXcQ", - "isSeekable": true, - "author": "RickAstleyVEVO", - "length": 212000, - "isStream": false, - "position": 0, - "title": "Rick Astley - Never Gonna Give You Up", - "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", - "isrc": null, - "sourceName": "youtube" - }, - "pluginInfo": {} - }, - "reason": "finished" + "loadType": "track", + "data": { + "encoded": "...", + "info": { ... }, + "pluginInfo": { ... } + } } ```
---- - -##### TrackExceptionEvent - -Dispatched when a track throws an exception. - -| Field | Type | Description | -|-----------|---------------------------------------|------------------------------------| -| track | [Track](#track) object | The track that threw the exception | -| exception | [Exception](#exception-object) object | The occurred exception | - -##### Exception Object - -| Field | Type | Description | -|----------|-----------------------|-------------------------------| -| message | ?string | The message of the exception | -| severity | [Severity](#severity) | The severity of the exception | -| cause | string | The cause of the exception | +##### Playlist Result Data -##### Severity - -| Severity | Description | -|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `common` | The cause is known and expected, indicates that there is nothing wrong with the library itself | -| `suspicious` | The cause might not be exactly known, but is possibly caused by outside factors. For example when an outside service responds in a format that we do not expect | -| `fault` | The probable cause is an issue with the library or there is no way to tell what the cause might be. This is the default level and other levels are used in cases where the thrower has more in-depth knowledge about the error | +| Field | Type | Description | +|------------|---------------------------------------|--------------------------------------------| +| info | [PlaylistInfo](#playlist-info) object | The info of the playlist | +| pluginInfo | Object | Addition playlist info provided by plugins | +| tracks | array of [Track](#track) objects | The tracks of the playlist |
Example Payload -```json +```yaml { - "op": "event", - "type": "TrackExceptionEvent", - "guildId": "...", - "track": { - "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - "info": { - "identifier": "dQw4w9WgXcQ", - "isSeekable": true, - "author": "RickAstleyVEVO", - "length": 212000, - "isStream": false, - "position": 0, - "title": "Rick Astley - Never Gonna Give You Up", - "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", - "isrc": null, - "sourceName": "youtube" - }, - "pluginInfo": {} - }, - "exception": { - "message": "...", - "severity": "common", - "cause": "..." + "loadType": "playlist", + "data": { + "info": { ... }, + "pluginInfo": { ... }, + "tracks": [ ... ] } } ```
---- - -##### TrackStuckEvent +##### Search Result Data -Dispatched when a track gets stuck while playing. - -| Field | Type | Description | -|-------------|------------------------|-------------------------------------------------| -| track | [Track](#track) object | The track that got stuck | -| thresholdMs | int | The threshold in milliseconds that was exceeded | +Array of [Track](#track) objects from the search result.
Example Payload -```json +```yaml { - "op": "event", - "type": "TrackStuckEvent", - "guildId": "...", - "track": { - "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - "info": { - "identifier": "dQw4w9WgXcQ", - "isSeekable": true, - "author": "RickAstleyVEVO", - "length": 212000, - "isStream": false, - "position": 0, - "title": "Rick Astley - Never Gonna Give You Up", - "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", - "isrc": null, - "sourceName": "youtube" + "loadType": "search", + "data": [ + { + "encoded": "...", + "info": { ... }, + "pluginInfo": { ... } }, - "pluginInfo": {} - }, - "thresholdMs": 123456789 + ... + ] } ```
---- - -##### WebSocketClosedEvent +##### Empty Result Data -Dispatched when an audio WebSocket (to Discord) is closed. -This can happen for various reasons (normal and abnormal), e.g. when using an expired voice server update. -4xxx codes are usually bad. -See the [Discord Docs](https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-close-event-codes). - -| Field | Type | Description | -|----------|--------|-----------------------------------------------------------------------------------------------------------------------------------| -| code | int | The [Discord close event code](https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-close-event-codes) | -| reason | string | The close reason | -| byRemote | bool | Whether the connection was closed by Discord | +Empty object.
Example Payload -```json +```yaml { - "op": "event", - "type": "WebSocketClosedEvent", - "guildId": "...", - "code": 4006, - "reason": "Your session is no longer valid.", - "byRemote": true + "loadType": "empty", + "data": {} } ```
---- - -### REST API +##### Error Result Data -Lavalink exposes a REST API to allow for easy control of the players. -Most routes require the `Authorization` header with the configured password. - -``` -Authorization: youshallnotpass -``` - -Routes are prefixed with `/v3` as of `v3.7.0` and `/v4` as of `v4.0.0`. Routes without an API prefix were removed in v4 (except `/version`). - -#### Error Responses - -When Lavalink encounters an error, it will respond with a JSON object containing more information about the error. Include the `trace=true` query param to also receive the full stack trace. - -| Field | Type | Description | -|-----------|--------|-----------------------------------------------------------------------------| -| timestamp | int | The timestamp of the error in milliseconds since the Unix epoch | -| status | int | The HTTP status code | -| error | string | The HTTP status code message | -| trace? | string | The stack trace of the error when `trace=true` as query param has been sent | -| message | string | The error message | -| path | string | The request path | +[Exception](websocket.md#exception-object) object with the error.
Example Payload -```json +```yaml { - "timestamp": 1667857581613, - "status": 404, - "error": "Not Found", - "trace": "...", - "message": "Session not found", - "path": "/v4/sessions/xtaug914v9k5032f/players/817327181659111454" + "loadType": "error", + "data": { + "message": "Something went wrong", + "severity": "fault", + "cause": "..." + } } ```
-#### Get Players - -Returns a list of players in this specific session. - -``` -GET /v4/sessions/{sessionId}/players -``` - -##### Player - -| Field | Type | Description | -|---------|--------------------------------------|-------------------------------------------------------| -| guildId | string | The guild id of the player | -| track | ?[Track](#track) object | The currently playing track | -| volume | int | The volume of the player, range 0-1000, in percentage | -| paused | bool | Whether the player is paused | -| state | [Player State](#player-state) object | The state of the player | -| voice | [Voice State](#voice-state) object | The voice state of the player | -| filters | [Filters](#filters) object | The filters used by the player | - -##### Track - -| Field | Type | Description | -|------------|----------------------------------|-----------------------------------------| -| encoded | string | The base64 encoded track data | -| info | [Track Info](#track-info) object | Info about the track | -| pluginInfo | object | Addition track info provided by plugins | - -##### Track Info - -| Field | Type | Description | -|------------|---------|---------------------------------------------------------------------------------------| -| identifier | string | The track identifier | -| isSeekable | bool | Whether the track is seekable | -| author | string | The track author | -| length | int | The track length in milliseconds | -| isStream | bool | Whether the track is a stream | -| position | int | The track position in milliseconds | -| title | string | The track title | -| uri | ?string | The track uri | -| artworkUrl | ?string | The track artwork url | -| isrc | ?string | The track [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code) | -| sourceName | string | The track source name | - -##### Voice State - -| Field | Type | Description | -|------------|--------|---------------------------------------------------------------------------------------------| -| token | string | The Discord voice token to authenticate with | -| endpoint | string | The Discord voice endpoint to connect to | -| sessionId | string | The Discord voice session id to authenticate with | - -`token`, `endpoint`, and `sessionId` are the 3 required values for connecting to one of Discord's voice servers. -`sessionId` is provided by the Voice State Update event sent by Discord, whereas the `endpoint` and `token` are provided -with the Voice Server Update. Please refer to https://discord.com/developers/docs/topics/gateway-events#voice - -
-Example Payload - -```yaml -[ - { - "guildId": "...", - "track": { - "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - "info": { - "identifier": "dQw4w9WgXcQ", - "isSeekable": true, - "author": "RickAstleyVEVO", - "length": 212000, - "isStream": false, - "position": 60000, - "title": "Rick Astley - Never Gonna Give You Up", - "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", - "isrc": null, - "sourceName": "youtube" - }, - "pluginInfo": {} - }, - "volume": 100, - "paused": false, - "state": { - "time": 1500467109, - "position": 60000, - "connected": true, - "ping": 50 - }, - "voice": { - "token": "...", - "endpoint": "...", - "sessionId": "..." - }, - "filters": { ... } - }, - ... -] -``` - -
- --- -#### Get Player +### Track Decoding -Returns the player for this guild in this session. +Decode a single track into its info, where `BASE64` is the encoded base64 data. ``` -GET /v4/sessions/{sessionId}/players/{guildId} +GET /v4/decodetrack?encodedTrack=BASE64 ``` Response: -[Player](#Player) object +[Track](#track) object
Example Payload ```yaml { - "guildId": "...", - "track": { - "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - "info": { - "identifier": "dQw4w9WgXcQ", - "isSeekable": true, - "author": "RickAstleyVEVO", - "length": 212000, - "isStream": false, - "position": 60000, - "title": "Rick Astley - Never Gonna Give You Up", - "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", - "isrc": null, - "sourceName": "youtube" - } - }, - "volume": 100, - "paused": false, - "state": { - "time": 1500467109, - "position": 60000, - "connected": true, - "ping": 50 - }, - "voice": { - "token": "...", - "endpoint": "...", - "sessionId": "..." + "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + "info": { + "identifier": "dQw4w9WgXcQ", + "isSeekable": true, + "author": "RickAstleyVEVO", + "length": 212000, + "isStream": false, + "position": 0, + "title": "Rick Astley - Never Gonna Give You Up", + "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", + "isrc": null, + "sourceName": "youtube" }, - "filters": { ... } + "pluginInfo": {} } ``` @@ -769,72 +267,38 @@ Response: --- -#### Update Player - -Updates or creates the player for this guild if it doesn't already exist. - -``` -PATCH /v4/sessions/{sessionId}/players/{guildId}?noReplace=true -``` - -Query Params: - -| Field | Type | Description | -|------------|------|------------------------------------------------------------------------------| -| noReplace? | bool | Whether to replace the current track with the new track. Defaults to `false` | - -Request: - -| Field | Type | Description | -|-----------------|------------------------------------|-----------------------------------------------------------------------------------------------| -| encodedTrack? * | ?string | The base64 encoded track to play. `null` stops the current track | -| identifier? * | string | The identifier of the track to play | -| position? | int | The track position in milliseconds | -| endTime? | ?int | The track end time in milliseconds (must be > 0). `null` resets this if it was set previously | -| volume? | int | The player volume, in percentage, from 0 to 1000 | -| paused? | bool | Whether the player is paused | -| filters? | [Filters](#filters) object | The new filters to apply. This will override all previously applied filters | -| voice? | [Voice State](#voice-state) object | Information required for connecting to Discord | +Decodes multiple tracks into their info -> **Note** -> - \* `encodedTrack` and `identifier` are mutually exclusive. -> - `sessionId` in the path should be the value from the [ready op](#ready-op). +``` +POST /v4/decodetracks +``` -When `identifier` is used, Lavalink will try to resolve the identifier as a single track. An HTTP `400` error is returned when resolving a playlist, search result, or no tracks. +Request: + +Array of track data strings
Example Payload ```yaml -{ - "encodedTrack": "...", - "identifier": "...", - "endTime": 0, - "volume": 100, - "position": 32400, - "paused": false, - "filters": { ... }, - "voice": { - "token": "...", - "endpoint": "...", - "sessionId": "..." - } -} +[ + "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + ... +] ```
Response: -[Player](#Player) object +Array of [Track](#track) objects
Example Payload ```yaml -{ - "guildId": "...", - "track": { +[ + { "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", "info": { "identifier": "dQw4w9WgXcQ", @@ -842,35 +306,52 @@ Response: "author": "RickAstleyVEVO", "length": 212000, "isStream": false, - "position": 60000, + "position": 0, "title": "Rick Astley - Never Gonna Give You Up", "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", "isrc": null, "sourceName": "youtube" - } - }, - "volume": 100, - "paused": false, - "state": { - "time": 1500467109, - "position": 60000, - "connected": true, - "ping": 50 - }, - "voice": { - "token": "...", - "endpoint": "...", - "sessionId": "..." + }, + "pluginInfo": {} }, - "filters": { ... } -} + ... +] ```
--- +## Player API + +### Common Types ### {: #player-api-types } + +#### Player + +| Field | Type | Description | +|---------|--------------------------------------------------|-------------------------------------------------------| +| guildId | string | The guild id of the player | +| track | ?[Track](#track) object | The currently playing track | +| volume | int | The volume of the player, range 0-1000, in percentage | +| paused | bool | Whether the player is paused | +| state | [Player State](websocket.md#player-state) object | The state of the player | +| voice | [Voice State](#voice-state) object | The voice state of the player | +| filters | [Filters](#filters) object | The filters used by the player | + +#### Voice State + +| Field | Type | Description | +|-----------|--------|---------------------------------------------------| +| token | string | The Discord voice token to authenticate with | +| endpoint | string | The Discord voice endpoint to connect to | +| sessionId | string | The Discord voice session id to authenticate with | + +`token`, `endpoint`, and `sessionId` are the 3 required values for connecting to one of Discord's voice servers. +`sessionId` is provided by the Voice State Update event sent by Discord, whereas the `endpoint` and `token` are provided +with the Voice Server Update. Please refer to https://discord.com/developers/docs/topics/gateway-events#voice + + #### Filters Filters are used in above requests and look like this @@ -1008,9 +489,9 @@ Any smoothing values equal to or less than 1.0 will disable the filter. |------------|-------|--------------------------------| | smoothing? | float | The smoothing factor (1.0 < x) | -##### Plugin Filter +##### Plugin Filters -Plugins can add their own filters. The key is the name of the plugin, and the value is the configuration for that plugin. The configuration is plugin specific. See [Plugins](PLUGINS.md) for more plugin information. +Plugins can add their own filters. The key is the name of the plugin, and the value is the configuration for that plugin. The configuration is plugin specific. See [Plugins](plugins.md) for more plugin information.
Example Payload @@ -1077,202 +558,211 @@ Plugins can add their own filters. The key is the name of the plugin, and the va --- -#### Destroy Player - -Destroys the player for this guild in this session. - -``` -DELETE /v4/sessions/{sessionId}/players/{guildId} -``` - -Response: - -204 - No Content - ---- - -#### Update Session +### Get Players -Updates the session with the resuming state and timeout. +Returns a list of players in this specific session. ``` -PATCH /v4/sessions/{sessionId} -``` - -Request: - -| Field | Type | Description | -|-----------|------|-----------------------------------------------------| -| resuming? | bool | Whether resuming is enabled for this session or not | -| timeout? | int | The timeout in seconds (default is 60s) | - -
-Example Payload - -```json -{ - "resuming": false, - "timeout": 0 -} +GET /v4/sessions/{sessionId}/players ``` -
- -Response: - -| Field | Type | Description | -|----------|------|-----------------------------------------------------| -| resuming | bool | Whether resuming is enabled for this session or not | -| timeout | int | The timeout in seconds (default is 60s) | -
Example Payload -```json -{ - "resuming": true, - "timeout": 60 -} +```yaml +[ + { + "guildId": "...", + "track": { + "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + "info": { + "identifier": "dQw4w9WgXcQ", + "isSeekable": true, + "author": "RickAstleyVEVO", + "length": 212000, + "isStream": false, + "position": 60000, + "title": "Rick Astley - Never Gonna Give You Up", + "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", + "isrc": null, + "sourceName": "youtube" + }, + "pluginInfo": {} + }, + "volume": 100, + "paused": false, + "state": { + "time": 1500467109, + "position": 60000, + "connected": true, + "ping": 50 + }, + "voice": { + "token": "...", + "endpoint": "...", + "sessionId": "..." + }, + "filters": { ... } + }, + ... +] ```
--- -#### Track Loading +### Get Player -This endpoint is used to resolve audio tracks for use with the [Update Player](#update-player) endpoint. +Returns the player for this guild in this session. ``` -GET /v4/loadtracks?identifier=dQw4w9WgXcQ +GET /v4/sessions/{sessionId}/players/{guildId} ``` Response: -##### Track Loading Result - -| Field | Type | Description | -|----------|-------------------------------------|------------------------| -| loadType | [LoadResultType](#load-result-type) | The type of the result | -| data | [LoadResultData](#load-result-data) | The data of the result | - -##### Load Result Type - -| Load Result Type | Description | -|------------------|-----------------------------------------------| -| `track` | A track has been loaded | -| `playlist` | A playlist has been loaded | -| `search` | A search result has been loaded | -| `empty` | There has been no matches for your identifier | -| `error` | Loading has failed with an error | - -##### Load Result Data - -###### Load Result Data - Track - -[Track](#track) object with the loaded track. - -
-Example Payload - -```yaml -{ - "loadType": "track", - "data": { - "encoded": "...", - "info": { ... }, - "pluginInfo": { ... } - } -} -``` - -
- -###### Load Result Data - Playlist - -| Field | Type | Description | -|------------|---------------------------------------|---------------------------------------------| -| info | [PlaylistInfo](#playlist-info) object | The info of the playlist | -| pluginInfo | Object | Addition playlist info provided by plugins | -| tracks | array of [Track](#track) objects | The tracks of the playlist | - -###### Playlist Info - -| Field | Type | Description | -|---------------|--------|-----------------------------------------------------------------| -| name | string | The name of the playlist | -| selectedTrack | int | The selected track of the playlist (-1 if no track is selected) | +[Player](#Player) object
Example Payload ```yaml { - "loadType": "playlist", - "data": { - "info": { ... }, - "pluginInfo": { ... }, - "tracks": [ ... ] - } + "guildId": "...", + "track": { + "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + "info": { + "identifier": "dQw4w9WgXcQ", + "isSeekable": true, + "author": "RickAstleyVEVO", + "length": 212000, + "isStream": false, + "position": 60000, + "title": "Rick Astley - Never Gonna Give You Up", + "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", + "isrc": null, + "sourceName": "youtube" + } + }, + "volume": 100, + "paused": false, + "state": { + "time": 1500467109, + "position": 60000, + "connected": true, + "ping": 50 + }, + "voice": { + "token": "...", + "endpoint": "...", + "sessionId": "..." + }, + "filters": { ... } } ```
- -###### Load Result Data - Search - -Array of [Track](#track) objects from the search result. - -
-Example Payload - -```yaml -{ - "loadType": "search", - "data": [ - { - "encoded": "...", - "info": { ... }, - "pluginInfo": { ... } - }, - ... - ] -} + +--- + +### Update Player + +Updates or creates the player for this guild if it doesn't already exist. + +``` +PATCH /v4/sessions/{sessionId}/players/{guildId}?noReplace=true ``` -
+Query Params: + +| Field | Type | Description | +|------------|------|------------------------------------------------------------------------------| +| noReplace? | bool | Whether to replace the current track with the new track. Defaults to `false` | -###### Load Result Data - Empty +Request: -Empty object. +| Field | Type | Description | +|-----------------|------------------------------------|-----------------------------------------------------------------------------------------------| +| encodedTrack? * | ?string | The base64 encoded track to play. `null` stops the current track | +| identifier? * | string | The identifier of the track to play | +| position? | int | The track position in milliseconds | +| endTime? | ?int | The track end time in milliseconds (must be > 0). `null` resets this if it was set previously | +| volume? | int | The player volume, in percentage, from 0 to 1000 | +| paused? | bool | Whether the player is paused | +| filters? | [Filters](#filters) object | The new filters to apply. This will override all previously applied filters | +| voice? | [Voice State](#voice-state) object | Information required for connecting to Discord | + +> **Note** +> - \* `encodedTrack` and `identifier` are mutually exclusive. +> - `sessionId` in the path should be the value from the [ready op](websocket.md#ready-op). + +When `identifier` is used, Lavalink will try to resolve the identifier as a single track. An HTTP `400` error is returned when resolving a playlist, search result, or no tracks.
Example Payload ```yaml { - "loadType": "empty", - "data": {} + "encodedTrack": "...", + "identifier": "...", + "endTime": 0, + "volume": 100, + "position": 32400, + "paused": false, + "filters": { ... }, + "voice": { + "token": "...", + "endpoint": "...", + "sessionId": "..." + } } ```
-###### Load Result Data - Error +Response: -[Exception](#exception-object) object with the error. +[Player](#Player) object
Example Payload ```yaml { - "loadType": "error", - "data": { - "message": "Something went wrong", - "severity": "fault", - "cause": "..." - } + "guildId": "...", + "track": { + "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + "info": { + "identifier": "dQw4w9WgXcQ", + "isSeekable": true, + "author": "RickAstleyVEVO", + "length": 212000, + "isStream": false, + "position": 60000, + "title": "Rick Astley - Never Gonna Give You Up", + "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", + "isrc": null, + "sourceName": "youtube" + } + }, + "volume": 100, + "paused": false, + "state": { + "time": 1500467109, + "position": 60000, + "connected": true, + "ping": 50 + }, + "voice": { + "token": "...", + "endpoint": "...", + "sessionId": "..." + }, + "filters": { ... } } ``` @@ -1280,110 +770,71 @@ Empty object. --- -#### Track Searching - -Lavalink supports searching via YouTube, YouTube Music, and Soundcloud. To search, you must prefix your identifier with `ytsearch:`, `ytmsearch:` or `scsearch:` respectively. - -When a search prefix is used, the returned `loadType` will be `search`. Note that disabling the respective source managers renders these search prefixes useless. Plugins may also implement prefixes to allow for more search engines to be utilised. - ---- - -#### Track Decoding +### Destroy Player -Decode a single track into its info, where `BASE64` is the encoded base64 data. +Destroys the player for this guild in this session. ``` -GET /v4/decodetrack?encodedTrack=BASE64 +DELETE /v4/sessions/{sessionId}/players/{guildId} ``` Response: -[Track](#track) object - -
-Example Payload +204 - No Content -```yaml -{ - "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - "info": { - "identifier": "dQw4w9WgXcQ", - "isSeekable": true, - "author": "RickAstleyVEVO", - "length": 212000, - "isStream": false, - "position": 0, - "title": "Rick Astley - Never Gonna Give You Up", - "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", - "isrc": null, - "sourceName": "youtube" - }, - "pluginInfo": {} -} -``` +--- -
+## Session API ---- +### Update Session -Decodes multiple tracks into their info +Updates the session with the resuming state and timeout. ``` -POST /v4/decodetracks +PATCH /v4/sessions/{sessionId} ``` Request: -Array of track data strings +| Field | Type | Description | +|-----------|------|-----------------------------------------------------| +| resuming? | bool | Whether resuming is enabled for this session or not | +| timeout? | int | The timeout in seconds (default is 60s) |
Example Payload -```yaml -[ - "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - ... -] +```json +{ + "resuming": false, + "timeout": 0 +} ```
Response: -Array of [Track](#track) objects +| Field | Type | Description | +|----------|------|-----------------------------------------------------| +| resuming | bool | Whether resuming is enabled for this session or not | +| timeout | int | The timeout in seconds (default is 60s) |
Example Payload -```yaml -[ - { - "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", - "info": { - "identifier": "dQw4w9WgXcQ", - "isSeekable": true, - "author": "RickAstleyVEVO", - "length": 212000, - "isStream": false, - "position": 0, - "title": "Rick Astley - Never Gonna Give You Up", - "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", - "isrc": null, - "sourceName": "youtube" - }, - "pluginInfo": {} - }, - ... -] +```json +{ + "resuming": true, + "timeout": 60 +} ```
--- -#### Get Lavalink info +## Get Lavalink info Request Lavalink information. @@ -1393,7 +844,7 @@ GET /v4/info Response: -##### Info Response +### Info Response | Field | Type | Description | |----------------|-------------------------------------------|-----------------------------------------------------------------| @@ -1406,9 +857,9 @@ Response: | filters | array of strings | The enabled filters for this server | | plugins | array of [Plugin](#plugin-object) objects | The enabled plugins for this server | -##### Version Object +#### Version Object -Parsed Semantic Versioning 2.0.0. See https://semver.org/ for more info +Parsed [Semantic Versioning 2.0.0](https://semver.org/) | Field | Type | Description | |------------|---------|------------------------------------------------------------------------------------| @@ -1419,7 +870,7 @@ Parsed Semantic Versioning 2.0.0. See https://semver.org/ for more info | preRelease | ?string | The pre-release version according to semver as a `.` separated list of identifiers | | build | ?string | The build metadata according to semver as a `.` separated list of identifiers | -##### Git Object +#### Git Object | Field | Type | Description | |------------|--------|----------------------------------------------------------------| @@ -1427,7 +878,7 @@ Parsed Semantic Versioning 2.0.0. See https://semver.org/ for more info | commit | string | The commit this Lavalink server was built on | | commitTime | int | The millisecond unix timestamp for when the commit was created | -##### Plugin Object +#### Plugin Object | Field | Type | Description | |---------|--------|---------------------------| @@ -1482,7 +933,23 @@ Parsed Semantic Versioning 2.0.0. See https://semver.org/ for more info --- -#### Get Lavalink stats +## Get Lavalink version + +Request Lavalink version. + +``` +GET /version +``` + +Response: + +``` +4.0.0 +``` + +--- + +## Get Lavalink stats Request Lavalink statistics. @@ -1493,7 +960,7 @@ GET /v4/stats Response: `frameStats` is always missing for this endpoint. -[Stats](#stats-object) object +[Stats](websocket.md#stats-object) object
Example Payload @@ -1521,40 +988,14 @@ Response: --- -#### Get Lavalink version - -Request Lavalink version. - -``` -GET /version -``` - -Response: - -``` -4.0.0 -``` - ---- - -### RoutePlanner API +## RoutePlanner API Additionally, there are a few REST endpoints for the ip rotation extension. -#### Get RoutePlanner status -``` -GET /v4/routeplanner/status -``` - -Response: - -| Field | Type | Description | -|---------|---------------------------------------------|-----------------------------------------------------------------------| -| class | ?[Route Planner Type](#route-planner-types) | The name of the RoutePlanner implementation being used by this server | -| details | ?[Details](#details-object) object | The status details of the RoutePlanner | +### Common Types ### {: #route-planner-api-types } -##### Route Planner Types +#### Route Planner Types | Route Planner Type | Description | |------------------------------|-----------------------------------------------------------------------------------------------------------------------------| @@ -1563,7 +1004,7 @@ Response: | `RotatingNanoIpRoutePlanner` | IP address used is switched on clock update, rotates to a different /64 block on ban. Use with at least 2x /64 IPv6 blocks. | | `BalancingIpRoutePlanner` | IP address used is selected at random per request. Recommended for larger IP blocks. | -##### Details Object +#### Details Object | Field | Type | Description | Valid Types | |---------------------|-------------------------------------------------------|---------------------------------------------------------------------------------------|----------------------------------------------------| @@ -1575,21 +1016,21 @@ Response: | currentAddressIndex | string | The current offset in the ip block | `NanoIpRoutePlanner`, `RotatingNanoIpRoutePlanner` | | blockIndex | string | The information in which /64 block ips are chosen. This number increases on each ban. | `RotatingNanoIpRoutePlanner` | -##### IP Block Object +#### IP Block Object | Field | Type | Description | |-------|---------------------------------|--------------------------| | type | [IP Block Type](#ip-block-type) | The type of the ip block | | size | string | The size of the ip block | -##### IP Block Type +#### IP Block Type | IP Block Type | Description | |----------------|---------------------| | `Inet4Address` | The ipv4 block type | | `Inet6Address` | The ipv6 block type | -##### Failing Address Object +#### Failing Address Object | Field | Type | Description | |------------------|--------|----------------------------------------------------------| @@ -1597,6 +1038,21 @@ Response: | failingTimestamp | int | The timestamp when the address failed | | failingTime | string | The timestamp when the address failed as a pretty string | +--- + +### Get RoutePlanner status + +``` +GET /v4/routeplanner/status +``` + +Response: + +| Field | Type | Description | +|---------|---------------------------------------------|-----------------------------------------------------------------------| +| class | ?[Route Planner Type](#route-planner-types) | The name of the RoutePlanner implementation being used by this server | +| details | ?[Details](#details-object) object | The status details of the RoutePlanner | +
Example Payload @@ -1625,7 +1081,7 @@ Response: --- -#### Unmark a failed address +### Unmark a failed address ``` POST /v4/routeplanner/free/address @@ -1654,7 +1110,7 @@ Response: --- -#### Unmark all failed address +### Unmark all failed address ``` POST /v4/routeplanner/free/all @@ -1663,63 +1119,3 @@ POST /v4/routeplanner/free/all Response: 204 - No Content - ---- - -### Resuming Lavalink Sessions - -What happens after your client disconnects is dependent on whether the session has been configured for resuming. - -* If resuming is disabled all voice connections are closed immediately. -* If resuming is enabled all music will continue playing. You will then be able to resume your session, allowing you to control the players again. - -To enable resuming, you must call the [Update Session](#update-session) endpoint with the `resuming` and `timeout`. - -To resume a session, specify the session id in your WebSocket handshake request headers: - -``` -Session-Id: The id of the session you want to resume. -``` - -You can tell if your session was resumed by looking at the handshake response header `Session-Resumed` which is either `true` or `false`. - -``` -Session-Resumed: true -``` - -In case your websocket library doesn't support reading headers you can listen for the [ready op](#ready-op) and check the `resumed` field. - -When a session is paused, any events that would normally have been sent are queued up. When the session is resumed, this -queue is then emptied and the events are replayed. - ---- - -### Special notes - -* When your shard's main WS connection dies, so does all your Lavalink audio connections - * This also includes resumes - -* If Lavalink-Server suddenly dies (think SIGKILL) the client will have to terminate any audio connections by sending this event to Discord: - -```json -{ - "op": 4, - "d": { - "self_deaf": false, - "guild_id": "GUILD_ID_HERE", - "channel_id": null, - "self_mute": false - } -} -``` - ---- - -# Common pitfalls - -Admittedly Lavalink isn't inherently the most intuitive thing ever, and people tend to run into the same mistakes over again. Please double-check the following if you run into problems developing your client, and you can't connect to a voice channel or play audio: - -1. Check that you are intercepting **VOICE_SERVER_UPDATE**s and **VOICE_STATE_UPDATE**s to **Lavalink**. You only need the `endpoint`, `token`, and `session_id`. -2. Check that you aren't expecting to hear audio when you have forgotten to queue something up OR forgotten to join a voice channel. -3. Check that you are not trying to create a voice connection with your Discord library. -4. When in doubt, check the debug logfile at `/logs/debug.log`. diff --git a/docs/api/websocket.md b/docs/api/websocket.md new file mode 100644 index 000000000..487c5aa36 --- /dev/null +++ b/docs/api/websocket.md @@ -0,0 +1,454 @@ +--- +description: Lavalink WebSocket API documentation. +--- + +# WebSocket API + +## Opening a connection + +You can establish a WebSocket connection against the path `/v4/websocket`. + +When opening a websocket connection, you must supply 3 required headers: + +| Header Name | Description | +|-----------------|-------------------------------------------------| +| `Authorization` | The password you set in your Lavalink config | +| `User-Id` | The user id of the bot | +| `Client-Name` | The name of the client in `NAME/VERSION` format | +| `Session-Id`? * | The id of the previous session to resume | + +**\*For more information on resuming see [Resuming](index.md#resuming)** + +
+Example Headers + +``` +Authorization: youshallnotpass +User-Id: 170939974227541168 +Client-Name: lavalink-client/2.0.0 +``` + +
+ +Websocket messages all follow the following standard format: + +| Field | Type | Description | +|-------|----------------------|---------------------------------------| +| op | [OP Type](#op-types) | The op type | +| ... | ... | Extra fields depending on the op type | + +
+Example Payload + +```yaml +{ + "op": "...", + ... +} +``` + +
+ +## OP Types + +| OP Type | Description | +|-----------------------------------|---------------------------------------------------------------| +| [ready](#ready-op) | Dispatched when you successfully connect to the Lavalink node | +| [playerUpdate](#player-update-op) | Dispatched every x seconds with the latest player state | +| [stats](#stats-op) | Dispatched when the node sends stats once per minute | +| [event](#event-op) | Dispatched when player or voice events occur | + +### Ready OP + +Dispatched by Lavalink upon successful connection and authorization. Contains fields determining if resuming was successful, as well as the session id. + +| Field | Type | Description | +|-----------|--------|------------------------------------------------------------------------------------------------| +| resumed | bool | Whether this session was resumed | +| sessionId | string | The Lavalink session id of this connection. Not to be confused with a Discord voice session id | + +
+Example Payload + +```json +{ + "op": "ready", + "resumed": false, + "sessionId": "..." +} +``` + +
+ +--- + +### Player Update OP + +Dispatched every x seconds (configurable in `application.yml`) with the current state of the player. + +| Field | Type | Description | +|---------|--------------------------------------|----------------------------| +| guildId | string | The guild id of the player | +| state | [Player State](#player-state) object | The player state | + +### Player State + +| Field | Type | Description | +|-----------|------|------------------------------------------------------------------------------------------| +| time | int | Unix timestamp in milliseconds | +| position | int | The position of the track in milliseconds | +| connected | bool | Whether Lavalink is connected to the voice gateway | +| ping | int | The ping of the node to the Discord voice server in milliseconds (`-1` if not connected) | + +
+Example Payload + +```json +{ + "op": "playerUpdate", + "guildId": "...", + "state": { + "time": 1500467109, + "position": 60000, + "connected": true, + "ping": 50 + } +} +``` + +
+ +--- + +### Stats OP + +A collection of statistics sent every minute. + +#### Stats Object + +| Field | Type | Description | +|----------------|-------------------------------------|--------------------------------------------------------------------------------------------------| +| players | int | The amount of players connected to the node | +| playingPlayers | int | The amount of players playing a track | +| uptime | int | The uptime of the node in milliseconds | +| memory | [Memory](#memory) object | The memory stats of the node | +| cpu | [CPU](#cpu) object | The cpu stats of the node | +| frameStats | ?[Frame Stats](#frame-stats) object | The frame stats of the node. `null` if the node has no players or when retrieved via `/v4/stats` | + +##### Memory + +| Field | Type | Description | +|------------|------|------------------------------------------| +| free | int | The amount of free memory in bytes | +| used | int | The amount of used memory in bytes | +| allocated | int | The amount of allocated memory in bytes | +| reservable | int | The amount of reservable memory in bytes | + +##### CPU + +| Field | Type | Description | +|--------------|-------|----------------------------------| +| cores | int | The amount of cores the node has | +| systemLoad | float | The system load of the node | +| lavalinkLoad | float | The load of Lavalink on the node | + +##### Frame Stats + +| Field | Type | Description | +|-----------|------|----------------------------------------------------------------------| +| sent | int | The amount of frames sent to Discord | +| nulled | int | The amount of frames that were nulled | +| deficit * | int | The difference between sent frames and the expected amount of frames | + +\* The expected amount of frames is 3000 (1 every 20 ms) per player. If the `deficit` is negative, too many frames were sent, and if it's positive, not enough frames got sent. + +
+Example Payload + +```json +{ + "op": "stats", + "players": 1, + "playingPlayers": 1, + "uptime": 123456789, + "memory": { + "free": 123456789, + "used": 123456789, + "allocated": 123456789, + "reservable": 123456789 + }, + "cpu": { + "cores": 4, + "systemLoad": 0.5, + "lavalinkLoad": 0.5 + }, + "frameStats": { + "sent": 6000, + "nulled": 10, + "deficit": -3010 + } +} +``` + +
+ +--- + +### Event OP + +Server dispatched an event. See the [Event Types](#event-types) section for more information. + +| Field | Type | Description | +|---------|---------------------------|-------------------------------------| +| type | [EventType](#event-types) | The type of event | +| guildId | string | The guild id | +| ... | ... | Extra fields depending on the event | + +
+Example Payload + +```yaml +{ + "op": "event", + "type": "...", + "guildId": "...", + ... +} +``` + +
+ +##### Event Types + +| Event Type | Description | +|-----------------------------------------------|-----------------------------------------------------------------------------| +| [TrackStartEvent](#trackstartevent) | Dispatched when a track starts playing | +| [TrackEndEvent](#trackendevent) | Dispatched when a track ends | +| [TrackExceptionEvent](#trackexceptionevent) | Dispatched when a track throws an exception | +| [TrackStuckEvent](#trackstuckevent) | Dispatched when a track gets stuck while playing | +| [WebSocketClosedEvent](#websocketclosedevent) | Dispatched when the websocket connection to Discord voice servers is closed | + +#### TrackStartEvent + +Dispatched when a track starts playing. + +| Field | Type | Description | +|-------|-------------------------------|--------------------------------| +| track | [Track](rest.md#track) object | The track that started playing | + +
+Example Payload + +```json +{ + "op": "event", + "type": "TrackStartEvent", + "guildId": "...", + "track": { + "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + "info": { + "identifier": "dQw4w9WgXcQ", + "isSeekable": true, + "author": "RickAstleyVEVO", + "length": 212000, + "isStream": false, + "position": 0, + "title": "Rick Astley - Never Gonna Give You Up", + "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", + "isrc": null, + "sourceName": "youtube" + }, + "pluginInfo": {} + } +} +``` + +
+ +--- + +#### TrackEndEvent + +Dispatched when a track ends. + +| Field | Type | Description | +|--------|-------------------------------------|------------------------------| +| track | [Track](rest.md#track) object | The track that ended playing | +| reason | [TrackEndReason](#track-end-reason) | The reason the track ended | + +##### Track End Reason + +| Reason | Description | May Start Next | +|--------------|----------------------------|----------------| +| `finished` | The track finished playing | true | +| `loadFailed` | The track failed to load | true | +| `stopped` | The track was stopped | false | +| `replaced` | The track was replaced | false | +| `cleanup` | The track was cleaned up | false | + +
+Example Payload + +```json +{ + "op": "event", + "type": "TrackEndEvent", + "guildId": "...", + "track": { + "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + "info": { + "identifier": "dQw4w9WgXcQ", + "isSeekable": true, + "author": "RickAstleyVEVO", + "length": 212000, + "isStream": false, + "position": 0, + "title": "Rick Astley - Never Gonna Give You Up", + "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", + "isrc": null, + "sourceName": "youtube" + }, + "pluginInfo": {} + }, + "reason": "finished" +} +``` + +
+ +--- + +#### TrackExceptionEvent + +Dispatched when a track throws an exception. + +| Field | Type | Description | +|-----------|---------------------------------------|------------------------------------| +| track | [Track](rest.md#track) object | The track that threw the exception | +| exception | [Exception](#exception-object) object | The occurred exception | + +##### Exception Object + +| Field | Type | Description | +|----------|-----------------------|-------------------------------| +| message | ?string | The message of the exception | +| severity | [Severity](#severity) | The severity of the exception | +| cause | string | The cause of the exception | + +##### Severity + +| Severity | Description | +|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common` | The cause is known and expected, indicates that there is nothing wrong with the library itself | +| `suspicious` | The cause might not be exactly known, but is possibly caused by outside factors. For example when an outside service responds in a format that we do not expect | +| `fault` | The probable cause is an issue with the library or there is no way to tell what the cause might be. This is the default level and other levels are used in cases where the thrower has more in-depth knowledge about the error | + +
+Example Payload + +```json +{ + "op": "event", + "type": "TrackExceptionEvent", + "guildId": "...", + "track": { + "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + "info": { + "identifier": "dQw4w9WgXcQ", + "isSeekable": true, + "author": "RickAstleyVEVO", + "length": 212000, + "isStream": false, + "position": 0, + "title": "Rick Astley - Never Gonna Give You Up", + "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", + "isrc": null, + "sourceName": "youtube" + }, + "pluginInfo": {} + }, + "exception": { + "message": "...", + "severity": "common", + "cause": "..." + } +} +``` + +
+ +--- + +#### TrackStuckEvent + +Dispatched when a track gets stuck while playing. + +| Field | Type | Description | +|-------------|-------------------------------|-------------------------------------------------| +| track | [Track](rest.md#track) object | The track that got stuck | +| thresholdMs | int | The threshold in milliseconds that was exceeded | + +
+Example Payload + +```json +{ + "op": "event", + "type": "TrackStuckEvent", + "guildId": "...", + "track": { + "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAADPCAAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==", + "info": { + "identifier": "dQw4w9WgXcQ", + "isSeekable": true, + "author": "RickAstleyVEVO", + "length": 212000, + "isStream": false, + "position": 0, + "title": "Rick Astley - Never Gonna Give You Up", + "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg", + "isrc": null, + "sourceName": "youtube" + }, + "pluginInfo": {} + }, + "thresholdMs": 123456789 +} +``` + +
+ +--- + +#### WebSocketClosedEvent + +Dispatched when an audio WebSocket (to Discord) is closed. +This can happen for various reasons (normal and abnormal), e.g. when using an expired voice server update. +4xxx codes are usually bad. +See the [Discord Docs](https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-close-event-codes). + +| Field | Type | Description | +|----------|--------|-----------------------------------------------------------------------------------------------------------------------------------| +| code | int | The [Discord close event code](https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-close-event-codes) | +| reason | string | The close reason | +| byRemote | bool | Whether the connection was closed by Discord | + +
+Example Payload + +```json +{ + "op": "event", + "type": "WebSocketClosedEvent", + "guildId": "...", + "code": 4006, + "reason": "Your session is no longer valid.", + "byRemote": true +} +``` + +
\ No newline at end of file diff --git a/docs/assets/favicon.png b/docs/assets/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..a35922acaaada5c48429c06bd2a84b080fccd3aa GIT binary patch literal 2445 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 LNkvXXu0mjfwu6Lj literal 0 HcmV?d00001 diff --git a/docs/assets/images/lavalink.svg b/docs/assets/images/lavalink.svg new file mode 100644 index 000000000..0ade923fd --- /dev/null +++ b/docs/assets/images/lavalink.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + diff --git a/docs/assets/logo.svg b/docs/assets/logo.svg new file mode 100644 index 000000000..5c3e28f60 --- /dev/null +++ b/docs/assets/logo.svg @@ -0,0 +1,18 @@ + + + + + diff --git a/docs/changelog/index.md b/docs/changelog/index.md new file mode 100644 index 000000000..e86584f59 --- /dev/null +++ b/docs/changelog/index.md @@ -0,0 +1,119 @@ +--- +description: Lavalink changelog. +--- + +# Changelog + +Each release usually includes various fixes and improvements. +The most noteworthy of these, as well as any features and breaking changes, are listed here. + +## Significant changes + +
+v3.7.0 -> v4.0.0 + +* removed all non version `/v3` or `/v4` endpoints (except `/version`). +* `/v4/websocket` does not accept any messages anymore. +* `v4` uses the `sessionId` instead of the `resumeKey` for resuming. +* `v4` now returns the tracks `artworkUrl` and `isrc` if the source supports it. +* removal of deprecated json fields like `track`. +* addition of `artworkUrl` and `isrc` fields to the [Track Info](#track-info) object. +* addition of the full [Track](#track) object in [TrackStartEvent](#trackstartevent), [TrackEndEvent](#trackendevent), [TrackExceptionEvent](#trackexceptionevent) and [TrackStuckEvent](#trackstuckevent). +* updated capitalization of [Track End Reason](#track-end-reason) and [Severity](#severity) +* reworked [Load Result](#track-loading-result) object + +All websocket ops are removed as of `v4.0.0` and replaced with the following endpoints and json fields: + +* `play` -> [Update Player Endpoint](#update-player) `encodedTrack` or `identifier` field +* `stop` -> [Update Player Endpoint](#update-player) `encodedTrack` field with `null` +* `pause` -> [Update Player Endpoint](#update-player) `pause` field +* `seek` -> [Update Player Endpoint](#update-player) `position` field +* `volume` -> [Update Player Endpoint](#update-player) `volume` field +* `filters` -> [Update Player Endpoint](#update-player) `filters` field +* `destroy` -> [Destroy Player Endpoint](#destroy-player) +* `voiceUpdate` -> [Update Player Endpoint](#update-player) `voice` field +* `configureResuming` -> [Update Session Endpoint](#update-session) + +
+ +
+v3.6.0 -> v3.7.0 + +* Moved HTTP endpoints under the new `/v3` path with `/version` as the only exception. +* Deprecation of the old HTTP paths. +* WebSocket handshakes should be done with `/v3/websocket`. Handshakes on `/` are now deprecated. +* Deprecation of all client-to-server messages (play, stop, pause, seek, volume, filters, destroy, voiceUpdate & configureResuming). +* Addition of REST endpoints intended to replace client requests. +* Addition of new WebSocket dispatch [Ready OP](#ready-op) to get `sessionId` and `resume` status. +* Addition of new [Session](#update-session)/[Player](#get-player) REST API. +* Addition of `/v3/info`, replaces `/plugins`. +* Deprecation of `Track.track` in existing endpoints. Use `Track.encoded` instead. +* Deprecation of `TrackXEvent.track` in WebSocket dispatches. Use `TrackXEvent.encodedTrack` instead. +* Player now has a `state` field which contains the same structure as returned by the `playerUpdate` OP. + +All websocket ops are deprecated as of `v3.7.0` and replaced with the following endpoints and json fields: + +* `play` -> [Update Player Endpoint](#update-player) `track` or `identifier` field +* `stop` -> [Update Player Endpoint](#update-player) `track` field with `null` +* `pause` -> [Update Player Endpoint](#update-player) `pause` field +* `seek` -> [Update Player Endpoint](#update-player) `position` field +* `volume` -> [Update Player Endpoint](#update-player) `volume` field +* `filters` -> [Update Player Endpoint](#update-player) `filters` field +* `destroy` -> [Destroy Player Endpoint](#destroy-player) +* `voiceUpdate` -> [Update Player Endpoint](#update-player) `voice` field +* `configureResuming` -> [Update Session Endpoint](#update-session) + +
+ +
+v3.3 -> v3.4 + +* Added filters +* The `error` string on the `TrackExceptionEvent` has been deprecated and replaced by + the [Exception](#exception-object) object following the same structure as the `LOAD_FAILED` error on [`/loadtracks`](#track-loading). +* Added the `connected` boolean to player updates. +* Added source name to REST api track objects +* Clients are now requested to make their name known during handshake + +
+ +
+v2.0 -> v3.0 + +* The response of `/loadtracks` has been completely changed (again since the initial v3.0 pre-release). +* Lavalink v3.0 now reports its version as a handshake response header. + `Lavalink-Major-Version` has a value of `3` for v3.0 only. It's missing for any older version. + +
+ + +
+v1.3 -> v2.0 + +With the release of v2.0 many unnecessary ops were removed: + +* `connect` +* `disconnect` +* `validationRes` +* `isConnectedRes` +* `validationReq` +* `isConnectedReq` +* `sendWS` + +With Lavalink 1.x the server had the responsibility of handling Discord `VOICE_SERVER_UPDATE`s as well as its own internal ratelimiting. +This remote handling makes things unnecessarily complicated and adds a lot og points where things could go wrong. +One problem we noticed is that since JDA is unaware of ratelimits on the bot's gateway connection, it would keep adding +to the ratelimit queue to the gateway. With this update this is now the responsibility of the Lavalink client or the +Discord client. + +A voice connection is now initiated by forwarding a `voiceUpdate` (VOICE_SERVER_UPDATE) to the server. When you want to +disconnect or move to a different voice channel you must send Discord a new VOICE_STATE_UPDATE. If you want to move your +connection to a new Lavalink server you can simply send the VOICE_SERVER_UPDATE to the new node, and the other node +will be disconnected by Discord. + +Depending on your Discord library, it may be possible to take advantage of the library's OP 4 handling. For instance, +the JDA client takes advantage of JDA's websocket write thread to send OP 4s for connects, disconnects and reconnects. + +
+ + diff --git a/docs/changelog/v2.md b/docs/changelog/v2.md new file mode 100644 index 000000000..7773703ac --- /dev/null +++ b/docs/changelog/v2.md @@ -0,0 +1,36 @@ +## v2.2 + +* Lavaplayer updated to 1.3.x [\#115](https://github.com/lavalink-devs/Lavalink/pull/115) +* Version command line flag [\#121](https://github.com/lavalink-devs/Lavalink/pull/121) +* Fix race condition in `/loadtracks` endpoint leading to some requests never completing [\#125](https://github.com/lavalink-devs/Lavalink/pull/125) + +Contributors: +[@Devoxin](https://github.com/Devoxin), +[@freyacodes](https://github.com/freyacodes/), +[@napstr](https://github.com/napstr) + +## v2.1 + +* Add prometheus metrics [\#105](https://github.com/lavalink-devs/Lavalink/pull/105), [\#106](https://github.com/lavalink-devs/Lavalink/pull/106) + +Contributors: +[@freyacodes](https://github.com/freyacodes/), +[@napstr](https://github.com/napstr), +[@Repulser](https://github.com/Repulser/) + +## v2.0.1 + +* Configurable playlist load limit [\#60](https://github.com/lavalink-devs/Lavalink/pull/60) +* [Docker Releases](https://hub.docker.com/r/fredboat/lavalink/), [\#74](https://github.com/lavalink-devs/Lavalink/pull/74) + +Contributors: +[@Devoxin](https://github.com/Devoxin), +[@freyacodes](https://github.com/freyacodes/), +[@itslukej](https://github.com/itslukej/), +[@napstr](https://github.com/napstr), +[@Repulser](https://github.com/Repulser/) + +## v2.0 + +Please see [here](https://github.com/lavalink-devs/Lavalink/commit/b8dd3c8a7e186755c1ab343d19a552baecf138e7) +and [here](https://github.com/lavalink-devs/Lavalink/commit/08a34c99a47a18ade7bd14e6c55ab92348caaa88) diff --git a/docs/changelog/v3.md b/docs/changelog/v3.md new file mode 100644 index 000000000..1be1b2e34 --- /dev/null +++ b/docs/changelog/v3.md @@ -0,0 +1,315 @@ +## v3.7.9 +* Update lavaplayer to [`1.5.1`](https://github.com/lavalink-devs/lavaplayer/releases/tag/1.5.1) - Fixed YouTube access token errors +* Fixed websocket crash when seeking and nothing is playing +* Fixed error when seeking and player is not playing anything + +## v3.7.8 + +* Fix YouTube 403 errors +* Fix YouTube access token errors + +## v3.7.7 + +* Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) + +## v3.7.6 + +* Update Lavaplayer to [`1.4.1`](https://github.com/Walkyst/lavaplayer-fork/releases/tag/1.4.1) & [`1.4.2`](https://github.com/Walkyst/lavaplayer-fork/releases/tag/1.4.2) +* New support for `MUSL` based systems (most notably `alpine`) +* New `alpine` docker image variant (use `-alpine` suffix) + +## v3.7.5 + +* Fix `endTime` in `Player Update` endpoint only applying when playing a new track +* Fix errors when doing multiple session resumes +* Update lavaplayer to `1.4.0` see [here](https://github.com/Walkyst/lavaplayer-fork/releases/tag/1.4.0) for more info + +> **Note** +> Lavalink Docker images are now found in the GitHub Container Registry instead of DockerHub + +## v3.7.4 + +* Fix an issue where Lavalink would not destroy a session when a client disconnects + +## v3.7.3 + +* Fix breaking change where `/decodetrack` would return a full track instead of the track info + +## v3.7.2 + +* Fix breaking change where frameStats would be null instead of omitted + +## v3.7.1 + +* Revert of application.yml autocreate as it can cause issues with differently named configs + +## v3.7.0 + +* New REST API for player control and deprecation of all websocket OPs. For more info see [here](https://github.com/lavalink-devs/Lavalink/blob/master/IMPLEMENTATION.md#significant-changes-v360---v370) +* Autocreate default `application.yml` if none was found. https://github.com/lavalink-devs/Lavalink/pull/781 +* New config option to disable jda nas. https://github.com/lavalink-devs/Lavalink/pull/780 +* New config option to disable specific filters. https://github.com/lavalink-devs/Lavalink/pull/779 +* Update lavaplayer to `1.3.99.2`. https://github.com/lavalink-devs/Lavalink/pull/794 +* Update udpqueue.rs to `v0.2.6`. https://github.com/lavalink-devs/Lavalink/pull/802 + +Contributors: +[@topi314](https://github.com/topi314), [@Devoxin](https://github.com/Devoxin), [@melike2d](https://github.com/melike2d), [@freyacodes](https://github.com/freyacodes), [@aikaterna](https://github.com/aikaterna), [@ooliver1](https://github.com/ooliver1) + +## v3.6.2 + +* Update lavaplayer to `1.3.99.1`. For more info see [here](https://github.com/lavalink-devs/Lavalink/pull/773) + +## v3.6.1 + +* Update lavaplayer to `1.3.99`. For more info see [here](https://github.com/lavalink-devs/Lavalink/pull/768) + +## v3.6.0 + +* New userId & clientName getters in the plugin-api. For more info see [here](https://github.com/lavalink-devs/Lavalink/pull/743). + +Contributors: +[@melike2d](https://github.com/melike2d) + +## v3.5.1 + +* Update udpqueue.rs to `0.2.5` which fixes crashes when ipv6 is disabled +* Fix null socketContext in `IPlayer` for plugins +* New `ping` field in player update. see https://github.com/lavalink-devs/Lavalink/pull/738 for more info + +Contributors: +[@topi314](https://github.com/topi314), [@Devoxin](https://github.com/Devoxin), and [@freyacodes](https://github.com/freyacodes) + +## v3.5 + +* New plugin system. For more info see [here](https://github.com/lavalink-devs/Lavalink/blob/master/PLUGINS.md). +* Add support for HTTP proxying via httpConfig. For more info see [here](https://github.com/lavalink-devs/Lavalink/pull/595). +* Update koe version to 2.0.0-rc1. + - this fixes the WebSocketClosedEvent with code 1006 problem. +* Fix error when enabling timescale and lowpass filters. +* Fix player not playing after moving between voice chats or changing regions. +* Fix guild ids sent as numbers in json. +* Fix missing timescale natives. +* Fix setting endMarkerHit to correctly set FINISHED as the reason. +* Undeprecation of the `volume` property in the `play` OP. +* Configurable track stuck threshold. For more info see [here](https://github.com/lavalink-devs/Lavalink/pull/676). +* Add JDA-NAS support for more CPU Architectures. For more info see [here](https://github.com/lavalink-devs/Lavalink/pull/692). Big thanks goes to @MinnDevelopment here. +* Update lavaplayer to [`1.3.98.4`](https://github.com/Walkyst/lavaplayer-fork/releases/tag/1.3.98.4) which fixes the latest yt cipher issues and age restricted tracks + +Contributors: +[@freyacodes](https://github.com/freyacodes), +[@davidffa](https://github.com/davidffa), +[@Walkyst](https://github.com/Walkyst), +[@topi314](https://github.com/topi314), +[@duncte123](https://github.com/duncte123), +[@Kodehawa](https://github.com/Kodehawa), +[@Devoxin](https://github.com/Devoxin), +[@Muh9049](https://github.com/Muh9049), +[@melike2d](https://github.com/melike2d), +[@ToxicMushroom](https://github.com/ToxicMushroom), +[@mooner1022](https://github.com/mooner1022), +[@rohank05](https://github.com/rohank05), +[@Fabricio20](https://github.com/Fabricio20), +[@TheEssemm](https://github.com/TheEssemm), and +[@jack1142](https://github.com/jack1142) + +## v3.4 + +* New filters system +* Deprecation of `TrackExceptionEvent.error`, replaced by `TrackExceptionEvent.exception` +* Added the `connected` boolean to player updates. +* Updated lavaplayer, fixes Soundcloud +* Added source name to REST api track objects +* Clients are now requested to make their name known during handshake + +Contributors: +[@freyacodes](https://github.com/freyacodes), +[@duncte123](https://github.com/duncte123), +[@DaliborTrampota](https://github.com/DaliborTrampota), +[@Mandruyd](https://github.com/Mandruyd), +[@Allvaa](https://github.com/@Allvaa), and +[@topi314](https://github.com/topi314) + +## v3.3.2.5 + +* Update Lavaplayer to 1.3.76 + +## v3.3.2.4 + +* Update Lavaplayer to 1.3.74 + +## v3.3.2.3 + +* Update Lavaplayer to 1.3.65, fixes Soundcloud + +## v3.3.2.2 + +* Updated Lavaplayer to 1.3.61 +* Fixed a ConcurrentModificationException ([Thewsomeguy](https://github.com/Thewsomeguy)) + +## v3.3.2.1 + +* Updated to Sedmelluq's Lavaplayer 1.3.53 + +## v3.3.2 + +* Replaced Magma with Koe. +* Finally implemented `stopTime` for `play` op. +* Added `playerUpdateInterval` config option. +* Added `environment` to Sentry config. +* Fixed #332 +* Updated IP rotator. +* Update lavaplayer to `1.3.59` from devoxin's fork. +* Added a Testbot for development. + +Contributors: +[@freyacodes](https://github.com/freyacodes), +[@Thewsomeguy](https://github.com/Thewsomeguy), +[@Neuheit](https://github.com/Neuheit), +[@Sangoon_Is_Noob](https://github.com/Sangoon_Is_Noob), +[@TheEssem](https://github.com/Essem), and +[@Devoxin](https://github.com/Devoxin) + +## v3.3.1.4 + +* Update lavaplayer to `1.3.54.3` from devoxin's fork. + +## v3.3.1.3 + +* Update lavaplayer to `1.3.53` from devoxin's fork. + +## v3.3.1.2 + +* Update lavaplayer to [@Devoxin](https://github.com/Devoxin)'s' fork + +## v3.3.1.1 + +* Updated Lavaplayer to `1.3.50`. This notably fixes YouTube search. + +Search patch contributed by [@freyacodes](https://github.com/freyacodes) + +## v3.3.1 + +* Update Magma and Lavaplayer. +* Added TrackStartEvent event. +* Added retryLimit configuration option. +* Use a single AudioPlayerManager for all WS connections, reducing overhead. +* Docker images now use Zulu JDK 13 to mitigate TLS 1.3 problems. + +Contributors: +[@freyacodes](https://github.com/freyacodes), +[@duncte123](https://github.com/duncte123), +[@ByteAlex](https://github.com/ByteAlex), and +[@Xavinlol](https://github.com/Xavinlol) + +## v3.3 + +Officially limit Lavalink to JRE 11 and up. Magma has long been having issues with older versions. + +## v3.2.2 + +* IP rotation system for getting around certain ratelimits. +* Update Lavaplayer to 1.3.32. +* Docker container now uses a non-root user. + +Contributors: +[@freyacodes](https://github.com/freyacodes), +[@ByteAlex](https://github.com/ByteAlex), +[@duncte123](https://github.com/duncte123), and +[@james7132](https://github.com/james7132) + +## v3.2.1.1 + +* Updated Lavaplayer to 1.3.19. This release includes a patch which fixes loading youtube URLs. + https://github.com/sedmelluq/lavaplayer/pull/199 +* Made the WebSocket handshake return code 401 instead of 200 on bad auth. #208 + +Contributors: +[@freyacodes](https://github.com/freyacodes) and +[@Devoxin](https://github.com/Devoxin) + +## v3.2.1 + +* Update dependencies -- fixes frequent youtube HTTP errors +* Return `FriendlyException` message on `LOAD_FAILED` #174 +* Add option to disable `ytsearch` and `scsearch` #194 + +Contributors: +[@Devoxin](https://github.com/Devoxin), +[@duncte123](https://github.com/duncte123), +[@freyacodes](https://github.com/freyacodes), and +[@napstr](https://github.com/napstr) + +## v3.2.0.3 + +* Add compatibility for Java 8-10 + +Contributor: +[@MinnDevelopment](https://github.com/MinnDevelopment/) + +## v3.2.0.2 + +* Patched magma + +Contributor: +[@freyacodes](https://github.com/freyacodes/) + +## v3.2.0.1 + +* Bumped to Java 11. Treating this as a patch version, as v3.2 still requires Java 11 due to a Magma update. + +[@freyacodes](https://github.com/freyacodes) + +## v3.2 + +* Added support for resuming +* Added noReplace option to the play op +* Sending the same voice server update will not cause an existing connection to reconnect + +Contributor: +[@freyacodes](https://github.com/freyacodes) + +## v3.1.2 + +* Add API version header to all responses + +Contributor: +[@Devoxin](https://github.com/Devoxin) + +## v3.1.1 + +* Add equalizer support +* Update lavaplayer to 1.3.10 +* Fixed automatic versioning +* Added build config to upload binaries to GitHub releases from CI + +Contributors: +[@Devoxin](https://github.com/Devoxin), +[@freyacodes](https://github.com/freyacodes/), +[@calebj](https://github.com/calebj) + +## v3.1 + +* Replaced JDAA with Magma +* Added an event for when the Discord voice WebSocket is closed +* Replaced Tomcat and Java_Websocket with Undertow. WS and REST is now handled by the same + server and port. Port is specified by `server.port`. + +## v3.0 + +* **Breaking:** The minimum required Java version to run the server is now Java 10. + **Please note**: Java 10 will be obsolete + as of [September 2018 with the release of Java 11](http://www.java-countdown.xyz/). Expect a Lavalink major version release that will be targetting + Java 11 by that time. +* **Breaking:** Changes to the output of the /loadtracks endpoint. [\#91](https://github.com/lavalink-devs/Lavalink/pull/91), [\#114](https://github.com/lavalink-devs/Lavalink/pull/114), [\#116](https://github.com/lavalink-devs/Lavalink/pull/116) +* **Breaking:** The Java client has been moved to a [new repository](https://github.com/lavalink-devs/Lavalink-Client). +* **Breaking:** The Java client has been made generic. This is a breaking change so please read the [migration guide](https://github.com/lavalink-devs/Lavalink-Client#migrating-from-v2-to-v3). +* Better configurable logging. [\#97](https://github.com/lavalink-devs/Lavalink/pull/97) +* Add custom sentry tags, change sentry dsn configuration location. [\#103](https://github.com/lavalink-devs/Lavalink/pull/103) +* Add Lavalink version header to websocket handshake. [\#111](https://github.com/lavalink-devs/Lavalink/pull/111) +* Use git tags for easier version visibility. [\#129](https://github.com/lavalink-devs/Lavalink/pull/129) + +Contributors: +[@Devoxin](https://github.com/Devoxin), +[@freyacodes](https://github.com/freyacodes/), +[@napstr](https://github.com/napstr), +[@SamOphis](https://github.com/SamOphis) diff --git a/docs/changelog/v4.md b/docs/changelog/v4.md new file mode 100644 index 000000000..b877503d3 --- /dev/null +++ b/docs/changelog/v4.md @@ -0,0 +1,40 @@ +## v4.0.0-beta.5 +* Update lavaplayer to [`2.0.3`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Fixed YouTube access token errors +* Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](../api/plugins.md#distributing-your-plugin) +* Fixed error when seeking and player is not playing anything in + +## v4.0.0-beta.4 + +* Update lavaplayer to [`2.0.2`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Support MPEG 2.5 and fixed some requests not timing out +* Add `Omissible#isPresent` & `Omissible#isOmitted` to the `protocol` module +* Fix null pointer when a playlist has no selected track + +## v4.0.0-beta.3 + +* Update lavaplayer to [`2.0.0`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.0) - Fixed YouTube 403 errors & YouTube access token errors + +## v4.0.0-beta.2 + +* Update lavaplayer to [`08cfbc0`](https://github.com/Walkyst/lavaplayer-fork/commit/08cfbc05953128f3cf727ea3bcbe41dabcd1c7db) - Fixed ogg streaming +* Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) +* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) + +## v4.0.0-beta.1 + +* New Lavalink now requires Java 17 or higher to run +* **Removal of all websocket messages sent by the client. Everything is now done via [REST](../api/rest.md)** +* Update to [Lavaplayer custom branch](https://github.com/Walkyst/lavaplayer-fork/tree/custom), which includes native support for artwork urls and ISRCs in the track info +* Addition of full `Track` objects in following events: `TrackStartEvent`, `TrackEndEvent`, `TrackExceptionEvent`, `TrackStuckEvent` +* Resuming a session now requires the `Session-Id` header instead of `Resume-Key` header +* Reworked track loading result. For more info see [here](../api/rest.md#track-loading-result) +* Update to the [Protocol Module](https://github.com/lavalink-devs/Lavalink/tree/master/protocol) to support Kotlin/JS +* Removal of all `/v3` endpoints except `/version`. All other endpoints are now under `/v4` + +> **Warning** +> This is a beta release, and as such, may contain bugs. Please report any bugs you find to the [issue tracker](https://github.com/lavalink-devs/Lavalink/issues/new/choose). +> For more info on the changes in this release, see [here](../api/index.md#v370---v400) +> If you have any question regarding the changes in this release, please ask in the [support server]({{ discord_help }}) or [GitHub discussions](https://github.com/lavalink-devs/Lavalink/discussions/categories/q-a) + +Contributors: +[@topi314](https://github.com/topi314), [@freyacodes](https://github.com/freyacodes), [@DRSchlaubi](https://github.com/DRSchlaubi) and [@melike2d](https://github.com/melike2d) + diff --git a/docs/clients.md b/docs/clients.md new file mode 100644 index 000000000..075cbdb52 --- /dev/null +++ b/docs/clients.md @@ -0,0 +1,49 @@ +--- +description: A list of Lavalink client libraries. +--- + +# Client Libraries + +| Client | Platform | Compatible With | Additional Information | +|-------------------------------------------------------------------------|-----------------|--------------------------------------------|--------------------------------| +| [Lavalink-Client](https://github.com/lavalink-devs/Lavalink-Client) | Java/Kotlin/JVM | JDA/Discord4J/**Any** | Uses reactor | +| [Lavalink.kt](https://github.com/DRSchlaubi/Lavalink.kt) | Kotlin | Kord/JDA/**Any** | Kotlin Coroutines | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Wavelink](https://github.com/PythonistaGuild/Wavelink/tree/feature/v3) | Python | discord.py **V2** | Pre-Release (Version 3+) | +| [Moonlink.js](https://github.com/1Lucas1apk/moonlink.js) | Node.js | **Any** | | +| [Magmastream](https://github.com/Blackfort-Hosting/magmastream) | Node.js | **Any** | | +| [Lavacord](https://github.com/lavacord/Lavacord) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Lavalink-Client](https://github.com/tomato6966/Lavalink-Client) | Node.js | **Any** | | +| [FastLink](https://github.com/PerformanC/FastLink) | Node.js | **Any** | | +| [Riffy](https://github.com/riffy-team/riffy) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | v10.4.2+ | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus/Remora | v4+ | +| [Coglink](https://github.com/PerformanC/Coglink) | C | Concord | | +| [lavalink-rs](https://gitlab.com/vicky5124/lavalink-rs) | Rust, Python | **Any** | `tokio`-based, `asyncio`-based | + +
+v3.7 supporting Client Libraries + +| Client | Platform | Compatible With | Additional Information | +|---------------------------------------------------------------|----------|--------------------------------------------|---------------------------------| +| [Lavalink.kt](https://github.com/DRSchlaubi/lavalink.kt) | Kotlin | JDA/Kord/**Any** | Kotlin Coroutines | +| [lavaplay.py](https://github.com/HazemMeqdad/lavaplay.py) | Python | **Any\*** | *`asyncio`-based libraries only | +| [Mafic](https://github.com/ooliver1/mafic) | Python | discord.py **V2**/nextcord/disnake/py-cord | | +| [Wavelink](https://github.com/PythonistaGuild/Wavelink) | Python | discord.py **V2** | Version >=2, <3 | +| [Pomice](https://github.com/cloudwithax/pomice) | Python | discord.py **V2** | | +| [Lavacord](https://github.com/lavacord/lavacord) | Node.js | **Any** | | +| [Poru](https://github.com/parasop/poru) | Node.js | **Any** | | +| [Shoukaku](https://github.com/Deivu/Shoukaku) | Node.js | **Any** | | +| [Cosmicord.js](https://github.com/SudhanPlayz/Cosmicord.js) | Node.js | **Any** | | +| [DisCatSharp](https://github.com/Aiko-IT-Systems/DisCatSharp) | .NET | DisCatSharp | Only prior v10.4.1 | +| [Nomia](https://github.com/DHCPCD9/Nomia) | .NET | DSharpPlus | | +| [Lavalink4NET](https://github.com/angelobreuer/Lavalink4NET) | .NET | Discord.Net/DSharpPlus | < v4 | +| [DisGoLink](https://github.com/disgoorg/disgolink) | Go | **Any** | | + +
+ +Or alternatively, you can create your own client library, following the [implementation documentation](api/index.md). +Any client libraries marked with `Unmaintained` have been marked as such as their repositories have not received any commits for at least 1 year since time of checking, +however they are listed as they may still support Lavalink, and/or have not needed maintenance, however keep in mind that compatibility and full feature support is not guaranteed. diff --git a/docs/configuration/binary.md b/docs/configuration/binary.md new file mode 100644 index 000000000..9ebe74257 --- /dev/null +++ b/docs/configuration/binary.md @@ -0,0 +1,12 @@ +--- +description: How to run Lavalink as a standalone binary +--- + +# Standalone Binary + +Download binaries from the [Download Server](https://repo.arbjerg.dev/artifacts/lavalink/), [GitHub releases](https://github.com/lavalink-devs/Lavalink/releases) (specific versions prior to `v3.5` can be found in the [CI Server](https://ci.fredboat.com/viewLog.html?buildId=lastSuccessful&buildTypeId=Lavalink_Build&tab=artifacts&guest=1)) +or [GitHub actions](https://github.com/lavalink-devs/Lavalink/actions). + +Put an `application.yml` file in your working directory. ([Example here](index.md#example-applicationyml)) + +Run with `java -jar Lavalink.jar` from the same directory diff --git a/docs/configuration/docker.md b/docs/configuration/docker.md new file mode 100644 index 000000000..5f4284c2f --- /dev/null +++ b/docs/configuration/docker.md @@ -0,0 +1,54 @@ +--- +description: How to run Lavalink as a Docker container +--- + +# Docker + +Docker images can be found under [packages](https://github.com/lavalink-devs/Lavalink/pkgs/container/lavalink) with old builds prior to `v3.7.4` being available on [Docker Hub](https://hub.docker.com/r/fredboat/lavalink/). +There are 2 image variants `Ubuntu` and `Alpine`, the `Alpine` variant is smaller and can be used with the `-alpine` suffix, for example `ghcr.io/lavalink-devs/lavalink:3-alpine`. + +Install [Docker](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) + +Create a `docker-compose.yml` with the following content: + +```yaml title="docker-compose.yml" +version: "3.8" + +services: + lavalink: + # pin the image version to Lavalink v4 + image: ghcr.io/lavalink-devs/lavalink:4 + container_name: lavalink + restart: unless-stopped + environment: + # set Java options here + - _JAVA_OPTIONS=-Xmx6G + # set lavalink server port + - SERVER_PORT=2333 + # set password for lavalink + - LAVALINK_SERVER_PASSWORD=youshallnotpass + volumes: + # mount application.yml from the same directory or use environment variables + - ./application.yml:/opt/Lavalink/application.yml + # persist plugins between restarts, make sure to set the correct permissions (user: 322, group: 322) + - ./plugins/:/opt/Lavalink/plugins/ + networks: + - lavalink + expose: + # lavalink exposes port 2333 to connect to for other containers (this is for documentation purposes only) + - 2333 + ports: + # you only need this if you want to make your lavalink accessible from outside of containers + - "2333:2333" +networks: + # create a lavalink network you can add other containers to, to give them access to Lavalink + lavalink: + name: lavalink +``` + +Create an `application.yml` file in the same directory as the `docker-compose.yml` file. ([Example here](index.md#example-applicationyml)) or use environment variables ([Example here](index.md#example-environment-variables)) + +Run `docker compose up -d`. See [Docker Compose Up](https://docs.docker.com/engine/reference/commandline/compose_up/) + +If your bot also runs in a docker container you can make that container join the lavalink network and use `lavalink` (service name) as the hostname to connect. +See [Docker Networking](https://docs.docker.com/network/) & [Docker Compose Networking](https://docs.docker.com/compose/networking/) diff --git a/docs/configuration/index.md b/docs/configuration/index.md new file mode 100644 index 000000000..91745d799 --- /dev/null +++ b/docs/configuration/index.md @@ -0,0 +1,115 @@ +--- +description: How to configure Lavalink +--- + +# Configuration + +The server configuration is done in `application.yml`. You can find an example below. + +## Example application.yml + +
+application.yml + +```yaml title="application.yml" +--8<-- "LavalinkServer/application.yml.example" +``` + +
+ +Alternatively, you can also use environment variables to configure the server. The environment variables are named the same as the keys in the `application.yml` file, but in uppercase and with `.` replaced with `_`. For example, `server.port` becomes `SERVER_PORT`. +For arrays, the index is appended to the key, starting at 0. For example, `LAVALINK_PLUGINS_0_DEPENDENCY` refers to the `dependency` key of the first plugin. + +## Example environment variables + +
+environment variables + +```env title="enviroment variables" +SERVER_PORT +SERVER_ADDRESS +SERVER_HTTP2_ENABLED + +LAVALINK_PLUGINS_0_DEPENDENCY +LAVALINK_PLUGINS_0_REPOSITORY + +LAVALINK_PLUGINS_1_DEPENDENCY +LAVALINK_PLUGINS_1_REPOSITORY + +LAVALINK_PLUGINS_DIR +LAVALINK_DEFAULT_PLUGIN_REPOSITORY +LAVALINK_DEFAULT_PLUGIN_SNAPSHOT_REPOSITORY + +LAVALINK_SERVER_PASSWORD +LAVALINK_SERVER_SOURCES_YOUTUBE +LAVALINK_SERVER_SOURCES_BANDCAMP +LAVALINK_SERVER_SOURCES_SOUNDCLOUD +LAVALINK_SERVER_SOURCES_TWITCH +LAVALINK_SERVER_SOURCES_VIMEO +LAVALINK_SERVER_SOURCES_HTTP +LAVALINK_SERVER_SOURCES_LOCAL + +LAVALINK_SERVER_FILTERS_VOLUME +LAVALINK_SERVER_FILTERS_EQUALIZER +LAVALINK_SERVER_FILTERS_KARAOKE +LAVALINK_SERVER_FILTERS_TIMESCALE +LAVALINK_SERVER_FILTERS_TREMOLO +LAVALINK_SERVER_FILTERS_VIBRATO +LAVALINK_SERVER_FILTERS_DISTORTION +LAVALINK_SERVER_FILTERS_ROTATION +LAVALINK_SERVER_FILTERS_CHANNEL_MIX +LAVALINK_SERVER_FILTERS_LOW_PASS + +LAVALINK_SERVER_BUFFER_DURATION_MS +LAVALINK_SERVER_FRAME_BUFFER_DURATION_MS +LAVALINK_SERVER_OPUS_ENCODING_QUALITY +LAVALINK_SERVER_RESAMPLING_QUALITY +LAVALINK_SERVER_TRACK_STUCK_THRESHOLD_MS +LAVALINK_SERVER_USE_SEEK_GHOSTING + +LAVALINK_SERVER_PLAYER_UPDATE_INTERVAL +LAVALINK_SERVER_YOUTUBE_SEARCH_ENABLED +LAVALINK_SERVER_SOUNDCLOUD_SEARCH_ENABLED + +LAVALINK_SERVER_GC_WARNINGS + +LAVALINK_SERVER_RATELIMIT_IP_BLOCKS +LAVALINK_SERVER_RATELIMIT_EXCLUDE_IPS +LAVALINK_SERVER_RATELIMIT_STRATEGY +LAVALINK_SERVER_RATELIMIT_SEARCH_TRIGGERS_FAIK +LAVALINK_SERVER_RATELIMIT_RETRY_LIMIT + +LAVALINK_SERVER_YOUTUBE_CONFIG_EMAIL +LAVALINK_SERVER_YOUTUBE_CONFIG_PASSWORD + +LAVALINK_SERVER_HTTP_CONFIG_PROXY_HOST +LAVALINK_SERVER_HTTP_CONFIG_PROXY_PORT +LAVALINK_SERVER_HTTP_CONFIG_PROXY_USER +LAVALINK_SERVER_HTTP_CONFIG_PROXY_PASSWORD + +METRICS_PROMETHEUS_ENABLED +METRICS_PROMETHEUS_ENDPOINT + +SENTRY_DSN +SENTRY_ENVIRONMENT +SENTRY_TAGS_SOME_KEY +SENTRY_TAGS_ANOTHER_KEY + +LOGGING_FILE_PATH +LOGGING_LEVEL_ROOT +LOGGING_LEVEL_LAVALINK + +LOGGING_REQUEST_ENABLED +LOGGING_REQUEST_INCLUDE_CLIENT_INFO +LOGGING_REQUEST_INCLUDE_HEADERS +LOGGING_REQUEST_INCLUDE_QUERY_STRING +LOGGING_REQUEST_INCLUDE_PAYLOAD +LOGGING_REQUEST_MAX_PAYLOAD_LENGTH + +LOGGING_LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE +LOGGING_LOGBACK_ROLLINGPOLICY_MAX_HISTORY +``` + +
+ +You can also use a combination of both. Environment variables take precedence over the `application.yml` file. diff --git a/docs/configuration/systemd.md b/docs/configuration/systemd.md new file mode 100644 index 000000000..da0cf695b --- /dev/null +++ b/docs/configuration/systemd.md @@ -0,0 +1,52 @@ +--- +description: How to run Lavalink as a Systemd service +--- + +# Systemd Service + +If you're using a Systemd-based Linux distribution you may want to install Lavalink as a background service. You will need to create a `lavalink.service` file inside `/usr/lib/systemd/system`. Create the file with the following template (replacing the values inside the `<>` brackets): + +```ini title="lavalink.service" +[Unit] +# Describe the service +Description=Lavalink Service + +# Configure service order +After=syslog.target network.target + +[Service] +# The user which will run Lavalink +User= + +# The group which will run Lavalink +Group= + +# Where the program should start +WorkingDirectory= + +# The command to start Lavalink +ExecStart=java -Xmx4G -jar /Lavalink.jar + +# Restart the service if it crashes +Restart=on-failure + +# Delay each restart by 5s +RestartSec=5s + +[Install] +# Start this service as part of normal system start-up +WantedBy=multi-user.target +``` + +To initiate the service, run + +```shell +$ sudo systemctl daemon-reload +$ sudo systemctl enable lavalink +$ sudo systemctl start lavalink +``` + +In addition to the usual log files, you can also view the log with +```shell +$ sudo journalctl -u lavalink +``` \ No newline at end of file diff --git a/docs/docker/Dockerfile b/docs/docker/Dockerfile new file mode 100644 index 000000000..faea375a7 --- /dev/null +++ b/docs/docker/Dockerfile @@ -0,0 +1,9 @@ +FROM squidfunk/mkdocs-material + +COPY requirements.txt /tmp/requirements.txt + +RUN pip install --no-cache-dir -r /tmp/requirements.txt + +# Start development server by default +ENTRYPOINT ["mkdocs"] +CMD ["serve", "--dev-addr=0.0.0.0:8000"] diff --git a/docs/docker/docker-compose.yml b/docs/docker/docker-compose.yml new file mode 100644 index 000000000..945c66c2a --- /dev/null +++ b/docs/docker/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.9' + +services: + mkdocs: + build: + context: ../../ + dockerfile: docs/docker/Dockerfile + container_name: mkdocs + restart: unless-stopped + ports: + - "8000:8000" + volumes: + - ../../:/docs/ + environment: + - TZ=Europe/Berlin diff --git a/docs/getting-started/faq.md b/docs/getting-started/faq.md new file mode 100644 index 000000000..8179ae8b7 --- /dev/null +++ b/docs/getting-started/faq.md @@ -0,0 +1,46 @@ +--- +description: Lavalink frequently asked questions. +--- + +# FAQ + +## What is Lavalink? + +Lavalink is a standalone audio player node that is used to stream music to Discord voice servers. It is written in Java and is based on [lavaplayer](https://github.com/lavalink-devs/lavaplayer) and [koe](https://github.com/KyokoBot/koe). + +## What is Lavalink used for? + +Lavalink is used to stream music to Discord voice servers. It is used by many Discord music bots, including [FredBoat](https://fredboat.com) and many others. + +## How do I install Lavalink? + +See the [Getting Started](index.md) for instructions on how to install Lavalink. + +## How do I configure Lavalink? + +See the [Configuration](../configuration/index.md) page for instructions on how to configure Lavalink. + +## How do I connect to Lavalink? + +See the [Clients](../clients.md) page for a list of clients that can connect to Lavalink. Each client has its own instructions on how to connect to Lavalink. + +## How do I run Lavalink in the background? + +See the [Docker](../configuration/docker.md) or [Systemd](../configuration/systemd.md) configuration pages for instructions on how to run Lavalink in the background. + +## How do I update Lavalink? + +Updating Lavalink is as simple as downloading the latest `Lavalink.jar` from [GitHub](https://github.com/lavalink-devs/Lavalink/releases/latest) and replacing the old jar file with the new one. +When using Docker, you can simply pull the latest image from [GitHub Container Registry](https://github.com/lavalink-devs/Lavalink/pkgs/container/lavalink). + +## How do I report a bug? + +Open an issue on the [issue tracker](https://github.com/lavalink-devs/Lavalink/issues/new?labels=bug&template=bug_report.md). + +## How do I get help? + +Join the [Lavalink support Discord]({{ discord_help }}) or open a [GitHub discussion](https://github.com/lavalink-devs/Lavalink/discussions/new?category=q-a). + +## How do I get support for a client? + +Open an issue on the client's GitHub repository or join the client's support Discord. The [Lavalink support Discord]({{ discord }}) also has a channel for each client where you can get support. \ No newline at end of file diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md new file mode 100644 index 000000000..d10319171 --- /dev/null +++ b/docs/getting-started/index.md @@ -0,0 +1,33 @@ +--- +description: Lavalink getting started guide. +--- + +# Getting Started + +Welcome to the Lavalink Getting Started guide. If you're new to Lavalink, follow these steps to get started: + +## Prerequisites + +Install Java 17 or higher. You can download it [here](https://www.azul.com/downloads/?package=jdk#zulu). + +## Installation + +Download the latest `Lavalink.jar` from [GitHub](https://github.com/lavalink-devs/Lavalink/releases/latest). + +## Configuration + +Check out the [configuration](../configuration/index.md) page to learn how to configure Lavalink. + +## Running Lavalink + +Run Lavalink with `java -jar Lavalink.jar`. + +If you want to keep Lavalink running in the background, you can check out the [Docker](../configuration/docker.md) or [Systemd](../configuration/systemd.md) configuration pages. + +## Connecting to Lavalink + +Pick a client from the [clients](../clients.md) page and follow their instructions on how to connect to Lavalink. + +## Getting stuck? + +If you're stuck, you can join the [Lavalink support Discord]({{ discord_help }}) or open a [GitHub discussion](https://github.com/lavalink-devs/Lavalink/discussions/new?category=q-a) for help or questions. diff --git a/docs/getting-started/troubleshooting.md b/docs/getting-started/troubleshooting.md new file mode 100644 index 000000000..c92f29a57 --- /dev/null +++ b/docs/getting-started/troubleshooting.md @@ -0,0 +1,55 @@ +--- +description: Lavalink troubleshooting steps. +--- + +# Trouble Shooting + +## Lavalink won't start + +If Lavalink won't start, check the following: + +- Make sure you have Java 17 or higher installed. You can download it [here](https://www.azul.com/downloads/?package=jdk#zulu). + +- Make sure you have downloaded the latest `Lavalink.jar` from [GitHub](https://github.com/lavalink-devs/Lavalink/releases/latest). + +- Make sure you have configured Lavalink correctly. Check out the [configuration](../configuration/index.md) page for more information. + +- If you're using Docker, make sure you have configured Docker correctly. + Check out the [Docker](../configuration/docker.md) page for more information. + +- If you're using Systemd, make sure you have configured Systemd correctly. + Check out the [Systemd](../configuration/systemd.md) page for more information. + +- If you are using a firewall, make sure you have opened the port you configured Lavalink to use. + +- If you are using a reverse proxy, make sure you have configured it correctly. Nginx needs to be configured to pass the `Upgrade` header for WebSockets to work. + +## Configuring more detailed Logging + +If you are having issues with Lavalink, you can enable more detailed logging by adding the following to your `application.yml`: + +In general there are 6 log levels: `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR` and `OFF`. + + +```yaml title="application.yml" +logging: + level: + # Set this to DEBUG to enable more detailed logging. Please note that this will log probably spam your console. + root: INFO + # Set this to DEBUG to enable more detailed logging from Lavalink + lavalink: DEBUG + # Set this to TRACE to see all WebSocket messages + lavalink.server.io.SocketContext: TRACE + + # This will log all requests to the REST API + request: + enabled: true + includeClientInfo: true + includeHeaders: false + includeQueryString: true + includePayload: true +``` + +## Lavalink won't connect to Discord / Play Audio + +If Lavalink doesn't connect to Discord, make sure you forward the `sessionId`, `token` and `enpoint` to Lavalink via the [player update endpoint](../api/rest.md#update-player). diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..fc5f0491d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,60 @@ +--- +template: home.html +title: Home +description: Standalone audio sending node based on Lavaplayer. +hide: + - footer + - navigation + - navigation.tabs + - toc + - path +--- + +## Features + +::cards:: + +- title: Powered by Lavaplayer + icon: ':material-music:' + url: https://github.com/lavalink-devs/lavaplayer +- title: Minimal CPU/memory footprint + icon: ':octicons-cpu-16:' +- title: Twitch/YouTube stream support + icon: ':material-youtube:' +- title: Event system + icon: ':fontawesome-solid-right-left:' + url: api/websocket.md +- title: Seeking + icon: ':material-fast-forward-10:' + url: api/rest.md#update-player +- title: Volume control + icon: ':material-volume-high:' + url: api/rest.md#update-player +- title: Full REST API + icon: ':material-api:' + url: api/rest.md +- title: Statistics + icon: ':octicons-graph-16:' + url: api/rest.md#get-lavalink-stats +- title: Basic authentication + icon: ':material-lock:' + url: api/rest.md +- title: Prometheus metrics + icon: ':simple-prometheus:' + url: https://prometheus.io/ +- title: Docker images + icon: ':simple-docker:' + url: configuration/docker.md +- title: Plugin support + icon: ':material-power-plug-outline:' + url: plugins.md + +::/cards:: + +## Found a Bug? + +If you found a bug, please report it on the [issue tracker](https://github.com/lavalink-devs/Lavalink/issues/new?labels=bug&template=bug_report.md). + +## Need Help? + +Join the [Lavalink support Discord]({{ discord_help }}) or open a [GitHub discussion](https://github.com/lavalink-devs/Lavalink/discussions/new?category=q-a) for help or questions. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml new file mode 100644 index 000000000..17d70d029 --- /dev/null +++ b/docs/mkdocs.yml @@ -0,0 +1,127 @@ +# yaml-language-server: $schema=https://squidfunk.github.io/mkdocs-material/schema.json + +site_name: Lavalink Docs +site_description: Lavalink Documentation +site_author: Lavalink Contributors +site_url: https://lavalink.dev +site_dir: ../site +docs_dir: . + +repo_name: Lavalink +repo_url: https://github.com/lavalink-devs/Lavalink +edit_uri: edit/master/docs/ + +copyright: Licensed under the MIT license + +nav: + - Home: index.md + - Getting Started: + - getting-started/index.md + - Troubleshooting: getting-started/troubleshooting.md + - FAQ: getting-started/faq.md + - Configuration: + - configuration/index.md + - Binary: configuration/binary.md + - Systemd: configuration/systemd.md + - Docker: configuration/docker.md + - Clients: clients.md + - Plugins: plugins.md + - API: + - api/index.md + - Websocket: api/websocket.md + - Rest: api/rest.md + - Plugins: api/plugins.md + - Changelog: + - changelog/index.md + - v4: changelog/v4.md + - v3: changelog/v3.md + - v2: changelog/v2.md + +extra_css: + - stylesheets/style.css + - stylesheets/neoteroi-cards.css + +extra: + homepage: / + discord: https://discord.gg/BTHvsc7WsT + discord_help: https://discord.gg/ZW4s47Ppw4 + social: + - icon: fontawesome/brands/github + link: https://github.com/lavalink-devs + - icon: fontawesome/brands/discord + link: https://discord.gg/BTHvsc7WsT + +theme: + name: material + custom_dir: overrides + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + primary: custom + accent: custom + toggle: + icon: material/brightness-7 + name: Switch to dark mode + + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: custom + accent: custom + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.instant + - navigation.tracking + - navigation.tabs + - navigation.top + - navigation.tabs.sticky + - navigation.footer + - navigation.path + - navigation.indexes + - toc.follow + - content.code.annotate + - announce.dismiss + font: + text: Roboto + code: Roboto Mono + favicon: assets/favicon.png + logo: assets/logo.svg + icon: + repo: fontawesome/brands/github + +markdown_extensions: + - admonition + - meta + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight + - footnotes + - def_list + - attr_list + - md_in_html + - toc: + permalink: true + - pymdownx.tasklist: + custom_checkbox: true + - pymdownx.tabbed: + alternate_style: true + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + - pymdownx.snippets: + check_paths: true + base_path: ../ + - neoteroi.cards + +plugins: + - offline + - search: + lang: en + - same-dir + - social: + cards_layout_options: + background_color: "#ff624a" + color: "#FFFFFF" + - git-revision-date-localized + - markdownextradata diff --git a/docs/overrides/home.html b/docs/overrides/home.html new file mode 100644 index 000000000..db0525ebe --- /dev/null +++ b/docs/overrides/home.html @@ -0,0 +1,32 @@ +{% extends "main.html" %} +{% block tabs %} +{{ super() }} + +
+
+
+
+
+
+ +
+
+ {{ page.content }} +
+
+
+
+{% endblock %} +{% block content %} +{% endblock %} +{% block footer %} +{{ super() }} +{% endblock %} + diff --git a/docs/overrides/main.html b/docs/overrides/main.html new file mode 100644 index 000000000..af7d54ba8 --- /dev/null +++ b/docs/overrides/main.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} + +{% block announce %} +The Lavalink docs are currently a work in progress. You can give us feedback on GitHub +{% endblock %} \ No newline at end of file diff --git a/docs/plugins.md b/docs/plugins.md new file mode 100644 index 000000000..4ea709419 --- /dev/null +++ b/docs/plugins.md @@ -0,0 +1,24 @@ +--- +description: A list of plugins for Lavalink. +--- + +# Plugins + +Lavalink supports third-party plugins to add additional functionality such as custom audio sources, custom filters, +WebSocket handling, REST endpoints, and much more. + +Lavalink loads all .jar files placed in the `plugins` directory, which you may need to create yourself. Lavalink can +also download plugin .jar files automatically by editing the configuration file. See the respective plugin repository +for instructions. + +| Plugin | Description | +|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| +| [Google Cloud TTS plugin](https://github.com/DuncteBot/tts-plugin) | A text to speech plugin using the [google cloud tts api](https://cloud.google.com/text-to-speech/docs) | +| [SponsorBlock plugin](https://github.com/topi314/Sponsorblock-Plugin) | Skip sponsor segments in YouTube videos & return YouTube video chapter information | +| [LavaSrc plugin](https://github.com/topi314/LavaSrc) | Spotify, Apple Music & Deezer(native play) support | +| [LavaSearch plugin](https://github.com/topi314/LavaSearch) | Advanced search functionality including playlists, albums, artists, tracks & terms | +| [DuncteBot plugin](https://github.com/DuncteBot/skybot-lavalink-plugin) | Additional source managers that are not widely used | +| [Extra Filter plugin](https://github.com/rohank05/lavalink-filter-plugin) | Additional audio filters for lavalink | +| [XM plugin](https://github.com/esmBot/lava-xm-plugin) | Support for various [music tracker module](https://en.wikipedia.org/wiki/Module_file) formats | + +If you want to make your own plugin see [here](api/plugins.md) \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 000000000..c29c2bb64 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,9 @@ +mkdocs +mkdocs-material +mkdocs-material-extensions +mkdocs-git-revision-date-localized-plugin +pillow +cairosvg +neoteroi-mkdocs +mkdocs-same-dir +mkdocs-markdownextradata-plugin \ No newline at end of file diff --git a/docs/stylesheets/neoteroi-cards.css b/docs/stylesheets/neoteroi-cards.css new file mode 100644 index 000000000..13cbf35ef --- /dev/null +++ b/docs/stylesheets/neoteroi-cards.css @@ -0,0 +1,76 @@ +.nt-cards.nt-grid { + display: grid; + grid-auto-columns: 1fr; + gap: 0.5rem; + max-width: 100vw; + overflow-x: auto; + padding: 1rem; +} + +.nt-cards.nt-grid.cols-2 { + grid-template-columns: repeat(2, 1fr); +} + +.nt-cards.nt-grid.cols-3 { + grid-template-columns: repeat(3, 1fr); +} + +@media only screen and (max-width: 900px) { + .nt-cards.nt-grid { + grid-template-columns: repeat(2, 1fr) !important; + } +} + +@media only screen and (max-width: 600px) { + .nt-cards.nt-grid { + grid-template-columns: repeat(1, 1fr) !important; + } +} + +.nt-card { + border-radius: 4px; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); + background-color: var(--md-typeset-kbd-color); +} + +.nt-card:hover { + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.24), 0 3px 1px -2px rgba(0, 0, 0, 0.3), 0 1px 5px 0 rgba(0, 0, 0, 0.22); +} + +.nt-card-wrap > div, +.nt-card > a > div { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + padding: .625em; + border-radius: 4px; +} + +.nt-card > a > div:hover { + background-color: var(--md-typeset-kbd-color); +} + +.nt-card-content { + width: 100%; +} + +.nt-card-title { + font-weight: bold; + margin: 4px 0 8px 0; + text-align: center; + color: var(--md-default-fg-color); +} + +.nt-card-icon { + color: var(--md-default-fg-color); +} + +.nt-card-icon svg, +.nt-card-icon .twemoji, +.nt-card-icon .icon { + display: block; + width: 34px !important; + height: 34px !important; + max-height: 34px !important; +} diff --git a/docs/stylesheets/style.css b/docs/stylesheets/style.css new file mode 100644 index 000000000..e3fd47d9e --- /dev/null +++ b/docs/stylesheets/style.css @@ -0,0 +1,51 @@ +:root { + --md-primary-fg-color: #ff624a; + --md-primary-fg-color--light: #d39674; + --md-primary-fg-color--dark: #b25d09; + + --md-accent-fg-color: #c24734; + + @media screen { + [data-md-color-scheme="slate"] { + --md-default-fg-color: hsla(var(--md-hue), 15%, 90%, 1); + } + } +} + +.md-tabs__link { + opacity: 1; + font-weight: bold; +} + +.md-tabs__item.md-tabs__item--active { + border-bottom: 4px solid var(--md-default-fg-color); +} + +.container { + margin-top: 1rem; +} + +.container .logo { + text-align: center; +} + +.logo .md-button { + margin-bottom: 4px; +} + +#home__title { + font-size: 2rem; + font-weight: 600; + margin-bottom: 1rem; + color: unset; +} + +#home__logo { + width: 10rem; +} + +@media only screen and (max-width: 479px) { + .home__logo { + width: 6rem; + } +} \ No newline at end of file From 95217d0cdedc7a3ac9c96957c469752d90ee7080 Mon Sep 17 00:00:00 2001 From: ttmx Date: Sat, 2 Dec 2023 12:18:46 +0000 Subject: [PATCH 54/73] Change the default max heap allocation to java default (#955) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove forced Xmx on docker entrypoint * Set default readme copypastable Xmx value to 1G * Remove forced Xmx4G from alpine docker file --------- Co-authored-by: Toπ # Conflicts: # README.md --- LavalinkServer/docker/Dockerfile | 2 +- LavalinkServer/docker/alpine.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LavalinkServer/docker/Dockerfile b/LavalinkServer/docker/Dockerfile index 43a0af872..916af5e14 100644 --- a/LavalinkServer/docker/Dockerfile +++ b/LavalinkServer/docker/Dockerfile @@ -12,4 +12,4 @@ USER lavalink COPY LavalinkServer/build/libs/Lavalink.jar Lavalink.jar -ENTRYPOINT ["java", "-Djdk.tls.client.protocols=TLSv1.1,TLSv1.2", "-Xmx4G", "-jar", "Lavalink.jar"] +ENTRYPOINT ["java", "-Djdk.tls.client.protocols=TLSv1.1,TLSv1.2", "-jar", "Lavalink.jar"] diff --git a/LavalinkServer/docker/alpine.Dockerfile b/LavalinkServer/docker/alpine.Dockerfile index e24daeed2..3409b4c49 100644 --- a/LavalinkServer/docker/alpine.Dockerfile +++ b/LavalinkServer/docker/alpine.Dockerfile @@ -14,4 +14,4 @@ USER lavalink COPY LavalinkServer/build/libs/Lavalink-musl.jar Lavalink.jar -ENTRYPOINT ["java", "-Djdk.tls.client.protocols=TLSv1.1,TLSv1.2", "-Xmx4G", "-jar", "Lavalink.jar"] +ENTRYPOINT ["java", "-Djdk.tls.client.protocols=TLSv1.1,TLSv1.2", "-jar", "Lavalink.jar"] From c2b6b09ec8db5d7418bc0cb5846fb7c7d98e0eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sat, 2 Dec 2023 13:36:52 +0100 Subject: [PATCH 55/73] allow for deserialization of plugin info into data classes (#987) * allow for deserialization of plugin info into data classes * fix unit test * fixup java access for plugin info deserialization Co-authored-by: viztea * rename deserialize to deserializePluginInfo & docs * remove unused import --------- Co-authored-by: viztea --- .../lavalink/protocol/v4/loadResult.kt | 14 ++++++++++- .../arbjerg/lavalink/protocol/v4/player.kt | 24 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/loadResult.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/loadResult.kt index 59ca4f8ee..f1b902d1f 100644 --- a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/loadResult.kt +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/loadResult.kt @@ -135,7 +135,19 @@ data class Playlist( val info: PlaylistInfo, val pluginInfo: JsonObject, val tracks: List -) : LoadResult.Data +) : LoadResult.Data { + + /** + * Deserialize the plugin info into a specific type. + * This method is a convenience method meant to be used in Java, + * since Kotlin extension methods are painful to use in Java. + * + * @param deserializer The deserializer to use. (e.g. `T.Companion.serializer()`) + * + * @return the deserialized plugin info as type T + */ + fun deserializePluginInfo(deserializer: DeserializationStrategy): T = pluginInfo.deserialize(deserializer) +} @Serializable data class Exception( diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/player.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/player.kt index 5cc31ac00..f76d14c84 100644 --- a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/player.kt +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/player.kt @@ -1,10 +1,18 @@ package dev.arbjerg.lavalink.protocol.v4 +import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.serializer import kotlin.jvm.JvmInline -@Serializable() +inline fun JsonObject.deserialize(): T = + deserialize(json.serializersModule.serializer()) + +fun JsonObject.deserialize(deserializer: DeserializationStrategy): T = + json.decodeFromJsonElement(deserializer, this) + +@Serializable @JvmInline value class Players(val players: List) @@ -24,7 +32,19 @@ data class Track( val encoded: String, val info: TrackInfo, val pluginInfo: JsonObject -) : LoadResult.Data +) : LoadResult.Data { + + /** + * Deserialize the plugin info into a specific type. + * This method is a convenience method meant to be used in Java, + * since Kotlin extension methods are painful to use in Java. + * + * @param deserializer The deserializer to use. (e.g. `T.Companion.serializer()`) + * + * @return the deserialized plugin info as type T + */ + fun deserializePluginInfo(deserializer: DeserializationStrategy): T = pluginInfo.deserialize(deserializer) +} @Serializable @JvmInline From 3c442f31689c41fed1191c14851833524dde015f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sat, 2 Dec 2023 13:50:14 +0100 Subject: [PATCH 56/73] Allow setting user data on tracks (#983) * implement track user data * fix unit tests and add Track#copyWithUserData * remove unnecessary exceptionally * use loadItemSync instead of loadItem in player rest handler * Update protocol/src/commonTest/kotlin/PlayerSerializerTest.kt Co-authored-by: Duncan Sterken * throw http 400 if both track and encodedTrack/identifier is set * add convenient deserializeUserData method for java --------- Co-authored-by: Duncan Sterken --- .../server/player/PlayerRestHandler.kt | 119 +++++++++++------- .../main/java/lavalink/server/util/util.kt | 2 +- .../arbjerg/lavalink/protocol/v4/player.kt | 35 +++++- .../kotlin/LoadResultSerializerTest.kt | 3 +- .../kotlin/MessageSerializerTest.kt | 12 +- .../commonTest/kotlin/PlayerSerializerTest.kt | 16 ++- 6 files changed, 129 insertions(+), 58 deletions(-) diff --git a/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt b/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt index 6bd043499..6a837dbf5 100644 --- a/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt +++ b/LavalinkServer/src/main/java/lavalink/server/player/PlayerRestHandler.kt @@ -59,8 +59,28 @@ class PlayerRestHandler( ): ResponseEntity { val context = socketContext(socketServer, sessionId) - val encodedTrack = playerUpdate.encodedTrack - if (encodedTrack is Omissible.Present && playerUpdate.identifier is Omissible.Present) { + if (playerUpdate.track.isPresent() && (playerUpdate.encodedTrack is Omissible.Present || playerUpdate.identifier is Omissible.Present)) { + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot specify both track and encodedTrack/identifier") + } + + val track = if (playerUpdate.track.isPresent()) { + playerUpdate.track + } else { + if (playerUpdate.encodedTrack is Omissible.Present || playerUpdate.identifier is Omissible.Present) { + PlayerUpdateTrack( + playerUpdate.encodedTrack, + playerUpdate.identifier + ).toOmissible() + } else { + Omissible.Omitted() + } + } + + val encodedTrack = track.ifPresent { it.encoded } ?: Omissible.Omitted() + val identifier = track.ifPresent { it.identifier } ?: Omissible.Omitted() + val userData = track.ifPresent { it.userData } ?: Omissible.Omitted() + + if (encodedTrack is Omissible.Present && identifier is Omissible.Present) { throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot specify both encodedTrack and identifier") } @@ -112,17 +132,23 @@ class PlayerRestHandler( // we handle pause differently for playing new tracks val paused = playerUpdate.paused - paused.takeIfPresent { encodedTrack is Omissible.Omitted && playerUpdate.identifier is Omissible.Omitted } + paused.takeIfPresent { encodedTrack is Omissible.Omitted && identifier is Omissible.Omitted } ?.let { player.setPause(it) } + // we handle userData differently for playing new tracks + userData.takeIfPresent { encodedTrack is Omissible.Omitted && identifier is Omissible.Omitted } + ?.let { + player.track?.userData = it + } + playerUpdate.volume.ifPresent { player.setVolume(it) } // we handle position differently for playing new tracks - playerUpdate.position.takeIfPresent { encodedTrack is Omissible.Omitted && playerUpdate.identifier is Omissible.Omitted } + playerUpdate.position.takeIfPresent { encodedTrack is Omissible.Omitted && identifier is Omissible.Omitted } ?.let { if (player.isPlaying) { player.seekTo(it) @@ -130,7 +156,7 @@ class PlayerRestHandler( } } - playerUpdate.endTime.takeIfPresent { encodedTrack is Omissible.Omitted && playerUpdate.identifier is Omissible.Omitted } + playerUpdate.endTime.takeIfPresent { encodedTrack is Omissible.Omitted && identifier is Omissible.Omitted } ?.let { endTime -> val marker = TrackMarker(endTime, TrackEndMarkerHandler(player)) player.track?.setMarker(marker) @@ -141,7 +167,7 @@ class PlayerRestHandler( SocketServer.sendPlayerUpdate(context, player) } - if (encodedTrack is Omissible.Present || playerUpdate.identifier is Omissible.Present) { + if (encodedTrack is Omissible.Present || identifier is Omissible.Present) { if (noReplace && player.track != null) { log.info("Skipping play request because of noReplace") @@ -149,64 +175,67 @@ class PlayerRestHandler( } player.setPause(if (paused is Omissible.Present) paused.value else false) - val track: AudioTrack? = if (encodedTrack is Omissible.Present) { + val newTrack: AudioTrack? = if (encodedTrack is Omissible.Present) { encodedTrack.value?.let { decodeTrack(context.audioPlayerManager, it) } } else { val trackFuture = CompletableFuture() - val identifier = playerUpdate.identifier as Omissible.Present - context.audioPlayerManager.loadItem(identifier.value, object : AudioLoadResultHandler { - override fun trackLoaded(track: AudioTrack) { - trackFuture.complete(track) - } - - override fun playlistLoaded(playlist: AudioPlaylist) { - trackFuture.completeExceptionally( - ResponseStatusException( - HttpStatus.BAD_REQUEST, - "Cannot play a playlist or search result" + context.audioPlayerManager.loadItemSync( + (identifier as Omissible.Present).value, + object : AudioLoadResultHandler { + override fun trackLoaded(track: AudioTrack) { + trackFuture.complete(track) + } + + override fun playlistLoaded(playlist: AudioPlaylist) { + trackFuture.completeExceptionally( + ResponseStatusException( + HttpStatus.BAD_REQUEST, + "Cannot play a playlist or search result" + ) ) - ) - } - - override fun noMatches() { - trackFuture.completeExceptionally( - ResponseStatusException( - HttpStatus.BAD_REQUEST, - "No matches found for identifier" + } + + override fun noMatches() { + trackFuture.completeExceptionally( + ResponseStatusException( + HttpStatus.BAD_REQUEST, + "No matches found for identifier" + ) ) - ) - } - - override fun loadFailed(exception: FriendlyException) { - trackFuture.completeExceptionally( - ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, - exception.message, - getRootCause(exception) + } + + override fun loadFailed(exception: FriendlyException) { + trackFuture.completeExceptionally( + ResponseStatusException( + HttpStatus.INTERNAL_SERVER_ERROR, + exception.message, + getRootCause(exception) + ) ) - ) - } - }) + } + }) - trackFuture.exceptionally { - throw it - }.join() + trackFuture.join() } - track?.let { + newTrack?.let { playerUpdate.position.ifPresent { position -> - track.position = position + newTrack.position = position + } + + userData.ifPresent { userData -> + newTrack.userData = userData } playerUpdate.endTime.ifPresent { endTime -> if (endTime != null) { - track.setMarker(TrackMarker(endTime, TrackEndMarkerHandler(player))) + newTrack.setMarker(TrackMarker(endTime, TrackEndMarkerHandler(player))) } } - player.play(track) + player.play(newTrack) player.provideTo(context.getMediaConnection(player)) } ?: player.stop() } diff --git a/LavalinkServer/src/main/java/lavalink/server/util/util.kt b/LavalinkServer/src/main/java/lavalink/server/util/util.kt index 4a093cd27..a3b63d39e 100644 --- a/LavalinkServer/src/main/java/lavalink/server/util/util.kt +++ b/LavalinkServer/src/main/java/lavalink/server/util/util.kt @@ -54,7 +54,7 @@ fun AudioTrack.toTrack(encoded: String, pluginInfoModifiers: List deserializePluginInfo(deserializer: DeserializationStrategy): T = pluginInfo.deserialize(deserializer) + + /** + * Deserialize the user data into a specific type. + * This method is a convenience method meant to be used in Java, + * since Kotlin extension methods are painful to use in Java. + * + * @param deserializer The deserializer to use. (e.g. `T.Companion.serializer()`) + * + * @return the deserialized user data as type T + */ + fun deserializeUserData(deserializer: DeserializationStrategy): T = userData.deserialize(deserializer) + + /** + * Copy this track with a new user data json. + * + * @param userData The new user data json. + * + * @return A copy of this track with the new user data json. + */ + fun copyWithUserData(userData: JsonObject): Track { + return copy(userData = userData) + } } @Serializable @@ -84,10 +107,20 @@ data class PlayerState( val ping: Long ) +@Serializable +data class PlayerUpdateTrack( + val encoded: Omissible = Omissible.Omitted(), + val identifier: Omissible = Omissible.Omitted(), + val userData: Omissible = Omissible.Omitted() +) + @Serializable data class PlayerUpdate( + @Deprecated("Use PlayerUpdateTrack#encoded instead", ReplaceWith("encoded")) val encodedTrack: Omissible = Omissible.Omitted(), + @Deprecated("Use PlayerUpdateTrack#identifier instead") val identifier: Omissible = Omissible.Omitted(), + val track: Omissible = Omissible.Omitted(), val position: Omissible = Omissible.Omitted(), val endTime: Omissible = Omissible.Omitted(), val volume: Omissible = Omissible.Omitted(), diff --git a/protocol/src/commonTest/kotlin/LoadResultSerializerTest.kt b/protocol/src/commonTest/kotlin/LoadResultSerializerTest.kt index c16e3ee13..af921b860 100644 --- a/protocol/src/commonTest/kotlin/LoadResultSerializerTest.kt +++ b/protocol/src/commonTest/kotlin/LoadResultSerializerTest.kt @@ -29,7 +29,8 @@ class LoadResultSerializerTest { "isrc": null, "sourceName": "youtube" }, - "pluginInfo": {} + "pluginInfo": {}, + "userData": {} }, "exception": null } diff --git a/protocol/src/commonTest/kotlin/MessageSerializerTest.kt b/protocol/src/commonTest/kotlin/MessageSerializerTest.kt index b1af3b5ce..c5c841a4b 100644 --- a/protocol/src/commonTest/kotlin/MessageSerializerTest.kt +++ b/protocol/src/commonTest/kotlin/MessageSerializerTest.kt @@ -130,7 +130,8 @@ class MessageSerializerTest { "isrc": null, "sourceName": "youtube" }, - "pluginInfo": {} + "pluginInfo": {}, + "userData": {} } } """.trimIndent() @@ -183,7 +184,8 @@ class MessageSerializerTest { "isrc": null, "sourceName": "youtube" }, - "pluginInfo": {} + "pluginInfo": {}, + "userData": {} }, "reason": "finished" } @@ -238,7 +240,8 @@ class MessageSerializerTest { "isrc": null, "sourceName": "youtube" }, - "pluginInfo": {} + "pluginInfo": {}, + "userData": {} }, "exception": { "message": "...", @@ -301,7 +304,8 @@ class MessageSerializerTest { "isrc": null, "sourceName": "youtube" }, - "pluginInfo": {} + "pluginInfo": {}, + "userData": {} }, "thresholdMs": 123456789 } diff --git a/protocol/src/commonTest/kotlin/PlayerSerializerTest.kt b/protocol/src/commonTest/kotlin/PlayerSerializerTest.kt index 8d2af63b7..f895be5e7 100644 --- a/protocol/src/commonTest/kotlin/PlayerSerializerTest.kt +++ b/protocol/src/commonTest/kotlin/PlayerSerializerTest.kt @@ -27,7 +27,8 @@ private const val json = """ "artworkUrl": null, "isrc": null }, - "pluginInfo": {} + "pluginInfo": {}, + "userData": {} }, "volume": 100, "paused": false, @@ -52,7 +53,9 @@ private const val json = """ //language=json const val updateJson = """ { - "identifier": "...", + "track": { + "identifier": "..." + }, "endTime": 0, "volume": 100, "position": 32400, @@ -112,8 +115,7 @@ class PlayerSerializerTest { val json = """{}""" test(json) { - assertIs>(encodedTrack) - assertIs>(identifier) + assertIs>(track) assertIs>(position) assertIs>(endTime) assertIs>(volume) @@ -127,7 +129,7 @@ class PlayerSerializerTest { @JsName("test3") fun `test encodedTrack and identifier exclusivity`() { //language=json - val json = """{"encodedTrack": "", "identifier": ""}""" + val json = """{"track": {"encoded": "", "identifier": ""}}""" assertFailsWith { Json.decodeFromString(json) } } @@ -136,7 +138,9 @@ class PlayerSerializerTest { @JsName("test4") fun `test update player serialization`() { test(updateJson) { - identifier shouldBe "..." + track.requirePresent { + identifier shouldBe "..." + } endTime shouldBe 0 volume shouldBe 100 position shouldBe 32400 From 526c880d6ef15798394fd3d3308ca0bc1d817559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sat, 2 Dec 2023 14:13:04 +0100 Subject: [PATCH 57/73] add docs for track user data (#984) * document track user data * Apply suggestions from code review Co-authored-by: Duncan Sterken Co-authored-by: Freya Arbjerg * readded depreacted fields --------- Co-authored-by: Duncan Sterken Co-authored-by: Freya Arbjerg --- docs/api/plugins.md | 5 +-- docs/api/rest.md | 80 +++++++++++++++++++++++++++++--------------- docs/changelog/v3.md | 5 +-- docs/changelog/v4.md | 9 ++--- docs/mkdocs.yml | 3 ++ 5 files changed, 67 insertions(+), 35 deletions(-) diff --git a/docs/api/plugins.md b/docs/api/plugins.md index eda76de6b..cf80765ce 100644 --- a/docs/api/plugins.md +++ b/docs/api/plugins.md @@ -4,8 +4,9 @@ description: Make your own plugin for Lavalink. # Make your own plugin -> **Note:** -> If your plugin is developed in Kotlin make sure you are using **Kotlin v1.8.22** +!!! info + + If your plugin is developed in Kotlin make sure you are using **Kotlin v1.8.22** Follow [these steps](https://github.com/lavalink-devs/lavalink-plugin-template#how-to-use-this-template) to set up a new Lavalink plugin diff --git a/docs/api/rest.md b/docs/api/rest.md index e2c5ecb2d..97bc5a903 100644 --- a/docs/api/rest.md +++ b/docs/api/rest.md @@ -53,11 +53,12 @@ When Lavalink encounters an error, it will respond with a JSON object containing #### Track -| Field | Type | Description | -|------------|----------------------------------|-----------------------------------------| -| encoded | string | The base64 encoded track data | -| info | [Track Info](#track-info) object | Info about the track | -| pluginInfo | object | Addition track info provided by plugins | +| Field | Type | Description | +|------------|----------------------------------|-------------------------------------------------------------------------------| +| encoded | string | The base64 encoded track data | +| info | [Track Info](#track-info) object | Info about the track | +| pluginInfo | object | Additional track info provided by plugins | +| userData | object | Additional track data provided via the [Update Player](#update-player) endpoint | #### Track Info @@ -89,7 +90,7 @@ When Lavalink encounters an error, it will respond with a JSON object containing This endpoint is used to resolve audio tracks for use with the [Update Player](#update-player) endpoint. -!!! note +!!! tip Lavalink supports searching via YouTube, YouTube Music, and Soundcloud. To search, you must prefix your identifier with `ytsearch:`, `ytmsearch:` or `scsearch:` respectively. @@ -136,7 +137,8 @@ Response: "data": { "encoded": "...", "info": { ... }, - "pluginInfo": { ... } + "pluginInfo": { ... }, + "userData": { ... } } } ``` @@ -181,7 +183,8 @@ Array of [Track](#track) objects from the search result. { "encoded": "...", "info": { ... }, - "pluginInfo": { ... } + "pluginInfo": { ... }, + "userData": { ... } }, ... ] @@ -259,7 +262,8 @@ Response: "isrc": null, "sourceName": "youtube" }, - "pluginInfo": {} + "pluginInfo": { ... }, + "userData": { ... } } ``` @@ -313,7 +317,8 @@ Array of [Track](#track) objects "isrc": null, "sourceName": "youtube" }, - "pluginInfo": {} + "pluginInfo": { ... }, + "userData": { ... } }, ... ] @@ -588,7 +593,8 @@ GET /v4/sessions/{sessionId}/players "isrc": null, "sourceName": "youtube" }, - "pluginInfo": {} + "pluginInfo": { ... }, + "userData": { ... } }, "volume": 100, "paused": false, @@ -676,6 +682,10 @@ Updates or creates the player for this guild if it doesn't already exist. PATCH /v4/sessions/{sessionId}/players/{guildId}?noReplace=true ``` +!!! info + + `sessionId` in the path should be the value from the [ready op](websocket.md#ready-op). + Query Params: | Field | Type | Description | @@ -684,20 +694,33 @@ Query Params: Request: -| Field | Type | Description | -|-----------------|------------------------------------|-----------------------------------------------------------------------------------------------| -| encodedTrack? * | ?string | The base64 encoded track to play. `null` stops the current track | -| identifier? * | string | The identifier of the track to play | -| position? | int | The track position in milliseconds | -| endTime? | ?int | The track end time in milliseconds (must be > 0). `null` resets this if it was set previously | -| volume? | int | The player volume, in percentage, from 0 to 1000 | -| paused? | bool | Whether the player is paused | -| filters? | [Filters](#filters) object | The new filters to apply. This will override all previously applied filters | -| voice? | [Voice State](#voice-state) object | Information required for connecting to Discord | - -> **Note** -> - \* `encodedTrack` and `identifier` are mutually exclusive. -> - `sessionId` in the path should be the value from the [ready op](websocket.md#ready-op). +| Field | Type | Description | +|--------------------|---------------------------------------------|-----------------------------------------------------------------------------------------------| +| track? | [Update Player Track](#update-player-track) | Specification for a new track to load, as well as user data to set | +| ~~encodedTrack?~~* | ?string | The base64 encoded track to play. `null` stops the current track | +| ~~identifier?~~* | string | The identifier of the track to play | +| *position*? | int | The track position in milliseconds | +| endTime? | ?int | The track end time in milliseconds (must be > 0). `null` resets this if it was set previously | +| volume? | int | The player volume, in percentage, from 0 to 1000 | +| paused? | bool | Whether the player is paused | +| filters? | [Filters](#filters) object | The new filters to apply. This will override all previously applied filters | +| voice? | [Voice State](#voice-state) object | Information required for connecting to Discord | + +!!! info + + \* `encoded` and `identifier` are mutually exclusive and `DEPRECATED`. Use `track` instead. + +#### Update Player Track + +| Field | Type | Description | +|--------------|---------|---------------------------------------------------------------------| +| encoded?* | ?string | The base64 encoded track to play. `null` stops the current track | +| identifier?* | string | The identifier of the track to play | +| userData? | object | Additional track data to be sent back in the [Track Object](#track) | + +!!! info + + \* `encoded` and `identifier` are mutually exclusive. When `identifier` is used, Lavalink will try to resolve the identifier as a single track. An HTTP `400` error is returned when resolving a playlist, search result, or no tracks. @@ -706,8 +729,11 @@ When `identifier` is used, Lavalink will try to resolve the identifier as a sing ```yaml { - "encodedTrack": "...", - "identifier": "...", + "track": { + "encoded": "...", + "identifier": "...", + "userData": { ... } + }, "endTime": 0, "volume": 100, "position": 32400, diff --git a/docs/changelog/v3.md b/docs/changelog/v3.md index 1be1b2e34..8d4258760 100644 --- a/docs/changelog/v3.md +++ b/docs/changelog/v3.md @@ -24,8 +24,9 @@ * Fix errors when doing multiple session resumes * Update lavaplayer to `1.4.0` see [here](https://github.com/Walkyst/lavaplayer-fork/releases/tag/1.4.0) for more info -> **Note** -> Lavalink Docker images are now found in the GitHub Container Registry instead of DockerHub +!!! info + + Lavalink Docker images are now found in the GitHub Container Registry instead of DockerHub ## v3.7.4 diff --git a/docs/changelog/v4.md b/docs/changelog/v4.md index b877503d3..cd7813a7b 100644 --- a/docs/changelog/v4.md +++ b/docs/changelog/v4.md @@ -30,10 +30,11 @@ * Update to the [Protocol Module](https://github.com/lavalink-devs/Lavalink/tree/master/protocol) to support Kotlin/JS * Removal of all `/v3` endpoints except `/version`. All other endpoints are now under `/v4` -> **Warning** -> This is a beta release, and as such, may contain bugs. Please report any bugs you find to the [issue tracker](https://github.com/lavalink-devs/Lavalink/issues/new/choose). -> For more info on the changes in this release, see [here](../api/index.md#v370---v400) -> If you have any question regarding the changes in this release, please ask in the [support server]({{ discord_help }}) or [GitHub discussions](https://github.com/lavalink-devs/Lavalink/discussions/categories/q-a) +!!! warning + + This is a beta release, and as such, may contain bugs. Please report any bugs you find to the [issue tracker](https://github.com/lavalink-devs/Lavalink/issues/new/choose). + For more info on the changes in this release, see [here](../api/index.md#v370---v400) + If you have any question regarding the changes in this release, please ask in the [support server]({{ discord_help }}) or [GitHub discussions](https://github.com/lavalink-devs/Lavalink/discussions/categories/q-a) Contributors: [@topi314](https://github.com/topi314), [@freyacodes](https://github.com/freyacodes), [@DRSchlaubi](https://github.com/DRSchlaubi) and [@melike2d](https://github.com/melike2d) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 17d70d029..7214bf763 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -96,6 +96,9 @@ markdown_extensions: - pymdownx.details - pymdownx.superfences - pymdownx.highlight + - pymdownx.caret + - pymdownx.mark + - pymdownx.tilde - footnotes - def_list - attr_list From bd3a25dcc924a7fb7ad5a023c15e6a8350c7554e Mon Sep 17 00:00:00 2001 From: Freya Arbjerg Date: Sat, 2 Dec 2023 14:16:51 +0100 Subject: [PATCH 58/73] Fix typo in field name --- docs/api/rest.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/rest.md b/docs/api/rest.md index 97bc5a903..72d3f9722 100644 --- a/docs/api/rest.md +++ b/docs/api/rest.md @@ -708,7 +708,7 @@ Request: !!! info - \* `encoded` and `identifier` are mutually exclusive and `DEPRECATED`. Use `track` instead. + \* `encodedTrack` and `identifier` are mutually exclusive and deprecated. Use `track` instead. #### Update Player Track From 9e330997916506db009b76c000eab511c4f9cd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sat, 2 Dec 2023 23:26:19 +0100 Subject: [PATCH 59/73] update docker ubuntu from 20 to 22 --- LavalinkServer/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LavalinkServer/docker/Dockerfile b/LavalinkServer/docker/Dockerfile index 916af5e14..b48cf6bc5 100644 --- a/LavalinkServer/docker/Dockerfile +++ b/LavalinkServer/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:18-jre-focal +FROM eclipse-temurin:18-jre-jammy # Run as non-root user RUN groupadd -g 322 lavalink && \ From 8bae18ef0555e8199be65b0e000dcdc72aa37eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 13:08:27 +0100 Subject: [PATCH 60/73] exclude old lava-common version --- LavalinkServer/build.gradle.kts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/LavalinkServer/build.gradle.kts b/LavalinkServer/build.gradle.kts index 7d809c7e3..c4d3f9649 100644 --- a/LavalinkServer/build.gradle.kts +++ b/LavalinkServer/build.gradle.kts @@ -54,7 +54,9 @@ dependencies { implementation(libs.koe.udpqueue) { exclude(module="udp-queue") } - implementation(libs.bundles.udpqueue.natives) + implementation(libs.bundles.udpqueue.natives) { + exclude(group = "com.sedmelluq", module = "lava-common") + } implementation(libs.lavaplayer) implementation(libs.lavaplayer.ip.rotator) From 2671e026365aaf3ed062967ea905c8404b4e6c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 13:11:47 +0100 Subject: [PATCH 61/73] update lavaplayer to 2.0.4 --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index ab216aa19..459f9affe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,7 +36,7 @@ fun VersionCatalogBuilder.spring() { } fun VersionCatalogBuilder.voice() { - version("lavaplayer", "2.0.3") + version("lavaplayer", "2.0.4") library("lavaplayer", "dev.arbjerg", "lavaplayer").versionRef("lavaplayer") library("lavaplayer-ip-rotator", "dev.arbjerg", "lavaplayer-ext-youtube-rotator").versionRef("lavaplayer") From 2b95fcf796107b115bf279ccc5e186f49c981b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 13:18:54 +0100 Subject: [PATCH 62/73] update repo link to repo.lavalink.dev --- docs/configuration/binary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/binary.md b/docs/configuration/binary.md index 9ebe74257..9bee2f5f1 100644 --- a/docs/configuration/binary.md +++ b/docs/configuration/binary.md @@ -4,7 +4,7 @@ description: How to run Lavalink as a standalone binary # Standalone Binary -Download binaries from the [Download Server](https://repo.arbjerg.dev/artifacts/lavalink/), [GitHub releases](https://github.com/lavalink-devs/Lavalink/releases) (specific versions prior to `v3.5` can be found in the [CI Server](https://ci.fredboat.com/viewLog.html?buildId=lastSuccessful&buildTypeId=Lavalink_Build&tab=artifacts&guest=1)) +Download binaries from the [Download Server](https://repo.lavalink.dev/artifacts/lavalink/), [GitHub releases](https://github.com/lavalink-devs/Lavalink/releases) (specific versions prior to `v3.5` can be found in the [CI Server](https://ci.fredboat.com/viewLog.html?buildId=lastSuccessful&buildTypeId=Lavalink_Build&tab=artifacts&guest=1)) or [GitHub actions](https://github.com/lavalink-devs/Lavalink/actions). Put an `application.yml` file in your working directory. ([Example here](index.md#example-applicationyml)) From a93cfbad2732af6ca1e0a2b92bb244f9285199de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 13:39:21 +0100 Subject: [PATCH 63/73] update changelog --- CHANGELOG.md | 21 +++++++++++++++++++++ docs/changelog/v3.md | 3 +++ docs/changelog/v4.md | 15 +++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78fa3df62..2366a4264 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,19 @@ Each release usually includes various fixes and improvements. The most noteworthy of these, as well as any features and breaking changes, are listed here. +## 4.0.0 +* Fix NPE when omitting plugin repository +* Allow setting user data on tracks in the REST API. For more info see [here](https://lavalink.dev/api/rest.html#update-player-track) +* Update to Koe [`2.0.0-rc2`](https://github.com/KyokoBot/koe/releases/tag/2.0.0-rc2) +* Update lavaplayer to [`2.0.4`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.4) +* Enable request logging by default +* Update docker ubuntu base image from focal(`20`) to jammy(`22`) +* Remove default 4GB max heap allocation from docker image + +> [!WARNING] +> Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. +> On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker). + ## 4.0.0-beta.5 * Update lavaplayer to [`2.0.3`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Fixed YouTube access token errors * Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](https://github.com/lavalink-devs/Lavalink/blob/master/PLUGINS.md#distributing-your-plugin) @@ -39,6 +52,14 @@ The most noteworthy of these, as well as any features and breaking changes, are Contributors: [@topi314](https://github.com/topi314), [@freyacodes](https://github.com/freyacodes), [@DRSchlaubi](https://github.com/DRSchlaubi) and [@melike2d](https://github.com/melike2d) +## v3.7.10 +* Update lavaplayer to [`1.5.2`](https://github.com/lavalink-devs/lavaplayer/releases/tag/1.5.2) - Fixed NPE on missing author in playlist tracks in YouTube + +## 3.7.9 +* Update lavaplayer to [`1.5.1`](https://github.com/lavalink-devs/lavaplayer/releases/tag/1.5.1) - Fixed YouTube access token errors +* Fixed websocket crash when seeking and nothing is playing +* Fixed error when seeking and player is not playing anything + ## 3.7.8 * Fix YouTube 403 errors * Fix YouTube access token errors diff --git a/docs/changelog/v3.md b/docs/changelog/v3.md index 8d4258760..33e635fa5 100644 --- a/docs/changelog/v3.md +++ b/docs/changelog/v3.md @@ -1,3 +1,6 @@ +## v3.7.10 +* Update lavaplayer to [`1.5.2`](https://github.com/lavalink-devs/lavaplayer/releases/tag/1.5.2) - Fixed NPE on missing author in playlist tracks in YouTube + ## v3.7.9 * Update lavaplayer to [`1.5.1`](https://github.com/lavalink-devs/lavaplayer/releases/tag/1.5.1) - Fixed YouTube access token errors * Fixed websocket crash when seeking and nothing is playing diff --git a/docs/changelog/v4.md b/docs/changelog/v4.md index cd7813a7b..707cbb654 100644 --- a/docs/changelog/v4.md +++ b/docs/changelog/v4.md @@ -1,3 +1,18 @@ +## v4.0.0 +* Fix NPE when omitting plugin repository +* Allow setting user data on tracks in the REST API. For more info see [here](https://lavalink.dev/api/rest.html#update-player-track) +* Update to Koe [`2.0.0-rc2`](https://github.com/KyokoBot/koe/releases/tag/2.0.0-rc2) +* Update lavaplayer to [`2.0.4`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.4) +* Enable request logging by default +* Update docker ubuntu base image from focal(`20`) to jammy(`22`) +* Remove default 4GB max heap allocation from docker image + +!!! warning + + Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. + On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker). + + ## v4.0.0-beta.5 * Update lavaplayer to [`2.0.3`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Fixed YouTube access token errors * Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](../api/plugins.md#distributing-your-plugin) From 3ae0600b435d053d5f5c6e17869641b62c45ceff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 13:43:33 +0100 Subject: [PATCH 64/73] update changelog --- docs/changelog/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog/index.md b/docs/changelog/index.md index e86584f59..572a99faf 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -21,6 +21,8 @@ The most noteworthy of these, as well as any features and breaking changes, are * addition of the full [Track](#track) object in [TrackStartEvent](#trackstartevent), [TrackEndEvent](#trackendevent), [TrackExceptionEvent](#trackexceptionevent) and [TrackStuckEvent](#trackstuckevent). * updated capitalization of [Track End Reason](#track-end-reason) and [Severity](#severity) * reworked [Load Result](#track-loading-result) object +* allow setting user data on tracks in the REST API. For more info see [here](https://lavalink.dev/api/rest.html#update-player-track) + All websocket ops are removed as of `v4.0.0` and replaced with the following endpoints and json fields: From f1a0b6c9d163ead3963ce0538b53601ceb3ecade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 15:06:38 +0100 Subject: [PATCH 65/73] update changelog --- CHANGELOG.md | 21 +++++++++++++++++++-- docs/changelog/v4.md | 19 +++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2366a4264..8ec25e06c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,22 @@ Each release usually includes various fixes and improvements. The most noteworthy of these, as well as any features and breaking changes, are listed here. ## 4.0.0 -* Fix NPE when omitting plugin repository +* Lavalink now requires Java 17 or higher to run +* **Removal of all websocket messages sent by the client. Everything is now done via [REST](../api/rest.md)** +* Update Lavaplayer to [`2.0.4`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.4), which includes native support for artwork urls and ISRCs in the track info +* Addition of full `Track` objects in following events: `TrackStartEvent`, `TrackEndEvent`, `TrackExceptionEvent`, `TrackStuckEvent` +* Resuming a session now requires the `Session-Id` header instead of `Resume-Key` header +* Reworked track loading result. For more info see [here](../api/rest.md#track-loading-result) +* Update to the [Protocol Module](https://github.com/lavalink-devs/Lavalink/tree/master/protocol) to support Kotlin/JS +* Removal of all `/v3` endpoints except `/version`. All other endpoints are now under `/v4` +* Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) +* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) +* Add `Omissible#isPresent` & `Omissible#isOmitted` to the `protocol` module +* Fix null pointer when a playlist has no selected track +* Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](../api/plugins.md#distributing-your-plugin) +* Fixed error when seeking and player is not playing anything in * Allow setting user data on tracks in the REST API. For more info see [here](https://lavalink.dev/api/rest.html#update-player-track) * Update to Koe [`2.0.0-rc2`](https://github.com/KyokoBot/koe/releases/tag/2.0.0-rc2) -* Update lavaplayer to [`2.0.4`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.4) * Enable request logging by default * Update docker ubuntu base image from focal(`20`) to jammy(`22`) * Remove default 4GB max heap allocation from docker image @@ -16,6 +28,9 @@ The most noteworthy of these, as well as any features and breaking changes, are > Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. > On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker). +
+v4.0.0 - Betas + ## 4.0.0-beta.5 * Update lavaplayer to [`2.0.3`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Fixed YouTube access token errors * Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](https://github.com/lavalink-devs/Lavalink/blob/master/PLUGINS.md#distributing-your-plugin) @@ -52,6 +67,8 @@ The most noteworthy of these, as well as any features and breaking changes, are Contributors: [@topi314](https://github.com/topi314), [@freyacodes](https://github.com/freyacodes), [@DRSchlaubi](https://github.com/DRSchlaubi) and [@melike2d](https://github.com/melike2d) +
+ ## v3.7.10 * Update lavaplayer to [`1.5.2`](https://github.com/lavalink-devs/lavaplayer/releases/tag/1.5.2) - Fixed NPE on missing author in playlist tracks in YouTube diff --git a/docs/changelog/v4.md b/docs/changelog/v4.md index 707cbb654..31e19443e 100644 --- a/docs/changelog/v4.md +++ b/docs/changelog/v4.md @@ -1,8 +1,20 @@ ## v4.0.0 -* Fix NPE when omitting plugin repository +* Lavalink now requires Java 17 or higher to run +* **Removal of all websocket messages sent by the client. Everything is now done via [REST](../api/rest.md)** +* Update Lavaplayer to [`2.0.4`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.4), which includes native support for artwork urls and ISRCs in the track info +* Addition of full `Track` objects in following events: `TrackStartEvent`, `TrackEndEvent`, `TrackExceptionEvent`, `TrackStuckEvent` +* Resuming a session now requires the `Session-Id` header instead of `Resume-Key` header +* Reworked track loading result. For more info see [here](../api/rest.md#track-loading-result) +* Update to the [Protocol Module](https://github.com/lavalink-devs/Lavalink/tree/master/protocol) to support Kotlin/JS +* Removal of all `/v3` endpoints except `/version`. All other endpoints are now under `/v4` +* Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) +* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) +* Add `Omissible#isPresent` & `Omissible#isOmitted` to the `protocol` module +* Fix null pointer when a playlist has no selected track +* Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](../api/plugins.md#distributing-your-plugin) +* Fixed error when seeking and player is not playing anything in * Allow setting user data on tracks in the REST API. For more info see [here](https://lavalink.dev/api/rest.html#update-player-track) * Update to Koe [`2.0.0-rc2`](https://github.com/KyokoBot/koe/releases/tag/2.0.0-rc2) -* Update lavaplayer to [`2.0.4`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.4) * Enable request logging by default * Update docker ubuntu base image from focal(`20`) to jammy(`22`) * Remove default 4GB max heap allocation from docker image @@ -12,6 +24,8 @@ Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker). +
+v4.0.0 - Betas ## v4.0.0-beta.5 * Update lavaplayer to [`2.0.3`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.2) - Fixed YouTube access token errors @@ -54,3 +68,4 @@ Contributors: [@topi314](https://github.com/topi314), [@freyacodes](https://github.com/freyacodes), [@DRSchlaubi](https://github.com/DRSchlaubi) and [@melike2d](https://github.com/melike2d) +
From 0fd5a3398282e57562809cf372019d90d3bc9dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 15:10:57 +0100 Subject: [PATCH 66/73] allow markdown in details --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ec25e06c..e5238c60a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ The most noteworthy of these, as well as any features and breaking changes, are > Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. > On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker). -
+
v4.0.0 - Betas ## 4.0.0-beta.5 From 8fd6954ef2c2a655eaa7d5d1b583c74a312d4e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 15:17:22 +0100 Subject: [PATCH 67/73] allow markdown in details for real this time --- CHANGELOG.md | 2 +- docs/changelog/v4.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5238c60a..8ec25e06c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ The most noteworthy of these, as well as any features and breaking changes, are > Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. > On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker). -
+
v4.0.0 - Betas ## 4.0.0-beta.5 diff --git a/docs/changelog/v4.md b/docs/changelog/v4.md index 31e19443e..07334fe7c 100644 --- a/docs/changelog/v4.md +++ b/docs/changelog/v4.md @@ -24,7 +24,7 @@ Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker). -
+
v4.0.0 - Betas ## v4.0.0-beta.5 From 3732de678b6d3ed6f4f3d21132f3fb265e1428c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 15:21:36 +0100 Subject: [PATCH 68/73] reorder v4 changelog entries --- CHANGELOG.md | 22 +++++++++++----------- docs/changelog/v4.md | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ec25e06c..a5e7db6e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,23 +6,23 @@ The most noteworthy of these, as well as any features and breaking changes, are ## 4.0.0 * Lavalink now requires Java 17 or higher to run * **Removal of all websocket messages sent by the client. Everything is now done via [REST](../api/rest.md)** +* Remove default 4GB max heap allocation from docker image +* Removal of all `/v3` endpoints except `/version`. All other endpoints are now under `/v4` +* Reworked track loading result. For more info see [here](https://lavalink.dev/api/rest.md#track-loading-result) +* Update docker ubuntu base image from focal(`20`) to jammy(`22`) +* Update to Koe [`2.0.0-rc2`](https://github.com/KyokoBot/koe/releases/tag/2.0.0-rc2) * Update Lavaplayer to [`2.0.4`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.4), which includes native support for artwork urls and ISRCs in the track info +* Update to the [Protocol Module](https://github.com/lavalink-devs/Lavalink/tree/master/protocol) to support Kotlin/JS +* Allow setting user data on tracks in the REST API. For more info see [here](https://lavalink.dev/api/rest.html#update-player-track) +* Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](https://lavalink.dev/api/plugins.md#distributing-your-plugin) * Addition of full `Track` objects in following events: `TrackStartEvent`, `TrackEndEvent`, `TrackExceptionEvent`, `TrackStuckEvent` * Resuming a session now requires the `Session-Id` header instead of `Resume-Key` header -* Reworked track loading result. For more info see [here](../api/rest.md#track-loading-result) -* Update to the [Protocol Module](https://github.com/lavalink-devs/Lavalink/tree/master/protocol) to support Kotlin/JS -* Removal of all `/v3` endpoints except `/version`. All other endpoints are now under `/v4` * Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) -* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) * Add `Omissible#isPresent` & `Omissible#isOmitted` to the `protocol` module -* Fix null pointer when a playlist has no selected track -* Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](../api/plugins.md#distributing-your-plugin) -* Fixed error when seeking and player is not playing anything in -* Allow setting user data on tracks in the REST API. For more info see [here](https://lavalink.dev/api/rest.html#update-player-track) -* Update to Koe [`2.0.0-rc2`](https://github.com/KyokoBot/koe/releases/tag/2.0.0-rc2) +* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) * Enable request logging by default -* Update docker ubuntu base image from focal(`20`) to jammy(`22`) -* Remove default 4GB max heap allocation from docker image +* Fixed error when seeking and player is not playing anything in +* Fixed null pointer when a playlist has no selected track > [!WARNING] > Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. diff --git a/docs/changelog/v4.md b/docs/changelog/v4.md index 07334fe7c..1c9bffb20 100644 --- a/docs/changelog/v4.md +++ b/docs/changelog/v4.md @@ -1,23 +1,23 @@ ## v4.0.0 * Lavalink now requires Java 17 or higher to run * **Removal of all websocket messages sent by the client. Everything is now done via [REST](../api/rest.md)** +* Remove default 4GB max heap allocation from docker image +* Removal of all `/v3` endpoints except `/version`. All other endpoints are now under `/v4` +* Reworked track loading result. For more info see [here](../api/rest.md#track-loading-result) +* Update docker ubuntu base image from focal(`20`) to jammy(`22`) +* Update to Koe [`2.0.0-rc2`](https://github.com/KyokoBot/koe/releases/tag/2.0.0-rc2) * Update Lavaplayer to [`2.0.4`](https://github.com/lavalink-devs/lavaplayer/releases/tag/2.0.4), which includes native support for artwork urls and ISRCs in the track info +* Update to the [Protocol Module](https://github.com/lavalink-devs/Lavalink/tree/master/protocol) to support Kotlin/JS +* Allow setting user data on tracks in the REST API. For more info see [here](../api/rest.md#update-player-track) +* Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](../api/plugins.md#distributing-your-plugin) * Addition of full `Track` objects in following events: `TrackStartEvent`, `TrackEndEvent`, `TrackExceptionEvent`, `TrackStuckEvent` * Resuming a session now requires the `Session-Id` header instead of `Resume-Key` header -* Reworked track loading result. For more info see [here](../api/rest.md#track-loading-result) -* Update to the [Protocol Module](https://github.com/lavalink-devs/Lavalink/tree/master/protocol) to support Kotlin/JS -* Removal of all `/v3` endpoints except `/version`. All other endpoints are now under `/v4` * Add JDA-NAS support for musl (`x86-64`, `aarch64`) based systems (most notably `alpine`) -* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) * Add `Omissible#isPresent` & `Omissible#isOmitted` to the `protocol` module -* Fix null pointer when a playlist has no selected track -* Added default plugin repository. Plugin devs can now request their plugin to be added to the default repository. For more info see [here](../api/plugins.md#distributing-your-plugin) -* Fixed error when seeking and player is not playing anything in -* Allow setting user data on tracks in the REST API. For more info see [here](https://lavalink.dev/api/rest.html#update-player-track) -* Update to Koe [`2.0.0-rc2`](https://github.com/KyokoBot/koe/releases/tag/2.0.0-rc2) +* New config option to specify the directory to load plugins from. `lavalink.pluginsDir` (defaults to `./plugins`) * Enable request logging by default -* Update docker ubuntu base image from focal(`20`) to jammy(`22`) -* Remove default 4GB max heap allocation from docker image +* Fixed error when seeking and player is not playing anything in +* Fixed null pointer when a playlist has no selected track !!! warning From ea6f77291990f6ae2f7a43a52639f996b49a16b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 15:32:36 +0100 Subject: [PATCH 69/73] Update CHANGELOG.md Co-authored-by: Freya Arbjerg --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5e7db6e5..ff0ec9644 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ The most noteworthy of these, as well as any features and breaking changes, are * Fixed null pointer when a playlist has no selected track > [!WARNING] -> Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. +> Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. The default is 1GB or 25% of total memory, whichever is lower. > On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker).
From baec7f7f78e5e56f0b476ea84bc07cdd51695c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 15:35:43 +0100 Subject: [PATCH 70/73] Update CHANGELOG.md Co-authored-by: Freya Arbjerg --- docs/changelog/v4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog/v4.md b/docs/changelog/v4.md index 1c9bffb20..e7db702f5 100644 --- a/docs/changelog/v4.md +++ b/docs/changelog/v4.md @@ -21,7 +21,7 @@ !!! warning - Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. + Lavalink previously set the `-Xmx` flag to `4G` in docker. This caused issues with some systems which had less than 4GB of RAM. We have now removed this flag and let the JVM decide the max heap allocation. The default is 1GB or 25% of total memory, whichever is lower. On how to increase the max heap allocation, see [here](https://lavalink.dev/configuration/docker.html#docker).
From 678fb30d1c38caa2c3cbfa799180226e6aa58c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 15:44:23 +0100 Subject: [PATCH 71/73] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1288be1cd..21b57fc18 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ A [basic example bot](Testbot) is available. [![Lavalink Guild](https://discordapp.com/api/guilds/1082302532421943407/embed.png?style=banner2)](https://discord.gg/ZW4s47Ppw4) > [!Warning] -> Lavalink v4 is now in beta! See [the changelog](CHANGELOG.md) for more information. +> Lavalink v4 is now **out** of beta! See [the changelog](CHANGELOG.md) for more information. ## Getting started * Pick one of the [up-to-date clients](https://lavalink.dev/clients). Advanced users can create their own using the [API documentation From acc60694c712faff21f4582aa2a010293ca4634a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sun, 3 Dec 2023 15:45:17 +0100 Subject: [PATCH 72/73] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 21b57fc18..5382fb723 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A [basic example bot](Testbot) is available. [![Lavalink Guild](https://discordapp.com/api/guilds/1082302532421943407/embed.png?style=banner2)](https://discord.gg/ZW4s47Ppw4) -> [!Warning] +> [!NOTE] > Lavalink v4 is now **out** of beta! See [the changelog](CHANGELOG.md) for more information. ## Getting started From 3121f0c653bc78e9e765d7074d5cac920fc84dc7 Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Sun, 3 Dec 2023 20:27:54 +0100 Subject: [PATCH 73/73] Add java json API --- protocol/build.gradle.kts | 1 + .../lavalink/protocol/v4/utils/JsonArray.kt | 70 +++++++++++++++++ .../lavalink/protocol/v4/utils/JsonObject.kt | 78 +++++++++++++++++++ .../protocol/v4/utils/JsonPrimitive.kt | 22 ++++++ .../protocol/v4/utils/serialization.kt | 27 +++++++ protocol/src/jvmTest/java/JsonArrayTest.java | 26 +++++++ protocol/src/jvmTest/java/JsonObjectTest.java | 26 +++++++ .../src/jvmTest/java/JsonPrimitiveTest.java | 30 +++++++ 8 files changed, 280 insertions(+) create mode 100644 protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonArray.kt create mode 100644 protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonObject.kt create mode 100644 protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonPrimitive.kt create mode 100644 protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/serialization.kt create mode 100644 protocol/src/jvmTest/java/JsonArrayTest.java create mode 100644 protocol/src/jvmTest/java/JsonObjectTest.java create mode 100644 protocol/src/jvmTest/java/JsonPrimitiveTest.java diff --git a/protocol/build.gradle.kts b/protocol/build.gradle.kts index 74e2758ef..2343d352b 100644 --- a/protocol/build.gradle.kts +++ b/protocol/build.gradle.kts @@ -16,6 +16,7 @@ group = "dev.arbjerg.lavalink" kotlin { jvm { + withJava() compilations.all { kotlinOptions { jvmTarget = "17" diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonArray.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonArray.kt new file mode 100644 index 000000000..17a32588c --- /dev/null +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonArray.kt @@ -0,0 +1,70 @@ +@file:JvmName("JsonArrays") + +package dev.arbjerg.lavalink.protocol.v4.utils + +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonPrimitive +import kotlin.jvm.JvmName + +/** + * Returns an empty [JsonArray]. + */ +@get:JvmName("empty") +val EMPTY_ARRAY = JsonArray(emptyList()) + +/** + * Creates a new [JavaJsonArrayBuilder]. + */ +@JvmName("builder") +fun arrayBuilder(): JavaJsonArrayBuilder = JavaJsonArrayBuilder(mutableListOf()) + + +/** + * Json Array builder + */ +class JavaJsonArrayBuilder internal constructor(private val contents: MutableList) : + MutableList by contents { + + /** + * Adds [value]. + */ + fun add(value: String) = apply { contents.add(JsonPrimitive(value)) } + /** + * Adds [value]. + */ + fun add(value: Number) = apply { contents.add(JsonPrimitive(value)) } + /** + * Adds `null`. + */ + fun addNull() = apply { contents.add(JsonPrimitive(null)) } + + /** + * Builds and adds a new JsonObject. + */ + fun addObject() = ChildJavaJsonObjectBuilder(this, mutableMapOf()) + + fun build() = JsonArray(contents) +} + +class ChildJavaJsonArrayBuilder( + private val key: String, + private val objectBuilder: JavaJsonObjectBuilder, + private val contents: MutableList +) : MutableList by contents { + /** + * Adds [value]. + */ + fun add(value: String) = apply { contents.add(JsonPrimitive(value)) } + /** + * Adds [value]. + */ + fun add(value: Number) = apply { contents.add(JsonPrimitive(value)) } + /** + * Adds `null`. + */ + fun addNull() = apply { contents.add(JsonPrimitive(null)) } + fun build() = objectBuilder.apply { + put(key, JsonArray(this@ChildJavaJsonArrayBuilder.contents)) + } +} diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonObject.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonObject.kt new file mode 100644 index 000000000..709073069 --- /dev/null +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonObject.kt @@ -0,0 +1,78 @@ +@file:JvmName("JsonObjects") + +package dev.arbjerg.lavalink.protocol.v4.utils + +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlin.jvm.JvmName + +/** + * Returns an empty [JsonObject]. + */ +@get:JvmName("empty") +val EMPTY_OBJECT = JsonObject(emptyMap()) + +/** + * Returns a new [JavaJsonObjectBuilder]. + */ +@JvmName("builder") +fun objectBuilder(): JavaJsonObjectBuilder = JavaJsonObjectBuilder(mutableMapOf()) + + +/** + * Json object builder. + */ +class JavaJsonObjectBuilder(private val contents: MutableMap) : + MutableMap by contents { + + /** + * Puts [key] to [value]. + */ + fun put(key: String, value: String) = apply { contents[key] = JsonPrimitive(value) } + /** + * Puts [key] to [value]. + */ + fun put(key: String, value: Number) = apply { contents[key] = JsonPrimitive(value) } + /** + * Puts [key] to `null`.` + */ + fun putNull(key: String) = apply { contents[key] = JsonNull } + + /** + * Creates an array for [key]. + */ + fun putArray(key: String): ChildJavaJsonArrayBuilder = ChildJavaJsonArrayBuilder(key, this, mutableListOf()) + + /** + * Builds the object. + */ + fun build() = JsonObject(contents) +} + +class ChildJavaJsonObjectBuilder( + private val arrayBuilder: JavaJsonArrayBuilder, + private val contents: MutableMap +) : MutableMap by contents { + + /** + * Puts [key] to [value]. + */ + fun put(key: String, value: String) = apply { contents[key] = JsonPrimitive(value) } + /** + * Puts [key] to [value]. + */ + fun put(key: String, value: Number) = apply { contents[key] = JsonPrimitive(value) } + /** + * Puts [key] to `null`. + */ + fun putNull(key: String) = apply { contents[key] = JsonNull } + + /** + * Returns to the [JavaJsonObjectBuilder] + */ + fun build() = arrayBuilder.apply { + add(JsonObject(this@ChildJavaJsonObjectBuilder.contents)) + } +} diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonPrimitive.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonPrimitive.kt new file mode 100644 index 000000000..12a7a82a5 --- /dev/null +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/JsonPrimitive.kt @@ -0,0 +1,22 @@ +@file:JvmName("JsonPrimitives") + +package dev.arbjerg.lavalink.protocol.v4.utils + +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonPrimitive +import kotlin.jvm.JvmName + +/** + * Returns a Json representation of `null`. + */ +fun jsonNull() = JsonNull + +/** + * Returns the [JsonPrimitive] representing [string]. + */ +fun fromString(string: String) = JsonPrimitive(string) + +/** + * Returns the [JsonPrimitive] representing [number]. + */ +fun fromNumber(number: Number) = JsonPrimitive(number) diff --git a/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/serialization.kt b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/serialization.kt new file mode 100644 index 000000000..62cccfe22 --- /dev/null +++ b/protocol/src/commonMain/kotlin/dev/arbjerg/lavalink/protocol/v4/utils/serialization.kt @@ -0,0 +1,27 @@ +@file:JvmName("Serialization") +package dev.arbjerg.lavalink.protocol.v4.utils + +import dev.arbjerg.lavalink.protocol.v4.json +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlin.jvm.JvmName + +/** + * Serializes a [JsonElement] into a String. + */ +fun serialize(element: JsonElement) = json.encodeToString(element) + +/** + * Deserializes [source] into an [JsonElement]. + */ +fun deserializeJsonElement(source: String): JsonElement = json.decodeFromString(source) +/** + * Deserializes [source] into an [JsonObject]. + */ +fun deserializeJsonObject(source: String): JsonObject = json.decodeFromString(source) +/** + * Deserializes [source] into an [JsonArray]. + */ +fun deserializeJsonArray(source: String): JsonArray = json.decodeFromString(source) diff --git a/protocol/src/jvmTest/java/JsonArrayTest.java b/protocol/src/jvmTest/java/JsonArrayTest.java new file mode 100644 index 000000000..fbcda7db2 --- /dev/null +++ b/protocol/src/jvmTest/java/JsonArrayTest.java @@ -0,0 +1,26 @@ +import dev.arbjerg.lavalink.protocol.v4.utils.JsonArrays; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class JsonArrayTest { + @Test + public void testEmptyArray() { + Assertions.assertEquals("[]", JsonArrays.empty().toString()); + } + + @Test + public void testBuilder() { + var array = JsonArrays.builder() + .add("21") + .addNull() + .addObject() + .put("test", 21) + .build() + .build() + .toString(); + + var source = "[\"21\",null,{\"test\":21}]"; + + Assertions.assertEquals(source, array); + } +} diff --git a/protocol/src/jvmTest/java/JsonObjectTest.java b/protocol/src/jvmTest/java/JsonObjectTest.java new file mode 100644 index 000000000..69a3bfc51 --- /dev/null +++ b/protocol/src/jvmTest/java/JsonObjectTest.java @@ -0,0 +1,26 @@ +import dev.arbjerg.lavalink.protocol.v4.utils.JsonObjects; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class JsonObjectTest { + @Test + public void testBuilder() { + var obj = JsonObjects.builder() + .put("time", 42) + .putArray("children") + .add("banana_bread") + .build() + .putNull("is_null") + .build() + .toString(); + + var source = "{\"time\":42,\"children\":[\"banana_bread\"],\"is_null\":null}"; + + Assertions.assertEquals(source, obj); + } + + @Test + public void testNull() { + Assertions.assertEquals("{}", JsonObjects.empty().toString()); + } +} diff --git a/protocol/src/jvmTest/java/JsonPrimitiveTest.java b/protocol/src/jvmTest/java/JsonPrimitiveTest.java new file mode 100644 index 000000000..5718661c7 --- /dev/null +++ b/protocol/src/jvmTest/java/JsonPrimitiveTest.java @@ -0,0 +1,30 @@ +import dev.arbjerg.lavalink.protocol.v4.utils.JsonPrimitives; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class JsonPrimitiveTest { + + @Test + public void testNull() { + Assertions.assertEquals("null", JsonPrimitives.jsonNull().toString()); + } + + @Test + public void testNumber() { + testNumber(Byte.MAX_VALUE); + testNumber(Short.MAX_VALUE); + testNumber(Integer.MAX_VALUE); + testNumber(Long.MAX_VALUE); + testNumber(Float.MAX_VALUE); + testNumber(Double.MAX_VALUE); + } + + @Test + public void testString() { + Assertions.assertEquals("\"test123\"", JsonPrimitives.fromString("test123").toString()); + } + + private void testNumber(Number number) { + Assertions.assertEquals(String.valueOf(number), JsonPrimitives.fromNumber(number).toString()); + } +}