Fix image

This commit is contained in:
Him188 2020-02-04 17:11:57 +08:00
parent c83bf64a8a
commit f244a12b8b
11 changed files with 79 additions and 44 deletions

View File

@ -4,6 +4,7 @@ import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.FriendNameRemark import net.mamoe.mirai.data.FriendNameRemark
import net.mamoe.mirai.data.PreviousNameList import net.mamoe.mirai.data.PreviousNameList
import net.mamoe.mirai.data.Profile import net.mamoe.mirai.data.Profile
import net.mamoe.mirai.message.data.CustomFaceFromFile
import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.NotOnlineImageFromFile import net.mamoe.mirai.message.data.NotOnlineImageFromFile
@ -206,14 +207,24 @@ internal class GroupImpl(
} }
socket.close() socket.close()
val resourceId = image.calculateImageResourceId() val resourceId = image.calculateImageResourceId()
return NotOnlineImageFromFile(
resourceId = resourceId, return CustomFaceFromFile(
md5 = image.md5, md5 = image.md5,
filepath = resourceId, filepath = resourceId,
fileLength = image.inputSize.toInt(), fileId = response.fileId.toInt(),
fileType = 66, // ?
height = image.height, height = image.height,
width = image.width, width = image.width,
imageType = image.imageType imageType = image.imageType,
bizType = 0,
serverIp = response.uploadIpList.first(),
serverPort = response.uploadPortList.first(),
signature = image.md5,
size = image.inputSize.toInt(),
useful = 1,
source = 200,
origin = 1,
pbReserve = byteArrayOf(0x78, 0x02)
) )
} }
} }

View File

