3 Commits

Author SHA1 Message Date
c97f79335a Shamrock: Support /set_group_comment_face 2024-01-28 23:45:05 +08:00
e07e75747a Shamrock: Support big face and bubble face 2024-01-28 23:22:06 +08:00
9482641c38 Shamrock: fix #213 2024-01-28 22:38:54 +08:00
9 changed files with 185 additions and 46 deletions

View File

@ -0,0 +1,14 @@
package moe.whitechi73.protobuf.oidb.cmd0x9082
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Oidb0x9082(
@ProtoNumber(2) val peer: ULong = ULong.MIN_VALUE,
@ProtoNumber(3) val msgSeq: ULong = ULong.MIN_VALUE,
@ProtoNumber(4) val faceIndex: String = "",
@ProtoNumber(5) val flag: UInt = UInt.MIN_VALUE,
@ProtoNumber(6) val u1: UInt = UInt.MIN_VALUE,
@ProtoNumber(7) val u2: UInt = UInt.MIN_VALUE,
)

View File

@ -19,4 +19,11 @@ public class QQSysFaceUtil {
public static String getFaceDescription(int localId) { public static String getFaceDescription(int localId) {
return ""; return "";
} }
public static String getPrueFaceDescription(String str) {
if (str == null) {
return null;
}
return str.startsWith("/") ? str.substring(1) : str;
}
} }

View File

@ -0,0 +1,19 @@
package moe.fuqiuluo.qqinterface.servlet
import kotlinx.serialization.encodeToByteArray
import kotlinx.serialization.protobuf.ProtoBuf
import moe.whitechi73.protobuf.oidb.cmd0x9082.Oidb0x9082
internal object ChatSvc: BaseSvc() {
fun setGroupMessageCommentFace(peer: Long, msgSeq: ULong, faceIndex: String, isSet: Boolean) {
val serviceId = if (isSet) 1 else 2
sendOidb("OidbSvcTrpcTcp.0x9082_$serviceId", 36994, serviceId, ProtoBuf.encodeToByteArray(Oidb0x9082(
peer = peer.toULong(),
msgSeq = msgSeq,
faceIndex = faceIndex,
flag = 1u,
u1 = 0u,
u2 = 0u
)))
}
}

View File

