Review MessageKey and Messages:

- Add `Image.isGroupImage`, `Image.isFriendImage`
- Simplify `FlashImage`:
  - Remove `GroupFlashImage`, `FriendFlashImage`
  - Java-friendly factory functions and Kotlin-friendly top-level constructor-like functions
- Unify names of constants in `PokeMessage.Key`
- Make constants in VipFace `@JvmField`
- Review `Image`:
  - Make `AbstractImage` internal (`@MiraiInternalApi`)
  - Improve docs
  - Move top-level regexes to companion statics
- Make Nudge.sendNudge static
- Opt-in `net.mamoe.mirai.message.data.ExperimentalMessageKey`
This commit is contained in:
Him188 2020-12-10 13:54:40 +08:00
parent 7d5063653a
commit 288f325ca0
14 changed files with 244 additions and 193 deletions

View File

@ -252,7 +252,9 @@ val experimentalAnnotations = arrayOf(
"net.mamoe.mirai.utils.MiraiInternalApi",
"net.mamoe.mirai.utils.MiraiExperimentalApi",
"net.mamoe.mirai.LowLevelApi",
"net.mamoe.mirai.utils.UnstableExternalImage"
"net.mamoe.mirai.utils.UnstableExternalImage",
"net.mamoe.mirai.message.data.ExperimentalMessageKey"
)
fun Project.configureKotlinExperimentalUsages() {

View File

@ -95,9 +95,18 @@ public interface IMirai : LowLevelApiAccessor {
@JvmBlockingBridge
public suspend fun recallMessage(bot: Bot, source: MessageSource)
/**
* 发送戳一戳消息
*/
@JvmBlockingBridge
public suspend fun sendNudge(bot: Bot, nudge: Nudge, receiver: Contact): Boolean
/**
* 构造 [Image]
*
* @see Image
* @see Image.fromId
*/
public fun createImage(imageId: String): Image
/**

View File

@ -111,8 +111,6 @@ private val builtInSerializersModule = SerializersModule {
contextual(PokeMessage::class, PokeMessage.serializer())
contextual(VipFace::class, VipFace.serializer())
contextual(FlashImage::class, FlashImage.serializer())
contextual(GroupFlashImage::class, GroupFlashImage.serializer())
contextual(FriendFlashImage::class, FriendFlashImage.serializer())
contextual(VipFace.Kind::class, VipFace.Kind.serializer())

View File

@ -39,13 +39,12 @@ public sealed class Nudge {
* 需要 [使用协议][BotConfiguration.protocol] [MiraiProtocol.ANDROID_PHONE].
*
* @param receiver 这条 "戳一戳" 消息的接收对象. (不是 "" 动作的对象, 而是接收 "A 戳了 B" 这条消息的对象)
* @return 成功发送时为 `true`. 若对方禁用 "戳一戳" 功能, 返回 `false`.
* @throws UnsupportedOperationException 当未使用 [安卓协议][MiraiProtocol.ANDROID_PHONE] 时抛出
*
* @see MemberNudgedEvent 成员被戳事件
* @see BotNudgedEvent [Bot] 被戳事件
*
* @throws UnsupportedOperationException 当未使用 [安卓协议][MiraiProtocol.ANDROID_PHONE] 时抛出
*
* @return 成功发送时为 `true`. 若对方禁用 "戳一戳" 功能, 返回 `false`.
* @see Contact.sendNudge
*/
@JvmBlockingBridge
@MiraiExperimentalApi
@ -69,6 +68,7 @@ public sealed class Nudge {
*/
@MiraiExperimentalApi
@JvmBlockingBridge
@JvmStatic
public suspend fun Contact.sendNudge(nudge: Nudge): Boolean = nudge.sendTo(this)
}
}

View File

@ -55,31 +55,56 @@ public data class PokeMessage internal constructor(
public val type: Int,
public val id: Int
) : HummerMessage(), CodableMessage {
@ExperimentalMessageKey
override val key: MessageKey<HummerMessage> get() = Key
@Suppress("DEPRECATION_ERROR", "DEPRECATION", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
public companion object Key :
AbstractPolymorphicMessageKey<HummerMessage, PokeMessage>(HummerMessage, { it.castOrNull() }) {
/** 戳一戳 */
@JvmField
public val Poke: PokeMessage = PokeMessage("戳一戳", 1, -1)
public val ChuoYiChuo: PokeMessage = PokeMessage("戳一戳", 1, -1)
/** 戳一戳 */
@JvmField
@Deprecated("Use ChuoYiChuo", replaceWith = ReplaceWith("ChuoYiChuo"))
public val Poke: PokeMessage = ChuoYiChuo
/** 比心 */
@JvmField
public val ShowLove: PokeMessage = PokeMessage("比心", 2, -1)
public val BiXin: PokeMessage = PokeMessage("比心", 2, -1)
/** 比心 */
@JvmField
@Deprecated("Use BiXin", replaceWith = ReplaceWith("BiXin"))
public val ShowLove: PokeMessage = BiXin
/** 点赞 */
@JvmField
public val Like: PokeMessage = PokeMessage("点赞", 3, -1)
public val DianZan: PokeMessage = PokeMessage("点赞", 3, -1)
/** 点赞 */
@JvmField
@Deprecated("Use DianZan", replaceWith = ReplaceWith("DianZan"))
public val Like: PokeMessage = DianZan
/** 心碎 */
@JvmField
public val Heartbroken: PokeMessage = PokeMessage("心碎", 4, -1)
public val XinSui: PokeMessage = PokeMessage("心碎", 4, -1)
/** 心碎 */
@JvmField
@Deprecated("Use XinSui", replaceWith = ReplaceWith("XinSui"))
public val Heartbroken: PokeMessage = XinSui
/** 666 */
@JvmField
public val SixSixSix: PokeMessage = PokeMessage("666", 5, -1)
public val LiuLiuLiu: PokeMessage = PokeMessage("666", 5, -1)
/** 666 */
@JvmField
@Deprecated("Use LiuLiuLiu", replaceWith = ReplaceWith("LiuLiuLiu"))
public val SixSixSix: PokeMessage = LiuLiuLiu
/** 放大招 */
@JvmField
@ -129,9 +154,9 @@ public data class PokeMessage internal constructor(
/**
* 所有类型数组
*/
@JvmStatic
@JvmField
public val values: Array<PokeMessage> = arrayOf(
Poke, ShowLove, Like, Heartbroken, SixSixSix,
ChuoYiChuo, BiXin, DianZan, XinSui, LiuLiuLiu,
FangDaZhao, BaoBeiQiu, Rose, ZhaoHuanShu, RangNiPi,
JieYin, ShouLei, GouYin, ZhuaYiXia, SuiPing
)
@ -160,7 +185,7 @@ public data class PokeMessage internal constructor(
* ## mirai 码支持
* 格式: &#91;mirai:vipface:*[Kind.id]*,*[Kind.name]*,*[count]*&#93;
*
* @see Types 使用伴生对象中的常量
* @see VipFace.Key 使用伴生对象中的常量
*/
@Serializable
public data class VipFace internal constructor(
@ -180,49 +205,50 @@ public data class VipFace internal constructor(
}
}
@ExperimentalMessageKey
override val key: MessageKey<VipFace> get() = Key
@Suppress("DEPRECATION_ERROR", "DEPRECATION", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
public companion object Key :
AbstractPolymorphicMessageKey<HummerMessage, VipFace>(HummerMessage, { it.safeCast() }) {
@JvmStatic
@JvmField
public val LiuLian: Kind = 9 to "榴莲"
@JvmStatic
@JvmField
public val PingDiGuo: Kind = 1 to "平底锅"
@JvmStatic
@JvmField
public val ChaoPiao: Kind = 12 to "钞票"
@JvmStatic
@JvmField
public val LueLueLue: Kind = 10 to "略略略"
@JvmStatic
@JvmField
public val ZhuTou: Kind = 4 to "猪头"
@JvmStatic
@JvmField
public val BianBian: Kind = 6 to "便便"
@JvmStatic
@JvmField
public val ZhaDan: Kind = 5 to "炸弹"
@JvmStatic
@JvmField
public val AiXin: Kind = 2 to "爱心"
@JvmStatic
@JvmField
public val HaHa: Kind = 3 to "哈哈"
@JvmStatic
@JvmField
public val DianZan: Kind = 1 to "点赞"
@JvmStatic
@JvmField
public val QinQin: Kind = 7 to "亲亲"
@JvmStatic
@JvmField
public val YaoWan: Kind = 8 to "药丸"
@JvmStatic
@JvmField
public val values: Array<Kind> = arrayOf(
LiuLian, PingDiGuo, ChaoPiao, LueLueLue, ZhuTou,
BianBian, ZhaDan, AiXin, HaHa, DianZan, QinQin, YaoWan
@ -255,24 +281,19 @@ public data class VipFace internal constructor(
* @see Image 查看图片相关信息
*/
@Serializable
public sealed class FlashImage : MessageContent, HummerMessage(), CodableMessage, ConstrainSingle {
override val key: MessageKey<FlashImage> get() = Key
public data class FlashImage(
/**
* 闪照的内容图片, 即一个普通图片.
*/
@Contextual
public val image: Image
) : MessageContent, HummerMessage(), CodableMessage, ConstrainSingle {
@ExperimentalMessageKey
override val key: MessageKey<FlashImage>
get() = Key
public companion object Key :
AbstractPolymorphicMessageKey<HummerMessage, FlashImage>(HummerMessage, { it.safeCast() }) {
/**
* 将普通图片转换为闪照.
*/
@JvmStatic
@JvmName("from")
public operator fun invoke(image: Image): FlashImage {
return when (image) {
is GroupImage -> GroupFlashImage(image)
is FriendImage -> FriendFlashImage(image)
else -> throw IllegalArgumentException("不支持的图片类型(Please use GroupImage or FriendImage)")
}
}
/**
* 将普通图片转换为闪照.
@ -280,51 +301,35 @@ public sealed class FlashImage : MessageContent, HummerMessage(), CodableMessage
* @param imageId 图片 id, 详见 [Image.imageId]
*/
@JvmStatic
@JvmName("from")
public operator fun invoke(imageId: String): FlashImage {
return invoke(Image(imageId))
}
public fun from(imageId: String): FlashImage = FlashImage(Image(imageId))
}
/**
* 闪照的内容图片, 即一个普通图片.
*/
public abstract val image: Image
private val stringValue: String by lazy(LazyThreadSafetyMode.NONE) { "[mirai:flash:${image.imageId}]" }
private var stringValue: String? = null
get() {
return field ?: kotlin.run {
field = "[mirai:flash:${image.imageId}]"
field
}
}
public final override fun toString(): String = stringValue!!
public override fun toString(): String = stringValue
public override fun contentToString(): String = "[闪照]"
}
/**
* 将普通图片转换为闪照.
*/
@JvmSynthetic
public inline fun FlashImage(imageId: String): FlashImage = FlashImage.from(imageId)
/**
* 将普通图片转换为闪照.
*/
@JvmSynthetic
public inline fun Image.flash(): FlashImage = FlashImage(this)
/**
* 将普通图片转换为闪照.
*/
@JvmSynthetic
public inline fun GroupImage.flash(): GroupFlashImage = FlashImage(this) as GroupFlashImage
@JvmSynthetic
public inline fun FriendImage.flash(): FriendFlashImage = FlashImage(this) as FriendFlashImage
public inline fun GroupImage.flash(): FlashImage = FlashImage(this)
/**
* @see FlashImage.invoke
* 将普通图片转换为闪照.
*/
@Serializable
public data class GroupFlashImage(@Contextual override val image: GroupImage) : FlashImage() {
public companion object Key :
AbstractPolymorphicMessageKey<FlashImage, GroupFlashImage>(FlashImage, { it.safeCast() })
}
/**
* @see FlashImage.invoke
*/
@Serializable
public data class FriendFlashImage(@Contextual override val image: FriendImage) : FlashImage() {
public companion object Key :
AbstractPolymorphicMessageKey<FlashImage, FriendFlashImage>(FlashImage, { it.safeCast() })
}
@JvmSynthetic
public inline fun FriendImage.flash(): FlashImage = FlashImage(this)

View File

@ -22,7 +22,8 @@
package net.mamoe.mirai.message.data
import kotlinx.io.core.Input
import event.sendAsImageTo
import event.uploadAsImage
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.serializer
@ -31,17 +32,18 @@ import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.Bot
import net.mamoe.mirai.IMirai
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.Contact
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.FRIEND_IMAGE_ID_REGEX_2
import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
import net.mamoe.mirai.message.data.Image.Key.queryUrl
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.MiraiInternalApi
import net.mamoe.mirai.utils.safeCast
import net.mamoe.mirai.utils.sendImage
import net.mamoe.mirai.utils.*
import java.io.File
import java.io.InputStream
import java.net.URL
import kotlin.LazyThreadSafetyMode.NONE
/**
* 自定义表情 (收藏的表情) 和普通图片.
@ -50,27 +52,23 @@ import java.net.URL
* 最推荐的存储方式是存储图片原文件, 每次发送图片时都使用文件上传.
* 在上传时服务器会根据其缓存情况回复已有的图片 ID 或要求客户端上传. 详见 [Contact.uploadImage]
*
* ### 根据 ID 构造图片
* - [Image.fromId]. Kotlin, 更推荐使用顶层函数 `val image = Image("id")`
*
* ### 上传和发送图片
* @see Contact.uploadImage 上传 [图片文件][ExternalImage] 并得到 [Image] 消息
* @see Contact.sendImage 上传 [图片文件][ExternalImage] 并发送返回的 [Image] 作为一条消息
* @see Image.sendTo 上传 [图片文件][ExternalImage] 并得到 [Image] 消息
* - [Contact.uploadImage] 上传 [图片文件][ExternalImage] 并得到 [Image] 消息
* - [Contact.sendImage] 上传 [图片文件][ExternalImage] 并发送返回的 [Image] 作为一条消息
* - [Image.sendTo] 上传 [图片文件][ExternalImage] 并得到 [Image] 消息
*
* @see File.uploadAsImage
* @see InputStream.uploadAsImage
* @see Input.uploadAsImage
* @see URL.uploadAsImage
* - [File.uploadAsImage]
* - [InputStream.uploadAsImage]
*
* @see File.sendAsImageTo
* @see InputStream.sendAsImageTo
* @see Input.sendAsImageTo
* @see URL.sendAsImageTo
* - [File.sendAsImageTo]
* - [InputStream.sendAsImageTo]
*
* ### 下载图片
* @see Image.queryUrl 扩展函数. 查询图片下载链接
* @see Bot.queryImageUrl 查询图片下载链接 (Java 使用)
*
* 查看平台 `actual` 定义以获取上传方式扩展.
* - [Image.queryUrl] 扩展函数. 查询图片下载链接
* - [IMirai.queryImageUrl] 查询图片下载链接 (Java 使用)
*
* ## mirai 码支持
* 格式: &#91;mirai:image:*[Image.imageId]*&#93;
@ -88,7 +86,7 @@ public interface Image : Message, MessageContent, CodableMessage {
*
* ### 格式
* 群图片:
* - [GROUP_IMAGE_ID_REGEX], 示例: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai` (后缀一定为 ".mirai")
* - [GROUP_IMAGE_ID_REGEX], 示例: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.ext` (ext 为文件后缀, png)
*
* 好友图片:
* - [FRIEND_IMAGE_ID_REGEX_1], 示例: `/f8f1ab55-bf8e-4236-b55e-955848d7069f`
@ -139,9 +137,55 @@ public interface Image : Message, MessageContent, CodableMessage {
val bot = Bot._instances.peekFirst()?.get() ?: error("No Bot available to query image url")
return Mirai.queryImageUrl(bot, this)
}
/**
* 好友图片 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`
*/
@Suppress("RegExpRedundantEscape") // This is required on Android
// Java: MessageUtils.GROUP_IMAGE_ID_REGEX
@JvmStatic
@MiraiExperimentalApi
@get:JvmName("getGroupImageIdRegex")
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}""")
}
}
@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] 以便发送.
* 这个图片必须是服务器已经存在的图片.
@ -151,35 +195,35 @@ public interface Image : Message, MessageContent, CodableMessage {
*
* @see Image 获取更多说明
* @see Image.imageId 获取更多说明
*
* @see IMirai.createImage
*/
@JvmSynthetic
public inline fun Image(imageId: String): Image = Image.fromId(imageId)
/**
* 所有 [Image] 实现的基类.
*/
@MiraiInternalApi
public sealed class AbstractImage : Image { // make sealed in 1.3.0 ?
private var _stringValue: String? = null
get() = field ?: kotlin.run {
field = "[mirai:image:$imageId]"
field
}
final override fun toString(): String = _stringValue!!
final override fun contentToString(): String = "[图片]"
}
/**
* 计算图片的 md5 校验值.
*
* Java 使用: `MessageUtils.calculateImageMd5(image)`
*/
@MiraiInternalApi
@get:JvmName("calculateImageMd5")
public val Image.md5: ByteArray
get() = calculateImageMd5ByImageId(imageId)
/**
* 所有 [Image] 实现的基类.
*/
@MiraiInternalApi
public sealed class AbstractImage : Image {
private val _stringValue: String? by lazy(NONE) { "[mirai:image:$imageId]" }
final override fun toString(): String = _stringValue!!
final override fun contentToString(): String = "[图片]"
}
/**
* 好友图片
*
@ -203,32 +247,4 @@ public abstract class FriendImage @MiraiInternalApi public constructor() :
public abstract class GroupImage @MiraiInternalApi public constructor() :
AbstractImage() { // change to sealed in the future.
public companion object
}
/**
* 好友图片 ID 正则表达式
*
* `/f8f1ab55-bf8e-4236-b55e-955848d7069f`
* @see FRIEND_IMAGE_ID_REGEX_2
*/
// Java: MessageUtils.FRIEND_IMAGE_ID_REGEX_1
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
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`
*/
@Suppress("RegExpRedundantEscape")
// This is required on Android
// Java: MessageUtils.GROUP_IMAGE_ID_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}""")
}

View File

@ -28,6 +28,7 @@ import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.MessageSerializer
import net.mamoe.mirai.message.MessageSerializerImpl
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.safeCast
import kotlin.contracts.contract
@ -187,6 +188,12 @@ public interface Message { // must be interface. Don't consider any changes.
KSerializer<Message> by PolymorphicSerializer(Message::class)
}
/**
* 标注一个实验性的 [MessageKey] API.
*
* `1.0-M2` 时将会推进 [MessageKey] 到稳定状态并删除此注解.
*/
@PlannedRemoval("1.0-M2")
@MiraiExperimentalApi
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
public annotation class ExperimentalMessageKey
@ -297,8 +304,8 @@ public interface MessageMetadata : SingleMessage {
@ExperimentalMessageKey
public interface ConstrainSingle : SingleMessage {
/**
* 用于判断是否为同一种元素的 [Key]
* @see Key 查看更多信息
* 用于判断是否为同一种元素的 [MessageKey]
* @see MessageKey 查看更多信息
*/
@ExperimentalMessageKey
public val key: MessageKey<*>

View File

@ -67,6 +67,7 @@ import net.mamoe.mirai.utils.safeCast
*/
@Serializable(MessageSourceSerializer::class)
public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
@ExperimentalMessageKey
public final override val key: MessageKey<MessageSource> get() = Key
/**
@ -222,6 +223,7 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
* 引用这条消息. 仅从服务器接收的消息 (即来自 [MessageEvent]) 才可以通过这个方式被引用.
* @see QuoteReply
*/
@JvmStatic
public fun MessageChain.quote(): QuoteReply = QuoteReply(this.source)
}
}
@ -347,7 +349,8 @@ public sealed class OnlineMessageSource : MessageSource() {
}
public abstract class FromTemp : Incoming() {
public companion object Key : AbstractPolymorphicMessageKey<Incoming, FromTemp>(Incoming, { it.safeCast() })
public companion object Key :
AbstractPolymorphicMessageKey<Incoming, FromTemp>(Incoming, { it.safeCast() })
public abstract override val sender: Member
public inline val group: Group get() = sender.group

View File

@ -43,6 +43,7 @@ import net.mamoe.mirai.utils.safeCast
public data class QuoteReply(public val source: MessageSource) : Message, MessageMetadata, ConstrainSingle {
public companion object Key : AbstractMessageKey<QuoteReply>({ it.safeCast() })
@ExperimentalMessageKey
public override val key: MessageKey<QuoteReply> get() = Key
// TODO: 2020/12/2 QuoteReply.toString

View File

@ -13,6 +13,9 @@
package 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.FRIEND_IMAGE_ID_REGEX_2
import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
import net.mamoe.mirai.utils.MiraiExperimentalApi
import kotlin.native.concurrent.SharedImmutable

View File

@ -41,6 +41,9 @@ import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.action.Nudge
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.FRIEND_IMAGE_ID_REGEX_2
import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.currentTimeSeconds

View File

@ -14,37 +14,44 @@ 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.FriendFlashImage
import net.mamoe.mirai.message.data.GroupFlashImage
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 GroupFlashImage.toJceData() = ImMsgBody.Elem(
commonElem = ImMsgBody.CommonElem(
serviceType = 3,
businessType = 0,
pbElem = HummerCommelem.MsgElemInfoServtype3(
flashTroopPic = ImMsgBody.CustomFace(
filePath = image.imageId,
md5 = image.md5,
pbReserve = byteArrayOf(0x78, 0x06)
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())
)
).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer())
)
)
)
internal fun FriendFlashImage.toJceData() = 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)
image.isGroupImage -> ImMsgBody.Elem(
commonElem = ImMsgBody.CommonElem(
serviceType = 3,
businessType = 0,
pbElem = HummerCommelem.MsgElemInfoServtype3(
flashTroopPic = ImMsgBody.CustomFace(
filePath = image.imageId,
md5 = image.md5,
pbReserve = byteArrayOf(0x78, 0x06)
)
).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer())
)
).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer())
)
)
)
else -> error("Internal error: an image is neither group image nor friend image.")
}
}

