mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
325 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 | ||
![]() |
68af73970e | ||
![]() |
b6ed8d4975 | ||
![]() |
d07d3645ce | ||
![]() |
123759ab17 | ||
![]() |
f2f1f893d8 | ||
![]() |
db93a8eed2 | ||
![]() |
12ab6d4a7d | ||
![]() |
add759e889 | ||
![]() |
f315f7977d | ||
![]() |
f2f6701ebd | ||
![]() |
1a92794d33 | ||
![]() |
7640deb798 | ||
![]() |
f1e8ef1cf6 | ||
![]() |
5e5ac0162e | ||
![]() |
0c013820f0 | ||
![]() |
4b3a9e5847 | ||
![]() |
e4982256a4 | ||
![]() |
babc4927a8 | ||
![]() |
6dd84cf469 | ||
![]() |
a8800e3899 | ||
![]() |
5f03496046 | ||
![]() |
41500c17a2 | ||
![]() |
2dcfde8b9a | ||
![]() |
5c3305d8fa | ||
![]() |
0d1fe99f53 | ||
![]() |
4c03ffeec7 | ||
![]() |
8101d17482 | ||
![]() |
bc7b4dcc2a | ||
![]() |
3db8b9078d | ||
![]() |
943dbbefd3 | ||
![]() |
480abcb853 | ||
![]() |
60aaaff58e | ||
![]() |
e3b889bbe8 | ||
![]() |
ac5506a43b | ||
![]() |
b29f533a3b | ||
![]() |
a8ee86b09e | ||
![]() |
0238c53302 | ||
![]() |
665e3c806f | ||
![]() |
8c96838441 | ||
![]() |
4a722daec6 | ||
![]() |
4e0cdbcb91 | ||
![]() |
08976624cd | ||
![]() |
fdeba94653 | ||
![]() |
d3b100b7e5 | ||
![]() |
1de3e18b08 | ||
![]() |
d5c3c95682 | ||
![]() |
dabe1e29ed |
@@ -1,21 +1,21 @@
|
|||||||
# EditorConfig is awesome: https://EditorConfig.org
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
# top-most EditorConfig file
|
# top-most EditorConfig file
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
# Unix-style newlines with a newline ending every file
|
# Unix-style newlines with a newline ending every file
|
||||||
[*]
|
[*]
|
||||||
end_of_line = lf|crlf
|
end_of_line = lf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
# Matches multiple files with brace expansion notation
|
# Matches multiple files with brace expansion notation
|
||||||
# Set default charset
|
# Set default charset
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
|
|
||||||
# 2 space indentation
|
# 2 space indentation
|
||||||
[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}]
|
[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
# Unfortunately, EditorConfig doesn't support space configuration inside import braces directly.
|
# 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,9 +1,10 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
'env': {
|
'env': {
|
||||||
|
'browser': true,
|
||||||
'es2021': true,
|
'es2021': true,
|
||||||
'node': true
|
'node': true
|
||||||
},
|
},
|
||||||
'ignorePatterns': ['src/core/', 'src/core.lib/'],
|
'ignorePatterns': ['src/core/', 'src/core.lib/','src/proto/'],
|
||||||
'extends': [
|
'extends': [
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:@typescript-eslint/recommended'
|
'plugin:@typescript-eslint/recommended'
|
||||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: "Build"
|
name: "Build Action"
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
target_platform: [win32]
|
target_platform: [win32]
|
||||||
target_arch: [x64]
|
target_arch: [x64,ia32]
|
||||||
steps:
|
steps:
|
||||||
- name: Clone Main Repository
|
- name: Clone Main Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: "release"
|
name: "Build Release"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
target_platform: [win32]
|
target_platform: [win32]
|
||||||
target_arch: [x64]
|
target_arch: [x64,ia32]
|
||||||
steps:
|
steps:
|
||||||
- name: Clone Main Repository
|
- name: Clone Main Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -130,6 +130,7 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
body_path: CHANGELOG.md
|
body_path: CHANGELOG.md
|
||||||
files: |
|
files: |
|
||||||
|
NapCat.win32.ia32.zip
|
||||||
NapCat.win32.x64.zip
|
NapCat.win32.x64.zip
|
||||||
NapCat.linux.x64.zip
|
NapCat.linux.x64.zip
|
||||||
NapCat.linux.arm64.zip
|
NapCat.linux.arm64.zip
|
||||||
|
69
.github/workflows/test.yml
vendored
Normal file
69
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
name: "Build Test"
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions: write-all
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target_platform: [linux]
|
||||||
|
target_arch: [x64, arm64]
|
||||||
|
steps:
|
||||||
|
- name: Clone Main Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: 'NapNeko/NapCatQQ'
|
||||||
|
submodules: true
|
||||||
|
ref: main
|
||||||
|
token: ${{ secrets.NAPCAT_BUILD }}
|
||||||
|
- name: Use Node.js 20.X
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20.x
|
||||||
|
- name: Build NuCat Linux
|
||||||
|
run: |
|
||||||
|
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||||
|
npm run build:prod
|
||||||
|
cd dist
|
||||||
|
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||||
|
cd ..
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||||
|
path: dist
|
||||||
|
build-win32:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target_platform: [win32]
|
||||||
|
target_arch: [x64,ia32]
|
||||||
|
steps:
|
||||||
|
- name: Clone Main Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: 'NapNeko/NapCatQQ'
|
||||||
|
submodules: true
|
||||||
|
ref: main
|
||||||
|
token: ${{ secrets.NAPCAT_BUILD }}
|
||||||
|
- name: Use Node.js 20.X
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20.x
|
||||||
|
- name: Build NuCat Linux
|
||||||
|
run: |
|
||||||
|
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||||
|
npm run build:prod
|
||||||
|
cd dist
|
||||||
|
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||||
|
cd ..
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||||
|
path: dist
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ dist/
|
|||||||
# Build
|
# Build
|
||||||
*.db
|
*.db
|
||||||
checkVersion.sh
|
checkVersion.sh
|
||||||
|
bun.lockb
|
||||||
|
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,4 +0,0 @@
|
|||||||
[submodule "src/core"]
|
|
||||||
path = src/core
|
|
||||||
url = https://github.com/NapNeko/core.git
|
|
||||||
branch = master
|
|
25
docs/changelogs/CHANGELOG.v1.6.7.md
Normal file
25
docs/changelogs/CHANGELOG.v1.6.7.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# v1.6.7
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
||||||
|
## 使用前警告
|
||||||
|
1. 在最近版本由于QQ本体大幅变动,为了保证NapCat可用性,NapCat近期启动与安装方式将将大幅变动,请关注文档和社群获取。
|
||||||
|
2. 在Core上完全执行开源,请不要用于违法用途,如此可能造成NapCat完全停止更新。
|
||||||
|
3. 针对原启动方式的围堵,NapCat研发了多种方式,除此其余理论与扩展的分析和思路将部分展示于Docs,以便各位参与开发与维护NapCat。
|
||||||
|
## 其余·备注
|
||||||
|
启动方式: WayBoot.03 (Electron Main进程为Node 直接注入代码 同理项目: LiteLoader)
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
1. 尝试 修复 卡顿问题
|
||||||
|
2. 尝试 修复 精华消息被设置/一起听 接收时的报错
|
||||||
|
3. 优化 Uin与Uid 转换速度
|
||||||
|
4. 修复CQCode可能存在的解码问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
1. 戳一戳上报raw
|
||||||
|
2. 精华消息设置通知事件
|
||||||
|
3. 新增设置/删除群精华API
|
||||||
|
4. 新增最近联系列表API(RAW 不稳定)
|
||||||
|
5. 新增设置所有消息已读API(非标准)
|
||||||
|
6. 新增获取点赞信息获取API(非标准)
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
15
docs/changelogs/old/CHANGELOG.v1.3.8.md
Normal file
15
docs/changelogs/old/CHANGELOG.v1.3.8.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# v1.3.8
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.9-23873 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 优化打包后体积问题
|
||||||
|
* 修复QQ等级获取
|
||||||
|
* 兼容 9.7.x 版本换行符 统一为 \n
|
||||||
|
* 修复处理加群请求 字段异常情况
|
||||||
|
* 修复退群通知问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.3.9.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.3.9.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 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)
|
12
docs/changelogs/old/CHANGELOG.v1.4.0.md
Normal file
12
docs/changelogs/old/CHANGELOG.v1.4.0.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# 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)
|
14
docs/changelogs/old/CHANGELOG.v1.4.1.md
Normal file
14
docs/changelogs/old/CHANGELOG.v1.4.1.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# v1.4.1
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 提高部分Api兼容性
|
||||||
|
* 优化日志膨胀问题
|
||||||
|
* 在线状态刷新问题修复
|
||||||
|
## 新增与调整
|
||||||
|
* 支持非管理群 本地记录时间数据 (建议 **备份配置 清空配置 重新配置**)
|
||||||
|
* 新增英译中接口 Api: /translate_en2zh
|
||||||
|
* 新增群文件管理相关扩展接口 Api: /get_group_file_count /get_group_file_list /set_group_file_folder /del_group_file /del_group_file_folder
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.4.2.md
Normal file
12
docs/changelogs/old/CHANGELOG.v1.4.2.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# v1.4.2
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复获取群文件列表Api
|
||||||
|
* 修复退群通知问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.4.3.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.4.3.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.4.3
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复名片通知
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
10
docs/changelogs/old/CHANGELOG.v1.4.4.md
Normal file
10
docs/changelogs/old/CHANGELOG.v1.4.4.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# v1.4.4
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 更新
|
||||||
|
* **重大更新:**更新了版本号
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||||
|
|
12
docs/changelogs/old/CHANGELOG.v1.4.5.md
Normal file
12
docs/changelogs/old/CHANGELOG.v1.4.5.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# v1.4.5
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 紧急修复二维扫码问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||||
|
|
12
docs/changelogs/old/CHANGELOG.v1.4.6.md
Normal file
12
docs/changelogs/old/CHANGELOG.v1.4.6.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# v1.4.6
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 优化整体稳定性
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||||
|
|
11
docs/changelogs/old/CHANGELOG.v1.4.7.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.4.7.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.4.7
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 临时扩展 Api: GoCQHTTPUploadGroupFile folder_id字段 用于选择文件夹
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.4.8.md
Normal file
12
docs/changelogs/old/CHANGELOG.v1.4.8.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# v1.4.8
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 优化Guid的生成方式
|
||||||
|
* 支持临时消息获取群来源
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.4.9.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.4.9.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.4.9
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复接口调用问题 接口标准化 API:set_group_add_request
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.0.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.5.0.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.5.0
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修正各Api默认值
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.5.1.md
Normal file
12
docs/changelogs/old/CHANGELOG.v1.5.1.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# v1.5.1
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 支持 新Api: set_self_profile 可设置个性签名
|
||||||
|
* 修复 Api: get_group_system_msg
|
||||||
|
* 整理日志、添加颜色、使用统一的日志函数以提高日志可读性
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
13
docs/changelogs/old/CHANGELOG.v1.5.2.md
Normal file
13
docs/changelogs/old/CHANGELOG.v1.5.2.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# v1.5.2
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 替换Uid/Uin为内部实现
|
||||||
|
* 增加HttpApi调用稳定性
|
||||||
|
* 修复 GetMsg 兼容性
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
* 支持真正意义上的陌生人信息获取 Api: GoCQHTTP_GetStrangerInfo
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
15
docs/changelogs/old/CHANGELOG.v1.5.3.md
Normal file
15
docs/changelogs/old/CHANGELOG.v1.5.3.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# v1.5.3
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-23568
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复引用消息id问题
|
||||||
|
* 修复添加好友的通知
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
* 扩展群分享Json生成
|
||||||
|
* 扩展关于收藏的一系列接口
|
||||||
|
* 支持专属群头衔获取
|
||||||
|
* 支持视频获取直链
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.4.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.5.4.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.5.4
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-23568
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 紧急修复视频与文件问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.5.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.5.5.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.5.5
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-23568
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 紧急修复一些问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.6.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.5.6.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.5.6
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-24568
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复一些问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.7.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.5.7.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.5.7
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-24568
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复一些问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
14
docs/changelogs/old/CHANGELOG.v1.5.8.md
Normal file
14
docs/changelogs/old/CHANGELOG.v1.5.8.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# v1.5.8
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-24568
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复视频文件残留问题
|
||||||
|
* 重构 getcookies接口 支持大部分常见域
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
* 日志大小限制
|
||||||
|
* 支持 QQ音乐 卡片 无签名支持时 启用内置方法(缺点没有封面 限速1min/条)
|
||||||
|
* 支持Window X86-32机器
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.5.9.md
Normal file
12
docs/changelogs/old/CHANGELOG.v1.5.9.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# v1.5.9
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 优化缓存问题
|
||||||
|
* 修复poke异常上报
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.6.0.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.6.0.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.6.0
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
* 新增图片subtype属性 区分表情图片与商城图片
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.6.1.md
Normal file
11
docs/changelogs/old/CHANGELOG.v1.6.1.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# v1.6.1
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
* 修复poke异常事件
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
13
docs/changelogs/old/CHANGELOG.v1.6.2.md
Normal file
13
docs/changelogs/old/CHANGELOG.v1.6.2.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# v1.6.2
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复获取Cookies异常崩溃问题
|
||||||
|
* 尝试修复成员退群缓存问题
|
||||||
|
* 修复自身退群后群缓存清理问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
13
docs/changelogs/old/CHANGELOG.v1.6.3.md
Normal file
13
docs/changelogs/old/CHANGELOG.v1.6.3.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# v1.6.3
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
* 修复带有groupid的私聊消息异常发送到群聊消息
|
||||||
|
* 尝试修复rws热重载失效问题
|
||||||
|
* 尝试修复进群事件无法正常获取uin
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
18
docs/changelogs/old/CHANGELOG.v1.6.4.md
Normal file
18
docs/changelogs/old/CHANGELOG.v1.6.4.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# v1.6.4
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
||||||
|
## 使用前警告
|
||||||
|
1. 在最近版本由于QQ本体大幅变动,为了保证NapCat可用性,NapCat近期启动与安装方式将将大幅变动,请关注文档和社群获取。
|
||||||
|
2. 在Core上完全执行开源,请不要用于违法用途,如此可能造成NapCat完全停止更新。
|
||||||
|
3. 针对原启动方式的围堵,NapCat研发了多种方式,除此其余理论与扩展的分析和思路将部分展示于Docs,以便各位参与开发与维护NapCat。
|
||||||
|
## 其余·备注
|
||||||
|
启动方式: WayBoot.03 (Electron Main进程为Node 直接注入代码 同理项目: LiteLoader)
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
1. 支持Win平台 9.9.12
|
||||||
|
2. 修复部分发送图片下载异常情况
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
没有哦
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
18
docs/changelogs/old/CHANGELOG.v1.6.5.md
Normal file
18
docs/changelogs/old/CHANGELOG.v1.6.5.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# v1.6.5
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
||||||
|
## 使用前警告
|
||||||
|
1. 在最近版本由于QQ本体大幅变动,为了保证NapCat可用性,NapCat近期启动与安装方式将将大幅变动,请关注文档和社群获取。
|
||||||
|
2. 在Core上完全执行开源,请不要用于违法用途,如此可能造成NapCat完全停止更新。
|
||||||
|
3. 针对原启动方式的围堵,NapCat研发了多种方式,除此其余理论与扩展的分析和思路将部分展示于Docs,以便各位参与开发与维护NapCat。
|
||||||
|
## 其余·备注
|
||||||
|
启动方式: WayBoot.03 (Electron Main进程为Node 直接注入代码 同理项目: LiteLoader)
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
1. 优化了WrapperNative载入代码
|
||||||
|
2. 优化缓存
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
没有哦
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
17
docs/changelogs/old/CHANGELOG.v1.6.6.md
Normal file
17
docs/changelogs/old/CHANGELOG.v1.6.6.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# v1.6.6
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
||||||
|
## 使用前警告
|
||||||
|
1. 在最近版本由于QQ本体大幅变动,为了保证NapCat可用性,NapCat近期启动与安装方式将将大幅变动,请关注文档和社群获取。
|
||||||
|
2. 在Core上完全执行开源,请不要用于违法用途,如此可能造成NapCat完全停止更新。
|
||||||
|
3. 针对原启动方式的围堵,NapCat研发了多种方式,除此其余理论与扩展的分析和思路将部分展示于Docs,以便各位参与开发与维护NapCat。
|
||||||
|
## 其余·备注
|
||||||
|
启动方式: WayBoot.03 (Electron Main进程为Node 直接注入代码 同理项目: LiteLoader)
|
||||||
|
|
||||||
|
## 修复与优化
|
||||||
|
1. 修复了一些问题
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
没有哦
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
48
docs/develop/Image.NTAndroid.md
Normal file
48
docs/develop/Image.NTAndroid.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
public static final int C2C_PIC_DOWNLOAD = 1004;
|
||||||
|
public static final String C2C_PIC_DOWNLOAD_DOMAIN = "c2cpicdw.qpic.cn";
|
||||||
|
public static final String C2C_PIC_DOWNLOAD_QUIC_DOMAIN = "c2cpicdw.quic.qpic.cn";
|
||||||
|
public static final int FLAG_NOT_UPLOAD = 3;
|
||||||
|
public static final int FLAG_UPLOADINFO_ERROR = 4;
|
||||||
|
public static final int GROUP_PIC_DOWNLOAD = 1000;
|
||||||
|
public static final String GROUP_PIC_DOWNLOAD_DOMAIN = "gchat.qpic.cn";
|
||||||
|
public static final String GROUP_PIC_DOWNLOAD_QUIC_DOMAIN = "gchat.quic.qpic.cn";
|
||||||
|
public static final String GUILD_PIC_DOWNLOAD_DOMAIN = "gchat.qpic.cn/qmeetpic";
|
||||||
|
public static final boolean NEW_STORE_FLAG = true;
|
||||||
|
public static final String PTT_VIDEO_DOWNLOAD_DOMAIN = "grouptalk.c2c.qq.com";
|
||||||
|
|
||||||
|
protected static final int AVIF_DECODE_EXCEPTION = 4;
|
||||||
|
protected static final int AVIF_DECODE_FAIL = 1;
|
||||||
|
protected static final int AVIF_DECODE_FAIL_SO_FAIL = 2;
|
||||||
|
protected static final int AVIF_DECODE_FAIL_UNKNOWN = 6;
|
||||||
|
protected static final int AVIF_DECODE_FILETYPE_ERROR = 5;
|
||||||
|
protected static final int AVIF_DECODE_OOM = 3;
|
||||||
|
protected static final int AVIF_DECODE_RENAME_FAIL = 7;
|
||||||
|
protected static final int AVIF_DECODE_SUC = 0;
|
||||||
|
public static final String AVIF_FILE_SUFFIX = ".avif";
|
||||||
|
public static final int AVIF_REQ_APPRUNTIME_NULL = 12;
|
||||||
|
public static final int AVIF_REQ_CODEC_UNSURPPORT = 5;
|
||||||
|
protected static final int AVIF_REQ_DENSITY_UNSURPPORT = 10;
|
||||||
|
protected static final int AVIF_REQ_FLASH_PHOTO = 9;
|
||||||
|
protected static final int AVIF_REQ_HAS_TMP_AVIF = 7;
|
||||||
|
protected static final int AVIF_REQ_INVALID_MSG_RECORD = 2;
|
||||||
|
protected static final int AVIF_REQ_IS_RAW_PHOTO = 3;
|
||||||
|
protected static final int AVIF_REQ_OUTPUTSTREAM_UNSURPPORT = 11;
|
||||||
|
protected static final int AVIF_REQ_OVERSIZE = 6;
|
||||||
|
protected static final int AVIF_REQ_RETRY = 1;
|
||||||
|
public static final int AVIF_REQ_SO_DOWNLOAD_FAILED = 8;
|
||||||
|
protected static final int AVIF_REQ_SUC = 0;
|
||||||
|
public static final int AVIF_REQ_SWITCH_CLOSE = 4;
|
||||||
|
public static final String C2C_PIC_DOWNLOAD_ERROR_CODE = "C2CPicDownloadErrorCode";
|
||||||
|
static final int DOWNLOAD_ST_COMPLETE = 1;
|
||||||
|
static final int DOWNLOAD_ST_HEAD = 2;
|
||||||
|
static final int DOWNLOAD_ST_LEFT = 4;
|
||||||
|
static final int DOWNLOAD_ST_PART = 3;
|
||||||
|
private static final int ENCRYPT_APPID = 1600000226;
|
||||||
|
public static final String GROUP_PIC_DOWNLOAD_ERROR_CODE = "GroupPicDownloadErrorCode";
|
||||||
|
public static final String KEY_PIC_DOWNLOAD_ERROR_CODE = "param_detail_code";
|
||||||
|
protected static final int QUIC_FAIL_IP_LIST_EMPTY = 1;
|
||||||
|
protected static final int QUIC_FAIL_REQUEST_HTTPS = 3;
|
||||||
|
protected static final int QUIC_FAIL_REQUEST_QUIC = 2;
|
||||||
|
protected static final int QUIC_FAIL_SO_LOAD = 4;
|
||||||
|
public static final String REPORT_TAG_DIRECT_DOWNLOAD_FAIL = "report_direct_download_fail";
|
||||||
|
public static final String REQ_PARAM_AVIF = "tp=avif";
|
444
docs/develop/Msg常量NTAndroid.md
Normal file
444
docs/develop/Msg常量NTAndroid.md
Normal file
@@ -0,0 +1,444 @@
|
|||||||
|
```java
|
||||||
|
MsgConstant
|
||||||
|
int ARKSTRUCTELEMENTSUBTYPETENCENTDOCFROMMINIAPP = 1;
|
||||||
|
int ARKSTRUCTELEMENTSUBTYPETENCENTDOCFROMPLUSPANEL = 2;
|
||||||
|
int ARKSTRUCTELEMENTSUBTYPEUNKNOWN = 0;
|
||||||
|
int ATTYPEALL = 1;
|
||||||
|
int ATTYPECATEGORY = 512;
|
||||||
|
int ATTYPECHANNEL = 16;
|
||||||
|
int ATTYPEME = 4;
|
||||||
|
int ATTYPEONE = 2;
|
||||||
|
int ATTYPEONLINE = 64;
|
||||||
|
int ATTYPEROLE = 8;
|
||||||
|
int ATTYPESUMMON = 32;
|
||||||
|
int ATTYPESUMMONONLINE = 128;
|
||||||
|
int ATTYPESUMMONROLE = 256;
|
||||||
|
int ATTYPEUNKNOWN = 0;
|
||||||
|
int CALENDARELEMSUBTYPECOMMON = 3;
|
||||||
|
int CALENDARELEMSUBTYPESTRONG = 1;
|
||||||
|
int CALENDARELEMSUBTYPEUNKNOWN = 0;
|
||||||
|
int CALENDARELEMSUBTYPEWEAK = 2;
|
||||||
|
int FACEBUBBLEELEMSUBTYPENORMAL = 1;
|
||||||
|
int FACEBUBBLEELEMSUBTYPEUNKNOWN = 0;
|
||||||
|
int FETCHLONGMSGERRCODEMSGEXPIRED = 196;
|
||||||
|
int FILEELEMENTSUBTYPEAI = 16;
|
||||||
|
int FILEELEMENTSUBTYPEAPP = 11;
|
||||||
|
int FILEELEMENTSUBTYPEAUDIO = 3;
|
||||||
|
int FILEELEMENTSUBTYPEDOC = 4;
|
||||||
|
int FILEELEMENTSUBTYPEEMOTICON = 15;
|
||||||
|
int FILEELEMENTSUBTYPEEXCEL = 6;
|
||||||
|
int FILEELEMENTSUBTYPEFOLDER = 13;
|
||||||
|
int FILEELEMENTSUBTYPEHTML = 10;
|
||||||
|
int FILEELEMENTSUBTYPEIPA = 14;
|
||||||
|
int FILEELEMENTSUBTYPENORMAL = 0;
|
||||||
|
int FILEELEMENTSUBTYPEPDF = 7;
|
||||||
|
int FILEELEMENTSUBTYPEPIC = 1;
|
||||||
|
int FILEELEMENTSUBTYPEPPT = 5;
|
||||||
|
int FILEELEMENTSUBTYPEPSD = 12;
|
||||||
|
int FILEELEMENTSUBTYPETXT = 8;
|
||||||
|
int FILEELEMENTSUBTYPEVIDEO = 2;
|
||||||
|
int FILEELEMENTSUBTYPEZIP = 9;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEAIOOP = 15;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEBLOCK = 14;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEBUDDY = 5;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEBUDDYNOTIFY = 9;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEEMOJIREPLY = 3;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEESSENCE = 7;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEFEED = 6;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEFEEDCHANNELMSG = 11;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEFILE = 10;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEGROUP = 4;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEGROUPNOTIFY = 8;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEJSON = 17;
|
||||||
|
int GRAYTIPELEMENTSUBTYPELOCALMSG = 13;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEPROCLAMATION = 2;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEREVOKE = 1;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEUNKNOWN = 0;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEWALLET = 16;
|
||||||
|
int GRAYTIPELEMENTSUBTYPEXMLMSG = 12;
|
||||||
|
int INLINEKEYBOARDBUTTONRENDERSTYLEBLUEBLACKGROUND = 4;
|
||||||
|
int INLINEKEYBOARDBUTTONRENDERSTYLEBLUEBORDER = 1;
|
||||||
|
int INLINEKEYBOARDBUTTONRENDERSTYLEGRAYBORDER = 0;
|
||||||
|
int INLINEKEYBOARDBUTTONRENDERSTYLENOBORDER = 2;
|
||||||
|
int INLINEKEYBOARDBUTTONRENDERSTYLEREDCHARACTER = 3;
|
||||||
|
int INPUTSTATUSTYPECANCEL = 2;
|
||||||
|
int INPUTSTATUSTYPESPEAK = 3;
|
||||||
|
int INPUTSTATUSTYPETEXT = 1;
|
||||||
|
int KACTIVITYMSG = 22;
|
||||||
|
int KADDLOCALMSGEXTINFOTYPEPROLOGUEMSG = 1;
|
||||||
|
int KANONYMOUSATMEMSGTYPEINMSGBOX = 1001;
|
||||||
|
int KANONYMOUSFLAGFROMOTHERPEOPLE = 1;
|
||||||
|
int KANONYMOUSFLAGFROMOWN = 2;
|
||||||
|
int KANONYMOUSFLAGINVALID = 0;
|
||||||
|
int KAPPCHANNELMSG = 16;
|
||||||
|
int KATALLMSGTYPEINMSGBOX = 2000;
|
||||||
|
int KATMEMSGTYPEINMSGBOX = 1000;
|
||||||
|
int KATTRIBUTETYPEADELIEMSG = 16;
|
||||||
|
int KATTRIBUTETYPEEXTENDBUSINESS = 13;
|
||||||
|
int KATTRIBUTETYPEFEEDBACKSTATE = 17;
|
||||||
|
int KATTRIBUTETYPEGROUPHONOR = 2;
|
||||||
|
int KATTRIBUTETYPEKINGHONOR = 3;
|
||||||
|
int KATTRIBUTETYPELONGMSG = 8;
|
||||||
|
int KATTRIBUTETYPEMEMORYSTATEMSGINFO = 18;
|
||||||
|
int KATTRIBUTETYPEMSG = 0;
|
||||||
|
int KATTRIBUTETYPEMSGBOXEVENTTYPE = 14;
|
||||||
|
int KATTRIBUTETYPEPERSONAL = 1;
|
||||||
|
int KATTRIBUTETYPEPUBLICACCOUNT = 4;
|
||||||
|
int KATTRIBUTETYPEQQCONNECT = 12;
|
||||||
|
int KATTRIBUTETYPESENDMSGRSPTRANSSVRINFO = 15;
|
||||||
|
int KATTRIBUTETYPESHAREDMSGINFO = 5;
|
||||||
|
int KATTRIBUTETYPETEMPCHATGAMESESSION = 6;
|
||||||
|
int KATTRIBUTETYPETOROBOTMSG = 9;
|
||||||
|
int KATTRIBUTETYPEUININFO = 7;
|
||||||
|
int KATTRIBUTETYPEZPLAN = 11;
|
||||||
|
int KAUTOREPLYTEXTNONEINDEX = -1;
|
||||||
|
int KAVRECORDMSG = 19;
|
||||||
|
int KBUSINESSTYPGUILD = 1;
|
||||||
|
int KBUSINESSTYPNT = 0;
|
||||||
|
int KCHATTYPEADELIE = 42;
|
||||||
|
int KCHATTYPEBUDDYNOTIFY = 5;
|
||||||
|
int KCHATTYPEC2C = 1;
|
||||||
|
int KCHATTYPECIRCLE = 113;
|
||||||
|
int KCHATTYPEDATALINE = 8;
|
||||||
|
int KCHATTYPEDATALINEMQQ = 134;
|
||||||
|
int KCHATTYPEDISC = 3;
|
||||||
|
int KCHATTYPEFAV = 41;
|
||||||
|
int KCHATTYPEGAMEMESSAGE = 105;
|
||||||
|
int KCHATTYPEGAMEMESSAGEFOLDER = 116;
|
||||||
|
int KCHATTYPEGROUP = 2;
|
||||||
|
int KCHATTYPEGROUPBLESS = 133;
|
||||||
|
int KCHATTYPEGROUPGUILD = 9;
|
||||||
|
int KCHATTYPEGROUPHELPER = 7;
|
||||||
|
int KCHATTYPEGROUPNOTIFY = 6;
|
||||||
|
int KCHATTYPEGUILD = 4;
|
||||||
|
int KCHATTYPEGUILDMETA = 16;
|
||||||
|
int KCHATTYPEMATCHFRIEND = 104;
|
||||||
|
int KCHATTYPEMATCHFRIENDFOLDER = 109;
|
||||||
|
int KCHATTYPENEARBY = 106;
|
||||||
|
int KCHATTYPENEARBYASSISTANT = 107;
|
||||||
|
int KCHATTYPENEARBYFOLDER = 110;
|
||||||
|
int KCHATTYPENEARBYHELLOFOLDER = 112;
|
||||||
|
int KCHATTYPENEARBYINTERACT = 108;
|
||||||
|
int KCHATTYPEQQNOTIFY = 132;
|
||||||
|
int KCHATTYPERELATEACCOUNT = 131;
|
||||||
|
int KCHATTYPESERVICEASSISTANT = 118;
|
||||||
|
int KCHATTYPESERVICEASSISTANTSUB = 201;
|
||||||
|
int KCHATTYPESQUAREPUBLIC = 115;
|
||||||
|
int KCHATTYPESUBSCRIBEFOLDER = 30;
|
||||||
|
int KCHATTYPETEMPADDRESSBOOK = 111;
|
||||||
|
int KCHATTYPETEMPBUSSINESSCRM = 102;
|
||||||
|
int KCHATTYPETEMPC2CFROMGROUP = 100;
|
||||||
|
int KCHATTYPETEMPC2CFROMUNKNOWN = 99;
|
||||||
|
int KCHATTYPETEMPFRIENDVERIFY = 101;
|
||||||
|
int KCHATTYPETEMPNEARBYPRO = 119;
|
||||||
|
int KCHATTYPETEMPPUBLICACCOUNT = 103;
|
||||||
|
int KCHATTYPETEMPWPA = 117;
|
||||||
|
int KCHATTYPEUNKNOWN = 0;
|
||||||
|
int KCHATTYPEWEIYUN = 40;
|
||||||
|
int KCOMMONREDENVELOPEMSGTYPEINMSGBOX = 1007;
|
||||||
|
int KDOWNSOURCETYPEAIOINNER = 1;
|
||||||
|
int KDOWNSOURCETYPEBIGSCREEN = 2;
|
||||||
|
int KDOWNSOURCETYPEHISTORY = 3;
|
||||||
|
int KDOWNSOURCETYPEUNKNOWN = 0;
|
||||||
|
int KELEMTYPEACTIVITY = 25;
|
||||||
|
int KELEMTYPEACTIVITYSTATE = 41;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPECREATEMOBATEAM = 12;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEDISBANDMOBATEAM = 11;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEFEEDSQUARE = 10001;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEFINISHGAME = 16;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEFINISHMATCHTEAM = 14;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEHOTCHAT = 10000;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEMINIGAME = 18;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEMUSICPLAY = 17;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPENEWSMOBA = 9;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPENOLIVE = 2;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPENOSCREENSHARE = 7;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPENOVOICE = 3;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEONLIVE = 1;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEONSCREENSHARE = 6;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEONVOICE = 4;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPESTARTMATCHTEAM = 13;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPETARTGAME = 15;
|
||||||
|
int KELEMTYPEACTIVITYSUBTYPEUNKNOWN = 0;
|
||||||
|
int KELEMTYPEADELIEACTIONBAR = 44;
|
||||||
|
int KELEMTYPEADELIERECOMMENDEDMSG = 43;
|
||||||
|
int KELEMTYPEARKSTRUCT = 10;
|
||||||
|
int KELEMTYPEAVRECORD = 21;
|
||||||
|
int KELEMTYPECALENDAR = 19;
|
||||||
|
int KELEMTYPEFACE = 6;
|
||||||
|
int KELEMTYPEFACEBUBBLE = 27;
|
||||||
|
int KELEMTYPEFEED = 22;
|
||||||
|
int KELEMTYPEFILE = 3;
|
||||||
|
int KELEMTYPEGIPHY = 15;
|
||||||
|
int KELEMTYPEGRAYTIP = 8;
|
||||||
|
int KELEMTYPEINLINEKEYBOARD = 17;
|
||||||
|
int KELEMTYPEINTEXTGIFT = 18;
|
||||||
|
int KELEMTYPELIVEGIFT = 12;
|
||||||
|
int KELEMTYPEMARKDOWN = 14;
|
||||||
|
int KELEMTYPEMARKETFACE = 11;
|
||||||
|
int KELEMTYPEMULTIFORWARD = 16;
|
||||||
|
int KELEMTYPEONLINEFILE = 23;
|
||||||
|
int KELEMTYPEPIC = 2;
|
||||||
|
int KELEMTYPEPROLOGUE = 46;
|
||||||
|
int KELEMTYPEPTT = 4;
|
||||||
|
int KELEMTYPEREPLY = 7;
|
||||||
|
int KELEMTYPESHARELOCATION = 28;
|
||||||
|
int KELEMTYPESTRUCTLONGMSG = 13;
|
||||||
|
int KELEMTYPETASKTOPMSG = 29;
|
||||||
|
int KELEMTYPETEXT = 1;
|
||||||
|
int KELEMTYPETOFU = 26;
|
||||||
|
int KELEMTYPEUNKNOWN = 0;
|
||||||
|
int KELEMTYPEVIDEO = 5;
|
||||||
|
int KELEMTYPEWALLET = 9;
|
||||||
|
int KELEMTYPEYOLOGAMERESULT = 20;
|
||||||
|
int KENTERAIO = 1;
|
||||||
|
int KEXITAIO = 2;
|
||||||
|
int KFEEDBACKBUTTONTYPEDISLIKE = 2;
|
||||||
|
int KFEEDBACKBUTTONTYPELIKE = 1;
|
||||||
|
int KFEEDBACKBUTTONTYPEPROMPTCLICK = 5;
|
||||||
|
int KFEEDBACKBUTTONTYPEREGENERATE = 4;
|
||||||
|
int KFEEDBACKBUTTONTYPEUNKNOWN = 0;
|
||||||
|
int KFEEDBACKOPTLIKE = 1;
|
||||||
|
int KFEEDBACKOPTUNKNOWN = 0;
|
||||||
|
int KFEEDBACKOPTUNLIKE = 2;
|
||||||
|
int KFRIENDNEWADDEDMSGTYPEINMSGBOX = 1008;
|
||||||
|
int KGAMEBOXNEWMSGTYPEINMSGBOX = 3000;
|
||||||
|
int KGIFTATMEMSGTYPEINMSGBOX = 1005;
|
||||||
|
int KGROUPFILEATALLMSGTYPEINMSGBOX = 2001;
|
||||||
|
int KGROUPHOMEWORK = 20000;
|
||||||
|
int KGROUPHOMEWORKTASK = 20001;
|
||||||
|
int KGROUPKEYWORDMSGTYPEINMSGBOX = 2006;
|
||||||
|
int KGROUPMANNOUNCEATALLMSGTYPEINMSGBOX = 2004;
|
||||||
|
int KGROUPTASKATALLMSGTYPEINMSGBOX = 2003;
|
||||||
|
int KGROUPUNREADTYPEINMSGBOX = 2007;
|
||||||
|
int KGUILDCHANNELLIST = 10;
|
||||||
|
int KHIGHLIGHTWORDINTEMPCHATTYPEINMSGBOX = 1009;
|
||||||
|
int KHOMEWORKREMINDER = 10000;
|
||||||
|
int KLIKEORDISLIKESTATEDISLIKE = 2;
|
||||||
|
int KLIKEORDISLIKESTATELIKE = 1;
|
||||||
|
int KLIKEORDISLIKESTATENONESELECTED = 0;
|
||||||
|
int KMARKETFACE = 17;
|
||||||
|
int KMEMORYSTATEMSGTYPEADELIEWELCOME = 1;
|
||||||
|
int KMEMORYSTATEMSGTYPEUNKNOWN = 0;
|
||||||
|
int KMINIPROGRAMNOTICE = 114;
|
||||||
|
int KMSGSUBTYPEARKGROUPANNOUNCE = 3;
|
||||||
|
int KMSGSUBTYPEARKGROUPANNOUNCECONFIRMREQUIRED = 4;
|
||||||
|
int KMSGSUBTYPEARKGROUPGIFTATME = 5;
|
||||||
|
int KMSGSUBTYPEARKGROUPTASKATALL = 6;
|
||||||
|
int KMSGSUBTYPEARKMULTIMSG = 7;
|
||||||
|
int KMSGSUBTYPEARKNORMAL = 0;
|
||||||
|
int KMSGSUBTYPEARKTENCENTDOCFROMMINIAPP = 1;
|
||||||
|
int KMSGSUBTYPEARKTENCENTDOCFROMPLUSPANEL = 2;
|
||||||
|
int KMSGSUBTYPEEMOTICON = 15;
|
||||||
|
int KMSGSUBTYPEFILEAPP = 11;
|
||||||
|
int KMSGSUBTYPEFILEAUDIO = 3;
|
||||||
|
int KMSGSUBTYPEFILEDOC = 4;
|
||||||
|
int KMSGSUBTYPEFILEEXCEL = 6;
|
||||||
|
int KMSGSUBTYPEFILEFOLDER = 13;
|
||||||
|
int KMSGSUBTYPEFILEHTML = 10;
|
||||||
|
int KMSGSUBTYPEFILEIPA = 14;
|
||||||
|
int KMSGSUBTYPEFILENORMAL = 0;
|
||||||
|
int KMSGSUBTYPEFILEPDF = 7;
|
||||||
|
int KMSGSUBTYPEFILEPIC = 1;
|
||||||
|
int KMSGSUBTYPEFILEPPT = 5;
|
||||||
|
int KMSGSUBTYPEFILEPSD = 12;
|
||||||
|
int KMSGSUBTYPEFILETXT = 8;
|
||||||
|
int KMSGSUBTYPEFILEVIDEO = 2;
|
||||||
|
int KMSGSUBTYPEFILEZIP = 9;
|
||||||
|
int KMSGSUBTYPELINK = 5;
|
||||||
|
int KMSGSUBTYPEMARKETFACE = 1;
|
||||||
|
int KMSGSUBTYPEMIXEMOTICON = 7;
|
||||||
|
int KMSGSUBTYPEMIXFACE = 3;
|
||||||
|
int KMSGSUBTYPEMIXMARKETFACE = 2;
|
||||||
|
int KMSGSUBTYPEMIXPIC = 1;
|
||||||
|
int KMSGSUBTYPEMIXREPLY = 4;
|
||||||
|
int KMSGSUBTYPEMIXTEXT = 0;
|
||||||
|
int KMSGSUBTYPETENCENTDOC = 6;
|
||||||
|
int KMSGTYPEARKSTRUCT = 11;
|
||||||
|
int KMSGTYPEFACEBUBBLE = 24;
|
||||||
|
int KMSGTYPEFILE = 3;
|
||||||
|
int KMSGTYPEGIFT = 14;
|
||||||
|
int KMSGTYPEGIPHY = 13;
|
||||||
|
int KMSGTYPEGRAYTIPS = 5;
|
||||||
|
int KMSGTYPEMIX = 2;
|
||||||
|
int KMSGTYPEMULTIMSGFORWARD = 8;
|
||||||
|
int KMSGTYPENULL = 1;
|
||||||
|
int KMSGTYPEONLINEFILE = 21;
|
||||||
|
int KMSGTYPEONLINEFOLDER = 27;
|
||||||
|
int KMSGTYPEPROLOGUE = 29;
|
||||||
|
int KMSGTYPEPTT = 6;
|
||||||
|
int KMSGTYPEREPLY = 9;
|
||||||
|
int KMSGTYPESHARELOCATION = 25;
|
||||||
|
int KMSGTYPESTRUCT = 4;
|
||||||
|
int KMSGTYPESTRUCTLONGMSG = 12;
|
||||||
|
int KMSGTYPETEXTGIFT = 15;
|
||||||
|
int KMSGTYPEUNKNOWN = 0;
|
||||||
|
int KMSGTYPEVIDEO = 7;
|
||||||
|
int KMSGTYPEWALLET = 10;
|
||||||
|
int KNEEDCONFIRMGROUPMANNOUNCEATALLMSGTYPEINMSGBOX = 2005;
|
||||||
|
int KNOTPASSTHROUGHEVENTTYPEUPPERBOUNDARY = 9999;
|
||||||
|
int KPTTFORMATTYPEAMR = 0;
|
||||||
|
int KPTTFORMATTYPESILK = 1;
|
||||||
|
int KPTTTRANSLATESTATUSFAIL = 3;
|
||||||
|
int KPTTTRANSLATESTATUSSUC = 2;
|
||||||
|
int KPTTTRANSLATESTATUSTRANSLATING = 1;
|
||||||
|
int KPTTTRANSLATESTATUSUNKNOWN = 0;
|
||||||
|
int KPTTVIPLEVELTYPENONE = 0;
|
||||||
|
int KPTTVIPLEVELTYPEQQVIP = 0;
|
||||||
|
int KPTTVIPLEVELTYPESVIP = 0;
|
||||||
|
int KPTTVOICECHANGETYPEBEASTMACHINE = 7;
|
||||||
|
int KPTTVOICECHANGETYPEBOY = 2;
|
||||||
|
int KPTTVOICECHANGETYPECATCHCOLD = 13;
|
||||||
|
int KPTTVOICECHANGETYPEECHO = 5;
|
||||||
|
int KPTTVOICECHANGETYPEFATGUY = 16;
|
||||||
|
int KPTTVOICECHANGETYPEFLASHING = 9;
|
||||||
|
int KPTTVOICECHANGETYPEGIRL = 1;
|
||||||
|
int KPTTVOICECHANGETYPEHORRIBLE = 3;
|
||||||
|
int KPTTVOICECHANGETYPEKINDERGARTEN = 6;
|
||||||
|
int KPTTVOICECHANGETYPEMEDAROT = 15;
|
||||||
|
int KPTTVOICECHANGETYPENONE = 0;
|
||||||
|
int KPTTVOICECHANGETYPEOPTIMUSPRIME = 8;
|
||||||
|
int KPTTVOICECHANGETYPEOUTOFDATE = 14;
|
||||||
|
int KPTTVOICECHANGETYPEPAPI = 11;
|
||||||
|
int KPTTVOICECHANGETYPEQUICK = 4;
|
||||||
|
int KPTTVOICECHANGETYPESTUTTER = 10;
|
||||||
|
int KPTTVOICECHANGETYPETRAPPEDBEAST = 12;
|
||||||
|
int KPTTVOICETYPEINTERCOM = 1;
|
||||||
|
int KPTTVOICETYPESOUNDRECORD = 2;
|
||||||
|
int KPTTVOICETYPEUNKNOW = 0;
|
||||||
|
int KPTTVOICETYPEVOICECHANGE = 3;
|
||||||
|
int KPUBLICACCOUNTTIANSHUHIGHLIGHTWORDTYPEINMSGBOX = 1010;
|
||||||
|
int KREPLYABSELEMTYPEFACE = 2;
|
||||||
|
int KREPLYABSELEMTYPEPIC = 3;
|
||||||
|
int KREPLYABSELEMTYPETEXT = 1;
|
||||||
|
int KREPLYABSELEMTYPEUNKNOWN = 0;
|
||||||
|
int KREPLYATMEMSGTYPEINMSGBOX = 1002;
|
||||||
|
int KRMDOWNTYPEORIG = 1;
|
||||||
|
int KRMDOWNTYPETHUMB = 2;
|
||||||
|
int KRMDOWNTYPEUNKNOWN = 0;
|
||||||
|
int KRMFILETHUMBSIZE128 = 128;
|
||||||
|
int KRMFILETHUMBSIZE320 = 320;
|
||||||
|
int KRMFILETHUMBSIZE384 = 384;
|
||||||
|
int KRMFILETHUMBSIZE750 = 750;
|
||||||
|
int KRMPICAIOTHUMBSIZE = 0;
|
||||||
|
int KRMPICTHUMBSIZE198 = 198;
|
||||||
|
int KRMPICTHUMBSIZE720 = 720;
|
||||||
|
int KRMPICTYPEBMP = 3;
|
||||||
|
int KRMPICTYPECHECKOTHER = 900;
|
||||||
|
int KRMPICTYPEGIF = 2;
|
||||||
|
int KRMPICTYPEJPG = 0;
|
||||||
|
int KRMPICTYPENEWPICAPNG = 2001;
|
||||||
|
int KRMPICTYPENEWPICBMP = 1005;
|
||||||
|
int KRMPICTYPENEWPICGIF = 2000;
|
||||||
|
int KRMPICTYPENEWPICJPEG = 1000;
|
||||||
|
int KRMPICTYPENEWPICPNG = 1001;
|
||||||
|
int KRMPICTYPENEWPICPROGERSSIVJPEG = 1003;
|
||||||
|
int KRMPICTYPENEWPICSHARPP = 1004;
|
||||||
|
int KRMPICTYPENEWPICWEBP = 1002;
|
||||||
|
int KRMPICTYPEPNG = 1;
|
||||||
|
int KRMPICTYPEUNKOWN = 0;
|
||||||
|
int KRMTHUMBSIZEZERO = 0;
|
||||||
|
int KRMTRNASFERSTATUSDOWNLOADING = 3;
|
||||||
|
int KRMTRNASFERSTATUSFAIL = 5;
|
||||||
|
int KRMTRNASFERSTATUSINIT = 1;
|
||||||
|
int KRMTRNASFERSTATUSSUC = 4;
|
||||||
|
int KRMTRNASFERSTATUSUNKOW = 0;
|
||||||
|
int KRMTRNASFERSTATUSUPLOADING = 2;
|
||||||
|
int KRMTRNASFERSTATUSUSERCANCEL = 6;
|
||||||
|
int KSEEKINGPARTNERFLAGSEEKING = 1;
|
||||||
|
int KSEEKINGPARTNERFLAGUNKNOWN = 0;
|
||||||
|
int KSENDSTATUSFAILED = 0;
|
||||||
|
int KSENDSTATUSSENDING = 1;
|
||||||
|
int KSENDSTATUSSUCCESS = 2;
|
||||||
|
int KSENDSTATUSSUCCESSNOSEQ = 3;
|
||||||
|
int KSENDTYPEDROPPED = 6;
|
||||||
|
int KSENDTYPELOCAL = 3;
|
||||||
|
int KSENDTYPEOTHERDEVICE = 2;
|
||||||
|
int KSENDTYPERECV = 0;
|
||||||
|
int KSENDTYPESELF = 1;
|
||||||
|
int KSENDTYPESELFFORWARD = 4;
|
||||||
|
int KSENDTYPESELFMULTIFORWARD = 5;
|
||||||
|
int KSESSIONTYPEADDRESSBOOK = 5;
|
||||||
|
int KSESSIONTYPEC2C = 1;
|
||||||
|
int KSESSIONTYPEDISC = 3;
|
||||||
|
int KSESSIONTYPEFAV = 41;
|
||||||
|
int KSESSIONTYPEGROUP = 2;
|
||||||
|
int KSESSIONTYPEGROUPBLESS = 52;
|
||||||
|
int KSESSIONTYPEGUILD = 4;
|
||||||
|
int KSESSIONTYPEGUILDMETA = 16;
|
||||||
|
int KSESSIONTYPENEARBYPRO = 54;
|
||||||
|
int KSESSIONTYPEQQNOTIFY = 51;
|
||||||
|
int KSESSIONTYPERELATEACCOUNT = 50;
|
||||||
|
int KSESSIONTYPESERVICEASSISTANT = 19;
|
||||||
|
int KSESSIONTYPESUBSCRIBEFOLDER = 30;
|
||||||
|
int KSESSIONTYPETYPEBUDDYNOTIFY = 7;
|
||||||
|
int KSESSIONTYPETYPEGROUPHELPER = 9;
|
||||||
|
int KSESSIONTYPETYPEGROUPNOTIFY = 8;
|
||||||
|
int KSESSIONTYPEUNKNOWN = 0;
|
||||||
|
int KSESSIONTYPEWEIYUN = 40;
|
||||||
|
int KSPECIALCAREMSGTYPEINMSGBOX = 1006;
|
||||||
|
int KSPECIFIEDREDENVELOPEATMEMSGTYPEINMSGBOX = 1004;
|
||||||
|
int KSPECIFIEDREDENVELOPEATONEMSGTYPEINMSGBOX = 1003;
|
||||||
|
int KTENCENTDOCTYPEADDON = 110;
|
||||||
|
int KTENCENTDOCTYPEDOC = 0;
|
||||||
|
int KTENCENTDOCTYPEDRAWING = 89;
|
||||||
|
int KTENCENTDOCTYPEDRIVE = 101;
|
||||||
|
int KTENCENTDOCTYPEFILE = 100;
|
||||||
|
int KTENCENTDOCTYPEFLOWCHART = 91;
|
||||||
|
int KTENCENTDOCTYPEFOLDER = 3;
|
||||||
|
int KTENCENTDOCTYPEFORM = 2;
|
||||||
|
int KTENCENTDOCTYPEMIND = 90;
|
||||||
|
int KTENCENTDOCTYPENOTES = 5;
|
||||||
|
int KTENCENTDOCTYPEPDF = 6;
|
||||||
|
int KTENCENTDOCTYPEPROGRAM = 7;
|
||||||
|
int KTENCENTDOCTYPESHEET = 1;
|
||||||
|
int KTENCENTDOCTYPESLIDE = 4;
|
||||||
|
int KTENCENTDOCTYPESMARTCANVAS = 8;
|
||||||
|
int KTENCENTDOCTYPESMARTSHEET = 9;
|
||||||
|
int KTENCENTDOCTYPESPEECH = 102;
|
||||||
|
int KTENCENTDOCTYPEUNKNOWN = 10;
|
||||||
|
int KTOFURECORDMSG = 23;
|
||||||
|
int KTOPMSGTYPETASK = 1;
|
||||||
|
int KTOPMSGTYPEUNKNOWN = 0;
|
||||||
|
int KTRIGGERTYPEAUTO = 1;
|
||||||
|
int KTRIGGERTYPEMANUAL = 0;
|
||||||
|
int KUNKNOWN = 0;
|
||||||
|
int KUNKNOWNTYPEINMSGBOX = 0;
|
||||||
|
int KUNREADCNTUPTYPEALLDIRECTSESSION = 4;
|
||||||
|
int KUNREADCNTUPTYPEALLFEEDSINGUILD = 6;
|
||||||
|
int KUNREADCNTUPTYPEALLGUILD = 3;
|
||||||
|
int KUNREADCNTUPTYPECATEGORY = 5;
|
||||||
|
int KUNREADCNTUPTYPECHANNEL = 1;
|
||||||
|
int KUNREADCNTUPTYPECONTACT = 0;
|
||||||
|
int KUNREADCNTUPTYPEGUILD = 2;
|
||||||
|
int KUNREADCNTUPTYPEGUILDGROUP = 7;
|
||||||
|
int KUNREADSHOWTTYPEGRAYPOINT = 2;
|
||||||
|
int KUNREADSHOWTYPEREDPOINT = 1;
|
||||||
|
int KUNREADSHOWTYPESMALLGRAYPOINT = 4;
|
||||||
|
int KUNREADSHOWTYPESMALLREDPOINT = 3;
|
||||||
|
int KUNREADSHOWTYPEUNKNOWN = 0;
|
||||||
|
int KVASGIFTCOINTYPECOIN = 0;
|
||||||
|
int KVASGIFTCOINTYPEMARKETCOIN = 1;
|
||||||
|
int KYOLOGAMERESULTMSG = 18;
|
||||||
|
int PIC_800_RECOMMENDED = 7;
|
||||||
|
int PIC_AIGC_EMOJI = 14;
|
||||||
|
int PIC_ALBUM_GIF = 11;
|
||||||
|
int PIC_COMMERCIAL_ADVERTISING = 9;
|
||||||
|
int PIC_FIND = 10;
|
||||||
|
int PIC_HOT = 2;
|
||||||
|
int PIC_HOT_EMOJI = 13;
|
||||||
|
int PIC_NORMAL = 0;
|
||||||
|
int PIC_PK = 3;
|
||||||
|
int PIC_QQZONE = 5;
|
||||||
|
int PIC_SELFIE_GIF = 8;
|
||||||
|
int PIC_SEND_FROM_TAB_SEARCH_BOX = 12;
|
||||||
|
int PIC_USER = 1;
|
||||||
|
int PIC_WISDOM_FIGURE = 4;
|
||||||
|
int REPLYORIGINALMSGSTATEHASRECALL = 1;
|
||||||
|
int REPLYORIGINALMSGSTATEUNKNOWN = 0;
|
||||||
|
int SHARELOCATIONELEMSUBTYPENORMAL = 1;
|
||||||
|
int SHARELOCATIONELEMSUBTYPEUNKNOWN = 0;
|
||||||
|
int TEXTELEMENTSUBTYPELINK = 1;
|
||||||
|
int TEXTELEMENTSUBTYPETENCENTDOC = 2;
|
||||||
|
int TEXTELEMENTSUBTYPEUNKNOWN = 0;
|
||||||
|
```
|
16
docs/develop/NC 1.6.X的计划.md
Normal file
16
docs/develop/NC 1.6.X的计划.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# 开发方向
|
||||||
|
方向一 NativeCall/Hook:
|
||||||
|
1. 崩溃检测机制的实现
|
||||||
|
2. Api_Caller 的Hook 可以拿到Event/Handler 进一步提升NC 即时的拦截与处理一些事件比如ReCall拦截
|
||||||
|
3. Node包装层 进一步分析,拿到脱离自带Listener/Adapter,可以拿到一些更加底层的数据变动 或许包括更多二进制数据
|
||||||
|
|
||||||
|
方向二 全新的无头启动 Way01
|
||||||
|
1. 基于Node启动原理,借助导出符号获取函数地址 再次还原NodeMain
|
||||||
|
|
||||||
|
方向三 发包与收包
|
||||||
|
1. 参考 方向一/3 大概可以收包
|
||||||
|
2. 发包 (暂时没有计划)
|
||||||
|
|
||||||
|
方向四 版本控制
|
||||||
|
1. 根据不同版本进行逻辑控制
|
||||||
|
2. 某些参数的自动提取
|
1
docs/develop/碎碎的研究记录.md
Normal file
1
docs/develop/碎碎的研究记录.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
getMsgUniqueId 传入时间 产出一个唯一ID 发送消息作为一个参数
|
139
package.json
139
package.json
@@ -1,67 +1,72 @@
|
|||||||
{
|
{
|
||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.3.6",
|
"version": "1.6.7",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"watch:dev": "vite --mode development",
|
"watch:dev": "vite --mode development",
|
||||||
"watch:prod": "vite --mode production",
|
"watch:prod": "vite --mode production",
|
||||||
"build:dev": "vite build --mode development",
|
"build:dev": "vite build --mode development",
|
||||||
"build:prod": "vite build --mode production",
|
"build:prod": "vite build --mode production",
|
||||||
"build": "npm run build:dev",
|
"build": "npm run build:dev",
|
||||||
"build:core": "cd ./src/core && npm run build && cd ../.. && node ./script/copy-core.cjs",
|
"build:core": "cd ./src/core && npm run build && cd ../.. && node ./script/copy-core.cjs",
|
||||||
"build:webui": "cd ./src/webui && vite build",
|
"build:webui": "cd ./src/webui && vite build",
|
||||||
"watch": "npm run watch:dev",
|
"watch": "npm run watch:dev",
|
||||||
"debug-win": "powershell dist/napcat.ps1",
|
"debug-win": "powershell dist/napcat.ps1",
|
||||||
"lint": "eslint --fix src/**/*.{js,ts}",
|
"lint": "eslint --fix src/**/*.{js,ts}",
|
||||||
"release": "npm run build:prod",
|
"release": "npm run build:prod",
|
||||||
"depend": "cd dist && npm install --omit=dev"
|
"depend": "cd dist && npm install --omit=dev"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@log4js-node/log4js-api": "^1.0.2",
|
"@babel/core": "^7.24.7",
|
||||||
"@rollup/plugin-commonjs": "^25.0.7",
|
"@babel/preset-typescript": "^7.24.7",
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"vite-plugin-babel": "^1.2.0",
|
||||||
"@rollup/plugin-typescript": "^11.1.6",
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||||
"@types/cors": "^2.8.17",
|
"@babel/plugin-proposal-decorators": "^7.24.7",
|
||||||
"@types/express": "^4.17.21",
|
"@log4js-node/log4js-api": "^1.0.2",
|
||||||
"@types/figlet": "^1.5.8",
|
"@protobuf-ts/plugin": "^2.9.4",
|
||||||
"@types/fluent-ffmpeg": "^2.1.24",
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@types/node": "^20.11.30",
|
"@rollup/plugin-typescript": "^11.1.6",
|
||||||
"@types/qrcode-terminal": "^0.12.2",
|
"@types/cors": "^2.8.17",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/express": "^4.17.21",
|
||||||
"@types/ws": "^8.5.10",
|
"@types/figlet": "^1.5.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
"@types/fluent-ffmpeg": "^2.1.24",
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
"@types/node": "^20.11.30",
|
||||||
"eslint": "^8.57.0",
|
"@types/qrcode-terminal": "^0.12.2",
|
||||||
"eslint-import-resolver-typescript": "^3.6.1",
|
"@types/uuid": "^10.0.0",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"@types/ws": "^8.5.10",
|
||||||
"i": "^0.3.7",
|
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||||
"javascript-obfuscator": "^4.1.0",
|
"@typescript-eslint/parser": "^7.4.0",
|
||||||
"rollup": "^4.13.2",
|
"eslint": "^8.57.0",
|
||||||
"rollup-plugin-dts": "^6.1.0",
|
"eslint-import-resolver-typescript": "^3.6.1",
|
||||||
"rollup-plugin-obfuscator": "^1.1.0",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"typescript": "^5.3.3",
|
"i": "^0.3.7",
|
||||||
"vite": "^5.2.6",
|
"javascript-obfuscator": "^4.1.0",
|
||||||
"vite-plugin-cp": "^4.0.8",
|
"rollup": "^4.13.2",
|
||||||
"vite-plugin-dts": "^3.8.2",
|
"rollup-plugin-dts": "^6.1.0",
|
||||||
"vite-tsconfig-paths": "^4.3.2"
|
"rollup-plugin-obfuscator": "^1.1.0",
|
||||||
},
|
"typescript": "^5.3.3",
|
||||||
"dependencies": {
|
"vite": "^5.2.6",
|
||||||
"@protobuf-ts/plugin": "^2.9.4",
|
"vite-plugin-cp": "^4.0.8",
|
||||||
"ajv": "^8.13.0",
|
"vite-plugin-dts": "^3.8.2",
|
||||||
"commander": "^12.0.0",
|
"vite-tsconfig-paths": "^4.3.2"
|
||||||
"cors": "^2.8.5",
|
},
|
||||||
"express": "^5.0.0-beta.2",
|
"dependencies": {
|
||||||
"fast-xml-parser": "^4.3.6",
|
"ajv": "^8.13.0",
|
||||||
"file-type": "^19.0.0",
|
"chalk": "^5.3.0",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"commander": "^12.0.0",
|
||||||
"image-size": "^1.1.1",
|
"cors": "^2.8.5",
|
||||||
"json-schema-to-ts": "^3.1.0",
|
"express": "^5.0.0-beta.2",
|
||||||
"log4js": "^6.9.1",
|
"fast-xml-parser": "^4.3.6",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"file-type": "^19.0.0",
|
||||||
"silk-wasm": "^3.3.4",
|
"fluent-ffmpeg": "^2.1.2",
|
||||||
"sqlite3": "^5.1.7",
|
"image-size": "^1.1.1",
|
||||||
"uuid": "^9.0.1",
|
"json-schema-to-ts": "^3.1.0",
|
||||||
"ws": "^8.16.0"
|
"log4js": "^6.9.1",
|
||||||
}
|
"qrcode-terminal": "^0.12.0",
|
||||||
}
|
"silk-wasm": "^3.6.1",
|
||||||
|
"sqlite3": "^5.1.7",
|
||||||
|
"uuid": "^10.0.0",
|
||||||
|
"ws": "^8.16.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
45
script/BootWay.03.ps1
Normal file
45
script/BootWay.03.ps1
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Dont Use This Script
|
||||||
|
# 2024.7.3
|
||||||
|
function Get-QQpath {
|
||||||
|
try {
|
||||||
|
$key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ"
|
||||||
|
$uninstallString = $key.UninstallString
|
||||||
|
return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
throw "get QQ path error: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function Select-QQPath {
|
||||||
|
Add-Type -AssemblyName System.Windows.Forms
|
||||||
|
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||||
|
|
||||||
|
$dialogTitle = "Select QQ.exe"
|
||||||
|
|
||||||
|
$filePicker = New-Object System.Windows.Forms.OpenFileDialog
|
||||||
|
$filePicker.Title = $dialogTitle
|
||||||
|
$filePicker.Filter = "Executable Files (*.exe)|*.exe|All Files (*.*)|*.*"
|
||||||
|
$filePicker.FilterIndex = 1
|
||||||
|
$null = $filePicker.ShowDialog()
|
||||||
|
if (-not ($filePicker.FileName)) {
|
||||||
|
throw "User did not select an .exe file."
|
||||||
|
}
|
||||||
|
return $filePicker.FileName
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = $args -join " "
|
||||||
|
Try {
|
||||||
|
$QQpath = Get-QQpath
|
||||||
|
}
|
||||||
|
Catch {
|
||||||
|
$QQpath = Select-QQPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Test-Path $QQpath)) {
|
||||||
|
throw "provided QQ path is invalid: $QQpath"
|
||||||
|
}
|
||||||
|
|
||||||
|
$Bootfile = Join-Path $PSScriptRoot "napcat.mjs"
|
||||||
|
$env:ELECTRON_RUN_AS_NODE = 1
|
||||||
|
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
||||||
|
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& chcp 65001;& '$($commandInfo.Path)' --enable-logging $params}"
|
28
script/NapCat.164.bat
Normal file
28
script/NapCat.164.bat
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
@echo off
|
||||||
|
chcp 65001
|
||||||
|
:: 检查是否有管理员权限
|
||||||
|
net session >nul 2>&1
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo 请求管理员权限...
|
||||||
|
powershell -Command "Start-Process '%~f0' -Verb runAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
:: 如果有管理员权限,继续执行
|
||||||
|
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"
|
||||||
|
|
||||||
|
echo !QQPath!
|
||||||
|
"!QQPath!" --enable-logging %*
|
||||||
|
|
||||||
|
pause
|
3
script/NapCat.Way01.bat
Normal file
3
script/NapCat.Way01.bat
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
REM 全新启动脚本 基于 Hook Native 预计版本1.6.0左右发布
|
||||||
|
@echo off
|
||||||
|
pause
|
20
script/index.js
Normal file
20
script/index.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// --------------------
|
||||||
|
// 2024.7.3 9.9.12 BootWay.03 其余方法暂不公开(此方案为临时方案 Win平台已验证)
|
||||||
|
// 缺陷 (已知)
|
||||||
|
// 1.与非入侵式不同 现在破坏本体代码
|
||||||
|
// 2.重启代码与正常启动代码失效
|
||||||
|
// 3.Win需要补丁
|
||||||
|
// 4.更新后丢失内容 需要重写此文件
|
||||||
|
// 5.安装难度上升与周围基础设施失效
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const CurrentPath = path.dirname(__filename)
|
||||||
|
const hasNapcatParam = process.argv.includes('--enable-logging');
|
||||||
|
if (hasNapcatParam) {
|
||||||
|
(async () => {
|
||||||
|
await import("file://" + path.join(CurrentPath, './napcat/napcat.mjs'));
|
||||||
|
})();
|
||||||
|
} else {
|
||||||
|
require('./launcher.node').load('external_index', module);
|
||||||
|
}
|
18
script/napcat-9912-utf8.bat
Normal file
18
script/napcat-9912-utf8.bat
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
chcp 65001
|
||||||
|
:loop_read
|
||||||
|
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||||
|
set "RetString=%%b"
|
||||||
|
goto :napcat_boot
|
||||||
|
)
|
||||||
|
|
||||||
|
:napcat_boot
|
||||||
|
for %%a in ("!RetString!") do (
|
||||||
|
set "pathWithoutUninstall=%%~dpa"
|
||||||
|
)
|
||||||
|
|
||||||
|
set "QQPath=!pathWithoutUninstall!"
|
||||||
|
cd /d !QQPath!
|
||||||
|
echo !QQPath!
|
||||||
|
QQ.exe --enable-logging %*
|
41
script/napcat-9912-utf8.ps1
Normal file
41
script/napcat-9912-utf8.ps1
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
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) + "\"
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Location -Path $QQpath
|
||||||
|
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& chcp 65001;& ./QQ.exe --enable-logging $params}"
|
17
script/napcat-9912.bat
Normal file
17
script/napcat-9912.bat
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
:loop_read
|
||||||
|
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||||
|
set "RetString=%%b"
|
||||||
|
goto :napcat_boot
|
||||||
|
)
|
||||||
|
|
||||||
|
:napcat_boot
|
||||||
|
for %%a in ("!RetString!") do (
|
||||||
|
set "pathWithoutUninstall=%%~dpa"
|
||||||
|
)
|
||||||
|
|
||||||
|
set QQPath=!pathWithoutUninstall!
|
||||||
|
cd /d !QQPath!
|
||||||
|
echo !QQPath!
|
||||||
|
QQ.exe --enable-logging %*
|
41
script/napcat-9912.ps1
Normal file
41
script/napcat-9912.ps1
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
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) + "\"
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Location -Path $QQpath
|
||||||
|
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& ./QQ.exe --enable-logging $params}"
|
@@ -15,4 +15,4 @@ for %%a in ("!RetString!") do (
|
|||||||
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
||||||
set ELECTRON_RUN_AS_NODE=1
|
set ELECTRON_RUN_AS_NODE=1
|
||||||
echo !QQPath!
|
echo !QQPath!
|
||||||
"!QQPath!" ./napcat.cjs %*
|
"!QQPath!" ./napcat.mjs %*
|
||||||
|
@@ -37,7 +37,7 @@ if (!(Test-Path $QQpath)) {
|
|||||||
throw "provided QQ path is invalid: $QQpath"
|
throw "provided QQ path is invalid: $QQpath"
|
||||||
}
|
}
|
||||||
|
|
||||||
$Bootfile = Join-Path $PSScriptRoot "napcat.cjs"
|
$Bootfile = Join-Path $PSScriptRoot "napcat.mjs"
|
||||||
$env:ELECTRON_RUN_AS_NODE = 1
|
$env:ELECTRON_RUN_AS_NODE = 1
|
||||||
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
$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)' $Bootfile $params}"
|
@@ -14,4 +14,4 @@ for %%a in ("!RetString!") do (
|
|||||||
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
||||||
set ELECTRON_RUN_AS_NODE=1
|
set ELECTRON_RUN_AS_NODE=1
|
||||||
echo !QQPath!
|
echo !QQPath!
|
||||||
"!QQPath!" ./napcat.cjs %*
|
"!QQPath!" ./napcat.mjs %*
|
||||||
|
@@ -37,7 +37,7 @@ if (!(Test-Path $QQpath)) {
|
|||||||
throw "provided QQ path is invalid: $QQpath"
|
throw "provided QQ path is invalid: $QQpath"
|
||||||
}
|
}
|
||||||
|
|
||||||
$Bootfile = Join-Path $PSScriptRoot "napcat.cjs"
|
$Bootfile = Join-Path $PSScriptRoot "napcat.mjs"
|
||||||
$env:ELECTRON_RUN_AS_NODE = 1
|
$env:ELECTRON_RUN_AS_NODE = 1
|
||||||
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
||||||
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& '$($commandInfo.Path)' $Bootfile $params}"
|
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& '$($commandInfo.Path)' $Bootfile $params}"
|
@@ -18,4 +18,4 @@ if ! [ -x /opt/QQ/qq ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
/opt/QQ/qq "${SCRIPT_DIR}/napcat.cjs" "$@"
|
/opt/QQ/qq "${SCRIPT_DIR}/napcat.mjs" "$@"
|
||||||
|
@@ -37,14 +37,14 @@ export abstract class HttpServerBase {
|
|||||||
const authHeader = req.get('authorization');
|
const authHeader = req.get('authorization');
|
||||||
if (authHeader) {
|
if (authHeader) {
|
||||||
clientToken = authHeader.split('Bearer ').pop() || '';
|
clientToken = authHeader.split('Bearer ').pop() || '';
|
||||||
logDebug('receive http header token', clientToken);
|
//logDebug('receive http header token', clientToken);
|
||||||
} else if (req.query.access_token) {
|
} else if (req.query.access_token) {
|
||||||
if (Array.isArray(req.query.access_token)) {
|
if (Array.isArray(req.query.access_token)) {
|
||||||
clientToken = req.query.access_token[0].toString();
|
clientToken = req.query.access_token[0].toString();
|
||||||
} else {
|
} else {
|
||||||
clientToken = req.query.access_token.toString();
|
clientToken = req.query.access_token.toString();
|
||||||
}
|
}
|
||||||
logDebug('receive http url token', clientToken);
|
//logDebug('receive http url token', clientToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serverToken && clientToken != serverToken) {
|
if (serverToken && clientToken != serverToken) {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { sleep } from '@/common/utils/helper';
|
import { sleep } from '@/common/utils/helper';
|
||||||
|
import { logError } from './log';
|
||||||
type AsyncQueueTask = (() => void) | (()=>Promise<void>);
|
type AsyncQueueTask = (() => void) | (()=>Promise<void>);
|
||||||
|
// 2024.7.13 废弃
|
||||||
|
|
||||||
export class AsyncQueue {
|
export class AsyncQueue {
|
||||||
private tasks: (AsyncQueueTask)[] = [];
|
private tasks: (AsyncQueueTask)[] = [];
|
||||||
@@ -26,7 +26,8 @@ export class AsyncQueue {
|
|||||||
await taskRet;
|
await taskRet;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
// console.error(e);
|
||||||
|
logError(e);
|
||||||
}
|
}
|
||||||
this.tasks.shift();
|
this.tasks.shift();
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { log, logDebug, logError } from '@/common/utils/log';
|
import { log, logDebug, logError } from '@/common/utils/log';
|
||||||
|
import { dirname } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
const configDir = path.resolve(__dirname, 'config');
|
const configDir = path.resolve(__dirname, 'config');
|
||||||
fs.mkdirSync(configDir, { recursive: true });
|
fs.mkdirSync(configDir, { recursive: true });
|
||||||
|
181
src/common/utils/EventTask.ts
Normal file
181
src/common/utils/EventTask.ts
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
import { NodeIQQNTWrapperSession } from '@/core/wrapper';
|
||||||
|
import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
|
interface Internal_MapKey {
|
||||||
|
timeout: number,
|
||||||
|
createtime: number,
|
||||||
|
func: (...arg: any[]) => any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListenerClassBase {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListenerIBase {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
|
new(listener: any): ListenerClassBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NTEventWrapper {
|
||||||
|
|
||||||
|
private ListenerMap: { [key: string]: ListenerIBase } | undefined;//ListenerName-Unique -> Listener构造函数
|
||||||
|
private WrapperSession: NodeIQQNTWrapperSession | undefined;//WrapperSession
|
||||||
|
private ListenerManger: 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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
init({ ListenerMap, WrapperSession }: { ListenerMap: { [key: string]: typeof ListenerClassBase }, WrapperSession: NodeIQQNTWrapperSession }) {
|
||||||
|
this.ListenerMap = ListenerMap;
|
||||||
|
this.WrapperSession = WrapperSession;
|
||||||
|
}
|
||||||
|
CreatEventFunction<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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
CreatListenerFunction<T>(listenerMainName: string, uniqueCode: string = ''): T {
|
||||||
|
const ListenerType = this.ListenerMap![listenerMainName];
|
||||||
|
let Listener = this.ListenerManger.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.CreatEventFunction<(listener: T) => number>(Service);
|
||||||
|
addfunc!(Listener as T);
|
||||||
|
//console.log(addfunc!(Listener as T));
|
||||||
|
this.ListenerManger.set(listenerMainName + uniqueCode, Listener);
|
||||||
|
}
|
||||||
|
return Listener as T;
|
||||||
|
}
|
||||||
|
//统一回调清理事件
|
||||||
|
async DispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||||
|
//console.log(ListenerMainName, this.EventTask.get(ListenerMainName), ListenerSubName, this.EventTask.get(ListenerMainName)?.get(ListenerSubName));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
task.func(...args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async CallNoListenerEvent<EventType extends (...args: any[]) => Promise<any>,>(EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
||||||
|
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||||
|
const EventFunc = this.CreatEventFunction<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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async CallNormalEvent<EventType extends (...args: any[]) => Promise<any>, ListenerType extends (...args: any[]) => void>(EventName = '', ListenerName = '', waitTimes = 1, timeout: number = 3000, ...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 < waitTimes) {
|
||||||
|
reject(new Error('NTEvent EventName:' + EventName + ' ListenerName:' + ListenerName + ' timeout'));
|
||||||
|
} else {
|
||||||
|
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const Timeouter = setTimeout(databack, timeout);
|
||||||
|
|
||||||
|
const ListenerNameList = ListenerName.split('/');
|
||||||
|
const ListenerMainName = ListenerNameList[0];
|
||||||
|
const ListenerSubName = ListenerNameList[1];
|
||||||
|
const eventCallbak = {
|
||||||
|
timeout: timeout,
|
||||||
|
createtime: Date.now(),
|
||||||
|
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.CreatListenerFunction(ListenerMainName);
|
||||||
|
const EventFunc = this.CreatEventFunction<EventType>(EventName);
|
||||||
|
//console.log("测试打点", args);
|
||||||
|
retEvent = await EventFunc!(...(args as any[]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const NTEventDispatch = new NTEventWrapper();
|
||||||
|
|
||||||
|
// 示例代码 快速创建事件
|
||||||
|
// 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) });
|
161
src/common/utils/LRUCache.ts
Normal file
161
src/common/utils/LRUCache.ts
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
import { logError, logDebug } from '@/common/utils/log';
|
||||||
|
|
||||||
|
type group_id = number;
|
||||||
|
type user_id = number;
|
||||||
|
|
||||||
|
class cacheNode<T> {
|
||||||
|
value: T;
|
||||||
|
groupId: group_id;
|
||||||
|
userId: user_id;
|
||||||
|
prev: cacheNode<T> | null;
|
||||||
|
next: cacheNode<T> | null;
|
||||||
|
timestamp: number;
|
||||||
|
|
||||||
|
constructor(groupId: group_id, userId: user_id, value: T) {
|
||||||
|
this.groupId = groupId;
|
||||||
|
this.userId = userId;
|
||||||
|
this.value = value;
|
||||||
|
this.prev = null;
|
||||||
|
this.next = null;
|
||||||
|
this.timestamp = Date.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type cache<T, K = { [key: user_id]: cacheNode<T> }> = { [key: group_id]: K };
|
||||||
|
type removeObject<T> = cache<T, { userId: user_id, value: T }[]>
|
||||||
|
class LRU<T> {
|
||||||
|
private maxAge: number;
|
||||||
|
private maxSize: number;
|
||||||
|
private currentSize: number;
|
||||||
|
private cache: cache<T>;
|
||||||
|
private head: cacheNode<T> | null = null;
|
||||||
|
private tail: cacheNode<T> | null = null;
|
||||||
|
private onFuncs: ((node: removeObject<T>) => void)[] = [];
|
||||||
|
|
||||||
|
constructor(maxAge: number = 6e4 * 3, maxSize: number = 1e4) {
|
||||||
|
this.maxAge = maxAge;
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
this.cache = Object.create(null);
|
||||||
|
this.currentSize = 0;
|
||||||
|
|
||||||
|
if (maxSize == 0) return;
|
||||||
|
setInterval(() => this.removeExpired(), this.maxAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除LRU节点
|
||||||
|
private removeLRUNode(node: cacheNode<T>) {
|
||||||
|
logDebug(
|
||||||
|
'removeLRUNode',
|
||||||
|
node.groupId,
|
||||||
|
node.userId,
|
||||||
|
node.value,
|
||||||
|
this.currentSize
|
||||||
|
);
|
||||||
|
node.prev = node.next = null;
|
||||||
|
delete this.cache[node.groupId][node.userId];
|
||||||
|
this.removeNode(node);
|
||||||
|
this.onFuncs.forEach((func) => func({ [node.groupId]: [node] }));
|
||||||
|
this.currentSize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public on(func: (node: removeObject<T>) => void) {
|
||||||
|
this.onFuncs.push(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeExpired() {
|
||||||
|
const now = Date.now();
|
||||||
|
let current = this.tail;
|
||||||
|
let totalNodeNum = 0;
|
||||||
|
|
||||||
|
const removeObject: cache<T, { userId: user_id, value: T }[]> = {};
|
||||||
|
|
||||||
|
while (current && now - current.timestamp > this.maxAge) {
|
||||||
|
// 收集节点
|
||||||
|
if (!removeObject[current.groupId]) removeObject[current.groupId] = [];
|
||||||
|
removeObject[current.groupId].push({ userId: current.userId, value: current.value });
|
||||||
|
// 删除LRU节点
|
||||||
|
delete this.cache[current.groupId][current.userId];
|
||||||
|
current = current.prev;
|
||||||
|
totalNodeNum++;
|
||||||
|
this.currentSize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!totalNodeNum) return;
|
||||||
|
|
||||||
|
// 跟新链表指向
|
||||||
|
if (current) { current.next = null; } else { this.head = null; }
|
||||||
|
this.tail = current;
|
||||||
|
|
||||||
|
this.onFuncs.forEach(func => func(removeObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
private addNode(node: cacheNode<T>) {
|
||||||
|
node.next = this.head;
|
||||||
|
if (this.head) this.head.prev = node;
|
||||||
|
if (!this.tail) this.tail = node;
|
||||||
|
this.head = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeNode(node: cacheNode<T>) {
|
||||||
|
if (node.prev) node.prev.next = node.next;
|
||||||
|
if (node.next) node.next.prev = node.prev;
|
||||||
|
if (node === this.head) this.head = node.next;
|
||||||
|
if (node === this.tail) this.tail = node.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveToHead(node: cacheNode<T>) {
|
||||||
|
if (this.head === node) return;
|
||||||
|
|
||||||
|
this.removeNode(node);
|
||||||
|
this.addNode(node);
|
||||||
|
node.prev = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set(groupId: group_id, userId: user_id, value: T) {
|
||||||
|
if (!this.cache[groupId]) {
|
||||||
|
this.cache[groupId] = Object.create(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupObject = this.cache[groupId];
|
||||||
|
|
||||||
|
if (groupObject[userId]) {
|
||||||
|
const node = groupObject[userId];
|
||||||
|
node.value = value;
|
||||||
|
node.timestamp = Date.now();
|
||||||
|
this.moveToHead(node);
|
||||||
|
} else {
|
||||||
|
const node = new cacheNode(groupId, userId, value);
|
||||||
|
groupObject[userId] = node;
|
||||||
|
this.currentSize++;
|
||||||
|
this.addNode(node);
|
||||||
|
if (this.currentSize > this.maxSize) {
|
||||||
|
const tail = this.tail!;
|
||||||
|
this.removeLRUNode(tail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public get(groupId: group_id): { userId: user_id; value: T }[];
|
||||||
|
public get(groupId: group_id, userId: user_id): null | { userId: user_id; value: T };
|
||||||
|
public get(groupId: group_id, userId?: user_id): any {
|
||||||
|
const groupObject = this.cache[groupId];
|
||||||
|
if (!groupObject) return userId === undefined ? [] : null;
|
||||||
|
|
||||||
|
if (userId === undefined) {
|
||||||
|
return Object.entries(groupObject).map(([userId, { value }]) => ({
|
||||||
|
userId: Number(userId),
|
||||||
|
value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupObject[userId]) {
|
||||||
|
return { userId, value: groupObject[userId].value };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default LRU;
|
53
src/common/utils/MessageUnique.ts
Normal file
53
src/common/utils/MessageUnique.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
|
class LimitedHashTable<K, V> {
|
||||||
|
private keyToValue: Map<K, V> = new Map();
|
||||||
|
private valueToKey: Map<V, K> = new Map();
|
||||||
|
private maxSize: number;
|
||||||
|
private KeyQueneList: K[] = [];
|
||||||
|
private ValueQueneList: V[] = [];
|
||||||
|
constructor(maxSize: number) {
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
}
|
||||||
|
set(key: K, value: V): void {
|
||||||
|
this.keyToValue.set(key, value);
|
||||||
|
this.valueToKey.set(value, key);
|
||||||
|
if (this.KeyQueneList.length >= this.maxSize || this.ValueQueneList.length >= this.maxSize) {
|
||||||
|
this.KeyQueneList.shift();
|
||||||
|
this.ValueQueneList.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(key: K): V | undefined {
|
||||||
|
return this.keyToValue.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
getKey(value: V): K | undefined {
|
||||||
|
return this.valueToKey.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(key: K): void {
|
||||||
|
const value = this.keyToValue.get(key);
|
||||||
|
if (value !== undefined) {
|
||||||
|
this.keyToValue.delete(key);
|
||||||
|
this.valueToKey.delete(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageUniqueWrapper {
|
||||||
|
private msgIdMap: LimitedHashTable<number, string> = new LimitedHashTable(1000);
|
||||||
|
createMsg(MsgId: string) {
|
||||||
|
const ShortId = parseInt(crypto.createHash('sha1').update('2345').digest('hex').slice(0, 8), 16);
|
||||||
|
this.msgIdMap.set(ShortId, MsgId);
|
||||||
|
return ShortId;
|
||||||
|
}
|
||||||
|
getMsgIdByShortId(ShortId: number) {
|
||||||
|
return this.msgIdMap.getValue(ShortId);
|
||||||
|
}
|
||||||
|
getShortIdByMsgId(MsgId: string) {
|
||||||
|
return this.msgIdMap.getKey(MsgId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MessageUnique = new MessageUniqueWrapper();
|
17
src/common/utils/Packet.ts
Normal file
17
src/common/utils/Packet.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// 方案一 MiniApp发包方案
|
||||||
|
// 前置条件: 处于GUI环境 存在MiniApp
|
||||||
|
|
||||||
|
import { NTQQSystemApi } from '@/core';
|
||||||
|
|
||||||
|
// 前排提示: 开发验证仅Win平台开展
|
||||||
|
export class MiniAppUtil {
|
||||||
|
static async RunMiniAppWithGUI() {
|
||||||
|
//process.env.ELECTRON_RUN_AS_NODE = undefined;//没用还是得自己用cpp之类的语言写个程序转发参数
|
||||||
|
return NTQQSystemApi.BootMiniApp(process.execPath, 'miniapp://open/1007?url=https%3A%2F%2Fm.q.qq.com%2Fa%2Fs%2Fedd0a83d3b8afe233dfa07adaaf8033f%3Fscene%3D1007%26min_refer%3D10001');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 方案二 MiniApp发包方案 替代MiniApp方案
|
||||||
|
// 前置条件: 无
|
||||||
|
export class MojoMiniAppUtil{
|
||||||
|
|
||||||
|
}
|
@@ -2,6 +2,7 @@ import path from 'node:path';
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import { systemPlatform } from '@/common/utils/system';
|
import { systemPlatform } from '@/common/utils/system';
|
||||||
|
import { logError } from '@/common/utils/log';
|
||||||
|
|
||||||
export const exePath = process.execPath;
|
export const exePath = process.execPath;
|
||||||
|
|
||||||
@@ -37,11 +38,11 @@ type QQVersionConfigInfo = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let _qqVersionConfigInfo: QQVersionConfigInfo = {
|
let _qqVersionConfigInfo: QQVersionConfigInfo = {
|
||||||
'baseVersion': '9.9.9-23361',
|
'baseVersion': '9.9.12-25765',
|
||||||
'curVersion': '9.9.9-23361',
|
'curVersion': '9.9.12-25765',
|
||||||
'prevVersion': '',
|
'prevVersion': '',
|
||||||
'onErrorVersions': [],
|
'onErrorVersions': [],
|
||||||
'buildId': '23361'
|
'buildId': '25765'
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fs.existsSync(configVersionInfoPath)) {
|
if (fs.existsSync(configVersionInfoPath)) {
|
||||||
@@ -49,24 +50,28 @@ if (fs.existsSync(configVersionInfoPath)) {
|
|||||||
const _ =JSON.parse(fs.readFileSync(configVersionInfoPath).toString());
|
const _ =JSON.parse(fs.readFileSync(configVersionInfoPath).toString());
|
||||||
_qqVersionConfigInfo = Object.assign(_qqVersionConfigInfo, _);
|
_qqVersionConfigInfo = Object.assign(_qqVersionConfigInfo, _);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Load QQ version config info failed, Use default version', e);
|
logError('Load QQ version config info failed, Use default version', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const qqVersionConfigInfo: QQVersionConfigInfo = _qqVersionConfigInfo;
|
export const qqVersionConfigInfo: QQVersionConfigInfo = _qqVersionConfigInfo;
|
||||||
|
//V1_WIN_NQ_9.9.12_25765_GW_B
|
||||||
export const qqPkgInfo: QQPkgInfo = require(pkgInfoPath);
|
export const qqPkgInfo: QQPkgInfo = JSON.parse(fs.readFileSync(pkgInfoPath).toString());
|
||||||
// platform_type: 3,
|
// platform_type: 3,
|
||||||
// app_type: 4,
|
// app_type: 4,
|
||||||
// app_version: '9.9.9-23159',
|
// app_version: '9.9.12-25765',
|
||||||
// qua: 'V1_WIN_NQ_9.9.9_23159_GW_B',
|
// qua: 'V1_WIN_NQ_9.9.12_25765_GW_B',
|
||||||
// appid: '537213764',
|
// appid: '537234702',
|
||||||
// platVer: '10.0.26100',
|
// platVer: '10.0.26100',
|
||||||
// clientVer: '9.9.9-23159',
|
// clientVer: '9.9.9-25765',
|
||||||
|
|
||||||
let _appid: string = '537213803'; // 默认为 Windows 平台的 appid
|
// Linux
|
||||||
|
// app_version: '3.2.9-25765',
|
||||||
|
// qua: 'V1_LNX_NQ_3.2.10_25765_GW_B',
|
||||||
|
|
||||||
|
let _appid: string = '537234702'; // 默认为 Windows 平台的 appid
|
||||||
if (systemPlatform === 'linux') {
|
if (systemPlatform === 'linux') {
|
||||||
_appid = '537213827';
|
_appid = '537234773';
|
||||||
}
|
}
|
||||||
// todo: mac 平台的 appid
|
// todo: mac 平台的 appid
|
||||||
export const appid = _appid;
|
export const appid = _appid;
|
@@ -1,5 +1,5 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { encode, getDuration, getWavFileInfo, isWav } from 'silk-wasm';
|
import { encode, getDuration, getWavFileInfo, isWav, isSilk } from 'silk-wasm';
|
||||||
import fsPromise from 'fs/promises';
|
import fsPromise from 'fs/promises';
|
||||||
import { log, logError } from './log';
|
import { log, logError } from './log';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
@@ -24,7 +24,7 @@ export async function encodeSilk(filePath: string) {
|
|||||||
const fileHeader = buffer.toString('hex', 0, bytesToRead);
|
const fileHeader = buffer.toString('hex', 0, bytesToRead);
|
||||||
return fileHeader;
|
return fileHeader;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('读取文件错误:', err);
|
logError('读取文件错误:', err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,10 +63,11 @@ export async function encodeSilk(filePath: string) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const file = await fsPromise.readFile(filePath);
|
||||||
const pttPath = path.join(TEMP_DIR, uuidv4());
|
const pttPath = path.join(TEMP_DIR, uuidv4());
|
||||||
if (getFileHeader(filePath) !== '02232153494c4b') {
|
if (!isSilk(file)) {
|
||||||
log(`语音文件${filePath}需要转换成silk`);
|
log(`语音文件${filePath}需要转换成silk`);
|
||||||
const _isWav = await isWavFile(filePath);
|
const _isWav = isWav(file);
|
||||||
const pcmPath = pttPath + '.pcm';
|
const pcmPath = pttPath + '.pcm';
|
||||||
let sampleRate = 0;
|
let sampleRate = 0;
|
||||||
const convert = () => {
|
const convert = () => {
|
||||||
@@ -96,7 +97,7 @@ export async function encodeSilk(filePath: string) {
|
|||||||
if (!_isWav) {
|
if (!_isWav) {
|
||||||
input = await convert();
|
input = await convert();
|
||||||
} else {
|
} else {
|
||||||
input = fs.readFileSync(filePath);
|
input = file;
|
||||||
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000];
|
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000];
|
||||||
const { fmt } = getWavFileInfo(input);
|
const { fmt } = getWavFileInfo(input);
|
||||||
// log(`wav文件信息`, fmt)
|
// log(`wav文件信息`, fmt)
|
||||||
@@ -113,7 +114,7 @@ export async function encodeSilk(filePath: string) {
|
|||||||
duration: silk.duration / 1000
|
duration: silk.duration / 1000
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const silk = fs.readFileSync(filePath);
|
const silk = file;
|
||||||
let duration = 0;
|
let duration = 0;
|
||||||
try {
|
try {
|
||||||
duration = getDuration(silk) / 1000;
|
duration = getDuration(silk) / 1000;
|
||||||
|
@@ -1,7 +1,11 @@
|
|||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fs from 'fs';
|
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) {
|
export function getModuleWithArchName(moduleName: string) {
|
||||||
const systemPlatform = os.platform();
|
const systemPlatform = os.platform();
|
||||||
const cpuArch = os.arch();
|
const cpuArch = os.arch();
|
||||||
@@ -14,6 +18,6 @@ export function cpModule(moduleName: string) {
|
|||||||
try {
|
try {
|
||||||
fs.copyFileSync(path.join(currentDir, fileName), path.join(currentDir, `${moduleName}.node`));
|
fs.copyFileSync(path.join(currentDir, fileName), path.join(currentDir, `${moduleName}.node`));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
477
src/common/utils/db.ts
Normal file
477
src/common/utils/db.ts
Normal file
@@ -0,0 +1,477 @@
|
|||||||
|
import { ElementType, FileElement, PicElement, PttElement, RawMessage, VideoElement } from '../../core/src/entities';
|
||||||
|
|
||||||
|
import sqlite3 from 'sqlite3';
|
||||||
|
import { log, logDebug, logError } from '@/common/utils/log';
|
||||||
|
import { NTQQMsgApi } from '@/core';
|
||||||
|
import LRU from '@/common/utils/LRUCache';
|
||||||
|
|
||||||
|
export interface IRember {
|
||||||
|
last_sent_time: number;
|
||||||
|
join_time: number;
|
||||||
|
user_id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type DBMsg = {
|
||||||
|
id: number,
|
||||||
|
shortId: number,
|
||||||
|
longId: string,
|
||||||
|
seq: number,
|
||||||
|
peerUid: string,
|
||||||
|
chatType: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DBFile = {
|
||||||
|
name: string; // 文件名
|
||||||
|
path: string;
|
||||||
|
url: string;
|
||||||
|
size: number;
|
||||||
|
uuid: string;
|
||||||
|
msgId: string;
|
||||||
|
elementId: string;
|
||||||
|
element: PicElement | VideoElement | FileElement | PttElement;
|
||||||
|
elementType: ElementType.PIC | ElementType.VIDEO | ElementType.FILE | ElementType.PTT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DBUtilBase {
|
||||||
|
protected db: sqlite3.Database | undefined;
|
||||||
|
|
||||||
|
async init(dbPath: string) {
|
||||||
|
if (this.db) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
this.db = new sqlite3.Database(dbPath, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
|
||||||
|
if (err) {
|
||||||
|
logError('Could not connect to database', err);
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.createTable();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createTable() {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.db?.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DBUtil extends DBUtilBase {
|
||||||
|
private msgCache: Map<string | number, RawMessage> = new Map<string | number, RawMessage>();
|
||||||
|
private globalMsgShortId = -2147483640;
|
||||||
|
private groupIds: number[] = [];
|
||||||
|
private LURCache = new LRU<number>();
|
||||||
|
private LastSentCache = new (class {
|
||||||
|
private cache: { gid: number; uid: number }[] = [];
|
||||||
|
private maxSize: number;
|
||||||
|
|
||||||
|
constructor(maxSize: number = 50000) {
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(gid: number, uid: number): boolean {
|
||||||
|
const exists = this.cache.some(
|
||||||
|
(entry) => entry.gid === gid && entry.uid === uid
|
||||||
|
);
|
||||||
|
if (!exists) {
|
||||||
|
this.cache.push({ gid, uid });
|
||||||
|
if (this.cache.length > this.maxSize) {
|
||||||
|
this.cache.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const interval = 1000 * 60 * 10; // 10分钟清理一次缓存
|
||||||
|
setInterval(() => {
|
||||||
|
logDebug('清理消息缓存');
|
||||||
|
this.msgCache.forEach((msg, key) => {
|
||||||
|
if ((Date.now() - parseInt(msg.msgTime) * 1000) > interval) {
|
||||||
|
this.msgCache.delete(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(dbPath: string) {
|
||||||
|
await super.init(dbPath);
|
||||||
|
this.globalMsgShortId = await this.getCurrentMaxShortId();
|
||||||
|
|
||||||
|
|
||||||
|
// 初始化群缓存列表
|
||||||
|
this.db!.serialize(() => {
|
||||||
|
const sql = 'SELECT * FROM sqlite_master WHERE type=\'table\'';
|
||||||
|
this.db!.all(sql, [], (err, rows: { name: string }[]) => {
|
||||||
|
if (err) return logError(err);
|
||||||
|
rows.forEach((row) => this.groupIds.push(parseInt(row.name)));
|
||||||
|
//logDebug(`已加载 ${groupIds.length} 个群`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.LURCache.on(async (nodeObject) => {
|
||||||
|
|
||||||
|
Object.entries(nodeObject).forEach(async ([_groupId, datas]) => {
|
||||||
|
const userIds = datas.map(v => v.userId);
|
||||||
|
const groupId = Number(_groupId);
|
||||||
|
logDebug('插入发言时间', _groupId);
|
||||||
|
|
||||||
|
await this.createGroupInfoTimeTableIfNotExist(groupId);
|
||||||
|
|
||||||
|
const needCreatUsers = await this.getNeedCreatList(groupId, userIds);
|
||||||
|
const updateList = needCreatUsers.length > 0 ? datas.filter(user => !needCreatUsers.includes(user.userId)) : datas;
|
||||||
|
const insertList = needCreatUsers.map(userId => datas.find(e => userId == e.userId)!);
|
||||||
|
|
||||||
|
logDebug('updateList', updateList);
|
||||||
|
logDebug('insertList', insertList);
|
||||||
|
|
||||||
|
if (insertList.length) {
|
||||||
|
const insertSql = `INSERT INTO "${groupId}" (last_sent_time, user_id) VALUES ${insertList.map(() => '(?, ?)').join(', ')};`;
|
||||||
|
|
||||||
|
this.db!.all(insertSql, insertList.map(v => [v.value, v.userId]).flat(), err => {
|
||||||
|
if (err) {
|
||||||
|
logError(`群 ${groupId} 插入失败`);
|
||||||
|
logError(`更新Sql : ${insertSql}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateList.length) {
|
||||||
|
const updateSql =
|
||||||
|
`UPDATE "${groupId}" SET last_sent_time = CASE ` +
|
||||||
|
updateList.map(v => `WHEN user_id = ${v.userId} THEN ${v.value}`).join(' ') +
|
||||||
|
' ELSE last_sent_time END WHERE user_id IN ' +
|
||||||
|
`(${updateList.map(v => v.userId).join(', ')});`;
|
||||||
|
|
||||||
|
this.db!.all(updateSql, [], err => {
|
||||||
|
if (err) {
|
||||||
|
logError(`群 ${groupId} 跟新失败`);
|
||||||
|
logError(`更新Sql : ${updateSql}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async getNeedCreatList(groupId: number, userIds: number[]) {
|
||||||
|
|
||||||
|
// 获取缓存中没有的
|
||||||
|
const unhas = userIds.filter(userId => !this.LastSentCache.get(groupId, userId));
|
||||||
|
|
||||||
|
if (unhas.length == 0) {
|
||||||
|
logDebug('缓存全部命中');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
logDebug('缓存未全部命中');
|
||||||
|
|
||||||
|
const sql = `SELECT * FROM "${groupId}" WHERE user_id IN (${unhas.map(() => '?').join(',')})`;
|
||||||
|
|
||||||
|
return new Promise<number[]>((resolve) => {
|
||||||
|
this.db!.all(sql, unhas, (err, rows: { user_id: number }[]) => {
|
||||||
|
const has = rows.map(v => v.user_id);
|
||||||
|
const needCreatUsers = unhas.filter(userId => !has.includes(userId));
|
||||||
|
|
||||||
|
if (needCreatUsers.length == 0) {
|
||||||
|
logDebug('数据库全部命中');
|
||||||
|
} else {
|
||||||
|
logDebug('数据库未全部命中');
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(needCreatUsers);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
async createGroupInfoTimeTableIfNotExist(groupId: number) {
|
||||||
|
const createTableSQL = (groupId: number) =>
|
||||||
|
`CREATE TABLE IF NOT EXISTS "${groupId}" (
|
||||||
|
user_id INTEGER,
|
||||||
|
last_sent_time INTEGER,
|
||||||
|
join_time INTEGER,
|
||||||
|
PRIMARY KEY (user_id)
|
||||||
|
);`;
|
||||||
|
|
||||||
|
if (this.groupIds.includes(groupId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const sql = createTableSQL(groupId);
|
||||||
|
this.db!.all(sql, (err) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.groupIds.push(groupId);
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
protected createTable() {
|
||||||
|
// 消息记录
|
||||||
|
const createTableSQL = `
|
||||||
|
CREATE TABLE IF NOT EXISTS msgs (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
shortId INTEGER NOT NULL UNIQUE,
|
||||||
|
longId TEXT NOT NULL UNIQUE,
|
||||||
|
seq INTEGER NOT NULL,
|
||||||
|
peerUid TEXT NOT NULL,
|
||||||
|
chatType INTEGER NOT NULL
|
||||||
|
)`;
|
||||||
|
this.db!.run(createTableSQL, function (err) {
|
||||||
|
if (err) {
|
||||||
|
logError('Could not create table msgs', err.stack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 文件缓存
|
||||||
|
const createFileTableSQL = `
|
||||||
|
CREATE TABLE IF NOT EXISTS files (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
path TEXT NOT NULL,
|
||||||
|
url TEXT,
|
||||||
|
size INTEGER NOT NULL,
|
||||||
|
uuid TEXT,
|
||||||
|
elementType INTEGER,
|
||||||
|
element TEXT NOT NULL,
|
||||||
|
elementId TEXT NOT NULL,
|
||||||
|
msgId TEXT NOT NULL
|
||||||
|
)`;
|
||||||
|
this.db!.run(createFileTableSQL, function (err) {
|
||||||
|
if (err) {
|
||||||
|
logError('Could not create table files', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getCurrentMaxShortId() {
|
||||||
|
return new Promise<number>((resolve, reject) => {
|
||||||
|
this.db!.get('SELECT MAX(shortId) as maxId FROM msgs', (err, row: { maxId: number }) => {
|
||||||
|
if (err) {
|
||||||
|
logDebug('Could not get max short id, Use default -2147483640', err);
|
||||||
|
return resolve(-2147483640);
|
||||||
|
}
|
||||||
|
logDebug('数据库中消息最大短id', row?.maxId);
|
||||||
|
resolve(row?.maxId ?? -2147483640);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getMsg(query: string, params: any[]) {
|
||||||
|
const stmt = this.db!.prepare(query);
|
||||||
|
return new Promise<RawMessage | null>((resolve, reject) => {
|
||||||
|
stmt.get(...params, (err: any, row: DBMsg) => {
|
||||||
|
// log("getMsg", row, err);
|
||||||
|
if (err) {
|
||||||
|
logError('Could not get msg', err, query, params);
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
if (!row) {
|
||||||
|
// logDebug('不存在数据库中的消息,不进行处理', query, params);
|
||||||
|
resolve(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const msgId = row.longId;
|
||||||
|
NTQQMsgApi.getMsgsByMsgId({ peerUid: row.peerUid, chatType: row.chatType }, [msgId]).then(res => {
|
||||||
|
const msg = res.msgList[0];
|
||||||
|
if (!msg) {
|
||||||
|
resolve(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msg.id = row.shortId;
|
||||||
|
resolve(msg);
|
||||||
|
}).catch(e => {
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMsgByShortId(shortId: number): Promise<RawMessage | null> {
|
||||||
|
if (this.msgCache.has(shortId)) {
|
||||||
|
return this.msgCache.get(shortId)!;
|
||||||
|
}
|
||||||
|
const getStmt = 'SELECT * FROM msgs WHERE shortId = ?';
|
||||||
|
return this.getMsg(getStmt, [shortId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMsgByLongId(longId: string): Promise<RawMessage | null> {
|
||||||
|
if (this.msgCache.has(longId)) {
|
||||||
|
return this.msgCache.get(longId)!;
|
||||||
|
}
|
||||||
|
return this.getMsg('SELECT * FROM msgs WHERE longId = ?', [longId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMsgBySeq(peerUid: string, seq: string): Promise<RawMessage | null> {
|
||||||
|
const stmt = 'SELECT * FROM msgs WHERE peerUid = ? AND seq = ?';
|
||||||
|
return this.getMsg(stmt, [peerUid, seq]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addMsg(msg: RawMessage, update = true): Promise<number> {
|
||||||
|
const existMsg = await this.getMsgByLongId(msg.msgId);
|
||||||
|
if (existMsg) {
|
||||||
|
// logDebug('消息已存在,更新数据库', msg.msgId);
|
||||||
|
if (update) this.updateMsg(msg).then();
|
||||||
|
return existMsg.id!;
|
||||||
|
}
|
||||||
|
const stmt = this.db!.prepare('INSERT INTO msgs (shortId, longId, seq, peerUid, chatType) VALUES (?, ?, ?, ?, ?)');
|
||||||
|
// const runAsync = promisify(stmt.run.bind(stmt));
|
||||||
|
const shortId = ++this.globalMsgShortId;
|
||||||
|
msg.id = shortId;
|
||||||
|
//logDebug(`记录消息到数据库, 消息长id: ${msg.msgId}, 短id: ${msg.id}`);
|
||||||
|
this.msgCache.set(shortId, msg);
|
||||||
|
this.msgCache.set(msg.msgId, msg);
|
||||||
|
stmt.run(this.globalMsgShortId, msg.msgId, msg.msgSeq.toString(), msg.peerUid, msg.chatType, (err: any) => {
|
||||||
|
if (err) {
|
||||||
|
if (err.errno === 19) {
|
||||||
|
this.getMsgByLongId(msg.msgId).then((msg: RawMessage | null) => {
|
||||||
|
if (msg) {
|
||||||
|
this.msgCache.set(shortId, msg);
|
||||||
|
this.msgCache.set(msg.msgId, msg);
|
||||||
|
// logDebug('获取消息短id成功', msg.id);
|
||||||
|
} else {
|
||||||
|
logError('db could not get msg by long id', err);
|
||||||
|
}
|
||||||
|
}).catch(e => logError('db getMsgByLongId error', e));
|
||||||
|
} else {
|
||||||
|
logError('db could not add msg', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return shortId;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateMsg(msg: RawMessage) {
|
||||||
|
const existMsg = this.msgCache.get(msg.msgId);
|
||||||
|
if (existMsg) {
|
||||||
|
Object.assign(existMsg, msg);
|
||||||
|
}
|
||||||
|
//logDebug(`更新消息, shortId:${msg.id}, seq: ${msg.msgSeq}, msgId: ${msg.msgId}`);
|
||||||
|
const stmt = this.db!.prepare('UPDATE msgs SET seq=? WHERE longId=?');
|
||||||
|
stmt.run(msg.msgSeq, msg.msgId, (err: any) => {
|
||||||
|
if (err) {
|
||||||
|
logError('updateMsg db error', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async addFileCache(file: DBFile) {
|
||||||
|
const stmt = this.db!.prepare('INSERT INTO files (name, path, url, size, uuid, elementType ,element, elementId, msgId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
stmt.run(file.name, file.path, file.url, file.size, file.uuid,
|
||||||
|
file.elementType,
|
||||||
|
JSON.stringify(file.element),
|
||||||
|
file.elementId,
|
||||||
|
file.msgId,
|
||||||
|
function (err: any) {
|
||||||
|
if (err) {
|
||||||
|
logError('db could not add file', err);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getFileCache(query: string, params: any[]) {
|
||||||
|
const stmt = this.db!.prepare(query);
|
||||||
|
return new Promise<DBFile | null>((resolve, reject) => {
|
||||||
|
stmt.get(...params, (err: any, row: DBFile & { element: string }) => {
|
||||||
|
if (err) {
|
||||||
|
logError('db could not get file cache', err);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
if (row) {
|
||||||
|
row.element = JSON.parse(row.element);
|
||||||
|
}
|
||||||
|
resolve(row);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFileCacheByName(name: string): Promise<DBFile | null> {
|
||||||
|
return this.getFileCache('SELECT * FROM files WHERE name = ?', [name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFileCacheByUuid(uuid: string): Promise<DBFile | null> {
|
||||||
|
return this.getFileCache('SELECT * FROM files WHERE uuid = ?', [uuid]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: 是否所有的文件都有uuid?语音消息有没有uuid?
|
||||||
|
async updateFileCache(file: DBFile) {
|
||||||
|
const stmt = this.db!.prepare('UPDATE files SET path = ?, url = ? WHERE uuid = ?');
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
stmt.run(file.path, file.url, file.uuid, function (err: any) {
|
||||||
|
if (err) {
|
||||||
|
logError('db could not update file cache', err);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLastSentTimeAndJoinTime(
|
||||||
|
groupId: number
|
||||||
|
): Promise<IRember[]> {
|
||||||
|
logDebug('读取发言时间', groupId);
|
||||||
|
return new Promise<IRember[]>((resolve, reject) => {
|
||||||
|
this.db!.all(`SELECT * FROM "${groupId}" `, (err, rows: IRember[]) => {
|
||||||
|
const cache = this.LURCache.get(groupId).map(e => ({ user_id: e.userId, last_sent_time: e.value }));
|
||||||
|
if (err) {
|
||||||
|
logError('查询发言时间失败', groupId);
|
||||||
|
return resolve(cache.map(e => ({ ...e, join_time: 0 })));
|
||||||
|
}
|
||||||
|
Object.assign(rows, cache);
|
||||||
|
logDebug('查询发言时间成功', groupId, rows);
|
||||||
|
resolve(rows);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
insertLastSentTime(
|
||||||
|
groupId: number,
|
||||||
|
userId: number,
|
||||||
|
time: number
|
||||||
|
) {
|
||||||
|
this.LURCache.set(groupId, userId, time);
|
||||||
|
}
|
||||||
|
async insertJoinTime(
|
||||||
|
groupId: number,
|
||||||
|
userId: number,
|
||||||
|
time: number
|
||||||
|
) {
|
||||||
|
await this.createGroupInfoTimeTableIfNotExist(groupId);
|
||||||
|
this.db!.all(
|
||||||
|
`INSERT OR REPLACE INTO "${groupId}" (user_id, last_sent_time, join_time) VALUES (?,?,?)`,
|
||||||
|
[userId, time, time],
|
||||||
|
(err) => {
|
||||||
|
if (err)
|
||||||
|
logError(err),
|
||||||
|
Promise.reject(),
|
||||||
|
logError('插入入群时间失败', userId, groupId);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const dbUtil = new DBUtil();
|
@@ -1,10 +1,10 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import fsPromise from 'fs/promises';
|
import fsPromise, { stat } from 'fs/promises';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import util from 'util';
|
import util from 'util';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { log } from './log';
|
import { log, logError } from './log';
|
||||||
import { dbUtil } from '@/core/utils/db';
|
import { dbUtil } from '@/common/utils/db';
|
||||||
import * as fileType from 'file-type';
|
import * as fileType from 'file-type';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { napCatCore } from '@/core';
|
import { napCatCore } from '@/core';
|
||||||
@@ -50,7 +50,40 @@ export function checkFileReceived(path: string, timeout: number = 3000): Promise
|
|||||||
check();
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果文件存在,则无需做任何事情,Promise 解决(resolve)自身
|
||||||
|
}
|
||||||
export async function file2base64(path: string) {
|
export async function file2base64(path: string) {
|
||||||
const readFile = util.promisify(fs.readFile);
|
const readFile = util.promisify(fs.readFile);
|
||||||
const result = {
|
const result = {
|
||||||
@@ -115,6 +148,8 @@ export async function httpDownload(options: string | HttpDownloadOptions): Promi
|
|||||||
};
|
};
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
url = options;
|
url = options;
|
||||||
|
const host = new URL(url).hostname;
|
||||||
|
headers['Host'] = host;
|
||||||
} else {
|
} else {
|
||||||
url = options.url;
|
url = options.url;
|
||||||
if (options.headers) {
|
if (options.headers) {
|
||||||
@@ -125,7 +160,12 @@ export async function httpDownload(options: string | HttpDownloadOptions): Promi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const fetchRes = await fetch(url, { headers });
|
const fetchRes = await fetch(url, { headers }).catch((err) => {
|
||||||
|
if (err.cause) {
|
||||||
|
throw err.cause;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`);
|
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`);
|
||||||
|
|
||||||
const blob = await fetchRes.blob();
|
const blob = await fetchRes.blob();
|
||||||
@@ -262,12 +302,12 @@ export async function copyFolder(sourcePath: string, destPath: string) {
|
|||||||
try {
|
try {
|
||||||
await fsPromise.copyFile(srcPath, dstPath);
|
await fsPromise.copyFile(srcPath, dstPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
|
logError(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
|
||||||
// 这里可以决定是否要继续复制其他文件
|
// 这里可以决定是否要继续复制其他文件
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('复制文件夹时出错:', error);
|
logError('复制文件夹时出错:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,12 @@ import crypto from 'node:crypto';
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import { log, logDebug } from './log';
|
import { log, logDebug } from './log';
|
||||||
|
import { dirname } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import * as fsPromise from 'node:fs/promises';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
export function sleep(ms: number): Promise<void> {
|
export function sleep(ms: number): Promise<void> {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
@@ -37,8 +43,117 @@ export function truncateString(obj: any, maxLength = 500) {
|
|||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
export function simpleDecorator(target: any, context: any) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function CacheClassFunc(ttl: number = 3600 * 1000, customKey: string = '') {
|
||||||
|
// const cache = new Map<string, { expiry: number; value: any }>();
|
||||||
|
// return function CacheClassFuncDecorator(originalMethod: Function, context: ClassMethodDecoratorContext) {
|
||||||
|
// async function CacheClassFuncDecoratorInternal(this: any, ...args: any[]) {
|
||||||
|
// const key = `${customKey}${String(context.name)}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`;
|
||||||
|
// const cachedValue = cache.get(key);
|
||||||
|
// if (cachedValue && cachedValue.expiry > Date.now()) {
|
||||||
|
// return cachedValue.value;
|
||||||
|
// }
|
||||||
|
// const result = originalMethod.call(this, ...args);
|
||||||
|
// cache.set(key, { expiry: Date.now() + ttl, value: result });
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// return CacheClassFuncDecoratorInternal;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
export function CacheClassFuncAsync(ttl: number = 3600 * 1000, customKey: string = '') {
|
||||||
|
//console.log('CacheClassFuncAsync', ttl, customKey);
|
||||||
|
function logExecutionTime(target: any, methodName: string, descriptor: PropertyDescriptor) {
|
||||||
|
//console.log('logExecutionTime', target, methodName, descriptor);
|
||||||
|
const cache = new Map<string, { expiry: number; value: any }>();
|
||||||
|
const originalMethod = descriptor.value;
|
||||||
|
descriptor.value = async function (...args: any[]) {
|
||||||
|
const key = `${customKey}${String(methodName)}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`;
|
||||||
|
cache.forEach((value, key) => {
|
||||||
|
if (value.expiry < Date.now()) {
|
||||||
|
cache.delete(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const cachedValue = cache.get(key);
|
||||||
|
if (cachedValue && cachedValue.expiry > Date.now()) {
|
||||||
|
return cachedValue.value;
|
||||||
|
}
|
||||||
|
// const start = Date.now();
|
||||||
|
const result = await originalMethod.apply(this, args);
|
||||||
|
// const end = Date.now();
|
||||||
|
// console.log(`Method ${methodName} executed in ${end - start} ms.`);
|
||||||
|
cache.set(key, { expiry: Date.now() + ttl, value: result });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return logExecutionTime;
|
||||||
|
}
|
||||||
|
export function CacheClassFuncAsyncExtend(ttl: number = 3600 * 1000, customKey: string = '', checker: any = (...data: any[]) => { return true; }) {
|
||||||
|
//console.log('CacheClassFuncAsync', ttl, customKey);
|
||||||
|
function logExecutionTime(target: any, methodName: string, descriptor: PropertyDescriptor) {
|
||||||
|
//console.log('logExecutionTime', target, methodName, descriptor);
|
||||||
|
const cache = new Map<string, { expiry: number; value: any }>();
|
||||||
|
const originalMethod = descriptor.value;
|
||||||
|
descriptor.value = async function (...args: any[]) {
|
||||||
|
const key = `${customKey}${String(methodName)}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`;
|
||||||
|
cache.forEach((value, key) => {
|
||||||
|
if (value.expiry < Date.now()) {
|
||||||
|
cache.delete(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const cachedValue = cache.get(key);
|
||||||
|
if (cachedValue && cachedValue.expiry > Date.now()) {
|
||||||
|
return cachedValue.value;
|
||||||
|
}
|
||||||
|
// const start = Date.now();
|
||||||
|
const result = await originalMethod.apply(this, args);
|
||||||
|
if (!checker(...args, result)) {
|
||||||
|
return result;//丢弃缓存
|
||||||
|
}
|
||||||
|
// const end = Date.now();
|
||||||
|
// console.log(`Method ${methodName} executed in ${end - start} ms.`);
|
||||||
|
cache.set(key, { expiry: Date.now() + ttl, value: result });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return logExecutionTime;
|
||||||
|
}
|
||||||
|
// export function CacheClassFuncAsync(ttl: number = 3600 * 1000, customKey: string = ''): any {
|
||||||
|
// const cache = new Map<string, { expiry: number; value: any }>();
|
||||||
|
|
||||||
|
// // 注意:在JavaScript装饰器中,我们通常不直接处理ClassMethodDecoratorContext这样的类型,
|
||||||
|
// // 因为装饰器的参数通常是目标类(对于类装饰器)、属性名(对于属性装饰器)等。
|
||||||
|
// // 对于方法装饰器,我们关注的是方法本身及其描述符。
|
||||||
|
// // 但这里我们维持原逻辑,假设有一个自定义的处理上下文的方式。
|
||||||
|
|
||||||
|
// return function (originalMethod: Function): any {
|
||||||
|
// console.log(originalMethod);
|
||||||
|
// // 由于JavaScript装饰器原生不支持异步直接定义,我们保持async定义以便处理异步方法。
|
||||||
|
// async function decoratorWrapper(this: any, ...args: any[]): Promise<any> {
|
||||||
|
// console.log(...args);
|
||||||
|
// const key = `${customKey}${originalMethod.name}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`;
|
||||||
|
// const cachedValue = cache.get(key);
|
||||||
|
// // 遍历cache 清除expiry内容
|
||||||
|
// cache.forEach((value, key) => {
|
||||||
|
// if (value.expiry < Date.now()) {
|
||||||
|
// cache.delete(key);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// if (cachedValue && cachedValue.expiry > Date.now()) {
|
||||||
|
// return cachedValue.value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 直接await异步方法的结果
|
||||||
|
// const result = await originalMethod.apply(this, args);
|
||||||
|
// cache.set(key, { expiry: Date.now() + ttl, value: result });
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 返回装饰后的方法,保持与原方法相同的名称和描述符(如果需要更精细的控制,可以考虑使用Object.getOwnPropertyDescriptor等)
|
||||||
|
// return decoratorWrapper;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 函数缓存装饰器,根据方法名、参数、自定义key生成缓存键,在一定时间内返回缓存结果
|
* 函数缓存装饰器,根据方法名、参数、自定义key生成缓存键,在一定时间内返回缓存结果
|
||||||
@@ -132,6 +247,10 @@ export function migrateConfig(oldConfig: any) {
|
|||||||
enable: oldConfig.enableWsReverse,
|
enable: oldConfig.enableWsReverse,
|
||||||
urls: oldConfig.wsReverseUrls,
|
urls: oldConfig.wsReverseUrls,
|
||||||
},
|
},
|
||||||
|
GroupLocalTime: {
|
||||||
|
Record: false,
|
||||||
|
RecordList: []
|
||||||
|
},
|
||||||
debug: oldConfig.debug,
|
debug: oldConfig.debug,
|
||||||
heartInterval: oldConfig.heartInterval,
|
heartInterval: oldConfig.heartInterval,
|
||||||
messagePostFormat: oldConfig.messagePostFormat,
|
messagePostFormat: oldConfig.messagePostFormat,
|
||||||
@@ -139,6 +258,7 @@ export function migrateConfig(oldConfig: any) {
|
|||||||
musicSignUrl: oldConfig.musicSignUrl,
|
musicSignUrl: oldConfig.musicSignUrl,
|
||||||
reportSelfMessage: oldConfig.reportSelfMessage,
|
reportSelfMessage: oldConfig.reportSelfMessage,
|
||||||
token: oldConfig.token,
|
token: oldConfig.token,
|
||||||
|
|
||||||
};
|
};
|
||||||
return newConfig;
|
return newConfig;
|
||||||
}
|
}
|
||||||
@@ -147,12 +267,49 @@ export async function UpdateConfig() {
|
|||||||
const configFiles = await fs.readdir(path.join(__dirname, 'config'));
|
const configFiles = await fs.readdir(path.join(__dirname, 'config'));
|
||||||
for (const file of configFiles) {
|
for (const file of configFiles) {
|
||||||
if (file.match(/^onebot11_\d+.json$/)) {
|
if (file.match(/^onebot11_\d+.json$/)) {
|
||||||
let CurrentConfig = JSON.parse(await fs.readFile(path.join(__dirname, 'config', file), 'utf8'));
|
const CurrentConfig = JSON.parse(await fs.readFile(path.join(__dirname, 'config', file), 'utf8'));
|
||||||
if (isValidOldConfig(CurrentConfig)) {
|
if (isValidOldConfig(CurrentConfig)) {
|
||||||
log("正在迁移旧配置到新配置 File:", file);
|
log('正在迁移旧配置到新配置 File:', file);
|
||||||
let NewConfig = migrateConfig(CurrentConfig);
|
const NewConfig = migrateConfig(CurrentConfig);
|
||||||
await fs.writeFile(path.join(__dirname, 'config', file), JSON.stringify(NewConfig, null, 2));
|
await fs.writeFile(path.join(__dirname, 'config', file), JSON.stringify(NewConfig, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export function isEqual(obj1: any, obj2: any) {
|
||||||
|
if (obj1 === obj2) return true;
|
||||||
|
if (obj1 == null || obj2 == null) return false;
|
||||||
|
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2;
|
||||||
|
|
||||||
|
const keys1 = Object.keys(obj1);
|
||||||
|
const keys2 = Object.keys(obj2);
|
||||||
|
|
||||||
|
if (keys1.length !== keys2.length) return false;
|
||||||
|
|
||||||
|
for (const key of keys1) {
|
||||||
|
if (!isEqual(obj1[key], obj2[key])) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -2,6 +2,12 @@ import log4js, { Configuration } from 'log4js';
|
|||||||
import { truncateString } from '@/common/utils/helper';
|
import { truncateString } from '@/common/utils/helper';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { SelfInfo } from '@/core';
|
import { SelfInfo } from '@/core';
|
||||||
|
import { dirname } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
export enum LogLevel {
|
export enum LogLevel {
|
||||||
DEBUG = 'debug',
|
DEBUG = 'debug',
|
||||||
@@ -33,17 +39,17 @@ const logConfig: Configuration = {
|
|||||||
FileAppender: { // 输出到文件的appender
|
FileAppender: { // 输出到文件的appender
|
||||||
type: 'file',
|
type: 'file',
|
||||||
filename: logPath, // 指定日志文件的位置和文件名
|
filename: logPath, // 指定日志文件的位置和文件名
|
||||||
maxLoogSize: 10485760, // 日志文件的最大大小(单位:字节),这里设置为10MB
|
maxLogSize: 10485760, // 日志文件的最大大小(单位:字节),这里设置为10MB
|
||||||
layout: {
|
layout: {
|
||||||
type: 'pattern',
|
type: 'pattern',
|
||||||
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] - %m'
|
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] %X{userInfo} | %m'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ConsoleAppender: { // 输出到控制台的appender
|
ConsoleAppender: { // 输出到控制台的appender
|
||||||
type: 'console',
|
type: 'console',
|
||||||
layout: {
|
layout: {
|
||||||
type: 'pattern',
|
type: 'pattern',
|
||||||
pattern: '%d{yyyy-MM-dd hh:mm:ss} [%p] - %m'
|
pattern: `%d{yyyy-MM-dd hh:mm:ss} [%[%p%]] ${chalk.magenta('%X{userInfo}')} | %m`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -55,7 +61,9 @@ const logConfig: Configuration = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
log4js.configure(logConfig);
|
log4js.configure(logConfig);
|
||||||
|
const loggerConsole = log4js.getLogger('console');
|
||||||
|
const loggerFile = log4js.getLogger('file');
|
||||||
|
const loggerDefault = log4js.getLogger('default');
|
||||||
|
|
||||||
export function setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
export function setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
||||||
logConfig.categories.file.level = fileLogLevel;
|
logConfig.categories.file.level = fileLogLevel;
|
||||||
@@ -64,12 +72,12 @@ export function setLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setLogSelfInfo(selfInfo: SelfInfo) {
|
export function setLogSelfInfo(selfInfo: SelfInfo) {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
const userInfo = `${selfInfo.nick}(${selfInfo.uin})`;
|
||||||
// @ts-expect-error
|
loggerConsole.addContext('userInfo', userInfo);
|
||||||
logConfig.appenders.FileAppender.layout.pattern = logConfig.appenders.ConsoleAppender.layout.pattern =
|
loggerFile.addContext('userInfo', userInfo);
|
||||||
`%d{yyyy-MM-dd hh:mm:ss} [%p] ${selfInfo.nick}(${selfInfo.uin}) %m`;
|
loggerDefault.addContext('userInfo', userInfo);
|
||||||
log4js.configure(logConfig);
|
|
||||||
}
|
}
|
||||||
|
setLogSelfInfo({ nick: '', uin: '', uid: '' });
|
||||||
|
|
||||||
let fileLogEnabled = true;
|
let fileLogEnabled = true;
|
||||||
let consoleLogEnabled = true;
|
let consoleLogEnabled = true;
|
||||||
@@ -80,7 +88,7 @@ export function enableConsoleLog(enable: boolean) {
|
|||||||
consoleLogEnabled = enable;
|
consoleLogEnabled = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMsg(msg: any[]){
|
function formatMsg(msg: any[]) {
|
||||||
let logMsg = '';
|
let logMsg = '';
|
||||||
for (const msgItem of msg) {
|
for (const msgItem of msg) {
|
||||||
// 判断是否是对象
|
// 判断是否是对象
|
||||||
@@ -91,15 +99,18 @@ function formatMsg(msg: any[]){
|
|||||||
}
|
}
|
||||||
logMsg += msgItem + ' ';
|
logMsg += msgItem + ' ';
|
||||||
}
|
}
|
||||||
return '\n' + logMsg + '\n';
|
return logMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _log(level: LogLevel, ...args: any[]){
|
// eslint-disable-next-line no-control-regex
|
||||||
if (consoleLogEnabled){
|
const colorEscape = /\x1B[@-_][0-?]*[ -/]*[@-~]/g;
|
||||||
log4js.getLogger('console')[level](formatMsg(args));
|
|
||||||
|
function _log(level: LogLevel, ...args: any[]) {
|
||||||
|
if (consoleLogEnabled) {
|
||||||
|
loggerConsole[level](formatMsg(args));
|
||||||
}
|
}
|
||||||
if (fileLogEnabled){
|
if (fileLogEnabled) {
|
||||||
log4js.getLogger('file')[level](formatMsg(args));
|
loggerFile[level](formatMsg(args).replace(colorEscape, ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,3 +126,11 @@ export function logDebug(...args: any[]) {
|
|||||||
export function logError(...args: any[]) {
|
export function logError(...args: any[]) {
|
||||||
_log(LogLevel.ERROR, ...args);
|
_log(LogLevel.ERROR, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function logWarn(...args: any[]) {
|
||||||
|
_log(LogLevel.WARN, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logFatal(...args: any[]) {
|
||||||
|
_log(LogLevel.FATAL, ...args);
|
||||||
|
}
|
@@ -1,37 +1,44 @@
|
|||||||
import { resolve } from "node:path";
|
import { resolve } from 'node:path';
|
||||||
import { spawn } from "node:child_process";
|
import { spawn } from 'node:child_process';
|
||||||
import { pid, ppid, exit } from 'node: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) {
|
export async function rebootWithQuickLogin(uin: string) {
|
||||||
let batScript = resolve(__dirname, './napcat.bat');
|
const batScript = resolve(__dirname, './napcat.bat');
|
||||||
let batUtf8Script = resolve(__dirname, './napcat-utf8.bat');
|
const batUtf8Script = resolve(__dirname, './napcat-utf8.bat');
|
||||||
let bashScript = resolve(__dirname, './napcat.sh');
|
const bashScript = resolve(__dirname, './napcat.sh');
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
const subProcess = spawn(`start ${batUtf8Script} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
const subProcess = spawn(`start ${batUtf8Script} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||||
subProcess.unref();
|
subProcess.unref();
|
||||||
// 子父进程一起送走 有点效果
|
// 子父进程一起送走 有点效果
|
||||||
spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
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' });
|
spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||||
} else if (process.platform === 'linux') {
|
} else if (process.platform === 'linux') {
|
||||||
const subProcess = spawn(`${bashScript} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
const subProcess = spawn(`${bashScript} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||||
//还没兼容
|
//还没兼容
|
||||||
subProcess.unref();
|
subProcess.unref();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
//exit(0);
|
//exit(0);
|
||||||
}
|
}
|
||||||
export async function rebootWithNormolLogin() {
|
export async function rebootWithNormolLogin() {
|
||||||
let batScript = resolve(__dirname, './napcat.bat');
|
const batScript = resolve(__dirname, './napcat.bat');
|
||||||
let batUtf8Script = resolve(__dirname, './napcat-utf8.bat');
|
const batUtf8Script = resolve(__dirname, './napcat-utf8.bat');
|
||||||
let bashScript = resolve(__dirname, './napcat.sh');
|
const bashScript = resolve(__dirname, './napcat.sh');
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
const subProcess = spawn(`start ${batUtf8Script} `, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
const subProcess = spawn(`start ${batUtf8Script} `, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' });
|
||||||
subProcess.unref();
|
subProcess.unref();
|
||||||
// 子父进程一起送走 有点效果
|
// 子父进程一起送走 有点效果
|
||||||
spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
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' });
|
spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' });
|
||||||
} else if (process.platform === 'linux') {
|
} else if (process.platform === 'linux') {
|
||||||
const subProcess = spawn(`${bashScript}`, { detached: true, windowsHide: false, env: process.env, shell: true });
|
const subProcess = spawn(`${bashScript}`, { detached: true, windowsHide: false, env: process.env, shell: true });
|
||||||
subProcess.unref();
|
subProcess.unref();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,37 +1,60 @@
|
|||||||
import https from 'node:https';
|
import https from 'node:https';
|
||||||
import http from 'node:http';
|
import http from 'node:http';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import { NTQQUserApi } from '@/core';
|
||||||
export class RequestUtil {
|
export class RequestUtil {
|
||||||
// 适用于获取服务器下发cookies时获取,仅GET
|
// 适用于获取服务器下发cookies时获取,仅GET
|
||||||
static async HttpsGetCookies(url: string): Promise<Map<string, string>> {
|
static async HttpsGetCookies(url: string): Promise<{ [key: string]: string }> {
|
||||||
return new Promise<Map<string, string>>((resolve, reject) => {
|
const client = url.startsWith('https') ? https : http;
|
||||||
const protocol = url.startsWith('https://') ? https : http;
|
return new Promise((resolve, reject) => {
|
||||||
protocol.get(url, (res) => {
|
const req = client.get(url, (res) => {
|
||||||
const cookiesHeader = res.headers['set-cookie'];
|
let cookies: { [key: string]: string } = {};
|
||||||
if (!cookiesHeader) {
|
const handleRedirect = (res: http.IncomingMessage) => {
|
||||||
resolve(new Map<string, string>());
|
//console.log(res.headers.location);
|
||||||
} else {
|
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||||
const cookiesMap = new Map<string, string>();
|
if (res.headers.location) {
|
||||||
cookiesHeader.forEach((cookieStr) => {
|
const redirectUrl = new URL(res.headers.location, url);
|
||||||
cookieStr.split(';').forEach((cookiePart) => {
|
RequestUtil.HttpsGetCookies(redirectUrl.href).then((redirectCookies) => {
|
||||||
const trimmedPart = cookiePart.trim();
|
// 合并重定向过程中的cookies
|
||||||
if (trimmedPart.includes('=')) {
|
cookies = { ...cookies, ...redirectCookies };
|
||||||
const [key, value] = trimmedPart.split('=').map(part => part.trim());
|
resolve(cookies);
|
||||||
cookiesMap.set(key, decodeURIComponent(value)); // 解码cookie值
|
}).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;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
resolve(cookiesMap);
|
|
||||||
}
|
}
|
||||||
}).on('error', (error) => {
|
|
||||||
reject(error);
|
|
||||||
});
|
});
|
||||||
|
req.on('error', (error: any) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 请求和回复都是JSON data传原始内容 自动编码json
|
// 请求和回复都是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> {
|
static async HttpGetJson<T>(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}, isJsonRet: boolean = true, isArgJson: boolean = true): Promise<T> {
|
||||||
let option = new URL(url);
|
const option = new URL(url);
|
||||||
const protocol = url.startsWith('https://') ? https : http;
|
const protocol = url.startsWith('https://') ? https : http;
|
||||||
const options = {
|
const options = {
|
||||||
hostname: option.hostname,
|
hostname: option.hostname,
|
||||||
@@ -40,6 +63,10 @@ export class RequestUtil {
|
|||||||
method: method,
|
method: method,
|
||||||
headers: headers
|
headers: headers
|
||||||
};
|
};
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json',
|
||||||
|
// 'Content-Length': Buffer.byteLength(postData),
|
||||||
|
// },
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const req = protocol.request(options, (res: any) => {
|
const req = protocol.request(options, (res: any) => {
|
||||||
let responseBody = '';
|
let responseBody = '';
|
||||||
@@ -81,7 +108,86 @@ export class RequestUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 请求返回都是原始内容
|
// 请求返回都是原始内容
|
||||||
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: Record<string, string> = {}) {
|
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) {
|
||||||
return this.HttpGetJson<string>(url, method, data, headers, false, false);
|
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): Promise<string> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
type retType = { retcode: number, result?: { url: string } };
|
||||||
|
try {
|
||||||
|
const cookies = Object.entries(await NTQQUserApi.getCookies('connect.qq.com')).map(([key, value]) => `${key}=${value}`).join('; ');
|
||||||
|
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.error('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);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,17 +1,74 @@
|
|||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
import { networkInterfaces } from 'os';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
// 缓解Win7设备兼容性问题
|
// 缓解Win7设备兼容性问题
|
||||||
let osName: string;
|
let osName: string;
|
||||||
|
// 设备ID
|
||||||
|
let machineId: Promise<string>;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
osName = os.hostname();
|
osName = os.hostname();
|
||||||
} catch (e) {
|
} 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 || uuidv4(); // 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 systemPlatform = os.platform();
|
||||||
export const cpuArch = os.arch();
|
export const cpuArch = os.arch();
|
||||||
export const systemVersion = os.release();
|
export const systemVersion = os.release();
|
||||||
export const hostname = osName;
|
export const hostname = osName;
|
||||||
const homeDir = os.homedir();
|
|
||||||
export const downloadsPath = path.join(homeDir, 'Downloads');
|
export const downloadsPath = path.join(homeDir, 'Downloads');
|
||||||
export const systemName = os.type();
|
export const systemName = os.type();
|
@@ -2,30 +2,30 @@
|
|||||||
* 运行时类型转换与检查类
|
* 运行时类型转换与检查类
|
||||||
*/
|
*/
|
||||||
export class TypeCheck {
|
export class TypeCheck {
|
||||||
static isEmpty(value: any): boolean {
|
static isEmpty(value: any): boolean {
|
||||||
return value === null || value === undefined || value === '' ||
|
return value === null || value === undefined || value === '' ||
|
||||||
(Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0);
|
(Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TypeConvert {
|
export class TypeConvert {
|
||||||
static toNumber(value: any): number {
|
static toNumber(value: any): number {
|
||||||
const num = Number(value);
|
const num = Number(value);
|
||||||
if (isNaN(num)) {
|
if (isNaN(num)) {
|
||||||
throw new Error(`无法将输入转换为数字: ${value}`);
|
throw new Error(`无法将输入转换为数字: ${value}`);
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
static toString(value: any): string {
|
static toString(value: any): string {
|
||||||
return String(value);
|
return String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static toBoolean(value: any): boolean {
|
static toBoolean(value: any): boolean {
|
||||||
return Boolean(value);
|
return Boolean(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static toArray(value: any): any[] {
|
static toArray(value: any): any[] {
|
||||||
return Array.isArray(value) ? value : [value];
|
return Array.isArray(value) ? value : [value];
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -14,7 +14,7 @@ export async function checkVersion(): Promise<string> {
|
|||||||
try {
|
try {
|
||||||
version = (await RequestUtil.HttpGetJson<{ version: string }>(url)).version;
|
version = (await RequestUtil.HttpGetJson<{ version: string }>(url)).version;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logDebug(e);
|
logDebug('检测更新异常',e);
|
||||||
}
|
}
|
||||||
if (version) {
|
if (version) {
|
||||||
resolve(version);
|
resolve(version);
|
||||||
|
@@ -24,7 +24,7 @@ export async function getVideoInfo(filePath: string) {
|
|||||||
} else {
|
} else {
|
||||||
const videoStream = metadata.streams.find((s: { codec_type: string; }) => s.codec_type === 'video');
|
const videoStream = metadata.streams.find((s: { codec_type: string; }) => s.codec_type === 'video');
|
||||||
if (videoStream) {
|
if (videoStream) {
|
||||||
console.log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
|
log(`视频尺寸: ${videoStream.width}x${videoStream.height}`);
|
||||||
} else {
|
} else {
|
||||||
return reject('未找到视频流信息。');
|
return reject('未找到视频流信息。');
|
||||||
}
|
}
|
||||||
|
1
src/core
1
src/core
Submodule src/core deleted from 00d059a88e
@@ -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 _0x312801=_0x226a;(function(_0x2467bd,_0x1ea46c){var _0x55b3b9=_0x226a,_0xc5a225=_0x2467bd();while(!![]){try{var _0x37ca7d=-parseInt(_0x55b3b9(0xb8))/0x1*(-parseInt(_0x55b3b9(0xb7))/0x2)+parseInt(_0x55b3b9(0xbe))/0x3*(-parseInt(_0x55b3b9(0xb6))/0x4)+-parseInt(_0x55b3b9(0xba))/0x5*(parseInt(_0x55b3b9(0xbd))/0x6)+parseInt(_0x55b3b9(0xbf))/0x7+-parseInt(_0x55b3b9(0xbb))/0x8+-parseInt(_0x55b3b9(0xc0))/0x9+-parseInt(_0x55b3b9(0xbc))/0xa*(-parseInt(_0x55b3b9(0xb9))/0xb);if(_0x37ca7d===_0x1ea46c)break;else _0xc5a225['push'](_0xc5a225['shift']());}catch(_0x37c00a){_0xc5a225['push'](_0xc5a225['shift']());}}}(_0x3f33,0xa7262));function _0x226a(_0x147607,_0x4d8036){var _0x3f3311=_0x3f33();return _0x226a=function(_0x226afb,_0x3c304e){_0x226afb=_0x226afb-0xb5;var _0x4481fe=_0x3f3311[_0x226afb];return _0x4481fe;},_0x226a(_0x147607,_0x4d8036);}function _0x3f33(){var _0x49480f=['109615yGGBGb','417840uZphAj','6916336dArrkB','3280WaNFfO','84tMzoBS','2219037UDDDKL','8472464uELZIr','11638368bueewF','onMSFStatusChange','getGroupCode','4vhGRRP','546190CcHtON','1ZYSbWg'];_0x3f33=function(){return _0x49480f;};return _0x3f33();}export class DependsAdapter{[_0x312801(0xc1)](_0x1bb24c,_0x487012){}['onMSFSsoError'](_0x41a22e){}[_0x312801(0xb5)](_0x487b3b){}}
|
|
@@ -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 _0xd918(_0x41483d,_0x889907){var _0x58bf19=_0x58bf();return _0xd918=function(_0xd918d8,_0x1ca855){_0xd918d8=_0xd918d8-0x1a8;var _0x922fac=_0x58bf19[_0xd918d8];return _0x922fac;},_0xd918(_0x41483d,_0x889907);}var _0x2ff274=_0xd918;(function(_0x4e51bb,_0x3ea197){var _0x37f53a=_0xd918,_0x443375=_0x4e51bb();while(!![]){try{var _0x1e5344=-parseInt(_0x37f53a(0x1ad))/0x1+parseInt(_0x37f53a(0x1af))/0x2+parseInt(_0x37f53a(0x1ac))/0x3*(parseInt(_0x37f53a(0x1b0))/0x4)+-parseInt(_0x37f53a(0x1b4))/0x5*(parseInt(_0x37f53a(0x1ae))/0x6)+parseInt(_0x37f53a(0x1a9))/0x7*(-parseInt(_0x37f53a(0x1ab))/0x8)+-parseInt(_0x37f53a(0x1aa))/0x9+parseInt(_0x37f53a(0x1b2))/0xa;if(_0x1e5344===_0x3ea197)break;else _0x443375['push'](_0x443375['shift']());}catch(_0x35dc93){_0x443375['push'](_0x443375['shift']());}}}(_0x58bf,0x469fd));export class DispatcherAdapter{[_0x2ff274(0x1b3)](_0x1d95f2){}[_0x2ff274(0x1a8)](_0x3ea26c){}[_0x2ff274(0x1b1)](_0x10acdf){}}function _0x58bf(){var _0x4f3322=['dispatchRequest','2046670cXvFGX','dispatchCall','21STBWCf','2445264sDyRrR','2408lpMgBD','294726nxCwLq','374542jqZJvb','6PeQMDn','1135130cwIbEO','8xmGioW','dispatchCallWithJson','5817030ZXbzaz'];_0x58bf=function(){return _0x4f3322;};return _0x58bf();}
|
|
@@ -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 _0x542e(_0x24d725,_0x626b2e){var _0x560aad=_0x560a();return _0x542e=function(_0x542ed4,_0x34edc1){_0x542ed4=_0x542ed4-0x76;var _0x635f00=_0x560aad[_0x542ed4];return _0x635f00;},_0x542e(_0x24d725,_0x626b2e);}var _0x12c22c=_0x542e;(function(_0x5f520f,_0x2af615){var _0x261cf6=_0x542e,_0x19e611=_0x5f520f();while(!![]){try{var _0x4f968b=parseInt(_0x261cf6(0x7c))/0x1+-parseInt(_0x261cf6(0x78))/0x2+parseInt(_0x261cf6(0x82))/0x3+parseInt(_0x261cf6(0x7e))/0x4+-parseInt(_0x261cf6(0x7b))/0x5*(-parseInt(_0x261cf6(0x7d))/0x6)+parseInt(_0x261cf6(0x7a))/0x7+parseInt(_0x261cf6(0x84))/0x8*(-parseInt(_0x261cf6(0x80))/0x9);if(_0x4f968b===_0x2af615)break;else _0x19e611['push'](_0x19e611['shift']());}catch(_0x364fba){_0x19e611['push'](_0x19e611['shift']());}}}(_0x560a,0x219d4));export class GlobalAdapter{[_0x12c22c(0x76)](..._0x2596f6){}[_0x12c22c(0x85)](..._0x5aa245){}['onShowErrUITips'](..._0x30bb0b){}[_0x12c22c(0x81)](..._0x526a26){}[_0x12c22c(0x7f)](..._0xda6e56){}[_0x12c22c(0x83)](..._0x24f600){}[_0x12c22c(0x79)](..._0x4642b6){}[_0x12c22c(0x77)](..._0x4dc1b2){}}function _0x560a(){var _0x8b3fc=['15ChtyeH','20320Tkwggx','310938UySqVX','724892uXQoPU','getAppSetting','7299JGoYfC','fixPicImgType','78327jdPzcS','onInstallFinished','3488ttTWCp','onGetSrvCalTime','onLog','onGetOfflineMsg','82140zEVtjW','onUpdateGeneralFlag','1044603ksIwqi'];_0x560a=function(){return _0x8b3fc;};return _0x560a();}
|
|
@@ -1 +0,0 @@
|
|||||||
function _0x3c69(_0x3bcbf7,_0x5062f6){var _0x18dfde=_0x18df();return _0x3c69=function(_0x3c698a,_0x2be4a1){_0x3c698a=_0x3c698a-0x18d;var _0x4fa004=_0x18dfde[_0x3c698a];return _0x4fa004;},_0x3c69(_0x3bcbf7,_0x5062f6);}(function(_0x10db25,_0x5cfed7){var _0x503822=_0x3c69,_0x22f0ac=_0x10db25();while(!![]){try{var _0x4c1fac=parseInt(_0x503822(0x192))/0x1+-parseInt(_0x503822(0x191))/0x2*(-parseInt(_0x503822(0x18d))/0x3)+-parseInt(_0x503822(0x18e))/0x4+-parseInt(_0x503822(0x18f))/0x5+parseInt(_0x503822(0x195))/0x6*(parseInt(_0x503822(0x190))/0x7)+-parseInt(_0x503822(0x193))/0x8*(-parseInt(_0x503822(0x196))/0x9)+-parseInt(_0x503822(0x194))/0xa;if(_0x4c1fac===_0x5cfed7)break;else _0x22f0ac['push'](_0x22f0ac['shift']());}catch(_0x1ef1d6){_0x22f0ac['push'](_0x22f0ac['shift']());}}}(_0x18df,0x6ee29));function _0x18df(){var _0x306bf8=['85099McqKSS','446612gfPezC','628119vRfteW','16UHyByL','9280230MKmgnk','312AXqpyn','1833957mTigZj','6zFIsSs','244244XMOWDt','3355860pyDEWQ'];_0x18df=function(){return _0x306bf8;};return _0x18df();}export*from'./NodeIDependsAdapter';export*from'./NodeIDispatcherAdapter';export*from'./NodeIGlobalAdapter';
|
|
37
src/core.lib/src/apis/file.d.ts
vendored
37
src/core.lib/src/apis/file.d.ts
vendored
@@ -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>;
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
5
src/core.lib/src/apis/friend.d.ts
vendored
5
src/core.lib/src/apis/friend.d.ts
vendored
@@ -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 _0x200bce=_0x521e;function _0xbabf(){const _0x211bb5=['addListener','2865738XvhlRl','set','66454YjOygA','uid','获取好友列表完成','reqTime','829616gfjVgA','push','3355675vCCGpI','getBuddyService','QypPz','handleFriendRequest','117iGJzXo','onBuddyListChange','delete','buddyList','获取好友列表超时','gJDqR','getFriends','friendUid','uin','onLoginSuccess','70828vHbuOz','getBuddyList','EHncv','approvalFriendRequest','session','iWgub','qlebO','开始获取好友列表','19828488yGaGlA','3392438TVQZNU'];_0xbabf=function(){return _0x211bb5;};return _0xbabf();}(function(_0x2df1dc,_0x19f282){const _0x6bf846=_0x521e,_0x80a8c=_0x2df1dc();while(!![]){try{const _0x44b977=-parseInt(_0x6bf846(0x16a))/0x1+parseInt(_0x6bf846(0x14d))/0x2+parseInt(_0x6bf846(0x153))/0x3*(-parseInt(_0x6bf846(0x15d))/0x4)+-parseInt(_0x6bf846(0x14f))/0x5+-parseInt(_0x6bf846(0x168))/0x6+-parseInt(_0x6bf846(0x166))/0x7+parseInt(_0x6bf846(0x165))/0x8;if(_0x44b977===_0x19f282)break;else _0x80a8c['push'](_0x80a8c['shift']());}catch(_0x59682b){_0x80a8c['push'](_0x80a8c['shift']());}}}(_0xbabf,0x7aca6));import{BuddyListener,napCatCore}from'@/core';import{logDebug}from'@/common/utils/log';import{uid2UinMap}from'@/core/data';import{randomUUID}from'crypto';const buddyChangeTasks=new Map(),buddyListener=new BuddyListener();function _0x521e(_0x32b35a,_0x4316c1){const _0xbabf17=_0xbabf();return _0x521e=function(_0x521e87,_0x464bc2){_0x521e87=_0x521e87-0x14a;let _0x4e917c=_0xbabf17[_0x521e87];return _0x4e917c;},_0x521e(_0x32b35a,_0x4316c1);}buddyListener[_0x200bce(0x154)]=_0xf2c49a=>{const _0x4a6b60=_0x200bce;for(const [_0x58ff70,_0x533778]of buddyChangeTasks){_0x533778(_0xf2c49a),buddyChangeTasks[_0x4a6b60(0x155)](_0x58ff70);}},setTimeout(()=>{const _0x331f78=_0x200bce;napCatCore[_0x331f78(0x15c)](()=>{const _0x148e1d=_0x331f78;napCatCore[_0x148e1d(0x167)](buddyListener);});},0x64);export class NTQQFriendApi{static async[_0x200bce(0x159)](_0x29cefa=![]){const _0x2c974d=_0x200bce,_0x1fd5d8={'qlebO':_0x2c974d(0x157),'gJDqR':function(_0x43b2bf,_0x49881f,_0x2b7903){return _0x43b2bf(_0x49881f,_0x2b7903);},'yvXxm':function(_0x10044e,_0x44494e){return _0x10044e(_0x44494e);},'EHncv':function(_0x577260,_0x33e923,_0x293431){return _0x577260(_0x33e923,_0x293431);},'iWgub':function(_0x43c87a){return _0x43c87a();}};return new Promise((_0x17a917,_0x2dd79f)=>{const _0x533a8b=_0x2c974d,_0x301724={'QypPz':function(_0x3f9258,_0x1fa332,_0x32a466){const _0x3a40f2=_0x521e;return _0x1fd5d8[_0x3a40f2(0x15f)](_0x3f9258,_0x1fa332,_0x32a466);}};let _0x3f2664=![];_0x1fd5d8[_0x533a8b(0x158)](setTimeout,()=>{const _0x51eb22=_0x533a8b;!_0x3f2664&&(logDebug(_0x1fd5d8['qlebO']),_0x2dd79f(_0x1fd5d8[_0x51eb22(0x163)]));},0x1388);const _0x21371c=[],_0x4d537d=_0x2686ce=>{const _0x258077=_0x533a8b;for(const _0x1a06c1 of _0x2686ce){for(const _0x2da3ba of _0x1a06c1[_0x258077(0x156)]){_0x21371c[_0x258077(0x14e)](_0x2da3ba),uid2UinMap[_0x2da3ba[_0x258077(0x14a)]]=_0x2da3ba[_0x258077(0x15b)];}}_0x3f2664=!![],_0x1fd5d8[_0x258077(0x158)](logDebug,_0x258077(0x14b),_0x21371c),_0x1fd5d8['yvXxm'](_0x17a917,_0x21371c);};buddyChangeTasks[_0x533a8b(0x169)](_0x1fd5d8[_0x533a8b(0x162)](randomUUID),_0x4d537d),napCatCore[_0x533a8b(0x161)]['getBuddyService']()[_0x533a8b(0x15e)](_0x29cefa)['then'](_0x1e52f8=>{const _0x1724cc=_0x533a8b;_0x301724[_0x1724cc(0x151)](logDebug,_0x1724cc(0x164),_0x1e52f8);});});}static async[_0x200bce(0x152)](_0x5c339a,_0x2b7159){const _0x223df1=_0x200bce;napCatCore[_0x223df1(0x161)][_0x223df1(0x150)]()?.[_0x223df1(0x160)]({'friendUid':_0x5c339a[_0x223df1(0x15a)],'reqTime':_0x5c339a[_0x223df1(0x14c)],'accept':_0x2b7159});}}
|
|
33
src/core.lib/src/apis/group.d.ts
vendored
33
src/core.lib/src/apis/group.d.ts
vendored
@@ -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<unknown>;
|
|
||||||
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>;
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
(function(_0x42ec9e,_0x3c5d53){var _0x26790a=_0x4120,_0x1cf0b9=_0x42ec9e();while(!![]){try{var _0x12ccdb=parseInt(_0x26790a(0xa1))/0x1*(-parseInt(_0x26790a(0xa8))/0x2)+parseInt(_0x26790a(0xa3))/0x3+-parseInt(_0x26790a(0xa4))/0x4+parseInt(_0x26790a(0x9e))/0x5*(-parseInt(_0x26790a(0xa5))/0x6)+parseInt(_0x26790a(0xa2))/0x7+parseInt(_0x26790a(0xa0))/0x8*(-parseInt(_0x26790a(0xa7))/0x9)+-parseInt(_0x26790a(0xa6))/0xa*(-parseInt(_0x26790a(0x9f))/0xb);if(_0x12ccdb===_0x3c5d53)break;else _0x1cf0b9['push'](_0x1cf0b9['shift']());}catch(_0xbba197){_0x1cf0b9['push'](_0x1cf0b9['shift']());}}}(_0x5bf8,0x5d7c7));export*from'./file';function _0x4120(_0x5e1952,_0x137c1b){var _0x5bf8fe=_0x5bf8();return _0x4120=function(_0x41206d,_0x213e6a){_0x41206d=_0x41206d-0x9e;var _0x9c8c9=_0x5bf8fe[_0x41206d];return _0x9c8c9;},_0x4120(_0x5e1952,_0x137c1b);}export*from'./friend';export*from'./group';function _0x5bf8(){var _0x25fec3=['1084932TAbQsr','5687800qhIJgq','1773ZjlHgT','272378dWjIPd','10DlCeMH','33tXMZNU','25336ZEgeJd','1DQMToq','976647qkfmox','941649ujvmGm','2620372YxyMrf'];_0x5bf8=function(){return _0x25fec3;};return _0x5bf8();}export*from'./msg';export*from'./user';export*from'./webapi';export*from'./sign';export*from'./system';
|
|
25
src/core.lib/src/apis/msg.d.ts
vendored
25
src/core.lib/src/apis/msg.d.ts
vendored
@@ -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>;
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
12
src/core.lib/src/apis/sign.d.ts
vendored
12
src/core.lib/src/apis/sign.d.ts
vendored
@@ -1,12 +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;
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
export{};
|
|
3
src/core.lib/src/apis/system.d.ts
vendored
3
src/core.lib/src/apis/system.d.ts
vendored
@@ -1,3 +0,0 @@
|
|||||||
export declare class NTQQSystemApi {
|
|
||||||
static hasOtherRunningQQProcess(): Promise<boolean>;
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
function _0xe208(_0x239302,_0x48d04f){var _0x34ef9f=_0x34ef();return _0xe208=function(_0xe20843,_0x541c07){_0xe20843=_0xe20843-0x13e;var _0x19a61e=_0x34ef9f[_0xe20843];return _0x19a61e;},_0xe208(_0x239302,_0x48d04f);}var _0x3f60c9=_0xe208;function _0x34ef(){var _0x406d51=['4900240iHNPdG','1370170vDQCth','2972523tLPDlP','4203250HeADmm','908327esyrES','4ZClBmZ','hasOtherRunningQQProcess','5169774BrFFYi','8558163ynHfmc','10JnedOb','7nGjUnb','util'];_0x34ef=function(){return _0x406d51;};return _0x34ef();}(function(_0x1f3083,_0xe1cf2e){var _0xf220e2=_0xe208,_0x6caf01=_0x1f3083();while(!![]){try{var _0x2e3826=-parseInt(_0xf220e2(0x144))/0x1+parseInt(_0xf220e2(0x141))/0x2+-parseInt(_0xf220e2(0x142))/0x3*(-parseInt(_0xf220e2(0x145))/0x4)+-parseInt(_0xf220e2(0x143))/0x5+-parseInt(_0xf220e2(0x147))/0x6*(parseInt(_0xf220e2(0x13e))/0x7)+parseInt(_0xf220e2(0x140))/0x8+-parseInt(_0xf220e2(0x148))/0x9*(-parseInt(_0xf220e2(0x149))/0xa);if(_0x2e3826===_0xe1cf2e)break;else _0x6caf01['push'](_0x6caf01['shift']());}catch(_0x5d654c){_0x6caf01['push'](_0x6caf01['shift']());}}}(_0x34ef,0x99815));import{napCatCore}from'@/core';export class NTQQSystemApi{static async[_0x3f60c9(0x146)](){var _0x1497e8=_0x3f60c9;return napCatCore[_0x1497e8(0x13f)][_0x1497e8(0x146)]();}}
|
|
22
src/core.lib/src/apis/user.d.ts
vendored
22
src/core.lib/src/apis/user.d.ts
vendored
@@ -1,22 +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 getSkey(cached?: boolean): Promise<string | undefined>;
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user