From 1a4c3ba6029c2a8573b123d2b327b3df94a1d251 Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 1 May 2020 21:51:09 +0800 Subject: [PATCH] Simplify Image structure: deprecate online and offline classification. --- .../mirai/qqandroid/QQAndroidBot.common.kt | 1 + .../mirai/qqandroid/contact/FriendImpl.kt | 15 +- .../mirai/qqandroid/contact/GroupImpl.kt | 1 + .../mirai/qqandroid/contact/MemberImpl.kt | 4 +- .../mirai/qqandroid/message/convension.kt | 8 +- .../mirai/qqandroid/message/imagesImpl.kt | 8 +- .../qqandroid/message/outgoingSourceImpl.kt | 4 +- .../kotlin/net.mamoe.mirai/contact/Contact.kt | 2 +- .../kotlin/net.mamoe.mirai/contact/Group.kt | 4 +- .../kotlin/net.mamoe.mirai/contact/User.kt | 4 +- .../net.mamoe.mirai/message/data/Image.kt | 174 +++++++++++------- .../net.mamoe.mirai/message/data/Message.kt | 11 +- .../net.mamoe.mirai/message/data/impl.kt | 2 +- .../net.mamoe.mirai/utils/ExternalImage.kt | 5 +- .../mamoe/mirai/message/SendImageUtilsJvm.kt | 22 +-- .../net/mamoe/mirai/message/data/Image.kt | 5 +- 16 files changed, 160 insertions(+), 110 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt index b270b3858..dbef3f8c5 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt @@ -720,6 +720,7 @@ internal abstract class QQAndroidBotBase constructor( } } + @Suppress("DEPRECATION") override suspend fun queryImageUrl(image: Image): String = when (image) { is OnlineFriendImageImpl -> image.originUrl is OnlineGroupImageImpl -> image.originUrl diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt index ecfab54db..75d86d63f 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt @@ -25,8 +25,8 @@ import net.mamoe.mirai.event.events.BeforeImageUploadEvent import net.mamoe.mirai.event.events.EventCancelledException import net.mamoe.mirai.event.events.ImageUploadEvent import net.mamoe.mirai.message.MessageReceipt +import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Message -import net.mamoe.mirai.message.data.OfflineFriendImage import net.mamoe.mirai.message.data.isContentNotEmpty import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.network.highway.postImage @@ -86,7 +86,7 @@ internal class FriendImpl( @JvmSynthetic @OptIn(MiraiInternalAPI::class, ExperimentalStdlibApi::class, ExperimentalTime::class) - override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage = try { + override suspend fun uploadImage(image: ExternalImage): Image = try { if (BeforeImageUploadEvent(this, image).broadcast().isCancelled) { throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup") } @@ -103,11 +103,12 @@ internal class FriendImpl( ) ).sendAndExpect() - @Suppress("UNCHECKED_CAST") // bug + @Suppress("UNCHECKED_CAST", "DEPRECATION") // bug return when (response) { - is LongConn.OffPicUp.Response.FileExists -> OfflineFriendImage(response.resourceId).also { - ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast() - } + is LongConn.OffPicUp.Response.FileExists -> net.mamoe.mirai.message.data.OfflineFriendImage(response.resourceId) + .also { + ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast() + } is LongConn.OffPicUp.Response.RequireUpload -> { bot.network.logger.verbose { "[Http] Uploading friend image, size=${image.inputSize.sizeToString()}" @@ -139,7 +140,7 @@ internal class FriendImpl( )*/ // 为什么不能 ?? - return OfflineFriendImage(response.resourceId).also { + return net.mamoe.mirai.message.data.OfflineFriendImage(response.resourceId).also { ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast() } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt index 62f74b828..da8048897 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt @@ -399,6 +399,7 @@ internal class GroupImpl( return MessageReceipt(source, this, botAsMember) } + @Suppress("DEPRECATION") @OptIn(ExperimentalTime::class) @JvmSynthetic override suspend fun uploadImage(image: ExternalImage): OfflineGroupImage = try { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt index 8f0ecbbf4..a5f0350cf 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt @@ -24,8 +24,8 @@ import net.mamoe.mirai.event.events.MemberCardChangeEvent import net.mamoe.mirai.event.events.MemberLeaveEvent import net.mamoe.mirai.event.events.MemberSpecialTitleChangeEvent import net.mamoe.mirai.message.MessageReceipt +import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Message -import net.mamoe.mirai.message.data.OfflineFriendImage import net.mamoe.mirai.message.data.asMessageChain import net.mamoe.mirai.message.data.isContentNotEmpty import net.mamoe.mirai.qqandroid.QQAndroidBot @@ -81,7 +81,7 @@ internal class MemberImpl constructor( } @JvmSynthetic - override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage = qq.uploadImage(image) + override suspend fun uploadImage(image: ExternalImage): Image = qq.uploadImage(image) override var permission: MemberPermission = memberInfo.permission diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt index 31ae7e9c3..c4f22992f 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt @@ -129,10 +129,14 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B ) transformOneMessage(UNSUPPORTED_POKE_MESSAGE_PLAIN) } - is OfflineGroupImage -> elements.add(ImMsgBody.Elem(customFace = it.toJceData())) + is @Suppress("DEPRECATION") + OfflineGroupImage + -> elements.add(ImMsgBody.Elem(customFace = it.toJceData())) is OnlineGroupImageImpl -> elements.add(ImMsgBody.Elem(customFace = it.delegate)) is OnlineFriendImageImpl -> elements.add(ImMsgBody.Elem(notOnlineImage = it.delegate)) - is OfflineFriendImage -> elements.add(ImMsgBody.Elem(notOnlineImage = it.toJceData())) + is @Suppress("DEPRECATION") + OfflineFriendImage + -> elements.add(ImMsgBody.Elem(notOnlineImage = it.toJceData())) is GroupFlashImage -> elements.add(it.toJceData()) .also { transformOneMessage(UNSUPPORTED_FLASH_MESSAGE_PLAIN) } is FriendFlashImage -> elements.add(it.toJceData()) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/imagesImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/imagesImpl.kt index 3e8356b6a..c00b02f26 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/imagesImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/imagesImpl.kt @@ -16,7 +16,8 @@ import net.mamoe.mirai.utils.ExternalImage internal class OnlineGroupImageImpl( internal val delegate: ImMsgBody.CustomFace -) : OnlineGroupImage() { +) : @Suppress("DEPRECATION") +OnlineGroupImage() { override val imageId: String = ExternalImage.generateImageId(delegate.md5) override val originUrl: String get() = "http://gchat.qpic.cn" + delegate.origUrl @@ -32,7 +33,8 @@ internal class OnlineGroupImageImpl( internal class OnlineFriendImageImpl( internal val delegate: ImMsgBody.NotOnlineImage -) : OnlineFriendImage() { +) : @Suppress("DEPRECATION") +OnlineFriendImage() { override val imageId: String get() = delegate.resId override val originUrl: String get() = if (delegate.origUrl.isNotEmpty()) { @@ -51,6 +53,7 @@ internal class OnlineFriendImageImpl( } } +@Suppress("DEPRECATION") internal fun OfflineGroupImage.toJceData(): ImMsgBody.CustomFace { return ImMsgBody.CustomFace( filePath = this.imageId, @@ -67,6 +70,7 @@ private val oldData: ByteArray = "15 36 20 39 32 6B 41 31 00 38 37 32 66 30 36 36 30 33 61 65 31 30 33 62 37 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 30 31 45 39 34 35 31 42 2D 37 30 45 44 2D 45 41 45 33 2D 42 33 37 43 2D 31 30 31 46 31 45 45 42 46 35 42 35 7D 2E 70 6E 67 41".hexToBytes() +@Suppress("DEPRECATION") internal fun OfflineFriendImage.toJceData(): ImMsgBody.NotOnlineImage { return ImMsgBody.NotOnlineImage( filePath = this.imageId, diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/outgoingSourceImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/outgoingSourceImpl.kt index 1ea7feb39..b73f0479b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/outgoingSourceImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/outgoingSourceImpl.kt @@ -146,7 +146,7 @@ internal class MessageSourceToGroupImpl( type = 0, time = time, pbReserve = SourceMsg.ResvAttr( - origUids = id.toLong() and 0xffFFffFF // id is actually messageRandom + origUids = internalId.toLong() and 0xffFFffFF // id is actually messageRandom ).toByteArray(SourceMsg.ResvAttr.serializer()), srcMsg = MsgComm.Msg( msgHead = MsgComm.MsgHead( @@ -156,7 +156,7 @@ internal class MessageSourceToGroupImpl( c2cCmd = 1, msgSeq = sequenceId, msgTime = time, - msgUid = id.toLong() and 0xffFFffFF, // ok + msgUid = internalId.toLong() and 0xffFFffFF, // ok groupInfo = MsgComm.GroupInfo(groupCode = targetId), isSrcMsg = true ), diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt index 71959069d..ac0ea3dd1 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt @@ -89,7 +89,7 @@ abstract class Contact : CoroutineScope, ContactJavaFriendlyAPI(), ContactOrBot * @throws OverFileSizeMaxException 当图片文件过大而被服务器拒绝上传时抛出. (最大大小约为 20 MB, 但 mirai 限制的大小为 30 MB) */ @JvmSynthetic - abstract suspend fun uploadImage(image: ExternalImage): OfflineImage + abstract suspend fun uploadImage(image: ExternalImage): Image final override fun equals(other: Any?): Boolean = super.equals(other) final override fun hashCode(): Int = super.hashCode() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index 11a38f1e4..4957d9dd2 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -20,8 +20,8 @@ import net.mamoe.mirai.event.events.* import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent import net.mamoe.mirai.message.MessageReceipt +import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Message -import net.mamoe.mirai.message.data.OfflineGroupImage import net.mamoe.mirai.message.data.toMessage import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.internal.runBlocking @@ -172,7 +172,7 @@ abstract class Group : Contact(), CoroutineScope { * @throws OverFileSizeMaxException 当图片文件过大而被服务器拒绝上传时. (最大大小约为 20 MB) */ @JvmSynthetic - abstract override suspend fun uploadImage(image: ExternalImage): OfflineGroupImage + abstract override suspend fun uploadImage(image: ExternalImage): Image companion object { /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/User.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/User.kt index 7db56e1cc..dd5e9d2d5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/User.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/User.kt @@ -19,8 +19,8 @@ import net.mamoe.mirai.event.events.ImageUploadEvent import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent import net.mamoe.mirai.message.MessageReceipt +import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Message -import net.mamoe.mirai.message.data.OfflineFriendImage import net.mamoe.mirai.message.data.toMessage import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.OverFileSizeMaxException @@ -91,7 +91,7 @@ abstract class User : Contact(), CoroutineScope { * @throws OverFileSizeMaxException 当图片文件过大而被服务器拒绝上传时. (最大大小约为 20 MB) */ @JvmSynthetic - abstract override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage + abstract override suspend fun uploadImage(image: ExternalImage): Image abstract override fun toString(): String } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt index 3e239dd3f..48a81f6b5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt @@ -10,7 +10,7 @@ @file:JvmMultifileClass @file:JvmName("MessageUtils") -@file:Suppress("EXPERIMENTAL_API_USAGE", "unused") +@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "WRONG_MODIFIER_CONTAINING_DECLARATION", "DEPRECATION") package net.mamoe.mirai.message.data @@ -81,9 +81,50 @@ expect interface Image : Message, MessageContent { @Deprecated(""" 不要自行实现 Image, 它必须由协议模块实现, 否则会无法发送也无法解析. """, level = DeprecationLevel.HIDDEN) - @Suppress("PropertyName", "DeprecatedCallableAddReplaceWith") + @Suppress("PropertyName") @get:JvmSynthetic - val DoNotImplementThisClass: Nothing? + internal val DoNotImplementThisClass: Nothing? +} + +/** + * 群图片. + * + * 群拖 + * + * @property imageId 形如 `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai` (后缀一定为 `".mirai"`) + * @see Image 查看更多说明 + */ +@Suppress("DEPRECATION_ERROR") +// CustomFace +@OptIn(MiraiInternalAPI::class) +sealed class GroupImage : AbstractImage() { + companion object Key : Message.Key { + override val typeName: String get() = "GroupImage" + } +} + +/** + * 计算图片的 md5 校验值. + * + * 在 Java 使用: `MessageUtils.calculateImageMd5(image)` + */ +@get:JvmName("calculateImageMd5") +@SinceMirai("0.39.0") +val Image.md5: ByteArray + get() = calculateImageMd5ByImageId(imageId) + + +/** + * 好友图片 + * + * [imageId] 形如 `/f8f1ab55-bf8e-4236-b55e-955848d7069f` (37 长度) 或 `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206` (54 长度) + */ // NotOnlineImage +@Suppress("DEPRECATION_ERROR") +@OptIn(MiraiInternalAPI::class) +sealed class FriendImage : AbstractImage() { + companion object Key : Message.Key { + override val typeName: String get() = "FriendImage" + } } /** @@ -148,29 +189,18 @@ fun Image(imageId: String): OfflineImage = when { else -> throw IllegalArgumentException("Illegal imageId: $imageId. $ILLEGAL_IMAGE_ID_EXCEPTION_MESSAGE") } -// region 在线图片 - -/** - * 在服务器上的图片. 它可以直接获取下载链接. - * - * 一般由 [Contact.uploadImage] 得到 - */ -interface OnlineImage : Image { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineImage" - } - - /** - * 原图下载链接. 包含域名 - */ - val originUrl: String -} - /** * 查询原图下载链接. + * + * 当图片为从服务器接收的消息中的图片时, 可以直接获取下载链接, 本函数不会挂起协程. + * 其他情况下协程可能会挂起并向服务器查询下载链接, 或不挂起并拼接一个链接. + * + * @return 原图 HTTP 下载链接 (非 HTTPS) + * @throws IllegalStateException 当无任何 [Bot] 在线时抛出 (因为无法获取相关协议) */ @JvmSynthetic suspend fun Image.queryUrl(): String { + @Suppress("DEPRECATION") @OptIn(MiraiInternalAPI::class) return when (this) { is OnlineImage -> this.originUrl @@ -179,10 +209,32 @@ suspend fun Image.queryUrl(): String { } } -// endregion 在线图片 + +///////////////////////// +///// 以下 API 已弃用 ///// +///////////////////////// -// region 离线图片 +// region 已启用 + +internal const val ONLINE_OFFLINE_DEPRECATION_MESSAGE = """ +自 1.0.0 起, mirai 已经能正常处理离线图片和在线图片的下载链接等功能. +使用者无需考虑一个图片为在线图片还是离线图片, 只需使用 Image 类型. +""" + + +@PlannedRemoval("1.2.0") // 改为 internal +@Deprecated(ONLINE_OFFLINE_DEPRECATION_MESSAGE, + level = DeprecationLevel.WARNING, + replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image") +) +interface OnlineImage : Image { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineImage" + } + + val originUrl: String +} /** * 离线的图片, 即为客户端主动上传到服务器而获得的 [Image] 实例. @@ -190,45 +242,37 @@ suspend fun Image.queryUrl(): String { * * 一般由 [Contact.uploadImage] 得到 */ +@PlannedRemoval("1.2.0") // 改为 internal +@Deprecated(ONLINE_OFFLINE_DEPRECATION_MESSAGE, + level = DeprecationLevel.WARNING, + replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image") +) interface OfflineImage : Image { companion object Key : Message.Key { override val typeName: String get() = "OfflineImage" } } -/** - * 原图下载链接. 包含域名 - */ +@PlannedRemoval("1.2.0") // 删除 +@Deprecated(ONLINE_OFFLINE_DEPRECATION_MESSAGE, + level = DeprecationLevel.HIDDEN +) @JvmSynthetic suspend fun OfflineImage.queryUrl(): String { @OptIn(MiraiInternalAPI::class) return BotImpl.instances.peekFirst().get()?.queryImageUrl(this) ?: error("No Bot available to query image url") } -// endregion 离线图片 - -// region 群图片 - - -/** - * 群图片. - * - * [imageId] 形如 `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai` (45 长度) - */ -@Suppress("DEPRECATION_ERROR") -// CustomFace -@OptIn(MiraiInternalAPI::class) -sealed class GroupImage : AbstractImage() { - companion object Key : Message.Key { - override val typeName: String get() = "GroupImage" - } -} - /** * 通过 [Group.uploadImage] 上传得到的 [GroupImage]. 它的链接需要查询 [Bot.queryImageUrl] * * @param imageId 参考 [Image.imageId] */ +@PlannedRemoval("1.2.0") // 改为 internal +@Deprecated(ONLINE_OFFLINE_DEPRECATION_MESSAGE, + level = DeprecationLevel.WARNING, + replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image") +) @Serializable data class OfflineGroupImage( override val imageId: String @@ -241,40 +285,26 @@ data class OfflineGroupImage( } } -@get:JvmName("calculateImageMd5") -@SinceMirai("0.39.0") -val Image.md5: ByteArray - get() = calculateImageMd5ByImageId(imageId) - /** * 接收消息时获取到的 [GroupImage]. 它可以直接获取下载链接 [originUrl] */ +@PlannedRemoval("1.2.0") // 改为 internal +@Deprecated(ONLINE_OFFLINE_DEPRECATION_MESSAGE, + level = DeprecationLevel.WARNING, + replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image") +) abstract class OnlineGroupImage : GroupImage(), OnlineImage - -// endregion 群图片 - -// region 好友图片 - - -/** - * 好友图片 - * - * [imageId] 形如 `/f8f1ab55-bf8e-4236-b55e-955848d7069f` (37 长度) 或 `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206` (54 长度) - */ // NotOnlineImage -@Suppress("DEPRECATION_ERROR") -@OptIn(MiraiInternalAPI::class) -sealed class FriendImage : AbstractImage() { - companion object Key : Message.Key { - override val typeName: String get() = "FriendImage" - } -} - /** * 通过 [Group.uploadImage] 上传得到的 [GroupImage]. 它的链接需要查询 [Bot.queryImageUrl] * * @param imageId 参考 [Image.imageId] */ +@PlannedRemoval("1.2.0") // 改为 internal +@Deprecated(ONLINE_OFFLINE_DEPRECATION_MESSAGE, + level = DeprecationLevel.WARNING, + replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image") +) @Serializable data class OfflineFriendImage( override val imageId: String @@ -289,6 +319,11 @@ data class OfflineFriendImage( /** * 接收消息时获取到的 [FriendImage]. 它可以直接获取下载链接 [originUrl] */ +@PlannedRemoval("1.2.0") // 改为 internal +@Deprecated(ONLINE_OFFLINE_DEPRECATION_MESSAGE, + level = DeprecationLevel.WARNING, + replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image") +) abstract class OnlineFriendImage : FriendImage(), OnlineImage // endregion @@ -326,6 +361,7 @@ sealed class AbstractImage : Image { field = "[mirai:image:$imageId]" field } + final override fun toString(): String = _stringValue!! final override fun contentToString(): String = "[图片]" } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt index b33d48118..dffe346e7 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt @@ -25,6 +25,7 @@ import kotlin.jvm.JvmSynthetic /** * 可发送的或从服务器接收的消息. + * * 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等. * * [消息][Message] 分为 @@ -37,20 +38,20 @@ import kotlin.jvm.JvmSynthetic * 这与使用 [String] 的使用非常类似. * * 比较 [SingleMessage] 与 [String]: - * `if(message.contentToString() == "你好") qq.sendMessage(event)` + * `if(message.contentToString() == "你好") friend.sendMessage(event)` * - * 连接 [Message] 与 [Message], [String], (使用 operator [Message.plus]): - * ```kotlin + * 连接 [Message] 与 [Message], [String], (使用操作符 [Message.plus]): + * ``` * text = PlainText("Hello ") * qq.sendMessage(text + "world") * ``` * * `Message1 + Message2 + Message3`, 类似 [String] 的连接: - * + * ``` * +----------+ plus +----------+ plus +----------+ * | Message1 | <------ | Message2 | <------ | Message3 | * +----------+ +----------+ +----------+ - * + * ``` * * 但注意: 不能 `String + Message`. 只能 `Message + String` * diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/impl.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/impl.kt index 7e7f01bbe..6a2e0f432 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/impl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/impl.kt @@ -198,7 +198,7 @@ internal inline fun List.indexOfFirst(offset: Int, predicate: (T) -> Bool @OptIn(MiraiExperimentalAPI::class) @JvmSynthetic -@Suppress("UNCHECKED_CAST", "DEPRECATION_ERROR") +@Suppress("UNCHECKED_CAST", "DEPRECATION_ERROR", "DEPRECATION") internal fun MessageChain.firstOrNullImpl(key: Message.Key): M? = when (key) { At -> firstIsInstanceOrNull() AtAll -> firstIsInstanceOrNull() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt index baf377551..03f7fad91 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt @@ -21,7 +21,6 @@ import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.User import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.Image -import net.mamoe.mirai.message.data.OfflineImage import net.mamoe.mirai.message.data.sendTo import net.mamoe.mirai.message.data.toLongUnsigned import kotlin.jvm.JvmSynthetic @@ -117,7 +116,7 @@ suspend fun ExternalImage.sendTo(contact: C): MessageReceipt = * @see contact 图片上传对象. 由于好友图片与群图片不通用, 上传时必须提供目标联系人 */ @JvmSynthetic -suspend fun ExternalImage.upload(contact: Contact): OfflineImage = when (contact) { +suspend fun ExternalImage.upload(contact: Contact): Image = when (contact) { is Group -> contact.uploadImage(this) is User -> contact.uploadImage(this) else -> error("unreachable") @@ -129,6 +128,8 @@ suspend fun ExternalImage.upload(contact: Contact): OfflineImage = when (contact @JvmSynthetic suspend inline fun C.sendImage(image: ExternalImage): MessageReceipt = image.sendTo(this) + +@JvmSynthetic internal operator fun ByteArray.get(rangeStart: Int, rangeEnd: Int): String = buildString { for (it in rangeStart..rangeEnd) { append(this@get[it].fixToString()) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt index 31bfecdeb..c01a42aa9 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt @@ -16,7 +16,6 @@ import kotlinx.coroutines.withContext import kotlinx.io.core.Input import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.message.data.Image -import net.mamoe.mirai.message.data.OfflineImage import net.mamoe.mirai.utils.OverFileSizeMaxException import net.mamoe.mirai.utils.sendTo import net.mamoe.mirai.utils.toExternalImage @@ -82,8 +81,9 @@ suspend fun File.sendAsImageTo(contact: C): MessageReceipt { * 在 [Dispatchers.IO] 中将图片上传后构造 [Image]. 不会创建临时文件 * @throws OverFileSizeMaxException */ +@JvmSynthetic @Throws(OverFileSizeMaxException::class) -suspend fun BufferedImage.upload(contact: Contact): OfflineImage = +suspend fun BufferedImage.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact) /** @@ -91,7 +91,7 @@ suspend fun BufferedImage.upload(contact: Contact): OfflineImage = * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend fun URL.uploadAsImage(contact: Contact): OfflineImage = +suspend fun URL.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact) /** @@ -99,7 +99,7 @@ suspend fun URL.uploadAsImage(contact: Contact): OfflineImage = * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend fun Input.uploadAsImage(contact: Contact): OfflineImage = +suspend fun Input.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact) /** @@ -107,7 +107,7 @@ suspend fun Input.uploadAsImage(contact: Contact): OfflineImage = * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend fun InputStream.uploadAsImage(contact: Contact): OfflineImage = +suspend fun InputStream.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact) /** @@ -115,7 +115,7 @@ suspend fun InputStream.uploadAsImage(contact: Contact): OfflineImage = * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend fun File.uploadAsImage(contact: Contact): OfflineImage { +suspend fun File.uploadAsImage(contact: Contact): Image { require(this.isFile && this.exists() && this.canRead()) { "file ${this.path} is not readable" } return withContext(Dispatchers.IO) { toExternalImage() }.upload(contact) } @@ -170,34 +170,34 @@ suspend inline fun C.sendImage(file: File): MessageReceipt = fi * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend inline fun Contact.uploadImage(bufferedImage: BufferedImage): OfflineImage = bufferedImage.upload(this) +suspend inline fun Contact.uploadImage(bufferedImage: BufferedImage): Image = bufferedImage.upload(this) /** * 在 [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片上传, 但不发送 * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend inline fun Contact.uploadImage(imageUrl: URL): OfflineImage = imageUrl.uploadAsImage(this) +suspend inline fun Contact.uploadImage(imageUrl: URL): Image = imageUrl.uploadAsImage(this) /** * 在 [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片上传, 但不发送 * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend inline fun Contact.uploadImage(imageInput: Input): OfflineImage = imageInput.uploadAsImage(this) +suspend inline fun Contact.uploadImage(imageInput: Input): Image = imageInput.uploadAsImage(this) /** * 在 [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片上传, 但不发送 * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend inline fun Contact.uploadImage(imageStream: InputStream): OfflineImage = imageStream.uploadAsImage(this) +suspend inline fun Contact.uploadImage(imageStream: InputStream): Image = imageStream.uploadAsImage(this) /** * 在 [Dispatchers.IO] 中将文件作为图片上传, 但不发送 * @throws OverFileSizeMaxException */ @Throws(OverFileSizeMaxException::class) -suspend inline fun Contact.uploadImage(file: File): OfflineImage = file.uploadAsImage(this) +suspend inline fun Contact.uploadImage(file: File): Image = file.uploadAsImage(this) // endregion \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/data/Image.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/data/Image.kt index 78f5f49f4..def08db8c 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/data/Image.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/data/Image.kt @@ -9,6 +9,7 @@ @file:JvmMultifileClass @file:JvmName("MessageUtils") +@file:Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION") package net.mamoe.mirai.message.data @@ -74,7 +75,7 @@ actual interface Image : Message, MessageContent { @Deprecated(""" 不要自行实现 OnlineGroupImage, 它必须由协议模块实现, 否则会无法发送也无法解析. """, level = DeprecationLevel.HIDDEN) - @Suppress("PropertyName", "DeprecatedCallableAddReplaceWith") + @Suppress( "PropertyName", "unused") @get:JvmSynthetic - actual val DoNotImplementThisClass: Nothing? + internal actual val DoNotImplementThisClass: Nothing? } \ No newline at end of file