mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-09 01:30:17 +08:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
522bcba33e
@ -11,7 +11,6 @@
|
||||
|
||||
package net.mamoe.mirai.qqandroid
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.forms.formData
|
||||
@ -45,6 +44,7 @@ import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.LongMsg
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.*
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.voice.PttStore
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.qqandroid.utils.MiraiPlatformUtils
|
||||
import net.mamoe.mirai.qqandroid.utils.encodeToString
|
||||
@ -56,6 +56,7 @@ import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.jvm.JvmField
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.log
|
||||
import kotlin.random.Random
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.FriendInfo as JceFriendInfo
|
||||
|
||||
@ -560,7 +561,7 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun _lowLevelGetAnnouncement(groupId: Long, fid: String): GroupAnnouncement {
|
||||
val data = network.async {
|
||||
HttpClient().post<String> {
|
||||
MiraiPlatformUtils.Http.post<String> {
|
||||
url("https://web.qun.qq.com/cgi-bin/announce/get_feed")
|
||||
body = MultiPartFormDataContent(formData {
|
||||
append("qid", groupId)
|
||||
@ -587,7 +588,7 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun _lowLevelGetGroupActiveData(groupId: Long, page: Int): GroupActiveData {
|
||||
val data = network.async {
|
||||
HttpClient().get<String> {
|
||||
MiraiPlatformUtils.Http.get<String> {
|
||||
url("https://qqweb.qq.com/c/activedata/get_mygroup_data")
|
||||
parameter("bkn", bkn)
|
||||
parameter("gc", groupId)
|
||||
@ -792,6 +793,21 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@MiraiExperimentalAPI
|
||||
@LowLevelAPI
|
||||
override suspend fun _lowLevelQueryGroupVoiceDownloadUrl(
|
||||
md5: ByteArray,
|
||||
groupId: Long,
|
||||
dstUin: Long
|
||||
): String {
|
||||
network.run {
|
||||
val response: PttStore.GroupPttDown.Response.DownLoadInfo =
|
||||
PttStore.GroupPttDown(client, groupId, dstUin,md5).sendAndExpect()
|
||||
return "http://${response.strDomain}${response.downPara.encodeToString()}"
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION", "OverridingDeprecatedMember")
|
||||
override suspend fun queryImageUrl(image: Image): String = when (image) {
|
||||
is ConstOriginUrlAware -> image.originUrl
|
||||
|
@ -32,7 +32,9 @@ import kotlin.contracts.contract
|
||||
private val UNSUPPORTED_MERGED_MESSAGE_PLAIN = PlainText("你的QQ暂不支持查看[转发多条消息],请期待后续版本。")
|
||||
private val UNSUPPORTED_POKE_MESSAGE_PLAIN = PlainText("[戳一戳]请使用最新版手机QQ体验新功能。")
|
||||
private val UNSUPPORTED_FLASH_MESSAGE_PLAIN = PlainText("[闪照]请使用新版手机QQ查看闪照。")
|
||||
private val UNSUPPORTED_VOICE_MESSAGE_PLAIN = PlainText("收到语音消息,你需要升级到最新版QQ才能接收,升级地址https://im.qq.com")
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: Boolean): MutableList<ImMsgBody.Elem> {
|
||||
val elements = ArrayList<ImMsgBody.Elem>(this.size)
|
||||
@ -156,7 +158,20 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B
|
||||
is VipFace -> {
|
||||
transformOneMessage(PlainText(it.contentToString()))
|
||||
}
|
||||
is PttMessage,
|
||||
is PttMessage -> {
|
||||
elements.add(
|
||||
ImMsgBody.Elem(
|
||||
extraInfo = ImMsgBody.ExtraInfo(flags = 16, groupMask = 1)
|
||||
)
|
||||
)
|
||||
elements.add(
|
||||
ImMsgBody.Elem(
|
||||
elemFlags2 = ImMsgBody.ElemFlags2(
|
||||
vipStatus = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
is ForwardMessage,
|
||||
is MessageSource, // mirai metadata only
|
||||
is RichMessage // already transformed above
|
||||
@ -218,10 +233,11 @@ internal fun MsgComm.Msg.toMessageChain(
|
||||
val ptt = this.msgBody.richText.ptt
|
||||
|
||||
val pptMsg = ptt?.run {
|
||||
when(fileType) {
|
||||
4 -> Voice(String(fileName), fileMd5, String(downPara))
|
||||
else -> null
|
||||
}
|
||||
// when (fileType) {
|
||||
// 4 -> Voice(String(fileName), fileMd5, fileSize.toLong(),String(downPara))
|
||||
// else -> null
|
||||
// }
|
||||
Voice(String(fileName), fileMd5, fileSize.toLong(),String(downPara))
|
||||
}
|
||||
|
||||
return buildMessageChain(elements.size + 1 + if (pptMsg == null) 0 else 1) {
|
||||
@ -274,13 +290,13 @@ private fun MessageChain.cleanupRubbishMessageElements(): MessageChain {
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
if (last is FlashImage && element is PlainText) {
|
||||
if (element == UNSUPPORTED_FLASH_MESSAGE_PLAIN) {
|
||||
// 解决tim发送的语音无法正常识别
|
||||
if (element is PlainText) {
|
||||
if (element == UNSUPPORTED_VOICE_MESSAGE_PLAIN) {
|
||||
last = element
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
add(element)
|
||||
last = element
|
||||
}
|
||||
@ -431,7 +447,8 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(groupIdOrZero: Long, bot: B
|
||||
.orEmpty(),
|
||||
proto.pokeType,
|
||||
proto.vaspokeId
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
3 -> {
|
||||
val proto = element.commonElem.pbElem.loadAs(HummerCommelem.MsgElemInfoServtype3.serializer())
|
||||
|
@ -12,7 +12,10 @@
|
||||
package net.mamoe.mirai.qqandroid.network.highway
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.request.port
|
||||
import io.ktor.client.request.post
|
||||
import io.ktor.client.request.url
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.http.URLProtocol
|
||||
@ -29,8 +32,9 @@ import kotlinx.io.core.use
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.CSDataHighwayHead
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x388
|
||||
import net.mamoe.mirai.qqandroid.utils.*
|
||||
import net.mamoe.mirai.qqandroid.utils.PlatformSocket
|
||||
import net.mamoe.mirai.qqandroid.utils.SocketException
|
||||
import net.mamoe.mirai.qqandroid.utils.addSuppressedMirai
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.utils.io.withUse
|
||||
@ -180,6 +184,50 @@ internal object HighwayHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun uploadPttToServers(
|
||||
bot: QQAndroidBot,
|
||||
servers: List<Pair<Int, Int>>,
|
||||
content: ByteArray,
|
||||
md5: ByteArray,
|
||||
uKey: ByteArray, fileKey: ByteArray
|
||||
) {
|
||||
servers.retryWithServers(10 * 1000, {
|
||||
throw IllegalStateException("cannot upload ptt, failed on all servers.", it)
|
||||
}, { s: String, i: Int ->
|
||||
bot.network.logger.verbose {
|
||||
"[Highway] Uploading ptt to ${s}:$i, size=${content.size.toLong().sizeToString()}"
|
||||
}
|
||||
val time = measureTime {
|
||||
uploadPttToServer(s, i, content, md5, uKey, fileKey)
|
||||
}
|
||||
bot.network.logger.verbose {
|
||||
"[Highway] Uploading ptt: succeed at ${(content.size.toDouble() / 1024 / time.inSeconds).roundToInt()} KiB/s"
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private suspend fun uploadPttToServer(
|
||||
serverIp: String,
|
||||
serverPort: Int,
|
||||
content: ByteArray,
|
||||
md5: ByteArray,
|
||||
uKey: ByteArray, fileKey: ByteArray
|
||||
) {
|
||||
MiraiPlatformUtils.Http.post<String> {
|
||||
url("http://$serverIp:$serverPort")
|
||||
parameter("ver", 4679)
|
||||
parameter("ukey", uKey.toUHexString(""))
|
||||
parameter("filekey", fileKey.toUHexString(""))
|
||||
parameter("filesize", content.size)
|
||||
parameter("bmd5", md5.toUHexString(""))
|
||||
parameter("mType", "pttDu")
|
||||
parameter("voice_encodec", 0)
|
||||
body = content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -273,7 +273,7 @@ internal class TryUpPttReq(
|
||||
internal class TryUpPttRsp(
|
||||
@ProtoId(1) @JvmField val fileId: Long = 0L,
|
||||
@ProtoId(2) @JvmField val result: Int = 0,
|
||||
@ProtoId(3) @JvmField val failMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoId(3) @JvmField val failMsg: ByteArray? = null,
|
||||
@ProtoId(4) @JvmField val boolFileExit: Boolean = false,
|
||||
@ProtoId(5) @JvmField val uint32UpIp: List<Int>? = null,
|
||||
@ProtoId(6) @JvmField val uint32UpPort: List<Int>? = null,
|
||||
|
@ -20,6 +20,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.*
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.voice.PttStore
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.ConfigPushSvc
|
||||
@ -139,6 +140,8 @@ internal object KnownPacketFactories {
|
||||
FriendList.GetTroopListSimplify,
|
||||
FriendList.GetTroopMemberList,
|
||||
ImgStore.GroupPicUp,
|
||||
PttStore.GroupPttUp,
|
||||
PttStore.GroupPttDown,
|
||||
LongConn.OffPicUp,
|
||||
LongConn.OffPicDown,
|
||||
TroopManagement.EditSpecialTitle,
|
||||
|
@ -30,6 +30,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.qqandroid.utils.hexToBytes
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
|
||||
@ -138,7 +139,14 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
richText = ImMsgBody.RichText(
|
||||
elems = message.toRichTextElems(forGroup = true, withGeneralFlags = true),
|
||||
ptt = message.firstOrNull(PttMessage)?.run {
|
||||
ImMsgBody.Ptt(fileName = fileName.toByteArray(), fileMd5 = md5)
|
||||
ImMsgBody.Ptt(
|
||||
fileName = fileName.toByteArray(),
|
||||
fileMd5 = md5,
|
||||
boolValid = true,
|
||||
fileSize = fileSize.toInt(),
|
||||
fileType = 4,
|
||||
pbReserve = byteArrayOf(0)
|
||||
)
|
||||
}
|
||||
)
|
||||
),
|
||||
|
@ -53,6 +53,7 @@ internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("Onlin
|
||||
// 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 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 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00
|
||||
if (!bot.firstLoginSucceed) return null
|
||||
val pbPushMsg = readProtoBuf(MsgOnlinePush.PbPushMsg.serializer())
|
||||
// bot.logger.debug(pbPushMsg._miraiContentToString())
|
||||
|
||||
if (pbPushMsg.msg.msgHead.fromUin == bot.id) {
|
||||
return SendGroupMessageReceipt(
|
||||
|
@ -0,0 +1,160 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.voice
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.qqandroid.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.network.Packet
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x388
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.getRandomString
|
||||
import net.mamoe.mirai.qqandroid.utils._miraiContentToString
|
||||
import net.mamoe.mirai.qqandroid.utils.encodeToString
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.utils.toUHexString
|
||||
|
||||
internal class PttStore {
|
||||
object GroupPttUp : OutgoingPacketFactory<GroupPttUp.Response>("PttStore.GroupPttUp") {
|
||||
|
||||
sealed class Response : Packet {
|
||||
|
||||
class RequireUpload(
|
||||
val fileId: Long,
|
||||
val uKey: ByteArray,
|
||||
val uploadIpList: List<Int>,
|
||||
val uploadPortList: List<Int>,
|
||||
val fileKey: ByteArray
|
||||
) : GroupPttUp.Response() {
|
||||
override fun toString(): String {
|
||||
return "RequireUpload(fileId=$fileId, uKey=${uKey.contentToString()})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
uin: Long,
|
||||
groupCode: Long,
|
||||
md5: ByteArray,
|
||||
size: Long,
|
||||
voiceLength: Int,
|
||||
fileId: Long = 0
|
||||
): OutgoingPacket {
|
||||
val pack = Cmd0x388.ReqBody(
|
||||
netType = 3, // wifi
|
||||
subcmd = 3,
|
||||
msgTryupPttReq = listOf(
|
||||
Cmd0x388.TryUpPttReq(
|
||||
srcUin = uin,
|
||||
groupCode = groupCode,
|
||||
fileId = fileId,
|
||||
fileSize = size,
|
||||
fileMd5 = md5,
|
||||
fileName = md5,
|
||||
srcTerm = 5,
|
||||
platformType = 9,
|
||||
buType = 4,
|
||||
innerIp = 0,
|
||||
buildVer = "6.5.5.663".encodeToByteArray(),
|
||||
voiceLength = voiceLength,
|
||||
codec = 0,
|
||||
voiceType = 1,
|
||||
boolNewUpChan = true
|
||||
)
|
||||
)
|
||||
)
|
||||
return buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(Cmd0x388.ReqBody.serializer(), pack)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
val resp0 = readProtoBuf(Cmd0x388.RspBody.serializer())
|
||||
resp0.msgTryupPttRsp ?: error("cannot find `msgTryupPttRsp` from `Cmd0x388.RspBody`")
|
||||
val resp = resp0.msgTryupPttRsp.first()
|
||||
if (resp.failMsg != null) {
|
||||
throw IllegalStateException(resp.failMsg.encodeToString())
|
||||
}
|
||||
return Response.RequireUpload(
|
||||
fileId = resp.fileid,
|
||||
uKey = resp.upUkey,
|
||||
uploadIpList = resp.uint32UpIp!!,
|
||||
uploadPortList = resp.uint32UpPort!!,
|
||||
fileKey = resp.fileKey
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object GroupPttDown : OutgoingPacketFactory<GroupPttDown.Response>("PttStore.GroupPttDown") {
|
||||
|
||||
sealed class Response() : Packet {
|
||||
class DownLoadInfo(
|
||||
val downDomain: ByteArray,
|
||||
val downPara:ByteArray,
|
||||
val strDomain:String,
|
||||
val uint32DownIp:List<Int>,
|
||||
val uint32DownPort:List<Int>
|
||||
) : GroupPttDown.Response() {
|
||||
override fun toString(): String {
|
||||
return "GroupPttDown(downPara=${downPara.encodeToString()},strDomain=$strDomain})"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
groupCode: Long,
|
||||
dstUin:Long,
|
||||
md5: ByteArray
|
||||
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
Cmd0x388.ReqBody.serializer(), Cmd0x388.ReqBody(
|
||||
netType = 3, // wifi
|
||||
subcmd = 4,
|
||||
msgGetpttUrlReq = listOf(
|
||||
Cmd0x388.GetPttUrlReq(
|
||||
groupCode = groupCode,
|
||||
fileMd5 = md5,
|
||||
dstUin = dstUin,
|
||||
buType = 4,
|
||||
innerIp = 0,
|
||||
buildVer = "6.5.5.663".encodeToByteArray(),
|
||||
codec = 0,
|
||||
reqTerm = 5,
|
||||
reqPlatformType = 9
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
val resp0 = readProtoBuf(Cmd0x388.RspBody.serializer())
|
||||
resp0.msgGetpttUrlRsp ?: error("cannot find `msgGetpttUrlRsp` from `Cmd0x388.RspBody`")
|
||||
val resp = resp0.msgGetpttUrlRsp.first()
|
||||
if (!resp.failMsg.contentEquals(EMPTY_BYTE_ARRAY)){
|
||||
throw IllegalStateException(resp.failMsg.encodeToString())
|
||||
}
|
||||
return Response.DownLoadInfo(
|
||||
downDomain = resp.downDomain,
|
||||
downPara = resp.downPara,
|
||||
uint32DownIp = resp.uint32DownIp!!,
|
||||
uint32DownPort = resp.uint32DownPort!!,
|
||||
strDomain = resp.strDomain
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -16,6 +16,7 @@ import net.mamoe.mirai.data.*
|
||||
import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
|
||||
import net.mamoe.mirai.event.events.MemberJoinRequestEvent
|
||||
import net.mamoe.mirai.event.events.NewFriendRequestEvent
|
||||
import net.mamoe.mirai.message.data.Voice
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import net.mamoe.mirai.utils.WeakRef
|
||||
|
||||
@ -159,4 +160,13 @@ interface LowLevelBotAPIAccessor {
|
||||
blackList: Boolean,
|
||||
message: String = ""
|
||||
)
|
||||
|
||||
/**
|
||||
* 查询语音的下载连接
|
||||
*
|
||||
* */
|
||||
|
||||
@LowLevelAPI
|
||||
@MiraiExperimentalAPI
|
||||
suspend fun _lowLevelQueryGroupVoiceDownloadUrl(md5: ByteArray, groupId: Long, dstUin: Long): String
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ abstract class PttMessage : MessageContent {
|
||||
|
||||
abstract val fileName: String
|
||||
abstract val md5: ByteArray
|
||||
abstract val fileSize: Long
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +26,7 @@ abstract class PttMessage : MessageContent {
|
||||
class Voice(
|
||||
override val fileName: String,
|
||||
override val md5: ByteArray,
|
||||
override val fileSize: Long,
|
||||
private val _url: String
|
||||
) : PttMessage() {
|
||||
|
||||
@ -33,9 +35,9 @@ class Voice(
|
||||
get() = "Voice"
|
||||
}
|
||||
|
||||
val url: String
|
||||
val url: String?
|
||||
get() = if (_url.startsWith("http")) _url
|
||||
else "http://grouptalk.c2c.qq.com$_url"
|
||||
else null
|
||||
|
||||
private var _stringValue: String? = null
|
||||
get() = field ?: kotlin.run {
|
||||
|
Loading…
Reference in New Issue
Block a user