浏览代码

[core] Add `NewTechImage: AbstractImage()`. (#2836)

汤意工坊 1 年之前
父节点
当前提交
76696ee941

+ 3 - 0
mirai-core/src/commonMain/kotlin/message/image/AbstractImage.kt

@@ -69,5 +69,8 @@ internal sealed class FriendImage : AbstractImage()
 // moved from mirai-core-api since 2.11
 // moved from mirai-core-api since 2.11
 internal sealed class GroupImage : AbstractImage()
 internal sealed class GroupImage : AbstractImage()
 
 
+// NT Image
+internal sealed class NewTechImage : AbstractImage()
+
 private val imageLogger: MiraiLogger by lazy { MiraiLogger.Factory.create(Image::class, "Image") }
 private val imageLogger: MiraiLogger by lazy { MiraiLogger.Factory.create(Image::class, "Image") }
 internal val Image.Key.logger get() = imageLogger
 internal val Image.Key.logger get() = imageLogger

+ 46 - 0
mirai-core/src/commonMain/kotlin/message/image/OnlineImage.kt

@@ -21,6 +21,7 @@ import net.mamoe.mirai.message.data.Image
 import net.mamoe.mirai.message.data.ImageType
 import net.mamoe.mirai.message.data.ImageType
 import net.mamoe.mirai.utils.generateImageId
 import net.mamoe.mirai.utils.generateImageId
 import net.mamoe.mirai.utils.generateImageIdFromResourceId
 import net.mamoe.mirai.utils.generateImageIdFromResourceId
+import net.mamoe.mirai.utils.hexToBytes
 import net.mamoe.mirai.utils.structureToString
 import net.mamoe.mirai.utils.structureToString
 
 
 internal sealed interface OnlineImage : Image, ConstOriginUrlAware {
 internal sealed interface OnlineImage : Image, ConstOriginUrlAware {
@@ -137,6 +138,51 @@ internal class OnlineGroupImageImpl(
     }
     }
 }
 }
 
 
+@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+internal sealed class OnlineNewTechImage : NewTechImage(), OnlineImage
+
+@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
+@Serializable(with = OnlineNewTechImageImpl.Serializer::class)
+internal class OnlineNewTechImageImpl(
+    internal val commonElem: ImMsgBody.CommonElem,
+) : OnlineNewTechImage() {
+
+    private val delegate = commonElem.pbElem.loadAs(ImMsgBody.NewTechImageInfo.serializer())
+
+    object Serializer : Image.FallbackSerializer("OnlineNewTechImage")
+
+    override val md5 = delegate.info.msgInfo.imageInfo.md5.hexToBytes()
+
+    private val senderMeta = delegate.meta.main.friendMeta ?: delegate.meta.main.groupMeta!!
+    override val size: Long get() = delegate.info.msgInfo.imageInfo.size
+    override val width: Int
+        get() = delegate.info.msgInfo.imageInfo.imageWidth
+    override val height: Int
+        get() = delegate.info.msgInfo.imageInfo.imageHeight
+    override val imageType: ImageType
+        get() = OnlineImageIds.speculateImageType(
+            delegate.info.msgInfo.imageInfo.filePath,
+            delegate.info.msgInfo.imageInfo.imageType.type
+        )
+
+    override val imageId: String = generateImageId(
+        md5,
+        OnlineImageIds.speculateImageTypeNameFromFilePath(delegate.info.msgInfo.imageInfo.filePath)
+    ).takeIf {
+        Image.IMAGE_ID_REGEX.matches(it)
+    } ?: generateImageId(md5)
+
+    override val originUrl: String
+        get() = if (senderMeta.origUrl.isBlank()) {
+            gchatImageUrlByImageId(imageId)
+        } else "http://" + delegate.info.noKeyDownloadInfo.domain + senderMeta.origUrl
+
+    override val isEmoji: Boolean by lazy {
+        delegate.meta.main.isEmoji == 1 || delegate.meta.main.displayStr == "[动画表情]"
+
+    }
+}
+
 private object OnlineImageIds {
 private object OnlineImageIds {
 
 
     fun speculateImageType(filePath: String, imageTypeInt: Int): ImageType {
     fun speculateImageType(filePath: String, imageTypeInt: Int): ImageType {

+ 7 - 0
mirai-core/src/commonMain/kotlin/message/protocol/impl/ImageProtocol.kt

@@ -49,6 +49,7 @@ internal class ImageProtocol : MessageProtocol() {
             add(MessageSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer()))
             add(MessageSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer()))
             add(MessageSerializer(OnlineFriendImageImpl::class, OnlineFriendImageImpl.serializer()))
             add(MessageSerializer(OnlineFriendImageImpl::class, OnlineFriendImageImpl.serializer()))
             add(MessageSerializer(OnlineGroupImageImpl::class, OnlineGroupImageImpl.serializer()))
             add(MessageSerializer(OnlineGroupImageImpl::class, OnlineGroupImageImpl.serializer()))
+            add(MessageSerializer(OnlineNewTechImageImpl::class, OnlineNewTechImageImpl.serializer()))
         }
         }
     }
     }
 
 
