feat: add osu command
This commit is contained in:
10 files changed
+152
-38
No files matched your search
@@ -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()
|
||||
)
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<OSUAccessToken>(
|
||||
"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<OSUUserData>(
|
||||
"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<String>()
|
||||
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<String>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -50,4 +50,6 @@ data class Config(
|
||||
val azureAppClientId: String,
|
||||
val youtubeDataApiKey: String,
|
||||
val naiLongApiUrl: String,
|
||||
val osuClientSecret: String,
|
||||
val osuClientId: Int
|
||||
)
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -50,4 +50,6 @@ class ConfigManager : JsonFileHandler<Config>("config.json") {
|
||||
val azureAppClientId = config.azureAppClientId
|
||||
val youtubeDataApiKey = config.youtubeDataApiKey
|
||||
val naiLongApiUrl = config.naiLongApiUrl
|
||||
val osuClientId = config.osuClientId
|
||||
val osuClientSecret = config.osuClientSecret
|
||||
}
|
||||
Reference in New Issue
Block a user