From 6bce847a0f967bb6f928d93cf2ce909f2f7d4660 Mon Sep 17 00:00:00 2001 From: RTAkland Date: Wed, 5 Feb 2025 13:24:18 +0800 Subject: [PATCH] feat: add osu command --- build.gradle.kts | 4 + src/main/kotlin/cn/rtast/fancybot/Const.kt | 9 +- src/main/kotlin/cn/rtast/fancybot/FancyBot.kt | 2 - .../rtast/fancybot/commands/StatusCommand.kt | 3 - .../fancybot/commands/lookup/OSUCommand.kt | 85 +++++++++++++++++++ .../kotlin/cn/rtast/fancybot/entity/Config.kt | 2 + .../fancybot/entity/osu/OSUAccessToken.kt | 15 ++++ .../rtast/fancybot/entity/osu/OSUUserData.kt | 37 ++++++++ .../rtast/fancybot/util/CommandInterceptor.kt | 31 ------- .../rtast/fancybot/util/file/ConfigManager.kt | 2 + 10 files changed, 152 insertions(+), 38 deletions(-) create mode 100644 src/main/kotlin/cn/rtast/fancybot/commands/lookup/OSUCommand.kt create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/osu/OSUAccessToken.kt create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/osu/OSUUserData.kt delete mode 100644 src/main/kotlin/cn/rtast/fancybot/util/CommandInterceptor.kt diff --git a/build.gradle.kts b/build.gradle.kts index cfd4f0d..fa44fb9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -67,4 +67,8 @@ tasks.register("deployBot") { application { mainClass = "cn.rtast.fancybot.FancyBotKt" applicationName = "FancyBot" +} + +kotlin { + jvmToolchain(17) } \ 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 ac5f388..fbb7b5c 100644 --- a/src/main/kotlin/cn/rtast/fancybot/Const.kt +++ b/src/main/kotlin/cn/rtast/fancybot/Const.kt @@ -23,6 +23,7 @@ import cn.rtast.fancybot.util.file.* import cn.rtast.fancybot.util.item.ItemManager import com.google.gson.Gson import com.google.gson.GsonBuilder +import java.io.File import java.time.Instant val gson: Gson = GsonBuilder() @@ -31,6 +32,7 @@ val gson: Gson = GsonBuilder() .create() const val ROOT_PATH = "./data" +val ROOT_PATH_ = File(ROOT_PATH).apply { mkdirs() } const val ASSETS_BASE_URL = "https://static.rtast.cn" const val API_RTAST_URL = "https://api.rtast.cn" const val PBI_API_URL = "https://pbi.us.kg" @@ -73,7 +75,9 @@ val DEFAULT_CONFIG = Config( apiRtastKey = "114514", azureAppClientId = "114514", youtubeDataApiKey = "114514", - naiLongApiUrl = "http://127.0.0.1:5000/nailong" + naiLongApiUrl = "http://127.0.0.1:5000/nailong", + osuClientId = 111, + osuClientSecret = "222" ) val configManager = ConfigManager() @@ -112,5 +116,6 @@ val commands = listOf( TodayEatCommand(), TodayDrinkCommand(), MCLoginCommand(), RCONCommand(), GravatarCommand(), PastebinCommand(), ShuffleEchoCommand(), TodayDontEatCommand(), TodayDontDrinkCommand(), MCBotCommand(), HTTPCatCommand(), HTTPDogCommand(), - AITTSCommand(), NWWNCommand(), TJBGXLCommand(), XNMCommand(), SJCommand() + AITTSCommand(), NWWNCommand(), TJBGXLCommand(), XNMCommand(), SJCommand(), + OSUCommand() ) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt index 37b5a9f..fb7b39d 100644 --- a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt +++ b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt @@ -18,7 +18,6 @@ import cn.rtast.fancybot.commands.reply.InvertImageCommand import cn.rtast.fancybot.commands.reply.RandomRGBCommand import cn.rtast.fancybot.commands.reply.SpeedUpGIFCommand import cn.rtast.fancybot.enums.WSType -import cn.rtast.fancybot.util.CommandInterceptor import cn.rtast.fancybot.util.Logger import cn.rtast.fancybot.util.initDatabase import cn.rtast.fancybot.util.misc.* @@ -285,7 +284,6 @@ suspend fun main() { WSType.Client -> ROneBotFactory.createClient(configManager.wsAddress, accessToken, fancyBot) WSType.Server -> ROneBotFactory.createServer(configManager.wsPort, accessToken, fancyBot) } - ROneBotFactory.interceptor = CommandInterceptor() instance.addListeningGroups(*configManager.listeningGroups.toLongArray()) initDatabase() initFilesDir() diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/StatusCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/StatusCommand.kt index 7cfe115..828613b 100644 --- a/src/main/kotlin/cn/rtast/fancybot/commands/StatusCommand.kt +++ b/src/main/kotlin/cn/rtast/fancybot/commands/StatusCommand.kt @@ -10,7 +10,6 @@ package cn.rtast.fancybot.commands import cn.rtast.fancybot.START_UP_TIME import cn.rtast.fancybot.annotations.CommandDescription import cn.rtast.fancybot.enums.CommandAction -import cn.rtast.fancybot.util.CommandInterceptor import cn.rtast.fancybot.util.file.insertActionRecord import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.onebot.MessageChain @@ -44,8 +43,6 @@ class StatusCommand : BaseCommand() { .addText("操作系统: $osName / 系统架构: $osArch") .addNewLine() .addText("Java版本: $javaVersion / Kotlin版本: $kotlinVersion") - .addNewLine() - .addText("指令共执行: ${CommandInterceptor.file.readText()} 次") .build() message.reply(msg) insertActionRecord(CommandAction.Status, message.sender.userId) diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/lookup/OSUCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/lookup/OSUCommand.kt new file mode 100644 index 0000000..021d665 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/commands/lookup/OSUCommand.kt @@ -0,0 +1,85 @@ +/* + * Copyright © 2025 RTAkland + * Author: RTAkland + * Date: 2025/2/4 + */ + + +package cn.rtast.fancybot.commands.lookup + +import cn.rtast.fancybot.annotations.CommandDescription +import cn.rtast.fancybot.configManager +import cn.rtast.fancybot.entity.osu.OSUAccessToken +import cn.rtast.fancybot.entity.osu.OSUUserData +import cn.rtast.fancybot.util.Http +import cn.rtast.rob.entity.GroupMessage +import cn.rtast.rob.onebot.MessageChain +import cn.rtast.rob.util.BaseCommand +import java.awt.Color +import java.awt.RenderingHints +import java.awt.image.BufferedImage + +@CommandDescription("osu!") +class OSUCommand : BaseCommand() { + override val commandNames = listOf("/osu") + + private val clientSecret = configManager.osuClientSecret + private val clientId = configManager.osuClientId + + private fun getAccessToken(): String { + return Http.post( + "https://osu.ppy.sh/oauth/token", + formBody = mapOf( + "client_id" to clientId, "client_secret" to clientSecret, + "grant_type" to "client_credentials", "scope" to "public" + ), + headers = mapOf("Content-Type" to "application/x-www-form-urlencoded", "Accept" to "application/json") + ).accessToken + } + + private fun getUser(username: String): OSUUserData { + val token = this.getAccessToken() + val resp = Http.get( + "https://osu.ppy.sh/api/v2/users/$username/osu", + headers = mapOf("Authorization" to "Bearer $token"), + ) + return resp + } + + private fun generateProgressBar(percent: Int, length: Int = 10): String { + val completedLength = (percent * length) / 100 + val remainingLength = length - completedLength + val progressBar = "█".repeat(completedLength) + " ".repeat(remainingLength) + return "[$progressBar] $percent%" + } + + private fun formatDuration(seconds: Long): String { + val days = seconds / (24 * 3600) + val hours = (seconds % (24 * 3600)) / 3600 + val minutes = (seconds % 3600) / 60 + val parts = mutableListOf() + if (days > 0) parts.add("${days}d") + if (hours > 0) parts.add("${hours}h") + if (minutes > 0) parts.add("${minutes}m") + return parts.joinToString(" ") + } + + override suspend fun executeGroup(message: GroupMessage, args: List) { + val username = args.first() + val userData = getUser(username) + val msg = MessageChain.Builder() + .addText(userData.username) + .addNewLine() + .addText("等级 | Lv.${userData.statistics.level.current} ${generateProgressBar(userData.statistics.level.progress)}") + .addNewLine() + .addText("排名 | #${userData.statistics.globalRank} / ${userData.countryCode} #${userData.statistics.countryRank}") + .addNewLine() + .addText("准确率 | ${userData.statistics.hitAccuracy}%") + .addNewLine() + .addText("游玩时间 | ${formatDuration(userData.statistics.playTime)}") + .addNewLine() + .addText("游玩次数 | ${userData.statistics.playCount}") + .build() + message.reply(msg) + } +} \ 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 index 535f53b..b09b7d1 100644 --- a/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt +++ b/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt @@ -50,4 +50,6 @@ data class Config( val azureAppClientId: String, val youtubeDataApiKey: String, val naiLongApiUrl: String, + val osuClientSecret: String, + val osuClientId: Int ) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/osu/OSUAccessToken.kt b/src/main/kotlin/cn/rtast/fancybot/entity/osu/OSUAccessToken.kt new file mode 100644 index 0000000..b2e8059 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/osu/OSUAccessToken.kt @@ -0,0 +1,15 @@ +/* + * Copyright © 2025 RTAkland + * Author: RTAkland + * Date: 2025/2/5 + */ + + +package cn.rtast.fancybot.entity.osu + +import com.google.gson.annotations.SerializedName + +data class OSUAccessToken( + @SerializedName("access_token") + val accessToken: String, +) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/osu/OSUUserData.kt b/src/main/kotlin/cn/rtast/fancybot/entity/osu/OSUUserData.kt new file mode 100644 index 0000000..89316ae --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/osu/OSUUserData.kt @@ -0,0 +1,37 @@ +/* + * Copyright © 2025 RTAkland + * Author: RTAkland + * Date: 2025/2/5 + */ + + +package cn.rtast.fancybot.entity.osu + +import com.google.gson.annotations.SerializedName + +data class OSUUserData( + val statistics: Statistics, + @SerializedName("country_code") + val countryCode: String, + val username: String, +) { + data class Statistics( + @SerializedName("global_rank") + val globalRank: Long, + @SerializedName("play_time") + val playTime: Long, + @SerializedName("hit_accuracy") + val hitAccuracy: Double, + @SerializedName("country_rank") + val countryRank: Int, + val pp: Float, + val level: Level, + @SerializedName("play_count") + val playCount: Int, + ) + + data class Level( + val current: Int, + val progress: Int + ) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/CommandInterceptor.kt b/src/main/kotlin/cn/rtast/fancybot/util/CommandInterceptor.kt deleted file mode 100644 index 9144669..0000000 --- a/src/main/kotlin/cn/rtast/fancybot/util/CommandInterceptor.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright © 2024 RTAkland - * Author: RTAkland - * Date: 2024/11/7 - */ - - -package cn.rtast.fancybot.util - -import cn.rtast.fancybot.ROOT_PATH -import cn.rtast.rob.ROneBotFactory -import cn.rtast.rob.entity.GroupMessage -import cn.rtast.rob.entity.PrivateMessage -import cn.rtast.rob.interceptor.ExecutionInterceptor -import cn.rtast.rob.util.BaseCommand -import java.io.File - -class CommandInterceptor : ExecutionInterceptor() { - - companion object { - val file = File(ROOT_PATH, "/caches/command_execution_count").apply { createNewFile() } - } - - override suspend fun afterGroupExecute(message: GroupMessage, command: BaseCommand) { - file.writeText(ROneBotFactory.totalCommandExecutionTimes.toString()) - } - - override suspend fun afterPrivateExecute(message: PrivateMessage, command: BaseCommand) { - file.writeText(ROneBotFactory.totalCommandExecutionTimes.toString()) - } -} \ 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 index 976dde6..a795992 100644 --- a/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt +++ b/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt @@ -50,4 +50,6 @@ class ConfigManager : JsonFileHandler("config.json") { val azureAppClientId = config.azureAppClientId val youtubeDataApiKey = config.youtubeDataApiKey val naiLongApiUrl = config.naiLongApiUrl + val osuClientId = config.osuClientId + val osuClientSecret = config.osuClientSecret } \ No newline at end of file