mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-13 06:30:13 +08:00
Support forward message refinement, close #623
This commit is contained in:
parent
d7272e7e9a
commit
b659d55fec
@ -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;
|
||||
|
@ -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>
|
||||
|
||||
/**
|
||||
* 通过好友验证
|
||||
*
|
||||
|
@ -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")
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user