diff --git a/build.gradle.kts b/build.gradle.kts
index ee67215..2776494 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -39,6 +39,7 @@ val coroutinesver = "1.1.0"
val ktor_version = "2.3.0"
val exposedver = "0.40.1"
val postgresver = "42.3.8"
+val krontabver = "1.0.0"
val mavenArtifact = "lilJudd"
project.base.archivesName.set(mavenArtifact)
@@ -93,6 +94,9 @@ dependencies {
shadow("org.jetbrains.exposed:exposed-dao:$exposedver")
shadow("org.jetbrains.exposed:exposed-jdbc:$exposedver")
shadow("org.postgresql:postgresql:$postgresver")
+
+ //Korntab
+ shadow("dev.inmo:krontab:$krontabver")
}
@@ -106,7 +110,8 @@ val templateProps = mapOf(
"coroutinesversion" to coroutinesver,
"ktorversion" to ktor_version,
"exposedversion" to exposedver,
- "postgresversion" to postgresver
+ "postgresversion" to postgresver,
+ "krontabversion" to krontabver
)
diff --git a/src/main/kotlin/net/moonleay/lilJudd/Bot.kt b/src/main/kotlin/net/moonleay/lilJudd/Bot.kt
index 8b3ce9a..ec55b96 100644
--- a/src/main/kotlin/net/moonleay/lilJudd/Bot.kt
+++ b/src/main/kotlin/net/moonleay/lilJudd/Bot.kt
@@ -20,17 +20,20 @@ package net.moonleay.lilJudd
import com.kotlindiscord.kord.extensions.ExtensibleBot
import dev.kord.common.entity.PresenceStatus
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
import net.moonleay.botendo.build.BuildConstants
import net.moonleay.lilJudd.data.CredentialManager
import net.moonleay.lilJudd.data.DB
import net.moonleay.lilJudd.extensions.FeatureManageExtension
import net.moonleay.lilJudd.extensions.VersionExtension
+import net.moonleay.lilJudd.features.TimePlanner
import net.moonleay.lilJudd.util.Logger
import kotlin.system.exitProcess
object Bot {
//The kord object gets set at app launch
- private lateinit var bot: ExtensibleBot
+ lateinit var bot: ExtensibleBot
suspend fun start() {
Logger.out("Starting Bot...")
@@ -49,7 +52,7 @@ object Bot {
exitProcess(3)
}
- //Connect to the Database
+ //Connect to the database
DB.connect(
CredentialManager.dbDomain,
CredentialManager.dbName,
@@ -57,6 +60,17 @@ object Bot {
CredentialManager.dbPassword
)
+ //Register the TimePlanner thread
+ val coroutineJob = GlobalScope.launch {
+ TimePlanner.registerThread()
+ }
+
+ // Add a shutdown hook to cancel the coroutine when the application is terminated
+ Runtime.getRuntime().addShutdownHook(Thread {
+ coroutineJob.cancel()
+ })
+
+
//Add Bot token to kord
bot = ExtensibleBot(CredentialManager.token) {
applicationCommands {
diff --git a/src/main/kotlin/net/moonleay/lilJudd/extensions/FeatureManageExtension.kt b/src/main/kotlin/net/moonleay/lilJudd/extensions/FeatureManageExtension.kt
index 61b598d..2bdd9e4 100644
--- a/src/main/kotlin/net/moonleay/lilJudd/extensions/FeatureManageExtension.kt
+++ b/src/main/kotlin/net/moonleay/lilJudd/extensions/FeatureManageExtension.kt
@@ -92,7 +92,7 @@ class FeatureManageExtension : Extension() {
MessageUtil.getEmbed(
Color(0x52E01A),
"200: Success",
- "The feature was enabled in channel ${args.channel.data.name}",
+ "The feature was enabled in channel ${args.channel.data.name.value}",
u.asUser().username + "#" + u.asUser().discriminator
)
)
diff --git a/src/main/kotlin/net/moonleay/lilJudd/extensions/VersionExtension.kt b/src/main/kotlin/net/moonleay/lilJudd/extensions/VersionExtension.kt
index 949df89..c116c02 100644
--- a/src/main/kotlin/net/moonleay/lilJudd/extensions/VersionExtension.kt
+++ b/src/main/kotlin/net/moonleay/lilJudd/extensions/VersionExtension.kt
@@ -37,7 +37,8 @@ class VersionExtension : Extension() {
"Lil' Judd",
"Lil' Judd ***v." + BuildConstants.version + "***\n" +
"Kord-Extensions ***v." + BuildConstants.kordVersion + "***\n" +
- "Coroutines ***v." + BuildConstants.coroutinesVersion + "***"
+ "Coroutines ***v." + BuildConstants.coroutinesVersion + "***\n" +
+ "Krontab ***v." + BuildConstants.krontabVersion + "***"
)
}
}
diff --git a/src/main/kotlin/net/moonleay/lilJudd/features/TimePlanner.kt b/src/main/kotlin/net/moonleay/lilJudd/features/TimePlanner.kt
new file mode 100644
index 0000000..31775c1
--- /dev/null
+++ b/src/main/kotlin/net/moonleay/lilJudd/features/TimePlanner.kt
@@ -0,0 +1,110 @@
+/*
+ * lilJudd
+ * Copyright (C) 2023 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.lilJudd.features
+
+import com.kotlindiscord.kord.extensions.utils.addReaction
+import dev.inmo.krontab.buildSchedule
+import dev.inmo.krontab.doInfinity
+import dev.kord.common.Color
+import dev.kord.common.entity.Snowflake
+import dev.kord.core.behavior.channel.createMessage
+import dev.kord.core.entity.Message
+import dev.kord.core.entity.channel.MessageChannel
+import kotlinx.coroutines.delay
+import net.moonleay.lilJudd.Bot
+import net.moonleay.lilJudd.data.tables.TimePlanningChannels
+import net.moonleay.lilJudd.util.Logger
+import net.moonleay.lilJudd.util.MessageUtil
+import org.jetbrains.exposed.sql.selectAll
+import org.jetbrains.exposed.sql.transactions.transaction
+import java.time.ZoneId
+import java.time.ZonedDateTime
+
+
+object TimePlanner {
+ /* /--------------- Seconds
+ | /------------- Minutes
+ | | /----------- Hours
+ | | | /--------- Days of months
+ | | | | /------- Months
+ | | | | | /----- (optional) Year
+ | | | | | | /--- (optional) Timezone offset
+ | | | | | | | / (optional) Week days
+ * * * * * * 0o *w*/
+
+ suspend fun registerThread() {
+ Logger.out("Adding scheduler...")
+ val scheduler = buildSchedule("0 0 4 * * * 0o 1") // 0 0 4 * * * 0o 1 // 0o is UTC
+ scheduler.doInfinity {
+ Logger.out("Starting to notify...")
+ val channelList = mutableListOf()
+ transaction {
+ for (tp in TimePlanningChannels.selectAll()) {
+ channelList.add(Snowflake(tp[TimePlanningChannels.channelid]))
+ Logger.out("Have to notify channel with ID ${tp[TimePlanningChannels.channelid]}.")
+ }
+ }
+ Logger.out("${channelList.count()} Channels to notify!")
+ for (ch in channelList) {
+ if (Bot.bot.kordRef.getChannel(ch)!!.asChannelOrNull() == null)
+ return@doInfinity
+ val c = Bot.bot.kordRef.getChannelOf(ch)!!
+ c.createMessage {
+ this.embeds.add(
+ MessageUtil.getEmbed(
+ Color(0X4C4645),
+ "Time Planning Feature",
+ "Do you have time on the following Days?",
+ "Automated Message"
+ )
+ )
+ }
+ delay(3000)
+ var then = ZonedDateTime.now(ZoneId.of("Europe/Berlin")).withHour(4).withMinute(0).withSecond(0)
+ repeat(6) {
+ val m = c.createMessage {
+ this.embeds.add(
+ MessageUtil.getEmbedSmall(
+ Color(0X4C4645),
+ "",
+ "${then.dayOfWeek.name}, ${then.dayOfMonth}.${then.monthValue}.${then.year} /${it + 1}. weekday"
+ )
+ )
+ }
+ then = then.plusDays(1).withHour(20).withMinute(24).withSecond(0)
+ delay(500)
+ addReactions(m)
+ delay(1000)
+ Logger.out("Finished sending day $it")
+ }
+ Logger.out("Finished with ${c.data.guildId.value}")
+ }
+ Logger.out("Done! Until next Monday! <3 ")
+ }
+ }
+
+ private suspend fun addReactions(msg: Message) {
+ msg.addReaction("✅")
+ delay(300)
+ msg.addReaction("❌")
+ delay(300)
+ msg.addReaction("❓")
+ delay(300)
+ }
+}
diff --git a/src/main/kotlin/net/moonleay/lilJudd/util/MessageUtil.kt b/src/main/kotlin/net/moonleay/lilJudd/util/MessageUtil.kt
index d299336..0544acb 100644
--- a/src/main/kotlin/net/moonleay/lilJudd/util/MessageUtil.kt
+++ b/src/main/kotlin/net/moonleay/lilJudd/util/MessageUtil.kt
@@ -70,6 +70,18 @@ object MessageUtil {
}
}
+ ///Get an embedded msg with title and description
+ fun getEmbedSmall(
+ color: Color,
+ title: String,
+ description: String
+ ): EmbedBuilder {
+ val ebb = EmbedBuilder()
+ ebb.title = title
+ ebb.description = description
+ return ebb
+ }
+
///Get an embedded msg with title, description and a src
fun getEmbed(
color: Color,
@@ -77,10 +89,8 @@ object MessageUtil {
description: String,
source: String
): EmbedBuilder {
+ val ebb = getEmbedSmall(color, title, description)
val now: LocalDateTime = LocalDateTime.now()
- val ebb = EmbedBuilder()
- ebb.title = title
- ebb.description = description
ebb.footer = EmbedBuilder.Footer()
ebb.footer!!.text = ">" + dtf.format(now) + " - $source"
ebb.color = color
diff --git a/src/main/kotlin/net/moonleay/lilJudd/util/TimeUtil.kt b/src/main/kotlin/net/moonleay/lilJudd/util/TimeUtil.kt
new file mode 100644
index 0000000..1edfe17
--- /dev/null
+++ b/src/main/kotlin/net/moonleay/lilJudd/util/TimeUtil.kt
@@ -0,0 +1,129 @@
+/*
+ * lilJudd
+ * Copyright (C) 2023 moonleay
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package net.moonleay.lilJudd.util
+
+import java.time.Duration
+import java.util.concurrent.TimeUnit
+
+
+object TimeUtil {
+
+ fun getTimeFormatedShortend(time2: Long): String {
+ var time = time2
+ val days: Long = TimeUnit.MILLISECONDS
+ .toDays(time)
+ time -= TimeUnit.DAYS.toMillis(days)
+ val hours: Long = TimeUnit.MILLISECONDS
+ .toHours(time)
+ time -= TimeUnit.HOURS.toMillis(hours)
+ val minutes: Long = TimeUnit.MILLISECONDS
+ .toMinutes(time)
+ time -= TimeUnit.MINUTES.toMillis(minutes)
+ val seconds: Long = TimeUnit.MILLISECONDS
+ .toSeconds(time)
+ var s = ""
+ if (days >= 1) {
+ s += days.toString() + "d "
+ }
+ if (hours >= 1) {
+ s += hours.toString() + "h "
+ }
+ if (minutes >= 1) {
+ s += minutes.toString() + "m "
+ }
+ if (seconds >= 1 && hours < 1) {
+ s += seconds.toString() + "s"
+ }
+ if (s.isEmpty() || s.isBlank()) {
+ s = "None"
+ }
+ return s
+ }
+
+ fun getTimeFormatedRaw(time2: Long): String {
+ var time = time2
+ val days: Long = TimeUnit.MILLISECONDS
+ .toDays(time)
+ time -= TimeUnit.DAYS.toMillis(days)
+ val hours: Long = TimeUnit.MILLISECONDS
+ .toHours(time)
+ time -= TimeUnit.HOURS.toMillis(hours)
+ val minutes: Long = TimeUnit.MILLISECONDS
+ .toMinutes(time)
+ time -= TimeUnit.MINUTES.toMillis(minutes)
+ val seconds: Long = TimeUnit.MILLISECONDS
+ .toSeconds(time)
+ var s = ""
+ if (days >= 1) {
+ s += days.toString() + "d "
+ }
+ if (hours >= 1) {
+ s += hours.toString() + "h "
+ }
+ if (minutes >= 1) {
+ s += minutes.toString() + "m "
+ }
+ if (seconds >= 1) {
+ s += seconds.toString() + "s"
+ }
+ if (s.isEmpty() || s.isBlank()) {
+ s = "None"
+ }
+ return s
+ }
+
+
+ //This 100000%ly can be improved, I wrote this at 2am
+ fun getTimeUnformated(timeStr: String): Long {
+ var days: Long = 0
+ var hours: Long = 0
+ var minutes: Long = 0
+ var seconds: Long = 0
+ val timeArr = timeStr.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ for (s in timeArr) {
+ if (s.endsWith("d")) {
+ days = s.split("d".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0].toLong()
+ } else if (s.endsWith("h")) {
+ hours = s.split("h".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0].toLong()
+ } else if (s.endsWith("m")) {
+ minutes = s.split("m".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0].toLong()
+ } else if (s.endsWith("s")) {
+ seconds = s.split("s".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0].toLong()
+ }
+ }
+ return Duration.ofSeconds(seconds).plus(Duration.ofMinutes(minutes)).plus(Duration.ofHours(hours))
+ .plus(Duration.ofDays(days)).toMillis()
+ }
+
+ private val DaysUntilMonday: Map = object : HashMap() {
+ init {
+ put("MONDAY", 0)
+ put("TUESDAY", 6)
+ put("WEDNESDAY", 5)
+ put("THURSDAY", 4)
+ put("FRIDAY", 3)
+ put("SATURDAY", 2)
+ put("SUNDAY", 1)
+ }
+ }
+
+ fun getDelay(day: String): Int {
+ return DaysUntilMonday[day]!!
+ }
+}
diff --git a/src/main/templates/net/moonleay/lilJudd/build/BuildConstants.kt b/src/main/templates/net/moonleay/lilJudd/build/BuildConstants.kt
index 0d9f6cd..fdcf269 100644
--- a/src/main/templates/net/moonleay/lilJudd/build/BuildConstants.kt
+++ b/src/main/templates/net/moonleay/lilJudd/build/BuildConstants.kt
@@ -1,6 +1,6 @@
/*
* lilJudd
- * Copyright (C) 2023 limited_dev
+ * Copyright (C) 2023 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,4 +26,5 @@ internal object BuildConstants {
const val ktorVersion = "${ktorversion}"
const val exposedVersion = "${exposedversion}"
const val postgresVersion = "${postgresversion}"
+ const val krontabVersion = "${krontabversion}"
}