diff --git a/.gitignore b/.gitignore index 8e86108..651d066 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /.idea /build /.kotlin +/data diff --git a/build.gradle.kts b/build.gradle.kts index b806ea4..329231b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,8 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { - kotlin("jvm") version "2.0.0" - id("com.gradleup.shadow") version "8.3.0" + alias(libs.plugins.kotlin) + alias(libs.plugins.shadow) } group = "cn.rtast" @@ -27,9 +27,8 @@ tasks.compileJava { dependencies { - implementation("cn.rtast:ROneBot:1.2.2") - implementation("com.google.code.gson:gson:2.11.0") - implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.14") + implementation(libs.rOneBot) + implementation(libs.okhttp) } tasks.build { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..ccd1c6c --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,15 @@ +[versions] +kotlinVersion = "2.0.10" +ronebotVersion = "1.2.4" +shadowVersion = "8.3.0" +okhttpVersion = "5.0.0-alpha.14" + +[libraries] +rOneBot = { group = "cn.rtast", name = "ROneBot", version.ref = "ronebotVersion" } +okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttpVersion" } + +[bundles] + +[plugins] +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlinVersion" } +shadow = { id = "com.gradleup.shadow", version.ref = "shadowVersion" } \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/Const.kt b/src/main/kotlin/cn/rtast/fancybot/Const.kt index 577a1ed..8f51867 100644 --- a/src/main/kotlin/cn/rtast/fancybot/Const.kt +++ b/src/main/kotlin/cn/rtast/fancybot/Const.kt @@ -7,6 +7,7 @@ package cn.rtast.fancybot +import cn.rtast.fancybot.entity.Config import com.google.gson.Gson import com.google.gson.GsonBuilder @@ -15,3 +16,9 @@ val gson: Gson = GsonBuilder() .disableHtmlEscaping() .serializeNulls() .create() + +const val ROOT_PATH = "./data" + +val DEFAULT_CONFIG = Config( + cnmApi = "https://ncm.rtast.cn" +) diff --git a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt index 04b485e..1454398 100644 --- a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt +++ b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt @@ -10,6 +10,9 @@ package cn.rtast.fancybot import cn.rtast.fancybot.commands.EchoCommand import cn.rtast.fancybot.commands.JrrpCommand import cn.rtast.fancybot.commands.MusicCommand +import cn.rtast.fancybot.commands.MyPointCommand +import cn.rtast.fancybot.commands.SignCommand +import cn.rtast.fancybot.util.file.ConfigManager import cn.rtast.rob.ROneBotFactory import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.util.ob.OBMessage @@ -21,13 +24,11 @@ class FancyBot : OBMessage { override suspend fun onGroupMessage(websocket: WebSocket, message: GroupMessage, json: String) { println(message.rawMessage) } -} -val commands = listOf( - EchoCommand(), - JrrpCommand(), - MusicCommand() -) + override suspend fun onWebsocketError(webSocket: WebSocket, ex: Exception) { + println(ex.message) + } +} fun createFakeServer() { val server = HttpServer.create(InetSocketAddress(8000), 0) @@ -42,6 +43,15 @@ fun createFakeServer() { println("Server is running on port 8000...") } +val commands = listOf( + EchoCommand(), + JrrpCommand(), + MusicCommand(), + SignCommand(), + MyPointCommand() +) + +val configManager = ConfigManager() fun main() { val address = System.getenv("WS_ADDRESS") diff --git a/src/main/kotlin/cn/rtast/fancybot/cmd/GenerateDefaultConfig.kt b/src/main/kotlin/cn/rtast/fancybot/cmd/GenerateDefaultConfig.kt new file mode 100644 index 0000000..369d24e --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/cmd/GenerateDefaultConfig.kt @@ -0,0 +1,18 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/30 + */ + + +package cn.rtast.fancybot.cmd + +import cn.rtast.fancybot.DEFAULT_CONFIG +import cn.rtast.fancybot.util.toJson +import java.io.File + +fun main() { + val file = File("src/main/resources/config.json") + file.writeText(DEFAULT_CONFIG.toJson()) + println("Generated default config") +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/JrrpCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/JrrpCommand.kt index 15294c7..33c528f 100644 --- a/src/main/kotlin/cn/rtast/fancybot/commands/JrrpCommand.kt +++ b/src/main/kotlin/cn/rtast/fancybot/commands/JrrpCommand.kt @@ -7,23 +7,29 @@ package cn.rtast.fancybot.commands +import cn.rtast.fancybot.util.file.JrrpManager import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.util.BaseCommand import cn.rtast.rob.util.ob.OBMessage -import kotlin.random.Random class JrrpCommand : BaseCommand() { - override val commandName = "/今日人品" + override val commandName = "/jrrp" + + private val jrrpManager = JrrpManager() override suspend fun executeGroup(listener: OBMessage, message: GroupMessage, args: List) { - val randomNumber = Random.nextInt(0, 101) - val scoreDesc = when (randomNumber) { + if (jrrpManager.isJrrped(message.sender.userId)) { + listener.sendGroupMessage(message.groupId, "你今天已经今日人品过啦, 明天再来吧~") + return + } + val randomPoint = jrrpManager.jrrp(message.sender.userId) + val scoreDesc = when (randomPoint) { in 0..10 -> "人品不太好呢" in 30..50 -> "人品一般般" in 70..90 -> "人品还不错哦" in 90..100 -> "人品超级好呢!" else -> "人品还行哦" } - listener.sendGroupMessage(message.groupId, "$scoreDesc($randomNumber)") + listener.sendGroupMessage(message.groupId, "$scoreDesc($randomPoint)") } } \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/MusicCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/MusicCommand.kt index d8f363b..875ab3f 100644 --- a/src/main/kotlin/cn/rtast/fancybot/commands/MusicCommand.kt +++ b/src/main/kotlin/cn/rtast/fancybot/commands/MusicCommand.kt @@ -7,9 +7,10 @@ package cn.rtast.fancybot.commands -import cn.rtast.fancybot.entity.Search -import cn.rtast.fancybot.entity.SearchedResult -import cn.rtast.fancybot.entity.SongUrl +import cn.rtast.fancybot.configManager +import cn.rtast.fancybot.entity.music.Search +import cn.rtast.fancybot.entity.music.SearchedResult +import cn.rtast.fancybot.entity.music.SongUrl import cn.rtast.fancybot.util.Http import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.util.BaseCommand @@ -44,7 +45,7 @@ class MusicCommand : BaseCommand() { } val keyword = args.drop(1).joinToString(" ") val result = Http.get( - "https://music.api.yhdzz.cn/search", + "${configManager.ncmAPI}/search", mapOf("keywords" to keyword), ) val tempResults = mutableListOf() @@ -67,7 +68,10 @@ class MusicCommand : BaseCommand() { val searchedResultGet = searchedResult[message.sender.userId]!! val finalResult = searchedResultGet[index] val url = - Http.get("https://music.api.yhdzz.cn/song/url?id=${finalResult.id}").data.first().url + Http.get( + "${configManager.ncmAPI}/song/url", + mapOf("id" to finalResult.id) + ).data.first().url val cqCode = "[CQ:music,type=custom,url=https://music.163.com/#/song?id=${finalResult.id}," + "audio=$url,title=《${finalResult.name}》-- ${finalResult.artists}]" listener.sendGroupMessage(message.groupId, cqCode) diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/SignCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/SignCommand.kt new file mode 100644 index 0000000..dfccef1 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/commands/SignCommand.kt @@ -0,0 +1,42 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/30 + */ + + +package cn.rtast.fancybot.commands + +import cn.rtast.fancybot.util.file.SignManager +import cn.rtast.rob.entity.GroupMessage +import cn.rtast.rob.util.BaseCommand +import cn.rtast.rob.util.ob.OBMessage + +private val signManager = SignManager() + +class SignCommand : BaseCommand() { + override val commandName = "/签到" + + override suspend fun executeGroup(listener: OBMessage, message: GroupMessage, args: List) { + if (signManager.isSigned(message.sender.userId)) { + listener.sendGroupMessage(message.groupId, "你今天已经签到, 明天再来吧~") + return + } + val randomPoint = signManager.sign(message.sender.userId) + listener.sendGroupMessage(message.groupId, "你获得了 $randomPoint 点分数!\n发送‘/我的分数’ 即可查看当前的分数") + } +} + +class MyPointCommand: BaseCommand() { + override val commandName = "/我的分数" + + override suspend fun executeGroup(listener: OBMessage, message: GroupMessage, args: List) { + val status = signManager.getStatus(message.sender.userId) + if (status == null) { + listener.sendGroupMessage(message.groupId, "你还没有签到过呢! 先发送‘/签到’再来查询吧~") + return + } else { + listener.sendGroupMessage(message.groupId, "你当前的分数为: ${status.points}") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt b/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt new file mode 100644 index 0000000..a15984c --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt @@ -0,0 +1,12 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/30 + */ + + +package cn.rtast.fancybot.entity + +data class Config( + val cnmApi: String, +) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/jrrp/JrrpRecord.kt b/src/main/kotlin/cn/rtast/fancybot/entity/jrrp/JrrpRecord.kt new file mode 100644 index 0000000..fd22b52 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/jrrp/JrrpRecord.kt @@ -0,0 +1,14 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/29 + */ + + +package cn.rtast.fancybot.entity.jrrp + +data class JrrpRecord( + val id: Long, + val timestamp: Long, + var points: Long, +) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/jrrp/SignRecord.kt b/src/main/kotlin/cn/rtast/fancybot/entity/jrrp/SignRecord.kt new file mode 100644 index 0000000..2ba467c --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/jrrp/SignRecord.kt @@ -0,0 +1,11 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/30 + */ + + +package cn.rtast.fancybot.entity.jrrp + +class SignRecord { +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/Search.kt b/src/main/kotlin/cn/rtast/fancybot/entity/music/Search.kt similarity index 90% rename from src/main/kotlin/cn/rtast/fancybot/entity/Search.kt rename to src/main/kotlin/cn/rtast/fancybot/entity/music/Search.kt index f8a0e6b..07dc1bc 100644 --- a/src/main/kotlin/cn/rtast/fancybot/entity/Search.kt +++ b/src/main/kotlin/cn/rtast/fancybot/entity/music/Search.kt @@ -5,7 +5,7 @@ */ -package cn.rtast.fancybot.entity +package cn.rtast.fancybot.entity.music data class Search( val result: Result, diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/SearchedResult.kt b/src/main/kotlin/cn/rtast/fancybot/entity/music/SearchedResult.kt similarity index 83% rename from src/main/kotlin/cn/rtast/fancybot/entity/SearchedResult.kt rename to src/main/kotlin/cn/rtast/fancybot/entity/music/SearchedResult.kt index d25bbc8..5dccedb 100644 --- a/src/main/kotlin/cn/rtast/fancybot/entity/SearchedResult.kt +++ b/src/main/kotlin/cn/rtast/fancybot/entity/music/SearchedResult.kt @@ -5,7 +5,7 @@ */ -package cn.rtast.fancybot.entity +package cn.rtast.fancybot.entity.music data class SearchedResult( val id: Long, diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/SongUrl.kt b/src/main/kotlin/cn/rtast/fancybot/entity/music/SongUrl.kt similarity index 82% rename from src/main/kotlin/cn/rtast/fancybot/entity/SongUrl.kt rename to src/main/kotlin/cn/rtast/fancybot/entity/music/SongUrl.kt index 6f0f99a..f4f90f2 100644 --- a/src/main/kotlin/cn/rtast/fancybot/entity/SongUrl.kt +++ b/src/main/kotlin/cn/rtast/fancybot/entity/music/SongUrl.kt @@ -5,7 +5,7 @@ */ -package cn.rtast.fancybot.entity +package cn.rtast.fancybot.entity.music data class SongUrl( val data: List diff --git a/src/main/kotlin/cn/rtast/fancybot/util/DateUtil.kt b/src/main/kotlin/cn/rtast/fancybot/util/DateUtil.kt new file mode 100644 index 0000000..68a8f44 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/util/DateUtil.kt @@ -0,0 +1,20 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/29 + */ + + +package cn.rtast.fancybot.util + +import java.time.Instant +import java.time.LocalDate +import java.time.ZoneId + +fun Long.isSameDay(other: Long): Boolean { + val currentDate = LocalDate.now() + val dateToCompare = Instant.ofEpochSecond(other) + .atZone(ZoneId.systemDefault()) + .toLocalDate() + return currentDate == dateToCompare +} diff --git a/src/main/kotlin/cn/rtast/fancybot/util/JsonFileHandler.kt b/src/main/kotlin/cn/rtast/fancybot/util/JsonFileHandler.kt new file mode 100644 index 0000000..d542f3d --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/util/JsonFileHandler.kt @@ -0,0 +1,61 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/29 + */ + + +package cn.rtast.fancybot.util + +import cn.rtast.fancybot.ROOT_PATH +import cn.rtast.fancybot.gson +import java.io.File + +abstract class JsonFileHandler { + + val file: File + + constructor(filename: String) { + this.file = File(ROOT_PATH, filename) + initFile(null) + } + + constructor(filename: String, defaultConfig: T) { + this.file = File(ROOT_PATH, filename) + initFile(defaultConfig) + } + + private fun initFile(defaultConfig: T?) { + val configPath = File(ROOT_PATH) + configPath.mkdirs() + + if (this.file.createNewFile()) { + if (defaultConfig != null) { + this.write(defaultConfig) + } else { + val resourceConfig = this::class.java.classLoader + .getResourceAsStream(file.name) + ?.reader()?.readText()!! + this.write(resourceConfig) + } + } + } + + private fun write(data: String) { + this.file.writeText(data) + } + + fun write(data: T) { + this.write(gson.toJson(data)) + } + + inline fun read(): T { + val content = this.file.readText() + return content.fromJson() + } + + inline fun readArray(): T { + val content = this.file.readText() + return content.fromArrayJson() + } +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt b/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt new file mode 100644 index 0000000..a3afa12 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/30 + */ + + +package cn.rtast.fancybot.util.file + +import cn.rtast.fancybot.entity.Config +import cn.rtast.fancybot.util.JsonFileHandler + +class ConfigManager : JsonFileHandler("config.json") { + + val ncmAPI get() = this.read().cnmApi +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/file/JrrpManager.kt b/src/main/kotlin/cn/rtast/fancybot/util/file/JrrpManager.kt new file mode 100644 index 0000000..cbdcfc8 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/util/file/JrrpManager.kt @@ -0,0 +1,31 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/29 + */ + + +package cn.rtast.fancybot.util.file + +import cn.rtast.fancybot.entity.jrrp.JrrpRecord +import cn.rtast.fancybot.util.JsonFileHandler +import cn.rtast.fancybot.util.isSameDay +import java.time.Instant +import kotlin.random.Random + +class JrrpManager : JsonFileHandler>("jrrp.json", listOf()) { + + fun isJrrped(id: Long): Boolean { + val allJrrp = this.readArray>() + val user = allJrrp.find { it.id == id } ?: return false + return user.timestamp.isSameDay(Instant.now().epochSecond) + } + + fun jrrp(id: Long): Int { + val allJrrp = this.readArray>() + allJrrp.removeAll { it.id == id } + allJrrp.add(JrrpRecord(id, Instant.now().epochSecond, 0)) + this.write(allJrrp) + return Random.nextInt(0, 101) + } +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/file/SignManager.kt b/src/main/kotlin/cn/rtast/fancybot/util/file/SignManager.kt new file mode 100644 index 0000000..1bf961e --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/util/file/SignManager.kt @@ -0,0 +1,39 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/8/30 + */ + + +package cn.rtast.fancybot.util.file + +import cn.rtast.fancybot.entity.jrrp.JrrpRecord +import cn.rtast.fancybot.util.JsonFileHandler +import cn.rtast.fancybot.util.isSameDay +import java.time.Instant +import kotlin.random.Random + +class SignManager : JsonFileHandler>("sign.json", listOf()) { + + fun isSigned(id: Long): Boolean { + val allSign = this.readArray>() + val user = allSign.find { it.id == id } ?: return false + return user.timestamp.isSameDay(Instant.now().epochSecond) + } + + fun sign(id: Long): Long { + val allSign = this.readArray>() + val randomPoint = Random.nextLong(0, 101) + val current = allSign.find { it.id == id } ?: JrrpRecord(id, Instant.now().epochSecond, 0) + current.points = randomPoint + current.points + allSign.remove(current) + allSign.add(current) + this.write(allSign) + return randomPoint + current.points + } + + fun getStatus(id: Long): JrrpRecord? { + val allSign = this.readArray>() + return allSign.find { it.id == id } + } +} \ No newline at end of file diff --git a/src/main/resources/config.json b/src/main/resources/config.json new file mode 100644 index 0000000..d987f94 --- /dev/null +++ b/src/main/resources/config.json @@ -0,0 +1,3 @@ +{ + "cnmApi": "https://ncm.rtast.cn" +} \ No newline at end of file