diff --git a/README.md b/README.md index 0a0b1a3c6..013528c94 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ Go to [`https://duncte.bot/invite`][inviteLink] and follow the steps on the webs While self-hosting is very much possible with Docker, please note that no support will be provided with self-hosting. The code of this bot was made public for people who want to see how the bot works or want to contribute to it. +# Used external libraries +Skybot relies on [this lib](https://github.com/sot-tech/LottieConverter/releases/tag/r0.2) for lottie conversion. # Support [![Support Server](https://discord.com/api/guilds/191245668617158656/embed.png?style=banner2)](https://duncte.bot/server) diff --git a/assets b/assets new file mode 120000 index 000000000..083280534 --- /dev/null +++ b/assets @@ -0,0 +1 @@ +bot/assets/ \ No newline at end of file diff --git a/bot/Dockerfile b/bot/Dockerfile index c4a1ca312..9315c8928 100644 --- a/bot/Dockerfile +++ b/bot/Dockerfile @@ -17,6 +17,8 @@ FROM azul/zulu-openjdk-alpine:19-jre # also add some fonts RUN apk add --no-cache libstdc++ fontconfig font-noto +COPY ./assets/lottieconverter_musl /skybot/assets/lottieconverter + WORKDIR /skybot COPY --from=builder /skybot/bot/build/libs/bot*-prod.jar ./skybot.jar diff --git a/bot/assets/lottieconverter b/bot/assets/lottieconverter new file mode 100644 index 000000000..db307c056 Binary files /dev/null and b/bot/assets/lottieconverter differ diff --git a/bot/assets/lottieconverter_musl b/bot/assets/lottieconverter_musl new file mode 100644 index 000000000..efed88eb0 Binary files /dev/null and b/bot/assets/lottieconverter_musl differ diff --git a/bot/src/main/java/ml/duncte123/skybot/commands/utils/EnlargeCommand.java b/bot/src/main/java/ml/duncte123/skybot/commands/utils/EnlargeCommand.java index ea5f08d8a..05fb1371f 100644 --- a/bot/src/main/java/ml/duncte123/skybot/commands/utils/EnlargeCommand.java +++ b/bot/src/main/java/ml/duncte123/skybot/commands/utils/EnlargeCommand.java @@ -36,6 +36,9 @@ import net.dv8tion.jda.api.utils.FileUpload; import org.jetbrains.annotations.NotNull; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.List; import static me.duncte123.botcommons.messaging.MessageUtils.sendMsg; @@ -59,12 +62,22 @@ public void execute(@NotNull CommandContext ctx) { final StickerItem sticker = stickers.get(0); final StickerFormat formatType = sticker.getFormatType(); - if (formatType == StickerFormat.UNKNOWN || formatType == StickerFormat.LOTTIE) { - sendMsg(ctx, "The sticker supplied could not be rendered"); - return; + switch (formatType) { + case GIF: + this.uploadFile(sticker.getIconUrl(), ctx); + break; + case PNG: + case APNG: + this.uploadFile(sticker.getIconUrl().replace("apng", "png"), ctx); + break; + case LOTTIE: + this.sendLottieGif(sticker.getIconUrl(), sticker.getName(), ctx); + break; + default: + sendMsg(ctx, "The sticker supplied could not be rendered"); + break; } - this.uploadFile(sticker.getIconUrl().replace("apng", "png"), ctx); return; } @@ -114,6 +127,54 @@ public void execute(@NotNull CommandContext ctx) { this.uploadFile(emojiUrl, ctx); } + // TODO: use virtual threads + private void sendLottieGif(final String lottieUrl, final String stickerName, final CommandContext ctx) { + WebUtils.ins.getText(lottieUrl, (it) -> it.setRateLimiter(RateLimiter.directLimiter())).async( + (lottieJson) -> { + try { + final var bytes = this.renderLottie(lottieJson); + + ctx.getChannel() + .sendFiles( + FileUpload.fromData(bytes, "%s.gif".formatted(stickerName)) + ) + .setMessageReference(ctx.getMessage()) + .queue(); + } catch (final IOException e) { + LOGGER.error("Failed to render lottie", e); + sendMsg(ctx, "Failed to render lottie: " + e.getMessage()); + } + }, + (error) -> { + Sentry.captureException(error); + sendMsg(ctx, "Failed to render lottie: " + error.getMessage()); + } + ); + } + + private byte[] renderLottie(final String lottieJson) throws IOException { + final var tmpFile = File.createTempFile("lottie-json", ".json"); + + try (var writer = Files.newBufferedWriter(tmpFile.toPath(), StandardCharsets.UTF_8)) { + writer.write(lottieJson); + } + + final var programFile = new File("assets/lottieconverter"); + final var process = new ProcessBuilder() + .command( + programFile.getAbsolutePath(), + "-", "-", "gif", "512x512", "60" + ) + .redirectInput(ProcessBuilder.Redirect.from(tmpFile)) + .start(); + + try (var stream = process.getInputStream()) { + return stream.readAllBytes(); + } finally { + tmpFile.delete(); + } + } + private void uploadFile(final String url, final CommandContext ctx) { WebUtils.ins.getByteStream(url, (it) -> it.setRateLimiter(RateLimiter.directLimiter())).async( (bytes) -> { diff --git a/build.gradle.kts b/build.gradle.kts index 893129f7b..2da7adacc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -45,7 +45,7 @@ allprojects { } tasks.withType { - gradleVersion = "8.2.1" + gradleVersion = "8.5" distributionType = Wrapper.DistributionType.BIN } } diff --git a/docker-compose.yml b/docker-compose.yml index a4d2fb65b..6ffed20a1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -46,7 +46,7 @@ services: # Options are: psql, web - USE_DATABASE=psql - - JDBC_URI=jdbc:postgresql://localhost:5432/skybot?user=root&password=root + - JDBC_URI=jdbc:postgresql://localhost:5433/skybot?user=root&password=postgres # - REDIS_HOST=localhost - REDIS_HOST=disabled dashboard: diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa..033e24c4c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 17a8ddce2..1af9e0930 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68d6..fcb6fca14 100755 --- a/gradlew +++ b/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +130,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,6 +197,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt index e1ed1408f..8aa1a9598 100644 --- a/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt +++ b/shared/src/main/kotlin/ml/duncte123/skybot/database/PostgreDatabase.kt @@ -49,6 +49,9 @@ class PostgreDatabase(jdbcURI: String, ohShitFn: (Int, Int) -> Unit = { _, _ -> } init { + // Needed for docker it seems + Class.forName("org.postgresql.ds.PGSimpleDataSource") + val config = HikariConfig() // IT IS postgresql:// NOT psql://