mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 05:12:17 +00:00
Compare commits
18 Commits
30b48c6677
...
1.0.8
Author | SHA1 | Date | |
---|---|---|---|
fb00e5c1ff | |||
7bfb9b7b61 | |||
c43689822b | |||
7952453137 | |||
2f61f6da00 | |||
db252b6b6c | |||
137c354acc | |||
1c7f6bd034 | |||
649d8771ca | |||
af7b0f732e | |||
12738fd52c | |||
b165e1c0c2 | |||
29c1ad8bc9 | |||
262af4108b | |||
a22dc50f14 | |||
e629981218 | |||
103381c17a | |||
7540ef04bb |
@ -31,7 +31,7 @@
|
||||
|
||||
<provider
|
||||
android:name=".ui.service.internal.MultifunctionalProvider"
|
||||
android:authorities="moe.fuqiuluo.xqbot.provider"
|
||||
android:authorities="moe.fuqiuluo.108.provider"
|
||||
android:exported="true"
|
||||
android:grantUriPermissions="true"
|
||||
tools:ignore="ExportedContentProvider" />
|
||||
|
@ -249,6 +249,11 @@ object ShamrockConfig {
|
||||
return preferences.getBoolean("enable_auto_start", false)
|
||||
}
|
||||
|
||||
fun disableAutoSyncSetting(ctx: Context): Boolean {
|
||||
val preferences = ctx.getSharedPreferences("config", 0)
|
||||
return preferences.getBoolean("disable_auto_sync_setting", false)
|
||||
}
|
||||
|
||||
fun enableAliveReply(ctx: Context): Boolean {
|
||||
val preferences = ctx.getSharedPreferences("config", 0)
|
||||
return preferences.getBoolean("alive_reply", false)
|
||||
@ -264,6 +269,11 @@ object ShamrockConfig {
|
||||
preferences.edit().putBoolean("enable_auto_start", v).apply()
|
||||
}
|
||||
|
||||
fun setDisableAutoSyncSetting(ctx: Context, v: Boolean) {
|
||||
val preferences = ctx.getSharedPreferences("config", 0)
|
||||
preferences.edit().putBoolean("disable_auto_sync_setting", v).apply()
|
||||
}
|
||||
|
||||
fun setAliveReply(ctx: Context, v: Boolean) {
|
||||
val preferences = ctx.getSharedPreferences("config", 0)
|
||||
preferences.edit().putBoolean("alive_reply", v).apply()
|
||||
@ -322,6 +332,7 @@ object ShamrockConfig {
|
||||
"shell" to preferences.getBoolean("shell", false),
|
||||
"alive_reply" to preferences.getBoolean("alive_reply", false),
|
||||
"enable_sync_msg_as_sent_msg" to preferences.getBoolean("enable_sync_msg_as_sent_msg", false),
|
||||
"disable_auto_sync_setting" to preferences.getBoolean("disable_auto_sync_setting", false),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ fun LabFragment() {
|
||||
ActionBox(
|
||||
modifier = Modifier.padding(top = 12.dp),
|
||||
painter = painterResource(id = R.drawable.round_logo_dev_24),
|
||||
title = "实验功能"
|
||||
title = "基础设置"
|
||||
) { color ->
|
||||
Column {
|
||||
Divider(
|
||||
@ -142,6 +142,16 @@ fun LabFragment() {
|
||||
return@Function true
|
||||
}
|
||||
|
||||
Function(
|
||||
title = "禁止Shamrock同步设置",
|
||||
desc = "禁止Shamrock同步设置,防止恢复手动修改后的配置文件。",
|
||||
descColor = color,
|
||||
isSwitch = ShamrockConfig.disableAutoSyncSetting(ctx)
|
||||
) {
|
||||
ShamrockConfig.setDisableAutoSyncSetting(ctx, it)
|
||||
return@Function true
|
||||
}
|
||||
|
||||
kotlin.runCatching {
|
||||
ctx.getSharedPreferences("shared_config", Context.MODE_WORLD_READABLE)
|
||||
}.onSuccess {
|
||||
|
@ -1,7 +1,7 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
@file:Suppress("ArrayInDataClass")
|
||||
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,5 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,5 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
@ -12,4 +12,4 @@ data class WeiyunCommonReq (
|
||||
@ProtoNumber(2009) val addRichMediaReq: WeiyunAddRichMediaReq? = null,
|
||||
@ProtoNumber(2010) val fastUploadResourceReq: WeiyunFastUploadResourceReq? = null,
|
||||
|
||||
)
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,5 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,6 +1,6 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,5 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,5 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,5 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,6 +1,6 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,7 +1,7 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
@file:Suppress("ArrayInDataClass")
|
||||
|
||||
package moe.whitechi73.protobuf.fav
|
||||
package protobuf.fav
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.group_file_common
|
||||
package protobuf.group_file_common
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
405
protobuf/src/main/java/protobuf/guild/GetGuildFeeds.kt
Normal file
405
protobuf/src/main/java/protobuf/guild/GetGuildFeeds.kt
Normal file
@ -0,0 +1,405 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package protobuf.guild
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import protobuf.qweb.QWebExtInfo
|
||||
|
||||
@Serializable
|
||||
data class GetGuildFeedsReq(
|
||||
@ProtoNumber(1) var count: Int,
|
||||
@ProtoNumber(2) var from: Int? = null,
|
||||
@ProtoNumber(3) var feedAttchInfo: ByteArray? = null,
|
||||
@ProtoNumber(4) var guildId: ULong? = null,
|
||||
@ProtoNumber(5) var getType: Int? = null,
|
||||
@ProtoNumber(6) var sortOption: Int? = null,
|
||||
@ProtoNumber(7) var u7: Int? = null,
|
||||
@ProtoNumber(8) var u8: Int? = null,
|
||||
@ProtoNumber(9) var u9: ByteArray? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GetGuildFeedsRsp(
|
||||
@ProtoNumber(1) var vecFeed: List<StFeed>? = null,
|
||||
@ProtoNumber(2) var isFinish: Int = 0,
|
||||
//@ProtoNumber(3) var feedAttchInfo: ByteArray? = null,
|
||||
//@ProtoNumber(4) var traceId: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StFeed(
|
||||
@SerialName("id") @ProtoNumber(1) var id: String,
|
||||
@SerialName("title") @ProtoNumber(2) var title: StRichText,
|
||||
@SerialName("poster") @ProtoNumber(4) var poster: StUser? = null,
|
||||
@SerialName("videos") @ProtoNumber(5) var videos: List<StVideo>? = null,
|
||||
@SerialName("contents") @ProtoNumber(6) var contents: StRichText? = null,
|
||||
@SerialName("create_time") @ProtoNumber(7) var createTime: ULong? = null,
|
||||
@SerialName("comment_count") @ProtoNumber(9) var commentCount: UInt? = null,
|
||||
|
||||
@SerialName("comments") @ProtoNumber(10) var vecComment: List<StComment>? = null,
|
||||
@SerialName("share") @ProtoNumber(11) var share: StShare? = null,
|
||||
@SerialName("visitor_info") @ProtoNumber(12) var visitorInfo: StVisitor? = null,
|
||||
@SerialName("images") @ProtoNumber(13) var images: List<StImage>? = null,
|
||||
@SerialName("poi") @ProtoNumber(14) var poiInfo: StPoiInfoV2? = null,
|
||||
@SerialName("op_mask") @ProtoNumber(17) var opMask: List<Int>? = null,
|
||||
@SerialName("channel_info") @ProtoNumber(21) var channelInfo: StChannelInfo? = null,
|
||||
@SerialName("create_time_ns") @ProtoNumber(22) var createTimeNs: ULong? = null,
|
||||
@SerialName("update_time") @ProtoNumber(28) var updateTime: ULong? = null,
|
||||
@SerialName("total_like") @ProtoNumber(29) var totalLike: StTotalLike? = null,
|
||||
@SerialName("discussion_mum") @ProtoNumber(31) var discussionMum: UInt? = null,
|
||||
@SerialName("feed_type") @ProtoNumber(32) var feedType: UInt? = null,
|
||||
@SerialName("default_background_img") @ProtoNumber(34) var defaultBackgroundImg: String? = null,
|
||||
@SerialName("group_code") @ProtoNumber(35) var groupCode: ULong? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StTotalLike (
|
||||
@SerialName("count") @ProtoNumber(1) var likeCount: UInt? = null,
|
||||
@SerialName("is_clicked") @ProtoNumber(2) var isClicked: UInt? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StPoiInfoV2(
|
||||
@SerialName("poi_id") @ProtoNumber(1) var poiId: String? = null,
|
||||
@SerialName("name") @ProtoNumber(2) var name: String? = null,
|
||||
@SerialName("poi_type") @ProtoNumber(3) var poiType: Int? = null,
|
||||
@SerialName("type_name") @ProtoNumber(4) var typeName: String? = null,
|
||||
@SerialName("address") @ProtoNumber(5) var address: String? = null,
|
||||
@SerialName("district_code") @ProtoNumber(6) var districtCode: Int? = null,
|
||||
@SerialName("gps") @ProtoNumber(7) var gps: StGPSV2? = null,
|
||||
@SerialName("distance") @ProtoNumber(8) var distance: Int? = null,
|
||||
@SerialName("hot_value") @ProtoNumber(9) var hotValue: Int? = null,
|
||||
@SerialName("phone") @ProtoNumber(10) var phone: String? = null,
|
||||
@SerialName("country") @ProtoNumber(11) var country: String? = null,
|
||||
@SerialName("province") @ProtoNumber(12) var province: String? = null,
|
||||
@SerialName("city") @ProtoNumber(13) var city: String? = null,
|
||||
@SerialName("poi_num") @ProtoNumber(14) var poiNum: Int? = null,
|
||||
@SerialName("poi_order_type") @ProtoNumber(15) var poiOrderType: Int? = null,
|
||||
@SerialName("default_name") @ProtoNumber(16) var defaultName: String? = null,
|
||||
@SerialName("district") @ProtoNumber(17) var district: String? = null,
|
||||
@SerialName("dian_ping_id") @ProtoNumber(18) var dianPingId: String? = null,
|
||||
@SerialName("distance_text") @ProtoNumber(19) var distanceText: String? = null,
|
||||
@SerialName("display_name") @ProtoNumber(20) var displayName: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StGPSV2(
|
||||
@SerialName("lat") @ProtoNumber(1) var latitude: Long? = null,
|
||||
@SerialName("lon") @ProtoNumber(2) var longitude: Long? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StShare(
|
||||
@SerialName("title") @ProtoNumber(1) var title: String? = null,
|
||||
@SerialName("desc") @ProtoNumber(2) var desc: String? = null,
|
||||
@SerialName("type") @ProtoNumber(3) var type: UInt? = null,
|
||||
@SerialName("url") @ProtoNumber(4) var url: String? = null,
|
||||
@SerialName("author") @ProtoNumber(5) var author: StUser? = null,
|
||||
@SerialName("poster") @ProtoNumber(6) var poster: StUser? = null,
|
||||
@SerialName("videos") @ProtoNumber(7) var videos: List<StVideo>? = null,
|
||||
@SerialName("short_url") @ProtoNumber(8) var shorturl: String? = null,
|
||||
@SerialName("share_card_info") @ProtoNumber(9) var shareCardInfo: String? = null,
|
||||
//@ProtoNumber(10) var shareQzoneInfo: Any? = null,
|
||||
@SerialName("images") @ProtoNumber(11) var images: List<StImage>? = null,
|
||||
@SerialName("publish_total_user") @ProtoNumber(12) var publishTotalUser: UInt? = null,
|
||||
@SerialName("shared_count") @ProtoNumber(13) var sharedCount: UInt? = null,
|
||||
//@ProtoNumber(14) var channelShareInfo: Any? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StVisitor(
|
||||
@SerialName("view_count")
|
||||
@ProtoNumber(1) val viewCount: UInt? = null,
|
||||
@SerialName("recome_count")
|
||||
@ProtoNumber(3) val recomeCount: UInt? = null,
|
||||
@SerialName("view_desc")
|
||||
@ProtoNumber(4) val viewDesc: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StComment(
|
||||
@SerialName("id") @ProtoNumber(1) var id: String? = null,
|
||||
@SerialName("poster") @ProtoNumber(2) var postUser: StUser? = null,
|
||||
@SerialName("create_time") @ProtoNumber(3) var createTime: ULong? = null,
|
||||
@SerialName("content") @ProtoNumber(4) var content: String? = null,
|
||||
@SerialName("reply_count") @ProtoNumber(5) var replyCount: UInt? = null,
|
||||
@SerialName("replies") @ProtoNumber(6) var vecReply: List<StReply>? = null,
|
||||
//@ProtoNumber(7) var busiData: Any? = null,
|
||||
@SerialName("like_info") @ProtoNumber(8) var likeInfo: StLike? = null,
|
||||
@SerialName("type_flag") @ProtoNumber(9) var typeFlag: UInt? = null,
|
||||
@SerialName("at_uin_list") @ProtoNumber(10) var atUinList: List<String>? = null,
|
||||
@SerialName("type_flag2") @ProtoNumber(11) var typeFlag2: UInt? = null,
|
||||
@SerialName("create_time_ns") @ProtoNumber(12) var createTimeNs: ULong? = null,
|
||||
@SerialName("store_ext_info") @ProtoNumber(13) var storeExtInfo: List<QWebExtInfo>? = null,
|
||||
@SerialName("third_id") @ProtoNumber(14) var thirdId: String? = null,
|
||||
@SerialName("source_type") @ProtoNumber(15) var sourceType: UInt? = null,
|
||||
@SerialName("rich_contents") @ProtoNumber(16) var richContents: StRichText? = null,
|
||||
@SerialName("images") @ProtoNumber(17) var images: List<StImage>? = null,
|
||||
@SerialName("sequence") @ProtoNumber(18) var sequence: ULong? = null,
|
||||
@SerialName("next_page_reply") @ProtoNumber(19) var nextPageReply: Boolean? = null,
|
||||
@SerialName("attach_info") @ProtoNumber(20) var attachInfo: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StReply(
|
||||
@SerialName("id") @ProtoNumber(1) var id: String? = null,
|
||||
@SerialName("poster") @ProtoNumber(2) var postUser: StUser? = null,
|
||||
@SerialName("create_time") @ProtoNumber(3) var createTime: ULong? = null,
|
||||
@SerialName("content") @ProtoNumber(4) var content: String? = null,
|
||||
@SerialName("target") @ProtoNumber(5) var targetUser: StUser? = null,
|
||||
//@ProtoNumber(6) var busiData: ByteArray? = null,
|
||||
@SerialName("like_info") @ProtoNumber(7) var likeInfo: StLike? = null,
|
||||
@SerialName("type_flag") @ProtoNumber(8) var typeFlag: UInt? = null,
|
||||
@SerialName("modify_flag") @ProtoNumber(9) var modifyflag: UInt? = null,
|
||||
@SerialName("at_uin_list") @ProtoNumber(10) var atUinList: List<String>? = null,
|
||||
@SerialName("type_flag2") @ProtoNumber(11) var typeFlag2: UInt? = null,
|
||||
@SerialName("create_time_ns") @ProtoNumber(12) var createTimeNs: ULong? = null,
|
||||
@SerialName("store_ext_info") @ProtoNumber(13) var storeExtInfo: List<QWebExtInfo>? = null,
|
||||
@SerialName("third_id") @ProtoNumber(14) var thirdId: String? = null,
|
||||
@SerialName("target_reply_id") @ProtoNumber(15) var targetReplyID: String? = null,
|
||||
@SerialName("source_type") @ProtoNumber(16) var sourceType: UInt? = null,
|
||||
@SerialName("rich_contents") @ProtoNumber(17) var richContents: StRichText? = null,
|
||||
@SerialName("images") @ProtoNumber(18) var images: List<StImage>? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StLike(
|
||||
@SerialName("id")
|
||||
@ProtoNumber(1) var id: String? = null,
|
||||
@SerialName("count")
|
||||
@ProtoNumber(2) var count: UInt? = null,
|
||||
@SerialName("status")
|
||||
@ProtoNumber(3) var status: UInt? = null,
|
||||
@SerialName("like_uin_list")
|
||||
@ProtoNumber(4) var vecUser: List<StUser>? = null,
|
||||
@SerialName("poster")
|
||||
@ProtoNumber(6) var postUser: StUser? = null,
|
||||
@SerialName("has_liked_count")
|
||||
@ProtoNumber(7) var hasLikedCount: UInt? = null,
|
||||
@SerialName("owner_status")
|
||||
@ProtoNumber(8) var ownerStatus: UInt? = null,
|
||||
@SerialName("jump_url")
|
||||
@ProtoNumber(9) var jumpUrl: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StVideo(
|
||||
@SerialName("file_id") @ProtoNumber(1) var fileId: String? = null,
|
||||
@SerialName("file_size") @ProtoNumber(2) var fileSize: UInt? = null,
|
||||
@SerialName("duration") @ProtoNumber(3) var duration: UInt? = null,
|
||||
@SerialName("width") @ProtoNumber(4) var width: UInt? = null,
|
||||
@SerialName("height") @ProtoNumber(5) var height: UInt? = null,
|
||||
@SerialName("play_url") @ProtoNumber(6) var playUrl: String? = null,
|
||||
@SerialName("trans_status") @ProtoNumber(7) var transStatus: UInt? = null,
|
||||
@SerialName("video_prior") @ProtoNumber(8) var videoPrior: UInt? = null,
|
||||
@SerialName("video_rate") @ProtoNumber(9) var videoRate: UInt? = null,
|
||||
//@ProtoNumber(10) var vecVideoUrl: String? = null,
|
||||
//@ProtoNumber(11) var busiData: Any? = null,
|
||||
@SerialName("approval_status") @ProtoNumber(12) var approvalStatus: UInt? = null,
|
||||
@SerialName("video_source") @ProtoNumber(13) var videoSource: UInt? = null,
|
||||
@SerialName("media_quality_rank") @ProtoNumber(14) var mediaQualityRank: UInt? = null,
|
||||
@SerialName("media_quality_score") @ProtoNumber(15) var mediaQualityScore: Float? = null,
|
||||
@SerialName("md5") @ProtoNumber(16) var videoMD5: String? = null,
|
||||
@SerialName("is_quic") @ProtoNumber(17) var isQuic: UInt? = null,
|
||||
@SerialName("orientation") @ProtoNumber(18) var orientation: Int? = null,
|
||||
@SerialName("cover") @ProtoNumber(19) var cover: StImage? = null,
|
||||
@SerialName("pattern_id") @ProtoNumber(20) var patternId: String? = null,
|
||||
@SerialName("display_index") @ProtoNumber(21) var displayIndex: UInt? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StRichText(
|
||||
@SerialName("contents") @ProtoNumber(1) var contents: List<StRichTextContent>? = null,
|
||||
@SerialName("images") @ProtoNumber(2) var images: List<StImage>? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StRichTextContent(
|
||||
@SerialName("type") @ProtoNumber(1) var type: Int? = null,
|
||||
@SerialName("pattern_id") @ProtoNumber(2) var patternId: String? = null,
|
||||
@SerialName("text") @ProtoNumber(3) var textContent: StRichTextTextContent? = null,
|
||||
@SerialName("at") @ProtoNumber(4) var atContent: StRichTextAtContent? = null,
|
||||
@SerialName("url") @ProtoNumber(5) var urlContent: StRichTextURLContent? = null,
|
||||
@SerialName("emoji") @ProtoNumber(6) var emojiContent: StRichTextEmojiContent? = null,
|
||||
@SerialName("channel") @ProtoNumber(7) var channelContent: StRichTextChannelContent? = null,
|
||||
@SerialName("guild") @ProtoNumber(8) var guildContent: StRichTextGuildContent? = null,
|
||||
@SerialName("icon") @ProtoNumber(9) var iconContent: StRichTextIconContent? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StRichTextIconContent(
|
||||
@SerialName("url") @ProtoNumber(1) val url: String? = null
|
||||
)
|
||||
@Serializable
|
||||
data class StRichTextGuildContent(
|
||||
@SerialName("channel_info") @ProtoNumber(1) val channelInfo: StChannelInfo? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StRichTextChannelContent(
|
||||
@SerialName("channel_info") @ProtoNumber(1) val channelInfo: StChannelInfo? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StChannelInfo(
|
||||
//@SerialName("sign") @ProtoNumber(1) var sign: String? = null,
|
||||
@SerialName("name")
|
||||
@ProtoNumber(2) var name: String? = null,
|
||||
@SerialName("icon_url")
|
||||
@ProtoNumber(3) var iconUrl: String? = null,
|
||||
@SerialName("type")
|
||||
@ProtoNumber(4) var privateType: Int? = null,
|
||||
@SerialName("guild_name")
|
||||
@ProtoNumber(5) var guildName: String? = null,
|
||||
@SerialName("hot_icon")
|
||||
@ProtoNumber(6) var hotIcon: String? = null,
|
||||
@SerialName("hot_index")
|
||||
@ProtoNumber(7) var hotIndex: UInt? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StRichTextEmojiContent(
|
||||
@ProtoNumber(1) var id: String? = null,
|
||||
@ProtoNumber(2) var type: String? = null,
|
||||
@ProtoNumber(3) var name: String? = null,
|
||||
@ProtoNumber(4) var url: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StRichTextURLContent(
|
||||
@ProtoNumber(1) var url: String? = null,
|
||||
@SerialName("display") @ProtoNumber(2) var displayText: String? = null,
|
||||
@ProtoNumber(3) var type: Int? = null,
|
||||
@SerialName("play_url") @ProtoNumber(4) var playUrl: String? = null,
|
||||
@SerialName("platform") @ProtoNumber(5) var thirdPlatform: ThirdPlatform? = null,
|
||||
@SerialName("third_video_info") @ProtoNumber(6) var thirdVideoInfo: CommThirdVideoInfo? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CommThirdVideoInfo(
|
||||
@SerialName("cover") @ProtoNumber(1) val cover: String? = null,
|
||||
@SerialName("duration") @ProtoNumber(2) val duration: ULong? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ThirdPlatform(
|
||||
@ProtoNumber(1) var icon: String? = null,
|
||||
@ProtoNumber(2) var name: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StRichTextTextContent(
|
||||
@ProtoNumber(1) var text: String? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StRichTextAtContent(
|
||||
@ProtoNumber(1) var type: Int? = null,
|
||||
@SerialName("guild_info") @ProtoNumber(2) var guildInfo: GuildInfo? = null,
|
||||
@SerialName("role_info") @ProtoNumber(3) var roleGroupId: RoleGroupInfo? = null,
|
||||
@ProtoNumber(4) var user: StUser? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StUser(
|
||||
@ProtoNumber(1) var id: String? = null,
|
||||
@ProtoNumber(2) var nick: String? = null,
|
||||
@ProtoNumber(3) var icon: StIconInfo? = null,
|
||||
@ProtoNumber(4) var desc: String? = null,
|
||||
@SerialName("follow_state") @ProtoNumber(5) var followState: UInt? = null,
|
||||
@ProtoNumber(6) var type: UInt? = null,
|
||||
@ProtoNumber(7) var sex: UInt? = null,
|
||||
@ProtoNumber(8) var birthday: ULong? = null,
|
||||
@ProtoNumber(9) var school: String? = null,
|
||||
@ProtoNumber(11) var location: String? = null,
|
||||
//@ProtoNumber(12) var busiData: ByteArray? = null,
|
||||
@SerialName("frd") @ProtoNumber(13) var frdState: UInt? = null,
|
||||
@SerialName("relation_state") @ProtoNumber(14) var relationState: UInt? = null,
|
||||
@SerialName("black_state") @ProtoNumber(15) var blackState: UInt? = null,
|
||||
@ProtoNumber(16) var medal: StTagMedalInfo? = null,
|
||||
@ProtoNumber(17) var constellation: Int? = null,
|
||||
@SerialName("jump_url") @ProtoNumber(18) var jumpUrl: String? = null,
|
||||
@SerialName("location_code") @ProtoNumber(19) var locationCode: String? = null,
|
||||
@SerialName("third_id") @ProtoNumber(20) var thirdId: String? = null,
|
||||
@ProtoNumber(21) var company: String? = null,
|
||||
@SerialName("certification_desc") @ProtoNumber(22) var certificationDesc: String? = null,
|
||||
@SerialName("desc_type") @ProtoNumber(23) var descType: UInt? = null,
|
||||
//@ProtoNumber(24) var channelUserInfo: Any? = null,
|
||||
//@SerialName("login_id") @ProtoNumber(25) var loginId: String? = null,
|
||||
@ProtoNumber(26) var uin: ULong? = null,
|
||||
@SerialName("nick_flag") @ProtoNumber(27) var nickFlag: UInt? = null,
|
||||
@SerialName("manage_tag") @ProtoNumber(28) var manageTag: CustomManageTag? = null,
|
||||
//@SerialName("personal_medal") @ProtoNumber(29) var personalMedal: PersonalMedal? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PersonalMedal(
|
||||
@SerialName("start") @ProtoNumber(1) val startTime: ULong? = null,
|
||||
@SerialName("end") @ProtoNumber(2) val endTime: ULong? = null,
|
||||
@ProtoNumber(3) var url: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StTagMedalInfo(
|
||||
@SerialName("id") @ProtoNumber(1) val tagId: ULong? = null,
|
||||
@SerialName("name") @ProtoNumber(2) val tagName: String? = null,
|
||||
@ProtoNumber(3) val rank: ULong? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CustomManageTag(
|
||||
@ProtoNumber(3) val color: UInt? = null,
|
||||
@SerialName("name") @ProtoNumber(2) val tagName: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StIconInfo(
|
||||
//@SerialName("url_40") @ProtoNumber(1) var iconUrl40: String? = null,
|
||||
//@SerialName("url_100") @ProtoNumber(2) var iconUrl100: String? = null,
|
||||
//@SerialName("url_140") @ProtoNumber(3) var iconUrl140: String? = null,
|
||||
//@SerialName("url_640") @ProtoNumber(4) var iconUrl640: String? = null,
|
||||
@SerialName("url") @ProtoNumber(5) var iconUrl: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class RoleGroupInfo(
|
||||
@SerialName("role") @ProtoNumber(1) var roleId: ULong? = null,
|
||||
@ProtoNumber(2) var name: String? = null,
|
||||
@ProtoNumber(3) var color: ULong? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GuildInfo(
|
||||
@SerialName("guild_id") @ProtoNumber(1) var guildId: ULong? = null,
|
||||
@ProtoNumber(2) var name: String? = null,
|
||||
@SerialName("join_time") @ProtoNumber(3) var joinTime: ULong? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StImage(
|
||||
@ProtoNumber(1) var width: UInt? = null,
|
||||
@ProtoNumber(2) var height: UInt? = null,
|
||||
@ProtoNumber(3) var picUrl: String? = null,
|
||||
@SerialName("image_urls") @ProtoNumber(4) var vecImageUrl: List<StImageUrl>? = null,
|
||||
@SerialName("id") @ProtoNumber(5) var picId: String? = null,
|
||||
//@ProtoNumber(6) var busiData: Any? = null,
|
||||
@SerialName("md5") @ProtoNumber(7) var imageMD5: String? = null,
|
||||
@SerialName("layer_pic_url") @ProtoNumber(8) var layerPicUrl: String? = null,
|
||||
@SerialName("pattern_id") @ProtoNumber(9) var patternId: String? = null,
|
||||
@SerialName("display_index") @ProtoNumber(10) var displayIndex: Int? = null,
|
||||
@SerialName("size") @ProtoNumber(11) var origSize: UInt? = null,
|
||||
@SerialName("is_original") @ProtoNumber(12) var isOrig: Boolean? = null,
|
||||
@SerialName("is_gif") @ProtoNumber(13) var isGif: Boolean? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StImageUrl(
|
||||
@SerialName("level_type") @ProtoNumber(1) var levelType: UInt? = null,
|
||||
@ProtoNumber(2) var url: String? = null,
|
||||
@ProtoNumber(3) var width: UInt? = null,
|
||||
@ProtoNumber(4) var height: UInt? = null,
|
||||
//@ProtoNumber(5) var busiData: Any? = null,
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.message
|
||||
package protobuf.message
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -1,7 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.whitechi73.protobuf.oidb
|
||||
package protobuf.oidb
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
@ -11,4 +9,4 @@ data class TrpcOidb(
|
||||
@ProtoNumber(2) val service: Int = Int.MIN_VALUE,
|
||||
@ProtoNumber(4) val buffer: ByteArray,
|
||||
@ProtoNumber(12) val flag: Int = Int.MIN_VALUE,
|
||||
)
|
||||
)
|
@ -1,11 +1,11 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package moe.whitechi73.protobuf.oidb.cmd0x6d7
|
||||
package protobuf.oidb.cmd0x6d7
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import moe.whitechi73.protobuf.group_file_common.FolderInfo
|
||||
import protobuf.group_file_common.FolderInfo
|
||||
|
||||
@Serializable
|
||||
data class Oidb0x6d7ReqBody(
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.oidb.cmd0x9082
|
||||
package protobuf.oidb.cmd0x9082
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.oidb.cmd0xf16
|
||||
package protobuf.oidb.cmd0xf16
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
117
protobuf/src/main/java/protobuf/oidb/cmd0xf88/Oidb0xf88.kt
Normal file
117
protobuf/src/main/java/protobuf/oidb/cmd0xf88/Oidb0xf88.kt
Normal file
@ -0,0 +1,117 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package protobuf.oidb.cmd0xf88
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf88Req(
|
||||
@ProtoNumber(1) val filter: GProFilter,
|
||||
@ProtoNumber(2) val memberId: ULong,
|
||||
@ProtoNumber(3) val tinyId: ULong,
|
||||
@ProtoNumber(4) val guildId: ULong,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf88Rsp(
|
||||
@ProtoNumber(1) val userInfo: GProUserInfo?
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GProUserInfo(
|
||||
@ProtoNumber(1) var memberId: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(2) var memberTinyid: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(3) var nickName: String? = null,
|
||||
@ProtoNumber(4) var gender: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(5) var allow: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(6) var url: String? = null,
|
||||
@ProtoNumber(7) var birthday: String? = null,
|
||||
@ProtoNumber(8) var fullBirthday: String? = null,
|
||||
@ProtoNumber(9) var fullAge: String? = null,
|
||||
@ProtoNumber(10) var country: String? = null,
|
||||
@ProtoNumber(11) var province: String? = null,
|
||||
@ProtoNumber(12) var city: String? = null,
|
||||
@ProtoNumber(13) var cityId: String? = null,
|
||||
@ProtoNumber(14) var cityZoneId: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(15) var msgHeadInfo: GProHeadInfo? = null,
|
||||
@ProtoNumber(16) var joinTime: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(17) var memberRole: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(18) var memberType: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(19) var beAdminTime: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(20) var memberName: String? = null,
|
||||
//@ProtoNumber(21) var clientPresence: Any? = null,
|
||||
//@ProtoNumber(22) var client_archive: ArrayList<>? = null,
|
||||
//@ProtoNumber(23) var bind_client_account: ArrayList<>? = null,
|
||||
@ProtoNumber(24) var hasMoreArchive: Boolean = false,
|
||||
//@ProtoNumber(25) var firstArchiveArkData: Any? = null,
|
||||
@ProtoNumber(26) var directMsgBlackFlag: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(27) var setGroupProProfile: Boolean = false,
|
||||
@ProtoNumber(28) var joinGroupProTimestamp: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(29) var shutUpExpireTime: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(30) var avatarMeta: ByteArray? = null,
|
||||
@ProtoNumber(31) var memberNameFlag: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(32) var faceAuthStatus: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(33) var verifyUrl: String? = null,
|
||||
@ProtoNumber(34) var constellation: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(35) var personalSign: ByteArray? = null,
|
||||
//@ProtoNumber(36) var voice_live_info: Any? = null,
|
||||
@ProtoNumber(37) var avatarFlag: UInt = UInt.MIN_VALUE,
|
||||
//@ProtoNumber(38) var isQQFriend: Any? = null,
|
||||
//@ProtoNumber(39) var openid: Any? = null,
|
||||
//@ProtoNumber(40) var personalSignTemplate: Any? = null,
|
||||
//@ProtoNumber(41) var showVoiceLiveStatusSwitch: Any? = null,
|
||||
@ProtoNumber(99) var isMember: UInt = UInt.MIN_VALUE,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GProHeadInfo(
|
||||
@ProtoNumber(1) var timestamp: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(2) var faceFlag: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(3) var baseUrl: String? = null,
|
||||
@ProtoNumber(4) var type: UInt = UInt.MIN_VALUE
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GProFilter(
|
||||
@ProtoNumber(3) val nickName: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(4) val gender: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(5) val allow: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(6) val url: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(7) val birthday: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(8) val fullBirthday: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(9) val fullAge: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(10) val country: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(11) val province: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(12) val city: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(13) val cityId: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(14) val cityZoneId: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(15) val headInfo: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(16) val joinTime: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(17) val memberRole: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(18) val memberType: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(19) val beAdminTime: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(20) val memberName: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(21) val clientPresence: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(22) val clientArchive: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(23) val bindClientAccount: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(24) val hasMoreArchive: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(25) val firstArchiveBaseInfo: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(26) val directMsgBlackFlag: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(27) val joinGroupProTimestamp: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(28) val shutupExpireTime: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(29) val faceAuthStatus: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(30) val constellation: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(31) val personalSign: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(32) val voiceLiveInfo: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(33) val isQQFriend: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(34) val personalSignTemplate: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(35) val showVoiceLiveStatusSwitch: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(36) val openid: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(37) val isMember: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(99) val needGroupProProfile: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(100) val avatarMeta: UInt = UInt.MIN_VALUE,
|
||||
) {
|
||||
|
||||
}
|
61
protobuf/src/main/java/protobuf/oidb/cmd0xfc2/Oidb0xfc2.kt
Normal file
61
protobuf/src/main/java/protobuf/oidb/cmd0xfc2/Oidb0xfc2.kt
Normal file
@ -0,0 +1,61 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package protobuf.oidb.cmd0xfc2
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xfc2ReqBody(
|
||||
@ProtoNumber(1) var msgCmd: Int? = null,
|
||||
@ProtoNumber(3) var msgBusType: Int? = null,
|
||||
@ProtoNumber(4) var msgChannelInfo: Oidb0xfc2ChannelInfo? = null,
|
||||
@ProtoNumber(5) var msgTerminalType: Int? = null,
|
||||
//@ProtoNumber(100) var msg_apply_upload_req: Any? = null,
|
||||
//@ProtoNumber(200) var msg_upload_completed_req: Any? = null,
|
||||
@ProtoNumber(300) var msgApplyDownloadReq: Oidb0xfc2MsgApplyDownloadReq? = null,
|
||||
//@ProtoNumber(400) var msg_apply_preview_req: Any? = null,
|
||||
//@ProtoNumber(500) var msg_apply_security_strike_req: Any? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xfc2RspBody(
|
||||
@ProtoNumber(1) var msgCmd: Int? = null,
|
||||
@ProtoNumber(5) var msgBusType: Int? = null,
|
||||
//@ProtoNumber(110) var msg_apply_upload_rsp: Any? = null,
|
||||
//@ProtoNumber(210) var msg_upload_completed_rsp: Any? = null,
|
||||
@ProtoNumber(310) var msgApplyDownloadRsp: Oidb0xfc2MsgApplyDownloadRsp? = null,
|
||||
//@ProtoNumber(410) var msg_apply_preview_rsp: Any? = null,
|
||||
//@ProtoNumber(510) var msg_apply_security_strike_rsp: Any? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xfc2MsgApplyDownloadRsp(
|
||||
@ProtoNumber(1) var msgDownloadInfo: Oidb0xfc2MsgDownloadInfo? = null,
|
||||
//@ProtoNumber(2) var msgFileInfo: Any? = null,
|
||||
//@ProtoNumber(3) var msgChacha20Param: Any? = null,
|
||||
//@ProtoNumber(4) var useEncrypt: UInt = UInt.MIN_VALUE,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xfc2MsgDownloadInfo(
|
||||
@ProtoNumber(1) var downloadKey: ByteArray? = null,
|
||||
//@ProtoNumber(2) var msg_out_addr: Any? = null,
|
||||
//@ProtoNumber(3) var msg_inner_addr: Any? = null,
|
||||
//@ProtoNumber(4) var msg_out_addr_ipv6: Any? = null,
|
||||
@ProtoNumber(5) var downloadDomain: String? = null,
|
||||
@ProtoNumber(6) var downloadUrl: String? = null,
|
||||
//@ProtoNumber(7) var str_cookie: Any? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xfc2MsgApplyDownloadReq(
|
||||
@ProtoNumber(1) val fieldId: String,
|
||||
@ProtoNumber(2) val supportEncrypt: Int,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xfc2ChannelInfo(
|
||||
@ProtoNumber(3) val guildId: ULong,
|
||||
@ProtoNumber(4) val channelId: ULong,
|
||||
)
|
99
protobuf/src/main/java/protobuf/oidb/cmx0xf57/Oidb0xf57.kt
Normal file
99
protobuf/src/main/java/protobuf/oidb/cmx0xf57/Oidb0xf57.kt
Normal file
@ -0,0 +1,99 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package protobuf.oidb.cmx0xf57
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf57Req(
|
||||
@ProtoNumber(1) val filter: Oidb0xf57Filter,
|
||||
@ProtoNumber(2) val guildInfo: Oidb0xf57GuildInfo,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf57Rsp(
|
||||
@ProtoNumber(1) val metaInfo: Oidb0xf57MetaInfo,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf57MetaInfo(
|
||||
@ProtoNumber(3) val guildId: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(4) val meta: Oidb0xf57Meta? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf57Meta(
|
||||
@ProtoNumber(2) val guildCode: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(4) val createTime: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(5) val maxMemberCount: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(6) val memberCount: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(8) val name: String? = null,
|
||||
@ProtoNumber(11) val robotMaxNum: Int = Int.MIN_VALUE,
|
||||
@ProtoNumber(12) val adminMaxNum: Int = Int.MIN_VALUE,
|
||||
@ProtoNumber(13) val profile: String? = null,
|
||||
@ProtoNumber(14) val avatarSeq: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(18) val ownerId: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(19) val coverSeq: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(20) val clientId: Int = Int.MIN_VALUE,
|
||||
@ProtoNumber(27) val displayId: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf57GuildInfo(
|
||||
@ProtoNumber(1) val guildId: ULong = ULong.MIN_VALUE
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf57Filter(
|
||||
@ProtoNumber(1) val u1: Oidb0xf57U1,
|
||||
@ProtoNumber(2) val u2: Oidb0xf57U2,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf57U1(
|
||||
@ProtoNumber(2) val u1: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(4) val u2: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(5) val u3: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(6) val u4: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(7) val u5: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(8) val u6: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(11) val u7: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(12) val u8: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(13) val u9: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(14) val u10: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(45) val u11: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(18) val u12: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(19) val u13: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(20) val u14: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(22) val u15: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(23) val u16: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(5002) val u17: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(5003) val u18: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(5004) val u19: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(5005) val u20: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(5006) val u23: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(10007) val u21: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(15) val u22: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(30001) val u24: UInt = UInt.MIN_VALUE,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Oidb0xf57U2(
|
||||
@ProtoNumber(3) val u1: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(4) val u2: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(6) val u3: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(11) val u4: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(14) val u5: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(15) val u6: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(16) val u7: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(17) val u8: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(32) val u9: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(31) val u10: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(29) val u11: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(26) val u12: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(23) val u13: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(22) val u14: UInt = UInt.MIN_VALUE,
|
||||
@ProtoNumber(18) val u15: UInt = UInt.MIN_VALUE,
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,4 +1,4 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
@ -1,8 +1,8 @@
|
||||
package moe.whitechi73.protobuf.push
|
||||
package protobuf.push
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import moe.whitechi73.protobuf.message.MessageBody
|
||||
import protobuf.message.MessageBody
|
||||
|
||||
@Serializable
|
||||
data class MessagePush(
|
37
protobuf/src/main/java/protobuf/qweb/QWeb.kt
Normal file
37
protobuf/src/main/java/protobuf/qweb/QWeb.kt
Normal file
@ -0,0 +1,37 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package protobuf.qweb
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
@Serializable
|
||||
data class QWebReq(
|
||||
@ProtoNumber(1) val seq: Int = 0,
|
||||
@ProtoNumber(2) val qua: String = "",
|
||||
@ProtoNumber(3) val deviceInfo: String = "",
|
||||
@ProtoNumber(4) val buffer: ByteArray? = null,
|
||||
@ProtoNumber(5) val traceId: String = "",
|
||||
@ProtoNumber(6) val module: String = "",
|
||||
@ProtoNumber(7) var cmdname: String? = null,
|
||||
//@ProtoNumber(8) var loginSig: Any? = null,
|
||||
//@ProtoNumber(9) var Crypto: Any? = null,
|
||||
@ProtoNumber(10) var extinfo: List<QWebExtInfo>? = null,
|
||||
//@ProtoNumber(11) var contentType: Any? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class QWebExtInfo(
|
||||
@ProtoNumber(1) val key: String,
|
||||
@ProtoNumber(2) val value: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class QWebRsp(
|
||||
@ProtoNumber(1) var seq: Int? = null,
|
||||
//@ProtoNumber(2) var retCode: Int? = null,
|
||||
//@ProtoNumber(3) var errMsg: String? = null,
|
||||
@ProtoNumber(4) var buffer: ByteArray? = null,
|
||||
//@ProtoNumber(5) var Extinfo: List<QWebExtInfo>? = null,
|
||||
)
|
@ -440,7 +440,7 @@ public interface IGPSService extends IRuntimeService {
|
||||
void getChannelInvisibleRoleList(String str, String str2, @NonNull com.tencent.mobileqq.qqguildsdk.data.type.e eVar);*/
|
||||
|
||||
@NonNull
|
||||
List<IGProChannelInfo> getChannelList(String str);
|
||||
List<IGProChannelInfo> getChannelList(String str);
|
||||
|
||||
/*
|
||||
@Nullable
|
||||
@ -502,7 +502,7 @@ public interface IGPSService extends IRuntimeService {
|
||||
|
||||
String getGuildIdOf(String str);
|
||||
|
||||
@Nullable
|
||||
@Nullable
|
||||
IGProGuildInfo getGuildInfo(String str);
|
||||
|
||||
//void getGuildLableInfo(com.tencent.mobileqq.qqguildsdk.data.genc.ak akVar, com.tencent.mobileqq.i2.a.a.bi biVar);
|
||||
@ -712,7 +712,7 @@ public interface IGPSService extends IRuntimeService {
|
||||
int getShareButtonFromCache(long j2, long j3, boolean z);
|
||||
|
||||
@Nullable
|
||||
IGProSimpleProfile getSimpleProfile(String str, String str2, int i2);
|
||||
IGProSimpleProfile getSimpleProfile(String guildId, String tinyId, int appId);
|
||||
|
||||
List<IGProGuildInfo> getSortedGuildList();
|
||||
|
||||
@ -819,7 +819,7 @@ public interface IGPSService extends IRuntimeService {
|
||||
|
||||
void refreshGuildList(boolean z);
|
||||
|
||||
void refreshGuildUserProfileInfo(String str, String str2);
|
||||
void refreshGuildUserProfileInfo(String guildId, String userTinyId);
|
||||
|
||||
void refreshPollingData();
|
||||
|
||||
|
@ -31,12 +31,8 @@ public final class GProRoleCreateInfo {
|
||||
return "GProRoleCreateInfo{name=" + this.name + ",color=" + this.color + ",bHoist=" + this.bHoist + ",rolePermissions=" + this.rolePermissions + ",}";
|
||||
}
|
||||
|
||||
public GProRoleCreateInfo(String str, long j2, boolean z, GProRolePermission gProRolePermission) {
|
||||
public GProRoleCreateInfo(String name, long color, boolean hoist, GProRolePermission permissions) {
|
||||
this.name = "";
|
||||
this.rolePermissions = new GProRolePermission();
|
||||
this.name = str;
|
||||
this.color = j2;
|
||||
this.bHoist = z;
|
||||
this.rolePermissions = gProRolePermission;
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,6 @@ public final class GProRoleMemberList {
|
||||
}
|
||||
|
||||
public GProRoleMemberList(GProGuildRole gProGuildRole, ArrayList<GProUser> arrayList) {
|
||||
this.role = new GProGuildRole();
|
||||
this.members = new ArrayList<>();
|
||||
this.role = gProGuildRole;
|
||||
this.members = arrayList;
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
public interface IGProCreateRoleCallback {
|
||||
void onCreateRoleResult(int code, String msg, GProSecurityResult result, GProGuildRole role);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface IGProFetchChannelInvisibleRoleListCallback {
|
||||
void onFetchChannelInvisibleRoleList(int code, String reason, ArrayList<GProGuildRole> roles);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface IGProFetchChannelLiveableRoleListCallback {
|
||||
void onFetchChannelLiveableRoleList(int code, String reason, int seq, ArrayList<GProGuildRole> roles);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
public interface IGProFetchGuildInfoCallback {
|
||||
void onFetchGuildInfo(int i2, String str, GProGuild gProGuild);
|
||||
void onFetchGuildInfo(int code, String reason, GProGuild gProGuild);
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface IGProFetchMemberListWithRoleCallback {
|
||||
void onFetchMemberListWithRoleCallback(int result, String reason, boolean finish, long nextIndex, long nextRoleIdIndex, boolean isSmallGuild, int seq, ArrayList<GProRoleMemberList> roleList);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface IGProFetchMemberRolesCallback {
|
||||
void onFetchMemberRolesCallback(int code, String reason, ArrayList<GProGuildRole> roles);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface IGProFetchRoleListPermissionCallback {
|
||||
void onFetchRoleListPermissionCallback(int code, String msg, ArrayList<GProGuildRole> roles, ArrayList<GProGuildRole> lvRoles, ArrayList<Long> myRoles, long unused);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface IGProFetchRolePermissionCallback {
|
||||
void onFetchRolePermissionCallback(int code, String msg, GProGuildRole role, GProRolePermission permission, ArrayList<GProRolePermissionDesc> permissionDescs, ArrayList<GProRolePermissionCategory> permissionCategories);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface IGProFetchTopFeedsCallback {
|
||||
void onResult(int code, String msg, ArrayList<GProTopFeed> feeds);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface IGProGetUserInfoCallback {
|
||||
void onGetUserInfo(int code, String reason, ArrayList<GProUser> userList, ArrayList<Long> tinyIdList);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
public interface IGProResultCallback {
|
||||
void onResult(int code, String msg, GProSecurityResult result);
|
||||
}
|
@ -23,15 +23,54 @@ public interface IKernelGuildService {
|
||||
|
||||
void fetchAddGuildInfo(int appId, long guildId, IGProAddGuildInfoCallBack iGProAddGuildInfoCallBack);
|
||||
|
||||
void fetchGuildInfo(long j2, int i2, IGProFetchGuildInfoCallback iGProFetchGuildInfoCallback);
|
||||
void fetchGuildInfo(long guildId, int seq, IGProFetchGuildInfoCallback iGProFetchGuildInfoCallback);
|
||||
|
||||
//void fetchGuildInfoByAppIdentity(GProGuildIdentity gProGuildIdentity, String str, String str2, IGProFetchGuildInfoByAppIdentityCallback iGProFetchGuildInfoByAppIdentityCallback);
|
||||
|
||||
void fetchGuildInfoForGuest(long j2, int i2, IGProFetchGuildInfoCallback iGProFetchGuildInfoCallback);
|
||||
void fetchGuildInfoForGuest(long guildId, int seq, IGProFetchGuildInfoCallback cb);
|
||||
|
||||
GProGuild getGuildInfoFromCache(long j2);
|
||||
//void fetchGuestGuildInfoWithChannelList(String guildId, String str2, int i2, int seq, String str3,
|
||||
// IGProFetchGuestGuildInfoWithChannelListCallback iGProFetchGuestGuildInfoWithChannelListCallback);
|
||||
|
||||
void refreshGuildInfo(long guildId, boolean force, int appId);
|
||||
GProGuild getGuildInfoFromCache(long guildId);
|
||||
|
||||
// 第一次请求: startIndex = 0 , roleIdIndex = 2
|
||||
void fetchMemberListWithRole(long guildId, long channelId, long startIndex, long roleIndex, int count, int seq, IGProFetchMemberListWithRoleCallback cb);
|
||||
|
||||
void refreshGuildInfo(long guildId, boolean force, int seq);
|
||||
|
||||
void refreshGuildInfoOnly(long j2, boolean z, int i2);
|
||||
|
||||
void refreshGuildUserProfileInfo(long guildId, long tinyId, int seq);
|
||||
|
||||
void fetchUserInfo(long guildId, long channelId, ArrayList<Long> tinyIdList, int seq, IGProGetUserInfoCallback cb);
|
||||
|
||||
@Deprecated(since = "QQ新版本不支持创建话题子频道")
|
||||
void fetchTopFeeds(long guildId, long channelId, IGProFetchTopFeedsCallback cb);
|
||||
|
||||
void fetchChannelInvisibleRoleList(long guildId, long channelId, IGProFetchChannelInvisibleRoleListCallback cb);
|
||||
|
||||
void fetchChannelLiveableRoleList(long guildId, long channelId, IGProFetchChannelLiveableRoleListCallback cb);
|
||||
|
||||
void fetchMemberRoles(long guildId, long channelId, long tinyId, int seq, IGProFetchMemberRolesCallback cb);
|
||||
|
||||
void fetchRoleListWithPermission(long guildId, int seq, IGProFetchRoleListPermissionCallback cb);
|
||||
|
||||
void fetchRoleWithPermission(long guildId, long roleId, int seq, IGProFetchRolePermissionCallback cb);
|
||||
|
||||
GProSimpleProfile getSimpleProfile(long guildId, long tinyId, int seq);
|
||||
|
||||
GProFaceAuthInfo getFaceAuthInfo();
|
||||
|
||||
String getGuildUserAvatarUrl(long guildId, long tinyId, int seq);
|
||||
|
||||
String getGuildUserNickname(long guildId);
|
||||
|
||||
void deleteRole(long guild, long role, IGProResultCallback cb);
|
||||
|
||||
void setMemberRoles(long guild, long u1, long u2, long tinyId, ArrayList<Long> addRoles, ArrayList<Long> removeRoles, IGProResultCallback cb);
|
||||
|
||||
void setRoleInfo(long guild, long role, GProRoleCreateInfo info, IGProResultCallback cb);
|
||||
|
||||
void createRole(long guildId, GProRoleCreateInfo info, ArrayList<Long> initialUsers, IGProCreateRoleCallback cb);
|
||||
}
|
||||
|
@ -138,6 +138,12 @@ char * __cdecl my_strstr(const char *lhs, const char *rhs) {
|
||||
}
|
||||
|
||||
int fake_memcmp(const void* __lhs, const void* __rhs, size_t __n) {
|
||||
if (__lhs == nullptr || __rhs == nullptr) {
|
||||
if (__n != 0) {
|
||||
LOGI("[Shamrock] undefined behaviour in fake_memcmp");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (my_strstr((const char*) __rhs, "shamrock") && my_strstr((const char*) __lhs, "shamrock")) {
|
||||
if (backup_memcmp(__lhs, __rhs, __n) == 0) {
|
||||
// 底层广播判断
|
||||
|
@ -7,6 +7,10 @@ import com.tencent.mobileqq.app.QQAppInterface
|
||||
import com.tencent.mobileqq.msf.core.MsfCore
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro
|
||||
import com.tencent.qphone.base.remote.ToServiceMsg
|
||||
import io.ktor.utils.io.core.BytePacketBuilder
|
||||
import io.ktor.utils.io.core.readBytes
|
||||
import io.ktor.utils.io.core.writeFully
|
||||
import io.ktor.utils.io.core.writeInt
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -15,11 +19,13 @@ import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.internal.DynamicReceiver
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.internal.IPCRequest
|
||||
import moe.whitechi73.protobuf.oidb.TrpcOidb
|
||||
import protobuf.oidb.TrpcOidb
|
||||
import mqq.app.MobileQQ
|
||||
import tencent.im.oidb.oidb_sso
|
||||
import kotlin.coroutines.resume
|
||||
@ -38,7 +44,7 @@ internal abstract class BaseSvc {
|
||||
|
||||
suspend fun sendOidbAW(cmd: String, cmdId: Int, serviceId: Int, data: ByteArray, trpc: Boolean = false, timeout: Long = 5000L): ByteArray? {
|
||||
val seq = MsfCore.getNextSeq()
|
||||
return withTimeoutOrNull(timeout) {
|
||||
val buffer = withTimeoutOrNull(timeout) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
||||
@ -53,11 +59,21 @@ internal abstract class BaseSvc {
|
||||
if (it == null)
|
||||
DynamicReceiver.unregister(seq)
|
||||
}?.copyOf()
|
||||
try {
|
||||
if (buffer != null && buffer.size >= 5 && buffer[4] == 120.toByte()) {
|
||||
val builder = BytePacketBuilder()
|
||||
val deBuffer = DeflateTools.uncompress(buffer.slice(4))
|
||||
builder.writeInt(deBuffer.size)
|
||||
builder.writeFully(deBuffer)
|
||||
return builder.build().readBytes()
|
||||
}
|
||||
} catch (_: Exception) { }
|
||||
return buffer
|
||||
}
|
||||
|
||||
suspend fun sendBufferAW(cmd: String, isPb: Boolean, data: ByteArray, timeout: Long = 5000L): ByteArray? {
|
||||
val seq = MsfCore.getNextSeq()
|
||||
return withTimeoutOrNull<ByteArray?>(timeout) {
|
||||
val buffer = withTimeoutOrNull<ByteArray?>(timeout) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
||||
@ -71,6 +87,16 @@ internal abstract class BaseSvc {
|
||||
if (it == null)
|
||||
DynamicReceiver.unregister(seq)
|
||||
}?.copyOf()
|
||||
try {
|
||||
if (buffer != null && buffer.size >= 5 && buffer[4] == 120.toByte()) {
|
||||
val builder = BytePacketBuilder()
|
||||
val deBuffer = DeflateTools.uncompress(buffer.slice(4))
|
||||
builder.writeInt(deBuffer.size)
|
||||
builder.writeFully(deBuffer)
|
||||
return builder.build().readBytes()
|
||||
}
|
||||
} catch (_: Exception) { }
|
||||
return buffer
|
||||
}
|
||||
|
||||
fun sendOidb(cmd: String, cmdId: Int, serviceId: Int, buffer: ByteArray, seq: Int = -1, trpc: Boolean = false) {
|
||||
@ -125,7 +151,7 @@ internal abstract class BaseSvc {
|
||||
|
||||
protected suspend fun sendAW(toServiceMsg: ToServiceMsg, timeout: Long = 5000L): ByteArray? {
|
||||
val seq = MsfCore.getNextSeq()
|
||||
return withTimeoutOrNull<ByteArray?>(timeout) {
|
||||
val buffer = withTimeoutOrNull<ByteArray?>(timeout) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
DynamicReceiver.register(IPCRequest(toServiceMsg.serviceCmd, seq) {
|
||||
@ -139,6 +165,16 @@ internal abstract class BaseSvc {
|
||||
}.also {
|
||||
if (it == null) DynamicReceiver.unregister(seq)
|
||||
}?.copyOf()
|
||||
try {
|
||||
if (buffer != null && buffer.size >= 5 && buffer[4] == 120.toByte()) {
|
||||
val builder = BytePacketBuilder()
|
||||
val deBuffer = DeflateTools.uncompress(buffer.slice(4))
|
||||
builder.writeInt(deBuffer.size)
|
||||
builder.writeFully(deBuffer)
|
||||
return builder.build().readBytes()
|
||||
}
|
||||
} catch (_: Exception) { }
|
||||
return buffer
|
||||
}
|
||||
|
||||
protected fun sendExtra(cmd: String, builder: (Bundle) -> Unit) {
|
||||
|
@ -2,18 +2,20 @@ package moe.fuqiuluo.qqinterface.servlet
|
||||
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import moe.whitechi73.protobuf.oidb.cmd0x9082.Oidb0x9082
|
||||
import 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(
|
||||
sendOidb("OidbSvcTrpcTcp.0x9082_$serviceId", 36994, serviceId, ProtoBuf.encodeToByteArray(
|
||||
Oidb0x9082(
|
||||
peer = peer.toULong(),
|
||||
msgSeq = msgSeq,
|
||||
faceIndex = faceIndex,
|
||||
flag = 1u,
|
||||
u1 = 0u,
|
||||
u2 = 0u
|
||||
)))
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
@ -12,27 +12,29 @@ import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
|
||||
import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.shamrock.tools.toHexString
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.whitechi73.protobuf.oidb.cmd0x6d7.CreateFolderReq
|
||||
import moe.whitechi73.protobuf.oidb.cmd0x6d7.DeleteFolderReq
|
||||
import moe.whitechi73.protobuf.oidb.cmd0x6d7.MoveFolderReq
|
||||
import moe.whitechi73.protobuf.oidb.cmd0x6d7.Oidb0x6d7ReqBody
|
||||
import moe.whitechi73.protobuf.oidb.cmd0x6d7.Oidb0x6d7RespBody
|
||||
import moe.whitechi73.protobuf.oidb.cmd0x6d7.RenameFolderReq
|
||||
import protobuf.oidb.cmd0x6d7.CreateFolderReq
|
||||
import protobuf.oidb.cmd0x6d7.DeleteFolderReq
|
||||
import protobuf.oidb.cmd0x6d7.MoveFolderReq
|
||||
import protobuf.oidb.cmd0x6d7.Oidb0x6d7ReqBody
|
||||
import protobuf.oidb.cmd0x6d7.Oidb0x6d7RespBody
|
||||
import protobuf.oidb.cmd0x6d7.RenameFolderReq
|
||||
import tencent.im.oidb.cmd0x6d6.oidb_0x6d6
|
||||
import tencent.im.oidb.cmd0x6d8.oidb_0x6d8
|
||||
import tencent.im.oidb.oidb_sso
|
||||
import moe.whitechi73.protobuf.group_file_common.FolderInfo as GroupFileCommonFolderInfo
|
||||
import protobuf.group_file_common.FolderInfo as GroupFileCommonFolderInfo
|
||||
|
||||
internal object FileSvc: BaseSvc() {
|
||||
suspend fun createFileFolder(groupId: String, folderName: String, parentFolderId: String = "/"): Result<GroupFileCommonFolderInfo> {
|
||||
val data = ProtoBuf.encodeToByteArray(Oidb0x6d7ReqBody(
|
||||
val data = ProtoBuf.encodeToByteArray(
|
||||
Oidb0x6d7ReqBody(
|
||||
createFolder = CreateFolderReq(
|
||||
groupCode = groupId.toULong(),
|
||||
appId = 3u,
|
||||
parentFolderId = parentFolderId,
|
||||
folderName = folderName
|
||||
)
|
||||
))
|
||||
)
|
||||
)
|
||||
val resultBuffer = sendOidbAW("OidbSvc.0x6d7_0", 1751, 0, data)
|
||||
?: return Result.failure(Exception("unable to fetch result"))
|
||||
val oidbPkg = oidb_sso.OIDBSSOPkg()
|
||||
@ -45,13 +47,15 @@ internal object FileSvc: BaseSvc() {
|
||||
}
|
||||
|
||||
suspend fun deleteGroupFolder(groupId: String, folderUid: String): Boolean {
|
||||
val buffer = sendOidbAW("OidbSvc.0x6d7_1", 1751, 1, ProtoBuf.encodeToByteArray(Oidb0x6d7ReqBody(
|
||||
val buffer = sendOidbAW("OidbSvc.0x6d7_1", 1751, 1, ProtoBuf.encodeToByteArray(
|
||||
Oidb0x6d7ReqBody(
|
||||
deleteFolder = DeleteFolderReq(
|
||||
groupCode = groupId.toULong(),
|
||||
appId = 3u,
|
||||
folderId = folderUid
|
||||
)
|
||||
))) ?: return false
|
||||
)
|
||||
)) ?: return false
|
||||
val oidbPkg = oidb_sso.OIDBSSOPkg()
|
||||
oidbPkg.mergeFrom(buffer.slice(4))
|
||||
val rsp = ProtoBuf.decodeFromByteArray<Oidb0x6d7RespBody>(oidbPkg.bytes_bodybuffer.get().toByteArray())
|
||||
@ -59,14 +63,16 @@ internal object FileSvc: BaseSvc() {
|
||||
}
|
||||
|
||||
suspend fun moveGroupFolder(groupId: String, folderUid: String, newParentFolderUid: String): Boolean {
|
||||
val buffer = sendOidbAW("OidbSvc.0x6d7_2", 1751, 2, ProtoBuf.encodeToByteArray(Oidb0x6d7ReqBody(
|
||||
val buffer = sendOidbAW("OidbSvc.0x6d7_2", 1751, 2, ProtoBuf.encodeToByteArray(
|
||||
Oidb0x6d7ReqBody(
|
||||
moveFolder = MoveFolderReq(
|
||||
groupCode = groupId.toULong(),
|
||||
appId = 3u,
|
||||
folderId = folderUid,
|
||||
parentFolderId = "/"
|
||||
)
|
||||
))) ?: return false
|
||||
)
|
||||
)) ?: return false
|
||||
val oidbPkg = oidb_sso.OIDBSSOPkg()
|
||||
oidbPkg.mergeFrom(buffer.slice(4))
|
||||
val rsp = ProtoBuf.decodeFromByteArray<Oidb0x6d7RespBody>(oidbPkg.bytes_bodybuffer.get().toByteArray())
|
||||
@ -74,14 +80,16 @@ internal object FileSvc: BaseSvc() {
|
||||
}
|
||||
|
||||
suspend fun renameFolder(groupId: String, folderUid: String, name: String): Boolean {
|
||||
val buffer = sendOidbAW("OidbSvc.0x6d7_3", 1751, 3, ProtoBuf.encodeToByteArray(Oidb0x6d7ReqBody(
|
||||
val buffer = sendOidbAW("OidbSvc.0x6d7_3", 1751, 3, ProtoBuf.encodeToByteArray(
|
||||
Oidb0x6d7ReqBody(
|
||||
renameFolder = RenameFolderReq(
|
||||
groupCode = groupId.toULong(),
|
||||
appId = 3u,
|
||||
folderId = folderUid,
|
||||
folderName = name
|
||||
)
|
||||
))) ?: return false
|
||||
)
|
||||
)) ?: return false
|
||||
val oidbPkg = oidb_sso.OIDBSSOPkg()
|
||||
oidbPkg.mergeFrom(buffer.slice(4))
|
||||
val rsp = ProtoBuf.decodeFromByteArray<Oidb0x6d7RespBody>(oidbPkg.bytes_bodybuffer.get().toByteArray())
|
||||
|
@ -1,12 +1,370 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package moe.fuqiuluo.qqinterface.servlet
|
||||
|
||||
import com.tencent.mobileqq.qqguildsdk.api.IGPSService
|
||||
import com.tencent.qqnt.kernel.nativeinterface.GProGuildRole
|
||||
import com.tencent.qqnt.kernel.nativeinterface.GProRoleCreateInfo
|
||||
import com.tencent.qqnt.kernel.nativeinterface.GProRoleMemberList
|
||||
import com.tencent.qqnt.kernel.nativeinterface.GProRolePermission
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import io.ktor.utils.io.core.readBytes
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.decodeFromByteArray
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.GProChannelInfo
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.GetGuildMemberListNextToken
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.GuildInfo
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.GuildStatus
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.SlowModeInfo
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
|
||||
import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.shamrock.tools.toHexString
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import protobuf.guild.GetGuildFeedsReq
|
||||
import protobuf.guild.GetGuildFeedsRsp
|
||||
import protobuf.oidb.cmd0xf88.GProFilter
|
||||
import protobuf.oidb.cmd0xf88.GProUserInfo
|
||||
import protobuf.oidb.cmd0xf88.Oidb0xf88Req
|
||||
import protobuf.oidb.cmd0xf88.Oidb0xf88Rsp
|
||||
import protobuf.oidb.cmx0xf57.Oidb0xf57Filter
|
||||
import protobuf.oidb.cmx0xf57.Oidb0xf57GuildInfo
|
||||
import protobuf.oidb.cmx0xf57.Oidb0xf57MetaInfo
|
||||
import protobuf.oidb.cmx0xf57.Oidb0xf57Req
|
||||
import protobuf.oidb.cmx0xf57.Oidb0xf57Rsp
|
||||
import protobuf.oidb.cmx0xf57.Oidb0xf57U1
|
||||
import protobuf.oidb.cmx0xf57.Oidb0xf57U2
|
||||
import protobuf.qweb.QWebExtInfo
|
||||
import protobuf.qweb.QWebReq
|
||||
import protobuf.qweb.QWebRsp
|
||||
import tencent.im.oidb.oidb_sso
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
internal object GProSvc: BaseSvc() {
|
||||
|
||||
|
||||
fun getSelfTinyId(): Long {
|
||||
fun getSelfTinyId(): ULong {
|
||||
val service = app.getRuntimeService(IGPSService::class.java, "all")
|
||||
return service.selfTinyId.toLong()
|
||||
return service.selfTinyId.toULong()
|
||||
}
|
||||
|
||||
suspend fun getGuildInfo(guildId: ULong): Result<Oidb0xf57MetaInfo> {
|
||||
val respBuffer = sendOidbAW("OidbSvcTrpcTcp.0xf57_9", 0xf57, 9, ProtoBuf.encodeToByteArray(
|
||||
Oidb0xf57Req(
|
||||
filter = Oidb0xf57Filter(
|
||||
u1 = Oidb0xf57U1(1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u),
|
||||
u2 = Oidb0xf57U2(1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u)
|
||||
),
|
||||
guildInfo = Oidb0xf57GuildInfo(guildId = guildId)
|
||||
)
|
||||
))
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
if (respBuffer == null) {
|
||||
return Result.failure(Exception("unable to send packet"))
|
||||
}
|
||||
body.mergeFrom(respBuffer.slice(4))
|
||||
return runCatching {
|
||||
ProtoBuf.decodeFromByteArray<Oidb0xf57Rsp>(
|
||||
body.bytes_bodybuffer.get().toByteArray()
|
||||
).metaInfo
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getGuildFeeds(guildId: ULong, channelId: ULong, startIndex: Int): Result<GetGuildFeedsRsp> {
|
||||
val buffer = sendBufferAW("QChannelSvr.trpc.qchannel.commreader.ComReader.GetGuildFeeds", true, ProtoBuf.encodeToByteArray(QWebReq(
|
||||
seq = 10,
|
||||
qua = PlatformUtils.getQUA(),
|
||||
deviceInfo = "i=&imsi=&mac=02:00:00:00:00:00&m=Shamrock&o=114514&a=1919810&sd=0&c64=1&sc=1&p=8000*8000&aid=123456789012345678901234567890abcdef&f=Tencent&mm=5610&cf=1726&cc=8&qimei=&qimei36=&sharpP=1&n=nether_world&support_xsj_live=false&client_mod=concise&timezone=America/La_Paz&material_sdk_version=&vh265=&refreshrate=10086&hwlevel=9&suphdr=1&is_teenager_mod=8&liveH265=&bmst=5&AV1=0",
|
||||
buffer = ProtoBuf.encodeToByteArray(GetGuildFeedsReq(
|
||||
count = 12,
|
||||
from = startIndex,
|
||||
feedAttchInfo = EMPTY_BYTE_ARRAY,
|
||||
guildId = guildId,
|
||||
getType = 1,
|
||||
u7 = 0,
|
||||
u8 = 1,
|
||||
u9 = EMPTY_BYTE_ARRAY
|
||||
)),
|
||||
traceId = app.account + "_0_0",
|
||||
extinfo = listOf(
|
||||
QWebExtInfo("fc-appid", "96"),
|
||||
QWebExtInfo("environment_id", "shamrock"),
|
||||
QWebExtInfo("tiny_id", getSelfTinyId().toString()),
|
||||
)
|
||||
))) ?: return Result.failure(Exception("unable to send packet"))
|
||||
val webRsp = ProtoBuf.decodeFromByteArray<QWebRsp>(buffer.slice(4))
|
||||
if(webRsp.buffer == null) return Result.failure(Exception("server error"))
|
||||
val wupBuffer = webRsp.buffer!!
|
||||
val feeds = ProtoBuf.decodeFromByteArray<GetGuildFeedsRsp>(wupBuffer)
|
||||
return Result.success(feeds)
|
||||
}
|
||||
|
||||
fun getChannelList(guildId: ULong, refresh: Boolean = false): Result<ArrayList<GProChannelInfo>> {
|
||||
if (refresh) {
|
||||
refreshGuildInfo(guildId)
|
||||
}
|
||||
val result = arrayListOf<GProChannelInfo>()
|
||||
app.getRuntimeService(IGPSService::class.java, "all").getChannelList(guildId.toString()).forEach {
|
||||
result.add(GProChannelInfo(
|
||||
ownerGuildId = guildId,
|
||||
guildId = it.guildId,
|
||||
channelId = it.channelUin.toLong(),
|
||||
channelUin = it.channelUin.toLong(),
|
||||
channelName = it.channelName ?: "",
|
||||
channelType = it.type,
|
||||
createTime = it.createTime,
|
||||
creatorTinyId = it.creatorId.toLong(),
|
||||
talkPermission = it.talkPermission,
|
||||
visibleType = it.visibleType,
|
||||
currentSlowMode = it.slowModeKey,
|
||||
slowModes = it.gProSlowModeInfoList.map {
|
||||
SlowModeInfo(it.slowModeKey, it.slowModeText, it.speakFrequency, it.slowModeCircle)
|
||||
},
|
||||
appIconUrl = it.iconUrl,
|
||||
jumpType = it.appChannelJumpType,
|
||||
jumpSwitch = it.jumpSwitch,
|
||||
jumpUrl = it.appChannelJumpUrl,
|
||||
categoryId = it.categoryId,
|
||||
myTalkPermission = it.myTalkPermissionType,
|
||||
maxMemberCount = it.channelMemberMax
|
||||
))
|
||||
}
|
||||
return Result.success(result)
|
||||
}
|
||||
|
||||
fun refreshGuildInfo(guildId: ULong) {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
kernelGProService.refreshGuildInfo(guildId.toLong(), true, 1)
|
||||
}
|
||||
|
||||
suspend fun getGuildMemberList(
|
||||
guildId: ULong,
|
||||
startIndex: Long = 0,
|
||||
roleIndex: Long = 1,
|
||||
count: Int = 50,
|
||||
fetchAll: Boolean = false,
|
||||
result: ArrayList<GProRoleMemberList> = arrayListOf()
|
||||
): Result<Pair<GetGuildMemberListNextToken, ArrayList<GProRoleMemberList>>> {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
|
||||
val fetchGuildMemberListResult: Pair<GetGuildMemberListNextToken, ArrayList<GProRoleMemberList>> = (withTimeoutOrNull(5000) {
|
||||
suspendCancellableCoroutine {
|
||||
kernelGProService.fetchMemberListWithRole(guildId.toLong(), 0, startIndex, roleIndex, count, 0) { code, reason, finish, nextIndex, nextRoleIdIndex, _, seq, roleList ->
|
||||
if (code == 0) {
|
||||
it.resume(GetGuildMemberListNextToken(nextIndex, nextRoleIdIndex, seq, finish) to roleList)
|
||||
} else {
|
||||
LogCenter.log("fetchMemberListWithRole failed: $code($reason)", Level.WARN)
|
||||
it.resume(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}) ?: return Result.failure(Exception("unable to fetch guild member list"))
|
||||
|
||||
val nextToken = fetchGuildMemberListResult.first
|
||||
val roleList = fetchGuildMemberListResult.second
|
||||
result.addAll(roleList)
|
||||
return if (fetchAll) {
|
||||
if (!fetchGuildMemberListResult.first.finish) {
|
||||
getGuildMemberList(guildId, nextToken.startIndex, nextToken.roleIndex, count, true, result)
|
||||
} else {
|
||||
Result.success(nextToken.copy(finish = true) to result)
|
||||
}
|
||||
} else {
|
||||
Result.success(nextToken to result)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSelfGuildInfo(): Result<GProUserInfo> {
|
||||
val selfTinyId = getSelfTinyId()
|
||||
return getUserGuildInfo(0u, selfTinyId)
|
||||
}
|
||||
|
||||
suspend fun getUserGuildInfo(
|
||||
guildId: ULong,
|
||||
memberTinyId: ULong
|
||||
): Result<GProUserInfo> {
|
||||
val respBuffer = sendOidbAW("OidbSvcTrpcTcp.0xf88_1", 0xf88, 1, ProtoBuf.encodeToByteArray(
|
||||
Oidb0xf88Req(
|
||||
filter = GProFilter(1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u),
|
||||
memberId = 0uL,
|
||||
tinyId = memberTinyId,
|
||||
guildId = guildId
|
||||
)
|
||||
))
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
if (respBuffer == null) {
|
||||
return Result.failure(Exception("unable to send packet"))
|
||||
}
|
||||
body.mergeFrom(respBuffer.slice(4))
|
||||
return runCatching {
|
||||
ProtoBuf.decodeFromByteArray<Oidb0xf88Rsp>(
|
||||
body.bytes_bodybuffer.get().toByteArray()
|
||||
).userInfo!!
|
||||
}
|
||||
}
|
||||
|
||||
private fun getGuildListByOldApi(result: ArrayList<GuildInfo>) {
|
||||
app.getRuntimeService(IGPSService::class.java, "all").guildList?.forEach {
|
||||
result.add(GuildInfo(
|
||||
guildId = it.guildID.toLong(),
|
||||
guildName = it.guildName ?: "",
|
||||
guildDisplayId = it.guildNumber ?: "",
|
||||
profile = it.profile ?: "",
|
||||
status = GuildStatus(
|
||||
isEnable = !it.isFrozen && !it.isBanned,
|
||||
isBanned = it.isBanned,
|
||||
isFrozen = it.isFrozen
|
||||
),
|
||||
ownerId = 0,
|
||||
shutUpTime = it.shutUpExpireTime,
|
||||
allowSearch = it.allowSearch
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getGuildListByNt(result: ArrayList<GuildInfo>) {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
kernelGProService.guildListFromCache.forEach {
|
||||
if (it.result != 0) return@forEach
|
||||
val guildInfo = it.guildInfo
|
||||
result.add(GuildInfo(
|
||||
guildId = it.guildId,
|
||||
guildName = guildInfo.guildName ?: "",
|
||||
guildDisplayId = guildInfo.guildNumber ?: "",
|
||||
profile = guildInfo.profile ?: "",
|
||||
status = GuildStatus(
|
||||
isEnable = guildInfo.guildStatus?.isEnable == 1,
|
||||
isBanned = guildInfo.guildStatus?.isBanned == 1,
|
||||
isFrozen = guildInfo.guildStatus?.isFrozen == 1
|
||||
),
|
||||
ownerId = guildInfo.ownerTinyid,
|
||||
shutUpTime = guildInfo.shutupExpireTime,
|
||||
allowSearch = guildInfo.allowSearch == 1
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun fetchGuildMemberRoles(guildId: ULong, tinyId: ULong, refresh: Boolean = false): Result<ArrayList<GProGuildRole>> {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
if (refresh) {
|
||||
kernelGProService.refreshGuildUserProfileInfo(guildId.toLong(), tinyId.toLong(), 1)
|
||||
}
|
||||
val result: ArrayList<GProGuildRole> = withTimeoutOrNull(5000) {
|
||||
suspendCancellableCoroutine {
|
||||
kernelGProService.fetchMemberRoles(guildId.toLong(), 0, tinyId.toLong(), 2) { code, reason, roles ->
|
||||
it.resume(roles)
|
||||
}
|
||||
}
|
||||
} ?: return Result.failure(Exception("unable to fetch guild member roles"))
|
||||
return Result.success(result)
|
||||
}
|
||||
|
||||
fun getGuildList(refresh: Boolean = false, forceOldApi: Boolean): ArrayList<GuildInfo> {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
if (refresh) {
|
||||
kernelGProService.refreshGuildList(true)
|
||||
kernelGProService.guildListFromCache.forEach {
|
||||
refreshGuildInfo(it.guildId.toULong())
|
||||
}
|
||||
}
|
||||
val result = arrayListOf<GuildInfo>()
|
||||
if (PlatformUtils.getQQVersionCode() < PlatformUtils.QQ_9_0_8_VER || forceOldApi) {
|
||||
getGuildListByOldApi(result)
|
||||
} else {
|
||||
runCatching {
|
||||
getGuildListByNt(result)
|
||||
}.onFailure {
|
||||
LogCenter.log("GetGuildListByNt failed: ${it.stackTraceToString()}", Level.ERROR)
|
||||
getGuildListByOldApi(result) // 防止QQ更新API导致无法获取
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
suspend fun getGuildRoles(guildId: ULong): Result<List<GProGuildRole>> {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
val roles: List<GProGuildRole> = withTimeoutOrNull(5000) {
|
||||
suspendCancellableCoroutine {
|
||||
kernelGProService.fetchRoleListWithPermission(guildId.toLong(), 1) { code, _, roles, _, _, _ ->
|
||||
if (code != 0) it.resume(null) else it.resume(roles)
|
||||
}
|
||||
}
|
||||
} ?: return Result.failure(Exception("unable to fetch guild roles"))
|
||||
return Result.success(roles)
|
||||
}
|
||||
|
||||
fun deleteGuildRole(guildId: ULong, roleId: ULong) {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
kernelGProService.deleteRole(guildId.toLong(), roleId.toLong()) { code, msg, result ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("deleteGuildRole failed: $code($msg) => $result", Level.WARN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setMemberRole(guildId: ULong, tinyId: ULong, roleId: ULong, isSet: Boolean) {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
val addList = arrayListOf<Long>()
|
||||
val rmList = arrayListOf<Long>()
|
||||
(if (isSet) addList else rmList).add(roleId.toLong())
|
||||
kernelGProService.setMemberRoles(guildId.toLong(), 0, 0, tinyId.toLong(), addList, rmList) { code, msg, result ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("setMemberRole failed: $code($msg) => $result", Level.WARN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getGuildRolePermission(guildId: ULong, roleId: ULong): Result<GProGuildRole> {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
val role:GProGuildRole = withTimeoutOrNull(5000) {
|
||||
suspendCancellableCoroutine {
|
||||
kernelGProService.fetchRoleWithPermission(guildId.toLong(), roleId.toLong(), 1) { code, msg, role, _, _, _ ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("getGuildRolePermission failed: $code($msg)", Level.WARN)
|
||||
it.resume(null)
|
||||
} else it.resume(role)
|
||||
}
|
||||
}
|
||||
} ?: return Result.failure(Exception("unable to fetch guild role permission"))
|
||||
return Result.success(role)
|
||||
}
|
||||
|
||||
suspend fun updateGuildRole(guildId: ULong, roleId: ULong, name: String, color: Long): Result<Unit> {
|
||||
val oldInfo = getGuildRolePermission(guildId, roleId).onFailure {
|
||||
return Result.failure(it)
|
||||
}.getOrThrow()
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
val info = GProRoleCreateInfo(
|
||||
name, color, oldInfo.bHoist, oldInfo.rolePermissions
|
||||
)
|
||||
kernelGProService.setRoleInfo(guildId.toLong(), roleId.toLong(), info) { code, msg, result ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("updateGuildRole failed: $code($msg) => $result", Level.WARN)
|
||||
}
|
||||
}
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
suspend fun createGuildRole(guildId: ULong, name: String, color: Long, initialUsers: ArrayList<Long>): Result<GProGuildRole> {
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
val permission = GProRolePermission(false, arrayListOf())
|
||||
val info = GProRoleCreateInfo(name, color, false, permission)
|
||||
val role: GProGuildRole = withTimeoutOrNull(5000) {
|
||||
suspendCancellableCoroutine {
|
||||
kernelGProService.createRole(guildId.toLong(), info, initialUsers) { code, msg, result, role ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("createGuildRole failed: $code($msg) => $result", Level.WARN)
|
||||
it.resume(null)
|
||||
} else it.resume(role)
|
||||
}
|
||||
}
|
||||
} ?: return Result.failure(Exception("unable to create guild role"))
|
||||
return Result.success(role)
|
||||
}
|
||||
}
|
@ -14,7 +14,6 @@ import com.tencent.mobileqq.pb.ByteStringMicro
|
||||
import com.tencent.mobileqq.troop.api.ITroopInfoService
|
||||
import com.tencent.mobileqq.troop.api.ITroopMemberInfoService
|
||||
import com.tencent.protofile.join_group_link.join_group_link
|
||||
import com.tencent.qphone.base.remote.FromServiceMsg
|
||||
import com.tencent.qphone.base.remote.ToServiceMsg
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MemberInfo
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
@ -75,8 +74,8 @@ import moe.fuqiuluo.shamrock.utils.FileUtils
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import moe.whitechi73.protobuf.oidb.cmd0xf16.Oidb0xf16
|
||||
import moe.whitechi73.protobuf.oidb.cmd0xf16.SetGroupRemarkReq
|
||||
import protobuf.oidb.cmd0xf16.Oidb0xf16
|
||||
import protobuf.oidb.cmd0xf16.SetGroupRemarkReq
|
||||
import mqq.app.MobileQQ
|
||||
import tencent.im.group.group_member_info
|
||||
import tencent.im.oidb.cmd0x88d.oidb_0x88d
|
||||
@ -272,13 +271,15 @@ internal object GroupSvc: BaseSvc() {
|
||||
}
|
||||
|
||||
fun modifyGroupRemark(groupId: Long, remark: String): Boolean {
|
||||
sendOidb("OidbSvc.0xf16_1", 3862, 1, ProtoBuf.encodeToByteArray(Oidb0xf16(
|
||||
sendOidb("OidbSvc.0xf16_1", 3862, 1, ProtoBuf.encodeToByteArray(
|
||||
Oidb0xf16(
|
||||
setGroupRemarkReq = SetGroupRemarkReq(
|
||||
groupCode = groupId.toULong(),
|
||||
groupUin = groupCode2GroupUin(groupId).toULong(),
|
||||
groupRemark = remark
|
||||
)
|
||||
)))
|
||||
)
|
||||
))
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ internal object MsgSvc: BaseSvc() {
|
||||
?: return Result.failure(Exception("没有对应消息映射,消息获取失败"))
|
||||
|
||||
val peerId = mapping.peerId
|
||||
val contact = MessageHelper.generateContact(mapping.chatType, peerId)
|
||||
val contact = MessageHelper.generateContact(mapping.chatType, peerId, mapping.subPeerId ?: "")
|
||||
|
||||
val msg = withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
@ -89,11 +89,11 @@ internal object MsgSvc: BaseSvc() {
|
||||
suspend fun getMsgByQMsgId(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
qqMsgId: Long
|
||||
qqMsgId: Long,
|
||||
subPeerId: String = ""
|
||||
): Result<MsgRecord> {
|
||||
val contact = MessageHelper.generateContact(chatType, peerId)
|
||||
val service = QRoute.api(IMsgService::class.java) ?:
|
||||
return Result.failure(Exception("获取消息服务"))
|
||||
val contact = MessageHelper.generateContact(chatType, peerId, subPeerId)
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
|
||||
val msg = withTimeoutOrNull(5000) {
|
||||
suspendCoroutine { continuation ->
|
||||
@ -152,7 +152,7 @@ internal object MsgSvc: BaseSvc() {
|
||||
val mapping = MessageHelper.getMsgMappingByHash(msgHash)
|
||||
?: return -1 to "无法找到消息映射"
|
||||
|
||||
val contact = MessageHelper.generateContact(mapping.chatType, mapping.peerId)
|
||||
val contact = MessageHelper.generateContact(mapping.chatType, mapping.peerId, mapping.subPeerId ?: "")
|
||||
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
msgService.recallMsg(contact, arrayListOf(mapping.qqMsgId)) { code, why ->
|
||||
@ -184,7 +184,7 @@ internal object MsgSvc: BaseSvc() {
|
||||
}
|
||||
val result = MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, fromId, MessageCallback(peedId, 0))
|
||||
result.onFailure {
|
||||
LogCenter.log(it.stackTraceToString(), Level.ERROR)
|
||||
LogCenter.log("sendToAio: " + it.stackTraceToString(), Level.ERROR)
|
||||
return result
|
||||
}
|
||||
val sendResult = result.getOrThrow()
|
||||
@ -192,7 +192,7 @@ internal object MsgSvc: BaseSvc() {
|
||||
// 发送失败,可能网络问题出现红色感叹号,重试
|
||||
// 例如 rich media transfer failed
|
||||
delay(100)
|
||||
MessageHelper.resendMsg(chatType, peedId, fromId, sendResult.qqMsgId, 3, sendResult.msgHashId)
|
||||
MessageHelper.resendMsg(chatType, peedId, fromId, sendResult.qqMsgId, retryCnt, sendResult.msgHashId)
|
||||
} else {
|
||||
result
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet
|
||||
|
||||
import com.tencent.mobileqq.msf.core.MsfCore
|
||||
import com.tencent.qqnt.kernel.nativeinterface.Contact
|
||||
import com.tencent.qqnt.kernel.nativeinterface.IKernelMsgService
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
@ -16,14 +15,14 @@ import moe.fuqiuluo.shamrock.remote.action.handlers.GetHistoryMsg
|
||||
import moe.fuqiuluo.shamrock.remote.service.listener.AioListener
|
||||
import moe.fuqiuluo.shamrock.tools.broadcast
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.whitechi73.protobuf.message.JsonElement
|
||||
import moe.whitechi73.protobuf.message.MessageBody
|
||||
import moe.whitechi73.protobuf.message.MessageContentHead
|
||||
import moe.whitechi73.protobuf.message.MessageElement
|
||||
import moe.whitechi73.protobuf.message.MessageElementList
|
||||
import moe.whitechi73.protobuf.message.MessageHead
|
||||
import moe.whitechi73.protobuf.message.RichMessage
|
||||
import moe.whitechi73.protobuf.push.MessagePush
|
||||
import protobuf.message.JsonElement
|
||||
import protobuf.message.MessageBody
|
||||
import protobuf.message.MessageContentHead
|
||||
import protobuf.message.MessageElement
|
||||
import protobuf.message.MessageElementList
|
||||
import protobuf.message.MessageHead
|
||||
import protobuf.message.RichMessage
|
||||
import protobuf.push.MessagePush
|
||||
import mqq.app.MobileQQ
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
@ -33,9 +32,11 @@ internal object PacketSvc: BaseSvc() {
|
||||
*/
|
||||
suspend fun fakeSelfRecvJsonMsg(msgService: IKernelMsgService, content: String): Long {
|
||||
return fakeReceiveSelfMsg(msgService) {
|
||||
listOf(MessageElement(
|
||||
listOf(
|
||||
MessageElement(
|
||||
json = JsonElement((byteArrayOf(1) + DeflateTools.compress(content.toByteArray())))
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
package moe.fuqiuluo.qqinterface.servlet
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import com.tencent.mobileqq.app.QQAppInterface
|
||||
import com.tencent.mobileqq.transfile.HttpNetReq
|
||||
import com.tencent.mobileqq.transfile.INetEngineListener
|
||||
@ -24,18 +23,18 @@ import moe.fuqiuluo.shamrock.tools.toHexString
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.shamrock.utils.MD5
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import moe.whitechi73.protobuf.fav.WeiyunAddRichMediaReq
|
||||
import moe.whitechi73.protobuf.fav.WeiyunAuthor
|
||||
import moe.whitechi73.protobuf.fav.WeiyunCollectCommInfo
|
||||
import moe.whitechi73.protobuf.fav.WeiyunComm
|
||||
import moe.whitechi73.protobuf.fav.WeiyunCommonReq
|
||||
import moe.whitechi73.protobuf.fav.WeiyunFastUploadResourceReq
|
||||
import moe.whitechi73.protobuf.fav.WeiyunGetFavContentReq
|
||||
import moe.whitechi73.protobuf.fav.WeiyunGetFavListReq
|
||||
import moe.whitechi73.protobuf.fav.WeiyunMsgHead
|
||||
import moe.whitechi73.protobuf.fav.WeiyunPicInfo
|
||||
import moe.whitechi73.protobuf.fav.WeiyunRichMediaContent
|
||||
import moe.whitechi73.protobuf.fav.WeiyunRichMediaSummary
|
||||
import protobuf.fav.WeiyunAddRichMediaReq
|
||||
import protobuf.fav.WeiyunAuthor
|
||||
import protobuf.fav.WeiyunCollectCommInfo
|
||||
import protobuf.fav.WeiyunComm
|
||||
import protobuf.fav.WeiyunCommonReq
|
||||
import protobuf.fav.WeiyunFastUploadResourceReq
|
||||
import protobuf.fav.WeiyunGetFavContentReq
|
||||
import protobuf.fav.WeiyunGetFavListReq
|
||||
import protobuf.fav.WeiyunMsgHead
|
||||
import protobuf.fav.WeiyunPicInfo
|
||||
import protobuf.fav.WeiyunRichMediaContent
|
||||
import protobuf.fav.WeiyunRichMediaSummary
|
||||
import mqq.manager.TicketManager
|
||||
import oicq.wlogin_sdk.request.Ticket
|
||||
import oicq.wlogin_sdk.request.WtTicketPromise
|
||||
@ -95,7 +94,8 @@ internal object QFavSvc: BaseSvc() {
|
||||
getFavContentReq = WeiyunGetFavContentReq(
|
||||
cidList = arrayListOf(id)
|
||||
)
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun addImageMsg(
|
||||
@ -147,9 +147,11 @@ internal object QFavSvc: BaseSvc() {
|
||||
),
|
||||
contentType = 1u
|
||||
),
|
||||
richMediaContent = listOf(WeiyunRichMediaContent(
|
||||
richMediaContent = listOf(
|
||||
WeiyunRichMediaContent(
|
||||
rawData = """<img src="$picUrl" />""".toByteArray(),
|
||||
picList = listOf(WeiyunPicInfo(
|
||||
picList = listOf(
|
||||
WeiyunPicInfo(
|
||||
uri = picUrl,
|
||||
md5 = md5Bytes,
|
||||
sha1 = md5.toByteArray(),
|
||||
@ -160,10 +162,13 @@ internal object QFavSvc: BaseSvc() {
|
||||
size = size.toULong(),
|
||||
type = 0u,
|
||||
picId = pid
|
||||
))
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun applyUpImageMsg(
|
||||
@ -180,7 +185,8 @@ internal object QFavSvc: BaseSvc() {
|
||||
val md5 = MD5.genFileMd5(image.absolutePath)
|
||||
return sendWeiyunReq(20010, WeiyunCommonReq(
|
||||
fastUploadResourceReq = WeiyunFastUploadResourceReq(
|
||||
picInfoList = listOf(WeiyunPicInfo(
|
||||
picInfoList = listOf(
|
||||
WeiyunPicInfo(
|
||||
md5 = md5,
|
||||
name = md5.toHexString(),
|
||||
width = width.toUInt(),
|
||||
@ -195,9 +201,11 @@ internal object QFavSvc: BaseSvc() {
|
||||
groupId = groupId.toULong(),
|
||||
groupName = groupName
|
||||
)
|
||||
)),
|
||||
)
|
||||
),
|
||||
)
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun addRichMediaMsg(
|
||||
@ -229,11 +237,14 @@ internal object QFavSvc: BaseSvc() {
|
||||
brief = content,
|
||||
contentType = 1u
|
||||
),
|
||||
richMediaContent = listOf(WeiyunRichMediaContent(
|
||||
richMediaContent = listOf(
|
||||
WeiyunRichMediaContent(
|
||||
rawData = content.textToHtml().toByteArray(),
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun String.textToHtml(): String {
|
||||
@ -318,7 +329,9 @@ internal object QFavSvc: BaseSvc() {
|
||||
}
|
||||
val pSKey = getWeiYunPSKey()
|
||||
httpNetReq.mHttpMethod = HttpNetReq.HTTP_POST
|
||||
httpNetReq.mSendData = DeflateTools.gzip(packData(packHead(cmd, pSKey), ProtoBuf.encodeToByteArray(WeiyunComm(req = req))))
|
||||
httpNetReq.mSendData = DeflateTools.gzip(packData(packHead(cmd, pSKey), ProtoBuf.encodeToByteArray(
|
||||
WeiyunComm(req = req)
|
||||
)))
|
||||
httpNetReq.mOutStream = outputStream
|
||||
httpNetReq.mStartDownOffset = 0L
|
||||
httpNetReq.mReqProperties["Shamrock"] = "true"
|
||||
@ -338,7 +351,8 @@ internal object QFavSvc: BaseSvc() {
|
||||
}
|
||||
|
||||
private fun packHead(cmd: Int, pskey: String): ByteArray {
|
||||
return ProtoBuf.encodeToByteArray(WeiyunMsgHead(
|
||||
return ProtoBuf.encodeToByteArray(
|
||||
WeiyunMsgHead(
|
||||
uin = app.longAccountUin.toULong(),
|
||||
seq = seq++.toUInt(),
|
||||
type = 1u,
|
||||
@ -350,7 +364,8 @@ internal object QFavSvc: BaseSvc() {
|
||||
key = pskey.toByteArray(),
|
||||
majorVersion = MAJOR_VERSION.toUInt(),
|
||||
minorVersion = MINOR_VERSION.toUInt(),
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun packData(head: ByteArray, body: ByteArray): ByteArray {
|
||||
|
@ -32,12 +32,12 @@ internal suspend fun MsgRecord.toCQCode(): String {
|
||||
return MessageConvert.convertMessageRecordToCQCode(this)
|
||||
}
|
||||
|
||||
internal suspend fun List<MsgElement>.toSegments(chatType: Int, peerId: String): MessageSegmentList {
|
||||
return MessageConvert.convertMessageElementsToMsgSegment(chatType, this, peerId)
|
||||
internal suspend fun List<MsgElement>.toSegments(chatType: Int, peerId: String, subPeer: String): MessageSegmentList {
|
||||
return MessageConvert.convertMessageElementsToMsgSegment(chatType, this, peerId, subPeer)
|
||||
}
|
||||
|
||||
internal suspend fun List<MsgElement>.toCQCode(chatType: Int, peerId: String): String {
|
||||
return MessageConvert.convertMsgElementsToCQCode(this, chatType, peerId)
|
||||
internal suspend fun List<MsgElement>.toCQCode(chatType: Int, peerId: String, subPeer: String): String {
|
||||
return MessageConvert.convertMsgElementsToCQCode(this, chatType, peerId, subPeer)
|
||||
}
|
||||
|
||||
|
||||
@ -64,14 +64,15 @@ internal object MessageConvert {
|
||||
suspend fun convertMessageElementsToMsgSegment(
|
||||
chatType: Int,
|
||||
elements: List<MsgElement>,
|
||||
peerId: String
|
||||
peerId: String,
|
||||
subPeer: String
|
||||
): ArrayList<MessageSegment> {
|
||||
val messageData = arrayListOf<MessageSegment>()
|
||||
elements.forEach { msg ->
|
||||
kotlin.runCatching {
|
||||
val elementId = msg.elementType
|
||||
val converter = convertMap[elementId]
|
||||
converter?.convert(chatType, peerId, msg)
|
||||
converter?.convert(chatType, peerId, subPeer, msg)
|
||||
?: throw UnsupportedOperationException("不支持的消息element类型:$elementId")
|
||||
}.onSuccess {
|
||||
messageData.add(it)
|
||||
@ -87,35 +88,45 @@ internal object MessageConvert {
|
||||
}
|
||||
|
||||
suspend fun convertMessageRecordToMsgSegment(record: MsgRecord, chatType: Int = record.chatType): ArrayList<MessageSegment> {
|
||||
return convertMessageElementsToMsgSegment(chatType, record.elements, record.peerUin.toString())
|
||||
val peerId = when(chatType) {
|
||||
MsgConstant.KCHATTYPEGUILD -> record.guildId
|
||||
else -> record.peerUin.toString()
|
||||
}
|
||||
return convertMessageElementsToMsgSegment(chatType, record.elements, peerId, record.channelId ?: peerId)
|
||||
}
|
||||
|
||||
suspend fun convertMsgElementsToCQCode(
|
||||
elements: List<MsgElement>,
|
||||
chatType: Int,
|
||||
peerId: String
|
||||
peerId: String,
|
||||
subPeer: String
|
||||
): String {
|
||||
if(elements.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
val msgList = convertMessageElementsToMsgSegment(chatType, elements, peerId).map {
|
||||
val msgList = convertMessageElementsToMsgSegment(chatType, elements, peerId, subPeer).map {
|
||||
it.toJson()
|
||||
}
|
||||
return MessageHelper.encodeCQCode(msgList)
|
||||
}
|
||||
|
||||
suspend fun convertMessageRecordToCQCode(record: MsgRecord, chatType: Int = record.chatType): String {
|
||||
val peerId = when(chatType) {
|
||||
MsgConstant.KCHATTYPEGUILD -> record.guildId
|
||||
else -> record.peerUin.toString()
|
||||
}
|
||||
return MessageHelper.encodeCQCode(
|
||||
convertMessageElementsToMsgSegment(
|
||||
chatType,
|
||||
record.elements,
|
||||
record.peerUin.toString()
|
||||
peerId,
|
||||
record.channelId ?: peerId
|
||||
).map { it.toJson() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun interface IMessageConvert {
|
||||
suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment
|
||||
suspend fun convert(chatType: Int, peerId: String, subPeer: String, element: MsgElement): MessageSegment
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,12 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
* 文本 / 艾特 消息转换消息段
|
||||
*/
|
||||
data object TextConverter: MessageElemConverter() {
|
||||
override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val text = element.textElement
|
||||
return if (text.atType != MsgConstant.ATTYPEUNKNOWN) {
|
||||
MessageSegment(
|
||||
@ -43,7 +48,12 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
* 小表情 / 戳一戳 消息转换消息段
|
||||
*/
|
||||
data object FaceConverter: MessageElemConverter() {
|
||||
override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val face = element.faceElement
|
||||
|
||||
if (face.faceType == 5) {
|
||||
@ -112,6 +122,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val image = element.picElement
|
||||
@ -131,6 +142,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
"url" to when(chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(md5)
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPicDownUrl(md5)
|
||||
MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGuildPicDownUrl(md5)
|
||||
else -> unknownChatType(chatType)
|
||||
},
|
||||
"subType" to image.picSubType,
|
||||
@ -147,6 +159,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val record = element.pttElement
|
||||
@ -162,6 +175,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
"url" to when(chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPttDownUrl("0", record.md5HexStr, record.fileUuid)
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPttDownUrl("0", record.fileUuid)
|
||||
MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGroupPttDownUrl("0", record.md5HexStr, record.fileUuid)
|
||||
else -> unknownChatType(chatType)
|
||||
}
|
||||
).also {
|
||||
@ -183,6 +197,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val video = element.videoElement
|
||||
@ -195,6 +210,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)
|
||||
else -> unknownChatType(chatType)
|
||||
}
|
||||
).also {
|
||||
@ -212,6 +228,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val face = element.marketFaceElement
|
||||
@ -235,6 +252,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val data = element.arkElement.bytesData.asJsonObject
|
||||
@ -297,6 +315,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val reply = element.replyElement
|
||||
@ -329,6 +348,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val tip = element.grayTipElement
|
||||
@ -364,6 +384,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val fileMsg = element.fileElement
|
||||
@ -373,8 +394,11 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
val fileId = fileMsg.fileUuid
|
||||
val bizId = fileMsg.fileBizId ?: 0
|
||||
val fileSubId = fileMsg.fileSubId ?: ""
|
||||
val url = if (chatType == MsgConstant.KCHATTYPEC2C) RichProtoSvc.getC2CFileDownUrl(fileId, fileSubId)
|
||||
else RichProtoSvc.getGroupFileDownUrl(peerId.toLong(), fileId, bizId)
|
||||
val url = when (chatType) {
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CFileDownUrl(fileId, fileSubId)
|
||||
MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGuildFileDownUrl(peerId, subPeer, fileId, bizId)
|
||||
else -> RichProtoSvc.getGroupFileDownUrl(peerId.toLong(), fileId, bizId)
|
||||
}
|
||||
|
||||
return MessageSegment(
|
||||
type = "file",
|
||||
@ -398,6 +422,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val multiMsg = element.multiForwardMsgElement
|
||||
@ -414,6 +439,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val longMsg = element.structLongMsgElement
|
||||
@ -430,6 +456,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val markdown = element.markdownElement
|
||||
@ -446,6 +473,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val bubbleElement = element.faceBubbleElement
|
||||
|
@ -0,0 +1,78 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.structures
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GuildInfo(
|
||||
@SerialName("guild_id") var guildId: Long,
|
||||
@SerialName("guild_name") var guildName: String,
|
||||
@SerialName("guild_display_id") var guildDisplayId: String,
|
||||
@SerialName("profile") var profile: String,
|
||||
@SerialName("status") var status: GuildStatus,
|
||||
@SerialName("owner_id") var ownerId: Long,
|
||||
@SerialName("shutup_expire_time") var shutUpTime: Long,
|
||||
@SerialName("allow_search") var allowSearch: Boolean
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GuildStatus(
|
||||
@SerialName("is_enable") var isEnable: Boolean,
|
||||
@SerialName("is_banned") var isBanned: Boolean,
|
||||
@SerialName("is_frozen") var isFrozen: Boolean
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GProChannelInfo(
|
||||
@SerialName("owner_guild_id") val ownerGuildId: ULong,
|
||||
@SerialName("channel_id") val channelId: Long,
|
||||
@SerialName("channel_uin") val channelUin: Long,
|
||||
@SerialName("guild_id") val guildId: String,
|
||||
@SerialName("channel_type") val channelType: Int,
|
||||
@SerialName("channel_name") val channelName: String,
|
||||
@SerialName("create_time") val createTime: Long,
|
||||
@SerialName("max_member_count") val maxMemberCount: Int,
|
||||
@SerialName("creator_tiny_id") val creatorTinyId: Long,
|
||||
@SerialName("talk_permission") val talkPermission: Int,
|
||||
@SerialName("visible_type") val visibleType: Int,
|
||||
@SerialName("current_slow_mode") val currentSlowMode: Int,
|
||||
@SerialName("slow_modes") val slowModes: List<SlowModeInfo>,
|
||||
@SerialName("icon_url") val appIconUrl: String? = null,
|
||||
@SerialName("jump_switch") val jumpSwitch: Int = Int.MIN_VALUE,
|
||||
@SerialName("jump_type") val jumpType: Int = Int.MIN_VALUE,
|
||||
@SerialName("jump_url") val jumpUrl: String? = null,
|
||||
@SerialName("category_id") val categoryId: Long = Long.MIN_VALUE,
|
||||
@SerialName("my_talk_permission") val myTalkPermission: Int = Int.MIN_VALUE,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SlowModeInfo(
|
||||
@SerialName("slow_mode_key") val slowModeKey: Int,
|
||||
@SerialName("slow_mode_text") val slowModeText: String,
|
||||
@SerialName("speak_frequency") val speakFrequency: Int,
|
||||
@SerialName("slow_mode_circle") val slowModeCircle: Int
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GetGuildMemberListNextToken(
|
||||
@SerialName("start_index") val startIndex: Long,
|
||||
@SerialName("role_index") val roleIndex: Long,
|
||||
@SerialName("seq") val seq: Int,
|
||||
@SerialName("finish") val finish: Boolean
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GuildMemberInfo(
|
||||
@SerialName("tiny_id") val tinyId: Long,
|
||||
@SerialName("title") val title: String,
|
||||
@SerialName("nickname") val nickname: String,
|
||||
@SerialName("role_id") val roleId: Long,
|
||||
@SerialName("role_name") val roleName: String,
|
||||
@SerialName("role_color") val roleColor: Long,
|
||||
@SerialName("join_time") val joinTime: Long,
|
||||
@SerialName("robot_type") val robotType: Int,
|
||||
@SerialName("type") val type: Int,
|
||||
@SerialName("in_black") val inBlack: Boolean,
|
||||
@SerialName("platform") val platform: Int,
|
||||
)
|
||||
|
@ -1,3 +1,4 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.fuqiuluo.qqinterface.servlet.transfile
|
||||
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro
|
||||
@ -6,6 +7,10 @@ import com.tencent.mobileqq.transfile.api.IProtoReqManager
|
||||
import com.tencent.mobileqq.transfile.protohandler.RichProto
|
||||
import com.tencent.mobileqq.transfile.protohandler.RichProtoProc
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.decodeFromByteArray
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
@ -14,6 +19,10 @@ import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.shamrock.tools.toHexString
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import protobuf.oidb.cmd0xfc2.Oidb0xfc2ChannelInfo
|
||||
import protobuf.oidb.cmd0xfc2.Oidb0xfc2MsgApplyDownloadReq
|
||||
import protobuf.oidb.cmd0xfc2.Oidb0xfc2ReqBody
|
||||
import protobuf.oidb.cmd0xfc2.Oidb0xfc2RspBody
|
||||
import mqq.app.MobileQQ
|
||||
import tencent.im.cs.cmd0x346.cmd0x346
|
||||
import tencent.im.oidb.cmd0x6d6.oidb_0x6d6
|
||||
@ -22,6 +31,32 @@ import tencent.im.oidb.oidb_sso
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
internal object RichProtoSvc: BaseSvc() {
|
||||
suspend fun getGuildFileDownUrl(peerId: String, channelId: String, fileId: String, bizId: Int): String {
|
||||
val buffer = sendOidbAW("OidbSvcTrpcTcp.0xfc2_0", 4034, 0, ProtoBuf.encodeToByteArray(
|
||||
Oidb0xfc2ReqBody(
|
||||
msgCmd = 1200,
|
||||
msgBusType = 4202,
|
||||
msgChannelInfo = Oidb0xfc2ChannelInfo(
|
||||
guildId = peerId.toULong(),
|
||||
channelId = channelId.toULong()
|
||||
),
|
||||
msgTerminalType = 2,
|
||||
msgApplyDownloadReq = Oidb0xfc2MsgApplyDownloadReq(
|
||||
fieldId = fileId,
|
||||
supportEncrypt = 0
|
||||
)
|
||||
)
|
||||
)) ?: return ""
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
body.mergeFrom(buffer.slice(4))
|
||||
ProtoBuf.decodeFromByteArray<Oidb0xfc2RspBody>(body.bytes_bodybuffer.get().toByteArray()).msgApplyDownloadRsp?.let {
|
||||
it.msgDownloadInfo?.let {
|
||||
return "https://${it.downloadDomain}${it.downloadUrl}&fname=$fileId&isthumb=0"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
suspend fun getGroupFileDownUrl(
|
||||
peerId: Long,
|
||||
fileId: String,
|
||||
@ -34,27 +69,23 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
uint32_bus_id.set(bizId)
|
||||
str_file_id.set(fileId)
|
||||
})
|
||||
}.toByteArray())
|
||||
if (buffer == null) {
|
||||
}.toByteArray()) ?: return ""
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
body.mergeFrom(buffer.slice(4))
|
||||
val result = oidb_0x6d6.RspBody().mergeFrom(body.bytes_bodybuffer.get().toByteArray())
|
||||
if (body.uint32_result.get() != 0
|
||||
|| result.download_file_rsp.int32_ret_code.get() != 0) {
|
||||
return ""
|
||||
} else {
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
body.mergeFrom(buffer.slice(4))
|
||||
val result = oidb_0x6d6.RspBody().mergeFrom(body.bytes_bodybuffer.get().toByteArray())
|
||||
if (body.uint32_result.get() != 0
|
||||
|| result.download_file_rsp.int32_ret_code.get() != 0) {
|
||||
return ""
|
||||
}
|
||||
|
||||
val domain = if (!result.download_file_rsp.str_download_dns.has())
|
||||
("https://" + result.download_file_rsp.str_download_ip.get())
|
||||
else ("http://" + result.download_file_rsp.str_download_dns.get())
|
||||
val downloadUrl = result.download_file_rsp.bytes_download_url.get().toByteArray().toHexString()
|
||||
val appId = MobileQQ.getMobileQQ().appId
|
||||
val version = PlatformUtils.getQQVersion(MobileQQ.getContext())
|
||||
|
||||
return "$domain/ftn_handler/$downloadUrl/?fname=$fileId&client_proto=qq&client_appid=$appId&client_type=android&client_ver=$version&client_down_type=auto&client_aio_type=unk"
|
||||
}
|
||||
|
||||
val domain = if (!result.download_file_rsp.str_download_dns.has())
|
||||
("https://" + result.download_file_rsp.str_download_ip.get())
|
||||
else ("http://" + result.download_file_rsp.str_download_dns.get())
|
||||
val downloadUrl = result.download_file_rsp.bytes_download_url.get().toByteArray().toHexString()
|
||||
val appId = MobileQQ.getMobileQQ().appId
|
||||
val version = PlatformUtils.getQQVersion(MobileQQ.getContext())
|
||||
|
||||
return "$domain/ftn_handler/$downloadUrl/?fname=$fileId&client_proto=qq&client_appid=$appId&client_type=android&client_ver=$version&client_down_type=auto&client_aio_type=unk"
|
||||
}
|
||||
|
||||
suspend fun getC2CFileDownUrl(
|
||||
@ -83,7 +114,7 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
}.toByteArray())
|
||||
|
||||
if (buffer == null) {
|
||||
if (retryCnt < 3) {
|
||||
if (retryCnt < 5) {
|
||||
return getC2CFileDownUrl(fileId, subId, retryCnt + 1)
|
||||
}
|
||||
return ""
|
||||
@ -122,6 +153,10 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
return "https://c2cpicdw.qpic.cn/offpic_new/0/123-0-${md5.uppercase()}/0?term=2"
|
||||
}
|
||||
|
||||
fun getGuildPicDownUrl(md5: String): String {
|
||||
return "https://gchat.qpic.cn/qmeetpic/0/0-0-${md5.uppercase()}/0?term=2"
|
||||
}
|
||||
|
||||
suspend fun getC2CVideoDownUrl(
|
||||
peerId: String,
|
||||
md5Hex: String,
|
||||
@ -287,4 +322,11 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getGuildPttDownUrl(
|
||||
peerId: String,
|
||||
md5Hex: String,
|
||||
fileUUId: String
|
||||
): String {
|
||||
return "unsupported"
|
||||
}
|
||||
}
|
@ -90,7 +90,7 @@ internal object MessageHelper {
|
||||
|
||||
// ActionMsg No Care
|
||||
if (msg.isEmpty()) {
|
||||
return Result.success(uniseq.copy(msgTime = System.currentTimeMillis(), msgHashId = 0))
|
||||
return Result.success(uniseq.copy(msgTime = System.currentTimeMillis()))
|
||||
}
|
||||
|
||||
val totalSize = msg.filter {
|
||||
@ -107,12 +107,7 @@ internal object MessageHelper {
|
||||
val sendRet = withTimeoutOrNull<Pair<Int, String>>(estimateTime) {
|
||||
suspendCancellableCoroutine {
|
||||
GlobalScope.launch {
|
||||
sendResult = sendMessageWithoutMsgId(
|
||||
chatType,
|
||||
peerId,
|
||||
msg,
|
||||
fromId
|
||||
) { code, message ->
|
||||
sendResult = sendMessageWithoutMsgId(chatType, peerId, msg, fromId) { code, message ->
|
||||
callback.onResult(code, message)
|
||||
it.resume(code to message)
|
||||
}
|
||||
@ -248,10 +243,17 @@ internal object MessageHelper {
|
||||
}
|
||||
|
||||
suspend fun generateContact(chatType: Int, id: String, subId: String = ""): Contact {
|
||||
val peerId = if (MsgConstant.KCHATTYPEC2C == chatType || MsgConstant.KCHATTYPETEMPC2CFROMGROUP == chatType) {
|
||||
ContactHelper.getUidByUinAsync(id.toLong())
|
||||
} else id
|
||||
return Contact(chatType, peerId, subId)
|
||||
val peerId = when(chatType) {
|
||||
MsgConstant.KCHATTYPEC2C, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> {
|
||||
ContactHelper.getUidByUinAsync(id.toLong())
|
||||
}
|
||||
else -> id
|
||||
}
|
||||
return if (chatType == MsgConstant.KCHATTYPEGUILD) {
|
||||
Contact(chatType, subId, peerId)
|
||||
} else {
|
||||
Contact(chatType, peerId, subId)
|
||||
}
|
||||
}
|
||||
|
||||
fun obtainMessageTypeByDetailType(detailType: String): Int {
|
||||
@ -308,6 +310,7 @@ internal object MessageHelper {
|
||||
MsgConstant.KCHATTYPEGROUP -> "grp$msgId"
|
||||
MsgConstant.KCHATTYPEC2C -> "c2c$msgId"
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> "tmpgrp$msgId"
|
||||
MsgConstant.KCHATTYPEGUILD -> "guild$msgId"
|
||||
else -> error("不支持的消息来源类型 | generateMsgIdHash: $chatType")
|
||||
}
|
||||
return abs(key.hashCode())
|
||||
@ -341,11 +344,12 @@ internal object MessageHelper {
|
||||
time: Long,
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeerId: String,
|
||||
msgSeq: Int,
|
||||
subChatType: Int = chatType
|
||||
) {
|
||||
val database = MessageDB.getInstance()
|
||||
val mapping = MessageMapping(hash, qqMsgId, chatType, subChatType, peerId, time, msgSeq)
|
||||
val mapping = MessageMapping(hash, qqMsgId, chatType, subChatType, peerId, time, msgSeq, subPeerId)
|
||||
database.messageMappingDao().insert(mapping)
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import mqq.app.MobileQQ
|
||||
|
||||
@Entity(tableName = "message_mapping")
|
||||
@Entity(tableName = "message_mapping_v2")
|
||||
data class MessageMapping (
|
||||
@PrimaryKey
|
||||
val msgHashId: Int,
|
||||
@ -21,7 +21,8 @@ data class MessageMapping (
|
||||
val subChatType: Int, // 细化各种事件消息
|
||||
val peerId: String,
|
||||
val time: Long,
|
||||
val msgSeq: Int
|
||||
val msgSeq: Int,
|
||||
val subPeerId: String,
|
||||
)
|
||||
|
||||
@Dao
|
||||
@ -29,25 +30,25 @@ interface MessageMappingDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(mapping: MessageMapping)
|
||||
|
||||
@Query("UPDATE message_mapping SET msgSeq = :msgSeq WHERE msgHashId = :hash")
|
||||
@Query("UPDATE message_mapping_v2 SET msgSeq = :msgSeq WHERE msgHashId = :hash")
|
||||
fun updateMsgSeqByMsgHash(hash: Int, msgSeq: Int)
|
||||
|
||||
@Query("DELETE FROM message_mapping WHERE msgHashId = :hash")
|
||||
@Query("DELETE FROM message_mapping_v2 WHERE msgHashId = :hash")
|
||||
fun deleteByMsgHash(hash: Int)
|
||||
|
||||
@Query("SELECT * FROM message_mapping WHERE msgHashId = :msgHashId")
|
||||
@Query("SELECT * FROM message_mapping_v2 WHERE msgHashId = :msgHashId")
|
||||
fun queryByMsgHashId(msgHashId: Int): MessageMapping?
|
||||
|
||||
@Query("SELECT * FROM message_mapping WHERE qqMsgId = :qqMsgId AND chatType = :chatType")
|
||||
@Query("SELECT * FROM message_mapping_v2 WHERE qqMsgId = :qqMsgId AND chatType = :chatType")
|
||||
fun queryByQqMsgId(chatType: Int, qqMsgId: Long): MessageMapping?
|
||||
|
||||
@Query("SELECT * FROM message_mapping WHERE chatType = :chatType")
|
||||
@Query("SELECT * FROM message_mapping_v2 WHERE chatType = :chatType")
|
||||
fun queryByChatType(chatType: Int): List<MessageMapping>
|
||||
|
||||
@Query("SELECT * FROM message_mapping WHERE subChatType = :subChatType AND chatType = :chatType")
|
||||
@Query("SELECT * FROM message_mapping_v2 WHERE subChatType = :subChatType AND chatType = :chatType")
|
||||
fun queryBySubChatType(chatType: Int, subChatType: Int): List<MessageMapping>
|
||||
|
||||
@Query("SELECT * FROM message_mapping WHERE peerId = :peerId AND chatType = :chatType")
|
||||
@Query("SELECT * FROM message_mapping_v2 WHERE peerId = :peerId AND chatType = :chatType")
|
||||
fun queryByPeerId(chatType: Int, peerId: String): List<MessageMapping>
|
||||
|
||||
//@Query("SELECT * FROM message_mapping WHERE msgSeq = :msgSeq AND chatType = :chatType")
|
||||
@ -55,7 +56,7 @@ interface MessageMappingDao {
|
||||
// 不要调用这个,seq不唯一啊,老哥!!!!!!!!!!!!!
|
||||
// 我就说怎么这么多bug
|
||||
|
||||
@Query("SELECT * FROM message_mapping WHERE msgSeq = :msgSeq AND chatType = :chatType AND peerId = :peerId")
|
||||
@Query("SELECT * FROM message_mapping_v2 WHERE msgSeq = :msgSeq AND chatType = :chatType AND peerId = :peerId")
|
||||
fun queryByMsgSeq(chatType: Int, peerId: String, msgSeq: Int): MessageMapping?
|
||||
}
|
||||
|
||||
@ -64,7 +65,7 @@ internal abstract class MessageDB: RoomDatabase() {
|
||||
abstract fun messageMappingDao(): MessageMappingDao
|
||||
|
||||
companion object {
|
||||
private const val DB_NAME = "message_mapping.db"
|
||||
private const val DB_NAME = "message_mapping_v2.db"
|
||||
|
||||
@Volatile
|
||||
private var instance: MessageDB? = null
|
||||
|
@ -0,0 +1,42 @@
|
||||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
|
||||
@OneBotHandler("create_guild_role")
|
||||
internal object CreateGuildRole: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
val name = session.getString("name")
|
||||
val color = session.getLong("color")
|
||||
val initialUsers = session.getArray("initial_users").map {
|
||||
it.asString.toULong()
|
||||
}
|
||||
return invoke(guildId, color, name, initialUsers, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(guildId: ULong, color: Long, name: String, initialUsers: List<ULong>, echo: JsonElement = EmptyJsonString): String {
|
||||
val result = GProSvc.createGuildRole(guildId, name, color, initialUsers as ArrayList<Long>).onFailure {
|
||||
return error(it.message ?: "Unknown error", echo)
|
||||
}.getOrThrow()
|
||||
return ok(data = CreateGuildRoleResult(
|
||||
result.roleId.toULong()
|
||||
), echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id", "color", "name", "initial_users")
|
||||
|
||||
@Serializable
|
||||
data class CreateGuildRoleResult(
|
||||
@SerialName("role_id") val roleId: ULong
|
||||
)
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
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("delete_guild_role")
|
||||
internal object DeleteGuildRole: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
val roleId = session.getString("role_id").toULong()
|
||||
return invoke(guildId, roleId, session.echo)
|
||||
}
|
||||
|
||||
operator fun invoke(guildId: ULong, roleId: ULong, echo: JsonElement = EmptyJsonString): String {
|
||||
GProSvc.deleteGuildRole(guildId, roleId)
|
||||
return ok("success", echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id", "role_id")
|
||||
}
|
@ -16,7 +16,7 @@ import moe.fuqiuluo.shamrock.utils.CryptTools
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.shamrock.utils.FileUtils
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
import moe.whitechi73.protobuf.fav.WeiyunComm
|
||||
import protobuf.fav.WeiyunComm
|
||||
|
||||
@OneBotHandler("fav.add_image_msg")
|
||||
internal object FavAddImageMsg: IActionHandler() {
|
||||
|
@ -13,7 +13,7 @@ import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
import moe.whitechi73.protobuf.fav.WeiyunComm
|
||||
import protobuf.fav.WeiyunComm
|
||||
|
||||
@OneBotHandler("fav.add_text_msg")
|
||||
internal object FavAddTextMsg: IActionHandler() {
|
||||
|
@ -16,7 +16,7 @@ import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
import moe.whitechi73.protobuf.fav.WeiyunComm
|
||||
import protobuf.fav.WeiyunComm
|
||||
|
||||
@OneBotHandler("fav.get_item_content")
|
||||
internal object FavGetItemContent: IActionHandler() {
|
||||
|
@ -13,7 +13,7 @@ import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
import moe.whitechi73.protobuf.fav.WeiyunComm
|
||||
import protobuf.fav.WeiyunComm
|
||||
|
||||
@OneBotHandler("fav.get_item_list")
|
||||
internal object FavGetItemList: IActionHandler() {
|
||||
|
@ -41,7 +41,7 @@ internal object GetForwardMsg: IActionHandler() {
|
||||
msg.senderUin, msg.sendNickName
|
||||
.ifEmpty { msg.sendMemberName }
|
||||
.ifEmpty { msg.sendRemarkName }
|
||||
.ifEmpty { msg.peerName }, "unknown", 0, msg.senderUid
|
||||
.ifEmpty { msg.peerName }, "unknown", 0, msg.senderUid, msg.senderUid
|
||||
),
|
||||
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||
it.toJson()
|
||||
|
@ -0,0 +1,35 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.GProChannelInfo
|
||||
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("get_guild_channel_list")
|
||||
internal object GetGProChannelList: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id")
|
||||
val refresh = session.getBooleanOrDefault("refresh", session.getBooleanOrDefault("no_cache", false))
|
||||
return invoke(guildId.toULong(), refresh, echo = session.echo)
|
||||
}
|
||||
|
||||
operator fun invoke(guildId: ULong, refresh: Boolean, echo: JsonElement = EmptyJsonString): String {
|
||||
val result = GProSvc.getChannelList(guildId, refresh)
|
||||
result.onFailure {
|
||||
return error(it.message ?: "unable to fetch channel list", echo)
|
||||
}
|
||||
return ok(GuildChannelListResult(result.getOrThrow()), echo, "success")
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id")
|
||||
|
||||
@Serializable
|
||||
data class GuildChannelListResult(
|
||||
@SerialName("channel_list") val channelList: List<GProChannelInfo>
|
||||
)
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
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
|
||||
import protobuf.guild.StFeed
|
||||
|
||||
@OneBotHandler("get_guild_feeds")
|
||||
internal object GetGuildFeeds: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
val channelId = session.getStringOrNull("channel_id")?.toULong() ?: 0uL
|
||||
val from = session.getIntOrNull("from") ?: 0
|
||||
return invoke(guildId, channelId, from, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(guildId: ULong, channelId: ULong, startIndex: Int, echo: JsonElement = EmptyJsonString): String {
|
||||
val result = GProSvc.getGuildFeeds(guildId, channelId, startIndex).getOrElse {
|
||||
GProSvc.getGuildFeeds(guildId, 0uL, startIndex).onFailure {
|
||||
return error(it.message ?: "server error", echo)
|
||||
}.getOrThrow()
|
||||
}
|
||||
if (result.vecFeed == null) {
|
||||
return error("server error", echo)
|
||||
}
|
||||
return ok(GetGuildFeedsResult(result.isFinish == 1, result.vecFeed!!), echo = echo)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class GetGuildFeedsResult(
|
||||
val isFinish: Boolean,
|
||||
val feeds: List<StFeed>
|
||||
)
|
||||
}
|
@ -3,6 +3,8 @@ package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.GuildInfo
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
@ -16,63 +18,18 @@ import mqq.app.MobileQQ
|
||||
@OneBotHandler("get_guild_list")
|
||||
internal object GetGuildList : IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
return invoke(echo = session.echo)
|
||||
val oldSdk = session.getBooleanOrDefault("old_sdk", false)
|
||||
val refresh = session.getBooleanOrDefault("refresh", session.getBooleanOrDefault("no_cache", false))
|
||||
return invoke(refresh, oldSdk, echo = session.echo)
|
||||
}
|
||||
|
||||
operator fun invoke(refresh: Boolean = true, echo: JsonElement = EmptyJsonString): String {
|
||||
PlatformUtils.requireMinQQVersion(version = PlatformUtils.QQ_9_0_8_VER)
|
||||
|
||||
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
|
||||
if (refresh) {
|
||||
kernelGProService.refreshGuildList(true)
|
||||
kernelGProService.guildListFromCache.forEach {
|
||||
kernelGProService.refreshGuildInfo(it.guildId, true, 1)
|
||||
}
|
||||
}
|
||||
val result = arrayListOf<GuildInfo>()
|
||||
kernelGProService.guildListFromCache.forEach {
|
||||
if (it.result != 0) return@forEach
|
||||
val guildInfo = it.guildInfo
|
||||
result.add(
|
||||
GuildInfo(
|
||||
guildId = it.guildId,
|
||||
guildName = guildInfo.guildName ?: "",
|
||||
guildDisplayId = guildInfo.guildNumber ?: "",
|
||||
profile = guildInfo.profile ?: "",
|
||||
status = GuildStatus(
|
||||
isEnable = guildInfo.guildStatus?.isEnable == 1,
|
||||
isBanned = guildInfo.guildStatus?.isBanned == 1,
|
||||
isFrozen = guildInfo.guildStatus?.isFrozen == 1
|
||||
),
|
||||
ownerId = guildInfo.ownerTinyid,
|
||||
shutUpTime = guildInfo.shutupExpireTime
|
||||
))
|
||||
}
|
||||
return ok(GuildListResult(
|
||||
result
|
||||
), echo, "success")
|
||||
operator fun invoke(refresh: Boolean = true, oldSdk: Boolean, echo: JsonElement = EmptyJsonString): String {
|
||||
val result = GProSvc.getGuildList(refresh, oldSdk)
|
||||
return ok(GuildListResult(result), echo, "success")
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class GuildListResult(
|
||||
@SerialName("guild_list") var guildList: List<GuildInfo> = arrayListOf()
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GuildInfo(
|
||||
@SerialName("guild_id") var guildId: Long,
|
||||
@SerialName("guild_name") var guildName: String,
|
||||
@SerialName("guild_display_id") var guildDisplayId: String,
|
||||
@SerialName("profile") var profile: String,
|
||||
@SerialName("status") var status: GuildStatus,
|
||||
@SerialName("owner_id") var ownerId: Long,
|
||||
@SerialName("shutup_expire_time") var shutUpTime: Long,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GuildStatus(
|
||||
@SerialName("is_enable") var isEnable: Boolean,
|
||||
@SerialName("is_banned") var isBanned: Boolean,
|
||||
@SerialName("is_frozen") var isFrozen: Boolean
|
||||
)
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromByteArray
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.GetGuildMemberListNextToken
|
||||
import moe.fuqiuluo.qqinterface.servlet.structures.GuildMemberInfo
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.tools.hex2ByteArray
|
||||
import moe.fuqiuluo.shamrock.tools.toHexString
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
|
||||
@OneBotHandler("get_guild_member_list")
|
||||
internal object GetGuildMemberList: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id")
|
||||
val all = session.getBooleanOrDefault("all", false)
|
||||
return invoke(guildId.toULong(), all, session.getStringOrNull("next_token") ?: "", session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(guildId: ULong, all: Boolean, nextTokenStr: String, echo: JsonElement = EmptyJsonString): String {
|
||||
val curNextToken = if (nextTokenStr.isEmpty()) null else ProtoBuf.decodeFromByteArray<GetGuildMemberListNextToken>(nextTokenStr.hex2ByteArray())
|
||||
val result = GProSvc.getGuildMemberList(
|
||||
guildId = guildId,
|
||||
fetchAll = all,
|
||||
startIndex = curNextToken?.startIndex ?: 0,
|
||||
roleIndex = curNextToken?.roleIndex ?: 1,
|
||||
count = 50
|
||||
)
|
||||
result.onFailure {
|
||||
return error(it.message ?: "unable to fetch guild member list", echo)
|
||||
}
|
||||
val nextToken = result.getOrThrow().first
|
||||
val members = arrayListOf<GuildMemberInfo>()
|
||||
result.getOrThrow().second.forEach {
|
||||
it.members.forEach { user ->
|
||||
members.add(GuildMemberInfo(
|
||||
tinyId = user.tinyId,
|
||||
title = user.memberName,
|
||||
nickname = user.nickName,
|
||||
roleId = user.roleManagementTag.roleId,
|
||||
roleName = user.roleManagementTag.tagName,
|
||||
roleColor = user.roleManagementTag.color,
|
||||
joinTime = user.joinTime,
|
||||
robotType = user.robotType,
|
||||
type = user.type,
|
||||
inBlack = user.inBlack,
|
||||
platform = user.platform
|
||||
))
|
||||
}
|
||||
}
|
||||
return ok(GetGuildMemberListResult(
|
||||
members = members,
|
||||
finish = nextToken.finish,
|
||||
nextToken = ProtoBuf.encodeToByteArray(nextToken).toHexString(),
|
||||
))
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id")
|
||||
|
||||
@Serializable
|
||||
data class GetGuildMemberListResult(
|
||||
@SerialName("members") val members: List<GuildMemberInfo>,
|
||||
@SerialName("next_token") val nextToken: String,
|
||||
@SerialName("finished") val finish: Boolean
|
||||
)
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.tools.ifNullOrEmpty
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
|
||||
@OneBotHandler("get_guild_member_profile")
|
||||
internal object GetGuildMemberProfile: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
val userId = session.getString("user_id").toULong()
|
||||
return invoke(guildId, userId, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(guildId: ULong, userId: ULong, echo: JsonElement = EmptyJsonString): String {
|
||||
val userResult = GProSvc.getUserGuildInfo(guildId, userId).onFailure {
|
||||
return error(it.message ?: "unable to fetch guild member info", echo)
|
||||
}.getOrThrow()
|
||||
val roles = GProSvc.fetchGuildMemberRoles(guildId, userId).onFailure {
|
||||
return error(it.message ?: "unable to fetch guild member roles", echo)
|
||||
}.getOrThrow()
|
||||
|
||||
return ok(GetGuildMemberInfo(
|
||||
tinyId = userResult.memberTinyid,
|
||||
nickname = userResult.nickName ?: "",
|
||||
avatarUrl = userResult.url ?: "",
|
||||
joinTime = userResult.joinTime,
|
||||
roles = roles.map {
|
||||
RoleInfo(
|
||||
roleId = it.roleId.toString(),
|
||||
roleName = it.name.ifNullOrEmpty(it.levelDsc.ifNullOrEmpty(it.displayTagName ?: ""))!!,
|
||||
color = it.color,
|
||||
permission = it.rolePermissions.permissionList.map {
|
||||
Permission(
|
||||
rootId = it.rootId,
|
||||
childIds = it.childIds ?: emptyList()
|
||||
)
|
||||
},
|
||||
type = it.type,
|
||||
displayName = it.displayTagName ?: ""
|
||||
)
|
||||
}
|
||||
), echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id", "user_id")
|
||||
|
||||
@Serializable
|
||||
data class GetGuildMemberInfo(
|
||||
@SerialName("tiny_id") val tinyId: ULong,
|
||||
@SerialName("nickname") val nickname: String,
|
||||
@SerialName("avatar_url") val avatarUrl: String,
|
||||
@SerialName("join_time") val joinTime: ULong,
|
||||
@SerialName("roles") val roles: List<RoleInfo>
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class RoleInfo(
|
||||
@SerialName("role_id") val roleId: String,
|
||||
@SerialName("role_name") val roleName: String,
|
||||
@SerialName("color") val color: Long,
|
||||
@SerialName("permission") val permission: List<Permission>,
|
||||
@SerialName("type") val type: Int,
|
||||
@SerialName("display_name") val displayName: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Permission(
|
||||
@SerialName("root_id") val rootId: Int,
|
||||
@SerialName("child_ids") val childIds: List<Int>
|
||||
)
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
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("get_guild_meta_by_guest")
|
||||
internal object GetGuildMetaByGuest: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
return invoke(guildId, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(guildId: ULong, echo: JsonElement = EmptyJsonString): String {
|
||||
val result = GProSvc.getGuildInfo(guildId)
|
||||
result.onFailure {
|
||||
return error(it.message ?: "unable to fetch guild info", echo)
|
||||
}
|
||||
val info = result.getOrThrow()
|
||||
if (info.meta == null) {
|
||||
return error("unable to fetch guild meta", echo)
|
||||
}
|
||||
val meta = info.meta!!
|
||||
return ok(GetGuildMetaByGuestResponse(
|
||||
guildId = info.guildId,
|
||||
guildName = meta.name ?: "",
|
||||
guildProfile = meta.profile ?: "",
|
||||
createTime = meta.createTime,
|
||||
maxMemberCount = meta.maxMemberCount,
|
||||
maxRobotCount = meta.robotMaxNum,
|
||||
maxAdminCount = meta.adminMaxNum,
|
||||
memberCount = meta.memberCount,
|
||||
ownerId = meta.ownerId,
|
||||
guildDisplayId = meta.displayId ?: ""
|
||||
), echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id")
|
||||
|
||||
@Serializable
|
||||
data class GetGuildMetaByGuestResponse(
|
||||
@SerialName("guild_id") val guildId: ULong,
|
||||
@SerialName("guild_name") val guildName: String,
|
||||
@SerialName("guild_profile") val guildProfile: String,
|
||||
@SerialName("create_time") val createTime: Long,
|
||||
@SerialName("max_member_count") val maxMemberCount: Long,
|
||||
@SerialName("max_robot_count") val maxRobotCount: Int,
|
||||
@SerialName("max_admin_count") val maxAdminCount: Int,
|
||||
@SerialName("member_count") val memberCount: Long,
|
||||
@SerialName("owner_id") val ownerId: ULong,
|
||||
@SerialName("guild_display_id") val guildDisplayId: String
|
||||
)
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildMemberProfile.Permission
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
|
||||
@OneBotHandler("get_guild_roles")
|
||||
internal object GetGuildRoles: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
return invoke(guildId, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(guildId: ULong, echo: JsonElement = EmptyJsonString): String {
|
||||
val result = GProSvc.getGuildRoles(guildId).onFailure {
|
||||
return error(it.message ?: "unable to fetch guild roles", echo)
|
||||
}.getOrThrow()
|
||||
return ok(GetGuildRolesResult(result.map {
|
||||
GuildRole(
|
||||
color = it.color,
|
||||
disabled = it.bHoist,
|
||||
independent = it.isChannelRole,
|
||||
maxCount = it.memberLimit,
|
||||
memberCount = it.count,
|
||||
owned = it.isNotSort,
|
||||
roleId = it.roleId,
|
||||
roleName = it.name,
|
||||
permission = it.rolePermissions.permissionList.map {
|
||||
Permission(it.rootId, it.childIds)
|
||||
},
|
||||
)
|
||||
}), echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id")
|
||||
|
||||
@Serializable
|
||||
data class GetGuildRolesResult(
|
||||
@SerialName("roles") val roles: List<GuildRole>
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GuildRole(
|
||||
@SerialName("argb_color") val color: Long,
|
||||
@SerialName("disabled") val disabled: Boolean,
|
||||
@SerialName("independent") val independent: Boolean,
|
||||
@SerialName("max_count") val maxCount: Int,
|
||||
@SerialName("member_count") val memberCount: Int,
|
||||
@SerialName("owned") val owned: Boolean,
|
||||
@SerialName("role_id") val roleId: Long,
|
||||
@SerialName("role_name") val roleName: String,
|
||||
@SerialName("permission") val permission: List<Permission>,
|
||||
)
|
||||
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.mobileqq.qqguildsdk.api.IGPSService
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
|
||||
@OneBotHandler("get_guild_service_profile")
|
||||
@ -15,18 +16,24 @@ internal object GetGuildServiceProfile : IActionHandler() {
|
||||
return invoke(echo = session.echo)
|
||||
}
|
||||
|
||||
operator fun invoke(echo: JsonElement = EmptyJsonString): String {
|
||||
// TODO: get_guild_service_profile
|
||||
return ok(EmptyJsonObject, echo, "此功能尚未实现")
|
||||
|
||||
val service = AppRuntimeFetcher.appRuntime
|
||||
.getRuntimeService(IGPSService::class.java, "all")
|
||||
if (!service.isGProSDKInitCompleted) {
|
||||
return error("GPro服务没有初始化", echo = echo)
|
||||
suspend operator fun invoke(echo: JsonElement = EmptyJsonString): String {
|
||||
val result = GProSvc.getSelfGuildInfo()
|
||||
result.onFailure {
|
||||
return error(it.message ?: "unable to fetch self guild info", echo)
|
||||
}
|
||||
|
||||
val tinyId = service.selfTinyId
|
||||
|
||||
return ok(echo = echo)
|
||||
val info = result.getOrThrow()
|
||||
//LogCenter.log(info.toString())
|
||||
return ok(GuildServiceProfile(
|
||||
nickName = info.nickName ?: info.memberName ?: "",
|
||||
tinyId = info.memberTinyid,
|
||||
avatarUrl = info.url ?: ""
|
||||
), echo = echo)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class GuildServiceProfile(
|
||||
@SerialName("nickname") val nickName: String,
|
||||
@SerialName("tiny_id") val tinyId: ULong,
|
||||
@SerialName("avatar_url") val avatarUrl: String,
|
||||
)
|
||||
}
|
@ -65,7 +65,7 @@ internal object GetHistoryMsg: IActionHandler() {
|
||||
msgId = msgHash,
|
||||
realId = msg.msgSeq.toInt(),
|
||||
sender = MessageSender(
|
||||
msg.senderUin, msg.sendNickName, "unknown", 0, msg.senderUid
|
||||
msg.senderUin, msg.sendNickName, "unknown", 0, msg.senderUid, msg.senderUid
|
||||
),
|
||||
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||
it.toJson()
|
||||
@ -89,7 +89,7 @@ internal object GetHistoryMsg: IActionHandler() {
|
||||
msg.senderUin, msg.sendNickName
|
||||
.ifEmpty { msg.sendMemberName }
|
||||
.ifEmpty { msg.sendRemarkName }
|
||||
.ifEmpty { msg.peerName }, "unknown", 0, msg.senderUid
|
||||
.ifEmpty { msg.peerName }, "unknown", 0, msg.senderUid, msg.senderUid
|
||||
),
|
||||
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||
it.toJson()
|
||||
|
@ -34,7 +34,10 @@ internal object GetMsg: IActionHandler() {
|
||||
msg.senderUin, msg.sendNickName
|
||||
.ifEmpty { msg.sendMemberName }
|
||||
.ifEmpty { msg.sendRemarkName }
|
||||
.ifEmpty { msg.peerName }, "unknown", 0, msg.senderUid
|
||||
.ifEmpty { msg.peerName }, "unknown",
|
||||
0,
|
||||
msg.senderUid,
|
||||
msg.senderUid
|
||||
),
|
||||
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||
it.toJson()
|
||||
|
@ -0,0 +1,112 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.MessageResult
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.tools.json
|
||||
import moe.fuqiuluo.shamrock.tools.jsonArray
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
|
||||
@OneBotHandler("send_guild_message", ["send_guild_msg", "send_guild_channel_msg"])
|
||||
internal object SendGuildMessage: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
val channelId = session.getString("channel_id").toULong()
|
||||
val retryCnt = session.getIntOrNull("retry_cnt") ?: 3
|
||||
val recallDuration = session.getLongOrNull("recall_duration")
|
||||
return if (session.isString("message")) {
|
||||
val autoEscape = session.getBooleanOrDefault("auto_escape", false)
|
||||
val message = session.getString("message")
|
||||
return invoke(guildId, channelId, message, autoEscape, retryCnt, recallDuration, echo = session.echo)
|
||||
} else if (session.isArray("message")) {
|
||||
val message = session.getArray("message")
|
||||
return invoke(guildId, channelId, message, echo = session.echo, retryCnt = retryCnt, recallDuration = recallDuration)
|
||||
} else {
|
||||
val message = session.getObject("message")
|
||||
invoke(guildId, channelId, listOf(message).jsonArray, session.echo, retryCnt, recallDuration = recallDuration)
|
||||
}
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
guildId: ULong,
|
||||
channelId: ULong,
|
||||
message: String,
|
||||
autoEscape: Boolean,
|
||||
retryCnt: Int,
|
||||
recallDuration: Long?,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val result = if (autoEscape) {
|
||||
MsgSvc.sendToAio(MsgConstant.KCHATTYPEGUILD, guildId.toString(), listOf(
|
||||
mapOf(
|
||||
"type" to "text",
|
||||
"data" to mapOf(
|
||||
"text" to message
|
||||
)
|
||||
)
|
||||
).json, fromId = channelId.toString(), retryCnt)
|
||||
} else {
|
||||
val msg = MessageHelper.decodeCQCode(message)
|
||||
if (msg.isEmpty()) {
|
||||
LogCenter.log("CQ码不合法", Level.WARN)
|
||||
return logic("CQCode is illegal", echo)
|
||||
} else {
|
||||
MsgSvc.sendToAio(MsgConstant.KCHATTYPEGUILD, guildId.toString(), msg, fromId = channelId.toString(), retryCnt)
|
||||
}
|
||||
}
|
||||
if (result.isFailure) {
|
||||
return logic(result.exceptionOrNull()?.message ?: "", echo)
|
||||
}
|
||||
val sendMsgResult = result.getOrThrow()
|
||||
if (sendMsgResult.msgHashId <= 0) {
|
||||
return logic("send message failed", echo = echo)
|
||||
}
|
||||
recallDuration?.let { autoRecall(sendMsgResult.msgHashId, it) }
|
||||
return ok(
|
||||
MessageResult(
|
||||
msgId = sendMsgResult.msgHashId,
|
||||
time = (sendMsgResult.msgTime * 0.001).toLong()
|
||||
), echo = echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
guildId: ULong, channelId: ULong, message: JsonArray, echo: JsonElement = EmptyJsonString, retryCnt: Int, recallDuration: Long?,
|
||||
): String {
|
||||
val result = MsgSvc.sendToAio(MsgConstant.KCHATTYPEGUILD, guildId.toString(), message, fromId = channelId.toString(), retryCnt)
|
||||
if (result.isFailure) {
|
||||
return logic(result.exceptionOrNull()?.message ?: "", echo)
|
||||
}
|
||||
val sendMsgResult = result.getOrThrow()
|
||||
if (sendMsgResult.msgHashId <= 0) {
|
||||
return logic("send message failed", echo = echo)
|
||||
}
|
||||
recallDuration?.let { autoRecall(sendMsgResult.msgHashId, it) }
|
||||
return ok(MessageResult(
|
||||
msgId = sendMsgResult.msgHashId,
|
||||
time = (sendMsgResult.msgTime * 0.001).toLong()
|
||||
), echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id", "channel_id", "message")
|
||||
|
||||
private fun autoRecall(msgHash: Int, duration: Long) {
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
delay(duration)
|
||||
MsgSvc.recallMsg(msgHash)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -81,9 +81,6 @@ internal object SendMessage: IActionHandler() {
|
||||
recallDuration: Long?,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
//if (!ContactHelper.checkContactAvailable(chatType, peerId)) {
|
||||
// return logic("contact is not found", echo = echo)
|
||||
//}
|
||||
val result = if (autoEscape) {
|
||||
MsgSvc.sendToAio(chatType, peerId, listOf(
|
||||
mapOf(
|
||||
|
@ -0,0 +1,42 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
|
||||
@OneBotHandler("set_guild_member_role")
|
||||
internal object SetGuildMemberRole: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
val role = session.getString("role_id").toULong()
|
||||
val set = session.getBooleanOrDefault("set", false)
|
||||
return if (session.has("user_id")) {
|
||||
val userId = session.getString("user_id").toULong()
|
||||
invoke(guildId, userId, role, set, echo = session.echo)
|
||||
} else if (session.isArray("users")) {
|
||||
invoke(guildId, session.getArray("users").map {
|
||||
it.asString.toULong()
|
||||
}, role, set, echo = session.echo)
|
||||
} else {
|
||||
logic("missing user_id or users", echo = session.echo)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun invoke(guildId: ULong, users: List<ULong>, roleId: ULong, set: Boolean, echo: JsonElement = EmptyJsonString): String {
|
||||
users.forEach {
|
||||
GProSvc.setMemberRole(guildId, it, roleId, set)
|
||||
}
|
||||
return ok("success", echo = echo)
|
||||
}
|
||||
|
||||
operator fun invoke(guildId: ULong, user: ULong, roleId: ULong, set: Boolean, echo: JsonElement = EmptyJsonString): String {
|
||||
GProSvc.setMemberRole(guildId, user, roleId, set)
|
||||
return ok("success", echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("guild_id", "role_id")
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
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("update_guild_role")
|
||||
internal object UpdateGuildRole: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val guildId = session.getString("guild_id").toULong()
|
||||
val roleId = session.getString("role_id").toULong()
|
||||
val name = session.getString("name")
|
||||
val color = session.getLong("color")
|
||||
return invoke(guildId, roleId, name, color, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(guildId: ULong, roleId: ULong, name: String, color: Long, echo: JsonElement = EmptyJsonString): String {
|
||||
val result = GProSvc.updateGuildRole(guildId, roleId, name, color).onFailure {
|
||||
return error(it.message ?: "Unknown error", echo)
|
||||
}
|
||||
return ok("success", echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("role_id", "guild_id", "name", "color")
|
||||
}
|
@ -1,33 +1,171 @@
|
||||
package moe.fuqiuluo.shamrock.remote.api
|
||||
|
||||
import com.tencent.mobileqq.qqguildsdk.api.IGPSService
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.response.respondText
|
||||
import io.ktor.server.routing.Routing
|
||||
import moe.fuqiuluo.shamrock.remote.structures.EmptyObject
|
||||
import io.ktor.server.routing.get
|
||||
import io.ktor.server.routing.post
|
||||
import io.ktor.server.routing.route
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.CreateGuildRole
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.DeleteGuildRole
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGProChannelList
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildFeeds
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildList
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildMemberList
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildMemberProfile
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildMetaByGuest
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildRoles
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildServiceProfile
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.SendGuildMessage
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.SendMessage
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.SetGuildMemberRole
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.UpdateGuildRole
|
||||
import moe.fuqiuluo.shamrock.tools.fetchGetOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.fetchGetOrThrow
|
||||
import moe.fuqiuluo.shamrock.tools.fetchOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.fetchOrThrow
|
||||
import moe.fuqiuluo.shamrock.tools.fetchPostJsonArray
|
||||
import moe.fuqiuluo.shamrock.tools.fetchPostJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.fetchPostJsonString
|
||||
import moe.fuqiuluo.shamrock.tools.fetchPostOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.fetchPostOrThrow
|
||||
import moe.fuqiuluo.shamrock.tools.getOrPost
|
||||
import moe.fuqiuluo.shamrock.tools.respond
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import moe.fuqiuluo.shamrock.tools.isJsonData
|
||||
import moe.fuqiuluo.shamrock.tools.isJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.isJsonString
|
||||
import moe.fuqiuluo.shamrock.tools.jsonArray
|
||||
|
||||
fun Routing.guildAction() {
|
||||
getOrPost("/get_guild_service_profile") {
|
||||
val service = AppRuntimeFetcher.appRuntime
|
||||
.getRuntimeService(IGPSService::class.java, "all")
|
||||
val tinyId = service.selfTinyId
|
||||
|
||||
}
|
||||
|
||||
getOrPost("/refresh_guild_list") {
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val guildService = sessionService.guildService
|
||||
guildService.refreshGuildList(true)
|
||||
respond(false, -100, msg = "测试接口", data = EmptyObject)
|
||||
call.respondText(GetGuildServiceProfile(), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_guild_list") {
|
||||
val refresh = fetchGetOrNull("refresh") ?: fetchOrNull("no_cache")
|
||||
call.respondText(GetGuildList(refresh?.toBoolean() ?: false, false), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
call.respondText("ok")
|
||||
getOrPost("/get_guild_member_list") {
|
||||
val guildId = fetchOrThrow("guild_id")
|
||||
val all = fetchGetOrNull("all")?.toBoolean() ?: false
|
||||
call.respondText(GetGuildMemberList(guildId.toULong(), all, fetchOrNull("next_token") ?: ""), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_guild_meta_by_guest") {
|
||||
val guildId = fetchOrThrow("guild_id")
|
||||
call.respondText(GetGuildMetaByGuest(guildId.toULong()), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_guild_channel_list") {
|
||||
val guildId = fetchOrThrow("guild_id")
|
||||
val refresh = fetchGetOrNull("refresh") ?: fetchOrNull("no_cache")
|
||||
call.respondText(GetGProChannelList(guildId.toULong(), refresh?.toBoolean() ?: false), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_guild_member_profile") {
|
||||
val guildId = fetchOrThrow("guild_id")
|
||||
val userId = fetchOrThrow("user_id")
|
||||
call.respondText(GetGuildMemberProfile(guildId.toULong(), userId.toULong()), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
route("/(send_guild_channel_msg|send_guild_message|send_guild_msg)".toRegex()) {
|
||||
get {
|
||||
val guildId = fetchGetOrThrow("guild_id").toULong()
|
||||
val channelId = fetchGetOrThrow("channel_id").toULong()
|
||||
val message = fetchGetOrThrow("message")
|
||||
val autoEscape = fetchGetOrNull("auto_escape")?.toBoolean() ?: false
|
||||
val retryCnt = fetchGetOrNull("retry_cnt")?.toInt() ?: 3
|
||||
val recallDuration = fetchGetOrNull("recall_duration")?.toLong()
|
||||
call.respondText(SendGuildMessage(guildId, channelId, message, autoEscape, retryCnt, recallDuration), ContentType.Application.Json)
|
||||
}
|
||||
post {
|
||||
val retryCnt = fetchOrNull("retry_cnt")?.toInt() ?: 3
|
||||
val recallDuration = fetchOrNull("recall_duration")?.toLong()
|
||||
val guildId = fetchOrThrow("guild_id").toULong()
|
||||
val channelId = fetchOrThrow("channel_id").toULong()
|
||||
call.respondText(if (isJsonData() && !isJsonString("message")) {
|
||||
if (isJsonObject("message")) {
|
||||
SendGuildMessage(
|
||||
guildId = guildId,
|
||||
channelId = channelId,
|
||||
message = listOf(fetchPostJsonObject("message")).jsonArray,
|
||||
retryCnt = retryCnt,
|
||||
recallDuration = recallDuration
|
||||
)
|
||||
} else {
|
||||
SendGuildMessage(
|
||||
guildId = guildId,
|
||||
channelId = channelId,
|
||||
message = fetchPostJsonArray("message"),
|
||||
retryCnt = retryCnt,
|
||||
recallDuration = recallDuration
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val autoEscape = fetchPostOrNull("auto_escape")?.toBooleanStrict() ?: false
|
||||
SendGuildMessage(
|
||||
guildId = guildId,
|
||||
channelId = channelId,
|
||||
message = fetchOrThrow("message"),
|
||||
autoEscape = autoEscape,
|
||||
retryCnt = retryCnt,
|
||||
recallDuration = recallDuration
|
||||
)
|
||||
}, ContentType.Application.Json)
|
||||
}
|
||||
}
|
||||
|
||||
getOrPost("/get_guild_feeds") {
|
||||
val guildId = fetchOrThrow("guild_id").toULong()
|
||||
val channelId = fetchOrNull("channel_id")?.toULong() ?: 0uL
|
||||
val from = fetchOrNull("from")?.toInt() ?: 0
|
||||
call.respondText(GetGuildFeeds(guildId, channelId, from), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_guild_roles") {
|
||||
val guildId = fetchOrThrow("guild_id").toULong()
|
||||
call.respondText(GetGuildRoles(guildId), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/delete_guild_role") {
|
||||
val guildId = fetchOrThrow("guild_id").toULong()
|
||||
val roleId = fetchOrThrow("role_id").toULong()
|
||||
call.respondText(DeleteGuildRole(guildId, roleId), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_guild_member_role") {
|
||||
val guildId = fetchOrThrow("guild_id").toULong()
|
||||
val roleId = fetchOrThrow("role_id").toULong()
|
||||
val set = fetchOrNull("set")?.toBoolean() ?: false
|
||||
val userId = fetchOrNull("user_id")?.toULong()
|
||||
val users = fetchOrNull("users")?.split(",")?.map { it.toULong() }
|
||||
call.respondText(
|
||||
if (userId != null) {
|
||||
SetGuildMemberRole(guildId, userId, roleId, set)
|
||||
} else if (users != null) {
|
||||
SetGuildMemberRole(guildId, users, roleId, set)
|
||||
} else {
|
||||
throw IllegalArgumentException("missing user_id or users")
|
||||
},
|
||||
ContentType.Application.Json
|
||||
)
|
||||
}
|
||||
|
||||
getOrPost("/update_guild_role") {
|
||||
val guildId = fetchOrThrow("guild_id").toULong()
|
||||
val roleId = fetchOrThrow("role_id").toULong()
|
||||
val name = fetchOrThrow("name")
|
||||
val color = fetchOrThrow("color").toLong()
|
||||
call.respondText(UpdateGuildRole(guildId, roleId, name, color), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/create_guild_role") {
|
||||
val guildId = fetchOrThrow("guild_id").toULong()
|
||||
val name = fetchOrThrow("name")
|
||||
val color = fetchOrThrow("color").toLong()
|
||||
val initialUsers = fetchOrThrow("initial_users").split(",").map { it.toULong() }
|
||||
call.respondText(CreateGuildRole(guildId, color, name, initialUsers), ContentType.Application.Json)
|
||||
}
|
||||
}
|
@ -74,7 +74,7 @@ internal object GlobalEventTransmitter: BaseSvc() {
|
||||
peerId = uin,
|
||||
userId = record.senderUin,
|
||||
message = if(ShamrockConfig.useCQ()) rawMsg.json
|
||||
else elements.toSegments(record.chatType, record.peerUin.toString()).map {
|
||||
else elements.toSegments(record.chatType, record.peerUin.toString(), "0").map {
|
||||
it.toJson()
|
||||
}.json,
|
||||
rawMessage = rawMsg,
|
||||
@ -129,7 +129,7 @@ internal object GlobalEventTransmitter: BaseSvc() {
|
||||
peerId = botUin,
|
||||
userId = record.senderUin,
|
||||
message = if(ShamrockConfig.useCQ()) rawMsg.json
|
||||
else elements.toSegments(record.chatType, record.peerUin.toString()).map {
|
||||
else elements.toSegments(record.chatType, record.peerUin.toString(), "0").map {
|
||||
it.toJson()
|
||||
}.json,
|
||||
rawMessage = rawMsg,
|
||||
@ -147,6 +147,54 @@ internal object GlobalEventTransmitter: BaseSvc() {
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送私聊消息
|
||||
*/
|
||||
suspend fun transGuildMessage(
|
||||
record: MsgRecord,
|
||||
elements: ArrayList<MsgElement>,
|
||||
rawMsg: String,
|
||||
msgHash: Int,
|
||||
postType: PostType,
|
||||
): Boolean {
|
||||
val botUin = app.longAccountUin
|
||||
var nickName = record.sendNickName
|
||||
if (nickName.isNullOrEmpty()) {
|
||||
CardSvc.getProfileCard(record.senderUin.toString()).onSuccess {
|
||||
nickName = it.strNick ?: record.peerName
|
||||
}
|
||||
}
|
||||
transMessageEvent(record,
|
||||
MessageEvent(
|
||||
time = record.msgTime,
|
||||
selfId = botUin,
|
||||
postType = postType,
|
||||
messageType = MsgType.Guild,
|
||||
subType = MsgSubType.Channel,
|
||||
messageId = msgHash,
|
||||
targetId = record.peerUin,
|
||||
peerId = botUin,
|
||||
userId = record.senderUid.toLong(),
|
||||
message = if(ShamrockConfig.useCQ()) rawMsg.json
|
||||
else elements.toSegments(record.chatType, record.guildId, record.channelId).map {
|
||||
it.toJson()
|
||||
}.json,
|
||||
rawMessage = rawMsg,
|
||||
font = 0,
|
||||
sender = Sender(
|
||||
userId = record.senderUid.toLong(),
|
||||
nickname = nickName,
|
||||
card = record.sendMemberName,
|
||||
role = MemberRole.Member,
|
||||
title = record.sendNickName,
|
||||
level = record.roleId.toString(),
|
||||
tinyId = record.senderUid
|
||||
),
|
||||
)
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,19 +39,46 @@ internal object ShamrockConfig {
|
||||
fun updateConfig(intent: Intent) {
|
||||
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
|
||||
mmkv.apply {
|
||||
putBoolean( "tablet", intent.getBooleanExtra("tablet", false)) // 强制平板模式
|
||||
putInt( "port", intent.getIntExtra("port", 5700)) // 主动HTTP端口
|
||||
putBoolean( "ws", intent.getBooleanExtra("ws", false)) // 主动WS开关
|
||||
putBoolean( "http", intent.getBooleanExtra("http", false)) // HTTP回调开关
|
||||
putString( "http_addr", intent.getStringExtra("http_addr")) // WebHook回调地址
|
||||
putBoolean( "ws_client", intent.getBooleanExtra("ws_client", false)) // 被动WS开关
|
||||
putBoolean( "use_cqcode", intent.getBooleanExtra("use_cqcode", false)) // 使用CQ码
|
||||
putBoolean( "inject_packet", intent.getBooleanExtra("inject_packet", false)) // 拦截无用包
|
||||
putBoolean( "debug", intent.getBooleanExtra("debug", false)) // 调试模式
|
||||
|
||||
if (!intent.getBooleanExtra("disable_auto_sync_setting", false)) {
|
||||
putBoolean(
|
||||
"tablet",
|
||||
intent.getBooleanExtra("tablet", false)
|
||||
) // 强制平板模式
|
||||
putInt("port", intent.getIntExtra("port", 5700)) // 主动HTTP端口
|
||||
putBoolean("ws", intent.getBooleanExtra("ws", false)) // 主动WS开关
|
||||
putBoolean(
|
||||
"http",
|
||||
intent.getBooleanExtra("http", false)
|
||||
) // HTTP回调开关
|
||||
putString(
|
||||
"http_addr",
|
||||
intent.getStringExtra("http_addr")
|
||||
) // WebHook回调地址
|
||||
putBoolean(
|
||||
"ws_client",
|
||||
intent.getBooleanExtra("ws_client", false)
|
||||
) // 被动WS开关
|
||||
putBoolean(
|
||||
"use_cqcode",
|
||||
intent.getBooleanExtra("use_cqcode", false)
|
||||
) // 使用CQ码
|
||||
putBoolean(
|
||||
"inject_packet",
|
||||
intent.getBooleanExtra("inject_packet", false)
|
||||
) // 拦截无用包
|
||||
putBoolean("debug", intent.getBooleanExtra("debug", false)) // 调试模式
|
||||
putString( "key_store", intent.getStringExtra("key_store")) // 证书路径
|
||||
putString( "ssl_pwd", intent.getStringExtra("ssl_pwd")) // 证书密码
|
||||
putString( "ssl_private_pwd", intent.getStringExtra("ssl_private_pwd")) // 证书私钥密码
|
||||
putString( "ssl_alias", intent.getStringExtra("ssl_alias")) // 证书别名
|
||||
putInt( "ssl_port", intent.getIntExtra("ssl_port", 5701)) // 主动HTTP端口
|
||||
putBoolean("alive_reply", intent.getBooleanExtra("alive_reply", false)) // 自回复测试
|
||||
putBoolean("enable_self_msg", intent.getBooleanExtra("enable_self_msg", false)) // 推送自己发的消息
|
||||
putBoolean("shell", intent.getBooleanExtra("shell", false)) // 开启Shell接口
|
||||
putBoolean("enable_sync_msg_as_sent_msg", intent.getBooleanExtra("enable_sync_msg_as_sent_msg", false)) // 推送同步消息
|
||||
}
|
||||
Config.defaultToken = intent.getStringExtra("token")
|
||||
Config.antiTrace = intent.getBooleanExtra("anti_qq_trace", true)
|
||||
|
||||
val wsPort = intent.getIntExtra("ws_port", 5800)
|
||||
Config.activeWebSocket = if (Config.activeWebSocket == null) ConnectionConfig(
|
||||
address = "0.0.0.0",
|
||||
@ -59,28 +86,17 @@ internal object ShamrockConfig {
|
||||
) else Config.activeWebSocket?.also {
|
||||
it.port = wsPort
|
||||
}
|
||||
|
||||
Config.passiveWebSocket = intent.getStringExtra("ws_addr")?.split(",", "|", ",")?.filter { address ->
|
||||
address.isNotBlank() && (address.startsWith("ws://") || address.startsWith("wss://"))
|
||||
}?.map {
|
||||
ConnectionConfig(address = it)
|
||||
}?.toMutableList()
|
||||
|
||||
putString( "key_store", intent.getStringExtra("key_store")) // 证书路径
|
||||
putString( "ssl_pwd", intent.getStringExtra("ssl_pwd")) // 证书密码
|
||||
putString( "ssl_private_pwd", intent.getStringExtra("ssl_private_pwd")) // 证书私钥密码
|
||||
putString( "ssl_alias", intent.getStringExtra("ssl_alias")) // 证书别名
|
||||
putInt( "ssl_port", intent.getIntExtra("ssl_port", 5701)) // 主动HTTP端口
|
||||
|
||||
putBoolean("alive_reply", intent.getBooleanExtra("alive_reply", false)) // 自回复测试
|
||||
|
||||
putBoolean("enable_self_msg", intent.getBooleanExtra("enable_self_msg", false)) // 推送自己发的消息
|
||||
putBoolean("shell", intent.getBooleanExtra("shell", false)) // 开启Shell接口
|
||||
putBoolean("enable_sync_msg_as_sent_msg", intent.getBooleanExtra("enable_sync_msg_as_sent_msg", false)) // 推送同步消息
|
||||
|
||||
putBoolean("isInit", true)
|
||||
}
|
||||
updateConfig()
|
||||
if (!intent.getBooleanExtra("disable_auto_sync_setting", false)) {
|
||||
updateConfig()
|
||||
}
|
||||
}
|
||||
|
||||
private val mmkv: MMKV
|
||||
|
@ -35,6 +35,7 @@ internal data class MessageSender(
|
||||
@SerialName("sex") val sex: String,
|
||||
@SerialName("age") val age: Int,
|
||||
@SerialName("uid") val uid: String,
|
||||
@SerialName("tiny_id") val tinyId: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
@ -21,12 +21,15 @@ internal enum class MsgSubType {
|
||||
@SerialName("group") GroupLess,
|
||||
@SerialName("friend") Friend,
|
||||
@SerialName("other") Other,
|
||||
|
||||
@SerialName("channel") Channel
|
||||
}
|
||||
|
||||
@Serializable
|
||||
internal enum class MsgType {
|
||||
@SerialName("group") Group,
|
||||
@SerialName("private") Private
|
||||
@SerialName("private") Private,
|
||||
@SerialName("guild") Guild
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@ -94,4 +97,5 @@ internal data class Sender(
|
||||
@SerialName("role") val role: MemberRole?,
|
||||
@SerialName("title") val title: String,
|
||||
@SerialName("level") val level: String,
|
||||
@SerialName("tiny_id") val tinyId: String = "0",
|
||||
)
|
@ -38,8 +38,6 @@ internal object AioListener : IKernelMsgListener {
|
||||
|
||||
private suspend fun handleMsg(record: MsgRecord) {
|
||||
try {
|
||||
if (record.chatType == MsgConstant.KCHATTYPEGUILD) return // TODO: 频道消息暂不处理
|
||||
|
||||
messageLessListenerMap.firstNotNullOfOrNull {
|
||||
if (it.key == record.msgSeq) it else null
|
||||
}?.let {
|
||||
@ -50,17 +48,22 @@ internal object AioListener : IKernelMsgListener {
|
||||
|
||||
val msgHash = MessageHelper.generateMsgIdHash(record.chatType, record.msgId)
|
||||
|
||||
val peerId = when(record.chatType) {
|
||||
MsgConstant.KCHATTYPEGUILD -> record.guildId
|
||||
else -> record.peerUin.toString()
|
||||
}
|
||||
MessageHelper.saveMsgMapping(
|
||||
hash = msgHash,
|
||||
qqMsgId = record.msgId,
|
||||
chatType = record.chatType,
|
||||
subChatType = record.chatType,
|
||||
peerId = record.peerUin.toString(),
|
||||
peerId = peerId,
|
||||
msgSeq = record.msgSeq.toInt(),
|
||||
time = record.msgTime
|
||||
time = record.msgTime,
|
||||
subPeerId = record.channelId ?: peerId
|
||||
)
|
||||
|
||||
val rawMsg = record.elements.toCQCode(record.chatType, record.peerUin.toString())
|
||||
val rawMsg = record.elements.toCQCode(record.chatType, peerId, record.channelId ?: peerId)
|
||||
if (rawMsg.isEmpty()) return
|
||||
|
||||
if (ShamrockConfig.aliveReply() && rawMsg == "ping") {
|
||||
@ -119,6 +122,16 @@ internal object AioListener : IKernelMsgListener {
|
||||
LogCenter.log("私聊临时消息推送失败 -> MessageTransmitter", Level.WARN)
|
||||
}
|
||||
}
|
||||
|
||||
MsgConstant.KCHATTYPEGUILD -> {
|
||||
LogCenter.log("频道消息(guildId = ${record.guildId}, sender=${record.senderUid}, id = [$msgHash | ${record.msgId}], msg = $rawMsg)")
|
||||
if(!GlobalEventTransmitter.MessageTransmitter
|
||||
.transGuildMessage(record, record.elements, rawMsg, msgHash, postType = postType)
|
||||
) {
|
||||
LogCenter.log("频道消息推送失败 -> MessageTransmitter", Level.WARN)
|
||||
}
|
||||
}
|
||||
|
||||
else -> LogCenter.log("不支持PUSH事件: ${record.chatType}")
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
@ -131,21 +144,25 @@ internal object AioListener : IKernelMsgListener {
|
||||
}
|
||||
|
||||
override fun onAddSendMsg(record: MsgRecord) {
|
||||
if (record.chatType == MsgConstant.KCHATTYPEGUILD) return // TODO: 频道消息暂不处理
|
||||
if (record.peerUin == TicketSvc.getLongUin()) return // 发给自己的消息不处理
|
||||
|
||||
GlobalScope.launch {
|
||||
try {
|
||||
val msgHash = MessageHelper.generateMsgIdHash(record.chatType, record.msgId)
|
||||
|
||||
val peerId = when(record.chatType) {
|
||||
MsgConstant.KCHATTYPEGUILD -> record.guildId
|
||||
else -> record.peerUin.toString()
|
||||
}
|
||||
MessageHelper.saveMsgMapping(
|
||||
hash = msgHash,
|
||||
qqMsgId = record.msgId,
|
||||
chatType = record.chatType,
|
||||
subChatType = record.chatType,
|
||||
peerId = record.peerUin.toString(),
|
||||
peerId = peerId,
|
||||
msgSeq = record.msgSeq.toInt(),
|
||||
time = record.msgTime
|
||||
time = record.msgTime,
|
||||
subPeerId = record.channelId ?: peerId
|
||||
)
|
||||
|
||||
LogCenter.log("预发送消息($msgHash | ${record.msgSeq} | ${record.msgId})")
|
||||
@ -167,6 +184,10 @@ internal object AioListener : IKernelMsgListener {
|
||||
|
||||
GlobalScope.launch {
|
||||
val msgHash = MessageHelper.generateMsgIdHash(record.chatType, record.msgId)
|
||||
val peerId = when(record.chatType) {
|
||||
MsgConstant.KCHATTYPEGUILD -> record.guildId
|
||||
else -> record.peerUin.toString()
|
||||
}
|
||||
|
||||
val mapping = MessageHelper.getMsgMappingByHash(msgHash)
|
||||
if (mapping == null) {
|
||||
@ -175,9 +196,10 @@ internal object AioListener : IKernelMsgListener {
|
||||
qqMsgId = record.msgId,
|
||||
chatType = record.chatType,
|
||||
subChatType = record.chatType,
|
||||
peerId = record.peerUin.toString(),
|
||||
peerId = peerId,
|
||||
msgSeq = record.msgSeq.toInt(),
|
||||
time = record.msgTime
|
||||
time = record.msgTime,
|
||||
subPeerId = record.channelId ?: peerId
|
||||
)
|
||||
} else {
|
||||
LogCenter.log("Update message info from ${mapping.msgSeq} to ${record.msgSeq}", Level.INFO)
|
||||
@ -190,7 +212,7 @@ internal object AioListener : IKernelMsgListener {
|
||||
|| record.peerUin == TicketSvc.getLongUin()
|
||||
) return@launch
|
||||
|
||||
val rawMsg = record.elements.toCQCode(record.chatType, record.peerUin.toString())
|
||||
val rawMsg = record.elements.toCQCode(record.chatType, peerId, record.channelId ?: peerId)
|
||||
if (rawMsg.isEmpty()) return@launch
|
||||
LogCenter.log("自发消息(target = ${record.peerUin}, id = $msgHash, msg = $rawMsg)")
|
||||
|
||||
|
@ -31,8 +31,21 @@ import moe.fuqiuluo.shamrock.tools.asJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.shamrock.tools.readBuf32Long
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.PacketHandler
|
||||
import moe.whitechi73.protobuf.message.*
|
||||
import moe.whitechi73.protobuf.push.*
|
||||
import protobuf.message.MessageContentHead
|
||||
import protobuf.message.MessageHead
|
||||
import protobuf.message.RichMessage
|
||||
import protobuf.push.C2CCommonTipsEvent
|
||||
import protobuf.push.C2CRecallEvent
|
||||
import protobuf.push.FriendApplyEvent
|
||||
import protobuf.push.GroupAdminChangeEvent
|
||||
import protobuf.push.GroupApplyEvent
|
||||
import protobuf.push.GroupBanEvent
|
||||
import protobuf.push.GroupCommonTipsEvent
|
||||
import protobuf.push.GroupInviteEvent
|
||||
import protobuf.push.GroupInvitedApplyEvent
|
||||
import protobuf.push.GroupListChangeEvent
|
||||
import protobuf.push.MessagePush
|
||||
import protobuf.push.MessagePushClientInfo
|
||||
|
||||
internal object PrimitiveListener {
|
||||
fun registerListener() {
|
||||
@ -579,7 +592,7 @@ internal object PrimitiveListener {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun onInviteGroup(time: Long, msgHead: MessageHead,richMsg: RichMessage) {
|
||||
private suspend fun onInviteGroup(time: Long, msgHead: MessageHead, richMsg: RichMessage) {
|
||||
val event = ProtoBuf.decodeFromByteArray<GroupInviteEvent>(richMsg.rawBuffer!!)
|
||||
val groupCode = event.groupCode
|
||||
val invitorUid = event.inviterUid
|
||||
|
@ -18,6 +18,10 @@ import kotlin.random.Random
|
||||
internal object PlatformUtils {
|
||||
const val QQ_9_0_8_VER = 5540
|
||||
|
||||
fun getQUA(): String {
|
||||
return "V1_AND_SQ_${getQQVersion(MobileQQ.getContext())}_${getQQVersionCode()}_YYB_D"
|
||||
}
|
||||
|
||||
fun getQQVersion(context: Context): String {
|
||||
val packageInfo: PackageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
||||
return packageInfo.versionName
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user