diff --git a/qqinterface/src/main/java/com/tencent/mobileqq/emoticon/QQSysFaceUtil.java b/qqinterface/src/main/java/com/tencent/mobileqq/emoticon/QQSysFaceUtil.java index ff9d14a..8264bf5 100644 --- a/qqinterface/src/main/java/com/tencent/mobileqq/emoticon/QQSysFaceUtil.java +++ b/qqinterface/src/main/java/com/tencent/mobileqq/emoticon/QQSysFaceUtil.java @@ -19,4 +19,11 @@ public class QQSysFaceUtil { public static String getFaceDescription(int localId) { return ""; } + + public static String getPrueFaceDescription(String str) { + if (str == null) { + return null; + } + return str.startsWith("/") ? str.substring(1) : str; + } } diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/MessageMaker.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/MessageMaker.kt index 5e3f05b..bcfabc2 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/MessageMaker.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/MessageMaker.kt @@ -9,6 +9,7 @@ import com.tencent.mobileqq.qroute.QRoute import com.tencent.qphone.base.remote.ToServiceMsg import com.tencent.qqnt.aio.adapter.api.IAIOPttApi import com.tencent.qqnt.kernel.nativeinterface.ArkElement +import com.tencent.qqnt.kernel.nativeinterface.FaceBubbleElement import com.tencent.qqnt.kernel.nativeinterface.FaceElement import com.tencent.qqnt.kernel.nativeinterface.MarkdownElement import com.tencent.qqnt.kernel.nativeinterface.MarketFaceElement @@ -20,9 +21,9 @@ import com.tencent.qqnt.kernel.nativeinterface.PttElement import com.tencent.qqnt.kernel.nativeinterface.QQNTWrapperUtil import com.tencent.qqnt.kernel.nativeinterface.ReplyElement import com.tencent.qqnt.kernel.nativeinterface.RichMediaFilePathInfo +import com.tencent.qqnt.kernel.nativeinterface.SmallYellowFaceInfo import com.tencent.qqnt.kernel.nativeinterface.TextElement import com.tencent.qqnt.kernel.nativeinterface.VideoElement -import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject @@ -45,7 +46,9 @@ import moe.fuqiuluo.qqinterface.servlet.transfile.with import moe.fuqiuluo.shamrock.helper.ActionMsgException import moe.fuqiuluo.shamrock.helper.ContactHelper import moe.fuqiuluo.shamrock.helper.IllegalParamsException +import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.LocalCacheHelper +import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.helper.LogicException import moe.fuqiuluo.shamrock.helper.MessageHelper import moe.fuqiuluo.shamrock.helper.MusicHelper @@ -62,8 +65,6 @@ import moe.fuqiuluo.shamrock.utils.AudioUtils import moe.fuqiuluo.shamrock.utils.FileUtils import moe.fuqiuluo.shamrock.utils.MediaType import moe.fuqiuluo.shamrock.utils.PlatformUtils -import moe.fuqiuluo.shamrock.helper.Level -import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher import moe.fuqiuluo.shamrock.xposed.helper.msgService @@ -106,8 +107,32 @@ internal object MessageMaker { "basketball" to MessageMaker::createBasketballElem, //"node" to MessageMaker::createNodeElem, //"multi_msg" to MessageMaker::createLongMsgStruct, + "bubble_face" to MessageMaker::createBubbleFaceElem, ) + private suspend fun createBubbleFaceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result { + data.checkAndThrow("id", "count") + val faceId = data["id"].asInt + val local = QQSysFaceUtil.convertToLocal(faceId) + val name = QQSysFaceUtil.getFaceDescription(local) + val count = data["count"].asInt + val elem = MsgElement() + elem.elementType = MsgConstant.KELEMTYPEFACEBUBBLE + val face = FaceBubbleElement() + face.faceType = 13 + face.faceCount = count + face.faceSummary = QQSysFaceUtil.getPrueFaceDescription(name) + val smallYellowFaceInfo = SmallYellowFaceInfo() + smallYellowFaceInfo.index = faceId + smallYellowFaceInfo.compatibleText = face.faceSummary + smallYellowFaceInfo.text = face.faceSummary + face.yellowFaceInfo = smallYellowFaceInfo + face.faceFlag = 0 + face.content = data["text"].asStringOrNull ?: "[${face.faceSummary}]x$count" + elem.faceBubbleElement = face + return Result.success(elem) + } + // private suspend fun createNodeElem( // chatType: Int, // msgId: Long, @@ -475,19 +500,31 @@ internal object MessageMaker { private suspend fun createFaceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result { data.checkAndThrow("id") + val big = data["big"].asBooleanOrNull ?: false + val elem = MsgElement() elem.elementType = MsgConstant.KELEMTYPEFACE val face = FaceElement() + // 1 old face + // 2 normal face + // 3 super face // 4 is market face // 5 is vas poke - face.faceType = 0 + face.faceType = if (big) 3 else 2 val serverId = data["id"].asInt - val localId = QQSysFaceUtil.convertToLocal(serverId) face.faceIndex = serverId - face.faceText = QQSysFaceUtil.getFaceDescription(localId) + face.faceText = QQSysFaceUtil.getFaceDescription(QQSysFaceUtil.convertToLocal(serverId)) face.imageType = 0 - face.packId = "0" + if (big) { + face.stickerId = 30.toString() + face.packId = "1" + face.sourceType = 1 + face.stickerType = 1 + face.randomType = 1 + } else { + face.packId = "0" + } elem.faceElement = face return Result.success(elem) diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/convert/MessageConvert.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/convert/MessageConvert.kt index 488159d..361c4be 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/convert/MessageConvert.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/convert/MessageConvert.kt @@ -4,6 +4,7 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgConstant import com.tencent.qqnt.kernel.nativeinterface.MsgElement import com.tencent.qqnt.kernel.nativeinterface.MsgRecord import kotlinx.serialization.json.JsonElement +import moe.fuqiuluo.qqinterface.servlet.msg.convert.MessageElemConverter.* import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.helper.MessageHelper @@ -43,19 +44,20 @@ internal suspend fun List.toCQCode(chatType: Int, peerId: String): S internal object MessageConvert { private val convertMap by lazy { mutableMapOf( - MsgConstant.KELEMTYPETEXT to MessageElemConverter.TextConverter, - MsgConstant.KELEMTYPEFACE to MessageElemConverter.FaceConverter, - MsgConstant.KELEMTYPEPIC to MessageElemConverter.ImageConverter, - MsgConstant.KELEMTYPEPTT to MessageElemConverter.VoiceConverter, - MsgConstant.KELEMTYPEVIDEO to MessageElemConverter.VideoConverter, - MsgConstant.KELEMTYPEMARKETFACE to MessageElemConverter.MarketFaceConverter, - MsgConstant.KELEMTYPEARKSTRUCT to MessageElemConverter.StructJsonConverter, - MsgConstant.KELEMTYPEREPLY to MessageElemConverter.ReplyConverter, - MsgConstant.KELEMTYPEGRAYTIP to MessageElemConverter.GrayTipsConverter, - MsgConstant.KELEMTYPEFILE to MessageElemConverter.FileConverter, - MsgConstant.KELEMTYPEMARKDOWN to MessageElemConverter.MarkdownConverter, - //MsgConstant.KELEMTYPEMULTIFORWARD to MessageElemConverter.XmlMultiMsgConverter, - //MsgConstant.KELEMTYPESTRUCTLONGMSG to MessageElemConverter.XmlLongMsgConverter, + MsgConstant.KELEMTYPETEXT to TextConverter, + MsgConstant.KELEMTYPEFACE to FaceConverter, + MsgConstant.KELEMTYPEPIC to ImageConverter, + MsgConstant.KELEMTYPEPTT to VoiceConverter, + MsgConstant.KELEMTYPEVIDEO to VideoConverter, + MsgConstant.KELEMTYPEMARKETFACE to MarketFaceConverter, + MsgConstant.KELEMTYPEARKSTRUCT to StructJsonConverter, + MsgConstant.KELEMTYPEREPLY to ReplyConverter, + MsgConstant.KELEMTYPEGRAYTIP to GrayTipsConverter, + MsgConstant.KELEMTYPEFILE to FileConverter, + MsgConstant.KELEMTYPEMARKDOWN to MarkdownConverter, + //MsgConstant.KELEMTYPEMULTIFORWARD to XmlMultiMsgConverter, + //MsgConstant.KELEMTYPESTRUCTLONGMSG to XmlLongMsgConverter, + MsgConstant.KELEMTYPEFACEBUBBLE to BubbleFaceConverter, ) } @@ -65,11 +67,11 @@ internal object MessageConvert { peerId: String ): ArrayList { val messageData = arrayListOf() - elements.forEach { + elements.forEach { msg -> kotlin.runCatching { - val elementId = it.elementType + val elementId = msg.elementType val converter = convertMap[elementId] - converter?.convert(chatType, peerId, it) + converter?.convert(chatType, peerId, msg) ?: throw UnsupportedOperationException("不支持的消息element类型:$elementId") }.onSuccess { messageData.add(it) @@ -77,7 +79,7 @@ internal object MessageConvert { if (it is UnknownError) { // 不处理的消息类型,抛出unknown error } else { - LogCenter.log("消息element转换错误:$it", Level.WARN) + LogCenter.log("消息element转换错误:$it, elementType: ${msg.elementType}", Level.WARN) } } } diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/convert/MessageElemConverter.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/convert/MessageElemConverter.kt index bacf6c0..bbe606b 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/convert/MessageElemConverter.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/convert/MessageElemConverter.kt @@ -45,6 +45,7 @@ internal sealed class MessageElemConverter: IMessageConvert { data object FaceConverter: MessageElemConverter() { override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment { val face = element.faceElement + if (face.faceType == 5) { return MessageSegment( type = "poke", @@ -55,8 +56,6 @@ internal sealed class MessageElemConverter: IMessageConvert { ) ) } - - when (face.faceIndex) { 114 -> { return MessageSegment( @@ -87,7 +86,8 @@ internal sealed class MessageElemConverter: IMessageConvert { else -> return MessageSegment( type = "face", data = hashMapOf( - "id" to face.faceIndex + "id" to face.faceIndex, + "big" to (face.faceType == 3) ) ) } @@ -431,6 +431,23 @@ internal sealed class MessageElemConverter: IMessageConvert { } } + data object BubbleFaceConverter: MessageElemConverter() { + override suspend fun convert( + chatType: Int, + peerId: String, + element: MsgElement + ): MessageSegment { + val bubbleElement = element.faceBubbleElement + return MessageSegment( + type = "bubble_face", + data = mapOf( + "id" to bubbleElement.yellowFaceInfo.index, + "count" to (bubbleElement.faceCount ?: 1), + ) + ) + } + } + protected fun unknownChatType(chatType: Int) { throw UnsupportedOperationException("Not supported chat type: $chatType") }