@@ -88,6 +89,9 @@ internal class ImageProtocol : MessageProtocol() {
                         }
                         }
                     }
                     }
                 }
                 }
+                data.commonElem != null && data.commonElem.serviceType == 48 -> {
+                    collect(OnlineNewTechImageImpl(data.commonElem))
+                }
                 else -> {
                 else -> {
                     markNotConsumed()
                     markNotConsumed()
                 }
                 }
@@ -129,6 +133,9 @@ internal class ImageProtocol : MessageProtocol() {
                         collect(ImMsgBody.Elem(customFace = data.toJceData().toCustomFace()))
                         collect(ImMsgBody.Elem(customFace = data.toJceData().toCustomFace()))
                     }
                     }
                 }
                 }
+                is OnlineNewTechImageImpl -> {
+                    collect(ImMsgBody.Elem(commonElem = data.commonElem))
+                }
             }
             }
         }
         }
 
 

+ 134 - 0
mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt

@@ -696,6 +696,140 @@ internal class ImMsgBody : ProtoBuf {
         @ProtoNumber(56) @JvmField val pbReserve: ByteArray = EMPTY_BYTE_ARRAY,
         @ProtoNumber(56) @JvmField val pbReserve: ByteArray = EMPTY_BYTE_ARRAY,
     ) : ProtoBuf
     ) : ProtoBuf
 
 
