mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-03 23:22:29 +08:00
Unify image id
This commit is contained in:
parent
b7232182ae
commit
1d24a810fe
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||||
*
|
*
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 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.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -36,13 +36,15 @@ import net.mamoe.mirai.contact.Contact
|
|||||||
import net.mamoe.mirai.contact.Contact.Companion.sendImage
|
import net.mamoe.mirai.contact.Contact.Companion.sendImage
|
||||||
import net.mamoe.mirai.contact.Contact.Companion.uploadImage
|
import net.mamoe.mirai.contact.Contact.Companion.uploadImage
|
||||||
import net.mamoe.mirai.message.code.CodableMessage
|
import net.mamoe.mirai.message.code.CodableMessage
|
||||||
import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX
|
||||||
import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_1
|
||||||
import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
|
||||||
import net.mamoe.mirai.message.data.Image.Key.queryUrl
|
import net.mamoe.mirai.message.data.Image.Key.queryUrl
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.ExternalResource
|
||||||
import java.io.File
|
import net.mamoe.mirai.utils.ExternalResource.Companion.sendAsImageTo
|
||||||
import java.io.InputStream
|
import net.mamoe.mirai.utils.ExternalResource.Companion.uploadAsImage
|
||||||
|
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||||
|
import net.mamoe.mirai.utils.safeCast
|
||||||
import kotlin.LazyThreadSafetyMode.NONE
|
import kotlin.LazyThreadSafetyMode.NONE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,15 +58,12 @@ import kotlin.LazyThreadSafetyMode.NONE
|
|||||||
* - [Image.fromId]. 在 Kotlin, 更推荐使用顶层函数 `val image = Image("id")`
|
* - [Image.fromId]. 在 Kotlin, 更推荐使用顶层函数 `val image = Image("id")`
|
||||||
*
|
*
|
||||||
* ### 上传和发送图片
|
* ### 上传和发送图片
|
||||||
* - [Contact.uploadImage] 上传 [图片文件][ExternalImage] 并得到 [Image] 消息
|
* - [Contact.uploadImage] 上传 [资源文件][ExternalResource] 并得到 [Image] 消息
|
||||||
* - [Contact.sendImage] 上传 [图片文件][ExternalImage] 并发送返回的 [Image] 作为一条消息
|
* - [Contact.sendImage] 上传 [资源文件][ExternalResource] 并发送返回的 [Image] 作为一条消息
|
||||||
* - [Image.sendTo] 上传 [图片文件][ExternalImage] 并得到 [Image] 消息
|
|
||||||
*
|
*
|
||||||
* - [File.uploadAsImage]
|
* - [ExternalResource.uploadAsImage]
|
||||||
* - [InputStream.uploadAsImage]
|
* - [ExternalResource.sendAsImageTo]
|
||||||
*
|
* - [Contact.sendImage]
|
||||||
* - [File.sendAsImageTo]
|
|
||||||
* - [InputStream.sendAsImageTo]
|
|
||||||
*
|
*
|
||||||
* ### 下载图片
|
* ### 下载图片
|
||||||
* - [Image.queryUrl] 扩展函数. 查询图片下载链接
|
* - [Image.queryUrl] 扩展函数. 查询图片下载链接
|
||||||
@ -85,12 +84,7 @@ public interface Image : Message, MessageContent, CodableMessage {
|
|||||||
* 图片 id 不一定会长时间保存, 也可能在将来改变格式, 因此不建议使用 id 发送图片.
|
* 图片 id 不一定会长时间保存, 也可能在将来改变格式, 因此不建议使用 id 发送图片.
|
||||||
*
|
*
|
||||||
* ### 格式
|
* ### 格式
|
||||||
* 群图片:
|
* 所有图片的 id 都满足正则表达式 [IMAGE_ID_REGEX]. 示例: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.ext` (ext 为文件后缀, 如 png)
|
||||||
* - [GROUP_IMAGE_ID_REGEX], 示例: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.ext` (ext 为文件后缀, 如 png)
|
|
||||||
*
|
|
||||||
* 好友图片:
|
|
||||||
* - [FRIEND_IMAGE_ID_REGEX_1], 示例: `/f8f1ab55-bf8e-4236-b55e-955848d7069f`
|
|
||||||
* - [FRIEND_IMAGE_ID_REGEX_2], 示例: `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206`
|
|
||||||
*
|
*
|
||||||
* @see Image 使用 id 构造图片
|
* @see Image 使用 id 构造图片
|
||||||
*/
|
*/
|
||||||
@ -147,52 +141,40 @@ public interface Image : Message, MessageContent, CodableMessage {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 好友图片 ID 正则表达式
|
* 统一 ID 正则表达式
|
||||||
*
|
|
||||||
* `/f8f1ab55-bf8e-4236-b55e-955848d7069f`
|
|
||||||
* @see FRIEND_IMAGE_ID_REGEX_2
|
|
||||||
*/
|
|
||||||
// Java: MessageUtils.FRIEND_IMAGE_ID_REGEX_1
|
|
||||||
@JvmStatic
|
|
||||||
@MiraiExperimentalApi
|
|
||||||
@get:JvmName("getFriendImageIdRegex1")
|
|
||||||
public val FRIEND_IMAGE_ID_REGEX_1: Regex = Regex("""/[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}""")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 好友图片 ID 正则表达式 2
|
|
||||||
*
|
|
||||||
* `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206`
|
|
||||||
* @see FRIEND_IMAGE_ID_REGEX_1
|
|
||||||
*/
|
|
||||||
// Java: MessageUtils.FRIEND_IMAGE_ID_REGEX_2
|
|
||||||
@JvmStatic
|
|
||||||
@MiraiExperimentalApi
|
|
||||||
@get:JvmName("getFriendImageIdRegex2")
|
|
||||||
public val FRIEND_IMAGE_ID_REGEX_2: Regex = Regex("""/[0-9]*-[0-9]*-[0-9a-fA-F]{32}""")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 群图片 ID 正则表达式
|
|
||||||
*
|
*
|
||||||
* `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.ext`
|
* `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.ext`
|
||||||
*/
|
*/
|
||||||
@Suppress("RegExpRedundantEscape") // This is required on Android
|
@Suppress("RegExpRedundantEscape") // This is required on Android
|
||||||
// Java: MessageUtils.GROUP_IMAGE_ID_REGEX
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@MiraiExperimentalApi
|
@get:JvmName("getImageIdRegex")
|
||||||
@get:JvmName("getGroupImageIdRegex")
|
public val IMAGE_ID_REGEX: Regex =
|
||||||
public val GROUP_IMAGE_ID_REGEX: Regex =
|
|
||||||
Regex("""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\..{3,5}""")
|
Regex("""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\..{3,5}""")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片资源 ID 正则表达式 1. mirai 内部使用.
|
||||||
|
*
|
||||||
|
* `/f8f1ab55-bf8e-4236-b55e-955848d7069f`
|
||||||
|
* @see IMAGE_RESOURCE_ID_REGEX_2
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@MiraiInternalApi
|
||||||
|
@get:JvmName("getImageResourceIdRegex1")
|
||||||
|
public val IMAGE_RESOURCE_ID_REGEX_1: Regex = Regex("""/[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}""")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片资源 ID 正则表达式 2. mirai 内部使用.
|
||||||
|
*
|
||||||
|
* `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206`
|
||||||
|
* @see IMAGE_RESOURCE_ID_REGEX_1
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@MiraiInternalApi
|
||||||
|
@get:JvmName("getImageResourceIdRegex2")
|
||||||
|
public val IMAGE_RESOURCE_ID_REGEX_2: Regex = Regex("""/[0-9]*-[0-9]*-[0-9a-fA-F]{32}""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MiraiExperimentalApi
|
|
||||||
public val Image.isGroupImage: Boolean
|
|
||||||
get() = GROUP_IMAGE_ID_REGEX matches imageId
|
|
||||||
|
|
||||||
@MiraiExperimentalApi
|
|
||||||
public val Image.isFriendImage: Boolean
|
|
||||||
get() = FRIEND_IMAGE_ID_REGEX_1 matches imageId || FRIEND_IMAGE_ID_REGEX_2 matches imageId
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过 [Image.imageId] 构造一个 [Image] 以便发送.
|
* 通过 [Image.imageId] 构造一个 [Image] 以便发送.
|
||||||
* 这个图片必须是服务器已经存在的图片.
|
* 这个图片必须是服务器已经存在的图片.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||||
*
|
*
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 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.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -14,9 +14,9 @@
|
|||||||
package net.mamoe.mirai.message.data
|
package net.mamoe.mirai.message.data
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX
|
||||||
import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_1
|
||||||
import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||||
import kotlin.native.concurrent.SharedImmutable
|
import kotlin.native.concurrent.SharedImmutable
|
||||||
|
|
||||||
@ -240,9 +240,9 @@ internal fun String.imageIdToMd5(offset: Int): ByteArray {
|
|||||||
internal fun calculateImageMd5ByImageId(imageId: String): ByteArray {
|
internal fun calculateImageMd5ByImageId(imageId: String): ByteArray {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
return when {
|
return when {
|
||||||
imageId matches FRIEND_IMAGE_ID_REGEX_2 -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
|
imageId matches IMAGE_ID_REGEX -> imageId.imageIdToMd5(1)
|
||||||
imageId matches FRIEND_IMAGE_ID_REGEX_1 -> imageId.imageIdToMd5(1)
|
imageId matches IMAGE_RESOURCE_ID_REGEX_2 -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
|
||||||
imageId matches GROUP_IMAGE_ID_REGEX -> imageId.imageIdToMd5(1)
|
imageId matches IMAGE_RESOURCE_ID_REGEX_1 -> imageId.imageIdToMd5(1)
|
||||||
|
|
||||||
else -> error(
|
else -> error(
|
||||||
"illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE"
|
"illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE"
|
||||||
@ -251,8 +251,8 @@ internal fun calculateImageMd5ByImageId(imageId: String): ByteArray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE: String =
|
internal val ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE: String =
|
||||||
"ImageId must match Regex `${FRIEND_IMAGE_ID_REGEX_1.pattern}`, " +
|
"ImageId must match Regex `${IMAGE_RESOURCE_ID_REGEX_1.pattern}`, " +
|
||||||
"`${FRIEND_IMAGE_ID_REGEX_2.pattern}` or " +
|
"`${IMAGE_RESOURCE_ID_REGEX_2.pattern}` or " +
|
||||||
"`${GROUP_IMAGE_ID_REGEX.pattern}`"
|
"`${IMAGE_ID_REGEX.pattern}`"
|
||||||
|
|
||||||
// endregion
|
// endregion
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||||
*
|
*
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 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.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -25,10 +25,27 @@ public fun generateImageId(md5: ByteArray, format: String = "mirai"): String {
|
|||||||
return """{${generateUUID(md5)}}.$format"""
|
return """{${generateUUID(md5)}}.$format"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
public fun generateImageIdFromResourceId(resourceId: String, format: String = "mirai"): String? {
|
||||||
|
// friend image id: /1040400290-3666252994-EFF4427CE3D27DB6B1D9A8AB72E7A29C
|
||||||
|
// friend image id: /1040400290-3666252994-EFF4427C E3D2 7DB6 B1D9 A8AB72E7A29C
|
||||||
|
// group image id: {EF42A82D-8DB6-5D0F-4F11-68961D8DA5CB}.png
|
||||||
|
|
||||||
|
val md5String = resourceId.substringAfterLast("-").substringAfter("/").takeIf { it.length == 32 } ?: return null
|
||||||
|
return "{${generateUUID(md5String)}}.$format"
|
||||||
|
}
|
||||||
|
|
||||||
public fun generateUUID(md5: ByteArray): String {
|
public fun generateUUID(md5: ByteArray): String {
|
||||||
return "${md5[0, 3]}-${md5[4, 5]}-${md5[6, 7]}-${md5[8, 9]}-${md5[10, 15]}"
|
return "${md5[0, 3]}-${md5[4, 5]}-${md5[6, 7]}-${md5[8, 9]}-${md5[10, 15]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun generateUUID(md5String: String): String {
|
||||||
|
with(md5String) {
|
||||||
|
check(length == 32) { "it should md5String.length == 32" }
|
||||||
|
return "${substring(0, 8)}-${substring(8, 12)}-${substring(12, 16)}-${substring(16, 20)}-${substring(20, 32)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public operator fun ByteArray.get(rangeStart: Int, rangeEnd: Int): String = buildString {
|
public operator fun ByteArray.get(rangeStart: Int, rangeEnd: Int): String = buildString {
|
||||||
for (it in rangeStart..rangeEnd) {
|
for (it in rangeStart..rangeEnd) {
|
||||||
|
@ -36,9 +36,9 @@ import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
|||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
import net.mamoe.mirai.message.action.Nudge
|
import net.mamoe.mirai.message.action.Nudge
|
||||||
import net.mamoe.mirai.message.data.*
|
import net.mamoe.mirai.message.data.*
|
||||||
import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX
|
||||||
import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_1
|
||||||
import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
|
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
@ -815,9 +815,9 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
|||||||
|
|
||||||
override fun createImage(imageId: String): Image {
|
override fun createImage(imageId: String): Image {
|
||||||
return when {
|
return when {
|
||||||
imageId matches FRIEND_IMAGE_ID_REGEX_1 -> OfflineFriendImage(imageId)
|
imageId matches IMAGE_ID_REGEX -> OfflineGroupImage(imageId)
|
||||||
imageId matches FRIEND_IMAGE_ID_REGEX_2 -> OfflineFriendImage(imageId)
|
imageId matches IMAGE_RESOURCE_ID_REGEX_1 -> OfflineFriendImage(imageId)
|
||||||
imageId matches GROUP_IMAGE_ID_REGEX -> OfflineGroupImage(imageId)
|
imageId matches IMAGE_RESOURCE_ID_REGEX_2 -> OfflineFriendImage(imageId)
|
||||||
else ->
|
else ->
|
||||||
@Suppress("INVISIBLE_MEMBER")
|
@Suppress("INVISIBLE_MEMBER")
|
||||||
throw IllegalArgumentException("Illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE")
|
throw IllegalArgumentException("Illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE")
|
||||||
|
@ -21,12 +21,14 @@ import net.mamoe.mirai.event.events.BeforeImageUploadEvent
|
|||||||
import net.mamoe.mirai.event.events.EventCancelledException
|
import net.mamoe.mirai.event.events.EventCancelledException
|
||||||
import net.mamoe.mirai.event.events.ImageUploadEvent
|
import net.mamoe.mirai.event.events.ImageUploadEvent
|
||||||
import net.mamoe.mirai.internal.message.OfflineFriendImage
|
import net.mamoe.mirai.internal.message.OfflineFriendImage
|
||||||
|
import net.mamoe.mirai.internal.message.getImageType
|
||||||
import net.mamoe.mirai.internal.network.highway.postImage
|
import net.mamoe.mirai.internal.network.highway.postImage
|
||||||
import net.mamoe.mirai.internal.network.highway.sizeToString
|
import net.mamoe.mirai.internal.network.highway.sizeToString
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Cmd0x352
|
import net.mamoe.mirai.internal.network.protocol.data.proto.Cmd0x352
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.LongConn
|
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.LongConn
|
||||||
import net.mamoe.mirai.message.data.Image
|
import net.mamoe.mirai.message.data.Image
|
||||||
import net.mamoe.mirai.utils.ExternalResource
|
import net.mamoe.mirai.utils.ExternalResource
|
||||||
|
import net.mamoe.mirai.utils.generateImageIdFromResourceId
|
||||||
import net.mamoe.mirai.utils.toUHexString
|
import net.mamoe.mirai.utils.toUHexString
|
||||||
import net.mamoe.mirai.utils.verbose
|
import net.mamoe.mirai.utils.verbose
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@ -71,10 +73,16 @@ internal abstract class AbstractUser(
|
|||||||
else -> "unknown"
|
else -> "unknown"
|
||||||
}
|
}
|
||||||
return when (response) {
|
return when (response) {
|
||||||
is LongConn.OffPicUp.Response.FileExists -> OfflineFriendImage(response.resourceId)
|
is LongConn.OffPicUp.Response.FileExists -> OfflineFriendImage(
|
||||||
.also {
|
imageId = generateImageIdFromResourceId(
|
||||||
ImageUploadEvent.Succeed(this, resource, it).broadcast()
|
resourceId = response.resourceId,
|
||||||
}
|
format = getImageType(response.imageInfo.fileType).takeIf { it != ExternalResource.DEFAULT_FORMAT_NAME }
|
||||||
|
?: resource.formatName
|
||||||
|
) ?: response.resourceId
|
||||||
|
).also {
|
||||||
|
ImageUploadEvent.Succeed(this, resource, it).broadcast()
|
||||||
|
}
|
||||||
|
|
||||||
is LongConn.OffPicUp.Response.RequireUpload -> {
|
is LongConn.OffPicUp.Response.RequireUpload -> {
|
||||||
bot.network.logger.verbose {
|
bot.network.logger.verbose {
|
||||||
"[Http] Uploading $kind image, size=${resource.size.sizeToString()}"
|
"[Http] Uploading $kind image, size=${resource.size.sizeToString()}"
|
||||||
@ -105,7 +113,9 @@ internal abstract class AbstractUser(
|
|||||||
)*/
|
)*/
|
||||||
// 为什么不能 ??
|
// 为什么不能 ??
|
||||||
|
|
||||||
OfflineFriendImage(response.resourceId).also {
|
OfflineFriendImage(
|
||||||
|
generateImageIdFromResourceId(response.resourceId, resource.formatName) ?: response.resourceId
|
||||||
|
).also {
|
||||||
ImageUploadEvent.Succeed(this, resource, it).broadcast()
|
ImageUploadEvent.Succeed(this, resource, it).broadcast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
@file:Suppress("DEPRECATION_ERROR", "UnusedImport")
|
|
||||||
|
|
||||||
package net.mamoe.mirai.internal.message
|
|
||||||
|
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem
|
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
|
||||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
|
||||||
import net.mamoe.mirai.message.data.FlashImage
|
|
||||||
import net.mamoe.mirai.message.data.isFriendImage
|
|
||||||
import net.mamoe.mirai.message.data.isGroupImage
|
|
||||||
import net.mamoe.mirai.message.data.md5
|
|
||||||
|
|
||||||
|
|
||||||
internal fun FlashImage.toJceData(): ImMsgBody.Elem {
|
|
||||||
return when {
|
|
||||||
image.isFriendImage -> ImMsgBody.Elem(
|
|
||||||
commonElem = ImMsgBody.CommonElem(
|
|
||||||
serviceType = 3,
|
|
||||||
businessType = 0,
|
|
||||||
pbElem = HummerCommelem.MsgElemInfoServtype3(
|
|
||||||
flashC2cPic = ImMsgBody.NotOnlineImage(
|
|
||||||
filePath = image.imageId,
|
|
||||||
resId = image.imageId,
|
|
||||||
picMd5 = image.md5,
|
|
||||||
oldPicMd5 = false,
|
|
||||||
pbReserve = byteArrayOf(0x78, 0x06)
|
|
||||||
)
|
|
||||||
).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
image.isGroupImage -> ImMsgBody.Elem(
|
|
||||||
commonElem = ImMsgBody.CommonElem(
|
|
||||||
serviceType = 3,
|
|
||||||
businessType = 0,
|
|
||||||
pbElem = HummerCommelem.MsgElemInfoServtype3(
|
|
||||||
flashTroopPic = ImMsgBody.CustomFace(
|
|
||||||
filePath = image.imageId,
|
|
||||||
picMd5 = image.md5,
|
|
||||||
pbReserve = byteArrayOf(0x78, 0x06)
|
|
||||||
)
|
|
||||||
).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
else -> error("Internal error: an image is neither group image nor friend image.")
|
|
||||||
}
|
|
||||||
}
|
|
@ -177,8 +177,10 @@ internal fun MessageChain.toRichTextElems(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
is FlashImage -> elements.add(currentMessage.toJceData())
|
is FlashImage -> elements.add(currentMessage.toJceData(messageTarget))
|
||||||
.also { transformOneMessage(UNSUPPORTED_FLASH_MESSAGE_PLAIN) }
|
.also { transformOneMessage(UNSUPPORTED_FLASH_MESSAGE_PLAIN) }
|
||||||
|
|
||||||
|
|
||||||
is AtAll -> elements.add(atAllData)
|
is AtAll -> elements.add(atAllData)
|
||||||
is Face -> elements.add(
|
is Face -> elements.add(
|
||||||
if (currentMessage.id >= 260) {
|
if (currentMessage.id >= 260) {
|
||||||
|
@ -16,17 +16,19 @@ import net.mamoe.mirai.Bot
|
|||||||
import net.mamoe.mirai.IMirai
|
import net.mamoe.mirai.IMirai
|
||||||
import net.mamoe.mirai.contact.Contact
|
import net.mamoe.mirai.contact.Contact
|
||||||
import net.mamoe.mirai.contact.Contact.Companion.uploadImage
|
import net.mamoe.mirai.contact.Contact.Companion.uploadImage
|
||||||
|
import net.mamoe.mirai.contact.ContactOrBot
|
||||||
import net.mamoe.mirai.contact.Group
|
import net.mamoe.mirai.contact.Group
|
||||||
|
import net.mamoe.mirai.contact.User
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||||
import net.mamoe.mirai.message.data.FriendImage
|
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||||
import net.mamoe.mirai.message.data.GroupImage
|
import net.mamoe.mirai.message.data.*
|
||||||
import net.mamoe.mirai.message.data.Image
|
import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX
|
||||||
import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1
|
|
||||||
import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2
|
|
||||||
import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
|
|
||||||
import net.mamoe.mirai.message.data.md5
|
|
||||||
import net.mamoe.mirai.utils.*
|
|
||||||
import net.mamoe.mirai.utils.ExternalResource.Companion.DEFAULT_FORMAT_NAME
|
import net.mamoe.mirai.utils.ExternalResource.Companion.DEFAULT_FORMAT_NAME
|
||||||
|
import net.mamoe.mirai.utils.generateImageId
|
||||||
|
import net.mamoe.mirai.utils.generateImageIdFromResourceId
|
||||||
|
import net.mamoe.mirai.utils.hexToBytes
|
||||||
|
import net.mamoe.mirai.utils.toUHexString
|
||||||
|
|
||||||
internal class OnlineGroupImageImpl(
|
internal class OnlineGroupImageImpl(
|
||||||
internal val delegate: ImMsgBody.CustomFace
|
internal val delegate: ImMsgBody.CustomFace
|
||||||
@ -36,7 +38,7 @@ OnlineGroupImage() {
|
|||||||
delegate.picMd5,
|
delegate.picMd5,
|
||||||
delegate.filePath.substringAfterLast('.')
|
delegate.filePath.substringAfterLast('.')
|
||||||
).takeIf {
|
).takeIf {
|
||||||
GROUP_IMAGE_ID_REGEX.matches(it)
|
IMAGE_ID_REGEX.matches(it)
|
||||||
} ?: generateImageId(delegate.picMd5)
|
} ?: generateImageId(delegate.picMd5)
|
||||||
|
|
||||||
override val originUrl: String
|
override val originUrl: String
|
||||||
@ -60,7 +62,8 @@ internal class OnlineFriendImageImpl(
|
|||||||
internal val delegate: ImMsgBody.NotOnlineImage
|
internal val delegate: ImMsgBody.NotOnlineImage
|
||||||
) : @Suppress("DEPRECATION")
|
) : @Suppress("DEPRECATION")
|
||||||
OnlineFriendImage() {
|
OnlineFriendImage() {
|
||||||
override val imageId: String get() = delegate.resId
|
override val imageId: String =
|
||||||
|
generateImageIdFromResourceId(delegate.resId, getImageType(delegate.imgType)) ?: delegate.resId
|
||||||
override val originUrl: String
|
override val originUrl: String
|
||||||
get() = if (delegate.origUrl.isNotBlank()) {
|
get() = if (delegate.origUrl.isNotBlank()) {
|
||||||
"http://c2cpicdw.qpic.cn" + this.delegate.origUrl
|
"http://c2cpicdw.qpic.cn" + this.delegate.origUrl
|
||||||
@ -96,7 +99,7 @@ internal fun getImageType(id: Int): String {
|
|||||||
1002 -> "webp"
|
1002 -> "webp"
|
||||||
1005 -> "bmp"
|
1005 -> "bmp"
|
||||||
2000 -> "gif"
|
2000 -> "gif"
|
||||||
2001 -> "png"
|
2001, 3 -> "png"
|
||||||
else -> DEFAULT_FORMAT_NAME
|
else -> DEFAULT_FORMAT_NAME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,6 +119,7 @@ internal fun ImMsgBody.NotOnlineImage.toCustomFace(): ImMsgBody.CustomFace {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// aka friend image id
|
||||||
internal fun ImMsgBody.NotOnlineImageOrCustomFace.calculateResId(): String {
|
internal fun ImMsgBody.NotOnlineImageOrCustomFace.calculateResId(): String {
|
||||||
val url = origUrl.takeIf { it.isNotBlank() }
|
val url = origUrl.takeIf { it.isNotBlank() }
|
||||||
?: thumbUrl.takeIf { it.isNotBlank() }
|
?: thumbUrl.takeIf { it.isNotBlank() }
|
||||||
@ -165,12 +169,13 @@ private val oldData: ByteArray =
|
|||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
internal fun OfflineFriendImage.toJceData(): ImMsgBody.NotOnlineImage {
|
internal fun OfflineFriendImage.toJceData(): ImMsgBody.NotOnlineImage {
|
||||||
|
val friendImageId = this.friendImageId
|
||||||
return ImMsgBody.NotOnlineImage(
|
return ImMsgBody.NotOnlineImage(
|
||||||
filePath = this.imageId,
|
filePath = friendImageId,
|
||||||
resId = this.imageId,
|
resId = friendImageId,
|
||||||
oldPicMd5 = false,
|
oldPicMd5 = false,
|
||||||
picMd5 = this.md5,
|
picMd5 = this.md5,
|
||||||
downloadPath = this.imageId,
|
downloadPath = friendImageId,
|
||||||
original = 1,
|
original = 1,
|
||||||
pbReserve = byteArrayOf(0x78, 0x02)
|
pbReserve = byteArrayOf(0x78, 0x02)
|
||||||
)
|
)
|
||||||
@ -207,21 +212,6 @@ internal interface SuspendDeferredOriginUrlAware : Image {
|
|||||||
suspend fun getUrl(bot: Bot): String
|
suspend fun getUrl(bot: Bot): String
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 由 [ExternalImage] 委托的 [Image] 类型.
|
|
||||||
*/
|
|
||||||
@MiraiExperimentalApi("Will be renamed to OfflineImage on 1.2.0")
|
|
||||||
@Suppress("DEPRECATION_ERROR")
|
|
||||||
internal class ExperimentalDeferredImage internal constructor(
|
|
||||||
@Suppress("CanBeParameter") private val externalImage: ExternalResource // for future use
|
|
||||||
) : AbstractImage(), SuspendDeferredOriginUrlAware {
|
|
||||||
override suspend fun getUrl(bot: Bot): String {
|
|
||||||
TODO()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val imageId: String = externalImage.calculateResourceId()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("EXPOSED_SUPER_INTERFACE")
|
@Suppress("EXPOSED_SUPER_INTERFACE")
|
||||||
internal interface OnlineImage : Image, ConstOriginUrlAware {
|
internal interface OnlineImage : Image, ConstOriginUrlAware {
|
||||||
override val originUrl: String
|
override val originUrl: String
|
||||||
@ -236,8 +226,6 @@ internal interface OnlineImage : Image, ConstOriginUrlAware {
|
|||||||
internal interface OfflineImage : Image
|
internal interface OfflineImage : Image
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过 [Group.uploadImage] 上传得到的 [GroupImage]. 它的链接需要查询 [IMirai.queryImageUrl]
|
|
||||||
*
|
|
||||||
* @param imageId 参考 [Image.imageId]
|
* @param imageId 参考 [Image.imageId]
|
||||||
*/
|
*/
|
||||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
@ -254,7 +242,7 @@ internal data class OfflineGroupImage(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
require(imageId matches GROUP_IMAGE_ID_REGEX) {
|
require(imageId matches IMAGE_ID_REGEX) {
|
||||||
"Illegal imageId. It must matches GROUP_IMAGE_ID_REGEX"
|
"Illegal imageId. It must matches GROUP_IMAGE_ID_REGEX"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,6 +254,12 @@ internal data class OfflineGroupImage(
|
|||||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
internal abstract class OnlineGroupImage : GroupImage(), OnlineImage
|
internal abstract class OnlineGroupImage : GroupImage(), OnlineImage
|
||||||
|
|
||||||
|
internal val Image.friendImageId: String
|
||||||
|
get() {
|
||||||
|
// /1234567890-3666252994-EFF4427CE3D27DB6B1D9A8AB72E7A29C
|
||||||
|
return "/000000000-000000000-${md5.toUHexString("")}"
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过 [Group.uploadImage] 上传得到的 [GroupImage]. 它的链接需要查询 [IMirai.queryImageUrl]
|
* 通过 [Group.uploadImage] 上传得到的 [GroupImage]. 它的链接需要查询 [IMirai.queryImageUrl]
|
||||||
*
|
*
|
||||||
@ -276,13 +270,7 @@ internal data class OfflineFriendImage(
|
|||||||
override val imageId: String
|
override val imageId: String
|
||||||
) : FriendImage(), OfflineImage, DeferredOriginUrlAware {
|
) : FriendImage(), OfflineImage, DeferredOriginUrlAware {
|
||||||
override fun getUrl(bot: Bot): String {
|
override fun getUrl(bot: Bot): String {
|
||||||
return "http://c2cpicdw.qpic.cn/offpic_new/${bot.id}/${this.imageId}/0?term=2"
|
return "http://c2cpicdw.qpic.cn/offpic_new/${bot.id}${this.friendImageId}/0?term=2"
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
require(imageId matches FRIEND_IMAGE_ID_REGEX_1 || imageId matches FRIEND_IMAGE_ID_REGEX_2) {
|
|
||||||
"Illegal imageId. It must matches either FRIEND_IMAGE_ID_REGEX_1 or FRIEND_IMAGE_ID_REGEX_2"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,3 +280,38 @@ internal data class OfflineFriendImage(
|
|||||||
internal abstract class OnlineFriendImage : FriendImage(), OnlineImage
|
internal abstract class OnlineFriendImage : FriendImage(), OnlineImage
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
|
||||||
|
internal fun FlashImage.toJceData(messageTarget: ContactOrBot?): ImMsgBody.Elem {
|
||||||
|
return if (messageTarget is User) {
|
||||||
|
ImMsgBody.Elem(
|
||||||
|
commonElem = ImMsgBody.CommonElem(
|
||||||
|
serviceType = 3,
|
||||||
|
businessType = 0,
|
||||||
|
pbElem = HummerCommelem.MsgElemInfoServtype3(
|
||||||
|
flashC2cPic = ImMsgBody.NotOnlineImage(
|
||||||
|
filePath = image.friendImageId,
|
||||||
|
resId = image.friendImageId,
|
||||||
|
picMd5 = image.md5,
|
||||||
|
oldPicMd5 = false,
|
||||||
|
pbReserve = byteArrayOf(0x78, 0x06)
|
||||||
|
)
|
||||||
|
).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ImMsgBody.Elem(
|
||||||
|
commonElem = ImMsgBody.CommonElem(
|
||||||
|
serviceType = 3,
|
||||||
|
businessType = 0,
|
||||||
|
pbElem = HummerCommelem.MsgElemInfoServtype3(
|
||||||
|
flashTroopPic = ImMsgBody.CustomFace(
|
||||||
|
filePath = image.imageId,
|
||||||
|
picMd5 = image.md5,
|
||||||
|
pbReserve = byteArrayOf(0x78, 0x06)
|
||||||
|
)
|
||||||
|
).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user