@ -9,6 +9,7 @@ import com.tencent.mobileqq.qroute.QRoute
import com.tencent.qphone.base.remote.ToServiceMsg import com.tencent.qphone.base.remote.ToServiceMsg
import com.tencent.qqnt.aio.adapter.api.IAIOPttApi import com.tencent.qqnt.aio.adapter.api.IAIOPttApi
import com.tencent.qqnt.kernel.nativeinterface.ArkElement 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.FaceElement
import com.tencent.qqnt.kernel.nativeinterface.MarkdownElement import com.tencent.qqnt.kernel.nativeinterface.MarkdownElement
import com.tencent.qqnt.kernel.nativeinterface.MarketFaceElement import com.tencent.qqnt.kernel.nativeinterface.MarketFaceElement
@ -20,9 +21,9 @@ import com.tencent.qqnt.kernel.nativeinterface.PttElement
import com.tencent.qqnt.kernel.nativeinterface.QQNTWrapperUtil import com.tencent.qqnt.kernel.nativeinterface.QQNTWrapperUtil
import com.tencent.qqnt.kernel.nativeinterface.ReplyElement import com.tencent.qqnt.kernel.nativeinterface.ReplyElement
import com.tencent.qqnt.kernel.nativeinterface.RichMediaFilePathInfo import com.tencent.qqnt.kernel.nativeinterface.RichMediaFilePathInfo
import com.tencent.qqnt.kernel.nativeinterface.SmallYellowFaceInfo
import com.tencent.qqnt.kernel.nativeinterface.TextElement import com.tencent.qqnt.kernel.nativeinterface.TextElement
import com.tencent.qqnt.kernel.nativeinterface.VideoElement import com.tencent.qqnt.kernel.nativeinterface.VideoElement
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
@ -45,7 +46,9 @@ import moe.fuqiuluo.qqinterface.servlet.transfile.with
import moe.fuqiuluo.shamrock.helper.ActionMsgException import moe.fuqiuluo.shamrock.helper.ActionMsgException
import moe.fuqiuluo.shamrock.helper.ContactHelper import moe.fuqiuluo.shamrock.helper.ContactHelper
import moe.fuqiuluo.shamrock.helper.IllegalParamsException import moe.fuqiuluo.shamrock.helper.IllegalParamsException
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LocalCacheHelper import moe.fuqiuluo.shamrock.helper.LocalCacheHelper
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.LogicException import moe.fuqiuluo.shamrock.helper.LogicException
import moe.fuqiuluo.shamrock.helper.MessageHelper import moe.fuqiuluo.shamrock.helper.MessageHelper
import moe.fuqiuluo.shamrock.helper.MusicHelper import moe.fuqiuluo.shamrock.helper.MusicHelper
@ -62,8 +65,6 @@ import moe.fuqiuluo.shamrock.utils.AudioUtils
import moe.fuqiuluo.shamrock.utils.FileUtils import moe.fuqiuluo.shamrock.utils.FileUtils
import moe.fuqiuluo.shamrock.utils.MediaType import moe.fuqiuluo.shamrock.utils.MediaType
import moe.fuqiuluo.shamrock.utils.PlatformUtils import moe.fuqiuluo.shamrock.utils.PlatformUtils
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
import moe.fuqiuluo.shamrock.xposed.helper.msgService import moe.fuqiuluo.shamrock.xposed.helper.msgService
@ -106,8 +107,32 @@ internal object MessageMaker {
"basketball" to MessageMaker::createBasketballElem, "basketball" to MessageMaker::createBasketballElem,
//"node" to MessageMaker::createNodeElem, //"node" to MessageMaker::createNodeElem,
//"multi_msg" to MessageMaker::createLongMsgStruct, //"multi_msg" to MessageMaker::createLongMsgStruct,
"bubble_face" to MessageMaker::createBubbleFaceElem,
) )
private suspend fun createBubbleFaceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
data.checkAndThrow("id", "count")
val faceId = data["id"].asInt
val local = QQSysFaceUtil.convertToLocal(faceId)
val name = QQSysFaceUtil.getFaceDescription(local)
val count = data["count"].asInt
val elem = MsgElement()
elem.elementType = MsgConstant.KELEMTYPEFACEBUBBLE
val face = FaceBubbleElement()
face.faceType = 13
face.faceCount = count
face.faceSummary = QQSysFaceUtil.getPrueFaceDescription(name)
val smallYellowFaceInfo = SmallYellowFaceInfo()
smallYellowFaceInfo.index = faceId
smallYellowFaceInfo.compatibleText = face.faceSummary
smallYellowFaceInfo.text = face.faceSummary
face.yellowFaceInfo = smallYellowFaceInfo
face.faceFlag = 0
face.content = data["text"].asStringOrNull ?: "[${face.faceSummary}]x$count"
elem.faceBubbleElement = face
return Result.success(elem)
}
// private suspend fun createNodeElem( // private suspend fun createNodeElem(
// chatType: Int, // chatType: Int,
// msgId: Long, // msgId: Long,
@ -475,19 +500,31 @@ internal object MessageMaker {
private suspend fun createFaceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> { private suspend fun createFaceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
data.checkAndThrow("id") data.checkAndThrow("id")
val big = data["big"].asBooleanOrNull ?: false
val elem = MsgElement() val elem = MsgElement()
elem.elementType = MsgConstant.KELEMTYPEFACE elem.elementType = MsgConstant.KELEMTYPEFACE
val face = FaceElement() val face = FaceElement()
// 1 old face
// 2 normal face
// 3 super face
// 4 is market face // 4 is market face
// 5 is vas poke // 5 is vas poke
face.faceType = 0 face.faceType = if (big) 3 else 2
val serverId = data["id"].asInt val serverId = data["id"].asInt
val localId = QQSysFaceUtil.convertToLocal(serverId)
face.faceIndex = serverId face.faceIndex = serverId
face.faceText = QQSysFaceUtil.getFaceDescription(localId) face.faceText = QQSysFaceUtil.getFaceDescription(QQSysFaceUtil.convertToLocal(serverId))
face.imageType = 0 face.imageType = 0
if (big) {
face.stickerId = 30.toString()
face.packId = "1"
face.sourceType = 1
face.stickerType = 1
face.randomType = 1
} else {
face.packId = "0" face.packId = "0"
}
elem.faceElement = face elem.faceElement = face
return Result.success(elem) return Result.success(elem)

View File

@ -4,6 +4,7 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
import com.tencent.qqnt.kernel.nativeinterface.MsgElement import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.qqinterface.servlet.msg.convert.MessageElemConverter.*
import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.MessageHelper import moe.fuqiuluo.shamrock.helper.MessageHelper
@ -43,19 +44,20 @@ internal suspend fun List<MsgElement>.toCQCode(chatType: Int, peerId: String): S
internal object MessageConvert { internal object MessageConvert {
private val convertMap by lazy { private val convertMap by lazy {
mutableMapOf<Int, IMessageConvert>( mutableMapOf<Int, IMessageConvert>(
MsgConstant.KELEMTYPETEXT to MessageElemConverter.TextConverter, MsgConstant.KELEMTYPETEXT to TextConverter,
MsgConstant.KELEMTYPEFACE to MessageElemConverter.FaceConverter, MsgConstant.KELEMTYPEFACE to FaceConverter,
MsgConstant.KELEMTYPEPIC to MessageElemConverter.ImageConverter, MsgConstant.KELEMTYPEPIC to ImageConverter,
MsgConstant.KELEMTYPEPTT to MessageElemConverter.VoiceConverter, MsgConstant.KELEMTYPEPTT to VoiceConverter,
MsgConstant.KELEMTYPEVIDEO to MessageElemConverter.VideoConverter, MsgConstant.KELEMTYPEVIDEO to VideoConverter,
MsgConstant.KELEMTYPEMARKETFACE to MessageElemConverter.MarketFaceConverter, MsgConstant.KELEMTYPEMARKETFACE to MarketFaceConverter,
MsgConstant.KELEMTYPEARKSTRUCT to MessageElemConverter.StructJsonConverter, MsgConstant.KELEMTYPEARKSTRUCT to StructJsonConverter,
MsgConstant.KELEMTYPEREPLY to MessageElemConverter.ReplyConverter, MsgConstant.KELEMTYPEREPLY to ReplyConverter,
MsgConstant.KELEMTYPEGRAYTIP to MessageElemConverter.GrayTipsConverter, MsgConstant.KELEMTYPEGRAYTIP to GrayTipsConverter,
MsgConstant.KELEMTYPEFILE to MessageElemConverter.FileConverter, MsgConstant.KELEMTYPEFILE to FileConverter,
MsgConstant.KELEMTYPEMARKDOWN to MessageElemConverter.MarkdownConverter, MsgConstant.KELEMTYPEMARKDOWN to MarkdownConverter,
//MsgConstant.KELEMTYPEMULTIFORWARD to MessageElemConverter.XmlMultiMsgConverter, //MsgConstant.KELEMTYPEMULTIFORWARD to XmlMultiMsgConverter,
//MsgConstant.KELEMTYPESTRUCTLONGMSG to MessageElemConverter.XmlLongMsgConverter, //MsgConstant.KELEMTYPESTRUCTLONGMSG to XmlLongMsgConverter,
MsgConstant.KELEMTYPEFACEBUBBLE to BubbleFaceConverter,
) )
} }
@ -65,11 +67,11 @@ internal object MessageConvert {
peerId: String peerId: String
): ArrayList<MessageSegment> { ): ArrayList<MessageSegment> {
val messageData = arrayListOf<MessageSegment>() val messageData = arrayListOf<MessageSegment>()
elements.forEach { elements.forEach { msg ->
kotlin.runCatching { kotlin.runCatching {
val elementId = it.elementType val elementId = msg.elementType
val converter = convertMap[elementId] val converter = convertMap[elementId]
converter?.convert(chatType, peerId, it) converter?.convert(chatType, peerId, msg)
?: throw UnsupportedOperationException("不支持的消息element类型$elementId") ?: throw UnsupportedOperationException("不支持的消息element类型$elementId")
}.onSuccess { }.onSuccess {
messageData.add(it) messageData.add(it)
@ -77,7 +79,7 @@ internal object MessageConvert {
if (it is UnknownError) { if (it is UnknownError) {
// 不处理的消息类型抛出unknown error // 不处理的消息类型抛出unknown error
} else { } else {
LogCenter.log("消息element转换错误$it", Level.WARN) LogCenter.log("消息element转换错误$it, elementType: ${msg.elementType}", Level.WARN)
} }
} }
} }

View File

@ -18,7 +18,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 文本 / 艾特 消息转换消息段 * 文本 / 艾特 消息转换消息段
*/ */
object TextConverter: MessageElemConverter() { data object TextConverter: MessageElemConverter() {
override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment { override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment {
val text = element.textElement val text = element.textElement
return if (text.atType != MsgConstant.ATTYPEUNKNOWN) { return if (text.atType != MsgConstant.ATTYPEUNKNOWN) {
@ -42,9 +42,10 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 小表情 / 戳一戳 消息转换消息段 * 小表情 / 戳一戳 消息转换消息段
*/ */
object FaceConverter: MessageElemConverter() { data object FaceConverter: MessageElemConverter() {
override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment { override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment {
val face = element.faceElement val face = element.faceElement
if (face.faceType == 5) { if (face.faceType == 5) {
return MessageSegment( return MessageSegment(
type = "poke", type = "poke",
@ -55,8 +56,6 @@ internal sealed class MessageElemConverter: IMessageConvert {
) )
) )
} }
when (face.faceIndex) { when (face.faceIndex) {
114 -> { 114 -> {
return MessageSegment( return MessageSegment(
@ -87,7 +86,8 @@ internal sealed class MessageElemConverter: IMessageConvert {
else -> return MessageSegment( else -> return MessageSegment(
type = "face", type = "face",
data = hashMapOf( data = hashMapOf(
"id" to face.faceIndex "id" to face.faceIndex,
"big" to (face.faceType == 3)
) )
) )
} }
@ -97,7 +97,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 图片消息转换消息段 * 图片消息转换消息段
*/ */
object ImageConverter: MessageElemConverter() { data object ImageConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -121,7 +121,9 @@ internal sealed class MessageElemConverter: IMessageConvert {
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(md5) MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(md5)
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPicDownUrl(md5) MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPicDownUrl(md5)
else -> unknownChatType(chatType) else -> unknownChatType(chatType)
} },
"subType" to image.picSubType,
"type" to if (image.isFlashPic) "flash" else "show"
) )
) )
} }
@ -130,7 +132,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 语音消息转换消息段 * 语音消息转换消息段
*/ */
object VoiceConverter: MessageElemConverter() { data object VoiceConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -166,7 +168,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 视频消息转换消息段 * 视频消息转换消息段
*/ */
object VideoConverter: MessageElemConverter() { data object VideoConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -195,7 +197,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 商城大表情消息转换消息段 * 商城大表情消息转换消息段
*/ */
object MarketFaceConverter: MessageElemConverter() { data object MarketFaceConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -218,7 +220,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* JSON消息转消息段 * JSON消息转消息段
*/ */
object StructJsonConverter: MessageElemConverter() { data object StructJsonConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -280,7 +282,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 回复消息转消息段 * 回复消息转消息段
*/ */
object ReplyConverter: MessageElemConverter() { data object ReplyConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -312,7 +314,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 灰色提示条消息过滤 * 灰色提示条消息过滤
*/ */
object GrayTipsConverter: MessageElemConverter() { data object GrayTipsConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -347,7 +349,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 文件消息转换消息段 * 文件消息转换消息段
*/ */
object FileConverter: MessageElemConverter() { data object FileConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -381,7 +383,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
/** /**
* 老板QQ的合并转发信息 * 老板QQ的合并转发信息
*/ */
object XmlMultiMsgConverter: MessageElemConverter() { data object XmlMultiMsgConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -397,7 +399,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
} }
} }
object XmlLongMsgConverter: MessageElemConverter() { data object XmlLongMsgConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -413,7 +415,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
} }
} }
object MarkdownConverter: MessageElemConverter() { data object MarkdownConverter: MessageElemConverter() {
override suspend fun convert( override suspend fun convert(
chatType: Int, chatType: Int,
peerId: String, peerId: String,
@ -429,6 +431,23 @@ internal sealed class MessageElemConverter: IMessageConvert {
} }
} }
data object BubbleFaceConverter: MessageElemConverter() {
override suspend fun convert(
chatType: Int,
peerId: String,
element: MsgElement
): MessageSegment {
val bubbleElement = element.faceBubbleElement
return MessageSegment(
type = "bubble_face",
data = mapOf(
"id" to bubbleElement.yellowFaceInfo.index,
"count" to (bubbleElement.faceCount ?: 1),
)
)
}
}
protected fun unknownChatType(chatType: Int) { protected fun unknownChatType(chatType: Int) {
throw UnsupportedOperationException("Not supported chat type: $chatType") throw UnsupportedOperationException("Not supported chat type: $chatType")
} }

View File

@ -0,0 +1,30 @@
package moe.fuqiuluo.shamrock.remote.action.handlers
import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.qqinterface.servlet.ChatSvc
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import moe.fuqiuluo.shamrock.helper.MessageHelper
import moe.fuqiuluo.shamrock.remote.action.ActionSession
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
import moe.fuqiuluo.symbols.OneBotHandler
@OneBotHandler("set_group_comment_face")
internal object SetGroupCommentFace: IActionHandler() {
override suspend fun internalHandle(session: ActionSession): String {
val groupId = session.getLong("group_id")
val msgId = session.getIntOrNull("msg_id") ?: session.getInt("message_id")
val faceId = session.getInt("face_id")
val isSet = session.getBooleanOrDefault("is_set", true)
return invoke(groupId, msgId, faceId, isSet, session.echo)
}
operator fun invoke(groupId: Long, msgHash: Int, faceIndex: Int, isSet: Boolean, echo: JsonElement = EmptyJsonString): String {
val mapping = MessageHelper.getMsgMappingByHash(msgHash)
?: return error("failed to locate message", echo = echo)
ChatSvc.setGroupMessageCommentFace(groupId, mapping.msgSeq.toULong(), faceIndex.toString(), isSet)
return ok("success", echo = echo)
}
override val requiredParams: Array<String> = arrayOf("group_id", "face_id")
}

View File

@ -1,19 +1,30 @@
package moe.fuqiuluo.shamrock.remote.api package moe.fuqiuluo.shamrock.remote.api
import io.ktor.http.ContentType import io.ktor.http.ContentType
import moe.fuqiuluo.shamrock.helper.LogicException
import io.ktor.server.application.call import io.ktor.server.application.call
import io.ktor.server.response.respondText import io.ktor.server.response.respondText
import io.ktor.server.routing.Routing import io.ktor.server.routing.Routing
import moe.fuqiuluo.shamrock.remote.action.ActionManager
import moe.fuqiuluo.shamrock.remote.action.ActionSession
import moe.fuqiuluo.shamrock.remote.action.handlers.* import moe.fuqiuluo.shamrock.remote.action.handlers.*
import moe.fuqiuluo.shamrock.tools.fetch import moe.fuqiuluo.shamrock.tools.fetchGetOrNull
import moe.fuqiuluo.shamrock.tools.fetchOrNull import moe.fuqiuluo.shamrock.tools.fetchOrNull
import moe.fuqiuluo.shamrock.tools.fetchOrThrow import moe.fuqiuluo.shamrock.tools.fetchOrThrow
import moe.fuqiuluo.shamrock.tools.getOrPost import moe.fuqiuluo.shamrock.tools.getOrPost
fun Routing.troopAction() { fun Routing.troopAction() {
getOrPost("/set_group_comment_face") {
val groupId = fetchOrThrow("group_id").toLong()
val msgId = fetchOrNull("msg_id")?.toIntOrNull() ?: fetchOrThrow("message_id").toInt()
val faceId = fetchOrThrow("face_id").toInt()
val isSet = fetchGetOrNull("is_set") ?: "true"
call.respondText(SetGroupCommentFace(groupId, msgId, faceId, when(isSet) {
"true" -> true
"false" -> false
"1" -> true
"0" -> false
else -> true
}), ContentType.Application.Json)
}
getOrPost("/get_not_joined_group_info") { getOrPost("/get_not_joined_group_info") {
val groupId = fetchOrThrow("group_id") val groupId = fetchOrThrow("group_id")
call.respondText(GetNotJoinedGroupInfo(groupId), ContentType.Application.Json) call.respondText(GetNotJoinedGroupInfo(groupId), ContentType.Application.Json)

View File

@ -16,7 +16,7 @@ import moe.fuqiuluo.shamrock.xposed.ipc.ShamrockIpc
import moe.fuqiuluo.symbols.Process import moe.fuqiuluo.symbols.Process
import moe.fuqiuluo.symbols.XposedHook import moe.fuqiuluo.symbols.XposedHook
@XposedHook(Process.MSF, 0) @XposedHook(Process.MSF, priority = 0)
internal class IpcService: IAction { internal class IpcService: IAction {
override fun invoke(ctx: Context) { override fun invoke(ctx: Context) {
if (!PlatformUtils.isMsfProcess()) return if (!PlatformUtils.isMsfProcess()) return