+    @Serializable
+    internal class NewTechImageType(
+        @ProtoNumber(1) @JvmField val i: Int = 0,
+        @ProtoNumber(2) @JvmField val type: Int = 0,
+        @ProtoNumber(3) @JvmField val j: Int = 0,
+        @ProtoNumber(4) @JvmField val k: Int = 0,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageFileInfo(
+        @ProtoNumber(1) @JvmField val size: Long = 0L,
+        @ProtoNumber(2) @JvmField val md5: String = "",
+        @ProtoNumber(3) @JvmField val sha1: String = "",
+        @ProtoNumber(4) @JvmField val filePath: String = "",
+        @ProtoNumber(5) @JvmField val imageType: NewTechImageType,
+        @ProtoNumber(6) @JvmField val imageWidth: Int = 0,
+        @ProtoNumber(7) @JvmField val imageHeight: Int = 0,
+        @ProtoNumber(8) @JvmField val i: Int = 0,
+        @ProtoNumber(9) @JvmField val j: Int = 0,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageMsgInfo(
+        @ProtoNumber(1) @JvmField val imageInfo: NewTechImageFileInfo,
+        @ProtoNumber(2) @JvmField val fileId: String = "",
+        @ProtoNumber(3) @JvmField val i: Int = 0,
+        @ProtoNumber(4) @JvmField val timestamp: Long = 0L,
+        @ProtoNumber(5) @JvmField val friendOrGroup: Int = 0,
+        @ProtoNumber(6) @JvmField val j: Int = 0,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageSpec(
+        @ProtoNumber(1) @JvmField val origin: String = "&spec=0",
+        @ProtoNumber(2) @JvmField val large: String = "&spec=720",
+        @ProtoNumber(3) @JvmField val small: String = "&spec=198",
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageNoKeyDownloadInfo(
+        @ProtoNumber(1) @JvmField val noKeyUrl: String = "",
+        @ProtoNumber(2) @JvmField val spec: NewTechImageSpec,
+        @ProtoNumber(3) @JvmField val domain: String = "multimedia.nt.qq.com.cn",
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageGroupInfo(
+        @ProtoNumber(1) @JvmField val groupId: Long = 0L,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageFriendInfo(
+        @ProtoNumber(1) @JvmField val i: Int = 0,
+        @ProtoNumber(2) @JvmField val j: String = "",
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageSenderInfo(
+        @ProtoNumber(101) @JvmField val i: Int = 0,
+        @ProtoNumber(102) @JvmField val j: Int = 0,
+        @ProtoNumber(200) @JvmField val k: Int = 0,
+        @ProtoNumber(201) @JvmField val friendInfo: NewTechImageFriendInfo?,
+        @ProtoNumber(202) @JvmField val groupInfo: NewTechImageGroupInfo?,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageInfoMain(
+        @ProtoNumber(1) @JvmField val msgInfo: NewTechImageMsgInfo,
+        @ProtoNumber(2) @JvmField val noKeyDownloadInfo: NewTechImageNoKeyDownloadInfo,
+        @ProtoNumber(5) @JvmField val k: Int = 0,
+        @ProtoNumber(6) @JvmField val senderInfo: NewTechImageSenderInfo,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageMetaInfoSenderMetaSenderUnknown(
+        @ProtoNumber(1) @JvmField val i: Int = 0,
+        @ProtoNumber(2) @JvmField val j: ByteArray = EMPTY_BYTE_ARRAY,
+        @ProtoNumber(3) @JvmField val k: Int = 0,
+        @ProtoNumber(4) @JvmField val l: Int = 0,
+        @ProtoNumber(5) @JvmField val m: Int = 0,
+        @ProtoNumber(7) @JvmField val n: ByteArray = EMPTY_BYTE_ARRAY,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageMetaInfoSenderMeta(
+        @ProtoNumber(1) @JvmField val i: Int = 0,
+        @ProtoNumber(3) @JvmField val j: Int = 0,
+        @ProtoNumber(4) @JvmField val k: Int = 0,
+        @ProtoNumber(9) @JvmField val displayStr: String = "",
+        @ProtoNumber(10) @JvmField val l: Int = 0,
+        @ProtoNumber(12) @JvmField val m: ByteArray? = EMPTY_BYTE_ARRAY,
+        @ProtoNumber(18) @JvmField val n: ByteArray? = EMPTY_BYTE_ARRAY,
+        @ProtoNumber(19) @JvmField val o: ByteArray? = EMPTY_BYTE_ARRAY,
+        @ProtoNumber(20) @JvmField val friendUnknown: NewTechImageMetaInfoSenderMetaSenderUnknown?,
+        @ProtoNumber(21) @JvmField val groupUnknown: NewTechImageMetaInfoSenderMetaSenderUnknown?,
+        @ProtoNumber(30) @JvmField val origUrl: String = "",
+        @ProtoNumber(31) @JvmField val md5Upper: String = "",
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageMetaInfoMain(
+        @ProtoNumber(1) @JvmField val isEmoji: Int = 0,
+        @ProtoNumber(2) @JvmField val displayStr: String = "",
+        @ProtoNumber(11) @JvmField val friendMeta: NewTechImageMetaInfoSenderMeta?,
+        @ProtoNumber(12) @JvmField val groupMeta: NewTechImageMetaInfoSenderMeta?,
+        @ProtoNumber(1001) @JvmField val i: Int = 0,
+        @ProtoNumber(1002) @JvmField val j: Int = 0,
+        @ProtoNumber(1003) @JvmField val k: Int? = 0,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageMetaInfoUnknown2(
+        @ProtoNumber(3) @JvmField val i: ByteArray = EMPTY_BYTE_ARRAY,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageMetaInfoUnknown3(
+        @ProtoNumber(11) @JvmField val i: ByteArray = EMPTY_BYTE_ARRAY,
+        @ProtoNumber(12) @JvmField val j: ByteArray = EMPTY_BYTE_ARRAY,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageMetaInfo(
+        @ProtoNumber(1) @JvmField val main: NewTechImageMetaInfoMain,
+        @ProtoNumber(2) @JvmField val unknown1: NewTechImageMetaInfoUnknown2,
+        @ProtoNumber(3) @JvmField val unknown2: NewTechImageMetaInfoUnknown3,
+    ) : ProtoBuf
+
+    @Serializable
+    internal class NewTechImageInfo(
+        @ProtoNumber(1) @JvmField val info: NewTechImageInfoMain,
+        @ProtoNumber(2) @JvmField val meta: NewTechImageMetaInfo,
+    ) : ProtoBuf
+
     interface NotOnlineImageOrCustomFace {
     interface NotOnlineImageOrCustomFace {
         val thumbUrl: String
         val thumbUrl: String
         val origUrl: String
         val origUrl: String