mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 23:50:08 +08:00
Support Image.isUploaded
, (#1671)
* Support `Image.isUploaded`, add member `Image.md5`, add `Image.calculateImageMd5ByImageId`, close #1401 * Update docs
This commit is contained in:
parent
79d92a0114
commit
bd041e43d1
@ -4445,9 +4445,14 @@ public abstract interface class net/mamoe/mirai/message/data/Image : net/mamoe/m
|
||||
public static fun getImageResourceIdRegex1 ()Lkotlin/text/Regex;
|
||||
public static fun getImageResourceIdRegex2 ()Lkotlin/text/Regex;
|
||||
public abstract fun getImageType ()Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public fun getMd5 ()[B
|
||||
public abstract fun getSize ()J
|
||||
public abstract fun getWidth ()I
|
||||
public fun isEmoji ()Z
|
||||
public static fun isUploaded (Lnet/mamoe/mirai/Bot;[BJ)Z
|
||||
public static fun isUploaded (Lnet/mamoe/mirai/Bot;[BJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public static fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;)Z
|
||||
public static fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public static fun queryUrl (Lnet/mamoe/mirai/message/data/Image;)Ljava/lang/String;
|
||||
public static fun queryUrl (Lnet/mamoe/mirai/message/data/Image;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
@ -4463,10 +4468,15 @@ public final class net/mamoe/mirai/message/data/Image$AsStringSerializer : kotli
|
||||
|
||||
public final class net/mamoe/mirai/message/data/Image$Key : net/mamoe/mirai/message/data/AbstractMessageKey {
|
||||
public static final field SERIAL_NAME Ljava/lang/String;
|
||||
public final fun calculateImageMd5ByImageId (Ljava/lang/String;)[B
|
||||
public final fun fromId (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/Image;
|
||||
public final fun getImageIdRegex ()Lkotlin/text/Regex;
|
||||
public final fun getImageResourceIdRegex1 ()Lkotlin/text/Regex;
|
||||
public final fun getImageResourceIdRegex2 ()Lkotlin/text/Regex;
|
||||
public final fun isUploaded (Lnet/mamoe/mirai/Bot;[BJ)Z
|
||||
public final fun isUploaded (Lnet/mamoe/mirai/Bot;[BJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public final fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;)Z
|
||||
public final fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public final fun queryUrl (Lnet/mamoe/mirai/message/data/Image;)Ljava/lang/String;
|
||||
public final fun queryUrl (Lnet/mamoe/mirai/message/data/Image;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
@ -4488,6 +4498,7 @@ public final class net/mamoe/mirai/message/data/ImageType : java/lang/Enum {
|
||||
public static final field JPG Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public static final field PNG Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public static final field UNKNOWN Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public final fun getFormatName ()Ljava/lang/String;
|
||||
public static final fun match (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public static final fun matchOrNull (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public static fun valueOf (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
|
||||
@ -4853,7 +4864,7 @@ public final class net/mamoe/mirai/message/data/MessageUtils {
|
||||
public static final fun buildMessageChain (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/MessageChain;
|
||||
public static final synthetic fun buildMessageSource (Lnet/mamoe/mirai/Bot;Lnet/mamoe/mirai/message/data/MessageSourceKind;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
|
||||
public static final synthetic fun buildMessageSource (Lnet/mamoe/mirai/IMirai;JLnet/mamoe/mirai/message/data/MessageSourceKind;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
|
||||
public static final fun calculateImageMd5 (Lnet/mamoe/mirai/message/data/Image;)[B
|
||||
public static final synthetic fun calculateImageMd5 (Lnet/mamoe/mirai/message/data/Image;)[B
|
||||
public static final fun contentsList (Lnet/mamoe/mirai/message/data/MessageChain;)Ljava/util/List;
|
||||
public static final synthetic fun contentsSequence (Lnet/mamoe/mirai/message/data/MessageChain;)Lkotlin/sequences/Sequence;
|
||||
public static final fun copySource (Lnet/mamoe/mirai/message/data/MessageSource;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
|
||||
|
@ -4445,9 +4445,14 @@ public abstract interface class net/mamoe/mirai/message/data/Image : net/mamoe/m
|
||||
public static fun getImageResourceIdRegex1 ()Lkotlin/text/Regex;
|
||||
public static fun getImageResourceIdRegex2 ()Lkotlin/text/Regex;
|
||||
public abstract fun getImageType ()Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public fun getMd5 ()[B
|
||||
public abstract fun getSize ()J
|
||||
public abstract fun getWidth ()I
|
||||
public fun isEmoji ()Z
|
||||
public static fun isUploaded (Lnet/mamoe/mirai/Bot;[BJ)Z
|
||||
public static fun isUploaded (Lnet/mamoe/mirai/Bot;[BJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public static fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;)Z
|
||||
public static fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public static fun queryUrl (Lnet/mamoe/mirai/message/data/Image;)Ljava/lang/String;
|
||||
public static fun queryUrl (Lnet/mamoe/mirai/message/data/Image;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
@ -4463,10 +4468,15 @@ public final class net/mamoe/mirai/message/data/Image$AsStringSerializer : kotli
|
||||
|
||||
public final class net/mamoe/mirai/message/data/Image$Key : net/mamoe/mirai/message/data/AbstractMessageKey {
|
||||
public static final field SERIAL_NAME Ljava/lang/String;
|
||||
public final fun calculateImageMd5ByImageId (Ljava/lang/String;)[B
|
||||
public final fun fromId (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/Image;
|
||||
public final fun getImageIdRegex ()Lkotlin/text/Regex;
|
||||
public final fun getImageResourceIdRegex1 ()Lkotlin/text/Regex;
|
||||
public final fun getImageResourceIdRegex2 ()Lkotlin/text/Regex;
|
||||
public final fun isUploaded (Lnet/mamoe/mirai/Bot;[BJ)Z
|
||||
public final fun isUploaded (Lnet/mamoe/mirai/Bot;[BJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public final fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;)Z
|
||||
public final fun isUploaded (Lnet/mamoe/mirai/message/data/Image;Lnet/mamoe/mirai/Bot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public final fun queryUrl (Lnet/mamoe/mirai/message/data/Image;)Ljava/lang/String;
|
||||
public final fun queryUrl (Lnet/mamoe/mirai/message/data/Image;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
@ -4488,6 +4498,7 @@ public final class net/mamoe/mirai/message/data/ImageType : java/lang/Enum {
|
||||
public static final field JPG Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public static final field PNG Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public static final field UNKNOWN Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public final fun getFormatName ()Ljava/lang/String;
|
||||
public static final fun match (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public static final fun matchOrNull (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
|
||||
public static fun valueOf (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/ImageType;
|
||||
@ -4853,7 +4864,7 @@ public final class net/mamoe/mirai/message/data/MessageUtils {
|
||||
public static final fun buildMessageChain (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/MessageChain;
|
||||
public static final synthetic fun buildMessageSource (Lnet/mamoe/mirai/Bot;Lnet/mamoe/mirai/message/data/MessageSourceKind;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
|
||||
public static final synthetic fun buildMessageSource (Lnet/mamoe/mirai/IMirai;JLnet/mamoe/mirai/message/data/MessageSourceKind;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
|
||||
public static final fun calculateImageMd5 (Lnet/mamoe/mirai/message/data/Image;)[B
|
||||
public static final synthetic fun calculateImageMd5 (Lnet/mamoe/mirai/message/data/Image;)[B
|
||||
public static final fun contentsList (Lnet/mamoe/mirai/message/data/MessageChain;)Ljava/util/List;
|
||||
public static final synthetic fun contentsSequence (Lnet/mamoe/mirai/message/data/MessageChain;)Lkotlin/sequences/Sequence;
|
||||
public static final fun copySource (Lnet/mamoe/mirai/message/data/MessageSource;Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/message/data/OfflineMessageSource;
|
||||
|
@ -100,7 +100,7 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
public val height: Int
|
||||
|
||||
/**
|
||||
* 图片的大小(字节), 当无法获取时为 0
|
||||
* 图片的大小(字节), 当无法获取时为 0. 可用于 [isUploaded].
|
||||
*
|
||||
* @since 2.8.0
|
||||
*/
|
||||
@ -122,6 +122,15 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
*/
|
||||
public val isEmoji: Boolean get() = false
|
||||
|
||||
/**
|
||||
* 图片文件 MD5. 可用于 [isUploaded].
|
||||
*
|
||||
* @return 16 bytes
|
||||
* @see isUploaded
|
||||
* @since 2.9.0
|
||||
*/ // was an extension on Image before 2.9.0-M1.
|
||||
public val md5: ByteArray get() = calculateImageMd5ByImageId(imageId)
|
||||
|
||||
public object AsStringSerializer : KSerializer<Image> by String.serializer().mapPrimitive(
|
||||
SERIAL_NAME,
|
||||
serialize = { imageId },
|
||||
@ -143,6 +152,7 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
)
|
||||
}
|
||||
|
||||
@JvmBlockingBridge
|
||||
public companion object Key : AbstractMessageKey<Image>({ it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "Image"
|
||||
|
||||
@ -166,12 +176,56 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
* @throws IllegalStateException 当无任何 [Bot] 在线时抛出 (因为无法获取相关协议)
|
||||
*/
|
||||
@JvmStatic
|
||||
@JvmBlockingBridge
|
||||
public suspend fun Image.queryUrl(): String {
|
||||
val bot = Bot.instancesSequence.firstOrNull() ?: error("No Bot available to query image url")
|
||||
return Mirai.queryImageUrl(bot, this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 当图片在服务器上存在时返回 `true`, 这意味着图片可以直接发送给 [contact].
|
||||
*
|
||||
* 若返回 `false`, 则图片需要用 [ExternalResource] 重新上传 ([Contact.uploadImage]).
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
@JvmStatic
|
||||
public suspend fun Image.isUploaded(bot: Bot): Boolean =
|
||||
InternalImageProtocol.instance.isUploaded(bot, md5, size, null, imageType, width, height)
|
||||
|
||||
/**
|
||||
* 当图片在服务器上存在时返回 `true`, 这意味着图片可以直接发送给 [contact].
|
||||
*
|
||||
* 若返回 `false`, 则图片需要用 [ExternalResource] 重新上传 ([Contact.uploadImage]).
|
||||
*
|
||||
* @param md5 图片文件 MD5. 可通过 [Image.md5] 获得.
|
||||
* @param size 图片文件大小.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
@JvmStatic
|
||||
public suspend fun isUploaded(
|
||||
bot: Bot,
|
||||
md5: ByteArray,
|
||||
size: Long,
|
||||
): Boolean = InternalImageProtocol.instance.isUploaded(bot, md5, size, null)
|
||||
|
||||
/**
|
||||
* 由 [Image.imageId] 计算 [Image.md5].
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public fun calculateImageMd5ByImageId(imageId: String): ByteArray {
|
||||
@Suppress("DEPRECATION")
|
||||
return when {
|
||||
imageId matches IMAGE_ID_REGEX -> imageId.imageIdToMd5(1)
|
||||
imageId matches IMAGE_RESOURCE_ID_REGEX_2 -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
|
||||
imageId matches IMAGE_RESOURCE_ID_REGEX_1 -> imageId.imageIdToMd5(1)
|
||||
|
||||
else -> throw IllegalArgumentException(
|
||||
"Illegal imageId: '$imageId'. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一 ID 正则表达式
|
||||
@ -222,17 +276,24 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
@JvmSynthetic
|
||||
public inline fun Image(imageId: String): Image = Image.fromId(imageId)
|
||||
|
||||
public enum class ImageType {
|
||||
PNG,
|
||||
BMP,
|
||||
JPG,
|
||||
GIF,
|
||||
public enum class ImageType(
|
||||
/**
|
||||
* @since 2.9.0
|
||||
*/
|
||||
@MiraiInternalApi public val formatName: String,
|
||||
) {
|
||||
PNG("png"),
|
||||
BMP("bmp"),
|
||||
JPG("jpg"),
|
||||
GIF("gif"),
|
||||
|
||||
//WEBP, //Unsupported by pc client
|
||||
APNG,
|
||||
UNKNOWN;
|
||||
APNG("png"),
|
||||
UNKNOWN("gif"); // bad design, should use `null` to represent unknown, but we cannot change it anymore.
|
||||
|
||||
public companion object {
|
||||
private val IMAGE_TYPE_ENUM_LIST = values()
|
||||
|
||||
@JvmStatic
|
||||
public fun match(str: String): ImageType {
|
||||
return matchOrNull(str) ?: UNKNOWN
|
||||
@ -250,15 +311,12 @@ public enum class ImageType {
|
||||
// Internals
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 计算图片的 md5 校验值.
|
||||
*
|
||||
* 在 Java 使用: `MessageUtils.calculateImageMd5(image)`
|
||||
*/
|
||||
@Deprecated("Use member function", level = DeprecationLevel.HIDDEN) // safe since it was internal
|
||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||
@MiraiInternalApi
|
||||
@get:JvmName("calculateImageMd5")
|
||||
public val Image.md5: ByteArray
|
||||
get() = calculateImageMd5ByImageId(imageId)
|
||||
get() = Image.calculateImageMd5ByImageId(imageId)
|
||||
|
||||
|
||||
/**
|
||||
@ -320,4 +378,35 @@ public abstract class FriendImage @MiraiInternalApi public constructor() :
|
||||
public abstract class GroupImage @MiraiInternalApi public constructor() :
|
||||
AbstractImage() { // change to sealed in the future.
|
||||
public companion object
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 内部图片协议实现
|
||||
* @since 2.9.0-M1
|
||||
*/
|
||||
@MiraiInternalApi
|
||||
public interface InternalImageProtocol { // naming it Internal* to assign it a lower priority when resolving Image*
|
||||
/**
|
||||
* @param context 用于检查的 [Contact]. 群图片与好友图片是两个通道, 建议使用欲发送到的 [Contact] 对象作为 [contact] 参数, 但目前不提供此参数时也可以检查.
|
||||
*/
|
||||
public suspend fun isUploaded(
|
||||
bot: Bot,
|
||||
md5: ByteArray,
|
||||
size: Long,
|
||||
context: Contact? = null,
|
||||
type: ImageType = ImageType.UNKNOWN,
|
||||
width: Int = 0,
|
||||
height: Int = 0
|
||||
): Boolean
|
||||
|
||||
@MiraiInternalApi
|
||||
public companion object {
|
||||
public val instance: InternalImageProtocol by lazy {
|
||||
loadService(
|
||||
InternalImageProtocol::class,
|
||||
"net.mamoe.mirai.internal.message.InternalImageProtocolImpl"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import net.mamoe.mirai.utils.asImmutable
|
||||
import net.mamoe.mirai.utils.replaceAllKotlin
|
||||
import kotlin.native.concurrent.SharedImmutable
|
||||
|
||||
// region image
|
||||
|
||||
@ -201,7 +200,6 @@ internal fun MessageChainImplBySequence(
|
||||
//////////////////////
|
||||
|
||||
|
||||
@SharedImmutable
|
||||
@get:JvmSynthetic
|
||||
internal val EMPTY_BYTE_ARRAY = ByteArray(0)
|
||||
|
||||
@ -247,20 +245,6 @@ internal fun String.imageIdToMd5(offset: Int): ByteArray {
|
||||
error("Internal error: failed imageIdToMd5, no enough chars. Input=$this, offset=$offset")
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
internal fun calculateImageMd5ByImageId(imageId: String): ByteArray {
|
||||
@Suppress("DEPRECATION")
|
||||
return when {
|
||||
imageId matches IMAGE_ID_REGEX -> imageId.imageIdToMd5(1)
|
||||
imageId matches IMAGE_RESOURCE_ID_REGEX_2 -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
|
||||
imageId matches IMAGE_RESOURCE_ID_REGEX_1 -> imageId.imageIdToMd5(1)
|
||||
|
||||
else -> error(
|
||||
"illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal val ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE: String =
|
||||
"ImageId must match Regex `${IMAGE_RESOURCE_ID_REGEX_1.pattern}`, " +
|
||||
"`${IMAGE_RESOURCE_ID_REGEX_2.pattern}` or " +
|
||||
|
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE")
|
||||
|
||||
@ -35,17 +35,17 @@ internal class ImageTest {
|
||||
fun testCalculateImageMd5ByImageId() {
|
||||
assertEquals(
|
||||
"01E9451B-70ED-EAE3-B37C-101F1EEBF5B5".filterNot { it == '-' }.autoHexToBytes().contentToString(),
|
||||
calculateImageMd5ByImageId("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai").contentToString()
|
||||
Image.calculateImageMd5ByImageId("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai").contentToString()
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"f8f1ab55-bf8e-4236-b55e-955848d7069f".filterNot { it == '-' }.autoHexToBytes().contentToString(),
|
||||
calculateImageMd5ByImageId("/f8f1ab55-bf8e-4236-b55e-955848d7069f").contentToString()
|
||||
Image.calculateImageMd5ByImageId("/f8f1ab55-bf8e-4236-b55e-955848d7069f").contentToString()
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"BFB7027B9354B8F899A062061D74E206".filterNot { it == '-' }.autoHexToBytes().contentToString(),
|
||||
calculateImageMd5ByImageId("/000000000-3814297509-BFB7027B9354B8F899A062061D74E206").contentToString()
|
||||
Image.calculateImageMd5ByImageId("/000000000-3814297509-BFB7027B9354B8F899A062061D74E206").contentToString()
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.message
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.User
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.asQQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Cmd0x352
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.LongConn
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.message.data.ImageType
|
||||
import net.mamoe.mirai.message.data.InternalImageProtocol
|
||||
import net.mamoe.mirai.utils.cast
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
|
||||
internal class InternalImageProtocolImpl : InternalImageProtocol {
|
||||
|
||||
/**
|
||||
* Test Notes:
|
||||
*
|
||||
* - 查图片只需要 md5 和 size
|
||||
* - 上传给群的图片可以通过 GroupPicUp(groupCode=user.id) 或 OffPicUp(dstUin=user.id) 查询
|
||||
* - 上传给好友的图片可以通过 GroupPicUp(groupCode=group.id) 或 OffPicUp(dstUin=group.id) 查询
|
||||
*/
|
||||
fun interface ImageUploadedChecker<C : Contact?> {
|
||||
suspend fun isUploaded(
|
||||
bot: QQAndroidBot,
|
||||
context: C,
|
||||
md5: ByteArray,
|
||||
type: ImageType,
|
||||
size: Long,
|
||||
width: Int,
|
||||
height: Int
|
||||
): Boolean
|
||||
|
||||
companion object {
|
||||
val checkers = mapOf(
|
||||
Group::class to ImageUploadedCheckerGroup(),
|
||||
User::class to ImageUploadedCheckerUser(),
|
||||
null to ImageUploadedCheckerFallback()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ImageUploadedCheckerGroup : ImageUploadedChecker<Group> {
|
||||
override suspend fun isUploaded(
|
||||
bot: QQAndroidBot,
|
||||
context: Group,
|
||||
md5: ByteArray,
|
||||
type: ImageType,
|
||||
size: Long,
|
||||
width: Int,
|
||||
height: Int
|
||||
): Boolean {
|
||||
val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp(
|
||||
bot.client,
|
||||
uin = bot.id,
|
||||
groupCode = context.id,
|
||||
md5 = md5,
|
||||
size = size,
|
||||
filename = "${md5.toUHexString("")}.${type.formatName}",
|
||||
picWidth = width,
|
||||
picHeight = height,
|
||||
picType = getIdByImageType(type),
|
||||
originalPic = 1
|
||||
).sendAndExpect(bot)
|
||||
|
||||
return response is ImgStore.GroupPicUp.Response.FileExists
|
||||
}
|
||||
}
|
||||
|
||||
class ImageUploadedCheckerUser : ImageUploadedChecker<User> {
|
||||
override suspend fun isUploaded(
|
||||
bot: QQAndroidBot,
|
||||
context: User,
|
||||
md5: ByteArray,
|
||||
type: ImageType,
|
||||
size: Long,
|
||||
width: Int,
|
||||
height: Int
|
||||
): Boolean {
|
||||
val resp = LongConn.OffPicUp(
|
||||
bot.client,
|
||||
Cmd0x352.TryUpImgReq(
|
||||
buType = 1,
|
||||
srcUin = bot.id,
|
||||
dstUin = context.id,
|
||||
fileMd5 = md5,
|
||||
fileSize = size,
|
||||
imgWidth = width,
|
||||
imgHeight = height,
|
||||
imgType = getIdByImageType(type),
|
||||
fileName = "${md5.toUHexString("")}.${type.formatName}",
|
||||
imgOriginal = true,
|
||||
buildVer = bot.client.buildVer,
|
||||
),
|
||||
).sendAndExpect<LongConn.OffPicUp.Response>(bot)
|
||||
|
||||
return resp is LongConn.OffPicUp.Response.FileExists
|
||||
}
|
||||
}
|
||||
|
||||
class ImageUploadedCheckerFallback : ImageUploadedChecker<Nothing?> {
|
||||
override suspend fun isUploaded(
|
||||
bot: QQAndroidBot,
|
||||
context: Nothing?,
|
||||
md5: ByteArray,
|
||||
type: ImageType,
|
||||
size: Long,
|
||||
width: Int,
|
||||
height: Int
|
||||
): Boolean {
|
||||
val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp(
|
||||
bot.client,
|
||||
uin = bot.id,
|
||||
groupCode = 1,
|
||||
md5 = md5,
|
||||
size = size,
|
||||
filename = "${md5.toUHexString("")}.${type.formatName}",
|
||||
picWidth = width,
|
||||
picHeight = height,
|
||||
picType = getIdByImageType(type),
|
||||
originalPic = 1
|
||||
).sendAndExpect(bot)
|
||||
|
||||
return response is ImgStore.GroupPicUp.Response.FileExists
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun isUploaded(
|
||||
bot: Bot,
|
||||
md5: ByteArray,
|
||||
size: Long,
|
||||
context: Contact?,
|
||||
type: ImageType,
|
||||
width: Int,
|
||||
height: Int
|
||||
): Boolean {
|
||||
val checker = findChecker(context) ?: return false
|
||||
checker.cast<ImageUploadedChecker<Contact?>>()
|
||||
return checker.isUploaded(bot.asQQAndroidBot(), context.cast<Contact?>(), md5, type, size, width, height)
|
||||
}
|
||||
|
||||
fun findChecker(context: Contact?) = ImageUploadedChecker.checkers.asSequence()
|
||||
.find { bothNull(it.key, context) || it.key?.isInstance(context) == true }?.value
|
||||
|
||||
private fun bothNull(a: Any?, b: Any?) = a == null && b == null
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
#
|
||||
# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
#
|
||||
# https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
#
|
||||
|
||||
net.mamoe.mirai.internal.message.InternalImageProtocolImpl
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.message
|
||||
|
||||
import net.mamoe.mirai.internal.notice.processors.AbstractNoticeProcessorTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertIs
|
||||
|
||||
internal class InternalImageProtocolImplTest : AbstractNoticeProcessorTest() { // borrow Bot testkit
|
||||
val instance = InternalImageProtocolImpl()
|
||||
|
||||
@Test
|
||||
fun testFindChecker() {
|
||||
assertIs<InternalImageProtocolImpl.ImageUploadedCheckerGroup>(instance.findChecker(setBot(1).addGroup(2, 3)))
|
||||
assertIs<InternalImageProtocolImpl.ImageUploadedCheckerUser>(instance.findChecker(setBot(1).addFriend(2)))
|
||||
assertIs<InternalImageProtocolImpl.ImageUploadedCheckerFallback>(instance.findChecker(null))
|
||||
|
||||
// these 3 tests are complete -- no need to add more when adding more checkers.
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user