mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 05:12:17 +00:00
Compare commits
7 Commits
14bf5fc0a2
...
8f8580d542
Author | SHA1 | Date | |
---|---|---|---|
8f8580d542 | |||
0ed4480878 | |||
c3e0031aa4 | |||
388c963e88 | |||
4283651b1e | |||
50d7dfa06d | |||
b3a2e605fb |
@ -8,5 +8,5 @@ import protobuf.message.element.*
|
||||
data class MessageElement(
|
||||
@ProtoNumber(1) val text: TextElement? = null,
|
||||
@ProtoNumber(51) val json: JsonElement? = null,
|
||||
@ProtoNumber(53) val richMedia: RichMediaElement? = null,
|
||||
@ProtoNumber(53) val commElem: CommonElement? = null,
|
||||
)
|
@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
@Serializable
|
||||
data class RichMediaElement(
|
||||
data class CommonElement(
|
||||
@ProtoNumber(1) val type: Int? = null,
|
||||
@ProtoNumber(2) val data: ByteArray? = null,
|
||||
@ProtoNumber(3) val u1: Int? = null,
|
@ -79,6 +79,10 @@ public final class InlineKeyboardButton {
|
||||
return "InlineKeyboardButton{id=" + this.id + ",label=" + this.label + ",visitedLabel=" + this.visitedLabel + ",style=" + this.style + ",type=" + this.type + ",clickLimit=" + this.clickLimit + ",unsupportTips=" + this.unsupportTips + ",data=" + this.data + ",atBotShowChannelList=" + this.atBotShowChannelList + ",permissionType=" + this.permissionType + ",specifyRoleIds=" + this.specifyRoleIds + ",specifyTinyids=" + this.specifyTinyids + ",}";
|
||||
}
|
||||
|
||||
public InlineKeyboardButton(String str, String str2, String str3, int i, int i2, int i3, String str4, String str5, boolean z, int i4, ArrayList<String> arrayList, ArrayList<String> arrayList2, boolean z2, int i5, boolean z3, ArrayList<SubscribeMsgTemplateID> arrayList3) {
|
||||
|
||||
}
|
||||
|
||||
public InlineKeyboardButton(String str, String str2, String str3, int i2, int i3, int i4, String str4, String str5, boolean z, int i5, ArrayList<String> arrayList, ArrayList<String> arrayList2) {
|
||||
this.id = "";
|
||||
this.label = "";
|
||||
|
@ -0,0 +1,4 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
public class SubscribeMsgTemplateID {
|
||||
}
|
@ -11,6 +11,9 @@ import com.tencent.qqnt.aio.adapter.api.IAIOPttApi
|
||||
import com.tencent.qqnt.kernel.nativeinterface.ArkElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.FaceBubbleElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.FaceElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.InlineKeyboardButton
|
||||
import com.tencent.qqnt.kernel.nativeinterface.InlineKeyboardElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.InlineKeyboardRow
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MarkdownElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MarketFaceElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MarketFaceSupportSize
|
||||
@ -53,9 +56,11 @@ import moe.fuqiuluo.shamrock.helper.LogicException
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.helper.MusicHelper
|
||||
import moe.fuqiuluo.shamrock.helper.ParamsException
|
||||
import moe.fuqiuluo.shamrock.tools.asBoolean
|
||||
import moe.fuqiuluo.shamrock.tools.asBooleanOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.asInt
|
||||
import moe.fuqiuluo.shamrock.tools.asIntOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.asJsonArray
|
||||
import moe.fuqiuluo.shamrock.tools.asJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.asLong
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
@ -108,8 +113,62 @@ internal object MessageMaker {
|
||||
//"node" to MessageMaker::createNodeElem,
|
||||
//"multi_msg" to MessageMaker::createLongMsgStruct,
|
||||
"bubble_face" to MessageMaker::createBubbleFaceElem,
|
||||
"inline_keyboard" to MessageMaker::createInlineKeywordElem
|
||||
)
|
||||
|
||||
private suspend fun createInlineKeywordElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
fun tryNewKeyboardButton(btn: JsonObject): InlineKeyboardButton {
|
||||
return runCatching {
|
||||
InlineKeyboardButton(
|
||||
btn["id"].asString,
|
||||
btn["label"].asString,
|
||||
btn["visited_label"].asString,
|
||||
btn["style"].asInt,
|
||||
btn["type"].asInt,
|
||||
btn["click_limit"].asInt,
|
||||
btn["unsupport_tips"].asString,
|
||||
btn["data"].asString,
|
||||
btn["at_bot_show_channel_list"].asBoolean,
|
||||
btn["permission_type"].asInt,
|
||||
ArrayList(btn["specify_role_ids"].asJsonArray.map { it.asString }),
|
||||
ArrayList(btn["specify_tinyids"].asJsonArray.map { it.asString }),
|
||||
false, 0, false, arrayListOf()
|
||||
)
|
||||
}.getOrElse {
|
||||
InlineKeyboardButton(
|
||||
btn["id"].asString,
|
||||
btn["label"].asString,
|
||||
btn["visited_label"].asString,
|
||||
btn["style"].asInt,
|
||||
btn["type"].asInt,
|
||||
btn["click_limit"].asInt,
|
||||
btn["unsupport_tips"].asString,
|
||||
btn["data"].asString,
|
||||
btn["at_bot_show_channel_list"].asBoolean,
|
||||
btn["permission_type"].asInt,
|
||||
ArrayList(btn["specify_role_ids"].asJsonArray.map { it.asString }),
|
||||
ArrayList(btn["specify_tinyids"].asJsonArray.map { it.asString }),
|
||||
)
|
||||
}
|
||||
}
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEINLINEKEYBOARD
|
||||
val rows = arrayListOf<InlineKeyboardRow>()
|
||||
|
||||
val keyboard = Json.parseToJsonElement(data["data"].asString).asJsonObject
|
||||
keyboard["rows"].asJsonArray.forEach {
|
||||
val row = it.asJsonObject
|
||||
val buttons = arrayListOf<InlineKeyboardButton>()
|
||||
row["buttons"].asJsonArray.forEach { button ->
|
||||
val btn = button.asJsonObject
|
||||
buttons.add(tryNewKeyboardButton(btn))
|
||||
}
|
||||
rows.add(InlineKeyboardRow(buttons))
|
||||
}
|
||||
elem.inlineKeyboardElement = InlineKeyboardElement(rows, keyboard["bot_appid"].asLong)
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createBubbleFaceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
data.checkAndThrow("id", "count")
|
||||
val faceId = data["id"].asInt
|
||||
@ -569,10 +628,10 @@ internal object MessageMaker {
|
||||
}
|
||||
|
||||
private suspend fun createMarkdownElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
data.checkAndThrow("text")
|
||||
data.checkAndThrow("content")
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEMARKDOWN
|
||||
val markdown = MarkdownElement(data["text"].asString)
|
||||
val markdown = MarkdownElement(data["content"].asString)
|
||||
elem.markdownElement = markdown
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ internal object MessageConvert {
|
||||
//MsgConstant.KELEMTYPEMULTIFORWARD to XmlMultiMsgConverter,
|
||||
//MsgConstant.KELEMTYPESTRUCTLONGMSG to XmlLongMsgConverter,
|
||||
MsgConstant.KELEMTYPEFACEBUBBLE to BubbleFaceConverter,
|
||||
MsgConstant.KELEMTYPEINLINEKEYBOARD to InlineKeyboardConverter,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,10 @@ package moe.fuqiuluo.qqinterface.servlet.msg.convert
|
||||
import com.tencent.mobileqq.qmmkv.QMMKV
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
||||
import kotlinx.serialization.json.add
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import kotlinx.serialization.json.putJsonArray
|
||||
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
|
||||
import moe.fuqiuluo.shamrock.helper.ContactHelper
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
@ -13,6 +17,7 @@ import moe.fuqiuluo.shamrock.helper.db.ImageMapping
|
||||
import moe.fuqiuluo.shamrock.helper.db.MessageDB
|
||||
import moe.fuqiuluo.shamrock.tools.asJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.shamrock.tools.hex2ByteArray
|
||||
import moe.fuqiuluo.shamrock.tools.json
|
||||
import mqq.app.MobileQQ
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
@ -209,7 +214,15 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val video = element.videoElement
|
||||
val md5 = video.fileName.split(".")[0]
|
||||
val md5 = if (video.fileName.contains("/")) {
|
||||
video.videoMd5.takeIf {
|
||||
!it.isNullOrEmpty()
|
||||
}?.hex2ByteArray() ?: video.fileName.split("/").let {
|
||||
it[it.size - 2].hex2ByteArray()
|
||||
}
|
||||
} else video.fileName.split(".")[0].hex2ByteArray()
|
||||
|
||||
//LogCenter.log({ "receive video msg: $video" }, Level.DEBUG)
|
||||
|
||||
return MessageSegment(
|
||||
type = "video",
|
||||
@ -218,7 +231,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
"url" to when(chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupVideoDownUrl("0", md5, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CVideoDownUrl("0", md5, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGroupVideoDownUrl(peerId, md5, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGroupVideoDownUrl("0", md5, video.fileUuid)
|
||||
else -> unknownChatType(chatType)
|
||||
}
|
||||
).also {
|
||||
@ -495,6 +508,53 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
}
|
||||
}
|
||||
|
||||
data object InlineKeyboardConverter: MessageElemConverter() {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val keyboard = element.inlineKeyboardElement
|
||||
return MessageSegment(
|
||||
type = "inline_keyboard",
|
||||
data = mapOf(
|
||||
"data" to buildJsonObject {
|
||||
putJsonArray("rows") {
|
||||
keyboard.rows.forEach { row ->
|
||||
add(buildJsonObject row@{
|
||||
putJsonArray("buttons") {
|
||||
row.buttons.forEach { button ->
|
||||
add(buildJsonObject {
|
||||
put("id", button.id ?: "")
|
||||
put("label", button.label ?: "")
|
||||
put("visited_label", button.visitedLabel ?: "")
|
||||
put("style", button.style)
|
||||
put("type", button.type)
|
||||
put("click_limit", button.clickLimit)
|
||||
put("unsupport_tips", button.unsupportTips ?: "")
|
||||
put("data", button.data)
|
||||
put("at_bot_show_channel_list", button.atBotShowChannelList)
|
||||
put("permission_type", button.permissionType)
|
||||
putJsonArray("specify_role_ids") {
|
||||
button.specifyRoleIds?.forEach { add(it) }
|
||||
}
|
||||
putJsonArray("specify_tinyids") {
|
||||
button.specifyTinyids?.forEach { add(it) }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
put("bot_appid", keyboard.botAppid)
|
||||
}.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun unknownChatType(chatType: Int) {
|
||||
throw UnsupportedOperationException("Not supported chat type: $chatType")
|
||||
}
|
||||
|
@ -167,9 +167,10 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
originalUrl: String,
|
||||
md5: String,
|
||||
): String {
|
||||
val domain = if (originalUrl.startsWith("/download")) GPRO_PIC_NT else GPRO_PIC
|
||||
val isNtServer = originalUrl.startsWith("/download")
|
||||
val domain = if (isNtServer) GPRO_PIC_NT else GPRO_PIC
|
||||
if (originalUrl.isNotEmpty()) {
|
||||
if (!originalUrl.contains("rkey=")) {
|
||||
if (isNtServer && !originalUrl.contains("rkey=")) {
|
||||
return "https://$domain$originalUrl&rkey=$multiMediaRKey"
|
||||
}
|
||||
return "https://$domain$originalUrl"
|
||||
@ -191,9 +192,10 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
originalUrl: String,
|
||||
md5: String
|
||||
): String {
|
||||
val domain = if (originalUrl.startsWith("/download")) GPRO_PIC_NT else GPRO_PIC
|
||||
val isNtServer = originalUrl.startsWith("/download")
|
||||
val domain = if (isNtServer) GPRO_PIC_NT else GPRO_PIC
|
||||
if (originalUrl.isNotEmpty()) {
|
||||
if (!originalUrl.contains("rkey=")) {
|
||||
if (isNtServer && !originalUrl.contains("rkey=")) {
|
||||
return "https://$domain$originalUrl&rkey=$multiMediaRKey"
|
||||
}
|
||||
return "https://$domain$originalUrl"
|
||||
@ -203,7 +205,7 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
|
||||
suspend fun getC2CVideoDownUrl(
|
||||
peerId: String,
|
||||
md5Hex: String,
|
||||
md5: ByteArray,
|
||||
fileUUId: String
|
||||
): String {
|
||||
return suspendCancellableCoroutine {
|
||||
@ -219,7 +221,7 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
downReq.troopUin = peerId
|
||||
downReq.clientType = 2
|
||||
downReq.fileId = fileUUId
|
||||
downReq.md5 = md5Hex.hex2ByteArray()
|
||||
downReq.md5 = md5
|
||||
downReq.busiType = FileTransfer.BUSI_TYPE_SHORT_VIDEO
|
||||
downReq.subBusiType = 0
|
||||
downReq.fileType = FileTransfer.VIDEO_FORMAT_MP4
|
||||
@ -246,7 +248,7 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
|
||||
suspend fun getGroupVideoDownUrl(
|
||||
peerId: String,
|
||||
md5Hex: String,
|
||||
md5: ByteArray,
|
||||
fileUUId: String
|
||||
): String {
|
||||
return suspendCancellableCoroutine {
|
||||
@ -262,7 +264,7 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
downReq.troopUin = peerId
|
||||
downReq.clientType = 2
|
||||
downReq.fileId = fileUUId
|
||||
downReq.md5 = md5Hex.hex2ByteArray()
|
||||
downReq.md5 = md5
|
||||
downReq.busiType = FileTransfer.BUSI_TYPE_SHORT_VIDEO
|
||||
downReq.subBusiType = 0
|
||||
downReq.fileType = FileTransfer.VIDEO_FORMAT_MP4
|
||||
|
@ -109,10 +109,11 @@ internal object PrimitiveListener {
|
||||
}
|
||||
|
||||
private fun onGroupMessage(msgTime: Long, body: MessageBody) {
|
||||
runCatching {
|
||||
body.rich?.elements?.filter {
|
||||
it.richMedia != null
|
||||
it.commElem != null && it.commElem!!.type == 48
|
||||
}?.map {
|
||||
ProtoBuf.decodeFromByteArray<RichMediaForPicData>(it.richMedia!!.data!!)
|
||||
ProtoBuf.decodeFromByteArray<RichMediaForPicData>(it.commElem!!.data!!)
|
||||
}?.forEach {
|
||||
it.display?.show?.download?.url?.let {
|
||||
RKEY_PATTERN.matcher(it).takeIf {
|
||||
@ -123,6 +124,8 @@ internal object PrimitiveListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun onC2CPoke(msgTime: Long, richMsg: MessageBody) {
|
||||
|
Reference in New Issue
Block a user