diff --git a/.github/workflows/root.yml b/.github/workflows/root.yml index 2ebd1de..be87cbd 100644 --- a/.github/workflows/root.yml +++ b/.github/workflows/root.yml @@ -1,81 +1,75 @@ name: Build & Publish on: - workflow_dispatch: push: branches: - root + schedule: + - cron: "0 6 * * *" jobs: build: runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: https://github.com/actions/checkout@v4 + - name: Disable SSL verify (Temporary Fix) + run: git config --global http.sslVerify false + + - uses: actions/checkout@v4 - name: Set up QEMU - uses: https://github.com/docker/setup-qemu-action@v3 - with: - cache-image: false + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: https://github.com/docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v3 - name: Set up Java - uses: https://github.com/actions/setup-java@v4 + uses: actions/setup-java@v4 with: java-version: 21 distribution: temurin - - name: "Restore Cache" - id: restore-cache - uses: https://data.forgejo.org/actions/cache/restore@v4 - - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - ~/.m2/repository - key: gradle-store - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - with: - dependency-graph: generate-and-submit - cache-disabled: true - - name: Get current date id: date run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - name: Gradle (Build) - run: "./gradlew build" - - - name: Login to DigitalOcean Registry - uses: https://github.com/docker/login-action@v3 - - with: - registry: registry.digitalocean.com - username: ${{ secrets.DOMAIL }} - password: ${{ secrets.DOKEY }} - - - name: Build and push - uses: https://github.com/docker/build-push-action@v6 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: true - tags: registry.digitalocean.com/jansel/feixiao:latest,registry.digitalocean.com/jansel/feixiao:${{ steps.date.outputs.date }} - - - name: "Save Cache" - uses: https://data.forgejo.org/actions/cache/save@v4 - + - name: Gradle Cache + uses: actions/cache/restore@v4 with: path: | ~/.gradle/caches ~/.gradle/wrapper - ~/.m2/repository - key: ${{ steps.restore-cache.outputs.cache-primary-key }} + key: ${{ runner.os }}-gradle-Feixiao + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Gradle (Build) + run: "./gradlew build" + + - name: Gradle Cache + uses: actions/cache/save@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-Feixiao + + - name: Login to Gitea Registry + uses: docker/login-action@v3 + + with: + registry: pi5:8125 + username: ${{ github.repository_owner }} + password: ${{ secrets.PW }} + + - name: Build the Docker image + run: docker build -t pi5:8125/jansel/feixiao:latest -t pi5:8125/jansel/feixiao:${{ steps.date.outputs.date }} . + + - name: Push the Docker image related to this workflow + run: docker push pi5:8125/jansel/feixiao:${{ steps.date.outputs.date }} + + - name: Push the latest Docker image + run: docker push pi5:8125/jansel/feixiao:latest \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 1e16934..c224ad5 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 1dff957..802ad4c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,17 +2,17 @@ import dev.kordex.gradle.plugins.docker.file.* import dev.kordex.gradle.plugins.kordex.DataCollection plugins { - distribution + kotlin("jvm") + kotlin("plugin.serialization") - alias(libs.plugins.kotlin.jvm) - alias(libs.plugins.kotlin.serialization) + id("com.github.johnrengelman.shadow") - alias(libs.plugins.kordex.plugin) - alias(libs.plugins.kordex.docker) + id("dev.kordex.gradle.docker") + id("dev.kordex.gradle.kordex") } group = "dev.jansel" -version = "1.2-SNAPSHOT" +version = "1.0-SNAPSHOT" dependencies { @@ -31,26 +31,9 @@ dependencies { implementation(libs.logging) } -// Configure distributions plugin -distributions { - main { - distributionBaseName = project.name - - contents { - // Copy the LICENSE file into the distribution - from("LICENSE") - - // Exclude src/main/dist/README.md - exclude("README.md") - } - } -} - - kordEx { kordExVersion = "2.3.1-SNAPSHOT" jvmTarget = 21 - ignoreIncompatibleKotlinVersion = true bot { // See https://docs.kordex.dev/data-collection.html @@ -75,51 +58,37 @@ docker { // Each function (aside from comment/emptyLine) corresponds to a Dockerfile instruction. // See: https://docs.docker.com/reference/dockerfile/ - from("openjdk:21-jdk-slim") + from("azul/zulu-openjdk-alpine:21-jre-headless-latest") emptyLine() - comment("Create required directories") runShell("mkdir -p /bot/plugins") runShell("mkdir -p /bot/data") - runShell("mkdir -p /dist/out") + + emptyLine() + + copy("build/libs/$name-*-all.jar", "/bot/bot.jar") emptyLine() // Add volumes for locations that you need to persist. This is important! - comment("Declare required volumes") volume("/bot/data") // Storage for data files volume("/bot/plugins") // Plugin ZIP/JAR location emptyLine() - comment("Copy the distribution files into the container") - copy("build/distributions/${project.name}-${project.version}.tar", "/dist") - - emptyLine() - - comment("Extract the distribution files, and prepare them for use") - runShell("tar -xf /dist/${project.name}-${project.version}.tar -C /dist/out") - - if (file("src/main/dist/plugins").isDirectory) { - runShell("mv /dist/out/${project.name}-${project.version}/plugins/* /bot/plugins") - } - - runShell("chmod +x /dist/out/${project.name}-${project.version}/bin/$name") - - emptyLine() - - comment("Clean up unnecessary files") - runShell("rm /dist/${project.name}-${project.version}.tar") - - emptyLine() - - comment("Set the correct working directory") workdir("/bot") emptyLine() - comment("Run the distribution start script") - entryPointExec("/dist/out/${project.name}-${project.version}/bin/$name") + entryPointExec( + "java", "-Xms2G", "-Xmx2G", + "-jar", "/bot/bot.jar" + ) } } + +tasks.wrapper { + gradleVersion = "8.11.1" + distributionType = Wrapper.DistributionType.BIN +} diff --git a/privacy-policy.md b/docs/privacy-policy.md similarity index 100% rename from privacy-policy.md rename to docs/privacy-policy.md diff --git a/terms-of-service.md b/docs/terms-of-service.md similarity index 100% rename from terms-of-service.md rename to docs/terms-of-service.md diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4766e0d..51def88 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,17 +1,16 @@ [versions] -kotlin = "2.1.21" # Note: Plugin versions must be updated in the settings.gradle.kts too +kotlin = "2.0.21" # Note: Plugin versions must be updated in the settings.gradle.kts too -groovy = "3.0.25" -jansi = "2.4.2" -kx-ser = "1.8.1" -logback = "1.5.18" +groovy = "3.0.23" +jansi = "2.4.1" +kx-ser = "1.7.3" +logback = "1.5.12" logback-groovy = "1.14.5" -logging = "7.0.7" -twitch4j = "1.25.0" +logging = "7.0.3" +twitch4j = "1.23.0" events4j = "0.12.2" -kx-coroutines = "1.10.2" -kmongo = "5.2.1" -kordex-gradle = "1.7.1" +kx-coroutines = "1.9.0" +kmongo = "5.1.0" [libraries] groovy = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" } @@ -25,11 +24,3 @@ logging = { module = "io.github.oshai:kotlin-logging", version.ref = "logging" } twitch4j = { module = "com.github.twitch4j:twitch4j", version.ref = "twitch4j" } events4j = { module = "com.github.philippheuer.events4j:events4j-handler-reactor", version.ref = "events4j" } kmongo = { module="org.litote.kmongo:kmongo-coroutine-serialization", version.ref = "kmongo" } - - -[plugins] -kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } -kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } - -kordex-docker = { id = "dev.kordex.gradle.docker", version.ref = "kordex-gradle" } -kordex-plugin = { id = "dev.kordex.gradle.kordex", version.ref = "kordex-gradle" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55..a4b76b9 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 ff23a68..e2847c8 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.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a9..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -86,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -114,7 +115,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -205,7 +206,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -213,7 +214,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index db3a6ac..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/renovate.json b/renovate.json deleted file mode 100644 index e655623..0000000 --- a/renovate.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended" - ], - "packageRules": [ - { - "matchUpdateTypes": [ - "minor", - "patch" - ] - } - ], - "prHourlyLimit": 0 -} diff --git a/settings.gradle.kts b/settings.gradle.kts index ebc20a7..84e3ff8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,14 @@ pluginManagement { + plugins { + // Update this in libs.version.toml when you change it here. + kotlin("jvm") version "2.0.21" + kotlin("plugin.serialization") version "2.0.21" + + id("com.github.johnrengelman.shadow") version "8.1.1" + + id("dev.kordex.gradle.docker") version "1.6.0" + id("dev.kordex.gradle.kordex") version "1.6.0" + } repositories { gradlePluginPortal() mavenCentral() diff --git a/src/main/kotlin/dev/jansel/feixiao/database/Migrator.kt b/src/main/kotlin/dev/jansel/feixiao/database/Migrator.kt index 5e539eb..2043779 100644 --- a/src/main/kotlin/dev/jansel/feixiao/database/Migrator.kt +++ b/src/main/kotlin/dev/jansel/feixiao/database/Migrator.kt @@ -1,14 +1,8 @@ package dev.jansel.feixiao.database -import com.github.philippheuer.events4j.reactor.ReactorEventHandler -import com.github.twitch4j.TwitchClientBuilder import dev.jansel.feixiao.database.collections.MetaCollection import dev.jansel.feixiao.database.entities.MetaData import dev.jansel.feixiao.database.migrations.v1 -import dev.jansel.feixiao.database.migrations.v2 -import dev.jansel.feixiao.twitchClient -import dev.jansel.feixiao.utils.twitchcid -import dev.jansel.feixiao.utils.twitchcs import dev.kordex.core.koin.KordExKoinComponent import io.github.oshai.kotlinlogging.KotlinLogging import org.koin.core.component.inject @@ -21,13 +15,6 @@ object Migrator : KordExKoinComponent { suspend fun migrate() { logger.info { "Starting main database migration" } - logger.info { "Initializing Twitch client just in case" } - twitchClient = TwitchClientBuilder.builder() - .withEnableHelix(true) - .withDefaultEventHandler(ReactorEventHandler::class.java) - .withClientId(twitchcid) - .withClientSecret(twitchcs) - .build() var meta = mainMetaCollection.get() @@ -48,7 +35,6 @@ object Migrator : KordExKoinComponent { try { when (nextVersion) { 1 -> ::v1 - 2 -> ::v2 else -> break }(db.mongo) diff --git a/src/main/kotlin/dev/jansel/feixiao/database/collections/StreamerCollection.kt b/src/main/kotlin/dev/jansel/feixiao/database/collections/StreamerCollection.kt index 3471e94..1954f78 100644 --- a/src/main/kotlin/dev/jansel/feixiao/database/collections/StreamerCollection.kt +++ b/src/main/kotlin/dev/jansel/feixiao/database/collections/StreamerCollection.kt @@ -3,7 +3,6 @@ package dev.jansel.feixiao.database.collections import dev.jansel.feixiao.database.Database import dev.jansel.feixiao.database.entities.Server import dev.jansel.feixiao.database.entities.StreamerData -import dev.jansel.feixiao.utils.getTwitchIdByName import dev.kord.common.entity.Snowflake import dev.kordex.core.koin.KordExKoinComponent import org.koin.core.component.inject @@ -36,7 +35,7 @@ class StreamerCollection : KordExKoinComponent { ) } else { collection.insertOne( - StreamerData(streamerName, getTwitchIdByName(streamerName), listOf(Server(guildId, channelId, roleId, liveMessage))) + StreamerData(streamerName, listOf(Server(guildId, channelId, roleId, liveMessage))) ) } } diff --git a/src/main/kotlin/dev/jansel/feixiao/database/entities/StreamerData.kt b/src/main/kotlin/dev/jansel/feixiao/database/entities/StreamerData.kt index 9e79d75..3425532 100644 --- a/src/main/kotlin/dev/jansel/feixiao/database/entities/StreamerData.kt +++ b/src/main/kotlin/dev/jansel/feixiao/database/entities/StreamerData.kt @@ -6,7 +6,6 @@ import kotlinx.serialization.Serializable @Serializable data class StreamerData( val name: String, - val id: String?, val servers: List ) diff --git a/src/main/kotlin/dev/jansel/feixiao/database/migrations/v2.kt b/src/main/kotlin/dev/jansel/feixiao/database/migrations/v2.kt deleted file mode 100644 index df0f783..0000000 --- a/src/main/kotlin/dev/jansel/feixiao/database/migrations/v2.kt +++ /dev/null @@ -1,16 +0,0 @@ -package dev.jansel.feixiao.database.migrations - -import dev.jansel.feixiao.database.entities.StreamerData -import dev.jansel.feixiao.utils.getTwitchIdByName -import org.litote.kmongo.coroutine.CoroutineDatabase -import org.litote.kmongo.eq -import org.litote.kmongo.setValue - -suspend fun v2(db: CoroutineDatabase) { - db.getCollection("streamerData").findOne(StreamerData::id eq null)?.let { - db.getCollection("streamerData").updateOne( - StreamerData::name eq it.name, - setValue(StreamerData::id, getTwitchIdByName(it.name)) - ) - } -} diff --git a/src/main/kotlin/dev/jansel/feixiao/extensions/EventHooks.kt b/src/main/kotlin/dev/jansel/feixiao/extensions/EventHooks.kt index c9a4ca6..5fb0e0d 100644 --- a/src/main/kotlin/dev/jansel/feixiao/extensions/EventHooks.kt +++ b/src/main/kotlin/dev/jansel/feixiao/extensions/EventHooks.kt @@ -4,8 +4,6 @@ import dev.jansel.feixiao.database.collections.StreamerCollection import dev.jansel.feixiao.database.entities.StreamerData import dev.jansel.feixiao.logger import dev.jansel.feixiao.twitchClient -import dev.jansel.feixiao.utils.getTwitchIdByName -import dev.jansel.feixiao.utils.getTwitchNameById import dev.jansel.feixiao.utils.tchannelid import dev.jansel.feixiao.utils.tserverid import dev.kord.core.behavior.getChannelOf @@ -14,7 +12,6 @@ import dev.kord.core.event.gateway.ReadyEvent import dev.kordex.core.extensions.Extension import dev.kordex.core.extensions.event import org.litote.kmongo.eq -import org.litote.kmongo.setValue class EventHooks : Extension() { override val name = "eventhooks" @@ -30,10 +27,8 @@ class EventHooks : Extension() { // check every entry in the database and enable the stream event listener if a server is listening to the streamer StreamerCollection().collection.find().toList().forEach { if (it.servers.isNotEmpty()) { - val currentName = getTwitchNameById(it.id!!) - twitchClient!!.clientHelper.enableStreamEventListener(currentName) - logger.info { "Enabled stream event listener for $currentName" } - StreamerCollection().collection.updateOne(StreamerData::name eq it.name, setValue(StreamerData::name, currentName)) + twitchClient!!.clientHelper.enableStreamEventListener(it.name) + logger.info { "Enabled stream event listener for ${it.name}" } } else { logger.info { "No servers are listening to ${it.name}, deleting from the database..." } StreamerCollection().collection.deleteMany(StreamerData::name eq it.name) diff --git a/src/main/kotlin/dev/jansel/feixiao/modals/EditStreamerModal.kt b/src/main/kotlin/dev/jansel/feixiao/modals/EditStreamerModal.kt new file mode 100644 index 0000000..3029d99 --- /dev/null +++ b/src/main/kotlin/dev/jansel/feixiao/modals/EditStreamerModal.kt @@ -0,0 +1,29 @@ +package dev.jansel.feixiao.modals + +import dev.jansel.feixiao.i18n.Translations +import dev.kordex.core.components.forms.ModalForm +import dev.kordex.core.i18n.types.Key + +class EditStreamerModal : ModalForm() { + override var title = Translations.Streamer.Modals.Edit.title + + val streamerName = lineText { + label = Translations.Streamer.Modals.Edit.Streamername.label + placeholder = Translations.Streamer.Modals.Edit.Streamername.placeholder + } + + val channel = lineText { + label = Translations.Streamer.Modals.Edit.Channel.label + placeholder = Translations.Streamer.Modals.Edit.Channel.placeholder + } + + val role = lineText { + label = Translations.Streamer.Modals.Edit.Role.label + placeholder = Translations.Streamer.Modals.Edit.Role.placeholder + } + + val message = paragraphText { + label = Translations.Streamer.Modals.Edit.Message.label + placeholder = Translations.Streamer.Modals.Edit.Message.placeholder + } +} diff --git a/src/main/kotlin/dev/jansel/feixiao/utils/_Utils.kt b/src/main/kotlin/dev/jansel/feixiao/utils/_Utils.kt index 97ece69..c1b55da 100644 --- a/src/main/kotlin/dev/jansel/feixiao/utils/_Utils.kt +++ b/src/main/kotlin/dev/jansel/feixiao/utils/_Utils.kt @@ -3,7 +3,6 @@ package dev.jansel.feixiao.utils import dev.jansel.feixiao.database.Database import dev.jansel.feixiao.database.collections.MetaCollection import dev.jansel.feixiao.database.collections.StreamerCollection -import dev.jansel.feixiao.twitchClient import dev.kord.common.entity.Snowflake import dev.kordex.core.builders.ExtensibleBotBuilder import dev.kordex.core.utils.env @@ -53,23 +52,3 @@ suspend inline fun ExtensibleBotBuilder.twitch(active: Boolean) { } } - -fun getTwitchNameById(id: String): String? { - val resultList = twitchClient!!.helix?.getUsers(null, listOf(id), null)?.execute() - resultList?.users?.forEach { user -> - if (user.id == id) { - return user.displayName - } - } - return null -} - -fun getTwitchIdByName(name: String): String? { - val resultList = twitchClient!!.helix?.getUsers(null, null, listOf(name))?.execute() - resultList?.users?.forEach { user -> - if (user.displayName == name) { - return user.id - } - } - return null -} diff --git a/src/main/resources/translations/feixiao/strings.properties b/src/main/resources/translations/feixiao/strings.properties index 81c90c9..2f7d47d 100644 --- a/src/main/resources/translations/feixiao/strings.properties +++ b/src/main/resources/translations/feixiao/strings.properties @@ -33,6 +33,14 @@ streamer.command.arguments.update.role.description=The role to assign to the str streamer.command.arguments.update.message.name=message streamer.command.arguments.update.message.description=Custom Announce message. Placeholders (in curly braces): url, name, title, category, role (if set) - +streamer.modals.edit.title=Edit Streamer +streamer.modals.edit.streamername.label=Streamer Name +streamer.modals.edit.streamername.placeholder=Streamer Name +streamer.modals.edit.channel.label=Channel +streamer.modals.edit.channel.placeholder=Channel ID for the live messages. Leave empty for no change. +streamer.modals.edit.role.label=Role +streamer.modals.edit.role.placeholder=Role ID to assign to the stream pings. Leave empty for no change. +streamer.modals.edit.message.label=Message +streamer.modals.edit.message.placeholder=Message to send when the streamer goes live. Placeholders: {url}, {name}, {title}, {category}, {role} # more to come...