Support forward message refinement, close #623

This commit is contained in:
Karlatemp 2021-02-02 20:14:40 +08:00 committed by Him188
parent d7272e7e9a
commit b659d55fec
5 changed files with 90 additions and 13 deletions

View File

@ -91,6 +91,8 @@ public abstract interface class net/mamoe/mirai/IMirai : net/mamoe/mirai/LowLeve
public abstract fun createImage (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/Image;
public synthetic fun deleteGroupAnnouncement (Lnet/mamoe/mirai/Bot;JLjava/lang/String;)Lkotlin/Unit;
public fun deleteGroupAnnouncement (Lnet/mamoe/mirai/Bot;JLjava/lang/String;)V
public fun downloadForwardMessage (Lnet/mamoe/mirai/Bot;Ljava/lang/String;)Ljava/util/List;
public abstract fun downloadForwardMessage (Lnet/mamoe/mirai/Bot;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun downloadLongMessage (Lnet/mamoe/mirai/Bot;Ljava/lang/String;)Lnet/mamoe/mirai/message/data/MessageChain;
public abstract fun downloadLongMessage (Lnet/mamoe/mirai/Bot;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getBotFactory ()Lnet/mamoe/mirai/BotFactory;

View File

@ -179,6 +179,15 @@ public interface IMirai : LowLevelApiAccessor {
resourceId: String,
): MessageChain
/**
* @since 2.3
*/
@JvmBlockingBridge
public suspend fun downloadForwardMessage(
bot: Bot,
resourceId: String,
): List<ForwardMessage.Node>
/**
* 通过好友验证
*

View File

@ -965,6 +965,28 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
)
override suspend fun downloadLongMessage(bot: Bot, resourceId: String): MessageChain {
return downloadMultiMsgTransmit(bot, resourceId, ResourceKind.LONG_MESSAGE).msg
.toMessageChainNoSource(bot.id, 0, MessageSourceKind.GROUP)
}
override suspend fun downloadForwardMessage(bot: Bot, resourceId: String): List<ForwardMessage.Node> {
return downloadMultiMsgTransmit(bot, resourceId, ResourceKind.FORWARD_MESSAGE).msg.map { msg ->
ForwardMessage.Node(
senderId = msg.msgHead.fromUin,
time = msg.msgHead.msgTime,
senderName = msg.msgHead.groupInfo?.groupCard
?: msg.msgHead.fromNick.takeIf { it.isNotEmpty() }
?: msg.msgHead.fromUin.toString(),
messageChain = listOf(msg).toMessageChainNoSource(bot.id, 0, MessageSourceKind.GROUP)
)
}
}
private suspend fun downloadMultiMsgTransmit(
bot: Bot,
resourceId: String,
resourceKind: ResourceKind,
): MsgTransmit.PbMultiMsgTransmit {
bot.asQQAndroidBot()
when (val resp = MultiMsg.ApplyDown(bot.client, 2, resourceId, 1).sendAndExpect(bot)) {
is MultiMsg.ApplyDown.Response.RequireDownload -> {
@ -977,7 +999,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
host = "https://ssl.htdata.qq.com",
port = 443,
times = 3,
resourceKind = ResourceKind.LONG_MESSAGE,
resourceKind = resourceKind,
channelKind = ChannelKind.HTTP
) { host, _ ->
http.get("$host${origin.thumbDownPara}")
@ -985,7 +1007,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
} else tryServersDownload(
bot = bot,
servers = origin.uint32DownIp.zip(origin.uint32DownPort),
resourceKind = ResourceKind.LONG_MESSAGE,
resourceKind = resourceKind,
channelKind = ChannelKind.HTTP
) { ip, port ->
http.get("http://$ip:$port${origin.thumbDownPara}")
@ -1011,9 +1033,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
}
val content = down.msgContent.ungzip()
val transmit = content.loadAs(MsgTransmit.PbMultiMsgTransmit.serializer())
return transmit.msg.toMessageChainNoSource(bot.id, 0, MessageSourceKind.GROUP)
return content.loadAs(MsgTransmit.PbMultiMsgTransmit.serializer())
}
MultiMsg.ApplyDown.Response.MessageTooLarge -> {
error("Message is too large and cannot download")

View File

@ -32,18 +32,57 @@ internal data class LongMessageInternal internal constructor(override val conten
}
// internal runtime value, not serializable
internal data class ForwardMessageInternal(override val content: String, val resId: String) : AbstractServiceMessage(), RefinableMessage {
@Suppress("RegExpRedundantEscape", "UnnecessaryVariable")
internal data class ForwardMessageInternal(override val content: String, val resId: String) : AbstractServiceMessage(),
RefinableMessage {
override val serviceId: Int get() = 35
override suspend fun refine(contact: Contact, context: MessageChain): Message {
// val bot = contact.bot.asQQAndroidBot()
// TODO: 2021/2/2 Support forward message refinement
// https://github.com/mamoe/mirai/issues/623
return this
val bot = contact.bot.asQQAndroidBot()
val msgXml = content.substringAfter("<msg", "")
val xmlHead = msgXml.substringBefore("<item")
val xmlFoot: String
val xmlContent = msgXml.substringAfter("<item").let {
xmlFoot = it.substringAfter("</item", "")
it.substringBefore("</item")
}
val brief = xmlHead.findField("brief")
val summary = SUMMARY_REGEX.find(xmlContent)?.let { it.groupValues[1] } ?: ""
val titles = TITLE_REGEX.findAll(xmlContent)
.map { it.groupValues[2].trim() }.toMutableList()
val title = titles.removeFirstOrNull() ?: ""
val preview = titles
val source = xmlFoot.findField("name")
return RichMessageOrigin(resId) + ForwardMessage(
preview = preview,
title = title,
brief = brief,
source = source,
summary = summary.trim(),
nodeList = Mirai.downloadForwardMessage(bot, resId)
)
}
companion object Key :
AbstractPolymorphicMessageKey<ServiceMessage, ForwardMessageInternal>(ServiceMessage, { it.safeCast() })
AbstractPolymorphicMessageKey<ServiceMessage, ForwardMessageInternal>(ServiceMessage, { it.safeCast() }) {
val SUMMARY_REGEX = """\<summary.*\>(.*?)\<\/summary\>""".toRegex()
@Suppress("SpellCheckingInspection")
val TITLE_REGEX = """\<title([A-Za-z\s#\"0-9\=]*)\>([\u0000-\uFFFF]*?)\<\/title\>""".toRegex()
fun String.findField(type: String): String {
return substringAfter("$type=\"", "")
.substringBefore("\"", "")
}
}
}
internal interface RefinableMessage : SingleMessage {

View File

@ -391,11 +391,18 @@ private object ReceiveMessageTransformer {
val resId = findStringProperty("m_resid")
val msg = when(findStringProperty("multiMsgFlag").toIntOrNull()) {
val msg = if (resId.isEmpty()) {
SimpleServiceMessage(35, content)
} else when (findStringProperty("multiMsgFlag").toIntOrNull()) {
1 -> LongMessageInternal(content, resId)
0 -> ForwardMessageInternal(content, resId)
else -> {
SimpleServiceMessage(35, content)
// from PC QQ
if (findStringProperty("action") == "viewMultiMsg") {
ForwardMessageInternal(content, resId)
} else {
SimpleServiceMessage(35, content)
}
}
}