From ff65333a8f131746945e8c74c53c101b7d4c53f1 Mon Sep 17 00:00:00 2001 From: RTAkland Date: Sat, 12 Oct 2024 18:35:16 +0800 Subject: [PATCH] feat: support parse bilibili user --- src/main/kotlin/cn/rtast/fancybot/FancyBot.kt | 3 +- ...arseCommand.kt => BilibiliParseCommand.kt} | 55 ++++++++++++++++++- .../fancybot/entity/bili/BiliUserInfo.kt | 16 ++++++ .../cn/rtast/fancybot/entity/bili/UserInfo.kt | 32 +++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) rename src/main/kotlin/cn/rtast/fancybot/commands/parse/{BVParseCommand.kt => BilibiliParseCommand.kt} (80%) create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/bili/BiliUserInfo.kt create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/bili/UserInfo.kt diff --git a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt index 70dc5a6..6d9cc50 100644 --- a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt +++ b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt @@ -68,7 +68,8 @@ class FancyBot : OneBotListener { ReverseGIFCommand.callback(message) AsciiArtCommand.callback(message) ScanQRCodeCommand.callback(message) - BVParseCommand.parse(this, message) + BiliVideoParseCommand.parse(this, message) + BiliUserParseCommand.parse(this, message) if (message.rawMessage.toList().any { it in arrayListOf('*', '-', '/', '+', '=') }) { val calculateResult = CalculateCommand.parse(message.rawMessage) diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/parse/BVParseCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/parse/BilibiliParseCommand.kt similarity index 80% rename from src/main/kotlin/cn/rtast/fancybot/commands/parse/BVParseCommand.kt rename to src/main/kotlin/cn/rtast/fancybot/commands/parse/BilibiliParseCommand.kt index 751a891..f65b9b8 100644 --- a/src/main/kotlin/cn/rtast/fancybot/commands/parse/BVParseCommand.kt +++ b/src/main/kotlin/cn/rtast/fancybot/commands/parse/BilibiliParseCommand.kt @@ -11,11 +11,14 @@ import cn.rtast.fancybot.entity.bili.* import cn.rtast.fancybot.util.Http import cn.rtast.fancybot.util.misc.Resources import cn.rtast.fancybot.util.misc.drawCustomImage +import cn.rtast.fancybot.util.misc.drawString +import cn.rtast.fancybot.util.misc.toBufferedImage import cn.rtast.fancybot.util.str.encodeToBase64 import cn.rtast.fancybot.util.str.formatNumber import cn.rtast.fancybot.util.str.fromJson import cn.rtast.fancybot.util.str.setTruncate import cn.rtast.fancybot.util.misc.toByteArray +import cn.rtast.fancybot.util.misc.toURL import cn.rtast.rob.entity.GroupMessage import cn.rtast.rob.enums.ArrayMessageType import cn.rtast.rob.util.ob.MessageChain @@ -24,6 +27,7 @@ import okhttp3.OkHttpClient import okhttp3.Request import java.awt.Color import java.awt.Font +import java.awt.Image import java.awt.RenderingHints import java.awt.image.BufferedImage import java.math.BigInteger @@ -31,7 +35,7 @@ import java.net.URI import javax.imageio.ImageIO -object BVParseCommand { +object BiliVideoParseCommand { private val avRegex = Regex("av(\\d+)", RegexOption.IGNORE_CASE) private val bvRegex = Regex("BV[\\dA-Za-z]{10}") private val shortUrlRegex = Regex("https://b23\\.tv/\\w{6,8}") @@ -230,4 +234,53 @@ object BVParseCommand { .build() listener.sendGroupMessage(message.groupId, msg) } +} + +object BiliUserParseCommand { + + private val idRegex = Regex("https://space\\.bilibili\\.com/(\\d+)") + private const val USER_INFO_API_URL = "https://api.bilibili.com/x/web-interface/card" + private val font = Font("Serif", Font.BOLD, 24) + private const val IMAGE_WIDTH = 500 + private const val IMAGE_HEIGHT = 300 + + + private fun getUserInfo(userId: String): BiliUserInfo { + val result = Http.get(USER_INFO_API_URL, mapOf("mid" to userId)).data.card + return BiliUserInfo(result.name, result.levelInfo.currentLevel, result.face, result.fans, result.sign) + } + + private fun getUserFace(url: String) = url.toURL().readBytes().toBufferedImage() + + private fun createUserImage(userInfo: BiliUserInfo): String { + val image = BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_ARGB) + val g2d = image.createGraphics() + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) + g2d.color = Color.WHITE + g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT) + g2d.font = font + g2d.color = Color.BLACK + g2d.drawString("用户名: ${userInfo.name}", 150, 50) + g2d.drawString("粉丝数: ${userInfo.fans}", 150, 100) + g2d.drawString("等级: ${userInfo.level}", 150, 150) + g2d.drawString("签名: ${userInfo.sign}", 150, 200, 200) + val faceImage = getUserFace(userInfo.avatar) + val resizedFaceImage = faceImage.getScaledInstance(100, 100, Image.SCALE_SMOOTH) + g2d.drawImage(resizedFaceImage, 20, 20, null) + g2d.dispose() + return image.toByteArray().encodeToBase64() + } + + suspend fun parse(listener: OneBotListener, message: GroupMessage) { + val match = idRegex.find(message.rawMessage) + if (match != null) { + val userId = match.groupValues[1] + val userInfo = this.getUserInfo(userId) + val userCardImage = this.createUserImage(userInfo) + val msg = MessageChain.Builder() + .addImage(userCardImage, true) + .build() + listener.sendGroupMessage(message.groupId, msg) + } + } } \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/bili/BiliUserInfo.kt b/src/main/kotlin/cn/rtast/fancybot/entity/bili/BiliUserInfo.kt new file mode 100644 index 0000000..37d24e4 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/bili/BiliUserInfo.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/10/12 + */ + + +package cn.rtast.fancybot.entity.bili + +data class BiliUserInfo( + val name: String, + val level: Int, + val avatar: String, + val fans: Int, + val sign: String, +) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/bili/UserInfo.kt b/src/main/kotlin/cn/rtast/fancybot/entity/bili/UserInfo.kt new file mode 100644 index 0000000..f1a0751 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/bili/UserInfo.kt @@ -0,0 +1,32 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/10/12 + */ + + +package cn.rtast.fancybot.entity.bili + +import com.google.gson.annotations.SerializedName + +data class UserInfo( + val data: Data +) { + data class Data( + val card: Card, + ) + + data class Card( + val face: String, + val name: String, + val fans: Int, + val sign: String, + @SerializedName("level_info") + val levelInfo: LevelInfo + ) + + data class LevelInfo( + @SerializedName("current_level") + val currentLevel: Int, + ) +} \ No newline at end of file