View File

@ -134,18 +134,11 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B
)
transformOneMessage(UNSUPPORTED_POKE_MESSAGE_PLAIN)
}
is @Suppress("DEPRECATION")
OfflineGroupImage
-> elements.add(ImMsgBody.Elem(customFace = it.toJceData()))
is 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 @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())
.also { transformOneMessage(UNSUPPORTED_FLASH_MESSAGE_PLAIN) }
is OfflineFriendImage -> elements.add(ImMsgBody.Elem(notOnlineImage = it.toJceData()))
is FlashImage -> elements.add(it.toJceData()).also { transformOneMessage(UNSUPPORTED_FLASH_MESSAGE_PLAIN) }
is AtAll -> elements.add(atAllData)
is Face -> elements.add(ImMsgBody.Elem(face = it.toJceData()))
is QuoteReply -> {
@ -160,9 +153,7 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B
}
}
}
is VipFace -> {
transformOneMessage(PlainText(it.contentToString()))
}
is VipFace -> transformOneMessage(PlainText(it.contentToString()))
is PttMessage -> {
elements.add(
ImMsgBody.Elem(
@ -480,10 +471,10 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(groupIdOrZero: Long, botId:
3 -> {
val proto = element.commonElem.pbElem.loadAs(HummerCommelem.MsgElemInfoServtype3.serializer())
if (proto.flashTroopPic != null) {
list.add(GroupFlashImage(OnlineGroupImageImpl(proto.flashTroopPic)))
list.add(FlashImage(OnlineGroupImageImpl(proto.flashTroopPic)))
}
if (proto.flashC2cPic != null) {
list.add(FriendFlashImage(OnlineFriendImageImpl(proto.flashC2cPic)))
list.add(FlashImage(OnlineFriendImageImpl(proto.flashC2cPic)))
}
}
}

View File

@ -18,7 +18,13 @@ import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.hexToBytes
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.FriendImage
import net.mamoe.mirai.message.data.GroupImage
import net.mamoe.mirai.message.data.Image
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.ExternalImage
import net.mamoe.mirai.utils.MiraiExperimentalApi