mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-10 12:10:10 +08:00
Graceful ImageUploading
This commit is contained in:
parent
de86041d44
commit
ff160c20c8
@ -4,15 +4,15 @@ package net.mamoe.mirai.message
|
|||||||
|
|
||||||
import net.mamoe.mirai.contact.Contact
|
import net.mamoe.mirai.contact.Contact
|
||||||
import net.mamoe.mirai.contact.QQ
|
import net.mamoe.mirai.contact.QQ
|
||||||
import net.mamoe.mirai.contact.sendMessage
|
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket
|
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket
|
||||||
import net.mamoe.mirai.utils.ExternalImage
|
import net.mamoe.mirai.utils.ExternalImage
|
||||||
|
|
||||||
|
// region Message Base
|
||||||
/**
|
/**
|
||||||
* 可发送的或从服务器接收的消息.
|
* 可发送的或从服务器接收的消息.
|
||||||
* 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等.
|
* 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等.
|
||||||
*
|
*
|
||||||
* #### 在 Kotlin 使用 [Message]
|
* **在 Kotlin 使用 [Message]**
|
||||||
* 这与使用 [String] 的使用非常类似.
|
* 这与使用 [String] 的使用非常类似.
|
||||||
*
|
*
|
||||||
* 比较 [Message] 与 [String] (使用 infix [Message.eq]):
|
* 比较 [Message] 与 [String] (使用 infix [Message.eq]):
|
||||||
@ -44,6 +44,15 @@ interface Message {
|
|||||||
*/
|
*/
|
||||||
val stringValue: String
|
val stringValue: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型 Key.
|
||||||
|
* 除 [MessageChain] 外, 每个 [Message] 类型都拥有一个`伴生对象`(companion object) 来持有一个 Key
|
||||||
|
* 在 [MessageChain.get] 时将会使用到这个 Key 进行判断类型.
|
||||||
|
*
|
||||||
|
* @param M 指代持有它的消息类型
|
||||||
|
*/
|
||||||
|
interface Key<M>
|
||||||
|
|
||||||
infix fun eq(other: Message): Boolean = this == other
|
infix fun eq(other: Message): Boolean = this == other
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,20 +85,26 @@ interface Message {
|
|||||||
|
|
||||||
infix operator fun plus(another: Message): MessageChain = this.concat(another)
|
infix operator fun plus(another: Message): MessageChain = this.concat(another)
|
||||||
infix operator fun plus(another: String): MessageChain = this.concat(another.toMessage())
|
infix operator fun plus(another: String): MessageChain = this.concat(another.toMessage())
|
||||||
infix operator fun plus(another: Number): MessageChain = this.concat(another.toString().toMessage())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 [this] 发送给指定联系人
|
* 将 [this] 发送给指定联系人
|
||||||
*/
|
*/
|
||||||
suspend fun Message.sendTo(contact: Contact) = contact.sendMessage(this)
|
suspend fun Message.sendTo(contact: Contact) = contact.sendMessage(this)
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region PlainText
|
||||||
// ==================================== PlainText ====================================
|
// ==================================== PlainText ====================================
|
||||||
|
|
||||||
inline class PlainText(override val stringValue: String) : Message {
|
inline class PlainText(override val stringValue: String) : Message {
|
||||||
override operator fun contains(sub: String): Boolean = sub in stringValue
|
override operator fun contains(sub: String): Boolean = sub in stringValue
|
||||||
}
|
override fun toString(): String = stringValue
|
||||||
|
|
||||||
|
companion object Key : Message.Key<PlainText>
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Image
|
||||||
// ==================================== Image ====================================
|
// ==================================== Image ====================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,6 +115,9 @@ inline class PlainText(override val stringValue: String) : Message {
|
|||||||
*/
|
*/
|
||||||
inline class Image(val id: ImageId) : Message {
|
inline class Image(val id: ImageId) : Message {
|
||||||
override val stringValue: String get() = "[${id.value}]"
|
override val stringValue: String get() = "[${id.value}]"
|
||||||
|
override fun toString(): String = stringValue
|
||||||
|
|
||||||
|
companion object Key : Message.Key<Image>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,6 +134,10 @@ fun ImageId.image(): Image = Image(this)
|
|||||||
|
|
||||||
suspend fun ImageId.sendTo(contact: Contact) = contact.sendMessage(this.image())
|
suspend fun ImageId.sendTo(contact: Contact) = contact.sendMessage(this.image())
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
|
||||||
|
// region At
|
||||||
// ==================================== At ====================================
|
// ==================================== At ====================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -125,8 +147,14 @@ inline class At(val targetQQ: UInt) : Message {
|
|||||||
constructor(target: QQ) : this(target.id)
|
constructor(target: QQ) : this(target.id)
|
||||||
|
|
||||||
override val stringValue: String get() = "[@$targetQQ]"
|
override val stringValue: String get() = "[@$targetQQ]"
|
||||||
}
|
override fun toString(): String = stringValue
|
||||||
|
|
||||||
|
companion object Key : Message.Key<At>
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
|
||||||
|
// region Face
|
||||||
// ==================================== Face ====================================
|
// ==================================== Face ====================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,10 +162,17 @@ inline class At(val targetQQ: UInt) : Message {
|
|||||||
*/
|
*/
|
||||||
inline class Face(val id: FaceID) : Message {
|
inline class Face(val id: FaceID) : Message {
|
||||||
override val stringValue: String get() = "[face${id.value}]"
|
override val stringValue: String get() = "[face${id.value}]"
|
||||||
}
|
override fun toString(): String = stringValue
|
||||||
|
|
||||||
|
companion object Key : Message.Key<Face>
|
||||||
|
}
|
||||||
|
// endregion Face
|
||||||
|
|
||||||
|
|
||||||
|
// region MessageChain
|
||||||
// ==================================== MessageChain ====================================
|
// ==================================== MessageChain ====================================
|
||||||
|
|
||||||
|
// region constructors
|
||||||
/**
|
/**
|
||||||
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 8
|
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 8
|
||||||
*/
|
*/
|
||||||
@ -178,6 +213,27 @@ fun SingleMessageChain(delegate: Message): MessageChain {
|
|||||||
require(delegate !is MessageChain) { "delegate for SingleMessageChain should not be any instance of MessageChain" }
|
require(delegate !is MessageChain) { "delegate for SingleMessageChain should not be any instance of MessageChain" }
|
||||||
return SingleMessageChainImpl(delegate)
|
return SingleMessageChainImpl(delegate)
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取第一个 [M] 类型的 [Message] 实例
|
||||||
|
*/
|
||||||
|
inline fun <reified M : Message> MessageChain.firstOrNull(): Message? = this.firstOrNull { M::class.isInstance(it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取第一个 [M] 类型的 [Message] 实例
|
||||||
|
* @throws [NoSuchElementException] 如果找不到该类型的实例
|
||||||
|
*/
|
||||||
|
inline fun <reified M : Message> MessageChain.first(): Message = this.first { M::class.isInstance(it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取第一个 [M] 类型的 [Message] 实例
|
||||||
|
*/
|
||||||
|
inline fun <reified M : Message> MessageChain.any(): Boolean = this.firstOrNull { M::class.isInstance(it) } !== null
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息链. 即 MutableList<Message>.
|
* 消息链. 即 MutableList<Message>.
|
||||||
@ -204,6 +260,20 @@ interface MessageChain : Message, MutableList<Message> {
|
|||||||
operator fun plusAssign(plain: String) {
|
operator fun plusAssign(plain: String) {
|
||||||
this.concat(plain.toMessage())
|
this.concat(plain.toMessage())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取第一个类型为 [key] 的 [Message] 实例
|
||||||
|
*
|
||||||
|
* @param key 由各个类型消息的伴生对象持有. 如 [PlainText.Key]
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
operator fun <M> get(key: Message.Key<M>): M = when (key) {
|
||||||
|
At -> first<At>()
|
||||||
|
PlainText -> first<PlainText>()
|
||||||
|
Image -> first<Image>()
|
||||||
|
Face -> first<Face>()
|
||||||
|
else -> error("unknown key: $key")
|
||||||
|
} as M
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -403,15 +473,4 @@ internal inline class SingleMessageChainImpl(
|
|||||||
override operator fun contains(element: Message): Boolean = element === delegate
|
override operator fun contains(element: Message): Boolean = element === delegate
|
||||||
override val size: Int get() = 1
|
override val size: Int get() = 1
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取第一个 [M] 类型的实例
|
|
||||||
*/
|
|
||||||
inline fun <reified M : Message> MessageChain.firstOrNull(): Message? = this.firstOrNull { M::class.isInstance(it) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取第一个 [M] 类型的实例
|
|
||||||
* @throws [NoSuchElementException] 如果找不到该类型的实例
|
|
||||||
*/
|
|
||||||
inline fun <reified M : Message> MessageChain.first(): Message = this.first { M::class.isInstance(it) }
|
|
@ -23,6 +23,9 @@ import net.mamoe.mirai.withSession
|
|||||||
/**
|
/**
|
||||||
* 上传图片
|
* 上传图片
|
||||||
* 挂起直到上传完成或失败
|
* 挂起直到上传完成或失败
|
||||||
|
*
|
||||||
|
* 在 JVM 下, `SendImageUtilsJvm.kt` 内有多个捷径函数
|
||||||
|
*
|
||||||
* @throws OverFileSizeMaxException 如果文件过大, 服务器拒绝接收时
|
* @throws OverFileSizeMaxException 如果文件过大, 服务器拒绝接收时
|
||||||
*/
|
*/
|
||||||
suspend fun QQ.uploadImage(image: ExternalImage): ImageId = bot.withSession {
|
suspend fun QQ.uploadImage(image: ExternalImage): ImageId = bot.withSession {
|
||||||
|
@ -26,6 +26,9 @@ class OverFileSizeMaxException : IllegalStateException()
|
|||||||
/**
|
/**
|
||||||
* 上传群图片
|
* 上传群图片
|
||||||
* 挂起直到上传完成或失败
|
* 挂起直到上传完成或失败
|
||||||
|
*
|
||||||
|
* 在 JVM 下, `SendImageUtilsJvm.kt` 内有多个捷径函数
|
||||||
|
*
|
||||||
* @throws OverFileSizeMaxException 如果文件过大, 服务器拒绝接收时
|
* @throws OverFileSizeMaxException 如果文件过大, 服务器拒绝接收时
|
||||||
*/
|
*/
|
||||||
suspend fun Group.uploadImage(image: ExternalImage): ImageId = withSession {
|
suspend fun Group.uploadImage(image: ExternalImage): ImageId = withSession {
|
||||||
|
@ -7,7 +7,9 @@ import kotlinx.io.core.Input
|
|||||||
import net.mamoe.mirai.contact.Contact
|
import net.mamoe.mirai.contact.Contact
|
||||||
import net.mamoe.mirai.contact.Group
|
import net.mamoe.mirai.contact.Group
|
||||||
import net.mamoe.mirai.contact.QQ
|
import net.mamoe.mirai.contact.QQ
|
||||||
|
import net.mamoe.mirai.message.Image
|
||||||
import net.mamoe.mirai.message.ImageId
|
import net.mamoe.mirai.message.ImageId
|
||||||
|
import net.mamoe.mirai.message.image
|
||||||
import net.mamoe.mirai.message.sendTo
|
import net.mamoe.mirai.message.sendTo
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.action.uploadImage
|
import net.mamoe.mirai.network.protocol.tim.packet.action.uploadImage
|
||||||
|
|
||||||
@ -22,7 +24,8 @@ fun ExternalImage(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 外部图片. 图片数据还没有读取到内存.
|
* 外部图片. 图片数据还没有读取到内存.
|
||||||
* @see ExternalImage.sendTo
|
* @see ExternalImage.sendTo 上传图片并以纯图片消息发送给联系人
|
||||||
|
* @See ExternalImage.upload 上传图片并得到 [Image] 消息
|
||||||
*/
|
*/
|
||||||
class ExternalImage(
|
class ExternalImage(
|
||||||
val width: Int,
|
val width: Int,
|
||||||
@ -58,10 +61,21 @@ suspend fun ExternalImage.sendTo(contact: Contact) = when (contact) {
|
|||||||
is QQ -> contact.uploadImage(this).sendTo(contact)
|
is QQ -> contact.uploadImage(this).sendTo(contact)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传图片并通过图片 ID 构造 [Image]
|
||||||
|
* 这个函数可能需消耗一段时间
|
||||||
|
*
|
||||||
|
* @see contact 图片上传对象. 由于好友图片与群图片不通用, 上传时必须提供目标联系人
|
||||||
|
*/
|
||||||
|
suspend fun ExternalImage.upload(contact: Contact): Image = when (contact) {
|
||||||
|
is Group -> contact.uploadImage(this).image()
|
||||||
|
is QQ -> contact.uploadImage(this).image()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将图片发送给 [this]
|
* 将图片发送给 [this]
|
||||||
*/
|
*/
|
||||||
suspend fun Contact.sendMessage(image: ExternalImage) = image.sendTo(this)
|
suspend fun Contact.sendImage(image: ExternalImage) = image.sendTo(this)
|
||||||
|
|
||||||
private operator fun ByteArray.get(range: IntRange): String = buildString {
|
private operator fun ByteArray.get(range: IntRange): String = buildString {
|
||||||
range.forEach {
|
range.forEach {
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package net.mamoe.mirai.utils.internal
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
internal fun Int.coerceAtLeastOrFail(value: Int): Int {
|
||||||
|
require(this > value)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
internal fun Long.coerceAtLeastOrFail(value: Long): Long {
|
||||||
|
require(this > value)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表示这个参数必须为正数
|
||||||
|
*/
|
||||||
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
|
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||||
|
internal annotation class PositiveNumbers
|
@ -2,13 +2,6 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai
|
package net.mamoe.mirai
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
actual typealias MiraiEnvironment = MiraiEnvironmentJvm
|
actual typealias MiraiEnvironment = MiraiEnvironmentJvm
|
||||||
|
|
||||||
object MiraiEnvironmentJvm {
|
object MiraiEnvironmentJvm
|
||||||
/**
|
|
||||||
* JVM only, 临时文件夹
|
|
||||||
*/
|
|
||||||
val TEMP_DIR: File = createTempDir().apply { deleteOnExit() }
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ import net.mamoe.mirai.contact.Contact
|
|||||||
import net.mamoe.mirai.network.protocol.tim.packet.action.OverFileSizeMaxException
|
import net.mamoe.mirai.network.protocol.tim.packet.action.OverFileSizeMaxException
|
||||||
import net.mamoe.mirai.utils.sendTo
|
import net.mamoe.mirai.utils.sendTo
|
||||||
import net.mamoe.mirai.utils.toExternalImage
|
import net.mamoe.mirai.utils.toExternalImage
|
||||||
|
import net.mamoe.mirai.utils.upload
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -18,14 +19,14 @@ import java.net.URL
|
|||||||
* 发送图片的一些扩展函数.
|
* 发送图片的一些扩展函数.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// region Type extensions
|
// region IMAGE.sendAsImageTo(Contact)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将图片发送到指定联系人. 不会保存临时文件
|
* 将图片发送到指定联系人. 不会创建临时文件
|
||||||
* @throws OverFileSizeMaxException
|
* @throws OverFileSizeMaxException
|
||||||
*/
|
*/
|
||||||
@Throws(OverFileSizeMaxException::class)
|
@Throws(OverFileSizeMaxException::class)
|
||||||
suspend fun BufferedImage.sendAsImageTo(contact: Contact) = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
|
suspend fun BufferedImage.sendTo(contact: Contact) = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载 [URL] 到临时文件并将其作为图片发送到指定联系人
|
* 下载 [URL] 到临时文件并将其作为图片发送到指定联系人
|
||||||
@ -57,15 +58,53 @@ suspend fun File.sendAsImageTo(contact: Contact) = withContext(Dispatchers.IO) {
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// region IMAGE.Upload(Contact): Image
|
||||||
|
|
||||||
// region Contact extensions
|
/**
|
||||||
|
* 将图片上传后构造 [Image]. 不会创建临时文件
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun BufferedImage.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载 [URL] 到临时文件并将其作为图片上传后构造 [Image]
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun URL.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 [Input] 到临时文件并将其作为图片上传后构造 [Image]
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun Input.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 [InputStream] 到临时文件并将其作为图片上传后构造 [Image]
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun InputStream.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文件作为图片上传后构造 [Image]
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun File.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Contact.sendImage(IMAGE)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将图片发送到指定联系人. 不会保存临时文件
|
* 将图片发送到指定联系人. 不会保存临时文件
|
||||||
* @throws OverFileSizeMaxException
|
* @throws OverFileSizeMaxException
|
||||||
*/
|
*/
|
||||||
@Throws(OverFileSizeMaxException::class)
|
@Throws(OverFileSizeMaxException::class)
|
||||||
suspend fun Contact.sendImage(bufferedImage: BufferedImage) = bufferedImage.sendAsImageTo(this)
|
suspend fun Contact.sendImage(bufferedImage: BufferedImage) = bufferedImage.sendTo(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载 [URL] 到临时文件并将其作为图片发送到指定联系人
|
* 下载 [URL] 到临时文件并将其作为图片发送到指定联系人
|
||||||
@ -95,4 +134,43 @@ suspend fun Contact.sendImage(imageStream: InputStream) = imageStream.sendAsImag
|
|||||||
@Throws(OverFileSizeMaxException::class)
|
@Throws(OverFileSizeMaxException::class)
|
||||||
suspend fun Contact.sendImage(file: File) = file.sendAsImageTo(this)
|
suspend fun Contact.sendImage(file: File) = file.sendAsImageTo(this)
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Contact.uploadImage(IMAGE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将图片发送到指定联系人. 不会保存临时文件
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun Contact.uploadImage(bufferedImage: BufferedImage): Image = bufferedImage.upload(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载 [URL] 到临时文件并将其作为图片发送到指定联系人
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun Contact.uploadImage(imageUrl: URL): Image = imageUrl.upload(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 [Input] 到临时文件并将其作为图片发送到指定联系人
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun Contact.uploadImage(imageInput: Input): Image = imageInput.upload(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 [InputStream] 到临时文件并将其作为图片发送到指定联系人
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun Contact.uploadImage(imageStream: InputStream): Image = imageStream.upload(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文件作为图片发送到指定联系人
|
||||||
|
* @throws OverFileSizeMaxException
|
||||||
|
*/
|
||||||
|
@Throws(OverFileSizeMaxException::class)
|
||||||
|
suspend fun Contact.uploadImage(file: File): Image = file.upload(this)
|
||||||
|
|
||||||
// endregion
|
// endregion
|
Loading…
Reference in New Issue
Block a user