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...