Skip to content

Commit

Permalink
Support Image.isUploaded, (#1671)
Browse files Browse the repository at this point in the history
* Support `Image.isUploaded`,
add member `Image.md5`,
add `Image.calculateImageMd5ByImageId`,
close #1401

* Update docs
  • Loading branch information
Him188 committed Nov 16, 2021
1 parent 79d92a0 commit bd041e4
Show file tree
Hide file tree
Showing 8 changed files with 332 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
121 changes: 105 additions & 16 deletions mirai-core-api/src/commonMain/kotlin/message/data/Image.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public interface Image : Message, MessageContent, CodableMessage {
public val height: Int

/**
* 图片的大小(字节), 当无法获取时为 0
* 图片的大小(字节), 当无法获取时为 0. 可用于 [isUploaded].
*
* @since 2.8.0
*/
Expand All @@ -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 },
Expand All @@ -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"

Expand All @@ -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 正则表达式
Expand Down Expand Up @@ -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
Expand All @@ -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)


/**
Expand Down Expand Up @@ -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"
)
}
}
}
16 changes: 0 additions & 16 deletions mirai-core-api/src/commonMain/kotlin/message/data/impl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -201,7 +200,6 @@ internal fun MessageChainImplBySequence(
//////////////////////


@SharedImmutable
@get:JvmSynthetic
internal val EMPTY_BYTE_ARRAY = ByteArray(0)

Expand Down Expand Up @@ -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 " +
Expand Down
14 changes: 7 additions & 7 deletions mirai-core-api/src/commonTest/kotlin/message.data/ImageTest.kt
Original file line number Diff line number Diff line change
@@ -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")

Expand Down Expand Up @@ -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()
)

}
Expand Down

0 comments on commit bd041e4

Please sign in to comment.