From b729fc1fbdcc8f0d45617ab921c8f79467b25099 Mon Sep 17 00:00:00 2001 From: ryoii Date: Fri, 10 Feb 2023 18:28:51 +0800 Subject: [PATCH] Support modifying forward message display content #680 --- docs/api/MessageType.md | 30 ++++++++++++------- .../adapter/internal/convertor/convertor.kt | 19 +++++++++++- .../adapter/internal/convertor/message.kt | 2 +- .../api/http/adapter/internal/dto/message.kt | 22 ++++++++++++-- 4 files changed, 58 insertions(+), 15 deletions(-) diff --git a/docs/api/MessageType.md b/docs/api/MessageType.md index 814008f1..22e5cb5a 100644 --- a/docs/api/MessageType.md +++ b/docs/api/MessageType.md @@ -441,6 +441,13 @@ ```json5 { "type": "Forward", + "display": { + "title": "群聊的聊天记录", + "brief": "[聊天记录]", + "source": "聊天记录", + "preview": ["msg1", "msg2", "msg3", "msg4"], + "summary": "查看x条转发消息" + }, "nodeList": [ { "senderId": 123, @@ -457,17 +464,18 @@ } ``` -| 名字 | 类型 | 说明 | -|----------------------|--------|----------------------------------------| -| nodeList | object | 消息节点 | -| senderId | Long | 发送人QQ号 | -| time | Int | 发送时间 | -| senderName | String | 显示名称 | -| messageChain | Array | 消息数组 | -| messageId | Int | 可以只使用消息messageId,从当前对话上下文缓存中读取一条消息作为节点 | -| messageRef | object | 引用缓存中其他对话上下文的消息作为节点 | -| messageRef.messageId | Int | 引用的 messageId | -| messageRef.target | Int | 引用的上下文目标,群号、好友账号 | +| 名字 | 类型 | 说明 | +|----------------------|--------|----------------------------------------------------------| +| display | object | 转发消息的卡片显示文本,参考上文json确认参数含义,值为表示使用客户端默认值;display为空表示全用默认值 | +| nodeList | object | 消息节点 | +| senderId | Long | 发送人QQ号 | +| time | Int | 发送时间 | +| senderName | String | 显示名称 | +| messageChain | Array | 消息数组 | +| messageId | Int | 可以只使用消息messageId,从当前对话上下文缓存中读取一条消息作为节点 | +| messageRef | object | 引用缓存中其他对话上下文的消息作为节点 | +| messageRef.messageId | Int | 引用的 messageId | +| messageRef.target | Int | 引用的上下文目标,群号、好友账号 | > (senderId, time, senderName, messageChain), messageId, messageRef 是三种不同构造引用节点的方式,选其中一个/组传参即可 diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/convertor/convertor.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/convertor/convertor.kt index 65587797..c34eb42d 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/convertor/convertor.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/convertor/convertor.kt @@ -69,6 +69,7 @@ internal suspend fun MessageDTO.toMessage(contact: Contact, cache: Persistence) name.isNotEmpty() -> Face(FaceMap[name]) else -> Face(255) } + is PlainDTO -> PlainText(text) is ImageDTO -> imageLikeToMessage(contact) is FlashImageDTO -> imageLikeToMessage(contact)?.flash() @@ -80,6 +81,7 @@ internal suspend fun MessageDTO.toMessage(contact: Contact, cache: Persistence) is DiceDTO -> Dice(value) is MusicShareDTO -> MusicShare(MusicKind.valueOf(kind), title, summary, jumpUrl, pictureUrl, musicUrl, brief) is ForwardMessageDTO -> buildForwardMessage(contact) { + display?.let { displayStrategy = display } nodeList.forEach { if (it.messageId != null) { cache.getMessageOrNull(Context(intArrayOf(it.messageId), contact))?.apply { @@ -95,6 +97,7 @@ internal suspend fun MessageDTO.toMessage(contact: Contact, cache: Persistence) } } } + is MiraiCodeDTO -> MiraiCode.deserializeMiraiCode(code) // ignore is QuoteDTO, @@ -112,33 +115,47 @@ private suspend fun ImageLikeDTO.imageLikeToMessage(contact: Contact) = when { size = this@imageLikeToMessage.size isEmoji = this@imageLikeToMessage.isEmoji } + !url.isNullOrBlank() -> withContext(Dispatchers.IO) { url!!.useUrl { it.uploadAsImage(contact) } } + !path.isNullOrBlank() -> with(File(path!!)) { if (exists()) { inputStream().useStream { it.uploadAsImage(contact) } } else throw NoSuchFileException(this) } + !base64.isNullOrBlank() -> with(Base64.getDecoder().decode(base64)) { inputStream().useStream { it.uploadAsImage(contact) } } + else -> null } private suspend fun VoiceLikeDTO.voiceLikeToMessage(contact: Contact) = when { contact !is AudioSupported -> null - !voiceId.isNullOrBlank() -> OfflineAudio.Factory.create(voiceId!!, voiceId!!.substringBefore(".").toHexArray(), 0, AudioCodec.SILK, null) + !voiceId.isNullOrBlank() -> OfflineAudio.Factory.create( + voiceId!!, + voiceId!!.substringBefore(".").toHexArray(), + 0, + AudioCodec.SILK, + null + ) + !url.isNullOrBlank() -> withContext(Dispatchers.IO) { url!!.useUrl { contact.uploadAudio(it) } } + !path.isNullOrBlank() -> with(File(path!!)) { if (exists()) { inputStream().useStream { contact.uploadAudio(it) } } else throw NoSuchFileException(this) } + !base64.isNullOrBlank() -> with(Base64.getDecoder().decode(base64)) { inputStream().useStream { contact.uploadAudio(it) } } + else -> null } \ No newline at end of file diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/convertor/message.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/convertor/message.kt index edd98837..0d59b5de 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/convertor/message.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/convertor/message.kt @@ -82,7 +82,7 @@ internal suspend fun Message.toDTO() = when (this) { is Dice -> DiceDTO(value) is MarketFace -> MarketFaceDTO(id, name) is MusicShare -> MusicShareDTO(kind.name, title, summary, jumpUrl, pictureUrl, musicUrl, brief) - is ForwardMessage -> ForwardMessageDTO(nodeList.map { + is ForwardMessage -> ForwardMessageDTO(null, nodeList.map { ForwardMessageNode(it.senderId, it.time, it.senderName, it.messageChain.toDTO { d -> d != UnknownMessageDTO }) }) is FileMessage -> FileDTO(id, name, size) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/dto/message.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/dto/message.kt index 32d6d123..155b8317 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/dto/message.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/internal/dto/message.kt @@ -12,6 +12,8 @@ package net.mamoe.mirai.api.http.adapter.internal.dto import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.MessageIdDTO +import net.mamoe.mirai.message.data.ForwardMessage +import net.mamoe.mirai.message.data.RawForwardMessage @Serializable internal sealed class MessagePacketDTO : EventDTO() { @@ -172,7 +174,7 @@ internal data class DiceDTO( @Serializable @SerialName("MarketFace") internal data class MarketFaceDTO( - val id: Int, + val id: Int, val name: String, ) : MessageDTO() @@ -191,9 +193,25 @@ internal data class MusicShareDTO( @Serializable @SerialName("Forward") internal data class ForwardMessageDTO( - val nodeList: List + val display: ForwardMessageDisplayDTO?, + val nodeList: List, ) : MessageDTO() +@Serializable +internal data class ForwardMessageDisplayDTO( + val brief: String?, + val preview: List?, + val source: String?, + val summary: String?, + val title: String?, +) : ForwardMessage.DisplayStrategy { + override fun generateBrief(forward: RawForwardMessage) = brief ?: super.generateBrief(forward) + override fun generatePreview(forward: RawForwardMessage) = preview ?: super.generatePreview(forward) + override fun generateSource(forward: RawForwardMessage) = source ?: super.generateSource(forward) + override fun generateSummary(forward: RawForwardMessage) = summary ?: super.generateSummary(forward) + override fun generateTitle(forward: RawForwardMessage) = title ?: super.generateTitle(forward) +} + @Serializable internal data class ForwardMessageNode( val senderId: Long? = null,