Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fba2078fc0 | ||
|
|
20a37fe2de | ||
|
|
8f6d26b65c | ||
|
|
b58a194c8a | ||
|
|
52f1b0a0ce | ||
|
|
c2b8fb223b | ||
|
|
20e4eff899 | ||
|
|
0efcca36d2 | ||
|
|
ab417802a0 | ||
|
|
73d68cce4a | ||
|
|
e4ac2de660 | ||
|
|
8d1241808a | ||
|
|
b810040145 | ||
|
|
c01d7dae2d | ||
|
|
dfca3c2483 | ||
|
|
1bb4be086f | ||
|
|
fd226c45f6 | ||
|
|
21fed5b25f | ||
|
|
dde093d321 | ||
|
|
b99fb247ac | ||
|
|
28930fdad4 | ||
|
|
ea4d1d3275 | ||
|
|
62e852d510 | ||
|
|
7ddd4d6461 | ||
|
|
6b9307de2a | ||
|
|
234046ce10 | ||
|
|
73b29cf1e2 | ||
|
|
4b3bf170c0 | ||
|
|
a7fbaba2d7 | ||
|
|
fc79241f3d | ||
|
|
a88c37ea56 | ||
|
|
9b2358b7f1 | ||
|
|
257135763f | ||
|
|
610a3499f2 | ||
|
|
69752b8837 | ||
|
|
610473b57c | ||
|
|
1e5721d7d5 | ||
|
|
6c2b45679a | ||
|
|
6785922379 | ||
|
|
4e85124aeb | ||
|
|
6b30a03f55 | ||
|
|
876894d8c6 | ||
|
|
ea20d94146 | ||
|
|
c7669777cb | ||
|
|
3b43bba4a0 | ||
|
|
0ab4946bf1 | ||
|
|
a7fb18d5c0 | ||
|
|
a0fbb0f861 | ||
|
|
e6c93ab1c0 | ||
|
|
7152213344 | ||
|
|
a8e913cfde | ||
|
|
4ac074f3dd | ||
|
|
436249597d | ||
|
|
016a742d90 | ||
|
|
6d863ac29c | ||
|
|
ae981fe57d | ||
|
|
0c6a75b722 | ||
|
|
bfd9b1b7c7 | ||
|
|
12f6b1ca45 | ||
|
|
04264110ee | ||
|
|
e4a112c329 | ||
|
|
ef4dee8886 | ||
|
|
e7ee21ca30 | ||
|
|
23ee480c4f | ||
|
|
7816271302 | ||
|
|
b57814f14a | ||
|
|
b18e86f81c | ||
|
|
7b1b503703 | ||
|
|
32d4febf10 | ||
|
|
814973af58 | ||
|
|
ecee642e10 | ||
|
|
9afc0f6667 | ||
|
|
e9e517533a | ||
|
|
4a531ccea1 | ||
|
|
fb8e0595c2 | ||
|
|
d748d6e400 | ||
|
|
6b99fa1f24 | ||
|
|
ca5abc635c | ||
|
|
35e75be0d0 | ||
|
|
cf401a659d | ||
|
|
bd56968efb | ||
|
|
a78bc686cd | ||
|
|
ad8c962c25 | ||
|
|
be91976498 | ||
|
|
57821b839e | ||
|
|
ad334ed09f | ||
|
|
a955937e02 | ||
|
|
3c42cc17c8 | ||
|
|
deeab036d3 | ||
|
|
a1badcd9a1 | ||
|
|
52762438c6 | ||
|
|
3294079b72 | ||
|
|
1c6bdf20b6 | ||
|
|
fac00be995 | ||
|
|
e7e8e99946 | ||
|
|
9f9749548a | ||
|
|
db1ac85acf | ||
|
|
d5eaeb429a | ||
|
|
4e7595d8d1 | ||
|
|
f25fdcdc3d | ||
|
|
7a4de75e07 | ||
|
|
545b57a57d | ||
|
|
32c3aa7979 | ||
|
|
013f703241 | ||
|
|
c463ad5fd6 | ||
|
|
412b8473fe | ||
|
|
02df2132b4 | ||
|
|
a964d5c93f | ||
|
|
eafc32a915 | ||
|
|
df4b84b4b9 | ||
|
|
6e094eb4fc | ||
|
|
9e7d7bcb4c | ||
|
|
63b3cc8c02 | ||
|
|
7a88786685 | ||
|
|
427889f8ca | ||
|
|
82c9c28439 | ||
|
|
c84c1f2e96 | ||
|
|
a3ee8672ed | ||
|
|
4cfde09016 | ||
|
|
0b8dcbebe9 | ||
|
|
aa12506221 | ||
|
|
39ed9dea01 | ||
|
|
6f095470ad | ||
|
|
2a5d2cc146 | ||
|
|
b5e8218551 | ||
|
|
062cc307fb | ||
|
|
e99ff1be35 | ||
|
|
404a213896 | ||
|
|
0a07f16ef6 | ||
|
|
f9bf8f9901 | ||
|
|
b6ae67bf3e | ||
|
|
191ce0798f | ||
|
|
40362590c8 | ||
|
|
87f6dc7c0b | ||
|
|
2f2c1f263a | ||
|
|
8841cbb3d0 | ||
|
|
a2e20a8092 | ||
|
|
6a7c7a0ab5 | ||
|
|
44a8c8e35d | ||
|
|
1cbfccc4eb | ||
|
|
e12c0b5536 | ||
|
|
b7a8781308 | ||
|
|
73a8fcd35b | ||
|
|
a2ad39f78d | ||
|
|
832635d6f5 | ||
|
|
dacb56bc20 | ||
|
|
e5a9821027 | ||
|
|
bbe666eb73 | ||
|
|
000cb3d80c | ||
|
|
40f85dbf5f | ||
|
|
d6646ebadf | ||
|
|
e02bddc78f | ||
|
|
08e679184b | ||
|
|
5c877e894b | ||
|
|
5918f03cb1 | ||
|
|
78263d716c | ||
|
|
15f4841328 | ||
|
|
ae5d50141b | ||
|
|
8839563ff8 | ||
|
|
6d954b2d5d | ||
|
|
6e125f15a4 | ||
|
|
e344921a06 | ||
|
|
4cbaf0dc70 | ||
|
|
ef7d2f4a82 | ||
|
|
5f7d998b0b | ||
|
|
2c14281168 | ||
|
|
9feab4bc79 | ||
|
|
63237bc112 | ||
|
|
99f4752c89 | ||
|
|
ef1ed5aa8b | ||
|
|
1258270ac4 | ||
|
|
bb7a2f5f6c | ||
|
|
c865d32d95 | ||
|
|
87c3b24488 | ||
|
|
5a5257294b | ||
|
|
a9ca951854 | ||
|
|
2a9353ee70 | ||
|
|
18e134b92a | ||
|
|
6c87e15a52 | ||
|
|
a710821c35 | ||
|
|
de4aeedce5 | ||
|
|
1f71a01453 | ||
|
|
6371d79d33 | ||
|
|
80d2218aa6 | ||
|
|
bc636f109c | ||
|
|
76d58af4d8 | ||
|
|
84e5417a8c | ||
|
|
89188958ec | ||
|
|
b5d24d751d | ||
|
|
3269061db4 | ||
|
|
9f576f43cc | ||
|
|
505c6e0e0e | ||
|
|
9936b49ee0 | ||
|
|
707bc765b9 | ||
|
|
8780c987ea | ||
|
|
7aa01f786d | ||
|
|
340e94d54e | ||
|
|
509b123064 | ||
|
|
8060b1c753 | ||
|
|
33ef3e7d59 | ||
|
|
704e5f7134 | ||
|
|
91bc3ab525 | ||
|
|
2e6bded9d0 | ||
|
|
c6e980ed96 | ||
|
|
32a932ad5c | ||
|
|
f6d2bd04e9 | ||
|
|
b0266b470f | ||
|
|
0ed969fa3f | ||
|
|
90a7b5e0d3 | ||
|
|
c5bf656fe7 | ||
|
|
6bce4533a3 | ||
|
|
8a8aa0016e | ||
|
|
7e4ebd330c | ||
|
|
c304845117 | ||
|
|
ee85f3e824 | ||
|
|
3f6f1dcd78 | ||
|
|
c271a4b2cb | ||
|
|
fa07dfb720 | ||
|
|
6f6b258f22 | ||
|
|
717b246cb6 | ||
|
|
5990e0c2eb | ||
|
|
827df80ec8 | ||
|
|
7117fae2b2 | ||
|
|
15e9462140 | ||
|
|
714f8327ea | ||
|
|
fedb77e304 | ||
|
|
06d2884a88 | ||
|
|
b50556802c | ||
|
|
b18dfdb9ba | ||
|
|
173f83808e | ||
|
|
fbe2d78331 | ||
|
|
e5fd9c6366 | ||
|
|
3623b991ff | ||
|
|
2cabd7879c | ||
|
|
a1a378d6f5 | ||
|
|
b016268fdb | ||
|
|
dfb31b78d9 | ||
|
|
4eed603d36 | ||
|
|
cdc10d6c4b | ||
|
|
cb03501eff | ||
|
|
c2e28ab5a6 | ||
|
|
24a166cb94 | ||
|
|
1d3ac0c9b3 | ||
|
|
ff29b62398 | ||
|
|
d9e016db8b | ||
|
|
6cfd50a7b8 | ||
|
|
6605d3812a | ||
|
|
be71abe580 | ||
|
|
518ff48e97 | ||
|
|
8a4add257f | ||
|
|
7842cd0bc0 | ||
|
|
ffe480ad44 | ||
|
|
e4d3f95257 | ||
|
|
245eabe85f | ||
|
|
22e7eb1ffc | ||
|
|
d663a58d65 | ||
|
|
fa5d5f1bcc | ||
|
|
7178095aef | ||
|
|
4704faa011 | ||
|
|
0f77d9df1f | ||
|
|
e02c3fca8b | ||
|
|
abe0838a63 | ||
|
|
6583e3d0c9 | ||
|
|
2093d68bfb | ||
|
|
d3a55d50c0 | ||
|
|
471733b243 | ||
|
|
47fa717bce | ||
|
|
cfc68e70b6 | ||
|
|
bd9ee62118 | ||
|
|
aaa874b099 | ||
|
|
958709faf2 | ||
|
|
52ab93013c | ||
|
|
9203fa3df2 | ||
|
|
9ef3edabce | ||
|
|
c771d75a00 | ||
|
|
1db27ab0e3 | ||
|
|
cd45f7051c | ||
|
|
588ea7978e | ||
|
|
946f12cf6a | ||
|
|
7e49bfa984 | ||
|
|
7b10d75aeb | ||
|
|
34e4963ccd | ||
|
|
9fc9ed805c | ||
|
|
db4c5bc3a3 | ||
|
|
024faa2561 | ||
|
|
b46459de5f | ||
|
|
ac7f025223 | ||
|
|
e4343650c6 | ||
|
|
80c5259b05 | ||
|
|
004a65d933 | ||
|
|
38289918c2 | ||
|
|
0e46f9f213 | ||
|
|
be03b973e5 | ||
|
|
a0bf2b3d3d | ||
|
|
755ab36e83 | ||
|
|
30975f7360 | ||
|
|
828307fc52 | ||
|
|
e79ca4fa4c | ||
|
|
43288eb5c0 | ||
|
|
9518595e48 | ||
|
|
3c4cd3743f | ||
|
|
b39cbffe14 | ||
|
|
f588d3f35b | ||
|
|
54b06872eb | ||
|
|
0786c608a4 | ||
|
|
c70b2eaa30 | ||
|
|
c417a95e1f | ||
|
|
5ae9be0291 | ||
|
|
e2a6e3ea58 | ||
|
|
8fd5fa185b | ||
|
|
66707661e9 | ||
|
|
4e18ec5951 | ||
|
|
05b77b5042 | ||
|
|
d6cfe11d97 | ||
|
|
dd4d59e4e7 | ||
|
|
7cb8626e16 | ||
|
|
89b5202adb | ||
|
|
40ae0c1449 | ||
|
|
81a8115c56 | ||
|
|
0ddd26bd51 | ||
|
|
69e2133a27 | ||
|
|
b04f85949b | ||
|
|
667dba01ae | ||
|
|
85a8cef628 | ||
|
|
3099acfd00 | ||
|
|
b00fe0b5f8 | ||
|
|
9a64b8bdb6 | ||
|
|
c01e493bd2 | ||
|
|
890236af23 | ||
|
|
ea678d805d | ||
|
|
29699418ff | ||
|
|
87bb36c39f | ||
|
|
7cb85ed73c | ||
|
|
c647771a6d | ||
|
|
6c3d737219 | ||
|
|
a1f38fed7a | ||
|
|
c36bb77286 | ||
|
|
1a1acdc3c9 | ||
|
|
ef8e60c405 | ||
|
|
31c1cc47bf | ||
|
|
351fed7359 | ||
|
|
f49e7cbe57 | ||
|
|
7da8ea5e99 | ||
|
|
8fa6a12a7c | ||
|
|
1070278eaf | ||
|
|
16b1a6b153 | ||
|
|
096a7534e0 | ||
|
|
b0897187d2 | ||
|
|
885d94882d | ||
|
|
11a3341e13 | ||
|
|
231890f78a | ||
|
|
a272feda6a | ||
|
|
bc936a0ca7 | ||
|
|
28030c2d13 | ||
|
|
7fe9176286 | ||
|
|
1105f9b8d6 | ||
|
|
e4653defa8 | ||
|
|
1c62a1e839 | ||
|
|
3a3bbfe201 | ||
|
|
1c38833998 | ||
|
|
38894177ee | ||
|
|
dce8416942 | ||
|
|
14219e9b42 | ||
|
|
7b459e7502 | ||
|
|
31824c0504 | ||
|
|
e203abae85 | ||
|
|
faf83b680b | ||
|
|
67dcbcb842 | ||
|
|
6533a25404 | ||
|
|
4dc760b0e9 | ||
|
|
25933b9043 | ||
|
|
a53aaa456e | ||
|
|
e8a7ea07a5 | ||
|
|
8817dc6b10 | ||
|
|
491ec04b46 | ||
|
|
8a5d4a683b | ||
|
|
dfc7c7357a | ||
|
|
690a2f7d34 | ||
|
|
58f22b24e4 | ||
|
|
3cce9f528b | ||
|
|
20fd5ac8cb | ||
|
|
9e05e086eb | ||
|
|
056e0adddf | ||
|
|
b36388200d | ||
|
|
9793e5741a | ||
|
|
143380c012 | ||
|
|
4b92254945 | ||
|
|
f9c1d8b4a6 | ||
|
|
c0c469339b | ||
|
|
0ca6343ed7 | ||
|
|
3db74c3427 | ||
|
|
48d5cb53bd | ||
|
|
fd7d2dbf53 | ||
|
|
6609697752 | ||
|
|
dcd6e1973e | ||
|
|
3614a6e932 | ||
|
|
931a0210e5 | ||
|
|
f9e7de4b42 | ||
|
|
8e0b79594e | ||
|
|
17122c4360 | ||
|
|
154f7b6a30 | ||
|
|
52e5543d0b | ||
|
|
3c304bd2ae | ||
|
|
26609bb8fd | ||
|
|
de3fa9aaa4 | ||
|
|
788665f84c | ||
|
|
3943782971 | ||
|
|
8f899c40f2 | ||
|
|
a1f582399e | ||
|
|
440b63f662 | ||
|
|
7d2cc3b56b | ||
|
|
5fe3422469 | ||
|
|
6c02cedb1e | ||
|
|
3cc2f1dcad | ||
|
|
773cdc5877 | ||
|
|
361a7329d7 | ||
|
|
29910f1236 | ||
|
|
4a164016f5 | ||
|
|
cebd3e62a4 | ||
|
|
2562a38fa1 | ||
|
|
d46c922bbf | ||
|
|
66b59982f7 | ||
|
|
ad397ccf7f | ||
|
|
bdef80ede7 | ||
|
|
385dcbc75a | ||
|
|
74cf501c8f | ||
|
|
0c200d6748 | ||
|
|
e65a36c517 | ||
|
|
126b54ad40 | ||
|
|
78637751af | ||
|
|
f96526ee3a | ||
|
|
b3c7a91f3d | ||
|
|
b8daeef0c4 | ||
|
|
2b662944cf | ||
|
|
3d516df01e | ||
|
|
26b4a9b15b | ||
|
|
0f8af273ae | ||
|
|
fa29a31da9 | ||
|
|
9e0d2606d8 | ||
|
|
338dedd6e0 | ||
|
|
1f893b1393 | ||
|
|
b783d6f928 | ||
|
|
8ca0d40f05 | ||
|
|
2f40a80434 | ||
|
|
812d8eb5bb | ||
|
|
bf5f548349 | ||
|
|
ebf90e72b9 | ||
|
|
31d7d42edf | ||
|
|
833875b42f | ||
|
|
b901c10f3c | ||
|
|
8ab678bd97 | ||
|
|
55d5072f46 | ||
|
|
a379ffd0f2 | ||
|
|
4501d73134 | ||
|
|
5f15774ec7 | ||
|
|
c9e057599e | ||
|
|
66851f5625 | ||
|
|
b33c235b4d | ||
|
|
d6693b6114 | ||
|
|
36b4d26c78 | ||
|
|
617592d90a | ||
|
|
15a77b8070 | ||
|
|
606eccd22b | ||
|
|
5613450313 | ||
|
|
c59b5564af | ||
|
|
330b086b8b | ||
|
|
9837ef4f36 | ||
|
|
add46b3251 | ||
|
|
e169199107 | ||
|
|
92fe654850 | ||
|
|
b257486404 | ||
|
|
bdf2e33f40 | ||
|
|
224d361923 | ||
|
|
3452fa56df | ||
|
|
cd256235da | ||
|
|
361a164f2a | ||
|
|
0e60d4b198 | ||
|
|
67b47e39b4 | ||
|
|
8f54310f63 | ||
|
|
c7a7494d7e | ||
|
|
af88b3166d | ||
|
|
b7837b2a14 | ||
|
|
950ddc749e | ||
|
|
df081ef0cf | ||
|
|
7b24f90d9f | ||
|
|
f2e4579fd8 | ||
|
|
97cb351827 | ||
|
|
c1ec53fdbb | ||
|
|
98214aa429 | ||
|
|
ce7deac2dd | ||
|
|
612092b867 | ||
|
|
92579d5949 | ||
|
|
9ab07060ae | ||
|
|
0d45125d79 | ||
|
|
9ced152778 | ||
|
|
3685ab2e3e | ||
|
|
be605f11f2 | ||
|
|
8cca8df976 | ||
|
|
990a31e961 | ||
|
|
5db201c342 | ||
|
|
a625e30dd4 | ||
|
|
b236cdd060 | ||
|
|
2db9899184 | ||
|
|
fe5d6db986 | ||
|
|
7c7bf8fecf | ||
|
|
76e3a46378 | ||
|
|
16f3897fec | ||
|
|
045e120854 | ||
|
|
2b7fcce9b2 | ||
|
|
9685931694 | ||
|
|
1dc844435a | ||
|
|
18892379de | ||
|
|
620d61c8dc | ||
|
|
9f91398875 | ||
|
|
a29b1154a9 | ||
|
|
34d19a471a | ||
|
|
2ef6477d7c | ||
|
|
26e6800836 | ||
|
|
9dbbcf3872 | ||
|
|
6b3343e1e4 | ||
|
|
ef48f754a5 | ||
|
|
3be1ede847 | ||
|
|
7bff1b61e8 | ||
|
|
6affd0eb68 | ||
|
|
0a112d15e0 | ||
|
|
4e03f582bb | ||
|
|
8f186c1c5e | ||
|
|
cd1bae9a1f | ||
|
|
60796c26ca | ||
|
|
28927f950d | ||
|
|
95f16ebc8c | ||
|
|
25bca8385d | ||
|
|
965c7f23b4 | ||
|
|
33082af9cc | ||
|
|
1f7f3565b0 | ||
|
|
f784363696 | ||
|
|
37bd51e138 | ||
|
|
c367728c43 | ||
|
|
61f0f5d884 | ||
|
|
5f2ebeead7 | ||
|
|
7646037fc7 | ||
|
|
eac6d285ff | ||
|
|
b921d5e734 | ||
|
|
831d808e63 | ||
|
|
451b88d7e3 | ||
|
|
f916682a71 | ||
|
|
2d76bcf0cf | ||
|
|
8db294efe6 | ||
|
|
5cc5149aed | ||
|
|
7ecb01dc9f | ||
|
|
8bf1a545d9 | ||
|
|
efb2be2f94 | ||
|
|
bd2edda494 | ||
|
|
991172eae4 | ||
|
|
fc7631f9aa | ||
|
|
a21efb7d2f | ||
|
|
03bc844ad0 | ||
|
|
f7bdc35ed6 | ||
|
|
0efdffd857 | ||
|
|
6a16a42d0c | ||
|
|
e9c00c72b1 | ||
|
|
ab22f36b8a | ||
|
|
c57497cd91 | ||
|
|
ba123236e5 | ||
|
|
338b6e4607 | ||
|
|
f88c717560 | ||
|
|
f8ffc92db5 | ||
|
|
98c23c172c | ||
|
|
781c107d8c | ||
|
|
186668c075 | ||
|
|
cf9f785193 | ||
|
|
72d2d3f224 | ||
|
|
087c76b394 | ||
|
|
4f9fb2c8c3 | ||
|
|
334e43e764 | ||
|
|
7843256402 | ||
|
|
0522ba35fe | ||
|
|
24d3b52e0b | ||
|
|
3177110f0f | ||
|
|
e1b8243a67 | ||
|
|
b1c6ce3885 | ||
|
|
0b4b25a11e | ||
|
|
1176fe984a | ||
|
|
6ca768c3ee | ||
|
|
3da1659c8d | ||
|
|
9aa4cd319c | ||
|
|
5af866cdca | ||
|
|
2b421fa447 | ||
|
|
30ec964325 | ||
|
|
714d7d72eb | ||
|
|
687aa0f363 | ||
|
|
8363ab07a7 | ||
|
|
c46a757339 | ||
|
|
557864395b | ||
|
|
3f7a85d80b | ||
|
|
8d18d2ce1f | ||
|
|
7141ba1587 | ||
|
|
44d350a225 | ||
|
|
239b8e72d9 | ||
|
|
279bdb6fb1 | ||
|
|
a0cea819da | ||
|
|
9ab7f60544 | ||
|
|
aaf7191bf3 | ||
|
|
628c9be0c8 | ||
|
|
733052720c | ||
|
|
a10f007194 | ||
|
|
6fa50c58d3 | ||
|
|
c54a58d6e4 | ||
|
|
34cb1ea3fd | ||
|
|
f640b0ca91 | ||
|
|
60e16da42e | ||
|
|
0cdceb95d6 | ||
|
|
70bd22d925 | ||
|
|
82462dd647 | ||
|
|
c0466e943d | ||
|
|
b187b4695d | ||
|
|
b1956d2a37 | ||
|
|
590b622e5f | ||
|
|
3d8174396a | ||
|
|
b8dc6e9bd9 | ||
|
|
8ee99109dc | ||
|
|
902041d4ee | ||
|
|
cc34aef47e | ||
|
|
0afbbe7c7a | ||
|
|
8004553ba7 | ||
|
|
0023b2846a | ||
|
|
34775c1816 | ||
|
|
e0759e704b | ||
|
|
0aa225ca78 | ||
|
|
b43b4ee5c0 | ||
|
|
0cdb8cecbf | ||
|
|
fd6a306742 | ||
|
|
7f3b3d2277 | ||
|
|
8be5b977bf | ||
|
|
d7ddb15f9c | ||
|
|
9a6a1798d0 | ||
|
|
14196fd349 | ||
|
|
941b89a523 | ||
|
|
a5f9e5f8c0 | ||
|
|
80c3356c8f | ||
|
|
914136b750 | ||
|
|
f9a60795f5 | ||
|
|
19640927c7 | ||
|
|
22faac7e36 | ||
|
|
30d260ab32 | ||
|
|
115120d066 | ||
|
|
1327844736 | ||
|
|
29904f3cb7 | ||
|
|
50395594b7 | ||
|
|
9360af88b3 | ||
|
|
376370336c | ||
|
|
70df6e3302 | ||
|
|
0a1fc2dc12 | ||
|
|
9857f6e437 | ||
|
|
56d6ebe916 | ||
|
|
81134ea2d4 | ||
|
|
a9f3e7fc54 | ||
|
|
eb84e2f8c9 | ||
|
|
61cfa0e86d | ||
|
|
0a01b8ade9 | ||
|
|
1457efa9a4 | ||
|
|
fa5c7add7a | ||
|
|
d644eba4d1 | ||
|
|
9c422c1a8f | ||
|
|
b6db37202f | ||
|
|
4ca3891089 | ||
|
|
4c7ed01776 | ||
|
|
45c922c377 | ||
|
|
f854c258bd | ||
|
|
a643fac073 | ||
|
|
861f105bea | ||
|
|
bf10ce9f1e | ||
|
|
ccf521d0a8 | ||
|
|
6075d98eaa | ||
|
|
a3801fc243 | ||
|
|
a1f0c05f3a | ||
|
|
a568c96929 | ||
|
|
d58bcf3c0e | ||
|
|
985f2e6436 | ||
|
|
ad441fa793 | ||
|
|
316300cc86 | ||
|
|
5c4f37b234 | ||
|
|
77b51a072d | ||
|
|
2536e1ae6a | ||
|
|
14822c9599 | ||
|
|
e53c37adc9 | ||
|
|
c37539354c | ||
|
|
ae0277f33c | ||
|
|
b863896249 | ||
|
|
5b42f8b743 | ||
|
|
3883fab614 | ||
|
|
61d6bcec4b | ||
|
|
3b5902b033 | ||
|
|
3a88c21a3b | ||
|
|
91a5055dee | ||
|
|
7befd1469f | ||
|
|
c72ebe495c | ||
|
|
19e06b97e6 | ||
|
|
7519825303 | ||
|
|
d9315bf309 | ||
|
|
8c36c809a0 | ||
|
|
8138aa3cb2 | ||
|
|
87aef3ca78 | ||
|
|
a3f1d26d6b | ||
|
|
06cebc5670 | ||
|
|
867fd62d77 | ||
|
|
650cdf2916 | ||
|
|
ebf461f2fd | ||
|
|
27fa319b2a | ||
|
|
d95ac894f4 | ||
|
|
ae84a8dd11 | ||
|
|
2fc963f986 | ||
|
|
be1f938ebd | ||
|
|
cccf4d503d | ||
|
|
9dad2a8ac6 | ||
|
|
75af104f07 | ||
|
|
76ecba245b | ||
|
|
3697c2ced8 | ||
|
|
b9d1d84716 | ||
|
|
64b2d547ce | ||
|
|
d8d2ff7e4e | ||
|
|
8aa5dc6482 | ||
|
|
474ba20e61 | ||
|
|
bdea2d02a9 | ||
|
|
c4307481f1 | ||
|
|
b8ac1b28bd | ||
|
|
24038cda95 | ||
|
|
86c82e9608 | ||
|
|
daab5d150b | ||
|
|
9ff82bdb90 | ||
|
|
c6d70ef1cf | ||
|
|
15d4bb3c76 | ||
|
|
3e698981fd | ||
|
|
9d45c934a5 | ||
|
|
c2bf9cf93e | ||
|
|
b3c6fd7f26 | ||
|
|
ccd155de71 | ||
|
|
1f90d2e46b | ||
|
|
4c5d974c22 | ||
|
|
392eda1cbc | ||
|
|
a9da3279e8 | ||
|
|
1ce8351180 | ||
|
|
96c334478a | ||
|
|
f1b0875b05 | ||
|
|
cea9e11c83 | ||
|
|
f098b39200 | ||
|
|
012d948b59 | ||
|
|
3334cd0a71 | ||
|
|
d63d53fd88 | ||
|
|
a7fa39b2fd | ||
|
|
40bb42e193 | ||
|
|
9c382c639b | ||
|
|
a43cde38f1 | ||
|
|
c35d2e08cd | ||
|
|
3377c383c1 | ||
|
|
c00e6d95cd | ||
|
|
725fccf4ed | ||
|
|
13129bd219 | ||
|
|
4561977bcf | ||
|
|
40be8a91f5 | ||
|
|
2a04d5830b | ||
|
|
82a38574f3 | ||
|
|
fea3a33c2b | ||
|
|
9a502cdf6f | ||
|
|
4b616299cf | ||
|
|
102243e064 | ||
|
|
4b21ac5ebe | ||
|
|
4dd7363dd3 | ||
|
|
3d5e5ab78f | ||
|
|
73045a1b21 | ||
|
|
871173a7cf | ||
|
|
0002313093 | ||
|
|
948cf5cca6 | ||
|
|
d40230879c | ||
|
|
ab22b775f1 | ||
|
|
42c85224ba | ||
|
|
e57444a353 | ||
|
|
3c6503d495 | ||
|
|
149b518f48 | ||
|
|
74621447ff | ||
|
|
3280952931 | ||
|
|
9e670e2736 | ||
|
|
9fc6347a2f | ||
|
|
ec7a15a192 | ||
|
|
7f99982810 | ||
|
|
935d83aaf8 | ||
|
|
0ff6edd546 | ||
|
|
94f629585a | ||
|
|
89c04be02f | ||
|
|
3151965ea8 | ||
|
|
bdf5159be1 | ||
|
|
0499ebbea3 | ||
|
|
d5843b7236 | ||
|
|
1c9c574a90 | ||
|
|
39acf20e48 | ||
|
|
52eb6ed5ab | ||
|
|
ee78d2d59d | ||
|
|
60dc5c4a38 | ||
|
|
50a0dc0355 | ||
|
|
3f681ec914 | ||
|
|
0bf499f191 | ||
|
|
389695a0d6 | ||
|
|
07f1afb312 | ||
|
|
ae91e61304 | ||
|
|
6248991b01 | ||
|
|
7f2d57ef62 | ||
|
|
31f8f884f1 | ||
|
|
4f4af5985a | ||
|
|
a716fdf6d4 | ||
|
|
9717f64abd | ||
|
|
adf239183a | ||
|
|
6cf209c79c | ||
|
|
decc5fb3c0 | ||
|
|
1e0820d613 | ||
|
|
70124d5177 | ||
|
|
269de65201 | ||
|
|
1d11abbfb6 | ||
|
|
700f308d6e | ||
|
|
21b6928ca6 | ||
|
|
998c67a649 | ||
|
|
fb99e878b0 | ||
|
|
1619adfc27 | ||
|
|
5510fb473f | ||
|
|
be1878cb2b | ||
|
|
15ab121cbd | ||
|
|
aa79b0e861 | ||
|
|
b80e550bcd | ||
|
|
dbc40b5814 | ||
|
|
0d5696a644 | ||
|
|
ceffa05802 | ||
|
|
d5668920b6 | ||
|
|
516f2da144 | ||
|
|
33c94e1888 | ||
|
|
51ab58cd91 | ||
|
|
aa7798d1d1 | ||
|
|
9067a1fc92 | ||
|
|
4024b6c564 | ||
|
|
d39730928b | ||
|
|
e1f049229c | ||
|
|
8f2676ec19 | ||
|
|
32d26248dc | ||
|
|
16f926401b | ||
|
|
66d60d3599 | ||
|
|
5a35ab6c34 | ||
|
|
ba1542bd31 | ||
|
|
453060945a | ||
|
|
c8351be461 | ||
|
|
9954da22a6 | ||
|
|
907b5611eb | ||
|
|
5f075de212 | ||
|
|
8fcf3c5079 | ||
|
|
07cee90c7a | ||
|
|
75ad495b98 | ||
|
|
0bb7288ad2 | ||
|
|
ad72415532 | ||
|
|
0ad0353fc0 | ||
|
|
9fa0dcd7aa | ||
|
|
1f2e80cd39 | ||
|
|
6cb6034d43 | ||
|
|
25134c6ac6 | ||
|
|
92bf42878a | ||
|
|
9f4582d158 |
No files matched your search
+3
-3
@@ -5,7 +5,7 @@ root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf|crlf
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
@@ -15,7 +15,7 @@ charset = utf-8
|
||||
# 2 space indentation
|
||||
[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
indent_size = 4
|
||||
|
||||
# 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.
|
||||
# You'll need to rely on your linter/formatter like ESLint or Prettier for that.
|
||||
@@ -1 +0,0 @@
|
||||
VITE_BUILD_TYPE = Development
|
||||
@@ -0,0 +1,2 @@
|
||||
VITE_BUILD_TYPE = Production
|
||||
VITE_BUILD_PLATFORM = Framework
|
||||
@@ -1 +1,2 @@
|
||||
VITE_BUILD_TYPE = Production
|
||||
VITE_BUILD_PLATFORM = Shell
|
||||
+59
-63
@@ -1,68 +1,64 @@
|
||||
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': {
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es2021': true,
|
||||
'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
|
||||
}
|
||||
'ignorePatterns': ['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',
|
||||
4
|
||||
],
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix'
|
||||
],
|
||||
'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'],
|
||||
}
|
||||
},
|
||||
'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'],
|
||||
}
|
||||
};
|
||||
+16
-24
@@ -1,4 +1,4 @@
|
||||
name: "Build"
|
||||
name: "Build Action"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
@@ -8,14 +8,9 @@ on:
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
Build-LiteLoader:
|
||||
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
|
||||
@@ -28,26 +23,22 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Build NuCat Linux
|
||||
- name: Build NuCat Framework
|
||||
run: |
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
npm i
|
||||
npm run build:framework
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm i --omit=dev
|
||||
rm package-lock.json
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
name: NapCat.Framework
|
||||
path: dist
|
||||
build-win32:
|
||||
Build-Shell:
|
||||
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
|
||||
@@ -60,15 +51,16 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Build NuCat Linux
|
||||
- name: Build NuCat LiteLoader
|
||||
run: |
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
npm i
|
||||
npm run build:shell
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm i --omit=dev
|
||||
rm package-lock.json
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
name: NapCat.Shell
|
||||
path: dist
|
||||
@@ -1,4 +1,4 @@
|
||||
name: "release"
|
||||
name: "Build Release"
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -30,14 +30,9 @@ jobs:
|
||||
ls
|
||||
node ./script/checkVersion.cjs
|
||||
sh ./checkVersion.sh
|
||||
build-linux:
|
||||
Build-LiteLoader:
|
||||
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
|
||||
@@ -51,28 +46,21 @@ jobs:
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Build NuCat Linux
|
||||
- name: Build NuCat Framework
|
||||
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
|
||||
npm i
|
||||
npm run build:framework
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm i --omit=dev
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
name: NapCat.Framework
|
||||
path: dist
|
||||
build-win32:
|
||||
Build-Shell:
|
||||
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
|
||||
@@ -87,24 +75,22 @@ jobs:
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Build NuCat Linux
|
||||
- name: Build NuCat Shell
|
||||
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
|
||||
npm i
|
||||
npm run build:shell
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm i --omit=dev
|
||||
cd ..
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
name: NapCat.Shell
|
||||
path: dist
|
||||
|
||||
release-napcat:
|
||||
needs: [build-win32,build-linux]
|
||||
needs: [Build-LiteLoader,Build-Shell]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download All Artifact
|
||||
@@ -130,9 +116,8 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body_path: CHANGELOG.md
|
||||
files: |
|
||||
NapCat.win32.x64.zip
|
||||
NapCat.linux.x64.zip
|
||||
NapCat.linux.arm64.zip
|
||||
NapCat.Framework.zip
|
||||
NapCat.Shell.zip
|
||||
# NapCat.darwin.x64.zip
|
||||
# NapCat.darwin.arm64.zip
|
||||
draft: true
|
||||
+2
-1
@@ -14,4 +14,5 @@ dist/
|
||||
|
||||
# Build
|
||||
*.db
|
||||
checkVersion.sh
|
||||
checkVersion.sh
|
||||
bun.lockb
|
||||
@@ -1,4 +0,0 @@
|
||||
[submodule "src/core"]
|
||||
path = src/core
|
||||
url = https://github.com/NapNeko/core.git
|
||||
branch = master
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"printWidth": 120,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
@@ -1,21 +1,339 @@
|
||||
MIT License
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (c) 2024 NapCatQQ
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
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:
|
||||
Preamble
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
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.
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -2,32 +2,33 @@
|
||||
<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>
|
||||
|
||||
---
|
||||
|
||||
## 项目介绍
|
||||
NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现。
|
||||
|
||||
NapCatQQ 是基于 PC NTQQ 本体实现一套无头 Bot 框架。
|
||||
|
||||
名字寓意 瞌睡猫QQ,像睡着了一样在后台低占用运行的无需GUI界面的NTQQ。
|
||||
## 项目优势
|
||||
- [x] **多种启动方式**:支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
|
||||
- [x] **低占用**:无头模式占用资源极低,适合在服务器上运行
|
||||
- [x] **WebUI**:自带 WebUI 支持,远程管理更加便捷
|
||||
|
||||
## 如何使用
|
||||
|
||||
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
|
||||
|
||||
**首次使用** 请务必前往 [官方文档](https://napneko.github.io/) 查看使用文档与教程
|
||||
**首次使用**请务必前往[官方文档](https://napneko.github.io/)查看使用教程。
|
||||
|
||||
|
||||
## 项目声明
|
||||
|
||||
* 请不要在无关地方宣传NapCatQQ,本项目只是用于学习 node 相关知识,切勿用于违法用途
|
||||
|
||||
* NapCat 不会收集用户隐私信息,但是未来可能会为了更好的利于 NapCat 的优化会收集一些设备信息,如 cpu 架构,系统版本等
|
||||
|
||||
## 相关链接
|
||||
|
||||
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
||||
|
||||
## 附加协议
|
||||
禁止未授权任何项目使用Core部分代码用于二次开发与分发
|
||||
|
||||
## 鸣谢名单
|
||||
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供初始版本基础
|
||||
|
||||
[Lagrange](https://github.com/LagrangeDev/Lagrange.Core)
|
||||
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
|
||||
|
||||
<!--
|
||||
QQ群:545402644
|
||||
-->
|
||||
---
|
||||
**任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**
|
||||
@@ -1,17 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,18 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,11 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,15 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,11 +0,0 @@
|
||||
# v1.3.9
|
||||
|
||||
QQ Version: Windows 9.9.10-23873 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修复QQ等级获取与兼容性问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
@@ -1,12 +0,0 @@
|
||||
# v1.4.0
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
|
||||
## 新增与调整
|
||||
* 支持空间Cookies获取
|
||||
* 支持获取在线设备 API /get_online_clients
|
||||
* 支持图片OCR API: /.ocr_image /ocr_image
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"manifest_version": 4,
|
||||
"type": "extension",
|
||||
"name": "NapCat",
|
||||
"slug": "NapCat",
|
||||
"description": "OneBot v11 protocol implementation with NapCat logic",
|
||||
"version": "2.0.2",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
"name": "MliKiowa",
|
||||
"link": "https://github.com/MliKiowa"
|
||||
},
|
||||
{
|
||||
"name": "Young",
|
||||
"link": "https://github.com/Wesley-Young"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"repo": "NapNeko/NapCatQQ",
|
||||
"branch": "main"
|
||||
},
|
||||
"platform": [
|
||||
"win32",
|
||||
"linux",
|
||||
"darwin"
|
||||
],
|
||||
"injects": {
|
||||
"renderer": "./renderer.js",
|
||||
"main": "./liteloader.cjs",
|
||||
"preload": "./preload.cjs"
|
||||
}
|
||||
}
|
||||
+65
-66
@@ -1,66 +1,65 @@
|
||||
{
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "1.4.0",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "2.0.2",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
"build:webui": "cd ./src/webui && vite build",
|
||||
"lint": "eslint --fix src/**/*.{js,ts}",
|
||||
"depend": "cd dist && npm install --omit=dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.24.7",
|
||||
"@babel/preset-typescript": "^7.24.7",
|
||||
"@log4js-node/log4js-api": "^1.0.2",
|
||||
"@protobuf-ts/plugin": "^2.9.4",
|
||||
"@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/jest": "^29.5.12",
|
||||
"@types/node": "^22.0.1",
|
||||
"@types/qrcode-terminal": "^0.12.2",
|
||||
"@types/ws": "^8.5.12",
|
||||
"@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-babel": "^1.2.0",
|
||||
"vite-plugin-cp": "^4.0.8",
|
||||
"vite-plugin-dts": "^3.8.2",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.13.0",
|
||||
"async-mutex": "^0.5.0",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.1.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.6.1",
|
||||
"strtok3": "8.0.1",
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
# Dont Use This Script
|
||||
# 2024.7.3
|
||||
function Get-QQpath {
|
||||
try {
|
||||
$key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ"
|
||||
@@ -40,4 +42,4 @@ if (!(Test-Path $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}"
|
||||
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& chcp 65001;& '$($commandInfo.Path)' --enable-logging }"
|
||||
@@ -0,0 +1,90 @@
|
||||
@echo off
|
||||
REM 检查当前会话是否具有管理员权限
|
||||
openfiles >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
REM 如果不是管理员,则重新启动脚本以管理员模式运行
|
||||
echo 请求管理员权限...
|
||||
powershell -Command "Start-Process cmd -ArgumentList '/c %~f0 %*' -Verb RunAs"
|
||||
exit /b
|
||||
)
|
||||
|
||||
REM 设置当前工作目录
|
||||
cd /d %~dp0
|
||||
|
||||
REM 获取当前目录路径
|
||||
set currentPath=%cd%
|
||||
set currentPath=%currentPath:\=/%
|
||||
|
||||
REM 生成JavaScript代码
|
||||
set "jsCode=(async () =^>await import('file:///%currentPath%/napcat.mjs'))();"
|
||||
|
||||
REM 将JavaScript代码保存到文件中
|
||||
echo %jsCode% > loadScript.js
|
||||
echo JavaScript code has been generated and saved to loadScript.js
|
||||
|
||||
REM 设置NAPCAT_PATH环境变量为 当前目录的loadScript.js地址
|
||||
set NAPCAT_PATH=%cd%\loadScript.js
|
||||
|
||||
REM 获取QQ路径
|
||||
|
||||
|
||||
: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
|
||||
|
||||
REM 拿不到QQ路径则退出
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
REM 收集dbghelp.dll路径和HASH信息
|
||||
set QQdir=%~dp0
|
||||
set oldDllPath=%QQdir%dbghelp.dll
|
||||
set newDllPath=%currentPath%\dbghelp.dll
|
||||
|
||||
for /f "tokens=*" %%A in ('certutil -hashfile "%oldDllPath%" MD5') do (
|
||||
if not defined oldDllHash set oldDllHash=%%A
|
||||
)
|
||||
for /f "tokens=*" %%A in ('certutil -hashfile "%newDllPath%" MD5') do (
|
||||
if not defined newDllHash set newDllHash=%%A
|
||||
)
|
||||
|
||||
REM 如果文件一致则跳过
|
||||
if "%oldDllHash%" neq "%newDllHash%" (
|
||||
tasklist /fi "imagename eq QQ.exe" 2>nul | find /i "QQ.exe" >nul
|
||||
if %errorlevel% equ 0 (
|
||||
REM 文件占用则退出
|
||||
echo dbghelp.dll is in use, cannot continue.
|
||||
) else (
|
||||
REM 文件未占用则尝试覆盖
|
||||
copy /y "%newDllPath%" "%oldDllPath%"
|
||||
if %errorlevel% neq 0 (
|
||||
echo Failed to copy dbghelp.dll
|
||||
pause
|
||||
exit /b
|
||||
) else (
|
||||
echo dbghelp.dll has been copied to %QQdir%
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
REM 带参数启动QQ
|
||||
REM 判断wt是否存在,存在则通过wt启动,不存在则通过cmd启动
|
||||
REM %QQPath% --enable-logging %*
|
||||
where wt >nul 2>nul
|
||||
if %errorlevel% equ 0 (
|
||||
wt "cmd" /c "%QQPath%" --enable-logging %*
|
||||
) else (
|
||||
"%QQPath%" --enable-logging %*
|
||||
)
|
||||
@@ -0,0 +1,123 @@
|
||||
# 检查当前会话是否具有管理员权限
|
||||
function Test-Administrator {
|
||||
$user = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
(New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
|
||||
}
|
||||
|
||||
if (-not (Test-Administrator)) {
|
||||
# 如果不是管理员,则重新启动脚本以管理员模式运行
|
||||
$scriptPath = $myInvocation.MyCommand.Path
|
||||
if (-not $scriptPath) {
|
||||
$scriptPath = $PSCommandPath
|
||||
}
|
||||
$newProcess = New-Object System.Diagnostics.ProcessStartInfo "powershell";
|
||||
$newProcess.Arguments = "-File `"$scriptPath`" $args"
|
||||
$newProcess.Verb = "runas";
|
||||
[System.Diagnostics.Process]::Start($newProcess);
|
||||
exit
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
# 设置当前工作目录
|
||||
$scriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
||||
Set-Location $scriptDirectory
|
||||
|
||||
# 获取当前目录路径
|
||||
$currentPath = Get-Location
|
||||
|
||||
# 替换\为/
|
||||
$currentPath = $currentPath -replace '\\', '/'
|
||||
|
||||
# 生成JavaScript代码
|
||||
$jsCode = @"
|
||||
(async () => {
|
||||
await import('file:///$currentPath/napcat.mjs');
|
||||
})();
|
||||
"@
|
||||
|
||||
# 将JavaScript代码保存到文件中
|
||||
$jsFilePath = Join-Path $currentPath "loadScript.js"
|
||||
$jsCode | Out-File -FilePath $jsFilePath -Encoding UTF8
|
||||
|
||||
Write-Output "JavaScript code has been generated and saved to $jsFilePath"
|
||||
# 设置NAPCAT_PATH环境变量为 当前目录的loadScript.js地址
|
||||
$env:NAPCAT_PATH = $jsFilePath
|
||||
|
||||
$params = $args -join " "
|
||||
Try {
|
||||
$QQpath = Get-QQpath
|
||||
}
|
||||
Catch {
|
||||
$QQpath = Select-QQPath
|
||||
}
|
||||
# 拿不到QQ路径则退出
|
||||
if (!(Test-Path $QQpath)) {
|
||||
Write-Output "provided QQ path is invalid: $QQpath"
|
||||
Read-Host "Press any key to continue..."
|
||||
exit
|
||||
}
|
||||
|
||||
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
||||
|
||||
# 收集dbghelp.dll路径和HASH信息
|
||||
$QQpath = Split-Path $QQpath
|
||||
$oldDllPath = Join-Path $QQpath "dbghelp.dll"
|
||||
$oldDllHash = Get-FileHash $oldDllPath -Algorithm MD5
|
||||
$newDllPath = Join-Path $currentPath "dbghelp.dll"
|
||||
$newDllHash = Get-FileHash $newDllPath -Algorithm MD5
|
||||
# 如果文件一致则跳过
|
||||
if ($oldDllHash.Hash -ne $newDllHash.Hash) {
|
||||
$processes = Get-Process -Name QQ -ErrorAction SilentlyContinue
|
||||
if ($processes) {
|
||||
# 文件占用则退出
|
||||
Write-Output "dbghelp.dll is in use by the following processes:"
|
||||
$processes | ForEach-Object { Write-Output "$($_.Id) $($_.Name) $($_.Path)" }
|
||||
Write-Output "dbghelp.dll is in use, cannot continue."
|
||||
Read-Host "Press any key to continue..."
|
||||
exit
|
||||
} else {
|
||||
# 文件未占用则尝试覆盖
|
||||
try {
|
||||
Copy-Item -Path "$newDllPath" -Destination "$oldDllPath" -Force
|
||||
Write-Output "dbghelp.dll has been copied to $QQpath"
|
||||
} catch {
|
||||
Write-Output "Failed to copy dbghelp.dll: $_"
|
||||
Read-Host "Press any key to continue..."
|
||||
exit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 带参数启动QQ
|
||||
try {
|
||||
Start-Process powershell -ArgumentList '-noexit', '-noprofile', "-command &{& chcp 65001;& '$($commandInfo.Path)' --enable-logging $params}" -NoNewWindow -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Output "Failed to start process as administrator: $_"
|
||||
Read-Host "Press any key to continue..."
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
@echo off
|
||||
REM 检查当前会话是否具有管理员权限
|
||||
openfiles >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
REM 如果不是管理员,则重新启动脚本以管理员模式运行
|
||||
echo 请求管理员权限...
|
||||
where wt >nul 2>nul
|
||||
if %errorlevel% equ 0 (
|
||||
powershell -Command "Start-Process cmd -ArgumentList ' /c %~f0 %*' -Verb RunAs"
|
||||
) else (
|
||||
powershell -Command "Start-Process wt -ArgumentList 'cmd /c %~f0 %*' -Verb RunAs"
|
||||
)
|
||||
|
||||
REM wt "cmd" /c "%~f0 %*"
|
||||
exit /b
|
||||
)
|
||||
|
||||
REM 设置当前工作目录
|
||||
cd /d %~dp0
|
||||
|
||||
REM 获取当前目录路径
|
||||
set currentPath=%cd%
|
||||
set currentPath=%currentPath:\=/%
|
||||
|
||||
REM 生成JavaScript代码
|
||||
set "jsCode=(async () =^>await import('file:///%currentPath%/napcat.mjs'))();"
|
||||
|
||||
REM 将JavaScript代码保存到文件中
|
||||
echo %jsCode% > loadScript.js
|
||||
echo JavaScript code has been generated and saved to loadScript.js
|
||||
|
||||
REM 设置NAPCAT_PATH环境变量为 当前目录的loadScript.js地址
|
||||
set NAPCAT_PATH=%cd%\loadScript.js
|
||||
|
||||
REM 获取QQ路径
|
||||
|
||||
|
||||
: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
|
||||
|
||||
REM 拿不到QQ路径则退出
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
REM 收集dbghelp.dll路径和HASH信息
|
||||
set QQdir=%~dp0
|
||||
set oldDllPath=%QQdir%dbghelp.dll
|
||||
set newDllPath=%currentPath%\dbghelp.dll
|
||||
|
||||
for /f "tokens=*" %%A in ('certutil -hashfile "%oldDllPath%" MD5') do (
|
||||
if not defined oldDllHash set oldDllHash=%%A
|
||||
)
|
||||
for /f "tokens=*" %%A in ('certutil -hashfile "%newDllPath%" MD5') do (
|
||||
if not defined newDllHash set newDllHash=%%A
|
||||
)
|
||||
|
||||
REM 如果文件一致则跳过
|
||||
if "%oldDllHash%" neq "%newDllHash%" (
|
||||
tasklist /fi "imagename eq QQ.exe" 2>nul | find /i "QQ.exe" >nul
|
||||
if %errorlevel% equ 0 (
|
||||
REM 文件占用则退出
|
||||
echo dbghelp.dll is in use, cannot continue.
|
||||
) else (
|
||||
REM 文件未占用则尝试覆盖
|
||||
copy /y "%newDllPath%" "%oldDllPath%"
|
||||
if %errorlevel% neq 0 (
|
||||
echo Failed to copy dbghelp.dll
|
||||
pause
|
||||
exit /b
|
||||
) else (
|
||||
echo dbghelp.dll has been copied to %QQdir%
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
REM 带参数启动QQ
|
||||
REM 判断wt是否存在,存在则通过wt启动,不存在则通过cmd启动
|
||||
REM %QQPath% --enable-logging %*
|
||||
chcp 65001
|
||||
"%QQPath%" --enable-logging %*
|
||||
@@ -11,7 +11,7 @@ try {
|
||||
|
||||
// 验证 targetVersion 格式
|
||||
if (!targetVersion || typeof targetVersion !== 'string') {
|
||||
console.error("[NapCat] [CheckVersion] 目标版本格式不正确或未设置!");
|
||||
console.log("[NapCat] [CheckVersion] 目标版本格式不正确或未设置!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -38,5 +38,5 @@ try {
|
||||
writeScriptToFile(safeScriptContent);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[NapCat] [CheckVersion] 检测过程中发生错误:", error);
|
||||
console.log("[NapCat] [CheckVersion] 检测过程中发生错误:", error);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
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);
|
||||
Binary file not shown.
@@ -1,21 +0,0 @@
|
||||
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)
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
chcp 65001
|
||||
set ELECTRON_RUN_AS_NODE=1
|
||||
"H:\Program Files\QQNT最新版\QQ.exe" %~dp0/napcat.cjs %*
|
||||
@@ -1,15 +0,0 @@
|
||||
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}"
|
||||
@@ -1,17 +0,0 @@
|
||||
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
|
||||
@@ -1,18 +0,0 @@
|
||||
@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 %*
|
||||
@@ -1,17 +0,0 @@
|
||||
@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 %*
|
||||
@@ -1,43 +0,0 @@
|
||||
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}"
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/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" "$@"
|
||||
@@ -0,0 +1,263 @@
|
||||
import { NodeIQQNTWrapperSession } from '@/core/wrapper/wrapper';
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
interface Internal_MapKey {
|
||||
timeout: number;
|
||||
createtime: number;
|
||||
func: (...arg: any[]) => any;
|
||||
checker: ((...args: any[]) => boolean) | undefined;
|
||||
}
|
||||
|
||||
export type ListenerClassBase = Record<string, string>;
|
||||
|
||||
export interface ListenerIBase {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: any): ListenerClassBase;
|
||||
}
|
||||
|
||||
export class LegacyNTEventWrapper {
|
||||
private listenerMapping: Record<string, ListenerIBase>; //ListenerName-Unique -> Listener构造函数
|
||||
private WrapperSession: NodeIQQNTWrapperSession | undefined; //WrapperSession
|
||||
private listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); //ListenerName-Unique -> Listener实例
|
||||
private EventTask = new Map<string, Map<string, Map<string, Internal_MapKey>>>(); //tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
||||
|
||||
constructor(
|
||||
listenerMapping: Record<string, ListenerIBase>,
|
||||
wrapperSession: NodeIQQNTWrapperSession,
|
||||
) {
|
||||
this.listenerMapping = listenerMapping;
|
||||
this.WrapperSession = wrapperSession;
|
||||
}
|
||||
|
||||
createProxyDispatch(ListenerMainName: string) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const current = this;
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target: any, prop: any, receiver: any) {
|
||||
// console.log('get', prop, typeof target[prop]);
|
||||
if (typeof target[prop] === 'undefined') {
|
||||
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
||||
return (...args: any[]) => {
|
||||
current.dispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then();
|
||||
};
|
||||
}
|
||||
// 如果方法存在,正常返回
|
||||
return Reflect.get(target, prop, receiver);
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
createEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
|
||||
const eventNameArr = eventName.split('/');
|
||||
type eventType = {
|
||||
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> };
|
||||
};
|
||||
if (eventNameArr.length > 1) {
|
||||
const serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', '');
|
||||
const eventName = eventNameArr[1];
|
||||
//getNodeIKernelGroupListener,GroupService
|
||||
//console.log('2', eventName);
|
||||
const services = (this.WrapperSession as unknown as eventType)[serviceName]();
|
||||
let event = services[eventName];
|
||||
//重新绑定this
|
||||
event = event.bind(services);
|
||||
if (event) {
|
||||
return event as T;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
createListenerFunction<T>(listenerMainName: string, uniqueCode: string = ''): T {
|
||||
const ListenerType = this.listenerMapping![listenerMainName];
|
||||
let Listener = this.listenerManager.get(listenerMainName + uniqueCode);
|
||||
if (!Listener && ListenerType) {
|
||||
Listener = new ListenerType(this.createProxyDispatch(listenerMainName));
|
||||
const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1];
|
||||
const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener';
|
||||
const addfunc = this.createEventFunction<(listener: T) => number>(Service);
|
||||
addfunc!(Listener as T);
|
||||
//console.log(addfunc!(Listener as T));
|
||||
this.listenerManager.set(listenerMainName + uniqueCode, Listener);
|
||||
}
|
||||
return Listener as T;
|
||||
}
|
||||
|
||||
//统一回调清理事件
|
||||
async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||
//console.log("[EventDispatcher]",ListenerMainName, ListenerSubName, ...args);
|
||||
this.EventTask.get(ListenerMainName)
|
||||
?.get(ListenerSubName)
|
||||
?.forEach((task, uuid) => {
|
||||
//console.log(task.func, uuid, task.createtime, task.timeout);
|
||||
if (task.createtime + task.timeout < Date.now()) {
|
||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.delete(uuid);
|
||||
return;
|
||||
}
|
||||
if (task.checker && task.checker(...args)) {
|
||||
task.func(...args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async callNoListenerEvent<EventType extends (...args: any[]) => Promise<any> | any>(
|
||||
EventName = '',
|
||||
timeout: number = 3000,
|
||||
...args: Parameters<EventType>
|
||||
) {
|
||||
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||
const EventFunc = this.createEventFunction<EventType>(EventName);
|
||||
let complete = false;
|
||||
setTimeout(() => {
|
||||
if (!complete) {
|
||||
reject(new Error('NTEvent EventName:' + EventName + ' timeout'));
|
||||
}
|
||||
}, timeout);
|
||||
const retData = await EventFunc!(...args);
|
||||
complete = true;
|
||||
resolve(retData);
|
||||
});
|
||||
}
|
||||
|
||||
async RegisterListen<ListenerType extends (...args: any[]) => void>(
|
||||
ListenerName = '',
|
||||
waitTimes = 1,
|
||||
timeout = 5000,
|
||||
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||
) {
|
||||
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
||||
const ListenerNameList = ListenerName.split('/');
|
||||
const ListenerMainName = ListenerNameList[0];
|
||||
const ListenerSubName = ListenerNameList[1];
|
||||
const id = randomUUID();
|
||||
let complete = 0;
|
||||
let retData: Parameters<ListenerType> | undefined = undefined;
|
||||
const databack = () => {
|
||||
if (complete == 0) {
|
||||
reject(new Error(' ListenerName:' + ListenerName + ' timeout'));
|
||||
} else {
|
||||
resolve(retData!);
|
||||
}
|
||||
};
|
||||
const timeoutRef = setTimeout(databack, timeout);
|
||||
const eventCallbak = {
|
||||
timeout: timeout,
|
||||
createtime: Date.now(),
|
||||
checker: checker,
|
||||
func: (...args: Parameters<ListenerType>) => {
|
||||
complete++;
|
||||
retData = args;
|
||||
if (complete >= waitTimes) {
|
||||
clearTimeout(timeoutRef);
|
||||
databack();
|
||||
}
|
||||
},
|
||||
};
|
||||
if (!this.EventTask.get(ListenerMainName)) {
|
||||
this.EventTask.set(ListenerMainName, new Map());
|
||||
}
|
||||
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
|
||||
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
|
||||
}
|
||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
|
||||
this.createListenerFunction(ListenerMainName);
|
||||
});
|
||||
}
|
||||
|
||||
async CallNormalEvent<
|
||||
EventType extends (...args: any[]) => Promise<any>,
|
||||
ListenerType extends (...args: any[]) => void
|
||||
>(
|
||||
EventName = '',
|
||||
ListenerName = '',
|
||||
waitTimes = 1,
|
||||
timeout: number = 3000,
|
||||
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||
...args: Parameters<EventType>
|
||||
) {
|
||||
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(
|
||||
async (resolve, reject) => {
|
||||
const id = randomUUID();
|
||||
let complete = 0;
|
||||
let retData: Parameters<ListenerType> | undefined = undefined;
|
||||
let retEvent: any = {};
|
||||
const databack = () => {
|
||||
if (complete == 0) {
|
||||
reject(
|
||||
new Error(
|
||||
'Timeout: NTEvent EventName:' +
|
||||
EventName +
|
||||
' ListenerName:' +
|
||||
ListenerName +
|
||||
' EventRet:\n' +
|
||||
JSON.stringify(retEvent, null, 4) +
|
||||
'\n',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
|
||||
}
|
||||
};
|
||||
|
||||
const ListenerNameList = ListenerName.split('/');
|
||||
const ListenerMainName = ListenerNameList[0];
|
||||
const ListenerSubName = ListenerNameList[1];
|
||||
|
||||
const Timeouter = setTimeout(databack, timeout);
|
||||
|
||||
const eventCallbak = {
|
||||
timeout: timeout,
|
||||
createtime: Date.now(),
|
||||
checker: checker,
|
||||
func: (...args: any[]) => {
|
||||
complete++;
|
||||
//console.log('func', ...args);
|
||||
retData = args as Parameters<ListenerType>;
|
||||
if (complete >= waitTimes) {
|
||||
clearTimeout(Timeouter);
|
||||
databack();
|
||||
}
|
||||
},
|
||||
};
|
||||
if (!this.EventTask.get(ListenerMainName)) {
|
||||
this.EventTask.set(ListenerMainName, new Map());
|
||||
}
|
||||
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
|
||||
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
|
||||
}
|
||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
|
||||
this.createListenerFunction(ListenerMainName);
|
||||
const EventFunc = this.createEventFunction<EventType>(EventName);
|
||||
retEvent = await EventFunc!(...(args as any[]));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 示例代码 快速创建事件
|
||||
// let NTEvent = new NTEventWrapper();
|
||||
// let TestEvent = NTEvent.CreatEventFunction<(force: boolean) => Promise<Number>>('NodeIKernelProfileLikeService/GetTest');
|
||||
// if (TestEvent) {
|
||||
// TestEvent(true);
|
||||
// }
|
||||
|
||||
// 示例代码 快速创建监听Listener类
|
||||
// let NTEvent = new NTEventWrapper();
|
||||
// NTEvent.CreatListenerFunction<NodeIKernelMsgListener>('NodeIKernelMsgListener', 'core')
|
||||
|
||||
// 调用接口
|
||||
//let NTEvent = new NTEventWrapper();
|
||||
//let ret = await NTEvent.CallNormalEvent<(force: boolean) => Promise<Number>, (data1: string, data2: number) => void>('NodeIKernelProfileLikeService/GetTest', 'NodeIKernelMsgListener/onAddSendMsg', 1, 3000, true);
|
||||
|
||||
// 注册监听 解除监听
|
||||
// NTEventDispatch.RigisterListener('NodeIKernelMsgListener/onAddSendMsg','core',cb);
|
||||
// NTEventDispatch.UnRigisterListener('NodeIKernelMsgListener/onAddSendMsg','core');
|
||||
|
||||
// let GetTest = NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode);
|
||||
// GetTest('test');
|
||||
|
||||
// always模式
|
||||
// NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode,(...args:any[])=>{ console.log(args) });
|
||||
@@ -0,0 +1,140 @@
|
||||
import type { NodeIQQNTWrapperSession, WrapperNodeApi } from '@/core/wrapper/wrapper';
|
||||
import EventEmitter from 'node:events';
|
||||
|
||||
export type ListenerClassBase = Record<string, string>;
|
||||
|
||||
export interface ListenerIBase {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: any): ListenerClassBase;
|
||||
}
|
||||
|
||||
export class NTEventChannel extends EventEmitter {
|
||||
private wrapperApi: WrapperNodeApi;
|
||||
private wrapperSession: NodeIQQNTWrapperSession;
|
||||
private listenerRefStorage = new Map<string, ListenerIBase>();
|
||||
|
||||
constructor(WrapperApi: WrapperNodeApi, WrapperSession: NodeIQQNTWrapperSession) {
|
||||
super();
|
||||
this.on('error', () => {
|
||||
});
|
||||
this.wrapperApi = WrapperApi;
|
||||
this.wrapperSession = WrapperSession;
|
||||
}
|
||||
|
||||
dispatcherListener(ListenerEvent: string, ...args: any[]) {
|
||||
this.emit(ListenerEvent, ...args);
|
||||
}
|
||||
|
||||
createProxyDispatch(ListenerMainName: string) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const current = this;
|
||||
return new Proxy({}, {
|
||||
get(_target: any, prop: any, _receiver: any) {
|
||||
return (...args: any[]) => {
|
||||
current.dispatcherListener.apply(current, [ListenerMainName + '/' + prop, ...args]);
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getOrInitListener<T>(listenerMainName: string): Promise<T> {
|
||||
const ListenerType = this.wrapperApi[listenerMainName];
|
||||
//获取NTQQ 外部 Listener包装
|
||||
if (!ListenerType) throw new Error('Init Listener not found');
|
||||
let Listener = this.listenerRefStorage.get(listenerMainName);
|
||||
//判断是否已创建 创建则跳过
|
||||
if (!Listener && ListenerType) {
|
||||
Listener = new ListenerType(this.createProxyDispatch(listenerMainName));
|
||||
if (!Listener) throw new Error('Init Listener failed');
|
||||
//实例化NTQQ Listener外包装
|
||||
const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1];
|
||||
const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener';
|
||||
const addfunc = this.createEventFunction<(listener: T) => number>(Service);
|
||||
//添加Listener到NTQQ
|
||||
addfunc!(Listener as T);
|
||||
this.listenerRefStorage.set(listenerMainName, Listener);
|
||||
//保存Listener实例
|
||||
}
|
||||
return Listener as T;
|
||||
}
|
||||
|
||||
async createEventWithListener<EventType extends (...args: any) => any, ListenerType extends (...args: any) => any>
|
||||
(
|
||||
eventName: string,
|
||||
listenerName: string,
|
||||
waitTimes = 1,
|
||||
timeout: number = 3000,
|
||||
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||
...eventArg: Parameters<EventType>
|
||||
) {
|
||||
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(async (resolve, reject) => {
|
||||
const ListenerNameList = listenerName.split('/');
|
||||
const ListenerMainName = ListenerNameList[0];
|
||||
//const ListenerSubName = ListenerNameList[1];
|
||||
this.getOrInitListener<ListenerType>(ListenerMainName);
|
||||
let complete = 0;
|
||||
const retData: Parameters<ListenerType> | undefined = undefined;
|
||||
let retEvent: any = {};
|
||||
const databack = () => {
|
||||
if (complete == 0) {
|
||||
reject(new Error('Timeout: NTEvent EventName:' + eventName + ' ListenerName:' + listenerName + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n'));
|
||||
} else {
|
||||
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
|
||||
}
|
||||
};
|
||||
const Timeouter = setTimeout(databack, timeout);
|
||||
const callback = (...args: Parameters<ListenerType>) => {
|
||||
if (checker(...args)) {
|
||||
complete++;
|
||||
if (complete >= waitTimes) {
|
||||
clearTimeout(Timeouter);
|
||||
this.removeListener(listenerName, callback);
|
||||
databack();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.on(listenerName, callback);
|
||||
const EventFunc = this.createEventFunction<EventType>(eventName);
|
||||
retEvent = await EventFunc!(...(eventArg as any[]));
|
||||
});
|
||||
}
|
||||
|
||||
private createEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
|
||||
const eventNameArr = eventName.split('/');
|
||||
type eventType = {
|
||||
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> }
|
||||
}
|
||||
if (eventNameArr.length > 1) {
|
||||
const serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', '');
|
||||
const eventName = eventNameArr[1];
|
||||
//getNodeIKernelGroupListener,GroupService
|
||||
//console.log('2', eventName);
|
||||
const services = (this.wrapperSession as unknown as eventType)[serviceName]();
|
||||
const event = services[eventName]
|
||||
//重新绑定this
|
||||
.bind(services);
|
||||
if (event) {
|
||||
return event as T;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async callEvent<EventType extends (...args: any[]) => Promise<any> | any>(
|
||||
EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
||||
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||
const EventFunc = this.createEventFunction<EventType>(EventName);
|
||||
let complete = false;
|
||||
const Timeouter = setTimeout(() => {
|
||||
if (!complete) {
|
||||
reject(new Error('NTEvent EventName:' + EventName + ' timeout'));
|
||||
}
|
||||
}, timeout);
|
||||
const retData = await EventFunc!(...args);
|
||||
complete = true;
|
||||
resolve(retData);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//NTEvent2.0
|
||||
@@ -0,0 +1,30 @@
|
||||
import path, { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fs from 'fs';
|
||||
|
||||
export const napcat_version = '2.0.2';
|
||||
|
||||
export class NapCatPathWrapper {
|
||||
binaryPath: string;
|
||||
logsPath: string;
|
||||
configPath: string;
|
||||
cachePath: string;
|
||||
staticPath: string;
|
||||
|
||||
constructor(mainPath: string = dirname(fileURLToPath(import.meta.url))) {
|
||||
this.binaryPath = mainPath;
|
||||
this.logsPath = path.join(this.binaryPath, 'logs');
|
||||
this.configPath = path.join(this.binaryPath, 'config');
|
||||
this.cachePath = path.join(this.binaryPath, 'cache');
|
||||
this.staticPath = path.join(this.binaryPath, 'static');
|
||||
if (fs.existsSync(this.logsPath)) {
|
||||
fs.mkdirSync(this.logsPath, { recursive: true });
|
||||
}
|
||||
if (fs.existsSync(this.configPath)) {
|
||||
fs.mkdirSync(this.configPath, { recursive: true });
|
||||
}
|
||||
if (fs.existsSync(this.cachePath)) {
|
||||
fs.mkdirSync(this.cachePath, { recursive: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
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() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +1,67 @@
|
||||
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';
|
||||
import type { NapCatCore } from '@/core';
|
||||
|
||||
export abstract class ConfigBase<T> {
|
||||
name: string;
|
||||
coreContext: NapCatCore;
|
||||
configPath: string;
|
||||
configData: T = {} as T;
|
||||
|
||||
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;
|
||||
protected constructor(name: string, coreContext: NapCatCore, configPath: string) {
|
||||
this.name = name;
|
||||
this.coreContext = coreContext;
|
||||
this.configPath = configPath;
|
||||
fs.mkdirSync(this.configPath, { recursive: true });
|
||||
this.read();
|
||||
}
|
||||
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);
|
||||
protected getKeys(): string[] | null {
|
||||
// 决定 key 在json配置文件中的顺序
|
||||
return null;
|
||||
}
|
||||
|
||||
getConfigPath(pathName: string | undefined): string {
|
||||
const suffix = pathName ? `_${pathName}` : '';
|
||||
const filename = `${this.name}${suffix}.json`;
|
||||
return path.join(this.configPath, filename);
|
||||
}
|
||||
|
||||
read(): T {
|
||||
const logger = this.coreContext.context.logger;
|
||||
const configPath = this.getConfigPath(this.coreContext.selfInfo.uin);
|
||||
if (!fs.existsSync(configPath)) {
|
||||
try {
|
||||
fs.writeFileSync(configPath, fs.readFileSync(this.getConfigPath(undefined), 'utf-8'));
|
||||
logger.log(`[Core] [Config] 配置文件创建成功!\n`);
|
||||
} catch (e: any) {
|
||||
logger.logError(`[Core] [Config] 创建配置文件时发生错误:`, e.message);
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.configData = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData);
|
||||
return this.configData;
|
||||
} catch (e: any) {
|
||||
if (e instanceof SyntaxError) {
|
||||
logger.logError(`[Core] [Config] 配置文件格式错误,请检查配置文件:`, e.message);
|
||||
} else {
|
||||
logger.logError(`[Core] [Config] 读取配置文件时发生错误:`, e.message);
|
||||
}
|
||||
return {} as T;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
save(newConfigData: T = this.configData as T) {
|
||||
const logger = this.coreContext.context.logger;
|
||||
const selfInfo = this.coreContext.selfInfo;
|
||||
this.configData = newConfigData;
|
||||
const configPath = this.getConfigPath(selfInfo.uin);
|
||||
try {
|
||||
fs.writeFileSync(configPath, JSON.stringify(newConfigData, this.getKeys(), 2));
|
||||
} catch (e: any) {
|
||||
logger.logError(`保存配置文件 ${configPath} 时发生错误:`, e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
export class LRUCache<K, V> {
|
||||
private capacity: number;
|
||||
private cache: Map<K, V>;
|
||||
|
||||
constructor(capacity: number) {
|
||||
this.capacity = capacity;
|
||||
this.cache = new Map<K, V>();
|
||||
}
|
||||
|
||||
public get(key: K): V | undefined {
|
||||
const value = this.cache.get(key);
|
||||
if (value !== undefined) {
|
||||
// Move the accessed key to the end to mark it as most recently used
|
||||
this.cache.delete(key);
|
||||
this.cache.set(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public put(key: K, value: V): void {
|
||||
if (this.cache.has(key)) {
|
||||
// If the key already exists, move it to the end to mark it as most recently used
|
||||
this.cache.delete(key);
|
||||
} else if (this.cache.size >= this.capacity) {
|
||||
// If the cache is full, remove the least recently used key (the first one in the map)
|
||||
const firstKey = this.cache.keys().next().value;
|
||||
this.cache.delete(firstKey);
|
||||
}
|
||||
this.cache.set(key, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
import { Peer } from '@/core';
|
||||
import crypto from 'crypto';
|
||||
|
||||
export class LimitedHashTable<K, V> {
|
||||
private keyToValue: Map<K, V> = new Map();
|
||||
private valueToKey: Map<V, K> = new Map();
|
||||
private maxSize: number;
|
||||
|
||||
constructor(maxSize: number) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
resize(count: number) {
|
||||
this.maxSize = count;
|
||||
}
|
||||
|
||||
set(key: K, value: V): void {
|
||||
// const isExist = this.keyToValue.get(key);
|
||||
// if (isExist && isExist === value) {
|
||||
// return;
|
||||
// }
|
||||
this.keyToValue.set(key, value);
|
||||
this.valueToKey.set(value, key);
|
||||
while (this.keyToValue.size !== this.valueToKey.size) {
|
||||
//console.log('keyToValue.size !== valueToKey.size Error Atom');
|
||||
this.keyToValue.clear();
|
||||
this.valueToKey.clear();
|
||||
}
|
||||
// console.log('---------------');
|
||||
// console.log(this.keyToValue);
|
||||
// console.log(this.valueToKey);
|
||||
// console.log('---------------');
|
||||
while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) {
|
||||
//console.log(this.keyToValue.size > this.maxSize, this.valueToKey.size > this.maxSize);
|
||||
const oldestKey = this.keyToValue.keys().next().value;
|
||||
this.valueToKey.delete(this.keyToValue.get(oldestKey)!);
|
||||
this.keyToValue.delete(oldestKey);
|
||||
}
|
||||
}
|
||||
|
||||
getValue(key: K): V | undefined {
|
||||
return this.keyToValue.get(key);
|
||||
}
|
||||
|
||||
getKey(value: V): K | undefined {
|
||||
return this.valueToKey.get(value);
|
||||
}
|
||||
|
||||
deleteByValue(value: V): void {
|
||||
const key = this.valueToKey.get(value);
|
||||
if (key !== undefined) {
|
||||
this.keyToValue.delete(key);
|
||||
this.valueToKey.delete(value);
|
||||
}
|
||||
}
|
||||
|
||||
deleteByKey(key: K): void {
|
||||
const value = this.keyToValue.get(key);
|
||||
if (value !== undefined) {
|
||||
this.keyToValue.delete(key);
|
||||
this.valueToKey.delete(value);
|
||||
}
|
||||
}
|
||||
|
||||
getKeyList(): K[] {
|
||||
return Array.from(this.keyToValue.keys());
|
||||
}
|
||||
|
||||
//获取最近刚写入的几个值
|
||||
getHeads(size: number): { key: K; value: V }[] | undefined {
|
||||
const keyList = this.getKeyList();
|
||||
if (keyList.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const result: { key: K; value: V }[] = [];
|
||||
const listSize = Math.min(size, keyList.length);
|
||||
for (let i = 0; i < listSize; i++) {
|
||||
const key = keyList[listSize - i];
|
||||
result.push({ key, value: this.keyToValue.get(key)! });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class MessageUniqueWrapper {
|
||||
private msgDataMap: LimitedHashTable<string, number>;
|
||||
private msgIdMap: LimitedHashTable<string, number>;
|
||||
|
||||
constructor(maxMap: number = 1000) {
|
||||
this.msgIdMap = new LimitedHashTable<string, number>(maxMap);
|
||||
this.msgDataMap = new LimitedHashTable<string, number>(maxMap);
|
||||
}
|
||||
|
||||
getRecentMsgIds(Peer: Peer, size: number): string[] {
|
||||
const heads = this.msgIdMap.getHeads(size);
|
||||
if (!heads) {
|
||||
return [];
|
||||
}
|
||||
const data = heads.map((t) => MessageUnique.getMsgIdAndPeerByShortId(t.value));
|
||||
const ret = data.filter((t) => t?.Peer.chatType === Peer.chatType && t?.Peer.peerUid === Peer.peerUid);
|
||||
return ret.map((t) => t?.MsgId).filter((t) => t !== undefined);
|
||||
}
|
||||
|
||||
createMsg(peer: Peer, msgId: string): number | undefined {
|
||||
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`;
|
||||
const hash = crypto.createHash('md5').update(key).digest();
|
||||
//设置第一个bit为0 保证shortId为正数
|
||||
hash[0] &= 0x7f;
|
||||
const shortId = hash.readInt32BE(0);
|
||||
//减少性能损耗
|
||||
// const isExist = this.msgIdMap.getKey(shortId);
|
||||
// if (isExist && isExist === msgId) {
|
||||
// return shortId;
|
||||
// }
|
||||
this.msgIdMap.set(msgId, shortId);
|
||||
this.msgDataMap.set(key, shortId);
|
||||
return shortId;
|
||||
}
|
||||
|
||||
getMsgIdAndPeerByShortId(shortId: number): { MsgId: string; Peer: Peer } | undefined {
|
||||
const data = this.msgDataMap.getKey(shortId);
|
||||
if (data) {
|
||||
const [msgId, chatTypeStr, peerUid] = data.split('|');
|
||||
const peer: Peer = {
|
||||
chatType: parseInt(chatTypeStr),
|
||||
peerUid,
|
||||
guildId: '',
|
||||
};
|
||||
return { MsgId: msgId, Peer: peer };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getShortIdByMsgId(msgId: string): number | undefined {
|
||||
return this.msgIdMap.getValue(msgId);
|
||||
}
|
||||
|
||||
getPeerByMsgId(msgId: string) {
|
||||
const shortId = this.msgIdMap.getValue(msgId);
|
||||
if (!shortId) return undefined;
|
||||
return this.getMsgIdAndPeerByShortId(shortId);
|
||||
}
|
||||
|
||||
resize(maxSize: number): void {
|
||||
this.msgIdMap.resize(maxSize);
|
||||
this.msgDataMap.resize(maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
export const MessageUnique: MessageUniqueWrapper = new MessageUniqueWrapper();
|
||||
@@ -1,72 +1,81 @@
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import { systemPlatform } from '@/common/utils/system';
|
||||
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper';
|
||||
import AppidTable from '@/core/external/appid.json';
|
||||
import { LogWrapper } from './log';
|
||||
|
||||
export const exePath = process.execPath;
|
||||
export class QQBasicInfoWrapper {
|
||||
QQMainPath: string | undefined;
|
||||
QQPackageInfoPath: string | undefined;
|
||||
QQVersionConfigPath: string | undefined;
|
||||
isQuickUpdate: boolean | undefined;
|
||||
QQVersionConfig: QQVersionConfigType | undefined;
|
||||
QQPackageInfo: QQPackageInfoType | undefined;
|
||||
QQVersionAppid: string | undefined;
|
||||
QQVersionQua: string | undefined;
|
||||
context: { logger: LogWrapper };
|
||||
|
||||
export const pkgInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'package.json');
|
||||
let configVersionInfoPath;
|
||||
constructor(context: { logger: LogWrapper }) {
|
||||
//基础目录获取
|
||||
this.context = context;
|
||||
this.QQMainPath = process.execPath;
|
||||
this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), 'resources', 'app', 'package.json');
|
||||
this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath);
|
||||
|
||||
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');
|
||||
//基础信息获取 无快更则启用默认模板填充
|
||||
this.isQuickUpdate = !!this.QQVersionConfigPath;
|
||||
this.QQVersionConfig = this.isQuickUpdate
|
||||
? JSON.parse(fs.readFileSync(this.QQVersionConfigPath!).toString())
|
||||
: getDefaultQQVersionConfigInfo();
|
||||
this.QQPackageInfo = JSON.parse(fs.readFileSync(this.QQPackageInfoPath).toString());
|
||||
const { appid: IQQVersionAppid, qua: IQQVersionQua } = this.getAppidV2();
|
||||
this.QQVersionAppid = IQQVersionAppid;
|
||||
this.QQVersionQua = IQQVersionQua;
|
||||
}
|
||||
|
||||
//基础函数
|
||||
getQQBuildStr() {
|
||||
return this.isQuickUpdate ? this.QQVersionConfig?.buildId : this.QQPackageInfo?.buildVersion;
|
||||
}
|
||||
|
||||
getFullQQVesion() {
|
||||
const version = this.isQuickUpdate ? this.QQVersionConfig?.curVersion : this.QQPackageInfo?.version;
|
||||
if (!version) throw new Error('QQ版本获取失败');
|
||||
return version;
|
||||
}
|
||||
|
||||
requireMinNTQQBuild(buildStr: string) {
|
||||
const currentBuild = parseInt(this.getQQBuildStr() || '0');
|
||||
if (currentBuild == 0) throw new Error('QQBuildStr获取失败');
|
||||
return currentBuild >= parseInt(buildStr);
|
||||
}
|
||||
|
||||
//此方法不要直接使用
|
||||
getQUAInternal() {
|
||||
return systemPlatform === 'linux'
|
||||
? `V1_LNX_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`
|
||||
: `V1_WIN_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
|
||||
}
|
||||
|
||||
getAppidV2(): { appid: string; qua: string } {
|
||||
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
||||
try {
|
||||
const fullVersion = this.getFullQQVesion();
|
||||
if (!fullVersion) throw new Error('QQ版本获取失败');
|
||||
const data = appidTbale[fullVersion];
|
||||
if (data) {
|
||||
return data;
|
||||
}
|
||||
} catch (e) {
|
||||
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||
}
|
||||
// 以下是兜底措施
|
||||
this.context.logger.log(
|
||||
`[QQ版本兼容性检测] ${this.getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`,
|
||||
);
|
||||
return { appid: systemPlatform === 'linux' ? '537237950' : '537237765', qua: this.getQUAInternal() };
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
export let QQBasicInfo: QQBasicInfoWrapper | undefined;
|
||||
+80
-125
@@ -1,135 +1,90 @@
|
||||
import fs from 'fs';
|
||||
import { encode, getDuration, getWavFileInfo, isWav } from 'silk-wasm';
|
||||
import { encode, getDuration, getWavFileInfo, isSilk, 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 { randomUUID } from 'crypto';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { getTempDir } from '@/common/utils/file';
|
||||
import { LogWrapper } from './log';
|
||||
|
||||
export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: LogWrapper) {
|
||||
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);
|
||||
logger.log('通过文件大小估算语音的时长:', duration);
|
||||
return duration;
|
||||
}
|
||||
|
||||
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);
|
||||
const file = await fsPromise.readFile(filePath);
|
||||
const pttPath = path.join(TEMP_DIR, randomUUID());
|
||||
if (!isSilk(file)) {
|
||||
logger.log(`语音文件${filePath}需要转换成silk`);
|
||||
const _isWav = isWav(file);
|
||||
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 => {
|
||||
logger.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);
|
||||
}
|
||||
logger.log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`);
|
||||
reject(Error('FFmpeg处理转换失败'));
|
||||
});
|
||||
});
|
||||
};
|
||||
let input: Buffer;
|
||||
if (!_isWav) {
|
||||
input = await convert();
|
||||
} else {
|
||||
input = file;
|
||||
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);
|
||||
logger.log(`语音文件${filePath}转换成功!`, pttPath, '时长:', silk.duration);
|
||||
return {
|
||||
converted: true,
|
||||
path: pttPath,
|
||||
duration: silk.duration / 1000,
|
||||
};
|
||||
} else {
|
||||
const silk = file;
|
||||
let duration = 0;
|
||||
try {
|
||||
duration = getDuration(silk) / 1000;
|
||||
} catch (e: any) {
|
||||
logger.log('获取语音文件时长失败, 使用文件大小推测时长', filePath, e.stack);
|
||||
duration = await guessDuration(filePath);
|
||||
}
|
||||
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,
|
||||
};
|
||||
return {
|
||||
converted: false,
|
||||
path: filePath,
|
||||
duration,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.logError('convert silk failed', error.stack);
|
||||
return {};
|
||||
}
|
||||
} catch (error: any) {
|
||||
logError('convert silk failed', error.stack);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
+252
-224
@@ -1,273 +1,301 @@
|
||||
import fs from 'fs';
|
||||
import fsPromise from 'fs/promises';
|
||||
import crypto from 'crypto';
|
||||
import fsPromise, { stat } from 'fs/promises';
|
||||
import crypto, { randomUUID } 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;
|
||||
};
|
||||
|
||||
import { LogWrapper } from './log';
|
||||
|
||||
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';
|
||||
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();
|
||||
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);
|
||||
}
|
||||
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 checkFileReceived2(path: string, timeout: number = 3000): Promise<void> {
|
||||
// 使用 Promise.race 来同时进行文件状态检查和超时计时
|
||||
// Promise.race 会返回第一个解决(resolve)或拒绝(reject)的 Promise
|
||||
await Promise.race([
|
||||
checkFile(path),
|
||||
timeoutPromise(timeout, `文件不存在: ${path}`),
|
||||
]);
|
||||
}
|
||||
|
||||
// 转换超时时间至 Promise
|
||||
function timeoutPromise(timeout: number, errorMsg: string): Promise<void> {
|
||||
return new Promise((_, reject) => {
|
||||
setTimeout(() => {
|
||||
reject(new Error(errorMsg));
|
||||
}, timeout);
|
||||
});
|
||||
}
|
||||
|
||||
// 异步检查文件是否存在
|
||||
async function checkFile(path: string): Promise<void> {
|
||||
try {
|
||||
await stat(path);
|
||||
} catch (error: any) {
|
||||
if (error.code === 'ENOENT') {
|
||||
// 如果文件不存在,则抛出一个错误
|
||||
throw new Error(`文件不存在: ${path}`);
|
||||
} else {
|
||||
// 对于 stat 调用的其他错误,重新抛出
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
check();
|
||||
});
|
||||
// 如果文件存在,则无需做任何事情,Promise 解决(resolve)自身
|
||||
}
|
||||
|
||||
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\\");
|
||||
// }
|
||||
const readFile = util.promisify(fs.readFile);
|
||||
const result = {
|
||||
err: '',
|
||||
data: '',
|
||||
};
|
||||
try {
|
||||
await checkFileReceived(path, 5000);
|
||||
} catch (e: any) {
|
||||
result.err = e.toString();
|
||||
return result;
|
||||
// 读取文件内容
|
||||
// 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();
|
||||
}
|
||||
const data = await readFile(path);
|
||||
// 转换为Base64编码
|
||||
result.data = data.toString('base64');
|
||||
} catch (err: any) {
|
||||
result.err = err.toString();
|
||||
}
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
export function calculateFileMD5(filePath: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 创建一个流式读取器
|
||||
const stream = fs.createReadStream(filePath);
|
||||
const hash = crypto.createHash('md5');
|
||||
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('data', (data: Buffer) => {
|
||||
// 当读取到数据时,更新哈希对象的状态
|
||||
hash.update(data);
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
// 文件读取完成,计算哈希
|
||||
const md5 = hash.digest('hex');
|
||||
resolve(md5);
|
||||
});
|
||||
stream.on('end', () => {
|
||||
// 文件读取完成,计算哈希
|
||||
const md5 = hash.digest('hex');
|
||||
resolve(md5);
|
||||
});
|
||||
|
||||
stream.on('error', (err: Error) => {
|
||||
// 处理可能的读取错误
|
||||
reject(err);
|
||||
stream.on('error', (err: Error) => {
|
||||
// 处理可能的读取错误
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export interface HttpDownloadOptions {
|
||||
url: string;
|
||||
headers?: Record<string, string> | string;
|
||||
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 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;
|
||||
const host = new URL(url).hostname;
|
||||
headers['Host'] = host;
|
||||
} 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 fetchRes = await fetch(url, { headers }).catch((err) => {
|
||||
if (err.cause) {
|
||||
throw err.cause;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`);
|
||||
|
||||
const blob = await fetchRes.blob();
|
||||
const buffer = await blob.arrayBuffer();
|
||||
return Buffer.from(buffer);
|
||||
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
|
||||
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];
|
||||
export async function uri2local(TempDir: string, UriOrPath: string, fileName: string | null = null): Promise<Uri2LocalRes> {
|
||||
const res = {
|
||||
success: false,
|
||||
errMsg: '',
|
||||
fileName: '',
|
||||
ext: '',
|
||||
path: '',
|
||||
isLocal: false,
|
||||
};
|
||||
if (!fileName) fileName = randomUUID();
|
||||
let filePath = path.join(TempDir, fileName);//临时目录
|
||||
let url = null;
|
||||
//区分path和uri
|
||||
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;
|
||||
if (fs.existsSync(UriOrPath)) url = new URL('file://' + UriOrPath);
|
||||
} catch (error: any) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
url = new URL(UriOrPath);
|
||||
} catch (error: any) {
|
||||
}
|
||||
|
||||
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)
|
||||
//验证url
|
||||
if (!url) {
|
||||
res.errMsg = `UriOrPath ${UriOrPath} 解析失败,可能${UriOrPath}不存在`;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
if (url.protocol == 'base64:') {
|
||||
// base64转成文件
|
||||
const base64Data = UriOrPath.split('base64://')[1];
|
||||
try {
|
||||
await fsPromise.copyFile(srcPath, dstPath);
|
||||
} catch (error) {
|
||||
console.error(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
|
||||
// 这里可以决定是否要继续复制其他文件
|
||||
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(UriOrPath);
|
||||
} 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(TempDir, randomUUID() + 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 {
|
||||
// 26702执行forword file文件操作 不应该在这里乱来
|
||||
// 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) {
|
||||
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, logger: LogWrapper) {
|
||||
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, logger);
|
||||
} else {
|
||||
try {
|
||||
await fsPromise.copyFile(srcPath, dstPath);
|
||||
} catch (error) {
|
||||
logger.logError(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
|
||||
// 这里可以决定是否要继续复制其他文件
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.logError('复制文件夹时出错:', error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('复制文件夹时出错:', error);
|
||||
}
|
||||
}
|
||||
+142
-156
@@ -1,179 +1,165 @@
|
||||
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';
|
||||
import fs from 'fs';
|
||||
import * as fsPromise from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import { QQLevel } from '@/core';
|
||||
|
||||
//下面这个类是用于将uid+msgid合并的类
|
||||
|
||||
export class UUIDConverter {
|
||||
static encode(highStr: string, lowStr: string): string {
|
||||
const high = BigInt(highStr);
|
||||
const low = BigInt(lowStr);
|
||||
const highHex = high.toString(16).padStart(16, '0');
|
||||
const lowHex = low.toString(16).padStart(16, '0');
|
||||
const combinedHex = highHex + lowHex;
|
||||
const uuid = `${combinedHex.substring(0, 8)}-${combinedHex.substring(8, 12)}-${combinedHex.substring(
|
||||
12,
|
||||
16,
|
||||
)}-${combinedHex.substring(16, 20)}-${combinedHex.substring(20)}`;
|
||||
return uuid;
|
||||
}
|
||||
|
||||
static decode(uuid: string): { high: string; low: string } {
|
||||
const hex = uuid.replace(/-/g, '');
|
||||
const high = BigInt('0x' + hex.substring(0, 16));
|
||||
const low = BigInt('0x' + hex.substring(16));
|
||||
return { high: high.toString(), low: low.toString() };
|
||||
}
|
||||
}
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export function PromiseTimer<T>(promise: Promise<T>, ms: number): Promise<T> {
|
||||
const timeoutPromise = new Promise<T>((_, reject) =>
|
||||
setTimeout(() => reject(new Error('PromiseTimer: Operation timed out')), ms),
|
||||
);
|
||||
return Promise.race([promise, timeoutPromise]);
|
||||
}
|
||||
|
||||
export async function runAllWithTimeout<T>(tasks: Promise<T>[], timeout: number): Promise<T[]> {
|
||||
const wrappedTasks = tasks.map((task) =>
|
||||
PromiseTimer(task, timeout).then(
|
||||
(result) => ({ status: 'fulfilled', value: result }),
|
||||
(error) => ({ status: 'rejected', reason: error }),
|
||||
),
|
||||
);
|
||||
const results = await Promise.all(wrappedTasks);
|
||||
return results
|
||||
.filter((result) => result.status === 'fulfilled')
|
||||
.map((result) => (result as { status: 'fulfilled'; value: T }).value);
|
||||
}
|
||||
|
||||
export function getMd5(s: string) {
|
||||
|
||||
const h = crypto.createHash('md5');
|
||||
h.update(s);
|
||||
return h.digest('hex');
|
||||
const h = crypto.createHash('md5');
|
||||
h.update(s);
|
||||
return h.digest('hex');
|
||||
}
|
||||
|
||||
export function isNull(value: any) {
|
||||
return value === undefined || value === null;
|
||||
return value === undefined || value === null;
|
||||
}
|
||||
|
||||
export function isNumeric(str: string) {
|
||||
return /^\d+$/.test(str);
|
||||
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 (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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
const keys1 = Object.keys(obj1);
|
||||
const keys2 = Object.keys(obj2);
|
||||
|
||||
if (keys1.length !== keys2.length) return false;
|
||||
if (keys1.length !== keys2.length) return false;
|
||||
|
||||
for (const key of keys1) {
|
||||
if (!isEqual(obj1[key], obj2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (const key of keys1) {
|
||||
if (!isEqual(obj1[key], obj2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
|
||||
if (os.platform() === 'linux') {
|
||||
return {
|
||||
baseVersion: '3.2.12-26702',
|
||||
curVersion: '3.2.12-26702',
|
||||
prevVersion: '',
|
||||
onErrorVersions: [],
|
||||
buildId: '26702',
|
||||
};
|
||||
}
|
||||
return {
|
||||
baseVersion: '9.9.15-26702',
|
||||
curVersion: '9.9.15-26702',
|
||||
prevVersion: '',
|
||||
onErrorVersions: [],
|
||||
buildId: '26702',
|
||||
};
|
||||
}
|
||||
|
||||
export function getQQVersionConfigPath(exePath: string = ''): string | undefined {
|
||||
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') {
|
||||
return undefined;
|
||||
}
|
||||
if (!fs.existsSync(configVersionInfoPath)) {
|
||||
return undefined;
|
||||
}
|
||||
return configVersionInfoPath;
|
||||
}
|
||||
|
||||
export async function deleteOldFiles(directoryPath: string, daysThreshold: number) {
|
||||
try {
|
||||
const files = await fsPromise.readdir(directoryPath);
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(directoryPath, file);
|
||||
const stats = await fsPromise.stat(filePath);
|
||||
const lastModifiedTime = stats.mtimeMs;
|
||||
const currentTime = Date.now();
|
||||
const timeDifference = currentTime - lastModifiedTime;
|
||||
const daysDifference = timeDifference / (1000 * 60 * 60 * 24);
|
||||
|
||||
if (daysDifference > daysThreshold) {
|
||||
await fsPromise.unlink(filePath); // Delete the file
|
||||
//console.log(`Deleted: ${filePath}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
//console.error('Error deleting files:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export function calcQQLevel(level: QQLevel) {
|
||||
const { crownNum, sunNum, moonNum, starNum } = level;
|
||||
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
||||
}
|
||||
+119
-104
@@ -1,123 +1,138 @@
|
||||
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);
|
||||
import chalk from 'chalk';
|
||||
|
||||
export enum LogLevel {
|
||||
DEBUG = 'debug',
|
||||
INFO = 'info',
|
||||
WARN = 'warn',
|
||||
ERROR = 'error',
|
||||
FATAL = 'fatal',
|
||||
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 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);
|
||||
export class LogWrapper {
|
||||
fileLogEnabled = true;
|
||||
consoleLogEnabled = true;
|
||||
logConfig: Configuration;
|
||||
loggerConsole: log4js.Logger;
|
||||
loggerFile: log4js.Logger;
|
||||
loggerDefault: log4js.Logger;
|
||||
// eslint-disable-next-line no-control-regex
|
||||
colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g;
|
||||
|
||||
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'
|
||||
}
|
||||
constructor(logDir: string) {
|
||||
const filename = `${getFormattedTimestamp()}.log`;
|
||||
const logPath = path.join(logDir, filename);
|
||||
this.logConfig = {
|
||||
appenders: {
|
||||
FileAppender: { // 输出到文件的appender
|
||||
type: 'file',
|
||||
filename: logPath, // 指定日志文件的位置和文件名
|
||||
maxLogSize: 10485760, // 日志文件的最大大小(单位:字节),这里设置为10MB
|
||||
layout: {
|
||||
type: 'pattern',
|
||||
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] %X{userInfo} | %m',
|
||||
},
|
||||
},
|
||||
ConsoleAppender: { // 输出到控制台的appender
|
||||
type: 'console',
|
||||
layout: {
|
||||
type: 'pattern',
|
||||
pattern: `%d{yyyy-MM-dd hh:mm:ss} [%[%p%]] ${chalk.magenta('%X{userInfo}')} | %m`,
|
||||
},
|
||||
},
|
||||
},
|
||||
categories: {
|
||||
default: { appenders: ['FileAppender', 'ConsoleAppender'], level: 'debug' }, // 默认情况下同时输出到文件和控制台
|
||||
file: { appenders: ['FileAppender'], level: 'debug' },
|
||||
console: { appenders: ['ConsoleAppender'], level: 'debug' },
|
||||
},
|
||||
};
|
||||
log4js.configure(this.logConfig);
|
||||
this.loggerConsole = log4js.getLogger('console');
|
||||
this.loggerFile = log4js.getLogger('file');
|
||||
this.loggerDefault = log4js.getLogger('default');
|
||||
this.setLogSelfInfo({ nick: '', uin: '', uid: '' });
|
||||
}
|
||||
},
|
||||
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;
|
||||
setFileAndConsoleLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
||||
this.logConfig.categories.file.level = fileLogLevel;
|
||||
this.logConfig.categories.console.level = consoleLogLevel;
|
||||
log4js.configure(this.logConfig);
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
setLogSelfInfo(selfInfo: { nick: string, uin: string, uid: string }) {
|
||||
const userInfo = `${selfInfo.nick}(${selfInfo.uin})`;
|
||||
this.loggerConsole.addContext('userInfo', userInfo);
|
||||
this.loggerFile.addContext('userInfo', userInfo);
|
||||
this.loggerDefault.addContext('userInfo', userInfo);
|
||||
}
|
||||
|
||||
export function log(...args: any[]) {
|
||||
// info 等级
|
||||
_log(LogLevel.INFO, ...args);
|
||||
}
|
||||
setFileLogEnabled(isEnabled: boolean) {
|
||||
this.fileLogEnabled = isEnabled;
|
||||
}
|
||||
|
||||
export function logDebug(...args: any[]) {
|
||||
_log(LogLevel.DEBUG, ...args);
|
||||
}
|
||||
setConsoleLogEnabled(isEnabled: boolean) {
|
||||
this.consoleLogEnabled = isEnabled;
|
||||
}
|
||||
|
||||
export function logError(...args: any[]) {
|
||||
_log(LogLevel.ERROR, ...args);
|
||||
formatMsg(msg: any[]) {
|
||||
let logMsg = '';
|
||||
for (const msgItem of msg) {
|
||||
if (msgItem instanceof Error) { // 判断是否是错误
|
||||
logMsg += msgItem.stack + ' ';
|
||||
continue;
|
||||
} else if (typeof msgItem === 'object') { // 判断是否是对象
|
||||
const obj = JSON.parse(JSON.stringify(msgItem, null, 2));
|
||||
logMsg += JSON.stringify(truncateString(obj)) + ' ';
|
||||
continue;
|
||||
}
|
||||
logMsg += msgItem + ' ';
|
||||
}
|
||||
return logMsg;
|
||||
}
|
||||
|
||||
|
||||
_log(level: LogLevel, ...args: any[]) {
|
||||
if (this.consoleLogEnabled) {
|
||||
this.loggerConsole[level](this.formatMsg(args));
|
||||
}
|
||||
if (this.fileLogEnabled) {
|
||||
this.loggerFile[level](this.formatMsg(args).replace(this.colorEscape, ''));
|
||||
}
|
||||
}
|
||||
|
||||
log(...args: any[]) {
|
||||
// info 等级
|
||||
this._log(LogLevel.INFO, ...args);
|
||||
}
|
||||
|
||||
logDebug(...args: any[]) {
|
||||
this._log(LogLevel.DEBUG, ...args);
|
||||
}
|
||||
|
||||
logError(...args: any[]) {
|
||||
this._log(LogLevel.ERROR, ...args);
|
||||
}
|
||||
|
||||
logWarn(...args: any[]) {
|
||||
this._log(LogLevel.WARN, ...args);
|
||||
}
|
||||
|
||||
logFatal(...args: any[]) {
|
||||
this._log(LogLevel.FATAL, ...args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { LogWrapper } from './log';
|
||||
|
||||
export function proxyHandlerOf(logger: LogWrapper) {
|
||||
return {
|
||||
get(target: any, prop: any, receiver: any) {
|
||||
// console.log('get', prop, typeof target[prop]);
|
||||
if (typeof target[prop] === 'undefined') {
|
||||
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
||||
return (..._args: unknown[]) => {
|
||||
logger.logDebug(`${target.constructor.name} has no method ${prop}`);
|
||||
};
|
||||
}
|
||||
// 如果方法存在,正常返回
|
||||
return Reflect.get(target, prop, receiver);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function proxiedListenerOf<T extends object>(listener: T, logger: LogWrapper) {
|
||||
return new Proxy<T>(listener, proxyHandlerOf(logger));
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
+184
-96
@@ -1,106 +1,194 @@
|
||||
import https from 'node:https';
|
||||
import http from 'node:http';
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
export class RequestUtil {
|
||||
// 适用于获取服务器下发cookies时获取,仅GET
|
||||
static async HttpsGetCookies(url: string): Promise<{ [key: string]: string }> {
|
||||
const client = url.startsWith('https') ? https : http;
|
||||
return new Promise((resolve, reject) => {
|
||||
client.get(url, (res) => {
|
||||
let cookies: { [key: string]: string } = {};
|
||||
const handleRedirect = (res: http.IncomingMessage) => {
|
||||
//console.log(res.headers.location);
|
||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
if (res.headers.location) {
|
||||
const redirectUrl = new URL(res.headers.location, url);
|
||||
RequestUtil.HttpsGetCookies(redirectUrl.href).then((redirectCookies) => {
|
||||
// 合并重定向过程中的cookies
|
||||
cookies = { ...cookies, ...redirectCookies };
|
||||
resolve(cookies);
|
||||
});
|
||||
} else {
|
||||
resolve(cookies);
|
||||
}
|
||||
} else {
|
||||
resolve(cookies);
|
||||
}
|
||||
// 适用于获取服务器下发cookies时获取,仅GET
|
||||
static async HttpsGetCookies(url: string): Promise<{ [key: string]: string }> {
|
||||
const client = url.startsWith('https') ? https : http;
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = client.get(url, (res) => {
|
||||
let cookies: { [key: string]: string } = {};
|
||||
const handleRedirect = (res: http.IncomingMessage) => {
|
||||
//console.log(res.headers.location);
|
||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
if (res.headers.location) {
|
||||
const redirectUrl = new URL(res.headers.location, url);
|
||||
RequestUtil.HttpsGetCookies(redirectUrl.href).then((redirectCookies) => {
|
||||
// 合并重定向过程中的cookies
|
||||
cookies = { ...cookies, ...redirectCookies };
|
||||
resolve(cookies);
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
resolve(cookies);
|
||||
}
|
||||
} else {
|
||||
resolve(cookies);
|
||||
}
|
||||
};
|
||||
res.on('data', () => {
|
||||
}); // Necessary to consume the stream
|
||||
res.on('end', () => {
|
||||
handleRedirect(res);
|
||||
});
|
||||
if (res.headers['set-cookie']) {
|
||||
//console.log(res.headers['set-cookie']);
|
||||
res.headers['set-cookie'].forEach((cookie) => {
|
||||
const parts = cookie.split(';')[0].split('=');
|
||||
const key = parts[0];
|
||||
const value = parts[1];
|
||||
if (key && value && key.length > 0 && value.length > 0) {
|
||||
cookies[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
req.on('error', (error: any) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 请求和回复都是JSON data传原始内容 自动编码json
|
||||
static async HttpGetJson<T>(url: string, method: string = 'GET', data?: any, headers: {
|
||||
[key: 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,
|
||||
};
|
||||
res.on('data', () => { }); // Necessary to consume the stream
|
||||
res.on('end', () => {
|
||||
handleRedirect(res);
|
||||
});
|
||||
if (res.headers['set-cookie']) {
|
||||
//console.log(res.headers['set-cookie']);
|
||||
res.headers['set-cookie'].forEach((cookie) => {
|
||||
const parts = cookie.split(';')[0].split('=');
|
||||
const key = parts[0];
|
||||
const value = parts[1];
|
||||
if (key && value && key.length > 0 && value.length > 0) {
|
||||
cookies[key] = value;
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Content-Length': Buffer.byteLength(postData),
|
||||
// },
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}).on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 请求和回复都是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();
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
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}`));
|
||||
// 请求返回都是原始内容
|
||||
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) {
|
||||
return this.HttpGetJson<string>(url, method, data, headers, false, false);
|
||||
}
|
||||
|
||||
static async createFormData(boundary: string, filePath: string): Promise<Buffer> {
|
||||
let type = 'image/png';
|
||||
if (filePath.endsWith('.jpg')) {
|
||||
type = 'image/jpeg';
|
||||
}
|
||||
const formDataParts = [
|
||||
`------${boundary}\r\n`,
|
||||
`Content-Disposition: form-data; name="share_image"; filename="${filePath}"\r\n`,
|
||||
'Content-Type: ' + type + '\r\n\r\n',
|
||||
];
|
||||
|
||||
const fileContent = readFileSync(filePath);
|
||||
const footer = `\r\n------${boundary}--`;
|
||||
return Buffer.concat([
|
||||
Buffer.from(formDataParts.join(''), 'utf8'),
|
||||
fileContent,
|
||||
Buffer.from(footer, 'utf8'),
|
||||
]);
|
||||
}
|
||||
|
||||
static async uploadImageForOpenPlatform(filePath: string, cookies: string): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
type retType = { retcode: number, result?: { url: string } };
|
||||
try {
|
||||
const options = {
|
||||
hostname: 'cgi.connect.qq.com',
|
||||
port: 443,
|
||||
path: '/qqconnectopen/upload_share_image',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Referer': 'https://cgi.connect.qq.com',
|
||||
'Cookie': cookies,
|
||||
'Accept': '*/*',
|
||||
'Connection': 'keep-alive',
|
||||
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW',
|
||||
},
|
||||
};
|
||||
const req = https.request(options, async (res) => {
|
||||
let responseBody = '';
|
||||
|
||||
res.on('data', (chunk: string | Buffer) => {
|
||||
responseBody += chunk.toString();
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
||||
const responseJson = JSON.parse(responseBody) as retType;
|
||||
resolve(responseJson.result!.url!);
|
||||
} else {
|
||||
reject(new Error(`Unexpected status code: ${res.statusCode}`));
|
||||
}
|
||||
} catch (parseError) {
|
||||
reject(parseError);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
console.log('Error during upload:', error);
|
||||
});
|
||||
|
||||
const body = await RequestUtil.createFormData('WebKitFormBoundary7MA4YWxkTrZu0gW', filePath);
|
||||
// req.setHeader('Content-Length', Buffer.byteLength(body));
|
||||
// console.log(`Prepared data size: ${Buffer.byteLength(body)} bytes`);
|
||||
req.write(body);
|
||||
req.end();
|
||||
return;
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} catch (parseError) {
|
||||
reject(parseError);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,73 @@
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { networkInterfaces } from 'os';
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
// 缓解Win7设备兼容性问题
|
||||
let osName: string;
|
||||
// 设备ID
|
||||
let machineId: Promise<string>;
|
||||
|
||||
try {
|
||||
osName = os.hostname();
|
||||
osName = os.hostname();
|
||||
} catch (e) {
|
||||
osName = 'NapCat'; // + crypto.randomUUID().substring(0, 4);
|
||||
osName = 'NapCat'; // + crypto.randomUUID().substring(0, 4);
|
||||
}
|
||||
|
||||
const invalidMacAddresses = new Set([
|
||||
'00:00:00:00:00:00',
|
||||
'ff:ff:ff:ff:ff:ff',
|
||||
'ac:de:48:00:11:22',
|
||||
]);
|
||||
|
||||
function validateMacAddress(candidate: string): boolean {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const tempCandidate = candidate.replace(/\-/g, ':').toLowerCase();
|
||||
return !invalidMacAddresses.has(tempCandidate);
|
||||
}
|
||||
|
||||
export async function getMachineId(): Promise<string> {
|
||||
if (!machineId) {
|
||||
machineId = (async () => {
|
||||
const id = await getMacMachineId();
|
||||
return id || randomUUID(); // fallback, generate a UUID
|
||||
})();
|
||||
}
|
||||
|
||||
return machineId;
|
||||
}
|
||||
|
||||
export function getMac(): string {
|
||||
const ifaces = networkInterfaces();
|
||||
for (const name in ifaces) {
|
||||
const networkInterface = ifaces[name];
|
||||
if (networkInterface) {
|
||||
for (const { mac } of networkInterface) {
|
||||
if (validateMacAddress(mac)) {
|
||||
return mac;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Unable to retrieve mac address (unexpected format)');
|
||||
}
|
||||
|
||||
async function getMacMachineId(): Promise<string | undefined> {
|
||||
try {
|
||||
const crypto = await import('crypto');
|
||||
const macAddress = getMac();
|
||||
return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex');
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const homeDir = os.homedir();
|
||||
|
||||
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();
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* 运行时类型转换与检查类
|
||||
*/
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//QQVersionType
|
||||
type QQPackageInfoType = {
|
||||
version: string;
|
||||
buildVersion: string;
|
||||
platform: string;
|
||||
eleArch: string;
|
||||
}
|
||||
type QQVersionConfigType = {
|
||||
baseVersion: string;
|
||||
curVersion: string;
|
||||
prevVersion: string;
|
||||
onErrorVersions: Array<any>;
|
||||
buildId: string;
|
||||
}
|
||||
type QQAppidTableType = {
|
||||
[key: string]: { appid: string, qua: string };
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
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!');
|
||||
});
|
||||
}
|
||||
+45
-73
@@ -1,14 +1,10 @@
|
||||
import { log } from './log';
|
||||
import ffmpeg from 'fluent-ffmpeg';
|
||||
import ffmpeg, { FfprobeStream } from 'fluent-ffmpeg';
|
||||
import fs from 'fs';
|
||||
import type { LogWrapper } from './log';
|
||||
|
||||
const defaultVideoThumbB64 = '/9j/4AAQSkZJRgABAQAAAQABAAD//gAXR2VuZXJhdGVkIGJ5IFNuaXBhc3Rl/9sAhAAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47AQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCAF/APADAREAAhEBAxEB/8QBogAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoLEAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+foBAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKCxEAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiAayNxwagBwNAC5oAM0xBmgBM0ANJoAjY0AQsaBkTGgCM0DEpAFAC0AFMBaACgAoEJTASgQlACUwCgQ4UAOFADhQA4UAOFADxQIkBqDQUGgBwagBQaBC5pgGaAELUAMLUARs1AETGgBhNAxhoASkAUALQIKYxaBBQAUwEoAQ0CEoASmAUAOoEKKAHCgBwoAeKAHigQ7NZmoZpgLmgBd1Ahd1ABupgNLUAMLUAMY0AMJoAYaAENACUCCgAoAWgAoAWgBKYCUAJQISgApgLQAooEOFACigB4oAeKBDxQAVmaiZpgGaAFzQAbqAE3UAIWpgNJoAYTQIaaAEoAQ0CEoASgBaACgBaACmAUAJQAlAgoAKYC0AKKBCigB4FADgKBDwKAHigBuazNRM0DEzTAM0AJmgAzQAhNAhpNACGmA2gQlACUCEoAKACgBaAFpgFACUAJQAUCCmAUALQIcBQA4CgB4FADgKBDhQA4UAMzWZqNzTGJQAZoATNABmgBKAEoEIaYCUCEoASgQlABQAtABQAtMBKACgAoEFABimAYoEKBQA4CgB4FADwKBDgKAFFADhQBCazNhKAEpgFACUAFACUAFAhDTAbQISgAoEJQAUALQAtMAoAKADFABigQYoAMUALimIUCgBwFAh4FADgKAHUALQAtAENZmwlACUwEoAKAEoAKACgQlMBpoEJQAUCCgBcUAFABTAXFAC4oAMUAGKBBigAxQIKYCigQ8UAOFADhQAtAC0ALQBDWZqJQMSgBKYBQAlABQISgBKYCGgQlAC0CCgBcUAFABTAUCkA7FMAxQAYoEJQAUCCmAooEOFADxQA4UAFAC0ALQBDWZqJQAlACUxhQAlABQIKAEoASmISgBcUCCgBaACgBcUAKBQAuKYC0CEoAQ0AJQISmAooEPFADhQA4UALQAtAC0AQ1maiUAFACUAJTAKAEoAKAEoAMUxBigAxQIWgAoAKAFAoAWgBaYBQIQ0ANNACUCCmIUUAOFADxQA4UALQAtABQBFWZqFACUAFACYpgFACUAFACUAFAgxTEFABQAUALQAooAWgAoAKYDTQIaaAEpiCgQ4UAOFAh4oGOFAC0ALSAKYEdZmglABQAUDDFACUwEoASgAoAKBBQIKYBQAUALQAtAC0AJQAhpgNJoENJoATNMQCgQ8UCHigB4oAWgYtABQAUAMrM0CgAoAKADFACUxiUAJQAlAgoAKYgoAKACgYtAC0AFAhDTAQmgBhNAhpNACZpiFBoEPFAEi0CHigB1ABQAUDEoAbWZoFABQAtABTAQ0ANNAxDQAlAhaAEpiCgAoGFAC0AFABmgBCaYhpNADCaBDSaBBmgABpiJFNAEimgB4NADqAFzQAlACE0AJWZoFAC0AFAC0wEIoAaaAG0AJQAUCCgApjCgAoAKADNABmgBpNMQ0mgBpNAhhNAgzQAoNADwaAHqaAJAaBDgaYC5oATNACZoAWszQKACgBaBDqYCGgBpoAYaBiUCCgBKYBQMKACgAoAM0AITQIaTQA0mmA0mgQ3NAhKAHCgBwNADwaAHg0AOBpiFzQAZoATNAD6zNAoAKAFoEOpgBoAaaAGGmAw0AJmgAzQMM0AGaADNABmgBM0AITQIaTQAhNMQw0AJQIKAFFADhQA4GgBwNADs0xC5oAM0CDNAEtZmoUCCgBaAHUwCgBppgRtQAw0ANzQAZoAM0AGaADNABmgBKAEoAQ0ANNMQhoEJQAlMBaQDgaAFBoAcDTAdmgQuaADNAgzQBPWZqFAgoAWgBaYC0CGmmBG1AyM0ANJoATNACZoAXNABmgAzQAUAJQAhoAQ0xDTQISmAUALQAUgHA0AKDTAdmgQuaBBQAtAFiszQKACgBaAFFMAoEIaYEbUDI2oAYaAEoASgAzQAuaACgAoAKAENMQ00AJTEFAhKACgAoAXNACg0AOBoAWgQtAC0AWazNAoAKACgBaYBQIQ0AMNMYw0AMIoAbQAlMAoAKACgAzSAKYhKAENACUxBQIKACgBKACgBaAHCgQ4UALQAUAWqzNAoAKACgApgFACGgQ00xjTQAwigBCKAG4pgJQAlABQAUCCgBKACgBKYgoEFABQISgAoAWgBRQA4UALQAUCLdZmoUAFABQAlMAoASgBDQA00wENACYoATFMBpFADSKAEoEJQAUAFABQAlMQtAgoASgQUAJQAUAKKAHCgBaBBQBbrM1CgAoAKACmAUAJQAlADaYBQAlACYpgIRQA0igBpFAhtABQAUAFMAoEFABQIKAEoASgQUALQAooAWgQUAW81mbC0CCgApgFACUAIaAEpgJQAUAFABQAhFMBpFADSKAGkUCExQAYoAMUAGKADFMQYoAMUCExSATFABQIKYBQAtABQIt5qDYM0ALmgQtIApgIaAENADaACmAlAC0ALQAUwGkUANIoAaRQAmKBBigAxQAYoAMUAGKBBigBMUAJigQmKAExTAKBC0AFAFnNQaig0AKDQAtAgoASgBDQAlMBKACgAFADhQAtMBCKAGkUAIRQAmKADFABigQmKADFACYoAXFABigQmKAExQAmKBCYpgJigAoAnzUGgZoAcDQAuaBC0AJQAhoASmAlABQAtADhQAtMAoATFACEUAJigAxQAYoATFAhMUAFABQAuKADFABigBpWgBCKBCYpgJigB+ag0DNADgaBDgaAFzQITNACUAJTAKACgBRQAopgOoAWgBKAEoAKACgAoASgBpoEJQAooAWgBaBhigBMUCEIoAQigBMUAJSLCgBQaBDgaQC5oEFACUwCgBKACmAtADhQA4UALQAUAJQAUAJQAUAJQAhoENoAWgBRQAooGLQAUAGKAGkUAIRQIZSKEoGKKBDhQAUCCgAoAKBBQAUwFoGKKAHCgBaACgAoASgAoASgBCaAEoEJmgAoAUGgBQaAHZoGFABQAUANoAjpDEoAWgBaAFoEFACUALQAUCCmAUAOFAxRQAtAC0AJQAUAJQAmaBDSaAEzQAmaYBmgBQaAHA0gFzQAuaBhmgAzQAlAEdIYUALQAtAgoAKAEoEFAC0AFMAoAUUDFFAC0ALQAUAJQAhoENNACE0wEoATNABmgBc0ALmgBc0gDNAC5oATNABmgBKRQlACigB1AgoASgQlABTAWgBKACgBaBi0ALQAZoAM0AFACGgQ00wENACUAJQAUCFzQMM0ALmgAzQAZoAM0AGaQC0igoAUUALQIWgBDQISmAUAFACUAFABQAuaBi5oAM0AGaBBmgBKAEpgIaAG0AJQAUCFoAM0DDNAC5oATNABmgAzQBJUlBQAooAWgQtACGmIaaACgAoASgBKACgBc0DCgQUAGaADNABTASgBDQAlACUAFAgoAKBhQAUAFABQAlAE1SUFAxRQIWgQtMBDQIQ0AJQAlAhKBiUAFABmgBc0AGaADNABTAKACgBKAEoASgQlABQAUAFAC0AFACUAFAE1SaBQAUCHCgQtMBKBCUAJQISgBDQA00DEzQAuaADNMBc0AGaADNABQAUAJQAlABQISgAoAKACgBaACgBKAEoAnqTQSgBRQIcKBC0xCUAJQISgBKAENADDQAmaYwzQAuaADNAC0AFABQAUAFAhKACgBKACgAoAWgAoELQAlAxKAJqk0EoAWgQooELTEFADaBCUABoENNMY00ANNAwzQAZoAXNAC0AFAC0CFoASgAoASgBKACgAoAWgQtABQAUANNAyWpNAoAKBCimIWgQUCEoASmIQ0ANNADTQMaaAEoGLmgAzQAtADhQIWgBaACgQhoASgYlACUALQIWgBaACgBKAENAyWpNBKYBQIcKBC0CEoEJTAKBCUANNADDQMQ0ANoGFAC5oAUGgBwNAhRQIWgBaAENACGgBtAwoAKAFzQIXNABmgAoAQ0DJKRoJQAtAhRQSLQIKYCUCCgBDQA00AMNAxpoGNoAM0AGaAFBoAcDQIcKBDqACgBDQAhoAQ0DEoAKADNAC5oEGaBhmgAoAkpGgUCCgQooELQIKYhKACgBKAGmgBpoGMNAxDQAlAwzQIUUAOFAhwoAcKBC0AJQAhoGNNACUAFABQAZoAXNABQAUAS0ixKACgQoNAhaYgoEFACUABoAaaAGmgYw0DENAxtABQAooEOFA
Line truncated
|
||||
|
||||
export const defaultVideoThumb = Buffer.from(defaultVideoThumbB64, 'base64');
|
||||
|
||||
export async function getVideoInfo(filePath: string) {
|
||||
const size = fs.statSync(filePath).size;
|
||||
return new Promise<{
|
||||
export async function getVideoInfo(filePath: string, logger: LogWrapper) {
|
||||
const size = fs.statSync(filePath).size;
|
||||
return new Promise<{
|
||||
width: number,
|
||||
height: number,
|
||||
time: number,
|
||||
@@ -16,72 +12,48 @@ export async function getVideoInfo(filePath: string) {
|
||||
size: number,
|
||||
filePath: string
|
||||
}>((resolve, reject) => {
|
||||
const ffmpegPath = process.env.FFMPEG_PATH;
|
||||
ffmpegPath && ffmpeg.setFfmpegPath(ffmpegPath);
|
||||
ffmpeg(filePath).ffprobe((err: any, metadata: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const videoStream = metadata.streams.find((s: { codec_type: string; }) => s.codec_type === 'video');
|
||||
if (videoStream) {
|
||||
console.log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
|
||||
} else {
|
||||
return reject('未找到视频流信息。');
|
||||
}
|
||||
resolve({
|
||||
width: videoStream.width, height: videoStream.height,
|
||||
time: parseInt(videoStream.duration),
|
||||
format: metadata.format.format_name,
|
||||
size,
|
||||
filePath
|
||||
});
|
||||
}
|
||||
});
|
||||
const ffmpegPath = process.env.FFMPEG_PATH;
|
||||
ffmpegPath && ffmpeg.setFfmpegPath(ffmpegPath);
|
||||
ffmpeg(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const videoStream = metadata.streams.find((s: FfprobeStream) => s.codec_type === 'video');
|
||||
if (videoStream) {
|
||||
logger.log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
|
||||
} else {
|
||||
return reject('未找到视频流信息。');
|
||||
}
|
||||
resolve({
|
||||
width: videoStream.width!, height: videoStream.height!,
|
||||
time: parseInt(videoStream.duration!),
|
||||
format: metadata.format.format_name!,
|
||||
size,
|
||||
filePath,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function encodeMp4(filePath: string) {
|
||||
const videoInfo = await getVideoInfo(filePath);
|
||||
log('视频信息', videoInfo);
|
||||
if (videoInfo.format.indexOf('mp4') === -1) {
|
||||
log('视频需要转换为MP4格式', filePath);
|
||||
// 转成mp4
|
||||
const newPath: string = await new Promise<string>((resolve, reject) => {
|
||||
const newPath = filePath + '.mp4';
|
||||
ffmpeg(filePath)
|
||||
.toFormat('mp4')
|
||||
.on('error', (err) => {
|
||||
reject(`转换视频格式失败: ${err.message}`);
|
||||
})
|
||||
.on('end', () => {
|
||||
log('视频转换为MP4格式完成');
|
||||
resolve(newPath); // 返回转换后的文件路径
|
||||
})
|
||||
.save(newPath);
|
||||
});
|
||||
return await getVideoInfo(newPath);
|
||||
}
|
||||
return videoInfo;
|
||||
}
|
||||
|
||||
export function checkFfmpeg(newPath: string | null = null): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
log('开始检查ffmpeg', newPath);
|
||||
if (newPath) {
|
||||
ffmpeg.setFfmpegPath(newPath);
|
||||
}
|
||||
try {
|
||||
ffmpeg.getAvailableFormats((err: any, formats: any) => {
|
||||
if (err) {
|
||||
log('ffmpeg is not installed or not found in PATH:', err);
|
||||
resolve(false);
|
||||
} else {
|
||||
log('ffmpeg is installed.');
|
||||
resolve(true);
|
||||
export function checkFfmpeg(newPath: string | null = null, logger: LogWrapper): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
logger.log('开始检查ffmpeg', newPath);
|
||||
if (newPath) {
|
||||
ffmpeg.setFfmpegPath(newPath);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
try {
|
||||
ffmpeg.getAvailableFormats((err: any, formats: any) => {
|
||||
if (err) {
|
||||
logger.log('ffmpeg is not installed or not found in PATH:', err);
|
||||
resolve(false);
|
||||
} else {
|
||||
logger.log('ffmpeg is installed.');
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
-1
Submodule src/core deleted from d7677362d1.
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
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 +0,0 @@
|
||||
var _0x2f9bbf=_0x8fe9;(function(_0x240c15,_0x13a1b9){var _0x44d52a=_0x8fe9,_0x48175b=_0x240c15();while(!![]){try{var _0x43e10a=-parseInt(_0x44d52a(0xd2))/0x1+-parseInt(_0x44d52a(0xca))/0x2*(parseInt(_0x44d52a(0xce))/0x3)+parseInt(_0x44d52a(0xcc))/0x4*(parseInt(_0x44d52a(0xcf))/0x5)+parseInt(_0x44d52a(0xd0))/0x6+parseInt(_0x44d52a(0xd4))/0x7+-parseInt(_0x44d52a(0xcd))/0x8+parseInt(_0x44d52a(0xcb))/0x9;if(_0x43e10a===_0x13a1b9)break;else _0x48175b['push'](_0x48175b['shift']());}catch(_0x212c5e){_0x48175b['push'](_0x48175b['shift']());}}}(_0x573b,0x4e014));export class DependsAdapter{[_0x2f9bbf(0xd1)](_0x571d8c,_0x2da53b){}['onMSFSsoError'](_0xeb8504){}[_0x2f9bbf(0xd3)](_0xc5cb23){}}function _0x8fe9(_0x18a1a4,_0xb679b){var _0x573b03=_0x573b();return _0x8fe9=function(_0x8fe947,_0x355420){_0x8fe947=_0x8fe947-0xca;var _0x14c474=_0x573b03[_0x8fe947];return _0x14c474;},_0x8fe9(_0x18a1a4,_0xb679b);}function _0x573b(){var _0x2f3e16=['onMSFStatusChange','178221cLXANj','getGroupCode','2825634SxDvBt','18NYwNJJ','3815829fEQwgG','3524MpzAYl','2522312mBhRkw','137181gBuRKZ','1655noChHQ','631842JoCFyL'];_0x573b=function(){return _0x2f3e16;};return _0x573b();}
|
||||
@@ -1,14 +0,0 @@
|
||||
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 +0,0 @@
|
||||
function _0x3ac0(_0xcb3d4b,_0x45f6cb){var _0x2b332b=_0x2b33();return _0x3ac0=function(_0x3ac014,_0x31f067){_0x3ac014=_0x3ac014-0x99;var _0x2afe55=_0x2b332b[_0x3ac014];return _0x2afe55;},_0x3ac0(_0xcb3d4b,_0x45f6cb);}var _0x280cdc=_0x3ac0;(function(_0x588061,_0x26dac4){var _0x15d572=_0x3ac0,_0x4587ee=_0x588061();while(!![]){try{var _0x254bd5=parseInt(_0x15d572(0x9c))/0x1*(parseInt(_0x15d572(0x9e))/0x2)+-parseInt(_0x15d572(0x9a))/0x3+parseInt(_0x15d572(0x9f))/0x4+-parseInt(_0x15d572(0xa2))/0x5*(-parseInt(_0x15d572(0x99))/0x6)+parseInt(_0x15d572(0xa3))/0x7+-parseInt(_0x15d572(0xa1))/0x8+-parseInt(_0x15d572(0xa0))/0x9;if(_0x254bd5===_0x26dac4)break;else _0x4587ee['push'](_0x4587ee['shift']());}catch(_0x56648a){_0x4587ee['push'](_0x4587ee['shift']());}}}(_0x2b33,0xf1277));function _0x2b33(){var _0xc7fab1=['1825kjRMcS','5841192YmjWIa','16560eAuaMG','3835482QHUUkd','dispatchCall','1946334JCCcaL','dispatchCallWithJson','2zkkgjJ','150988uHQIIQ','4671639vENctH','8324840uivMEo'];_0x2b33=function(){return _0xc7fab1;};return _0x2b33();}export class DispatcherAdapter{['dispatchRequest'](_0x248d19){}[_0x280cdc(0x9b)](_0x3add8e){}[_0x280cdc(0x9d)](_0x5c5ae9){}}
|
||||
@@ -1,24 +0,0 @@
|
||||
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 +0,0 @@
|
||||
function _0x1df5(_0x27abc9,_0x3c7ef2){var _0xc3f8d0=_0xc3f8();return _0x1df5=function(_0x1df5c8,_0x58406f){_0x1df5c8=_0x1df5c8-0xc1;var _0x38a336=_0xc3f8d0[_0x1df5c8];return _0x38a336;},_0x1df5(_0x27abc9,_0x3c7ef2);}var _0xf13a48=_0x1df5;function _0xc3f8(){var _0x515c7b=['onUpdateGeneralFlag','onInstallFinished','35oJkVEv','18689GsIXsr','6288639DoJhBd','16DRWxYZ','onGetOfflineMsg','46532ntLefW','214PFXCeb','onShowErrUITips','155508VNpANx','getAppSetting','onLog','fixPicImgType','5277gYNKnY','12124404nWZHLJ','5790JCJBEK','956112FsBkcc'];_0xc3f8=function(){return _0x515c7b;};return _0xc3f8();}(function(_0x19fe3e,_0x12ef0c){var _0x48c992=_0x1df5,_0x2282fb=_0x19fe3e();while(!![]){try{var _0x5c171b=-parseInt(_0x48c992(0xc8))/0x1+parseInt(_0x48c992(0xd1))/0x2*(-parseInt(_0x48c992(0xc5))/0x3)+-parseInt(_0x48c992(0xd0))/0x4*(parseInt(_0x48c992(0xcb))/0x5)+parseInt(_0x48c992(0xc1))/0x6+parseInt(_0x48c992(0xcd))/0x7*(parseInt(_0x48c992(0xce))/0x8)+parseInt(_0x48c992(0xc6))/0x9+parseInt(_0x48c992(0xc7))/0xa*(-parseInt(_0x48c992(0xcc))/0xb);if(_0x5c171b===_0x12ef0c)break;else _0x2282fb['push'](_0x2282fb['shift']());}catch(_0x14c6f7){_0x2282fb['push'](_0x2282fb['shift']());}}}(_0xc3f8,0xea75f));export class GlobalAdapter{[_0xf13a48(0xc3)](..._0x4af3af){}['onGetSrvCalTime'](..._0x3c2bc9){}[_0xf13a48(0xd2)](..._0x38db4e){}[_0xf13a48(0xc4)](..._0x5d1a18){}[_0xf13a48(0xc2)](..._0x43369d){}[_0xf13a48(0xca)](..._0x3eb3c8){}[_0xf13a48(0xc9)](..._0x190a92){}[_0xf13a48(0xcf)](..._0x314054){}}
|
||||
@@ -1 +0,0 @@
|
||||
(function(_0x1e35d8,_0x2d4ab1){var _0x52ccd1=_0x5571,_0x5ac369=_0x1e35d8();while(!![]){try{var _0x265d1f=-parseInt(_0x52ccd1(0x177))/0x1*(-parseInt(_0x52ccd1(0x16f))/0x2)+parseInt(_0x52ccd1(0x171))/0x3*(-parseInt(_0x52ccd1(0x178))/0x4)+parseInt(_0x52ccd1(0x179))/0x5*(parseInt(_0x52ccd1(0x17a))/0x6)+-parseInt(_0x52ccd1(0x173))/0x7*(-parseInt(_0x52ccd1(0x172))/0x8)+-parseInt(_0x52ccd1(0x170))/0x9+parseInt(_0x52ccd1(0x175))/0xa*(-parseInt(_0x52ccd1(0x176))/0xb)+parseInt(_0x52ccd1(0x174))/0xc;if(_0x265d1f===_0x2d4ab1)break;else _0x5ac369['push'](_0x5ac369['shift']());}catch(_0x344123){_0x5ac369['push'](_0x5ac369['shift']());}}}(_0x31a0,0x51157));export*from'./NodeIDependsAdapter';export*from'./NodeIDispatcherAdapter';function _0x5571(_0x2be41d,_0x9c2cf9){var _0x31a000=_0x31a0();return _0x5571=function(_0x5571ba,_0x70885c){_0x5571ba=_0x5571ba-0x16f;var _0x577c36=_0x31a000[_0x5571ba];return _0x577c36;},_0x5571(_0x2be41d,_0x9c2cf9);}function _0x31a0(){var _0x461736=['5345516eltSrV','25698oFpTAR','998288reazkd','20gnlqAE','69558qrUQAA','30aOeudC','3161007DhEdsG','6YQeRYL','1761088XheHBV','21jaMejO','6914304rjdkKR','10MSgoCn'];_0x31a0=function(){return _0x461736;};return _0x31a0();}export*from'./NodeIGlobalAdapter';
|
||||
Vendored
-37
@@ -1,37 +0,0 @@
|
||||
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 +0,0 @@
|
||||
const _0x56e080=_0x1d7b;(function(_0x408399,_0x26f80d){const _0xc4a18a=_0x1d7b,_0x520ad8=_0x408399();while(!![]){try{const _0xd14ccb=parseInt(_0xc4a18a(0x120))/0x1+-parseInt(_0xc4a18a(0x110))/0x2*(parseInt(_0xc4a18a(0x102))/0x3)+parseInt(_0xc4a18a(0xf2))/0x4+parseInt(_0xc4a18a(0x135))/0x5*(-parseInt(_0xc4a18a(0x106))/0x6)+-parseInt(_0xc4a18a(0x137))/0x7*(parseInt(_0xc4a18a(0xee))/0x8)+-parseInt(_0xc4a18a(0x136))/0x9*(parseInt(_0xc4a18a(0x113))/0xa)+-parseInt(_0xc4a18a(0x10a))/0xb*(-parseInt(_0xc4a18a(0xfd))/0xc);if(_0xd14ccb===_0x26f80d)break;else _0x520ad8['push'](_0x520ad8['shift']());}catch(_0x3efebf){_0x520ad8['push'](_0x520ad8['shift']());}}}(_0x1712,0x2abee));import{ElementType,IMAGE_HTTP_HOST,IMAGE_HTTP_HOST_NT}from'@/core/entities';import _0x11ce3f from'path';import _0x4e37dd from'fs';function _0x1d7b(_0xe4c278,_0x402c37){const _0x171203=_0x1712();return _0x1d7b=function(_0x1d7b08,_0x2f210a){_0x1d7b08=_0x1d7b08-0xe9;let _0x27b45c=_0x171203[_0x1d7b08];return _0x27b45c;},_0x1d7b(_0xe4c278,_0x402c37);}import _0x202f75 from'fs/promises';import{logDebug}from'@/common/utils/log';import{napCatCore}from'@/core';import{calculateFileMD5}from'@/common/utils/file';import*as _0x2f6c3e from'file-type';import{MsgListener}from'@/core/listeners';import _0x2d784c from'image-size';import{sessionConfig}from'@/core/sessionConfig';import{randomUUID}from'crypto';import{rkeyManager}from'../utils/rkey';function _0x1712(){const _0x51c942=['hotUpdate','GWGxu','downloadRichMedia','set','util','onLoginSuccess','fiNtG','getRichMediaFilePathForGuild','clearCacheDataByKeys','getFileCacheInfo','pNPcB','LZdwE','图片url获取失败','18904hCtUML','XDZBe','md5HexStr','downloadMedia','1393076VUzukb','copyFile','szaMH','addCacheScannedPaths','startsWith','group_rkey','getStorageCleanService','getHotUpdateCachePath','PIC','tmp','getRkey','3816bsUIBO','onRichMediaDownloadComplete','/gchatpic_new/0/0-0-','slzwG','jbKBh','21VyRrWU','getImageUrl','session','getChatCacheInfo','10350QfgAod','uploadFile','fileUuid','defaultFileDownloadPath','11143hsBtqy','ext','getFileType','LjprO','uIqpO','nazyL','71944KvFEvf','getImageSize','BhrsT','50dfqfgB','downloadPath','fileTypeFromFile','aggaR','oaBbW','includes','filePath','basename','下载超时','nJMgW','cFZrw','&rkey=','delete','315946FiotTK','Wneag','originImageUrl','scanCache','join','ZBqYJ','downloadMedia\x20complete','private_rkey','WBZtT','receive\x20downloadMedia\x20task','unlink','clearChatCacheInfo','yoIcB','/download','indexOf','getMsgService','QAmFE','toUpperCase','ZvzXb','getFileSize','XhDtV','865HIXqZK','31761qrWylX','721bEwIXD','clearCache','msgId'];_0x1712=function(){return _0x51c942;};return _0x1712();}import{AsyncQueue}from'@/common/utils/AsyncQueue';const getRKeyTaskQueue=new AsyncQueue(),downloadMediaTasks=new Map(),downloadMediaListener=new MsgListener();downloadMediaListener[_0x56e080(0xfe)]=_0x5b3aaf=>{const _0xdbbc96=_0x56e080;for(const [_0x3a71f0,_0x55f9a5]of downloadMediaTasks){_0x55f9a5(_0x5b3aaf),downloadMediaTasks[_0xdbbc96(0x11f)](_0x3a71f0);}},setTimeout(()=>{const _0x48ddd6=_0x56e080;napCatCore[_0x48ddd6(0x13f)](()=>{napCatCore['addListener'](downloadMediaListener);});},0x64);export class NTQQFileApi{static async[_0x56e080(0x10c)](_0x3a0b7d){const _0x1e5b4b=_0x56e080;return _0x2f6c3e[_0x1e5b4b(0x115)](_0x3a0b7d);}static async[_0x56e080(0xf3)](_0x24b426,_0x428aa0){const _0x278810=_0x56e080;await napCatCore['util'][_0x278810(0xf3)](_0x24b426,_0x428aa0);}static async[_0x56e080(0x133)](_0xdf93fc){const _0x22e783=_0x56e080;return await napCatCore[_0x22e783(0x13e)][_0x22e783(0x133)](_0xdf93fc);}static async[_0x56e080(0x107)](_0x3fdca9,_0x5ca4e6=ElementType[_0x56e080(0xfa)],_0x2a8c76=0x0){const _0x2827db=_0x56e080,_0x5d1eb5={'XhDtV':function(_0x2b82f8,_0x447ee1){return _0x2b82f8(_0x447ee1);},'LjprO':function(_0x4511b2,_0x4016bd){return _0x4511b2+_0x4016bd;},'XDZBe':function(_0x5be371,_0x2fc2d6){return _0x5be371===_0x2fc2d6;}},_0x5b5a82=await _0x5d1eb5[_0x2827db(0x134)](calculateFileMD5,_0x3fdca9);let _0x2d21f1=(await NTQQFileApi[_0x2827db(0x10c)](_0x3fdca9))?.[_0x2827db(0x10b)]||'';_0x2d21f1&&(_0x2d21f1=_0x5d1eb5[_0x2827db(0x10d)]('.',_0x2d21f1));let _0x38ce54=''+_0x11ce3f[_0x2827db(0x11a)](_0x3fdca9);_0x5d1eb5[_0x2827db(0xef)](_0x38ce54[_0x2827db(0x12e)]('.'),-0x1)&&(_0x38ce54+=_0x2d21f1);const _0x12cddc=napCatCore['session'][_0x2827db(0x12f)]()[_0x2827db(0x141)]({'md5HexStr':_0x5b5a82,'fileName':_0x38ce54,'elementType':_0x5ca4e6,'elementSubType':_0x2a8c76,'thumbSize':0x0,'needCreate':!![],'downloadType':0x1,'file_uuid':''});await NTQQFileApi[_0x2827db(0xf3)](_0x3fdca9,_0x12cddc);const _0x960dc3=await NTQQFileApi[_0x2827db(0x133)](_0x3fdca9);return{'md5':_0x5b5a82,'fileName':_0x38ce54,'path':_0x12cddc,'fileSize':_0x960dc3,'ext':_0x2d21f1};}static async[_0x56e080(0xf1)](_0x24291f,_0xb7f8c9,_0x699113,_0x14a0f5,_0x40aecb,_0x195bc4,_0x10b1f4=0x3e8*0x3c*0x2,_0x2ced63=![]){const _0x110fa2=_0x56e080,_0x4c84a0={'cFZrw':function(_0x54d28d,_0x3b6070,_0x2c93db,_0x1df284){return _0x5Line truncated
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
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 +0,0 @@
|
||||
const _0x2ed956=_0x421d;function _0x2e4e(){const _0x123d55=['获取好友列表完成','session','获取好友列表超时','KsVTJ','uid','mxcLN','onBuddyListChange','5449785eMbbTo','friendUid','199630ZNKrZP','sWUMo','KNlxN','77886OYKNGA','945MLgudi','hndDF','9242160cqEUGz','delete','开始获取好友列表','nQOiZ','addListener','buddyList','handleFriendRequest','reqTime','qlSML','push','iNegf','onLoginSuccess','getBuddyList','getBuddyService','RzsbV','1584wuMIgG','175MDKQvQ','80700fQLKSR','set','1626505osZtZM','getFriends','1829492wWzSkt'];_0x2e4e=function(){return _0x123d55;};return _0x2e4e();}(function(_0x3cdc52,_0x36e151){const _0x2fa9d0=_0x421d,_0x191342=_0x3cdc52();while(!![]){try{const _0x590ead=parseInt(_0x2fa9d0(0x159))/0x1+parseInt(_0x2fa9d0(0x15b))/0x2+parseInt(_0x2fa9d0(0x13e))/0x3+-parseInt(_0x2fa9d0(0x157))/0x4*(-parseInt(_0x2fa9d0(0x156))/0x5)+parseInt(_0x2fa9d0(0x143))/0x6*(-parseInt(_0x2fa9d0(0x144))/0x7)+parseInt(_0x2fa9d0(0x146))/0x8+-parseInt(_0x2fa9d0(0x155))/0x9*(parseInt(_0x2fa9d0(0x140))/0xa);if(_0x590ead===_0x36e151)break;else _0x191342['push'](_0x191342['shift']());}catch(_0x5df9b3){_0x191342['push'](_0x191342['shift']());}}}(_0x2e4e,0xe8be6));import{BuddyListener,napCatCore}from'@/core';function _0x421d(_0x42f14a,_0x4b9075){const _0x2e4e6f=_0x2e4e();return _0x421d=function(_0x421d8d,_0x2b8c6e){_0x421d8d=_0x421d8d-0x137;let _0x424382=_0x2e4e6f[_0x421d8d];return _0x424382;},_0x421d(_0x42f14a,_0x4b9075);}import{logDebug}from'@/common/utils/log';import{uid2UinMap}from'@/core/data';import{randomUUID}from'crypto';const buddyChangeTasks=new Map(),buddyListener=new BuddyListener();buddyListener[_0x2ed956(0x13d)]=_0xb1448a=>{const _0x14c0c1=_0x2ed956,_0x5b9209={'iNegf':function(_0x5bf7e2,_0x443837){return _0x5bf7e2(_0x443837);}};for(const [_0x482ad4,_0x415ef8]of buddyChangeTasks){_0x5b9209[_0x14c0c1(0x150)](_0x415ef8,_0xb1448a),buddyChangeTasks[_0x14c0c1(0x147)](_0x482ad4);}},setTimeout(()=>{const _0xd10f6d=_0x2ed956;napCatCore[_0xd10f6d(0x151)](()=>{const _0x2e9ec9=_0xd10f6d;napCatCore[_0x2e9ec9(0x14a)](buddyListener);});},0x64);export class NTQQFriendApi{static async[_0x2ed956(0x15a)](_0xf51c05=![]){const _0xbb2276=_0x2ed956,_0x35b699={'KNlxN':function(_0x193b35,_0x3b2c8b){return _0x193b35(_0x3b2c8b);},'RzsbV':_0xbb2276(0x137),'KsVTJ':function(_0x436b57,_0x252bc3){return _0x436b57(_0x252bc3);},'qlSML':_0xbb2276(0x148),'NxWCG':function(_0x53ad1b,_0x28cc05,_0x593b3d){return _0x53ad1b(_0x28cc05,_0x593b3d);},'hndDF':function(_0x2a74ce){return _0x2a74ce();}};return new Promise((_0x576cc4,_0x1f9a43)=>{const _0x3548fd=_0xbb2276,_0x525b6c={'nQOiZ':function(_0x2d5abe,_0x627498){const _0x523923=_0x421d;return _0x35b699[_0x523923(0x142)](_0x2d5abe,_0x627498);},'gVQlA':_0x3548fd(0x139),'PwBlA':function(_0x4d7c6a,_0x394884,_0x313fb1){return _0x4d7c6a(_0x394884,_0x313fb1);},'sWUMo':_0x35b699[_0x3548fd(0x154)],'mxcLN':function(_0x3a1111,_0x58f325){const _0x3d7c07=_0x3548fd;return _0x35b699[_0x3d7c07(0x13a)](_0x3a1111,_0x58f325);},'zdFHf':_0x35b699[_0x3548fd(0x14e)]};let _0x322f36=![];_0x35b699['NxWCG'](setTimeout,()=>{const _0x9f18af=_0x3548fd;!_0x322f36&&(_0x525b6c[_0x9f18af(0x149)](logDebug,_0x525b6c['gVQlA']),_0x525b6c[_0x9f18af(0x149)](_0x1f9a43,_0x525b6c['gVQlA']));},0x1388);const _0x14ed9e=[],_0x5d100a=_0x5edab4=>{const _0x188442=_0x3548fd;for(const _0xd2e480 of _0x5edab4){for(const _0x18d2f1 of _0xd2e480[_0x188442(0x14b)]){_0x14ed9e[_0x188442(0x14f)](_0x18d2f1),uid2UinMap[_0x18d2f1[_0x188442(0x13b)]]=_0x18d2f1['uin'];}}_0x322f36=!![],_0x525b6c['PwBlA'](logDebug,_0x525b6c[_0x188442(0x141)],_0x14ed9e),_0x525b6c[_0x188442(0x13c)](_0x576cc4,_0x14ed9e);};buddyChangeTasks[_0x3548fd(0x158)](_0x35b699[_0x3548fd(0x145)](randomUUID),_0x5d100a),napCatCore[_0x3548fd(0x138)][_0x3548fd(0x153)]()[_0x3548fd(0x152)](_0xf51c05)['then'](_0x4ad51f=>{_0x525b6c['PwBlA'](logDebug,_0x525b6c['zdFHf'],_0x4ad51f);});});}static async[_0x2ed956(0x14c)](_0x14396f,_0x336373){const _0x17477a=_0x2ed956;napCatCore[_0x17477a(0x138)][_0x17477a(0x153)]()?.['approvalFriendRequest']({'friendUid':_0x14396f[_0x17477a(0x13f)],'reqTime':_0x14396f[_0x17477a(0x14d)],'accept':_0x336373});}}
|
||||
Vendored
-33
@@ -1,33 +0,0 @@
|
||||
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 +0,0 @@
|
||||
const _0x19db1c=_0x3745;(function(_0x1f3848,_0x1e0335){const _0x3dc787=_0x3745,_0x3e811a=_0x1f3848();while(!![]){try{const _0x4046f6=parseInt(_0x3dc787(0xdc))/0x1*(-parseInt(_0x3dc787(0xcd))/0x2)+parseInt(_0x3dc787(0xff))/0x3+parseInt(_0x3dc787(0xf1))/0x4*(parseInt(_0x3dc787(0xfa))/0x5)+parseInt(_0x3dc787(0x106))/0x6*(-parseInt(_0x3dc787(0xd0))/0x7)+-parseInt(_0x3dc787(0xf3))/0x8*(-parseInt(_0x3dc787(0xe7))/0x9)+parseInt(_0x3dc787(0xd5))/0xa*(parseInt(_0x3dc787(0xd3))/0xb)+parseInt(_0x3dc787(0xfd))/0xc*(-parseInt(_0x3dc787(0xe4))/0xd);if(_0x4046f6===_0x1e0335)break;else _0x3e811a['push'](_0x3e811a['shift']());}catch(_0x174fa7){_0x3e811a['push'](_0x3e811a['shift']());}}}(_0x41d4,0xa8d1d));import{NTQQUserApi,napCatCore}from'@/core';import{GroupListener}from'@/core/index';import{uid2UinMap}from'@/core/data';import{logDebug}from'@/common/utils/log';import{randomUUID}from'crypto';const groupMemberTasks=new Map(),SingleScreenNotifiesTasks=new Map(),groupListener=new GroupListener();function _0x3745(_0x29ab8e,_0x12046c){const _0x41d44e=_0x41d4();return _0x3745=function(_0x37450e,_0x269cc9){_0x37450e=_0x37450e-0xcd;let _0x212196=_0x41d44e[_0x37450e];return _0x212196;},_0x3745(_0x29ab8e,_0x12046c);}groupListener[_0x19db1c(0x109)]=(_0xc3e424,_0x3c6de3,_0x1c82a7)=>{const _0x590a2f=_0x19db1c,_0x38095a={'optqe':function(_0x6274bd,_0x2f44cc,_0x59f6a6,_0x34f728){return _0x6274bd(_0x2f44cc,_0x59f6a6,_0x34f728);}};for(const [_0x18ba0e,_0x1f62a3]of SingleScreenNotifiesTasks){_0x38095a[_0x590a2f(0x114)](_0x1f62a3,_0xc3e424,_0x3c6de3,_0x1c82a7),groupMemberTasks[_0x590a2f(0xea)](_0x18ba0e);}},groupListener[_0x19db1c(0xe5)]=(_0x3638c5,_0x23bbf2)=>{const _0x1666f1=_0x19db1c,_0x27ffb1={'zpvLo':function(_0xea248b,_0x13a59b,_0x12d050){return _0xea248b(_0x13a59b,_0x12d050);}};for(const [_0x330966,_0x29ee0c]of groupMemberTasks){_0x27ffb1[_0x1666f1(0xfe)](_0x29ee0c,_0x3638c5,_0x23bbf2),groupMemberTasks[_0x1666f1(0xea)](_0x330966);}},setTimeout(()=>{napCatCore['onLoginSuccess'](()=>{napCatCore['addListener'](groupListener);});},0x64);export class NTQQGroupApi{static async['getGroups'](_0x56ec84=![]){const _0x2e4f76=_0x19db1c,_0x202d44={'zENfO':_0x2e4f76(0xf6),'tDJto':function(_0x2dee2e,_0xc076f3,_0x81700a){return _0x2dee2e(_0xc076f3,_0x81700a);},'FDWkg':_0x2e4f76(0xda),'ZxZoc':function(_0xaf4807,_0xef9162){return _0xaf4807(_0xef9162);},'zGBlS':function(_0x32d79d,_0x4a9bd7,_0xad53c8){return _0x32d79d(_0x4a9bd7,_0xad53c8);},'NlSqk':function(_0x400c82){return _0x400c82();}};let _0x585b75=![];return new Promise((_0x243489,_0x378995)=>{const _0x66bdcf=_0x2e4f76,_0x190f5d={'vaImU':function(_0x39265a,_0x23a3fc,_0x400865){const _0x19849c=_0x3745;return _0x202d44[_0x19849c(0xd4)](_0x39265a,_0x23a3fc,_0x400865);},'cOvaP':_0x202d44[_0x66bdcf(0xf7)],'tQdRp':function(_0x1aeb70,_0x2bc291){const _0x7bf998=_0x66bdcf;return _0x202d44[_0x7bf998(0x111)](_0x1aeb70,_0x2bc291);}};_0x202d44[_0x66bdcf(0xd2)](setTimeout,()=>{const _0x4b488e=_0x66bdcf;!_0x585b75&&(logDebug(_0x202d44[_0x4b488e(0xfb)]),_0x378995(_0x4b488e(0xf6)));},0x1388);const _0x1fb3a8=(_0x3107fa,_0x472f17)=>{const _0x5cae0d=_0x66bdcf;_0x585b75=!![],_0x190f5d['vaImU'](logDebug,_0x190f5d[_0x5cae0d(0x10d)],_0x472f17),_0x190f5d[_0x5cae0d(0xcf)](_0x243489,_0x472f17);};groupMemberTasks[_0x66bdcf(0xe1)](_0x202d44['NlSqk'](randomUUID),_0x1fb3a8),napCatCore[_0x66bdcf(0x117)]['getGroupService']()[_0x66bdcf(0x116)](_0x56ec84)['then']();});}static async['getSingleScreenNotifies'](_0x2c3e0d){const _0x1f6672=_0x19db1c,_0x422f89={'kJNUT':function(_0x43a2e,_0xcb0c56){return _0x43a2e(_0xcb0c56);},'BYxvT':function(_0x30bec9,_0x12c96f){return _0x30bec9(_0x12c96f);},'qKoWW':'获取群系统消息列表超时','cTsRX':function(_0x30e04d,_0x2f0a18,_0x272734){return _0x30e04d(_0x2f0a18,_0x272734);}},_0x499879=napCatCore['session'][_0x1f6672(0x107)]();return new Promise((_0x1c4c58,_0x137065)=>{const _0xc9ac64=_0x1f6672,_0x56c341={'UkfLu':function(_0x36c283,_0x509494,_0x3238a6){const _0x471cf4=_0x3745;return _0x422f89[_0x471cf4(0xe9)](_0x36c283,_0x509494,_0x3238a6);}};let _0x2e4de5=![];setTimeout(()=>{const _0x2bc57a=_0x3745;!_0x2e4de5&&(_0x422f89['kJNUT'](logDebug,_0x2bc57a(0x104)),_0x422f89['BYxvT'](_0x137065,_0x422f89[_0x2bc57a(0xec)]));},0x1388);const _0x365f76=(_0x3152e8,_0x15b2be,_0x170e22)=>{const _0x584915=_0x3745;_0x2e4de5=!![],_0x56c341[_0x584915(0xee)](logDebug,_0x584915(0x101),_0x170e22),_0x1c4c58(_0x170e22);};SingleScreenNotifiesTasks[_0xc9ac64(0xe1)](randomUUID(),_0x365f76),_0x499879[_0xc9ac64(0x103)](![],'',_0x2c3e0d);});}static async[_0x19db1c(0x10c)](_0x400e0b,_0x87c39d=0xbb8){const _0x4597da=_0x19db1c,_0x4ab2f0={'FCnaH':_0x4597da(0xe6),'qBSRA':function(_0x5d6ff6,_0x19b0fe){return _0x5d6ff6!==_0x19b0fe;},'SNYbF':function(_0x4bdafa,_0x25f6ad){return _0x4bdafa+_0x25f6ad;},'ssCui':_0x4597da(0xd7)},_0x23f712=napCatCore[_0x4597da(0x117)][_0x4597da(0x107)](),_0x38efe7=_0x23f712[_0x4597da(0xce)](_0x400e0b,_0x4ab2f0[_0x4597da(0xdf)]),_0x1ff3ad=await _0x23f712[_0x4597da(0xf5)](_0x38efe7,undefined,_0x87c39d);iLine truncated
|
||||
@@ -1 +0,0 @@
|
||||
function _0x216e(){var _0x1df19b=['846KaWYSf','161EFFznE','9056itswTm','5104945nWaDPE','5783vjiUDd','2920HuFlCr','4YeaEtq','6822360YWXhGL','35388wnfIrc','8482792enDWAw','298842mRBYFK','11poianb'];_0x216e=function(){return _0x1df19b;};return _0x216e();}(function(_0x313a28,_0x554195){var _0x5a79ad=_0x1354,_0x5ef870=_0x313a28();while(!![]){try{var _0x3ff0fe=parseInt(_0x5a79ad(0x1cf))/0x1+parseInt(_0x5a79ad(0x1cd))/0x2*(parseInt(_0x5a79ad(0x1d7))/0x3)+parseInt(_0x5a79ad(0x1d1))/0x4*(-parseInt(_0x5a79ad(0x1ce))/0x5)+parseInt(_0x5a79ad(0x1d5))/0x6*(parseInt(_0x5a79ad(0x1d8))/0x7)+parseInt(_0x5a79ad(0x1d4))/0x8+parseInt(_0x5a79ad(0x1d3))/0x9*(-parseInt(_0x5a79ad(0x1d0))/0xa)+-parseInt(_0x5a79ad(0x1d6))/0xb*(parseInt(_0x5a79ad(0x1d2))/0xc);if(_0x3ff0fe===_0x554195)break;else _0x5ef870['push'](_0x5ef870['shift']());}catch(_0x1e3883){_0x5ef870['push'](_0x5ef870['shift']());}}}(_0x216e,0xb754e));export*from'./file';export*from'./friend';export*from'./group';export*from'./msg';export*from'./user';export*from'./webapi';function _0x1354(_0x2467ef,_0x38fcad){var _0x216e9c=_0x216e();return _0x1354=function(_0x135413,_0x3a6bfc){_0x135413=_0x135413-0x1cd;var _0x3c1307=_0x216e9c[_0x135413];return _0x3c1307;},_0x1354(_0x2467ef,_0x38fcad);}export*from'./sign';export*from'./system';
|
||||
Vendored
-25
@@ -1,25 +0,0 @@
|
||||
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 +0,0 @@
|
||||
const _0x1cb803=_0x43ce;function _0x43ce(_0x45dc6f,_0x28a70c){const _0x371a93=_0x371a();return _0x43ce=function(_0x43cea6,_0x5b820f){_0x43cea6=_0x43cea6-0x1ad;let _0x574faf=_0x371a93[_0x43cea6];return _0x574faf;},_0x43ce(_0x45dc6f,_0x28a70c);}(function(_0x54076b,_0x5690ba){const _0x38a33a=_0x43ce,_0x4126bd=_0x54076b();while(!![]){try{const _0xf5bd1e=-parseInt(_0x38a33a(0x1d5))/0x1*(parseInt(_0x38a33a(0x1af))/0x2)+parseInt(_0x38a33a(0x1ce))/0x3*(parseInt(_0x38a33a(0x1c1))/0x4)+-parseInt(_0x38a33a(0x1e5))/0x5+-parseInt(_0x38a33a(0x1e4))/0x6+-parseInt(_0x38a33a(0x1ea))/0x7+parseInt(_0x38a33a(0x1eb))/0x8+parseInt(_0x38a33a(0x1df))/0x9*(parseInt(_0x38a33a(0x1d7))/0xa);if(_0xf5bd1e===_0x5690ba)break;else _0x4126bd['push'](_0x4126bd['shift']());}catch(_0x4b9524){_0x4126bd['push'](_0x4126bd['shift']());}}}(_0x371a,0xe5862));import{selfInfo}from'@/core/data';import{log,logError}from'@/common/utils/log';import{sleep}from'@/common/utils/helper';import{napCatCore}from'@/core';import{MsgListener}from'@/core/listeners';import{randomUUID}from'crypto';const sendMessagePool={},sendSuccessCBMap={},sentMsgTasks=new Map(),msgListener=new MsgListener();function _0x371a(){const _0x26eefa=['recallMsg','3fLRssZ','KbxIU','com.tencent.multimsg','peerUid','multiForwardMsgWithComment','then','dOjHI','24551ofjNqv','bytesData','39860kPnglU','chatType','KMjDm','GWYSR','catch','getMsgsIncludeSelf','sendMsg','forEach','7083YeXaSR','Fiycp','sendStatus','hrsGQ','SzrFa','5051658kWEvqc','6225470MRttUm','app','getMsgHistory','fetchRecentContact','setMsgRead','9993823sckFTx','3598136CYUiXr','activateChatAndGetHistory','aFKQc','42LlgZMy','eZOMI','delete','getMsgService','getMultiMsg','multiForwardMsg','uid','getMsgsByMsgId','parse','McsAs','forwardMsg','onMsgInfoListUpdate','msgId','sWLEI','OvnxQ','addListener','转发消息超时','setEmojiLike','5534712TBCykY','getMsgsBySeqAndCount','find','length','bXbMZ','wSung','jpktL','activateChat','session','iCdvg','发送超时','setMsgEmojiLikes'];_0x371a=function(){return _0x26eefa;};return _0x371a();}msgListener['onAddSendMsg']=_0xf7df8=>{const _0x3aec66=_0x43ce,_0x2857c9={'eZOMI':function(_0x2cdfdb,_0x3ce180){return _0x2cdfdb(_0x3ce180);},'McsAs':function(_0x5c277a,_0x9fcb59){return _0x5c277a instanceof _0x9fcb59;}};for(const [_0x1c4b99,_0x3d2f2f]of sentMsgTasks){_0x2857c9[_0x3aec66(0x1b0)](_0x3d2f2f,_0xf7df8),sentMsgTasks[_0x3aec66(0x1b1)](_0x1c4b99);}if(sendMessagePool[_0xf7df8[_0x3aec66(0x1d1)]]){const _0x5626a0=sendMessagePool[_0xf7df8[_0x3aec66(0x1d1)]]?.(_0xf7df8);_0x2857c9[_0x3aec66(0x1b8)](_0x5626a0,Promise)&&_0x5626a0[_0x3aec66(0x1d3)]()[_0x3aec66(0x1db)](logError);}},msgListener[_0x1cb803(0x1ba)]=_0x19f3a9=>{const _0x28d5df=_0x1cb803,_0x216be3={'kxeTf':function(_0x47f4f0,_0xa4d213){return _0x47f4f0(_0xa4d213);},'bXbMZ':function(_0x4547fe,_0xb73316){return _0x4547fe instanceof _0xb73316;}};_0x19f3a9[_0x28d5df(0x1de)](_0x5a7505=>{const _0x5e11ad=_0x28d5df;new Promise((_0x3112de,_0xe321b9)=>{const _0x1eecc5=_0x43ce;for(const _0x4ef6e2 in sendSuccessCBMap){const _0x2d2f9e=sendSuccessCBMap[_0x4ef6e2],_0x8f1a5b=_0x216be3['kxeTf'](_0x2d2f9e,_0x5a7505),_0x317998=_0x2c413c=>{_0x2c413c&&delete sendSuccessCBMap[_0x4ef6e2];};_0x216be3[_0x1eecc5(0x1c5)](_0x8f1a5b,Promise)?_0x8f1a5b['then'](_0x317998):_0x317998(_0x8f1a5b);}})[_0x5e11ad(0x1d3)]()[_0x5e11ad(0x1db)](log);});},setTimeout(()=>{napCatCore['onLoginSuccess'](()=>{const _0x1c6d2f=_0x43ce;napCatCore[_0x1c6d2f(0x1be)](msgListener);});},0x64);export class NTQQMsgApi{static async[_0x1cb803(0x1c0)](_0x3cbfdd,_0x169487,_0x348f6c,_0x26b59b=!![]){const _0x256ec6=_0x1cb803;return _0x348f6c=_0x348f6c['toString'](),napCatCore[_0x256ec6(0x1c9)][_0x256ec6(0x1b2)]()[_0x256ec6(0x1cc)](_0x3cbfdd,_0x169487,_0x348f6c,_0x348f6c[_0x256ec6(0x1c4)]>0x3?'2':'1',_0x26b59b);}static async['getMultiMsg'](_0xdb3cfa,_0x18a906,_0x4b31eb){const _0x521793=_0x1cb803;return napCatCore[_0x521793(0x1c9)][_0x521793(0x1b2)]()[_0x521793(0x1b3)](_0xdb3cfa,_0x18a906,_0x4b31eb);}static async['getMsgsByMsgId'](_0x192b67,_0x10d54c){const _0x56ace3=_0x1cb803;return await napCatCore[_0x56ace3(0x1c9)][_0x56ace3(0x1b2)]()[_0x56ace3(0x1b6)](_0x192b67,_0x10d54c);}static async[_0x1cb803(0x1c2)](_0x24397b,_0x42ce23,_0x1724cf,_0x419c46,_0x1b569d){const _0x3ffa2b=_0x1cb803;return await napCatCore[_0x3ffa2b(0x1c9)][_0x3ffa2b(0x1b2)]()[_0x3ffa2b(0x1c2)](_0x24397b,_0x42ce23,_0x1724cf,_0x419c46,_0x1b569d);}static async[_0x1cb803(0x1c8)](_0x3d7113){}static async[_0x1cb803(0x1ad)](_0x31c7e5){}static async[_0x1cb803(0x1e9)](_0x1815b7){const _0x10e803=_0x1cb803;return napCatCore[_0x10e803(0x1c9)][_0x10e803(0x1b2)]()[_0x10e803(0x1e9)](_0x1815b7);}static async[_0x1cb803(0x1e7)](_0x2dc9a1,_0x40648f,_0x4d3521){const _0x11f54d=_0x1cb803;return napCatCore[_0x11f54d(0x1c9)]['getMsgService']()[_0x11f54d(0x1dc)](_0x2dc9a1,_0x40648f,_0x4d3521,!![]);}static async[_0x1cb803(0x1e8)](){}static async[_0x1cb803(0x1cd)](_0x129f4a,_0x474ec4){const _0x4abe65=_0x1cb803;await napCatCore[_0x4abe65(0x1c9)][_0x4abe65(0x1b2)]()[_0Line truncated
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
export interface IdMusicSignPostData {
|
||||
type: 'qq' | '163';
|
||||
id: string | number;
|
||||
}
|
||||
export interface CustomMusicSignPostData {
|
||||
type: 'custom';
|
||||
url: string;
|
||||
audio: string;
|
||||
title: string;
|
||||
image?: string;
|
||||
singer?: string;
|
||||
}
|
||||
export interface MiniAppLuaJsonType {
|
||||
prompt: string;
|
||||
title: string;
|
||||
preview: string;
|
||||
jumpUrl: string;
|
||||
tag: string;
|
||||
tagIcon: string;
|
||||
source: string;
|
||||
sourcelogo: string;
|
||||
}
|
||||
export declare function SignMiniApp(CardData: MiniAppLuaJsonType): Promise<string>;
|
||||
@@ -1 +0,0 @@
|
||||
(function(_0x54aaa3,_0x20c2f2){const _0x3d1e67=_0x2ce1,_0x4f54b2=_0x54aaa3();while(!![]){try{const _0x546a3d=-parseInt(_0x3d1e67(0x15c))/0x1*(parseInt(_0x3d1e67(0x150))/0x2)+parseInt(_0x3d1e67(0x173))/0x3+parseInt(_0x3d1e67(0x14b))/0x4+-parseInt(_0x3d1e67(0x14a))/0x5+-parseInt(_0x3d1e67(0x153))/0x6*(parseInt(_0x3d1e67(0x14d))/0x7)+parseInt(_0x3d1e67(0x151))/0x8*(parseInt(_0x3d1e67(0x15b))/0x9)+parseInt(_0x3d1e67(0x156))/0xa;if(_0x546a3d===_0x20c2f2)break;else _0x4f54b2['push'](_0x4f54b2['shift']());}catch(_0x143fab){_0x4f54b2['push'](_0x4f54b2['shift']());}}}(_0x1cfb,0xa26f1));import{logDebug}from'@/common/utils/log';import{NTQQUserApi}from'./user';function _0x2ce1(_0x6e8d14,_0xda8b7b){const _0x1cfba1=_0x1cfb();return _0x2ce1=function(_0x2ce127,_0x23eba5){_0x2ce127=_0x2ce127-0x149;let _0x4d5b4a=_0x1cfba1[_0x2ce127];return _0x4d5b4a;},_0x2ce1(_0x6e8d14,_0xda8b7b);}import{selfInfo}from'../data';import{RequestUtil}from'@/common/utils/request';import{WebApi}from'./webapi';function _0x1cfb(){const _0x3206b0=['IOgTY','prompt','\x5c/\x5c/','znGko','p_skey','p_skey=','tianxuan.imgJumpArk','MiniApp\x20JSON\x20消息生成失败','yxEiY','eGnIc','&ark=','tfiGu','normal','zuKAZ','kIBHq','VnOfs','3144234RNaVhn','getQzoneCookies','skey','btuKB','GET','replace','LSvPm','signed_ark',';\x20skey=','preview','4719725WgmIqM','2960576VJYPse','miniapp','497iGWsVs','tagIcon','WvIMZ','4TicZIn','8dlJiuO','sourcelogo','34098ZHDWbW','jumpUrl','rODSC','5660050dCzLuX','QeMqd','title','MiniApp\x20JSON\x20消息生成成功',';\x20uin=o','7455132QmITfB','584904ywgFjF','SMOiZ','getSkey','uin','stringify','MsupA','gqNgq'];_0x1cfb=function(){return _0x3206b0;};return _0x1cfb();}export async function SignMiniApp(_0x358138){const _0xa8d864=_0x2ce1,_0x220bfb={'hqquW':'com.tencent.miniapp.lua','QeMqd':_0xa8d864(0x169),'tfiGu':_0xa8d864(0x14c),'eGnIc':_0xa8d864(0x16f),'SMOiZ':_0xa8d864(0x165),'VnOfs':function(_0x127d08,_0x37cb21){return _0x127d08+_0x37cb21;},'yxEiY':function(_0x1c63a3,_0x7e4244){return _0x1c63a3+_0x7e4244;},'znGko':function(_0x2e2b11,_0x141d4d){return _0x2e2b11+_0x141d4d;},'zuKAZ':function(_0x5d80d7,_0x3cac71){return _0x5d80d7+_0x3cac71;},'rODSC':_0xa8d864(0x168),'MsupA':_0xa8d864(0x17b),'btuKB':';\x20p_uin=o','gqNgq':_0xa8d864(0x15a),'WvIMZ':function(_0x2246ca,_0x29b85c){return _0x2246ca+_0x29b85c;},'kIBHq':'https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenNewSignedArk?g_tk=','IOgTY':_0xa8d864(0x16d),'LSvPm':function(_0x1429e6,_0x3f8bbc){return _0x1429e6(_0x3f8bbc);},'hKIgf':_0xa8d864(0x177),'rMtAp':function(_0x2898f3,_0x228af0,_0x5ee557){return _0x2898f3(_0x228af0,_0x5ee557);}};let _0x4d8a16={'app':_0x220bfb['hqquW'],'bizsrc':_0x220bfb[_0xa8d864(0x157)],'view':_0x220bfb[_0xa8d864(0x16e)],'prompt':_0x358138[_0xa8d864(0x164)],'config':{'type':_0x220bfb[_0xa8d864(0x16c)],'forward':0x1,'autosize':0x0},'meta':{'miniapp':{'title':_0x358138[_0xa8d864(0x158)],'preview':_0x358138[_0xa8d864(0x149)][_0xa8d864(0x178)](/\\/g,_0x220bfb[_0xa8d864(0x15d)]),'jumpUrl':_0x358138[_0xa8d864(0x154)][_0xa8d864(0x178)](/\\/g,_0x220bfb[_0xa8d864(0x15d)]),'tag':_0x358138['tag'],'tagIcon':_0x358138[_0xa8d864(0x14e)][_0xa8d864(0x178)](/\\/g,_0x220bfb['SMOiZ']),'source':_0x358138['source'],'sourcelogo':_0x358138[_0xa8d864(0x152)][_0xa8d864(0x178)](/\\/g,_0x220bfb[_0xa8d864(0x15d)])}}};const _0x31e957=await NTQQUserApi[_0xa8d864(0x15e)]();let _0x27741b=await NTQQUserApi[_0xa8d864(0x174)]();const _0x3e8053=WebApi['genBkn'](_0x27741b[_0xa8d864(0x167)]),_0x2f5063=_0x220bfb[_0xa8d864(0x172)](_0x220bfb[_0xa8d864(0x16b)](_0x220bfb[_0xa8d864(0x16b)](_0x220bfb['yxEiY'](_0x220bfb[_0xa8d864(0x166)](_0x220bfb[_0xa8d864(0x170)](_0x220bfb[_0xa8d864(0x155)],_0x27741b['p_skey']),_0x220bfb[_0xa8d864(0x161)]),_0x27741b[_0xa8d864(0x175)]),_0x220bfb[_0xa8d864(0x176)])+selfInfo[_0xa8d864(0x15f)],_0x220bfb[_0xa8d864(0x162)]),selfInfo[_0xa8d864(0x15f)]);let _0x5f41be=_0x220bfb[_0xa8d864(0x172)](_0x220bfb[_0xa8d864(0x14f)](_0x220bfb[_0xa8d864(0x166)](_0x220bfb[_0xa8d864(0x171)],_0x3e8053),_0x220bfb[_0xa8d864(0x163)]),_0x220bfb[_0xa8d864(0x179)](encodeURIComponent,JSON[_0xa8d864(0x160)](_0x4d8a16))),_0x16e440='';try{let _0x31ef23=await RequestUtil['HttpGetJson'](_0x5f41be,_0x220bfb['hKIgf'],undefined,{'Cookie':_0x2f5063});_0x220bfb['rMtAp'](logDebug,_0xa8d864(0x159),_0x31ef23),_0x16e440=_0x31ef23['data'][_0xa8d864(0x17a)];}catch(_0x3a0cf4){logDebug(_0xa8d864(0x16a),_0x3a0cf4);}return _0x16e440;}
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
export declare class NTQQSystemApi {
|
||||
static hasOtherRunningQQProcess(): Promise<boolean>;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
var _0x3385fe=_0x5d40;(function(_0x4e096e,_0x177c2c){var _0x4bde02=_0x5d40,_0x496d9b=_0x4e096e();while(!![]){try{var _0x324f89=-parseInt(_0x4bde02(0xc7))/0x1+parseInt(_0x4bde02(0xbc))/0x2+-parseInt(_0x4bde02(0xc1))/0x3+parseInt(_0x4bde02(0xbe))/0x4*(parseInt(_0x4bde02(0xbf))/0x5)+-parseInt(_0x4bde02(0xbd))/0x6*(-parseInt(_0x4bde02(0xc4))/0x7)+parseInt(_0x4bde02(0xbb))/0x8*(parseInt(_0x4bde02(0xc5))/0x9)+-parseInt(_0x4bde02(0xc6))/0xa*(parseInt(_0x4bde02(0xc3))/0xb);if(_0x324f89===_0x177c2c)break;else _0x496d9b['push'](_0x496d9b['shift']());}catch(_0x40a97a){_0x496d9b['push'](_0x496d9b['shift']());}}}(_0x43a6,0xc2561));import{napCatCore}from'@/core';function _0x5d40(_0x314a91,_0x2c26e4){var _0x43a636=_0x43a6();return _0x5d40=function(_0x5d4079,_0x214340){_0x5d4079=_0x5d4079-0xbb;var _0x2cb90e=_0x43a636[_0x5d4079];return _0x2cb90e;},_0x5d40(_0x314a91,_0x2c26e4);}export class NTQQSystemApi{static async[_0x3385fe(0xc0)](){var _0x5a8591=_0x3385fe;return napCatCore[_0x5a8591(0xc2)][_0x5a8591(0xc0)]();}}function _0x43a6(){var _0x21774a=['hasOtherRunningQQProcess','3785376LcCVcZ','util','253nLaLRL','36022FTLRie','1090827XaWlka','279460bMyGfV','1360566AQqLKb','96vjIEbL','791320oImEIX','1572fcWrKP','3451076vYNtrg','5GgcdPt'];_0x43a6=function(){return _0x21774a;};return _0x43a6();}
|
||||
Vendored
-25
@@ -1,25 +0,0 @@
|
||||
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 getQzoneCookies(): Promise<{
|
||||
[key: string]: string;
|
||||
}>;
|
||||
static getSkey(cached?: boolean): Promise<string | undefined>;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
const _0x48d1fa=_0x204b;function _0x45b9(){const _0x5c7922=['CreatTime','4293849QCnpTJ','push','NtDXp','beBGu','assign','response','like','PklFW','dKlNo','getSkey','qzlBc','skey','uid','&u1=https%3A%2F%2Fuser.qzone.qq.com%2F','Ybwoz','session','setStatus','result','vTBln','getUserDetailInfo\x20timeout','32020vwWfhm','GkZLZ','getTicketService','154105ItouQc','tdJWQ','&clientkey=','cHacO','TKCTP','getRobotService','PskeyData','now','getUserDetailInfoWithBizInfo','emHXq','getProfileLikeService','QvwVk','HttpsGetCookies','get','fromEntries','entries','Skey','ZEJol','getRobotUinRange','setQQAvatar','setHeader','tnNlw','136RlFWBy','uin','qvRLm','YwfDf','onLoginSuccess','HXzRi','632880bHhSZc','forEach','JOSiu','then','获取Pskey失败','5361402pbooYe','clientKey','keyIndex','delete','BltlH','HGnjI','LgzHf','请求获取Skey时失败','getMsgService','3ZtDgqp','693iPnJMz','917712JLwFWJ','58613880gHmYOP','%2Finfocenter&keyindex=19%27','tCuZg','KeyIndex','length','forceFetchClientKey','&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=','getProfileService','pdoVY','errMsg','getSelfInfo','addListener','setSelfOnlineStatus','ClientKey','getTipOffService','oxZlb','setBuddyProfileLike','domainPskeyMap','https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=','CSthU','8RCkiFa','set','11xEtqGK','QbzoY','PskeyTime'];_0x45b9=function(){return _0x5c7922;};return _0x45b9();}(function(_0x2ba81b,_0x1a1dd6){const _0x17db47=_0x204b,_0x4f74c1=_0x2ba81b();while(!![]){try{const _0x1d26e3=-parseInt(_0x17db47(0x1ed))/0x1+-parseInt(_0x17db47(0x1fd))/0x2*(parseInt(_0x17db47(0x1fb))/0x3)+parseInt(_0x17db47(0x1e7))/0x4*(-parseInt(_0x17db47(0x1d1))/0x5)+-parseInt(_0x17db47(0x1f2))/0x6+parseInt(_0x17db47(0x218))/0x7*(-parseInt(_0x17db47(0x212))/0x8)+parseInt(_0x17db47(0x1fc))/0x9*(-parseInt(_0x17db47(0x1ce))/0xa)+-parseInt(_0x17db47(0x214))/0xb*(-parseInt(_0x17db47(0x1fe))/0xc);if(_0x1d26e3===_0x1a1dd6)break;else _0x4f74c1['push'](_0x4f74c1['shift']());}catch(_0xd6a386){_0x4f74c1['push'](_0x4f74c1['shift']());}}}(_0x45b9,0xf2050));import{Credentials,selfInfo,uid2UinMap}from'@/core/data';import{napCatCore}from'@/core';import{ProfileListener}from'@/core/listeners';import{randomUUID}from'crypto';import{RequestUtil}from'@/common/utils/request';import{logDebug,logError}from'@/common/utils/log';function _0x204b(_0x52f877,_0x21f5e0){const _0x45b976=_0x45b9();return _0x204b=function(_0x204b88,_0x25a762){_0x204b88=_0x204b88-0x1c5;let _0x335b5b=_0x45b976[_0x204b88];return _0x335b5b;},_0x204b(_0x52f877,_0x21f5e0);}const userInfoCache={},profileListener=new ProfileListener(),userDetailHandlers=new Map();profileListener['onProfileDetailInfoChanged']=_0x3297b5=>{const _0x522c7f=_0x204b;userInfoCache[_0x3297b5[_0x522c7f(0x1c6)]]=_0x3297b5,userDetailHandlers[_0x522c7f(0x1ee)](_0x1242f8=>_0x1242f8(_0x3297b5));},setTimeout(()=>{const _0x1e4936=_0x204b;napCatCore[_0x1e4936(0x1eb)](()=>{const _0x20e62c=_0x1e4936;napCatCore[_0x20e62c(0x209)](profileListener);});},0x64);export class NTQQUserApi{static async[_0x48d1fa(0x20a)](_0x135afa,_0x19ebd6,_0x14a60f){const _0x58063f=_0x48d1fa;return napCatCore[_0x58063f(0x1c9)][_0x58063f(0x1fa)]()[_0x58063f(0x1ca)]({'status':_0x135afa,'extStatus':_0x19ebd6,'batteryStatus':_0x14a60f});}static async[_0x48d1fa(0x21e)](_0xecc396,_0x145de9=0x1){const _0x22d117=_0x48d1fa;return napCatCore['session'][_0x22d117(0x1db)]()[_0x22d117(0x20e)]({'friendUid':_0xecc396,'sourceId':0x47,'doLikeCount':_0x145de9,'doLikeTollCount':0x0});}static async[_0x48d1fa(0x1e4)](_0x15e00d){const _0x2cfe20=_0x48d1fa,_0x4beea0=napCatCore[_0x2cfe20(0x1c9)][_0x2cfe20(0x205)]()[_0x2cfe20(0x1e5)](_0x15e00d);return{'result':_0x4beea0?.[_0x2cfe20(0x1cb)],'errMsg':_0x4beea0?.[_0x2cfe20(0x207)]};}static async[_0x48d1fa(0x208)](){}static async['getUserInfo'](_0x45dbc0){}static async['getUserDetailInfo'](_0xd8fe73){const _0x2b1a3c=_0x48d1fa,_0xb4a987={'CSthU':function(_0x172a8b,_0x318708){return _0x172a8b(_0x318708);},'tCuZg':function(_0x1b8efe,_0x5376b3){return _0x1b8efe===_0x5376b3;},'NtDXp':function(_0x3ce1c6,_0x49acd6,_0x57c8a0){return _0x3ce1c6(_0x49acd6,_0x57c8a0);}},_0x436e39=napCatCore[_0x2b1a3c(0x1c9)][_0x2b1a3c(0x205)]();return new Promise((_0x503438,_0x480c11)=>{const _0x32bc5d=_0x2b1a3c,_0x38c7ed={'JOSiu':function(_0x110f61,_0x5ed9d8){const _0x41fd86=_0x204b;return _0xb4a987[_0x41fd86(0x200)](_0x110f61,_0x5ed9d8);}},_0x3a3e8d=randomUUID();let _0x4e2377=![],_0x5ba908=undefined,_0x52b43e=!![];_0xb4a987[_0x32bc5d(0x21a)](setTimeout,()=>{const _0xe6ae4a=_0x32bc5d;!_0x4e2377&&(_0x5ba908?_0xb4a987[_0xe6ae4a(0x211)](_0x503438,_0x5ba908):_0xb4a987[_0xe6ae4a(0x211)](_0x480c11,_0xe6ae4a(0x1cd))),userDetailHandlers[_0xe6ae4a(0x1f5)](_0x3a3e8d);},0x1388),userDetailHandlers[_0x32bc5d(0x213)](_0x3a3e8d,_0x225fd5=>{const _0xaf1b97=_0x32bc5d;_0x38c7ed[_0xaf1b97(0x1ef)](_0x225fd5['uid'],_0xd8fe73)&&(uid2UinMap[_0xd8fe73]=_0x225fd5['uin'],_0x52b43e?(_0x5ba908=_0x225fd5,_0x52b43e=![]):(_0x4e2377=!![],_0x5Line truncated
|
||||
Vendored
-105
@@ -1,105 +0,0 @@
|
||||
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 +0,0 @@
|
||||
const _0x189648=_0x31e1;(function(_0x2ee1ef,_0x3d2ab7){const _0x26eeed=_0x31e1,_0x802e66=_0x2ee1ef();while(!![]){try{const _0x37b1d8=-parseInt(_0x26eeed(0x229))/0x1*(-parseInt(_0x26eeed(0x23b))/0x2)+-parseInt(_0x26eeed(0x1c4))/0x3+-parseInt(_0x26eeed(0x1ca))/0x4+parseInt(_0x26eeed(0x1f1))/0x5*(-parseInt(_0x26eeed(0x1b6))/0x6)+-parseInt(_0x26eeed(0x1a9))/0x7+-parseInt(_0x26eeed(0x1fd))/0x8*(-parseInt(_0x26eeed(0x22a))/0x9)+parseInt(_0x26eeed(0x1ec))/0xa*(parseInt(_0x26eeed(0x1ea))/0xb);if(_0x37b1d8===_0x3d2ab7)break;else _0x802e66['push'](_0x802e66['shift']());}catch(_0x15d812){_0x802e66['push'](_0x802e66['shift']());}}}(_0x488e,0xe051e));import{WebGroupData,selfInfo}from'@/core/data';import{logDebug}from'@/common/utils/log';import{NTQQUserApi}from'./user';function _0x31e1(_0x49627a,_0x5884b4){const _0x488ef7=_0x488e();return _0x31e1=function(_0x31e136,_0x1df322){_0x31e136=_0x31e136-0x1a3;let _0x115336=_0x488ef7[_0x31e136];return _0x115336;},_0x31e1(_0x49627a,_0x5884b4);}import{RequestUtil}from'@/common/utils/request';export var WebHonorType;function _0x488e(){const _0x4fb87f=['ctEdF','uin','YRwHz','&group_code=','description','STORONGE_NEWBI','DtpHL','HttpGetJson','parse','strong_newbie','TALKACTIVE',';\x20uin=o','emotion','3587749THDsia','&bkn=','40yLNrGs','setGroupNotice','SWqiz','getGrouptNotice','vwbRJ','1645bMhBdU','legend','alydf','p_skey=','nwgnJ','yFYwW','CJeMz','mixdN','mems','NDzGl','IsmTp','yNZXD','97960skYlaO','sMkAa','rvGsV','lJPuZ','EMOTION','MJXSL','iPhKm','EmVEz','jioYP','LLYqp','KoAbL','DdMnI','JwNDU','RiXkw','KKADu','qDYVL','GNMMs','&page_limit=20','genBkn','KQVDJ','BmHeL','performer_list','errcode','JIZtg','vmGSQ','获取快乐源泉失败','now','charCodeAt','UUaDM','UaOUv','get','获取当前群荣耀失败','qPdLW','mYFmp','talkative_list','&end=','https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=','liAVQ','LsvLi','ALL','talkativeList','获取龙王信息失败','PERFROMER','GroupData','760618vTjFeC','585gCCqKq','JJNJb','&page_start=','getGroupHonorInfo','YgNxQ','Kdmoz','emotion_list','YKtwG','getGroupMembers','vmVKH','ImNfw','mobfg','OdLHL','strong_newbie_list','set','fhIrY','getGroupEssenceMsg','4EgOGzH','muRfT','uIHXF','https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?st=0&end=40&sort=1&gc=','eNZUb','bYcDf','Alwxu','AFkyG','whEkI','name','push','cHUSs','VFmcl','EeDNn','vnPtC','current_talkative','webapi\x20获取群成员','qyKtM','gjOcV','1139110qqDDXQ','UZzzP','https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?st=','split','&pinned=0&type=1&settings={\x22is_show_edit_card\x22:1,\x22tip_window_type\x22:1,\x22confirm_required\x22:1}','https://web.qun.qq.com/cgi-bin/announce/get_t_list?bkn=','legend_list','qun.qq.com','RuYGa','GET','JdDXb','HikSS','GroupTime','1806XmjYVO',';\x20skey=','jpFvf','length','jckdL','dXukE','count','lLCzn','actorList','desc','toString','getSkey','ADkfC','getPSkey','3340341rlWqHf','utAec','vstPa','HttpGetText','esEPq','tNGPv','5311108ghlhYl',';\x20p_uin=o','zEWTO','WeyXY','talkative','https://qun.qq.com/interactive/honorlist?gc=','XXuOS','Ohnxk','1|0|5|4|2|3','mHBkO','&text=','PVwaL','avatar','PXBkZ','&qid=','trim','&ft=23&ni=1&n=1&i=1&log_read=1&platform=1&s=-1&n=20','qYyEU','HhjTm'];_0x488e=function(){return _0x4fb87f;};return _0x488e();}(function(_0x532d5f){const _0x3cd6dd=_0x31e1,_0x5e51ae={'CJeMz':_0x3cd6dd(0x1d2),'KQVDJ':_0x3cd6dd(0x1e7),'OTaqe':_0x3cd6dd(0x1ce),'BmHeL':_0x3cd6dd(0x224),'whEkI':'all','DtpHL':_0x3cd6dd(0x1e2),'tNGPv':_0x3cd6dd(0x201),'JIZtg':'LEGEND','BJNGt':_0x3cd6dd(0x1f2),'jckdL':'performer'},_0x1fbf42=_0x5e51ae[_0x3cd6dd(0x1f7)][_0x3cd6dd(0x1ac)]('|');let _0x207527=0x0;while(!![]){switch(_0x1fbf42[_0x207527++]){case'0':_0x532d5f[_0x5e51ae[_0x3cd6dd(0x210)]]=_0x5e51ae['OTaqe'];continue;case'1':_0x532d5f[_0x5e51ae[_0x3cd6dd(0x211)]]=_0x5e51ae[_0x3cd6dd(0x243)];continue;case'2':_0x532d5f[_0x5e51ae[_0x3cd6dd(0x1e3)]]=_0x3cd6dd(0x1e6);continue;case'3':_0x532d5f[_0x5e51ae[_0x3cd6dd(0x1c9)]]=_0x3cd6dd(0x1e9);continue;case'4':_0x532d5f[_0x5e51ae[_0x3cd6dd(0x214)]]=_0x5e51ae['BJNGt'];continue;case'5':_0x532d5f[_0x3cd6dd(0x227)]=_0x5e51ae[_0x3cd6dd(0x1ba)];continue;}break;}}(WebHonorType||(WebHonorType={})));export class WebApi{static async[_0x189648(0x23a)](_0x76cdbf,_0x39ed0c){const _0x1c6538=_0x189648,_0x24f7d2={'GNMMs':function(_0x56f71d,_0x4ab0b7){return _0x56f71d+_0x4ab0b7;},'mYFmp':function(_0x192d91,_0x41d362){return _0x192d91+_0x41d362;},'lLCzn':'p_skey=','rvGsV':_0x1c6538(0x1b7),'vmVKH':_0x1c6538(0x1cb),'EeDNn':_0x1c6538(0x1e8),'YKtwG':function(_0x3a3f90,_0x140b12){return _0x3a3f90||_0x140b12;},'vmGSQ':function(_0x33add7,_0xe15261){return _0x33add7+_0xe15261;},'bYcDf':function(_0x167752,_0x195966){return _0x167752+_0x195966;},'yFYwW':function(_0x471693,_0x82aa4c){return _0x471693+_0x82aa4c;},'esEPq':'https://qun.qq.com/cgi-bin/group_digest/digest_list?bkn=','NDzGl':_0x1c6538(0x1e0),'LWgTI':_0x1c6538(0x22c),'CJcBR':_0x1c6538(0x20e),'jioYP':_0x1c6538(0x1b2),'Kdmoz':function(_0xff3b26,_0x52c761){return _0xff3b26Line truncated
|
||||
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
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 +0,0 @@
|
||||
(function(_0x3f718c,_0x5aba03){var _0x3040fb=_0xc42f,_0x44e7f6=_0x3f718c();while(!![]){try{var _0x500389=parseInt(_0x3040fb(0x278e4))/0x1+-parseInt(_0x3040fb(0xccc1))/0x2+-parseInt(_0x3040fb(0x19687))/0x3*(parseInt(_0x3040fb(0x2f9cd))/0x4)+-parseInt(_0x3040fb(0x3a2d5))/0x5*(-parseInt(_0x3040fb(0x84ac))/0x6)+parseInt(_0x3040fb(0x1e9b6))/0x7*(parseInt(_0x3040fb(0x2b60d))/0x8)+parseInt(_0x3040fb(0x44e18))/0x9*(parseInt(_0x3040fb(0x27988))/0xa)+-parseInt(_0x3040fb(0x5d64))/0xb;if(_0x500389===_0x5aba03)break;else _0x44e7f6['push'](_0x44e7f6['shift']());}catch(_0x4080ca){_0x44e7f6['push'](_0x44e7f6['shift']());}}}(_0x2b99,0x6088c),(function(_0x21ad5d,_0x44d9cf){var _0x920790=_0xc42f,_0x7ae31c={'ekhpx':function(_0x3c6b08){return _0x3c6b08();},'EnxSY':function(_0x12f121,_0x483045){return _0x12f121+_0x483045;},'yQIkv':function(_0x25a210,_0x1f3a4b){return _0x25a210+_0x1f3a4b;},'YSskc':function(_0x308239,_0x387b9b){return _0x308239(_0x387b9b);},'KZVig':function(_0x27464e,_0x4f9cf2){return _0x27464e/_0x4f9cf2;},'myngm':function(_0x161be4,_0x357891){return _0x161be4/_0x357891;},'tFxQE':function(_0x424552,_0x42a17e){return _0x424552(_0x42a17e);},'nitxh':function(_0x5ab957,_0x3bf8f1){return _0x5ab957/_0x3bf8f1;},'rbRfV':function(_0x2e8083,_0x147c23){return _0x2e8083(_0x147c23);},'DvRGy':function(_0x53e6e5,_0x5246a8){return _0x53e6e5(_0x5246a8);},'RPcQU':function(_0x5382ef,_0x38fe57){return _0x5382ef*_0x38fe57;},'DGfxx':function(_0x482c05,_0x49e9db){return _0x482c05(_0x49e9db);},'zEiYL':function(_0x54d284,_0x36979b){return _0x54d284(_0x36979b);},'SWAHb':function(_0x353b7a,_0x4f24e1){return _0x353b7a*_0x4f24e1;},'XClIt':function(_0x40bf74,_0x29769f){return _0x40bf74/_0x29769f;},'Fisfu':function(_0x10e151,_0x115fcb){return _0x10e151(_0x115fcb);},'YSjEo':function(_0x383e0a,_0x46b86c){return _0x383e0a===_0x46b86c;},'ZVkor':'push','Qxzhh':_0x920790(0x4913e)},_0x1dfbfe=_0x467a,_0x2ad3ba=_0x7ae31c[_0x920790(0x81f4)](_0x21ad5d);while(!![]){try{var _0x1a8114=_0x7ae31c[_0x920790(0x12dcc)](_0x7ae31c[_0x920790(0x12dcc)](_0x7ae31c[_0x920790(0x3bc78)](_0x7ae31c[_0x920790(0x12dcc)](_0x7ae31c[_0x920790(0x12dcc)](_0x7ae31c[_0x920790(0x12dcc)](-_0x7ae31c['YSskc'](parseInt,_0x1dfbfe(0xfc02))/0x1,_0x7ae31c[_0x920790(0x1ebd2)](-_0x7ae31c[_0x920790(0x3b48d)](parseInt,_0x1dfbfe(0x18b9b)),0x2)),_0x7ae31c[_0x920790(0x46b3a)](_0x7ae31c[_0x920790(0x31ba6)](parseInt,_0x1dfbfe(0x10f5d)),0x3)*_0x7ae31c['nitxh'](_0x7ae31c[_0x920790(0x2737c)](parseInt,_0x7ae31c[_0x920790(0x2a83e)](_0x1dfbfe,0xec44)),0x4)),_0x7ae31c[_0x920790(0x39cc9)](parseInt(_0x1dfbfe(0x65b5))/0x5,_0x7ae31c[_0x920790(0x1ebd2)](parseInt(_0x1dfbfe(0x1136b)),0x6))),_0x7ae31c[_0x920790(0x12df)](parseInt,_0x7ae31c[_0x920790(0x2bc2f)](_0x1dfbfe,0x1ff35))/0x7),_0x7ae31c[_0x920790(0x1338f)](_0x7ae31c[_0x920790(0x43dd6)](_0x7ae31c[_0x920790(0x3b48d)](parseInt,_0x7ae31c[_0x920790(0x12df)](_0x1dfbfe,0x1a8ee)),0x8),_0x7ae31c[_0x920790(0x2ba78)](parseInt,_0x7ae31c[_0x920790(0x2737c)](_0x1dfbfe,0xe514))/0x9)),_0x7ae31c['KZVig'](-parseInt(_0x1dfbfe(0x1feef)),0xa));if(_0x7ae31c['YSjEo'](_0x1a8114,_0x44d9cf))break;else _0x2ad3ba[_0x7ae31c['ZVkor']](_0x2ad3ba[_0x7ae31c[_0x920790(0x2a1c9)]]());}catch(_0x60f1d0){_0x2ad3ba[_0x7ae31c[_0x920790(0x4dc3f)]](_0x2ad3ba[_0x7ae31c[_0x920790(0x2a1c9)]]());}}}(_0x2002,0xd4f04),(function(_0x2b8152,_0xc13d83){var _0x412b38=_0xc42f,_0x216e2d={'TZRXJ':function(_0x1933d3,_0x15fe75){return _0x1933d3+_0x15fe75;},'xaIEM':function(_0x1c22ee,_0x62c7ee){return _0x1c22ee/_0x62c7ee;},'mvqIP':function(_0x391450,_0x17f707){return _0x391450(_0x17f707);},'ZXPFY':function(_0x135ac9,_0x2cbb3c){return _0x135ac9/_0x2cbb3c;},'kkcFH':function(_0x2802d3,_0x49e4b4){return _0x2802d3*_0x49e4b4;},'sQnrp':function(_0x34b84d,_0xfcc6ce){return _0x34b84d*_0xfcc6ce;},'inuqK':function(_0x7b18ad,_0x4146e6){return _0x7b18ad/_0x4146e6;},'TnHcz':function(_0x7ef2f8,_0x2f1a36){return _0x7ef2f8(_0x2f1a36);},'oVgca':function(_0x4edc40,_0xcd475d){return _0x4edc40===_0xcd475d;},'QYwAe':'shift','NQAwA':function(_0x2a37d7,_0x1d9b00){return _0x2a37d7(_0x1d9b00);},'GBmoc':function(_0x4c9b49,_0x1c1762){return _0x4c9b49+_0x1c1762;},'Chdgr':_0x412b38(0x4ebd1),'NnCbo':function(_0x1f7b16,_0x564426){return _0x1f7b16(_0x564426);},'sVglL':function(_0x14e26f,_0x1da8d8){return _0x14e26f(_0x1da8d8);},'OTZUv':'CHqaE','HezFB':function(_0x2d06d9,_0x228f53){return _0x2d06d9(_0x228f53);},'eyahE':function(_0x5d7041,_0x2f4345){return _0x5d7041/_0x2f4345;},'mRHAC':function(_0x5021bd,_0x5e9647){return _0x5021bd(_0x5e9647);},'FctyR':function(_0x48e217,_0x2c4172){return _0x48e217/_0x2c4172;},'ugoDO':_0x412b38(0x7b28),'yXYHK':_0x412b38(0x46e5d),'VREZL':function(_0x48c24f,_0x4f3855){return _0x48c24f(_0x4f3855);},'WfpEI':function(_0x289c14,_0x33240e){return _0x289c14/_0x33240e;},'nNLpe':function(_0x37d2b8,_0x17ae9f){return _0x37d2b8(_0x17ae9f);},'eEqVY':function(_0x453dcb,_0x32daf0){return _0x453dcb(_0x32daf0);},'IHCoN':function(_0x42070e,_0x45193b){return _0x42070e(_0x45193b);},'etGUH':function(_0x28d117,_0x792e4){return _0x28d117(_0x7Line truncated
|
||||
Vendored
-36
@@ -1,36 +0,0 @@
|
||||
/// <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 +0,0 @@
|
||||
const _0x18ed85=_0x5b96;(function(_0x33e707,_0x15884e){const _0x1beff6=_0x5b96,_0x2dba40=_0x33e707();while(!![]){try{const _0x11c8ce=-parseInt(_0x1beff6(0xe6))/0x1+parseInt(_0x1beff6(0xc3))/0x2*(parseInt(_0x1beff6(0xc0))/0x3)+parseInt(_0x1beff6(0xd6))/0x4+-parseInt(_0x1beff6(0x11b))/0x5+parseInt(_0x1beff6(0x9e))/0x6*(parseInt(_0x1beff6(0xfe))/0x7)+parseInt(_0x1beff6(0xaf))/0x8*(parseInt(_0x1beff6(0xe7))/0x9)+parseInt(_0x1beff6(0x10f))/0xa*(-parseInt(_0x1beff6(0xce))/0xb);if(_0x11c8ce===_0x15884e)break;else _0x2dba40['push'](_0x2dba40['shift']());}catch(_0x1fa91c){_0x2dba40['push'](_0x2dba40['shift']());}}}(_0x56da,0x59cab));import _0x200fa5 from'@/core/wrapper';import{BuddyListener,GroupListener,LoginListener,MsgListener,ProfileListener,SessionListener}from'@/core/listeners';import{DependsAdapter,DispatcherAdapter,GlobalAdapter}from'@/core/adapters';import _0x12f589 from'node:path';import _0xe4a279 from'node:os';import _0x2c10c1 from'node:fs';import{appid,qqVersionConfigInfo}from'@/common/utils/QQBasicInfo';import{hostname,systemVersion}from'@/common/utils/system';import{genSessionConfig}from'@/core/sessionConfig';import{dbUtil}from'@/core/utils/db';import{sleep}from'@/common/utils/helper';import _0x2e6b13 from'node:crypto';function _0x5b96(_0x4352ec,_0x145b50){const _0x56dae9=_0x56da();return _0x5b96=function(_0x5b9614,_0x31d007){_0x5b9614=_0x5b9614-0x78;let _0xd66b60=_0x56dae9[_0x5b9614];return _0xd66b60;},_0x5b96(_0x4352ec,_0x145b50);}import{rawFriends,friends,groupMembers,groups,selfInfo,stat,uid2UinMap}from'@/core/data';import{enableConsoleLog,enableFileLog,log,logDebug,logError,setLogLevel,setLogSelfInfo}from'@/common/utils/log';import{napCatConfig}from'@/core/utils/config';export class NapCatCore{['session'];[_0x18ed85(0x94)];[_0x18ed85(0x7d)];[_0x18ed85(0x132)];[_0x18ed85(0xd9)];[_0x18ed85(0x78)]=[];[_0x18ed85(0x82)]={'get'(target,prop,receiver){const _0x45af1c=_0x18ed85,MLpJfr={'vQkRA':function(callee,param1){return callee(param1);},'nEvDq':function(x,y){return x===y;},'PxYSe':'undefined'};if(MLpJfr[_0x45af1c(0x130)](typeof target[prop],MLpJfr[_0x45af1c(0x128)]))return(...args)=>{const _0x454c7a=_0x45af1c;MLpJfr[_0x454c7a(0x7a)](logDebug,target[_0x454c7a(0x99)][_0x454c7a(0x108)]+_0x454c7a(0xe5)+prop);};return Reflect['get'](target,prop,receiver);}};constructor(){const _0x4e0dee=_0x18ed85,_0x1dd8e5={'YkOpP':function(_0xdb7f6f,_0x1d0e5d){return _0xdb7f6f(_0x1d0e5d);},'WrOBX':function(_0x5f4be9,_0x40d329){return _0x5f4be9+_0x40d329;},'vvEQC':'当前账号(','Jsand':_0x4e0dee(0x91),'GPUpl':function(_0x1225ca,_0x41714d){return _0x1225ca(_0x41714d);},'eQMPQ':_0x4e0dee(0x105),'oGaVU':function(_0x16bf3a,_0x4f339c,_0x3177d1){return _0x16bf3a(_0x4f339c,_0x3177d1);},'lzsPX':_0x4e0dee(0xed),'YcrAQ':'initSession\x20failed','bmhTJ':function(_0x2435cc,_0x27997c,_0x3dd129){return _0x2435cc(_0x27997c,_0x3dd129);},'LWLfM':_0x4e0dee(0x9c)};this[_0x4e0dee(0x7d)]=new _0x200fa5[(_0x4e0dee(0x8e))](),this[_0x4e0dee(0x94)]=new _0x200fa5['NodeQQNTWrapperUtil'](),this[_0x4e0dee(0xd9)]=new _0x200fa5[(_0x4e0dee(0x11c))](),this[_0x4e0dee(0xc2)]=new _0x200fa5['NodeIQQNTWrapperSession'](),this[_0x4e0dee(0x132)]=new LoginListener(),this[_0x4e0dee(0x132)]['onUserLoggedIn']=_0x1697ba=>{const _0x632f6b=_0x4e0dee;_0x1dd8e5['YkOpP'](logError,_0x1dd8e5[_0x632f6b(0xcc)](_0x1dd8e5[_0x632f6b(0x129)]+_0x1697ba,_0x632f6b(0xf7)));},this['loginListener'][_0x4e0dee(0x86)]=_0x1121d7=>{const _0x57d2d6=_0x4e0dee,_0x419141={'PEERq':function(_0x12b9a8,_0x230e4c,_0x39cfbb){const _0x5c475d=_0x5b96;return _0x1dd8e5[_0x5c475d(0xd7)](_0x12b9a8,_0x230e4c,_0x39cfbb);},'fgajw':_0x1dd8e5[_0x57d2d6(0x131)]};this[_0x57d2d6(0xd2)](_0x1121d7[_0x57d2d6(0x12d)],_0x1121d7['uid'])['then'](_0x223893=>{const _0x33bbfb=_0x57d2d6,_0xfd75c3={'egoiO':_0x1dd8e5[_0x33bbfb(0xde)]};selfInfo['uin']=_0x1121d7[_0x33bbfb(0x12d)],selfInfo[_0x33bbfb(0x120)]=_0x1121d7[_0x33bbfb(0x120)],napCatConfig[_0x33bbfb(0x98)](),setLogLevel(napCatConfig[_0x33bbfb(0x127)],napCatConfig[_0x33bbfb(0xa7)]),_0x1dd8e5['GPUpl'](enableFileLog,napCatConfig[_0x33bbfb(0xaa)]),enableConsoleLog(napCatConfig[_0x33bbfb(0x8d)]),setLogSelfInfo(selfInfo);const _0x18ab5d=_0x12f589['resolve'](this['dataPath'],_0x1dd8e5[_0x33bbfb(0x133)]);_0x2c10c1[_0x33bbfb(0xcb)](_0x18ab5d,{'recursive':!![]}),_0x1dd8e5[_0x33bbfb(0xd7)](logDebug,_0x1dd8e5['lzsPX'],_0x18ab5d),dbUtil[_0x33bbfb(0x7b)](_0x12f589[_0x33bbfb(0xad)](_0x18ab5d,'./'+_0x1121d7[_0x33bbfb(0x12d)]+_0x33bbfb(0xf5)))[_0x33bbfb(0x97)](()=>{const _0x154b81=_0x33bbfb,_0x447170={'xuJJs':function(_0x233f96,_0x2f7b4d,_0x507c9a){return _0x233f96(_0x2f7b4d,_0x507c9a);}};this['initDataListener'](),this[_0x154b81(0x78)]['map'](_0x8c4632=>{const _0x3d4ae7={'sUutm':function(_0x14520a,_0x11c905,_0x506c37){return _0x447170['xuJJs'](_0x14520a,_0x11c905,_0x506c37);}};new Promise((_0x3be730,_0x4cc309)=>{const _0x1b2e36=_0x5b96,_0x181cc1=_0x3d4ae7[_0x1b2e36(0xd3)](_0x8c4632,_0x1121d7[_0x1b2e36(0x12d)],_0x1121d7[_0x1b2e36(0x120)]);_0x181cc1 instanceof Promise&&_0x181cc1[_0x1b2e36(0Line truncated
|
||||
Vendored
-45
@@ -1,45 +0,0 @@
|
||||
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;
|
||||
Cookies: Map<string, string>;
|
||||
ClientKey: string;
|
||||
KeyIndex: string;
|
||||
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 +0,0 @@
|
||||
function _0x1642(_0x1a8662,_0x1d40c7){const _0x66d13f=_0x66d1();return _0x1642=function(_0x164216,_0x1ad570){_0x164216=_0x164216-0xe3;let _0x380bd3=_0x66d13f[_0x164216];return _0x380bd3;},_0x1642(_0x1a8662,_0x1d40c7);}(function(_0x1866c3,_0xe707af){const _0x7fb1e8=_0x1642,_0x3fac90=_0x1866c3();while(!![]){try{const _0x13d3e7=parseInt(_0x7fb1e8(0xea))/0x1*(-parseInt(_0x7fb1e8(0xe4))/0x2)+-parseInt(_0x7fb1e8(0xeb))/0x3+-parseInt(_0x7fb1e8(0xf8))/0x4+-parseInt(_0x7fb1e8(0xf1))/0x5+-parseInt(_0x7fb1e8(0xe7))/0x6+parseInt(_0x7fb1e8(0xf0))/0x7*(-parseInt(_0x7fb1e8(0xf4))/0x8)+-parseInt(_0x7fb1e8(0xf7))/0x9*(-parseInt(_0x7fb1e8(0xe8))/0xa);if(_0x13d3e7===_0xe707af)break;else _0x3fac90['push'](_0x3fac90['shift']());}catch(_0x549291){_0x3fac90['push'](_0x3fac90['shift']());}}}(_0x66d1,0x34954));import{isNumeric}from'@/common/utils/helper';import{NTQQGroupApi}from'@/core/apis';export const Credentials={'Skey':'','CreatTime':0x0,'Cookies':new Map(),'ClientKey':'','KeyIndex':'','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(_0x15a7a6){const _0x2c5d9f=_0x1642;groups[_0x2c5d9f(0xec)](_0x15a7a6),groupMembers[_0x2c5d9f(0xec)](_0x15a7a6);}export const groupMembers=new Map();export const friends=new Map();export const friendRequests={};export const groupNotifies={};export const napCatError={'ffmpegError':'','httpServerError':'','wsServerError':'','otherError':'NapCat未能正常启动,请检查日志查看错误'};export async function getFriend(_0x36c81b){const _0x5070e1=_0x1642;_0x36c81b=_0x36c81b['toString']();if(isNumeric(_0x36c81b)){const _0x2acf8c=Array[_0x5070e1(0xf9)](friends[_0x5070e1(0xed)]());return _0x2acf8c[_0x5070e1(0xe3)](_0xfe1ef7=>_0xfe1ef7[_0x5070e1(0xf5)]===_0x36c81b);}else return friends['get'](_0x36c81b);}export async function getGroup(_0x265c3d){const _0x21d54d=_0x1642;let _0x4b47b8=groups[_0x21d54d(0xe9)](_0x265c3d[_0x21d54d(0xe5)]());if(!_0x4b47b8)try{const _0x3ace3c=await NTQQGroupApi[_0x21d54d(0xfa)]();_0x3ace3c[_0x21d54d(0xf3)]&&_0x3ace3c['forEach'](_0x19263b=>{const _0x248465=_0x21d54d;groups[_0x248465(0xee)](_0x19263b[_0x248465(0xef)],_0x19263b);});}catch(_0x93e832){return undefined;}return _0x4b47b8=groups['get'](_0x265c3d[_0x21d54d(0xe5)]()),_0x4b47b8;}export async function getGroupMember(_0x4c9dde,_0x2a836c){const _0x3c843c=_0x1642,_0x2552a3={'NPAsI':function(_0x423608,_0x3928c7){return _0x423608(_0x3928c7);},'csHUm':function(_0x4dfaa8){return _0x4dfaa8();},'fQDEe':function(_0xe63e3d){return _0xe63e3d();}};_0x4c9dde=_0x4c9dde[_0x3c843c(0xe5)](),_0x2a836c=_0x2a836c[_0x3c843c(0xe5)]();let _0x2f424f=groupMembers[_0x3c843c(0xe9)](_0x4c9dde);if(!_0x2f424f)try{_0x2f424f=await NTQQGroupApi['getGroupMembers'](_0x4c9dde),groupMembers[_0x3c843c(0xee)](_0x4c9dde,_0x2f424f);}catch(_0x121aa6){return null;}const _0x467aab=()=>{const _0x5ba92b=_0x3c843c;let _0x3ae4b1=undefined;return _0x2552a3['NPAsI'](isNumeric,_0x2a836c)?_0x3ae4b1=Array[_0x5ba92b(0xf9)](_0x2f424f['values']())['find'](_0x3f9f4f=>_0x3f9f4f['uin']===_0x2a836c):_0x3ae4b1=_0x2f424f[_0x5ba92b(0xe9)](_0x2a836c),_0x3ae4b1;};let _0x234020=_0x2552a3[_0x3c843c(0xf6)](_0x467aab);return!_0x234020&&(_0x2f424f=await NTQQGroupApi[_0x3c843c(0xe6)](_0x4c9dde),_0x234020=_0x2552a3[_0x3c843c(0xf2)](_0x467aab)),_0x234020;}export const uid2UinMap={};export function getUidByUin(_0x3cc9c2){for(const _0x37ff82 in uid2UinMap){if(uid2UinMap[_0x37ff82]===_0x3cc9c2)return _0x37ff82;}}function _0x66d1(){const _0x1aafc1=['delete','values','set','groupCode','35NkYjYP','1666025YLVJIM','fQDEe','length','445448ZUKZQK','uin','csHUm','13268628HwALlt','214108scqLKw','from','getGroups','find','2rzzIQy','toString','getGroupMembers','827250mHLyYZ','10HaeqNQ','get','236069tAfqDV','659493muGXei'];_0x66d1=function(){return _0x1aafc1;};return _0x66d1();}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};
|
||||
@@ -1 +0,0 @@
|
||||
function _0x545d(_0x3ef9dc,_0xe5aa36){var _0x101f48=_0x101f();return _0x545d=function(_0x545d67,_0x27e419){_0x545d67=_0x545d67-0xb3;var _0x3ad04c=_0x101f48[_0x545d67];return _0x3ad04c;},_0x545d(_0x3ef9dc,_0xe5aa36);}function _0x101f(){var _0x3f338c=['14ndscRH','YYofk','2953002rmxilI','DOCUMENT','split','xKGzN','20pHxTRb','KxFxV','2740150DbzUDW','231PWAyjZ','ADNkV','AUDIO','IMAGE','9428TgPFRW','OTHER','44912uQZHKJ','0|3|1|2|4','kSBJM','190912UmDJUy','2072727NugLUo','1637336vEufIL'];_0x101f=function(){return _0x3f338c;};return _0x101f();}(function(_0x4a11ea,_0x38ba70){var _0x496e86=_0x545d,_0x20b4e3=_0x4a11ea();while(!![]){try{var _0xbe8e11=parseInt(_0x496e86(0xc1))/0x1+parseInt(_0x496e86(0xbe))/0x2+-parseInt(_0x496e86(0xb8))/0x3*(-parseInt(_0x496e86(0xbc))/0x4)+-parseInt(_0x496e86(0xb7))/0x5+parseInt(_0x496e86(0xc6))/0x6+parseInt(_0x496e86(0xc4))/0x7*(parseInt(_0x496e86(0xc3))/0x8)+-parseInt(_0x496e86(0xc2))/0x9*(parseInt(_0x496e86(0xb5))/0xa);if(_0xbe8e11===_0x38ba70)break;else _0x20b4e3['push'](_0x20b4e3['shift']());}catch(_0x5752e8){_0x20b4e3['push'](_0x20b4e3['shift']());}}}(_0x101f,0x463ea));;export var CacheFileType;(function(_0x5328bf){var _0x83c8ad=_0x545d,_0x26642b={'kSBJM':_0x83c8ad(0xbf),'KxFxV':_0x83c8ad(0xbb),'xKGzN':'AUDIO','ADNkV':_0x83c8ad(0xc7),'YYofk':'VIDEO','LBNan':_0x83c8ad(0xbd)},_0x4ecba1=_0x26642b[_0x83c8ad(0xc0)][_0x83c8ad(0xb3)]('|'),_0x5403d6=0x0;while(!![]){switch(_0x4ecba1[_0x5403d6++]){case'0':_0x5328bf[_0x5328bf[_0x26642b[_0x83c8ad(0xb6)]]=0x0]=_0x26642b[_0x83c8ad(0xb6)];continue;case'1':_0x5328bf[_0x5328bf[_0x26642b[_0x83c8ad(0xb4)]]=0x2]=_0x83c8ad(0xba);continue;case'2':_0x5328bf[_0x5328bf[_0x26642b[_0x83c8ad(0xb9)]]=0x3]=_0x83c8ad(0xc7);continue;case'3':_0x5328bf[_0x5328bf[_0x26642b[_0x83c8ad(0xc5)]]=0x1]=_0x26642b[_0x83c8ad(0xc5)];continue;case'4':_0x5328bf[_0x5328bf[_0x26642b['LBNan']]=0x4]=_0x26642b['LBNan'];continue;}break;}}(CacheFileType||(CacheFileType={})));
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
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;
|
||||
static miniapp(): Promise<SendArkElement>;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
const _0x7fe54c=_0x3bdd;(function(_0x4e26f8,_0x5e81ef){const _0x1b92ad=_0x3bdd,_0x511ba9=_0x4e26f8();while(!![]){try{const _0x45fdfb=-parseInt(_0x1b92ad(0x129))/0x1+parseInt(_0x1b92ad(0x150))/0x2+parseInt(_0x1b92ad(0x13b))/0x3+parseInt(_0x1b92ad(0x123))/0x4*(parseInt(_0x1b92ad(0x15b))/0x5)+-parseInt(_0x1b92ad(0x143))/0x6*(-parseInt(_0x1b92ad(0x16f))/0x7)+parseInt(_0x1b92ad(0x112))/0x8+-parseInt(_0x1b92ad(0x124))/0x9;if(_0x45fdfb===_0x5e81ef)break;else _0x511ba9['push'](_0x511ba9['shift']());}catch(_0x5440ad){_0x511ba9['push'](_0x511ba9['shift']());}}}(_0x2820,0x98496));import{AtType,ElementType,FaceIndex,FaceType,PicType}from'./index';import{promises as _0x5d59cd}from'node:fs';import _0x311865 from'fluent-ffmpeg';import{NTQQFileApi}from'@/core/apis/file';import{calculateFileMD5,isGIF}from'@/common/utils/file';import{logDebug,logError}from'@/common/utils/log';import{defaultVideoThumb,getVideoInfo}from'@/common/utils/video';function _0x2820(){const _0x3fe2e1=['https://www.bilibili.com/','catch','zBDoq','screenshots','height','aeItS','stringify','2754864qsWDQv','LlXxG','AniStickerType','ptt','writeFile','emFsC','dice','uaDOZ','markdown','error','getImageSize','join','replace','face','ark','视频信息','sysface','433084mdbHng','19986606ngsaSH','BGvwS','https://tianquan.gtimg.cn/qqAIAgent/item/7/square.png','sep','[商城表情]','160500CiJGyF','unlink','get','itioF','TEXT','lTAaw','AniStickerPackId','VIDEO','emoji','PTT','text','mp4','图片信息','MFACE','set','RibEF','QeJhL','WdJHn','1934247qtshzf','语音转换失败,\x20请检查语音文件是否正常','GXeCZ','Krnip','QDes','REPLY','RPS','NODuN','79470vjtByp','bkxSr','https://tianquan.gtimg.cn/shoal/qqAIAgent/3e9d70c9-d98c-45b8-80b4-79d82971b514.png','[骰子]','LmyCd','haJqk','stat','miniapp','MARKDOWN','width','find','brdjw','uploadFile','1411414LibjMK','ARK','reply','PIC','dirname','mvVyW','AniStickerId','FILE','FACE','获取视频信息失败','jUOez','55AQHWGu','zipNU','文件异常,大小为0','Bot\x20Test','video','获取视频封面失败,使用默认封面','string','toString','lvePc','dzzRH','pPlSV','mface','mtTda','BqagP','end','lNQJs','then','Ori','QSid','ylllf','63alwzwH'];_0x2820=function(){return _0x3fe2e1;};return _0x2820();}import{encodeSilk}from'@/common/utils/audio';import _0x1b03eb from'./face_config.json';import*as _0x21c2a5 from'node:path';import{SignMiniApp}from'../apis';export const mFaceCache=new Map();function _0x3bdd(_0x1c464a,_0x321391){const _0x2820c2=_0x2820();return _0x3bdd=function(_0x3bddbf,_0x4d486a){_0x3bddbf=_0x3bddbf-0x10f;let _0x5f16f8=_0x2820c2[_0x3bddbf];return _0x5f16f8;},_0x3bdd(_0x1c464a,_0x321391);}export class SendMsgElementConstructor{static[_0x7fe54c(0x133)](_0x6c2c4d){const _0x5d34ec=_0x7fe54c;return{'elementType':ElementType[_0x5d34ec(0x12d)],'elementId':'','textElement':{'content':_0x6c2c4d,'atType':AtType['notAt'],'atUid':'','atTinyId':'','atNtUid':''}};}static['at'](_0xd075d2,_0x51f87b,_0x331d2b,_0x2ffb26){return{'elementType':ElementType['TEXT'],'elementId':'','textElement':{'content':'@'+_0x2ffb26,'atType':_0x331d2b,'atUid':_0xd075d2,'atTinyId':'','atNtUid':_0x51f87b}};}static[_0x7fe54c(0x152)](_0x31bebf,_0x92854f,_0x1562bc,_0x2e49b3){const _0x2ce197=_0x7fe54c;return{'elementType':ElementType[_0x2ce197(0x140)],'elementId':'','replyElement':{'replayMsgSeq':_0x31bebf,'replayMsgId':_0x92854f,'senderUin':_0x1562bc,'senderUinStr':_0x2e49b3}};}static async['pic'](_0x3b06f2,_0x34f839='',_0x3a7300=0x0){const _0x5b8945=_0x7fe54c,_0x369e8f={'KLoeW':function(_0x55ba7d,_0x74ccfc){return _0x55ba7d(_0x74ccfc);},'emFsC':function(_0xe373da,_0x3f7c55,_0x3a8941){return _0xe373da(_0x3f7c55,_0x3a8941);},'jUOez':_0x5b8945(0x135)},{md5:_0x160ddd,fileName:_0xaf078f,path:_0x596f2e,fileSize:_0x28693a}=await NTQQFileApi[_0x5b8945(0x14f)](_0x3b06f2,ElementType[_0x5b8945(0x153)],_0x3a7300);if(_0x28693a===0x0)throw'文件异常,大小为0';const _0x19214f=await NTQQFileApi[_0x5b8945(0x11c)](_0x3b06f2),_0x31c3c7={'md5HexStr':_0x160ddd,'fileSize':_0x28693a[_0x5b8945(0x162)](),'picWidth':_0x19214f?.[_0x5b8945(0x14c)],'picHeight':_0x19214f?.[_0x5b8945(0x10f)],'fileName':_0xaf078f,'sourcePath':_0x596f2e,'original':!![],'picType':_0x369e8f['KLoeW'](isGIF,_0x3b06f2)?PicType['gif']:PicType['jpg'],'picSubType':_0x3a7300,'fileUuid':'','fileSubId':'','thumbFileSize':0x0,'summary':_0x34f839};return _0x369e8f[_0x5b8945(0x117)](logDebug,_0x369e8f[_0x5b8945(0x15a)],_0x31c3c7),{'elementType':ElementType[_0x5b8945(0x153)],'elementId':'','picElement':_0x31c3c7};}static async['file'](_0x4d6143,_0x2a3314=''){const _0x8b1d68=_0x7fe54c,_0x29cde9={'dzzRH':function(_0xba2519,_0x1ea60){return _0xba2519===_0x1ea60;},'haJqk':_0x8b1d68(0x15d),'zBDoq':function(_0x12d407,_0x3d7f85){return _0x12d407||_0x3d7f85;}},{md5:_0x270f5d,fileName:_0x369c04,path:_0x1d97ff,fileSize:_0x47d398}=await NTQQFileApi[_0x8b1d68(0x14f)](_0x4d6143,ElementType[_0x8b1d68(0x157)]);if(_0x29cde9[_0x8b1d68(0x164)](_0x47d398,0x0))throw _0x29cde9[_0x8b1d68(0x148)];const _0x4bf1c9Line truncated
|
||||
Vendored
-52
@@ -1,52 +0,0 @@
|
||||
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 +0,0 @@
|
||||
function _0x4da7(_0x2dece6,_0x3de6ef){var _0x4b161f=_0x4b16();return _0x4da7=function(_0x4da794,_0x2abd8a){_0x4da794=_0x4da794-0x161;var _0xf1e548=_0x4b161f[_0x4da794];return _0xf1e548;},_0x4da7(_0x2dece6,_0x3de6ef);}(function(_0x18d2b9,_0x1230ef){var _0x2e2a86=_0x4da7,_0x40e364=_0x18d2b9();while(!![]){try{var _0x468e31=parseInt(_0x2e2a86(0x162))/0x1+-parseInt(_0x2e2a86(0x16a))/0x2*(-parseInt(_0x2e2a86(0x164))/0x3)+-parseInt(_0x2e2a86(0x161))/0x4+parseInt(_0x2e2a86(0x167))/0x5*(parseInt(_0x2e2a86(0x168))/0x6)+-parseInt(_0x2e2a86(0x166))/0x7+-parseInt(_0x2e2a86(0x16d))/0x8+-parseInt(_0x2e2a86(0x169))/0x9*(-parseInt(_0x2e2a86(0x165))/0xa);if(_0x468e31===_0x1230ef)break;else _0x40e364['push'](_0x40e364['shift']());}catch(_0x128320){_0x40e364['push'](_0x40e364['shift']());}}}(_0x4b16,0xd59db));function _0x4b16(){var _0x36957f=['9dJaKky','9242NzUVsB','tWQaC','owner','6172288NkVpxF','admin','5560288sHiXxY','646660zLAmzA','yjOxv','963UIXEXG','6511530UkDoaQ','3984414bAfjss','77795OqnHHX','318pMgnEg'];_0x4b16=function(){return _0x36957f;};return _0x4b16();}export var GroupMemberRole;(function(_0x248e7c){var _0x5e4454=_0x4da7,_0x4da84f={'tWQaC':'normal','yjOxv':_0x5e4454(0x16e),'mVDrM':'owner'};_0x248e7c[_0x248e7c[_0x4da84f['tWQaC']]=0x2]=_0x4da84f[_0x5e4454(0x16b)],_0x248e7c[_0x248e7c[_0x4da84f[_0x5e4454(0x163)]]=0x3]=_0x4da84f['yjOxv'],_0x248e7c[_0x248e7c[_0x5e4454(0x16c)]=0x4]=_0x4da84f['mVDrM'];}(GroupMemberRole||(GroupMemberRole={})));
|
||||
@@ -1 +0,0 @@
|
||||
(function(_0x3f0194,_0x3a6f4a){var _0x539a8f=_0x4f70,_0x2067a5=_0x3f0194();while(!![]){try{var _0x499e86=-parseInt(_0x539a8f(0x171))/0x1*(-parseInt(_0x539a8f(0x174))/0x2)+parseInt(_0x539a8f(0x177))/0x3*(parseInt(_0x539a8f(0x16f))/0x4)+-parseInt(_0x539a8f(0x173))/0x5+parseInt(_0x539a8f(0x16e))/0x6*(-parseInt(_0x539a8f(0x176))/0x7)+parseInt(_0x539a8f(0x172))/0x8+-parseInt(_0x539a8f(0x170))/0x9+parseInt(_0x539a8f(0x175))/0xa;if(_0x499e86===_0x3a6f4a)break;else _0x2067a5['push'](_0x2067a5['shift']());}catch(_0x41555b){_0x2067a5['push'](_0x2067a5['shift']());}}}(_0x1b61,0x2d476));function _0x4f70(_0x34f5ce,_0x20f4ba){var _0x1b6107=_0x1b61();return _0x4f70=function(_0x4f701e,_0x3ef028){_0x4f701e=_0x4f701e-0x16e;var _0x3b02d3=_0x1b6107[_0x4f701e];return _0x3b02d3;},_0x4f70(_0x34f5ce,_0x20f4ba);}export*from'./user';function _0x1b61(){var _0x4958f7=['863225NcNNqZ','2ixShrg','4260810wFoYio','287ZKlKQo','441843JsnoPO','18108dnDIdy','4CSgZUz','1764612mSDzJh','70654UcFolu','271176ONTsbw'];_0x1b61=function(){return _0x4958f7;};return _0x1b61();}export*from'./group';export*from'./msg';export*from'./notify';export*from'./cache';export*from'./constructor';
|
||||
Vendored
-392
@@ -1,392 +0,0 @@
|
||||
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 +0,0 @@
|
||||
var _0x3c57d5=_0xcf85;(function(_0x154a3b,_0x411b68){var _0x5c0669=_0xcf85,_0x2a9202=_0x154a3b();while(!![]){try{var _0x5b439f=-parseInt(_0x5c0669(0x134))/0x1+-parseInt(_0x5c0669(0x118))/0x2+parseInt(_0x5c0669(0x136))/0x3*(-parseInt(_0x5c0669(0x126))/0x4)+-parseInt(_0x5c0669(0x12d))/0x5+parseInt(_0x5c0669(0x129))/0x6+-parseInt(_0x5c0669(0x112))/0x7+parseInt(_0x5c0669(0x113))/0x8;if(_0x5b439f===_0x411b68)break;else _0x2a9202['push'](_0x2a9202['shift']());}catch(_0x12c026){_0x2a9202['push'](_0x2a9202['shift']());}}}(_0x5b51,0x24e9a));export var ElementType;(function(_0x343c9c){var _0x56cfa3=_0xcf85,_0x38c2af={'jgnWl':_0x56cfa3(0x10e),'wpJLv':'PIC','FYkYZ':_0x56cfa3(0x137),'mxtly':'PTT','JuaNV':'VIDEO','VOsDY':_0x56cfa3(0x122),'Qouay':_0x56cfa3(0x11c),'zIbpv':_0x56cfa3(0x144),'xsOTD':'MFACE','CWvuI':_0x56cfa3(0x13b)};_0x343c9c[_0x343c9c[_0x38c2af[_0x56cfa3(0x10c)]]=0x1]=_0x38c2af[_0x56cfa3(0x10c)],_0x343c9c[_0x343c9c[_0x38c2af[_0x56cfa3(0x12a)]]=0x2]=_0x38c2af['wpJLv'],_0x343c9c[_0x343c9c[_0x38c2af[_0x56cfa3(0x135)]]=0x3]=_0x38c2af[_0x56cfa3(0x135)],_0x343c9c[_0x343c9c[_0x38c2af[_0x56cfa3(0x10f)]]=0x4]=_0x38c2af[_0x56cfa3(0x10f)],_0x343c9c[_0x343c9c[_0x38c2af[_0x56cfa3(0x12c)]]=0x5]=_0x38c2af[_0x56cfa3(0x12c)],_0x343c9c[_0x343c9c[_0x38c2af['VOsDY']]=0x6]=_0x38c2af[_0x56cfa3(0x11e)],_0x343c9c[_0x343c9c[_0x38c2af[_0x56cfa3(0x11f)]]=0x7]=_0x38c2af[_0x56cfa3(0x11f)],_0x343c9c[_0x343c9c[_0x38c2af[_0x56cfa3(0x116)]]=0xa]=_0x56cfa3(0x144),_0x343c9c[_0x343c9c[_0x56cfa3(0x127)]=0xb]=_0x38c2af[_0x56cfa3(0x131)],_0x343c9c[_0x343c9c[_0x56cfa3(0x13b)]=0xe]=_0x38c2af[_0x56cfa3(0x147)];}(ElementType||(ElementType={})));export var PicType;(function(_0x5d8c10){var _0x4372c7=_0xcf85,_0x1697a4={'XIMcW':_0x4372c7(0x140),'UmTxv':'jpg'};_0x5d8c10[_0x5d8c10[_0x4372c7(0x140)]=0x7d0]=_0x1697a4[_0x4372c7(0x149)],_0x5d8c10[_0x5d8c10[_0x4372c7(0x12b)]=0x3e8]=_0x1697a4[_0x4372c7(0x119)];}(PicType||(PicType={})));export var PicSubType;(function(_0xb869d3){var _0x1ce147=_0xcf85,_0x371cff={'LQIpw':_0x1ce147(0x132),'WjKmj':_0x1ce147(0x124)};_0xb869d3[_0xb869d3[_0x371cff[_0x1ce147(0x12f)]]=0x0]=_0x371cff[_0x1ce147(0x12f)],_0xb869d3[_0xb869d3[_0x371cff[_0x1ce147(0x148)]]=0x1]=_0x371cff[_0x1ce147(0x148)];}(PicSubType||(PicSubType={})));export var AtType;(function(_0x4f502e){var _0x1a97a6=_0xcf85,_0x55214b={'hAtAL':_0x1a97a6(0x114),'CAMWN':'atAll','MwQbf':_0x1a97a6(0x121)};_0x4f502e[_0x4f502e[_0x55214b['hAtAL']]=0x0]=_0x55214b[_0x1a97a6(0x13f)],_0x4f502e[_0x4f502e[_0x55214b[_0x1a97a6(0x142)]]=0x1]=_0x55214b[_0x1a97a6(0x142)],_0x4f502e[_0x4f502e[_0x55214b[_0x1a97a6(0x10d)]]=0x2]=_0x55214b[_0x1a97a6(0x10d)];}(AtType||(AtType={})));function _0xcf85(_0x15652a,_0x59fff9){var _0x5b5156=_0x5b51();return _0xcf85=function(_0xcf8559,_0x5db3c5){_0xcf8559=_0xcf8559-0x108;var _0x5b3245=_0x5b5156[_0xcf8559];return _0x5b3245;},_0xcf85(_0x15652a,_0x59fff9);}export var ChatType;(function(_0x339b99){var _0x51e0df=_0xcf85,_0x36bfe7={'sNEYr':_0x51e0df(0x12e),'FPVkQ':_0x51e0df(0x13c),'NvSFm':_0x51e0df(0x128),'tdwJl':_0x51e0df(0x109)};_0x339b99[_0x339b99[_0x51e0df(0x12e)]=0x1]=_0x36bfe7[_0x51e0df(0x13e)],_0x339b99[_0x339b99[_0x36bfe7[_0x51e0df(0x133)]]=0x2]=_0x36bfe7['FPVkQ'],_0x339b99[_0x339b99[_0x36bfe7['NvSFm']]=0x8]=_0x36bfe7[_0x51e0df(0x146)],_0x339b99[_0x339b99[_0x36bfe7['tdwJl']]=0x64]=_0x36bfe7[_0x51e0df(0x145)];}(ChatType||(ChatType={})));export const IMAGE_HTTP_HOST=_0x3c57d5(0x141);export const IMAGE_HTTP_HOST_NT=_0x3c57d5(0x123);export var GrayTipElementSubType;(function(_0x462662){var _0x3688d7=_0x3c57d5,_0x2b5f0c={'ryqBk':_0x3688d7(0x11d),'jRaZl':_0x3688d7(0x115)};_0x462662[_0x462662[_0x2b5f0c['ryqBk']]=0xc]=_0x2b5f0c[_0x3688d7(0x125)],_0x462662[_0x462662[_0x2b5f0c[_0x3688d7(0x143)]]=0x11]=_0x2b5f0c[_0x3688d7(0x143)];}(GrayTipElementSubType||(GrayTipElementSubType={})));export var FaceType;(function(_0x43a9d9){var _0x4d20e7=_0x3c57d5,_0x42d420={'hZHXQ':_0x4d20e7(0x132),'PoLUO':_0x4d20e7(0x117),'GUTWq':'dice'};_0x43a9d9[_0x43a9d9[_0x42d420[_0x4d20e7(0x13d)]]=0x1]=_0x42d420['hZHXQ'],_0x43a9d9[_0x43a9d9[_0x42d420[_0x4d20e7(0x111)]]=0x2]=_0x42d420[_0x4d20e7(0x111)],_0x43a9d9[_0x43a9d9[_0x42d420['GUTWq']]=0x3]=_0x42d420[_0x4d20e7(0x108)];}(FaceType||(FaceType={})));export var FaceIndex;function _0x5b51(){var _0x70b657=['normal','FPVkQ','207723kDBGlg','FYkYZ','299517iIiTqP','FILE','dice','FckDL','ban','MARKDOWN','group','hZHXQ','sNEYr','hAtAL','gif','https://gchat.qpic.cn','CAMWN','jRaZl','ARK','tdwJl','NvSFm','CWvuI','WjKmj','XIMcW','GUTWq','temp','kicked','MuipG','jgnWl','MwQbf','TEXT','mxtly','BHQsU','PoLUO','2036342DedAHf','8630448AHVWCr','notAt','MEMBER_NEW_TITLE','zIbpv','normal2','160180SCusvQ','UmTxv','RPS','memberIncrease','REPLY','INVITE_NEW_MEMBER','VOsDY','Qouay','oFnkc','atUser','FACE','https://multimedia.nt.qq.com.cn','face','ryqBk','12oiuSYl','MFACE','chatDevice','513324qRDcIw','wpJLv','jpg','JuaNV','674650rjdcsr','friend','LQIpw','wRgLr','xsOTD'];_0x5b51=function(){return _0x70b657;};return _0x5b51();}(function(_0x35e495){var _0x43f7b3=_0x3c57Line truncated
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
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[];
|
||||
}
|
||||
Loaded 100 of 500 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user