188 Commits
1.0.8 ... 1.1.1

Author SHA1 Message Date
40d2911135 修复资源rkey获取异常 2024-07-16 17:47:39 +08:00
823d9911a0 fix #338 2024-07-16 17:11:48 +08:00
4adbc12a0b fix /get_group_root_files 2024-07-08 09:53:15 +08:00
114fbfdd23 fix /get_group_root_files 2024-07-08 09:44:26 +08:00
0a563d60a1 fix crash in QQ9.0.71 2024-07-08 09:17:56 +08:00
5fb1d0aeb9 fix ping-pong 2024-07-08 09:11:49 +08:00
012ecaa85d fix #335 2024-07-08 08:55:49 +08:00
7ea127a279 update shamrock 2024-07-08 08:15:05 +08:00
02f83a3c48 fix: remove debug log 2024-07-07 15:26:30 +08:00
4016c05882 fix: 9.0.71 compatible issues (part of) 2024-07-07 15:04:30 +08:00
59d762eecf fix https://github.com/KarinJS/kritor/issues/10 2024-04-11 12:37:54 +08:00
e891bc8512 fix build 2024-04-11 01:17:13 +08:00
494c70f2f8 update kritor 2024-04-11 00:58:36 +08:00
7baf459b2a Shamrock: fix scene and group code 2024-04-10 21:09:10 +08:00
36a09ca088 update kritor 2024-04-08 20:00:44 +08:00
926c4659f6 Shamrock: add kritor metadata 2024-04-07 16:51:21 +08:00
cb7c68f36c fix: build error 2024-04-07 16:27:35 +08:00
72af39208c update kritor 2024-04-07 16:08:33 +08:00
042f4bd330 fix build err 2024-04-04 19:44:56 +08:00
9aef71b09f fix build err 2024-04-04 18:56:48 +08:00
9cbe755520 fix missing elem-type for kritor 2024-04-04 18:51:58 +08:00
df02f9f872 fix #316 2024-03-28 19:37:10 +08:00
5cbb695a66 fix crash 2024-03-28 19:27:11 +08:00
c014e85faa update kritor 2024-03-27 16:21:49 +08:00
4a396b0935 Update kritor 2024-03-25 01:12:59 +08:00
d59fcf9f6a update kritor 2024-03-25 01:10:33 +08:00
cdc664f44a fix build error 2024-03-24 05:33:57 +08:00
ad313f384c fix kritor 2024-03-24 05:19:50 +08:00
b6a510ce05 Update .gitmodules 2024-03-21 19:35:16 +08:00
bed5947909 update kritor 2024-03-21 19:15:58 +08:00
fb6578d243 chore: try to fix ci 2024-03-21 17:50:39 +08:00
d33cace7aa Shamrock: forward messages resources upload 2024-03-21 17:39:51 +08:00
659d4e5da4 commit Readme.md 2024-03-21 16:21:54 +08:00
ac2aee8c0e 関連プロジェクトのヒントを追加する 2024-03-21 16:17:25 +08:00
0faada7b5a Merge pull request #310 from whitechi73/kritor
kritorをmasterブランチに設定する
2024-03-21 16:15:12 +08:00
680317da13 kritorをmasterブランチに設定する
kritorをmasterブランチに設定する
2024-03-21 16:13:45 +08:00
7782feb6ac Merge pull request #303 from tobycroft/master
GetFile的type新增gzip,会将数据流压缩后再b64降低带宽占用
2024-03-18 22:43:18 +08:00
d66358a1f3 Shamrock: 提供开发者服务支持
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-18 21:02:05 +08:00
824f280b3a 修改error 提示 2024-03-18 15:40:14 +08:00
6936262d62 GetFile的type新增gzip,会将数据流压缩后再b64降低带宽占用
- 使用gzip压缩
2024-03-18 15:24:24 +08:00
0955267ee5 Merge branch 'whitechi73:master' into master 2024-03-18 13:56:26 +08:00
f3da62fa74 GetFile的type新增gzip,会将数据流压缩后再b64降低带宽占用
- 使用gzip压缩
2024-03-18 13:49:03 +08:00
abbac6315c Merge pull request #301 from tobycroft/master
新增get_file方法(算是补全下功能)
2024-03-18 13:34:51 +08:00
0cf10eabd6 fix: set field file_type not required 2024-03-18 13:34:13 +08:00
8c33267887 fileType加入空匹配,可支持空传 2024-03-18 13:30:18 +08:00
f030104ff2 get_record的ws加入单独的md5字段,方便后续get_file拿文件 2024-03-18 13:23:20 +08:00
ee5fcc3403 Shamrock: 精华消息支持
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-18 11:49:38 +08:00
5e819179b4 get_record的ws加入单独的md5字段,方便后续get_file拿文件 2024-03-18 04:08:07 +08:00
ea206faf4f get_record的ws加入单独的md5字段,方便后续get_file拿文件 2024-03-18 04:07:11 +08:00
5adfc544a2 修正file_type参数不正确问题 2024-03-18 03:46:51 +08:00
bdb75841cf AGP更新 2024-03-18 03:23:11 +08:00
a3dc0d06b2 新增get_file方法,主要解决使用反向websocket的时候获取文件麻烦的问题,目前仅支持base64的type返回,未来将支持更多模式,测试后将发布至文档 2024-03-18 03:17:36 +08:00
3664352f23 新增get_file方法,主要解决使用反向websocket的时候获取文件麻烦的问题,目前仅支持base64的type返回,未来将支持更多模式,测试后将发布至文档 2024-03-18 03:05:28 +08:00
2770979fee 新增get_file方法,主要解决使用反向websocket的时候获取文件麻烦的问题,目前仅支持base64的type返回,未来将支持更多模式,测试后将发布至文档 2024-03-18 02:57:44 +08:00
6c9b282c6a Shamrock: 实现消息服务
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-16 19:39:45 +08:00
3a07116093 Shamrock: 实现事件推送
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-15 01:37:28 +08:00
be58c368e9 Merge pull request #295 from tobycroft/master
notice类消息,新增source字段
2024-03-15 00:34:42 +08:00
a95d8d85e8 Shamrock: 完成消息推送
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-14 20:33:30 +08:00
1d035fa378 Shamrock: fix 群聊和私聊转发分别处理 2024-03-14 18:57:45 +08:00
7d0b60271e Shamrock: fix 群聊转发图片 2024-03-14 18:25:01 +08:00
d38777d06a notice类消息,新增source,解决poke等特殊消息没有办法直接判断消息来源的问题。修改后通过notice类消息的source字段,则可判断需要使用那种struct来接收 2024-03-14 15:05:01 +08:00
7bacea3288 Shamrock: イベントプッシュの実装
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-12 21:02:36 +08:00
ca47f9dbdf Shamrock: グループファイルサービスの実装
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-12 18:46:05 +08:00
cb4268edef Shamrock: 实现Kritor核心服务
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-11 12:48:11 +08:00
c16f9d543c Shamrock: 实现联系人服务
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-11 12:30:42 +08:00
93c49953cf Merge pull request #289 from Linwenxuan05/patch-1
添加相关项目
2024-03-11 11:45:56 +08:00
883e949cc1 添加相关项目 2024-03-11 11:41:46 +08:00
a528030cbb Shamrock: 实现鉴权操作
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 16:05:20 +08:00
bbdfb7c04e Shamrock: 实现鉴权
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 16:04:52 +08:00
1afc0ac6a6 Shamrock: 修复服务器TLS异常
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 07:57:23 +08:00
638bf72392 Shamrock: 修复配置文件下发
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 07:44:02 +08:00
07364c8298 Shamrock: 修复kritor构建错误
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 02:26:53 +08:00
ee6e13a5bb Shamrock: 修正频道proto文件错误
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 01:58:18 +08:00
c3934778c7 Shamrock: 修正频道proto文件错误
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 01:56:02 +08:00
13a49dd70b Shamrock: 添加对kritor的依赖
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 01:00:20 +08:00
5637db43be Shamrock: 重构收包起,减少拷贝
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-10 00:33:26 +08:00
69cdbad643 Shamrock: rm CIO
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-08 01:19:26 +08:00
a06708bf95 Shamrock: build for kritor
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-08 01:11:24 +08:00
2ac0003166 Shamrock: fix wrong check field name 2024-03-05 13:25:56 +08:00
d92d1daffb 统一发送图片时的参数 (#276)
* 统一发送图片时的请求参数

* 修改另一个 ElemMaker
2024-03-04 01:13:21 +08:00
27f837adbe Shamrock: 支持NT图片合并转发
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-02 18:03:13 +08:00
661680e60b Shamrock: 绕过资源上传检测
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-01 20:29:28 +08:00
54b7eb95a8 Shamrock: 修复真机反检测异常
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-03-01 20:29:13 +08:00
265fff3cd2 Merge pull request #271 from PisLuanyao/master
fix termination by PullConfig for Emu
2024-03-01 18:04:46 +08:00
8ca0a3815a Merge branch 'whitechi73:master' into master 2024-03-01 17:50:16 +09:00
da6d34c53e fix Crash for Emu
强制初始化配置
2024-03-01 16:48:49 +08:00
61ffb37951 Merge pull request #269 from PisLuanyao/master
fix NativeLoader for Emu
2024-03-01 15:40:44 +08:00
593f461ffe fix NativeLoader for Emu
发现 isEmu 里反射的有问题,会出现 java.lang.NoSuchFieldException: No field vmInstructionSet in class Ldalvik/system/VMRuntime; (declaration of 'dalvik.system.VMRuntime' appears in /system/framework/core-libart.jar)
2024-03-01 14:57:21 +08:00
12d594697d fix buttons 2024-03-01 09:40:31 +08:00
352aa5f737 Merge pull request #268 from huankong233/master
修正错误部分错误
2024-03-01 01:34:47 +08:00
9546e90bec 修正报错无法通过 Websocket 返回 2024-03-01 00:23:46 +08:00
26b4d95ad8 修正错误的拼写 2024-02-29 23:56:00 +08:00
4a6109fbe6 修正 websocket 中 alias 的名称
修正 QuickOperation 中 错误的返回
2024-02-29 23:35:23 +08:00
d6142173c9 Merge pull request #267 from PisLuanyao/master
NativeLoader
2024-02-29 22:42:01 +08:00
38cf806b40 Shamrock: review
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-29 22:40:36 +08:00
82269bb171 NativeLoader
应该是这样关?
猫脑过载.png
2024-02-29 20:43:18 +08:00
fc0d7a62af NativeLoader
修复isEmu里因手残导致的问题
2024-02-29 19:32:36 +08:00
60fdfd9071 Shamrock: fix #265
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-29 11:34:32 +08:00
1f620bcc06 NativeLoader
现在,可以在HMA做了隐藏的情况下正确加载库文件

借鉴过来的,貌似会导致亿点问题

感觉isEmu也会翻车呢  ┭┮﹏┭┮
2024-02-29 11:29:26 +08:00
737acfa41b Shamrock: Rollback 52ec43abf80d6595d1fe3b490ebe1bfc23bf0ab8 commit
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-29 10:42:36 +08:00
3619cba33c Shamrock: Fix interface(get_img) support for nt
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-29 09:58:21 +08:00
52ec43abf8 Shamrock: fix nt image error in very old qq
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-29 09:41:56 +08:00
e96c356de4 禁止版本9.0.20基于getPackageGids的检测 (#263)
* 禁止基于getPackageGids的检测
2024-02-29 01:19:49 +08:00
bbdb0a65fb add alias for websocket (#262)
Co-authored-by: Simplxs <simplxsa@gmail.com>
2024-02-28 21:58:58 +08:00
ec56e32be1 refactor send_forward_msg 2024-02-28 21:51:06 +08:00
4dc83fdeba Shamrock: add real_id for long msg
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-28 00:03:47 +08:00
541422a43e Shamrock: fix #260
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-27 22:35:31 +08:00
cb7bf00e17 Shamrock: Automatically remove group forward messages
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-27 22:25:38 +08:00
a3171b3111 Shamrock: fix #259
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-27 16:53:32 +08:00
02626489eb Shamrock: fix remove redundant dollar 2024-02-27 13:05:36 +08:00
a9a2e9a3dd Shamrock: fix #258
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-26 20:59:29 +08:00
964c55de31 Shamrock: fix #256
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-26 20:51:45 +08:00
befb4a2bef Merge pull request #257 from huankong233/master
add `delete_delay` option in QuickOperation
2024-02-26 20:50:04 +08:00
210609bd7b use coroutines 2024-02-26 18:51:05 +08:00
3e03d4782d fix 2024-02-26 18:31:10 +08:00
675a7a5321 refactor InlineKeyboard 2024-02-26 17:11:48 +08:00
a78b5cab23 add delete_delay option in QuickOperation 2024-02-26 15:05:13 +08:00
252a3527a8 Merge remote-tracking branch 'origin/master' 2024-02-25 17:32:07 +08:00
ea4cf06edf Shamrock: 修复download_file指定名称失败
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-25 17:31:57 +08:00
1424efd7f8 send_forward_msg(support image) 2024-02-25 14:33:59 +08:00
eb807a0332 Shamrock: support upload resource by NtKernel x3
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-25 12:46:40 +08:00
e9a3a82b68 Shamrock: support upload resource by NtKernel x2
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-25 12:40:39 +08:00
fca66f3259 Shamrock: support upload resource by NtKernel
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-25 11:42:42 +08:00
92ebe0c6a8 send_forward_msg(support markdown, button...) 2024-02-25 04:10:29 +08:00
6b1147d065 Shamrock: fix #252
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-25 03:38:09 +08:00
720313124c Shamrock: support requestUploadGroupPic
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-25 03:27:55 +08:00
68ea62ea0b fix get_group_files_by_folder 2024-02-24 19:27:09 +08:00
5584a41af0 fix get_group_msg_history 2024-02-24 18:58:35 +08:00
0bca46bba3 upgrade kotlin 2024-02-24 17:51:02 +08:00
4f1d19fcbd upgrade kotlin version to 1.9.22 2024-02-24 16:25:31 +08:00
9a85e4d537 replace all group_id and user_id to Long 2024-02-24 16:25:31 +08:00
fac92d8094 Merge remote-tracking branch 'origin/master' 2024-02-24 12:32:02 +08:00
605f58da47 Shamrock: Using the NT kernel to upload resources
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-24 12:31:51 +08:00
d22f3ad1cb send_forward_msg(support at face...) 2024-02-24 02:14:56 +08:00
46ed966c18 Shamrock: recommend Lagrange
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-24 01:01:41 +08:00
623dc5da07 Shamrock: fix all multimedia pic fetch
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-24 00:34:28 +08:00
bd6d4f046c Shamrock: Remove rkey cache
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-23 20:52:44 +08:00
9ad66f2f92 Shamrock: fix #251
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-23 19:33:36 +08:00
b4c40e236a Shamrock: 快速序列化/反序列化 Protobuf
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-23 18:23:02 +08:00
9bbcc2f160 Shamrock: 允许私聊接收multimedia资源图片 #251
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-23 14:17:52 +08:00
00b355b877 Shamrock: fix #248
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-23 08:36:34 +08:00
071ddbb69a Shamrock: update LICENSE
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-22 18:13:55 +08:00
4d5c054bc4 Shamrock: 开源开发许可证
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-22 18:12:31 +08:00
87629666f2 refactor send_forward_msg(暂时只支持收发文字消息) 2024-02-22 01:04:56 +08:00
75633f78c4 Shamrock: fix #248
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-21 21:31:59 +08:00
c940aea153 Shamrock: Reusable and restrictive coroutine context
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-21 15:17:53 +08:00
18126b1fda fix bug 2024-02-21 02:16:47 +08:00
e9884a5fa8 fix bug(暂未完成 请勿使用) 2024-02-21 02:16:47 +08:00
aa7b241dba refactor send_forward_msg(暂未完成 请勿使用) 2024-02-21 02:16:46 +08:00
c70f3eabfe Shamrock: typo BaseTransmitServlet.kt
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-19 11:30:22 +08:00
1c65aab673 refactor send_forward_msg(暂未完成 请勿使用) 2024-02-19 04:14:26 +08:00
a5cdd64686 upgrade workflow 2024-02-19 04:13:50 +08:00
b07ca5bd03 fix linq 2024-02-19 04:13:49 +08:00
8f8580d542 Shamrock: remove debug log #242
Signed-off-by: 白池 <whitechi73@outlook.com>
2024-02-18 21:16:23 +08:00
0ed4480878 Shamrock: fix #242 2024-02-18 21:16:04 +08:00
c3e0031aa4 Shamrock: debug #242 2024-02-18 20:36:42 +08:00
388c963e88 Shamrock: fix markdown parser 2024-02-18 20:28:45 +08:00
4283651b1e Shamrock: fix comm_elem parser 2024-02-18 20:08:57 +08:00
50d7dfa06d Shamrock: support inline_keyboard msg 2024-02-18 20:00:37 +08:00
b3a2e605fb Shamrock: fix NT image acquisition 2024-02-18 18:52:56 +08:00
14bf5fc0a2 Shamrock: fix fakeReceiveSelfMsg 2024-02-18 07:51:43 +08:00
2c8b57a7dc Shamrock: fix #238 2024-02-18 07:45:48 +08:00
8e6c167987 Shamrock: fix #236 2024-02-18 07:37:47 +08:00
2c8094c8c8 Shamrock: 临时修补rkey缺失导致的qqnt图片无法获取 #236 2024-02-17 19:39:26 +08:00
62385d6f62 Shamrock: 修复合并转发获取图片错误 #236 2024-02-17 15:43:12 +08:00
3b210d7ed0 Shamrock: fix #236 2024-02-17 09:37:01 +08:00
63ce2d40bd Shamrock: fix get role by nt crash 2024-02-16 10:50:00 +08:00
36f8b6e54b Shamrock: Change the image upload source to a camera 2024-02-16 09:50:31 +08:00
58413044e9 Shamrock: typo log 2024-02-16 09:16:05 +08:00
3395cd9d95 Shamrock: 支持群临时消息推送携带群号以及群名称 2024-02-16 09:12:45 +08:00
494b1f1fd0 Shamrock: 允许禁止QQ启动无关紧要的进程服务 2024-02-16 00:09:35 +08:00
cf943fd13a Shamrock: atメッセージ優先nameパラメータ 2024-02-15 13:18:43 +08:00
9608b46799 Shamrock: 是正メッセージプッシュアイデンティティの取得が遅い 2024-02-15 13:14:37 +08:00
502956e3ec Shamrock: エイト・メッセージにニックネームの迅速なクエリを許可する 2024-02-15 13:01:34 +08:00
27b4c26da7 Shamrock: fix GlobalEventTransmitter x2 2024-02-11 14:28:07 +08:00
65f54360f8 Shamrock: not fix GlobalEventTransmitter x2 2024-02-11 14:06:10 +08:00
9a9fad975f Shamrock: not fix GlobalEventTransmitter 2024-02-11 13:57:58 +08:00
7153b21cd4 Shamrock: fix GlobalEventTransmitter 2024-02-11 13:42:28 +08:00
fdb2486090 Shamrock: Disable lost connection detection 2024-02-10 00:41:38 +08:00
d60b2a25d1 Update SECURITY.md 2024-02-09 08:04:40 +08:00
2d8dde6951 add history msg to database 2024-02-08 23:52:21 +08:00
78fd60dade Merge pull request #228 from Mythologyli/master
feat: get group applier uin from request msg
2024-02-08 22:34:40 +08:00
80dbf6af28 feat: get group applier uin from request msg 2024-02-08 22:27:55 +08:00
1e53753b5a Shamrock: fix #227 2024-02-08 20:17:51 +08:00
e727877268 Merge pull request #225 from MrXiaoM/fix-guild-message
修复 频道消息事件不符合 go-cqhttp 规范
2024-02-08 20:16:01 +08:00
63b69df3ea fix missing guild_id and channel_id 2024-02-08 14:51:14 +08:00
b03e02675b Shamrock: add timeout #223 2024-02-05 22:16:12 +08:00
e68a1ffd37 Shamrock: fix guild sync 2024-02-05 22:12:20 +08:00
483 changed files with 13750 additions and 20088 deletions

BIN
.github/jetbrains-variant-3.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@ -19,16 +19,16 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Setup JDK 17
uses: actions/setup-java@v4.0.0
uses: actions/setup-java@v4
with:
java-version: 17
distribution: "adopt"
- name: Cache Gradle Dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
@ -38,7 +38,7 @@ jobs:
restore-keys: gradle-deps
- name: Cache Gradle Build
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
~/.gradle/caches/build-cache-*
@ -82,19 +82,19 @@ jobs:
echo "|x86_64|$x86_64" >> $GITHUB_STEP_SUMMARY
- name: Upload ALL APK RELEASE
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "${{ env.SHAMROCK_VERSION_ALL }}"
path: "${{ env.APK_FILE_ALL }}"
- name: Upload ARM64 APK RELEASE
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "${{ env.SHAMROCK_VERSION_ARM64 }}"
path: "${{ env.APK_FILE_ARM64 }}"
- name: Upload X86_64 APK RELEASE
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "${{ env.SHAMROCK_VERSION_x86_64 }}"
path: "${{ env.APK_FILE_X86_64 }}"

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "kritor"]
path = kritor/kritor
url = https://github.com/KarinJS/kritor

View File

@ -16,19 +16,37 @@
## 简介
☘ 基于 Lsposed(**Non**-Riru) 实现 OneBot 标准的 QQ 机器人框架,原作者[**fuqiuluo**](https://github.com/fuqiuluo)已脱离开发接下来由白池接手哦本项目为OpenShamrock不会有任何收费行为欢迎大家的加入
☘ 基于 Lsposed(**Non**-Riru) 实现 Kritor 标准的 QQ 机器人框架!
> 本项目仅提供学习与交流用途请在24小时内删除。
> 本项目目的是研究 Xposed 和 LSPosed 框架的使用。 Epic 框架开发相关知识。
> Riru可能导致封禁请减少使用。
> 如有违反法律,请联系删除。
> 请勿在任何平台宣传,宣扬,转发本项目,请勿恶意修改企业安装包造成相关企业产生损失,如有违背,必将追责到底。
> 官方论坛,[点我直达](https://forum.libfekit.so/)
>
> 社区地址:[discord](https://discord.gg/MKR2wz863h)
## 兼容|迁移|替代 说明
- 一键移植:本项目基于 go-cqhttp 的文档进行开发实现。
- 平行部署:可多平台部署,未来将会支持 Docker 部署的教程
- 平行部署:可多平台部署。
## 相关项目
<table>
<tr>
<td><a href="https://github.com/LagrangeDev/Lagrange.Core">Lagrange.Core</a></td>
<td>NTQQ 的协议实现</td>
</tr>
<tr>
<td><a href="https://github.com/whitechi73/OpenShamrock">OpenShamrock</a></td>
<td>基于 Xposed 实现 OneBot 标准的机器人框架(👈你在这里</td>
</tr>
<tr>
<td><a href="https://github.com/chrononeko/chronocat">Chronocat</a></td>
<td>基于 Electron 的、模块化的 Satori 框架</td>
</tr>
</table>
## 权限声明
@ -46,13 +64,19 @@
<img src="https://github.com/whitechi73/OpenShamrock/assets/98259561/f04d60bc-ec40-41fc-bc15-62c146f1a1f1" width="160px" alt="Shamrock"> **我可爱吗?欢迎你的到来,这里是一个很大的地方,有着无限可能,主要是有你啦!**
## 鸣谢
感谢[**JetBrains**](https://www.jetbrains.com/zh-cn/community/opensource/#support)提供的开源开发许可证JetBrains 通过为核心项目贡献者免费提供一套一流的开发者工具来支持非商业开源项目。
[<img src=".github/jetbrains-variant-3.png" width="200"/>](https://www.jetbrains.com/zh-cn/community/opensource/#support)
## 开源协议
本项目使用 [GPL-3.0](LICENSE) 协议开放源代码
```text
Shamrock - OneBot standard QQ robot framework based on Xposed implementation
Copyright (C) 2023 Shamrock Team
Copyright (C) 2023 ~ 2024 Shamrock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@ -102,3 +126,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
[contrib-image]: https://contrib.rocks/image?repo=whitechi73/OpenShamrock
[contrib-link]: https://github.com/whitechi73/OpenShamrock/graphs/contributors

View File

@ -1,11 +1,19 @@
# Security Policy
## Support Version
## 支持的版本
| Version | Supported |
| 版本 | 支持状态 |
| ------- | ------------------ |
| 9.0.15 | :white_check_mark: |
| 8.9.75 | :white_check_mark: |
| 8.9.73 | :white_check_mark: |
| 8.9.98 | :white_check_mark: |
| < 8.9.68| :x: |
## 频道支持性说明
如果需要使用`频道`相关功能请升级QQ到9.0.8版本
## Riru检测问题
QQ自`9.0.8`开始将会检测riru可能作为封号因素

View File

@ -6,4 +6,9 @@ plugins {
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies {
//implementation(DEPENDENCY_PROTOBUF)
implementation(kotlinx("serialization-protobuf", "1.6.2"))
}

View File

@ -0,0 +1,9 @@
package kritor.service
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.FUNCTION)
annotation class Grpc(
val serviceName: String,
val funcName: String,
)

View File

@ -1,8 +0,0 @@
package moe.fuqiuluo.symbols
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.CLASS)
annotation class OneBotHandler(
val actionName: String,
val alias: Array<String> = []
)

View File

@ -0,0 +1,14 @@
package moe.fuqiuluo.symbols
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.protobuf.ProtoBuf
import kotlin.reflect.KClass
val EMPTY_BYTE_ARRAY = ByteArray(0)
interface Protobuf<T: Protobuf<T>>
inline fun <reified T: Protobuf<T>> ByteArray.decodeProtobuf(to: KClass<T>? = null): T {
return ProtoBuf.decodeFromByteArray(this)
}

View File

@ -4,7 +4,7 @@ import java.io.ByteArrayOutputStream
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
kotlin("plugin.serialization") version "1.9.21"
kotlin("plugin.serialization") version "1.9.22"
}
android {
@ -17,7 +17,7 @@ android {
minSdk = 27
targetSdk = 34
versionCode = getVersionCode()
versionName = "1.0.8" + ".r${getGitCommitCount()}." + getVersionName()
versionName = "1.1.1" + ".r${getGitCommitCount()}." + getVersionName()
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@ -92,7 +92,7 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.4"
kotlinCompilerExtensionVersion = "1.5.10"
}
packaging {
jniLibs {
@ -127,11 +127,6 @@ android {
}
configureAppSigningConfigsForRelease(project)
packagingOptions {
jniLibs {
useLegacyPackaging = true
}
}
}
fun configureAppSigningConfigsForRelease(project: Project) {
@ -206,14 +201,8 @@ dependencies {
implementation("io.coil-kt:coil-compose:2.4.0")
implementation(kotlinx("io-jvm", "0.1.16"))
implementation(ktor("server", "core"))
implementation(ktor("server", "host-common"))
implementation(ktor("server", "status-pages"))
implementation(ktor("server", "netty"))
implementation(ktor("server", "content-negotiation"))
implementation(ktor("client", "core"))
implementation(ktor("client", "content-negotiation"))
implementation(ktor("client", "cio"))
implementation(ktor("client", "okhttp"))
implementation(ktor("serialization", "kotlinx-json"))
implementation(project(":xposed"))

View File

@ -199,17 +199,36 @@
-keep class com.arthenica.ffmpegkit.NativeLoader { *; }
-keep class moe.fuqiuluo.** { *; }
-keep class moe.fuqiuluo.shamrock.app.** { *; }
-keep class moe.fuqiuluo.shamrock.ui.** { *; }
-keep class moe.fuqiuluo.shamrock.MainActivity { *; }
-keep class moe.fuqiuluo.shamrock.MainActivityKt { *; }
-keep class moe.fuqiuluo.shamrock.Manifest { *; }
-keep class moe.fuqiuluo.shamrock.xposed.** { *; }
-keep class moe.fuqiuluo.shamrock.helper.** { *; }
# tencent interfaces rules
-keep class com.tencent.** { *; }
-keep class com.qq.** { *; }
-keep class com.google.gson.** { *; }
-keep class de.** { *; }
-keep class epic.** { *; }
-keep class friendlist.** { *; }
-keep class KQQ.** { *; }
-keep class mqq.** { *; }
-keep class msf.** { *; }
-keep class oicq.** { *; }
-keep class QQService.** { *; }
-keep class SummaryCard.** { *; }
-keep class tencent.** { *; }
-keep class VIP.** { *; }
-keepclassmembers class * {
native <methods>;
}
-keep class io.netty.** { *; }
-keepclasseswithmembernames class * {
native <methods>;
}

View File

@ -37,9 +37,7 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
# List C/C++ source files with relative paths to this CMakeLists.txt.
${SRC_DIR}
md5.cpp
cqcode.cpp
silk.cpp
group_honor.cpp
message.cpp
shamrock.cpp)

View File

@ -1,138 +0,0 @@
#include <stdexcept>
#include "cqcode.h"
inline void replace_string(std::string& str, const std::string& from, const std::string& to) {
size_t startPos = 0;
while ((startPos = str.find(from, startPos)) != std::string::npos) {
str.replace(startPos, from.length(), to);
startPos += to.length();
}
}
inline int utf8_next_len(const std::string& str, size_t offset)
{
uint8_t c = (uint8_t)str[offset];
if (c >= 0xFC)
return 6;
else if (c >= 0xF8)
return 5;
else if (c >= 0xF0)
return 4;
else if (c >= 0xE0)
return 3;
else if (c >= 0xC0)
return 2;
else if (c > 0x00)
return 1;
else
return 0;
}
void decode_cqcode(const std::string& code, std::vector<std::unordered_map<std::string, std::string>>& dest) {
std::string cache;
bool is_start = false;
std::string key_tmp;
std::unordered_map<std::string, std::string> kv;
for(size_t i = 0; i < code.size(); i++) {
int utf8_char_len = utf8_next_len(code, i);
if(utf8_char_len == 0) {
continue;
}
std::string_view c(&code[i],utf8_char_len);
if (c == "[") {
if (is_start) {
throw illegal_code();
} else {
if (!cache.empty()) {
std::unordered_map<std::string, std::string> kv;
replace_string(cache, "&#91;", "[");
replace_string(cache, "&#93;", "]");
replace_string(cache, "&amp;", "&");
kv.emplace("_type", "text");
kv.emplace("text", cache);
dest.push_back(kv);
cache.clear();
}
std::string_view cq_flag(&code[i],4);
if(cq_flag == "[CQ:"){
is_start = true;
i += 3;
}else{
cache += c;
}
}
}
else if (c == "=") {
if (is_start) {
if (cache.empty()) {
throw illegal_code();
} else {
if (key_tmp.empty()) {
key_tmp.append(cache);
cache.clear();
} else {
cache += c;
}
}
} else {
cache += c;
}
}
else if (c == ",") {
if (is_start) {
if (kv.count("_type") == 0 && !cache.empty()) {
kv.emplace("_type", cache);
cache.clear();
} else {
if (!key_tmp.empty()) {
replace_string(cache, "&#91;", "[");
replace_string(cache, "&#93;", "]");
replace_string(cache, "&#44;", ",");
replace_string(cache, "&amp;", "&");
kv.emplace(key_tmp, cache);
cache.clear();
key_tmp.clear();
}
}
} else {
cache += c;
}
}
else if (c == "]") {
if (is_start) {
if (!cache.empty()) {
if (!key_tmp.empty()) {
replace_string(cache, "&#91;", "[");
replace_string(cache, "&#93;", "]");
replace_string(cache, "&#44;", ",");
replace_string(cache, "&amp;", "&");
kv.emplace(key_tmp, cache);
} else {
kv.emplace("_type", cache);
}
dest.push_back(kv);
kv.clear();
key_tmp.clear();
cache.clear();
is_start = false;
}
} else {
cache += c;
}
}
else {
cache += c;
i += (utf8_char_len - 1);
}
}
if (!cache.empty()) {
std::unordered_map<std::string, std::string> kv;
replace_string(cache, "&#91;", "[");
replace_string(cache, "&#93;", "]");
replace_string(cache, "&amp;", "&");
kv.emplace("_type", "text");
kv.emplace("text", cache);
dest.push_back(kv);
}
}

View File

@ -1,87 +0,0 @@
#include "jni.h"
#include <vector>
#include <string>
#include <algorithm>
struct Honor {
int id;
std::string name;
std::string icon_url;
int priority;
};
int calc_honor_flag(int honor_id, char honor_flag);
jobject make_honor_object(JNIEnv *env, jobject user_id, const Honor& honor);
extern "C"
JNIEXPORT jobject JNICALL
Java_moe_fuqiuluo_shamrock_remote_action_handlers_GetTroopHonor_nativeDecodeHonor(JNIEnv *env, jobject thiz,
jstring user_id,
jint honor_id,
jbyte honor_flag) {
static std::vector<Honor> honor_list = {
Honor{1, "龙王", "https://qzonestyle.gtimg.cn/aoi/sola/20200213150116_n4PxCiurbm.png", 1},
Honor{2, "群聊之火", "https://qzonestyle.gtimg.cn/aoi/sola/20200217190136_92JEGFKC5k.png", 3},
Honor{3, "群聊炽焰", "https://qzonestyle.gtimg.cn/aoi/sola/20200217190204_zgCTeSrMq1.png", 4},
Honor{5, "冒尖小春笋", "https://qzonestyle.gtimg.cn/aoi/sola/20200213150335_tUJCAtoKVP.png", 5},
Honor{6, "快乐源泉", "https://qzonestyle.gtimg.cn/aoi/sola/20200213150434_3tDmsJExCP.png", 7},
Honor{7, "学术新星", "https://sola.gtimg.cn/aoi/sola/20200515140645_j0X6gbuHNP.png", 8},
Honor{8, "顶尖学霸", "https://sola.gtimg.cn/aoi/sola/20200515140639_0CtWOpfVzK.png", 9},
Honor{9, "至尊学神", "https://sola.gtimg.cn/aoi/sola/20200515140628_P8UEYBjMBT.png", 10},
Honor{10, "一笔当先", "https://sola.gtimg.cn/aoi/sola/20200515140654_4r94tSCdaB.png", 11},
Honor{11, "奋进小翠竹", "https://sola.gtimg.cn/aoi/sola/20200812151819_wbj6z2NGoB.png", 6},
Honor{12, "氛围魔杖", "https://sola.gtimg.cn/aoi/sola/20200812151831_4ZJgQCaD1H.png", 2},
Honor{13, "壕礼皇冠", "https://sola.gtimg.cn/aoi/sola/20200930154050_juZOAMg7pt.png", 12},
};
int flag = calc_honor_flag(honor_id, honor_flag);
if ((honor_id != 1 && honor_id != 2 && honor_id != 3) || flag != 1) {
auto honor = *std::find_if(honor_list.begin(), honor_list.end(), [&honor_id](auto &honor) {
return honor.id == honor_id;
});
return make_honor_object(env, user_id, honor);
} else {
auto honor = *std::find_if(honor_list.begin(), honor_list.end(), [&honor_id](auto &honor) {
return honor.id == honor_id;
});
std::string url = "https://static-res.qq.com/static-res/groupInteract/vas/a/" + std::to_string(honor_id) + "_1.png";
honor = Honor{honor_id, honor.name, url, honor.priority};
return make_honor_object(env, user_id, honor);
}
}
int calc_honor_flag(int honor_id, char honor_flag) {
int flag;
if (honor_flag == 0) {
return 0;
}
if (honor_id == 1) {
flag = honor_flag;
} else if (honor_id == 2 || honor_id == 3) {
flag = honor_flag >> 2;
} else if (honor_id != 4) {
return 0;
} else {
flag = honor_flag >> 4;
}
return flag & 3;
}
jobject make_honor_object(JNIEnv *env, jobject user_id, const Honor& honor) {
jclass GroupMemberHonor = env->FindClass("moe/fuqiuluo/shamrock/remote/service/data/GroupMemberHonor");
jmethodID GroupMemberHonor_init = env->GetMethodID(GroupMemberHonor, "<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
auto user_id_str = (jstring) user_id;
jstring honor_desc = env->NewStringUTF(honor.name.c_str());
jstring uin_name = env->NewStringUTF("");
jstring honor_icon_url = env->NewStringUTF(honor.icon_url.c_str());
jobject ret = env->NewObject(GroupMemberHonor, GroupMemberHonor_init, user_id_str, uin_name, honor_icon_url, 0, honor.id, honor_desc);
env->DeleteLocalRef(GroupMemberHonor);
env->DeleteLocalRef(user_id_str);
env->DeleteLocalRef(honor_desc);
env->DeleteLocalRef(honor_icon_url);
return ret;
}

View File

@ -1,20 +0,0 @@
#ifndef UNTITLED_CQCODE_H
#define UNTITLED_CQCODE_H
#include <string>
#include <unordered_map>
#include <vector>
#include <exception>
class illegal_code: std::exception {
public:
[[nodiscard]] const char * what() const noexcept override {
return "Error cq code.";
}
};
void decode_cqcode(const std::string& code, std::vector<std::unordered_map<std::string, std::string>>& dest);
void encode_cqcode(const std::vector<std::unordered_map<std::string, std::string>>& segment, std::string& dest);
#endif //UNTITLED_CQCODE_H

View File

@ -1,5 +1,4 @@
#include "jni.h"
#include "cqcode.h"
#include <random>
inline void replace_string(std::string& str, const std::string& from, const std::string& to) {
@ -12,7 +11,7 @@ inline void replace_string(std::string& str, const std::string& from, const std:
extern "C"
JNIEXPORT jlong JNICALL
Java_moe_fuqiuluo_shamrock_helper_MessageHelper_createMessageUniseq(JNIEnv *env, jobject thiz,
Java_qq_service_msg_MessageHelper_createMessageUniseq(JNIEnv *env, jobject thiz,
jint chat_type,
jlong time) {
static std::random_device rd;
@ -32,123 +31,6 @@ Java_moe_fuqiuluo_shamrock_helper_MessageHelper_getChatType(JNIEnv *env, jobject
return (int32_t) ((int64_t) msg_id & 0xffL);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_moe_fuqiuluo_shamrock_helper_MessageHelper_nativeDecodeCQCode(JNIEnv *env, jobject thiz,
jstring code) {
jclass ArrayList = env->FindClass("java/util/ArrayList");
jmethodID NewArrayList = env->GetMethodID(ArrayList, "<init>", "()V");
jmethodID ArrayListAdd = env->GetMethodID(ArrayList, "add", "(Ljava/lang/Object;)Z");
jobject arrayList = env->NewObject(ArrayList, NewArrayList);
const char* cCode = env->GetStringUTFChars(code, nullptr);
std::string cppCode = cCode;
std::vector<std::unordered_map<std::string, std::string>> dest;
try {
decode_cqcode(cppCode, dest);
} catch (illegal_code& code) {
return arrayList;
}
jclass HashMap = env->FindClass("java/util/HashMap");
jmethodID NewHashMap = env->GetMethodID(HashMap, "<init>", "()V");
jclass String = env->FindClass("java/lang/String");
jmethodID NewString = env->GetMethodID(String, "<init>", "([BLjava/lang/String;)V");
jstring charset = env->NewStringUTF("UTF-8");
jmethodID put = env->GetMethodID(HashMap, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
for (auto& map : dest) {
jobject hashMap = env->NewObject(HashMap, NewHashMap);
for (const auto& pair : map) {
jbyteArray keyArray = env->NewByteArray((int) pair.first.size());
jbyteArray valueArray = env->NewByteArray((int) pair.second.size());
env->SetByteArrayRegion(keyArray, 0, (int) pair.first.size(), (jbyte*)pair.first.c_str());
env->SetByteArrayRegion(valueArray, 0, (int) pair.second.size(), (jbyte*)pair.second.c_str());
auto key = (jstring) env->NewObject(String, NewString, keyArray, charset);
auto value = (jstring) env->NewObject(String, NewString, valueArray, charset);
env->CallObjectMethod(hashMap, put, key, value);
}
env->CallBooleanMethod(arrayList, ArrayListAdd, hashMap);
}
env->DeleteLocalRef(ArrayList);
env->DeleteLocalRef(HashMap);
env->DeleteLocalRef(String);
env->DeleteLocalRef(charset);
env->ReleaseStringUTFChars(code, cCode);
return arrayList;
}
extern "C"
JNIEXPORT jstring JNICALL
Java_moe_fuqiuluo_shamrock_helper_MessageHelper_nativeEncodeCQCode(JNIEnv *env, jobject thiz,
jobject segment_list) {
jclass List = env->FindClass("java/util/List");
jmethodID ListSize = env->GetMethodID(List, "size", "()I");
jmethodID ListGet = env->GetMethodID(List, "get", "(I)Ljava/lang/Object;");
jclass Map = env->FindClass("java/util/Map");
jmethodID MapGet = env->GetMethodID(Map, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
jmethodID entrySetMethod = env->GetMethodID(Map, "entrySet", "()Ljava/util/Set;");
jclass setClass = env->FindClass("java/util/Set");
jmethodID iteratorMethod = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
jclass entryClass = env->FindClass("java/util/Map$Entry");
jmethodID getKeyMethod = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
jmethodID getValueMethod = env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
std::string result;
jint size = env->CallIntMethod(segment_list, ListSize);
for (int i = 0; i < size; i++ ) {
jobject segment = env->CallObjectMethod(segment_list, ListGet, i);
jobject entrySet = env->CallObjectMethod(segment, entrySetMethod);
jobject iterator = env->CallObjectMethod(entrySet, iteratorMethod);
auto type = (jstring) env->CallObjectMethod(segment, MapGet, env->NewStringUTF("_type"));
auto typeString = env->GetStringUTFChars(type, nullptr);
if (strcmp(typeString, "text") == 0) {
auto text = (jstring) env->CallObjectMethod(segment, MapGet, env->NewStringUTF("text"));
auto textString = env->GetStringUTFChars(text, nullptr);
std::string tmpValue = textString;
replace_string(tmpValue, "&", "&amp;");
replace_string(tmpValue, "[", "&#91;");
replace_string(tmpValue, "]", "&#93;");
replace_string(tmpValue, ",", "&#44;");
result.append(tmpValue);
env->ReleaseStringUTFChars(text, textString);
} else {
result.append("[CQ:");
result.append(typeString);
while (env->CallBooleanMethod(iterator, env->GetMethodID(env->GetObjectClass(iterator), "hasNext", "()Z"))) {
jobject entry = env->CallObjectMethod(iterator, env->GetMethodID(env->GetObjectClass(iterator), "next", "()Ljava/lang/Object;"));
auto key = (jstring) env->CallObjectMethod(entry, getKeyMethod);
auto value = (jstring) env->CallObjectMethod(entry, getValueMethod);
auto keyString = env->GetStringUTFChars(key, nullptr);
auto valueString = env->GetStringUTFChars(value, nullptr);
if (strcmp(keyString, "_type") != 0) {
std::string tmpValue = valueString;
replace_string(tmpValue, "&", "&amp;");
replace_string(tmpValue, "[", "&#91;");
replace_string(tmpValue, "]", "&#93;");
replace_string(tmpValue, ",", "&#44;");
result.append(",").append(keyString).append("=").append(tmpValue);
}
env->ReleaseStringUTFChars(key, keyString);
env->ReleaseStringUTFChars(value, valueString);
env->DeleteLocalRef(entry);
env->DeleteLocalRef(key);
env->DeleteLocalRef(value);
}
result.append("]");
}
env->ReleaseStringUTFChars(type, typeString);
}
env->DeleteLocalRef(List);
env->DeleteLocalRef(Map);
env->DeleteLocalRef(setClass);
env->DeleteLocalRef(entryClass);
return env->NewStringUTF(result.c_str());
}
extern "C"
JNIEXPORT jlong JNICALL
Java_moe_fuqiuluo_shamrock_helper_MessageHelper_insertChatTypeToMsgId(JNIEnv *env, jobject thiz,

View File

@ -12,7 +12,7 @@
extern "C"
JNIEXPORT jstring JNICALL
Java_moe_fuqiuluo_shamrock_xposed_hooks_PullConfig_testNativeLibrary(JNIEnv *env, jobject thiz) {
Java_moe_fuqiuluo_shamrock_xposed_actions_interacts_Init_testNativeLibrary(JNIEnv *env, jobject thiz) {
return env->NewStringUTF("加载Shamrock库成功~");
}

View File

@ -4,6 +4,7 @@ package moe.fuqiuluo.shamrock
import android.annotation.SuppressLint
import android.os.Bundle
import android.os.Handler
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
@ -64,7 +65,9 @@ import androidx.compose.ui.unit.sp
import androidx.core.view.WindowCompat
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import moe.fuqiuluo.shamrock.tools.GlobalUi
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
import moe.fuqiuluo.shamrock.ui.app.Logger
import moe.fuqiuluo.shamrock.ui.app.RuntimeState
@ -85,8 +88,16 @@ import moe.fuqiuluo.shamrock.ui.tools.getShamrockVersion
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LaunchedEffect(Unit) {
while (true) {
delay(5_000) // Delay in milliseconds
broadcastToModule {
putExtra("__cmd", "switch_status")
}
}
}
CompositionLocalProvider(
LocalIndication provides NoIndication
) {
@ -96,8 +107,9 @@ class MainActivity : ComponentActivity() {
isAppearanceLightStatusBars = true
}
WindowCompat.setDecorFitsSystemWindows(window, true)
broadcastToModule { putExtra("__cmd", "fetchPort") }
}
GlobalUi = Handler(mainLooper)
}
}
@ -153,7 +165,7 @@ private fun AppMainView() {
}
val ctx = LocalContext.current
LaunchedEffect(isFined.value) {
LaunchedEffect(isFined) {
if (isFined.value) {
AppRuntime.log(LocalString.logCentralLoadSuccessfully)
Toast.makeText(ctx, LocalString.frameworkYes, Toast.LENGTH_SHORT).show()
@ -284,58 +296,11 @@ private fun AnimatedTab(
val lastSelectedState = remember {
mutableIntStateOf(0)
}
val enter = remember {
scaleIn(animationSpec = TweenSpec(150, easing = FastOutLinearInEasing))
}
val exit = remember {
scaleOut(animationSpec = TweenSpec(150, easing = FastOutSlowInEasing))
}
val defaultConst = SELECTED_TABLE[index * 2]
val selectedConst = SELECTED_TABLE[(index * 2) + 1]
val isFirst: Boolean = (lastSelectedState.value and defaultConst) != defaultConst
var icon: @Composable (() -> Unit)? = null
var text: @Composable (() -> Unit)? = null
if (curSelected) {
text = {
AnimatedVisibility(visibleState = MutableTransitionState(false).also {
it.targetState =
isFirst || lastSelectedState.value and selectedConst == selectedConst
}, enter = enter, exit = exit, modifier = Modifier) {
Text(
text = titleWithIcon.first,
color = GlobalColor.TabItem,
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(bottom = 5.dp)
.indication(
remember { MutableInteractionSource() },
rememberRipple(color = Color.Transparent)
)
)
}
}
} else {
icon = {
Icon(
painter = painterResource(id = titleWithIcon.second),
contentDescription = titleWithIcon.first,
tint = Color.Unspecified,
modifier = Modifier
.height(24.dp)
.width(24.dp)
.padding(bottom = 5.dp)
.indication(
remember { MutableInteractionSource() },
rememberRipple(color = Color.Transparent)
)
)
}
}
ShamrockTab(
selected = curSelected,
onClick = {
@ -343,11 +308,13 @@ private fun AnimatedTab(
state.scrollToPage(index, 0f)
}
},
text = text,
icon = icon,
selectedContentColor = Color.Transparent,
unselectedContentColor = Color.Transparent,
indication = null
indication = null,
titleWithIcon = titleWithIcon,
visibleState = MutableTransitionState(false).also {
it.targetState = isFirst || lastSelectedState.value and selectedConst == selectedConst
}
)
lastSelectedState.value.let {
var tmp = it

View File

@ -0,0 +1,2 @@
package moe.fuqiuluo.shamrock.app.config

View File

@ -0,0 +1,33 @@
package moe.fuqiuluo.shamrock.app.config
import android.content.Context
import moe.fuqiuluo.shamrock.config.ConfigKey
import moe.fuqiuluo.shamrock.ui.service.internal.broadcastToModule
object ShamrockConfig {
internal fun getConfigPref(ctx: Context) = ctx.getSharedPreferences("config", 0)
internal inline operator fun <reified Type> get(ctx: Context, key: ConfigKey<Type>): Type {
val preferences = getConfigPref(ctx)
return when(Type::class) {
Int::class -> preferences.getInt(key.name(), key.default() as Int) as Type
Long::class -> preferences.getLong(key.name(), key.default() as Long) as Type
String::class -> preferences.getString(key.name(), key.default() as String) as Type
Boolean::class -> preferences.getBoolean(key.name(), key.default() as Boolean) as Type
else -> throw IllegalArgumentException("Unsupported type")
}
}
internal inline operator fun <reified Type> set(ctx: Context, key: ConfigKey<Type>, value: Type) {
val preferences = getConfigPref(ctx)
val editor = preferences.edit()
when(Type::class) {
Int::class -> editor.putInt(key.name(), value as Int)
Long::class -> editor.putLong(key.name(), value as Long)
String::class -> editor.putString(key.name(), value as String)
Boolean::class -> editor.putBoolean(key.name(), value as Boolean)
else -> throw IllegalArgumentException("Unsupported type")
}
editor.apply()
}
}

View File

@ -1,362 +0,0 @@
package moe.fuqiuluo.shamrock.ui.app
import android.content.Context
import moe.fuqiuluo.shamrock.ui.service.internal.broadcastToModule
object ShamrockConfig {
fun getSSLKeyPath(ctx: Context): String {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getString("key_store", "")!!
}
fun setSSLKeyPath(ctx: Context, path: String) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putString("key_store", path).apply()
pushUpdate(ctx)
}
fun getSSLPort(ctx: Context): Int {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getInt("ssl_port", 5701)
}
fun setSSLPort(ctx: Context, port: Int) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putInt("ssl_port", port).apply()
pushUpdate(ctx)
}
fun getSSLAlias(ctx: Context): String {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getString("ssl_alias", "")!!
}
fun setSSLAlias(ctx: Context, alias: String) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putString("ssl_alias", alias).apply()
pushUpdate(ctx)
}
fun getSSLPwd(ctx: Context): String {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getString("ssl_pwd", "")!!
}
fun setSSLPwd(ctx: Context, alias: String) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putString("ssl_pwd", alias).apply()
pushUpdate(ctx)
}
fun getSSLPrivatePwd(ctx: Context): String {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getString("ssl_private_pwd", "")!!
}
fun setSSLPrivatePwd(ctx: Context, alias: String) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putString("ssl_private_pwd", alias).apply()
pushUpdate(ctx)
}
fun getHttpAddr(ctx: Context): String {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getString("http_addr", "")!!
}
fun setHttpAddr(ctx: Context, v: String) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putString("http_addr", v).apply()
pushUpdate(ctx)
}
fun isPro(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("pro_api", false)
}
fun setPro(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("pro_api", v).apply()
ctx.broadcastToModule {
putExtra("type", "restart")
putExtra("__cmd", "change_port")
}
pushUpdate(ctx)
}
fun getToken(ctx: Context): String {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getString("token", null) ?: ""
}
fun setToken(ctx: Context, v: String?) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putString("token", v).apply()
pushUpdate(ctx)
}
fun isWs(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("ws", false)
}
fun setWs(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("ws", v).apply()
pushUpdate(ctx)
}
fun isWsClient(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("ws_client", false)
}
fun setWsClient(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("ws_client", v).apply()
pushUpdate(ctx)
}
fun isTablet(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("tablet", false)
}
fun setTablet(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("tablet", v).apply()
pushUpdate(ctx)
}
fun isUseCQCode(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("use_cqcode", false)
}
fun setUseCQCode(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("use_cqcode", v).apply()
pushUpdate(ctx)
}
fun isWebhook(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("webhook", false)
}
fun setWebhook(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("webhook", v).apply()
pushUpdate(ctx)
}
fun getWsAddr(ctx: Context): String {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getString("ws_addr", "")!!
}
fun setWsAddr(ctx: Context, v: String) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putString("ws_addr", v).apply()
pushUpdate(ctx)
}
fun getHttpPort(ctx: Context): Int {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getInt("port", 5700)
}
fun setHttpPort(ctx: Context, v: Int) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putInt("port", v).apply()
ctx.broadcastToModule {
putExtra("type", "port")
putExtra("port", v)
putExtra("__cmd", "change_port")
}
pushUpdate(ctx)
}
fun getWsPort(ctx: Context): Int {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getInt("ws_port", 5800)
}
fun setWsPort(ctx: Context, v: Int) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putInt("ws_port", v).apply()
ctx.broadcastToModule {
putExtra("type", "ws_port")
putExtra("port", v)
putExtra("__cmd", "change_port")
}
pushUpdate(ctx)
}
fun is2B(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("2B", false)
}
fun set2B(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("2B", v).apply()
}
fun setAutoClean(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("auto_clear", v).apply()
}
fun isAutoClean(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("auto_clear", false)
}
fun isDebug(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("debug", false)
}
fun setDebug(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("debug", v).apply()
}
fun isAntiTrace(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("anti_qq_trace", true)
}
fun setAntiTrace(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("anti_qq_trace", v).apply()
}
fun isInjectPacket(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("inject_packet", false)
}
fun setInjectPacket(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("inject_packet", v).apply()
}
fun enableAutoStart(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
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)
}
fun allowShell(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("shell", false)
}
fun setAutoStart(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
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()
}
fun setShellStatus(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("shell", v).apply()
}
fun enableSelfMsg(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("enable_self_msg", false)
}
fun enableSyncMsgAsSentMsg(ctx: Context): Boolean {
val preferences = ctx.getSharedPreferences("config", 0)
return preferences.getBoolean("enable_sync_msg_as_sent_msg", false)
}
fun setEnableSelfMsg(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("enable_self_msg", v).apply()
}
fun setEnableSyncMsgAsSentMsg(ctx: Context, v: Boolean) {
val preferences = ctx.getSharedPreferences("config", 0)
preferences.edit().putBoolean("enable_sync_msg_as_sent_msg", v).apply()
}
fun getConfigMap(ctx: Context): Map<String, Any?> {
val preferences = ctx.getSharedPreferences("config", 0)
return mapOf(
"tablet" to preferences.getBoolean("tablet", false),
"port" to preferences.getInt("port", 5700),
"ws" to preferences.getBoolean("ws", false),
"ws_port" to preferences.getInt("ws_port", 5800),
"ssl_port" to preferences.getInt("ssl_port", 5701),
"http" to preferences.getBoolean("webhook", false),
"http_addr" to preferences.getString("http_addr", ""),
"ws_client" to preferences.getBoolean("ws_client", false),
"use_cqcode" to preferences.getBoolean("use_cqcode", false),
"ws_addr" to preferences.getString("ws_addr", ""),
"ssl_alias" to preferences.getString("ssl_alias", ""),
"pro_api" to preferences.getBoolean("pro_api", false),
"token" to preferences.getString("token", null),
"ssl_pwd" to preferences.getString("ssl_pwd", ""),
"inject_packet" to preferences.getBoolean("inject_packet", false),
"debug" to preferences.getBoolean("debug", false),
"anti_qq_trace" to preferences.getBoolean("anti_qq_trace", true),
//"auto_clear" to preferences.getBoolean("auto_clear", false),
"ssl_private_pwd" to preferences.getString("ssl_private_pwd", ""),
"key_store" to preferences.getString("key_store", ""),
"enable_self_msg" to preferences.getBoolean("enable_self_msg", false),
"echo_number" to preferences.getBoolean("echo_number", false),
"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),
)
}
fun pushUpdate(ctx: Context) {
ctx.broadcastToModule {
getConfigMap(ctx).forEach { (key, value) ->
if (value == null) {
val v: String? = null
this.putExtra(key, v)
} else {
when (value) {
is Int -> this.putExtra(key, value)
is Long -> this.putExtra(key, value)
is Short -> this.putExtra(key, value)
is Byte -> this.putExtra(key, value)
is String -> this.putExtra(key, value)
is ByteArray -> this.putExtra(key, value)
is Boolean -> this.putExtra(key, value)
is Float -> this.putExtra(key, value)
is Double -> this.putExtra(key, value)
}
}
}
putExtra("__cmd", "push_config")
}
}
}

View File

@ -5,7 +5,6 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import android.widget.Toast
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
@ -25,6 +24,7 @@ import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -45,10 +45,12 @@ import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import coil.size.Size
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import moe.fuqiuluo.shamrock.R
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
import moe.fuqiuluo.shamrock.ui.app.Level
import moe.fuqiuluo.shamrock.ui.app.ShamrockConfig
import moe.fuqiuluo.shamrock.app.config.ShamrockConfig
import moe.fuqiuluo.shamrock.config.*
import moe.fuqiuluo.shamrock.ui.theme.GlobalColor
import moe.fuqiuluo.shamrock.ui.theme.LocalString
import moe.fuqiuluo.shamrock.ui.theme.ThemeColor
@ -72,110 +74,6 @@ fun DashboardFragment(
InformationCard(ctx)
APIInfoCard(ctx)
FunctionCard(scope, ctx, LocalString.functionSetting)
SSLCard(ctx)
}
}
@Composable
private fun SSLCard(ctx: Context) {
ActionBox(
modifier = Modifier.padding(top = 12.dp),
painter = painterResource(id = R.drawable.baseline_security_24),
title = LocalString.sslSetting
) {
Column {
Divider(
modifier = Modifier,
color = GlobalColor.Divider,
thickness = 0.2.dp
)
val sslPort = remember { mutableStateOf(ShamrockConfig.getSSLPort(ctx).toString()) }
TextItem(
title = "SSL端口",
desc = "端口范围在0~65565并确保可用。",
text = sslPort,
hint = "请输入端口号",
error = "端口范围应在0~65565",
checker = {
it.isNotBlank() && kotlin.runCatching { it.toInt() in 0..65565 }.getOrDefault(false)
},
confirm = {
val newPort = sslPort.value.toInt()
ShamrockConfig.setSSLPort(ctx, newPort)
AppRuntime.log("设置SSL(HTTP)端口为$newPort,立即生效尝试中。")
}
)
val keyStore = remember { mutableStateOf(ShamrockConfig.getSSLKeyPath(ctx)) }
TextItem(
title = "SSL证书",
desc = "BKS签名的证书。",
text = keyStore,
hint = "输入证书路径",
error = "证书路径不合法或不存在",
checker = {
it.isNotBlank()
},
confirm = {
val new = keyStore.value
ShamrockConfig.setSSLKeyPath(ctx, new)
AppRuntime.log("设置SSL证书为[$new]。")
}
)
val alias = remember { mutableStateOf(ShamrockConfig.getSSLAlias(ctx)) }
TextItem(
title = "SSL别名",
desc = "BKS签名的别名确保大小写区分正确。",
text = alias,
hint = "输入签名别名",
error = "别名不合法",
checker = {
it.isNotBlank()
},
confirm = {
val new = alias.value
ShamrockConfig.setSSLAlias(ctx, new)
AppRuntime.log("设置SSL别名为[$new]。")
}
)
val sslPwd = remember { mutableStateOf(ShamrockConfig.getSSLPwd(ctx)) }
TextItem(
title = "SSL密码",
desc = "BKS签名的密码。",
text = sslPwd,
hint = "输入签名密码",
error = "密码不合法",
checker = {
it.isNotBlank()
},
confirm = {
val new = sslPwd.value
ShamrockConfig.setSSLPwd(ctx, new)
AppRuntime.log("设置SSL密码为[$new]。")
}
)
val sslPrivatePwd = remember { mutableStateOf(ShamrockConfig.getSSLPrivatePwd(ctx)) }
TextItem(
title = "SSL Private密码",
desc = "BKS签名的Private密码。",
text = sslPrivatePwd,
hint = "输入Private密码",
error = "密码不合法",
checker = {
it.isNotBlank()
},
confirm = {
val new = sslPrivatePwd.value
ShamrockConfig.setSSLPrivatePwd(ctx, new)
AppRuntime.log("设置SSL Private密码为[$new]。")
}
)
}
}
}
@ -195,93 +93,35 @@ private fun APIInfoCard(
thickness = 0.2.dp
)
val wsPort = remember { mutableStateOf(ShamrockConfig.getWsPort(ctx).toString()) }
val port = remember { mutableStateOf(ShamrockConfig.getHttpPort(ctx).toString()) }
val rpcPort = remember { mutableStateOf(ShamrockConfig[ctx, RPCPort].toString()) }
TextItem(
title = "主动HTTP端口",
title = "RPC服务端口",
desc = "端口范围在0~65565并确保可用。",
text = port,
text = rpcPort,
hint = "请输入端口号",
error = "端口范围应在0~65565",
checker = {
it.isNotBlank() && kotlin.runCatching { it.toInt() in 0..65565 }.getOrDefault(false) && wsPort.value != it
it.isNotBlank() && kotlin.runCatching { it.toInt() in 0..65565 }
.getOrDefault(false) && rpcPort.value != it
},
confirm = {
val newPort = port.value.toInt()
ShamrockConfig.setHttpPort(ctx, newPort)
val newPort = rpcPort.value.toInt()
ShamrockConfig[ctx, RPCPort] = newPort
AppRuntime.log("设置主动HTTP监听端口为$newPort,立即生效尝试中。")
}
)
val rpcAddress = remember { mutableStateOf(ShamrockConfig[ctx, RPCAddress]) }
TextItem(
title = "主动WebSocket端口",
desc = "端口范围在0~65565并确保可用。",
text = wsPort,
hint = "请输入端口号",
error = "端口范围应在0~65565",
checker = {
it.isNotBlank() && kotlin.runCatching { it.toInt() in 0..65565 }.getOrDefault(false) && it != port.value
},
confirm = {
val newPort = wsPort.value.toInt()
ShamrockConfig.setWsPort(ctx, newPort)
AppRuntime.log("设置主动WebSocket监听端口为$newPort")
}
)
val webHookAddress = remember { mutableStateOf(ShamrockConfig.getHttpAddr(ctx)) }
TextItem(
title = "回调HTTP地址",
desc = "例如http://shamrock.moe:80。",
text = webHookAddress,
title = "回调RPC地址",
desc = "例如kritor.support:8081",
text = rpcAddress,
hint = "请输入回调地址",
error = "输入的地址不合法",
checker = {
it.isNotBlank()
},
confirm = {
if (it.startsWith("http://") || it.startsWith("https://")) {
ShamrockConfig.setHttpAddr(ctx, webHookAddress.value)
AppRuntime.log("设置回调HTTP地址为[${webHookAddress.value}]。")
} else {
Toast.makeText(ctx, "回调地址不合法", Toast.LENGTH_SHORT).show()
webHookAddress.value = ""
}
}
)
val wsAddress = remember { mutableStateOf(ShamrockConfig.getWsAddr(ctx)) }
TextItem(
title = "被动WebSocket地址",
desc = "例如ws://shamrock.moe:81多个使用逗号分隔。",
text = wsAddress,
hint = "请输入被动地址",
error = "输入的地址不合法",
checker = {
true
},
confirm = {
if (it.startsWith("ws://") || it.startsWith("wss://") || it.isBlank()) {
ShamrockConfig.setWsAddr(ctx, wsAddress.value)
AppRuntime.log("设置被动WebSocket地址为[${wsAddress.value}]。")
} else {
Toast.makeText(ctx, "被动WebSocket地址不合法", Toast.LENGTH_SHORT).show()
wsAddress.value = ""
}
}
)
val authToken = remember { mutableStateOf(ShamrockConfig.getToken(ctx)) }
TextItem(
title = "鉴权Token",
desc = "用于鉴权的Token。",
text = authToken,
hint = "请填写鉴权token",
error = "输入的参数不合法",
checker = { true },
confirm = {
ShamrockConfig.setToken(ctx, authToken.value)
AppRuntime.log("设置鉴权Token为[${authToken.value}]。")
ShamrockConfig[ctx, RPCAddress] = rpcAddress.value
AppRuntime.log("设置回调RPC地址为[${rpcAddress.value}]。")
}
)
@ -314,59 +154,59 @@ private fun FunctionCard(
Function(
title = "强制平板模式",
desc = "强制QQ使用平板模式实现共存登录。",
isSwitch = ShamrockConfig.isTablet(ctx)
isSwitch = ShamrockConfig[ctx, ForceTablet]
) {
ShamrockConfig.setTablet(ctx, it)
ShamrockConfig[ctx, ForceTablet] = it
return@Function true
}
Function(
title = "HTTP回调",
desc = "OneBot标准的HTTPAPI回调Shamrock作为Client。",
isSwitch = ShamrockConfig.isWebhook(ctx)
title = "主动RPC",
desc = "Kritor协议实现RPC由Shamrock放出rpc服务",
isSwitch = ShamrockConfig[ctx, ActiveRPC]
) {
ShamrockConfig.setWebhook(ctx, it)
ShamrockConfig[ctx, ActiveRPC] = it
return@Function true
}
Function(
title = "消息格式为CQ码",
desc = "HTTPAPI回调的消息格式关闭则为消息段。",
isSwitch = ShamrockConfig.isUseCQCode(ctx)
title = "被动RPC",
desc = "Kritor协议实现RPC由客户端提供反向的rpc服务",
isSwitch = ShamrockConfig[ctx, PassiveRPC]
) {
ShamrockConfig.setUseCQCode(ctx, it)
ShamrockConfig[ctx, PassiveRPC] = it
return@Function true
}
Function(
title = "主动WebSocket",
desc = "OneBot标准WebSocketShamrock作为Server。",
isSwitch = ShamrockConfig.isWs(ctx)
) {
ShamrockConfig.setWs(ctx, it)
return@Function true
run {
val uploadResourceGroup = remember { mutableStateOf(ShamrockConfig[ctx, ResourceGroup]) }
Column(
modifier = Modifier
.absolutePadding(left = 8.dp, right = 8.dp, top = 12.dp, bottom = 0.dp)
) {
Text(
modifier = Modifier.padding(2.dp),
text = "用来上传资源的群聊,错误的资源上传终点可能导致封禁,请自建一个群聊并填写在下方。",
color = Color.Red,
fontSize = 11.sp
)
}
TextItem(
title = "接受资源群聊",
desc = "用来上传资源的群聊,请自建一个群聊并填写在下方。",
text = uploadResourceGroup,
hint = "请输入群号",
error = "群号不合法",
checker = {
it.isNotBlank() && it.toULongOrNull() != null
},
confirm = {
val groupId = uploadResourceGroup.value
ShamrockConfig[ctx, ResourceGroup] = groupId
AppRuntime.log("设置接受资源群聊为[$groupId]。")
}
)
}
Function(
title = "被动WebSocket",
desc = "OneBot标准WebSocketShamrock作为Client。",
isSwitch = ShamrockConfig.isWsClient(ctx)
) {
ShamrockConfig.setWsClient(ctx, it)
return@Function true
}
/*
Function(
title = "专业级接口",
desc = "如果你不知道你在做什么,请不要开启本功能。",
descColor = Color.Red,
isSwitch = ShamrockConfig.isPro(ctx)
) {
ShamrockConfig.setPro(ctx, it)
AppRuntime.log("专业级API = $it", Level.WARN)
return@Function true
}*/
}
}
}
@ -445,9 +285,7 @@ private fun InfoItem(
.fillMaxWidth()
.combinedClickable(onDoubleClick = {
doubleClick?.invoke(content)
}) {
true
}
}) { true }
,
verticalAlignment = Alignment.CenterVertically
) {

View File

@ -23,7 +23,14 @@ import androidx.compose.ui.unit.sp
import moe.fuqiuluo.shamrock.R
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
import moe.fuqiuluo.shamrock.ui.app.Level
import moe.fuqiuluo.shamrock.ui.app.ShamrockConfig
import moe.fuqiuluo.shamrock.app.config.ShamrockConfig
import moe.fuqiuluo.shamrock.config.AliveReply
import moe.fuqiuluo.shamrock.config.AntiJvmTrace
import moe.fuqiuluo.shamrock.config.B2Mode
import moe.fuqiuluo.shamrock.config.DebugMode
import moe.fuqiuluo.shamrock.config.EnableOldBDH
import moe.fuqiuluo.shamrock.config.EnableSelfMessage
import moe.fuqiuluo.shamrock.ui.service.handlers.InitHandler
import moe.fuqiuluo.shamrock.ui.theme.GlobalColor
import moe.fuqiuluo.shamrock.ui.theme.LocalString
import moe.fuqiuluo.shamrock.ui.tools.NoticeTextDialog
@ -68,9 +75,9 @@ fun LabFragment() {
title = LocalString.b2Mode,
desc = LocalString.b2ModeDesc,
descColor = it,
isSwitch = ShamrockConfig.is2B(ctx)
isSwitch = ShamrockConfig[ctx, B2Mode]
) {
ShamrockConfig.set2B(ctx, it)
ShamrockConfig[ctx, B2Mode] = it
scope.toast(ctx, LocalString.restartToast)
return@Function true
}
@ -79,10 +86,10 @@ fun LabFragment() {
title = LocalString.showDebugLog,
desc = LocalString.showDebugLogDesc,
descColor = it,
isSwitch = ShamrockConfig.isDebug(ctx)
isSwitch = ShamrockConfig[ctx, DebugMode]
) {
ShamrockConfig.setDebug(ctx, it)
ShamrockConfig.pushUpdate(ctx)
ShamrockConfig[ctx, DebugMode] = it
InitHandler.update(ctx)
return@Function true
}
}
@ -100,55 +107,13 @@ fun LabFragment() {
thickness = 0.2.dp
)
/*
Function(
title = "自动清理QQ垃圾",
desc = "也许会导致奇怪的问题(无效)。",
descColor = color,
isSwitch = ShamrockConfig.isAutoClean(ctx)
) {
ShamrockConfig.setAutoClean(ctx, it)
ShamrockConfig.pushUpdate(ctx)
return@Function false
}*/
Function(
title = "自回复测试",
desc = "发送[ping],机器人发送一个具有调试信息的返回。",
descColor = color,
isSwitch = ShamrockConfig.enableAliveReply(ctx)
isSwitch = ShamrockConfig[ctx, AliveReply]
) {
ShamrockConfig.setAliveReply(ctx, it)
return@Function true
}
Function(
title = "开启Shell接口",
desc = "可能导致设备被入侵,请勿随意开启。",
descColor = color,
isSwitch = ShamrockConfig.allowShell(ctx)
) {
ShamrockConfig.setShellStatus(ctx, it)
return@Function true
}
Function(
title = "自动唤醒QQ",
desc = "QQ进程死亡时重新打开QQ进程前提本进程存活。",
descColor = color,
isSwitch = ShamrockConfig.enableAutoStart(ctx)
) {
ShamrockConfig.setAutoStart(ctx, it)
return@Function true
}
Function(
title = "禁止Shamrock同步设置",
desc = "禁止Shamrock同步设置防止恢复手动修改后的配置文件。",
descColor = color,
isSwitch = ShamrockConfig.disableAutoSyncSetting(ctx)
) {
ShamrockConfig.setDisableAutoSyncSetting(ctx, it)
ShamrockConfig[ctx, AliveReply] = it
return@Function true
}
@ -195,25 +160,14 @@ fun LabFragment() {
thickness = 0.2.dp
)
Function(
title = LocalString.injectPacket,
desc = LocalString.injectPacketDesc,
descColor = color,
isSwitch = ShamrockConfig.isInjectPacket(ctx)
) {
ShamrockConfig.setInjectPacket(ctx, it)
ShamrockConfig.pushUpdate(ctx)
return@Function true
}
Function(
title = LocalString.antiTrace,
desc = LocalString.antiTraceDesc,
descColor = color,
isSwitch = ShamrockConfig.isAntiTrace(ctx)
isSwitch = ShamrockConfig[ctx, AntiJvmTrace]
) {
ShamrockConfig.setAntiTrace(ctx, it)
ShamrockConfig.pushUpdate(ctx)
ShamrockConfig[ctx, AntiJvmTrace] = it
scope.toast(ctx, LocalString.restartToast)
return@Function true
}
@ -222,7 +176,7 @@ fun LabFragment() {
}.onSuccess {
Function(
title = "反检测加强",
desc = "可能导致某些设备频繁闪退",
desc = "可能导致某些设备频繁闪退,将拦截环境包上报。",
descColor = color,
isSwitch = it.getBoolean("super_anti", false)
) { v ->
@ -278,35 +232,23 @@ fun LabFragment() {
title = "自发消息推送",
desc = "推送Bot发送的消息未做特殊处理请勿打开。",
descColor = it,
isSwitch = ShamrockConfig.enableSelfMsg(ctx)
isSwitch = ShamrockConfig[ctx, EnableSelfMessage]
) {
ShamrockConfig.setEnableSelfMsg(ctx, it)
ShamrockConfig.pushUpdate(ctx)
ShamrockConfig[ctx, EnableSelfMessage] = it
InitHandler.update(ctx)
return@Function true
}
Function(
title = "同步消息推送类型异换",
desc = "推送来自同号异设备消息,将同步消息作为自发消息推送",
title = "启用旧版资源上传系统",
desc = "如果NT内核无法上传资源请打开本开关",
descColor = it,
isSwitch = ShamrockConfig.enableSyncMsgAsSentMsg(ctx)
isSwitch = ShamrockConfig[ctx, EnableOldBDH]
) {
ShamrockConfig.setEnableSyncMsgAsSentMsg(ctx, it)
ShamrockConfig.pushUpdate(ctx)
ShamrockConfig[ctx, EnableOldBDH] = it
InitHandler.update(ctx)
return@Function true
}
/*
Function(
title = "使用纯数字ECHO",
desc = "在部分强类型语言框架,需要打开此开关。",
descColor = it,
isSwitch = ShamrockConfig.isEchoNumber(ctx)
) {
ShamrockConfig.setEchoNumber(ctx, it)
ShamrockConfig.pushUpdate(ctx)
return@Function true
}*/
}
}
}

View File

@ -1,108 +0,0 @@
@file:OptIn(DelicateCoroutinesApi::class)
package moe.fuqiuluo.shamrock.ui.service
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.core.content.ContextCompat.startActivity
import io.ktor.client.request.get
import io.ktor.client.request.parameter
import io.ktor.client.request.url
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import moe.fuqiuluo.shamrock.remote.structures.CommonResult
import moe.fuqiuluo.shamrock.remote.structures.CurrentAccount
import moe.fuqiuluo.shamrock.remote.structures.Status
import moe.fuqiuluo.shamrock.tools.GlobalClient
import moe.fuqiuluo.shamrock.ui.app.AppRuntime.AccountInfo
import moe.fuqiuluo.shamrock.ui.app.AppRuntime.log
import moe.fuqiuluo.shamrock.ui.app.AppRuntime.state
import moe.fuqiuluo.shamrock.ui.app.Level
import moe.fuqiuluo.shamrock.ui.app.ShamrockConfig
import moe.fuqiuluo.shamrock.ui.service.internal.broadcastToModule
import java.net.ConnectException
import java.util.Timer
import kotlin.concurrent.timer
object DashboardInitializer {
private var servicePort: Int = 0
private lateinit var heartbeatTimer: Timer
operator fun invoke(context: Context, port: Int) {
servicePort = port
initHeartbeat(true, context)
}
private fun initHeartbeat(reload: Boolean, context: Context) {
if (::heartbeatTimer.isInitialized && !reload) {
return
}
if (::heartbeatTimer.isInitialized) {
heartbeatTimer.cancel()
}
heartbeatTimer = timer("heartbeat", false, 0, 1000L * 30) {
checkService(context)
}
}
private fun checkService(context: Context) {
GlobalScope.launch {
try {
GlobalClient.get {
url("http://127.0.0.1:$servicePort/get_account_info")
val token = ShamrockConfig.getToken(context)
if (token.isNotBlank()) {
//header("Authorization", "Bearer $token")
parameter("access_token", token)
}
}.let {
if (it.status == HttpStatusCode.OK) {
val result: CommonResult<CurrentAccount> = Json.decodeFromString(it.bodyAsText())
state.isFined.value = result.retcode == 0
if (result.retcode == Status.InternalHandlerError.code) {
log("账号未登录。", Level.WARN)
} else if (result.retcode != 0) {
log("尝试从接口获取账号信息失败,未知错误。", Level.ERROR)
} else {
AccountInfo.let { account ->
account.uin.value = result.data.uin.toString()
account.nick.value = result.data.nick
}
}
} else {
state.isFined.value = false
log("尝试从接口获取账号信息失败,服务运行异常。", Level.ERROR)
}
}
} catch (e: ConnectException) {
state.isFined.value = false
context.broadcastToModule {
putExtra("__cmd", "checkAndStartService")
}
if (ShamrockConfig.enableAutoStart(context)) {
log("检测到Service死亡正在尝试重新启动")
GlobalScope.launch(Dispatchers.Main) {
val packageName = "com.tencent.mobileqq"
val className = "com.tencent.mobileqq.activity.SplashActivity"
val intent = Intent()
intent.component = ComponentName(packageName, className)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.putExtra("from", "shamrock")
startActivity(context, intent, Bundle.EMPTY)
}
}
} catch (e: Throwable) {
state.isFined.value = false
log(e.stackTraceToString(), Level.ERROR)
}
}
}
}

View File

@ -1,15 +0,0 @@
package moe.fuqiuluo.shamrock.ui.service.handlers
import android.content.ContentValues
import android.content.Context
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
import moe.fuqiuluo.shamrock.ui.service.DashboardInitializer
object FetchPortHandler: ModuleHandler() {
override val cmd: String = "success"
override fun onReceive(callbackId: Int, values: ContentValues, context: Context) {
AppRuntime.state.supportVoice.value = values.getAsBoolean("voice")
DashboardInitializer(context, values.getAsInteger("port"))
}
}

View File

@ -3,13 +3,37 @@ package moe.fuqiuluo.shamrock.ui.service.handlers
import android.content.ContentValues
import android.content.Context
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
import moe.fuqiuluo.shamrock.ui.app.ShamrockConfig
import moe.fuqiuluo.shamrock.app.config.ShamrockConfig
import moe.fuqiuluo.shamrock.config.*
internal object InitHandler: ModuleHandler() {
override val cmd: String = "init"
override fun onReceive(callbackId: Int, values: ContentValues, context: Context) {
update(context)
}
fun update(context: Context) {
AppRuntime.log("推送QQ进程初始化设置数据包成功...")
callback(context, callbackId, ShamrockConfig.getConfigMap(context))
val maps = hashMapOf<String, Any?>()
ActiveRPC.update(context, maps)
AliveReply.update(context, maps)
AntiJvmTrace.update(context, maps)
DebugMode.update(context, maps)
EnableOldBDH.update(context, maps)
EnableSelfMessage.update(context, maps)
ForceTablet.update(context, maps)
PassiveRPC.update(context, maps)
ResourceGroup.update(context, maps)
RPCAddress.update(context, maps)
RPCPort.update(context, maps)
callback(context, 1, maps)
}
private inline fun <reified T> ConfigKey<T>.update(context: Context, map: HashMap<String, Any?>) {
map[name()] = ShamrockConfig[context, this]
}
}

View File

@ -29,6 +29,7 @@ abstract class ModuleHandler {
}
}
}
putExtra("__cmd", cmd)
putExtra("__hash", callbackId)
}
}

View File

@ -0,0 +1,49 @@
package moe.fuqiuluo.shamrock.ui.service.handlers
import android.content.ContentValues
import android.content.Context
import android.widget.Toast
import moe.fuqiuluo.shamrock.tools.GlobalUi
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
import java.util.Timer
import kotlin.concurrent.timer
import kotlin.concurrent.timerTask
object SwitchStatus: ModuleHandler() {
override val cmd: String
get() = "switch_status"
private var lastActiveTime = 0L
private var timer: Timer? = null
override fun onReceive(callbackId: Int, values: ContentValues, context: Context) {
val voiceSwitch = values.getAsBoolean("voice")
val nickname = values.getAsString("nickname")
val account = values.getAsString("account")
if (lastActiveTime == 0L) GlobalUi.post {
Toast.makeText(context, "激活成功", Toast.LENGTH_SHORT).show()
}
AppRuntime.state.apply {
isFined.value = true
coreVersion.value = values.getAsString("core_version")
coreName.value = "LSPosed"
supportVoice.value = voiceSwitch
}
AppRuntime.AccountInfo.apply {
uin.value = account
nick.value = nickname
}
lastActiveTime = System.currentTimeMillis()
startTimer()
}
private fun startTimer() {
timer?.cancel()
timer = timer("SwitchStatus", true, 0, 5_000) {
if (lastActiveTime != 0L && System.currentTimeMillis() - lastActiveTime > 30 * 1000) {
AppRuntime.state.isFined.value = false
lastActiveTime = 0
}
}
}
}

View File

@ -5,9 +5,9 @@ import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.database.Cursor
import android.net.Uri
import moe.fuqiuluo.shamrock.ui.service.ModuleTalker
import moe.fuqiuluo.shamrock.ui.service.handlers.*
import android.net.Uri
class MultifunctionalProvider: ContentProvider() {
override fun insert(uri: Uri, content: ContentValues?): Uri {
@ -28,8 +28,8 @@ class MultifunctionalProvider: ContentProvider() {
override fun onCreate(): Boolean {
ModuleTalker.register(InitHandler)
ModuleTalker.register(FetchPortHandler)
ModuleTalker.register(LogHandler)
ModuleTalker.register(SwitchStatus)
return true
}
@ -58,7 +58,7 @@ class MultifunctionalProvider: ContentProvider() {
inline fun Context.broadcastToModule(intentBuilder: Intent.() -> Unit) {
val intent = Intent()
intent.action = "moe.fuqiuluo.xqbot.dynamic"
intent.action = "moe.fuqiuluo.kritor.dynamic"
intent.intentBuilder()
sendBroadcast(intent)
}

View File

@ -1,23 +1,35 @@
package moe.fuqiuluo.shamrock.ui.tools
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.Indication
import androidx.compose.foundation.background
import androidx.compose.foundation.indication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.selection.selectable
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Text
import androidx.compose.material3.Typography
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@ -31,8 +43,10 @@ import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
@ -135,20 +149,18 @@ private fun TabBaselineLayout(
text: @Composable (() -> Unit)?,
icon: @Composable (() -> Unit)?
) {
Layout(
{
if (text != null) {
Box(
Modifier
.layoutId("text")
.padding(horizontal = HorizontalTextPadding)
) { text() }
}
if (icon != null) {
Box(Modifier.layoutId("icon")) { icon() }
}
Layout({
if (text != null) {
Box(
Modifier
.layoutId("text")
.padding(horizontal = HorizontalTextPadding)
) { text() }
}
) { measurables, constraints ->
if (icon != null) {
Box(Modifier.layoutId("icon")) { icon() }
}
}) { measurables, constraints ->
val textPlaceable = text?.let {
measurables.first { it.layoutId == "text" }.measure(
// Measure with loose constraints for height as we don't want the text to take up more
@ -247,21 +259,66 @@ fun ShamrockTab(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
text: @Composable (() -> Unit)? = null,
icon: @Composable (() -> Unit)? = null,
selectedContentColor: Color = GlobalColor.TabSelected,
unselectedContentColor: Color = selectedContentColor,
indication: Indication? = rememberRipple(bounded = true, color = selectedContentColor),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
titleWithIcon: Pair<String, Int>,
visibleState: MutableTransitionState<Boolean>
) {
val styledText: @Composable (() -> Unit)? = text?.let {
@Composable {
val style =
MaterialTheme.typography.fromToken(PrimaryNavigationTabTokens.LabelTextFont)
.copy(textAlign = TextAlign.Center)
ProvideTextStyle(style, content = text)
var text: @Composable (() -> Unit)? = null
var icon: @Composable (() -> Unit)? = null
if (!selected) {
icon = {
Icon(
painter = painterResource(id = titleWithIcon.second),
contentDescription = titleWithIcon.first,
tint = Color.Unspecified,
modifier = Modifier
.height(24.dp)
.width(24.dp)
.padding(bottom = 5.dp)
.indication(
remember { MutableInteractionSource() },
rememberRipple(color = Color.Transparent)
)
)
}
} else {
text = {
val style = MaterialTheme.typography
.fromToken(PrimaryNavigationTabTokens.LabelTextFont)
.copy(textAlign = TextAlign.Center)
ProvideTextStyle(style) {
AnimatedVisibility(
visibleState = visibleState,
enter = remember {
scaleIn(animationSpec = TweenSpec(150, easing = FastOutLinearInEasing))
},
exit = remember {
scaleOut(animationSpec = TweenSpec(150, easing = FastOutSlowInEasing))
},
modifier = Modifier
) {
Text(
text = titleWithIcon.first,
color = GlobalColor.TabItem,
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(bottom = 5.dp)
.indication(
remember { MutableInteractionSource() },
rememberRipple(color = Color.Transparent)
)
)
}
}
}
}
ShamrockTab(
selected,
onClick,
@ -272,7 +329,10 @@ fun ShamrockTab(
interactionSource,
indication
) {
TabBaselineLayout(icon = icon, text = styledText)
TabBaselineLayout(
icon = icon,
text = text
)
}
}

View File

@ -2,16 +2,14 @@ package moe.fuqiuluo.shamrock
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
fun test() {
}
}

View File

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.2.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.20" apply false
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
id("com.android.library") version "8.2.0" apply false
}

View File

@ -1,5 +1,5 @@
plugins {
kotlin("jvm") version "1.9.21"
kotlin("jvm") version "1.9.22"
}
repositories {

View File

@ -7,10 +7,6 @@ val DEPENDENCY_ANDROIDX = arrayOf(
"androidx.activity:activity-compose:1.7.2",
)
const val DEPENDENCY_JSON5K = "io.github.xn32:json5k:0.3.0"
const val DEPENDENCY_PROTOBUF = "com.google.protobuf:protobuf-java:3.24.0"
const val DEPENDENCY_JAVA_WEBSOCKET = "org.java-websocket:Java-WebSocket:1.5.4"
fun room(name: String) = "androidx.room:room-$name:${Versions.roomVersion}"
fun kotlinx(name: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$name:$version"
@ -19,8 +15,9 @@ fun ktor(target: String, name: String): String {
return "io.ktor:ktor-$target-$name:${Versions.ktorVersion}"
}
fun grpc(name: String, version: String) = "io.grpc:grpc-$name:$version"
object Versions {
const val roomVersion = "2.5.0"
const val ktorVersion = "2.3.3"
}

42
kritor/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

76
kritor/build.gradle.kts Normal file
View File

@ -0,0 +1,76 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
id("com.google.protobuf") version "0.9.4"
}
android {
namespace = "moe.whitechi73.kritor"
compileSdk = 34
defaultConfig {
minSdk = 24
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
protobuf(files("kritor/protos"))
implementation("com.google.protobuf:protobuf-java:4.26.0")
implementation(kotlinx("coroutines-core", "1.8.0"))
implementation(grpc("stub", "1.62.2"))
implementation(grpc("protobuf", "1.62.2"))
implementation(grpc("kotlin-stub", "1.4.1"))
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:4.26.0"
}
plugins {
create("grpc") {
artifact = "io.grpc:protoc-gen-grpc-java:1.62.2"
}
create("grpckt") {
artifact = "io.grpc:protoc-gen-grpc-kotlin:1.4.1:jdk8@jar"
}
}
generateProtoTasks {
all().forEach {
it.plugins {
create("grpc")
create("grpckt")
}
it.builtins {
create("java")
}
}
}
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
}

View File

1
kritor/kritor Submodule

Submodule kritor/kritor added at 3dec747a8e

21
kritor/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -1,6 +1,7 @@
plugins {
kotlin("jvm")
id("com.google.devtools.ksp") version "1.9.21-1.0.15"
id("com.google.devtools.ksp") version "1.9.22-1.0.17"
kotlin("plugin.serialization") version "1.9.22"
}
ksp {
@ -14,5 +15,8 @@ dependencies {
implementation("com.google.devtools.ksp:symbol-processing-api:1.9.21-1.0.15")
implementation("com.squareup:kotlinpoet:1.14.2")
//implementation(DEPENDENCY_PROTOBUF)
implementation(kotlinx("serialization-protobuf", "1.6.2"))
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.1.0")
}

View File

@ -0,0 +1,83 @@
@file:Suppress("UNCHECKED_CAST")
@file:OptIn(KspExperimental::class)
package moe.fuqiuluo.ksp.impl
import com.google.devtools.ksp.KspExperimental
import com.google.devtools.ksp.getAnnotationsByType
import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import kritor.service.Grpc
class GrpcProcessor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger
): SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
val symbols = resolver.getSymbolsWithAnnotation(Grpc::class.qualifiedName!!)
val actions = (symbols as Sequence<KSFunctionDeclaration>).toList()
if (actions.isEmpty()) return emptyList()
// 怎么返回nullable的结果
val packageName = "kritor.handlers"
val funcBuilder = FunSpec.builder("handleGrpc")
.addModifiers(KModifier.SUSPEND)
.addParameter("cmd", String::class)
.addParameter("data", ByteArray::class)
.returns(ByteArray::class)
val fileSpec = FileSpec.scriptBuilder("AutoGrpcHandlers", packageName)
logger.warn("Found ${actions.size} grpc-actions")
//logger.error(resolver.getClassDeclarationByName("io.kritor.AuthReq").toString())
//logger.error(resolver.getJavaClassByName("io.kritor.AuthReq").toString())
//logger.error(resolver.getKotlinClassByName("io.kritor.AuthReq").toString())
actions.forEach { action ->
val methodName = action.qualifiedName?.asString()!!
val grpcMethod = action.getAnnotationsByType(Grpc::class).first()
val service = grpcMethod.serviceName
val funcName = grpcMethod.funcName
funcBuilder.addStatement("if (cmd == \"${service}.${funcName}\") {\t")
val reqType = action.parameters[0].type.toString()
val rspType = action.returnType.toString()
funcBuilder.addStatement("val resp: $rspType = $methodName($reqType.parseFrom(data))")
funcBuilder.addStatement("return resp.toByteArray()")
funcBuilder.addStatement("}")
}
funcBuilder.addStatement("return EMPTY_BYTE_ARRAY")
fileSpec
.addStatement("import io.kritor.authentication.*")
.addStatement("import io.kritor.core.*")
.addStatement("import io.kritor.customization.*")
.addStatement("import io.kritor.developer.*")
.addStatement("import io.kritor.file.*")
.addStatement("import io.kritor.friend.*")
.addStatement("import io.kritor.group.*")
.addStatement("import io.kritor.guild.*")
.addStatement("import io.kritor.message.*")
.addStatement("import io.kritor.web.*")
.addFunction(funcBuilder.build())
.addImport("moe.fuqiuluo.symbols", "EMPTY_BYTE_ARRAY")
runCatching {
codeGenerator.createNewFile(
dependencies = Dependencies(aggregating = false),
packageName = packageName,
fileName = fileSpec.name
).use { outputStream ->
outputStream.writer().use {
fileSpec.build().writeTo(it)
}
}
}
return emptyList()
}
}

View File

@ -1,84 +0,0 @@
@file:OptIn(KspExperimental::class)
@file:Suppress("LocalVariableName", "UNCHECKED_CAST")
package moe.fuqiuluo.ksp.impl
import com.google.devtools.ksp.KspExperimental
import com.google.devtools.ksp.getAnnotationsByType
import com.google.devtools.ksp.getClassDeclarationByName
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSVisitorVoid
import com.google.devtools.ksp.validate
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import moe.fuqiuluo.symbols.OneBotHandler
class OneBotHandlerProcessor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger
): SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
val ActionManagerNode = resolver.getClassDeclarationByName("moe.fuqiuluo.shamrock.remote.action.ActionManager")
if (ActionManagerNode == null) {
logger.error("OneBotHandlerProcessor: ActionManager not found")
return emptyList()
}
val symbols = resolver.getSymbolsWithAnnotation(OneBotHandler::class.qualifiedName!!)
val unableToProcess = symbols.filterNot { it.validate() }
val oneBotHandlers = (symbols.filter {
it is KSClassDeclaration && it.validate() && it.classKind == ClassKind.OBJECT
} as Sequence<KSClassDeclaration>).toList()
if (oneBotHandlers.isNotEmpty()) {
ActionManagerNode.accept(ActionManagerVisitor(oneBotHandlers), Unit)
}
return unableToProcess.toList()
}
inner class ActionManagerVisitor(
private val actionHandlers: List<KSClassDeclaration>
): KSVisitorVoid() {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
val packageName = classDeclaration.packageName.asString()
// generate kotlin `init { }`
val fileSpec = FileSpec.builder(packageName, classDeclaration.qualifiedName?.asString() ?: run {
throw IllegalStateException("ActionManagerVisitor: classDeclaration.qualifiedName is null")
}).addFunction(FunSpec.builder("initManager").apply {
actionHandlers.forEach { handler ->
// fetch the params of the annotation
val annotation = handler.getAnnotationsByType(OneBotHandler::class).first()
val actionName = annotation.actionName
val alias = annotation.alias
alias.forEach { name ->
addStatement("actionMap[\"$name\"] = ${handler.simpleName.asString()}")
}
addStatement("actionMap[\"$actionName\"] = ${handler.simpleName.asString()}")
}
}.build()).apply {
addImport("moe.fuqiuluo.shamrock.remote.action.ActionManager", "actionMap")
actionHandlers.forEach {
addImport(it.packageName.asString(), it.simpleName.asString())
}
}.build()
codeGenerator.createNewFile(
dependencies = Dependencies(aggregating = false),
packageName = packageName,
fileName = "Auto" + classDeclaration.simpleName.asString()
).use { outputStream ->
outputStream.writer().use {
fileSpec.writeTo(it)
}
}
}
}
}

View File

@ -0,0 +1,77 @@
@file:Suppress("UNCHECKED_CAST")
package moe.fuqiuluo.ksp.impl
import com.google.devtools.ksp.isInternal
import com.google.devtools.ksp.isPrivate
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSDeclaration
import com.google.devtools.ksp.validate
import com.squareup.kotlinpoet.FileSpec
import kotlinx.serialization.Serializable
class ProtobufProcessor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger
): SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
val symbols = resolver.getSymbolsWithAnnotation(Serializable::class.qualifiedName!!)
val unableToProcess = symbols.filterNot { it.validate() }
val actions = (symbols.filter {
it is KSClassDeclaration && it.validate() && it.classKind == ClassKind.CLASS
} as Sequence<KSClassDeclaration>).filter {
it.superTypes.any { superType ->
superType.resolve().declaration.qualifiedName?.asString() == "moe.fuqiuluo.symbols.Protobuf"
}
}.toList()
if (actions.isNotEmpty()) {
actions.forEachIndexed { _, clz ->
if (clz.isInternal()) return@forEachIndexed
if (clz.isPrivate()) return@forEachIndexed
val packageName = "protobuf.auto"
val fileSpecBuilder = FileSpec.scriptBuilder("FastProtobuf", packageName)
fileSpecBuilder.addImport("kotlinx.serialization.protobuf", "ProtoBuf")
fileSpecBuilder.addImport("kotlinx.serialization", "decodeFromByteArray")
fileSpecBuilder.addImport("kotlinx.serialization", "encodeToByteArray")
if (clz.parentDeclaration != null) {
fileSpecBuilder.addImport(clz.importPackage, clz.simpleName.asString())
} else {
fileSpecBuilder.addImport(clz.packageName.asString(), clz.simpleName.asString())
}
if (clz.typeParameters.isNotEmpty()) {
val genericType = clz.typeParameters.joinToString(", ") { it.name.asString() }
fileSpecBuilder.addStatement("""inline fun <$genericType> ${clz.simpleName.asString()}<$genericType>.toByteArray() = ProtoBuf.encodeToByteArray(this)""")
} else {
fileSpecBuilder.addStatement("inline fun ${clz.simpleName.asString()}.toByteArray() = ProtoBuf.encodeToByteArray(this)")
}
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = packageName,
fileName = "FP${clz.simpleName.asString().hashCode()}"
).use { outputStream ->
outputStream.writer().use {
fileSpecBuilder.build().writeTo(it)
}
}
}
}
return unableToProcess.toList()
}
private val KSDeclaration.importPackage: String
get() = if (parentDeclaration != null) {
parentDeclaration!!.importPackage + "." + parentDeclaration!!.simpleName.asString()
} else packageName.asString()
}

View File

@ -1,5 +1,5 @@
@file:Suppress("UNCHECKED_CAST", "LocalVariableName", "PrivatePropertyName")
@file:OptIn(KspExperimental::class)
@file:OptIn(KspExperimental::class, KspExperimental::class)
package moe.fuqiuluo.ksp.impl
@ -27,10 +27,14 @@ class XposedHookProcessor(
private val logger: KSPLogger
): SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
val symbols = resolver.getSymbolsWithAnnotation(XposedHook::class.qualifiedName!!)
val symbols = resolver.getSymbolsWithAnnotation(
annotationName = XposedHook::class.qualifiedName!!,
inDepth = true
)
logger.warn("Found ${symbols.count()} classes annotated with XposedHook")
val unableToProcess = symbols.filterNot { it.validate() }
val actions = (symbols.filter {
it is KSClassDeclaration && it.validate() && it.classKind == ClassKind.CLASS
it is KSClassDeclaration && it.classKind == ClassKind.CLASS
} as Sequence<KSClassDeclaration>).toList()
if (actions.isNotEmpty()) {
@ -46,7 +50,7 @@ class XposedHookProcessor(
}
val context = ClassName("android.content", "Context")
val packageName = "moe.fuqiuluo.shamrock.xposed.hooks"
val packageName = "moe.fuqiuluo.shamrock.xposed.actions"
val fileSpec = FileSpec.builder(packageName, "AutoActionLoader").addFunction(FunSpec.builder("runFirstActions")
.addParameter("ctx", context)
.apply {
@ -96,16 +100,6 @@ class XposedHookProcessor(
}
}
}
return unableToProcess.toList()
}
inner class ActionLoaderVisitor(
private val firstActions: List<KSClassDeclaration>,
private val serviceActions: List<KSClassDeclaration>,
): KSVisitorVoid() {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
}
}
}

View File

@ -4,12 +4,12 @@ import com.google.auto.service.AutoService
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import moe.fuqiuluo.ksp.impl.OneBotHandlerProcessor
import moe.fuqiuluo.ksp.impl.GrpcProcessor
@AutoService(SymbolProcessorProvider::class)
class OneBotHandlerProcessorProvider: SymbolProcessorProvider {
class GrpcProvider: SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return OneBotHandlerProcessor(
return GrpcProcessor(
environment.codeGenerator,
environment.logger
)

View File

@ -0,0 +1,17 @@
package moe.fuqiuluo.ksp.providers
import com.google.auto.service.AutoService
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import moe.fuqiuluo.ksp.impl.ProtobufProcessor
@AutoService(SymbolProcessorProvider::class)
class ProtobufProvider: SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return ProtobufProcessor(
environment.codeGenerator,
environment.logger
)
}
}

View File

@ -1,7 +1,10 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
kotlin("plugin.serialization") version "1.9.21"
kotlin("plugin.serialization") version "1.9.22"
id("com.google.devtools.ksp") version "1.9.22-1.0.17"
}
android {
@ -34,8 +37,14 @@ android {
}
dependencies {
implementation(DEPENDENCY_PROTOBUF)
implementation(kotlinx("serialization-protobuf", "1.6.2"))
implementation(kotlinx("serialization-json", "1.6.2"))
implementation(project(":annotations"))
ksp(project(":processor"))
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
}

View File

@ -2,9 +2,10 @@ package protobuf.fav
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class WeiyunComm(
@ProtoNumber(1) val req: WeiyunCommonReq? = null,
@ProtoNumber(2) val resp: WeiyunCommonResp? = null
)
): Protobuf<WeiyunComm>

View File

@ -6,6 +6,7 @@ package protobuf.fav
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class WeiyunMsgHead(
@ -27,4 +28,5 @@ data class WeiyunMsgHead(
@ProtoNumber(103) val promptMsg: String? = null,
@ProtoNumber(111) val totalSpace: ULong = ULong.MIN_VALUE,
@ProtoNumber(112) val usedSpace: ULong = ULong.MIN_VALUE,
)
): Protobuf<WeiyunMsgHead>

View File

@ -6,6 +6,7 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
import protobuf.qweb.QWebExtInfo
@Serializable
@ -19,7 +20,7 @@ data class GetGuildFeedsReq(
@ProtoNumber(7) var u7: Int? = null,
@ProtoNumber(8) var u8: Int? = null,
@ProtoNumber(9) var u9: ByteArray? = null,
)
): Protobuf<GetGuildFeedsReq>
@Serializable
data class GetGuildFeedsRsp(
@ -27,7 +28,7 @@ data class GetGuildFeedsRsp(
@ProtoNumber(2) var isFinish: Int = 0,
//@ProtoNumber(3) var feedAttchInfo: ByteArray? = null,
//@ProtoNumber(4) var traceId: String? = null,
)
): Protobuf<GetGuildFeedsRsp>
@Serializable
data class StFeed(

View File

@ -0,0 +1,42 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.lightapp
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class AdaptShareInfoReq(
//@ProtoNumber(1) var extInfo: Any? = null,
@ProtoNumber(2) var appid: String? = null,
@ProtoNumber(3) var title: String? = null,
@ProtoNumber(4) var desc: String? = null,
@ProtoNumber(5) var time: ULong? = null,
@ProtoNumber(6) var scene: UInt? = null,
@ProtoNumber(7) var templetType: UInt? = null,
@ProtoNumber(8) var businessType: UInt? = null,
@ProtoNumber(9) var picUrl: String? = null,
@ProtoNumber(10) var vidUrl: String? = null,
@ProtoNumber(11) var jumpUrl: String? = null,
@ProtoNumber(12) var iconUrl: String? = null,
@ProtoNumber(13) var verType: UInt? = null,
@ProtoNumber(14) var shareType: UInt? = null,
@ProtoNumber(15) var versionId: String? = null,
@ProtoNumber(16) var withShareTicket: UInt? = null,
@ProtoNumber(17) var webURL: String? = null,
//@ProtoNumber(18) var appidRich: Any? = null,
@ProtoNumber(19) var template: Template? = null,
//@ProtoNumber(20) var rcvOpenId: Any? = null,
): Protobuf<AdaptShareInfoReq>
@Serializable
data class Template(
@ProtoNumber(1) var templateId: ULong? = null,
@ProtoNumber(2) var templateData: ByteArray? = null,
)
@Serializable
data class AdaptShareInfoResp(
@ProtoNumber(2) var json: String? = null,
): Protobuf<AdaptShareInfoResp>

View File

@ -0,0 +1,26 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class AppShareInfo(
@ProtoNumber(1) var appshareId: UInt? = null,
@ProtoNumber(2) var appshareCookie: ByteArray? = null,
@ProtoNumber(3) var appshareResource: PluginInfo? = null,
)
@Serializable
data class PluginInfo(
@ProtoNumber(1) var resId: UInt = 0u,
@ProtoNumber(2) var pkgName: String = "",
@ProtoNumber(3) var newVer: UInt = 0u,
@ProtoNumber(4) var resType: UInt = 0u,
@ProtoNumber(5) var lanType: UInt = 0u,
@ProtoNumber(6) var priority: UInt = 0u,
@ProtoNumber(7) var resName: String = "",
@ProtoNumber(8) var resDesc: String = "",
@ProtoNumber(9) var resUrlBig: String = "",
@ProtoNumber(10) var resUrlSmall: String = "",
@ProtoNumber(11) var resConf: String = "",
)

View File

@ -0,0 +1,31 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class ContentHead(
@ProtoNumber(1) val msgType: Int = Int.MIN_VALUE,
@ProtoNumber(2) val msgSubType: Int? = null,
@ProtoNumber(3) val divSeq: Int? = null,
@ProtoNumber(4) val msgViaRandom: Long = Long.MIN_VALUE,
@ProtoNumber(5) val sequence: Long? = null,
@ProtoNumber(6) val msgTime: Long? = null,
@ProtoNumber(7) val u2: Int? = null,
@ProtoNumber(8) val u6: Int? = null,
@ProtoNumber(9) val u7: Int? = null,
@ProtoNumber(11) val msgSeq: Long? = null,
@ProtoNumber(12) val msgRandom: Long = Long.MIN_VALUE, // 0x0100000000000000L xor msgViaRandom
@ProtoNumber(14) val u4: Long? = null,
@ProtoNumber(15) val forwardHead: ForwardHead? = null,
@ProtoNumber(28) val u5: Long? = null
)
@Serializable
data class ForwardHead(
@ProtoNumber(1) val u1: Int? = null,
@ProtoNumber(2) val u2: Int? = null,
@ProtoNumber(3) val u3: Int? = null,
@ProtoNumber(4) val ub641: String? = null,
@ProtoNumber(5) val avatar: String? = null
)

View File

@ -0,0 +1,64 @@
package protobuf.message
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import protobuf.message.element.*
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class Elem(
@ProtoNumber(1) val text: TextMsg? = null,
@ProtoNumber(2) val face: FaceMsg? = null,
// @ProtoNumber(3) val onlineImage: OnlineImage? = null,
@ProtoNumber(4) val notOnlineImage: NotOnlineImage? = null,
// @ProtoNumber(5) var transElemInfo: TransElem? = null,
@ProtoNumber(6) val marketFace: MarketFace? = null,
// @ProtoNumber(7) var elemFlags: ElemFlags? = null,
@ProtoNumber(8) val customFace: CustomFace? = null,
@ProtoNumber(9) var elemFlags2: ElemFlags2? = null,
// @ProtoNumber(10) var funFace: FunFace? = null,
// @ProtoNumber(11) var secretFile: SecretFileMsg? = null,
// @ProtoNumber(12) var richMsg: RichMsg? = null,
// @ProtoNumber(13) var groupFile: GroupFile? = null,
// @ProtoNumber(14) var pubGroup: PubGroup? = null,
// @ProtoNumber(15) var marketTrans: MarketTrans? = null,
// @ProtoNumber(16) var extraInfo: ExtraInfo? = null,
// @ProtoNumber(17) var shakeWindow: ShakeWindow? = null,
// @ProtoNumber(18) var pubAccount: PubAccount? = null,
// @ProtoNumber(19) var videoFile: VideoFile? = null,
// @ProtoNumber(20) var tipsInfo: TipsInfo? = null,
// @ProtoNumber(21) var anonGroupMsg: AnonymousGroupMsg? = null,
// @ProtoNumber(22) var qqLiveOld: QQLiveOld? = null,
// @ProtoNumber(23) var lifeOnline: LifeOnlineAccount? = null,
// @ProtoNumber(24) var qqwalletMsg: QQWalletMsg? = null,
// @ProtoNumber(25) var crmElem: CrmElem? = null,
// @ProtoNumber(26) var conferenceTipsInfo: ConferenceTipsInfo? = null,
// @ProtoNumber(27) var redbagInfo: RedBagInfo? = null,
// @ProtoNumber(28) var lowVersionTips: LowVersionTips? = null,
// @ProtoNumber(29) var bankcodeCtrlInfo: ByteArray? = null,
// @ProtoNumber(30) var nearByMsg: NearByMessageType? = null,
// @ProtoNumber(31) var customElem: CustomElem? = null,
// @ProtoNumber(32) var locationInfo: LocationInfo? = null,
// @ProtoNumber(33) var pubAccInfo: PubAccInfo? = null,
// @ProtoNumber(34) var smallEmoji: SmallEmoji? = null,
// @ProtoNumber(35) var fsjMsgElem: FSJMessageElem? = null,
// @ProtoNumber(36) var arkApp: ArkAppElem? = null,
@ProtoNumber(37) val generalFlags: GeneralFlags? = null,
// @ProtoNumber(38) var hcFlashPic: CustomFace? = null,
// @ProtoNumber(39) var deliverGiftMsg: DeliverGiftMsg? = null,
// @ProtoNumber(40) var bitapp_msg: BitAppMsg? = null,
// @ProtoNumber(41) var openQqData: OpenQQData? = null,
// @ProtoNumber(42) var apolloMsg: ApolloActMsg? = null,
// @ProtoNumber(43) var groupPubAccInfo: GroupPubAccountInfo? = null,
// @ProtoNumber(44) var blessMsg: BlessingMessage? = null,
@ProtoNumber(45) var srcMsg: SourceMsg? = null,
// @ProtoNumber(46) var lolaMsg: LolaMsg? = null,
// @ProtoNumber(47) var groupBusinessMsg: GroupBusinessMsg? = null,
// @ProtoNumber(48) var msgWorkflowNotify: WorkflowNotifyMsg? = null,
// @ProtoNumber(49) var patElem: PatsElem? = null,
// @ProtoNumber(50) var groupPostElem: GroupPostElem? = null,
@ProtoNumber(51) val lightApp: LightAppElem? = null,
// @ProtoNumber(52) var eimInfo: EIMInfo? = null,
@ProtoNumber(53) val commonElem: CommonElem? = null,
)

View File

@ -1,57 +0,0 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.message
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MessageBody(
@ProtoNumber(1) val msgHead: MessageHead? = null,
@ProtoNumber(2) val contentHead: MessageContentHead? = null,
@ProtoNumber(3) val richMsg: RichMessage? = null,
)
@Serializable
data class RichMessage(
@ProtoNumber(1) val elements: MessageElementList? = null,
@ProtoNumber(2) val rawBuffer: ByteArray? = null,
)
@Serializable
data class MessageElementList(
@ProtoNumber(2) val elements: List<MessageElement>? = null
)
@Serializable
data class MessageElement(
@ProtoNumber(51) val json: JsonElement? = null,
)
@Serializable
data class JsonElement(
@ProtoNumber(1) val data: ByteArray? = null,
)
@Serializable
data class MessageHead(
@ProtoNumber(1) val peer: Long = Long.MIN_VALUE,
@ProtoNumber(2) val peerUid: String? = null,
@ProtoNumber(3) val flag: Int = Int.MIN_VALUE,
@ProtoNumber(5) val receiver: Long? = null,
@ProtoNumber(6) val receiverUid: String? = null,
)
@Serializable
data class MessageContentHead(
@ProtoNumber(1) val msgType: Int = Int.MIN_VALUE,
@ProtoNumber(2) val msgSubType: Int = Int.MIN_VALUE,
@ProtoNumber(4) val u1: Long = Long.MIN_VALUE,
@ProtoNumber(5) val msgSeq: Long = Long.MIN_VALUE,
@ProtoNumber(6) val msgTime: Long? = null,
@ProtoNumber(7) val u2: Int? = null,
@ProtoNumber(11) val u3: Long? = null,
@ProtoNumber(12) val msgRandom: Long = Long.MIN_VALUE,
@ProtoNumber(14) val u4: Long? = null,
@ProtoNumber(28) val u5: Long? = null,
)

View File

@ -0,0 +1,11 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MsgBody(
@ProtoNumber(1) val richText: RichText? = null,
@ProtoNumber(2) val msgContent: ByteArray? = null,
@ProtoNumber(3) val msgEncryptContent: ByteArray? = null
)

View File

@ -0,0 +1,9 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MsgControl(
@ProtoNumber(1) val msgFlag: Int? = null,
)

View File

@ -0,0 +1,28 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class NotOnlineFile(
@ProtoNumber(1) var fileType: UInt? = null,
@ProtoNumber(2) var sig: ByteArray? = null,
@ProtoNumber(3) var fileUuid: ByteArray? = null,
@ProtoNumber(4) var fileMd5: ByteArray? = null,
@ProtoNumber(5) var fileName: ByteArray? = null,
@ProtoNumber(6) var fileSize: ULong? = null,
@ProtoNumber(7) var note: ByteArray? = null,
@ProtoNumber(8) var reserved: UInt? = null,
@ProtoNumber(9) var subcmd: UInt? = null,
@ProtoNumber(10) var microCloud: UInt? = null,
@ProtoNumber(11) var rptFileUrls: List<String>? = null,
@ProtoNumber(12) var downloadFlag: UInt? = null,
@ProtoNumber(50) var dangerEvel: UInt? = null,
@ProtoNumber(51) var lifeTime: UInt? = null,
@ProtoNumber(52) var uploadTime: UInt? = null,
@ProtoNumber(53) var absFileType: UInt? = null,
@ProtoNumber(54) var clientType: UInt? = null,
@ProtoNumber(55) var expireTime: UInt? = null,
@ProtoNumber(56) var pbReserve: ByteArray? = null,
@ProtoNumber(57) var fileidcrcMedia: String? = null,
)

View File

@ -0,0 +1,23 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class PbSendMsgReq(
@ProtoNumber(1) val routingHead: RoutingHead? = null,
@ProtoNumber(2) val contentHead: ContentHead? = null,
@ProtoNumber(3) val msgBody: MsgBody? = null,
@ProtoNumber(4) val msgSeq: UInt? = null,
@ProtoNumber(5) val msgRand: UInt? = null,
@ProtoNumber(6) val syncCookie: ByteArray? = null,
@ProtoNumber(7) val appShare: AppShareInfo? = null,
@ProtoNumber(8) val msgVia: UInt? = null,
@ProtoNumber(9) val dataStatist: UInt? = null,
// @ProtoNumber(10) val multiMsgAssist: MultiMsgAssist? = null,
// @ProtoNumber(11) val inputNotifyInfo: InputNotifyInfo? = null,
@ProtoNumber(12) val ctrl: MsgControl? = null,
// @ProtoNumber(13) val receiptReq: ReceiptReq? = null,
@ProtoNumber(14) val multiSendSeq: UInt? = null
) : Protobuf<PbSendMsgReq>

View File

@ -0,0 +1,40 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Ptt(
@ProtoNumber(1) var fileType: UInt?=null,
@ProtoNumber(2) var srcUin: ULong?=null,
@ProtoNumber(3) var fileUuid: String?=null,
@ProtoNumber(4) var fileMd5: ByteArray?=null,
@ProtoNumber(5) var fileName: String?=null,
@ProtoNumber(6) var fileSize: UInt?=null,
@ProtoNumber(7) var reserve: ByteArray?=null,
@ProtoNumber(8) var fileId: UInt?=null,
@ProtoNumber(9) var serverIp: UInt?=null,
@ProtoNumber(10) var serverPort: UInt?=null,
@ProtoNumber(11) var boolValid: Boolean = false,
@ProtoNumber(12) var signature: ByteArray?=null,
@ProtoNumber(13) var shortcut: ByteArray?=null,
@ProtoNumber(14) var fileKey: ByteArray?=null,
@ProtoNumber(15) var magicPttIndex: UInt?=null,
@ProtoNumber(16) var voiceSwitch: UInt?=null,
@ProtoNumber(17) var pttUrl: ByteArray?=null,
@ProtoNumber(18) var groupFileKey: String?=null,
@ProtoNumber(19) var time: UInt?=null,
@ProtoNumber(20) var downPara: ByteArray?=null,
@ProtoNumber(29) var format: UInt?=null,
@ProtoNumber(30) var pbReserve: PbReserve?=null,
@ProtoNumber(31) var rptPttUrls: List<String>? = null,
@ProtoNumber(32) var downloadFlag: UInt?=null,
){
companion object{
@Serializable
data class PbReserve(
@ProtoNumber(2) var magic: Int?=null,
@ProtoNumber(7) var reserve: Int?=null,
)
}
}

View File

@ -0,0 +1,11 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class PushMsgBody(
@ProtoNumber(1) val msgHead: ResponseHead? = null,
@ProtoNumber(2) val contentHead: ContentHead? = null,
@ProtoNumber(3) val body: MsgBody? = null,
)

View File

@ -0,0 +1,33 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.message
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class ResponseHead(
@ProtoNumber(1) val peer: Long = Long.MIN_VALUE,
@ProtoNumber(2) val peerUid: String? = null,
@ProtoNumber(3) val flag: Int = Int.MIN_VALUE,
@ProtoNumber(4) val appId: Int = Int.MIN_VALUE,
@ProtoNumber(5) val receiver: Long? = null,
@ProtoNumber(6) val receiverUid: String? = null,
@ProtoNumber(7) val forward: ResponseForward? = null,
@ProtoNumber(8) val responseGrp: ResponseGrp? = null,
)
@Serializable
data class ResponseForward(
@ProtoNumber(6) val friendName: String? = null,
@ProtoNumber(11) val u1: Int? = null,
)
@Serializable
data class ResponseGrp(
@ProtoNumber(1) val groupCode: ULong = ULong.MIN_VALUE,
@ProtoNumber(4) val memberCard: String? = null,
@ProtoNumber(5) val u1: Int? = null,
@ProtoNumber(7) val groupName: String? = null,
@ProtoNumber(10) val u2: Int? = null,
)

View File

@ -0,0 +1,31 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.message
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class RichText(
@ProtoNumber(1) val attr: Attr? = null,
@ProtoNumber(2) var elements: List<Elem>? = null,
@ProtoNumber(3) var not_online_file: NotOnlineFile? = null,
@ProtoNumber(4) var ptt: Ptt? = null,
@ProtoNumber(5) val tmp_ptt: TmpPtt? = null,
@ProtoNumber(6) val trans_211_tmp_msg: Trans211TmpMsg? = null,
)
@Serializable
data class Attr(
@ProtoNumber(1) val codePage: Int? = null,
@ProtoNumber(2) val time: UInt? = null,
@ProtoNumber(3) val random: UInt? = null,
@ProtoNumber(4) val color: UInt? = null,
@ProtoNumber(5) val size: UInt? = null,
@ProtoNumber(6) val effect: UInt? = null,
@ProtoNumber(7) val charSet: UInt? = null,
@ProtoNumber(8) val pitchAndFamily: UInt? = null,
@ProtoNumber(9) val fontName: String? = null,
@ProtoNumber(10) val reserve_data: ByteArray? = null,
)

View File

@ -0,0 +1,14 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import protobuf.message.routing.*
@Serializable
data class RoutingHead(
@ProtoNumber(1) val c2c: C2C? = null,
@ProtoNumber(2) val grp: Grp? = null,
@ProtoNumber(3) val grpTmp: GrpTmp? = null,
@ProtoNumber(6) val wpaTmp: WPATmp? = null,
@ProtoNumber(15) val trans0X211: Trans0X211? = null
)

View File

@ -0,0 +1,20 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class TmpPtt(
@ProtoNumber(1) var fileType: UInt? = null,
@ProtoNumber(2) var fileUuid: ByteArray? = null,
@ProtoNumber(3) var fileMd5: ByteArray? = null,
@ProtoNumber(4) var fileName: ByteArray? = null,
@ProtoNumber(5) var fileSize: UInt? = null,
@ProtoNumber(6) var pttTimes: UInt? = null,
@ProtoNumber(7) var userType: UInt? = null,
@ProtoNumber(8) var ptttransFlag: UInt? = null,
@ProtoNumber(9) var busiType: UInt? = null,
@ProtoNumber(10) var msgId: ULong? = null,
@ProtoNumber(30) var pbReserve: ByteArray? = null,
@ProtoNumber(31) var pttEncodeData: ByteArray? = null,
)

View File

@ -0,0 +1,10 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Trans211TmpMsg(
@ProtoNumber(1) var msgBody: ByteArray? = null,
@ProtoNumber(2) var c2cCmd: UInt? = null,
)

View File

@ -0,0 +1,11 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class CommonElem(
@ProtoNumber(1) val serviceType: Int? = null,
@ProtoNumber(2) val elem: ByteArray? = null,
@ProtoNumber(3) val businessType: Int? = null,
)

View File

@ -0,0 +1,64 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class CustomFace(
@ProtoNumber(1) var guid: ByteArray? = null,
@ProtoNumber(2) var filePath: String? = null,
@ProtoNumber(3) var shortcut: String? = null,
@ProtoNumber(4) var buffer: ByteArray? = null,
@ProtoNumber(5) var flag: ByteArray? = null,
@ProtoNumber(6) var oldData: ByteArray? = null,
@ProtoNumber(7) var fileId: UInt? = null,
@ProtoNumber(8) var serverIp: UInt? = null,
@ProtoNumber(9) var serverPort: UInt? = null,
@ProtoNumber(10) var fileType: UInt? = null, // 66
@ProtoNumber(11) var signature: ByteArray? = null,
@ProtoNumber(12) var useful: UInt? = null,
@ProtoNumber(13) var md5: ByteArray? = null,
@ProtoNumber(14) var thumbUrl: String? = null,
@ProtoNumber(15) var bigUrl: String? = null,
@ProtoNumber(16) var origUrl: String? = null,
@ProtoNumber(17) var bizType: UInt? = null,
@ProtoNumber(18) var repeatIndex: UInt? = null,
@ProtoNumber(19) var repeatImage: UInt? = null,
@ProtoNumber(20) var imageType: UInt? = null,
@ProtoNumber(21) var index: UInt? = null,
@ProtoNumber(22) var width: UInt? = null,
@ProtoNumber(23) var height: UInt? = null,
@ProtoNumber(24) var source: UInt? = null,
@ProtoNumber(25) var size: UInt? = null,
@ProtoNumber(26) var origin: Boolean? = null,
@ProtoNumber(27) var thumbWidth: UInt? = null,
@ProtoNumber(28) var thumbHeight: UInt? = null,
@ProtoNumber(29) var showLen: UInt? = null,
@ProtoNumber(30) var downloadLen: UInt? = null,
@ProtoNumber(31) var url400: String? = null,
@ProtoNumber(32) var width400: UInt? = null,
@ProtoNumber(33) var height400: UInt? = null,
@ProtoNumber(34) var pbReserve: PbReserve? = null,
) {
companion object {
@Serializable
data class PbReserve(
@ProtoNumber(1) var field1: Int? = null,
@ProtoNumber(3) var field3: Int? = null,
@ProtoNumber(4) var field4: Int? = null,
@ProtoNumber(10) var field10: Int? = null,
@ProtoNumber(21) var field21: Object1? = null,
@ProtoNumber(31) var field31: String? = null
)
@Serializable
data class Object1(
@ProtoNumber(1) var field1: Int? = null,
@ProtoNumber(2) var field2: String? = null,
@ProtoNumber(3) var field3: Int? = null,
@ProtoNumber(4) var field4: Int? = null,
@ProtoNumber(5) var field5: Int? = null,
@ProtoNumber(7) var md5Str: String? = null
)
}
}

View File

@ -0,0 +1,38 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class ElemFlags2(
@ProtoNumber(1) var color_text_id: UInt? = null,
@ProtoNumber(2) var msg_id: ULong? = null,
@ProtoNumber(3) var whisper_session_id: UInt? = null,
@ProtoNumber(4) var ptt_change_bit: UInt? = null,
@ProtoNumber(5) var vip_status: UInt? = null,
@ProtoNumber(6) var compatible_id: UInt? = null,
@ProtoNumber(7) var rpt_insts: List<Inst>? = null,
@ProtoNumber(8) var msg_rpt_cnt: UInt? = null,
@ProtoNumber(9) var src_inst: Inst? = null,
@ProtoNumber(10) var longtitude: UInt? = null,
@ProtoNumber(11) var latitude: UInt? = null,
@ProtoNumber(12) var custom_font: UInt? = null,
@ProtoNumber(13) var pc_support_def: PcSupportDef? = null,
@ProtoNumber(14) var crm_flags: UInt? = null,
)
@Serializable
data class Inst(
@ProtoNumber(1) var app_id: UInt? = null,
@ProtoNumber(2) var inst_id: UInt? = null,
)
@Serializable
data class PcSupportDef(
@ProtoNumber(1) var pc_ptl_begin: UInt? = null,
@ProtoNumber(2) var pc_ptl_end: UInt? = null,
@ProtoNumber(3) var mac_ptl_begin: UInt? = null,
@ProtoNumber(4) var mac_ptl_end: UInt? = null,
@ProtoNumber(5) var rpt_ptls_support: List<Int>? = null,
@ProtoNumber(6) var rpt_ptls_not_support: List<Int>? = null,
)

View File

@ -0,0 +1,12 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class FaceMsg(
@ProtoNumber(1) val index: Int? = null,
@ProtoNumber(2) var old: ByteArray? = null,
@ProtoNumber(11) var buf: ByteArray? = null,
)

View File

@ -0,0 +1,28 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class GeneralFlags(
@ProtoNumber(1) val bubbleDiyTextId: UInt? = null,
@ProtoNumber(2) val groupFlagNew: UInt? = null,
@ProtoNumber(3) val uin: ULong? = null,
@ProtoNumber(4) val rpId: ByteArray? = null,
@ProtoNumber(5) val prpFold: UInt? = null,
@ProtoNumber(6) val longTextFlag: UInt? = null,
@ProtoNumber(7) val longTextResid: String? = null,
@ProtoNumber(8) val groupType: UInt? = null,
@ProtoNumber(9) val toUinFlag: UInt? = null,
@ProtoNumber(10) val glamourLevel: UInt? = null,
@ProtoNumber(11) val memberLevel: UInt? = null,
@ProtoNumber(12) val groupRankSeq: ULong? = null,
@ProtoNumber(13) val olympicTorch: UInt? = null,
@ProtoNumber(14) val babyqGuideMsgCookie: ByteArray? = null,
@ProtoNumber(15) val expertFlag: UInt? = null,
@ProtoNumber(16) val bubbleSubId: UInt? = null,
@ProtoNumber(17) val pendantId: ULong? = null,
@ProtoNumber(18) val rpIndex: ByteArray? = null,
@ProtoNumber(19) val reserve: ByteArray? = null,
)

View File

@ -0,0 +1,9 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class LightAppElem(
@ProtoNumber(1) val data: ByteArray? = null,
)

View File

@ -0,0 +1,21 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MarketFace(
@ProtoNumber(1) var faceName: String? = null,
@ProtoNumber(2) var itemType: Int? = null,
@ProtoNumber(3) var faceInfo: Int? = null,
@ProtoNumber(4) var faceId: String? = null,
@ProtoNumber(5) var tabId: Int? = null,
@ProtoNumber(6) var subType: Int? = null,
@ProtoNumber(7) var key: ByteArray? = null,
@ProtoNumber(8) var param: ByteArray? = null,
@ProtoNumber(9) var mediaType: Int? = null,
@ProtoNumber(10) var imageWidth: Int? = null,
@ProtoNumber(11) var imageHeight: Int? = null,
@ProtoNumber(12) var mobileparam: ByteArray? = null,
@ProtoNumber(13) var pbReserve: ByteArray? = null,
)

View File

@ -0,0 +1,61 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class NotOnlineImage(
@ProtoNumber(1) val filePath: String? = null,
@ProtoNumber(2) val fileLen: UInt? = null,
@ProtoNumber(3) val downloadPath: String? = null,
@ProtoNumber(4) val oldVerSendFile: ByteArray? = null,
@ProtoNumber(5) val imgType: UInt? = null,
@ProtoNumber(6) val previewsImage: ByteArray? = null,
@ProtoNumber(7) val picMd5: ByteArray? = null,
@ProtoNumber(8) val picHeight: UInt? = null,
@ProtoNumber(9) val picWidth: UInt? = null,
@ProtoNumber(10) val resId: String? = null, // md5 + ".jpg"
@ProtoNumber(11) val flag: ByteArray? = null,
@ProtoNumber(12) val thumbUrl: String? = null,
@ProtoNumber(13) val original: Boolean? = null,
@ProtoNumber(14) val bigUrl: String? = null,
@ProtoNumber(15) val origUrl: String? = null,
@ProtoNumber(16) val bizType: UInt? = null,
@ProtoNumber(17) val result: UInt? = null,
@ProtoNumber(18) val index: UInt? = null,
@ProtoNumber(19) val opFaceBuf: ByteArray? = null,
@ProtoNumber(20) val oldPicMd5: Boolean = false,
@ProtoNumber(21) val thumbWidth: UInt? = null,
@ProtoNumber(22) val thumbHeight: UInt? = null,
@ProtoNumber(23) val fileId: UInt? = null,
@ProtoNumber(24) val showLen: UInt? = null,
@ProtoNumber(25) val downloadLen: UInt? = null,
@ProtoNumber(26) val url400: String? = null,
@ProtoNumber(27) val width400: UInt? = null,
@ProtoNumber(28) val height400: UInt? = null,
@ProtoNumber(29) val pbReserve: PbReserve? = null,
) {
companion object {
@Serializable
data class PbReserve(
@ProtoNumber(1) var field1: Int? = null,
@ProtoNumber(3) var field3: Int? = null,
@ProtoNumber(4) var field4: Int? = null,
@ProtoNumber(8) var field8: String? = null,
@ProtoNumber(10) var field10: Int? = null,
@ProtoNumber(20) var field20: Object1? = null,
@ProtoNumber(30) var url: String? = null,
@ProtoNumber(31) var md5Str: String? = null
)
@Serializable
data class Object1(
@ProtoNumber(1) var field1: Int? = null,
@ProtoNumber(2) var field2: String? = null,
@ProtoNumber(3) var field3: Int? = null,
@ProtoNumber(4) var field4: Int? = null,
@ProtoNumber(5) var field5: Int? = null,
@ProtoNumber(7) var field7: String? = null
)
}
}

View File

@ -0,0 +1,30 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import protobuf.message.Elem
@Serializable
data class SourceMsg(
@ProtoNumber(1) var origSeqs: List<Int>? = null,
@ProtoNumber(2) var senderUin: ULong? = null,
@ProtoNumber(3) var time: ULong? = null,
@ProtoNumber(4) var flag: UInt? = null,
@ProtoNumber(5) var elems: List<Elem>? = null,
@ProtoNumber(6) var type: UInt? = null,
@ProtoNumber(7) var richMsg: ByteArray? = null,
@ProtoNumber(8) var pbReserve: PbReserve? = null,
@ProtoNumber(9) var srcMsg: ByteArray? = null,
@ProtoNumber(10) var toUin: ULong? = null,
@ProtoNumber(11) var troopName: String? = null,
) {
companion object {
@Serializable
data class PbReserve(
@ProtoNumber(3) var msgRand: ULong? = null,
@ProtoNumber(6) var senderUid: String? = null,
@ProtoNumber(7) var receiverUid: String? = null,
@ProtoNumber(8) var field8: Int? = null,
)
}
}

View File

@ -0,0 +1,21 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class TextMsg(
@ProtoNumber(1) val str: String? = null,
@ProtoNumber(2) val link: String? = null,
@ProtoNumber(3) val attr6Buf: ByteArray? = null,
@ProtoNumber(4) val attr7Buf: ByteArray? = null,
@ProtoNumber(11) val buf: ByteArray? = null,
@ProtoNumber(12) val pbReserve: PbReserve? = null,
){
companion object {
@Serializable
data class PbReserve(
@ProtoNumber(1) val field1: String? = null, // [打 call]] 请使用最新版手机 QQ 体验新功能
)
}
}

View File

@ -0,0 +1,53 @@
package protobuf.message.element.commelem
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class ButtonExtra(
@ProtoNumber(1) val field1: Object1? = null,
) : Protobuf<ButtonExtra>
@Serializable
data class Object1(
@ProtoNumber(1) val rows: List<Row>? = null,
@ProtoNumber(2) val appid: ULong? = null,
)
@Serializable
data class Row(
@ProtoNumber(1) val buttons: List<Button>? = null,
)
@Serializable
data class Button(
@ProtoNumber(1) val id: String? = null,
@ProtoNumber(2) val renderData: RenderData? = null,
@ProtoNumber(3) val action: Action? = null,
)
@Serializable
data class RenderData(
@ProtoNumber(1) val label: String? = null,
@ProtoNumber(2) val visitedLabel: String? = null,
@ProtoNumber(3) val style: Int? = null,
)
@Serializable
data class Action(
@ProtoNumber(1) val type: Int? = null,
@ProtoNumber(2) val permission: Permission? = null,
@ProtoNumber(4) val unsupportTips: String? = null,
@ProtoNumber(5) val data: String? = null,
@ProtoNumber(7) val reply: Boolean? = null,
@ProtoNumber(8) val enter: Boolean? = null,
)
@Serializable
data class Permission(
@ProtoNumber(1) val type: Int? = null,
@ProtoNumber(2) val specifyRoleIds: List<String>? = null,
@ProtoNumber(3) val specifyUserIds: List<String>? = null,
)

View File

@ -0,0 +1,10 @@
package protobuf.message.element.commelem
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class MarkdownExtra(
@ProtoNumber(1) val content: String? = null,
) : Protobuf<MarkdownExtra>

View File

@ -0,0 +1,12 @@
package protobuf.message.element.commelem
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class PokeExtra(
@ProtoNumber(1) val type: Int? = null,
@ProtoNumber(7) val field7: Int? = null,
@ProtoNumber(8) val field8: Int? = null
) : Protobuf<PokeExtra>

View File

@ -0,0 +1,17 @@
package protobuf.message.element.commelem
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class QFaceExtra(
@ProtoNumber(1) val packId: String? = null,
@ProtoNumber(2) val stickerId: String? = null,
@ProtoNumber(3) val faceId: Int? = null,
@ProtoNumber(4) val field4: Int? = null,
@ProtoNumber(5) val field5: Int? = null,
@ProtoNumber(6) val result: String? = null,
@ProtoNumber(7) val faceText: String? = null,
@ProtoNumber(9) val field9: Int? = null
) : Protobuf<QFaceExtra>

View File

@ -0,0 +1,63 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.message.longmsg
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class LongMsgSettings(
@ProtoNumber(1) val field1: Int? = null,
@ProtoNumber(2) val field2: Int? = null,
@ProtoNumber(3) val field3: Int? = null,
@ProtoNumber(4) val field4: Int? = null,
)
@Serializable
data class LongMsgUid(
@ProtoNumber(2) val uid: String? = null,
)
@Serializable
data class RecvLongMsgInfo(
@ProtoNumber(1) val uid: LongMsgUid? = null,
@ProtoNumber(2) val resId: String? = null,
@ProtoNumber(3) val u1: Int? = null,
)
@Serializable
data class SendLongMsgInfo(
@ProtoNumber(1) val type: Int? = null,
@ProtoNumber(2) val uid: LongMsgUid? = null,
@ProtoNumber(3) val groupUin: ULong? = null,
@ProtoNumber(4) val payload: ByteArray? = null,
)
@Serializable
data class LongMsgReq(
@ProtoNumber(1) val recvInfo: RecvLongMsgInfo? = null,
@ProtoNumber(2) val sendInfo: SendLongMsgInfo? = null,
@ProtoNumber(15) val setting: LongMsgSettings? = null,
): Protobuf<LongMsgReq>
@Serializable
data class LongMsgRsp(
@ProtoNumber(1) val recvResult: RecvLongMsgResult? = null,
@ProtoNumber(2) val sendResult: SendLongMsgResult? = null,
@ProtoNumber(15) val setting: LongMsgSettings? = null
): Protobuf<LongMsgRsp> {
companion object {
@Serializable
data class SendLongMsgResult(
@ProtoNumber(3) val resId: String? = null,
)
@Serializable
data class RecvLongMsgResult(
@ProtoNumber(3) val resId: String? = null,
@ProtoNumber(4) val payload: ByteArray? = null,
)
}
}

View File

@ -0,0 +1,24 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.message.longmsg
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
import protobuf.message.PushMsgBody
@Serializable
data class LongMsgContent(
@ProtoNumber(1) val body: List<PushMsgBody>? = null
)
@Serializable
data class LongMsgAction(
@ProtoNumber(1) val command: String? = null,
@ProtoNumber(2) val data: LongMsgContent? = null
)
@Serializable
data class LongMsgPayload(
@ProtoNumber(2) val action: List<LongMsgAction>? = null
): Protobuf<LongMsgPayload>

View File

@ -0,0 +1 @@
package protobuf.message.multimedia

View File

@ -0,0 +1,14 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class C2C(
@ProtoNumber(1) val uin: UInt? = null,
@ProtoNumber(2) val uid: String? = null,
@ProtoNumber(3) val field3: UInt? = null,
@ProtoNumber(4) val sig: UInt? = null,
@ProtoNumber(5) val receiverUin: UInt? = null,
@ProtoNumber(6) val receiverUid: String? = null
)

View File

@ -0,0 +1,9 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Grp (
@ProtoNumber(1) var groupCode: UInt? = null,
)

View File

@ -0,0 +1,10 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class GrpTmp (
@ProtoNumber(1) var groupCode: UInt? = null,
@ProtoNumber(2) var ToUin: UInt? = null,
)

View File

@ -0,0 +1,11 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Trans0X211(
@ProtoNumber(1) val toUin: ULong? = null,
@ProtoNumber(2) val ccCmd: UInt? = null,
@ProtoNumber(8) val uid: String? = null
)

View File

@ -0,0 +1,10 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class WPATmp (
@ProtoNumber(1) val toUin: Int? = null,
@ProtoNumber(2) val sig: ByteArray? = null,
)

View File

@ -2,11 +2,15 @@ package protobuf.oidb
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class TrpcOidb(
@ProtoNumber(1) val cmd: Int = Int.MIN_VALUE,
@ProtoNumber(2) val service: Int = Int.MIN_VALUE,
@ProtoNumber(4) val buffer: ByteArray,
@ProtoNumber(3) val result: UInt? = null,
@ProtoNumber(4) val buffer: ByteArray? = null,
@ProtoNumber(5) val msg: String? = null,
//@ProtoNumber(11) val traceParams: Map<String, String> = mapOf(),
@ProtoNumber(12) val flag: Int = Int.MIN_VALUE,
)
): Protobuf<TrpcOidb>

View File

@ -0,0 +1,273 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.oidb.cmd0x11c5
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class NtV2RichMediaReq(
@ProtoNumber(1) val head: MultiMediaReqHead,
@ProtoNumber(2) val upload: UploadReq? = null, // 100
@ProtoNumber(3) val download: DownloadReq? = null,
@ProtoNumber(4) val downloadRkey: DownloadRkeyReq? = null,
@ProtoNumber(5) val delete: DeleteReq? = null,
@ProtoNumber(6) val uploadCompleted: UploadCompletedReq? = null,
@ProtoNumber(7) val msgInfoAuth: MsgInfoAuthReq? = null,
@ProtoNumber(8) val uploadKeyRenewal: UploadKeyRenewalReq? = null,
@ProtoNumber(9) val downloadSafe: DownloadSafeReq? = null,
@ProtoNumber(99) val extension: ByteArray? = null,
): Protobuf<NtV2RichMediaReq>
@Serializable
data class DownloadSafeReq(
@ProtoNumber(1) val index: IndexNode,
)
@Serializable
data class UploadKeyRenewalReq(
@ProtoNumber(1) val oldUkey: String,
@ProtoNumber(2) val subType: UInt,
)
@Serializable
data class MsgInfoAuthReq(
@ProtoNumber(1) val msg: ByteArray,
@ProtoNumber(2) val authTime: ULong,
)
@Serializable
data class UploadCompletedReq(
@ProtoNumber(1) val srvSendMsg: Boolean,
@ProtoNumber(2) val clientRandomId: ULong,
@ProtoNumber(3) val msgInfo: MsgInfo,
@ProtoNumber(4) val clientSeq: UInt,
)
@Serializable
data class MsgInfo(
@ProtoNumber(1) val msgInfoBody: List<MsgInfoBody>,
@ProtoNumber(2) val extBizInfo: ExtBizInfo?,
): Protobuf<MsgInfo>
@Serializable
data class MsgInfoBody(
@ProtoNumber(1) val index: IndexNode? = null,
@ProtoNumber(2) val picture: PictureInfo? = null,
@ProtoNumber(3) val video: VideoInfo? = null,
@ProtoNumber(4) val audio: AudioInfo? = null,
@ProtoNumber(5) val fileExist: Boolean? = null,
@ProtoNumber(6) val hashSum: ByteArray? = null,
)
@Serializable
class VideoInfo
@Serializable
class AudioInfo
@Serializable
data class PictureInfo(
@ProtoNumber(1) val urlPath: String,
@ProtoNumber(2) val ext: PicUrlExtInfo? = null,
@ProtoNumber(3) val domain: String? = null
)
@Serializable
data class PicUrlExtInfo(
@ProtoNumber(1) val originalParameter: String? = null,
@ProtoNumber(2) val bigParameter: String? = null,
@ProtoNumber(3) val thumbParameter: String? = null
)
@Serializable
data class DeleteReq(
@ProtoNumber(1) val index: List<IndexNode>,
@ProtoNumber(2) val needRecallMsg: Boolean? = null,
@ProtoNumber(3) val msgSeq: ULong? = null,
@ProtoNumber(4) val msgRandom: ULong? = null,
@ProtoNumber(5) val msgTime: ULong? = null,
)
@Serializable
data class DownloadRkeyReq(
@ProtoNumber(1) val types: List<Int>,
@ProtoNumber(2) val downloadType: Int
)
@Serializable
data class UploadReq(
@ProtoNumber(1) val uploadInfo: List<UploadInfo>,
@ProtoNumber(2) val tryFastUploadCompleted: Boolean? = null,
@ProtoNumber(3) val srvSendMsg: Boolean? = null,
@ProtoNumber(4) val clientRandomId: ULong = ULong.MIN_VALUE,
@ProtoNumber(5) val compatQMsgSceneType: UInt? = null,
@ProtoNumber(6) val extBizInfo: ExtBizInfo? = null,
@ProtoNumber(7) val clientSeq: UInt? = null,
@ProtoNumber(8) val noNeedCompatMsg: Boolean? = null,
)
@Serializable
data class ExtBizInfo(
@ProtoNumber(1) val pic: PicExtBizInfo? = null,
@ProtoNumber(2) val video: VideoExtBizInfo? = null,
@ProtoNumber(3) val ptt: PttExtBizInfo? = null,
@ProtoNumber(10) val busiType: UInt?,
)
@Serializable
data class PttExtBizInfo(
@ProtoNumber(1) val srcUin: ULong,
@ProtoNumber(2) val pttScene: UInt,
@ProtoNumber(3) val pttType: UInt,
@ProtoNumber(4) val changeVoice: UInt,
@ProtoNumber(5) val waveform: ByteArray? = null,
@ProtoNumber(6) val autoConvertText: UInt? = null,
@ProtoNumber(11) val bytesReserve: ByteArray? = null,
@ProtoNumber(12) val bytesPbReserve: ByteArray? = null,
@ProtoNumber(13) val bytesGeneralFlags: ByteArray? = null,
)
@Serializable
data class VideoExtBizInfo(
@ProtoNumber(1) val fromScene: UInt?,
@ProtoNumber(2) val toScene: UInt?,
@ProtoNumber(3) val bytesPbReserve: ByteArray?,
)
@Serializable
data class PicExtBizInfo(
@ProtoNumber(1) val bizType: UInt?,
@ProtoNumber(2) val textSummary: String?,
@ProtoNumber(11) val bytesPbReserveC2c: ByteArray? = null,
@ProtoNumber(12) val bytesPbReserveTroop: ByteArray? = null,
@ProtoNumber(1001) val fromScene: UInt? = null,
@ProtoNumber(1002) val toScene: UInt? = null,
@ProtoNumber(1003) val oldFileId: UInt? = null,
)
@Serializable
data class UploadInfo(
@ProtoNumber(1) val fileInfo: FileInfo,
@ProtoNumber(2) val subFileType: UInt
)
@Serializable
data class FileInfo(
@ProtoNumber(1) val fileSize: ULong?,
@ProtoNumber(2) val md5: String?,
@ProtoNumber(3) val sha1: String?,
@ProtoNumber(4) val name: String?,
@ProtoNumber(5) val fileType: FileType?,
@ProtoNumber(6) val width: UInt?,
@ProtoNumber(7) val height: UInt?,
@ProtoNumber(8) val time: UInt?,
@ProtoNumber(9) val original: UInt?,
)
@Serializable
data class FileType(
@ProtoNumber(1) val fileType: UInt = 0u,
@ProtoNumber(2) val picFormat: UInt = 0u,
@ProtoNumber(3) val videoFormat: UInt? = null,
@ProtoNumber(4) val voiceFormat: UInt? = null,
)
@Serializable
data class DownloadReq(
@ProtoNumber(1) val index: IndexNode,
@ProtoNumber(2) val ext: DownloadExt,
)
@Serializable
data class DownloadExt(
@ProtoNumber(1) val pic: PicDownloadExt? = null,
@ProtoNumber(2) val video: VideoDownloadExt,
@ProtoNumber(3) val voice: PttDownloadExt? = null,
)
@Serializable
class PicDownloadExt
@Serializable
class PttDownloadExt
@Serializable
data class VideoDownloadExt(
@ProtoNumber(1) val busiType: UInt?,
@ProtoNumber(2) val sceneType: UInt? = null,
@ProtoNumber(3) val subBusiType: UInt?,
@ProtoNumber(4) val msgCodecConfig: CodecConfigReq,
@ProtoNumber(5) val flag: UInt?,
)
@Serializable
data class CodecConfigReq(
@ProtoNumber(1) val platformChipinfo: String,
@ProtoNumber(2) val osVer: String,
@ProtoNumber(3) val deviceName: String,
)
@Serializable
data class IndexNode(
@ProtoNumber(1) val fileInfo: FileInfo,
@ProtoNumber(2) val fileUuid: String,
@ProtoNumber(3) val storeId: UInt, // 0为旧服务器 1为nt服务器
@ProtoNumber(4) val uploadTime: ULong,
@ProtoNumber(5) val ttl: ULong,
@ProtoNumber(6) val subType: UInt? = null,
@ProtoNumber(7) val storeAppId: UInt? = null
)
@Serializable
data class MultiMediaReqHead(
@ProtoNumber(1) val commonHead: CommonHead,
@ProtoNumber(2) val sceneInfo: SceneInfo,
@ProtoNumber(3) val clientMeta: ClientMeta
)
@Serializable
data class ClientMeta(
@ProtoNumber(1) val agentType: UInt,
)
@Serializable
data class SceneInfo(
@ProtoNumber(101) val requestType: UInt,
@ProtoNumber(102) val businessType: UInt,
@ProtoNumber(103) val appType: UInt? = null,
@ProtoNumber(200) var sceneType: UInt? = null,
@ProtoNumber(201) var c2c: C2CUserInfo? = null,
@ProtoNumber(202) var grp: GroupUserInfo? = null,
@ProtoNumber(203) var channel: ChannelUserInfo? = null,
@ProtoNumber(205) val byteArr: ByteArray?= null
)
@Serializable
data class ChannelUserInfo(
@ProtoNumber(1) val guildId: ULong,
@ProtoNumber(2) val channelId: ULong,
@ProtoNumber(3) val channelType: UInt,
)
@Serializable
data class GroupUserInfo(
@ProtoNumber(1) val uin: ULong,
)
@Serializable
data class C2CUserInfo(
@ProtoNumber(1) val accountType: UInt,
@ProtoNumber(2) val uid: String,
@ProtoNumber(3) val byteArr: ByteArray? = null
)
@Serializable
data class CommonHead(
@ProtoNumber(1) val requestId: ULong,
@ProtoNumber(2) val cmd: UInt,
@ProtoNumber(3) val msg: String? = null
)

View File

@ -0,0 +1,139 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.oidb.cmd0x11c5
import moe.fuqiuluo.symbols.EMPTY_BYTE_ARRAY
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class NtV2RichMediaRsp(
@ProtoNumber(1) val head: RspHead?,
@ProtoNumber(2) val upload: UploadRsp?,
@ProtoNumber(3) val download: DownloadRsp?,
@ProtoNumber(4) val downloadRkeyRsp: DownloadRkeyRsp?,
@ProtoNumber(5) val delete: DeleteRsp?,
@ProtoNumber(6) val uploadCompleted: UploadCompletedRsp?,
@ProtoNumber(7) val msgInfoAuth: MsgInfoAuthRsp?,
@ProtoNumber(8) val uploadKeyRenew: UploadKeyRenewalRsp?,
@ProtoNumber(9) val downloadSafe: DownloadSafeRsp?,
@ProtoNumber(99) val extension: ByteArray? = null,
): Protobuf<NtV2RichMediaRsp>
@Serializable
class DownloadSafeRsp
@Serializable
data class UploadKeyRenewalRsp(
@ProtoNumber(1) val ukey: String?,
@ProtoNumber(2) val ukeyTtlSec: ULong?,
)
@Serializable
data class MsgInfoAuthRsp(
@ProtoNumber(1) val authCode: UInt = 0u,
@ProtoNumber(2) val msg: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(3) val resultTime: ULong = 0u,
)
@Serializable
data class UploadCompletedRsp(
@ProtoNumber(1) val msgSeq: ULong?
)
@Serializable
class DeleteRsp
@Serializable
data class DownloadRkeyRsp(
@ProtoNumber(1) val rkeys: List<RKeyInfo>?
)
@Serializable
data class RKeyInfo(
@ProtoNumber(1) val rkey: String,
@ProtoNumber(2) val rkeyTtlSec: ULong?,
@ProtoNumber(3) val storeId: UInt = 0u,
@ProtoNumber(4) val rkeyCreateTime: UInt?,
@ProtoNumber(4) val type: UInt,
)
@Serializable
data class DownloadRsp(
@ProtoNumber(1) val rkeyParam: String?,
@ProtoNumber(2) val rkeyTtlSec: ULong?,
@ProtoNumber(3) val downloadInfo: DownloadInfo?,
@ProtoNumber(4) val rkeyCreateTime: UInt?
)
@Serializable
data class DownloadInfo(
@ProtoNumber(1) val domain: String,
@ProtoNumber(2) val urlPath: String? = null,
@ProtoNumber(3) val httpsPort: Int = Int.MIN_VALUE,
@ProtoNumber(4) val ipv4: List<Ipv4>,
@ProtoNumber(5) val ipv6: List<Ipv6>,
@ProtoNumber(6) val picUrlExtInfo: PicUrlExtInfo?,
@ProtoNumber(7) val videoExtInfo: VideoExtInfo? = null,
)
@Serializable
data class VideoExtInfo(
@ProtoNumber(1) val videoCodecFormat: UInt? = null,
)
@Serializable
data class UploadRsp(
@ProtoNumber(1) val ukey: String?,
@ProtoNumber(2) val ukeyTtlSec: ULong?,
@ProtoNumber(3) val ipv4: List<Ipv4>?,
@ProtoNumber(4) val ipv6: List<Ipv6>?,
@ProtoNumber(5) val msgSeq: ULong?,
@ProtoNumber(6) val msgInfo: MsgInfo? = null,
@ProtoNumber(7) val ext: List<RichmediaStorageTransInfo>? = null,
@ProtoNumber(8) val compatQMsg: ByteArray? = null,
@ProtoNumber(10) val subFileInfos: List<SubFileInfo>? = null,
)
@Serializable
data class SubFileInfo(
@ProtoNumber(1) val subType: UInt?,
@ProtoNumber(2) val ukey: String?,
@ProtoNumber(3) val ukeyTTLSec: ULong?,
@ProtoNumber(4) val ipv4: List<Ipv4>?,
@ProtoNumber(5) val ipv6: List<Ipv6>?,
)
@Serializable
data class RichmediaStorageTransInfo(
@ProtoNumber(1) val subType: UInt = UInt.MIN_VALUE,
@ProtoNumber(2) val extType: UInt = UInt.MIN_VALUE,
@ProtoNumber(3) val extValue: ByteArray? = null,
)
@Serializable
data class Ipv4(
@ProtoNumber(1) val outIp: Int = Int.MIN_VALUE,
@ProtoNumber(2) val outPort: Int = Int.MIN_VALUE,
@ProtoNumber(3) val inIp: Int = Int.MIN_VALUE,
@ProtoNumber(4) val inPort: Int = Int.MIN_VALUE,
@ProtoNumber(5) val ipType: Int = Int.MIN_VALUE,
)
@Serializable
data class Ipv6(
@ProtoNumber(1) val outIp: ByteArray? = null,
@ProtoNumber(2) val outPort: Int = Int.MIN_VALUE,
@ProtoNumber(3) val inIp: ByteArray? = null,
@ProtoNumber(4) val inPort: Int = Int.MIN_VALUE,
@ProtoNumber(5) val ipType: Int = Int.MIN_VALUE,
)
@Serializable
data class RspHead(
@ProtoNumber(1) val commonHead: CommonHead?,
@ProtoNumber(2) val retCode: UInt = 0u,
@ProtoNumber(3) val msg: String?
)

View File

@ -0,0 +1,63 @@
package protobuf.oidb.cmd0x388
import moe.fuqiuluo.symbols.EMPTY_BYTE_ARRAY
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class Cmd0x388ReqBody(
@ProtoNumber(1) var netType: Int = 0,
@ProtoNumber(2) var subCmd: Int = 0,
@ProtoNumber(3) var msgTryUpImg: ArrayList<TryUpImgReq>? = null,
// @ProtoNumber(4) var rpt_msg_getimg_url_req: ArrayList<GetImgUrlReq>? = null,
@ProtoNumber(5) var msgTryUpPttReq: ArrayList<TryUpPttReq>? = null,
// @ProtoNumber(6) var msgGetPttUrlReq: ArrayList<GetPttUrlReq>? = null,
@ProtoNumber(7) var commandId: Int = 0,
// @ProtoNumber(8) var rpt_msg_del_img_req: ArrayList<DelImgReq>? = null,
@ProtoNumber(1001) var extension: ByteArray = EMPTY_BYTE_ARRAY,
): Protobuf<Cmd0x388ReqBody>
@Serializable
data class TryUpImgReq(
@ProtoNumber(1) var groupCode: Long = 0,
@ProtoNumber(2) var srcUin: Long = 0,
@ProtoNumber(3) var fileId: Long? = null,
@ProtoNumber(4) var fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(5) var fileSize: Long = 0,
@ProtoNumber(6) var fileName: String = "",
@ProtoNumber(7) var srcTerm: Int = 0,
@ProtoNumber(8) var platformType: Int = 0,
@ProtoNumber(9) var buType: Int = 0,
@ProtoNumber(10) var picWidth: Int = 0,
@ProtoNumber(11) var picHeight: Int = 0,
@ProtoNumber(12) var picType: Int = 0,
@ProtoNumber(13) var buildVer: String = "",
@ProtoNumber(14) var innerIp: Int = 0,
@ProtoNumber(15) var appPicType: Int = 0,
@ProtoNumber(16) var originalPic: Int = 0,
@ProtoNumber(17) var fileIndex: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(18) var dstUin: Long = 0,
@ProtoNumber(19) var srvUpload: Int? = null,
@ProtoNumber(20) var transferUrl: ByteArray = EMPTY_BYTE_ARRAY,
)
@Serializable
data class TryUpPttReq(
@ProtoNumber(1) var groupCode: Long = 0,
@ProtoNumber(2) var srcUin: Long = 0,
@ProtoNumber(3) var fileId: Long = 0,
@ProtoNumber(4) var fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(5) var fileSize: Long = 0,
@ProtoNumber(6) var fileName: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(7) var srcTerm: Int = 0,
@ProtoNumber(8) var platformType: Int = 0,
@ProtoNumber(9) var buType: Int = 0,
@ProtoNumber(10) var buildVer: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(11) var innerIp: Int = 0,
@ProtoNumber(12) var voiceLength: Int = 0,
@ProtoNumber(13) var newUpChan: Boolean = false,
@ProtoNumber(14) var codec: Int = 0,
@ProtoNumber(15) var voiceType: Int = 0,
@ProtoNumber(16) var buId: Int = 0,
)

View File

@ -0,0 +1,78 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.oidb.cmd0x388
import moe.fuqiuluo.symbols.EMPTY_BYTE_ARRAY
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class Cmd0x388RspBody(
@ProtoNumber(1) var clientIp: UInt = 0u,
@ProtoNumber(2) var subCmd: UInt = 0u,
@ProtoNumber(3) var msgTryUpImgRsp: ArrayList<TryUpImgRsp>? = null,
@ProtoNumber(5) var msgTryUpPttRsp: ArrayList<TryUpPttRsp>? = null,
): Protobuf<Cmd0x388RspBody>
@Serializable
data class TryUpPttRsp(
@ProtoNumber(1) var fileId: Long = 0,
@ProtoNumber(2) var result: Int = 0,
@ProtoNumber(3) var failMsg: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(4) var fileExit: Boolean = false,
@ProtoNumber(5) var upIp: List<Int>? = null,
@ProtoNumber(6) var upPort: List<Int>? = null,
@ProtoNumber(7) var upUkey: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(8) var fileid: Long = 0,
@ProtoNumber(9) var upOffset: Long = 0,
@ProtoNumber(10) var blockSize: Long = 0,
@ProtoNumber(11) var fileKey: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(12) var channelType: Int = 0,
@ProtoNumber(26) var msgUpIp6: ArrayList<IPv6Info>? = null,
@ProtoNumber(27) var clientIp6: ByteArray = EMPTY_BYTE_ARRAY,
): Protobuf<TryUpPttRsp>
@Serializable
data class TryUpImgRsp(
@ProtoNumber(1) var extFileId: ULong = 0u, // 没有实际作用
@ProtoNumber(2) var result: UInt = 0u,
@ProtoNumber(3) var faiMsg: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(4) var fileExist: Boolean = false,
@ProtoNumber(5) var msgImgInfo: ImgInfo? = null, // 里面只是一堆垃圾
@ProtoNumber(6) var upIp: ArrayList<Long>? = null,
@ProtoNumber(7) var upPort: ArrayList<Int>? = null,
@ProtoNumber(8) var ukey: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(9) var fileId: Long = 0,
@ProtoNumber(10) var upOffset: ULong = 0u,
@ProtoNumber(11) var blockSize: Long = 0,
@ProtoNumber(12) var bool_new_big_chan: Boolean = false,
@ProtoNumber(26) var rpt_msg_up_ip6: ArrayList<IPv6Info>? = null,
@ProtoNumber(27) var client_ip6: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(1001) var msg_info4busi: TryUpInfo4Busi? = null,
)
@Serializable
data class TryUpInfo4Busi(
@ProtoNumber(1) var down_domain: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(2) var thumb_down_url: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(3) var original_down_url: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(4) var big_down_url: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(5) var file_resid: ByteArray = EMPTY_BYTE_ARRAY,
)
@Serializable
data class IPv6Info(
@ProtoNumber(1) var ip6: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(2) var port: UInt = 0u,
)
@Serializable
data class ImgInfo(
@ProtoNumber(1) var file_md5: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(2) var file_type: UInt = 0u,
@ProtoNumber(3) var file_size: ULong = 0u,
@ProtoNumber(4) var file_width: UInt = 0u,
@ProtoNumber(5) var file_height: UInt = 0u,
)

View File

@ -5,6 +5,7 @@ package protobuf.oidb.cmd0x6d7
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
import protobuf.group_file_common.FolderInfo
@Serializable
@ -13,7 +14,7 @@ data class Oidb0x6d7ReqBody(
@ProtoNumber(2) val deleteFolder: DeleteFolderReq? = null,
@ProtoNumber(3) val moveFolder: MoveFolderReq? = null,
@ProtoNumber(4) val renameFolder: RenameFolderReq? = null,
)
): Protobuf<Oidb0x6d7ReqBody>
@Serializable
data class CreateFolderReq(
@ -53,7 +54,7 @@ data class Oidb0x6d7RespBody(
@ProtoNumber(2) val deleteFolder: DeleteFolderResp? = null,
@ProtoNumber(3) val moveFolder: MoveFolderResp? = null,
@ProtoNumber(4) val renameFolder: RenameFolderResp? = null,
)
): Protobuf<Oidb0x6d7RespBody>
@Serializable
data class CreateFolderResp(

View File

@ -2,6 +2,7 @@ package protobuf.oidb.cmd0x9082
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class Oidb0x9082(
@ -11,4 +12,4 @@ data class Oidb0x9082(
@ProtoNumber(5) val flag: UInt = UInt.MIN_VALUE,
@ProtoNumber(6) val u1: UInt = UInt.MIN_VALUE,
@ProtoNumber(7) val u2: UInt = UInt.MIN_VALUE,
)
): Protobuf<Oidb0x9082>

View File

@ -2,11 +2,12 @@ package protobuf.oidb.cmd0xf16
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class Oidb0xf16(
@ProtoNumber(1) var setGroupRemarkReq: SetGroupRemarkReq? = null,
)
): Protobuf<Oidb0xf16>
@Serializable
data class SetGroupRemarkReq(

View File

@ -5,6 +5,7 @@ package protobuf.oidb.cmd0xf88
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class Oidb0xf88Req(
@ -12,12 +13,12 @@ data class Oidb0xf88Req(
@ProtoNumber(2) val memberId: ULong,
@ProtoNumber(3) val tinyId: ULong,
@ProtoNumber(4) val guildId: ULong,
)
): Protobuf<Oidb0xf88Req>
@Serializable
data class Oidb0xf88Rsp(
@ProtoNumber(1) val userInfo: GProUserInfo?
)
): Protobuf<Oidb0xf88Rsp>
@Serializable
data class GProUserInfo(

View File

@ -4,6 +4,7 @@ package protobuf.oidb.cmd0xfc2
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class Oidb0xfc2ReqBody(
@ -16,7 +17,7 @@ data class Oidb0xfc2ReqBody(
@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,
)
): Protobuf<Oidb0xfc2ReqBody>
@Serializable
data class Oidb0xfc2RspBody(
@ -27,7 +28,7 @@ data class Oidb0xfc2RspBody(
@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,
)
): Protobuf<Oidb0xfc2RspBody>
@Serializable
data class Oidb0xfc2MsgApplyDownloadRsp(

View File

@ -5,17 +5,18 @@ package protobuf.oidb.cmx0xf57
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class Oidb0xf57Req(
@ProtoNumber(1) val filter: Oidb0xf57Filter,
@ProtoNumber(2) val guildInfo: Oidb0xf57GuildInfo,
)
): Protobuf<Oidb0xf57Req>
@Serializable
data class Oidb0xf57Rsp(
@ProtoNumber(1) val metaInfo: Oidb0xf57MetaInfo,
)
): Protobuf<Oidb0xf57Rsp>
@Serializable
data class Oidb0xf57MetaInfo(

View File

@ -2,12 +2,13 @@ package protobuf.push
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class C2CCommonTipsEvent(
@ProtoNumber(7) val params: List<PokeParam>? = null,
@ProtoNumber(8) val xmlTips: String? = null,
)
): Protobuf<C2CCommonTipsEvent>
@Serializable
data class PokeParam(

Some files were not shown because too many files have changed in this diff Show More