@ -140,8 +140,8 @@ internal class stTroopMemberInfo(
@SerialId(3) val gender: Byte, @SerialId(3) val gender: Byte,
@SerialId(4) val nick: String = "", @SerialId(4) val nick: String = "",
@SerialId(5) val status: Byte = 20, @SerialId(5) val status: Byte = 20,
@SerialId(6) val sShowName: String? = "", @SerialId(6) val sShowName: String? = null,
@SerialId(8) val sName: String? = "", @SerialId(8) val sName: String? = null,
@SerialId(9) val cGender: Byte? = null, @SerialId(9) val cGender: Byte? = null,
@SerialId(10) val sPhone: String? = "", @SerialId(10) val sPhone: String? = "",
@SerialId(11) val sEmail: String? = "", @SerialId(11) val sEmail: String? = "",

View File

@ -40,6 +40,7 @@ internal class OnlinePush {
val group = bot.getGroup(pbPushMsg.msg.msgHead.groupInfo!!.groupCode) val group = bot.getGroup(pbPushMsg.msg.msgHead.groupInfo!!.groupCode)
// println(pbPushMsg.msg.msgBody.richText.contentToString())
val flags = extraInfo?.flags ?: 0 val flags = extraInfo?.flags ?: 0
return GroupMessageOrNull( return GroupMessageOrNull(
GroupMessage( GroupMessage(

View File

@ -1,9 +1,23 @@
package net.mamoe.mirai.qqandroid.utils package net.mamoe.mirai.qqandroid.utils
import net.mamoe.mirai.data.ImageLink import kotlinx.io.core.readUInt
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.discardExact
import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.toByteArray
private val AT_BUF_1 = byteArrayOf(0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00)
private val AT_BUF_2 = ByteArray(2)
internal fun At.toJceData(): ImMsgBody.Text {
return ImMsgBody.Text(
str = this.toString(),
attr6Buf = AT_BUF_1 + this.target.toInt().toByteArray() + AT_BUF_2
)
}
internal fun NotOnlineImageFromFile.toJceData(): ImMsgBody.NotOnlineImage { internal fun NotOnlineImageFromFile.toJceData(): ImMsgBody.NotOnlineImage {
return ImMsgBody.NotOnlineImage( return ImMsgBody.NotOnlineImage(
@ -36,6 +50,7 @@ internal fun CustomFaceFromFile.toJceData(): ImMsgBody.CustomFace {
height = this.height, height = this.height,
source = this.source, source = this.source,
size = this.size, size = this.size,
origin = this.origin,
pbReserve = this.pbReserve pbReserve = this.pbReserve
) )
} }
@ -116,9 +131,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
this.forEach { this.forEach {
when (it) { when (it) {
is PlainText -> elements.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = it.stringValue))) is PlainText -> elements.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = it.stringValue)))
is At -> { is At -> elements.add(ImMsgBody.Elem(text = it.toJceData()))
}
is CustomFaceFromFile -> elements.add(ImMsgBody.Elem(customFace = it.toJceData())) is CustomFaceFromFile -> elements.add(ImMsgBody.Elem(customFace = it.toJceData()))
is CustomFaceFromServer -> elements.add(ImMsgBody.Elem(customFace = it.delegate)) is CustomFaceFromServer -> elements.add(ImMsgBody.Elem(customFace = it.delegate))
is NotOnlineImageFromServer -> elements.add(ImMsgBody.Elem(notOnlineImage = it.delegate)) is NotOnlineImageFromServer -> elements.add(ImMsgBody.Elem(notOnlineImage = it.delegate))
@ -152,33 +165,25 @@ internal class CustomFaceFromServer(
override val height: Int get() = delegate.height override val height: Int get() = delegate.height
override val source: Int get() = delegate.source override val source: Int get() = delegate.source
override val size: Int get() = delegate.size override val size: Int get() = delegate.size
override val origin: Int get() = delegate.origin
override val pbReserve: ByteArray get() = delegate.pbReserve override val pbReserve: ByteArray get() = delegate.pbReserve
} }
internal class NotOnlineImageFromServer( internal class NotOnlineImageFromServer(
internal val delegate: ImMsgBody.NotOnlineImage internal val delegate: ImMsgBody.NotOnlineImage
) : NotOnlineImage() { ) : NotOnlineImage() {
override val resourceId: String override val resourceId: String get() = delegate.resId
get() = delegate.resId override val md5: ByteArray get() = delegate.picMd5
override val md5: ByteArray override val filepath: String get() = delegate.filePath
get() = delegate.picMd5 override val fileLength: Int get() = delegate.fileLen
override val filepath: String override val height: Int get() = delegate.picHeight
get() = delegate.filePath override val width: Int get() = delegate.picWidth
override val fileLength: Int override val bizType: Int get() = delegate.bizType
get() = delegate.fileLen override val imageType: Int get() = delegate.imgType
override val height: Int override val downloadPath: String get() = delegate.downloadPath
get() = delegate.picHeight
override val width: Int
get() = delegate.picWidth
override val bizType: Int
get() = delegate.bizType
override val imageType: Int
get() = delegate.imgType
override val downloadPath: String
get() = delegate.downloadPath
} }
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
internal fun ImMsgBody.RichText.toMessageChain(): MessageChain { internal fun ImMsgBody.RichText.toMessageChain(): MessageChain {
val message = MessageChain(initialCapacity = elems.size) val message = MessageChain(initialCapacity = elems.size)
@ -186,12 +191,17 @@ internal fun ImMsgBody.RichText.toMessageChain(): MessageChain {
when { when {
it.notOnlineImage != null -> message.add(NotOnlineImageFromServer(it.notOnlineImage)) it.notOnlineImage != null -> message.add(NotOnlineImageFromServer(it.notOnlineImage))
it.customFace != null -> message.add(CustomFaceFromServer(it.customFace)) it.customFace != null -> message.add(CustomFaceFromServer(it.customFace))
it.text != null -> message.add(it.text.str.toMessage()) it.text != null -> {
if (it.text.attr6Buf.isEmpty()) {
message.add(it.text.str.toMessage())
} else {
//00 01 00 00 00 0A 00 3E 03 3F A2 00 00
val id = it.text.attr6Buf.read { discardExact(7); readUInt().toLong() }
message.add(At(id, it.text.str))
}
}
} }
} }
return message return message
} }
internal inline class ImageLinkQQA(override val original: String) : ImageLink

View File

@ -6,6 +6,7 @@ import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
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.Member
import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.data.EventPacket import net.mamoe.mirai.data.EventPacket
import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.events.BotEvent
@ -19,6 +20,7 @@ import kotlin.jvm.JvmName
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
expect abstract class MessagePacket<TSender : QQ, TSubject : Contact>(bot: Bot) : MessagePacketBase<TSender, TSubject> expect abstract class MessagePacket<TSender : QQ, TSubject : Contact>(bot: Bot) : MessagePacketBase<TSender, TSubject>
@Suppress("NOTHING_TO_INLINE")
@MiraiInternalAPI @MiraiInternalAPI
abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) : EventPacket, BotEvent() { abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) : EventPacket, BotEvent() {
override val bot: Bot by _bot.unsafeWeakRef() override val bot: Bot by _bot.unsafeWeakRef()
@ -69,6 +71,8 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
suspend inline fun Message.send() = this.sendTo(subject) suspend inline fun Message.send() = this.sendTo(subject)
suspend inline fun String.send() = this.toMessage().sendTo(subject) suspend inline fun String.send() = this.toMessage().sendTo(subject)
inline fun QQ.at(): At = At(this as Member)
// endregion // endregion
// region Image download // region Image download

View File

@ -2,16 +2,18 @@
package net.mamoe.mirai.message.data package net.mamoe.mirai.message.data
import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.utils.MiraiInternalAPI
/** /**
* At 一个人. 只能发送给一个群. * At 一个人. 只能发送给一个群.
*/ */
inline class At(val target: Long) : Message { class At @MiraiInternalAPI constructor(val target: Long, val display: String) : Message {
constructor(target: QQ) : this(target.id) @UseExperimental(MiraiInternalAPI::class)
constructor(member: Member) : this(member.id, member.groupCard)
override fun toString(): String = "[@$target]" // TODO: 2019/11/25 使用群名称进行 at. 因为手机端只会显示这个文字 override fun toString(): String = display
companion object Key : Message.Key<At> companion object Key : Message.Key<At>
@ -24,4 +26,4 @@ inline class At(val target: Long) : Message {
* At 这个成员 * At 这个成员
*/ */
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun QQ.at(): At = At(this) inline fun Member.at(): At = At(this)

View File

@ -31,6 +31,7 @@ abstract class CustomFace : Image() {
abstract val source: Int abstract val source: Int
abstract val size:Int abstract val size:Int
abstract val pbReserve: ByteArray abstract val pbReserve: ByteArray
abstract val origin: Int
override fun toString(): String { override fun toString(): String {
return "[CustomFace]" return "[CustomFace]"
@ -57,6 +58,7 @@ data class CustomFaceFromFile(
override val height: Int, override val height: Int,
override val source: Int, override val source: Int,
override val size: Int, override val size: Int,
override val origin: Int,
override val pbReserve: ByteArray override val pbReserve: ByteArray
) : CustomFace() { ) : CustomFace() {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
@ -79,6 +81,7 @@ data class CustomFaceFromFile(
if (height != other.height) return false if (height != other.height) return false
if (source != other.source) return false if (source != other.source) return false
if (size != other.size) return false if (size != other.size) return false
if (origin != this.origin) return false
if (!pbReserve.contentEquals(other.pbReserve)) return false if (!pbReserve.contentEquals(other.pbReserve)) return false
return true return true
@ -114,6 +117,9 @@ abstract class NotOnlineImage : Image() {
open val bizType: Int get() = 0 open val bizType: Int get() = 0
open val imageType: Int get() = 1000 open val imageType: Int get() = 1000
open val downloadPath: String get() = resourceId open val downloadPath: String get() = resourceId
open val origin: Int get()= 1
open val signature: ByteArray get() = md5
open val fileType: Int get()= 66
override fun toString(): String { override fun toString(): String {
return "[NotOnlineImage $resourceId]" return "[NotOnlineImage $resourceId]"

View File

@ -39,7 +39,7 @@ class ExternalImage(
): ExternalImage = ExternalImage(width, height, md5, format, data, data.remaining, filename) ): ExternalImage = ExternalImage(width, height, md5, format, data, data.remaining, filename)
} }
private val format: String = when (val it =imageFormat.toLowerCase()) { private val format: String = when (val it = imageFormat.toLowerCase()) {
"jpeg" -> "jpg" //必须转换 "jpeg" -> "jpg" //必须转换
else -> it else -> it
} }
@ -56,7 +56,7 @@ class ExternalImage(
* SHARPP: 1004 * SHARPP: 1004
*/ */
val imageType: Int val imageType: Int
get() = when (format){ get() = when (format) {
"jpg" -> 1000 "jpg" -> 1000
"png" -> 1001 "png" -> 1001
"webp" -> 1002 "webp" -> 1002

View File

@ -1,6 +1,7 @@
apply plugin: "kotlin" apply plugin: "kotlin"
apply plugin: "java" apply plugin: "java"
apply plugin: "application" apply plugin: "application"
apply plugin: "kotlinx-serialization"
dependencies { dependencies {
implementation files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug implementation files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug

View File

@ -9,6 +9,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.alsoLogin import net.mamoe.mirai.alsoLogin
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.event.Subscribable import net.mamoe.mirai.event.Subscribable
import net.mamoe.mirai.event.events.ReceiveFriendAddRequestEvent import net.mamoe.mirai.event.events.ReceiveFriendAddRequestEvent
@ -67,7 +68,7 @@ suspend fun main() {
always { always {
} }
case("at me") { At(sender).reply() } case("at me") { At(sender as Member).reply() }
// 等同于 "at me" reply { At(sender) } // 等同于 "at me" reply { At(sender) }
"你好" reply "你好!" "你好" reply "你好!"

View File

@ -5,7 +5,6 @@ import kotlinx.coroutines.GlobalScope
import net.mamoe.mirai.event.events.BotLoginSucceedEvent import net.mamoe.mirai.event.events.BotLoginSucceedEvent
import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.event.subscribeMessages import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.message.data.At
import net.mamoe.mirai.plugin.PluginBase import net.mamoe.mirai.plugin.PluginBase
import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiExperimentalAPI
@ -19,7 +18,7 @@ class ImageSenderMain : PluginBase() {
this.bot.subscribeMessages { this.bot.subscribeMessages {
case("at me") { case("at me") {
(At(sender) + " ? ").reply() reply(sender.at() + " ? ")
} }
(contains("image") or contains("")) { (contains("image") or contains("")) {