mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-27 17:00:14 +08:00
Review MessageKey
and Message
s:
- 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:
parent
7d5063653a
commit
288f325ca0
@ -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() {
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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())
|
||||
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 码支持
|
||||
* 格式: [mirai:vipface:*[Kind.id]*,*[Kind.name]*,*[count]*]
|
||||
*
|
||||
* @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)
|
@ -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 码支持
|
||||
* 格式: [mirai:image:*[Image.imageId]*]
|
||||
@ -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}""")
|
||||
}
|
@ -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<*>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.")
|
||||
}
|
||||
}
|
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user