diff --git a/onebot/src/main/kotlin/client/config/BotConfig.kt b/onebot/src/main/kotlin/client/config/BotConfig.kt index ad589f6..21a63e0 100644 --- a/onebot/src/main/kotlin/client/config/BotConfig.kt +++ b/onebot/src/main/kotlin/client/config/BotConfig.kt @@ -31,6 +31,10 @@ class BotConfig( * 该选项无法禁止其它插件自行调用网络接口 */ val noPlatform: Boolean = false, + /** + * 发送消息时,是否使用 CQ 码 + */ + val useCQCode: Boolean = false, /** * 重连尝试次数 */ diff --git a/onebot/src/main/kotlin/client/core/Bot.kt b/onebot/src/main/kotlin/client/core/Bot.kt index 64b60be..dbe5fb5 100644 --- a/onebot/src/main/kotlin/client/core/Bot.kt +++ b/onebot/src/main/kotlin/client/core/Bot.kt @@ -52,6 +52,21 @@ class Bot( private var idInternal: Long = 0 val id: Long get() = idInternal + + fun JsonObject.addMessage(key: String, msg: String) { + runCatching { + JsonParser.parseString(msg).asJsonArray + }.onSuccess { + if (config.useCQCode) { + addProperty(key, CQCode.fromJson(it)) + } else { + add(key, it) + } + }.onFailure { + addProperty(key, msg) + } + } + /** * 发送消息 * @@ -82,13 +97,7 @@ class Bot( val action = ActionPathEnum.SEND_PRIVATE_MSG val params = JsonObject() params.addProperty("user_id", userId) - kotlin.runCatching { - JsonParser.parseString(msg).asJsonArray - }.onSuccess { - params.add("message", it) - }.onFailure { - params.addProperty("message", msg) - } + params.addMessage("message", msg) params.addProperty("auto_escape", autoEscape) val result = actionHandler.action(this, action, params) return result.withToken() @@ -107,13 +116,7 @@ class Bot( val action = ActionPathEnum.SEND_GROUP_MSG val params = JsonObject() params.addProperty("group_id", groupId) - kotlin.runCatching { - JsonParser.parseString(msg).asJsonArray - }.onSuccess { - params.add("message", it) - }.onFailure { - params.addProperty("message", msg) - } + params.addMessage("message", msg) params.addProperty("auto_escape", autoEscape) val result = actionHandler.action(this, action, params) return result.withToken() @@ -153,13 +156,7 @@ class Bot( val params = JsonObject() params.addProperty("guild_id", guildId) params.addProperty("channel_id", channelId) - kotlin.runCatching { - JsonParser.parseString(msg).asJsonArray - }.onSuccess { - params.add("message", it) - }.onFailure { - params.addProperty("message", msg) - } + params.addMessage("message", msg) val result = actionHandler.action(this, action, params) return result.withToken() } diff --git a/onebot/src/main/kotlin/sdk/util/CQCode.kt b/onebot/src/main/kotlin/sdk/util/CQCode.kt new file mode 100644 index 0000000..b6897e7 --- /dev/null +++ b/onebot/src/main/kotlin/sdk/util/CQCode.kt @@ -0,0 +1,101 @@ +package cn.evolvefield.onebot.sdk.util + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive + +object CQCode { + fun fromJson(json: JsonArray): String { + return buildString { + for (ele in json) { + val obj = ele.asJsonObject + val type = obj["type"].asString + val data = obj["data"] + if (data is JsonObject) { + // 纯文本 + if (type == "text") { + append(data["text"].asString + .replace("&", "&") + .replace("[", "[") + .replace("]", "]")) + continue + } + append("[CQ:$type") + for ((key, value) in data.asMap()) { + // 约定: key 不会出现需要转义的字符 + append(",$key=") + append( + if (value is JsonPrimitive) { + value.asString + } else { + value.toString() + }.replace("&", "&") + .replace("[", "[") + .replace("]", "]") + .replace(",", ",") + ) + } + } + append("]") + } + } + } + + fun toJson(s: String): JsonArray { + val array = JsonArray() + fun add(type: String, data: JsonObject.() -> Unit) { + array.add(JsonObject().also { + it.addProperty("type", type) + it.add("data", JsonObject().apply(data)) + }) + } + fun String.decode(): String { + return replace("&", "&") + .replace("[", "[") + .replace("]", "]") + } + fun String.decodeValue(): String { + return decode() + .replace(",", ",") + } + fun StringBuilder.decode(): String { + return toString() + .decode() + .also { clear() } + } + val temp = StringBuilder() + var flag = false + for (c in s) { + if (c == '[' && temp.isNotEmpty()) { + add("text") { + addProperty("text", temp.decode()) + } + } + temp.append(c) + if (!flag && temp.startsWith("[CQ:")) flag = true + if (flag && c == ']') { + val cq = temp.substring(4, temp.length - 1) + if (cq.contains(',')) { + val split = cq.split(',') + add(split[0]) { + for (s1 in split.drop(1)) { + if (!s1.contains('=')) continue + val (key, value) = s1 + .split('=', limit = 2) + .run { this[0] to this[1].decodeValue() } + addProperty(key, value) + } + } + } else add(cq) { } + temp.clear() + flag = false + } + } + if (temp.isNotEmpty()) { + add("text") { + addProperty("text", temp.decode()) + } + } + return array + } +} diff --git a/overflow-core/src/main/kotlin/top/mrxiaom/overflow/internal/message/OnebotMessages.kt b/overflow-core/src/main/kotlin/top/mrxiaom/overflow/internal/message/OnebotMessages.kt index 0691a18..6e854e6 100644 --- a/overflow-core/src/main/kotlin/top/mrxiaom/overflow/internal/message/OnebotMessages.kt +++ b/overflow-core/src/main/kotlin/top/mrxiaom/overflow/internal/message/OnebotMessages.kt @@ -1,6 +1,7 @@ package top.mrxiaom.overflow.internal.message import cn.evolvefield.onebot.sdk.entity.MsgId +import cn.evolvefield.onebot.sdk.util.CQCode import com.google.gson.JsonParser import kotlinx.serialization.encodeToString import kotlinx.serialization.json.* @@ -239,9 +240,18 @@ internal object OnebotMessages { * @param source 消息源 */ internal suspend fun deserializeFromOneBot(bot: RemoteBot, message: String, source: MessageSource? = null): MessageChain { - return kotlin.runCatching { Json.parseToJsonElement(message).jsonArray } - .map { deserializeFromOneBotJson(bot, it, source) }.getOrNull() ?: kotlin.run { + return runCatching { + Json.parseToJsonElement(message).jsonArray + }.map { + deserializeFromOneBotJson(bot, it, source) + }.getOrElse { + return runCatching { + Json.parseToJsonElement(CQCode.toJson(message).toString()).jsonArray + }.map { + deserializeFromOneBotJson(bot, it, source) + }.getOrElse { source?.plus(message) ?: PlainText(message).toMessageChain() + } } } @@ -421,7 +431,11 @@ internal object OnebotMessages { "inline_keyboard" -> { // OpenShamrock val botAppId = data["bot_appid"].long - val rows = data["rows"]!!.jsonArray.map { e1 -> + val rowsRaw = data["rows"].run { + if (this is JsonArray) this + else Json.parseToJsonElement(string).jsonArray + } + val rows = rowsRaw.jsonArray.map { e1 -> val obj1 = e1.jsonObject InlineKeyboardRow( buttons = obj1["buttons"]!!.jsonArray.map { e2 ->