mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-08 05:50:25 +00:00
Compare commits
781 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1e8ef1cf6 | ||
|
|
5e5ac0162e | ||
|
|
0c013820f0 | ||
|
|
4b3a9e5847 | ||
|
|
e4982256a4 | ||
|
|
babc4927a8 | ||
|
|
6dd84cf469 | ||
|
|
a8800e3899 | ||
|
|
5f03496046 | ||
|
|
41500c17a2 | ||
|
|
2dcfde8b9a | ||
|
|
5c3305d8fa | ||
|
|
0d1fe99f53 | ||
|
|
4c03ffeec7 | ||
|
|
8101d17482 | ||
|
|
bc7b4dcc2a | ||
|
|
3db8b9078d | ||
|
|
943dbbefd3 | ||
|
|
480abcb853 | ||
|
|
60aaaff58e | ||
|
|
e3b889bbe8 | ||
|
|
ac5506a43b | ||
|
|
b29f533a3b | ||
|
|
a8ee86b09e | ||
|
|
0238c53302 | ||
|
|
665e3c806f | ||
|
|
8c96838441 | ||
|
|
4a722daec6 | ||
|
|
4e0cdbcb91 | ||
|
|
08976624cd | ||
|
|
fdeba94653 | ||
|
|
d3b100b7e5 | ||
|
|
1de3e18b08 | ||
|
|
d5c3c95682 | ||
|
|
dabe1e29ed | ||
|
|
203d1c0cfc | ||
|
|
7edd8601be | ||
|
|
a4423247f4 | ||
|
|
4834b203a0 | ||
|
|
bbabb32d13 | ||
|
|
95112d6bdf | ||
|
|
36cdca5a3e | ||
|
|
6980a9f3fc | ||
|
|
7b09479cd2 | ||
|
|
5825fd6f36 | ||
|
|
2d5b45dd82 | ||
|
|
52dda1d1fe | ||
|
|
420624bee4 | ||
|
|
8abde7b7d0 | ||
|
|
9e5b1ba28e | ||
|
|
b9c7d3c18e | ||
|
|
10aeccbbe5 | ||
|
|
15d351ebc2 | ||
|
|
7194f31cb6 | ||
|
|
84b7e82446 | ||
|
|
8264423b1a | ||
|
|
37f897f3bf | ||
|
|
fe3efac145 | ||
|
|
9773aebefc | ||
|
|
06f2b8c371 | ||
|
|
e8f0bb8350 | ||
|
|
9bfa6b827b | ||
|
|
b21bc17a58 | ||
|
|
f4d5d417d0 | ||
|
|
91fc83621e | ||
|
|
461feca0ca | ||
|
|
5e9afab3f7 | ||
|
|
2599ca6450 | ||
|
|
fc99ad3a39 | ||
|
|
10e1c3e72c | ||
|
|
af5dedd4d4 | ||
|
|
3b986c1076 | ||
|
|
72f77e8b7c | ||
|
|
e893bf676f | ||
|
|
80eb34f611 | ||
|
|
5d01947552 | ||
|
|
d3a025ef7b | ||
|
|
c466df841e | ||
|
|
b3c6e2a0f3 | ||
|
|
076c9cfed7 | ||
|
|
c3f3d12f83 | ||
|
|
44974034ec | ||
|
|
d6175acd38 | ||
|
|
62eee5f05c | ||
|
|
d4e5201913 | ||
|
|
f4d584765a | ||
|
|
26e224f852 | ||
|
|
252358ed66 | ||
|
|
475afeb7c8 | ||
|
|
7cbbb846eb | ||
|
|
25f947968c | ||
|
|
cad824dcbc | ||
|
|
e506f50b00 | ||
|
|
96ec149a98 | ||
|
|
8c913512f6 | ||
|
|
4cc307299d | ||
|
|
407c6b4c5f | ||
|
|
8f87070434 | ||
|
|
4a63996ee2 | ||
|
|
0358fe7620 | ||
|
|
55e64395ed | ||
|
|
ff5fb18e14 | ||
|
|
52dd960857 | ||
|
|
430221c2de | ||
|
|
217bdf8f92 | ||
|
|
38c6c869bf | ||
|
|
84d46da67e | ||
|
|
eb9d6240d7 | ||
|
|
2d44a871b0 | ||
|
|
3f89f350ff | ||
|
|
1a8407a782 | ||
|
|
cf288a3f73 | ||
|
|
f1f37fb180 | ||
|
|
fb0dd079fd | ||
|
|
a6c584c85c | ||
|
|
77adf35a30 | ||
|
|
dc6951c2a9 | ||
|
|
d14ba3f0f7 | ||
|
|
78ddf36e35 | ||
|
|
d42734624d | ||
|
|
b5dbd9d59b | ||
|
|
bed3e1289b | ||
|
|
b11ca4e60e | ||
|
|
4fcf3aa2bd | ||
|
|
dc39da8ca5 | ||
|
|
c10c87d28e | ||
|
|
c6fe6f1cc5 | ||
|
|
1c2bbeb26d | ||
|
|
17ed3692d0 | ||
|
|
966a00f41e | ||
|
|
fd8d8f89aa | ||
|
|
305bb74072 | ||
|
|
7f4dcdd134 | ||
|
|
aac37dcce1 | ||
|
|
f539c662a5 | ||
|
|
c82f346dd0 | ||
|
|
21b4a87837 | ||
|
|
ae73bcf24b | ||
|
|
2a3b56bde1 | ||
|
|
b8ebededd8 | ||
|
|
227c4c422c | ||
|
|
652bfb93cc | ||
|
|
c2278e3536 | ||
|
|
caa2fca4e8 | ||
|
|
745cb0175c | ||
|
|
e5165a780f | ||
|
|
b4b91af02b | ||
|
|
5649ff9c2e | ||
|
|
5b4bf6c62a | ||
|
|
93cb662282 | ||
|
|
00a8715e58 | ||
|
|
7ecd479b3e | ||
|
|
8fe7d3aaec | ||
|
|
f32a693393 | ||
|
|
17ebc01597 | ||
|
|
827fb698e1 | ||
|
|
32bdf10fd2 | ||
|
|
b795e6c3d2 | ||
|
|
42ba524e4e | ||
|
|
317c6d96e3 | ||
|
|
3692d1499f | ||
|
|
b21fbad8a3 | ||
|
|
743334a68a | ||
|
|
951413eb38 | ||
|
|
32dcdef853 | ||
|
|
34c9254d4a | ||
|
|
14012a4668 | ||
|
|
575debca63 | ||
|
|
763cac8532 | ||
|
|
43faacd7a7 | ||
|
|
1d4e307e96 | ||
|
|
7f8933b0de | ||
|
|
81608ff025 | ||
|
|
db63675b8e | ||
|
|
f74a83bc46 | ||
|
|
bc1deba3e4 | ||
|
|
d6113a8f0a | ||
|
|
2062cd48ea | ||
|
|
1c965ef515 | ||
|
|
58291b7156 | ||
|
|
afd1648d80 | ||
|
|
21814ffa9a | ||
|
|
9d3522da54 | ||
|
|
e07a76755e | ||
|
|
ba46bcdeae | ||
|
|
8d7e44314c | ||
|
|
35a67498c7 | ||
|
|
90dd934f95 | ||
|
|
4087045542 | ||
|
|
d11cef5907 | ||
|
|
76c91d226c | ||
|
|
c2b4dd2afd | ||
|
|
25b39cb39a | ||
|
|
35dcb7b88b | ||
|
|
e5f7e7c26e | ||
|
|
c5c11fd6a6 | ||
|
|
8134083419 | ||
|
|
a87e624198 | ||
|
|
e4c62d20b4 | ||
|
|
fa195d9e55 | ||
|
|
5ef5773d23 | ||
|
|
6eea52afdf | ||
|
|
80e64af30f | ||
|
|
563b6ddc36 | ||
|
|
c051ab9dc4 | ||
|
|
87737a8bdb | ||
|
|
94273d80b0 | ||
|
|
a08ec2a4bd | ||
|
|
d246c556f4 | ||
|
|
65aa365e38 | ||
|
|
eeeae449b4 | ||
|
|
17c10a7ba2 | ||
|
|
69f4383678 | ||
|
|
07852a7295 | ||
|
|
20b7e9b6b5 | ||
|
|
75f43ccea4 | ||
|
|
59e5785e93 | ||
|
|
b38f52dba9 | ||
|
|
2a6b17a48e | ||
|
|
a6c056a894 | ||
|
|
5c3442a71f | ||
|
|
390253242f | ||
|
|
9ab80fe1ac | ||
|
|
91fdd09e7a | ||
|
|
db5bd5c8a4 | ||
|
|
ef94c2fe7c | ||
|
|
72a25ed8e1 | ||
|
|
eb065e218f | ||
|
|
33426736fc | ||
|
|
896658d5ce | ||
|
|
b14135ed72 | ||
|
|
a1baf2e32d | ||
|
|
f9aa2d3bce | ||
|
|
c95d0e0696 | ||
|
|
ad4b84d446 | ||
|
|
3e27d5fcb0 | ||
|
|
48a100f49a | ||
|
|
698649f981 | ||
|
|
780078c3aa | ||
|
|
4c25e4ddee | ||
|
|
c0a5ac2ac5 | ||
|
|
0435409870 | ||
|
|
c521269409 | ||
|
|
1e252b7e4c | ||
|
|
d72b1edc48 | ||
|
|
f7307e8e01 | ||
|
|
127905f04b | ||
|
|
261c6dabd5 | ||
|
|
cae84bbf02 | ||
|
|
cdb2bc52fa | ||
|
|
cd2972eee0 | ||
|
|
4036aa8d0e | ||
|
|
52c6927c44 | ||
|
|
a16e0a21a2 | ||
|
|
e796b21157 | ||
|
|
1c6bc478b4 | ||
|
|
98f39c6388 | ||
|
|
570c83571b | ||
|
|
c0c38d89e0 | ||
|
|
b866cfc03c | ||
|
|
28c2755b37 | ||
|
|
57bfc5c73a | ||
|
|
0f3f7d53a3 | ||
|
|
529e50fd7f | ||
|
|
2fa283f91d | ||
|
|
029a9ade93 | ||
|
|
f1ca8b15c8 | ||
|
|
4d8edd5da9 | ||
|
|
6c63990653 | ||
|
|
5b521409c6 | ||
|
|
3268fc1014 | ||
|
|
19afb4941b | ||
|
|
40e5111d41 | ||
|
|
a3a40e1e74 | ||
|
|
101caa6826 | ||
|
|
875fed8d77 | ||
|
|
69e28eb000 | ||
|
|
e5d3a8360c | ||
|
|
4545d9285b | ||
|
|
6702024805 | ||
|
|
78bad4842b | ||
|
|
b9a913cfed | ||
|
|
6f5a6f353f | ||
|
|
790c4f589d | ||
|
|
cd1bd3461f | ||
|
|
0280dcd6a8 | ||
|
|
fc337292bc | ||
|
|
fb1daa0e21 | ||
|
|
579b9dc0c2 | ||
|
|
dedd0be352 | ||
|
|
1c7d9c3513 | ||
|
|
0c7dfe2af4 | ||
|
|
8d1351a8a3 | ||
|
|
e6e68a6036 | ||
|
|
24658edc45 | ||
|
|
09eaa3116a | ||
|
|
e9bff466b5 | ||
|
|
5d77f50160 | ||
|
|
2ab91e363f | ||
|
|
34d881426f | ||
|
|
13ecaa0ad4 | ||
|
|
ce6185b1f7 | ||
|
|
2cfde6b75a | ||
|
|
37d0354751 | ||
|
|
0a0edcf203 | ||
|
|
d6aad2ea28 | ||
|
|
63084506ee | ||
|
|
c5d313574f | ||
|
|
caab998212 | ||
|
|
aa037cc3d9 | ||
|
|
642bffe374 | ||
|
|
d682b154fc | ||
|
|
d4a06d98cf | ||
|
|
856b5e16b1 | ||
|
|
a0aa208860 | ||
|
|
037a11e04f | ||
|
|
bd8a1d715f | ||
|
|
54ab1dc091 | ||
|
|
9471e63857 | ||
|
|
fa4a403f38 | ||
|
|
d608d65bf4 | ||
|
|
c0f2df172a | ||
|
|
788ef5d81c | ||
|
|
1c6b5cffe1 | ||
|
|
c04382b623 | ||
|
|
0bbe51f8fd | ||
|
|
ff7d7d15a0 | ||
|
|
4b3d083d3a | ||
|
|
a566dd390b | ||
|
|
7d1442da04 | ||
|
|
17fc982f55 | ||
|
|
ba417e2274 | ||
|
|
d345094b75 | ||
|
|
6da477480d | ||
|
|
e274088c06 | ||
|
|
1bcaa73c5c | ||
|
|
ca94e8f621 | ||
|
|
1c4e198f59 | ||
|
|
fdd13f9c66 | ||
|
|
4333ab624e | ||
|
|
9fe1eb3a42 | ||
|
|
ad251a7682 | ||
|
|
1fa740de2d | ||
|
|
466b89064a | ||
|
|
2748cb0ba3 | ||
|
|
aef0d5bdde | ||
|
|
c71e8f024a | ||
|
|
9411f07321 | ||
|
|
9b2a5c9bbf | ||
|
|
2b275523a0 | ||
|
|
31fe2f6da4 | ||
|
|
f95db623a5 | ||
|
|
a46313e483 | ||
|
|
31c330826e | ||
|
|
c4cf800142 | ||
|
|
b64a2b0006 | ||
|
|
a3702f2270 | ||
|
|
d221b1d470 | ||
|
|
0b22a6bc1d | ||
|
|
07e8acd003 | ||
|
|
9fce617c57 | ||
|
|
8d5c736975 | ||
|
|
4ccec05186 | ||
|
|
a4f456f002 | ||
|
|
fbdb941c27 | ||
|
|
a41cd42e8d | ||
|
|
77521e4627 | ||
|
|
b6a1242bac | ||
|
|
2f325cfe26 | ||
|
|
193b0ad0f0 | ||
|
|
ed476b7793 | ||
|
|
720fd94b7f | ||
|
|
ff87da105c | ||
|
|
a875e65536 | ||
|
|
0b2c6bb662 | ||
|
|
e44e2fbbb7 | ||
|
|
b3c93644fd | ||
|
|
a56b7ff636 | ||
|
|
c724236930 | ||
|
|
4853320b2b | ||
|
|
ba1acb6ac1 | ||
|
|
f32a6320fc | ||
|
|
9f914ce36a | ||
|
|
b037644e5a | ||
|
|
afd8c59f83 | ||
|
|
8aa4af3e91 | ||
|
|
630a8a2b97 | ||
|
|
dc34c4d00c | ||
|
|
fb42729dec | ||
|
|
b06989216a | ||
|
|
e5144f08cd | ||
|
|
c4a60190e8 | ||
|
|
efe9e4fa4c | ||
|
|
45800b1559 | ||
|
|
b0b2b8104f | ||
|
|
8dbc012825 | ||
|
|
a434176063 | ||
|
|
a013f750c7 | ||
|
|
aa1f49d02f | ||
|
|
7125a26309 | ||
|
|
329a35ebf0 | ||
|
|
d30043f595 | ||
|
|
745dfa1911 | ||
|
|
76203f49a7 | ||
|
|
870a915377 | ||
|
|
c174fce227 | ||
|
|
2b6e42e919 | ||
|
|
df73e1e5a3 | ||
|
|
3e902311d4 | ||
|
|
64a0037265 | ||
|
|
bcd4e38093 | ||
|
|
181a77d627 | ||
|
|
b353595ba9 | ||
|
|
75e3bb4f17 | ||
|
|
d2fa9192d4 | ||
|
|
4bcadc2de4 | ||
|
|
8ddff74260 | ||
|
|
95940fdb64 | ||
|
|
9cd5708948 | ||
|
|
d361683d79 | ||
|
|
9ad17a01f7 | ||
|
|
22ca1d443c | ||
|
|
2662e875ca | ||
|
|
8ae0d07ec1 | ||
|
|
76a9edb7f5 | ||
|
|
0ccb464e5b | ||
|
|
bef600efa2 | ||
|
|
58a182cd33 | ||
|
|
aa43334f41 | ||
|
|
a2a4c97f6c | ||
|
|
4217ba99fd | ||
|
|
589725f5cc | ||
|
|
3fea4602f8 | ||
|
|
8ea6aae875 | ||
|
|
2c70b2af68 | ||
|
|
54a2cbcb42 | ||
|
|
fdef821c60 | ||
|
|
dfa798a35d | ||
|
|
39b8eb6ff1 | ||
|
|
6cf71f67a9 | ||
|
|
f2e919725e | ||
|
|
869599126e | ||
|
|
3b1b200f6f | ||
|
|
93c646e3e4 | ||
|
|
3552f80a21 | ||
|
|
66d3a63998 | ||
|
|
6447825978 | ||
|
|
18b7df9fca | ||
|
|
c3781cab96 | ||
|
|
776098dba6 | ||
|
|
8d1b4f61e7 | ||
|
|
c13e2bdb96 | ||
|
|
4682254157 | ||
|
|
d7ca6b9213 | ||
|
|
4a76afbde8 | ||
|
|
a68349c23a | ||
|
|
920e005366 | ||
|
|
659f339020 | ||
|
|
3ee2d463af | ||
|
|
686ddb5460 | ||
|
|
e5d62488b7 | ||
|
|
eb93dd5005 | ||
|
|
6999d02d2d | ||
|
|
790e2b1427 | ||
|
|
a29c7cdfe4 | ||
|
|
6b7cd692a6 | ||
|
|
4d3925872a | ||
|
|
2bd0f6934a | ||
|
|
51783f17ed | ||
|
|
ce3aef3526 | ||
|
|
ee70afdfbb | ||
|
|
d96c4a56a2 | ||
|
|
9a39513dea | ||
|
|
8f22d63315 | ||
|
|
7f2a5bb95e | ||
|
|
0118dbd5fb | ||
|
|
09405de26c | ||
|
|
efa5ee0e57 | ||
|
|
80d558f37a | ||
|
|
901adc3fc7 | ||
|
|
01417be954 | ||
|
|
43b780cbe6 | ||
|
|
e83f36a12f | ||
|
|
77e3fc4ab0 | ||
|
|
eafd1adaba | ||
|
|
6b53abb7c9 | ||
|
|
f994c5d284 | ||
|
|
6fda220107 | ||
|
|
da290ed1c3 | ||
|
|
7e9cd80a1c | ||
|
|
379b7413d8 | ||
|
|
9181a4df16 | ||
|
|
df982afd51 | ||
|
|
5c2c3b4317 | ||
|
|
92d1309103 | ||
|
|
c43ee3c1d6 | ||
|
|
e0726e5283 | ||
|
|
5f3775584b | ||
|
|
77873d63c5 | ||
|
|
9e6b09765e | ||
|
|
1ad6ea4049 | ||
|
|
7c41da1cb9 | ||
|
|
adcf4bfc53 | ||
|
|
7a6321a9c1 | ||
|
|
d56b27a7b0 | ||
|
|
ed7657ab5f | ||
|
|
a414838416 | ||
|
|
93646577dc | ||
|
|
46db66038e | ||
|
|
efc4e9ce56 | ||
|
|
8d5eac7f80 | ||
|
|
7b94e49b81 | ||
|
|
c35fd4bdc8 | ||
|
|
98590e2d90 | ||
|
|
e6da0e5dd5 | ||
|
|
cb2baf747d | ||
|
|
a2f2eb03ce | ||
|
|
5c6acbb780 | ||
|
|
1be7031199 | ||
|
|
ed6399bde9 | ||
|
|
6709893781 | ||
|
|
686a426cda | ||
|
|
4f90bc7813 | ||
|
|
e307b289ae | ||
|
|
3baeff61a7 | ||
|
|
93ab9d12ee | ||
|
|
36e1317792 | ||
|
|
fa3e90a021 | ||
|
|
782a69cf13 | ||
|
|
d495f351c0 | ||
|
|
30bd3d2d52 | ||
|
|
ff5a21cca5 | ||
|
|
f8abb73c92 | ||
|
|
e97f323d9a | ||
|
|
3d27a4c05d | ||
|
|
9dbc13dbe4 | ||
|
|
c46a4c75b1 | ||
|
|
0bded73f16 | ||
|
|
1333733684 | ||
|
|
003be934de | ||
|
|
93ef20d358 | ||
|
|
94e1a6f0ba | ||
|
|
8661d09d57 | ||
|
|
0e5e21dc4e | ||
|
|
3b25c4987c | ||
|
|
2212eb17aa | ||
|
|
768bac1db8 | ||
|
|
3aef75085f | ||
|
|
ce8bef638a | ||
|
|
f0a0c90304 | ||
|
|
cd6c32b21d | ||
|
|
b31876d2d1 | ||
|
|
ebab8a190e | ||
|
|
1b7ce8e7a5 | ||
|
|
646bb6bd79 | ||
|
|
5a84b97ca9 | ||
|
|
6d41b5a4a1 | ||
|
|
a8bce36f3b | ||
|
|
ac2132f8ba | ||
|
|
cab4b57abe | ||
|
|
938fb30359 | ||
|
|
62346d7d9d | ||
|
|
cf1e5ca64b | ||
|
|
7d2d683d96 | ||
|
|
fe5042f1c3 | ||
|
|
a1dd76aee0 | ||
|
|
d1c91be167 | ||
|
|
9748d99f34 | ||
|
|
c90ffbeb62 | ||
|
|
eb7fafeabf | ||
|
|
3e50629462 | ||
|
|
65281a4554 | ||
|
|
454ec09d6a | ||
|
|
60e3c6858d | ||
|
|
f911f5b4fc | ||
|
|
ad1694d291 | ||
|
|
1130965f26 | ||
|
|
fe1f28998b | ||
|
|
45727fce05 | ||
|
|
d5c23e5add | ||
|
|
e3a8285f6c | ||
|
|
a791221cf6 | ||
|
|
b954d9b403 | ||
|
|
5e7e24a271 | ||
|
|
ffb1e598f6 | ||
|
|
bc2da8a645 | ||
|
|
6f2be3ed30 | ||
|
|
033a7bffb3 | ||
|
|
f2b2ea61a1 | ||
|
|
6f0783acc4 | ||
|
|
ce60aa3823 | ||
|
|
8075e70606 | ||
|
|
4402fc2d0a | ||
|
|
3e3ecda551 | ||
|
|
50beb8f346 | ||
|
|
8e033e3e06 | ||
|
|
dc029a318b | ||
|
|
8e91bc2c8e | ||
|
|
0ff5b4e90b | ||
|
|
20dec19bfe | ||
|
|
d261fbff26 | ||
|
|
6594b33bcc | ||
|
|
a1bb6cc1b1 | ||
|
|
7ce195b68e | ||
|
|
16d8d04aaa | ||
|
|
59565f7d90 | ||
|
|
43784a2495 | ||
|
|
3811d7469e | ||
|
|
c72b40a1e1 | ||
|
|
f00933969d | ||
|
|
759adc45e3 | ||
|
|
27ecf78372 | ||
|
|
c91b83a7ba | ||
|
|
39373ee63a | ||
|
|
2db64c69ae | ||
|
|
a699b71c02 | ||
|
|
6c07d22cda | ||
|
|
a2ee900ed5 | ||
|
|
e709f31b99 | ||
|
|
35afb12756 | ||
|
|
9bed9fe162 | ||
|
|
4ff5553804 | ||
|
|
32213be7a7 | ||
|
|
84894a73e1 | ||
|
|
b6ea185ce7 | ||
|
|
814ac0f731 | ||
|
|
a40bb29da3 | ||
|
|
e9b90079c0 | ||
|
|
dba383c27e | ||
|
|
42059b5817 | ||
|
|
f92a17c01b | ||
|
|
d6552ce333 | ||
|
|
0db89bde5a | ||
|
|
56a12185d4 | ||
|
|
c40170db5d | ||
|
|
1df3e9c414 | ||
|
|
b1570df8b9 | ||
|
|
023fd1ce36 | ||
|
|
a7fe74bc0c | ||
|
|
26c9abd9da | ||
|
|
a5e34645c5 | ||
|
|
b2831c0a19 | ||
|
|
648c1ea0f9 | ||
|
|
9cd927e06a | ||
|
|
4272413f55 | ||
|
|
e1711b7af6 | ||
|
|
f7d3f27d45 | ||
|
|
3a7a47f82d | ||
|
|
cc211706d5 | ||
|
|
22f74be4cd | ||
|
|
5a00d14f94 | ||
|
|
ecb4e7bf9f | ||
|
|
56e5b546e1 | ||
|
|
272f5a2f4f | ||
|
|
ddcbe78a01 | ||
|
|
00b6c964e2 | ||
|
|
d7d2b06ecc | ||
|
|
fafc59360d | ||
|
|
19e105785e | ||
|
|
b87ac09e43 | ||
|
|
af9092d7c7 | ||
|
|
24a1ffd652 | ||
|
|
662813cc58 | ||
|
|
d890b78290 | ||
|
|
58747d7d4a | ||
|
|
0773a4f39c | ||
|
|
66cc7f8a1f | ||
|
|
01ab40bf4a | ||
|
|
4c09147fd1 | ||
|
|
f9f426d788 | ||
|
|
ff8fa1bf31 | ||
|
|
59f99e4f6a | ||
|
|
7449ce9c3b | ||
|
|
f6bc8f0a1f | ||
|
|
4d10b8cdee | ||
|
|
5a61c5de09 | ||
|
|
f84d0db811 | ||
|
|
36ce3b08fe | ||
|
|
da8ea5b545 | ||
|
|
fad3dbf4cd | ||
|
|
034d12c347 | ||
|
|
c94dbf1d9a | ||
|
|
e516687a9e | ||
|
|
4a2f77b0a6 | ||
|
|
7b29ecba71 | ||
|
|
11241b8e07 | ||
|
|
52bbd1f20b | ||
|
|
4044750515 | ||
|
|
b670c546b9 | ||
|
|
f37bbf93cb | ||
|
|
87311ab41a | ||
|
|
ecb4d1845c | ||
|
|
35c232ab25 | ||
|
|
df0be2e251 | ||
|
|
871b3a102b | ||
|
|
02299e3892 | ||
|
|
6af4d6f5b8 | ||
|
|
4fb5700367 | ||
|
|
8579276381 | ||
|
|
7ba60b22c5 | ||
|
|
031932f41c | ||
|
|
079d0a89b1 | ||
|
|
c4fdce6d64 | ||
|
|
5604c2b29f | ||
|
|
74b5ab2b47 | ||
|
|
c29cbfe123 | ||
|
|
6fe5cb1ffd | ||
|
|
7edd5a7a8e | ||
|
|
c1edc1b99b | ||
|
|
4d1d890f72 | ||
|
|
fe0f82fa2b | ||
|
|
84083a65a8 | ||
|
|
fc91c6bc08 | ||
|
|
09120171ba | ||
|
|
a362f920dc | ||
|
|
9d7729f548 | ||
|
|
ed56e177cf | ||
|
|
9db28bd502 | ||
|
|
aded70eb2e | ||
|
|
dfbad85465 | ||
|
|
52076fe182 | ||
|
|
5575c3cb13 | ||
|
|
637d32efff | ||
|
|
fd54658e53 | ||
|
|
2f39a8d76e | ||
|
|
6a3e793500 | ||
|
|
3b3ffeda6b | ||
|
|
f7d92a3b11 | ||
|
|
d9d9ba8bf1 | ||
|
|
f5d9090183 | ||
|
|
705ecd1ef1 | ||
|
|
08b5266a86 | ||
|
|
ecc4846ba8 | ||
|
|
4aab705d11 | ||
|
|
4615a68bcc | ||
|
|
bf6934e8ac | ||
|
|
af8c304bd4 | ||
|
|
51dac5a5a8 | ||
|
|
56463d9e36 | ||
|
|
a6a339dc59 | ||
|
|
8423304ab5 | ||
|
|
bb7408dbe9 | ||
|
|
7eff4dcf02 | ||
|
|
d7ee3fec3d | ||
|
|
5e026a3e8d | ||
|
|
d5e117b89f | ||
|
|
c87a5501df | ||
|
|
7584ebba0b | ||
|
|
66075e3960 | ||
|
|
193ba781a0 | ||
|
|
3e5dd64acc | ||
|
|
d66ab7d389 | ||
|
|
d2e6b27ecd | ||
|
|
0588541357 | ||
|
|
096ea84af6 | ||
|
|
04d0cfd510 | ||
|
|
7653f969ec | ||
|
|
c4ab6a4a8d | ||
|
|
d1ecd1318f | ||
|
|
8d65b1427d | ||
|
|
e693a6057e | ||
|
|
d0aa490ac3 | ||
|
|
0b6cad7d4f | ||
|
|
14e6c6d9a6 | ||
|
|
b2061347a5 | ||
|
|
79979f0a3b | ||
|
|
48d70b2349 | ||
|
|
b1f6309662 | ||
|
|
1acde76292 | ||
|
|
3b4867d7ab | ||
|
|
5ae965f4d3 | ||
|
|
742427b77b | ||
|
|
3d70a101f1 | ||
|
|
99062a5ea3 | ||
|
|
056d87f7ae | ||
|
|
df5a58772c | ||
|
|
e45db05b8e | ||
|
|
d234f74703 | ||
|
|
3ae2a1be4a | ||
|
|
2b828abd90 | ||
|
|
4b598b1575 |
21
.editorconfig
Normal file
21
.editorconfig
Normal file
@@ -0,0 +1,21 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf|crlf
|
||||
insert_final_newline = true
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
# Set default charset
|
||||
charset = utf-8
|
||||
|
||||
# 2 space indentation
|
||||
[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Unfortunately, EditorConfig doesn't support space configuration inside import braces directly.
|
||||
# You'll need to rely on your linter/formatter like ESLint or Prettier for that.
|
||||
1
.env.development
Normal file
1
.env.development
Normal file
@@ -0,0 +1 @@
|
||||
VITE_BUILD_TYPE = Development
|
||||
1
.env.production
Normal file
1
.env.production
Normal file
@@ -0,0 +1 @@
|
||||
VITE_BUILD_TYPE = Production
|
||||
68
.eslintrc.cjs
Normal file
68
.eslintrc.cjs
Normal file
@@ -0,0 +1,68 @@
|
||||
module.exports = {
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es2021': true,
|
||||
'node': true
|
||||
},
|
||||
'ignorePatterns': ['src/core/', 'src/core.lib/','src/proto/'],
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended'
|
||||
],
|
||||
'overrides': [
|
||||
{
|
||||
'env': {
|
||||
'node': true
|
||||
},
|
||||
'files': [
|
||||
'.eslintrc.{js,cjs}'
|
||||
],
|
||||
'parserOptions': {
|
||||
'sourceType': 'script'
|
||||
}
|
||||
}
|
||||
],
|
||||
'parser': '@typescript-eslint/parser',
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 'latest',
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'plugins': [
|
||||
'@typescript-eslint',
|
||||
'import'
|
||||
],
|
||||
'settings': {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts']
|
||||
},
|
||||
'import/resolver': {
|
||||
'typescript': {
|
||||
'alwaysTryTypes': true
|
||||
}
|
||||
}
|
||||
},
|
||||
'rules': {
|
||||
'indent': [
|
||||
'error',
|
||||
2
|
||||
],
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix'
|
||||
],
|
||||
'quotes': [
|
||||
'error',
|
||||
'single'
|
||||
],
|
||||
'semi': [
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'no-unused-vars': 'off',
|
||||
'no-async-promise-executor': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
}
|
||||
};
|
||||
81
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
81
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
name: Bug 反馈
|
||||
description: 报告可能的 NapCat 异常行为
|
||||
title: '[BUG] '
|
||||
labels: bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
欢迎来到 NapCat 的 Issue Tracker!请填写以下表格来提交 Bug。
|
||||
在提交新的 Bug 反馈前,请确保您:
|
||||
* 已经搜索了现有的 issues,并且没有找到可以解决您问题的方法
|
||||
* 不与现有的某一 issue 重复
|
||||
- type: input
|
||||
id: system-version
|
||||
attributes:
|
||||
label: 系统版本
|
||||
description: 运行 QQNT 的系统版本
|
||||
placeholder: Windows 10 Pro Workstation 22H2
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: qqnt-version
|
||||
attributes:
|
||||
label: QQNT 版本
|
||||
description: 可在 QQNT 的「关于」的设置页中找到
|
||||
placeholder: 9.9.7-21804
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: napcat-version
|
||||
attributes:
|
||||
label: NapCat 版本
|
||||
description: 可在 LiteLoaderQQNT 的设置页或是 QQNT 的设置页侧栏中找到
|
||||
placeholder: 1.0.0
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: onebot-client-version
|
||||
attributes:
|
||||
label: OneBot 客户端
|
||||
description: 连接至 NapCat 的客户端版本信息
|
||||
placeholder: Overflow 2.16.0-2cf7991-SNAPSHOT
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: 发生了什么?
|
||||
description: 填写你认为的 NapCat 的不正常行为
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: how-reproduce
|
||||
attributes:
|
||||
label: 如何复现
|
||||
description: 填写应当如何操作才能触发这个不正常行为
|
||||
placeholder: |
|
||||
1. xxx
|
||||
2. xxx
|
||||
3. xxx
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what-expected
|
||||
attributes:
|
||||
label: 期望的结果?
|
||||
description: 填写你认为 NapCat 应当执行的正常行为
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: napcat-log
|
||||
attributes:
|
||||
label: NapCat 运行日志
|
||||
description: 粘贴相关日志内容到此处
|
||||
render: shell
|
||||
- type: textarea
|
||||
id: onebot-client-log
|
||||
attributes:
|
||||
label: OneBot 客户端运行日志
|
||||
description: 粘贴 OneBot 客户端的相关日志内容到此处
|
||||
render: shell
|
||||
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
||||
74
.github/workflows/build.yml
vendored
Normal file
74
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
name: "Build"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
if: ${{ startsWith(github.event.head_commit.message, 'build:') }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [linux]
|
||||
target_arch: [x64, arm64]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
build-win32:
|
||||
if: ${{ startsWith(github.event.head_commit.message, 'build:') }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [win32]
|
||||
target_arch: [x64]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
138
.github/workflows/release.yml
vendored
Normal file
138
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
name: "release"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
check-version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract version from tag
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Check Version
|
||||
run: |
|
||||
ls
|
||||
node ./script/checkVersion.cjs
|
||||
sh ./checkVersion.sh
|
||||
build-linux:
|
||||
needs: [check-version]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [linux]
|
||||
target_arch: [x64, arm64]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
export NAPCAT_BUILDSYS=${{ matrix.target_platform }}
|
||||
export NAPCAT_BUILDARCH=${{ matrix.target_arch }}
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
build-win32:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check-version]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [win32]
|
||||
target_arch: [x64]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
export NAPCAT_BUILDSYS=${{ matrix.target_platform }}
|
||||
export NAPCAT_BUILDARCH=${{ matrix.target_arch }}
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
|
||||
release-napcat:
|
||||
needs: [build-win32,build-linux]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download All Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Compress subdirectories
|
||||
run: |
|
||||
for dir in */; do
|
||||
base=$(basename "$dir")
|
||||
zip -r "${base}.zip" "$dir"
|
||||
done
|
||||
|
||||
- name: Extract version from tag
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||
|
||||
- name: Clone Changes Log
|
||||
run: curl -o CHANGELOG.md https://fastly.jsdelivr.net/gh/NapNeko/NapCatQQ@main/docs/changelogs/CHANGELOG.v${{ env.VERSION }}.md
|
||||
|
||||
- name: Create Release Draft and Upload Artifacts
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
name: NapCat V${{ env.VERSION }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body_path: CHANGELOG.md
|
||||
files: |
|
||||
NapCat.win32.x64.zip
|
||||
NapCat.linux.x64.zip
|
||||
NapCat.linux.arm64.zip
|
||||
# NapCat.darwin.x64.zip
|
||||
# NapCat.darwin.arm64.zip
|
||||
draft: true
|
||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Develop
|
||||
node_modules/
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
out/
|
||||
dist/
|
||||
/src/core.lib/common/
|
||||
/localdebug/
|
||||
|
||||
# Editor
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea/*
|
||||
|
||||
# Build
|
||||
*.db
|
||||
checkVersion.sh
|
||||
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[submodule "src/core"]
|
||||
path = src/core
|
||||
url = https://github.com/NapNeko/core.git
|
||||
branch = master
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 NapCatQQ
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
39
README.md
39
README.md
@@ -1,14 +1,33 @@
|
||||
# NapCatQQ
|
||||
<div align="center">
|
||||
<img src="https://socialify.git.ci/NapNeko/NapCatQQ/image?description=1&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2FNapNeko%2FNapCatQQ%2Fmain%2Flogo.png&name=1&stargazers=1&theme=Auto" alt="NapCatQQ" width="640" height="320" />
|
||||
</div>
|
||||
|
||||
## 介绍
|
||||
无
|
||||
## 项目介绍
|
||||
|
||||
## 下载与安装
|
||||
前往release获取
|
||||
NapCatQQ 是基于 PC NTQQ 本体实现一套无头 Bot 框架。
|
||||
|
||||
## 使用与配置
|
||||
参考文档
|
||||
名字寓意 瞌睡猫QQ,像睡着了一样在后台低占用运行的无需GUI界面的NTQQ。
|
||||
|
||||
## 开源与安全
|
||||
为了防止过于扩散与违规使用,未来 NapCat 发版都会不公布源码,在未来形势有所转变下可能会发布源码。
|
||||
代码将进行混淆与插桩,请不要违法使用与宣传本项目。
|
||||
## 如何使用
|
||||
|
||||
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
|
||||
|
||||
**首次使用** 请务必前往 [官方文档](https://napneko.github.io/) 查看使用文档与教程
|
||||
|
||||
|
||||
## 项目声明
|
||||
|
||||
* 请不要在无关地方宣传NapCatQQ,本项目只是用于学习 node 相关知识,切勿用于违法用途
|
||||
|
||||
* NapCat 不会收集用户隐私信息,但是未来可能会为了更好的利于 NapCat 的优化会收集一些设备信息,如 cpu 架构,系统版本等
|
||||
|
||||
## 相关链接
|
||||
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
||||
|
||||
## 鸣谢名单
|
||||
|
||||
[Lagrange](https://github.com/LagrangeDev/Lagrange.Core)
|
||||
|
||||
<!--
|
||||
QQ群:545402644
|
||||
-->
|
||||
|
||||
17
docs/changelogs/CHANGELOG.v1.3.3.md
Normal file
17
docs/changelogs/CHANGELOG.v1.3.3.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# v1.3.3
|
||||
|
||||
QQ Version: Windows 9.9.9-23424 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 尝试修复多开崩溃问题
|
||||
* 修复群列表更新问题
|
||||
* 修复兼容性问题支持Win7
|
||||
* 修复下载 http 资源缺少UA
|
||||
* 优化少量消息合并转发速度
|
||||
* 修复加载群通知时出现 getUserDetailInfo timeout 导致程序崩溃
|
||||
|
||||
## 新增与调整
|
||||
* 新增设置群公告 Api: /_send_group_notice
|
||||
* 新增重启实现 包括重启快速登录/普通重启 副作用: 原进程 无法清理
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
18
docs/changelogs/CHANGELOG.v1.3.5.md
Normal file
18
docs/changelogs/CHANGELOG.v1.3.5.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# v1.3.5
|
||||
|
||||
QQ Version: Windows 9.9.9-23424 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 优化启动脚本
|
||||
* 修复非管理时群成员减少事件上报 **无法获取操作者与操作类型**
|
||||
* 修复快速重启进程清理问题
|
||||
* 优化配置文件格式 支持自动更新配置 但仍然建议 **备份配置**
|
||||
* 修复正向反向ws多个客户端周期多次心跳问题
|
||||
|
||||
## 新增与调整
|
||||
* 支持WebUi热重载
|
||||
* 新增启动输出WEBUI秘钥
|
||||
* 新增群荣誉信息 /get_group_honor_info
|
||||
* 支持获取群系统消息 /get_group_system_msg
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
11
docs/changelogs/CHANGELOG.v1.3.6.md
Normal file
11
docs/changelogs/CHANGELOG.v1.3.6.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.3.6
|
||||
|
||||
QQ Version: Windows 9.9.9-23424 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修复戳一戳多次上报问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
15
docs/changelogs/CHANGELOG.v1.3.8.md
Normal file
15
docs/changelogs/CHANGELOG.v1.3.8.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# v1.3.8
|
||||
|
||||
QQ Version: Windows 9.9.9-23873 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 优化打包后体积问题
|
||||
* 修复QQ等级获取
|
||||
* 兼容 9.7.x 版本换行符 统一为 \n
|
||||
* 修复处理加群请求 字段异常情况
|
||||
* 修复退群通知问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
11
docs/changelogs/CHANGELOG.v1.3.9.md
Normal file
11
docs/changelogs/CHANGELOG.v1.3.9.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.3.9
|
||||
|
||||
QQ Version: Windows 9.9.9-23873 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修复QQ等级获取与兼容性问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
66
package.json
Normal file
66
package.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "1.3.9",
|
||||
"scripts": {
|
||||
"watch:dev": "vite --mode development",
|
||||
"watch:prod": "vite --mode production",
|
||||
"build:dev": "vite build --mode development",
|
||||
"build:prod": "vite build --mode production",
|
||||
"build": "npm run build:dev",
|
||||
"build:core": "cd ./src/core && npm run build && cd ../.. && node ./script/copy-core.cjs",
|
||||
"build:webui": "cd ./src/webui && vite build",
|
||||
"watch": "npm run watch:dev",
|
||||
"debug-win": "powershell dist/napcat.ps1",
|
||||
"lint": "eslint --fix src/**/*.{js,ts}",
|
||||
"release": "npm run build:prod",
|
||||
"depend": "cd dist && npm install --omit=dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@log4js-node/log4js-api": "^1.0.2",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/figlet": "^1.5.8",
|
||||
"@types/fluent-ffmpeg": "^2.1.24",
|
||||
"@types/node": "^20.11.30",
|
||||
"@types/qrcode-terminal": "^0.12.2",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||
"@typescript-eslint/parser": "^7.4.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"i": "^0.3.7",
|
||||
"javascript-obfuscator": "^4.1.0",
|
||||
"rollup": "^4.13.2",
|
||||
"rollup-plugin-dts": "^6.1.0",
|
||||
"rollup-plugin-obfuscator": "^1.1.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.2.6",
|
||||
"vite-plugin-cp": "^4.0.8",
|
||||
"vite-plugin-dts": "^3.8.2",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"@protobuf-ts/plugin": "^2.9.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.13.0",
|
||||
"commander": "^12.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.0.0-beta.2",
|
||||
"fast-xml-parser": "^4.3.6",
|
||||
"file-type": "^19.0.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"image-size": "^1.1.1",
|
||||
"json-schema-to-ts": "^3.1.0",
|
||||
"log4js": "^6.9.1",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"silk-wasm": "^3.3.4",
|
||||
"sqlite3": "^5.1.7",
|
||||
"uuid": "^9.0.1",
|
||||
"ws": "^8.16.0"
|
||||
}
|
||||
}
|
||||
42
script/checkVersion.cjs
Normal file
42
script/checkVersion.cjs
Normal file
@@ -0,0 +1,42 @@
|
||||
const fs = require("fs");
|
||||
const process = require("process");
|
||||
|
||||
console.log("[NapCat] [CheckVersion] 开始检测当前仓库版本...");
|
||||
try {
|
||||
const packageJson = require("../package.json");
|
||||
const currentVersion = packageJson.version;
|
||||
const targetVersion = process.env.VERSION;
|
||||
|
||||
console.log("[NapCat] [CheckVersion] currentVersion:", currentVersion, "targetVersion:", targetVersion);
|
||||
|
||||
// 验证 targetVersion 格式
|
||||
if (!targetVersion || typeof targetVersion !== 'string') {
|
||||
console.error("[NapCat] [CheckVersion] 目标版本格式不正确或未设置!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 写入脚本文件的统一函数
|
||||
const writeScriptToFile = (content) => {
|
||||
fs.writeFileSync("./checkVersion.sh", content, { flag: 'w' });
|
||||
console.log("[NapCat] [CheckVersion] checkVersion.sh 文件已更新。");
|
||||
};
|
||||
|
||||
if (currentVersion === targetVersion) {
|
||||
// 不需要更新版本,写入一个简单的脚本
|
||||
const simpleScript = "#!/bin/bash\necho \"CheckVersion Is Done\"";
|
||||
writeScriptToFile(simpleScript);
|
||||
} else {
|
||||
// 更新版本,构建安全的sed命令
|
||||
const safeScriptContent = `
|
||||
#!/bin/bash
|
||||
git config --global user.email "bot@test.wumiao.wang"
|
||||
git config --global user.name "Version"
|
||||
sed -i "s/\\\"version\\\": \\\"${currentVersion}\\\"/\\\"version\\\": \\\"${targetVersion}\\\"/g" package.json
|
||||
git add .
|
||||
git commit -m "chore:version change"
|
||||
git push -u origin main`;
|
||||
writeScriptToFile(safeScriptContent);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[NapCat] [CheckVersion] 检测过程中发生错误:", error);
|
||||
}
|
||||
32
script/copy-core.cjs
Normal file
32
script/copy-core.cjs
Normal file
@@ -0,0 +1,32 @@
|
||||
let fs = require('fs');
|
||||
let path = require('path');
|
||||
|
||||
const coreDistDir = path.join(path.resolve(__dirname, '../'), 'src/core/dist/core/src');
|
||||
const coreLibDir = path.join(path.resolve(__dirname, '../'), 'src/core.lib/src');
|
||||
|
||||
function copyDir(currentPath, outputDir) {
|
||||
fs.readdir(currentPath, { withFileTypes: true }, (err, entries) => {
|
||||
if (err?.errno === -4058) return;
|
||||
|
||||
entries.forEach(entry => {
|
||||
const localBasePath = path.join(currentPath, entry.name);
|
||||
const outputLocalBasePath = path.join(outputDir, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
// 如果是目录,递归调用
|
||||
if (!fs.existsSync(outputLocalBasePath)) {
|
||||
fs.mkdirSync(outputLocalBasePath, { recursive: true });
|
||||
}
|
||||
copyDir(localBasePath, outputLocalBasePath);
|
||||
}
|
||||
else{
|
||||
// 如果是文件,直接复制
|
||||
fs.copyFile(localBasePath, outputLocalBasePath, (err) => {
|
||||
if (err) throw err;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
copyDir(coreDistDir, coreLibDir);
|
||||
21
script/gen-version.ts
Normal file
21
script/gen-version.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { version } from '../src/onebot11/version'
|
||||
|
||||
const manifestPath = path.join(__dirname, '../package.json')
|
||||
|
||||
function readManifest (): any {
|
||||
if (fs.existsSync(manifestPath)) {
|
||||
return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'))
|
||||
}
|
||||
}
|
||||
|
||||
function writeManifest (manifest: any) {
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2))
|
||||
}
|
||||
|
||||
const manifest = readManifest()
|
||||
if (version !== manifest.version) {
|
||||
manifest.version = version
|
||||
writeManifest(manifest)
|
||||
}
|
||||
3
script/napcat-custom.bat
Normal file
3
script/napcat-custom.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
chcp 65001
|
||||
set ELECTRON_RUN_AS_NODE=1
|
||||
"H:\Program Files\QQNT最新版\QQ.exe" %~dp0/napcat.cjs %*
|
||||
15
script/napcat-gc.ps1
Normal file
15
script/napcat-gc.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
function Get-QQpath {
|
||||
try {
|
||||
$key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ"
|
||||
$uninstallString = $key.UninstallString
|
||||
return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe"
|
||||
}
|
||||
catch {
|
||||
throw "Error getting UninstallString: $_"
|
||||
}
|
||||
}
|
||||
$params = $args -join " "
|
||||
$QQpath = Get-QQpath
|
||||
$Bootfile = Join-Path (Get-Location) "\dist\inject.cjs"
|
||||
$env:ELECTRON_RUN_AS_NODE = 1
|
||||
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& '$QQpath' --expose-gc $Bootfile $params}"
|
||||
17
script/napcat-log.ps1
Normal file
17
script/napcat-log.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
function Get-QQpath {
|
||||
try {
|
||||
$key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ"
|
||||
$uninstallString = $key.UninstallString
|
||||
return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe"
|
||||
}
|
||||
catch {
|
||||
return "D:\QQ.exe"
|
||||
}
|
||||
}
|
||||
$params = $args -join " "
|
||||
$QQpath = Get-QQpath
|
||||
$Bootfile = Join-Path $PSScriptRoot "napcat.cjs"
|
||||
$env:ELECTRON_RUN_AS_NODE = 1
|
||||
$argumentList = '-noexit', '-noprofile', "-command `"$QQpath`" `"$Bootfile`" $params"
|
||||
Start-Process powershell -ArgumentList $argumentList -RedirectStandardOutput "log.txt" -RedirectStandardError "error.txt"
|
||||
powershell Get-Content -Wait -Encoding UTF8 log.txt
|
||||
18
script/napcat-utf8.bat
Normal file
18
script/napcat-utf8.bat
Normal file
@@ -0,0 +1,18 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
chcp 65001
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set "RetString=%%b"
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("!RetString!") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
||||
set ELECTRON_RUN_AS_NODE=1
|
||||
echo !QQPath!
|
||||
"!QQPath!" ./napcat.mjs %*
|
||||
43
script/napcat-utf8.ps1
Normal file
43
script/napcat-utf8.ps1
Normal file
@@ -0,0 +1,43 @@
|
||||
function Get-QQpath {
|
||||
try {
|
||||
$key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ"
|
||||
$uninstallString = $key.UninstallString
|
||||
return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe"
|
||||
}
|
||||
catch {
|
||||
throw "get QQ path error: $_"
|
||||
}
|
||||
}
|
||||
function Select-QQPath {
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||
|
||||
$dialogTitle = "Select QQ.exe"
|
||||
|
||||
$filePicker = New-Object System.Windows.Forms.OpenFileDialog
|
||||
$filePicker.Title = $dialogTitle
|
||||
$filePicker.Filter = "Executable Files (*.exe)|*.exe|All Files (*.*)|*.*"
|
||||
$filePicker.FilterIndex = 1
|
||||
$null = $filePicker.ShowDialog()
|
||||
if (-not ($filePicker.FileName)) {
|
||||
throw "User did not select an .exe file."
|
||||
}
|
||||
return $filePicker.FileName
|
||||
}
|
||||
|
||||
$params = $args -join " "
|
||||
Try {
|
||||
$QQpath = Get-QQpath
|
||||
}
|
||||
Catch {
|
||||
$QQpath = Select-QQPath
|
||||
}
|
||||
|
||||
if (!(Test-Path $QQpath)) {
|
||||
throw "provided QQ path is invalid: $QQpath"
|
||||
}
|
||||
|
||||
$Bootfile = Join-Path $PSScriptRoot "napcat.mjs"
|
||||
$env:ELECTRON_RUN_AS_NODE = 1
|
||||
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
||||
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& chcp 65001;& '$($commandInfo.Path)' $Bootfile $params}"
|
||||
17
script/napcat.bat
Normal file
17
script/napcat.bat
Normal file
@@ -0,0 +1,17 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set "RetString=%%b"
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("!RetString!") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
||||
set ELECTRON_RUN_AS_NODE=1
|
||||
echo !QQPath!
|
||||
"!QQPath!" ./napcat.mjs %*
|
||||
43
script/napcat.ps1
Normal file
43
script/napcat.ps1
Normal file
@@ -0,0 +1,43 @@
|
||||
function Get-QQpath {
|
||||
try {
|
||||
$key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ"
|
||||
$uninstallString = $key.UninstallString
|
||||
return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe"
|
||||
}
|
||||
catch {
|
||||
throw "get QQ path error: $_"
|
||||
}
|
||||
}
|
||||
function Select-QQPath {
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||
|
||||
$dialogTitle = "Select QQ.exe"
|
||||
|
||||
$filePicker = New-Object System.Windows.Forms.OpenFileDialog
|
||||
$filePicker.Title = $dialogTitle
|
||||
$filePicker.Filter = "Executable Files (*.exe)|*.exe|All Files (*.*)|*.*"
|
||||
$filePicker.FilterIndex = 1
|
||||
$null = $filePicker.ShowDialog()
|
||||
if (-not ($filePicker.FileName)) {
|
||||
throw "User did not select an .exe file."
|
||||
}
|
||||
return $filePicker.FileName
|
||||
}
|
||||
|
||||
$params = $args -join " "
|
||||
Try {
|
||||
$QQpath = Get-QQpath
|
||||
}
|
||||
Catch {
|
||||
$QQpath = Select-QQPath
|
||||
}
|
||||
|
||||
if (!(Test-Path $QQpath)) {
|
||||
throw "provided QQ path is invalid: $QQpath"
|
||||
}
|
||||
|
||||
$Bootfile = Join-Path $PSScriptRoot "napcat.mjs"
|
||||
$env:ELECTRON_RUN_AS_NODE = 1
|
||||
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
||||
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& '$($commandInfo.Path)' $Bootfile $params}"
|
||||
21
script/napcat.sh
Normal file
21
script/napcat.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
get_script_dir() {
|
||||
local script_path="${1:-$0}"
|
||||
local script_dir
|
||||
script_path=$(readlink -f "$script_path")
|
||||
script_dir=$(dirname "$script_path")
|
||||
|
||||
echo "$script_dir"
|
||||
}
|
||||
|
||||
SCRIPT_DIR=$(get_script_dir)
|
||||
|
||||
export ELECTRON_RUN_AS_NODE=1
|
||||
|
||||
if ! [ -x /opt/QQ/qq ]; then
|
||||
echo "Error: /opt/QQ/qq is not executable or does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/opt/QQ/qq "${SCRIPT_DIR}/napcat.mjs" "$@"
|
||||
124
src/common/server/http.ts
Normal file
124
src/common/server/http.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import express, { Express, Request, Response } from 'express';
|
||||
import cors from 'cors';
|
||||
import http from 'http';
|
||||
import { log, logDebug, logError } from '../utils/log';
|
||||
import { ob11Config } from '@/onebot11/config';
|
||||
|
||||
type RegisterHandler = (res: Response, payload: any) => Promise<any>
|
||||
|
||||
export abstract class HttpServerBase {
|
||||
name: string = 'NapCatQQ';
|
||||
private readonly expressAPP: Express;
|
||||
private server: http.Server | null = null;
|
||||
|
||||
constructor() {
|
||||
this.expressAPP = express();
|
||||
this.expressAPP.use(cors());
|
||||
this.expressAPP.use(express.urlencoded({ extended: true, limit: '5000mb' }));
|
||||
this.expressAPP.use((req, res, next) => {
|
||||
// 兼容处理没有带content-type的请求
|
||||
// log("req.headers['content-type']", req.headers['content-type'])
|
||||
req.headers['content-type'] = 'application/json';
|
||||
const originalJson = express.json({ limit: '5000mb' });
|
||||
// 调用原始的express.json()处理器
|
||||
originalJson(req, res, (err) => {
|
||||
if (err) {
|
||||
logError('Error parsing JSON:', err);
|
||||
return res.status(400).send('Invalid JSON');
|
||||
}
|
||||
next();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
authorize(req: Request, res: Response, next: () => void) {
|
||||
const serverToken = ob11Config.token;
|
||||
let clientToken = '';
|
||||
const authHeader = req.get('authorization');
|
||||
if (authHeader) {
|
||||
clientToken = authHeader.split('Bearer ').pop() || '';
|
||||
logDebug('receive http header token', clientToken);
|
||||
} else if (req.query.access_token) {
|
||||
if (Array.isArray(req.query.access_token)) {
|
||||
clientToken = req.query.access_token[0].toString();
|
||||
} else {
|
||||
clientToken = req.query.access_token.toString();
|
||||
}
|
||||
logDebug('receive http url token', clientToken);
|
||||
}
|
||||
|
||||
if (serverToken && clientToken != serverToken) {
|
||||
return res.status(403).send(JSON.stringify({ message: 'token verify failed!' }));
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
start(port: number, host: string) {
|
||||
try {
|
||||
this.expressAPP.get('/', (req: Request, res: Response) => {
|
||||
res.send(`${this.name}已启动`);
|
||||
});
|
||||
this.listen(port, host);
|
||||
} catch (e: any) {
|
||||
logError('HTTP服务启动失败', e.toString());
|
||||
// httpServerError = "HTTP服务启动失败, " + e.toString()
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
// httpServerError = ""
|
||||
if (this.server) {
|
||||
this.server.close();
|
||||
this.server = null;
|
||||
}
|
||||
}
|
||||
|
||||
restart(port: number, host: string) {
|
||||
this.stop();
|
||||
this.start(port, host);
|
||||
}
|
||||
|
||||
abstract handleFailed(res: Response, payload: any, err: any): void
|
||||
|
||||
registerRouter(method: 'post' | 'get' | string, url: string, handler: RegisterHandler) {
|
||||
if (!url.startsWith('/')) {
|
||||
url = '/' + url;
|
||||
}
|
||||
|
||||
// @ts-expect-error wait fix
|
||||
if (!this.expressAPP[method]) {
|
||||
const err = `${this.name} register router failed,${method} not exist`;
|
||||
logError(err);
|
||||
throw err;
|
||||
}
|
||||
// @ts-expect-error wait fix
|
||||
this.expressAPP[method](url, this.authorize, async (req: Request, res: Response) => {
|
||||
let payload = req.body;
|
||||
if (method == 'get') {
|
||||
payload = req.query;
|
||||
} else if (req.query) {
|
||||
payload = { ...req.query, ...req.body };
|
||||
}
|
||||
logDebug('收到http请求', url, payload);
|
||||
try {
|
||||
res.send(await handler(res, payload));
|
||||
} catch (e: any) {
|
||||
this.handleFailed(res, payload, e.stack.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected listen(port: number, host: string = '0.0.0.0') {
|
||||
host = host || '0.0.0.0';
|
||||
try {
|
||||
this.server = this.expressAPP.listen(port, host, () => {
|
||||
const info = `${this.name} started ${host}:${port}`;
|
||||
log(info);
|
||||
}).on('error', (err) => {
|
||||
logError('HTTP服务启动失败', err.toString());
|
||||
});
|
||||
} catch (e: any) {
|
||||
logError('HTTP服务启动失败, 请检查监听的ip地址和端口', e.stack.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
105
src/common/server/websocket.ts
Normal file
105
src/common/server/websocket.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { WebSocket, WebSocketServer } from 'ws';
|
||||
import urlParse from 'url';
|
||||
import { IncomingMessage } from 'node:http';
|
||||
import { log } from '@/common/utils/log';
|
||||
|
||||
class WebsocketClientBase {
|
||||
private wsClient: WebSocket | undefined;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
send(msg: string) {
|
||||
if (this.wsClient && this.wsClient.readyState == WebSocket.OPEN) {
|
||||
this.wsClient.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
onMessage(msg: string) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class WebsocketServerBase {
|
||||
private ws: WebSocketServer | null = null;
|
||||
public token: string = '';
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
start(port: number, host: string = '') {
|
||||
try {
|
||||
this.ws = new WebSocketServer({
|
||||
port,
|
||||
host: '',
|
||||
maxPayload: 1024 * 1024 * 1024
|
||||
}).on('error', () => {
|
||||
});
|
||||
log(`ws服务启动成功, ${host}:${port}`);
|
||||
} catch (e: any) {
|
||||
throw Error('ws服务启动失败, 请检查监听的ip和端口' + e.toString());
|
||||
}
|
||||
this.ws.on('connection', (wsClient, req) => {
|
||||
const url: string = req.url!.split('?').shift() || '/';
|
||||
this.authorize(wsClient, req);
|
||||
this.onConnect(wsClient, url, req);
|
||||
wsClient.on('message', async (msg) => {
|
||||
this.onMessage(wsClient, url, msg.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.ws && this.ws.close((err) => {
|
||||
log('ws server close failed!', err);
|
||||
});
|
||||
this.ws = null;
|
||||
}
|
||||
|
||||
restart(port: number) {
|
||||
this.stop();
|
||||
this.start(port);
|
||||
}
|
||||
|
||||
authorize(wsClient: WebSocket, req: IncomingMessage) {
|
||||
const url = req.url!.split('?').shift();
|
||||
log('ws connect', url);
|
||||
let clientToken: string = '';
|
||||
const authHeader = req.headers['authorization'];
|
||||
if (authHeader) {
|
||||
clientToken = authHeader.split('Bearer ').pop() || '';
|
||||
log('receive ws header token', clientToken);
|
||||
} else {
|
||||
const parsedUrl = urlParse.parse(req.url || '/', true);
|
||||
const urlToken = parsedUrl.query.access_token;
|
||||
if (urlToken) {
|
||||
if (Array.isArray(urlToken)) {
|
||||
clientToken = urlToken[0];
|
||||
} else {
|
||||
clientToken = urlToken;
|
||||
}
|
||||
log('receive ws url token', clientToken);
|
||||
}
|
||||
}
|
||||
if (this.token && clientToken != this.token) {
|
||||
this.authorizeFailed(wsClient);
|
||||
return wsClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
authorizeFailed(wsClient: WebSocket) {
|
||||
|
||||
}
|
||||
|
||||
onConnect(wsClient: WebSocket, url: string, req: IncomingMessage) {
|
||||
|
||||
}
|
||||
|
||||
onMessage(wsClient: WebSocket, url: string, msg: string) {
|
||||
|
||||
}
|
||||
|
||||
sendHeart() {
|
||||
|
||||
}
|
||||
}
|
||||
35
src/common/utils/AsyncQueue.ts
Normal file
35
src/common/utils/AsyncQueue.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { sleep } from '@/common/utils/helper';
|
||||
|
||||
type AsyncQueueTask = (() => void) | (()=>Promise<void>);
|
||||
|
||||
|
||||
export class AsyncQueue {
|
||||
private tasks: (AsyncQueueTask)[] = [];
|
||||
|
||||
public addTask(task: AsyncQueueTask) {
|
||||
this.tasks.push(task);
|
||||
// console.log('addTask', this.tasks.length);
|
||||
if (this.tasks.length === 1) {
|
||||
this.runQueue().then().catch(()=>{});
|
||||
}
|
||||
}
|
||||
|
||||
private async runQueue() {
|
||||
// console.log('runQueue', this.tasks.length);
|
||||
while (this.tasks.length > 0) {
|
||||
const task = this.tasks[0];
|
||||
// console.log('typeof task', typeof task);
|
||||
try {
|
||||
const taskRet = task();
|
||||
// console.log('type of taskRet', typeof taskRet, taskRet);
|
||||
if (taskRet instanceof Promise) {
|
||||
await taskRet;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
this.tasks.shift();
|
||||
await sleep(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
73
src/common/utils/ConfigBase.ts
Normal file
73
src/common/utils/ConfigBase.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { log, logDebug, logError } from '@/common/utils/log';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const configDir = path.resolve(__dirname, 'config');
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
|
||||
|
||||
export class ConfigBase<T>{
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
protected getKeys(): string[] | null {
|
||||
// 决定 key 在json配置文件中的顺序
|
||||
return null;
|
||||
}
|
||||
|
||||
getConfigDir(){
|
||||
const configDir = path.resolve(__dirname, 'config');
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
return configDir;
|
||||
}
|
||||
getConfigPath(): string {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
read() {
|
||||
const configPath = this.getConfigPath();
|
||||
if (!fs.existsSync(configPath)) {
|
||||
try{
|
||||
fs.writeFileSync(configPath, JSON.stringify(this, this.getKeys(), 2));
|
||||
log(`配置文件${configPath}已创建\n如果修改此文件后需要重启 NapCat 生效`);
|
||||
}
|
||||
catch (e: any) {
|
||||
logError(`创建配置文件 ${configPath} 时发生错误:`, e.message);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
try {
|
||||
const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
logDebug(`配置文件${configPath}已加载`, data);
|
||||
Object.assign(this, data);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
this.save(this); // 保存一次,让新版本的字段写入
|
||||
return this;
|
||||
} catch (e: any) {
|
||||
if (e instanceof SyntaxError) {
|
||||
logError(`配置文件 ${configPath} 格式错误,请检查配置文件:`, e.message);
|
||||
} else {
|
||||
logError(`读取配置文件 ${configPath} 时发生错误:`, e.message);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
save(config: T) {
|
||||
Object.assign(this, config);
|
||||
const configPath = this.getConfigPath();
|
||||
try {
|
||||
fs.writeFileSync(configPath, JSON.stringify(this, this.getKeys(), 2));
|
||||
} catch (e: any) {
|
||||
logError(`保存配置文件 ${configPath} 时发生错误:`, e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/common/utils/QQBasicInfo.ts
Normal file
72
src/common/utils/QQBasicInfo.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import { systemPlatform } from '@/common/utils/system';
|
||||
|
||||
export const exePath = process.execPath;
|
||||
|
||||
export const pkgInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'package.json');
|
||||
let configVersionInfoPath;
|
||||
|
||||
if (os.platform() !== 'linux') {
|
||||
configVersionInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'versions', 'config.json');
|
||||
} else {
|
||||
const userPath = os.homedir();
|
||||
const appDataPath = path.resolve(userPath, './.config/QQ');
|
||||
configVersionInfoPath = path.resolve(appDataPath, './versions/config.json');
|
||||
}
|
||||
|
||||
if (typeof configVersionInfoPath !== 'string') {
|
||||
throw new Error('Something went wrong when load QQ info path');
|
||||
}
|
||||
|
||||
export { configVersionInfoPath };
|
||||
|
||||
type QQPkgInfo = {
|
||||
version: string;
|
||||
buildVersion: string;
|
||||
platform: string;
|
||||
eleArch: string;
|
||||
}
|
||||
type QQVersionConfigInfo = {
|
||||
baseVersion: string;
|
||||
curVersion: string;
|
||||
prevVersion: string;
|
||||
onErrorVersions: Array<any>;
|
||||
buildId: string;
|
||||
}
|
||||
|
||||
let _qqVersionConfigInfo: QQVersionConfigInfo = {
|
||||
'baseVersion': '9.9.9-23361',
|
||||
'curVersion': '9.9.9-23361',
|
||||
'prevVersion': '',
|
||||
'onErrorVersions': [],
|
||||
'buildId': '23361'
|
||||
};
|
||||
|
||||
if (fs.existsSync(configVersionInfoPath)) {
|
||||
try {
|
||||
const _ =JSON.parse(fs.readFileSync(configVersionInfoPath).toString());
|
||||
_qqVersionConfigInfo = Object.assign(_qqVersionConfigInfo, _);
|
||||
} catch (e) {
|
||||
console.error('Load QQ version config info failed, Use default version', e);
|
||||
}
|
||||
}
|
||||
|
||||
export const qqVersionConfigInfo: QQVersionConfigInfo = _qqVersionConfigInfo;
|
||||
|
||||
export const qqPkgInfo: QQPkgInfo = JSON.parse(fs.readFileSync(pkgInfoPath).toString());
|
||||
// platform_type: 3,
|
||||
// app_type: 4,
|
||||
// app_version: '9.9.9-23159',
|
||||
// qua: 'V1_WIN_NQ_9.9.9_23159_GW_B',
|
||||
// appid: '537213764',
|
||||
// platVer: '10.0.26100',
|
||||
// clientVer: '9.9.9-23159',
|
||||
|
||||
let _appid: string = '537213803'; // 默认为 Windows 平台的 appid
|
||||
if (systemPlatform === 'linux') {
|
||||
_appid = '537213827';
|
||||
}
|
||||
// todo: mac 平台的 appid
|
||||
export const appid = _appid;
|
||||
135
src/common/utils/audio.ts
Normal file
135
src/common/utils/audio.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import fs from 'fs';
|
||||
import { encode, getDuration, getWavFileInfo, isWav } from 'silk-wasm';
|
||||
import fsPromise from 'fs/promises';
|
||||
import { log, logError } from './log';
|
||||
import path from 'node:path';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { getTempDir } from '@/common/utils/file';
|
||||
|
||||
let TEMP_DIR = './';
|
||||
setTimeout(() => {
|
||||
TEMP_DIR = getTempDir();
|
||||
}, 100);
|
||||
export async function encodeSilk(filePath: string) {
|
||||
function getFileHeader(filePath: string) {
|
||||
// 定义要读取的字节数
|
||||
const bytesToRead = 7;
|
||||
try {
|
||||
const buffer = fs.readFileSync(filePath, {
|
||||
encoding: null,
|
||||
flag: 'r',
|
||||
});
|
||||
|
||||
const fileHeader = buffer.toString('hex', 0, bytesToRead);
|
||||
return fileHeader;
|
||||
} catch (err) {
|
||||
console.error('读取文件错误:', err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function isWavFile(filePath: string) {
|
||||
return isWav(fs.readFileSync(filePath));
|
||||
}
|
||||
|
||||
async function guessDuration(pttPath: string) {
|
||||
const pttFileInfo = await fsPromise.stat(pttPath);
|
||||
let duration = pttFileInfo.size / 1024 / 3; // 3kb/s
|
||||
duration = Math.floor(duration);
|
||||
duration = Math.max(1, duration);
|
||||
log('通过文件大小估算语音的时长:', duration);
|
||||
return duration;
|
||||
}
|
||||
|
||||
// function verifyDuration(oriDuration: number, guessDuration: number) {
|
||||
// // 单位都是秒
|
||||
// if (oriDuration - guessDuration > 10) {
|
||||
// return guessDuration
|
||||
// }
|
||||
// oriDuration = Math.max(1, oriDuration)
|
||||
// return oriDuration
|
||||
// }
|
||||
// async function getAudioSampleRate(filePath: string) {
|
||||
// try {
|
||||
// const mm = await import('music-metadata');
|
||||
// const metadata = await mm.parseFile(filePath);
|
||||
// log(`${filePath}采样率`, metadata.format.sampleRate);
|
||||
// return metadata.format.sampleRate;
|
||||
// } catch (error) {
|
||||
// log(`${filePath}采样率获取失败`, error.stack);
|
||||
// // console.error(error);
|
||||
// }
|
||||
// }
|
||||
|
||||
try {
|
||||
const pttPath = path.join(TEMP_DIR, uuidv4());
|
||||
if (getFileHeader(filePath) !== '02232153494c4b') {
|
||||
log(`语音文件${filePath}需要转换成silk`);
|
||||
const _isWav = await isWavFile(filePath);
|
||||
const pcmPath = pttPath + '.pcm';
|
||||
let sampleRate = 0;
|
||||
const convert = () => {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
// todo: 通过配置文件获取ffmpeg路径
|
||||
const ffmpegPath = process.env.FFMPEG_PATH || 'ffmpeg';
|
||||
const cp = spawn(ffmpegPath, ['-y', '-i', filePath, '-ar', '24000', '-ac', '1', '-f', 's16le', pcmPath]);
|
||||
cp.on('error', err => {
|
||||
log('FFmpeg处理转换出错: ', err.message);
|
||||
return reject(err);
|
||||
});
|
||||
cp.on('exit', (code, signal) => {
|
||||
const EXIT_CODES = [0, 255];
|
||||
if (code == null || EXIT_CODES.includes(code)) {
|
||||
sampleRate = 24000;
|
||||
const data = fs.readFileSync(pcmPath);
|
||||
fs.unlink(pcmPath, (err) => {
|
||||
});
|
||||
return resolve(data);
|
||||
}
|
||||
log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`);
|
||||
reject(Error('FFmpeg处理转换失败'));
|
||||
});
|
||||
});
|
||||
};
|
||||
let input: Buffer;
|
||||
if (!_isWav) {
|
||||
input = await convert();
|
||||
} else {
|
||||
input = fs.readFileSync(filePath);
|
||||
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000];
|
||||
const { fmt } = getWavFileInfo(input);
|
||||
// log(`wav文件信息`, fmt)
|
||||
if (!allowSampleRate.includes(fmt.sampleRate)) {
|
||||
input = await convert();
|
||||
}
|
||||
}
|
||||
const silk = await encode(input, sampleRate);
|
||||
fs.writeFileSync(pttPath, silk.data);
|
||||
log(`语音文件${filePath}转换成功!`, pttPath, '时长:', silk.duration);
|
||||
return {
|
||||
converted: true,
|
||||
path: pttPath,
|
||||
duration: silk.duration / 1000
|
||||
};
|
||||
} else {
|
||||
const silk = fs.readFileSync(filePath);
|
||||
let duration = 0;
|
||||
try {
|
||||
duration = getDuration(silk) / 1000;
|
||||
} catch (e: any) {
|
||||
log('获取语音文件时长失败, 使用文件大小推测时长', filePath, e.stack);
|
||||
duration = await guessDuration(filePath);
|
||||
}
|
||||
|
||||
return {
|
||||
converted: false,
|
||||
path: filePath,
|
||||
duration,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
logError('convert silk failed', error.stack);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
24
src/common/utils/cpmodule.ts
Normal file
24
src/common/utils/cpmodule.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import * as os from 'os';
|
||||
import path from 'node:path';
|
||||
import fs from 'fs';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
export function getModuleWithArchName(moduleName: string) {
|
||||
const systemPlatform = os.platform();
|
||||
const cpuArch = os.arch();
|
||||
return `${moduleName}-${systemPlatform}-${cpuArch}.node`;
|
||||
}
|
||||
|
||||
export function cpModule(moduleName: string) {
|
||||
const currentDir = path.resolve(__dirname);
|
||||
const fileName = `./${getModuleWithArchName(moduleName)}`;
|
||||
try {
|
||||
fs.copyFileSync(path.join(currentDir, fileName), path.join(currentDir, `${moduleName}.node`));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
273
src/common/utils/file.ts
Normal file
273
src/common/utils/file.ts
Normal file
@@ -0,0 +1,273 @@
|
||||
import fs from 'fs';
|
||||
import fsPromise from 'fs/promises';
|
||||
import crypto from 'crypto';
|
||||
import util from 'util';
|
||||
import path from 'node:path';
|
||||
import { log } from './log';
|
||||
import { dbUtil } from '@/core/utils/db';
|
||||
import * as fileType from 'file-type';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { napCatCore } from '@/core';
|
||||
|
||||
export const getNapCatDir = () => {
|
||||
const p = path.join(napCatCore.dataPath, 'NapCat');
|
||||
fs.mkdirSync(p, { recursive: true });
|
||||
return p;
|
||||
};
|
||||
export const getTempDir = () => {
|
||||
const p = path.join(getNapCatDir(), 'temp');
|
||||
// 创建临时目录
|
||||
if (!fs.existsSync(p)) {
|
||||
fs.mkdirSync(p, { recursive: true });
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
|
||||
export function isGIF(path: string) {
|
||||
const buffer = Buffer.alloc(4);
|
||||
const fd = fs.openSync(path, 'r');
|
||||
fs.readSync(fd, buffer, 0, 4, 0);
|
||||
fs.closeSync(fd);
|
||||
return buffer.toString() === 'GIF8';
|
||||
}
|
||||
|
||||
// 定义一个异步函数来检查文件是否存在
|
||||
export function checkFileReceived(path: string, timeout: number = 3000): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
function check() {
|
||||
if (fs.existsSync(path)) {
|
||||
resolve();
|
||||
} else if (Date.now() - startTime > timeout) {
|
||||
reject(new Error(`文件不存在: ${path}`));
|
||||
} else {
|
||||
setTimeout(check, 100);
|
||||
}
|
||||
}
|
||||
|
||||
check();
|
||||
});
|
||||
}
|
||||
|
||||
export async function file2base64(path: string) {
|
||||
const readFile = util.promisify(fs.readFile);
|
||||
const result = {
|
||||
err: '',
|
||||
data: ''
|
||||
};
|
||||
try {
|
||||
// 读取文件内容
|
||||
// if (!fs.existsSync(path)){
|
||||
// path = path.replace("\\Ori\\", "\\Thumb\\");
|
||||
// }
|
||||
try {
|
||||
await checkFileReceived(path, 5000);
|
||||
} catch (e: any) {
|
||||
result.err = e.toString();
|
||||
return result;
|
||||
}
|
||||
const data = await readFile(path);
|
||||
// 转换为Base64编码
|
||||
result.data = data.toString('base64');
|
||||
} catch (err: any) {
|
||||
result.err = err.toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
export function calculateFileMD5(filePath: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 创建一个流式读取器
|
||||
const stream = fs.createReadStream(filePath);
|
||||
const hash = crypto.createHash('md5');
|
||||
|
||||
stream.on('data', (data: Buffer) => {
|
||||
// 当读取到数据时,更新哈希对象的状态
|
||||
hash.update(data);
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
// 文件读取完成,计算哈希
|
||||
const md5 = hash.digest('hex');
|
||||
resolve(md5);
|
||||
});
|
||||
|
||||
stream.on('error', (err: Error) => {
|
||||
// 处理可能的读取错误
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export interface HttpDownloadOptions {
|
||||
url: string;
|
||||
headers?: Record<string, string> | string;
|
||||
}
|
||||
|
||||
export async function httpDownload(options: string | HttpDownloadOptions): Promise<Buffer> {
|
||||
const chunks: Buffer[] = [];
|
||||
let url: string;
|
||||
let headers: Record<string, string> = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36'
|
||||
};
|
||||
if (typeof options === 'string') {
|
||||
url = options;
|
||||
} else {
|
||||
url = options.url;
|
||||
if (options.headers) {
|
||||
if (typeof options.headers === 'string') {
|
||||
headers = JSON.parse(options.headers);
|
||||
} else {
|
||||
headers = options.headers;
|
||||
}
|
||||
}
|
||||
}
|
||||
const fetchRes = await fetch(url, { headers });
|
||||
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`);
|
||||
|
||||
const blob = await fetchRes.blob();
|
||||
const buffer = await blob.arrayBuffer();
|
||||
return Buffer.from(buffer);
|
||||
}
|
||||
|
||||
type Uri2LocalRes = {
|
||||
success: boolean,
|
||||
errMsg: string,
|
||||
fileName: string,
|
||||
ext: string,
|
||||
path: string,
|
||||
isLocal: boolean
|
||||
}
|
||||
|
||||
export async function uri2local(uri: string, fileName: string | null = null): Promise<Uri2LocalRes> {
|
||||
const res = {
|
||||
success: false,
|
||||
errMsg: '',
|
||||
fileName: '',
|
||||
ext: '',
|
||||
path: '',
|
||||
isLocal: false
|
||||
};
|
||||
if (!fileName) {
|
||||
fileName = uuidv4();
|
||||
}
|
||||
let filePath = path.join(getTempDir(), fileName);
|
||||
let url = null;
|
||||
try {
|
||||
url = new URL(uri);
|
||||
} catch (e: any) {
|
||||
res.errMsg = `uri ${uri} 解析失败,` + e.toString() + ` 可能${uri}不存在`;
|
||||
return res;
|
||||
}
|
||||
|
||||
// log("uri protocol", url.protocol, uri);
|
||||
if (url.protocol == 'base64:') {
|
||||
// base64转成文件
|
||||
const base64Data = uri.split('base64://')[1];
|
||||
try {
|
||||
const buffer = Buffer.from(base64Data, 'base64');
|
||||
fs.writeFileSync(filePath, buffer);
|
||||
|
||||
} catch (e: any) {
|
||||
res.errMsg = 'base64文件下载失败,' + e.toString();
|
||||
return res;
|
||||
}
|
||||
} else if (url.protocol == 'http:' || url.protocol == 'https:') {
|
||||
// 下载文件
|
||||
let buffer: Buffer | null = null;
|
||||
try {
|
||||
buffer = await httpDownload(uri);
|
||||
} catch (e: any) {
|
||||
res.errMsg = `${url}下载失败,` + e.toString();
|
||||
return res;
|
||||
}
|
||||
try {
|
||||
const pathInfo = path.parse(decodeURIComponent(url.pathname));
|
||||
if (pathInfo.name) {
|
||||
fileName = pathInfo.name;
|
||||
if (pathInfo.ext) {
|
||||
fileName += pathInfo.ext;
|
||||
// res.ext = pathInfo.ext
|
||||
}
|
||||
}
|
||||
fileName = fileName.replace(/[/\\:*?"<>|]/g, '_');
|
||||
res.fileName = fileName;
|
||||
filePath = path.join(getTempDir(), uuidv4() + fileName);
|
||||
fs.writeFileSync(filePath, buffer);
|
||||
} catch (e: any) {
|
||||
res.errMsg = `${url}下载失败,` + e.toString();
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
let pathname: string;
|
||||
if (url.protocol === 'file:') {
|
||||
// await fs.copyFile(url.pathname, filePath);
|
||||
pathname = decodeURIComponent(url.pathname);
|
||||
if (process.platform === 'win32') {
|
||||
filePath = pathname.slice(1);
|
||||
} else {
|
||||
filePath = pathname;
|
||||
}
|
||||
} else {
|
||||
const cache = await dbUtil.getFileCacheByName(uri);
|
||||
if (cache) {
|
||||
filePath = cache.path;
|
||||
} else {
|
||||
filePath = uri;
|
||||
}
|
||||
}
|
||||
|
||||
res.isLocal = true;
|
||||
}
|
||||
// else{
|
||||
// res.errMsg = `不支持的file协议,` + url.protocol
|
||||
// return res
|
||||
// }
|
||||
// if (isGIF(filePath) && !res.isLocal) {
|
||||
// await fs.rename(filePath, filePath + ".gif");
|
||||
// filePath += ".gif";
|
||||
// }
|
||||
if (!res.isLocal && !res.ext) {
|
||||
try {
|
||||
const ext: string | undefined = (await fileType.fileTypeFromFile(filePath))?.ext;
|
||||
if (ext) {
|
||||
log('获取文件类型', ext, filePath);
|
||||
fs.renameSync(filePath, filePath + `.${ext}`);
|
||||
filePath += `.${ext}`;
|
||||
res.fileName += `.${ext}`;
|
||||
res.ext = ext;
|
||||
}
|
||||
} catch (e) {
|
||||
// log("获取文件类型失败", filePath,e.stack)
|
||||
}
|
||||
}
|
||||
res.success = true;
|
||||
res.path = filePath;
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function copyFolder(sourcePath: string, destPath: string) {
|
||||
try {
|
||||
const entries = await fsPromise.readdir(sourcePath, { withFileTypes: true });
|
||||
await fsPromise.mkdir(destPath, { recursive: true });
|
||||
for (const entry of entries) {
|
||||
const srcPath = path.join(sourcePath, entry.name);
|
||||
const dstPath = path.join(destPath, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
await copyFolder(srcPath, dstPath);
|
||||
} else {
|
||||
try {
|
||||
await fsPromise.copyFile(srcPath, dstPath);
|
||||
} catch (error) {
|
||||
console.error(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
|
||||
// 这里可以决定是否要继续复制其他文件
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('复制文件夹时出错:', error);
|
||||
}
|
||||
}
|
||||
179
src/common/utils/helper.ts
Normal file
179
src/common/utils/helper.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
import crypto from 'node:crypto';
|
||||
import path from 'node:path';
|
||||
import fs from 'fs/promises';
|
||||
import { log, logDebug } from './log';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export function getMd5(s: string) {
|
||||
|
||||
const h = crypto.createHash('md5');
|
||||
h.update(s);
|
||||
return h.digest('hex');
|
||||
}
|
||||
|
||||
export function isNull(value: any) {
|
||||
return value === undefined || value === null;
|
||||
}
|
||||
|
||||
export function isNumeric(str: string) {
|
||||
return /^\d+$/.test(str);
|
||||
}
|
||||
|
||||
export function truncateString(obj: any, maxLength = 500) {
|
||||
if (obj !== null && typeof obj === 'object') {
|
||||
Object.keys(obj).forEach(key => {
|
||||
if (typeof obj[key] === 'string') {
|
||||
// 如果是字符串且超过指定长度,则截断
|
||||
if (obj[key].length > maxLength) {
|
||||
obj[key] = obj[key].substring(0, maxLength) + '...';
|
||||
}
|
||||
} else if (typeof obj[key] === 'object') {
|
||||
// 如果是对象或数组,则递归调用
|
||||
truncateString(obj[key], maxLength);
|
||||
}
|
||||
});
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 函数缓存装饰器,根据方法名、参数、自定义key生成缓存键,在一定时间内返回缓存结果
|
||||
* @param ttl 超时时间,单位毫秒
|
||||
* @param customKey 自定义缓存键前缀,可为空,防止方法名参数名一致时导致缓存键冲突
|
||||
* @returns 处理后缓存或调用原方法的结果
|
||||
*/
|
||||
export function cacheFunc(ttl: number, customKey: string = '') {
|
||||
const cache = new Map<string, { expiry: number; value: any }>();
|
||||
|
||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
|
||||
const originalMethod = descriptor.value;
|
||||
const className = target.constructor.name; // 获取类名
|
||||
const methodName = propertyKey; // 获取方法名
|
||||
descriptor.value = async function (...args: any[]) {
|
||||
const cacheKey = `${customKey}${className}.${methodName}:${JSON.stringify(args)}`;
|
||||
const cached = cache.get(cacheKey);
|
||||
if (cached && cached.expiry > Date.now()) {
|
||||
return cached.value;
|
||||
} else {
|
||||
const result = await originalMethod.apply(this, args);
|
||||
cache.set(cacheKey, { value: result, expiry: Date.now() + ttl });
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
export function isValidOldConfig(config: any) {
|
||||
if (typeof config !== 'object') {
|
||||
return false;
|
||||
}
|
||||
const requiredKeys = [
|
||||
'httpHost', 'httpPort', 'httpPostUrls', 'httpSecret',
|
||||
'wsHost', 'wsPort', 'wsReverseUrls', 'enableHttp',
|
||||
'enableHttpHeart', 'enableHttpPost', 'enableWs', 'enableWsReverse',
|
||||
'messagePostFormat', 'reportSelfMessage', 'enableLocalFile2Url',
|
||||
'debug', 'heartInterval', 'token', 'musicSignUrl'
|
||||
];
|
||||
for (const key of requiredKeys) {
|
||||
if (!(key in config)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(config.httpPostUrls) || !Array.isArray(config.wsReverseUrls)) {
|
||||
return false;
|
||||
}
|
||||
if (config.httpPostUrls.some((url: any) => typeof url !== 'string')) {
|
||||
return false;
|
||||
}
|
||||
if (config.wsReverseUrls.some((url: any) => typeof url !== 'string')) {
|
||||
return false;
|
||||
}
|
||||
if (typeof config.httpPort !== 'number' || typeof config.wsPort !== 'number' || typeof config.heartInterval !== 'number') {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
typeof config.enableHttp !== 'boolean' ||
|
||||
typeof config.enableHttpHeart !== 'boolean' ||
|
||||
typeof config.enableHttpPost !== 'boolean' ||
|
||||
typeof config.enableWs !== 'boolean' ||
|
||||
typeof config.enableWsReverse !== 'boolean' ||
|
||||
typeof config.enableLocalFile2Url !== 'boolean' ||
|
||||
typeof config.reportSelfMessage !== 'boolean'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (config.messagePostFormat !== 'array' && config.messagePostFormat !== 'string') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
export function migrateConfig(oldConfig: any) {
|
||||
const newConfig = {
|
||||
http: {
|
||||
enable: oldConfig.enableHttp,
|
||||
host: oldConfig.httpHost,
|
||||
port: oldConfig.httpPort,
|
||||
secret: oldConfig.httpSecret,
|
||||
enableHeart: oldConfig.enableHttpHeart,
|
||||
enablePost: oldConfig.enableHttpPost,
|
||||
postUrls: oldConfig.httpPostUrls,
|
||||
},
|
||||
ws: {
|
||||
enable: oldConfig.enableWs,
|
||||
host: oldConfig.wsHost,
|
||||
port: oldConfig.wsPort,
|
||||
},
|
||||
reverseWs: {
|
||||
enable: oldConfig.enableWsReverse,
|
||||
urls: oldConfig.wsReverseUrls,
|
||||
},
|
||||
debug: oldConfig.debug,
|
||||
heartInterval: oldConfig.heartInterval,
|
||||
messagePostFormat: oldConfig.messagePostFormat,
|
||||
enableLocalFile2Url: oldConfig.enableLocalFile2Url,
|
||||
musicSignUrl: oldConfig.musicSignUrl,
|
||||
reportSelfMessage: oldConfig.reportSelfMessage,
|
||||
token: oldConfig.token,
|
||||
};
|
||||
return newConfig;
|
||||
}
|
||||
// 升级旧的配置到新的
|
||||
export async function UpdateConfig() {
|
||||
const configFiles = await fs.readdir(path.join(__dirname, 'config'));
|
||||
for (const file of configFiles) {
|
||||
if (file.match(/^onebot11_\d+.json$/)) {
|
||||
const CurrentConfig = JSON.parse(await fs.readFile(path.join(__dirname, 'config', file), 'utf8'));
|
||||
if (isValidOldConfig(CurrentConfig)) {
|
||||
log('正在迁移旧配置到新配置 File:', file);
|
||||
const NewConfig = migrateConfig(CurrentConfig);
|
||||
await fs.writeFile(path.join(__dirname, 'config', file), JSON.stringify(NewConfig, null, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export function isEqual(obj1: any, obj2: any) {
|
||||
if (obj1 === obj2) return true;
|
||||
if (obj1 == null || obj2 == null) return false;
|
||||
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2;
|
||||
|
||||
const keys1 = Object.keys(obj1);
|
||||
const keys2 = Object.keys(obj2);
|
||||
|
||||
if (keys1.length !== keys2.length) return false;
|
||||
|
||||
for (const key of keys1) {
|
||||
if (!isEqual(obj1[key], obj2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
123
src/common/utils/log.ts
Normal file
123
src/common/utils/log.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import log4js, { Configuration } from 'log4js';
|
||||
import { truncateString } from '@/common/utils/helper';
|
||||
import path from 'node:path';
|
||||
import { SelfInfo } from '@/core';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export enum LogLevel {
|
||||
DEBUG = 'debug',
|
||||
INFO = 'info',
|
||||
WARN = 'warn',
|
||||
ERROR = 'error',
|
||||
FATAL = 'fatal',
|
||||
}
|
||||
|
||||
const logDir = path.join(path.resolve(__dirname), 'logs');
|
||||
|
||||
function getFormattedTimestamp() {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = now.getDate().toString().padStart(2, '0');
|
||||
const hours = now.getHours().toString().padStart(2, '0');
|
||||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||
const seconds = now.getSeconds().toString().padStart(2, '0');
|
||||
const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
|
||||
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`;
|
||||
}
|
||||
|
||||
const filename = `${getFormattedTimestamp()}.log`;
|
||||
const logPath = path.join(logDir, filename);
|
||||
|
||||
const logConfig: Configuration = {
|
||||
appenders: {
|
||||
FileAppender: { // 输出到文件的appender
|
||||
type: 'file',
|
||||
filename: logPath, // 指定日志文件的位置和文件名
|
||||
maxLoogSize: 10485760, // 日志文件的最大大小(单位:字节),这里设置为10MB
|
||||
layout: {
|
||||
type: 'pattern',
|
||||
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] - %m'
|
||||
}
|
||||
},
|
||||
ConsoleAppender: { // 输出到控制台的appender
|
||||
type: 'console',
|
||||
layout: {
|
||||
type: 'pattern',
|
||||
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] - %m'
|
||||
}
|
||||
}
|
||||
},
|
||||
categories: {
|
||||
default: { appenders: ['FileAppender', 'ConsoleAppender'], level: 'debug' }, // 默认情况下同时输出到文件和控制台
|
||||
file: { appenders: ['FileAppender'], level: 'debug' },
|
||||
console: { appenders: ['ConsoleAppender'], level: 'debug' }
|
||||
}
|
||||
};
|
||||
|
||||
log4js.configure(logConfig);
|
||||
|
||||
|
||||
export function setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
||||
logConfig.categories.file.level = fileLogLevel;
|
||||
logConfig.categories.console.level = consoleLogLevel;
|
||||
log4js.configure(logConfig);
|
||||
}
|
||||
|
||||
export function setLogSelfInfo(selfInfo: SelfInfo) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
logConfig.appenders.FileAppender.layout.pattern = logConfig.appenders.ConsoleAppender.layout.pattern =
|
||||
`%d{yyyy-MM-dd hh:mm:ss} [%p] ${selfInfo.nick}(${selfInfo.uin}) %m`;
|
||||
log4js.configure(logConfig);
|
||||
}
|
||||
|
||||
let fileLogEnabled = true;
|
||||
let consoleLogEnabled = true;
|
||||
export function enableFileLog(enable: boolean) {
|
||||
fileLogEnabled = enable;
|
||||
}
|
||||
export function enableConsoleLog(enable: boolean) {
|
||||
consoleLogEnabled = enable;
|
||||
}
|
||||
|
||||
function formatMsg(msg: any[]){
|
||||
let logMsg = '';
|
||||
for (const msgItem of msg) {
|
||||
// 判断是否是对象
|
||||
if (typeof msgItem === 'object') {
|
||||
const obj = JSON.parse(JSON.stringify(msgItem, null, 2));
|
||||
logMsg += JSON.stringify(truncateString(obj)) + ' ';
|
||||
continue;
|
||||
}
|
||||
logMsg += msgItem + ' ';
|
||||
}
|
||||
return '\n' + logMsg + '\n';
|
||||
}
|
||||
|
||||
function _log(level: LogLevel, ...args: any[]){
|
||||
if (consoleLogEnabled){
|
||||
log4js.getLogger('console')[level](formatMsg(args));
|
||||
}
|
||||
if (fileLogEnabled){
|
||||
log4js.getLogger('file')[level](formatMsg(args));
|
||||
}
|
||||
}
|
||||
|
||||
export function log(...args: any[]) {
|
||||
// info 等级
|
||||
_log(LogLevel.INFO, ...args);
|
||||
}
|
||||
|
||||
export function logDebug(...args: any[]) {
|
||||
_log(LogLevel.DEBUG, ...args);
|
||||
}
|
||||
|
||||
export function logError(...args: any[]) {
|
||||
_log(LogLevel.ERROR, ...args);
|
||||
}
|
||||
7
src/common/utils/qqlevel.ts
Normal file
7
src/common/utils/qqlevel.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// QQ等级换算
|
||||
import { QQLevel } from '@/core/entities';
|
||||
|
||||
export function calcQQLevel(level: QQLevel) {
|
||||
const { crownNum, sunNum, moonNum, starNum } = level;
|
||||
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
||||
}
|
||||
44
src/common/utils/reboot.ts
Normal file
44
src/common/utils/reboot.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { resolve } from 'node:path';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { pid, ppid, exit } from 'node:process';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export async function rebootWithQuickLogin(uin: string) {
|
||||
const batScript = resolve(__dirname, './napcat.bat');
|
||||
const batUtf8Script = resolve(__dirname, './napcat-utf8.bat');
|
||||
const bashScript = resolve(__dirname, './napcat.sh');
|
||||
if (process.platform === 'win32') {
|
||||
const subProcess = spawn(`start ${batUtf8Script} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||
subProcess.unref();
|
||||
// 子父进程一起送走 有点效果
|
||||
spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||
spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||
} else if (process.platform === 'linux') {
|
||||
const subProcess = spawn(`${bashScript} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||
//还没兼容
|
||||
subProcess.unref();
|
||||
exit(0);
|
||||
}
|
||||
//exit(0);
|
||||
}
|
||||
export async function rebootWithNormolLogin() {
|
||||
const batScript = resolve(__dirname, './napcat.bat');
|
||||
const batUtf8Script = resolve(__dirname, './napcat-utf8.bat');
|
||||
const bashScript = resolve(__dirname, './napcat.sh');
|
||||
if (process.platform === 'win32') {
|
||||
const subProcess = spawn(`start ${batUtf8Script} `, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||
subProcess.unref();
|
||||
// 子父进程一起送走 有点效果
|
||||
spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||
spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||
} else if (process.platform === 'linux') {
|
||||
const subProcess = spawn(`${bashScript}`, { detached: true, windowsHide: false, env: process.env, shell: true });
|
||||
subProcess.unref();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
87
src/common/utils/request.ts
Normal file
87
src/common/utils/request.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import https from 'node:https';
|
||||
import http from 'node:http';
|
||||
|
||||
export class RequestUtil {
|
||||
// 适用于获取服务器下发cookies时获取,仅GET
|
||||
static async HttpsGetCookies(url: string): Promise<Map<string, string>> {
|
||||
return new Promise<Map<string, string>>((resolve, reject) => {
|
||||
const protocol = url.startsWith('https://') ? https : http;
|
||||
protocol.get(url, (res) => {
|
||||
const cookiesHeader = res.headers['set-cookie'];
|
||||
if (!cookiesHeader) {
|
||||
resolve(new Map<string, string>());
|
||||
} else {
|
||||
const cookiesMap = new Map<string, string>();
|
||||
cookiesHeader.forEach((cookieStr) => {
|
||||
cookieStr.split(';').forEach((cookiePart) => {
|
||||
const trimmedPart = cookiePart.trim();
|
||||
if (trimmedPart.includes('=')) {
|
||||
const [key, value] = trimmedPart.split('=').map(part => part.trim());
|
||||
cookiesMap.set(key, decodeURIComponent(value)); // 解码cookie值
|
||||
}
|
||||
});
|
||||
});
|
||||
resolve(cookiesMap);
|
||||
}
|
||||
}).on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 请求和回复都是JSON data传原始内容 自动编码json
|
||||
static async HttpGetJson<T>(url: string, method: string = 'GET', data?: any, headers: Record<string, string> = {}, isJsonRet: boolean = true, isArgJson: boolean = true): Promise<T> {
|
||||
const option = new URL(url);
|
||||
const protocol = url.startsWith('https://') ? https : http;
|
||||
const options = {
|
||||
hostname: option.hostname,
|
||||
port: option.port,
|
||||
path: option.href,
|
||||
method: method,
|
||||
headers: headers
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = protocol.request(options, (res: any) => {
|
||||
let responseBody = '';
|
||||
res.on('data', (chunk: string | Buffer) => {
|
||||
responseBody += chunk.toString();
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
||||
if (isJsonRet) {
|
||||
const responseJson = JSON.parse(responseBody);
|
||||
resolve(responseJson as T);
|
||||
} else {
|
||||
resolve(responseBody as T);
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`Unexpected status code: ${res.statusCode}`));
|
||||
}
|
||||
} catch (parseError) {
|
||||
reject(parseError);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error: any) => {
|
||||
reject(error);
|
||||
});
|
||||
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
||||
if (isArgJson) {
|
||||
req.write(JSON.stringify(data));
|
||||
} else {
|
||||
req.write(data);
|
||||
}
|
||||
|
||||
}
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// 请求返回都是原始内容
|
||||
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: Record<string, string> = {}) {
|
||||
return this.HttpGetJson<string>(url, method, data, headers, false, false);
|
||||
}
|
||||
}
|
||||
17
src/common/utils/system.ts
Normal file
17
src/common/utils/system.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
// 缓解Win7设备兼容性问题
|
||||
let osName: string;
|
||||
try {
|
||||
osName = os.hostname();
|
||||
} catch (e) {
|
||||
osName = 'NapCat'; // + crypto.randomUUID().substring(0, 4);
|
||||
}
|
||||
export const systemPlatform = os.platform();
|
||||
export const cpuArch = os.arch();
|
||||
export const systemVersion = os.release();
|
||||
export const hostname = osName;
|
||||
const homeDir = os.homedir();
|
||||
export const downloadsPath = path.join(homeDir, 'Downloads');
|
||||
export const systemName = os.type();
|
||||
31
src/common/utils/type.ts
Normal file
31
src/common/utils/type.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 运行时类型转换与检查类
|
||||
*/
|
||||
export class TypeCheck {
|
||||
static isEmpty(value: any): boolean {
|
||||
return value === null || value === undefined || value === '' ||
|
||||
(Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0);
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeConvert {
|
||||
static toNumber(value: any): number {
|
||||
const num = Number(value);
|
||||
if (isNaN(num)) {
|
||||
throw new Error(`无法将输入转换为数字: ${value}`);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static toString(value: any): string {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
static toBoolean(value: any): boolean {
|
||||
return Boolean(value);
|
||||
}
|
||||
|
||||
static toArray(value: any): any[] {
|
||||
return Array.isArray(value) ? value : [value];
|
||||
}
|
||||
}
|
||||
25
src/common/utils/version.ts
Normal file
25
src/common/utils/version.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { logDebug } from './log';
|
||||
import { RequestUtil } from './request';
|
||||
export async function checkVersion(): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const MirrorList =
|
||||
[
|
||||
'https://fastly.jsdelivr.net/gh/NapNeko/NapCatQQ@main/package.json',
|
||||
'https://gcore.jsdelivr.net/gh/NapNeko/NapCatQQ@main/package.json',
|
||||
'https://cdn.jsdelivr.us/gh/NapNeko/NapCatQQ@main/package.json',
|
||||
'https://jsd.cdn.zzko.cn/gh/NapNeko/NapCatQQ@main/package.json'
|
||||
];
|
||||
let version = undefined;
|
||||
for (const url of MirrorList) {
|
||||
try {
|
||||
version = (await RequestUtil.HttpGetJson<{ version: string }>(url)).version;
|
||||
} catch (e) {
|
||||
logDebug(e);
|
||||
}
|
||||
if (version) {
|
||||
resolve(version);
|
||||
}
|
||||
}
|
||||
reject('get verison error!');
|
||||
});
|
||||
}
|
||||
87
src/common/utils/video.ts
Normal file
87
src/common/utils/video.ts
Normal file
File diff suppressed because one or more lines are too long
1
src/core
Submodule
1
src/core
Submodule
Submodule src/core added at 5572791869
22
src/core.lib/package.json
Normal file
22
src/core.lib/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@napneko/core",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"main": "./index.js",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "eslint --fix ./src/**/*.ts",
|
||||
"build:dev": "vite build --mode development",
|
||||
"build:prod": "vite build --mode production",
|
||||
"build": "npm run build:dev"
|
||||
},
|
||||
"author": "NapNeko",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/NapNeko/NapCatQQ/issues"
|
||||
},
|
||||
"homepage": "https://github.com/NapNeko/NapCatQQ#readme"
|
||||
}
|
||||
14
src/core.lib/src/adapters/NodeIDependsAdapter.d.ts
vendored
Normal file
14
src/core.lib/src/adapters/NodeIDependsAdapter.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
interface IDependsAdapter {
|
||||
onMSFStatusChange(arg1: number, arg2: number): void;
|
||||
onMSFSsoError(args: unknown): void;
|
||||
getGroupCode(args: unknown): void;
|
||||
}
|
||||
export interface NodeIDependsAdapter extends IDependsAdapter {
|
||||
new (adapter: IDependsAdapter): NodeIDependsAdapter;
|
||||
}
|
||||
export declare class DependsAdapter implements IDependsAdapter {
|
||||
onMSFStatusChange(arg1: number, arg2: number): void;
|
||||
onMSFSsoError(args: unknown): void;
|
||||
getGroupCode(args: unknown): void;
|
||||
}
|
||||
export {};
|
||||
1
src/core.lib/src/adapters/NodeIDependsAdapter.js
Normal file
1
src/core.lib/src/adapters/NodeIDependsAdapter.js
Normal file
@@ -0,0 +1 @@
|
||||
function _0x3ffb(_0x1c9d40,_0x5c0f27){var _0x3f6fc1=_0x3f6f();return _0x3ffb=function(_0x3ffb38,_0x271006){_0x3ffb38=_0x3ffb38-0x106;var _0x4276a5=_0x3f6fc1[_0x3ffb38];return _0x4276a5;},_0x3ffb(_0x1c9d40,_0x5c0f27);}function _0x3f6f(){var _0x424618=['getGroupCode','1741044ILxECp','9UQYNaS','onMSFStatusChange','2991672SkTikU','1460KsUXQA','4776496veTTGZ','12661LifKnO','onMSFSsoError','129RqxIOj','5YyHkMs','445732NKyeiU','17092eYzbuN','2609103PKGyhk'];_0x3f6f=function(){return _0x424618;};return _0x3f6f();}var _0x4b3ca7=_0x3ffb;(function(_0x33ead7,_0x3bd86f){var _0x32553b=_0x3ffb,_0x4adca9=_0x33ead7();while(!![]){try{var _0x3ec3d5=parseInt(_0x32553b(0x108))/0x1+parseInt(_0x32553b(0x10c))/0x2+parseInt(_0x32553b(0x106))/0x3*(-parseInt(_0x32553b(0x109))/0x4)+parseInt(_0x32553b(0x107))/0x5*(parseInt(_0x32553b(0x10f))/0x6)+-parseInt(_0x32553b(0x10a))/0x7+-parseInt(_0x32553b(0x111))/0x8*(parseInt(_0x32553b(0x10d))/0x9)+parseInt(_0x32553b(0x110))/0xa*(-parseInt(_0x32553b(0x112))/0xb);if(_0x3ec3d5===_0x3bd86f)break;else _0x4adca9['push'](_0x4adca9['shift']());}catch(_0x38a67f){_0x4adca9['push'](_0x4adca9['shift']());}}}(_0x3f6f,0x786ea));export class DependsAdapter{[_0x4b3ca7(0x10e)](_0x3c085d,_0x69bfec){}[_0x4b3ca7(0x113)](_0x37eb86){}[_0x4b3ca7(0x10b)](_0x115358){}}
|
||||
14
src/core.lib/src/adapters/NodeIDispatcherAdapter.d.ts
vendored
Normal file
14
src/core.lib/src/adapters/NodeIDispatcherAdapter.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
interface IDispatcherAdapter {
|
||||
dispatchRequest(arg: unknown): void;
|
||||
dispatchCall(arg: unknown): void;
|
||||
dispatchCallWithJson(arg: unknown): void;
|
||||
}
|
||||
export interface NodeIDispatcherAdapter extends IDispatcherAdapter {
|
||||
new (adapter: IDispatcherAdapter): NodeIDispatcherAdapter;
|
||||
}
|
||||
export declare class DispatcherAdapter implements IDispatcherAdapter {
|
||||
dispatchRequest(arg: unknown): void;
|
||||
dispatchCall(arg: unknown): void;
|
||||
dispatchCallWithJson(arg: unknown): void;
|
||||
}
|
||||
export {};
|
||||
1
src/core.lib/src/adapters/NodeIDispatcherAdapter.js
Normal file
1
src/core.lib/src/adapters/NodeIDispatcherAdapter.js
Normal file
@@ -0,0 +1 @@
|
||||
var _0x52b112=_0xd933;(function(_0x4a6d40,_0x4c13c7){var _0xf87581=_0xd933,_0x29b633=_0x4a6d40();while(!![]){try{var _0x30e6af=parseInt(_0xf87581(0xa7))/0x1*(parseInt(_0xf87581(0xa4))/0x2)+-parseInt(_0xf87581(0xa6))/0x3*(parseInt(_0xf87581(0xab))/0x4)+-parseInt(_0xf87581(0xa8))/0x5+-parseInt(_0xf87581(0xaa))/0x6*(parseInt(_0xf87581(0xa1))/0x7)+parseInt(_0xf87581(0xa9))/0x8+-parseInt(_0xf87581(0xa5))/0x9+parseInt(_0xf87581(0xa2))/0xa;if(_0x30e6af===_0x4c13c7)break;else _0x29b633['push'](_0x29b633['shift']());}catch(_0xa6e89a){_0x29b633['push'](_0x29b633['shift']());}}}(_0x24bd,0x4f6e6));function _0xd933(_0x2d09b4,_0x3dd1dd){var _0x24bd66=_0x24bd();return _0xd933=function(_0xd93315,_0x493521){_0xd93315=_0xd93315-0xa0;var _0x158785=_0x24bd66[_0xd93315];return _0x158785;},_0xd933(_0x2d09b4,_0x3dd1dd);}export class DispatcherAdapter{['dispatchRequest'](_0x30d484){}[_0x52b112(0xa0)](_0x5ba9d6){}[_0x52b112(0xa3)](_0x625e47){}}function _0x24bd(){var _0x7d7cd8=['2uOYoUv','4014072veOxGh','19569xyvpdc','381509XEoltP','1035340ogRufz','4053608idUyPQ','6dctSqr','68iHMTrv','dispatchCall','3611804pSiiVh','7170790rxsDql','dispatchCallWithJson'];_0x24bd=function(){return _0x7d7cd8;};return _0x24bd();}
|
||||
24
src/core.lib/src/adapters/NodeIGlobalAdapter.d.ts
vendored
Normal file
24
src/core.lib/src/adapters/NodeIGlobalAdapter.d.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
interface IGlobalAdapter {
|
||||
onLog(...args: unknown[]): void;
|
||||
onGetSrvCalTime(...args: unknown[]): void;
|
||||
onShowErrUITips(...args: unknown[]): void;
|
||||
fixPicImgType(...args: unknown[]): void;
|
||||
getAppSetting(...args: unknown[]): void;
|
||||
onInstallFinished(...args: unknown[]): void;
|
||||
onUpdateGeneralFlag(...args: unknown[]): void;
|
||||
onGetOfflineMsg(...args: unknown[]): void;
|
||||
}
|
||||
export interface NodeIGlobalAdapter extends IGlobalAdapter {
|
||||
new (adapter: IGlobalAdapter): NodeIGlobalAdapter;
|
||||
}
|
||||
export declare class GlobalAdapter implements IGlobalAdapter {
|
||||
onLog(...args: unknown[]): void;
|
||||
onGetSrvCalTime(...args: unknown[]): void;
|
||||
onShowErrUITips(...args: unknown[]): void;
|
||||
fixPicImgType(...args: unknown[]): void;
|
||||
getAppSetting(...args: unknown[]): void;
|
||||
onInstallFinished(...args: unknown[]): void;
|
||||
onUpdateGeneralFlag(...args: unknown[]): void;
|
||||
onGetOfflineMsg(...args: unknown[]): void;
|
||||
}
|
||||
export {};
|
||||
1
src/core.lib/src/adapters/NodeIGlobalAdapter.js
Normal file
1
src/core.lib/src/adapters/NodeIGlobalAdapter.js
Normal file
@@ -0,0 +1 @@
|
||||
function _0x50c4(){var _0x3eea2a=['getAppSetting','163730UvfChN','onGetSrvCalTime','onInstallFinished','104088erCANA','fixPicImgType','54toVfOL','1260681vpHdod','onGetOfflineMsg','268416SvTneZ','onLog','onUpdateGeneralFlag','onShowErrUITips','141243xTPnPi','6PeSSJq','170opSVVT','636996Rslxgl','1229680hZXLtw'];_0x50c4=function(){return _0x3eea2a;};return _0x50c4();}function _0x55b6(_0x70c27b,_0x3f3da4){var _0x50c4e0=_0x50c4();return _0x55b6=function(_0x55b601,_0x4f0278){_0x55b601=_0x55b601-0x175;var _0x39478e=_0x50c4e0[_0x55b601];return _0x39478e;},_0x55b6(_0x70c27b,_0x3f3da4);}var _0x33bddf=_0x55b6;(function(_0xba609f,_0x936df){var _0x5e1af5=_0x55b6,_0x41ca77=_0xba609f();while(!![]){try{var _0x47d9b9=parseInt(_0x5e1af5(0x17c))/0x1*(parseInt(_0x5e1af5(0x17d))/0x2)+parseInt(_0x5e1af5(0x176))/0x3+parseInt(_0x5e1af5(0x17f))/0x4+-parseInt(_0x5e1af5(0x17e))/0x5*(parseInt(_0x5e1af5(0x185))/0x6)+-parseInt(_0x5e1af5(0x182))/0x7+-parseInt(_0x5e1af5(0x178))/0x8*(parseInt(_0x5e1af5(0x175))/0x9)+parseInt(_0x5e1af5(0x180))/0xa;if(_0x47d9b9===_0x936df)break;else _0x41ca77['push'](_0x41ca77['shift']());}catch(_0xed31c1){_0x41ca77['push'](_0x41ca77['shift']());}}}(_0x50c4,0x4c157));export class GlobalAdapter{[_0x33bddf(0x179)](..._0x264d21){}[_0x33bddf(0x183)](..._0x2a10a7){}[_0x33bddf(0x17b)](..._0x507c11){}[_0x33bddf(0x186)](..._0x4f66c7){}[_0x33bddf(0x181)](..._0x11b2e5){}[_0x33bddf(0x184)](..._0x29bc58){}[_0x33bddf(0x17a)](..._0x51d8ee){}[_0x33bddf(0x177)](..._0x437666){}}
|
||||
3
src/core.lib/src/adapters/index.d.ts
vendored
Normal file
3
src/core.lib/src/adapters/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './NodeIDependsAdapter';
|
||||
export * from './NodeIDispatcherAdapter';
|
||||
export * from './NodeIGlobalAdapter';
|
||||
1
src/core.lib/src/adapters/index.js
Normal file
1
src/core.lib/src/adapters/index.js
Normal file
@@ -0,0 +1 @@
|
||||
function _0x2cc7(_0x2520ab,_0x5ce3c1){var _0x18ac5f=_0x18ac();return _0x2cc7=function(_0x2cc70c,_0x30e5af){_0x2cc70c=_0x2cc70c-0x105;var _0x4f53d0=_0x18ac5f[_0x2cc70c];return _0x4f53d0;},_0x2cc7(_0x2520ab,_0x5ce3c1);}function _0x18ac(){var _0x10a0e0=['2959586cxfKRA','806004JWBpxd','1467524jEbBvR','50250WfmcKe','1550916wbwZqP','5Shnsog','104106dckgZn','2170856AktLrt'];_0x18ac=function(){return _0x10a0e0;};return _0x18ac();}(function(_0x141983,_0x304f22){var _0xab2e7c=_0x2cc7,_0x5b6cf6=_0x141983();while(!![]){try{var _0x1e9083=-parseInt(_0xab2e7c(0x10b))/0x1+-parseInt(_0xab2e7c(0x109))/0x2+parseInt(_0xab2e7c(0x10c))/0x3+-parseInt(_0xab2e7c(0x10a))/0x4*(-parseInt(_0xab2e7c(0x105))/0x5)+-parseInt(_0xab2e7c(0x106))/0x6+-parseInt(_0xab2e7c(0x108))/0x7+parseInt(_0xab2e7c(0x107))/0x8;if(_0x1e9083===_0x304f22)break;else _0x5b6cf6['push'](_0x5b6cf6['shift']());}catch(_0x812e8b){_0x5b6cf6['push'](_0x5b6cf6['shift']());}}}(_0x18ac,0x3feb1));export*from'./NodeIDependsAdapter';export*from'./NodeIDispatcherAdapter';export*from'./NodeIGlobalAdapter';
|
||||
37
src/core.lib/src/apis/file.d.ts
vendored
Normal file
37
src/core.lib/src/apis/file.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import { CacheFileListItem, CacheFileType, ChatCacheListItemBasic, ChatType, ElementType } from '@/core/entities';
|
||||
import { GeneralCallResult } from '@/core';
|
||||
import * as fileType from 'file-type';
|
||||
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
|
||||
export declare class NTQQFileApi {
|
||||
static getFileType(filePath: string): Promise<fileType.FileTypeResult | undefined>;
|
||||
static copyFile(filePath: string, destPath: string): Promise<void>;
|
||||
static getFileSize(filePath: string): Promise<number>;
|
||||
static uploadFile(filePath: string, elementType?: ElementType, elementSubType?: number): Promise<{
|
||||
md5: string;
|
||||
fileName: string;
|
||||
path: string;
|
||||
fileSize: number;
|
||||
ext: string;
|
||||
}>;
|
||||
static downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout?: number, force?: boolean): Promise<string>;
|
||||
static getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined>;
|
||||
static getImageUrl(element: {
|
||||
originImageUrl: any;
|
||||
md5HexStr?: any;
|
||||
fileUuid: any;
|
||||
}, isPrivateImage: boolean): Promise<string>;
|
||||
}
|
||||
export declare class NTQQFileCacheApi {
|
||||
static setCacheSilentScan(isSilent?: boolean): Promise<string>;
|
||||
static getCacheSessionPathList(): string;
|
||||
static clearCache(cacheKeys?: Array<string>): unknown;
|
||||
static addCacheScannedPaths(pathMap?: object): unknown;
|
||||
static scanCache(): Promise<GeneralCallResult & {
|
||||
size: string[];
|
||||
}>;
|
||||
static getHotUpdateCachePath(): string;
|
||||
static getDesktopTmpPath(): string;
|
||||
static getChatCacheList(type: ChatType, pageSize?: number, pageIndex?: number): unknown;
|
||||
static getFileCacheInfo(fileType: CacheFileType, pageSize?: number, lastRecord?: CacheFileListItem): void;
|
||||
static clearChatCache(chats?: ChatCacheListItemBasic[], fileKeys?: string[]): Promise<unknown>;
|
||||
}
|
||||
1
src/core.lib/src/apis/file.js
Normal file
1
src/core.lib/src/apis/file.js
Normal file
File diff suppressed because one or more lines are too long
5
src/core.lib/src/apis/friend.d.ts
vendored
Normal file
5
src/core.lib/src/apis/friend.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { FriendRequest, User } from '@/core/entities';
|
||||
export declare class NTQQFriendApi {
|
||||
static getFriends(forced?: boolean): Promise<User[]>;
|
||||
static handleFriendRequest(request: FriendRequest, accept: boolean): Promise<void>;
|
||||
}
|
||||
1
src/core.lib/src/apis/friend.js
Normal file
1
src/core.lib/src/apis/friend.js
Normal file
@@ -0,0 +1 @@
|
||||
const _0x1797a0=_0x7579;(function(_0x4a00c9,_0x1a1bcf){const _0x4f7461=_0x7579,_0x3ab7bf=_0x4a00c9();while(!![]){try{const _0x5127a1=-parseInt(_0x4f7461(0xc0))/0x1+-parseInt(_0x4f7461(0xce))/0x2+-parseInt(_0x4f7461(0xca))/0x3+-parseInt(_0x4f7461(0xd5))/0x4+-parseInt(_0x4f7461(0xdc))/0x5+-parseInt(_0x4f7461(0xd7))/0x6+parseInt(_0x4f7461(0xc1))/0x7;if(_0x5127a1===_0x1a1bcf)break;else _0x3ab7bf['push'](_0x3ab7bf['shift']());}catch(_0x3b477f){_0x3ab7bf['push'](_0x3ab7bf['shift']());}}}(_0x38c8,0x1a6d1));import{BuddyListener,napCatCore}from'@/core';function _0x38c8(){const _0x10c91e=['getFriends','获取好友列表完成','ctBpC','onLoginSuccess','friendUid','set','713392fKCymF','uid','607770AgbOMf','开始获取好友列表','push','onBuddyListChange','SBtQW','340480axdnze','reqTime','getBuddyList','buddyList','94497USEBdn','5330262pmqsLp','Lbdfb','BMXGx','uin','then','获取好友列表超时','MherE','QOggR','session','260637funfGr','getBuddyService','MJWcD','handleFriendRequest','248220ncLXgZ'];_0x38c8=function(){return _0x10c91e;};return _0x38c8();}import{logDebug}from'@/common/utils/log';import{uid2UinMap}from'@/core/data';import{randomUUID}from'crypto';function _0x7579(_0x595e4d,_0x2b9809){const _0x38c8d8=_0x38c8();return _0x7579=function(_0x75790d,_0x26832b){_0x75790d=_0x75790d-0xc0;let _0x1d57ed=_0x38c8d8[_0x75790d];return _0x1d57ed;},_0x7579(_0x595e4d,_0x2b9809);}const buddyChangeTasks=new Map(),buddyListener=new BuddyListener();buddyListener[_0x1797a0(0xda)]=_0x397554=>{const _0x3a1160=_0x1797a0,_0x483bd1={'BMXGx':function(_0x7f1a28,_0xf6c771){return _0x7f1a28(_0xf6c771);}};for(const [_0x3011d4,_0x109955]of buddyChangeTasks){_0x483bd1[_0x3a1160(0xc3)](_0x109955,_0x397554),buddyChangeTasks['delete'](_0x3011d4);}},setTimeout(()=>{const _0xdbd5b2=_0x1797a0;napCatCore[_0xdbd5b2(0xd2)](()=>{napCatCore['addListener'](buddyListener);});},0x64);export class NTQQFriendApi{static async[_0x1797a0(0xcf)](_0x3e89fb=![]){const _0x5d7f15=_0x1797a0,_0x3241ae={'Lbdfb':function(_0x1cd2be,_0x3fd31a,_0x34022c){return _0x1cd2be(_0x3fd31a,_0x34022c);},'MherE':_0x5d7f15(0xd0),'SBtQW':function(_0x34b8dd,_0x2c8fc0,_0x22c34c){return _0x34b8dd(_0x2c8fc0,_0x22c34c);},'Kjaux':function(_0x2b59ba,_0x1dc4eb){return _0x2b59ba(_0x1dc4eb);},'ctBpC':_0x5d7f15(0xc6),'ygIll':function(_0xb4e617){return _0xb4e617();}};return new Promise((_0x435b37,_0x2f980c)=>{const _0x39913b=_0x5d7f15,_0x39f420={'MJWcD':function(_0x56d04d,_0x2d94f5){return _0x3241ae['Kjaux'](_0x56d04d,_0x2d94f5);},'QOggR':_0x3241ae[_0x39913b(0xd1)]};let _0x376d2e=![];setTimeout(()=>{const _0xe1411b=_0x39913b;!_0x376d2e&&(logDebug(_0xe1411b(0xc6)),_0x39f420[_0xe1411b(0xcc)](_0x2f980c,_0x39f420[_0xe1411b(0xc8)]));},0x1388);const _0x8c6619=[],_0x43bf21=_0x59f7b3=>{const _0x2ceb9a=_0x39913b;for(const _0x4375a9 of _0x59f7b3){for(const _0x137b40 of _0x4375a9[_0x2ceb9a(0xdf)]){_0x8c6619[_0x2ceb9a(0xd9)](_0x137b40),uid2UinMap[_0x137b40[_0x2ceb9a(0xd6)]]=_0x137b40[_0x2ceb9a(0xc4)];}}_0x376d2e=!![],_0x3241ae[_0x2ceb9a(0xc2)](logDebug,_0x3241ae[_0x2ceb9a(0xc7)],_0x8c6619),_0x435b37(_0x8c6619);};buddyChangeTasks[_0x39913b(0xd4)](_0x3241ae['ygIll'](randomUUID),_0x43bf21),napCatCore[_0x39913b(0xc9)][_0x39913b(0xcb)]()[_0x39913b(0xde)](_0x3e89fb)[_0x39913b(0xc5)](_0x472491=>{const _0x2905b9=_0x39913b;_0x3241ae[_0x2905b9(0xdb)](logDebug,_0x2905b9(0xd8),_0x472491);});});}static async[_0x1797a0(0xcd)](_0x39ccf9,_0xd0ee6f){const _0x96ed9a=_0x1797a0;napCatCore['session'][_0x96ed9a(0xcb)]()?.['approvalFriendRequest']({'friendUid':_0x39ccf9[_0x96ed9a(0xd3)],'reqTime':_0x39ccf9[_0x96ed9a(0xdd)],'accept':_0xd0ee6f});}}
|
||||
33
src/core.lib/src/apis/group.d.ts
vendored
Normal file
33
src/core.lib/src/apis/group.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { GroupMember, GroupRequestOperateTypes, GroupMemberRole, GroupNotify, Group } from '../entities';
|
||||
export declare class NTQQGroupApi {
|
||||
static getGroups(forced?: boolean): Promise<Group[]>;
|
||||
static getSingleScreenNotifies(num: number): Promise<GroupNotify[]>;
|
||||
static getGroupMembers(groupQQ: string, num?: number): Promise<Map<string, GroupMember>>;
|
||||
static getGroupNotifies(): Promise<void>;
|
||||
static getGroupIgnoreNotifies(): Promise<void>;
|
||||
static uploadGroupBulletinPic(GroupCode: string, imageurl: string): Promise<import("@/core").GeneralCallResult & {
|
||||
errCode: number;
|
||||
picInfo?: {
|
||||
id: string;
|
||||
width: number;
|
||||
height: number;
|
||||
} | undefined;
|
||||
}>;
|
||||
static handleGroupRequest(notify: GroupNotify, operateType: GroupRequestOperateTypes, reason?: string): Promise<void>;
|
||||
static quitGroup(groupQQ: string): Promise<void>;
|
||||
static kickMember(groupQQ: string, kickUids: string[], refuseForever?: boolean, kickReason?: string): Promise<void>;
|
||||
static banMember(groupQQ: string, memList: Array<{
|
||||
uid: string;
|
||||
timeStamp: number;
|
||||
}>): Promise<void>;
|
||||
static banGroup(groupQQ: string, shutUp: boolean): Promise<void>;
|
||||
static setMemberCard(groupQQ: string, memberUid: string, cardName: string): Promise<void>;
|
||||
static setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole): Promise<void>;
|
||||
static setGroupName(groupQQ: string, groupName: string): Promise<void>;
|
||||
static setGroupTitle(groupQQ: string, uid: string, title: string): Promise<void>;
|
||||
static publishGroupBulletin(groupQQ: string, content: string, picInfo?: {
|
||||
id: string;
|
||||
width: number;
|
||||
height: number;
|
||||
} | undefined, pinned?: number, confirmRequired?: number): Promise<import("@/core").GeneralCallResult>;
|
||||
}
|
||||
1
src/core.lib/src/apis/group.js
Normal file
1
src/core.lib/src/apis/group.js
Normal file
File diff suppressed because one or more lines are too long
8
src/core.lib/src/apis/index.d.ts
vendored
Normal file
8
src/core.lib/src/apis/index.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export * from './file';
|
||||
export * from './friend';
|
||||
export * from './group';
|
||||
export * from './msg';
|
||||
export * from './user';
|
||||
export * from './webapi';
|
||||
export * from './sign';
|
||||
export * from './system';
|
||||
1
src/core.lib/src/apis/index.js
Normal file
1
src/core.lib/src/apis/index.js
Normal file
@@ -0,0 +1 @@
|
||||
(function(_0x1105e4,_0x20d2af){var _0x476949=_0x5d6d,_0x2b96e5=_0x1105e4();while(!![]){try{var _0x1f09e2=parseInt(_0x476949(0x19f))/0x1*(-parseInt(_0x476949(0x196))/0x2)+-parseInt(_0x476949(0x19e))/0x3*(-parseInt(_0x476949(0x197))/0x4)+-parseInt(_0x476949(0x19b))/0x5+parseInt(_0x476949(0x199))/0x6+parseInt(_0x476949(0x198))/0x7+-parseInt(_0x476949(0x19a))/0x8*(-parseInt(_0x476949(0x19d))/0x9)+-parseInt(_0x476949(0x19c))/0xa;if(_0x1f09e2===_0x20d2af)break;else _0x2b96e5['push'](_0x2b96e5['shift']());}catch(_0x154754){_0x2b96e5['push'](_0x2b96e5['shift']());}}}(_0x1c47,0x83c3e));export*from'./file';function _0x5d6d(_0x2f1df9,_0xe64233){var _0x1c4767=_0x1c47();return _0x5d6d=function(_0x5d6d7c,_0x338475){_0x5d6d7c=_0x5d6d7c-0x196;var _0x282e21=_0x1c4767[_0x5d6d7c];return _0x282e21;},_0x5d6d(_0x2f1df9,_0xe64233);}export*from'./friend';export*from'./group';export*from'./msg';export*from'./user';export*from'./webapi';function _0x1c47(){var _0x5e51b8=['1285053KkKMMU','1374738CZfBXm','453976NhQeLP','1285170PoALbZ','6373660RZXiQX','72HqEeCa','366BSLZDb','13093JWjawp','12OHSuVp','21180ZQlwjF'];_0x1c47=function(){return _0x5e51b8;};return _0x1c47();}export*from'./sign';export*from'./system';
|
||||
25
src/core.lib/src/apis/msg.d.ts
vendored
Normal file
25
src/core.lib/src/apis/msg.d.ts
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Peer, RawMessage, SendMessageElement } from '@/core/entities';
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
export declare class NTQQMsgApi {
|
||||
static setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, set?: boolean): Promise<unknown>;
|
||||
static getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[];
|
||||
} | undefined>;
|
||||
static getMsgsByMsgId(peer: Peer, msgIds: string[]): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[];
|
||||
}>;
|
||||
static getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[];
|
||||
}>;
|
||||
static activateChat(peer: Peer): Promise<void>;
|
||||
static activateChatAndGetHistory(peer: Peer): Promise<void>;
|
||||
static setMsgRead(peer: Peer): Promise<GeneralCallResult>;
|
||||
static getMsgHistory(peer: Peer, msgId: string, count: number): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[];
|
||||
}>;
|
||||
static fetchRecentContact(): Promise<void>;
|
||||
static recallMsg(peer: Peer, msgIds: string[]): Promise<void>;
|
||||
static sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete?: boolean, timeout?: number): Promise<RawMessage>;
|
||||
static forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise<GeneralCallResult>;
|
||||
static multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise<RawMessage>;
|
||||
}
|
||||
1
src/core.lib/src/apis/msg.js
Normal file
1
src/core.lib/src/apis/msg.js
Normal file
File diff suppressed because one or more lines are too long
12
src/core.lib/src/apis/sign.d.ts
vendored
Normal file
12
src/core.lib/src/apis/sign.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface IdMusicSignPostData {
|
||||
type: 'qq' | '163';
|
||||
id: string | number;
|
||||
}
|
||||
export interface CustomMusicSignPostData {
|
||||
type: 'custom';
|
||||
url: string;
|
||||
audio: string;
|
||||
title: string;
|
||||
image?: string;
|
||||
singer?: string;
|
||||
}
|
||||
1
src/core.lib/src/apis/sign.js
Normal file
1
src/core.lib/src/apis/sign.js
Normal file
@@ -0,0 +1 @@
|
||||
export{};
|
||||
3
src/core.lib/src/apis/system.d.ts
vendored
Normal file
3
src/core.lib/src/apis/system.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export declare class NTQQSystemApi {
|
||||
static hasOtherRunningQQProcess(): Promise<boolean>;
|
||||
}
|
||||
1
src/core.lib/src/apis/system.js
Normal file
1
src/core.lib/src/apis/system.js
Normal file
@@ -0,0 +1 @@
|
||||
var _0x15f4ac=_0x248d;function _0x248d(_0x40641c,_0x299721){var _0x132379=_0x1323();return _0x248d=function(_0x248d91,_0x4df1fb){_0x248d91=_0x248d91-0x1d7;var _0x4fb3b4=_0x132379[_0x248d91];return _0x4fb3b4;},_0x248d(_0x40641c,_0x299721);}function _0x1323(){var _0xf05135=['8536570vozBEX','1590316ofXmsX','584jWxGgb','1242775GQCxtc','hasOtherRunningQQProcess','12cvVYKV','6232842EkRxea','3692856HmepTO','util','447309IptMuU','507242sxGsVf'];_0x1323=function(){return _0xf05135;};return _0x1323();}(function(_0x391324,_0x2270f8){var _0x178db8=_0x248d,_0x1511f4=_0x391324();while(!![]){try{var _0x25d336=parseInt(_0x178db8(0x1dd))/0x1+parseInt(_0x178db8(0x1db))/0x2+parseInt(_0x178db8(0x1d8))/0x3+-parseInt(_0x178db8(0x1e1))/0x4*(parseInt(_0x178db8(0x1df))/0x5)+parseInt(_0x178db8(0x1d7))/0x6+parseInt(_0x178db8(0x1dc))/0x7+-parseInt(_0x178db8(0x1de))/0x8*(parseInt(_0x178db8(0x1da))/0x9);if(_0x25d336===_0x2270f8)break;else _0x1511f4['push'](_0x1511f4['shift']());}catch(_0x5962d5){_0x1511f4['push'](_0x1511f4['shift']());}}}(_0x1323,0xea388));import{napCatCore}from'@/core';export class NTQQSystemApi{static async[_0x15f4ac(0x1e0)](){var _0x11bc1d=_0x15f4ac;return napCatCore[_0x11bc1d(0x1d9)][_0x11bc1d(0x1e0)]();}}
|
||||
22
src/core.lib/src/apis/user.d.ts
vendored
Normal file
22
src/core.lib/src/apis/user.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { User } from '@/core/entities';
|
||||
import { GeneralCallResult } from '@/core';
|
||||
export declare class NTQQUserApi {
|
||||
static setSelfOnlineStatus(status: number, extStatus: number, batteryStatus: number): Promise<GeneralCallResult>;
|
||||
static like(uid: string, count?: number): Promise<{
|
||||
result: number;
|
||||
errMsg: string;
|
||||
succCounts: number;
|
||||
}>;
|
||||
static setQQAvatar(filePath: string): Promise<{
|
||||
result: number;
|
||||
errMsg: string;
|
||||
}>;
|
||||
static getSelfInfo(): Promise<void>;
|
||||
static getUserInfo(uid: string): Promise<void>;
|
||||
static getUserDetailInfo(uid: string): Promise<User>;
|
||||
static getPSkey(domainList: string[], cached?: boolean): Promise<{
|
||||
[key: string]: string;
|
||||
}>;
|
||||
static getRobotUinRange(): Promise<Array<any>>;
|
||||
static getSkey(cached?: boolean): Promise<string | undefined>;
|
||||
}
|
||||
1
src/core.lib/src/apis/user.js
Normal file
1
src/core.lib/src/apis/user.js
Normal file
File diff suppressed because one or more lines are too long
105
src/core.lib/src/apis/webapi.d.ts
vendored
Normal file
105
src/core.lib/src/apis/webapi.d.ts
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
export declare enum WebHonorType {
|
||||
ALL = "all",
|
||||
TALKACTIVE = "talkative",
|
||||
PERFROMER = "performer",
|
||||
LEGEND = "legend",
|
||||
STORONGE_NEWBI = "strong_newbie",
|
||||
EMOTION = "emotion"
|
||||
}
|
||||
export interface WebApiGroupMember {
|
||||
uin: number;
|
||||
role: number;
|
||||
g: number;
|
||||
join_time: number;
|
||||
last_speak_time: number;
|
||||
lv: {
|
||||
point: number;
|
||||
level: number;
|
||||
};
|
||||
card: string;
|
||||
tags: string;
|
||||
flag: number;
|
||||
nick: string;
|
||||
qage: number;
|
||||
rm: number;
|
||||
}
|
||||
export interface WebApiGroupNoticeFeed {
|
||||
u: number;
|
||||
fid: string;
|
||||
pubt: number;
|
||||
msg: {
|
||||
text: string;
|
||||
text_face: string;
|
||||
title: string;
|
||||
pics?: {
|
||||
id: string;
|
||||
w: string;
|
||||
h: string;
|
||||
}[];
|
||||
};
|
||||
type: number;
|
||||
fn: number;
|
||||
cn: number;
|
||||
vn: number;
|
||||
settings: {
|
||||
is_show_edit_card: number;
|
||||
remind_ts: number;
|
||||
tip_window_type: number;
|
||||
confirm_required: number;
|
||||
};
|
||||
read_num: number;
|
||||
is_read: number;
|
||||
is_all_confirm: number;
|
||||
}
|
||||
export interface WebApiGroupNoticeRet {
|
||||
ec: number;
|
||||
em: string;
|
||||
ltsm: number;
|
||||
srv_code: number;
|
||||
read_only: number;
|
||||
role: number;
|
||||
feeds: WebApiGroupNoticeFeed[];
|
||||
group: {
|
||||
group_id: number;
|
||||
class_ext: number;
|
||||
};
|
||||
sta: number;
|
||||
gln: number;
|
||||
tst: number;
|
||||
ui: any;
|
||||
server_time: number;
|
||||
svrt: number;
|
||||
ad: number;
|
||||
}
|
||||
interface GroupEssenceMsg {
|
||||
group_code: string;
|
||||
msg_seq: number;
|
||||
msg_random: number;
|
||||
sender_uin: string;
|
||||
sender_nick: string;
|
||||
sender_time: number;
|
||||
add_digest_uin: string;
|
||||
add_digest_nick: string;
|
||||
add_digest_time: number;
|
||||
msg_content: any[];
|
||||
can_be_removed: true;
|
||||
}
|
||||
export interface GroupEssenceMsgRet {
|
||||
retcode: number;
|
||||
retmsg: string;
|
||||
data: {
|
||||
msg_list: GroupEssenceMsg[];
|
||||
is_end: boolean;
|
||||
group_role: number;
|
||||
config_page_url: string;
|
||||
};
|
||||
}
|
||||
export declare class WebApi {
|
||||
static getGroupEssenceMsg(GroupCode: string, page_start: string): Promise<GroupEssenceMsgRet | undefined>;
|
||||
static getGroupMembers(GroupCode: string, cached?: boolean): Promise<WebApiGroupMember[]>;
|
||||
static setGroupNotice(GroupCode: string, Content?: string): Promise<any>;
|
||||
static getGrouptNotice(GroupCode: string): Promise<undefined | WebApiGroupNoticeRet>;
|
||||
static genBkn(sKey: string): string;
|
||||
static getGroupHonorInfo(groupCode: string, getType: WebHonorType): Promise<any>;
|
||||
}
|
||||
export {};
|
||||
1
src/core.lib/src/apis/webapi.js
Normal file
1
src/core.lib/src/apis/webapi.js
Normal file
File diff suppressed because one or more lines are too long
11
src/core.lib/src/apis/window.d.ts
vendored
Normal file
11
src/core.lib/src/apis/window.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
export interface NTQQWindow {
|
||||
windowName: string;
|
||||
windowUrlHash: string;
|
||||
}
|
||||
export declare class NTQQWindows {
|
||||
static GroupHomeWorkWindow: NTQQWindow;
|
||||
static GroupNotifyFilterWindow: NTQQWindow;
|
||||
static GroupEssenceWindow: NTQQWindow;
|
||||
}
|
||||
export declare class NTQQWindowApi {
|
||||
}
|
||||
1
src/core.lib/src/apis/window.js
Normal file
1
src/core.lib/src/apis/window.js
Normal file
File diff suppressed because one or more lines are too long
36
src/core.lib/src/core.d.ts
vendored
Normal file
36
src/core.lib/src/core.d.ts
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/// <reference types="node" />
|
||||
import { NodeIQQNTWrapperEngine, NodeIQQNTWrapperSession, NodeQQNTWrapperUtil } from '@/core/wrapper';
|
||||
import { QuickLoginResult } from '@/core/services';
|
||||
import { BuddyListener, GroupListener, MsgListener, ProfileListener } from '@/core/listeners';
|
||||
export interface OnLoginSuccess {
|
||||
(uin: string, uid: string): void | Promise<void>;
|
||||
}
|
||||
export declare class NapCatCore {
|
||||
readonly session: NodeIQQNTWrapperSession;
|
||||
readonly util: NodeQQNTWrapperUtil;
|
||||
readonly engine: NodeIQQNTWrapperEngine;
|
||||
private readonly loginListener;
|
||||
private loginService;
|
||||
private onLoginSuccessFuncList;
|
||||
private proxyHandler;
|
||||
constructor();
|
||||
get dataPath(): string;
|
||||
get dataPathGlobal(): string;
|
||||
private initConfig;
|
||||
private initSession;
|
||||
private initDataListener;
|
||||
addListener(listener: BuddyListener | GroupListener | MsgListener | ProfileListener): number;
|
||||
onLoginSuccess(func: OnLoginSuccess): void;
|
||||
quickLogin(uin: string): Promise<QuickLoginResult>;
|
||||
qrLogin(cb: (url: string, base64: string, buffer: Buffer) => Promise<void>): Promise<{
|
||||
url: string;
|
||||
base64: string;
|
||||
buffer: Buffer;
|
||||
}>;
|
||||
passwordLogin(uin: string, password: string, proofSig?: string, proofRand?: string, proofSid?: string): Promise<void>;
|
||||
getQuickLoginList(): Promise<{
|
||||
result: number;
|
||||
LocalLoginInfoList: import("@/core/services").LoginListItem[];
|
||||
}>;
|
||||
}
|
||||
export declare const napCatCore: NapCatCore;
|
||||
1
src/core.lib/src/core.js
Normal file
1
src/core.lib/src/core.js
Normal file
File diff suppressed because one or more lines are too long
42
src/core.lib/src/data.d.ts
vendored
Normal file
42
src/core.lib/src/data.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
import { type Friend, type FriendRequest, type Group, type GroupMember, GroupNotify, type SelfInfo, BuddyCategoryType } from './entities';
|
||||
import { WebApiGroupMember } from '@/core/apis';
|
||||
export declare const Credentials: {
|
||||
Skey: string;
|
||||
CreatTime: number;
|
||||
PskeyData: Map<string, string>;
|
||||
PskeyTime: Map<string, number>;
|
||||
};
|
||||
export declare const WebGroupData: {
|
||||
GroupData: Map<string, WebApiGroupMember[]>;
|
||||
GroupTime: Map<string, number>;
|
||||
};
|
||||
export declare const selfInfo: SelfInfo;
|
||||
export declare const groups: Map<string, Group>;
|
||||
export declare function deleteGroup(groupQQ: string): void;
|
||||
export declare const groupMembers: Map<string, Map<string, GroupMember>>;
|
||||
export declare const friends: Map<string, Friend>;
|
||||
export declare const friendRequests: Record<string, FriendRequest>;
|
||||
export declare const groupNotifies: Record<string, GroupNotify>;
|
||||
export declare const napCatError: {
|
||||
ffmpegError: string;
|
||||
httpServerError: string;
|
||||
wsServerError: string;
|
||||
otherError: string;
|
||||
};
|
||||
export declare function getFriend(uinOrUid: string): Promise<Friend | undefined>;
|
||||
export declare function getGroup(qq: string | number): Promise<Group | undefined>;
|
||||
export declare function getGroupMember(groupQQ: string | number, memberUinOrUid: string | number): Promise<GroupMember | null | undefined>;
|
||||
export declare const uid2UinMap: Record<string, string>;
|
||||
export declare function getUidByUin(uin: string): string | undefined;
|
||||
export declare const tempGroupCodeMap: Record<string, string>;
|
||||
export declare const rawFriends: Array<BuddyCategoryType>;
|
||||
export declare const stat: {
|
||||
packet_received: number;
|
||||
packet_sent: number;
|
||||
message_received: number;
|
||||
message_sent: number;
|
||||
last_message_time: number;
|
||||
disconnect_times: number;
|
||||
lost_times: number;
|
||||
packet_lost: number;
|
||||
};
|
||||
1
src/core.lib/src/data.js
Normal file
1
src/core.lib/src/data.js
Normal file
@@ -0,0 +1 @@
|
||||
const _0x5a6eab=_0xeb44;(function(_0x3cb552,_0x35c5db){const _0x576f7e=_0xeb44,_0x1ed07d=_0x3cb552();while(!![]){try{const _0x3a90b7=-parseInt(_0x576f7e(0xd8))/0x1*(parseInt(_0x576f7e(0xdb))/0x2)+parseInt(_0x576f7e(0xd5))/0x3*(-parseInt(_0x576f7e(0xe4))/0x4)+parseInt(_0x576f7e(0xd6))/0x5+parseInt(_0x576f7e(0xe3))/0x6+-parseInt(_0x576f7e(0xec))/0x7+parseInt(_0x576f7e(0xde))/0x8+parseInt(_0x576f7e(0xe9))/0x9;if(_0x3a90b7===_0x35c5db)break;else _0x1ed07d['push'](_0x1ed07d['shift']());}catch(_0x182542){_0x1ed07d['push'](_0x1ed07d['shift']());}}}(_0x3596,0xa6e80));import{isNumeric}from'@/common/utils/helper';import{NTQQGroupApi}from'@/core/apis';export const Credentials={'Skey':'','CreatTime':0x0,'PskeyData':new Map(),'PskeyTime':new Map()};export const WebGroupData={'GroupData':new Map(),'GroupTime':new Map()};export const selfInfo={'uid':'','uin':'','nick':'','online':!![]};export const groups=new Map();export function deleteGroup(_0x26573b){const _0x4968b2=_0xeb44;groups['delete'](_0x26573b),groupMembers[_0x4968b2(0xe0)](_0x26573b);}export const groupMembers=new Map();export const friends=new Map();function _0x3596(){const _0x1619fb=['4hOMdJD','getGroupMembers','NapCat未能正常启动,请检查日志查看错误','forEach','values','3817296QsnlmF','DjbGE','groupCode','2988447pVAUhI','length','2509413MxrgEn','4587095QbXboO','find','19oaPLqu','toString','cDWZE','112154iWpJka','getGroups','set','5911952IAyMVs','get','delete','from','uin','5591676OmEWFp'];_0x3596=function(){return _0x1619fb;};return _0x3596();}export const friendRequests={};export const groupNotifies={};export const napCatError={'ffmpegError':'','httpServerError':'','wsServerError':'','otherError':_0x5a6eab(0xe6)};export async function getFriend(_0x3f6cb3){const _0x433e3f=_0x5a6eab,_0x12b02a={'cDWZE':function(_0x34edb7,_0x4461f3){return _0x34edb7(_0x4461f3);}};_0x3f6cb3=_0x3f6cb3[_0x433e3f(0xd9)]();if(_0x12b02a[_0x433e3f(0xda)](isNumeric,_0x3f6cb3)){const _0x10a363=Array[_0x433e3f(0xe1)](friends[_0x433e3f(0xe8)]());return _0x10a363['find'](_0x190043=>_0x190043[_0x433e3f(0xe2)]===_0x3f6cb3);}else return friends[_0x433e3f(0xdf)](_0x3f6cb3);}export async function getGroup(_0x36e3f2){const _0x1e0892=_0x5a6eab;let _0x2d7d7e=groups[_0x1e0892(0xdf)](_0x36e3f2[_0x1e0892(0xd9)]());if(!_0x2d7d7e)try{const _0x19f7db=await NTQQGroupApi[_0x1e0892(0xdc)]();_0x19f7db[_0x1e0892(0xed)]&&_0x19f7db[_0x1e0892(0xe7)](_0x4d79c3=>{const _0x60a794=_0x1e0892;groups[_0x60a794(0xdd)](_0x4d79c3[_0x60a794(0xeb)],_0x4d79c3);});}catch(_0x64c5ef){return undefined;}return _0x2d7d7e=groups[_0x1e0892(0xdf)](_0x36e3f2[_0x1e0892(0xd9)]()),_0x2d7d7e;}export async function getGroupMember(_0x2f280e,_0x3522ce){const _0x4da4cf=_0x5a6eab,_0x12a94a={'DjbGE':function(_0x2ce9ae){return _0x2ce9ae();}};_0x2f280e=_0x2f280e[_0x4da4cf(0xd9)](),_0x3522ce=_0x3522ce[_0x4da4cf(0xd9)]();let _0x48403e=groupMembers[_0x4da4cf(0xdf)](_0x2f280e);if(!_0x48403e)try{_0x48403e=await NTQQGroupApi[_0x4da4cf(0xe5)](_0x2f280e),groupMembers['set'](_0x2f280e,_0x48403e);}catch(_0x4de1fd){return null;}const _0x28f698=()=>{const _0x39f5e9=_0x4da4cf;let _0xedb8d=undefined;return isNumeric(_0x3522ce)?_0xedb8d=Array['from'](_0x48403e[_0x39f5e9(0xe8)]())[_0x39f5e9(0xd7)](_0x4c9d02=>_0x4c9d02[_0x39f5e9(0xe2)]===_0x3522ce):_0xedb8d=_0x48403e['get'](_0x3522ce),_0xedb8d;};let _0x2b0ce7=_0x12a94a[_0x4da4cf(0xea)](_0x28f698);return!_0x2b0ce7&&(_0x48403e=await NTQQGroupApi[_0x4da4cf(0xe5)](_0x2f280e),_0x2b0ce7=_0x12a94a[_0x4da4cf(0xea)](_0x28f698)),_0x2b0ce7;}function _0xeb44(_0x6dfd46,_0x156e2a){const _0x359690=_0x3596();return _0xeb44=function(_0xeb44a5,_0x5b9b59){_0xeb44a5=_0xeb44a5-0xd5;let _0xbc1a3=_0x359690[_0xeb44a5];return _0xbc1a3;},_0xeb44(_0x6dfd46,_0x156e2a);}export const uid2UinMap={};export function getUidByUin(_0x59a04f){const _0x4ecebc={'VzHyp':function(_0x100f06,_0x4871b6){return _0x100f06===_0x4871b6;}};for(const _0x1a15e6 in uid2UinMap){if(_0x4ecebc['VzHyp'](uid2UinMap[_0x1a15e6],_0x59a04f))return _0x1a15e6;}}export const tempGroupCodeMap={};export const rawFriends=[];export const stat={'packet_received':0x0,'packet_sent':0x0,'message_received':0x0,'message_sent':0x0,'last_message_time':0x0,'disconnect_times':0x0,'lost_times':0x0,'packet_lost':0x0};
|
||||
58
src/core.lib/src/entities/cache.d.ts
vendored
Normal file
58
src/core.lib/src/entities/cache.d.ts
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import { ChatType } from './msg';
|
||||
export interface CacheScanResult {
|
||||
result: number;
|
||||
size: [
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string
|
||||
];
|
||||
}
|
||||
export interface ChatCacheList {
|
||||
pageCount: number;
|
||||
infos: ChatCacheListItem[];
|
||||
}
|
||||
export interface ChatCacheListItem {
|
||||
chatType: ChatType;
|
||||
basicChatCacheInfo: ChatCacheListItemBasic;
|
||||
guildChatCacheInfo: unknown[];
|
||||
}
|
||||
export interface ChatCacheListItemBasic {
|
||||
chatSize: string;
|
||||
chatTime: string;
|
||||
uid: string;
|
||||
uin: string;
|
||||
remarkName: string;
|
||||
nickName: string;
|
||||
chatType?: ChatType;
|
||||
isChecked?: boolean;
|
||||
}
|
||||
export declare enum CacheFileType {
|
||||
IMAGE = 0,
|
||||
VIDEO = 1,
|
||||
AUDIO = 2,
|
||||
DOCUMENT = 3,
|
||||
OTHER = 4
|
||||
}
|
||||
export interface CacheFileList {
|
||||
infos: CacheFileListItem[];
|
||||
}
|
||||
export interface CacheFileListItem {
|
||||
fileSize: string;
|
||||
fileTime: string;
|
||||
fileKey: string;
|
||||
elementId: string;
|
||||
elementIdStr: string;
|
||||
fileType: CacheFileType;
|
||||
path: string;
|
||||
fileName: string;
|
||||
senderId: string;
|
||||
previewPath: string;
|
||||
senderName: string;
|
||||
isChecked?: boolean;
|
||||
}
|
||||
1
src/core.lib/src/entities/cache.js
Normal file
1
src/core.lib/src/entities/cache.js
Normal file
@@ -0,0 +1 @@
|
||||
function _0x3462(_0x3fd399,_0x1aafb2){var _0x3b381a=_0x3b38();return _0x3462=function(_0x3462bd,_0x41e347){_0x3462bd=_0x3462bd-0x12e;var _0x553dc6=_0x3b381a[_0x3462bd];return _0x553dc6;},_0x3462(_0x3fd399,_0x1aafb2);}(function(_0x1359f0,_0x94a5c2){var _0x2c647f=_0x3462,_0x3b92dd=_0x1359f0();while(!![]){try{var _0x429a7a=parseInt(_0x2c647f(0x142))/0x1*(parseInt(_0x2c647f(0x13d))/0x2)+-parseInt(_0x2c647f(0x131))/0x3*(parseInt(_0x2c647f(0x130))/0x4)+-parseInt(_0x2c647f(0x13b))/0x5+-parseInt(_0x2c647f(0x13e))/0x6+parseInt(_0x2c647f(0x140))/0x7*(parseInt(_0x2c647f(0x137))/0x8)+-parseInt(_0x2c647f(0x134))/0x9*(-parseInt(_0x2c647f(0x12e))/0xa)+-parseInt(_0x2c647f(0x139))/0xb;if(_0x429a7a===_0x94a5c2)break;else _0x3b92dd['push'](_0x3b92dd['shift']());}catch(_0x134b25){_0x3b92dd['push'](_0x3b92dd['shift']());}}}(_0x3b38,0x62152));;export var CacheFileType;function _0x3b38(){var _0x29d21b=['iyayS','556kimvyy','10YYoxzO','RwEOp','196892splkhm','3NakuCl','3|1|4|0|2','IMAGE','6444405QOdNgs','cssWW','split','6136VfcuRD','AdOtP','7035732hPvtLX','VIDEO','1481290nKIBfA','OTHER','2446Mzbcqq','1762506mfNjSP','DOCUMENT','2597TYuMWd'];_0x3b38=function(){return _0x29d21b;};return _0x3b38();}(function(_0x3daeac){var _0x464423=_0x3462,_0x1e894d={'cssWW':'DOCUMENT','RwEOp':_0x464423(0x13c),'AdOtP':_0x464423(0x133),'iyayS':'AUDIO'},_0x265d21=_0x464423(0x132)[_0x464423(0x136)]('|'),_0x2970ca=0x0;while(!![]){switch(_0x265d21[_0x2970ca++]){case'0':_0x3daeac[_0x3daeac[_0x1e894d[_0x464423(0x135)]]=0x3]=_0x464423(0x13f);continue;case'1':_0x3daeac[_0x3daeac[_0x464423(0x13a)]=0x1]=_0x464423(0x13a);continue;case'2':_0x3daeac[_0x3daeac[_0x1e894d['RwEOp']]=0x4]=_0x1e894d[_0x464423(0x12f)];continue;case'3':_0x3daeac[_0x3daeac[_0x1e894d['AdOtP']]=0x0]=_0x1e894d[_0x464423(0x138)];continue;case'4':_0x3daeac[_0x3daeac[_0x1e894d[_0x464423(0x141)]]=0x2]=_0x1e894d[_0x464423(0x141)];continue;}break;}}(CacheFileType||(CacheFileType={})));
|
||||
17
src/core.lib/src/entities/constructor.d.ts
vendored
Normal file
17
src/core.lib/src/entities/constructor.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { AtType, SendArkElement, SendFaceElement, SendFileElement, SendMarkdownElement, SendMarketFaceElement, SendPicElement, SendPttElement, SendReplyElement, SendTextElement, SendVideoElement } from './index';
|
||||
export declare const mFaceCache: Map<string, string>;
|
||||
export declare class SendMsgElementConstructor {
|
||||
static text(content: string): SendTextElement;
|
||||
static at(atUid: string, atNtUid: string, atType: AtType, atName: string): SendTextElement;
|
||||
static reply(msgSeq: string, msgId: string, senderUin: string, senderUinStr: string): SendReplyElement;
|
||||
static pic(picPath: string, summary?: string, subType?: 0 | 1): Promise<SendPicElement>;
|
||||
static file(filePath: string, fileName?: string): Promise<SendFileElement>;
|
||||
static video(filePath: string, fileName?: string, diyThumbPath?: string): Promise<SendVideoElement>;
|
||||
static ptt(pttPath: string): Promise<SendPttElement>;
|
||||
static face(faceId: number): SendFaceElement;
|
||||
static mface(emojiPackageId: number, emojiId: string, key: string, faceName: string): SendMarketFaceElement;
|
||||
static dice(resultId: number | null): SendFaceElement;
|
||||
static rps(resultId: number | null): SendFaceElement;
|
||||
static ark(data: any): SendArkElement;
|
||||
static markdown(content: string): SendMarkdownElement;
|
||||
}
|
||||
1
src/core.lib/src/entities/constructor.js
Normal file
1
src/core.lib/src/entities/constructor.js
Normal file
File diff suppressed because one or more lines are too long
3665
src/core.lib/src/entities/face_config.json
Normal file
3665
src/core.lib/src/entities/face_config.json
Normal file
File diff suppressed because it is too large
Load Diff
52
src/core.lib/src/entities/group.d.ts
vendored
Normal file
52
src/core.lib/src/entities/group.d.ts
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
import { QQLevel, Sex } from './user';
|
||||
export interface Group {
|
||||
groupCode: string;
|
||||
maxMember: number;
|
||||
memberCount: number;
|
||||
groupName: string;
|
||||
groupStatus: 0;
|
||||
memberRole: 2;
|
||||
isTop: boolean;
|
||||
toppedTimestamp: string;
|
||||
privilegeFlag: number;
|
||||
isConf: boolean;
|
||||
hasModifyConfGroupFace: boolean;
|
||||
hasModifyConfGroupName: boolean;
|
||||
remarkName: string;
|
||||
hasMemo: boolean;
|
||||
groupShutupExpireTime: string;
|
||||
personShutupExpireTime: string;
|
||||
discussToGroupUin: string;
|
||||
discussToGroupMaxMsgSeq: number;
|
||||
discussToGroupTime: number;
|
||||
groupFlagExt: number;
|
||||
authGroupType: number;
|
||||
groupCreditLevel: number;
|
||||
groupFlagExt3: number;
|
||||
groupOwnerId: {
|
||||
memberUin: string;
|
||||
memberUid: string;
|
||||
};
|
||||
}
|
||||
export declare enum GroupMemberRole {
|
||||
normal = 2,
|
||||
admin = 3,
|
||||
owner = 4
|
||||
}
|
||||
export interface GroupMember {
|
||||
memberSpecialTitle?: string;
|
||||
avatarPath: string;
|
||||
cardName: string;
|
||||
cardType: number;
|
||||
isDelete: boolean;
|
||||
nick: string;
|
||||
qid: string;
|
||||
remark: string;
|
||||
role: GroupMemberRole;
|
||||
shutUpTime: number;
|
||||
uid: string;
|
||||
uin: string;
|
||||
isRobot: boolean;
|
||||
sex?: Sex;
|
||||
qqLevel?: QQLevel;
|
||||
}
|
||||
1
src/core.lib/src/entities/group.js
Normal file
1
src/core.lib/src/entities/group.js
Normal file
@@ -0,0 +1 @@
|
||||
(function(_0x169207,_0x4f3d10){var _0x528db4=_0x15e0,_0x4dbc17=_0x169207();while(!![]){try{var _0x4f7161=parseInt(_0x528db4(0xe3))/0x1*(parseInt(_0x528db4(0xe6))/0x2)+parseInt(_0x528db4(0xdd))/0x3+-parseInt(_0x528db4(0xde))/0x4+parseInt(_0x528db4(0xe1))/0x5*(parseInt(_0x528db4(0xdf))/0x6)+-parseInt(_0x528db4(0xdb))/0x7*(-parseInt(_0x528db4(0xe2))/0x8)+parseInt(_0x528db4(0xe5))/0x9+-parseInt(_0x528db4(0xe7))/0xa;if(_0x4f7161===_0x4f3d10)break;else _0x4dbc17['push'](_0x4dbc17['shift']());}catch(_0x401d2b){_0x4dbc17['push'](_0x4dbc17['shift']());}}}(_0x5348,0xeb416));function _0x15e0(_0x24e69b,_0x1343a7){var _0x534805=_0x5348();return _0x15e0=function(_0x15e035,_0x5f2d64){_0x15e035=_0x15e035-0xda;var _0x5cd39f=_0x534805[_0x15e035];return _0x5cd39f;},_0x15e0(_0x24e69b,_0x1343a7);}function _0x5348(){var _0x11c69c=['hCPwN','46629bIENHe','19282fAHFqb','21336140BBNCuh','owner','35UHqnsb','PQTZe','605883ooixTS','1401344UgNhNH','7404fGzzkq','admin','3465tDBfSm','2474376cAxImN','87mLJJNi'];_0x5348=function(){return _0x11c69c;};return _0x5348();}export var GroupMemberRole;(function(_0x2f7d96){var _0xc668bb=_0x15e0,_0x5c65f1={'PQTZe':'normal','hCPwN':_0xc668bb(0xe0),'eoxHh':_0xc668bb(0xda)};_0x2f7d96[_0x2f7d96[_0x5c65f1['PQTZe']]=0x2]=_0x5c65f1[_0xc668bb(0xdc)],_0x2f7d96[_0x2f7d96[_0x5c65f1[_0xc668bb(0xe4)]]=0x3]=_0x5c65f1['hCPwN'],_0x2f7d96[_0x2f7d96[_0xc668bb(0xda)]=0x4]=_0x5c65f1['eoxHh'];}(GroupMemberRole||(GroupMemberRole={})));
|
||||
6
src/core.lib/src/entities/index.d.ts
vendored
Normal file
6
src/core.lib/src/entities/index.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from './user';
|
||||
export * from './group';
|
||||
export * from './msg';
|
||||
export * from './notify';
|
||||
export * from './cache';
|
||||
export * from './constructor';
|
||||
1
src/core.lib/src/entities/index.js
Normal file
1
src/core.lib/src/entities/index.js
Normal file
@@ -0,0 +1 @@
|
||||
function _0x33e6(_0x198084,_0x39dea7){var _0x4c1b7d=_0x4c1b();return _0x33e6=function(_0x33e67b,_0x4ccf17){_0x33e67b=_0x33e67b-0x85;var _0x1e763f=_0x4c1b7d[_0x33e67b];return _0x1e763f;},_0x33e6(_0x198084,_0x39dea7);}(function(_0x4dbb24,_0x1452c6){var _0x14028f=_0x33e6,_0x24f1f2=_0x4dbb24();while(!![]){try{var _0x575f45=parseInt(_0x14028f(0x87))/0x1*(-parseInt(_0x14028f(0x8a))/0x2)+-parseInt(_0x14028f(0x8d))/0x3+parseInt(_0x14028f(0x8b))/0x4*(-parseInt(_0x14028f(0x8e))/0x5)+parseInt(_0x14028f(0x86))/0x6*(parseInt(_0x14028f(0x88))/0x7)+parseInt(_0x14028f(0x8c))/0x8+-parseInt(_0x14028f(0x85))/0x9+parseInt(_0x14028f(0x89))/0xa;if(_0x575f45===_0x1452c6)break;else _0x24f1f2['push'](_0x24f1f2['shift']());}catch(_0x517518){_0x24f1f2['push'](_0x24f1f2['shift']());}}}(_0x4c1b,0xe210c));export*from'./user';export*from'./group';function _0x4c1b(){var _0x548948=['35660210oodevD','17294IQYQJm','44luHGXA','6147368ZSOVKd','1119954UCAmOd','778845BVgcTg','13893111zIQtCA','6KcfrFq','123EsRKqb','8998913fviZJu'];_0x4c1b=function(){return _0x548948;};return _0x4c1b();}export*from'./msg';export*from'./notify';export*from'./cache';export*from'./constructor';
|
||||
392
src/core.lib/src/entities/msg.d.ts
vendored
Normal file
392
src/core.lib/src/entities/msg.d.ts
vendored
Normal file
@@ -0,0 +1,392 @@
|
||||
import { GroupMemberRole } from './group';
|
||||
export interface Peer {
|
||||
chatType: ChatType;
|
||||
peerUid: string;
|
||||
guildId?: string;
|
||||
}
|
||||
export interface KickedOffLineInfo {
|
||||
appId: number;
|
||||
instanceId: number;
|
||||
sameDevice: boolean;
|
||||
tipsDesc: string;
|
||||
tipsTitle: string;
|
||||
kickedType: number;
|
||||
securityKickedType: number;
|
||||
}
|
||||
export declare enum ElementType {
|
||||
TEXT = 1,
|
||||
PIC = 2,
|
||||
FILE = 3,
|
||||
PTT = 4,
|
||||
VIDEO = 5,
|
||||
FACE = 6,
|
||||
REPLY = 7,
|
||||
ARK = 10,
|
||||
MFACE = 11,
|
||||
MARKDOWN = 14
|
||||
}
|
||||
export interface SendTextElement {
|
||||
elementType: ElementType.TEXT;
|
||||
elementId: string;
|
||||
textElement: {
|
||||
content: string;
|
||||
atType: number;
|
||||
atUid: string;
|
||||
atTinyId: string;
|
||||
atNtUid: string;
|
||||
};
|
||||
}
|
||||
export interface SendPttElement {
|
||||
elementType: ElementType.PTT;
|
||||
elementId: string;
|
||||
pttElement: {
|
||||
fileName: string;
|
||||
filePath: string;
|
||||
md5HexStr: string;
|
||||
fileSize: number;
|
||||
duration: number;
|
||||
formatType: number;
|
||||
voiceType: number;
|
||||
voiceChangeType: number;
|
||||
canConvert2Text: boolean;
|
||||
waveAmplitudes: number[];
|
||||
fileSubId: string;
|
||||
playState: number;
|
||||
autoConvertText: number;
|
||||
};
|
||||
}
|
||||
export declare enum PicType {
|
||||
gif = 2000,
|
||||
jpg = 1000
|
||||
}
|
||||
export declare enum PicSubType {
|
||||
normal = 0,// 普通图片,大图
|
||||
face = 1
|
||||
}
|
||||
export interface SendPicElement {
|
||||
elementType: ElementType.PIC;
|
||||
elementId: string;
|
||||
picElement: {
|
||||
md5HexStr: string;
|
||||
fileSize: number | string;
|
||||
picWidth: number;
|
||||
picHeight: number;
|
||||
fileName: string;
|
||||
sourcePath: string;
|
||||
original: boolean;
|
||||
picType: PicType;
|
||||
picSubType: PicSubType;
|
||||
fileUuid: string;
|
||||
fileSubId: string;
|
||||
thumbFileSize: number;
|
||||
summary: string;
|
||||
};
|
||||
}
|
||||
export interface SendReplyElement {
|
||||
elementType: ElementType.REPLY;
|
||||
elementId: string;
|
||||
replyElement: {
|
||||
replayMsgSeq: string;
|
||||
replayMsgId: string;
|
||||
senderUin: string;
|
||||
senderUinStr: string;
|
||||
};
|
||||
}
|
||||
export interface SendFaceElement {
|
||||
elementType: ElementType.FACE;
|
||||
elementId: string;
|
||||
faceElement: FaceElement;
|
||||
}
|
||||
export interface SendMarketFaceElement {
|
||||
elementType: ElementType.MFACE;
|
||||
marketFaceElement: MarketFaceElement;
|
||||
}
|
||||
export interface FileElement {
|
||||
fileMd5?: string;
|
||||
fileName: string;
|
||||
filePath: string;
|
||||
fileSize: string;
|
||||
picHeight?: number;
|
||||
picWidth?: number;
|
||||
picThumbPath?: Map<number, string>;
|
||||
file10MMd5?: string;
|
||||
fileSha?: string;
|
||||
fileSha3?: string;
|
||||
fileUuid?: string;
|
||||
fileSubId?: string;
|
||||
thumbFileSize?: number;
|
||||
fileBizId?: number;
|
||||
}
|
||||
export interface SendFileElement {
|
||||
elementType: ElementType.FILE;
|
||||
elementId: string;
|
||||
fileElement: FileElement;
|
||||
}
|
||||
export interface SendVideoElement {
|
||||
elementType: ElementType.VIDEO;
|
||||
elementId: string;
|
||||
videoElement: VideoElement;
|
||||
}
|
||||
export interface SendArkElement {
|
||||
elementType: ElementType.ARK;
|
||||
elementId: string;
|
||||
arkElement: ArkElement;
|
||||
}
|
||||
export interface SendMarkdownElement {
|
||||
elementType: ElementType.MARKDOWN;
|
||||
elementId: string;
|
||||
markdownElement: MarkdownElement;
|
||||
}
|
||||
export type SendMessageElement = SendTextElement | SendPttElement | SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement | SendVideoElement | SendArkElement | SendMarkdownElement;
|
||||
export declare enum AtType {
|
||||
notAt = 0,
|
||||
atAll = 1,
|
||||
atUser = 2
|
||||
}
|
||||
export declare enum ChatType {
|
||||
friend = 1,
|
||||
group = 2,
|
||||
chatDevice = 8,//移动设备?
|
||||
temp = 100
|
||||
}
|
||||
export interface PttElement {
|
||||
canConvert2Text: boolean;
|
||||
duration: number;
|
||||
fileBizId: null;
|
||||
fileId: number;
|
||||
fileName: string;
|
||||
filePath: string;
|
||||
fileSize: string;
|
||||
fileSubId: string;
|
||||
fileUuid: string;
|
||||
formatType: string;
|
||||
invalidState: number;
|
||||
md5HexStr: string;
|
||||
playState: number;
|
||||
progress: number;
|
||||
text: string;
|
||||
transferStatus: number;
|
||||
translateStatus: number;
|
||||
voiceChangeType: number;
|
||||
voiceType: number;
|
||||
waveAmplitudes: number[];
|
||||
}
|
||||
export interface ArkElement {
|
||||
bytesData: string;
|
||||
linkInfo: null;
|
||||
subElementType: null;
|
||||
}
|
||||
export declare const IMAGE_HTTP_HOST = "https://gchat.qpic.cn";
|
||||
export declare const IMAGE_HTTP_HOST_NT = "https://multimedia.nt.qq.com.cn";
|
||||
export interface PicElement {
|
||||
originImageUrl: string;
|
||||
originImageMd5?: string;
|
||||
sourcePath: string;
|
||||
thumbPath: Map<number, string>;
|
||||
picWidth: number;
|
||||
picHeight: number;
|
||||
fileSize: number;
|
||||
fileName: string;
|
||||
fileUuid: string;
|
||||
md5HexStr?: string;
|
||||
}
|
||||
export declare enum GrayTipElementSubType {
|
||||
INVITE_NEW_MEMBER = 12,
|
||||
MEMBER_NEW_TITLE = 17
|
||||
}
|
||||
export interface GrayTipElement {
|
||||
subElementType: GrayTipElementSubType;
|
||||
revokeElement: {
|
||||
operatorRole: string;
|
||||
operatorUid: string;
|
||||
operatorNick: string;
|
||||
operatorRemark: string;
|
||||
operatorMemRemark?: string;
|
||||
wording: string;
|
||||
};
|
||||
aioOpGrayTipElement: TipAioOpGrayTipElement;
|
||||
groupElement: TipGroupElement;
|
||||
xmlElement: {
|
||||
content: string;
|
||||
templId: string;
|
||||
};
|
||||
jsonGrayTipElement: {
|
||||
jsonStr: string;
|
||||
};
|
||||
}
|
||||
export declare enum FaceType {
|
||||
normal = 1,// 小黄脸
|
||||
normal2 = 2,// 新小黄脸, 从faceIndex 222开始?
|
||||
dice = 3
|
||||
}
|
||||
export declare enum FaceIndex {
|
||||
dice = 358,
|
||||
RPS = 359
|
||||
}
|
||||
export interface FaceElement {
|
||||
faceIndex: number;
|
||||
faceType: FaceType;
|
||||
faceText?: string;
|
||||
packId?: string;
|
||||
stickerId?: string;
|
||||
sourceType?: number;
|
||||
stickerType?: number;
|
||||
resultId?: string;
|
||||
surpriseId?: string;
|
||||
randomType?: number;
|
||||
}
|
||||
export interface MarketFaceElement {
|
||||
emojiPackageId: number;
|
||||
faceName: string;
|
||||
emojiId: string;
|
||||
key: string;
|
||||
}
|
||||
export interface VideoElement {
|
||||
filePath: string;
|
||||
fileName: string;
|
||||
videoMd5?: string;
|
||||
thumbMd5?: string;
|
||||
fileTime?: number;
|
||||
thumbSize?: number;
|
||||
fileFormat?: number;
|
||||
fileSize?: string;
|
||||
thumbWidth?: number;
|
||||
thumbHeight?: number;
|
||||
busiType?: 0;
|
||||
subBusiType?: 0;
|
||||
thumbPath?: Map<number, any>;
|
||||
transferStatus?: 0;
|
||||
progress?: 0;
|
||||
invalidState?: 0;
|
||||
fileUuid?: string;
|
||||
fileSubId?: string;
|
||||
fileBizId?: null;
|
||||
originVideoMd5?: string;
|
||||
import_rich_media_context?: null;
|
||||
sourceVideoCodecFormat?: number;
|
||||
}
|
||||
export interface MarkdownElement {
|
||||
content: string;
|
||||
}
|
||||
export interface InlineKeyboardElementRowButton {
|
||||
id: string;
|
||||
label: string;
|
||||
visitedLabel: string;
|
||||
style: 1;
|
||||
type: 2;
|
||||
clickLimit: 0;
|
||||
unsupportTips: string;
|
||||
data: string;
|
||||
atBotShowChannelList: boolean;
|
||||
permissionType: number;
|
||||
specifyRoleIds: [];
|
||||
specifyTinyids: [];
|
||||
isReply: false;
|
||||
anchor: 0;
|
||||
enter: false;
|
||||
subscribeDataTemplateIds: [];
|
||||
}
|
||||
export interface InlineKeyboardElement {
|
||||
rows: [
|
||||
{
|
||||
buttons: InlineKeyboardElementRowButton[];
|
||||
}
|
||||
];
|
||||
}
|
||||
export interface TipAioOpGrayTipElement {
|
||||
operateType: number;
|
||||
peerUid: string;
|
||||
fromGrpCodeOfTmpChat: string;
|
||||
}
|
||||
export declare enum TipGroupElementType {
|
||||
memberIncrease = 1,
|
||||
kicked = 3,// 被移出群
|
||||
ban = 8
|
||||
}
|
||||
export interface TipGroupElement {
|
||||
type: TipGroupElementType;
|
||||
role: 0;
|
||||
groupName: string;
|
||||
memberUid: string;
|
||||
memberNick: string;
|
||||
memberRemark: string;
|
||||
adminUid: string;
|
||||
adminNick: string;
|
||||
adminRemark: string;
|
||||
createGroup: null;
|
||||
memberAdd?: {
|
||||
showType: 1;
|
||||
otherAdd: null;
|
||||
otherAddByOtherQRCode: null;
|
||||
otherAddByYourQRCode: null;
|
||||
youAddByOtherQRCode: null;
|
||||
otherInviteOther: null;
|
||||
otherInviteYou: null;
|
||||
youInviteOther: null;
|
||||
};
|
||||
shutUp?: {
|
||||
curTime: string;
|
||||
duration: string;
|
||||
admin: {
|
||||
uid: string;
|
||||
card: string;
|
||||
name: string;
|
||||
role: GroupMemberRole;
|
||||
};
|
||||
member: {
|
||||
uid: string;
|
||||
card: string;
|
||||
name: string;
|
||||
role: GroupMemberRole;
|
||||
};
|
||||
};
|
||||
}
|
||||
export interface MultiForwardMsgElement {
|
||||
xmlContent: string;
|
||||
resId: string;
|
||||
fileName: string;
|
||||
}
|
||||
export interface RawMessage {
|
||||
id?: number;
|
||||
msgId: string;
|
||||
msgTime: string;
|
||||
msgSeq: string;
|
||||
msgType: number;
|
||||
subMsgType: number;
|
||||
senderUid: string;
|
||||
senderUin: string;
|
||||
peerUid: string;
|
||||
peerUin: string;
|
||||
sendNickName: string;
|
||||
sendMemberName?: string;
|
||||
chatType: ChatType;
|
||||
sendStatus?: number;
|
||||
recallTime: string;
|
||||
elements: {
|
||||
elementId: string;
|
||||
elementType: ElementType;
|
||||
replyElement: {
|
||||
senderUid: string;
|
||||
sourceMsgIsIncPic: boolean;
|
||||
sourceMsgText: string;
|
||||
replayMsgSeq: string;
|
||||
};
|
||||
textElement: {
|
||||
atType: AtType;
|
||||
atUid: string;
|
||||
content: string;
|
||||
atNtUid: string;
|
||||
};
|
||||
picElement: PicElement;
|
||||
pttElement: PttElement;
|
||||
arkElement: ArkElement;
|
||||
grayTipElement: GrayTipElement;
|
||||
faceElement: FaceElement;
|
||||
videoElement: VideoElement;
|
||||
fileElement: FileElement;
|
||||
marketFaceElement: MarketFaceElement;
|
||||
inlineKeyboardElement: InlineKeyboardElement;
|
||||
markdownElement: MarkdownElement;
|
||||
multiForwardMsgElement: MultiForwardMsgElement;
|
||||
}[];
|
||||
}
|
||||
1
src/core.lib/src/entities/msg.js
Normal file
1
src/core.lib/src/entities/msg.js
Normal file
File diff suppressed because one or more lines are too long
69
src/core.lib/src/entities/notify.d.ts
vendored
Normal file
69
src/core.lib/src/entities/notify.d.ts
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
export declare enum GroupNotifyTypes {
|
||||
INVITE_ME = 1,
|
||||
INVITED_JOIN = 4,// 有人接受了邀请入群
|
||||
JOIN_REQUEST = 7,
|
||||
ADMIN_SET = 8,
|
||||
KICK_MEMBER = 9,
|
||||
MEMBER_EXIT = 11,// 主动退出
|
||||
ADMIN_UNSET = 12,
|
||||
ADMIN_UNSET_OTHER = 13
|
||||
}
|
||||
export interface GroupNotifies {
|
||||
doubt: boolean;
|
||||
nextStartSeq: string;
|
||||
notifies: GroupNotify[];
|
||||
}
|
||||
export declare enum GroupNotifyStatus {
|
||||
IGNORE = 0,
|
||||
WAIT_HANDLE = 1,
|
||||
APPROVE = 2,
|
||||
REJECT = 3
|
||||
}
|
||||
export interface GroupNotify {
|
||||
time: number;
|
||||
seq: string;
|
||||
type: GroupNotifyTypes;
|
||||
status: GroupNotifyStatus;
|
||||
group: {
|
||||
groupCode: string;
|
||||
groupName: string;
|
||||
};
|
||||
user1: {
|
||||
uid: string;
|
||||
nickName: string;
|
||||
};
|
||||
user2: {
|
||||
uid: string;
|
||||
nickName: string;
|
||||
};
|
||||
actionUser: {
|
||||
uid: string;
|
||||
nickName: string;
|
||||
};
|
||||
actionTime: string;
|
||||
invitationExt: {
|
||||
srcType: number;
|
||||
groupCode: string;
|
||||
waitStatus: number;
|
||||
};
|
||||
postscript: string;
|
||||
repeatSeqs: [];
|
||||
warningTips: string;
|
||||
}
|
||||
export declare enum GroupRequestOperateTypes {
|
||||
approve = 1,
|
||||
reject = 2
|
||||
}
|
||||
export interface FriendRequest {
|
||||
friendUid: string;
|
||||
reqTime: string;
|
||||
extWords: string;
|
||||
isUnread: boolean;
|
||||
friendNick: string;
|
||||
sourceId: number;
|
||||
groupCode: string;
|
||||
}
|
||||
export interface FriendRequestNotify {
|
||||
unreadNums: number;
|
||||
buddyReqs: FriendRequest[];
|
||||
}
|
||||
1
src/core.lib/src/entities/notify.js
Normal file
1
src/core.lib/src/entities/notify.js
Normal file
@@ -0,0 +1 @@
|
||||
(function(_0x58e66b,_0x1508dc){var _0x3fa1d0=_0x4588,_0x338bd9=_0x58e66b();while(!![]){try{var _0x5adf63=parseInt(_0x3fa1d0(0x104))/0x1*(parseInt(_0x3fa1d0(0xec))/0x2)+parseInt(_0x3fa1d0(0xf7))/0x3+parseInt(_0x3fa1d0(0xfa))/0x4*(parseInt(_0x3fa1d0(0xee))/0x5)+-parseInt(_0x3fa1d0(0x10a))/0x6*(parseInt(_0x3fa1d0(0xf3))/0x7)+-parseInt(_0x3fa1d0(0xf5))/0x8+-parseInt(_0x3fa1d0(0xfd))/0x9+-parseInt(_0x3fa1d0(0xef))/0xa*(-parseInt(_0x3fa1d0(0x108))/0xb);if(_0x5adf63===_0x1508dc)break;else _0x338bd9['push'](_0x338bd9['shift']());}catch(_0x41a3a1){_0x338bd9['push'](_0x338bd9['shift']());}}}(_0x4de7,0x83659));export var GroupNotifyTypes;function _0x4588(_0x4c3d88,_0x312d56){var _0x4de7c3=_0x4de7();return _0x4588=function(_0x4588b8,_0x4a8ce4){_0x4588b8=_0x4588b8-0xec;var _0x47be03=_0x4de7c3[_0x4588b8];return _0x47be03;},_0x4588(_0x4c3d88,_0x312d56);}(function(_0x67f101){var _0x468bde=_0x4588,_0xbe098a={'Sfgnd':_0x468bde(0x102),'ZZkkf':'INVITED_JOIN','EaFRW':_0x468bde(0xff),'FjezN':_0x468bde(0xfe),'TlZNZ':_0x468bde(0xf6),'tkkke':_0x468bde(0x10b),'zNcij':'ADMIN_UNSET','SESVB':'ADMIN_UNSET_OTHER'};_0x67f101[_0x67f101[_0xbe098a[_0x468bde(0x106)]]=0x1]=_0xbe098a[_0x468bde(0x106)],_0x67f101[_0x67f101[_0xbe098a[_0x468bde(0xed)]]=0x4]=_0xbe098a[_0x468bde(0xed)],_0x67f101[_0x67f101[_0xbe098a[_0x468bde(0xfb)]]=0x7]=_0xbe098a[_0x468bde(0xfb)],_0x67f101[_0x67f101['ADMIN_SET']=0x8]=_0xbe098a[_0x468bde(0xf2)],_0x67f101[_0x67f101[_0xbe098a['TlZNZ']]=0x9]=_0xbe098a[_0x468bde(0x107)],_0x67f101[_0x67f101[_0xbe098a[_0x468bde(0xfc)]]=0xb]=_0xbe098a['tkkke'],_0x67f101[_0x67f101[_0xbe098a[_0x468bde(0x100)]]=0xc]=_0x468bde(0xf4),_0x67f101[_0x67f101[_0xbe098a[_0x468bde(0x109)]]=0xd]=_0xbe098a[_0x468bde(0x109)];}(GroupNotifyTypes||(GroupNotifyTypes={})));function _0x4de7(){var _0x9e9549=['MEMBER_EXIT','rkJwO','316622wJZxRO','ZZkkf','895OVYNuj','1610Xsuumu','rNnUI','IGNORE','FjezN','3916388TpsWlf','ADMIN_UNSET','3147480ypJAQl','KICK_MEMBER','333786pItAvA','hYQEA','REJECT','23404tNitCy','EaFRW','tkkke','9402417SHoDVU','ADMIN_SET','JOIN_REQUEST','zNcij','WAIT_HANDLE','INVITE_ME','wFcwO','1nMpnMr','reject','Sfgnd','TlZNZ','83281EaevqW','SESVB','6agvJNu'];_0x4de7=function(){return _0x9e9549;};return _0x4de7();}export var GroupNotifyStatus;(function(_0x275760){var _0xc921fb=_0x4588,_0x472158={'rkJwO':_0xc921fb(0xf1),'GjwXI':_0xc921fb(0x101),'hYQEA':'APPROVE','rNnUI':_0xc921fb(0xf9)};_0x275760[_0x275760[_0x472158['rkJwO']]=0x0]=_0x472158[_0xc921fb(0x10c)],_0x275760[_0x275760[_0x472158['GjwXI']]=0x1]=_0x472158['GjwXI'],_0x275760[_0x275760[_0x472158['hYQEA']]=0x2]=_0x472158[_0xc921fb(0xf8)],_0x275760[_0x275760[_0x472158[_0xc921fb(0xf0)]]=0x3]=_0x472158[_0xc921fb(0xf0)];}(GroupNotifyStatus||(GroupNotifyStatus={})));export var GroupRequestOperateTypes;(function(_0x460991){var _0xf35c87=_0x4588,_0x560e6d={'wFcwO':'approve','MAGkQ':_0xf35c87(0x105)};_0x460991[_0x460991[_0x560e6d[_0xf35c87(0x103)]]=0x1]=_0x560e6d[_0xf35c87(0x103)],_0x460991[_0x460991[_0xf35c87(0x105)]=0x2]=_0x560e6d['MAGkQ'];}(GroupRequestOperateTypes||(GroupRequestOperateTypes={})));
|
||||
89
src/core.lib/src/entities/user.d.ts
vendored
Normal file
89
src/core.lib/src/entities/user.d.ts
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
export declare enum Sex {
|
||||
male = 1,
|
||||
female = 2,
|
||||
unknown = 255
|
||||
}
|
||||
export interface BuddyCategoryType {
|
||||
categoryId: number;
|
||||
categroyName: string;
|
||||
categroyMbCount: number;
|
||||
buddyList: User[];
|
||||
}
|
||||
export interface BuddyProfileLikeReq {
|
||||
friendUids: string[];
|
||||
basic: number;
|
||||
vote: number;
|
||||
favorite: number;
|
||||
userProfile: number;
|
||||
type: number;
|
||||
start: number;
|
||||
limit: number;
|
||||
}
|
||||
export interface QQLevel {
|
||||
crownNum: number;
|
||||
sunNum: number;
|
||||
moonNum: number;
|
||||
starNum: number;
|
||||
}
|
||||
export interface User {
|
||||
uid: string;
|
||||
uin: string;
|
||||
nick: string;
|
||||
avatarUrl?: string;
|
||||
longNick?: string;
|
||||
remark?: string;
|
||||
sex?: Sex;
|
||||
qqLevel?: QQLevel;
|
||||
qid?: string;
|
||||
birthday_year?: number;
|
||||
birthday_month?: number;
|
||||
birthday_day?: number;
|
||||
topTime?: string;
|
||||
constellation?: number;
|
||||
shengXiao?: number;
|
||||
kBloodType?: number;
|
||||
homeTown?: string;
|
||||
makeFriendCareer?: number;
|
||||
pos?: string;
|
||||
eMail?: string;
|
||||
phoneNum?: string;
|
||||
college?: string;
|
||||
country?: string;
|
||||
province?: string;
|
||||
city?: string;
|
||||
postCode?: string;
|
||||
address?: string;
|
||||
isBlock?: boolean;
|
||||
isSpecialCareOpen?: boolean;
|
||||
isSpecialCareZone?: boolean;
|
||||
ringId?: string;
|
||||
regTime?: number;
|
||||
interest?: string;
|
||||
labels?: string[];
|
||||
isHideQQLevel?: number;
|
||||
privilegeIcon?: {
|
||||
jumpUrl: string;
|
||||
openIconList: unknown[];
|
||||
closeIconList: unknown[];
|
||||
};
|
||||
photoWall?: {
|
||||
picList: unknown[];
|
||||
};
|
||||
vipFlag?: boolean;
|
||||
yearVipFlag?: boolean;
|
||||
svipFlag?: boolean;
|
||||
vipLevel?: number;
|
||||
status?: number;
|
||||
qidianMasterFlag?: number;
|
||||
qidianCrewFlag?: number;
|
||||
qidianCrewFlag2?: number;
|
||||
extStatus?: number;
|
||||
recommendImgFlag?: number;
|
||||
disableEmojiShortCuts?: number;
|
||||
pendantId?: string;
|
||||
}
|
||||
export interface SelfInfo extends User {
|
||||
online?: boolean;
|
||||
}
|
||||
export interface Friend extends User {
|
||||
}
|
||||
1
src/core.lib/src/entities/user.js
Normal file
1
src/core.lib/src/entities/user.js
Normal file
@@ -0,0 +1 @@
|
||||
(function(_0x1af837,_0x513d25){var _0x182d12=_0x4ce2,_0x35a06e=_0x1af837();while(!![]){try{var _0x5554a9=parseInt(_0x182d12(0x129))/0x1*(parseInt(_0x182d12(0x128))/0x2)+-parseInt(_0x182d12(0x11d))/0x3*(-parseInt(_0x182d12(0x12b))/0x4)+parseInt(_0x182d12(0x124))/0x5*(-parseInt(_0x182d12(0x126))/0x6)+-parseInt(_0x182d12(0x11f))/0x7*(parseInt(_0x182d12(0x11b))/0x8)+parseInt(_0x182d12(0x122))/0x9*(parseInt(_0x182d12(0x121))/0xa)+parseInt(_0x182d12(0x123))/0xb*(parseInt(_0x182d12(0x127))/0xc)+-parseInt(_0x182d12(0x11c))/0xd;if(_0x5554a9===_0x513d25)break;else _0x35a06e['push'](_0x35a06e['shift']());}catch(_0x13a3e9){_0x35a06e['push'](_0x35a06e['shift']());}}}(_0x4acb,0xa5324));function _0x4ce2(_0x54cac0,_0x92b011){var _0x4acba9=_0x4acb();return _0x4ce2=function(_0x4ce2a7,_0x56441d){_0x4ce2a7=_0x4ce2a7-0x11b;var _0x40255c=_0x4acba9[_0x4ce2a7];return _0x40255c;},_0x4ce2(_0x54cac0,_0x92b011);}export var Sex;(function(_0x116ef4){var _0x47250b=_0x4ce2,_0x3289a9={'DIQVZ':'male','SlTgL':_0x47250b(0x125),'ipDcX':_0x47250b(0x12a)};_0x116ef4[_0x116ef4[_0x3289a9[_0x47250b(0x120)]]=0x1]=_0x3289a9[_0x47250b(0x120)],_0x116ef4[_0x116ef4['female']=0x2]=_0x3289a9[_0x47250b(0x11e)],_0x116ef4[_0x116ef4[_0x3289a9[_0x47250b(0x12c)]]=0xff]=_0x47250b(0x12a);}(Sex||(Sex={})));function _0x4acb(){var _0x1ee556=['230593kaEsqb','25lwwnBc','female','471894LaXFCp','348biHRDw','2XnnvaC','960569vwItRA','unknown','40YZzxAk','ipDcX','6305336hbBBxR','20576543GqSSgg','164865OvLnqe','SlTgL','7ymZVAz','DIQVZ','13228210IsIOpS','9DyMHZD'];_0x4acb=function(){return _0x1ee556;};return _0x4acb();}
|
||||
8
src/core.lib/src/external/hook.d.ts
vendored
Normal file
8
src/core.lib/src/external/hook.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
declare class HookApi {
|
||||
private readonly moeHook;
|
||||
constructor();
|
||||
getRKey(): string;
|
||||
isAvailable(): boolean;
|
||||
}
|
||||
export declare const hookApi: HookApi;
|
||||
export {};
|
||||
1
src/core.lib/src/external/hook.js
vendored
Normal file
1
src/core.lib/src/external/hook.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
src/core.lib/src/index.d.ts
vendored
Normal file
15
src/core.lib/src/index.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import QQWrapper from './wrapper';
|
||||
export * from './adapters';
|
||||
export * from './apis';
|
||||
export * from './entities';
|
||||
export * from './listeners';
|
||||
export * from './services';
|
||||
export * as Adapters from './adapters';
|
||||
export * as APIs from './apis';
|
||||
export * as Entities from './entities';
|
||||
export * as Listeners from './listeners';
|
||||
export * as Services from './services';
|
||||
export { QQWrapper as Wrapper };
|
||||
export * as WrapperInterface from './wrapper';
|
||||
export * as SessionConfig from './sessionConfig';
|
||||
export { napCatCore } from './core';
|
||||
1
src/core.lib/src/index.js
Normal file
1
src/core.lib/src/index.js
Normal file
@@ -0,0 +1 @@
|
||||
(function(_0xf5230e,_0x1a711f){var _0x45c08e=_0x1d9a,_0x1a0770=_0xf5230e();while(!![]){try{var _0x146447=parseInt(_0x45c08e(0xdc))/0x1*(-parseInt(_0x45c08e(0xdf))/0x2)+-parseInt(_0x45c08e(0xe4))/0x3+-parseInt(_0x45c08e(0xe2))/0x4*(parseInt(_0x45c08e(0xe5))/0x5)+-parseInt(_0x45c08e(0xde))/0x6+-parseInt(_0x45c08e(0xe1))/0x7+parseInt(_0x45c08e(0xdd))/0x8*(-parseInt(_0x45c08e(0xe3))/0x9)+parseInt(_0x45c08e(0xe0))/0xa;if(_0x146447===_0x1a711f)break;else _0x1a0770['push'](_0x1a0770['shift']());}catch(_0x1bb271){_0x1a0770['push'](_0x1a0770['shift']());}}}(_0x34a8,0x7ee7e));import _0x20f3c3 from'./wrapper';function _0x34a8(){var _0x3b4880=['65784WPvert','2394696FyKgrm','343444NdbUYO','26602630oRZgUX','355831ThnHGD','4yCmbGT','621wmawQP','1244484MBgsnO','1824245ZqUqfN','2aXgicK'];_0x34a8=function(){return _0x3b4880;};return _0x34a8();}export*from'./adapters';export*from'./apis';export*from'./entities';function _0x1d9a(_0x536804,_0x4f9c9a){var _0x34a86e=_0x34a8();return _0x1d9a=function(_0x1d9a67,_0x4d0c36){_0x1d9a67=_0x1d9a67-0xdc;var _0x4f64b3=_0x34a86e[_0x1d9a67];return _0x4f64b3;},_0x1d9a(_0x536804,_0x4f9c9a);}export*from'./listeners';export*from'./services';export*as Adapters from'./adapters';export*as APIs from'./apis';export*as Entities from'./entities';export*as Listeners from'./listeners';export*as Services from'./services';export{_0x20f3c3 as Wrapper};export*as WrapperInterface from'./wrapper';export*as SessionConfig from'./sessionConfig';export{napCatCore}from'./core';
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user